chorus-cli 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +26 -18
- package/package.json +1 -1
- package/tools/__pycache__/coder.cpython-314.pyc +0 -0
- package/tools/coder.py +126 -112
package/index.js
CHANGED
|
@@ -18,41 +18,49 @@ const execPromise = util.promisify(exec);
|
|
|
18
18
|
const execFilePromise = util.promisify(execFile);
|
|
19
19
|
const fs = require('fs').promises;
|
|
20
20
|
|
|
21
|
-
// Returns a
|
|
21
|
+
// Returns a SHA-256 hash of this machine's hardware UUID (or a persistent random fallback).
|
|
22
|
+
// The raw UUID never leaves the device — only the hash is sent to the server.
|
|
22
23
|
async function getMachineId() {
|
|
24
|
+
const { createHash, randomUUID } = require('crypto');
|
|
25
|
+
let rawId;
|
|
26
|
+
|
|
23
27
|
try {
|
|
24
28
|
if (process.platform === 'darwin') {
|
|
25
29
|
const { stdout } = await execPromise(
|
|
26
30
|
"ioreg -rd1 -c IOPlatformExpertDevice | awk -F'\"' '/IOPlatformUUID/{print $4}'"
|
|
27
31
|
);
|
|
28
|
-
if (stdout.trim())
|
|
32
|
+
if (stdout.trim()) rawId = stdout.trim();
|
|
29
33
|
} else if (process.platform === 'linux') {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
if (id) return id;
|
|
34
|
+
const id = (await fs.readFile('/etc/machine-id', 'utf8')).trim();
|
|
35
|
+
if (id) rawId = id;
|
|
33
36
|
} else if (process.platform === 'win32') {
|
|
34
37
|
const { stdout } = await execPromise('wmic csproduct get UUID');
|
|
35
38
|
const lines = stdout.trim().split('\n');
|
|
36
39
|
if (lines.length > 1) {
|
|
37
40
|
const uuid = lines[1].trim();
|
|
38
|
-
if (uuid && uuid !== 'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF')
|
|
41
|
+
if (uuid && uuid !== 'FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF') rawId = uuid;
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
} catch { /* fall through to persistent fallback */ }
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
if (!rawId) {
|
|
47
|
+
// Persistent fallback: generate and cache a random UUID
|
|
48
|
+
const configDir = path.join(os.homedir(), '.config', 'chorus');
|
|
49
|
+
const idPath = path.join(configDir, 'machine-id');
|
|
50
|
+
try {
|
|
51
|
+
const existing = await fs.readFile(idPath, 'utf8');
|
|
52
|
+
if (existing.trim()) rawId = existing.trim();
|
|
53
|
+
} catch { /* no file yet */ }
|
|
54
|
+
|
|
55
|
+
if (!rawId) {
|
|
56
|
+
rawId = randomUUID();
|
|
57
|
+
const configDir2 = path.join(os.homedir(), '.config', 'chorus');
|
|
58
|
+
await fs.mkdir(configDir2, { recursive: true });
|
|
59
|
+
await fs.writeFile(path.join(configDir2, 'machine-id'), rawId + '\n');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
50
62
|
|
|
51
|
-
|
|
52
|
-
const newId = randomUUID();
|
|
53
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
54
|
-
await fs.writeFile(idPath, newId + '\n');
|
|
55
|
-
return newId;
|
|
63
|
+
return createHash('sha256').update(rawId).digest('hex');
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
// Run coder.py with real-time stderr streaming so progress is visible
|
package/package.json
CHANGED
|
Binary file
|
package/tools/coder.py
CHANGED
|
@@ -49,14 +49,9 @@ def is_token_limit_error(err):
|
|
|
49
49
|
msg = str(err)
|
|
50
50
|
return "token limit exceeded" in msg or "rate_limit_error" in msg
|
|
51
51
|
|
|
52
|
-
SYSTEM_PROMPT = """\
|
|
53
|
-
You are a coding agent. You receive a GitHub/Azure DevOps issue, a codebase map, \
|
|
54
|
-
and optionally a QA conversation with clarified requirements. Your job is to \
|
|
55
|
-
implement the changes and produce a clean, working diff.
|
|
56
|
-
|
|
57
|
-
Working directory: {cwd}
|
|
58
|
-
|
|
59
52
|
|
|
53
|
+
# ── Shared formatting rules (included in all prompts) ─────────────────────
|
|
54
|
+
_FORMAT_RULES = """\
|
|
60
55
|
OUTPUT FORMAT
|
|
61
56
|
|
|
62
57
|
Your output is displayed raw in a terminal. Never use markdown.
|
|
@@ -67,15 +62,20 @@ Use plain numbered lists (1. 2. 3.) when listing things.
|
|
|
67
62
|
Refer to code identifiers by name directly (e.g. myFunction not `myFunction`).
|
|
68
63
|
No greetings, preambles, encouragement, or sign-offs.
|
|
69
64
|
No "Great question!", "Let me", "Sure!", "I'll now", or similar filler.
|
|
70
|
-
State what you are doing, then do it. After completing work, state what changed.
|
|
65
|
+
State what you are doing, then do it. After completing work, state what changed."""
|
|
71
66
|
|
|
67
|
+
# ── Phase 1: Planning prompt (used once at the start of headless mode) ────
|
|
68
|
+
PLAN_PROMPT = """\
|
|
69
|
+
You are a coding agent. You receive a GitHub/Azure DevOps issue, a codebase map, \
|
|
70
|
+
and optionally a QA conversation with clarified requirements. Your job is to \
|
|
71
|
+
plan the implementation.
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Working directory: {cwd}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
""" + _FORMAT_RULES + """
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
TASK
|
|
79
79
|
|
|
80
80
|
Read the issue, QA conversation (if provided), and codebase map. Then produce a
|
|
81
81
|
written plan with exactly these sections:
|
|
@@ -101,17 +101,41 @@ APPROACH:
|
|
|
101
101
|
How you will implement this in 2-4 sentences. Reference specific patterns
|
|
102
102
|
from the codebase map.
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
ON AMBIGUITY
|
|
105
105
|
|
|
106
|
+
When requirements are unclear and no QA conversation was provided:
|
|
107
|
+
1. State your assumption explicitly.
|
|
108
|
+
2. Choose the most conventional/standard approach.
|
|
109
|
+
3. Flag it so the reviewer can catch disagreements early.
|
|
110
|
+
Do not guess ambitiously. Guess conservatively. A correct simple implementation beats
|
|
111
|
+
a broken ambitious one.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
# ── Phase 2: Execution prompt (used on every turn of the tool loop) ───────
|
|
115
|
+
EXEC_PROMPT = """\
|
|
116
|
+
You are a coding agent executing a plan. Implement the changes described in the
|
|
117
|
+
plan below. Do not re-plan or re-analyze. Execute.
|
|
118
|
+
|
|
119
|
+
Working directory: {cwd}
|
|
120
|
+
|
|
121
|
+
""" + _FORMAT_RULES + """
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
TOOL USAGE
|
|
106
125
|
|
|
107
|
-
|
|
126
|
+
Always use read_file before editing a file.
|
|
127
|
+
If edit_file fails with "old_string not found", re-read the file with read_file to
|
|
128
|
+
get the actual current content before retrying. Never guess at file contents.
|
|
129
|
+
Use edit_file for targeted changes. Use write_file for new files or complete rewrites.
|
|
130
|
+
Prefer editing existing files over creating new ones.
|
|
131
|
+
Use read_file, list_files, and search_files instead of bash with cat, find, or grep.
|
|
108
132
|
|
|
109
|
-
|
|
133
|
+
EXECUTION RULES
|
|
110
134
|
|
|
111
135
|
Reading files:
|
|
112
|
-
Only use read_file on files listed in
|
|
136
|
+
Only use read_file on files listed in the plan. If you discover you need another
|
|
113
137
|
file, note why -- but if you have read more than 12 files total, stop and
|
|
114
|
-
re-evaluate
|
|
138
|
+
re-evaluate. You are exploring, not implementing.
|
|
115
139
|
The one exception to reading a file again: if edit_file fails because old_string
|
|
116
140
|
was not found, re-read that file to get its current content before retrying.
|
|
117
141
|
|
|
@@ -125,77 +149,64 @@ Writing code:
|
|
|
125
149
|
Shell commands (bash tool):
|
|
126
150
|
You may run bash for: installing dependencies, running the project's existing
|
|
127
151
|
linter, running the project's existing tests, checking TypeScript compilation.
|
|
128
|
-
You may not run bash for: exploratory searching beyond what was in
|
|
152
|
+
You may not run bash for: exploratory searching beyond what was in the plan,
|
|
129
153
|
reading files you did not plan to read, testing scripts with improvised piped input.
|
|
130
|
-
Use read_file, list_files, and search_files instead of bash with cat, find, or grep.
|
|
131
154
|
Maximum 10 bash commands total. If you are approaching this limit, you are doing
|
|
132
155
|
too much exploration or too much debugging. Ship what you have.
|
|
133
156
|
|
|
134
|
-
|
|
135
|
-
PHASE 3: VERIFY
|
|
136
|
-
|
|
137
|
-
Before declaring done:
|
|
138
|
-
|
|
139
|
-
1. List every file you created or modified.
|
|
140
|
-
2. For each, confirm it is syntactically valid (ran linter or compiler if available).
|
|
141
|
-
3. If tests exist for the area you changed, run them and confirm they pass.
|
|
142
|
-
4. If you wrote a script/CLI tool, show the --help output or a dry-run invocation.
|
|
143
|
-
5. Write the PR description:
|
|
144
|
-
Title: conventional commit format (feat:, fix:, chore:, etc.)
|
|
145
|
-
Body: what changed, why, any assumptions made, anything the reviewer should
|
|
146
|
-
look at carefully.
|
|
147
|
-
|
|
148
|
-
|
|
149
157
|
BUDGET DISCIPLINE
|
|
150
158
|
|
|
151
|
-
You have a token budget. You do not know exactly how large it is, but you must act
|
|
152
|
-
as though it could run out at any time. This means:
|
|
153
|
-
|
|
154
159
|
Front-load the high-value work. Write the actual implementation code early. File
|
|
155
160
|
exploration is not progress -- committed code is progress.
|
|
156
161
|
|
|
157
162
|
Do not retry the same failing approach. If something fails twice, choose a different
|
|
158
163
|
approach or simplify. Do not iterate more than twice on the same problem.
|
|
159
164
|
|
|
160
|
-
If
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
No yak-shaving. If the issue says "create a screen scaffolding tool," build the tool.
|
|
165
|
-
Do not also create a demo script, a markdown doc, a bash wrapper, and sample outputs.
|
|
166
|
-
Deliver the core ask first. Only add extras if the implementation is solid and you
|
|
167
|
-
have headroom.
|
|
165
|
+
If something fundamental is broken, stop. Produce what you have, note what is
|
|
166
|
+
incomplete, and let the human finish. A partial, clean implementation is more
|
|
167
|
+
valuable than a complete, broken one.
|
|
168
168
|
|
|
169
|
+
No yak-shaving. Deliver the core ask. Do not create demo scripts, markdown docs,
|
|
170
|
+
bash wrappers, or sample outputs unless the issue asks for them.
|
|
169
171
|
|
|
170
172
|
WHAT NOT TO DO
|
|
171
173
|
|
|
172
|
-
Do not explore the filesystem to "understand the project." The codebase map
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
Do not overuse list_files, search_files, or bash for exploration. This is the single
|
|
176
|
-
most common failure mode. Each call costs tokens and time. If you need more than 3
|
|
177
|
-
exploratory calls, your plan was insufficient -- go back and improve the plan.
|
|
174
|
+
Do not explore the filesystem to "understand the project." The codebase map and your
|
|
175
|
+
plan already cover that. Read specific files for specific reasons.
|
|
178
176
|
|
|
179
|
-
Do not
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
Do not create documentation, READMEs, or demo files unless the issue asks for them.
|
|
177
|
+
Do not overuse list_files, search_files, or bash for exploration. If you need more
|
|
178
|
+
than 3 exploratory calls, your plan was insufficient.
|
|
183
179
|
|
|
180
|
+
Do not create interactive scripts that require stdin.
|
|
181
|
+
Do not create documentation or READMEs unless the issue asks for them.
|
|
184
182
|
Do not modify package.json, CI configs, or project infrastructure unless the issue
|
|
185
183
|
specifically requires it.
|
|
184
|
+
Do not keep going when stuck. After 2 failed attempts at the same problem, note the
|
|
185
|
+
issue, deliver what works, and move on.
|
|
186
186
|
|
|
187
|
-
|
|
188
|
-
the same problem, note the issue, deliver what works, and move on.
|
|
187
|
+
WHEN YOU ARE DONE
|
|
189
188
|
|
|
189
|
+
End with a verify block:
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
1. List every file you created or modified.
|
|
192
|
+
2. For each, confirm it is syntactically valid (ran linter or compiler if available).
|
|
193
|
+
3. If tests exist for the area you changed, run them and confirm they pass.
|
|
194
|
+
4. If you wrote a script/CLI tool, show the --help output or a dry-run invocation.
|
|
195
|
+
5. Write a summary in this exact format:
|
|
192
196
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
Do not
|
|
198
|
-
|
|
197
|
+
PR_TITLE: conventional commit format (feat:, fix:, chore:, etc.)
|
|
198
|
+
PR_BODY: what changed, why, any assumptions made, anything the reviewer should
|
|
199
|
+
look at carefully.
|
|
200
|
+
|
|
201
|
+
Do not output anything after the summary.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
# ── Interactive REPL prompt (conversational, no phased workflow) ──────────
|
|
205
|
+
REPL_PROMPT = """\
|
|
206
|
+
You are a coding agent running in an interactive terminal session.
|
|
207
|
+
Working directory: {cwd}
|
|
208
|
+
|
|
209
|
+
""" + _FORMAT_RULES + """
|
|
199
210
|
|
|
200
211
|
|
|
201
212
|
TOOL USAGE
|
|
@@ -205,6 +216,16 @@ TOOL USAGE
|
|
|
205
216
|
get the actual current content before retrying. Never guess at file contents.
|
|
206
217
|
Use edit_file for targeted changes. Use write_file for new files or complete rewrites.
|
|
207
218
|
Prefer editing existing files over creating new ones.
|
|
219
|
+
Use read_file, list_files, and search_files instead of bash with cat, find, or grep.
|
|
220
|
+
|
|
221
|
+
GUIDELINES
|
|
222
|
+
|
|
223
|
+
Be direct and concise. State what you will do, then do it.
|
|
224
|
+
Always use your tools. Never guess when you can look.
|
|
225
|
+
Do not write new unit tests unless the project already has substantive test coverage.
|
|
226
|
+
Do not attempt to build or compile the project unless asked.
|
|
227
|
+
Do not add unnecessary comments, docstrings, or type annotations.
|
|
228
|
+
For bash commands, prefer non-interactive commands.
|
|
208
229
|
"""
|
|
209
230
|
|
|
210
231
|
# ── Tool Definitions ────────────────────────────────────────────────────────
|
|
@@ -804,18 +825,19 @@ def stream_response(client, messages, system):
|
|
|
804
825
|
|
|
805
826
|
# ── Headless Prompt Mode ────────────────────────────────────────────────────
|
|
806
827
|
|
|
807
|
-
def run_prompt(client, prompt,
|
|
828
|
+
def run_prompt(client, prompt, plan_system, exec_system):
|
|
808
829
|
"""Run a single prompt non-interactively. Returns a JSON-serializable dict."""
|
|
809
|
-
|
|
810
|
-
# PHASE 1: Planning -
|
|
830
|
+
|
|
831
|
+
# PHASE 1: Planning - separate API call with planning prompt
|
|
811
832
|
print(f"\n{C.BOLD}{C.BLUE}📝 PLANNING PHASE{C.RESET}", file=sys.stderr, flush=True)
|
|
812
833
|
print(f"{C.DIM}Understanding the issue and creating a plan...{C.RESET}\n", file=sys.stderr, flush=True)
|
|
813
|
-
|
|
834
|
+
|
|
835
|
+
plan_text = ""
|
|
814
836
|
plan_messages = [
|
|
815
|
-
{"role": "system", "content":
|
|
816
|
-
{"role": "user", "content": f"{prompt}\n\
|
|
837
|
+
{"role": "system", "content": plan_system},
|
|
838
|
+
{"role": "user", "content": f"{prompt}\n\nProduce the plan using the exact sections: UNDERSTANDING, QUESTIONS STILL OPEN, FILES TO READ, FILES TO CREATE, FILES TO MODIFY, APPROACH. Do NOT write any code yet."}
|
|
817
839
|
]
|
|
818
|
-
|
|
840
|
+
|
|
819
841
|
try:
|
|
820
842
|
plan_response = client.chat.completions.create(
|
|
821
843
|
model=MODEL,
|
|
@@ -823,23 +845,26 @@ def run_prompt(client, prompt, system):
|
|
|
823
845
|
messages=plan_messages,
|
|
824
846
|
)
|
|
825
847
|
plan_text = plan_response.choices[0].message.content.strip()
|
|
826
|
-
|
|
848
|
+
|
|
827
849
|
# Print the plan with formatting
|
|
828
850
|
print(f"{C.CYAN}{'─' * 60}{C.RESET}", file=sys.stderr, flush=True)
|
|
829
851
|
for line in plan_text.split('\n'):
|
|
830
852
|
print(f"{C.CYAN} {line}{C.RESET}", file=sys.stderr, flush=True)
|
|
831
853
|
print(f"{C.CYAN}{'─' * 60}{C.RESET}\n", file=sys.stderr, flush=True)
|
|
832
|
-
|
|
854
|
+
|
|
833
855
|
except Exception as e:
|
|
834
856
|
print(f"{C.YELLOW}Could not generate plan: {e}{C.RESET}", file=sys.stderr, flush=True)
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
# PHASE 2: Execution - proceed with the actual coding
|
|
857
|
+
|
|
858
|
+
# PHASE 2: Execution - inject plan into the conversation so the agent can reference it
|
|
838
859
|
print(f"{C.BOLD}{C.GREEN}🔨 EXECUTING PLAN{C.RESET}\n", file=sys.stderr, flush=True)
|
|
839
|
-
|
|
860
|
+
|
|
861
|
+
exec_user_content = prompt
|
|
862
|
+
if plan_text:
|
|
863
|
+
exec_user_content = f"{prompt}\n\nHere is your plan. Follow it.\n\n{plan_text}"
|
|
864
|
+
|
|
840
865
|
messages = [
|
|
841
|
-
{"role": "system", "content":
|
|
842
|
-
{"role": "user", "content":
|
|
866
|
+
{"role": "system", "content": exec_system},
|
|
867
|
+
{"role": "user", "content": exec_user_content}
|
|
843
868
|
]
|
|
844
869
|
files_modified = set()
|
|
845
870
|
files_created = set()
|
|
@@ -982,37 +1007,22 @@ def run_prompt(client, prompt, system):
|
|
|
982
1007
|
final_text = msg.content
|
|
983
1008
|
break
|
|
984
1009
|
|
|
985
|
-
#
|
|
1010
|
+
# Parse PR_TITLE / PR_BODY from the agent's verify output (if present)
|
|
986
1011
|
summary = final_text.strip()
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
model=MODEL,
|
|
1002
|
-
max_tokens=1024,
|
|
1003
|
-
messages=summary_messages,
|
|
1004
|
-
)
|
|
1005
|
-
|
|
1006
|
-
if hasattr(summary_response, "usage") and summary_response.usage:
|
|
1007
|
-
total_input_tokens += summary_response.usage.prompt_tokens
|
|
1008
|
-
total_output_tokens += summary_response.usage.completion_tokens
|
|
1009
|
-
|
|
1010
|
-
summary = summary_response.choices[0].message.content.strip()
|
|
1011
|
-
except Exception as e:
|
|
1012
|
-
if is_token_limit_error(e):
|
|
1013
|
-
errors.append(str(e))
|
|
1014
|
-
else:
|
|
1015
|
-
raise
|
|
1012
|
+
pr_title_match = re.search(r'PR_TITLE:\s*(.+)', final_text)
|
|
1013
|
+
pr_body_match = re.search(r'PR_BODY:\s*([\s\S]+?)$', final_text)
|
|
1014
|
+
if pr_title_match:
|
|
1015
|
+
pr_title = pr_title_match.group(1).strip()
|
|
1016
|
+
pr_body = pr_body_match.group(1).strip() if pr_body_match else ""
|
|
1017
|
+
summary = f"{pr_title}\n\n{pr_body}".strip() if pr_body else pr_title
|
|
1018
|
+
elif not summary:
|
|
1019
|
+
# Fallback: build a minimal summary from file lists
|
|
1020
|
+
parts = []
|
|
1021
|
+
if files_created:
|
|
1022
|
+
parts.append(f"Created: {', '.join(sorted(files_created))}")
|
|
1023
|
+
if files_modified:
|
|
1024
|
+
parts.append(f"Modified: {', '.join(sorted(files_modified))}")
|
|
1025
|
+
summary = ". ".join(parts) if parts else "No changes produced."
|
|
1016
1026
|
|
|
1017
1027
|
result = {
|
|
1018
1028
|
"completed": len(errors) == 0,
|
|
@@ -1050,24 +1060,27 @@ def main():
|
|
|
1050
1060
|
if machine_id:
|
|
1051
1061
|
client_kwargs["default_headers"] = {"X-Machine-Id": machine_id}
|
|
1052
1062
|
client = OpenAI(**client_kwargs)
|
|
1053
|
-
|
|
1063
|
+
cwd = os.getcwd()
|
|
1054
1064
|
|
|
1055
1065
|
# Load codebase map if available
|
|
1066
|
+
map_suffix = ""
|
|
1056
1067
|
map_file = Path.cwd() / ".coder" / "map.md"
|
|
1057
1068
|
if map_file.exists():
|
|
1058
1069
|
try:
|
|
1059
1070
|
map_content = map_file.read_text(encoding="utf-8").strip()
|
|
1060
1071
|
if len(map_content) > 20000:
|
|
1061
|
-
map_content = map_content[:20000] + "\n\n... (map truncated
|
|
1062
|
-
|
|
1072
|
+
map_content = map_content[:20000] + "\n\n... (map truncated -- use list_files to explore further)"
|
|
1073
|
+
map_suffix = f"\n\n{map_content}"
|
|
1063
1074
|
print(f"{C.DIM}Loaded codebase map ({map_content.count(chr(10))} lines){C.RESET}", file=sys.stderr)
|
|
1064
1075
|
except OSError:
|
|
1065
1076
|
pass
|
|
1066
1077
|
|
|
1067
1078
|
# ── Headless prompt mode ────────────────────────────────────────────
|
|
1068
1079
|
if args.prompt:
|
|
1080
|
+
plan_system = PLAN_PROMPT.format(cwd=cwd) + map_suffix
|
|
1081
|
+
exec_system = EXEC_PROMPT.format(cwd=cwd) + map_suffix
|
|
1069
1082
|
try:
|
|
1070
|
-
result = run_prompt(client, args.prompt,
|
|
1083
|
+
result = run_prompt(client, args.prompt, plan_system, exec_system)
|
|
1071
1084
|
print(json.dumps(result, indent=2))
|
|
1072
1085
|
sys.exit(0 if result["completed"] else 1)
|
|
1073
1086
|
except Exception as e:
|
|
@@ -1092,6 +1105,7 @@ def main():
|
|
|
1092
1105
|
sys.exit(130)
|
|
1093
1106
|
|
|
1094
1107
|
# ── Interactive REPL mode ───────────────────────────────────────────
|
|
1108
|
+
system = REPL_PROMPT.format(cwd=cwd) + map_suffix
|
|
1095
1109
|
messages = []
|
|
1096
1110
|
|
|
1097
1111
|
mode_label = f" {C.YELLOW}(safe mode){C.RESET}" if SAFE_MODE else ""
|