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,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Text } from "ink";
3
+ import { useEffect, useState } from "react";
4
+ const FRAMES = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
5
+ /**
6
+ * Self-throttling spinner. Owns its own interval so the parent's reducer
7
+ * state isn't ticked on every frame — a hot stream of message_update events
8
+ * + a 100ms spinner would otherwise compound into needless full re-renders.
9
+ */
10
+ export function Throbber({ color = "cyan", intervalMs = 80 }) {
11
+ const [frame, setFrame] = useState(0);
12
+ useEffect(() => {
13
+ const id = setInterval(() => {
14
+ setFrame((f) => (f + 1) % FRAMES.length);
15
+ }, intervalMs);
16
+ return () => clearInterval(id);
17
+ }, [intervalMs]);
18
+ return _jsx(Text, { color: color, children: FRAMES[frame] });
19
+ }
20
+ //# sourceMappingURL=Throbber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Throbber.js","sourceRoot":"","sources":["../../src/ui/Throbber.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAOxD;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,UAAU,GAAG,EAAE,EAAiB;IAC1E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtC,SAAS,CAAC,GAAG,EAAE;QACd,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE;YAC3B,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC,EAAE,UAAU,CAAC,CAAC;QACf,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjB,OAAO,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,MAAM,CAAC,KAAK,CAAC,GAAQ,CAAC;AACnD,CAAC"}
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { useEffect, useState } from "react";
4
+ /**
5
+ * Sticky panel showing in-flight tool calls. Pulls from ChatState's
6
+ * tools map (pi-agent-core's tool_execution_start/update/end events)
7
+ * and only renders rows whose status is "running" — completed tools
8
+ * already appear as toolResult messages in the main chat, so showing
9
+ * them again here would be noise.
10
+ *
11
+ * Re-renders once per second to tick the elapsed counter without
12
+ * disturbing the parent reducer. The interval is cheap and only runs
13
+ * while at least one tool is in flight.
14
+ */
15
+ export function ToolPanel({ tools, previewLines = 3 }) {
16
+ const running = [];
17
+ for (const tool of tools.values()) {
18
+ if (tool.status === "running")
19
+ running.push(tool);
20
+ }
21
+ const [, force] = useState(0);
22
+ // Tick once a second so elapsed counters update. The interval only runs
23
+ // while a tool is actually running — when `tools` changes such that the
24
+ // running set is empty, the cleanup tears down the timer.
25
+ useEffect(() => {
26
+ let hasRunning = false;
27
+ for (const tool of tools.values()) {
28
+ if (tool.status === "running") {
29
+ hasRunning = true;
30
+ break;
31
+ }
32
+ }
33
+ if (!hasRunning)
34
+ return;
35
+ const id = setInterval(() => force((n) => n + 1), 1000);
36
+ return () => clearInterval(id);
37
+ }, [tools]);
38
+ if (running.length === 0)
39
+ return null;
40
+ return (_jsx(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: running.map((tool) => (_jsx(RunningTool, { tool: tool, previewLines: previewLines }, tool.id))) }));
41
+ }
42
+ function RunningTool({ tool, previewLines }) {
43
+ const elapsed = Math.max(0, Math.round((Date.now() - tool.startedAt) / 1000));
44
+ const argsHint = summarizeArgs(tool.args);
45
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "magenta", children: "\u2192 " }), _jsx(Text, { color: "magenta", bold: true, children: tool.name }), argsHint ? _jsx(Text, { dimColor: true, children: ` (${argsHint})` }) : null, _jsx(Text, { dimColor: true, children: ` · ${elapsed}s` })] }), tool.result ? _jsx(PartialOutput, { text: tool.result, maxLines: previewLines }) : null] }));
46
+ }
47
+ function PartialOutput({ text, maxLines }) {
48
+ const lines = text.replace(/\r/g, "").split("\n").filter(Boolean);
49
+ const tail = lines.slice(-maxLines);
50
+ if (tail.length === 0)
51
+ return null;
52
+ return (_jsx(Box, { flexDirection: "column", marginLeft: 2, children: tail.map((line, i) => (
53
+ // PartialOutput is purely presentational — index keys are safe
54
+ // because the tail slides forward as new lines arrive and there's
55
+ // no per-line state to mix up.
56
+ // biome-ignore lint/suspicious/noArrayIndexKey: stateless leaf
57
+ _jsx(Text, { dimColor: true, children: truncate(line, 100) }, i))) }));
58
+ }
59
+ function summarizeArgs(args) {
60
+ if (!args || typeof args !== "object")
61
+ return "";
62
+ const entries = Object.entries(args).slice(0, 2);
63
+ return entries
64
+ .map(([k, v]) => {
65
+ const s = typeof v === "string" ? `"${truncate(v, 24)}"` : safeJson(v);
66
+ return `${k}=${s}`;
67
+ })
68
+ .join(", ");
69
+ }
70
+ function safeJson(v) {
71
+ try {
72
+ return JSON.stringify(v).slice(0, 24);
73
+ }
74
+ catch {
75
+ return String(v).slice(0, 24);
76
+ }
77
+ }
78
+ function truncate(s, max) {
79
+ if (s.length <= max)
80
+ return s;
81
+ return `${s.slice(0, max - 1)}…`;
82
+ }
83
+ //# sourceMappingURL=ToolPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolPanel.js","sourceRoot":"","sources":["../../src/ui/ToolPanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { useState } from "react";
4
+ /**
5
+ * Free-form text input for the ask_user tool. Mirrors Input.tsx but
6
+ * with a question header above and routes its result to the user-query
7
+ * store instead of the chat reducer.
8
+ */
9
+ export function UserQueryView({ query, onAnswer, onCancel }) {
10
+ const [buffer, setBuffer] = useState("");
11
+ useInput((input, key) => {
12
+ if (key.ctrl && input === "c") {
13
+ onCancel();
14
+ return;
15
+ }
16
+ if (key.escape) {
17
+ onCancel();
18
+ return;
19
+ }
20
+ if (key.return) {
21
+ const trimmed = buffer.trim();
22
+ if (trimmed.length > 0) {
23
+ onAnswer(trimmed);
24
+ setBuffer("");
25
+ }
26
+ return;
27
+ }
28
+ if (key.backspace || key.delete) {
29
+ setBuffer((b) => b.slice(0, -1));
30
+ return;
31
+ }
32
+ if (input && !key.ctrl && !key.meta) {
33
+ setBuffer((b) => b + input);
34
+ }
35
+ });
36
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginY: 0, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: "magenta", children: ["? ", query.question] }) }), query.options && query.options.length > 0 ? (_jsx(Box, { flexDirection: "column", marginLeft: 2, children: query.options.map((option, i) => (_jsx(Text, { dimColor: true, children: `${i + 1}. ${option}` }, `${i}-${option}`))) })) : null, _jsxs(Box, { children: [_jsx(Text, { color: "magenta", children: "> " }), _jsx(Text, { children: buffer }), _jsx(Text, { color: "magenta", children: "\u258E" })] }), query.placeholder ? (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { dimColor: true, children: query.placeholder }) })) : null] }));
37
+ }
38
+ //# sourceMappingURL=UserQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserQuery.js","sourceRoot":"","sources":["../../src/ui/UserQuery.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AASjC;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAkB;IAC1E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEzC,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,IAAI,GAAG,CAAC,IAAI,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAC/B,QAAQ,EAAE,CAAC;YACX,OAAO;QACR,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,QAAQ,EAAE,CAAC;YACX,OAAO;QACR,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAClB,SAAS,CAAC,EAAE,CAAC,CAAC;YACf,CAAC;YACD,OAAO;QACR,CAAC;QACD,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACjC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACjC,OAAO;QACR,CAAC;QACD,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACrC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO,CACN,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,aAClD,KAAC,GAAG,cACH,MAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,mBACtB,KAAK,CAAC,QAAQ,IACX,GACF,EACL,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC5C,KAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC,YACvC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CACjC,KAAC,IAAI,IAAwB,QAAQ,kBACnC,GAAG,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,IADZ,GAAG,CAAC,IAAI,MAAM,EAAE,CAEpB,CACP,CAAC,GACG,CACN,CAAC,CAAC,CAAC,IAAI,EACR,MAAC,GAAG,eACH,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,YAAE,IAAI,GAAQ,EACnC,KAAC,IAAI,cAAE,MAAM,GAAQ,EACrB,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,uBAAS,IACzB,EACL,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CACpB,KAAC,GAAG,IAAC,UAAU,EAAE,CAAC,YACjB,KAAC,IAAI,IAAC,QAAQ,kBAAE,KAAK,CAAC,WAAW,GAAQ,GACpC,CACN,CAAC,CAAC,CAAC,IAAI,IACH,CACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Pure state machine for the input editor. Pulled out of the React
3
+ * component so we can unit-test cursor / kill-ring / undo behavior
4
+ * without standing up an Ink instance.
5
+ *
6
+ * Conventions match Emacs / readline so muscle memory transfers:
7
+ * Ctrl-A / Ctrl-E → start / end of line
8
+ * Ctrl-K / Ctrl-U → kill to end / kill to start
9
+ * Ctrl-W → kill word before cursor
10
+ * Ctrl-D / Backspace → delete forward / backward
11
+ * Ctrl-Y → yank (paste from kill ring)
12
+ * Ctrl-Z → undo
13
+ *
14
+ * The kill ring follows the Emacs accumulation rule: consecutive kills
15
+ * concatenate into a single ring entry; any non-kill action breaks the
16
+ * chain so the next kill starts a fresh entry.
17
+ */
18
+ const MAX_UNDO = 100;
19
+ const MAX_KILL_RING = 60;
20
+ export function initialInputState() {
21
+ return { buffer: "", cursor: 0, killRing: [], undoStack: [], lastAction: "init" };
22
+ }
23
+ export function setBuffer(state, buffer) {
24
+ const cursor = Math.min(state.cursor, buffer.length);
25
+ return { ...state, buffer, cursor, lastAction: "type" };
26
+ }
27
+ export function insertChar(state, ch) {
28
+ if (!ch)
29
+ return state;
30
+ const next = {
31
+ ...state,
32
+ buffer: state.buffer.slice(0, state.cursor) + ch + state.buffer.slice(state.cursor),
33
+ cursor: state.cursor + ch.length,
34
+ };
35
+ // Snapshot only at boundary transitions so a long type doesn't fill the stack.
36
+ if (state.lastAction !== "type") {
37
+ next.undoStack = pushUndo(state);
38
+ }
39
+ else {
40
+ next.undoStack = state.undoStack;
41
+ }
42
+ next.lastAction = "type";
43
+ return next;
44
+ }
45
+ export function backspace(state) {
46
+ if (state.cursor === 0)
47
+ return state;
48
+ return {
49
+ ...state,
50
+ buffer: state.buffer.slice(0, state.cursor - 1) + state.buffer.slice(state.cursor),
51
+ cursor: state.cursor - 1,
52
+ undoStack: pushUndo(state),
53
+ lastAction: "delete",
54
+ };
55
+ }
56
+ export function deleteForward(state) {
57
+ if (state.cursor >= state.buffer.length)
58
+ return state;
59
+ return {
60
+ ...state,
61
+ buffer: state.buffer.slice(0, state.cursor) + state.buffer.slice(state.cursor + 1),
62
+ undoStack: pushUndo(state),
63
+ lastAction: "delete",
64
+ };
65
+ }
66
+ export function moveLeft(state) {
67
+ if (state.cursor === 0)
68
+ return { ...state, lastAction: "move" };
69
+ return { ...state, cursor: state.cursor - 1, lastAction: "move" };
70
+ }
71
+ export function moveRight(state) {
72
+ if (state.cursor >= state.buffer.length)
73
+ return { ...state, lastAction: "move" };
74
+ return { ...state, cursor: state.cursor + 1, lastAction: "move" };
75
+ }
76
+ export function moveStart(state) {
77
+ return { ...state, cursor: 0, lastAction: "move" };
78
+ }
79
+ export function moveEnd(state) {
80
+ return { ...state, cursor: state.buffer.length, lastAction: "move" };
81
+ }
82
+ export function killToEnd(state) {
83
+ if (state.cursor >= state.buffer.length)
84
+ return state;
85
+ const killed = state.buffer.slice(state.cursor);
86
+ return {
87
+ ...state,
88
+ buffer: state.buffer.slice(0, state.cursor),
89
+ killRing: appendToKill(state, killed, "after"),
90
+ undoStack: pushUndo(state),
91
+ lastAction: "kill",
92
+ };
93
+ }
94
+ export function killToStart(state) {
95
+ if (state.cursor === 0)
96
+ return state;
97
+ const killed = state.buffer.slice(0, state.cursor);
98
+ return {
99
+ ...state,
100
+ buffer: state.buffer.slice(state.cursor),
101
+ cursor: 0,
102
+ killRing: appendToKill(state, killed, "before"),
103
+ undoStack: pushUndo(state),
104
+ lastAction: "kill",
105
+ };
106
+ }
107
+ export function killWordBack(state) {
108
+ if (state.cursor === 0)
109
+ return state;
110
+ const wordStart = findWordBoundaryBack(state.buffer, state.cursor);
111
+ const killed = state.buffer.slice(wordStart, state.cursor);
112
+ if (!killed)
113
+ return state;
114
+ return {
115
+ ...state,
116
+ buffer: state.buffer.slice(0, wordStart) + state.buffer.slice(state.cursor),
117
+ cursor: wordStart,
118
+ killRing: appendToKill(state, killed, "before"),
119
+ undoStack: pushUndo(state),
120
+ lastAction: "kill",
121
+ };
122
+ }
123
+ export function killWordForward(state) {
124
+ if (state.cursor >= state.buffer.length)
125
+ return state;
126
+ const wordEnd = findWordBoundaryForward(state.buffer, state.cursor);
127
+ const killed = state.buffer.slice(state.cursor, wordEnd);
128
+ if (!killed)
129
+ return state;
130
+ return {
131
+ ...state,
132
+ buffer: state.buffer.slice(0, state.cursor) + state.buffer.slice(wordEnd),
133
+ killRing: appendToKill(state, killed, "after"),
134
+ undoStack: pushUndo(state),
135
+ lastAction: "kill",
136
+ };
137
+ }
138
+ export function yank(state) {
139
+ const top = state.killRing[state.killRing.length - 1];
140
+ if (!top)
141
+ return state;
142
+ return {
143
+ ...state,
144
+ buffer: state.buffer.slice(0, state.cursor) + top + state.buffer.slice(state.cursor),
145
+ cursor: state.cursor + top.length,
146
+ undoStack: pushUndo(state),
147
+ lastAction: "yank",
148
+ };
149
+ }
150
+ export function undo(state) {
151
+ if (state.undoStack.length === 0)
152
+ return state;
153
+ const prev = state.undoStack[state.undoStack.length - 1];
154
+ return {
155
+ ...state,
156
+ buffer: prev.buffer,
157
+ cursor: prev.cursor,
158
+ undoStack: state.undoStack.slice(0, -1),
159
+ lastAction: "undo",
160
+ };
161
+ }
162
+ export function reset() {
163
+ return initialInputState();
164
+ }
165
+ // ─── helpers ─────────────────────────────────────────────────
166
+ function pushUndo(state) {
167
+ const snapshot = { buffer: state.buffer, cursor: state.cursor };
168
+ const next = [...state.undoStack, snapshot];
169
+ return next.length > MAX_UNDO ? next.slice(next.length - MAX_UNDO) : next;
170
+ }
171
+ /**
172
+ * Append `killed` to the most recent kill-ring entry if the previous
173
+ * action was also a kill (Emacs convention); otherwise push a new
174
+ * entry. `direction` controls whether this kill is concatenated before
175
+ * or after the existing entry — Ctrl-W/Backward kills prepend, Ctrl-K
176
+ * forward kills append.
177
+ */
178
+ function appendToKill(state, killed, direction) {
179
+ const ring = state.killRing.slice();
180
+ if (state.lastAction === "kill" && ring.length > 0) {
181
+ const head = ring[ring.length - 1];
182
+ ring[ring.length - 1] = direction === "before" ? killed + head : head + killed;
183
+ }
184
+ else {
185
+ ring.push(killed);
186
+ if (ring.length > MAX_KILL_RING)
187
+ ring.shift();
188
+ }
189
+ return ring;
190
+ }
191
+ const WORD_CHAR_RE = /[A-Za-z0-9_]/;
192
+ function findWordBoundaryBack(buffer, from) {
193
+ let i = from;
194
+ // Skip non-word chars first
195
+ while (i > 0 && !WORD_CHAR_RE.test(buffer[i - 1]))
196
+ i--;
197
+ // Then skip word chars
198
+ while (i > 0 && WORD_CHAR_RE.test(buffer[i - 1]))
199
+ i--;
200
+ return i;
201
+ }
202
+ function findWordBoundaryForward(buffer, from) {
203
+ let i = from;
204
+ while (i < buffer.length && !WORD_CHAR_RE.test(buffer[i]))
205
+ i++;
206
+ while (i < buffer.length && WORD_CHAR_RE.test(buffer[i]))
207
+ i++;
208
+ return i;
209
+ }
210
+ //# sourceMappingURL=input-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-state.js","sourceRoot":"","sources":["../../src/ui/input-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import wrapAnsi from "wrap-ansi";
2
+ /**
3
+ * Pre-wrap text to fit within `maxWidth` columns at word boundaries.
4
+ *
5
+ * Why we pre-wrap: Ink's `<Text>` will auto-wrap, but the wraps go
6
+ * straight to the terminal as visual line breaks. When the user
7
+ * select-and-copies, they get those wraps as `\n` chars in their
8
+ * clipboard — usually mid-word at column edges, which is the exact
9
+ * pi-tui complaint. Pre-wrapping at word boundaries means the `\n`s
10
+ * the user gets are at sensible positions.
11
+ *
12
+ * - `hard: true` so very long tokens (URLs, code identifiers) break
13
+ * at the column edge instead of overflowing.
14
+ * - `trim: false` preserves leading whitespace (indentation) so
15
+ * copied code doesn't lose its structure. Trailing whitespace per
16
+ * line is stripped manually below — wrap-ansi's `trim: true` would
17
+ * kill leading whitespace too, which is the wrong tradeoff.
18
+ */
19
+ export function wrapText(text, maxWidth) {
20
+ if (!text)
21
+ return [""];
22
+ if (maxWidth <= 0)
23
+ return text.split("\n");
24
+ const wrapped = wrapAnsi(text, maxWidth, { hard: true, trim: false });
25
+ return wrapped.split("\n").map(stripTrailingWhitespace);
26
+ }
27
+ function stripTrailingWhitespace(line) {
28
+ return line.replace(/[ \t]+$/, "");
29
+ }
30
+ //# sourceMappingURL=wrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap.js","sourceRoot":"","sources":["../../src/ui/wrap.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,QAAgB;IACtD,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACvB,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAY;IAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,60 @@
1
+ export class UserQueryCancelled extends Error {
2
+ constructor() {
3
+ super("user cancelled the query");
4
+ this.name = "UserQueryCancelled";
5
+ }
6
+ }
7
+ /**
8
+ * Per-agent-instance store that the ask_user tool blocks on. Mirrors the
9
+ * shape of PermissionStore — queue of pending requests, FIFO processing,
10
+ * UI subscribes to render the head and resolve via respond().
11
+ */
12
+ export class UserQueryStore {
13
+ queue = [];
14
+ listeners = new Set();
15
+ counter = 0;
16
+ ask(input) {
17
+ return new Promise((resolve, reject) => {
18
+ const query = {
19
+ id: `q-${++this.counter}`,
20
+ question: input.question,
21
+ options: input.options,
22
+ placeholder: input.placeholder,
23
+ };
24
+ this.queue.push({ query, resolve, reject });
25
+ this.notify();
26
+ });
27
+ }
28
+ current() {
29
+ return this.queue[0]?.query;
30
+ }
31
+ subscribe(listener) {
32
+ this.listeners.add(listener);
33
+ listener(this.current());
34
+ return () => {
35
+ this.listeners.delete(listener);
36
+ };
37
+ }
38
+ respond(id, answer) {
39
+ const head = this.queue[0];
40
+ if (!head || head.query.id !== id)
41
+ return;
42
+ head.resolve(answer);
43
+ this.queue.shift();
44
+ this.notify();
45
+ }
46
+ cancel(id) {
47
+ const head = this.queue[0];
48
+ if (!head || head.query.id !== id)
49
+ return;
50
+ head.reject(new UserQueryCancelled());
51
+ this.queue.shift();
52
+ this.notify();
53
+ }
54
+ notify() {
55
+ const cur = this.current();
56
+ for (const listener of this.listeners)
57
+ listener(cur);
58
+ }
59
+ }
60
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/user-queries/store.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC5C;QACC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IAClC,CAAC;CACD;AAED;;;;GAIG;AACH,MAAM,OAAO,cAAc;IACT,KAAK,GAIjB,EAAE,CAAC;IACS,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAC;IAClD,OAAO,GAAG,CAAC,CAAC;IAEpB,GAAG,CAAC,KAAqE;QACxE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACtC,MAAM,KAAK,GAAc;gBACxB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE;gBACzB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,WAAW,EAAE,KAAK,CAAC,WAAW;aAC9B,CAAC;YACF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,OAAO;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;IAC7B,CAAC;IAED,SAAS,CAAC,QAA2B;QACpC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACzB,OAAO,GAAG,EAAE;YACX,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,EAAU,EAAE,MAAc;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE;YAAE,OAAO;QAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAED,MAAM,CAAC,EAAU;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE;YAAE,OAAO;QAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,kBAAkB,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;IACf,CAAC;IAEO,MAAM;QACb,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;IACtD,CAAC;CACD"}
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "codebase-cli",
3
+ "version": "2.0.0-pre.0",
4
+ "description": "Codebase CLI — a TypeScript coding agent on the pi-mono runtime. OAuth-aware, any LLM provider, single install.",
5
+ "keywords": [
6
+ "ai",
7
+ "agent",
8
+ "cli",
9
+ "coding",
10
+ "claude",
11
+ "openai",
12
+ "anthropic",
13
+ "developer-tools",
14
+ "terminal",
15
+ "tui"
16
+ ],
17
+ "homepage": "https://codebase.design",
18
+ "bugs": {
19
+ "url": "https://github.com/codebase-foundation/codebase-cli/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/codebase-foundation/codebase-cli.git"
24
+ },
25
+ "license": "MIT",
26
+ "author": "Codebase Foundation",
27
+ "type": "module",
28
+ "bin": {
29
+ "codebase": "bin/codebase"
30
+ },
31
+ "main": "./dist/cli.js",
32
+ "files": [
33
+ "bin/",
34
+ "dist/",
35
+ "LICENSE",
36
+ "README.md"
37
+ ],
38
+ "engines": {
39
+ "node": ">=20.0.0"
40
+ },
41
+ "publishConfig": {
42
+ "registry": "https://registry.npmjs.org/"
43
+ },
44
+ "scripts": {
45
+ "dev": "tsx src/cli.tsx",
46
+ "build": "tsc && shx chmod +x dist/cli.js",
47
+ "clean": "shx rm -rf dist",
48
+ "typecheck": "tsc --noEmit",
49
+ "lint": "biome check src/",
50
+ "lint:fix": "biome check --write src/",
51
+ "format": "biome format --write src/",
52
+ "test": "vitest --run",
53
+ "test:watch": "vitest",
54
+ "check": "npm run typecheck && npm run lint && npm test",
55
+ "prepublishOnly": "npm run clean && npm run check && npm run build",
56
+ "prepack": "npm run build"
57
+ },
58
+ "dependencies": {
59
+ "@earendil-works/pi-agent-core": "0.74.0",
60
+ "@earendil-works/pi-ai": "0.74.0",
61
+ "glob": "^13.0.1",
62
+ "ignore": "^7.0.0",
63
+ "ink": "^5.2.1",
64
+ "react": "^18.3.1",
65
+ "typebox": "^1.1.24"
66
+ },
67
+ "devDependencies": {
68
+ "@biomejs/biome": "2.3.5",
69
+ "@types/node": "^22.10.5",
70
+ "@types/react": "^18.3.18",
71
+ "shx": "^0.4.0",
72
+ "tsx": "^4.20.3",
73
+ "typescript": "^5.9.2",
74
+ "vitest": "^2.1.8"
75
+ }
76
+ }