pi-plans 0.1.2 → 0.3.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.
Files changed (76) hide show
  1. package/README.md +98 -19
  2. package/index.ts +147 -66
  3. package/package.json +7 -1
  4. package/references/pi-planning-workflow.md +21 -3
  5. package/references/state-and-config.md +35 -3
  6. package/scripts/validate.ts +4 -0
  7. package/src/autocomplete.ts +163 -0
  8. package/src/code-graph/commands.ts +437 -0
  9. package/src/code-graph/discovery.ts +118 -0
  10. package/src/code-graph/git.ts +108 -0
  11. package/src/code-graph/identity.ts +59 -0
  12. package/src/code-graph/indexer.ts +281 -0
  13. package/src/code-graph/materialize.ts +166 -0
  14. package/src/code-graph/mode.ts +28 -0
  15. package/src/code-graph/mutations.ts +160 -0
  16. package/src/code-graph/parser.ts +51 -0
  17. package/src/code-graph/parsers/javascript.ts +35 -0
  18. package/src/code-graph/parsers/python.ts +160 -0
  19. package/src/code-graph/parsers/tree-sitter.ts +316 -0
  20. package/src/code-graph/paths.ts +85 -0
  21. package/src/code-graph/prompts.ts +18 -0
  22. package/src/code-graph/resolver.ts +69 -0
  23. package/src/code-graph/runtime.ts +158 -0
  24. package/src/code-graph/schema.ts +135 -0
  25. package/src/code-graph/screening.ts +82 -0
  26. package/src/code-graph/store.ts +278 -0
  27. package/src/code-graph/summary.ts +435 -0
  28. package/src/code-graph/types.ts +163 -0
  29. package/src/compaction.ts +1256 -0
  30. package/src/config-command.ts +326 -0
  31. package/src/exec.ts +519 -625
  32. package/src/plan.ts +37 -0
  33. package/src/query-hook.ts +82 -0
  34. package/src/refine-prompts.ts +50 -0
  35. package/src/refine-ui-helpers.ts +142 -0
  36. package/src/refine-ui-state.ts +144 -0
  37. package/src/refine-ui.ts +430 -0
  38. package/src/state.ts +24 -29
  39. package/src/subagent.ts +299 -70
  40. package/tests/ask-choice.test.ts +263 -0
  41. package/tests/autocomplete.test.ts +147 -0
  42. package/tests/code-graph-apply.test.ts +185 -0
  43. package/tests/code-graph-commands.test.ts +211 -0
  44. package/tests/code-graph-db.test.ts +166 -0
  45. package/tests/code-graph-discovery.test.ts +38 -0
  46. package/tests/code-graph-git.test.ts +94 -0
  47. package/tests/code-graph-index.test.ts +175 -0
  48. package/tests/code-graph-loop.e2e.test.ts +159 -0
  49. package/tests/code-graph-mutations.test.ts +117 -0
  50. package/tests/code-graph-parser.test.ts +85 -0
  51. package/tests/code-graph-rollback.test.ts +100 -0
  52. package/tests/code-graph-summary-batching.test.ts +518 -0
  53. package/tests/code-graph-summary.test.ts +148 -0
  54. package/tests/compaction.test.ts +388 -0
  55. package/tests/config-command.test.ts +255 -0
  56. package/tests/exec.test.ts +751 -422
  57. package/tests/execute-plan.test.ts +65 -0
  58. package/tests/fixtures/code-graph/sample.js +36 -0
  59. package/tests/fixtures/code-graph/sample.py +20 -0
  60. package/tests/fixtures/code-graph/sample.ts +15 -0
  61. package/tests/graph-aware-file-tools.test.ts +411 -0
  62. package/tests/plan.test.ts +11 -1
  63. package/tests/plans.test.ts +6 -5
  64. package/tests/query-hook.test.ts +82 -0
  65. package/tests/refine-prompts.test.ts +67 -2
  66. package/tests/refine-ui.test.ts +392 -0
  67. package/tests/state.test.ts +12 -15
  68. package/tests/subagent.test.ts +120 -0
  69. package/tools/ask-choice.ts +180 -11
  70. package/tools/code-graph.ts +254 -0
  71. package/tools/execute-plan.ts +7 -39
  72. package/tools/graph-aware-file-tools.ts +392 -0
  73. package/tools/plans.ts +84 -18
  74. package/tools/refine.ts +180 -80
  75. package/src/execution-panel.ts +0 -633
  76. package/tests/execution-panel.test.ts +0 -234
