@gajae-code/coding-agent 0.6.4 → 0.7.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/CHANGELOG.md +51 -0
- package/dist/types/async/job-manager.d.ts +3 -1
- package/dist/types/cli/daemon-cli.d.ts +25 -0
- package/dist/types/cli/migrate-cli.d.ts +20 -0
- package/dist/types/cli/notify-cli.d.ts +23 -0
- package/dist/types/cli/setup-cli.d.ts +20 -1
- package/dist/types/commands/daemon.d.ts +41 -0
- package/dist/types/commands/migrate.d.ts +33 -0
- package/dist/types/commands/notify.d.ts +41 -0
- package/dist/types/config/keybindings.d.ts +4 -0
- package/dist/types/config/model-profile-activation.d.ts +12 -0
- package/dist/types/config/model-profiles.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +38 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/daemon/builtin.d.ts +20 -0
- package/dist/types/daemon/control-types.d.ts +57 -0
- package/dist/types/daemon/runtime.d.ts +25 -0
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -2
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
- package/dist/types/gjc-runtime/session-layout.d.ts +59 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +47 -0
- package/dist/types/gjc-runtime/state-graph.d.ts +1 -1
- package/dist/types/gjc-runtime/state-runtime.d.ts +5 -4
- package/dist/types/gjc-runtime/state-schema.d.ts +2 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +38 -7
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +15 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +21 -4
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +1 -1
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +1 -1
- package/dist/types/harness-control-plane/storage.d.ts +2 -1
- package/dist/types/hooks/skill-state.d.ts +12 -4
- package/dist/types/migrate/action-planner.d.ts +11 -0
- package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
- package/dist/types/migrate/adapters/codex.d.ts +5 -0
- package/dist/types/migrate/adapters/index.d.ts +45 -0
- package/dist/types/migrate/adapters/opencode.d.ts +2 -0
- package/dist/types/migrate/executor.d.ts +2 -0
- package/dist/types/migrate/mcp-mapper.d.ts +20 -0
- package/dist/types/migrate/report.d.ts +18 -0
- package/dist/types/migrate/skill-normalizer.d.ts +27 -0
- package/dist/types/migrate/types.d.ts +126 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -1
- package/dist/types/modes/components/oauth-selector.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -2
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/types.d.ts +7 -1
- package/dist/types/notifications/config-commands.d.ts +26 -0
- package/dist/types/notifications/config.d.ts +61 -0
- package/dist/types/notifications/helpers.d.ts +55 -0
- package/dist/types/notifications/html-format.d.ts +62 -0
- package/dist/types/notifications/index.d.ts +28 -0
- package/dist/types/notifications/rate-limit-pool.d.ts +93 -0
- package/dist/types/notifications/telegram-cli.d.ts +19 -0
- package/dist/types/notifications/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/notifications/telegram-daemon-control.d.ts +56 -0
- package/dist/types/notifications/telegram-daemon.d.ts +276 -0
- package/dist/types/notifications/telegram-reference.d.ts +111 -0
- package/dist/types/notifications/threaded-inbound.d.ts +58 -0
- package/dist/types/notifications/threaded-render.d.ts +66 -0
- package/dist/types/notifications/topic-registry.d.ts +67 -0
- package/dist/types/research-plan/index.d.ts +1 -0
- package/dist/types/research-plan/ledger.d.ts +33 -0
- package/dist/types/rlm/artifacts.d.ts +1 -1
- package/dist/types/rlm/index.d.ts +12 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
- package/dist/types/session/agent-session.d.ts +39 -2
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/setup/credential-auto-import.d.ts +63 -0
- package/dist/types/setup/credential-import.d.ts +3 -0
- package/dist/types/setup/host-plugin-setup.d.ts +39 -0
- package/dist/types/skill-state/active-state.d.ts +6 -11
- package/dist/types/skill-state/canonical-skills.d.ts +3 -0
- package/dist/types/skill-state/workflow-hud.d.ts +2 -0
- package/dist/types/task/spawn-gate.d.ts +1 -10
- package/dist/types/tools/ask-answer-registry.d.ts +13 -0
- package/dist/types/tools/index.d.ts +18 -0
- package/dist/types/tools/subagent.d.ts +3 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +3 -0
- package/src/async/job-manager.ts +5 -1
- package/src/cli/daemon-cli.ts +122 -0
- package/src/cli/migrate-cli.ts +106 -0
- package/src/cli/notify-cli.ts +274 -0
- package/src/cli/setup-cli.ts +173 -84
- package/src/cli.ts +3 -0
- package/src/commands/daemon.ts +47 -0
- package/src/commands/deep-interview.ts +2 -2
- package/src/commands/migrate.ts +46 -0
- package/src/commands/notify.ts +61 -0
- package/src/commands/setup.ts +11 -1
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +7 -3
- package/src/config/model-profile-activation.ts +74 -5
- package/src/config/model-profiles.ts +7 -4
- package/src/config/model-registry.ts +6 -3
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +29 -0
- package/src/coordinator/contract.ts +3 -0
- package/src/coordinator-mcp/policy.ts +10 -2
- package/src/coordinator-mcp/server.ts +270 -1
- package/src/daemon/builtin.ts +46 -0
- package/src/daemon/control-types.ts +65 -0
- package/src/daemon/runtime.ts +51 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +0 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +28 -24
- package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
- package/src/defaults/gjc/skills/team/SKILL.md +51 -47
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +33 -13
- package/src/extensibility/custom-commands/loader.ts +0 -7
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +8 -0
- package/src/extensibility/gjc-plugins/injection.ts +23 -4
- package/src/extensibility/gjc-plugins/state.ts +16 -1
- package/src/gjc-runtime/deep-interview-recorder.ts +51 -18
- package/src/gjc-runtime/deep-interview-runtime.ts +49 -23
- package/src/gjc-runtime/goal-mode-request.ts +26 -11
- package/src/gjc-runtime/launch-tmux.ts +6 -1
- package/src/gjc-runtime/ralplan-runtime.ts +79 -50
- package/src/gjc-runtime/session-layout.ts +180 -0
- package/src/gjc-runtime/session-resolution.ts +217 -0
- package/src/gjc-runtime/state-graph.ts +1 -2
- package/src/gjc-runtime/state-migrations.ts +1 -0
- package/src/gjc-runtime/state-runtime.ts +247 -124
- package/src/gjc-runtime/state-schema.ts +2 -0
- package/src/gjc-runtime/state-writer.ts +289 -41
- package/src/gjc-runtime/team-runtime.ts +43 -19
- package/src/gjc-runtime/tmux-sessions.ts +7 -1
- package/src/gjc-runtime/ultragoal-guard.ts +102 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +226 -60
- package/src/gjc-runtime/workflow-command-ref.ts +1 -2
- package/src/gjc-runtime/workflow-manifest.generated.json +27 -2
- package/src/gjc-runtime/workflow-manifest.ts +12 -3
- package/src/goals/tools/goal-tool.ts +11 -2
- package/src/harness-control-plane/storage.ts +14 -4
- package/src/hooks/native-skill-hook.ts +38 -12
- package/src/hooks/skill-state.ts +178 -83
- package/src/internal-urls/docs-index.generated.ts +9 -6
- package/src/main.ts +30 -0
- package/src/migrate/action-planner.ts +318 -0
- package/src/migrate/adapters/claude-code.ts +39 -0
- package/src/migrate/adapters/codex.ts +70 -0
- package/src/migrate/adapters/index.ts +277 -0
- package/src/migrate/adapters/opencode.ts +52 -0
- package/src/migrate/executor.ts +81 -0
- package/src/migrate/mcp-mapper.ts +152 -0
- package/src/migrate/report.ts +104 -0
- package/src/migrate/skill-normalizer.ts +80 -0
- package/src/migrate/types.ts +163 -0
- package/src/modes/acp/acp-event-mapper.ts +1 -0
- package/src/modes/bridge/bridge-mode.ts +2 -2
- package/src/modes/components/custom-editor.ts +30 -20
- package/src/modes/components/hook-editor.ts +7 -2
- package/src/modes/components/oauth-selector.ts +19 -0
- package/src/modes/controllers/event-controller.ts +20 -0
- package/src/modes/controllers/selector-controller.ts +80 -17
- package/src/modes/interactive-mode.ts +6 -2
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/event-contract.ts +1 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +1 -0
- package/src/modes/shared/agent-wire/event-observation.ts +16 -0
- package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
- package/src/modes/shared/agent-wire/unattended-session.ts +22 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/utils/ui-helpers.ts +23 -0
- package/src/notifications/config-commands.ts +50 -0
- package/src/notifications/config.ts +107 -0
- package/src/notifications/helpers.ts +135 -0
- package/src/notifications/html-format.ts +389 -0
- package/src/notifications/index.ts +663 -0
- package/src/notifications/rate-limit-pool.ts +179 -0
- package/src/notifications/telegram-cli.ts +194 -0
- package/src/notifications/telegram-daemon-cli.ts +74 -0
- package/src/notifications/telegram-daemon-control.ts +370 -0
- package/src/notifications/telegram-daemon.ts +1370 -0
- package/src/notifications/telegram-reference.ts +335 -0
- package/src/notifications/threaded-inbound.ts +80 -0
- package/src/notifications/threaded-render.ts +155 -0
- package/src/notifications/topic-registry.ts +133 -0
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/task.md +1 -2
- package/src/research-plan/index.ts +1 -0
- package/src/research-plan/ledger.ts +177 -0
- package/src/rlm/artifacts.ts +12 -3
- package/src/rlm/index.ts +26 -0
- package/src/runtime-mcp/config-writer.ts +46 -0
- package/src/sdk.ts +16 -0
- package/src/session/agent-session.ts +128 -24
- package/src/session/auth-storage.ts +3 -0
- package/src/session/session-dump-format.ts +43 -2
- package/src/session/session-manager.ts +39 -5
- package/src/setup/credential-auto-import.ts +258 -0
- package/src/setup/credential-import.ts +17 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +10 -0
- package/src/setup/hermes-setup.ts +1 -1
- package/src/setup/host-plugin-setup.ts +142 -0
- package/src/skill-state/active-state.ts +72 -108
- package/src/skill-state/canonical-skills.ts +4 -0
- package/src/skill-state/deep-interview-mutation-guard.ts +28 -109
- package/src/skill-state/workflow-hud.ts +4 -2
- package/src/skill-state/workflow-state-contract.ts +3 -3
- package/src/slash-commands/builtin-registry.ts +4 -1
- package/src/task/agents.ts +1 -22
- package/src/task/executor.ts +5 -1
- package/src/task/index.ts +1 -41
- package/src/task/spawn-gate.ts +1 -38
- package/src/task/types.ts +1 -1
- package/src/tools/ask-answer-registry.ts +25 -0
- package/src/tools/ask.ts +108 -16
- package/src/tools/computer.ts +58 -4
- package/src/tools/image-gen.ts +5 -8
- package/src/tools/index.ts +19 -0
- package/src/tools/inspect-image.ts +16 -11
- package/src/tools/subagent-render.ts +7 -0
- package/src/tools/subagent.ts +38 -7
- package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
- package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
- package/src/prompts/agents/explore.md +0 -58
- package/src/prompts/agents/plan.md +0 -49
- package/src/prompts/agents/reviewer.md +0 -141
- package/src/prompts/agents/task.md +0 -16
- package/src/prompts/review-request.md +0 -70
package/src/tools/subagent.ts
CHANGED
|
@@ -17,6 +17,8 @@ const MAX_LIST_LIMIT = 50;
|
|
|
17
17
|
const RECEIPT_PREVIEW_WIDTH = 280;
|
|
18
18
|
const PREVIEW_WIDTH = 2_000;
|
|
19
19
|
const FULL_PREVIEW_WIDTH = 12_000;
|
|
20
|
+
const STEER_QUEUED_GUIDANCE =
|
|
21
|
+
"The steer message is queued for the subagent's next steering boundary and has not necessarily taken effect yet.";
|
|
20
22
|
|
|
21
23
|
const subagentSchema = z.object({
|
|
22
24
|
action: z
|
|
@@ -63,6 +65,9 @@ export interface SubagentSnapshot {
|
|
|
63
65
|
outputRef?: string;
|
|
64
66
|
truncated?: boolean;
|
|
65
67
|
guidance?: string;
|
|
68
|
+
steerMessage?: string;
|
|
69
|
+
steerState?: "queued" | "resume_queued" | "resume_started";
|
|
70
|
+
steerPauseRequested?: boolean;
|
|
66
71
|
/** Live streaming progress for the awaited subagent (await panel only; UI detail). */
|
|
67
72
|
progress?: AgentProgress;
|
|
68
73
|
/** True when a live in-session progress producer exists for this subagent. */
|
|
@@ -240,6 +245,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
240
245
|
}
|
|
241
246
|
const records: SubagentRecord[] = [];
|
|
242
247
|
const missing: SubagentSnapshot[] = [];
|
|
248
|
+
const steerStates = new Map<string, NonNullable<SubagentSnapshot["steerState"]>>();
|
|
243
249
|
const record = this.#findVisibleRecord(manager, id, ownerFilter);
|
|
244
250
|
const verifiedOutputIds = await this.#verifiedOutputIds(record ? [record] : []);
|
|
245
251
|
if (!record) {
|
|
@@ -249,23 +255,41 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
249
255
|
if (record.status === "running") {
|
|
250
256
|
const handle = manager.getLiveHandle(record.subagentId);
|
|
251
257
|
if (!handle) throw new ToolError(`Subagent ${record.subagentId} has no live handle.`);
|
|
252
|
-
|
|
258
|
+
const fromAgentId = this.session.getAgentId?.() ?? undefined;
|
|
259
|
+
await handle.injectMessage(message, "steer", { fromAgentId });
|
|
253
260
|
if (params.pause === true) manager.pauseSubagent(record.subagentId, ownerFilter);
|
|
261
|
+
records.push(manager.getSubagentRecord(record.subagentId, ownerFilter) ?? record);
|
|
262
|
+
steerStates.set(record.subagentId, "queued");
|
|
254
263
|
} else {
|
|
255
264
|
const result = manager.resumeSubagent(record.subagentId, ownerFilter, message);
|
|
256
|
-
if (!result.ok && result.reason === "context_unavailable") throw new ToolError("context unavailable");
|
|
257
265
|
if (!result.ok && result.reason === "not_found") {
|
|
258
266
|
missing.push(this.#missingSnapshot(id, "not_found", "No visible detached subagent matches this id."));
|
|
267
|
+
} else if (!result.ok) {
|
|
268
|
+
throw new ToolError(`Failed to resume subagent ${record.subagentId}: ${result.reason ?? "unknown"}.`);
|
|
259
269
|
} else {
|
|
260
|
-
|
|
270
|
+
const snapshotRecord = manager.getSubagentRecord(record.subagentId, ownerFilter) ?? record;
|
|
271
|
+
records.push(snapshotRecord);
|
|
272
|
+
steerStates.set(
|
|
273
|
+
snapshotRecord.subagentId,
|
|
274
|
+
result.queued === true || result.status === "queued" ? "resume_queued" : "resume_started",
|
|
275
|
+
);
|
|
261
276
|
}
|
|
262
277
|
}
|
|
263
|
-
if (record.status === "running")
|
|
264
|
-
records.push(manager.getSubagentRecord(record.subagentId, ownerFilter) ?? record);
|
|
265
278
|
}
|
|
266
279
|
return this.#buildSnapshotResult(
|
|
267
280
|
[
|
|
268
|
-
...records.map(record =>
|
|
281
|
+
...records.map(record => {
|
|
282
|
+
const snapshot = this.#recordSnapshot(manager, record, false, verbosity, verifiedOutputIds);
|
|
283
|
+
return {
|
|
284
|
+
...snapshot,
|
|
285
|
+
steerMessage: message,
|
|
286
|
+
steerState: steerStates.get(record.subagentId) ?? "queued",
|
|
287
|
+
steerPauseRequested: params.pause === true,
|
|
288
|
+
guidance: snapshot.guidance
|
|
289
|
+
? `${snapshot.guidance} ${STEER_QUEUED_GUIDANCE}`
|
|
290
|
+
: STEER_QUEUED_GUIDANCE,
|
|
291
|
+
};
|
|
292
|
+
}),
|
|
269
293
|
...missing,
|
|
270
294
|
],
|
|
271
295
|
"Subagent steer",
|
|
@@ -288,7 +312,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
288
312
|
if (ids.length === 1) return ids[0]!;
|
|
289
313
|
if (ids.length > 1) {
|
|
290
314
|
throw new ToolError(
|
|
291
|
-
`\`${action}\` accepts exactly one target because \`message\`
|
|
315
|
+
`\`${action}\` accepts exactly one target because \`message\` can be queued for only one subagent.`,
|
|
292
316
|
);
|
|
293
317
|
}
|
|
294
318
|
throw new ToolError(`\`${action}\` requires a single subagent id via \`id\`.`);
|
|
@@ -533,6 +557,10 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
533
557
|
if (snapshot.description) lines.push(`Description: ${snapshot.description}`);
|
|
534
558
|
if (snapshot.outputRef) lines.push(`Output: ${snapshot.outputRef}`);
|
|
535
559
|
if (snapshot.assignment) lines.push("Assignment:", "```", snapshot.assignment, "```");
|
|
560
|
+
if (snapshot.steerMessage) {
|
|
561
|
+
lines.push(`Steer (${snapshot.steerState ?? "queued"}):`, "```", snapshot.steerMessage, "```");
|
|
562
|
+
lines.push(STEER_QUEUED_GUIDANCE);
|
|
563
|
+
}
|
|
536
564
|
if (snapshot.resultPreview) {
|
|
537
565
|
lines.push(snapshot.errorText ? "Error preview:" : "Result preview:", "```", snapshot.resultPreview, "```");
|
|
538
566
|
if (snapshot.truncated)
|
|
@@ -770,6 +798,9 @@ function canonicalizeSnapshotForSignature(snapshot: SubagentSnapshot): unknown {
|
|
|
770
798
|
outputRef: snapshot.outputRef ?? null,
|
|
771
799
|
truncated: snapshot.truncated ?? false,
|
|
772
800
|
guidance: snapshot.guidance ?? null,
|
|
801
|
+
steerMessage: snapshot.steerMessage ?? null,
|
|
802
|
+
steerState: snapshot.steerState ?? null,
|
|
803
|
+
steerPauseRequested: snapshot.steerPauseRequested ?? false,
|
|
773
804
|
liveProgressAvailable: snapshot.liveProgressAvailable ?? null,
|
|
774
805
|
effectiveModel: snapshot.effectiveModel ?? null,
|
|
775
806
|
requestedModel: snapshot.requestedModel ?? null,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { CustomCommand, CustomCommandAPI } from "../../../../extensibility/custom-commands/types";
|
|
2
|
-
import type { HookCommandContext } from "../../../../extensibility/hooks/types";
|
|
3
|
-
export declare class ReviewCommand implements CustomCommand {
|
|
4
|
-
private api;
|
|
5
|
-
name: string;
|
|
6
|
-
description: string;
|
|
7
|
-
constructor(api: CustomCommandAPI);
|
|
8
|
-
execute(args: string[], ctx: HookCommandContext): Promise<string | undefined>;
|
|
9
|
-
}
|
|
10
|
-
export default ReviewCommand;
|
|
@@ -1,456 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* /review command - Interactive code review launcher
|
|
3
|
-
*
|
|
4
|
-
* Provides a menu to select review mode:
|
|
5
|
-
* 1. Review against a base branch (PR style)
|
|
6
|
-
* 2. Review uncommitted changes
|
|
7
|
-
* 3. Review a specific commit
|
|
8
|
-
* 4. Custom review instructions
|
|
9
|
-
*
|
|
10
|
-
* Runs git diff upfront, parses results, filters noise, and provides
|
|
11
|
-
* rich context for the orchestrating agent to distribute work across
|
|
12
|
-
* multiple reviewer agents based on diff weight and locality.
|
|
13
|
-
*/
|
|
14
|
-
import { prompt } from "@gajae-code/utils";
|
|
15
|
-
import type { CustomCommand, CustomCommandAPI } from "../../../../extensibility/custom-commands/types";
|
|
16
|
-
import type { HookCommandContext } from "../../../../extensibility/hooks/types";
|
|
17
|
-
import reviewRequestTemplate from "../../../../prompts/review-request.md" with { type: "text" };
|
|
18
|
-
import * as git from "../../../../utils/git";
|
|
19
|
-
|
|
20
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
-
// Types
|
|
22
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
-
|
|
24
|
-
interface FileDiff {
|
|
25
|
-
path: string;
|
|
26
|
-
linesAdded: number;
|
|
27
|
-
linesRemoved: number;
|
|
28
|
-
hunks: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface DiffStats {
|
|
32
|
-
files: FileDiff[];
|
|
33
|
-
totalAdded: number;
|
|
34
|
-
totalRemoved: number;
|
|
35
|
-
excluded: { path: string; reason: string; linesAdded: number; linesRemoved: number }[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
39
|
-
// Exclusion patterns for noise files
|
|
40
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
41
|
-
|
|
42
|
-
const EXCLUDED_PATTERNS: { pattern: RegExp; reason: string }[] = [
|
|
43
|
-
// Lock files
|
|
44
|
-
{ pattern: /\.lock$/, reason: "lock file" },
|
|
45
|
-
{ pattern: /-lock\.(json|yaml|yml)$/, reason: "lock file" },
|
|
46
|
-
{ pattern: /package-lock\.json$/, reason: "lock file" },
|
|
47
|
-
{ pattern: /yarn\.lock$/, reason: "lock file" },
|
|
48
|
-
{ pattern: /pnpm-lock\.yaml$/, reason: "lock file" },
|
|
49
|
-
{ pattern: /Cargo\.lock$/, reason: "lock file" },
|
|
50
|
-
{ pattern: /Gemfile\.lock$/, reason: "lock file" },
|
|
51
|
-
{ pattern: /poetry\.lock$/, reason: "lock file" },
|
|
52
|
-
{ pattern: /composer\.lock$/, reason: "lock file" },
|
|
53
|
-
{ pattern: /flake\.lock$/, reason: "lock file" },
|
|
54
|
-
|
|
55
|
-
// Generated/build artifacts
|
|
56
|
-
{ pattern: /\.min\.(js|css)$/, reason: "minified" },
|
|
57
|
-
{ pattern: /\.generated\./, reason: "generated" },
|
|
58
|
-
{ pattern: /\.snap$/, reason: "snapshot" },
|
|
59
|
-
{ pattern: /\.map$/, reason: "source map" },
|
|
60
|
-
{ pattern: /^dist\//, reason: "build output" },
|
|
61
|
-
{ pattern: /^build\//, reason: "build output" },
|
|
62
|
-
{ pattern: /^out\//, reason: "build output" },
|
|
63
|
-
{ pattern: /node_modules\//, reason: "vendor" },
|
|
64
|
-
{ pattern: /vendor\//, reason: "vendor" },
|
|
65
|
-
|
|
66
|
-
// Binary/assets (usually shown as binary in diff anyway)
|
|
67
|
-
{ pattern: /\.(png|jpg|jpeg|gif|ico|webp|avif)$/i, reason: "image" },
|
|
68
|
-
{ pattern: /\.(woff|woff2|ttf|eot|otf)$/i, reason: "font" },
|
|
69
|
-
{ pattern: /\.(pdf|zip|tar|gz|rar|7z)$/i, reason: "binary" },
|
|
70
|
-
];
|
|
71
|
-
|
|
72
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
73
|
-
// Diff parsing
|
|
74
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Check if a file path should be excluded from review.
|
|
78
|
-
* Returns the exclusion reason if excluded, undefined otherwise.
|
|
79
|
-
*/
|
|
80
|
-
function getExclusionReason(path: string): string | undefined {
|
|
81
|
-
for (const { pattern, reason } of EXCLUDED_PATTERNS) {
|
|
82
|
-
if (pattern.test(path)) return reason;
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Parse unified diff output into per-file stats.
|
|
89
|
-
* Splits on file boundaries, counts +/- lines, and filters excluded files.
|
|
90
|
-
*/
|
|
91
|
-
function parseDiff(diffOutput: string): DiffStats {
|
|
92
|
-
const files: FileDiff[] = [];
|
|
93
|
-
const excluded: DiffStats["excluded"] = [];
|
|
94
|
-
let totalAdded = 0;
|
|
95
|
-
let totalRemoved = 0;
|
|
96
|
-
|
|
97
|
-
// Split by file boundary: "diff --git a/... b/..."
|
|
98
|
-
const fileChunks = diffOutput.split(/^diff --git /m).filter(Boolean);
|
|
99
|
-
|
|
100
|
-
for (const chunk of fileChunks) {
|
|
101
|
-
// Extract file path from "a/path b/path" line
|
|
102
|
-
const headerMatch = chunk.match(/^a\/(.+?) b\/(.+)/);
|
|
103
|
-
if (!headerMatch) continue;
|
|
104
|
-
|
|
105
|
-
const path = headerMatch[2];
|
|
106
|
-
|
|
107
|
-
// Count added/removed lines (lines starting with + or - but not ++ or --)
|
|
108
|
-
let linesAdded = 0;
|
|
109
|
-
let linesRemoved = 0;
|
|
110
|
-
|
|
111
|
-
const lines = chunk.split("\n");
|
|
112
|
-
for (const line of lines) {
|
|
113
|
-
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
114
|
-
linesAdded++;
|
|
115
|
-
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
116
|
-
linesRemoved++;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const exclusionReason = getExclusionReason(path);
|
|
121
|
-
if (exclusionReason) {
|
|
122
|
-
excluded.push({ path, reason: exclusionReason, linesAdded, linesRemoved });
|
|
123
|
-
} else {
|
|
124
|
-
files.push({
|
|
125
|
-
path,
|
|
126
|
-
linesAdded,
|
|
127
|
-
linesRemoved,
|
|
128
|
-
hunks: `diff --git ${chunk}`,
|
|
129
|
-
});
|
|
130
|
-
totalAdded += linesAdded;
|
|
131
|
-
totalRemoved += linesRemoved;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return { files, totalAdded, totalRemoved, excluded };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Get file extension for display purposes.
|
|
140
|
-
*/
|
|
141
|
-
function getFileExt(path: string): string {
|
|
142
|
-
const match = path.match(/\.([^.]+)$/);
|
|
143
|
-
return match ? match[1] : "";
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Determine recommended number of reviewer agents based on diff weight.
|
|
148
|
-
* Uses total lines changed as the primary metric.
|
|
149
|
-
*/
|
|
150
|
-
function getRecommendedAgentCount(stats: DiffStats): number {
|
|
151
|
-
const totalLines = stats.totalAdded + stats.totalRemoved;
|
|
152
|
-
const fileCount = stats.files.length;
|
|
153
|
-
|
|
154
|
-
// Heuristics:
|
|
155
|
-
// - Tiny (<100 lines or 1-2 files): 1 agent
|
|
156
|
-
// - Small (<500 lines): 1-2 agents
|
|
157
|
-
// - Medium (<2000 lines): 2-4 agents
|
|
158
|
-
// - Large (<5000 lines): 4-8 agents
|
|
159
|
-
// - Huge (>5000 lines): 8-16 agents
|
|
160
|
-
|
|
161
|
-
if (totalLines < 100 || fileCount <= 2) return 1;
|
|
162
|
-
if (totalLines < 500) return Math.min(2, fileCount);
|
|
163
|
-
if (totalLines < 2000) return Math.min(4, Math.ceil(fileCount / 3));
|
|
164
|
-
if (totalLines < 5000) return Math.min(8, Math.ceil(fileCount / 2));
|
|
165
|
-
return Math.min(16, fileCount);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Extract first N lines of actual diff content (excluding headers) for preview.
|
|
170
|
-
*/
|
|
171
|
-
function getDiffPreview(hunks: string, maxLines: number): string {
|
|
172
|
-
const lines = hunks.split("\n");
|
|
173
|
-
const contentLines: string[] = [];
|
|
174
|
-
|
|
175
|
-
for (const line of lines) {
|
|
176
|
-
// Skip diff headers, keep actual content
|
|
177
|
-
if (
|
|
178
|
-
line.startsWith("diff --git") ||
|
|
179
|
-
line.startsWith("index ") ||
|
|
180
|
-
line.startsWith("---") ||
|
|
181
|
-
line.startsWith("+++") ||
|
|
182
|
-
line.startsWith("@@")
|
|
183
|
-
) {
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
contentLines.push(line);
|
|
187
|
-
if (contentLines.length >= maxLines) break;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return contentLines.join("\n");
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Thresholds for diff inclusion
|
|
194
|
-
const MAX_DIFF_CHARS = 50_000; // Don't include diff above this
|
|
195
|
-
const MAX_FILES_FOR_INLINE_DIFF = 20; // Don't include diff if more files than this
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Build the full review prompt with diff stats and distribution guidance.
|
|
199
|
-
*/
|
|
200
|
-
function buildReviewPrompt(mode: string, stats: DiffStats, rawDiff: string, additionalInstructions?: string): string {
|
|
201
|
-
const agentCount = getRecommendedAgentCount(stats);
|
|
202
|
-
const skipDiff = rawDiff.length > MAX_DIFF_CHARS || stats.files.length > MAX_FILES_FOR_INLINE_DIFF;
|
|
203
|
-
const totalLines = stats.totalAdded + stats.totalRemoved;
|
|
204
|
-
const linesPerFile = skipDiff ? Math.max(5, Math.floor(100 / stats.files.length)) : 0;
|
|
205
|
-
|
|
206
|
-
const filesWithExt = stats.files.map(f => ({
|
|
207
|
-
...f,
|
|
208
|
-
ext: getFileExt(f.path),
|
|
209
|
-
hunksPreview: skipDiff ? getDiffPreview(f.hunks, linesPerFile) : "",
|
|
210
|
-
}));
|
|
211
|
-
|
|
212
|
-
return prompt.render(reviewRequestTemplate, {
|
|
213
|
-
mode,
|
|
214
|
-
files: filesWithExt,
|
|
215
|
-
excluded: stats.excluded,
|
|
216
|
-
totalAdded: stats.totalAdded,
|
|
217
|
-
totalRemoved: stats.totalRemoved,
|
|
218
|
-
totalLines,
|
|
219
|
-
agentCount,
|
|
220
|
-
multiAgent: agentCount > 1,
|
|
221
|
-
skipDiff,
|
|
222
|
-
rawDiff: rawDiff.trim(),
|
|
223
|
-
linesPerFile,
|
|
224
|
-
additionalInstructions,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export class ReviewCommand implements CustomCommand {
|
|
229
|
-
name = "review";
|
|
230
|
-
description = "Launch interactive code review";
|
|
231
|
-
|
|
232
|
-
constructor(private api: CustomCommandAPI) {}
|
|
233
|
-
|
|
234
|
-
async execute(args: string[], ctx: HookCommandContext): Promise<string | undefined> {
|
|
235
|
-
if (!ctx.hasUI) {
|
|
236
|
-
const base = "Use the Task tool to run the 'reviewer' agent to review recent code changes.";
|
|
237
|
-
return args.length > 0 ? `${base} Focus: ${args.join(" ")}` : base;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Inline args act as additional instructions appended to the generated prompt.
|
|
241
|
-
// When present, skip option 4 (editor) — the args already provide the instructions.
|
|
242
|
-
const extraInstructions = args.length > 0 ? args.join(" ") : undefined;
|
|
243
|
-
|
|
244
|
-
const menuItems = extraInstructions
|
|
245
|
-
? [
|
|
246
|
-
"1. Review against a base branch (PR Style)",
|
|
247
|
-
"2. Review uncommitted changes",
|
|
248
|
-
"3. Review a specific commit",
|
|
249
|
-
]
|
|
250
|
-
: [
|
|
251
|
-
"1. Review against a base branch (PR Style)",
|
|
252
|
-
"2. Review uncommitted changes",
|
|
253
|
-
"3. Review a specific commit",
|
|
254
|
-
"4. Custom review instructions",
|
|
255
|
-
];
|
|
256
|
-
|
|
257
|
-
const mode = await ctx.ui.select("Review Mode", menuItems);
|
|
258
|
-
|
|
259
|
-
if (!mode) return undefined;
|
|
260
|
-
|
|
261
|
-
const modeNum = parseInt(mode[0], 10);
|
|
262
|
-
|
|
263
|
-
switch (modeNum) {
|
|
264
|
-
case 1: {
|
|
265
|
-
// PR-style review against base branch
|
|
266
|
-
const branches = await getGitBranches(this.api);
|
|
267
|
-
if (branches.length === 0) {
|
|
268
|
-
ctx.ui.notify("No git branches found", "error");
|
|
269
|
-
return undefined;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const baseBranch = await ctx.ui.select("Select base branch to compare against", branches);
|
|
273
|
-
if (!baseBranch) return undefined;
|
|
274
|
-
|
|
275
|
-
const currentBranch = await getCurrentBranch(this.api);
|
|
276
|
-
let diffText: string;
|
|
277
|
-
try {
|
|
278
|
-
diffText = await git.diff(this.api.cwd, { base: `${baseBranch}...${currentBranch}` });
|
|
279
|
-
} catch (err) {
|
|
280
|
-
ctx.ui.notify(`Failed to get diff: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
281
|
-
return undefined;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (!diffText.trim()) {
|
|
285
|
-
ctx.ui.notify(`No changes between ${baseBranch} and ${currentBranch}`, "warning");
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const stats = parseDiff(diffText);
|
|
290
|
-
if (stats.files.length === 0) {
|
|
291
|
-
ctx.ui.notify("No reviewable files (all changes filtered out)", "warning");
|
|
292
|
-
return undefined;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return buildReviewPrompt(
|
|
296
|
-
`Reviewing changes between \`${baseBranch}\` and \`${currentBranch}\` (PR-style)`,
|
|
297
|
-
stats,
|
|
298
|
-
diffText,
|
|
299
|
-
extraInstructions,
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
case 2: {
|
|
304
|
-
// Uncommitted changes - combine staged and unstaged
|
|
305
|
-
const status = await getGitStatus(this.api);
|
|
306
|
-
if (!status.trim()) {
|
|
307
|
-
ctx.ui.notify("No uncommitted changes found", "warning");
|
|
308
|
-
return undefined;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
let unstagedDiff: string;
|
|
312
|
-
let stagedDiff: string;
|
|
313
|
-
try {
|
|
314
|
-
[unstagedDiff, stagedDiff] = await Promise.all([
|
|
315
|
-
git.diff(this.api.cwd),
|
|
316
|
-
git.diff(this.api.cwd, { cached: true }),
|
|
317
|
-
]);
|
|
318
|
-
} catch (err) {
|
|
319
|
-
ctx.ui.notify(`Failed to get diff: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
320
|
-
return undefined;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const combinedDiff = [unstagedDiff, stagedDiff].filter(Boolean).join("\n");
|
|
324
|
-
|
|
325
|
-
if (!combinedDiff.trim()) {
|
|
326
|
-
ctx.ui.notify("No diff content found", "warning");
|
|
327
|
-
return undefined;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const stats = parseDiff(combinedDiff);
|
|
331
|
-
if (stats.files.length === 0) {
|
|
332
|
-
ctx.ui.notify("No reviewable files (all changes filtered out)", "warning");
|
|
333
|
-
return undefined;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return buildReviewPrompt(
|
|
337
|
-
"Reviewing uncommitted changes (staged + unstaged)",
|
|
338
|
-
stats,
|
|
339
|
-
combinedDiff,
|
|
340
|
-
extraInstructions,
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
case 3: {
|
|
345
|
-
// Specific commit
|
|
346
|
-
const commits = await getRecentCommits(this.api, 20);
|
|
347
|
-
if (commits.length === 0) {
|
|
348
|
-
ctx.ui.notify("No commits found", "error");
|
|
349
|
-
return undefined;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const selected = await ctx.ui.select("Select commit to review", commits);
|
|
353
|
-
if (!selected) return undefined;
|
|
354
|
-
|
|
355
|
-
// Extract commit hash from selection (format: "abc1234 message")
|
|
356
|
-
const hash = selected.split(" ")[0];
|
|
357
|
-
|
|
358
|
-
let diffText: string;
|
|
359
|
-
try {
|
|
360
|
-
diffText = await git.show(this.api.cwd, hash, { format: "" });
|
|
361
|
-
} catch (err) {
|
|
362
|
-
ctx.ui.notify(`Failed to get commit: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
363
|
-
return undefined;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (!diffText.trim()) {
|
|
367
|
-
ctx.ui.notify("Commit has no diff content", "warning");
|
|
368
|
-
return undefined;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const stats = parseDiff(diffText);
|
|
372
|
-
if (stats.files.length === 0) {
|
|
373
|
-
ctx.ui.notify("No reviewable files in commit (all changes filtered out)", "warning");
|
|
374
|
-
return undefined;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return buildReviewPrompt(`Reviewing commit \`${hash}\``, stats, diffText, extraInstructions);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
case 4: {
|
|
381
|
-
// Custom instructions - still uses the old approach since user provides context
|
|
382
|
-
const instructions = await ctx.ui.editor("Enter custom review instructions", "Review the following:\n\n");
|
|
383
|
-
if (!instructions?.trim()) return undefined;
|
|
384
|
-
|
|
385
|
-
// For custom, we still try to get current diff for context
|
|
386
|
-
let diffText: string | undefined;
|
|
387
|
-
try {
|
|
388
|
-
diffText = await git.diff(this.api.cwd, { base: "HEAD" });
|
|
389
|
-
} catch {
|
|
390
|
-
diffText = undefined;
|
|
391
|
-
}
|
|
392
|
-
const reviewDiff = diffText?.trim();
|
|
393
|
-
|
|
394
|
-
if (reviewDiff) {
|
|
395
|
-
const stats = parseDiff(reviewDiff);
|
|
396
|
-
// Even if all files filtered, include the custom instructions
|
|
397
|
-
return buildReviewPrompt(
|
|
398
|
-
`Custom review: ${instructions.split("\n")[0].slice(0, 60)}…`,
|
|
399
|
-
stats,
|
|
400
|
-
reviewDiff,
|
|
401
|
-
instructions,
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// No diff available, just pass instructions
|
|
406
|
-
return `## Code Review Request
|
|
407
|
-
|
|
408
|
-
### Mode
|
|
409
|
-
Custom review instructions
|
|
410
|
-
|
|
411
|
-
### Instructions
|
|
412
|
-
|
|
413
|
-
${instructions}
|
|
414
|
-
|
|
415
|
-
Use the Task tool with \`agent: "reviewer"\` to execute this review.`;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
default:
|
|
419
|
-
return undefined;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
async function getGitBranches(api: CustomCommandAPI): Promise<string[]> {
|
|
425
|
-
try {
|
|
426
|
-
return await git.branch.list(api.cwd, { all: true });
|
|
427
|
-
} catch {
|
|
428
|
-
return [];
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
async function getCurrentBranch(api: CustomCommandAPI): Promise<string> {
|
|
433
|
-
try {
|
|
434
|
-
return (await git.branch.current(api.cwd)) ?? "HEAD";
|
|
435
|
-
} catch {
|
|
436
|
-
return "HEAD";
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
async function getGitStatus(api: CustomCommandAPI): Promise<string> {
|
|
441
|
-
try {
|
|
442
|
-
return await git.status(api.cwd);
|
|
443
|
-
} catch {
|
|
444
|
-
return "";
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
async function getRecentCommits(api: CustomCommandAPI, count: number): Promise<string[]> {
|
|
449
|
-
try {
|
|
450
|
-
return await git.log.onelines(api.cwd, count);
|
|
451
|
-
} catch {
|
|
452
|
-
return [];
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
export default ReviewCommand;
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: explore
|
|
3
|
-
description: Fast read-only codebase scout returning compressed context for handoff
|
|
4
|
-
tools: read, search, find, web_search
|
|
5
|
-
model: pi/default
|
|
6
|
-
thinking-level: med
|
|
7
|
-
output:
|
|
8
|
-
properties:
|
|
9
|
-
summary:
|
|
10
|
-
metadata:
|
|
11
|
-
description: Brief summary of findings and conclusions
|
|
12
|
-
type: string
|
|
13
|
-
files:
|
|
14
|
-
metadata:
|
|
15
|
-
description: Files examined with relevant code references
|
|
16
|
-
elements:
|
|
17
|
-
properties:
|
|
18
|
-
path:
|
|
19
|
-
metadata:
|
|
20
|
-
description: Project-relative path or paths to the most relevant code reference(s), optionally suffixed with line ranges like `:12-34` when relevant
|
|
21
|
-
type: string
|
|
22
|
-
description:
|
|
23
|
-
metadata:
|
|
24
|
-
description: Section contents
|
|
25
|
-
type: string
|
|
26
|
-
architecture:
|
|
27
|
-
metadata:
|
|
28
|
-
description: Brief explanation of how pieces connect
|
|
29
|
-
type: string
|
|
30
|
-
hide: true
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
Investigate the codebase rapidly. Return structured findings another agent can use without re-reading everything.
|
|
34
|
-
|
|
35
|
-
<directives>
|
|
36
|
-
- You MUST use tools for broad pattern matching / code search as much as possible.
|
|
37
|
-
- You SHOULD invoke tools in parallel—this is a short investigation, and you are supposed to finish in a few seconds.
|
|
38
|
-
- If a search returns empty results, you MUST try at least one alternate strategy (different pattern, broader path, or AST search) before concluding the target doesn't exist.
|
|
39
|
-
</directives>
|
|
40
|
-
|
|
41
|
-
<thoroughness>
|
|
42
|
-
You MUST infer the thoroughness from the task; default to medium:
|
|
43
|
-
- **Quick**: Targeted lookups, key files only
|
|
44
|
-
- **Medium**: Follow imports, read critical sections
|
|
45
|
-
- **Thorough**: Trace all dependencies, check tests/types.
|
|
46
|
-
</thoroughness>
|
|
47
|
-
|
|
48
|
-
<procedure>
|
|
49
|
-
1. Locate relevant code using tools.
|
|
50
|
-
2. Read key sections (You NEVER read full files unless they're tiny)
|
|
51
|
-
3. Identify types/interfaces/key functions.
|
|
52
|
-
4. Note dependencies between files.
|
|
53
|
-
</procedure>
|
|
54
|
-
|
|
55
|
-
<critical>
|
|
56
|
-
You MUST operate as read-only. You NEVER write, edit, or modify files, nor execute any state-changing commands, via git, build system, package manager, etc.
|
|
57
|
-
You MUST keep going until complete.
|
|
58
|
-
</critical>
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: plan
|
|
3
|
-
description: Software architect for complex multi-file architectural decisions. NOT for simple tasks, single-file changes, or tasks completable in <5 tool calls.
|
|
4
|
-
tools: read, search, find, bash, lsp, web_search, ast_grep
|
|
5
|
-
spawns: explore
|
|
6
|
-
model: pi/default
|
|
7
|
-
thinking-level: high
|
|
8
|
-
hide: true
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
Analyze the codebase and the user's request. Produce a detailed implementation plan.
|
|
12
|
-
|
|
13
|
-
## Phase 1: Understand
|
|
14
|
-
1. Parse requirements precisely
|
|
15
|
-
2. Identify ambiguities; list assumptions
|
|
16
|
-
|
|
17
|
-
## Phase 2: Explore
|
|
18
|
-
1. Find existing patterns via `search`/`find`
|
|
19
|
-
2. Read key files; understand architecture
|
|
20
|
-
3. Trace data flow through relevant paths
|
|
21
|
-
4. Identify types, interfaces, contracts
|
|
22
|
-
5. Note dependencies between components
|
|
23
|
-
|
|
24
|
-
You MUST spawn `explore` agents for independent areas and synthesize findings.
|
|
25
|
-
|
|
26
|
-
## Phase 3: Design
|
|
27
|
-
1. List concrete changes (files, functions, types)
|
|
28
|
-
2. Define sequence and dependencies
|
|
29
|
-
3. Identify edge cases and error conditions
|
|
30
|
-
4. Consider alternatives; justify your choice
|
|
31
|
-
5. Note pitfalls/tricky parts
|
|
32
|
-
|
|
33
|
-
## Phase 4: Produce Plan
|
|
34
|
-
|
|
35
|
-
You MUST write a plan executable without re-exploration.
|
|
36
|
-
|
|
37
|
-
<structure>
|
|
38
|
-
- **Summary**: What to build and why (one paragraph).
|
|
39
|
-
- **Changes**: List concrete changes (files, functions, types), concrete as much as possible. Exact file paths/line ranges where relevant.
|
|
40
|
-
- **Sequence**: List sequence and dependencies between sub-tasks, to schedule them in the best order.
|
|
41
|
-
- **Edge Cases**: List edge cases and error conditions, to be aware of.
|
|
42
|
-
- **Verification**: List verification steps, to be able to verify the correctness.
|
|
43
|
-
- **Critical Files**: List critical files, to be able to read them and understand the codebase.
|
|
44
|
-
</structure>
|
|
45
|
-
|
|
46
|
-
<critical>
|
|
47
|
-
You MUST operate as read-only. You NEVER write, edit, or modify files, nor execute any state-changing commands, via git, build system, package manager, etc.
|
|
48
|
-
You MUST keep going until complete.
|
|
49
|
-
</critical>
|