@launch11/srgical 0.0.7 → 0.0.8
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/README.md +12 -2
- package/dist/commands/doctor.js +6 -0
- package/dist/core/advice-state.js +77 -0
- package/dist/core/agent.js +8 -0
- package/dist/core/augment.js +10 -0
- package/dist/core/claude.js +10 -0
- package/dist/core/codex.js +11 -0
- package/dist/core/planning-advice.js +22 -0
- package/dist/core/planning-epochs.js +3 -0
- package/dist/core/planning-pack-state.js +4 -1
- package/dist/core/prompts.js +58 -0
- package/dist/core/workspace.js +3 -1
- package/dist/ui/studio.js +162 -63
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ This repo currently ships the foundation for:
|
|
|
31
31
|
Prints the installed version with release-note links instead of only echoing the semver.
|
|
32
32
|
- `srgical doctor`
|
|
33
33
|
Reports the active plan, plan readiness, execution state, auto-run state, and which supported agents are available
|
|
34
|
-
locally.
|
|
34
|
+
locally, along with any cached AI advice for the selected plan.
|
|
35
35
|
- `srgical about`
|
|
36
36
|
Shows package details, release links, and the currently supported agent adapters.
|
|
37
37
|
- `srgical changelog`
|
|
@@ -40,7 +40,8 @@ This repo currently ships the foundation for:
|
|
|
40
40
|
Creates a local `.srgical/` planning pack from built-in templates, with `--plan <id>` for named plans.
|
|
41
41
|
- `srgical studio`
|
|
42
42
|
Opens a full-screen planning studio where you can switch between named plans, inspect readiness with `/readiness`,
|
|
43
|
-
inspect supported tools with `/agents`, and explicitly trigger pack writes,
|
|
43
|
+
inspect supported tools with `/agents`, refresh AI guidance with `/advice`, and explicitly trigger pack writes,
|
|
44
|
+
single-step execution, or `/auto`.
|
|
44
45
|
- `srgical run-next`
|
|
45
46
|
Replays the generated next-agent prompt through the active agent, with `--plan <id>` for plan targeting,
|
|
46
47
|
`--dry-run` for safe preview, `--agent <id>` for a one-run override, and `--auto` for bounded multi-step execution.
|
|
@@ -168,10 +169,19 @@ Inside the studio, the footer is intentionally minimal:
|
|
|
168
169
|
- `PgUp/PgDn` scrolls the transcript
|
|
169
170
|
- `/agents` chooses the current tool
|
|
170
171
|
- `/help` shows the full command set
|
|
172
|
+
- `/quit` exits the studio
|
|
171
173
|
|
|
172
174
|
The composer is now multiline with a minimum two-line visible input area. `Enter` sends, while `Shift+Enter`,
|
|
173
175
|
`Alt+Enter`, or `Ctrl+J` inserts a newline when the terminal exposes those keys distinctly.
|
|
174
176
|
|
|
177
|
+
The studio can also ask the active agent for an AI assessment of the current planning state. Run `/advice` to cache a
|
|
178
|
+
plain-English summary of:
|
|
179
|
+
|
|
180
|
+
- the problem statement the agent believes you are solving,
|
|
181
|
+
- whether the current plan state is clear or still fuzzy,
|
|
182
|
+
- what research or repo truth still needs to be gathered,
|
|
183
|
+
- and the best next move right now.
|
|
184
|
+
|
|
175
185
|
## Current Claude Caveat
|
|
176
186
|
|
|
177
187
|
Claude support is real, but it is not treated as interchangeable with Codex. The current non-interactive Claude path
|
package/dist/commands/doctor.js
CHANGED
|
@@ -91,6 +91,12 @@ function renderPlanDetailLines(state) {
|
|
|
91
91
|
if (state.autoRun) {
|
|
92
92
|
lines.push(`Auto run detail: attempted ${state.autoRun.stepsAttempted}${state.autoRun.maxSteps ? `/${state.autoRun.maxSteps}` : ""}, stop reason ${state.autoRun.stopReason ?? "none"}`);
|
|
93
93
|
}
|
|
94
|
+
if (state.advice) {
|
|
95
|
+
lines.push(`AI advice: ${state.advice.problemStatement}`, ` Clarity: ${state.advice.clarity}`, ` Assessment: ${state.advice.stateAssessment}`, ` Research: ${state.advice.researchNeeded.length > 0 ? state.advice.researchNeeded.join(", ") : "none"}`, ` Next: ${state.advice.nextAction}`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
lines.push("AI advice: none cached yet (run `/advice` in studio to generate guidance).");
|
|
99
|
+
}
|
|
94
100
|
return lines;
|
|
95
101
|
}
|
|
96
102
|
function renderNextStepLines(nextStepSummary, nextRecommended) {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadPlanningAdviceState = loadPlanningAdviceState;
|
|
4
|
+
exports.savePlanningAdviceState = savePlanningAdviceState;
|
|
5
|
+
exports.normalizePlanningAdvice = normalizePlanningAdvice;
|
|
6
|
+
exports.parsePlanningAdviceResponse = parsePlanningAdviceResponse;
|
|
7
|
+
const workspace_1 = require("./workspace");
|
|
8
|
+
async function loadPlanningAdviceState(workspaceRoot, options = {}) {
|
|
9
|
+
const paths = (0, workspace_1.getPlanningPackPaths)(workspaceRoot, options);
|
|
10
|
+
if (!(await (0, workspace_1.fileExists)(paths.adviceState))) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return normalizePlanningAdvice(JSON.parse(await (0, workspace_1.readText)(paths.adviceState)), paths.planId);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function savePlanningAdviceState(workspaceRoot, advice, options = {}) {
|
|
21
|
+
const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot, options);
|
|
22
|
+
const payload = {
|
|
23
|
+
version: 1,
|
|
24
|
+
planId: paths.planId,
|
|
25
|
+
updatedAt: new Date().toISOString(),
|
|
26
|
+
...advice
|
|
27
|
+
};
|
|
28
|
+
await (0, workspace_1.writeText)(paths.adviceState, JSON.stringify(payload, null, 2));
|
|
29
|
+
return payload;
|
|
30
|
+
}
|
|
31
|
+
function normalizePlanningAdvice(value, fallbackPlanId) {
|
|
32
|
+
if (!value || typeof value !== "object") {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const candidate = value;
|
|
36
|
+
const clarity = normalizeClarity(candidate.clarity);
|
|
37
|
+
if (candidate.version !== 1 ||
|
|
38
|
+
typeof candidate.problemStatement !== "string" ||
|
|
39
|
+
!clarity ||
|
|
40
|
+
typeof candidate.stateAssessment !== "string" ||
|
|
41
|
+
!Array.isArray(candidate.researchNeeded) ||
|
|
42
|
+
candidate.researchNeeded.some((item) => typeof item !== "string") ||
|
|
43
|
+
typeof candidate.advice !== "string" ||
|
|
44
|
+
typeof candidate.nextAction !== "string") {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
version: 1,
|
|
49
|
+
planId: typeof candidate.planId === "string" ? candidate.planId : fallbackPlanId,
|
|
50
|
+
updatedAt: typeof candidate.updatedAt === "string" ? candidate.updatedAt : new Date().toISOString(),
|
|
51
|
+
problemStatement: candidate.problemStatement.trim(),
|
|
52
|
+
clarity,
|
|
53
|
+
stateAssessment: candidate.stateAssessment.trim(),
|
|
54
|
+
researchNeeded: candidate.researchNeeded.map((item) => item.trim()).filter(Boolean),
|
|
55
|
+
advice: candidate.advice.trim(),
|
|
56
|
+
nextAction: candidate.nextAction.trim()
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function parsePlanningAdviceResponse(raw, fallbackPlanId) {
|
|
60
|
+
const jsonStart = raw.indexOf("{");
|
|
61
|
+
const jsonEnd = raw.lastIndexOf("}");
|
|
62
|
+
if (jsonStart === -1 || jsonEnd === -1 || jsonEnd <= jsonStart) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
return normalizePlanningAdvice(JSON.parse(raw.slice(jsonStart, jsonEnd + 1)), fallbackPlanId);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function normalizeClarity(value) {
|
|
73
|
+
if (value === "clear" || value === "mostly clear" || value === "still fuzzy") {
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
package/dist/core/agent.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.detectPrimaryAgent = detectPrimaryAgent;
|
|
|
8
8
|
exports.resolveExecutionAgent = resolveExecutionAgent;
|
|
9
9
|
exports.requestPlannerReply = requestPlannerReply;
|
|
10
10
|
exports.writePlanningPack = writePlanningPack;
|
|
11
|
+
exports.requestPlanningAdvice = requestPlanningAdvice;
|
|
11
12
|
exports.runNextPrompt = runNextPrompt;
|
|
12
13
|
exports.selectPrimaryAgent = selectPrimaryAgent;
|
|
13
14
|
exports.resetAgentAdaptersForTesting = resetAgentAdaptersForTesting;
|
|
@@ -31,6 +32,7 @@ const codexAdapter = {
|
|
|
31
32
|
};
|
|
32
33
|
},
|
|
33
34
|
requestPlannerReply: codex_1.requestPlannerReply,
|
|
35
|
+
requestPlanningAdvice: codex_1.requestPlanningAdvice,
|
|
34
36
|
writePlanningPack: codex_1.writePlanningPack,
|
|
35
37
|
runNextPrompt: codex_1.runNextPrompt
|
|
36
38
|
};
|
|
@@ -49,6 +51,7 @@ const claudeAdapter = {
|
|
|
49
51
|
};
|
|
50
52
|
},
|
|
51
53
|
requestPlannerReply: claude_1.requestPlannerReply,
|
|
54
|
+
requestPlanningAdvice: claude_1.requestPlanningAdvice,
|
|
52
55
|
writePlanningPack: claude_1.writePlanningPack,
|
|
53
56
|
runNextPrompt: claude_1.runNextPrompt
|
|
54
57
|
};
|
|
@@ -67,6 +70,7 @@ const augmentAdapter = {
|
|
|
67
70
|
};
|
|
68
71
|
},
|
|
69
72
|
requestPlannerReply: augment_1.requestPlannerReply,
|
|
73
|
+
requestPlanningAdvice: augment_1.requestPlanningAdvice,
|
|
70
74
|
writePlanningPack: augment_1.writePlanningPack,
|
|
71
75
|
runNextPrompt: augment_1.runNextPrompt
|
|
72
76
|
};
|
|
@@ -127,6 +131,10 @@ async function writePlanningPack(workspaceRoot, messages, options = {}) {
|
|
|
127
131
|
const { adapter } = await resolvePrimaryAgent(workspaceRoot, options);
|
|
128
132
|
return adapter.writePlanningPack(workspaceRoot, messages, options);
|
|
129
133
|
}
|
|
134
|
+
async function requestPlanningAdvice(workspaceRoot, messages, packState, options = {}) {
|
|
135
|
+
const { adapter } = await resolvePrimaryAgent(workspaceRoot, options);
|
|
136
|
+
return adapter.requestPlanningAdvice(workspaceRoot, messages, packState, options);
|
|
137
|
+
}
|
|
130
138
|
async function runNextPrompt(workspaceRoot, prompt, options = {}) {
|
|
131
139
|
const { adapter } = await resolveExecutionAgent(workspaceRoot, options.agentId, { planId: options.planId });
|
|
132
140
|
return adapter.runNextPrompt(workspaceRoot, prompt, { planId: options.planId });
|
package/dist/core/augment.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.detectAugment = detectAugment;
|
|
7
7
|
exports.requestPlannerReply = requestPlannerReply;
|
|
8
|
+
exports.requestPlanningAdvice = requestPlanningAdvice;
|
|
8
9
|
exports.writePlanningPack = writePlanningPack;
|
|
9
10
|
exports.runNextPrompt = runNextPrompt;
|
|
10
11
|
exports.setAugmentRuntimeForTesting = setAugmentRuntimeForTesting;
|
|
@@ -55,6 +56,15 @@ async function requestPlannerReply(workspaceRoot, messages, _options = {}) {
|
|
|
55
56
|
});
|
|
56
57
|
return result.lastMessage.trim();
|
|
57
58
|
}
|
|
59
|
+
async function requestPlanningAdvice(workspaceRoot, messages, packState, options = {}) {
|
|
60
|
+
const result = await runAugmentExec({
|
|
61
|
+
cwd: workspaceRoot,
|
|
62
|
+
prompt: await (0, prompts_1.buildAdvicePrompt)(messages, workspaceRoot, packState, options),
|
|
63
|
+
askMode: true,
|
|
64
|
+
maxTurns: 4
|
|
65
|
+
});
|
|
66
|
+
return result.lastMessage.trim();
|
|
67
|
+
}
|
|
58
68
|
async function writePlanningPack(workspaceRoot, messages, options = {}) {
|
|
59
69
|
const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot, options);
|
|
60
70
|
const augmentStatus = await detectAugment();
|
package/dist/core/claude.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.detectClaude = detectClaude;
|
|
7
7
|
exports.requestPlannerReply = requestPlannerReply;
|
|
8
|
+
exports.requestPlanningAdvice = requestPlanningAdvice;
|
|
8
9
|
exports.writePlanningPack = writePlanningPack;
|
|
9
10
|
exports.runNextPrompt = runNextPrompt;
|
|
10
11
|
exports.setClaudeRuntimeForTesting = setClaudeRuntimeForTesting;
|
|
@@ -49,6 +50,15 @@ async function requestPlannerReply(workspaceRoot, messages, _options = {}) {
|
|
|
49
50
|
});
|
|
50
51
|
return result.lastMessage.trim();
|
|
51
52
|
}
|
|
53
|
+
async function requestPlanningAdvice(workspaceRoot, messages, packState, options = {}) {
|
|
54
|
+
const result = await runClaudeExec({
|
|
55
|
+
cwd: workspaceRoot,
|
|
56
|
+
prompt: await (0, prompts_1.buildAdvicePrompt)(messages, workspaceRoot, packState, options),
|
|
57
|
+
permissionMode: "plan",
|
|
58
|
+
maxTurns: 4
|
|
59
|
+
});
|
|
60
|
+
return result.lastMessage.trim();
|
|
61
|
+
}
|
|
52
62
|
async function writePlanningPack(workspaceRoot, messages, options = {}) {
|
|
53
63
|
const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot, options);
|
|
54
64
|
const claudeStatus = await detectClaude();
|
package/dist/core/codex.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.detectCodex = detectCodex;
|
|
7
7
|
exports.requestPlannerReply = requestPlannerReply;
|
|
8
|
+
exports.requestPlanningAdvice = requestPlanningAdvice;
|
|
8
9
|
exports.writePlanningPack = writePlanningPack;
|
|
9
10
|
exports.runNextPrompt = runNextPrompt;
|
|
10
11
|
exports.setCodexRuntimeForTesting = setCodexRuntimeForTesting;
|
|
@@ -47,6 +48,16 @@ async function requestPlannerReply(workspaceRoot, messages, _options = {}) {
|
|
|
47
48
|
});
|
|
48
49
|
return result.lastMessage.trim();
|
|
49
50
|
}
|
|
51
|
+
async function requestPlanningAdvice(workspaceRoot, messages, packState, options = {}) {
|
|
52
|
+
const result = await runCodexExec({
|
|
53
|
+
cwd: workspaceRoot,
|
|
54
|
+
prompt: await (0, prompts_1.buildAdvicePrompt)(messages, workspaceRoot, packState, options),
|
|
55
|
+
allowWrite: false,
|
|
56
|
+
skipGitRepoCheck: true,
|
|
57
|
+
ephemeral: true
|
|
58
|
+
});
|
|
59
|
+
return result.lastMessage.trim();
|
|
60
|
+
}
|
|
50
61
|
async function writePlanningPack(workspaceRoot, messages, options = {}) {
|
|
51
62
|
const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot, options);
|
|
52
63
|
const codexStatus = await detectCodex();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refreshPlanningAdvice = refreshPlanningAdvice;
|
|
4
|
+
const advice_state_1 = require("./advice-state");
|
|
5
|
+
const agent_1 = require("./agent");
|
|
6
|
+
const planning_pack_state_1 = require("./planning-pack-state");
|
|
7
|
+
async function refreshPlanningAdvice(workspaceRoot, messages, options = {}) {
|
|
8
|
+
const packState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, options);
|
|
9
|
+
const raw = await (0, agent_1.requestPlanningAdvice)(workspaceRoot, messages, packState, options);
|
|
10
|
+
const parsed = (0, advice_state_1.parsePlanningAdviceResponse)(raw, packState.planId);
|
|
11
|
+
if (!parsed) {
|
|
12
|
+
throw new Error("Planning advice could not be parsed from the active agent response.");
|
|
13
|
+
}
|
|
14
|
+
return (0, advice_state_1.savePlanningAdviceState)(workspaceRoot, {
|
|
15
|
+
problemStatement: parsed.problemStatement,
|
|
16
|
+
clarity: parsed.clarity,
|
|
17
|
+
stateAssessment: parsed.stateAssessment,
|
|
18
|
+
researchNeeded: parsed.researchNeeded,
|
|
19
|
+
advice: parsed.advice,
|
|
20
|
+
nextAction: parsed.nextAction
|
|
21
|
+
}, options);
|
|
22
|
+
}
|
|
@@ -21,6 +21,7 @@ const ARCHIVED_PACK_FILE_NAMES = [
|
|
|
21
21
|
"studio-session.json",
|
|
22
22
|
"planning-state.json",
|
|
23
23
|
"auto-run-state.json",
|
|
24
|
+
"advice-state.json",
|
|
24
25
|
"execution-state.json",
|
|
25
26
|
"execution-log.md"
|
|
26
27
|
];
|
|
@@ -75,6 +76,7 @@ async function resetActivePlanningPack(paths) {
|
|
|
75
76
|
await (0, planning_state_1.savePlanningState)(paths.root, "scaffolded", { planId: paths.planId });
|
|
76
77
|
await Promise.all([
|
|
77
78
|
(0, promises_1.rm)(paths.autoRunState, { force: true }),
|
|
79
|
+
(0, promises_1.rm)(paths.adviceState, { force: true }),
|
|
78
80
|
(0, promises_1.rm)(paths.executionState, { force: true }),
|
|
79
81
|
(0, promises_1.rm)(paths.executionLog, { force: true })
|
|
80
82
|
]);
|
|
@@ -88,6 +90,7 @@ function listArchivablePaths(paths) {
|
|
|
88
90
|
paths.studioSession,
|
|
89
91
|
paths.planningState,
|
|
90
92
|
paths.autoRunState,
|
|
93
|
+
paths.adviceState,
|
|
91
94
|
paths.executionState,
|
|
92
95
|
paths.executionLog
|
|
93
96
|
];
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.readPlanningPackState = readPlanningPackState;
|
|
4
4
|
exports.isExecutionStepSummary = isExecutionStepSummary;
|
|
5
5
|
exports.isExecutionReadyState = isExecutionReadyState;
|
|
6
|
+
const advice_state_1 = require("./advice-state");
|
|
6
7
|
const auto_run_state_1 = require("./auto-run-state");
|
|
7
8
|
const execution_state_1 = require("./execution-state");
|
|
8
9
|
const planning_state_1 = require("./planning-state");
|
|
@@ -25,9 +26,10 @@ async function readPlanningPackState(workspaceRoot, options = {}) {
|
|
|
25
26
|
trackerReadable = false;
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
|
-
const [lastExecution, planningState, autoRun, docsPresent, studioSession] = await Promise.all([
|
|
29
|
+
const [lastExecution, planningState, advice, autoRun, docsPresent, studioSession] = await Promise.all([
|
|
29
30
|
(0, execution_state_1.loadExecutionState)(workspaceRoot, options),
|
|
30
31
|
(0, planning_state_1.loadPlanningState)(workspaceRoot, options),
|
|
32
|
+
(0, advice_state_1.loadPlanningAdviceState)(workspaceRoot, options),
|
|
31
33
|
(0, auto_run_state_1.loadAutoRunState)(workspaceRoot, options),
|
|
32
34
|
countPresentDocs(paths),
|
|
33
35
|
(0, studio_session_1.loadStudioSessionState)(workspaceRoot, options)
|
|
@@ -57,6 +59,7 @@ async function readPlanningPackState(workspaceRoot, options = {}) {
|
|
|
57
59
|
planningState,
|
|
58
60
|
packMode,
|
|
59
61
|
readiness,
|
|
62
|
+
advice,
|
|
60
63
|
autoRun,
|
|
61
64
|
executionActivated,
|
|
62
65
|
mode,
|
package/dist/core/prompts.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.buildPlannerPrompt = buildPlannerPrompt;
|
|
7
7
|
exports.buildPackWriterPrompt = buildPackWriterPrompt;
|
|
8
|
+
exports.buildAdvicePrompt = buildAdvicePrompt;
|
|
8
9
|
const promises_1 = require("node:fs/promises");
|
|
9
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
11
|
const workspace_1 = require("./workspace");
|
|
@@ -71,6 +72,46 @@ ${repoTruth}
|
|
|
71
72
|
|
|
72
73
|
Conversation transcript:
|
|
73
74
|
|
|
75
|
+
${renderTranscript(messages)}
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
async function buildAdvicePrompt(messages, workspaceRoot, packState, options = {}) {
|
|
79
|
+
const repoTruth = await buildRepoTruthSnapshot(workspaceRoot, options);
|
|
80
|
+
return `You are the planning advisor inside srgical.
|
|
81
|
+
|
|
82
|
+
Your job is to assess the current planning state and return only a single JSON object.
|
|
83
|
+
|
|
84
|
+
Assess the user's current problem statement, whether the repo/project state is clear enough yet, whether more research is needed, and what the best next move is.
|
|
85
|
+
|
|
86
|
+
Rules:
|
|
87
|
+
- Be specific to the current repository and transcript.
|
|
88
|
+
- Do not invent repo facts that are not supported by the transcript or repo truth snapshot.
|
|
89
|
+
- Prefer concise, practical advice over generic coaching.
|
|
90
|
+
- If the plan is still fuzzy, say so plainly.
|
|
91
|
+
- If more repo research is needed, name the missing area directly.
|
|
92
|
+
- Return valid JSON only. No markdown fences. No prose before or after the JSON.
|
|
93
|
+
|
|
94
|
+
Required JSON shape:
|
|
95
|
+
{
|
|
96
|
+
"version": 1,
|
|
97
|
+
"problemStatement": "string",
|
|
98
|
+
"clarity": "clear" | "mostly clear" | "still fuzzy",
|
|
99
|
+
"stateAssessment": "one short sentence",
|
|
100
|
+
"researchNeeded": ["string", "string"],
|
|
101
|
+
"advice": "one short paragraph",
|
|
102
|
+
"nextAction": "one concrete next move"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
Current deterministic planning state:
|
|
106
|
+
|
|
107
|
+
${renderPlanningStateSummary(packState)}
|
|
108
|
+
|
|
109
|
+
Repo truth snapshot:
|
|
110
|
+
|
|
111
|
+
${repoTruth}
|
|
112
|
+
|
|
113
|
+
Conversation transcript:
|
|
114
|
+
|
|
74
115
|
${renderTranscript(messages)}
|
|
75
116
|
`;
|
|
76
117
|
}
|
|
@@ -121,6 +162,23 @@ async function buildRepoTruthSnapshot(workspaceRoot, options = {}) {
|
|
|
121
162
|
renderNamedSnippet(".srgical/04-next-agent-prompt.md", nextPromptSnippet)
|
|
122
163
|
].join("\n");
|
|
123
164
|
}
|
|
165
|
+
function renderPlanningStateSummary(packState) {
|
|
166
|
+
return [
|
|
167
|
+
`- planId: ${packState.planId}`,
|
|
168
|
+
`- packDir: ${packState.packDir}`,
|
|
169
|
+
`- packPresent: ${packState.packPresent}`,
|
|
170
|
+
`- packMode: ${packState.packMode}`,
|
|
171
|
+
`- mode: ${packState.mode}`,
|
|
172
|
+
`- docsPresent: ${packState.docsPresent}/4`,
|
|
173
|
+
`- readiness: ${packState.readiness.score}/${packState.readiness.total}`,
|
|
174
|
+
`- readinessReadyToWrite: ${packState.readiness.readyToWrite}`,
|
|
175
|
+
`- missingReadinessSignals: ${packState.readiness.missingLabels.join(", ") || "none"}`,
|
|
176
|
+
`- nextRecommended: ${packState.currentPosition.nextRecommended ?? "none queued"}`,
|
|
177
|
+
`- nextStepId: ${packState.nextStepSummary?.id ?? "none"}`,
|
|
178
|
+
`- executionActivated: ${packState.executionActivated}`,
|
|
179
|
+
`- autoRunStatus: ${packState.autoRun?.status ?? "idle"}`
|
|
180
|
+
].join("\n");
|
|
181
|
+
}
|
|
124
182
|
async function summarizePackageManifest(workspaceRoot) {
|
|
125
183
|
const packageJsonPath = node_path_1.default.join(workspaceRoot, "package.json");
|
|
126
184
|
const exists = await (0, workspace_1.fileExists)(packageJsonPath);
|
package/dist/core/workspace.js
CHANGED
|
@@ -61,6 +61,7 @@ function getPlanningPackPaths(root, options = {}) {
|
|
|
61
61
|
executionLog: node_path_1.default.join(dir, "execution-log.md"),
|
|
62
62
|
planningState: node_path_1.default.join(dir, "planning-state.json"),
|
|
63
63
|
autoRunState: node_path_1.default.join(dir, "auto-run-state.json"),
|
|
64
|
+
adviceState: node_path_1.default.join(dir, "advice-state.json"),
|
|
64
65
|
activePlanFile: node_path_1.default.join(planningRoot, exports.ACTIVE_PLAN_FILE)
|
|
65
66
|
};
|
|
66
67
|
}
|
|
@@ -180,7 +181,8 @@ async function hasDefaultPlanPresence(root) {
|
|
|
180
181
|
fileExists(paths.executionState),
|
|
181
182
|
fileExists(paths.executionLog),
|
|
182
183
|
fileExists(paths.planningState),
|
|
183
|
-
fileExists(paths.autoRunState)
|
|
184
|
+
fileExists(paths.autoRunState),
|
|
185
|
+
fileExists(paths.adviceState)
|
|
184
186
|
]);
|
|
185
187
|
return checks.some(Boolean);
|
|
186
188
|
}
|
package/dist/ui/studio.js
CHANGED
|
@@ -15,13 +15,16 @@ const auto_run_1 = require("../core/auto-run");
|
|
|
15
15
|
const agent_1 = require("../core/agent");
|
|
16
16
|
const execution_controls_1 = require("../core/execution-controls");
|
|
17
17
|
const execution_state_1 = require("../core/execution-state");
|
|
18
|
+
const planning_advice_1 = require("../core/planning-advice");
|
|
18
19
|
const planning_pack_state_1 = require("../core/planning-pack-state");
|
|
19
20
|
const planning_state_1 = require("../core/planning-state");
|
|
20
21
|
const studio_session_1 = require("../core/studio-session");
|
|
21
22
|
const templates_1 = require("../core/templates");
|
|
22
23
|
const workspace_1 = require("../core/workspace");
|
|
23
|
-
const READY_FOOTER = " PgUp/PgDn scroll /agents choose tool /help commands ";
|
|
24
|
+
const READY_FOOTER = " PgUp/PgDn scroll /agents choose tool /help commands /quit exit ";
|
|
24
25
|
const ACTIVITY_FRAMES = ["[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]"];
|
|
26
|
+
const COMPOSER_CURSOR = "{black-fg}{#ffb14a-bg} {/}";
|
|
27
|
+
const escapeBlessedText = blessed_1.default.helpers.escape;
|
|
25
28
|
async function launchStudio(options = {}) {
|
|
26
29
|
let workspace = (0, workspace_1.resolveWorkspace)(options.workspace);
|
|
27
30
|
let planId = await (0, workspace_1.resolvePlanId)(workspace, options.planId);
|
|
@@ -99,14 +102,21 @@ async function launchStudio(options = {}) {
|
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
});
|
|
102
|
-
const input = blessed_1.default.
|
|
105
|
+
const input = blessed_1.default.box({
|
|
103
106
|
bottom: 1,
|
|
104
107
|
left: 0,
|
|
105
108
|
width: "100%",
|
|
106
109
|
height: 4,
|
|
107
|
-
inputOnFocus: true,
|
|
108
110
|
keys: true,
|
|
109
111
|
mouse: true,
|
|
112
|
+
tags: true,
|
|
113
|
+
clickable: true,
|
|
114
|
+
padding: {
|
|
115
|
+
top: 0,
|
|
116
|
+
right: 1,
|
|
117
|
+
bottom: 0,
|
|
118
|
+
left: 1
|
|
119
|
+
},
|
|
110
120
|
border: {
|
|
111
121
|
type: "line"
|
|
112
122
|
},
|
|
@@ -119,7 +129,6 @@ async function launchStudio(options = {}) {
|
|
|
119
129
|
}
|
|
120
130
|
}
|
|
121
131
|
});
|
|
122
|
-
configureComposer(input);
|
|
123
132
|
const footer = blessed_1.default.box({
|
|
124
133
|
bottom: 0,
|
|
125
134
|
left: 0,
|
|
@@ -148,6 +157,8 @@ async function launchStudio(options = {}) {
|
|
|
148
157
|
let trackerSummary = "loading...";
|
|
149
158
|
let executionSummary = "never run";
|
|
150
159
|
let autoSummary = "idle";
|
|
160
|
+
let adviceSummary = "run /advice for AI guidance";
|
|
161
|
+
let composerValue = "";
|
|
151
162
|
function setSidebar(status) {
|
|
152
163
|
const planningPaths = (0, workspace_1.getPlanningPackPaths)(workspace, { planId });
|
|
153
164
|
sidebar.setContent([
|
|
@@ -171,6 +182,9 @@ async function launchStudio(options = {}) {
|
|
|
171
182
|
"{bold}Auto{/bold}",
|
|
172
183
|
autoSummary,
|
|
173
184
|
"",
|
|
185
|
+
"{bold}Advice{/bold}",
|
|
186
|
+
adviceSummary,
|
|
187
|
+
"",
|
|
174
188
|
"{bold}State{/bold}",
|
|
175
189
|
status ?? getActivityState()
|
|
176
190
|
].join("\n"));
|
|
@@ -236,6 +250,10 @@ async function launchStudio(options = {}) {
|
|
|
236
250
|
transcript.setContent(rendered);
|
|
237
251
|
transcript.setScrollPerc(100);
|
|
238
252
|
}
|
|
253
|
+
function renderComposer() {
|
|
254
|
+
const escapedValue = escapeBlessedText(composerValue);
|
|
255
|
+
input.setContent(`${escapedValue}${COMPOSER_CURSOR}`);
|
|
256
|
+
}
|
|
239
257
|
function scrollTranscript(lines) {
|
|
240
258
|
transcript.scroll(lines);
|
|
241
259
|
screen.render();
|
|
@@ -254,6 +272,56 @@ async function launchStudio(options = {}) {
|
|
|
254
272
|
setFooter();
|
|
255
273
|
screen.render();
|
|
256
274
|
}
|
|
275
|
+
async function submitComposer() {
|
|
276
|
+
const rawValue = composerValue;
|
|
277
|
+
const text = rawValue.trim();
|
|
278
|
+
composerValue = "";
|
|
279
|
+
renderComposer();
|
|
280
|
+
if (!text || (busy && text !== "/stop")) {
|
|
281
|
+
screen.render();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (text.startsWith("/")) {
|
|
285
|
+
await handleSlashCommand(text);
|
|
286
|
+
input.focus();
|
|
287
|
+
renderComposer();
|
|
288
|
+
screen.render();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
startBusy("planner");
|
|
292
|
+
await appendMessage({
|
|
293
|
+
role: "user",
|
|
294
|
+
content: text
|
|
295
|
+
});
|
|
296
|
+
renderTranscript();
|
|
297
|
+
setSidebar();
|
|
298
|
+
setFooter();
|
|
299
|
+
renderComposer();
|
|
300
|
+
screen.render();
|
|
301
|
+
try {
|
|
302
|
+
const reply = await (0, agent_1.requestPlannerReply)(workspace, messages, { planId });
|
|
303
|
+
await appendMessage({
|
|
304
|
+
role: "assistant",
|
|
305
|
+
content: reply
|
|
306
|
+
});
|
|
307
|
+
await refreshAdvice(false);
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
await appendMessage({
|
|
311
|
+
role: "system",
|
|
312
|
+
content: `Planner call failed: ${error instanceof Error ? error.message : String(error)}`
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
stopBusy();
|
|
317
|
+
renderTranscript();
|
|
318
|
+
setSidebar();
|
|
319
|
+
setFooter();
|
|
320
|
+
renderComposer();
|
|
321
|
+
input.focus();
|
|
322
|
+
screen.render();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
257
325
|
async function refreshEnvironment() {
|
|
258
326
|
const [storedAgentId, packState] = await Promise.all([
|
|
259
327
|
(0, studio_session_1.loadStoredActiveAgentId)(workspace, { planId }),
|
|
@@ -273,9 +341,11 @@ async function launchStudio(options = {}) {
|
|
|
273
341
|
trackerSummary = formatTrackerSummary(packState.currentPosition);
|
|
274
342
|
executionSummary = formatExecutionSummary(packState.lastExecution);
|
|
275
343
|
autoSummary = formatAutoSummary(packState);
|
|
344
|
+
adviceSummary = formatAdviceSummary(packState.advice);
|
|
276
345
|
setSidebar();
|
|
277
346
|
setFooter();
|
|
278
347
|
renderTranscript();
|
|
348
|
+
renderComposer();
|
|
279
349
|
screen.render();
|
|
280
350
|
}
|
|
281
351
|
async function switchPlan(nextPlanId) {
|
|
@@ -284,6 +354,20 @@ async function launchStudio(options = {}) {
|
|
|
284
354
|
messages = await (0, studio_session_1.loadStudioSession)(workspace, { planId });
|
|
285
355
|
await refreshEnvironment();
|
|
286
356
|
}
|
|
357
|
+
async function refreshAdvice(showInTranscript = false) {
|
|
358
|
+
try {
|
|
359
|
+
const advice = await (0, planning_advice_1.refreshPlanningAdvice)(workspace, messages, { planId });
|
|
360
|
+
await refreshEnvironment();
|
|
361
|
+
if (showInTranscript) {
|
|
362
|
+
await appendSystemMessage(renderAdviceMessage(advice));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
if (showInTranscript) {
|
|
367
|
+
await appendSystemMessage(`Advice refresh failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
287
371
|
async function handleSlashCommand(command) {
|
|
288
372
|
if (command === "/quit") {
|
|
289
373
|
screen.destroy();
|
|
@@ -363,6 +447,17 @@ async function launchStudio(options = {}) {
|
|
|
363
447
|
await appendSystemMessage(renderReadinessMessage(packState));
|
|
364
448
|
return;
|
|
365
449
|
}
|
|
450
|
+
if (command === "/advice") {
|
|
451
|
+
startBusy("planner", "refreshing AI advice...");
|
|
452
|
+
try {
|
|
453
|
+
await refreshAdvice(true);
|
|
454
|
+
}
|
|
455
|
+
finally {
|
|
456
|
+
stopBusy();
|
|
457
|
+
await refreshEnvironment();
|
|
458
|
+
}
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
366
461
|
if (command === "/stop") {
|
|
367
462
|
const state = await (0, auto_run_1.requestAutoRunStop)(workspace, { planId });
|
|
368
463
|
await refreshEnvironment();
|
|
@@ -404,9 +499,10 @@ async function launchStudio(options = {}) {
|
|
|
404
499
|
"1. Talk normally to sharpen the plan against the real repo.",
|
|
405
500
|
"2. Use `/plans`, `/plan`, and `/plan new <id>` to manage named planning packs in this workspace.",
|
|
406
501
|
"3. Use `/readiness` to see what context is still missing before you write the pack.",
|
|
407
|
-
"4. Run `/
|
|
408
|
-
"5. Run `/
|
|
409
|
-
"6. Run `/
|
|
502
|
+
"4. Run `/advice` for an AI assessment of the problem statement, clarity, research gaps, and next move.",
|
|
503
|
+
"5. Run `/write` when the plan is ready to put on disk.",
|
|
504
|
+
"6. Run `/preview` for a safe execution preview, `/run` for one execution step, or `/auto [max]` for continuous execution.",
|
|
505
|
+
"7. Run `/stop` to stop auto mode after the current iteration.",
|
|
410
506
|
"",
|
|
411
507
|
"Controls:",
|
|
412
508
|
"- `Enter` sends the current message or command.",
|
|
@@ -432,6 +528,7 @@ async function launchStudio(options = {}) {
|
|
|
432
528
|
try {
|
|
433
529
|
const result = await (0, agent_1.writePlanningPack)(workspace, messages, { planId });
|
|
434
530
|
await (0, planning_state_1.markPlanningPackAuthored)(workspace, { planId });
|
|
531
|
+
await refreshAdvice(false);
|
|
435
532
|
await appendSystemMessage(`Planning pack updated for \`${planId}\`. Summary:\n${result}`);
|
|
436
533
|
}
|
|
437
534
|
catch (error) {
|
|
@@ -459,6 +556,7 @@ async function launchStudio(options = {}) {
|
|
|
459
556
|
planId,
|
|
460
557
|
stepLabel: packState.nextStepSummary?.id ?? packState.currentPosition.nextRecommended
|
|
461
558
|
});
|
|
559
|
+
await refreshAdvice(false);
|
|
462
560
|
await appendSystemMessage(`Execution run finished. ${(0, agent_1.getPrimaryAgentAdapter)().label} summary:\n${result}`);
|
|
463
561
|
}
|
|
464
562
|
catch (error) {
|
|
@@ -490,6 +588,7 @@ async function launchStudio(options = {}) {
|
|
|
490
588
|
await appendSystemMessage(line);
|
|
491
589
|
}
|
|
492
590
|
});
|
|
591
|
+
await refreshAdvice(false);
|
|
493
592
|
await appendSystemMessage(`Auto mode finished: ${result.summary}`);
|
|
494
593
|
}
|
|
495
594
|
catch (error) {
|
|
@@ -503,46 +602,36 @@ async function launchStudio(options = {}) {
|
|
|
503
602
|
}
|
|
504
603
|
await appendSystemMessage(`Unknown command: ${command}`);
|
|
505
604
|
}
|
|
506
|
-
input.on("
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
605
|
+
input.on("click", () => {
|
|
606
|
+
input.focus();
|
|
607
|
+
screen.render();
|
|
608
|
+
});
|
|
609
|
+
input.on("keypress", async (ch, key) => {
|
|
610
|
+
if (key.name === "pageup" || key.name === "ppage" || key.name === "pagedown" || key.name === "npage") {
|
|
511
611
|
return;
|
|
512
612
|
}
|
|
513
|
-
if (
|
|
514
|
-
await
|
|
515
|
-
input.focus();
|
|
613
|
+
if (key.name === "enter" && !key.shift && !key.meta && !key.ctrl) {
|
|
614
|
+
await submitComposer();
|
|
516
615
|
return;
|
|
517
616
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
renderTranscript();
|
|
524
|
-
setSidebar();
|
|
525
|
-
setFooter();
|
|
526
|
-
screen.render();
|
|
527
|
-
try {
|
|
528
|
-
const reply = await (0, agent_1.requestPlannerReply)(workspace, messages, { planId });
|
|
529
|
-
await appendMessage({
|
|
530
|
-
role: "assistant",
|
|
531
|
-
content: reply
|
|
532
|
-
});
|
|
617
|
+
if ((key.name === "enter" && (key.shift || key.meta)) || (key.ctrl && key.name === "j")) {
|
|
618
|
+
composerValue += "\n";
|
|
619
|
+
renderComposer();
|
|
620
|
+
screen.render();
|
|
621
|
+
return;
|
|
533
622
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
623
|
+
if (key.name === "backspace") {
|
|
624
|
+
composerValue = removeLastCodePoint(composerValue);
|
|
625
|
+
renderComposer();
|
|
626
|
+
screen.render();
|
|
627
|
+
return;
|
|
539
628
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
629
|
+
if (key.ctrl || key.meta) {
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (ch && !/^[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]$/.test(ch)) {
|
|
633
|
+
composerValue += ch;
|
|
634
|
+
renderComposer();
|
|
546
635
|
screen.render();
|
|
547
636
|
}
|
|
548
637
|
});
|
|
@@ -563,8 +652,10 @@ async function launchStudio(options = {}) {
|
|
|
563
652
|
});
|
|
564
653
|
}
|
|
565
654
|
renderTranscript();
|
|
655
|
+
renderComposer();
|
|
566
656
|
setSidebar("booting...");
|
|
567
657
|
setFooter(" Starting studio... ");
|
|
658
|
+
screen.program.hideCursor();
|
|
568
659
|
screen.render();
|
|
569
660
|
input.focus();
|
|
570
661
|
await refreshEnvironment();
|
|
@@ -633,6 +724,17 @@ function formatAutoSummary(packState) {
|
|
|
633
724
|
}
|
|
634
725
|
return lines.join("\n");
|
|
635
726
|
}
|
|
727
|
+
function formatAdviceSummary(advice) {
|
|
728
|
+
if (!advice) {
|
|
729
|
+
return "run /advice for AI guidance";
|
|
730
|
+
}
|
|
731
|
+
const lines = [
|
|
732
|
+
`problem: ${advice.problemStatement}`,
|
|
733
|
+
`clarity: ${advice.clarity}`,
|
|
734
|
+
`next: ${advice.nextAction}`
|
|
735
|
+
];
|
|
736
|
+
return lines.join("\n");
|
|
737
|
+
}
|
|
636
738
|
function formatAgentSummary(activeAgent, statuses) {
|
|
637
739
|
return [`active: ${activeAgent.label}`, ...statuses.map((status) => formatAgentStatusLine(status, status.id === activeAgent.id))]
|
|
638
740
|
.join("\n");
|
|
@@ -774,28 +876,8 @@ function deriveDisplayMode(packState) {
|
|
|
774
876
|
}
|
|
775
877
|
return packState.trackerReadable ? "Plan Written - Needs Step" : "Gathering Context";
|
|
776
878
|
}
|
|
777
|
-
function configureComposer(input) {
|
|
778
|
-
const internals = input;
|
|
779
|
-
const originalListener = internals._listener;
|
|
780
|
-
if (!originalListener) {
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
internals._listener = function patchedListener(ch, key) {
|
|
784
|
-
if (key.name === "enter" && !key.shift && !key.meta && !key.ctrl) {
|
|
785
|
-
if (typeof internals._done === "function") {
|
|
786
|
-
internals._done(null, internals.value ?? "");
|
|
787
|
-
}
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
if ((key.name === "enter" && (key.shift || key.meta)) || (key.ctrl && key.name === "j")) {
|
|
791
|
-
originalListener.call(this, "\n", { ...key, name: "enter" });
|
|
792
|
-
return;
|
|
793
|
-
}
|
|
794
|
-
originalListener.call(this, ch, key);
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
879
|
function renderStatusMessage(workspace, packState) {
|
|
798
|
-
|
|
880
|
+
const lines = [
|
|
799
881
|
`Plan: ${packState.planId}`,
|
|
800
882
|
`Planning dir: ${(0, workspace_1.getPlanningPackPaths)(workspace, { planId: packState.planId }).relativeDir}`,
|
|
801
883
|
`Mode: ${packState.mode}${packState.hasFailureOverlay ? " [last run failed]" : ""}`,
|
|
@@ -804,7 +886,11 @@ function renderStatusMessage(workspace, packState) {
|
|
|
804
886
|
`Execution activated: ${packState.executionActivated ? "yes" : "no"}`,
|
|
805
887
|
`Auto mode: ${packState.autoRun?.status ?? "idle"}`,
|
|
806
888
|
`Next step: ${packState.nextStepSummary?.id ?? packState.currentPosition.nextRecommended ?? "none queued"}`
|
|
807
|
-
]
|
|
889
|
+
];
|
|
890
|
+
if (packState.advice) {
|
|
891
|
+
lines.push(`Advice next: ${packState.advice.nextAction}`);
|
|
892
|
+
}
|
|
893
|
+
return lines.join("\n");
|
|
808
894
|
}
|
|
809
895
|
function renderReadinessMessage(packState) {
|
|
810
896
|
return [
|
|
@@ -820,6 +906,19 @@ function renderReadinessMessage(packState) {
|
|
|
820
906
|
: "Next: keep gathering repo truth, constraints, and the first execution slice."
|
|
821
907
|
].join("\n");
|
|
822
908
|
}
|
|
909
|
+
function renderAdviceMessage(advice) {
|
|
910
|
+
return [
|
|
911
|
+
`Problem: ${advice.problemStatement}`,
|
|
912
|
+
`Clarity: ${advice.clarity}`,
|
|
913
|
+
`Assessment: ${advice.stateAssessment}`,
|
|
914
|
+
`Research: ${advice.researchNeeded.length > 0 ? advice.researchNeeded.join(" | ") : "none"}`,
|
|
915
|
+
`Advice: ${advice.advice}`,
|
|
916
|
+
`Next: ${advice.nextAction}`
|
|
917
|
+
].join("\n");
|
|
918
|
+
}
|
|
919
|
+
function removeLastCodePoint(value) {
|
|
920
|
+
return Array.from(value).slice(0, -1).join("");
|
|
921
|
+
}
|
|
823
922
|
function renderPlanUsageMessage(currentPlanId, paths) {
|
|
824
923
|
return [
|
|
825
924
|
`Current plan: ${currentPlanId}`,
|