@@ -9,8 +9,10 @@ This skill set is written for the Pi coding agent's documented behavior:
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
11
  - the extension provides these tools: `plans` (workspace state), `ask_choice` (choice prompts), `refine` (reviewer/criticizer subagents), and `execute_plan` (execution handoff);
12
- - `refine` spawns read-only Pi subagents (`pi --mode json -p --no-session --tools read,grep,find,ls`) with isolated context; their results return to the main session as tool output;
13
- - the execution loop is extension-managed: remaining verifier items are injected each turn and `[DONE:VC-xxx]` markers are tracked with a footer progress widget.
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 `/apply-graph`; unexpected fallbacks (`not indexed` / `runtime unavailable` / `config read failed`) are marked at the top of the result while flag-off fallbacks stay unmarked;
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
+ - 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;
14
16
 
15
17
  ## Planning Boundary
16
18
 
@@ -60,6 +62,7 @@ Every user-facing planning or refinement question goes through the `ask_choice`
60
62
  - `options`: ordered options, recommended option first with `recommended: true` (exactly one), each with the tradeoff that matters in `description`;
61
63
  - do not add `Other` or `Auto-complete` yourself — the tool appends `Other…` second-last and `Auto-complete` last;
62
64
  - pass `autoComplete: false` for the merged accept/execute question — it contains the execution approval, so Auto-complete never appears there — and for any install waiver, publishing, deployment, merge, push, credential, or external-state question. Auto-complete may choose the recommended planning or refinement option only.
65
+ - When the user selects Auto-complete, it remains active for the current planning run: later eligible questions use their recommended options automatically, and the extension queues one deduplicated follow-up if the model stops after an auto-completed answer. `/plans-autocomplete-stop` disables it; session restore may reactivate it only for the same active run while its status is `planning`.
63
66
 
64
67
  Answers are recorded automatically in the active run's `decisions.jsonl`. You must still maintain `DECISIONS.md` in the artifact directory (summary table of questions, options, answers, answer sources, open assumptions).
65
68
 
@@ -126,13 +129,28 @@ A refinement round is complete when all reviewer outputs have returned or all cr
126
129
 
127
130
  When the user picks `✓ Accept PLAN_vN and execute it now` in the merged question, mark the plan accepted and call the `execute_plan` tool (or the user runs `/plans-execute`). It re-confirms with the user, then the extension enters execution mode:
128
131
 
129
- - every agent turn is injected with the remaining verifier checklist and execution rules (layered simplest implementation, no stopgaps, dependency and library discipline, minimum tests);
132
+ - every agent turn is injected with the remaining verifier checklist and execution rules (layered simplest implementation, waiting for subprocess-backed verification with backoff 5s -> 10s -> 20s -> 40s -> 80s, then keep polling at 80s and restart at 5s for each new subprocess, no stopgaps, dependency and library discipline, minimum tests);
133
+ - execution-phase compaction is handled only when Pi core emits manual `/compact`, threshold, or overflow events; summaries are deterministic VCC-style summaries, include session-derived plan/current-I/checklist context, use smart tail keep and `keep:N`, and never call a model or request proactive current-I compaction;
130
134
  - the read-only guard lifts: full write access returns;
131
135
  - the run status moves to `executing`, then `done` when the last `[DONE:VC-xxx]` marker lands;
132
136
  - `/plans-stop` stops execution; `/plans` shows progress.
133
137
 
134
138
  If the user declines, stay in planning (or stop, per their choice). Never start implementation without the approved handoff.
135
139
 
140
+ ### Post-Execution Continuation
141
+
142
+ 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).
143
+
144
+ The agent then asks one `ask_choice` question for the termination condition of the implementation-review loop:
145
+
146
+ - `autoComplete: false` — suppresses the run-scoped Auto-complete mode for this question.
147
+ - Options (recommended first): 1. until no high-severity finding (hard cap 5 rounds) 2. 1 round 3. 2 rounds 4. 3 rounds.
148
+ - Each refinement round calls `refine` with `role: "reviewer", target: "implementation"`, accepts findings on evidence, applies fixes, re-runs relevant tests, and records progress. The hard cap is 5 rounds regardless of the chosen termination condition.
149
+ - Round audit trail: `decisions.jsonl`, `subagents.jsonl`, and `pi-plans-ameliorate` entries (one at goal start, then one per round) carry `currentRound` for post-hoc verification.
150
+ - Headless sessions skip the prompt entirely; no `pi-plans-ameliorate` entry is appended.
151
+
152
+ `refine` accepts a `target` parameter (`"plan"` default, `"implementation"` for the post-execution loop). The implementation brief anchors findings to the plan's goals and acceptance criteria, explicitly assesses delivery maturity (MVP-only vs. long-term refinement: stopgaps, missing tests, technical debt, production readiness), and tags out-of-scope improvements as low severity.
153
+
136
154
  ## Red Flags
