34
34
35
35
from utils .telemetry import telemetry
36
36
from utils .task import Task
37
- from utils .utils import remove_lines_with_string , is_extension_old_version
37
+ from utils .utils import remove_lines_with_string
38
38
39
39
40
40
class Project :
@@ -58,8 +58,6 @@ def __init__(
58
58
current_step (str, optional): Current step in the project. Default is None.
59
59
"""
60
60
self .args = args
61
- # TODO remove everything related to is_extension_old_version once new version is released and everybody has to update core
62
- self .is_extension_old_version = is_extension_old_version (args )
63
61
self .llm_req_num = 0
64
62
self .command_runs_count = 0
65
63
self .user_inputs_count = 0
@@ -98,12 +96,13 @@ def __init__(
98
96
File .update_paths ()
99
97
100
98
# start loading of project (since backwards compatibility)
101
- self .should_overwrite_files = False
99
+ self .should_overwrite_files = None
102
100
self .last_detailed_user_review_goal = None
103
101
self .last_iteration = None
104
102
self .tasks_to_load = []
105
103
self .features_to_load = []
106
104
self .dev_steps_to_load = []
105
+ self .run_command = None
107
106
# end loading of project
108
107
109
108
def set_root_path (self , root_path : str ):
@@ -118,22 +117,41 @@ def setup_loading(self):
118
117
return
119
118
120
119
self .skip_steps = True
121
- should_overwrite_files = None
122
- while should_overwrite_files is None or should_overwrite_files .lower () not in AFFIRMATIVE_ANSWERS + NEGATIVE_ANSWERS :
123
- print ('Use GPT Pilot\' s code/Keep my changes' , type = 'buttons-only' )
124
- should_overwrite_files = styled_text (
120
+ while self .should_overwrite_files is None :
121
+ changes_made_question = f'Did you make any changes to "{ self .args ["name" ]} " project files since last time you used Pythagora?'
122
+ print (changes_made_question , type = 'ipc' , category = 'pythagora' )
123
+ print ('yes/no' , type = 'buttons-only' )
124
+ # must use styled_text() instead of ask_user() here to avoid finish_loading() call
125
+ changes_made = styled_text (
125
126
self ,
126
- "Can GPT Pilot overwrite code changes you made since last running GPT Pilot?" ,
127
- ignore_user_input_count = True
127
+ changes_made_question ,
128
+ ignore_user_input_count = True ,
128
129
)
129
130
130
- logger .info ('should_overwrite_files: %s' , should_overwrite_files )
131
- if should_overwrite_files in NEGATIVE_ANSWERS :
132
- self .should_overwrite_files = False
133
- break
134
- elif should_overwrite_files in AFFIRMATIVE_ANSWERS :
131
+ # if there were no changes just load files from db
132
+ if changes_made .lower () in NEGATIVE_ANSWERS :
135
133
self .should_overwrite_files = True
136
134
break
135
+ # otherwise ask user if they want to use those changes
136
+ elif changes_made .lower () in AFFIRMATIVE_ANSWERS :
137
+ use_changes_question = 'Do you want to use those changes you made?'
138
+ use_changes_msg = 'yes'
139
+ dont_use_changes_msg = 'no, restore last pythagora state'
140
+ print (use_changes_question , type = 'ipc' , category = 'pythagora' )
141
+ print (f'{ use_changes_msg } /{ dont_use_changes_msg } ' , type = 'buttons-only' )
142
+ print (f'"{ dont_use_changes_msg } " means Pythagora will restore (overwrite) all files to last stored state.\n '
143
+ f'"{ use_changes_msg } " means Pythagora will continue working on project using current state of files.' , type = 'hint' )
144
+ use_changes = styled_text (
145
+ self ,
146
+ use_changes_question ,
147
+ ignore_user_input_count = True
148
+ )
149
+
150
+ logger .info ('Use changes: %s' , use_changes )
151
+ if use_changes .lower () in NEGATIVE_ANSWERS + [dont_use_changes_msg ]:
152
+ self .should_overwrite_files = True
153
+ elif use_changes .lower () in AFFIRMATIVE_ANSWERS + [use_changes_msg ]:
154
+ self .should_overwrite_files = False
137
155
138
156
load_step_before_coding = ('step' in self .args and
139
157
self .args ['step' ] is not None and
@@ -155,6 +173,9 @@ def setup_loading(self):
155
173
self .checkpoints ['last_development_step' ] = self .dev_steps_to_load [- 1 ]
156
174
self .tasks_to_load = [el for el in self .dev_steps_to_load if 'breakdown.prompt' in el .get ('prompt_path' , '' )]
157
175
self .features_to_load = [el for el in self .dev_steps_to_load if 'feature_plan.prompt' in el .get ('prompt_path' , '' )]
176
+ self .run_command = next ((el for el in reversed (self .dev_steps_to_load ) if 'get_run_command.prompt' in el .get ('prompt_path' , '' )), None )
177
+ if self .run_command is not None :
178
+ self .run_command = json .loads (self .run_command ['llm_response' ]['text' ])['command' ]
158
179
159
180
def start (self ):
160
181
"""
@@ -216,11 +237,13 @@ def finish(self):
216
237
self .previous_features = get_features_by_app_id (self .args ['app_id' ])
217
238
if not self .skip_steps :
218
239
print ('' , type = 'verbose' , category = 'pythagora' )
240
+ if self .run_command and self .check_ipc ():
241
+ print (self .run_command , type = 'run_command' )
219
242
feature_description = ask_user (self , "Project is finished! Do you want to add any features or changes? "
220
243
"If yes, describe it here and if no, just press ENTER" ,
221
244
require_some_input = False )
222
245
223
- if feature_description == '' :
246
+ if feature_description == '' or feature_description == 'continue' :
224
247
return
225
248
226
249
print ('' , type = 'verbose' , category = 'agent:tech-lead' )
@@ -391,13 +414,14 @@ def save_file(self, data):
391
414
inputs_required = self .find_input_required_lines (data ['content' ])
392
415
for line_number , line_content in inputs_required :
393
416
user_input = None
417
+ print ('' , type = 'verbose' , category = 'human-intervention' )
394
418
print (color_yellow_bold (f'Input required on line { line_number } :\n { line_content } ' ) + '\n ' )
395
419
while user_input is None or user_input .lower () not in AFFIRMATIVE_ANSWERS + ['continue' ]:
396
420
print ({'path' : full_path , 'line' : line_number }, type = 'openFile' )
397
421
print ('continue' , type = 'buttons-only' )
398
422
user_input = ask_user (
399
423
self ,
400
- f'Please open the file { data ["path" ]} on the line { line_number } and add the required input. Once you\' re done, type "y" to continue.' ,
424
+ f'Please open the file { data ["path" ]} on the line { line_number } and add the required input. Please, also remove "// INPUT_REQUIRED" comment and once you\' re done, press " continue" .' ,
401
425
require_some_input = False ,
402
426
ignore_user_input_count = True
403
427
)
@@ -458,7 +482,7 @@ def normalize_path(path: str) -> Tuple[str, str]:
458
482
# - /pilot -> /pilot/
459
483
# - \pilot\server.js -> \pilot\server.js
460
484
# - \pilot -> \pilot\
461
- KNOWN_FILES = ["makefile" , "dockerfile" , "procfile" , "readme" , "license" ] # known exceptions that break the heuristic
485
+ KNOWN_FILES = ["makefile" , "dockerfile" , "procfile" , "readme" , "license" , "podfile" ] # known exceptions that break the heuristic
462
486
KNOWN_DIRS = [] # known exceptions that break the heuristic
463
487
base = os .path .basename (path )
464
488
if (
@@ -543,7 +567,10 @@ def restore_files(self, development_step_id):
543
567
544
568
clear_directory (self .root_path , ignore = self .files )
545
569
for file_snapshot in file_snapshots :
546
- update_file (file_snapshot .file .full_path , file_snapshot .content , project = self )
570
+ try :
571
+ update_file (file_snapshot .file .full_path , file_snapshot .content , project = self )
572
+ except (PermissionError , NotADirectoryError ) as err : # noqa
573
+ print (f"Error restoring file { file_snapshot .file .full_path } : { err } " )
547
574
if file_snapshot .file .full_path not in self .files :
548
575
self .files .append (file_snapshot .file .full_path )
549
576
0 commit comments