supipowers 1.2.6 → 1.5.0
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 +118 -56
- package/bin/install.ts +48 -128
- package/package.json +11 -3
- package/skills/code-review/SKILL.md +137 -40
- package/skills/context-mode/SKILL.md +67 -56
- package/skills/creating-supi-agents/SKILL.md +204 -0
- package/skills/debugging/SKILL.md +86 -40
- package/skills/fix-pr/SKILL.md +96 -65
- package/skills/planning/SKILL.md +103 -46
- package/skills/qa-strategy/SKILL.md +68 -46
- package/skills/receiving-code-review/SKILL.md +60 -53
- package/skills/release/SKILL.md +111 -39
- package/skills/tdd/SKILL.md +118 -67
- package/skills/verification/SKILL.md +71 -37
- package/src/bootstrap.ts +27 -5
- package/src/commands/agents.ts +249 -0
- package/src/commands/ai-review.ts +1113 -0
- package/src/commands/config.ts +224 -95
- package/src/commands/doctor.ts +19 -13
- package/src/commands/fix-pr.ts +8 -11
- package/src/commands/generate.ts +200 -0
- package/src/commands/model-picker.ts +5 -15
- package/src/commands/model.ts +4 -5
- package/src/commands/optimize-context.ts +202 -0
- package/src/commands/plan.ts +148 -92
- package/src/commands/qa.ts +14 -23
- package/src/commands/release.ts +504 -275
- package/src/commands/review.ts +643 -86
- package/src/commands/status.ts +44 -17
- package/src/commands/supi.ts +69 -41
- package/src/commands/update.ts +57 -2
- package/src/config/defaults.ts +6 -39
- package/src/config/loader.ts +388 -40
- package/src/config/model-resolver.ts +26 -22
- package/src/config/schema.ts +113 -48
- package/src/context/analyzer.ts +61 -2
- package/src/context/optimizer.ts +199 -0
- package/src/context-mode/compressor.ts +14 -11
- package/src/context-mode/detector.ts +16 -54
- package/src/context-mode/event-extractor.ts +45 -16
- package/src/context-mode/event-store.ts +225 -16
- package/src/context-mode/hooks.ts +195 -22
- package/src/context-mode/knowledge/chunker.ts +235 -0
- package/src/context-mode/knowledge/store.ts +187 -0
- package/src/context-mode/routing.ts +12 -23
- package/src/context-mode/sandbox/executor.ts +183 -0
- package/src/context-mode/sandbox/runners.ts +40 -0
- package/src/context-mode/snapshot-builder.ts +243 -7
- package/src/context-mode/tools.ts +440 -0
- package/src/context-mode/web/fetcher.ts +117 -0
- package/src/context-mode/web/html-to-md.ts +293 -0
- package/src/debug/logger.ts +107 -0
- package/src/deps/registry.ts +0 -20
- package/src/docs/drift.ts +454 -0
- package/src/fix-pr/fetch-comments.ts +66 -0
- package/src/git/commit-msg.ts +2 -1
- package/src/git/commit.ts +123 -141
- package/src/git/conventions.ts +2 -2
- package/src/git/status.ts +4 -1
- package/src/lsp/bridge.ts +138 -12
- package/src/planning/approval-flow.ts +125 -19
- package/src/planning/plan-writer-prompt.ts +4 -11
- package/src/planning/planning-ask-tool.ts +81 -0
- package/src/planning/prompt-builder.ts +9 -169
- package/src/planning/system-prompt.ts +290 -0
- package/src/platform/omp.ts +50 -4
- package/src/platform/progress.ts +182 -0
- package/src/platform/test-utils.ts +4 -1
- package/src/platform/tui-colors.ts +30 -0
- package/src/platform/types.ts +1 -0
- package/src/qa/detect-app-type.ts +102 -0
- package/src/qa/discover-routes.ts +353 -0
- package/src/quality/ai-session.ts +96 -0
- package/src/quality/ai-setup.ts +86 -0
- package/src/quality/gates/ai-review.ts +129 -0
- package/src/quality/gates/build.ts +8 -0
- package/src/quality/gates/command.ts +150 -0
- package/src/quality/gates/format.ts +28 -0
- package/src/quality/gates/lint.ts +22 -0
- package/src/quality/gates/lsp-diagnostics.ts +84 -0
- package/src/quality/gates/test-suite.ts +8 -0
- package/src/quality/gates/typecheck.ts +22 -0
- package/src/quality/registry.ts +25 -0
- package/src/quality/review-gates.ts +33 -0
- package/src/quality/runner.ts +268 -0
- package/src/quality/schemas.ts +48 -0
- package/src/quality/setup.ts +227 -0
- package/src/release/changelog.ts +7 -3
- package/src/release/channels/custom.ts +43 -0
- package/src/release/channels/gitea.ts +35 -0
- package/src/release/channels/github.ts +35 -0
- package/src/release/channels/gitlab.ts +35 -0
- package/src/release/channels/registry.ts +52 -0
- package/src/release/channels/types.ts +27 -0
- package/src/release/detector.ts +10 -63
- package/src/release/executor.ts +61 -51
- package/src/release/prompt.ts +38 -38
- package/src/release/version.ts +129 -10
- package/src/review/agent-loader.ts +331 -0
- package/src/review/consolidator.ts +180 -0
- package/src/review/default-agents/correctness.md +72 -0
- package/src/review/default-agents/maintainability.md +64 -0
- package/src/review/default-agents/security.md +67 -0
- package/src/review/fixer.ts +219 -0
- package/src/review/multi-agent-runner.ts +135 -0
- package/src/review/output.ts +147 -0
- package/src/review/prompts/agent-review-wrapper.md +36 -0
- package/src/review/prompts/fix-findings.md +32 -0
- package/src/review/prompts/fix-output-schema.md +18 -0
- package/src/review/prompts/invalid-output-retry.md +22 -0
- package/src/review/prompts/output-instructions.md +14 -0
- package/src/review/prompts/review-output-schema.md +38 -0
- package/src/review/prompts/single-review.md +53 -0
- package/src/review/prompts/validation-review.md +30 -0
- package/src/review/runner.ts +128 -0
- package/src/review/scope.ts +353 -0
- package/src/review/template.ts +15 -0
- package/src/review/types.ts +296 -0
- package/src/review/validator.ts +160 -0
- package/src/storage/plans.ts +5 -3
- package/src/storage/reports.ts +50 -7
- package/src/storage/review-sessions.ts +117 -0
- package/src/text.ts +19 -0
- package/src/types.ts +336 -26
- package/src/utils/paths.ts +39 -0
- package/src/visual/companion.ts +5 -3
- package/src/visual/start-server.ts +101 -0
- package/src/visual/stop-server.ts +39 -0
- package/bin/ctx-mode-wrapper.mjs +0 -66
- package/src/config/profiles.ts +0 -64
- package/src/context-mode/installer.ts +0 -38
- package/src/quality/ai-review-gate.ts +0 -43
- package/src/quality/gate-runner.ts +0 -67
- package/src/quality/lsp-gate.ts +0 -24
- package/src/quality/test-gate.ts +0 -39
- package/src/visual/scripts/start-server.sh +0 -98
- package/src/visual/scripts/stop-server.sh +0 -21
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Platform } from "../platform/types.js";
|
|
2
|
+
import type { DebugLogger } from "../debug/logger.js";
|
|
2
3
|
import type { ResolvedModel } from "../types.js";
|
|
4
|
+
import type { PlanningSystemPromptOptions } from "./system-prompt.js";
|
|
3
5
|
import { applyModelOverride } from "../config/model-resolver.js";
|
|
4
6
|
import { listPlans, readPlanFile } from "../storage/plans.js";
|
|
5
7
|
|
|
@@ -18,6 +20,12 @@ let planCwd: string = "";
|
|
|
18
20
|
let capturedNewSession: ((options?: any) => Promise<{ cancelled: boolean }>) | null = null;
|
|
19
21
|
/** Resolved model for plan action — re-applied on execution handoff. */
|
|
20
22
|
let capturedResolvedModel: ResolvedModel | null = null;
|
|
23
|
+
/** Guards against concurrent approval prompts from rapid agent_end events. */
|
|
24
|
+
let approvalPending = false;
|
|
25
|
+
/** Planning-system-prompt options captured from the command context at plan start. */
|
|
26
|
+
let planningPromptOptions: PlanningSystemPromptOptions | null = null;
|
|
27
|
+
/** Active debug logger for the current planning session. */
|
|
28
|
+
let planningDebugLogger: DebugLogger | null = null;
|
|
21
29
|
|
|
22
30
|
/** Mark planning as started (called by plan command after sending steer). */
|
|
23
31
|
export function startPlanTracking(
|
|
@@ -25,12 +33,25 @@ export function startPlanTracking(
|
|
|
25
33
|
paths: any,
|
|
26
34
|
newSession?: (options?: any) => Promise<{ cancelled: boolean }>,
|
|
27
35
|
resolvedModel?: ResolvedModel,
|
|
28
|
-
|
|
36
|
+
promptOptions?: PlanningSystemPromptOptions,
|
|
37
|
+
debugLogger?: DebugLogger,
|
|
38
|
+
): void {
|
|
29
39
|
planningActive = true;
|
|
30
40
|
planCwd = cwd;
|
|
31
41
|
plansBefore = listPlans(paths, cwd);
|
|
32
42
|
capturedNewSession = newSession ?? null;
|
|
33
43
|
capturedResolvedModel = resolvedModel ?? null;
|
|
44
|
+
planningPromptOptions = promptOptions ?? null;
|
|
45
|
+
planningDebugLogger = debugLogger ?? null;
|
|
46
|
+
approvalPending = false;
|
|
47
|
+
|
|
48
|
+
planningDebugLogger?.log("planning_tracking_started", {
|
|
49
|
+
cwd,
|
|
50
|
+
existingPlanCount: plansBefore.length,
|
|
51
|
+
hasNewSession: Boolean(newSession),
|
|
52
|
+
hasResolvedModel: Boolean(resolvedModel),
|
|
53
|
+
promptOptions: promptOptions ?? null,
|
|
54
|
+
});
|
|
34
55
|
}
|
|
35
56
|
|
|
36
57
|
/** Cancel plan tracking (e.g., session change). */
|
|
@@ -40,6 +61,9 @@ export function cancelPlanTracking(): void {
|
|
|
40
61
|
planCwd = "";
|
|
41
62
|
capturedNewSession = null;
|
|
42
63
|
capturedResolvedModel = null;
|
|
64
|
+
planningPromptOptions = null;
|
|
65
|
+
planningDebugLogger = null;
|
|
66
|
+
approvalPending = false;
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
/** Whether a planning session is currently active. */
|
|
@@ -47,6 +71,14 @@ export function isPlanningActive(): boolean {
|
|
|
47
71
|
return planningActive;
|
|
48
72
|
}
|
|
49
73
|
|
|
74
|
+
export function getPlanningPromptOptions(): PlanningSystemPromptOptions | null {
|
|
75
|
+
return planningPromptOptions;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getPlanningDebugLogger(): DebugLogger | null {
|
|
79
|
+
return planningDebugLogger;
|
|
80
|
+
}
|
|
81
|
+
|
|
50
82
|
/**
|
|
51
83
|
* Build the execution handoff prompt from an approved plan.
|
|
52
84
|
*
|
|
@@ -93,23 +125,40 @@ async function executeApproveFlow(
|
|
|
93
125
|
ctx: any,
|
|
94
126
|
planContent: string,
|
|
95
127
|
planPath: string,
|
|
96
|
-
|
|
128
|
+
newSession: ((options?: any) => Promise<{ cancelled: boolean }>) | null,
|
|
129
|
+
resolvedModel: ResolvedModel | null,
|
|
130
|
+
debugLogger: DebugLogger | null,
|
|
131
|
+
): Promise<void> {
|
|
97
132
|
const prompt = buildExecutionPrompt(planContent, planPath);
|
|
133
|
+
debugLogger?.log("execution_handoff_started", {
|
|
134
|
+
planPath,
|
|
135
|
+
promptLength: prompt.length,
|
|
136
|
+
usesNewSession: Boolean(newSession),
|
|
137
|
+
});
|
|
98
138
|
|
|
99
139
|
// Re-apply the plan model override for the execution turn.
|
|
100
140
|
// The planning turn's restore hook already fired (model reverted to default).
|
|
101
141
|
// We must switch again so the execution LLM turn uses the configured model.
|
|
102
|
-
if (
|
|
103
|
-
await applyModelOverride(platform, ctx, "plan",
|
|
142
|
+
if (resolvedModel) {
|
|
143
|
+
await applyModelOverride(platform, ctx, "plan", resolvedModel);
|
|
144
|
+
debugLogger?.log("execution_handoff_model_override_applied", {
|
|
145
|
+
configuredAction: "plan",
|
|
146
|
+
});
|
|
104
147
|
}
|
|
105
148
|
|
|
106
|
-
if (
|
|
107
|
-
const result = await
|
|
149
|
+
if (newSession) {
|
|
150
|
+
const result = await newSession();
|
|
108
151
|
if (result?.cancelled) {
|
|
152
|
+
debugLogger?.log("execution_handoff_new_session_cancelled", {
|
|
153
|
+
planPath,
|
|
154
|
+
});
|
|
109
155
|
ctx.ui.notify("Session start cancelled. Plan saved; run /supi:plan again to execute.");
|
|
110
156
|
return;
|
|
111
157
|
}
|
|
112
158
|
platform.sendUserMessage(prompt);
|
|
159
|
+
debugLogger?.log("execution_handoff_user_message_sent", {
|
|
160
|
+
planPath,
|
|
161
|
+
});
|
|
113
162
|
} else {
|
|
114
163
|
// Fallback: headless/SDK mode — steer in the current session.
|
|
115
164
|
platform.sendMessage(
|
|
@@ -120,6 +169,9 @@ async function executeApproveFlow(
|
|
|
120
169
|
},
|
|
121
170
|
{ deliverAs: "steer", triggerTurn: true },
|
|
122
171
|
);
|
|
172
|
+
debugLogger?.log("execution_handoff_same_session_steer_sent", {
|
|
173
|
+
planPath,
|
|
174
|
+
});
|
|
123
175
|
ctx.ui.notify("Plan approved — starting execution");
|
|
124
176
|
}
|
|
125
177
|
}
|
|
@@ -135,7 +187,7 @@ async function executeApproveFlow(
|
|
|
135
187
|
*/
|
|
136
188
|
export function registerPlanApprovalHook(platform: Platform): void {
|
|
137
189
|
platform.on("agent_end", async (_event: any, ctx: any) => {
|
|
138
|
-
if (!planningActive || !ctx?.hasUI) return;
|
|
190
|
+
if (!planningActive || !ctx?.hasUI || approvalPending) return;
|
|
139
191
|
|
|
140
192
|
// Detect newly written plan files
|
|
141
193
|
const plansNow = listPlans(platform.paths, planCwd);
|
|
@@ -151,20 +203,47 @@ export function registerPlanApprovalHook(platform: Platform): void {
|
|
|
151
203
|
// Pick the most recent new plan
|
|
152
204
|
const planName = newPlans[newPlans.length - 1];
|
|
153
205
|
const planContent = readPlanFile(platform.paths, planCwd, planName);
|
|
154
|
-
|
|
206
|
+
const debugLogger = planningDebugLogger;
|
|
207
|
+
if (!planContent) {
|
|
208
|
+
debugLogger?.log("approval_flow_plan_content_missing", {
|
|
209
|
+
planName,
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
155
213
|
|
|
156
214
|
const planPath = `${platform.paths.dotDirDisplay}/supipowers/plans/${planName}`;
|
|
157
|
-
|
|
158
|
-
const choice = await ctx.ui.select("Plan complete — what next?", [
|
|
215
|
+
const approvalOptions = [
|
|
159
216
|
"Approve and execute",
|
|
160
217
|
"Refine plan",
|
|
161
218
|
"Stay in plan mode",
|
|
162
|
-
]
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
approvalPending = true;
|
|
222
|
+
debugLogger?.log("approval_flow_presented", {
|
|
223
|
+
planName,
|
|
224
|
+
planPath,
|
|
225
|
+
options: approvalOptions,
|
|
226
|
+
});
|
|
227
|
+
const choice = await ctx.ui.select("Plan complete — what next?", approvalOptions);
|
|
228
|
+
approvalPending = false;
|
|
229
|
+
debugLogger?.log("approval_flow_choice", {
|
|
230
|
+
choice: choice ?? null,
|
|
231
|
+
planPath,
|
|
232
|
+
});
|
|
163
233
|
|
|
164
234
|
if (choice === "Approve and execute") {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
235
|
+
const executionNewSession = capturedNewSession;
|
|
236
|
+
const executionModel = capturedResolvedModel;
|
|
237
|
+
cancelPlanTracking();
|
|
238
|
+
await executeApproveFlow(
|
|
239
|
+
platform,
|
|
240
|
+
ctx,
|
|
241
|
+
planContent,
|
|
242
|
+
planPath,
|
|
243
|
+
executionNewSession,
|
|
244
|
+
executionModel,
|
|
245
|
+
debugLogger,
|
|
246
|
+
);
|
|
168
247
|
} else if (choice === "Refine plan") {
|
|
169
248
|
// Keep planning active, let user type refinement.
|
|
170
249
|
// Empty input is treated as misclick → fall through to approve.
|
|
@@ -172,16 +251,43 @@ export function registerPlanApprovalHook(platform: Platform): void {
|
|
|
172
251
|
const refinement = await ctx.ui.input("What should be refined?");
|
|
173
252
|
if (!refinement || !refinement.trim()) {
|
|
174
253
|
// Misclick: treat empty input as approval
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
254
|
+
debugLogger?.log("approval_flow_empty_refinement_treated_as_approve", {
|
|
255
|
+
planPath,
|
|
256
|
+
});
|
|
257
|
+
const executionNewSession = capturedNewSession;
|
|
258
|
+
const executionModel = capturedResolvedModel;
|
|
259
|
+
cancelPlanTracking();
|
|
260
|
+
await executeApproveFlow(
|
|
261
|
+
platform,
|
|
262
|
+
ctx,
|
|
263
|
+
planContent,
|
|
264
|
+
planPath,
|
|
265
|
+
executionNewSession,
|
|
266
|
+
executionModel,
|
|
267
|
+
debugLogger,
|
|
268
|
+
);
|
|
178
269
|
} else {
|
|
270
|
+
debugLogger?.log("approval_flow_refine_requested", {
|
|
271
|
+
planPath,
|
|
272
|
+
refinementLength: refinement.length,
|
|
273
|
+
});
|
|
179
274
|
ctx.ui.setEditorText?.(refinement);
|
|
180
275
|
}
|
|
181
|
-
} else {
|
|
182
|
-
//
|
|
276
|
+
} else if (choice === "Stay in plan mode") {
|
|
277
|
+
// Explicit user choice — cancel tracking, return control
|
|
278
|
+
debugLogger?.log("planning_tracking_cancelled", {
|
|
279
|
+
reason: "stay_in_plan_mode",
|
|
280
|
+
planPath,
|
|
281
|
+
});
|
|
183
282
|
cancelPlanTracking();
|
|
184
283
|
ctx.ui.notify("Planning complete. Plan saved but not executing.");
|
|
284
|
+
} else {
|
|
285
|
+
// Select was cancelled (returned undefined/null) — likely because a new
|
|
286
|
+
// agent turn started (e.g., background job completion). Don't cancel
|
|
287
|
+
// tracking; the next agent_end will re-prompt.
|
|
288
|
+
debugLogger?.log("approval_flow_choice_cancelled", {
|
|
289
|
+
planPath,
|
|
290
|
+
});
|
|
185
291
|
}
|
|
186
292
|
});
|
|
187
293
|
}
|
|
@@ -25,7 +25,8 @@ export function buildPlanWriterPrompt(options: PlanWriterOptions): string {
|
|
|
25
25
|
"",
|
|
26
26
|
"Write the plan assuming the implementing engineer has zero context for this codebase.",
|
|
27
27
|
"Document everything they need: which files to touch, complete code, testing, exact commands.",
|
|
28
|
-
"Give them the whole plan as bite-sized tasks. DRY. YAGNI. TDD.
|
|
28
|
+
"Give them the whole plan as bite-sized tasks. DRY. YAGNI. TDD.",
|
|
29
|
+
"Keep the plan local-only: do NOT include git add, git commit, git push, or other VCS steps in the plan.",
|
|
29
30
|
"",
|
|
30
31
|
|
|
31
32
|
// ── Scope Check ──────────────────────────────────────────────
|
|
@@ -73,7 +74,6 @@ export function buildPlanWriterPrompt(options: PlanWriterOptions): string {
|
|
|
73
74
|
"- Run it to verify it fails — one step",
|
|
74
75
|
"- Write minimal implementation — one step",
|
|
75
76
|
"- Run tests to verify it passes — one step",
|
|
76
|
-
"- Commit — one step",
|
|
77
77
|
"",
|
|
78
78
|
|
|
79
79
|
// ── Task Structure ───────────────────────────────────────────
|
|
@@ -113,13 +113,6 @@ export function buildPlanWriterPrompt(options: PlanWriterOptions): string {
|
|
|
113
113
|
"",
|
|
114
114
|
"Run: `bun test tests/path/test.ts`",
|
|
115
115
|
"Expected: PASS",
|
|
116
|
-
"",
|
|
117
|
-
"- [ ] **Step 5: Commit**",
|
|
118
|
-
"",
|
|
119
|
-
"```bash",
|
|
120
|
-
"git add tests/path/test.ts src/path/file.ts",
|
|
121
|
-
'git commit -m "feat: add specific feature"',
|
|
122
|
-
"```",
|
|
123
116
|
"````",
|
|
124
117
|
"",
|
|
125
118
|
|
|
@@ -129,9 +122,9 @@ export function buildPlanWriterPrompt(options: PlanWriterOptions): string {
|
|
|
129
122
|
"- Exact file paths always",
|
|
130
123
|
"- Complete code in plan (not 'add validation' — show the actual code)",
|
|
131
124
|
"- Exact commands with expected output",
|
|
132
|
-
"- DRY, YAGNI, TDD
|
|
125
|
+
"- DRY, YAGNI, TDD",
|
|
126
|
+
"- No git commit, push, or other VCS steps in the plan",
|
|
133
127
|
"",
|
|
134
|
-
|
|
135
128
|
// ── Plan Review Loop ─────────────────────────────────────────
|
|
136
129
|
"## Step 4: plan review loop",
|
|
137
130
|
"",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Platform } from "../platform/types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Register a `planning_ask` tool — identical to the built-in `ask` tool
|
|
5
|
+
* but with **no timeout**. OMP's built-in ask tool applies the user's
|
|
6
|
+
* `ask.timeout` setting (default 30s) and only disables it for OMP's
|
|
7
|
+
* native plan mode. Since `/supi:plan` is not native plan mode, planning
|
|
8
|
+
* questions would auto-dismiss. This tool bypasses that limitation.
|
|
9
|
+
*
|
|
10
|
+
* The tool is always registered (lightweight) but the planning system
|
|
11
|
+
* prompt directs the model to use it only during planning sessions.
|
|
12
|
+
*/
|
|
13
|
+
export function registerPlanningAskTool(platform: Platform): void {
|
|
14
|
+
if (!platform.registerTool) return;
|
|
15
|
+
|
|
16
|
+
platform.registerTool({
|
|
17
|
+
name: "planning_ask",
|
|
18
|
+
label: "Planning Question",
|
|
19
|
+
description:
|
|
20
|
+
"Ask the user questions during planning sessions. Use this instead of the ask tool when in /supi:plan planning mode. No timeout — the user can take as long as needed.",
|
|
21
|
+
promptSnippet:
|
|
22
|
+
"planning_ask — ask user questions during planning (no timeout, unlimited thinking time)",
|
|
23
|
+
parameters: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
question: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Question text to present to the user",
|
|
29
|
+
},
|
|
30
|
+
options: {
|
|
31
|
+
type: "array",
|
|
32
|
+
items: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
label: { type: "string", description: "Option label" },
|
|
36
|
+
},
|
|
37
|
+
required: ["label"],
|
|
38
|
+
},
|
|
39
|
+
description: "Available options for the user to choose from",
|
|
40
|
+
},
|
|
41
|
+
recommended: {
|
|
42
|
+
type: "number",
|
|
43
|
+
description: "Index of recommended option (0-indexed)",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
required: ["question", "options"],
|
|
47
|
+
},
|
|
48
|
+
async execute(
|
|
49
|
+
_toolCallId: string,
|
|
50
|
+
params: { question: string; options: { label: string }[]; recommended?: number },
|
|
51
|
+
_signal: AbortSignal,
|
|
52
|
+
_onUpdate: unknown,
|
|
53
|
+
ctx: any,
|
|
54
|
+
) {
|
|
55
|
+
const labels = params.options.map((o) => o.label);
|
|
56
|
+
if (labels.length === 0) {
|
|
57
|
+
return {
|
|
58
|
+
content: [{ type: "text", text: "Error: options must not be empty" }],
|
|
59
|
+
details: {},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const choice = await ctx.ui.select(params.question, labels, {
|
|
64
|
+
initialIndex: params.recommended,
|
|
65
|
+
// No timeout — planning decisions need unlimited time
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const selected = choice ?? labels[params.recommended ?? 0] ?? labels[0];
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: JSON.stringify({ question: params.question, selected }),
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
details: { question: params.question, selected },
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -1,181 +1,21 @@
|
|
|
1
|
-
import { buildSpecReviewerPrompt } from "./spec-reviewer.js";
|
|
2
|
-
import { buildPlanWriterPrompt } from "./plan-writer-prompt.js";
|
|
3
|
-
|
|
4
1
|
export interface PlanningPromptOptions {
|
|
5
2
|
topic?: string;
|
|
6
|
-
skillContent?: string;
|
|
7
|
-
dotDirDisplay: string;
|
|
8
3
|
}
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
|
-
* Build the
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* Follows supipowers' brainstorming skill flow:
|
|
15
|
-
* 1. Explore project context
|
|
16
|
-
* 2. Ask clarifying questions (one at a time)
|
|
17
|
-
* 3. Propose 2-3 approaches with trade-offs
|
|
18
|
-
* 4. Present design section by section
|
|
19
|
-
* 5. Write design doc to .omp/supipowers/specs/
|
|
20
|
-
* 6. Spec review loop (dispatch reviewer sub-agent)
|
|
21
|
-
* 7. User review gate
|
|
22
|
-
* 8. Handoff to implementation plan
|
|
6
|
+
* Build the kickoff steer prompt for collaborative planning.
|
|
7
|
+
* The planning workflow itself lives in the planning-mode system prompt.
|
|
23
8
|
*/
|
|
24
9
|
export function buildPlanningPrompt(options: PlanningPromptOptions): string {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"You are starting a collaborative planning session with the user.",
|
|
29
|
-
"Follow this process step by step. Do NOT skip phases or combine them.",
|
|
30
|
-
"",
|
|
31
|
-
|
|
32
|
-
// ── Phase 1: Context ─────────────────────────────────────────
|
|
33
|
-
"## Phase 1: Explore project context",
|
|
34
|
-
"",
|
|
35
|
-
"Before asking questions, understand the current project context:",
|
|
36
|
-
"- Check files, docs, recent commits",
|
|
37
|
-
"- Understand existing architecture and patterns",
|
|
38
|
-
"- Assess scope: if the request describes multiple independent subsystems, flag it immediately and help decompose into sub-projects before proceeding",
|
|
39
|
-
"",
|
|
40
|
-
|
|
41
|
-
// ── Topic ────────────────────────────────────────────────────
|
|
42
|
-
topic
|
|
43
|
-
? `The user wants to plan: ${topic}`
|
|
44
|
-
: "Ask the user what they want to build or accomplish.",
|
|
45
|
-
"",
|
|
46
|
-
|
|
47
|
-
// ── Phase 2: Clarify ─────────────────────────────────────────
|
|
48
|
-
"## Phase 2: Ask Clarifying Questions",
|
|
49
|
-
"",
|
|
50
|
-
"- Ask one question at a time — never overwhelm with multiple questions",
|
|
51
|
-
"- Prefer **multiple choice** questions when possible, but open-ended is fine too",
|
|
52
|
-
"- Focus on: purpose, constraints, success criteria",
|
|
53
|
-
"- If a topic needs more exploration, break it into multiple questions",
|
|
54
|
-
"- Continue until you have enough clarity to propose approaches",
|
|
55
|
-
"",
|
|
56
|
-
|
|
57
|
-
// ── Phase 3: Approaches ──────────────────────────────────────
|
|
58
|
-
"## Phase 3: Propose 2-3 Approaches",
|
|
59
|
-
"",
|
|
60
|
-
"- Present 2-3 different approaches with trade-offs",
|
|
61
|
-
"- Lead with your recommended option and explain why",
|
|
62
|
-
"- Present options conversationally with your recommendation and reasoning",
|
|
63
|
-
"- Wait for the user to choose before proceeding",
|
|
64
|
-
"",
|
|
65
|
-
|
|
66
|
-
// ── Phase 4: Design ──────────────────────────────────────────
|
|
67
|
-
"## Phase 4: Present Design",
|
|
68
|
-
"",
|
|
69
|
-
"Once aligned on approach, present the design:",
|
|
70
|
-
"- Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced",
|
|
71
|
-
"- Cover: architecture, components, data flow, error handling, testing",
|
|
72
|
-
"- Ask after each section whether it looks right so far",
|
|
73
|
-
"- Design for isolation and clarity: smaller units with clear boundaries",
|
|
74
|
-
"- Apply YAGNI ruthlessly — remove unnecessary features",
|
|
75
|
-
"- Be ready to go back and clarify if something doesn't make sense",
|
|
76
|
-
"",
|
|
77
|
-
|
|
78
|
-
// ── Phase 5: Write Spec ──────────────────────────────────────
|
|
79
|
-
"## Phase 5: Write Design Doc",
|
|
80
|
-
"",
|
|
81
|
-
"Once the user approves the design:",
|
|
82
|
-
"- Write the validated design doc to `.omp/supipowers/specs/YYYY-MM-DD-<topic>-design.md`",
|
|
83
|
-
"- Use clear, concise writing",
|
|
84
|
-
"- Commit the design document to git",
|
|
85
|
-
"",
|
|
86
|
-
|
|
87
|
-
// ── Phase 6: Spec Review Loop ────────────────────────────────
|
|
88
|
-
"## Phase 6: Spec Review Loop",
|
|
89
|
-
"",
|
|
90
|
-
"After writing the design doc, dispatch a spec-document-reviewer sub-agent to verify it:",
|
|
91
|
-
"",
|
|
92
|
-
"1. Dispatch the reviewer with this prompt:",
|
|
93
|
-
"",
|
|
94
|
-
"```",
|
|
95
|
-
buildSpecReviewerPrompt("<path-to-spec-file>"),
|
|
96
|
-
"```",
|
|
97
|
-
"",
|
|
98
|
-
"(Replace `<path-to-spec-file>` with the actual spec path.)",
|
|
99
|
-
"",
|
|
100
|
-
"2. If **Issues Found**: fix the issues, re-dispatch the reviewer",
|
|
101
|
-
"3. Repeat until **Approved** (max 5 iterations, then surface to human for guidance)",
|
|
102
|
-
"",
|
|
103
|
-
|
|
104
|
-
// ── Phase 7: User Gate ───────────────────────────────────────
|
|
105
|
-
"## Phase 7: User Review Gate",
|
|
106
|
-
"",
|
|
107
|
-
"After the spec review loop passes, ask the user to review the spec before proceeding:",
|
|
108
|
-
"",
|
|
109
|
-
'> "Spec written and committed to `<path>`. Please review it and let me know if you want to make any changes before we start writing out the implementation plan."',
|
|
110
|
-
"",
|
|
111
|
-
"Wait for the user's response. If they request changes, make them and re-run the spec review loop. Only proceed once the user approves.",
|
|
112
|
-
"",
|
|
113
|
-
|
|
114
|
-
// ── Phase 8: Handoff ─────────────────────────────────────────
|
|
115
|
-
"## Phase 8: Transition to Implementation Plan",
|
|
116
|
-
"",
|
|
117
|
-
"Once the user approves the spec, write a comprehensive implementation plan.",
|
|
118
|
-
"Follow these plan writing instructions:",
|
|
119
|
-
"",
|
|
120
|
-
buildPlanWriterPrompt({ specPath: "<path-to-approved-spec>", dotDirDisplay }),
|
|
121
|
-
"",
|
|
122
|
-
"(Replace `<path-to-approved-spec>` with the actual spec file path from Phase 5.)",
|
|
123
|
-
"",
|
|
124
|
-
|
|
125
|
-
// ── Principles ───────────────────────────────────────────────
|
|
126
|
-
"## Key Principles",
|
|
127
|
-
"",
|
|
128
|
-
"- **One question at a time** — Don't overwhelm with multiple questions",
|
|
129
|
-
"- **Multiple choice preferred** — Easier to answer than open-ended when possible",
|
|
130
|
-
"- **YAGNI ruthlessly** — Remove unnecessary features from all designs",
|
|
131
|
-
"- **Explore alternatives** — Always propose 2-3 approaches before settling",
|
|
132
|
-
"- **Incremental validation** — Present design, get approval before moving on",
|
|
133
|
-
"- **Decompose large scope** — If the request covers multiple independent subsystems, decompose into sub-projects first",
|
|
134
|
-
"- **Design for isolation** — Smaller units with clear boundaries and well-defined interfaces",
|
|
135
|
-
"",
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
if (skillContent) {
|
|
139
|
-
sections.push("## Additional Planning Guidelines", "", skillContent, "");
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return sections.join("\n");
|
|
10
|
+
return options.topic
|
|
11
|
+
? "Begin planning. Follow the planning phases in order."
|
|
12
|
+
: "Ask the user what they want to build or accomplish."
|
|
143
13
|
}
|
|
144
14
|
|
|
145
15
|
/**
|
|
146
|
-
* Build the quick
|
|
147
|
-
*
|
|
16
|
+
* Build the quick-plan kickoff steer prompt.
|
|
17
|
+
* The detailed quick-planning rules live in the planning-mode system prompt.
|
|
148
18
|
*/
|
|
149
|
-
export function buildQuickPlanPrompt(
|
|
150
|
-
|
|
151
|
-
skillContent?: string,
|
|
152
|
-
): string {
|
|
153
|
-
const sections: string[] = [
|
|
154
|
-
"Generate a concise implementation plan for the following task.",
|
|
155
|
-
"Skip brainstorming — go straight to task breakdown.",
|
|
156
|
-
"",
|
|
157
|
-
`Task: ${description}`,
|
|
158
|
-
"",
|
|
159
|
-
"Format the plan as markdown with YAML frontmatter:",
|
|
160
|
-
"",
|
|
161
|
-
"```yaml",
|
|
162
|
-
"---",
|
|
163
|
-
"name: <feature-name>",
|
|
164
|
-
"created: YYYY-MM-DD",
|
|
165
|
-
"tags: [tag1, tag2]",
|
|
166
|
-
"---",
|
|
167
|
-
"```",
|
|
168
|
-
"",
|
|
169
|
-
"Each task should have: name, **files**, **criteria**, and **complexity** (small/medium/large).",
|
|
170
|
-
"",
|
|
171
|
-
"After generating the plan, save it and tell the user:",
|
|
172
|
-
'> "Plan saved to `<path>`. Review it and approve when ready."',
|
|
173
|
-
"Then stop and wait. The user will see an approval prompt.",
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
if (skillContent) {
|
|
177
|
-
sections.push("", "Follow these planning guidelines:", skillContent);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return sections.join("\n");
|
|
19
|
+
export function buildQuickPlanPrompt(description: string): string {
|
|
20
|
+
return `Generate a concise implementation plan for: ${description}. Skip brainstorming — go straight to task breakdown.`;
|
|
181
21
|
}
|