137
155
 
138
156
  Stop and return to the workflow if any of these happen:
@@ -25,6 +25,7 @@ Bare repositories are refused with a clear error. A missing `git` executable is
25
25
  ```text
26
26
  <git-common-dir>/pi_plans/
27
27
  config.json
28
+ pi-vcc-config.json
28
29
  active.json
29
30
  runs/
30
31
  <run-id>/
@@ -36,7 +37,7 @@ Bare repositories are refused with a clear error. A missing `git` executable is
36
37
  cache/
37
38
  ```
38
39
 
39
- `config.json` is stable workspace preference state. `active.json` and `runs/` are run state. Large external references stay outside the repository by default under `~/.cache/pi-plans/refs/`, with metadata recorded in the run state and public artifacts.
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. Large external references stay outside the repository by default under `~/.cache/pi-plans/refs/`, with metadata recorded in the run state and public artifacts.
40
41
 
41
42
  ## Config Schema
42
43
 
@@ -76,6 +77,30 @@ Rules:
76
77
  - `artifact_root_updated_at` is the selection timestamp or `null` before confirmation.
77
78
  - 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.
78
79
 
80
+ ## VCC Compact Config
81
+
82
+ `pi-vcc-config.json` is scaffolded under the resolved `<git-common-dir>/pi_plans/` state root when an active planning or execution compaction hook first needs it. It is independent from `config.json` so planning preferences, run state, and compact policy can evolve separately.
83
+
84
+ Default values:
85
+
86
+ ```json
87
+ {
88
+ "overrideDefaultCompaction": true,
89
+ "smartKeepTail": true,
90
+ "continueAfterThresholdCompact": true,
91
+ "debug": false
92
+ }
93
+ ```
94
+
95
+ Rules:
96
+
97
+ - Only the repo-private file is read. Upstream global pi-vcc config such as `~/.pi/agent/pi-vcc-config.json` and `PI_VCC_CONFIG_PATH` are ignored.
98
+ - Missing files are created with defaults; valid files keep user values and receive missing default keys; invalid JSON is never clobbered and the runtime falls back to defaults for that read.
99
+ - `overrideDefaultCompaction:false` returns ordinary Pi manual/threshold/overflow compactions to Pi core. Explicit pi-plans internal compact hints can still use the VCC path.
100
+ - `smartKeepTail:true` starts from the requested/default keep count and may retain more recent user turns when the retained tail remains within the safe token budget. Explicit `keep:N` is honored.
101
+ - `continueAfterThresholdCompact:true` permits one hidden continuation after successful threshold/overflow compaction only on Pi versions that still need extension-driven resume behavior. Plain manual `/compact` never auto-continues, and `/compact <text>` sends the text once as the follow-up prompt.
102
+ - `debug:false` writes no diagnostics; `debug:true` writes a best-effort `/tmp/pi-vcc-debug.json` snapshot for local troubleshooting.
103
+
79
104
  ## Language Setting
80
105
 
81
106
  Before the first product planning question, check the persisted config (`plans` action `show`). If `language.tag` is missing or invalid, ask exactly one `ask_choice` question:
