supipowers 0.4.0 → 0.6.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/package.json +3 -3
- package/skills/context-mode/SKILL.md +38 -0
- package/skills/qa-strategy/SKILL.md +103 -21
- package/src/commands/config.ts +23 -2
- package/src/commands/fix-pr.ts +1 -1
- package/src/commands/plan.ts +1 -1
- package/src/commands/qa.ts +232 -148
- package/src/commands/release.ts +1 -1
- package/src/commands/review.ts +1 -1
- package/src/commands/run.ts +9 -4
- package/src/commands/supi.ts +1 -1
- package/src/config/defaults.ts +11 -0
- package/src/config/schema.ts +11 -0
- package/src/context-mode/compressor.ts +200 -0
- package/src/context-mode/detector.ts +43 -0
- package/src/context-mode/event-extractor.ts +170 -0
- package/src/context-mode/event-store.ts +168 -0
- package/src/context-mode/hooks.ts +176 -0
- package/src/context-mode/installer.ts +71 -0
- package/src/context-mode/snapshot-builder.ts +127 -0
- package/src/discipline/debugging.ts +7 -7
- package/src/discipline/receiving-review.ts +5 -5
- package/src/discipline/tdd.ts +2 -2
- package/src/discipline/verification.ts +9 -9
- package/src/git/base-branch.ts +30 -0
- package/src/git/branch-finish.ts +12 -3
- package/src/git/sanitize.ts +19 -0
- package/src/git/worktree.ts +38 -11
- package/src/index.ts +8 -1
- package/src/orchestrator/agent-prompts.ts +15 -7
- package/src/orchestrator/conflict-resolver.ts +3 -2
- package/src/orchestrator/dispatcher.ts +76 -21
- package/src/orchestrator/prompts.ts +46 -6
- package/src/planning/plan-reviewer.ts +1 -1
- package/src/planning/plan-writer-prompt.ts +6 -9
- package/src/planning/prompt-builder.ts +17 -16
- package/src/planning/spec-reviewer.ts +2 -2
- package/src/qa/config.ts +43 -0
- package/src/qa/matrix.ts +84 -0
- package/src/qa/prompt-builder.ts +212 -0
- package/src/qa/scripts/detect-app-type.sh +68 -0
- package/src/qa/scripts/discover-routes.sh +143 -0
- package/src/qa/scripts/ensure-playwright.sh +38 -0
- package/src/qa/scripts/run-e2e-tests.sh +99 -0
- package/src/qa/scripts/start-dev-server.sh +46 -0
- package/src/qa/scripts/stop-dev-server.sh +36 -0
- package/src/qa/session.ts +39 -55
- package/src/qa/types.ts +97 -0
- package/src/storage/qa-sessions.ts +9 -9
- package/src/types.ts +22 -70
- package/src/qa/detector.ts +0 -61
- package/src/qa/phases/discovery.ts +0 -34
- package/src/qa/phases/execution.ts +0 -65
- package/src/qa/phases/matrix.ts +0 -41
- package/src/qa/phases/reporting.ts +0 -71
- package/src/qa/report.ts +0 -22
- package/src/qa/runner.ts +0 -46
package/src/git/worktree.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertSafeRef } from "./sanitize.js";
|
|
1
2
|
import * as fs from "node:fs";
|
|
2
3
|
import * as path from "node:path";
|
|
3
4
|
|
|
@@ -25,20 +26,44 @@ export function detectWorktreeDir(cwd: string): string | null {
|
|
|
25
26
|
* Auto-detect project type and setup commands from project files.
|
|
26
27
|
*/
|
|
27
28
|
export function detectProjectSetup(cwd: string): ProjectSetup {
|
|
29
|
+
// Bun (check before generic package.json since Bun projects also have package.json)
|
|
30
|
+
if (fs.existsSync(path.join(cwd, "bun.lock")) || fs.existsSync(path.join(cwd, "bun.lockb"))) {
|
|
31
|
+
return { type: "node", installCommand: "bun install", testCommand: "bun test" };
|
|
32
|
+
}
|
|
28
33
|
if (fs.existsSync(path.join(cwd, "package.json"))) {
|
|
29
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
type: "node",
|
|
36
|
+
installCommand: "npm install",
|
|
37
|
+
testCommand: "npm test",
|
|
38
|
+
};
|
|
30
39
|
}
|
|
31
40
|
if (fs.existsSync(path.join(cwd, "Cargo.toml"))) {
|
|
32
|
-
return {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
return {
|
|
42
|
+
type: "rust",
|
|
43
|
+
installCommand: "cargo build",
|
|
44
|
+
testCommand: "cargo test",
|
|
45
|
+
};
|
|
36
46
|
}
|
|
37
47
|
if (fs.existsSync(path.join(cwd, "pyproject.toml"))) {
|
|
38
|
-
return {
|
|
48
|
+
return {
|
|
49
|
+
type: "python",
|
|
50
|
+
installCommand: "poetry install",
|
|
51
|
+
testCommand: "pytest",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (fs.existsSync(path.join(cwd, "requirements.txt"))) {
|
|
55
|
+
return {
|
|
56
|
+
type: "python",
|
|
57
|
+
installCommand: "pip install -r requirements.txt",
|
|
58
|
+
testCommand: "pytest",
|
|
59
|
+
};
|
|
39
60
|
}
|
|
40
61
|
if (fs.existsSync(path.join(cwd, "go.mod"))) {
|
|
41
|
-
return {
|
|
62
|
+
return {
|
|
63
|
+
type: "go",
|
|
64
|
+
installCommand: "go mod download",
|
|
65
|
+
testCommand: "go test ./...",
|
|
66
|
+
};
|
|
42
67
|
}
|
|
43
68
|
return { type: "unknown", installCommand: null, testCommand: null };
|
|
44
69
|
}
|
|
@@ -50,7 +75,7 @@ export interface WorktreePromptOptions {
|
|
|
50
75
|
|
|
51
76
|
/**
|
|
52
77
|
* Build the prompt that guides the agent through creating an isolated git worktree.
|
|
53
|
-
* Follows
|
|
78
|
+
* Follows supipowers' using-git-worktrees skill:
|
|
54
79
|
* - Smart directory selection (.worktrees > worktrees > ask)
|
|
55
80
|
* - .gitignore verification
|
|
56
81
|
* - Project setup detection
|
|
@@ -58,6 +83,7 @@ export interface WorktreePromptOptions {
|
|
|
58
83
|
*/
|
|
59
84
|
export function buildWorktreePrompt(options: WorktreePromptOptions): string {
|
|
60
85
|
const { branchName, cwd } = options;
|
|
86
|
+
assertSafeRef(branchName, "branchName");
|
|
61
87
|
|
|
62
88
|
return [
|
|
63
89
|
"## Set Up Isolated Worktree",
|
|
@@ -71,8 +97,8 @@ export function buildWorktreePrompt(options: WorktreePromptOptions): string {
|
|
|
71
97
|
`2. \`${cwd}/worktrees/\` — if it exists, use it`,
|
|
72
98
|
"3. Check CLAUDE.md for worktree directory preference",
|
|
73
99
|
"4. If none found, ask the user:",
|
|
74
|
-
|
|
75
|
-
|
|
100
|
+
" - `.worktrees/` (project-local, hidden)",
|
|
101
|
+
" - `~/.config/supipowers/worktrees/<project>/` (global location)",
|
|
76
102
|
"",
|
|
77
103
|
"### Step 2: Verify gitignore",
|
|
78
104
|
"",
|
|
@@ -97,10 +123,11 @@ export function buildWorktreePrompt(options: WorktreePromptOptions): string {
|
|
|
97
123
|
"",
|
|
98
124
|
"| File | Command |",
|
|
99
125
|
"|------|---------|",
|
|
126
|
+
"| `bun.lock` / `bun.lockb` | `bun install` |",
|
|
100
127
|
"| `package.json` | `npm install` |",
|
|
101
128
|
"| `Cargo.toml` | `cargo build` |",
|
|
102
|
-
"| `requirements.txt` | `pip install -r requirements.txt` |",
|
|
103
129
|
"| `pyproject.toml` | `poetry install` |",
|
|
130
|
+
"| `requirements.txt` | `pip install -r requirements.txt` |",
|
|
104
131
|
"| `go.mod` | `go mod download` |",
|
|
105
132
|
"",
|
|
106
133
|
"### Step 5: Verify baseline",
|
package/src/index.ts
CHANGED
|
@@ -13,12 +13,14 @@ import { registerQaCommand } from "./commands/qa.js";
|
|
|
13
13
|
import { registerReleaseCommand } from "./commands/release.js";
|
|
14
14
|
import { registerUpdateCommand, handleUpdate } from "./commands/update.js";
|
|
15
15
|
import { registerFixPrCommand } from "./commands/fix-pr.js";
|
|
16
|
+
import { loadConfig } from "./config/loader.js";
|
|
17
|
+
import { registerContextModeHooks } from "./context-mode/hooks.js";
|
|
16
18
|
|
|
17
19
|
// TUI-only commands — intercepted at the input level to prevent
|
|
18
20
|
// message submission and "Working..." indicator
|
|
19
21
|
const TUI_COMMANDS: Record<string, (pi: ExtensionAPI, ctx: any) => void> = {
|
|
20
22
|
"supi": (pi, ctx) => handleSupi(pi, ctx),
|
|
21
|
-
"supi:config": (
|
|
23
|
+
"supi:config": (pi, ctx) => handleConfig(pi, ctx),
|
|
22
24
|
"supi:status": (_pi, ctx) => handleStatus(ctx),
|
|
23
25
|
"supi:update": (pi, ctx) => handleUpdate(pi, ctx),
|
|
24
26
|
};
|
|
@@ -62,6 +64,11 @@ export default function supipowers(pi: ExtensionAPI): void {
|
|
|
62
64
|
return { handled: true };
|
|
63
65
|
});
|
|
64
66
|
|
|
67
|
+
// Context-mode integration
|
|
68
|
+
const config = loadConfig(process.cwd());
|
|
69
|
+
registerContextModeHooks(pi, config);
|
|
70
|
+
|
|
71
|
+
|
|
65
72
|
// Session start
|
|
66
73
|
pi.on("session_start", async (_event, ctx) => {
|
|
67
74
|
// Clean up any leftover visual companion from a previous session
|
|
@@ -13,7 +13,7 @@ export interface ImplementerPromptOptions {
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Build the prompt for an implementer sub-agent.
|
|
16
|
-
* Follows
|
|
16
|
+
* Follows supipowers' implementer-prompt.md pattern:
|
|
17
17
|
* - Full task description
|
|
18
18
|
* - Ask-before-starting section
|
|
19
19
|
* - TDD and code organization guidance
|
|
@@ -21,7 +21,9 @@ export interface ImplementerPromptOptions {
|
|
|
21
21
|
* - Self-review before reporting
|
|
22
22
|
* - Structured report format
|
|
23
23
|
*/
|
|
24
|
-
export function buildImplementerPrompt(
|
|
24
|
+
export function buildImplementerPrompt(
|
|
25
|
+
options: ImplementerPromptOptions,
|
|
26
|
+
): string {
|
|
25
27
|
const { task, planContext, workDir } = options;
|
|
26
28
|
|
|
27
29
|
return [
|
|
@@ -33,7 +35,9 @@ export function buildImplementerPrompt(options: ImplementerPromptOptions): strin
|
|
|
33
35
|
"",
|
|
34
36
|
"## Target Files",
|
|
35
37
|
"",
|
|
36
|
-
...task.files.
|
|
38
|
+
...(task.files.length > 0
|
|
39
|
+
? task.files.map((f) => `- ${f}`)
|
|
40
|
+
: ["(No specific files targeted \u2014 determine from task description)"]),
|
|
37
41
|
"",
|
|
38
42
|
"## Acceptance Criteria",
|
|
39
43
|
"",
|
|
@@ -152,12 +156,14 @@ export interface SpecComplianceReviewOptions {
|
|
|
152
156
|
|
|
153
157
|
/**
|
|
154
158
|
* Build the prompt for a spec compliance reviewer sub-agent.
|
|
155
|
-
* Follows
|
|
159
|
+
* Follows supipowers' spec-reviewer-prompt.md pattern:
|
|
156
160
|
* - Do not trust the implementer's report
|
|
157
161
|
* - Verify by reading actual code
|
|
158
162
|
* - Check for missing, extra, and misunderstood requirements
|
|
159
163
|
*/
|
|
160
|
-
export function buildSpecComplianceReviewPrompt(
|
|
164
|
+
export function buildSpecComplianceReviewPrompt(
|
|
165
|
+
options: SpecComplianceReviewOptions,
|
|
166
|
+
): string {
|
|
161
167
|
const { taskRequirements, implementerReport } = options;
|
|
162
168
|
|
|
163
169
|
return [
|
|
@@ -225,12 +231,14 @@ export interface CodeQualityReviewOptions {
|
|
|
225
231
|
|
|
226
232
|
/**
|
|
227
233
|
* Build the prompt for a code quality reviewer sub-agent.
|
|
228
|
-
* Follows
|
|
234
|
+
* Follows supipowers' code-quality-reviewer-prompt.md pattern:
|
|
229
235
|
* - Review git diff between base and head
|
|
230
236
|
* - Check file responsibilities and unit decomposition
|
|
231
237
|
* - Categorize issues as Critical/Important/Minor
|
|
232
238
|
*/
|
|
233
|
-
export function buildCodeQualityReviewPrompt(
|
|
239
|
+
export function buildCodeQualityReviewPrompt(
|
|
240
|
+
options: CodeQualityReviewOptions,
|
|
241
|
+
): string {
|
|
234
242
|
const { taskSummary, implementerReport, baseSha, headSha } = options;
|
|
235
243
|
|
|
236
244
|
return [
|
|
@@ -10,7 +10,8 @@ export interface ConflictResolution {
|
|
|
10
10
|
|
|
11
11
|
export function analyzeConflicts(
|
|
12
12
|
results: AgentResult[],
|
|
13
|
-
tasks: PlanTask[]
|
|
13
|
+
tasks: PlanTask[],
|
|
14
|
+
contextModeAvailable = false,
|
|
14
15
|
): ConflictResolution {
|
|
15
16
|
const conflictingFiles = detectConflicts(results);
|
|
16
17
|
|
|
@@ -33,6 +34,6 @@ export function analyzeConflicts(
|
|
|
33
34
|
return {
|
|
34
35
|
hasConflicts: true,
|
|
35
36
|
conflictingFiles,
|
|
36
|
-
mergePrompt: buildMergePrompt(conflictingFiles, agentOutputs),
|
|
37
|
+
mergePrompt: buildMergePrompt(conflictingFiles, agentOutputs, contextModeAvailable),
|
|
37
38
|
};
|
|
38
39
|
}
|
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
PlanTask,
|
|
4
|
+
AgentResult,
|
|
5
|
+
AgentStatus,
|
|
6
|
+
SupipowersConfig,
|
|
7
|
+
} from "../types.js";
|
|
3
8
|
import { buildTaskPrompt, buildFixPrompt } from "./prompts.js";
|
|
4
9
|
import {
|
|
5
10
|
buildSpecComplianceReviewPrompt,
|
|
6
11
|
buildCodeQualityReviewPrompt,
|
|
7
12
|
} from "./agent-prompts.js";
|
|
8
13
|
import { isLspAvailable } from "../lsp/detector.js";
|
|
9
|
-
import {
|
|
14
|
+
import { detectContextMode } from "../context-mode/detector.js";
|
|
15
|
+
import {
|
|
16
|
+
notifySuccess,
|
|
17
|
+
notifyWarning,
|
|
18
|
+
notifyError,
|
|
19
|
+
notifyInfo,
|
|
20
|
+
} from "../notifications/renderer.js";
|
|
10
21
|
|
|
11
22
|
export interface DispatchOptions {
|
|
12
23
|
pi: ExtensionAPI;
|
|
13
|
-
ctx: {
|
|
24
|
+
ctx: {
|
|
25
|
+
cwd: string;
|
|
26
|
+
ui: { notify(msg: string, type?: "info" | "warning" | "error"): void };
|
|
27
|
+
};
|
|
14
28
|
task: PlanTask;
|
|
15
29
|
planContext: string;
|
|
16
30
|
config: SupipowersConfig;
|
|
17
31
|
lspAvailable: boolean;
|
|
32
|
+
contextModeAvailable: boolean;
|
|
18
33
|
}
|
|
19
34
|
|
|
20
|
-
export async function dispatchAgent(
|
|
21
|
-
|
|
35
|
+
export async function dispatchAgent(
|
|
36
|
+
options: DispatchOptions,
|
|
37
|
+
): Promise<AgentResult> {
|
|
38
|
+
const { pi, ctx, task, planContext, config, lspAvailable, contextModeAvailable } = options;
|
|
22
39
|
const startTime = Date.now();
|
|
23
40
|
|
|
24
|
-
const prompt = buildTaskPrompt(task, planContext, config, lspAvailable);
|
|
41
|
+
const prompt = buildTaskPrompt(task, planContext, config, lspAvailable, contextModeAvailable);
|
|
25
42
|
|
|
26
43
|
try {
|
|
27
44
|
const result = await executeSubAgent(pi, prompt, task, config);
|
|
@@ -40,7 +57,11 @@ export async function dispatchAgent(options: DispatchOptions): Promise<AgentResu
|
|
|
40
57
|
notifySuccess(ctx, `Task ${task.id} completed`, task.name);
|
|
41
58
|
break;
|
|
42
59
|
case "done_with_concerns":
|
|
43
|
-
notifyWarning(
|
|
60
|
+
notifyWarning(
|
|
61
|
+
ctx,
|
|
62
|
+
`Task ${task.id} done with concerns`,
|
|
63
|
+
agentResult.concerns,
|
|
64
|
+
);
|
|
44
65
|
break;
|
|
45
66
|
case "blocked":
|
|
46
67
|
notifyError(ctx, `Task ${task.id} blocked`, agentResult.output);
|
|
@@ -72,11 +93,11 @@ async function executeSubAgent(
|
|
|
72
93
|
pi: ExtensionAPI,
|
|
73
94
|
prompt: string,
|
|
74
95
|
task: PlanTask,
|
|
75
|
-
config: SupipowersConfig
|
|
96
|
+
config: SupipowersConfig,
|
|
76
97
|
): Promise<SubAgentResult> {
|
|
77
98
|
throw new Error(
|
|
78
99
|
"Sub-agent dispatch requires OMP runtime. " +
|
|
79
|
-
|
|
100
|
+
"This will be connected to createAgentSession during integration.",
|
|
80
101
|
);
|
|
81
102
|
}
|
|
82
103
|
|
|
@@ -88,7 +109,7 @@ export interface ReviewResult {
|
|
|
88
109
|
|
|
89
110
|
/**
|
|
90
111
|
* Dispatch an implementer with 2-stage review (spec compliance + code quality).
|
|
91
|
-
* Follows
|
|
112
|
+
* Follows supipowers' subagent-driven-development pattern:
|
|
92
113
|
* 1. Implementer implements + self-reviews
|
|
93
114
|
* 2. Spec compliance reviewer verifies implementation matches spec
|
|
94
115
|
* 3. If spec issues → re-dispatch implementer with feedback
|
|
@@ -98,7 +119,7 @@ export interface ReviewResult {
|
|
|
98
119
|
export async function dispatchAgentWithReview(
|
|
99
120
|
options: DispatchOptions & { workDir?: string },
|
|
100
121
|
): Promise<AgentResult> {
|
|
101
|
-
const { pi, ctx, task, planContext, config, lspAvailable, workDir } = options;
|
|
122
|
+
const { pi, ctx, task, planContext, config, lspAvailable, contextModeAvailable, workDir } = options;
|
|
102
123
|
const maxReviewRetries = config.orchestration.maxFixRetries;
|
|
103
124
|
|
|
104
125
|
// Step 1: Dispatch implementer
|
|
@@ -111,7 +132,12 @@ export async function dispatchAgentWithReview(
|
|
|
111
132
|
|
|
112
133
|
// Step 2: Spec compliance review
|
|
113
134
|
for (let attempt = 0; attempt <= maxReviewRetries; attempt++) {
|
|
114
|
-
const specReview = await dispatchSpecReview(
|
|
135
|
+
const specReview = await dispatchSpecReview(
|
|
136
|
+
pi,
|
|
137
|
+
task,
|
|
138
|
+
implementResult,
|
|
139
|
+
config,
|
|
140
|
+
);
|
|
115
141
|
|
|
116
142
|
if (specReview.passed) {
|
|
117
143
|
notifyInfo(ctx, `Task ${task.id} spec review passed`);
|
|
@@ -119,14 +145,22 @@ export async function dispatchAgentWithReview(
|
|
|
119
145
|
}
|
|
120
146
|
|
|
121
147
|
if (attempt === maxReviewRetries) {
|
|
122
|
-
notifyWarning(
|
|
148
|
+
notifyWarning(
|
|
149
|
+
ctx,
|
|
150
|
+
`Task ${task.id} spec review failed after ${maxReviewRetries + 1} attempts`,
|
|
151
|
+
specReview.issues,
|
|
152
|
+
);
|
|
123
153
|
implementResult.status = "done_with_concerns";
|
|
124
154
|
implementResult.concerns = `Spec compliance issues: ${specReview.issues}`;
|
|
125
155
|
return implementResult;
|
|
126
156
|
}
|
|
127
157
|
|
|
128
158
|
// Re-dispatch implementer with spec review feedback
|
|
129
|
-
notifyInfo(
|
|
159
|
+
notifyInfo(
|
|
160
|
+
ctx,
|
|
161
|
+
`Task ${task.id} spec issues found, re-dispatching`,
|
|
162
|
+
specReview.issues,
|
|
163
|
+
);
|
|
130
164
|
const fixResult = await dispatchFixAgent({
|
|
131
165
|
...options,
|
|
132
166
|
previousOutput: implementResult.output,
|
|
@@ -141,7 +175,12 @@ export async function dispatchAgentWithReview(
|
|
|
141
175
|
|
|
142
176
|
// Step 3: Code quality review
|
|
143
177
|
for (let attempt = 0; attempt <= maxReviewRetries; attempt++) {
|
|
144
|
-
const qualityReview = await dispatchQualityReview(
|
|
178
|
+
const qualityReview = await dispatchQualityReview(
|
|
179
|
+
pi,
|
|
180
|
+
task,
|
|
181
|
+
implementResult,
|
|
182
|
+
config,
|
|
183
|
+
);
|
|
145
184
|
|
|
146
185
|
if (qualityReview.passed) {
|
|
147
186
|
notifyInfo(ctx, `Task ${task.id} quality review passed`);
|
|
@@ -149,14 +188,22 @@ export async function dispatchAgentWithReview(
|
|
|
149
188
|
}
|
|
150
189
|
|
|
151
190
|
if (attempt === maxReviewRetries) {
|
|
152
|
-
notifyWarning(
|
|
191
|
+
notifyWarning(
|
|
192
|
+
ctx,
|
|
193
|
+
`Task ${task.id} quality review failed after ${maxReviewRetries + 1} attempts`,
|
|
194
|
+
qualityReview.issues,
|
|
195
|
+
);
|
|
153
196
|
implementResult.status = "done_with_concerns";
|
|
154
197
|
implementResult.concerns = `Code quality issues: ${qualityReview.issues}`;
|
|
155
198
|
return implementResult;
|
|
156
199
|
}
|
|
157
200
|
|
|
158
201
|
// Re-dispatch implementer with quality review feedback
|
|
159
|
-
notifyInfo(
|
|
202
|
+
notifyInfo(
|
|
203
|
+
ctx,
|
|
204
|
+
`Task ${task.id} quality issues found, re-dispatching`,
|
|
205
|
+
qualityReview.issues,
|
|
206
|
+
);
|
|
160
207
|
const fixResult = await dispatchFixAgent({
|
|
161
208
|
...options,
|
|
162
209
|
previousOutput: implementResult.output,
|
|
@@ -186,7 +233,8 @@ async function dispatchSpecReview(
|
|
|
186
233
|
|
|
187
234
|
try {
|
|
188
235
|
const result = await executeSubAgent(pi, prompt, task, config);
|
|
189
|
-
const passed =
|
|
236
|
+
const passed =
|
|
237
|
+
result.status === "done" ||
|
|
190
238
|
result.output.toLowerCase().includes("spec compliant");
|
|
191
239
|
return {
|
|
192
240
|
passed,
|
|
@@ -226,12 +274,19 @@ async function dispatchQualityReview(
|
|
|
226
274
|
}
|
|
227
275
|
|
|
228
276
|
export async function dispatchFixAgent(
|
|
229
|
-
options: DispatchOptions & { previousOutput: string; failureReason: string }
|
|
277
|
+
options: DispatchOptions & { previousOutput: string; failureReason: string },
|
|
230
278
|
): Promise<AgentResult> {
|
|
231
|
-
const { pi, ctx, task, config, lspAvailable, previousOutput, failureReason } =
|
|
279
|
+
const { pi, ctx, task, config, lspAvailable, contextModeAvailable, previousOutput, failureReason } =
|
|
280
|
+
options;
|
|
232
281
|
const startTime = Date.now();
|
|
233
282
|
|
|
234
|
-
const prompt = buildFixPrompt(
|
|
283
|
+
const prompt = buildFixPrompt(
|
|
284
|
+
task,
|
|
285
|
+
previousOutput,
|
|
286
|
+
failureReason,
|
|
287
|
+
lspAvailable,
|
|
288
|
+
contextModeAvailable,
|
|
289
|
+
);
|
|
235
290
|
|
|
236
291
|
try {
|
|
237
292
|
const result = await executeSubAgent(pi, prompt, task, config);
|
|
@@ -10,17 +10,18 @@ export function buildTaskPrompt(
|
|
|
10
10
|
planContext: string,
|
|
11
11
|
config: SupipowersConfig,
|
|
12
12
|
lspAvailable: boolean,
|
|
13
|
+
contextModeAvailable = false,
|
|
13
14
|
workDir?: string,
|
|
14
15
|
): string {
|
|
15
|
-
|
|
16
|
+
let result = buildImplementerPrompt({
|
|
16
17
|
task,
|
|
17
18
|
planContext,
|
|
18
19
|
workDir: workDir ?? process.cwd(),
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
if (lspAvailable) {
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
result = [
|
|
24
|
+
result,
|
|
24
25
|
"",
|
|
25
26
|
"## LSP Available",
|
|
26
27
|
"You have access to the LSP tool. Use it to:",
|
|
@@ -32,7 +33,22 @@ export function buildTaskPrompt(
|
|
|
32
33
|
].join("\n");
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
if (contextModeAvailable) {
|
|
37
|
+
result = [
|
|
38
|
+
result,
|
|
39
|
+
"",
|
|
40
|
+
"## Context Mode Available",
|
|
41
|
+
"You have access to context-mode sandbox tools. Prefer them for large operations:",
|
|
42
|
+
"- Use `ctx_batch_execute` for multi-step operations",
|
|
43
|
+
"- Use `ctx_search` for querying indexed knowledge",
|
|
44
|
+
"- Use `ctx_execute` for single commands with large output",
|
|
45
|
+
"- Do NOT use `curl`/`wget` \u2014 use `ctx_fetch_and_index`",
|
|
46
|
+
"- Do NOT use Read for analyzing large files \u2014 use `ctx_execute_file`",
|
|
47
|
+
"- Keep output under 500 words; write large artifacts to files",
|
|
48
|
+
].join("\n");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
36
52
|
}
|
|
37
53
|
|
|
38
54
|
/** Build prompt for a fix agent */
|
|
@@ -40,7 +56,8 @@ export function buildFixPrompt(
|
|
|
40
56
|
task: PlanTask,
|
|
41
57
|
previousOutput: string,
|
|
42
58
|
failureReason: string,
|
|
43
|
-
lspAvailable: boolean
|
|
59
|
+
lspAvailable: boolean,
|
|
60
|
+
contextModeAvailable = false,
|
|
44
61
|
): string {
|
|
45
62
|
const sections: string[] = [
|
|
46
63
|
"# Fix Assignment",
|
|
@@ -74,13 +91,28 @@ export function buildFixPrompt(
|
|
|
74
91
|
sections.push("", buildLspValidationPrompt(task.files));
|
|
75
92
|
}
|
|
76
93
|
|
|
94
|
+
if (contextModeAvailable) {
|
|
95
|
+
sections.push(
|
|
96
|
+
"",
|
|
97
|
+
"## Context Mode Available",
|
|
98
|
+
"You have access to context-mode sandbox tools. Prefer them for large operations:",
|
|
99
|
+
"- Use `ctx_batch_execute` for multi-step operations",
|
|
100
|
+
"- Use `ctx_search` for querying indexed knowledge",
|
|
101
|
+
"- Use `ctx_execute` for single commands with large output",
|
|
102
|
+
"- Do NOT use `curl`/`wget` \u2014 use `ctx_fetch_and_index`",
|
|
103
|
+
"- Do NOT use Read for analyzing large files \u2014 use `ctx_execute_file`",
|
|
104
|
+
"- Keep output under 500 words; write large artifacts to files",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
77
108
|
return sections.join("\n");
|
|
78
109
|
}
|
|
79
110
|
|
|
80
111
|
/** Build prompt for a merge/conflict resolution agent */
|
|
81
112
|
export function buildMergePrompt(
|
|
82
113
|
conflictingFiles: string[],
|
|
83
|
-
agentOutputs: { taskName: string; output: string }[]
|
|
114
|
+
agentOutputs: { taskName: string; output: string }[],
|
|
115
|
+
contextModeAvailable = false,
|
|
84
116
|
): string {
|
|
85
117
|
const sections: string[] = [
|
|
86
118
|
"# Merge Assignment",
|
|
@@ -105,5 +137,13 @@ export function buildMergePrompt(
|
|
|
105
137
|
"4. If changes are incompatible, report BLOCKED with explanation"
|
|
106
138
|
);
|
|
107
139
|
|
|
140
|
+
if (contextModeAvailable) {
|
|
141
|
+
sections.push(
|
|
142
|
+
"",
|
|
143
|
+
"## Context Mode Available",
|
|
144
|
+
"Prefer context-mode sandbox tools for large operations.",
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
108
148
|
return sections.join("\n");
|
|
109
149
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Build the prompt for dispatching a plan document reviewer sub-agent.
|
|
3
|
-
* Follows the same pattern as
|
|
3
|
+
* Follows the same pattern as supipowers' plan-document-reviewer-prompt.md.
|
|
4
4
|
*/
|
|
5
5
|
export function buildPlanReviewerPrompt(
|
|
6
6
|
planFilePath: string,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { buildPlanReviewerPrompt } from "./plan-reviewer.js";
|
|
2
1
|
|
|
3
2
|
export interface PlanWriterOptions {
|
|
4
3
|
specPath: string;
|
|
@@ -8,7 +7,7 @@ export interface PlanWriterOptions {
|
|
|
8
7
|
* Build the plan writing prompt that guides the agent through creating
|
|
9
8
|
* a comprehensive implementation plan from an approved spec.
|
|
10
9
|
*
|
|
11
|
-
* Follows
|
|
10
|
+
* Follows supipowers' writing-plans skill:
|
|
12
11
|
* - Scope check
|
|
13
12
|
* - File structure mapping
|
|
14
13
|
* - Bite-sized tasks with TDD steps
|
|
@@ -139,13 +138,11 @@ export function buildPlanWriterPrompt(options: PlanWriterOptions): string {
|
|
|
139
138
|
"",
|
|
140
139
|
"Use `## Chunk N: <name>` headings to delimit chunks. Each chunk should be under 1000 lines and logically self-contained.",
|
|
141
140
|
"",
|
|
142
|
-
"1. Dispatch
|
|
143
|
-
"",
|
|
144
|
-
"
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"",
|
|
148
|
-
"(Replace `<plan-file-path>` with actual path and adjust Chunk number.)",
|
|
141
|
+
"1. Dispatch a plan-document-reviewer sub-agent for each chunk.",
|
|
142
|
+
" The reviewer checks: completeness, spec alignment, task decomposition,",
|
|
143
|
+
" file structure, file size rules, checkbox syntax, and chunk size.",
|
|
144
|
+
" Provide the reviewer with: the plan file path, the spec file path, and the chunk number.",
|
|
145
|
+
|
|
149
146
|
"",
|
|
150
147
|
"2. If **Issues Found**: fix the issues, re-dispatch the reviewer",
|
|
151
148
|
"3. Repeat until **Approved** (max 5 iterations, then surface to human for guidance)",
|
|
@@ -10,7 +10,7 @@ export interface PlanningPromptOptions {
|
|
|
10
10
|
* Build the comprehensive planning prompt that encodes the full brainstorming flow.
|
|
11
11
|
* This is the steering prompt sent to the agent when `/supi:plan` runs.
|
|
12
12
|
*
|
|
13
|
-
* Follows
|
|
13
|
+
* Follows supipowers' brainstorming skill flow:
|
|
14
14
|
* 1. Explore project context
|
|
15
15
|
* 2. Ask clarifying questions (one at a time)
|
|
16
16
|
* 3. Propose 2-3 approaches with trade-offs
|
|
@@ -103,8 +103,6 @@ export function buildPlanningPrompt(options: PlanningPromptOptions): string {
|
|
|
103
103
|
// ── Phase 7: User Gate ───────────────────────────────────────
|
|
104
104
|
"## Phase 7: User Review Gate",
|
|
105
105
|
"",
|
|
106
|
-
"After the spec review loop passes:",
|
|
107
|
-
"",
|
|
108
106
|
"After the spec review loop passes, ask the user to review the spec before proceeding:",
|
|
109
107
|
"",
|
|
110
108
|
'> "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."',
|
|
@@ -137,12 +135,7 @@ export function buildPlanningPrompt(options: PlanningPromptOptions): string {
|
|
|
137
135
|
];
|
|
138
136
|
|
|
139
137
|
if (skillContent) {
|
|
140
|
-
sections.push(
|
|
141
|
-
"## Additional Planning Guidelines",
|
|
142
|
-
"",
|
|
143
|
-
skillContent,
|
|
144
|
-
"",
|
|
145
|
-
);
|
|
138
|
+
sections.push("## Additional Planning Guidelines", "", skillContent, "");
|
|
146
139
|
}
|
|
147
140
|
|
|
148
141
|
return sections.join("\n");
|
|
@@ -152,14 +145,26 @@ export function buildPlanningPrompt(options: PlanningPromptOptions): string {
|
|
|
152
145
|
* Build the quick plan prompt that skips brainstorming.
|
|
153
146
|
* Used when `/supi:plan --quick <description>` is invoked.
|
|
154
147
|
*/
|
|
155
|
-
export function buildQuickPlanPrompt(
|
|
148
|
+
export function buildQuickPlanPrompt(
|
|
149
|
+
description: string,
|
|
150
|
+
skillContent?: string,
|
|
151
|
+
): string {
|
|
156
152
|
const sections: string[] = [
|
|
157
153
|
"Generate a concise implementation plan for the following task.",
|
|
158
154
|
"Skip brainstorming — go straight to task breakdown.",
|
|
159
155
|
"",
|
|
160
156
|
`Task: ${description}`,
|
|
161
157
|
"",
|
|
162
|
-
"Format the plan as markdown with YAML frontmatter
|
|
158
|
+
"Format the plan as markdown with YAML frontmatter:",
|
|
159
|
+
"",
|
|
160
|
+
"```yaml",
|
|
161
|
+
"---",
|
|
162
|
+
"name: <feature-name>",
|
|
163
|
+
"created: YYYY-MM-DD",
|
|
164
|
+
"tags: [tag1, tag2]",
|
|
165
|
+
"---",
|
|
166
|
+
"```",
|
|
167
|
+
"",
|
|
163
168
|
"Each task should have: name, [parallel-safe] or [sequential] annotation,",
|
|
164
169
|
"**files**, **criteria**, and **complexity** (small/medium/large).",
|
|
165
170
|
"",
|
|
@@ -167,11 +172,7 @@ export function buildQuickPlanPrompt(description: string, skillContent?: string)
|
|
|
167
172
|
];
|
|
168
173
|
|
|
169
174
|
if (skillContent) {
|
|
170
|
-
sections.push(
|
|
171
|
-
"",
|
|
172
|
-
"Follow these planning guidelines:",
|
|
173
|
-
skillContent,
|
|
174
|
-
);
|
|
175
|
+
sections.push("", "Follow these planning guidelines:", skillContent);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
return sections.join("\n");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Build the prompt for dispatching a spec document reviewer sub-agent.
|
|
3
|
-
* Follows the same pattern as
|
|
3
|
+
* Follows the same pattern as supipowers' spec-document-reviewer-prompt.md.
|
|
4
4
|
*/
|
|
5
5
|
export function buildSpecReviewerPrompt(specFilePath: string): string {
|
|
6
6
|
return [
|
|
@@ -12,7 +12,7 @@ export function buildSpecReviewerPrompt(specFilePath: string): string {
|
|
|
12
12
|
"",
|
|
13
13
|
"| Category | What to Look For |",
|
|
14
14
|
"|----------|------------------|",
|
|
15
|
-
|
|
15
|
+
'| Completeness | TODO markers, placeholders, "TBD", incomplete sections |',
|
|
16
16
|
"| Coverage | Missing error handling, edge cases, integration points |",
|
|
17
17
|
"| Consistency | Internal contradictions, conflicting requirements |",
|
|
18
18
|
"| Clarity | Ambiguous requirements that could be interpreted multiple ways |",
|