pi-plans 0.3.0 → 0.3.2
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 +22 -11
- package/agents/ref-analyst.md +18 -0
- package/index.ts +12 -14
- package/package.json +11 -2
- package/references/pi-planning-workflow.md +26 -5
- package/references/state-and-config.md +21 -6
- package/scripts/validate.ts +1 -0
- package/skills/plan-with-refs/SKILL.md +3 -3
- package/src/code-graph/commands.ts +73 -27
- package/src/code-graph/prompts.ts +1 -1
- package/src/config-command.ts +35 -0
- package/src/exec.ts +237 -5
- package/src/guard.ts +14 -1
- package/src/refine-prompts.ts +59 -0
- package/src/refine-ui-state.ts +1 -1
- package/src/refine-ui.ts +1 -1
- package/src/state.ts +17 -1
- package/src/subagent.ts +1 -0
- package/src/termination-prompt.ts +22 -0
- package/tests/analyze-refs.test.ts +265 -0
- package/tests/ask-choice.test.ts +1 -0
- package/tests/code-graph-apply-action.test.ts +173 -0
- package/tests/config-command.test.ts +8 -0
- package/tests/exec-lifecycle.test.ts +137 -0
- package/tests/exec.test.ts +15 -2
- package/tests/goal-wait.test.ts +269 -0
- package/tests/guard.test.ts +27 -1
- package/tests/plans.test.ts +10 -0
- package/tests/refine-prompts.test.ts +35 -1
- package/tests/refine-ui.test.ts +34 -0
- package/tests/state.test.ts +32 -0
- package/tests/subagent.test.ts +22 -0
- package/tools/analyze-refs.ts +263 -0
- package/tools/ask-choice.ts +2 -1
- package/tools/code-graph.ts +25 -2
- package/tools/execute-plan.ts +18 -0
- package/tools/graph-aware-file-tools.ts +2 -2
- package/tools/plans.ts +14 -2
package/README.md
CHANGED
|
@@ -114,11 +114,12 @@ Planning artifacts live under `./docs/pi-plans/YYYY-MM-DD-<topic>/` by default (
|
|
|
114
114
|
|---|---|
|
|
115
115
|
| Planning router + five specialist skills | Start with `/skill:planning` to route to the narrowest matching specialist (`plan-small` → `plan-big`, `debug-and-plan`, `plan-with-refs`) |
|
|
116
116
|
| Choice prompts | `ask_choice`: recommended option first, answers auto-recorded per run; choosing Auto-complete enables recommendation-only answers for later eligible questions in the current planning run, with `/plans-autocomplete-stop` available to take back control. After execution completes, the continuation prompt enters goal-running mode by default: it asks only for the implementation-review loop's termination condition and then keeps refining until the loop ends or the cap is reached. |
|
|
117
|
-
| Refinement rounds | Read-only reviewer/criticizer Pi subagents consolidate findings into the next plan version; delegated runs have standalone `Reviewer`/`Criticizer` progress overlays that close before the tool result returns |
|
|
117
|
+
| Refinement rounds | Read-only reviewer/criticizer Pi subagents consolidate findings into the next plan version; delegated runs have standalone `Reviewer`/`Criticizer` progress overlays that close before the tool result returns; `analyze_refs` shows the same kind of overlay titled `Refs` while per-reference analysis subagents run |
|
|
118
118
|
| Workspace state | Config, runs, decisions, refs, and subagent ledgers in `.git/pi_plans/` (git common dir) |
|
|
119
119
|
| VCC compact | Active planning/execution compaction uses deterministic, no-LLM VCC-style summaries when Pi core emits manual `/compact`, threshold, or overflow events. Summaries use five bracket sections plus a brief transcript, keep a smart recent tail, support `keep:N`, and write VCC details/stats without adding `/pi-vcc` commands. |
|
|
120
120
|
| Visible Refiner overlay | Delegated reviewer/criticizer subagents surface as a named public overlay in the TUI — one `Reviewer`/`Criticizer` panel with per-lane tool progress, full streaming transcript with follow-bottom scroll, Tab-pane focus, retention until the user presses `Esc` after completion, and clean cancelled/timed-out vs completed states. `reviewers: 3` renders three equal-height panes inside the same overlay |
|
|
121
121
|
| Tracked execution | Checklist injected each turn; `[DONE:VC-xxx]` markers drive completion; implementation items report progress with `[I-xxx:implemented]` / `[I-xxx:validating]` markers; the bottom status bar shows lifecycle, `x/y` progress, elapsed time, and input/output token usage in real time |
|
|
122
|
+
| Goal-wait continuation | In TUI/RPC, only a fully settled agent with unpassed VCs and no pending input or compaction gets one hidden wake carrying the latest checklist. Tool turns never queue reminders or consume guard rounds. The status bar shows progress; 3 no-progress cycles or 6 waiting cycles pause continuation. User interruption and final model errors also pause it. Only genuine user input or `/plans-execute` resumes; extension messages cannot. Print/JSON single-shot sessions track progress without automatic wakes. `/plans-stop` terminates execution |
|
|
122
123
|
| Execution handoff | The accepted plan resumes in the current session model; no separate model selection is performed. |
|
|
123
124
|
| Execution-phase compaction | Pi core owns scheduling; pi-plans maps the active plan path, current `I-###`, implementation IDs, and remaining `VC-###` checklist into the VCC sections. The old current-I proactive trigger and model-generated summary path are removed. |
|
|
124
125
|
| Planning-phase compaction | During `run.status=planning` with no active execution, pi-plans maps active run, artifact directory, latest plan path from session entries, and observed current-I markers into the VCC sections. Without an active planning run, compaction returns to Pi core. |
|
|
@@ -129,13 +130,14 @@ Planning artifacts live under `./docs/pi-plans/YYYY-MM-DD-<topic>/` by default (
|
|
|
129
130
|
|
|
130
131
|
| Tool / Command | Purpose |
|
|
131
132
|
|---|---|
|
|
132
|
-
| `plans` | State CLI: `init`, `show`, `set-language`, `set-artifact-root`, `set-role`, `start-run`, `set-status`, `record-decision`, `record-ref`, `record-subagent` |
|
|
133
|
+
| `plans` | State CLI: `init`, `show`, `set-language`, `set-artifact-root`, `set-refs-root`, `set-role`, `start-run`, `set-status`, `record-decision`, `record-ref`, `record-subagent` |
|
|
133
134
|
| `ask_choice` | Numbered choice prompt; `autoComplete: false` for the merged accept/execute question and external-state questions |
|
|
134
135
|
| `refine` | Reviewer/criticizer round via standalone read-only subagents (`--mode json -p --no-session --tools read,grep,find,ls`, plus `code_graph` for both roles when the workspace has the code graph enabled); `target: "plan"` (default) reviews the plan, `target: "implementation"` reviews the implemented worktree against the plan; delegated TUI runs show one `Reviewer`/`Criticizer` overlay (78% width × 78% height, top-center, ≥72 cols) with per-lane transcript, follow-bottom scroll, Tab focus, and retention until `Esc`; `reviewers: 3` renders three equal-height panes; enforces role/model confirmation gates |
|
|
136
|
+
| `analyze_refs` | plan-with-refs reference analysis: one independent read-only subagent per downloaded reference (cwd = the ref directory), reusing the reviewer role gates and the concurrent overlay (titled `Refs`); batches of at most 3 lanes run sequentially; returns structured per-reference sections for `REF_ANALYSIS.md` |
|
|
135
137
|
| `execute_plan` | Execution handoff: re-confirms with the user and enters extension-managed execution mode |
|
|
136
138
|
| `/plans` | Show config, active run, and execution progress |
|
|
137
|
-
| `/config-pi-plans` | Re-ask workspace defaults for language, artifact root, code graph, reviewer mode/model, and criticizer mode/model |
|
|
138
|
-
| `/plans-execute [plan.md]` |
|
|
139
|
+
| `/config-pi-plans` | Re-ask workspace defaults for language, artifact root, refs root, code graph, reviewer mode/model, and criticizer mode/model |
|
|
140
|
+
| `/plans-execute [plan.md]` | Resume a paused active execution without losing verified progress; otherwise enter the explicit execution handoff (defaults to highest `PLAN_vN.md`) |
|
|
139
141
|
| `/update-plan [plan.md] [reason…]` | Interrupt-and-refine: stops execution (if any), returns the run to planning, and directs the agent to revise the plan into `PLAN_vN+1.md` while preserving verified work |
|
|
140
142
|
| `/plans-autocomplete-stop` | Stop the current run's Auto-complete mode and return later planning questions to normal interaction |
|
|
141
143
|
| `/plans-stop` | Stop execution mode |
|
|
@@ -155,7 +157,7 @@ Pi core remains the owner of compaction scheduling: manual `/compact`, threshold
|
|
|
155
157
|
|
|
156
158
|
## Visible Refiner overlay
|
|
157
159
|
|
|
158
|
-
Delegated `refine` rounds (reviewer or criticizer) show their progress directly inside the Pi TUI instead of disappearing into the child process's terminal. The overlay is a public, named panel so users always know who is doing what:
|
|
160
|
+
Delegated `refine` rounds (reviewer or criticizer) and `analyze_refs` rounds (titled `Refs`) show their progress directly inside the Pi TUI instead of disappearing into the child process's terminal. The overlay is a public, named panel so users always know who is doing what:
|
|
159
161
|
|
|
160
162
|
- **Pi-btw-aligned geometry.** Each round uses `width: "78%"`, `minWidth: 72`, `maxHeight: "78%"`, `anchor: "top-center"`, and `{ top: 1, left: 2, right: 2 }` margins (no dependency on `pi-btw`; the renderer is built on Pi's public `pi-tui` primitives).
|
|
161
163
|
- **Complete streaming transcript.** Assistant text, thinking blocks, tool calls, tool results, and stderr are merged per turn/content block into lane entries without overlay-facing truncation; only the viewport slices them. Final `message_end` / `tool_execution_end` overwrite the live snapshot with the authoritative content.
|
|
@@ -248,18 +250,27 @@ read, and each function retains its full UTF-8 source.
|
|
|
248
250
|
config unreadable) are marked in the result; refiner and criticizer
|
|
249
251
|
subagents get the `code_graph` tool in their allowlist (verified in headless
|
|
250
252
|
no-session children); the executor loop
|
|
251
|
-
becomes DB-first: `code_graph` mutations →
|
|
252
|
-
|
|
253
|
+
becomes DB-first: `code_graph` mutations → `code_graph apply` (agent-side
|
|
254
|
+
materialization; its result carries counts and the post-apply drift
|
|
255
|
+
summary) → `plans final-commit` → `/init-graph`.
|
|
253
256
|
- The `code_graph` tool provides read-only screening (`status`, `screening`,
|
|
254
257
|
`get-function`, `manifest`), DB-first mutations (`update-function`,
|
|
255
258
|
`update-file`, `delete-file` — all mark files `pending_materialization`
|
|
256
|
-
and append to `change_log`),
|
|
259
|
+
and append to `change_log`), `list-pending`, and the agent-invokable
|
|
260
|
+
`apply` action (same planning/accepted gate as `/apply-graph`; also
|
|
261
|
+
refused for read-only refiner subagents via the `PI_PLANS_REFINER` env
|
|
262
|
+
marker; returns per-file counts plus a post-apply drift summary without
|
|
263
|
+
changing run status) so agents can navigate, stage, materialize, and
|
|
257
264
|
edit the graph without pulling `full_code`.
|
|
258
265
|
|
|
259
266
|
Runtime requirements: the base extension still requires Node ≥ 22.6; the
|
|
260
267
|
graph feature additionally requires Node ≥ 22.13 (or `--experimental-sqlite`)
|
|
261
268
|
so that `node:sqlite` is available without flag. Pi's host currently ships
|
|
262
|
-
Node ≥ 22.19, so a fresh install works out of the box.
|
|
269
|
+
Node ≥ 22.19, so a fresh install works out of the box. The code graph also
|
|
270
|
+
needs the optional `tree-sitter` parser packages, which are **not** installed
|
|
271
|
+
automatically — add them to the workspace (or global tree) where pi runs:
|
|
272
|
+
`npm i tree-sitter tree-sitter-javascript tree-sitter-typescript tree-sitter-python`. Without them, planning and execution work normally and graph
|
|
273
|
+
tools report which package is missing. On unsupported
|
|
263
274
|
runtimes (Bun, missing parsers) graph commands fail locally without
|
|
264
275
|
affecting the planning workflow.
|
|
265
276
|
|
|
@@ -280,7 +291,7 @@ pi-plans/
|
|
|
280
291
|
|
|
281
292
|
## Safety model
|
|
282
293
|
|
|
283
|
-
Before the approved handoff the workflow writes only `.git/pi_plans/` state, the run's artifact directory,
|
|
294
|
+
Before the approved handoff the workflow writes only `.git/pi_plans/` state, the run's artifact directory, `~/.cache/pi-plans/`, and the configured refs root (set via `plans set-refs-root` or `/config-pi-plans`; the recommended `.git/pi-plans/refs/` lives inside the git dir and needs no extra guard) — the extension blocks `edit`/`write` elsewhere while a run is `planning`/`accepted` (bash stays discipline-bound: inspection, `git init`, downloads into the cache). Reviewer/criticizer/ref-analyst subagents run with read-only tools. `Auto-complete` may answer planning and refinement questions only; it is never offered for execution, installs, publishing, deployment, merge, push, or credential use, and non-interactive sessions stop instead of auto-approving those.
|
|
284
295
|
|
|
285
296
|
## Verification
|
|
286
297
|
|
|
@@ -306,7 +317,7 @@ Planning and refinement choices only (the recommended option). Choosing Auto-com
|
|
|
306
317
|
|
|
307
318
|
**Where does all the state live?**
|
|
308
319
|
|
|
309
|
-
Preferences and run ledgers in `.git/pi_plans/` inside your workspace's git directory (never tracked, never published); plan artifacts under the configured artifact root (default `./docs/pi-plans/`);
|
|
320
|
+
Preferences and run ledgers in `.git/pi_plans/` inside your workspace's git directory (never tracked, never published); plan artifacts under the configured artifact root (default `./docs/pi-plans/`); reference downloads under the configured refs root — asked once per workspace (recommended `.git/pi-plans/refs/`), changeable via `plans set-refs-root` or `/config-pi-plans`.
|
|
310
321
|
|
|
311
322
|
**How is this different from just prompting an AI to make changes?**
|
|
312
323
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-plans-ref-analyst
|
|
3
|
+
description: Read-only reference analyst for pi-plans plan-with-refs runs; deep-reads one downloaded reference and extracts adoptable ideas for the target repository.
|
|
4
|
+
tools: read, grep, find, ls
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are a read-only reference analyst in the pi-plans plan-with-refs workflow.
|
|
8
|
+
|
|
9
|
+
Rules:
|
|
10
|
+
|
|
11
|
+
- Perform read-only analysis. Never edit, write, or delete any file.
|
|
12
|
+
- Your working directory is the local copy of ONE downloaded reference. Deep-read it: entry points, README/docs, core modules, tests, and configuration.
|
|
13
|
+
- Judge the reference through the lens of the target repository described in your task: what is worth borrowing, what is not, and why.
|
|
14
|
+
- Every claim needs evidence: a file path inside the reference (with line numbers when quoting). No evidence, no claim.
|
|
15
|
+
- You are evidence, not authority: state what you verified, not what you assume.
|
|
16
|
+
- Stay inside the reference directory; do not wander the filesystem.
|
|
17
|
+
|
|
18
|
+
Output structured Markdown in exactly the seven sections your task specifies, in that order, with no extra top-level sections.
|
package/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
drainExecutionFlush,
|
|
24
24
|
executionContextMessage,
|
|
25
25
|
filterExecutionResumeMessages,
|
|
26
|
+
filterGoalWaitMessages,
|
|
26
27
|
filterPlanningResumeMessages,
|
|
27
28
|
getExecution,
|
|
28
29
|
handleExecutionBeforeCompact,
|
|
@@ -67,9 +68,10 @@ import { latestPlanVersion, nextPlanVersionPath } from "./src/plan.ts";
|
|
|
67
68
|
import { configPiPlansCommand } from "./src/config-command.ts";
|
|
68
69
|
import { getRun, loadConfig, readActive, recordDecision, resolveStateRootOrNull, setRunStatus } from "./src/state.ts";
|
|
69
70
|
import { registerAskChoiceTool } from "./tools/ask-choice.ts";
|
|
70
|
-
import {
|
|
71
|
+
import { executeCommand, registerExecutePlanTool } from "./tools/execute-plan.ts";
|
|
71
72
|
import { registerPlansTool } from "./tools/plans.ts";
|
|
72
73
|
import { registerRefineTool } from "./tools/refine.ts";
|
|
74
|
+
import { registerAnalyzeRefsTool } from "./tools/analyze-refs.ts";
|
|
73
75
|
|
|
74
76
|
const baseDir = dirname(fileURLToPath(import.meta.url));
|
|
75
77
|
|
|
@@ -115,6 +117,7 @@ export default function piPlansExtension(pi: ExtensionAPI): void {
|
|
|
115
117
|
registerPlansTool(pi);
|
|
116
118
|
registerAskChoiceTool(pi);
|
|
117
119
|
registerRefineTool(pi, baseDir);
|
|
120
|
+
registerAnalyzeRefsTool(pi, baseDir);
|
|
118
121
|
registerExecutePlanTool(pi);
|
|
119
122
|
registerQueryInterviewHooks(pi, hasActivePlanningWorkflow);
|
|
120
123
|
registerCodeGraphTool(pi);
|
|
@@ -198,20 +201,20 @@ export default function piPlansExtension(pi: ExtensionAPI): void {
|
|
|
198
201
|
}
|
|
199
202
|
if (!graphEnabled) return;
|
|
200
203
|
if (event.toolName === "edit" || event.toolName === "write") {
|
|
201
|
-
ctx.ui?.notify?.("code-graph: source edited directly — run /update-graph to sync the graph, or use code_graph mutations +
|
|
204
|
+
ctx.ui?.notify?.("code-graph: source edited directly — run /update-graph to sync the graph, or use code_graph mutations + code_graph apply for DB-first edits", "info");
|
|
202
205
|
return;
|
|
203
206
|
}
|
|
204
207
|
if (event.toolName === "code_graph") {
|
|
205
208
|
const action = String((event.input as { action?: string }).action ?? "");
|
|
206
209
|
if (action === "update-function" || action === "update-file" || action === "delete-file") {
|
|
207
|
-
ctx.ui?.notify?.("code-graph: mutation staged — run
|
|
210
|
+
ctx.ui?.notify?.("code-graph: mutation staged — run code_graph apply to materialize (its result includes the post-apply drift summary)", "info");
|
|
208
211
|
}
|
|
209
212
|
}
|
|
210
213
|
});
|
|
211
214
|
|
|
212
215
|
pi.on("context", (event) => {
|
|
213
216
|
const filteredExecution = filterExecutionResumeMessages(event.messages as Array<{ customType?: string }>);
|
|
214
|
-
const messages = filterPlanningResumeMessages(filteredExecution);
|
|
217
|
+
const messages = filterGoalWaitMessages(filterPlanningResumeMessages(filteredExecution));
|
|
215
218
|
if (messages.length !== event.messages.length) {
|
|
216
219
|
return { messages };
|
|
217
220
|
}
|
|
@@ -234,14 +237,6 @@ export default function piPlansExtension(pi: ExtensionAPI): void {
|
|
|
234
237
|
noteCompactionEnded(ctx, event.customInstructions);
|
|
235
238
|
});
|
|
236
239
|
|
|
237
|
-
// Flush points for deferred execution-loop writes: primary drain when the
|
|
238
|
-
// agent run fully settles, backstop drain at the next run's start (covers
|
|
239
|
-
// continuation paths that might not emit agent_settled), plus the forced
|
|
240
|
-
// synchronous flush inside stop/complete.
|
|
241
|
-
pi.on("agent_settled", async (_event, ctx) => {
|
|
242
|
-
drainExecutionFlush(pi, ctx);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
240
|
// -----------------------------------------------------------------------
|
|
246
241
|
// Execution loop: inject remaining checklist each turn, track markers.
|
|
247
242
|
// -----------------------------------------------------------------------
|
|
@@ -382,7 +377,7 @@ export default function piPlansExtension(pi: ExtensionAPI): void {
|
|
|
382
377
|
description: "Execute handoff: enter tracked execution mode for an accepted plan",
|
|
383
378
|
handler: async (args, ctx) => {
|
|
384
379
|
const planPath = args.trim() || undefined;
|
|
385
|
-
const outcome = await
|
|
380
|
+
const outcome = await executeCommand(ctx, planPath);
|
|
386
381
|
ctx.ui.notify(outcome.message, outcome.status === "error" ? "error" : "info");
|
|
387
382
|
},
|
|
388
383
|
});
|
|
@@ -537,8 +532,11 @@ export default function piPlansExtension(pi: ExtensionAPI): void {
|
|
|
537
532
|
// -----------------------------------------------------------------------
|
|
538
533
|
// Session lifecycle
|
|
539
534
|
// -----------------------------------------------------------------------
|
|
535
|
+
pi.on("session_tree", async (_event, ctx) => {
|
|
536
|
+
await restoreFromSession(pi, ctx, ctx.sessionManager.getBranch() as unknown as Parameters<typeof restoreFromSession>[2]);
|
|
537
|
+
});
|
|
540
538
|
pi.on("session_start", async (_event, ctx) => {
|
|
541
|
-
await restoreFromSession(pi, ctx, ctx.sessionManager.
|
|
539
|
+
await restoreFromSession(pi, ctx, ctx.sessionManager.getBranch() as unknown as Parameters<typeof restoreFromSession>[2]);
|
|
542
540
|
restoreAutoCompleteFromSession(ctx, ctx.sessionManager.getEntries() as unknown as Parameters<typeof restoreAutoCompleteFromSession>[1]);
|
|
543
541
|
});
|
|
544
542
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-plans",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Human-in-the-loop planning extension for the Pi coding agent: researched, refined Markdown plans before any code changes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -55,10 +55,19 @@
|
|
|
55
55
|
"test": "node --experimental-strip-types scripts/run-tests.ts",
|
|
56
56
|
"prepack": "npm run validate && npm test"
|
|
57
57
|
},
|
|
58
|
-
"dependencies": {
|
|
58
|
+
"dependencies": {},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@earendil-works/pi-ai": "0.84.4",
|
|
61
|
+
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
62
|
+
"@earendil-works/pi-server": "0.84.4",
|
|
63
|
+
"@earendil-works/pi-tui": "0.84.4",
|
|
64
|
+
"typebox": "1.3.7",
|
|
59
65
|
"tree-sitter": "^0.25.1",
|
|
60
66
|
"tree-sitter-javascript": "^0.25.0",
|
|
61
67
|
"tree-sitter-python": "^0.25.0",
|
|
62
68
|
"tree-sitter-typescript": "^0.23.2"
|
|
69
|
+
},
|
|
70
|
+
"overrides": {
|
|
71
|
+
"tree-sitter": "^0.25.1"
|
|
63
72
|
}
|
|
64
73
|
}
|
|
@@ -8,18 +8,18 @@ This skill set is written for the Pi coding agent's documented behavior:
|
|
|
8
8
|
|
|
9
9
|
- the five skills are contributed by the pi-plans extension and loaded as Pi skills (also invokable as `/skill:<name>`);
|
|
10
10
|
- skill references and helper sources are resolved relative to the directory containing `SKILL.md`;
|
|
11
|
-
- the extension
|
|
12
|
-
- `refine` spawns read-only Pi subagents (`pi --mode json -p --no-session --tools read,grep,find,ls`, plus `code_graph` for both roles when workspace `graph_enabled` is true) with isolated context; delegated Reviewer/Criticizer runs show a standalone aggregate overlay titled `Reviewer` or `Criticizer` (78% × 78% top-center, ≥72 cols, no input row), stream assistant/thinking/tool events into per-lane transcripts with follow-bottom scroll, dismiss on `Esc` (close-only — the refiner child keeps running and its result still flows back as tool output), replace any retained finished overlay when a new round begins, and return conclusions to the main session as tool output;
|
|
13
|
-
- when graph mode is enabled, graph-aware `read`/`edit` overrides are active for indexed source files: `read` returns a capped function digest (≤50 lines, synthetic anonymous entries folded) by default — drill in via `offset/limit` or `code_graph get-function`, and `full: true` is the only whole-file exit (small/zero-function files return full text; safety truncation matches native read); `write`/`edit` stage DB-first mutations until
|
|
11
|
+
- Planning and reference analysis run with the extension tools `plans`, `ask_choice`, `refine`, `analyze_refs`, and `execute_plan`;
|
|
12
|
+
- `refine` spawns read-only Pi subagents (`pi --mode json -p --no-session --tools read,grep,find,ls`, plus `code_graph` for both roles when workspace `graph_enabled` is true) with isolated context; delegated Reviewer/Criticizer runs show a standalone aggregate overlay titled `Reviewer` or `Criticizer` (78% × 78% top-center, ≥72 cols, no input row), stream assistant/thinking/tool events into per-lane transcripts with follow-bottom scroll, dismiss on `Esc` (close-only — the refiner child keeps running and its result still flows back as tool output), replace any retained finished overlay when a new round begins, and return conclusions to the main session as tool output; `analyze_refs` spawns one read-only subagent per downloaded reference (cwd = that ref's directory) reusing the reviewer role gates, shows the same overlay titled `Refs` in batches of at most 3 lanes, and returns structured per-reference sections for `REF_ANALYSIS.md`;
|
|
13
|
+
- when graph mode is enabled, graph-aware `read`/`edit` overrides are active for indexed source files: `read` returns a capped function digest (≤50 lines, synthetic anonymous entries folded) by default — drill in via `offset/limit` or `code_graph get-function`, and `full: true` is the only whole-file exit (small/zero-function files return full text; safety truncation matches native read); `write`/`edit` stage DB-first mutations until materialized via the `code_graph` tool's `apply` action (same planning/accepted gate as /apply-graph; refused for read-only refiner subagents via the PI_PLANS_REFINER marker; returns a per-file report with counts and a post-apply drift summary, and never changes run status); unexpected fallbacks (`not indexed` / `runtime unavailable` / `config read failed`) are marked at the top of the result while flag-off fallbacks stay unmarked;
|
|
14
14
|
- the execution loop is extension-managed: remaining verifier items are injected each turn, implementation items emit `[I-###:current]`/`[I-###:implemented|validating]`, and `[DONE:VC-xxx]` markers are tracked with a bottom status bar;
|
|
15
15
|
- execution and planning compaction keep Pi's SessionManager as the history owner; during active pi-plans runs, `session_before_compact` uses a deterministic no-LLM VCC-style summary with `[Session Goal]`, `[Files And Changes]`, `[Commits]`, `[Outstanding Context]`, `[User Preferences]`, and a ranked brief transcript; Pi core owns manual `/compact`, threshold, and overflow scheduling, while pi-plans handles smart tail keep, `keep:N`, stats, and phase-specific run/plan/current-I/checklist context;
|
|
16
16
|
|
|
17
17
|
## Planning Boundary
|
|
18
18
|
|
|
19
19
|
- Treat the user's request as a planning target, not as write authorization.
|
|
20
|
-
- Before the execution handoff, do not edit target source files, docs, configs, package metadata, generated assets, or tests outside the planning artifact directory and the pi-plans state under `.git/pi_plans/`. The extension enforces this for `edit` and `write` while a run is active: only `.git/pi_plans/`, the run's artifact directory,
|
|
20
|
+
- Before the execution handoff, do not edit target source files, docs, configs, package metadata, generated assets, or tests outside the planning artifact directory and the pi-plans state under `.git/pi_plans/`. The extension enforces this for `edit` and `write` while a run is active: only `.git/pi_plans/`, the run's artifact directory, `~/.cache/pi-plans/`, and the configured refs root are writable. Bash is not machine-guarded — keep it read-only by discipline (inspection, `git init`, downloads into the cache).
|
|
21
21
|
- The normal pre-handoff writes are `.git/pi_plans/` state plus planning artifacts under the configured artifact root (default `./docs/pi-plans/...`).
|
|
22
|
-
-
|
|
22
|
+
- Downloaded references go to the workspace's configured refs root (`refs_root` in `.git/pi_plans/config.json`; unset → ask once via `ask_choice`, recommended `.git/pi-plans/refs/`, second `./refs/`, third `~/.cache/pi-plans/refs/`; persist with the `plans` tool, `set-refs-root`) and their paths and evidence are recorded in `REF_ANALYSIS.md`.
|
|
23
23
|
- After the user explicitly approves the execution handoff, leave this planning workflow and execute in the extension-managed loop (see Execution Handoff).
|
|
24
24
|
|
|
25
25
|
## State And Settings
|
|
@@ -137,6 +137,27 @@ When the user picks `✓ Accept PLAN_vN and execute it now` in the merged questi
|
|
|
137
137
|
|
|
138
138
|
If the user declines, stay in planning (or stop, per their choice). Never start implementation without the approved handoff.
|
|
139
139
|
|
|
140
|
+
### Execution Goal-Wait
|
|
141
|
+
|
|
142
|
+
In TUI/RPC, automatic goal-wait is evaluated only at `agent_settled`, after
|
|
143
|
+
Pi has finished natural tool continuation, retries, and compaction. The
|
|
144
|
+
extension rechecks that the same execution is active and incomplete, the
|
|
145
|
+
session is idle, and neither pending input nor compaction owns continuation.
|
|
146
|
+
Each eligible settled cycle can send at most one hidden custom message with
|
|
147
|
+
the current execution rules and remaining VC checklist. Tool `turn_end`
|
|
148
|
+
events only update progress; they never prequeue goal-wait reminders.
|
|
149
|
+
|
|
150
|
+
No-progress and literal `waiting for` counters advance only on eligible
|
|
151
|
+
settled cycles. Real marker progress resets both; thresholds remain 3 and 6.
|
|
152
|
+
User interruption and final model errors also pause continuation. Genuine
|
|
153
|
+
interactive/RPC user input or `/plans-execute` can resume a paused active
|
|
154
|
+
execution without losing verified VCs; extension input cannot unpause it.
|
|
155
|
+
New-plan handoffs and the `execute_plan` tool still require explicit approval.
|
|
156
|
+
Completion, stop, and session replacement invalidate the extension's wake
|
|
157
|
+
identity without clearing user or other-extension queues. Print/JSON
|
|
158
|
+
single-shot sessions keep VC tracking and completion but never auto-wake;
|
|
159
|
+
use RPC for persistent headless execution.
|
|
160
|
+
|
|
140
161
|
### Post-Execution Continuation
|
|
141
162
|
|
|
142
163
|
When execution completes in an interactive session, the completion message attaches a goal-running continuation block and triggers a new agent turn so the model can enter the implementation-review loop immediately. The interactive-only trigger keeps headless sessions silent (no unconsented subagent cost). The same behavior applies on both completion call sites (the normal `turn_end` completion and the `restoreFromSession` recovery path).
|
|
@@ -27,7 +27,7 @@ Bare repositories are refused with a clear error. A missing `git` executable is
|
|
|
27
27
|
config.json
|
|
28
28
|
pi-vcc-config.json
|
|
29
29
|
active.json
|
|
30
|
-
runs/
|
|
30
|
+
runs/ # note: the refs root is a sibling — .git/pi-plans/refs (hyphenated), not under pi_plans/
|
|
31
31
|
<run-id>/
|
|
32
32
|
run.json
|
|
33
33
|
decisions.jsonl
|
|
@@ -37,7 +37,7 @@ Bare repositories are refused with a clear error. A missing `git` executable is
|
|
|
37
37
|
cache/
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
`config.json` is stable workspace preference state. `pi-vcc-config.json` is the repo-private compaction config used only by pi-plans' VCC-style compact hook. `active.json` and `runs/` are run state.
|
|
40
|
+
`config.json` is stable workspace preference state. `pi-vcc-config.json` is the repo-private compaction config used only by pi-plans' VCC-style compact hook. `active.json` and `runs/` are run state. Reference downloads go to the configured `refs_root` (asked once per workspace when unset; the recommended `.git/pi-plans/refs/` sits inside the git dir so git never tracks it), with metadata recorded in the run state and public artifacts.
|
|
41
41
|
|
|
42
42
|
## Config Schema
|
|
43
43
|
|
|
@@ -61,7 +61,10 @@ The default config is:
|
|
|
61
61
|
},
|
|
62
62
|
"artifact_root": "./docs/pi-plans",
|
|
63
63
|
"artifact_root_source": "unset",
|
|
64
|
-
"artifact_root_updated_at": null
|
|
64
|
+
"artifact_root_updated_at": null,
|
|
65
|
+
"refs_root": null,
|
|
66
|
+
"refs_root_source": "unset",
|
|
67
|
+
"refs_root_updated_at": null
|
|
65
68
|
}
|
|
66
69
|
```
|
|
67
70
|
|
|
@@ -75,6 +78,7 @@ Rules:
|
|
|
75
78
|
- `artifact_root` is relative to the target workspace unless absolute.
|
|
76
79
|
- `artifact_root_source` is `user`, `auto`, or `unset`.
|
|
77
80
|
- `artifact_root_updated_at` is the selection timestamp or `null` before confirmation.
|
|
81
|
+
- `refs_root` is where plan-with-refs downloads references, relative to the target workspace unless absolute, or `null` before selection; `refs_root_source` is `user`, `auto`, or `unset`; `refs_root_updated_at` is the selection timestamp or `null`.
|
|
78
82
|
- There is intentionally no `effort` field: subagents inherit the dispatching session's model and thinking level unless an exact selector is stored. The real lever is the main session's thinking level at refine time.
|
|
79
83
|
|
|
80
84
|
## VCC Compact Config
|
|
@@ -115,11 +119,11 @@ Persist with `plans` (`set-language`, `languageSource: "user"`). Use the selecte
|
|
|
115
119
|
|
|
116
120
|
## Code Graph Enabled
|
|
117
121
|
|
|
118
|
-
`graph_enabled` (`boolean | null`) records whether the workspace wants graph-aware read/write/edit wrappers and `code_graph` mutations for indexed source files. `null` means the question was never asked: the first `plans` `init`/`show` in a workspace returns a `hint` instructing the agent to ask the user once via `ask_choice` (recommended: yes) and persist with the `plans` tool (`set-graph-enabled`, `enabled: true|false`). This question does not count against the planning-question limit. `/enable-graph` and `/disable-graph` toggle it later; disable refuses while graph drift is dirty.
|
|
122
|
+
`graph_enabled` (`boolean | null`) records whether the workspace wants graph-aware read/write/edit wrappers and `code_graph` mutations for indexed source files. `null` means the question was never asked: the first `plans` `init`/`show` in a workspace returns a `hint` instructing the agent to ask the user once via `ask_choice` (recommended: yes) and persist with the `plans` tool (`set-graph-enabled`, `enabled: true|false`). This question does not count against the planning-question limit. `/enable-graph` and `/disable-graph` toggle it later; disable refuses while graph drift is dirty. When enabled, DB-first staged edits are materialized agent-side via the `code_graph` tool's `apply` action (same planning/accepted gate as `/apply-graph`; refused for read-only refiner subagents via the `PI_PLANS_REFINER` env marker; the result carries per-file counts and a post-apply drift summary and never changes run status).
|
|
119
123
|
|
|
120
124
|
## `/config-pi-plans`
|
|
121
125
|
|
|
122
|
-
`/config-pi-plans` is an interactive workspace configuration wizard. It re-asks the workspace language, planning docs root, code graph toggle, reviewer mode/model, and criticizer mode/model, then writes the chosen defaults back to `.git/pi_plans/config.json`. When code graph is enabled, the extension also overrides built-in `read`/`write`/`edit` for indexed source files so graph-backed source reads and DB-first edits happen automatically. Model pickers can reuse the current session model, any available selector surfaced by `ctx.scopedModels` or the model registry, or a manually entered exact `provider/model` string. If a run is already active, only the workspace defaults change; the active run's `artifact_dir` and `language_tag` stay unchanged.
|
|
126
|
+
`/config-pi-plans` is an interactive workspace configuration wizard. It re-asks the workspace language, planning docs root, refs root, code graph toggle, reviewer mode/model, and criticizer mode/model, then writes the chosen defaults back to `.git/pi_plans/config.json`. When code graph is enabled, the extension also overrides built-in `read`/`write`/`edit` for indexed source files so graph-backed source reads and DB-first edits happen automatically. Model pickers can reuse the current session model, any available selector surfaced by `ctx.scopedModels` or the model registry, or a manually entered exact `provider/model` string. If a run is already active, only the workspace defaults change; the active run's `artifact_dir` and `language_tag` stay unchanged.
|
|
123
127
|
|
|
124
128
|
|
|
125
129
|
Before the first product planning question, check the persisted config again. If `artifact_root_source` is missing or `unset`, ask exactly one `ask_choice` question:
|
|
@@ -131,6 +135,15 @@ Before the first product planning question, check the persisted config again. If
|
|
|
131
135
|
|
|
132
136
|
Persist with `plans` (`set-artifact-root`, `artifactRoot: <selected path>`, `artifactRootSource: "user"` or `"auto"`). Use the selected path for the run's artifact directory root. This question does not count against the planning-question limit.
|
|
133
137
|
|
|
138
|
+
Before downloading any reference in a plan-with-refs flow, check the persisted config. If `refs_root_source` is missing or `unset`, ask exactly one `ask_choice` question:
|
|
139
|
+
|
|
140
|
+
1. `.git/pi-plans/refs` — recommended; inside the git dir so git never tracks the downloads.
|
|
141
|
+
2. `./refs/` — inside the worktree; the planning write guard allows writes under the configured refs root.
|
|
142
|
+
3. `~/.cache/pi-plans/refs/` — outside the repository; matches the historical default.
|
|
143
|
+
4. `Other` / `Auto-complete` — select the recommended path.
|
|
144
|
+
|
|
145
|
+
Persist with `plans` (`set-refs-root`, `refsRoot: <selected path>`, `refsRootSource: "user"` or `"auto"`). Download references under this root. This question does not count against the planning-question limit.
|
|
146
|
+
|
|
134
147
|
|
|
135
148
|
Before running a `refine` round, read the role setting from the persisted config.
|
|
136
149
|
|
|
@@ -160,10 +173,12 @@ When `mode` is `delegated-subagent`, the `refine` tool spawns a read-only `pi` s
|
|
|
160
173
|
|
|
161
174
|
The main agent consolidates the results, records dispositions, revises the plan, and asks the next merged accept/execute question — all in the same turn.
|
|
162
175
|
|
|
176
|
+
The `analyze_refs` tool (plan-with-refs) uses the same spawning machinery with the **reviewer** role's gates (`mode` must be `delegated-subagent`; a confirmed `current-session` reviewer is refused with guidance to switch, since analysis is spawn-only) and the reviewer's model selector. Each downloaded reference gets one independent read-only subagent whose system prompt comes from `agents/ref-analyst.md` and whose working directory is that reference's own directory; lanes never get `code_graph`. Lanes run in sequential batches of at most 3 under a standalone overlay titled `Refs`; each batch's controller opens and closes exactly like a single refine round. Successful spawns are recorded best-effort in `subagents.jsonl` with role `ref-analyst` (skipped when no active run exists, e.g. adhoc calls). The structured per-reference sections come back as the tool result; the main agent owns `REF_ANALYSIS.md` and fills `coverage`/`gaps` in `refs.jsonl` via `plans` (`record-ref`).
|
|
177
|
+
|
|
163
178
|
## Run State
|
|
164
179
|
|
|
165
180
|
One run directory per planning request: `<git-common-dir>/pi_plans/runs/<YYYYMMDDTHHMMSSZ-topic>/` (second-precision; `-2`, `-3` suffixes on collision).
|
|
166
181
|
|
|
167
182
|
`run.json` includes: run ID; skill name; original request; target workspace; artifact directory; language tag; status (`planning` → `accepted` → `executing` → `done`, with `stopped`/`abandoned` as exits); timestamps.
|
|
168
183
|
|
|
169
|
-
`decisions.jsonl` is appended automatically by `ask_choice` (question, options, answer, answer source). `subagents.jsonl` records reviewer/criticizer spawns. `refs.jsonl` records reference metadata via `plans` (`record-ref`).
|
|
184
|
+
`decisions.jsonl` is appended automatically by `ask_choice` (question, options, answer, answer source). `subagents.jsonl` records reviewer/criticizer/ref-analyst spawns. `refs.jsonl` records reference metadata via `plans` (`record-ref`).
|
package/scripts/validate.ts
CHANGED
|
@@ -16,15 +16,15 @@ Read `../../references/pi-planning-workflow.md` and `../../references/state-and-
|
|
|
16
16
|
1. Inspect the target Git repo read-only before external research so search terms match the actual codebase and constraints.
|
|
17
17
|
2. Create the `.git/pi_plans` run state and planning artifact directory once the topic is clear (`plans` action `start-run`).
|
|
18
18
|
3. Search proactively for related projects, articles, papers, docs, and prior art. Prefer a websearch skill when installed; otherwise use bash tools such as `curl` or `gh` when already available.
|
|
19
|
-
4.
|
|
19
|
+
4. Before the first download, check `refs_root` in `.git/pi_plans/config.json` (`plans` action `show`). If it is unset, ask exactly one `ask_choice` question — recommended `.git/pi-plans/refs/` (inside the git dir, never tracked), second `./refs/`, third `~/.cache/pi-plans/refs/` — and persist with `plans` (`set-refs-root`); this question does not count against the planning-question limit. Then download or clone at least 3 credible references before writing `PLAN_v1.md`, under the configured refs root (create per-ref subdirectories). Landing pages, README-only snapshots, abstracts, package metadata, or curl-only fragments do not count when deeper source material is available.
|
|
20
20
|
5. For every reference, record source metadata and local path in `REF_ANALYSIS.md` and in the run's `refs.jsonl` (via `plans` action `record-ref`): title, URL, kind, retrieval method, date accessed, local path, coverage, and evidence gaps.
|
|
21
|
-
6. For every reference,
|
|
21
|
+
6. For every reference, run the `analyze_refs` tool (required path — it replaces manual structured reads): one independent read-only subagent per reference deep-reads it and returns structured sections (Overview / Key Mechanisms And Design Tradeoffs / Adoptable Ideas For The Target Repo / Pitfalls And Anti-Patterns / Evidence Citations / Coverage / Evidence Gaps). Paste each analysis into `REF_ANALYSIS.md` and fill `coverage` and `gaps` in `refs.jsonl` via `plans` (`record-ref`) before asking adoption questions.
|
|
22
22
|
7. For every reference after analysis, ask at least 3 ref-specific adoption questions via `ask_choice` before using its ideas in `PLAN_v1.md`; each based on downloaded content, recommended option first, `Other` second-last, `Auto-complete` last (the tool appends both).
|
|
23
23
|
8. Block rather than pad if fewer than 3 credible references exist, unless the user explicitly narrows the topic or waives the minimum. `Auto-complete` cannot grant this waiver.
|
|
24
24
|
9. Continue with big-plan depth: at least 10 planning questions, required web research during brainstorming and refinement (`refine` `reviewers: 3` reviewer round, then a criticizer round), no refinement limit, at most five high-priority comments or questions per refinement round. Then the merged accept/execute question (ask_choice with `autoComplete: false`: ✓ Accept & execute now / Accept, don't execute yet / another round) and the `execute_plan` tool.
|
|
25
25
|
|
|
26
26
|
## REF_ANALYSIS.md
|
|
27
27
|
|
|
28
|
-
Include: original request and repo evidence that shaped the search; attempted queries and selection criteria; references selected and rejected; local download paths; structured
|
|
28
|
+
Include: original request and repo evidence that shaped the search; attempted queries and selection criteria; references selected and rejected; configured refs root and local download paths; the per-reference `analyze_refs` structured analyses (pasted verbatim, one section per reference); adoption questions and recorded answers; accepted ideas, rejected ideas, and reasons; evidence gaps and user-granted waivers; language, reviewer, and criticizer settings used.
|
|
29
29
|
|
|
30
30
|
Reference ideas are not eligible for `PLAN_v1.md` until their adoption question answers are recorded.
|
|
@@ -17,7 +17,7 @@ import { makeBackend } from "./parsers/javascript.ts";
|
|
|
17
17
|
import { PythonBackend } from "./parsers/python.ts";
|
|
18
18
|
import type { ParserBackend } from "./parser.ts";
|
|
19
19
|
import type { Language } from "./types.ts";
|
|
20
|
-
import { materialize } from "./materialize.ts";
|
|
20
|
+
import { materialize, type MaterializeReport } from "./materialize.ts";
|
|
21
21
|
import { generateSummaries, type CompletionHandle, type SummaryReport } from "./summary.ts";
|
|
22
22
|
import { readActive, getRun, setRunStatus } from "../state.ts";
|
|
23
23
|
|
|
@@ -84,12 +84,16 @@ async function bootstrap(ctx: CommandContext, opts: { reindex?: boolean }): Prom
|
|
|
84
84
|
return { store, paths, parsers, runtimeStatus: status };
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
function activePlanningRun(workdir: string): ActiveInfo | null {
|
|
88
|
+
const active = readActive(workdir);
|
|
89
|
+
if (!active) return null;
|
|
90
|
+
const run = getRun(workdir, active.run_id);
|
|
91
|
+
if (!run) return null;
|
|
92
|
+
return run.status === "planning" || run.status === "accepted" ? active : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
function denyActivePlanning(ctx: CommandContext): boolean {
|
|
88
|
-
|
|
89
|
-
if (!active) return false;
|
|
90
|
-
const run = getRun(ctx.cwd, active.run_id);
|
|
91
|
-
if (!run) return false;
|
|
92
|
-
return run.status === "planning" || run.status === "accepted";
|
|
96
|
+
return activePlanningRun(ctx.cwd) !== null;
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
export async function initGraphCommand(args: string, ctx: CommandContext): Promise<void> {
|
|
@@ -172,35 +176,77 @@ export async function initGraphCommand(args: string, ctx: CommandContext): Promi
|
|
|
172
176
|
}
|
|
173
177
|
}
|
|
174
178
|
|
|
175
|
-
export
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
export interface ApplyGraphCoreResult {
|
|
180
|
+
refused?: string;
|
|
181
|
+
failed?: string;
|
|
182
|
+
report?: MaterializeReport;
|
|
183
|
+
drift?: { pending: number; ok: boolean } | null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Shared core for /apply-graph and the code_graph "apply" tool action:
|
|
188
|
+
* gate (planning/accepted refusal) → bootstrap → materialize → drift summary.
|
|
189
|
+
* No notifications and no run-status side effects; callers own presentation
|
|
190
|
+
* and lifecycle transitions.
|
|
191
|
+
*/
|
|
192
|
+
export async function applyGraphCore(workdir: string, opts: { force?: boolean } = {}): Promise<ApplyGraphCoreResult> {
|
|
193
|
+
const planned = activePlanningRun(workdir);
|
|
194
|
+
if (planned) {
|
|
195
|
+
return { refused: `code-graph apply refused: a planning run is currently planning or accepted (run ${planned.run_id}).` };
|
|
179
196
|
}
|
|
180
|
-
|
|
181
|
-
const bootstrapResult = await bootstrap(
|
|
182
|
-
|
|
197
|
+
let bootstrapFailure = "";
|
|
198
|
+
const bootstrapResult = await bootstrap(
|
|
199
|
+
{ cwd: workdir, hasUI: false, ui: { notify: (message: string) => { bootstrapFailure ||= message; }, confirm: async () => false } } as never,
|
|
200
|
+
{},
|
|
201
|
+
);
|
|
202
|
+
if (!bootstrapResult) return { failed: bootstrapFailure || "code-graph runtime unavailable" };
|
|
183
203
|
const { store, paths } = bootstrapResult;
|
|
184
204
|
try {
|
|
185
|
-
const report = materialize({ store, worktreeRoot: paths.worktreeRoot, force:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
);
|
|
195
|
-
const active = readActive(ctx.cwd);
|
|
196
|
-
if (active) setRunStatus(ctx.cwd, active.run_id, "executing");
|
|
205
|
+
const report = materialize({ store, worktreeRoot: paths.worktreeRoot, force: opts.force ?? false });
|
|
206
|
+
let drift: ApplyGraphCoreResult["drift"] = null;
|
|
207
|
+
try {
|
|
208
|
+
const d = computeDrift(store, paths.worktreeRoot);
|
|
209
|
+
drift = { pending: d.pending.length, ok: d.ok };
|
|
210
|
+
} catch {
|
|
211
|
+
drift = null; // drift summary is best-effort; materialization already succeeded
|
|
212
|
+
}
|
|
213
|
+
return { report, drift };
|
|
197
214
|
} catch (error) {
|
|
198
|
-
|
|
215
|
+
return { failed: (error as Error).message };
|
|
199
216
|
} finally {
|
|
200
217
|
store.close();
|
|
201
218
|
}
|
|
202
219
|
}
|
|
203
220
|
|
|
221
|
+
export async function applyGraphCommand(args: string, ctx: CommandContext): Promise<void> {
|
|
222
|
+
if (denyActivePlanning(ctx)) {
|
|
223
|
+
ctx.ui.notify("code-graph apply refused: a planning run is currently planning or accepted.", "error");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const flags = parseCommandArgs(args).flags;
|
|
227
|
+
const core = await applyGraphCore(ctx.cwd, { force: flags.has("force") });
|
|
228
|
+
if (core.refused) {
|
|
229
|
+
ctx.ui.notify(core.refused, "error");
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (core.failed || !core.report) {
|
|
233
|
+
ctx.ui.notify(`code-graph apply failed: ${core.failed ?? "unknown error"}`, "error");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const report = core.report;
|
|
237
|
+
const stale = report.files.filter((file) => file.status === "stale").length;
|
|
238
|
+
const errors = report.files.filter((file) => file.status === "error").length;
|
|
239
|
+
const ok = report.files.filter((file) => file.status === "ok").length;
|
|
240
|
+
const deleted = report.files.filter((file) => file.status === "deleted").length;
|
|
241
|
+
const skipped = report.files.filter((file) => file.status === "skipped-missing").length;
|
|
242
|
+
ctx.ui.notify(
|
|
243
|
+
`code-graph apply: ${ok} ok, ${deleted} deleted, ${stale} stale, ${skipped} skipped-missing, ${errors} error`,
|
|
244
|
+
errors > 0 ? "error" : "info",
|
|
245
|
+
);
|
|
246
|
+
const active = readActive(ctx.cwd);
|
|
247
|
+
if (active) setRunStatus(ctx.cwd, active.run_id, "executing");
|
|
248
|
+
}
|
|
249
|
+
|
|
204
250
|
export async function graphStatusCommand(_args: string, ctx: CommandContext): Promise<void> {
|
|
205
251
|
const bootstrapResult = await bootstrap(ctx, {});
|
|
206
252
|
if (!bootstrapResult) return;
|
|
@@ -309,7 +355,7 @@ export function computeDrift(store: Store, worktreeRoot: string): DriftResult {
|
|
|
309
355
|
const recommendation = needsUpdate
|
|
310
356
|
? "run /update-graph to reindex changed paths"
|
|
311
357
|
: needsApply
|
|
312
|
-
? "run /apply-graph to materialize pending DB edits"
|
|
358
|
+
? "run code_graph apply (or /apply-graph) to materialize pending DB edits"
|
|
313
359
|
: "in sync";
|
|
314
360
|
return {
|
|
315
361
|
ok: hashDrift.every((item) => item.kind !== "hash-mismatch") && unindexed.length === 0,
|
|
@@ -13,6 +13,6 @@ export function graphBlockForRefiner(enabled: boolean): string {
|
|
|
13
13
|
|
|
14
14
|
export function graphBlockForExecutor(enabled: boolean): string {
|
|
15
15
|
return enabled
|
|
16
|
-
? "Code graph loop: indexed code files read as a function digest by default — never whole-file; drill in via offset/limit or code_graph get-function, full:true is the only whole-file exit. Edit via graph-aware edit (DB-first), then
|
|
16
|
+
? "Code graph loop: indexed code files read as a function digest by default — never whole-file; drill in via offset/limit or code_graph get-function, full:true is the only whole-file exit. Edit via graph-aware edit (DB-first), then code_graph apply (its result includes the post-apply drift summary) → plans final-commit."
|
|
17
17
|
: "Code graph disabled: edit source files directly with edit/write.";
|
|
18
18
|
}
|