@@ -88,7 +113,14 @@ Before the first product planning question, check the persisted config (`plans`
88
113
 
89
114
  Persist with `plans` (`set-language`, `languageSource: "user"`). Use the selected language for visible questions, choices, review summaries, criticizer questions, and Markdown artifacts. Keep IDs, file paths, command names, JSON keys, and protocol labels stable in English.
90
115
 
91
- ## Planning Docs Location
116
+ ## Code Graph Enabled
117
+
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.
119
+
120
+ ## `/config-pi-plans`
121
+
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.
123
+
92
124
 
93
125
  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:
94
126
 
@@ -120,7 +152,7 @@ If a spawn later fails because the stored selector is unavailable, reset the mar
120
152
 
121
153
  ## Subagent Spawning
122
154
 
123
- When `mode` is `delegated-subagent`, the `refine` tool spawns a read-only `pi` subprocess (`--mode json -p --no-session --tools read,grep,find,ls`) whose system prompt comes from `agents/reviewer.md` or `agents/criticizer.md`. The subagent:
155
+ When `mode` is `delegated-subagent`, the `refine` tool spawns a read-only `pi` subprocess (`--mode json -p --no-session --tools read,grep,find,ls`) whose system prompt comes from `agents/reviewer.md` or `agents/criticizer.md`. In TUI mode, delegated runs also show a standalone `Reviewer` or `Criticizer` overlay with live lane/tool status; the child is awaited and the overlay is closed before the tool result returns. The subagent:
124
156
 
125
157
  - performs read-only analysis and never edits files;
126
158
  - receives the full plan text and a review/criticism brief;
@@ -22,11 +22,15 @@ const REQUIRED_TOOL_FILES = [
22
22
  "tools/ask-choice.ts",
23
23
  "tools/refine.ts",
24
24
  "tools/execute-plan.ts",
25
+ "tools/code-graph.ts",
25
26
  "src/state.ts",
26
27
  "src/guard.ts",
27
28
  "src/plan.ts",
28
29
  "src/subagent.ts",
29
30
  "src/exec.ts",
31
+ "src/code-graph/runtime.ts",
32
+ "src/code-graph/schema.ts",
33
+ "src/code-graph/store.ts",
30
34
  ];
31
35
 
32
36
  const NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -0,0 +1,163 @@
1
+ /** Run-scoped Auto-complete state and planning-turn continuation. */
2
+
3
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
4
+ import { getRun, readActive } from "./state.ts";
5
+
6
+ export const AUTOCOMPLETE_ENTRY = "pi-plans-autocomplete";
7
+ const AUTOCOMPLETE_CONTINUE = "Continue the current planning workflow. Raise the next relevant question with ask_choice; do not stop after an auto-completed answer.";
8
+
9
+ type SessionEntry = { type: string; customType?: string; data?: unknown };
10
+
11
+ type AutoCompleteState = {
12
+ runId: string;
13
+ enabled: boolean;
14
+ pendingFollowUp: boolean;
15
+ askChoiceCount: number;
16
+ autoChoiceCount: number;
17
+ planWritten: boolean;
18
+ };
19
+
20
+ type SessionWithAutoComplete = ExtensionContext["sessionManager"] & {
21
+ __piPlansAutoComplete?: AutoCompleteState;
22
+ };
23
+
24
+ let api: ExtensionAPI | null = null;
25
+
26
+ export function setAutoCompleteApi(next: ExtensionAPI | null): void {
27
+ api = next;
28
+ }
29
+
30
+ function sessionState(ctx: ExtensionContext): AutoCompleteState | undefined {
31
+ return (ctx.sessionManager as SessionWithAutoComplete).__piPlansAutoComplete;
32
+ }
33
+
34
+ function activePlanningRun(ctx: ExtensionContext): { runId: string } | null {
35
+ const active = readActive(ctx.cwd);
36
+ if (!active) return null;
37
+ const run = getRun(ctx.cwd, active.run_id);
38
+ return run?.status === "planning" ? { runId: run.run_id } : null;
39
+ }
40
+
41
+ function appendState(runId: string, enabled: boolean, reason?: string): void {
42
+ if (!api) return;
43
+ api.appendEntry(AUTOCOMPLETE_ENTRY, { runId, enabled, ...(reason ? { reason } : {}) });
44
+ }
45
+
46
+ export function enableAutoComplete(ctx: ExtensionContext): boolean {
47
+ const run = activePlanningRun(ctx);
48
+ if (!run) return false;
49
+ const current = sessionState(ctx);
50
+ if (current?.enabled && current.runId === run.runId) return true;
51
+ (ctx.sessionManager as SessionWithAutoComplete).__piPlansAutoComplete = {
52
+ runId: run.runId,
53
+ enabled: true,
54
+ pendingFollowUp: false,
55
+ askChoiceCount: 0,
56
+ autoChoiceCount: 0,
57
+ planWritten: false,
58
+ };
59
+ appendState(run.runId, true);
60
+ return true;
61
+ }
62
+
63
+ export function disableAutoComplete(ctx: ExtensionContext, reason = "disabled"): boolean {
64
+ const state = sessionState(ctx);
65
+ const run = activePlanningRun(ctx);
66
+ const runId = state?.runId ?? run?.runId;
67
+ if (!runId && !state?.enabled) return false;
68
+ if (state) state.enabled = false;
69
+ if (runId) appendState(runId, false, reason);
70
+ return true;
71
+ }
72
+
73
+ export function isAutoCompleteEnabled(ctx: ExtensionContext): boolean {
74
+ const state = sessionState(ctx);
75
+ const run = activePlanningRun(ctx);
76
+ return !!state?.enabled && !!run && state.runId === run.runId;
77
+ }
78
+
79
+ /** Record every ask_choice call for this turn; autoChoice marks a recommendation selected by the mode. */
80
+ export function recordAskChoice(ctx: ExtensionContext, autoChoice: boolean): void {
81
+ const state = sessionState(ctx);
82
+ if (!state) return;
83
+ state.askChoiceCount += 1;
84
+ if (autoChoice) state.autoChoiceCount += 1;
85
+ }
86
+
87
+ export function markPlanWritten(ctx: ExtensionContext): void {
88
+ const state = sessionState(ctx);
89
+ if (state) state.planWritten = true;
90
+ }
91
+
92
+ export function resetAutoCompleteTurn(ctx: ExtensionContext): void {
93
+ const state = sessionState(ctx);
94
+ if (!state) return;
95
+ state.pendingFollowUp = false;
96
+ state.askChoiceCount = 0;
97
+ state.autoChoiceCount = 0;
98
+ state.planWritten = false;
99
+ }
100
+
101
+ export function shouldContinueAutoComplete(ctx: ExtensionContext): boolean {
102
+ const state = sessionState(ctx);
103
+ return isAutoCompleteEnabled(ctx)
104
+ && !!state
105
+ && state.autoChoiceCount > 0
106
+ && state.askChoiceCount === state.autoChoiceCount
107
+ && !state.planWritten
108
+ && !state.pendingFollowUp;
109
+ }
110
+
111
+ export async function continueAutoComplete(ctx: ExtensionContext): Promise<boolean> {
112
+ if (!api || !shouldContinueAutoComplete(ctx)) return false;
113
+ const state = sessionState(ctx);
114
+ if (!state) return false;
115
+ state.pendingFollowUp = true;
116
+ try {
117
+ await api.sendUserMessage(AUTOCOMPLETE_CONTINUE, { deliverAs: "followUp" });
118
+ return true;
119
+ } catch {
120
+ state.pendingFollowUp = false;
121
+ return false;
122
+ }
123
+ }
124
+
125
+ export function registerAutoCompleteTurnHandlers(pi: ExtensionAPI): void {
126
+ setAutoCompleteApi(pi);
127
+ pi.on("turn_start", async (_event, ctx) => {
128
+ resetAutoCompleteTurn(ctx);
129
+ });
130
+ pi.on("turn_end", async (event, ctx) => {
131
+ const message = event.message as { role?: string } | undefined;
132
+ if (message?.role === "assistant") await continueAutoComplete(ctx);
133
+ });
134
+ }
135
+
136
+ export function restoreAutoCompleteFromSession(ctx: ExtensionContext, entries: SessionEntry[]): void {
137
+ const session = ctx.sessionManager as SessionWithAutoComplete;
138
+ delete session.__piPlansAutoComplete;
139
+ let restored: { runId: string; enabled: boolean } | null = null;
140
+ for (let i = entries.length - 1; i >= 0; i--) {
141
+ const entry = entries[i];
142
+ if (entry.type !== "custom" || entry.customType !== AUTOCOMPLETE_ENTRY || !entry.data) continue;
143
+ const data = entry.data as { runId?: unknown; enabled?: unknown };
144
+ if (typeof data.runId === "string" && typeof data.enabled === "boolean") {
145
+ restored = { runId: data.runId, enabled: data.enabled };
146
+ break;
147
+ }
148
+ }
149
+ const active = activePlanningRun(ctx);
150
+ if (!restored || !restored.enabled || !active || restored.runId !== active.runId) return;
151
+ session.__piPlansAutoComplete = {
152
+ runId: active.runId,
153
+ enabled: true,
154
+ pendingFollowUp: false,
155
+ askChoiceCount: 0,
156
+ autoChoiceCount: 0,
157
+ planWritten: false,
158
+ };
159
+ }
160
+
161
+ export function autoCompleteStatus(ctx: ExtensionContext): "enabled" | "disabled" {
162
+ return isAutoCompleteEnabled(ctx) ? "enabled" : "disabled";
163
+ }