codebase-cli 2.0.0-pre.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 (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +266 -0
  3. package/bin/codebase +2 -0
  4. package/dist/agent/agent.js +198 -0
  5. package/dist/agent/agent.js.map +1 -0
  6. package/dist/agent/config.js +117 -0
  7. package/dist/agent/config.js.map +1 -0
  8. package/dist/agent/events.js +153 -0
  9. package/dist/agent/events.js.map +1 -0
  10. package/dist/agent/router.js +35 -0
  11. package/dist/agent/router.js.map +1 -0
  12. package/dist/agent/system-prompt.js +21 -0
  13. package/dist/agent/system-prompt.js.map +1 -0
  14. package/dist/auth/cli.js +138 -0
  15. package/dist/auth/cli.js.map +1 -0
  16. package/dist/auth/credentials.js +105 -0
  17. package/dist/auth/credentials.js.map +1 -0
  18. package/dist/auth/flow.js +222 -0
  19. package/dist/auth/flow.js.map +1 -0
  20. package/dist/auth/pkce.js +46 -0
  21. package/dist/auth/pkce.js.map +1 -0
  22. package/dist/cli.js +69 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/clipboard/copy.js +106 -0
  25. package/dist/clipboard/copy.js.map +1 -0
  26. package/dist/commands/builtins.js +203 -0
  27. package/dist/commands/builtins.js.map +1 -0
  28. package/dist/commands/registry.js +65 -0
  29. package/dist/commands/registry.js.map +1 -0
  30. package/dist/commands/types.js +2 -0
  31. package/dist/commands/types.js.map +1 -0
  32. package/dist/compaction/engine.js +209 -0
  33. package/dist/compaction/engine.js.map +1 -0
  34. package/dist/compaction/tokens.js +79 -0
  35. package/dist/compaction/tokens.js.map +1 -0
  36. package/dist/compaction/types.js +2 -0
  37. package/dist/compaction/types.js.map +1 -0
  38. package/dist/diagnostics/checkers.js +211 -0
  39. package/dist/diagnostics/checkers.js.map +1 -0
  40. package/dist/diagnostics/engine.js +71 -0
  41. package/dist/diagnostics/engine.js.map +1 -0
  42. package/dist/diagnostics/types.js +2 -0
  43. package/dist/diagnostics/types.js.map +1 -0
  44. package/dist/dotenv/loader.js +115 -0
  45. package/dist/dotenv/loader.js.map +1 -0
  46. package/dist/glue/client.js +47 -0
  47. package/dist/glue/client.js.map +1 -0
  48. package/dist/glue/intent.js +78 -0
  49. package/dist/glue/intent.js.map +1 -0
  50. package/dist/glue/narration.js +55 -0
  51. package/dist/glue/narration.js.map +1 -0
  52. package/dist/headless/run.js +89 -0
  53. package/dist/headless/run.js.map +1 -0
  54. package/dist/hooks/manager.js +158 -0
  55. package/dist/hooks/manager.js.map +1 -0
  56. package/dist/hooks/runner.js +70 -0
  57. package/dist/hooks/runner.js.map +1 -0
  58. package/dist/hooks/types.js +2 -0
  59. package/dist/hooks/types.js.map +1 -0
  60. package/dist/memory/inject.js +12 -0
  61. package/dist/memory/inject.js.map +1 -0
  62. package/dist/memory/store.js +178 -0
  63. package/dist/memory/store.js.map +1 -0
  64. package/dist/memory/types.js +10 -0
  65. package/dist/memory/types.js.map +1 -0
  66. package/dist/permissions/store.js +172 -0
  67. package/dist/permissions/store.js.map +1 -0
  68. package/dist/plan/flow.js +214 -0
  69. package/dist/plan/flow.js.map +1 -0
  70. package/dist/plan/prompts.js +69 -0
  71. package/dist/plan/prompts.js.map +1 -0
  72. package/dist/plan/store.js +37 -0
  73. package/dist/plan/store.js.map +1 -0
  74. package/dist/plan/types.js +3 -0
  75. package/dist/plan/types.js.map +1 -0
  76. package/dist/sessions/store.js +105 -0
  77. package/dist/sessions/store.js.map +1 -0
  78. package/dist/skills/loader.js +41 -0
  79. package/dist/skills/loader.js.map +1 -0
  80. package/dist/skills/platform-loader.js +63 -0
  81. package/dist/skills/platform-loader.js.map +1 -0
  82. package/dist/skills/types.js +21 -0
  83. package/dist/skills/types.js.map +1 -0
  84. package/dist/tools/ask-user.js +61 -0
  85. package/dist/tools/ask-user.js.map +1 -0
  86. package/dist/tools/dispatch-agent.js +178 -0
  87. package/dist/tools/dispatch-agent.js.map +1 -0
  88. package/dist/tools/edit-file.js +80 -0
  89. package/dist/tools/edit-file.js.map +1 -0
  90. package/dist/tools/errors.js +89 -0
  91. package/dist/tools/errors.js.map +1 -0
  92. package/dist/tools/file-ops.js +136 -0
  93. package/dist/tools/file-ops.js.map +1 -0
  94. package/dist/tools/file-state-cache.js +92 -0
  95. package/dist/tools/file-state-cache.js.map +1 -0
  96. package/dist/tools/git/branch.js +84 -0
  97. package/dist/tools/git/branch.js.map +1 -0
  98. package/dist/tools/git/commit.js +83 -0
  99. package/dist/tools/git/commit.js.map +1 -0
  100. package/dist/tools/git/diff.js +72 -0
  101. package/dist/tools/git/diff.js.map +1 -0
  102. package/dist/tools/git/git-helpers.js +58 -0
  103. package/dist/tools/git/git-helpers.js.map +1 -0
  104. package/dist/tools/git/log.js +70 -0
  105. package/dist/tools/git/log.js.map +1 -0
  106. package/dist/tools/git/status.js +97 -0
  107. package/dist/tools/git/status.js.map +1 -0
  108. package/dist/tools/git/worktree.js +132 -0
  109. package/dist/tools/git/worktree.js.map +1 -0
  110. package/dist/tools/glob.js +128 -0
  111. package/dist/tools/glob.js.map +1 -0
  112. package/dist/tools/grep.js +199 -0
  113. package/dist/tools/grep.js.map +1 -0
  114. package/dist/tools/list-files.js +120 -0
  115. package/dist/tools/list-files.js.map +1 -0
  116. package/dist/tools/memory-tools.js +127 -0
  117. package/dist/tools/memory-tools.js.map +1 -0
  118. package/dist/tools/multi-edit.js +87 -0
  119. package/dist/tools/multi-edit.js.map +1 -0
  120. package/dist/tools/notebook-edit.js +147 -0
  121. package/dist/tools/notebook-edit.js.map +1 -0
  122. package/dist/tools/permission.js +168 -0
  123. package/dist/tools/permission.js.map +1 -0
  124. package/dist/tools/plan-mode.js +76 -0
  125. package/dist/tools/plan-mode.js.map +1 -0
  126. package/dist/tools/read-file.js +135 -0
  127. package/dist/tools/read-file.js.map +1 -0
  128. package/dist/tools/registry.js +52 -0
  129. package/dist/tools/registry.js.map +1 -0
  130. package/dist/tools/shell.js +216 -0
  131. package/dist/tools/shell.js.map +1 -0
  132. package/dist/tools/task-store.js +70 -0
  133. package/dist/tools/task-store.js.map +1 -0
  134. package/dist/tools/tasks.js +131 -0
  135. package/dist/tools/tasks.js.map +1 -0
  136. package/dist/tools/types.js +2 -0
  137. package/dist/tools/types.js.map +1 -0
  138. package/dist/tools/web-fetch.js +152 -0
  139. package/dist/tools/web-fetch.js.map +1 -0
  140. package/dist/tools/web-search.js +169 -0
  141. package/dist/tools/web-search.js.map +1 -0
  142. package/dist/tools/write-file.js +70 -0
  143. package/dist/tools/write-file.js.map +1 -0
  144. package/dist/types.js +9 -0
  145. package/dist/types.js.map +1 -0
  146. package/dist/ui/App.js +216 -0
  147. package/dist/ui/App.js.map +1 -0
  148. package/dist/ui/Input.js +90 -0
  149. package/dist/ui/Input.js.map +1 -0
  150. package/dist/ui/Message.js +89 -0
  151. package/dist/ui/Message.js.map +1 -0
  152. package/dist/ui/MessageList.js +35 -0
  153. package/dist/ui/MessageList.js.map +1 -0
  154. package/dist/ui/Permission.js +39 -0
  155. package/dist/ui/Permission.js.map +1 -0
  156. package/dist/ui/Status.js +34 -0
  157. package/dist/ui/Status.js.map +1 -0
  158. package/dist/ui/TaskPanel.js +43 -0
  159. package/dist/ui/TaskPanel.js.map +1 -0
  160. package/dist/ui/Throbber.js +20 -0
  161. package/dist/ui/Throbber.js.map +1 -0
  162. package/dist/ui/ToolPanel.js +83 -0
  163. package/dist/ui/ToolPanel.js.map +1 -0
  164. package/dist/ui/UserQuery.js +38 -0
  165. package/dist/ui/UserQuery.js.map +1 -0
  166. package/dist/ui/input-state.js +210 -0
  167. package/dist/ui/input-state.js.map +1 -0
  168. package/dist/ui/wrap.js +30 -0
  169. package/dist/ui/wrap.js.map +1 -0
  170. package/dist/user-queries/store.js +60 -0
  171. package/dist/user-queries/store.js.map +1 -0
  172. package/package.json +76 -0
@@ -0,0 +1,172 @@
1
+ import { shellNeedsPermission } from "../tools/permission.js";
2
+ /**
3
+ * Tools that never need a permission prompt. The full read-only set
4
+ * (audit-flagged "read-only allowlist" from permission.go) plus the task
5
+ * read tools. Adding to this list requires careful thought: anything
6
+ * that lands here can run without ever asking the user.
7
+ */
8
+ const ALWAYS_ALLOWED = new Set([
9
+ "read_file",
10
+ "list_files",
11
+ "glob",
12
+ "grep",
13
+ "web_fetch",
14
+ "web_search",
15
+ "git_status",
16
+ "git_diff",
17
+ "git_log",
18
+ "dispatch_agent",
19
+ "list_tasks",
20
+ "get_task",
21
+ "create_task",
22
+ "update_task",
23
+ // ask_user is a question, not a mutation — the user-query UI gates the
24
+ // actual interaction so a permission prompt on top is redundant.
25
+ "ask_user",
26
+ // Memory tools are user-context, not destructive code edits — auto-allow.
27
+ "save_memory",
28
+ "read_memory",
29
+ ]);
30
+ /**
31
+ * Per-agent-instance permission store. Used by the agent's
32
+ * beforeToolCall hook to decide whether to allow, prompt, or block.
33
+ *
34
+ * Trust state is in-memory and session-scoped — restarting the CLI
35
+ * resets all per-tool/global trust. Persisting trust across sessions
36
+ * lands in Phase 6 (config) so users can choose what to remember.
37
+ */
38
+ export class PermissionStore {
39
+ trustAll = false;
40
+ trustedTools = new Set();
41
+ queue = [];
42
+ listeners = new Set();
43
+ counter = 0;
44
+ async evaluate(toolName, args) {
45
+ if (this.shouldAutoAllow(toolName, args))
46
+ return "allow";
47
+ return new Promise((resolve) => {
48
+ const request = {
49
+ id: `perm-${++this.counter}`,
50
+ tool: toolName,
51
+ summary: summarize(toolName, args),
52
+ detail: detailFor(toolName, args),
53
+ risk: riskFor(toolName, args),
54
+ };
55
+ this.queue.push({ request, resolve });
56
+ this.notify();
57
+ });
58
+ }
59
+ current() {
60
+ return this.queue[0]?.request;
61
+ }
62
+ subscribe(listener) {
63
+ this.listeners.add(listener);
64
+ listener(this.current());
65
+ return () => {
66
+ this.listeners.delete(listener);
67
+ };
68
+ }
69
+ respond(id, choice) {
70
+ const head = this.queue[0];
71
+ if (!head || head.request.id !== id)
72
+ return;
73
+ if (choice === "trust-tool")
74
+ this.trustedTools.add(head.request.tool);
75
+ else if (choice === "trust-all")
76
+ this.trustAll = true;
77
+ head.resolve(choice === "deny" ? "block" : "allow");
78
+ this.queue.shift();
79
+ this.notify();
80
+ }
81
+ /** Wipe trust state. Used by /reset and tests. */
82
+ clear() {
83
+ this.trustAll = false;
84
+ this.trustedTools.clear();
85
+ }
86
+ shouldAutoAllow(toolName, args) {
87
+ if (ALWAYS_ALLOWED.has(toolName))
88
+ return true;
89
+ if (this.trustAll)
90
+ return true;
91
+ if (this.trustedTools.has(toolName))
92
+ return true;
93
+ if (toolName === "shell") {
94
+ const cmd = args?.command;
95
+ if (typeof cmd === "string" && !shellNeedsPermission(cmd))
96
+ return true;
97
+ }
98
+ // git_branch with no name (or just listing) is read-only.
99
+ if (toolName === "git_branch") {
100
+ const a = args;
101
+ if (!a?.name)
102
+ return true;
103
+ }
104
+ return false;
105
+ }
106
+ notify() {
107
+ const cur = this.current();
108
+ for (const listener of this.listeners)
109
+ listener(cur);
110
+ }
111
+ }
112
+ /** Tool-specific human-readable summary line. */
113
+ function summarize(tool, args) {
114
+ const a = (args ?? {});
115
+ switch (tool) {
116
+ case "shell":
117
+ return `Run shell: ${truncate(stringOf(a.command), 80)}`;
118
+ case "write_file":
119
+ return `Create or overwrite: ${stringOf(a.path)}`;
120
+ case "edit_file":
121
+ return `Edit: ${stringOf(a.path)}`;
122
+ case "multi_edit":
123
+ return `Multi-edit: ${stringOf(a.path)}`;
124
+ case "notebook_edit":
125
+ return `${stringOf(a.operation) || "edit"} cell ${a.cell_index ?? ""} in ${stringOf(a.path)}`.trim();
126
+ case "git_commit":
127
+ return `git commit: ${truncate(stringOf(a.message), 80)}`;
128
+ case "git_branch": {
129
+ if (a.create)
130
+ return `Create branch: ${stringOf(a.name)}`;
131
+ if (a.name)
132
+ return `Switch to branch: ${stringOf(a.name)}`;
133
+ return "List branches";
134
+ }
135
+ case "enter_worktree":
136
+ return `Open worktree: ${stringOf(a.path)}`;
137
+ case "exit_worktree":
138
+ return "Exit worktree";
139
+ case "ask_user":
140
+ return `Ask user: ${truncate(stringOf(a.question), 80)}`;
141
+ default:
142
+ return `Run ${tool}`;
143
+ }
144
+ }
145
+ /** Multi-line detail for the prompt UI to expand. */
146
+ function detailFor(tool, args) {
147
+ const a = (args ?? {});
148
+ if (tool === "shell" && typeof a.command === "string")
149
+ return a.command;
150
+ if (tool === "git_commit" && typeof a.message === "string")
151
+ return a.message;
152
+ return undefined;
153
+ }
154
+ function riskFor(tool, args) {
155
+ const a = (args ?? {});
156
+ if (tool === "shell") {
157
+ const cmd = stringOf(a.command);
158
+ if (/\brm\s+-r/.test(cmd) || /\bgit\s+push/.test(cmd) || />\s*\/dev\//.test(cmd))
159
+ return "high";
160
+ return "medium";
161
+ }
162
+ if (tool === "git_commit" || tool === "git_branch")
163
+ return "medium";
164
+ return "medium";
165
+ }
166
+ function stringOf(v) {
167
+ return typeof v === "string" ? v : "";
168
+ }
169
+ function truncate(s, max) {
170
+ return s.length > max ? `${s.slice(0, max - 1)}…` : s;
171
+ }
172
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/permissions/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,214 @@
1
+ import { AGENT_PROMPT_FOOTER, AGENT_PROMPT_HEADER, PLAN_SYSTEM_PROMPT, QUESTION_SYSTEM_PROMPT, REVISE_SYSTEM_PROMPT, } from "./prompts.js";
2
+ import { ANSWER_START_BUILDING } from "./types.js";
3
+ export const MIN_QUESTIONS = 1;
4
+ export const MAX_QUESTIONS = 5;
5
+ /**
6
+ * Ask the smart-glue model for the next clarifying question.
7
+ * - questionNum < MAX_QUESTIONS: returns a question or done=true
8
+ * - questionNum >= MAX_QUESTIONS: forces done=true to bound the loop
9
+ * - questionNum < MIN_QUESTIONS: refuses to mark done=true; if the
10
+ * model insists, we keep going and synthesize a generic question.
11
+ */
12
+ export async function generateQuestion(glue, originalPrompt, qaHistory, questionNum, signal) {
13
+ if (questionNum >= MAX_QUESTIONS) {
14
+ return { done: true, reason: `reached max ${MAX_QUESTIONS} questions` };
15
+ }
16
+ const prompt = buildQuestionPrompt(originalPrompt, qaHistory);
17
+ let raw;
18
+ try {
19
+ raw = await glue.smart(prompt, QUESTION_SYSTEM_PROMPT, signal);
20
+ }
21
+ catch (err) {
22
+ return { done: true, reason: `glue error: ${err instanceof Error ? err.message : String(err)}` };
23
+ }
24
+ const parsed = extractJson(raw);
25
+ if (!parsed)
26
+ return { done: true, reason: "LLM returned no parseable JSON" };
27
+ if (typeof parsed === "object" &&
28
+ parsed !== null &&
29
+ "done" in parsed &&
30
+ parsed.done === true) {
31
+ if (questionNum < MIN_QUESTIONS) {
32
+ // Model wants to stop too early — ask one synthesized fallback.
33
+ return {
34
+ question: {
35
+ id: `q${questionNum + 1}`,
36
+ question: "What's the most important constraint or non-goal for this work?",
37
+ },
38
+ done: false,
39
+ };
40
+ }
41
+ return { done: true };
42
+ }
43
+ const q = normalizeQuestion(parsed, questionNum);
44
+ if (!q)
45
+ return { done: true, reason: "could not normalize question payload" };
46
+ return { question: q, done: false };
47
+ }
48
+ /** Generate a complete plan markdown from the original prompt + Q&A history. */
49
+ export async function generatePlan(glue, originalPrompt, qaHistory, signal) {
50
+ const prompt = buildPlanPrompt(originalPrompt, qaHistory);
51
+ const raw = await glue.smart(prompt, PLAN_SYSTEM_PROMPT, signal);
52
+ return raw.trim();
53
+ }
54
+ /** Apply user feedback to an existing plan and return the full revised plan. */
55
+ export async function revisePlan(glue, currentPlan, feedback, signal) {
56
+ const prompt = `Current plan:\n\n${currentPlan}\n\nUser feedback:\n${feedback}`;
57
+ const raw = await glue.smart(prompt, REVISE_SYSTEM_PROMPT, signal);
58
+ return raw.trim();
59
+ }
60
+ /**
61
+ * Wrap the approved plan as the prompt the main agent will receive.
62
+ * Header + footer phrasing is tuned to keep weaker models on-plan; do
63
+ * not casually rewrite them.
64
+ */
65
+ export function buildAgentPrompt(originalPrompt, plan, qaHistory) {
66
+ const lines = [AGENT_PROMPT_HEADER, "", `Original request: ${originalPrompt}`];
67
+ if (qaHistory.length > 0) {
68
+ lines.push("", "Clarifications:");
69
+ for (const qa of qaHistory) {
70
+ lines.push(`- Q: ${qa.question}`);
71
+ lines.push(` A: ${qa.answer}`);
72
+ }
73
+ }
74
+ lines.push("", "Plan:", plan, "", AGENT_PROMPT_FOOTER);
75
+ return lines.join("\n");
76
+ }
77
+ /**
78
+ * Interpret raw user input as an answer to a multiple-choice question.
79
+ * - 1-based number matching an option → the option's label
80
+ * - exact label match (case-insensitive) → the canonical label
81
+ * - input that matches the "start building" escape number → ANSWER_START_BUILDING
82
+ * - anything else → the trimmed raw input (free-form)
83
+ */
84
+ export function parseAnswer(input, question) {
85
+ const trimmed = input.trim();
86
+ if (!trimmed)
87
+ return trimmed;
88
+ if (!question?.options || question.options.length === 0)
89
+ return trimmed;
90
+ const idx = Number.parseInt(trimmed, 10);
91
+ if (Number.isFinite(idx)) {
92
+ if (idx >= 1 && idx <= question.options.length) {
93
+ return question.options[idx - 1].label;
94
+ }
95
+ // Escape: option count + 1 means "start building, skip remaining questions".
96
+ if (idx === question.options.length + 1)
97
+ return ANSWER_START_BUILDING;
98
+ }
99
+ const exact = question.options.find((o) => o.label.toLowerCase() === trimmed.toLowerCase());
100
+ if (exact)
101
+ return exact.label;
102
+ return trimmed;
103
+ }
104
+ // ─── helpers ──────────────────────────────────────────────────
105
+ function buildQuestionPrompt(originalPrompt, qaHistory) {
106
+ const lines = [`User request: ${originalPrompt}`];
107
+ if (qaHistory.length > 0) {
108
+ lines.push("", "Q&A so far:");
109
+ for (const qa of qaHistory) {
110
+ lines.push(`Q: ${qa.question}`);
111
+ lines.push(`A: ${qa.answer}`);
112
+ }
113
+ }
114
+ else {
115
+ lines.push("", "(no clarifications yet)");
116
+ }
117
+ return lines.join("\n");
118
+ }
119
+ function buildPlanPrompt(originalPrompt, qaHistory) {
120
+ const lines = [`User request: ${originalPrompt}`];
121
+ if (qaHistory.length > 0) {
122
+ lines.push("", "Clarifications:");
123
+ for (const qa of qaHistory) {
124
+ lines.push(`Q: ${qa.question}`);
125
+ lines.push(`A: ${qa.answer}`);
126
+ }
127
+ }
128
+ return lines.join("\n");
129
+ }
130
+ /**
131
+ * Extract a JSON object from a possibly-noisy LLM response. Some cheap
132
+ * models prefix or suffix prose; this finds the first balanced { ... }
133
+ * span and parses that. Returns null if nothing parses.
134
+ */
135
+ export function extractJson(raw) {
136
+ const trimmed = raw.trim();
137
+ try {
138
+ return JSON.parse(trimmed);
139
+ }
140
+ catch {
141
+ // fall through
142
+ }
143
+ const start = trimmed.indexOf("{");
144
+ if (start === -1)
145
+ return null;
146
+ let depth = 0;
147
+ let inString = false;
148
+ let inEscape = false;
149
+ for (let i = start; i < trimmed.length; i++) {
150
+ const ch = trimmed[i];
151
+ if (inEscape) {
152
+ inEscape = false;
153
+ continue;
154
+ }
155
+ if (ch === "\\" && inString) {
156
+ inEscape = true;
157
+ continue;
158
+ }
159
+ if (ch === '"') {
160
+ inString = !inString;
161
+ continue;
162
+ }
163
+ if (inString)
164
+ continue;
165
+ if (ch === "{")
166
+ depth++;
167
+ else if (ch === "}") {
168
+ depth--;
169
+ if (depth === 0) {
170
+ const candidate = trimmed.slice(start, i + 1);
171
+ try {
172
+ return JSON.parse(candidate);
173
+ }
174
+ catch {
175
+ return null;
176
+ }
177
+ }
178
+ }
179
+ }
180
+ return null;
181
+ }
182
+ function normalizeQuestion(raw, questionNum) {
183
+ if (!raw || typeof raw !== "object")
184
+ return null;
185
+ const r = raw;
186
+ if (typeof r.question !== "string" || !r.question.trim())
187
+ return null;
188
+ let options;
189
+ if (Array.isArray(r.options)) {
190
+ options = r.options
191
+ .map((o, i) => normalizeOption(o, i))
192
+ .filter((o) => o !== null);
193
+ if (options.length === 0)
194
+ options = undefined;
195
+ }
196
+ return {
197
+ id: `q${questionNum + 1}`,
198
+ question: r.question.trim(),
199
+ options,
200
+ };
201
+ }
202
+ function normalizeOption(raw, idx) {
203
+ if (!raw || typeof raw !== "object")
204
+ return null;
205
+ const r = raw;
206
+ if (typeof r.label !== "string" || !r.label.trim())
207
+ return null;
208
+ return {
209
+ id: typeof r.id === "string" && r.id.trim() ? r.id : `opt${idx + 1}`,
210
+ label: r.label.trim(),
211
+ description: typeof r.description === "string" ? r.description : undefined,
212
+ };
213
+ }
214
+ //# sourceMappingURL=flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow.js","sourceRoot":"","sources":["../../src/plan/flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Exact prompt phrasing preserved from the Go v1 plan flow. Changes to
3
+ * these strings should be deliberate — the Go version's tests pinned
4
+ * specific phrases so cheap models reliably emit JSON-shaped questions
5
+ * and stick to the plan during execution.
6
+ */
7
+ export const QUESTION_SYSTEM_PROMPT = `You design clarifying questions for a coding agent that will execute a multi-step plan.
8
+
9
+ You will be given the user's original request and a list of question/answer pairs already collected. Generate the NEXT useful question, or signal that you have enough information.
10
+
11
+ Output ONE valid JSON object on stdout, no prose around it. Two shapes are allowed:
12
+
13
+ 1) A new question:
14
+ {
15
+ "question": "How should authentication be handled?",
16
+ "options": [
17
+ { "id": "opt1", "label": "Email + password", "description": "Classic email/password login" },
18
+ { "id": "opt2", "label": "Magic link", "description": "Passwordless email link" }
19
+ ]
20
+ }
21
+
22
+ 2) A signal that no more questions are needed:
23
+ { "done": true }
24
+
25
+ Hard rules:
26
+ - Ask the question that most reduces ambiguity for the next step.
27
+ - Return options ONLY when there's a clean small choice set (2-5 options). Otherwise omit options for free-form answer.
28
+ - DO NOT ask follow-ups to questions already answered.
29
+ - DO NOT ask cosmetic questions ("which color?") unless the user request is itself cosmetic.
30
+ - After ~3-5 useful questions, signal done.`;
31
+ export const PLAN_SYSTEM_PROMPT = `You produce a step-by-step implementation plan based on a user request and a Q&A clarification log.
32
+
33
+ Output: a markdown plan, no preamble. Use this structure:
34
+
35
+ # <Short title>
36
+
37
+ ## Goal
38
+ One-sentence goal.
39
+
40
+ ## Steps
41
+ 1. <First concrete action — file/command level>
42
+ 2. <Next action>
43
+ ...
44
+
45
+ ## Files
46
+ - <path>: <one-line role>
47
+ - <path>: <one-line role>
48
+
49
+ ## Tests
50
+ - <how we'll verify each step works>
51
+
52
+ Hard rules:
53
+ - Be concrete. Reference specific files, functions, commands.
54
+ - Number every step. The agent will execute them in order.
55
+ - Keep it tight: aim for 5-15 steps, not 30.
56
+ - DO NOT include questions, caveats, or "if X then Y" branching. The Q&A is over.`;
57
+ export const REVISE_SYSTEM_PROMPT = `You revise an existing implementation plan based on user feedback.
58
+
59
+ Output: the FULL revised plan in the same markdown format. Don't write a diff or summary of changes. Don't ask follow-up questions — apply the feedback directly.
60
+
61
+ If the feedback is unclear or conflicts with the plan, make the most reasonable interpretation and proceed.`;
62
+ /**
63
+ * Wrapper text used when handing the approved plan back to the main
64
+ * agent. Phrasing tuned (Go v1) so weaker models stick to the plan
65
+ * instead of re-planning mid-execution.
66
+ */
67
+ export const AGENT_PROMPT_HEADER = "Build this project. Follow the approved plan exactly.";
68
+ export const AGENT_PROMPT_FOOTER = "Follow the plan step by step. Implement every listed item. Keep going until all files are written.";
69
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/plan/prompts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;4CAuBM,CAAC;AAE7C,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;kFAyBgD,CAAC;AAEnF,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;4GAIwE,CAAC;AAE7G;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,uDAAuD,CAAC;AAC3F,MAAM,CAAC,MAAM,mBAAmB,GAC/B,oGAAoG,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Per-agent-instance flag telling the permission gate to block destructive
3
+ * tools while the agent is producing a plan. Mode-driven by the model via
4
+ * enter_plan_mode / exit_plan_mode tool calls, or by the App's plan flow
5
+ * when the user approved a plan via the glue layer's Q&A.
6
+ */
7
+ export class PlanModeStore {
8
+ active = false;
9
+ listeners = new Set();
10
+ enter() {
11
+ if (this.active)
12
+ return;
13
+ this.active = true;
14
+ this.notify();
15
+ }
16
+ exit() {
17
+ if (!this.active)
18
+ return;
19
+ this.active = false;
20
+ this.notify();
21
+ }
22
+ isActive() {
23
+ return this.active;
24
+ }
25
+ subscribe(listener) {
26
+ this.listeners.add(listener);
27
+ listener(this.active);
28
+ return () => {
29
+ this.listeners.delete(listener);
30
+ };
31
+ }
32
+ notify() {
33
+ for (const listener of this.listeners)
34
+ listener(this.active);
35
+ }
36
+ }
37
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/plan/store.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACjB,MAAM,GAAG,KAAK,CAAC;IACN,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEzD,KAAK;QACJ,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAED,IAAI;QACH,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QACzB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAED,QAAQ;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED,SAAS,CAAC,QAA0B;QACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,OAAO,GAAG,EAAE;YACX,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC;IACH,CAAC;IAEO,MAAM;QACb,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;CACD"}
@@ -0,0 +1,3 @@
1
+ /** Special return value from parseAnswer when the user types "skip the rest, start". */
2
+ export const ANSWER_START_BUILDING = "__START_BUILDING__";
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plan/types.ts"],"names":[],"mappings":"AAyBA,wFAAwF;AACxF,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC"}
@@ -0,0 +1,105 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ export const SESSION_MAX_AGE_DAYS = 7;
6
+ export const SESSION_FORMAT_VERSION = 1;
7
+ /**
8
+ * Per-cwd session snapshot. Filename is keyed off sha256(cwd)[:8] so we
9
+ * can find prior sessions for the same directory across cli launches.
10
+ *
11
+ * load() returns null when no session exists, when the saved session
12
+ * predates `maxAgeDays`, or when the saved model id doesn't match the
13
+ * currently-resolved model — switching models invalidates compaction
14
+ * summaries and tool histories so a fresh start is the safer default.
15
+ */
16
+ export class SessionStore {
17
+ cwd;
18
+ path;
19
+ maxAgeMs;
20
+ constructor(options) {
21
+ this.cwd = options.cwd;
22
+ const dataRoot = options.dataRoot ?? join(homedir(), ".codebase");
23
+ const hash = createHash("sha256").update(this.cwd).digest("hex").slice(0, 8);
24
+ this.path = join(dataRoot, "sessions", `${hash}.json`);
25
+ this.maxAgeMs = (options.maxAgeDays ?? SESSION_MAX_AGE_DAYS) * 24 * 60 * 60 * 1000;
26
+ }
27
+ get filePath() {
28
+ return this.path;
29
+ }
30
+ load(modelId) {
31
+ if (!existsSync(this.path))
32
+ return null;
33
+ let raw;
34
+ try {
35
+ raw = readFileSync(this.path, "utf8");
36
+ }
37
+ catch {
38
+ return null;
39
+ }
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(raw);
43
+ }
44
+ catch {
45
+ // Malformed: drop the file so we don't trip over it forever.
46
+ this.clear();
47
+ return null;
48
+ }
49
+ if (parsed.formatVersion !== SESSION_FORMAT_VERSION)
50
+ return null;
51
+ if (parsed.workDir !== this.cwd)
52
+ return null;
53
+ if (parsed.modelId !== modelId)
54
+ return null;
55
+ if (Date.now() - parsed.updatedAt > this.maxAgeMs) {
56
+ this.clear();
57
+ return null;
58
+ }
59
+ if (!Array.isArray(parsed.messages) || parsed.messages.length === 0)
60
+ return null;
61
+ return parsed;
62
+ }
63
+ save(data) {
64
+ const dir = join(this.path, "..");
65
+ mkdirSync(dir, { recursive: true });
66
+ const payload = {
67
+ formatVersion: SESSION_FORMAT_VERSION,
68
+ workDir: this.cwd,
69
+ updatedAt: Date.now(),
70
+ ...data,
71
+ };
72
+ const tmp = `${this.path}.${randomBytes(4).toString("hex")}.tmp`;
73
+ try {
74
+ writeFileSync(tmp, JSON.stringify(payload, null, 2), { mode: 0o600 });
75
+ renameSync(tmp, this.path);
76
+ }
77
+ catch (err) {
78
+ try {
79
+ unlinkSync(tmp);
80
+ }
81
+ catch {
82
+ // best effort
83
+ }
84
+ throw err;
85
+ }
86
+ }
87
+ clear() {
88
+ if (!existsSync(this.path))
89
+ return false;
90
+ try {
91
+ unlinkSync(this.path);
92
+ return true;
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ }
98
+ /** Modification time of the persisted session, or null if absent. */
99
+ mtime() {
100
+ if (!existsSync(this.path))
101
+ return null;
102
+ return statSync(this.path).mtimeMs;
103
+ }
104
+ }
105
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/sessions/store.ts"],"names":[],"mappings":"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"}