codebase-cli 2.0.0-pre.3 → 2.0.0-pre.30

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 (77) hide show
  1. package/dist/agent/agent.js +10 -2
  2. package/dist/agent/agent.js.map +1 -1
  3. package/dist/agent/config.js +101 -20
  4. package/dist/agent/config.js.map +1 -1
  5. package/dist/agent/prompt-suggestion.js +145 -0
  6. package/dist/agent/prompt-suggestion.js.map +1 -0
  7. package/dist/agent/system-prompt.js +15 -0
  8. package/dist/agent/system-prompt.js.map +1 -1
  9. package/dist/app-server/protocol.js +7 -0
  10. package/dist/app-server/protocol.js.map +1 -0
  11. package/dist/app-server/server.js +241 -0
  12. package/dist/app-server/server.js.map +1 -0
  13. package/dist/auth/credentials.js +10 -0
  14. package/dist/auth/credentials.js.map +1 -1
  15. package/dist/auth/flow.js +145 -24
  16. package/dist/auth/flow.js.map +1 -1
  17. package/dist/cli.js +58 -6
  18. package/dist/cli.js.map +1 -1
  19. package/dist/commands/builtins.js +155 -5
  20. package/dist/commands/builtins.js.map +1 -1
  21. package/dist/commands/registry.js +46 -1
  22. package/dist/commands/registry.js.map +1 -1
  23. package/dist/glue/client.js +10 -1
  24. package/dist/glue/client.js.map +1 -1
  25. package/dist/headless/run.js +1 -1
  26. package/dist/headless/run.js.map +1 -1
  27. package/dist/hooks/manager.js +8 -2
  28. package/dist/hooks/manager.js.map +1 -1
  29. package/dist/permissions/store.js +4 -0
  30. package/dist/permissions/store.js.map +1 -1
  31. package/dist/projects/cli.js +92 -0
  32. package/dist/projects/cli.js.map +1 -0
  33. package/dist/projects/client.js +120 -0
  34. package/dist/projects/client.js.map +1 -0
  35. package/dist/projects/types.js +2 -0
  36. package/dist/projects/types.js.map +1 -0
  37. package/dist/skills/platform-loader.js +133 -38
  38. package/dist/skills/platform-loader.js.map +1 -1
  39. package/dist/tools/__test__/mock-tool-context.js +31 -0
  40. package/dist/tools/__test__/mock-tool-context.js.map +1 -0
  41. package/dist/tools/read-file.js +8 -2
  42. package/dist/tools/read-file.js.map +1 -1
  43. package/dist/ui/App.js +244 -17
  44. package/dist/ui/App.js.map +1 -1
  45. package/dist/ui/FirstRunSetup.js +66 -14
  46. package/dist/ui/FirstRunSetup.js.map +1 -1
  47. package/dist/ui/Input.js +270 -14
  48. package/dist/ui/Input.js.map +1 -1
  49. package/dist/ui/Markdown.js +286 -0
  50. package/dist/ui/Markdown.js.map +1 -0
  51. package/dist/ui/Message.js +604 -25
  52. package/dist/ui/Message.js.map +1 -1
  53. package/dist/ui/MessageList.js +100 -3
  54. package/dist/ui/MessageList.js.map +1 -1
  55. package/dist/ui/Permission.js +43 -20
  56. package/dist/ui/Permission.js.map +1 -1
  57. package/dist/ui/PixelC.js +25 -0
  58. package/dist/ui/PixelC.js.map +1 -0
  59. package/dist/ui/Status.js +213 -7
  60. package/dist/ui/Status.js.map +1 -1
  61. package/dist/ui/Throbber.js +11 -7
  62. package/dist/ui/Throbber.js.map +1 -1
  63. package/dist/ui/Welcome.js +59 -0
  64. package/dist/ui/Welcome.js.map +1 -0
  65. package/dist/ui/attachments.js +68 -0
  66. package/dist/ui/attachments.js.map +1 -0
  67. package/dist/ui/debug-input.js +44 -0
  68. package/dist/ui/debug-input.js.map +1 -0
  69. package/dist/ui/highlight.js +324 -0
  70. package/dist/ui/highlight.js.map +1 -0
  71. package/dist/ui/history-store.js +60 -0
  72. package/dist/ui/history-store.js.map +1 -0
  73. package/dist/ui/path-complete.js +102 -0
  74. package/dist/ui/path-complete.js.map +1 -0
  75. package/dist/ui/terminal-restore.js +83 -0
  76. package/dist/ui/terminal-restore.js.map +1 -0
  77. package/package.json +5 -1
@@ -1,20 +1,24 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Text } from "ink";
3
3
  import { useEffect, useState } from "react";
4
- const FRAMES = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
5
4
  /**
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.
5
+ * 8-frame pulse cycle the codebase pixel-C "scanning" through brightness
6
+ * levels. The compact (1-char) variant cycles a single block-glyph: ░▒▓█▓▒░.
7
+ * The full pixel-C variant scans a highlight row across the C shape.
8
+ *
9
+ * Self-throttling: owns its own interval so the parent's reducer state
10
+ * doesn't tick on every frame. A hot message_update stream + a 100ms
11
+ * spinner would otherwise compound into full re-renders 10× a second.
9
12
  */
10
- export function Throbber({ color = "cyan", intervalMs = 80 }) {
13
+ const COMPACT_FRAMES = ["░", "▒", "", "█", "█", "▓", "▒", "░"];
14
+ export function Throbber({ color = "cyan", intervalMs = 90 }) {
11
15
  const [frame, setFrame] = useState(0);
12
16
  useEffect(() => {
13
17
  const id = setInterval(() => {
14
- setFrame((f) => (f + 1) % FRAMES.length);
18
+ setFrame((f) => (f + 1) % COMPACT_FRAMES.length);
15
19
  }, intervalMs);
16
20
  return () => clearInterval(id);
17
21
  }, [intervalMs]);
18
- return _jsx(Text, { color: color, children: FRAMES[frame] });
22
+ return _jsx(Text, { color: color, children: COMPACT_FRAMES[frame] });
19
23
  }
20
24
  //# sourceMappingURL=Throbber.js.map
@@ -1 +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"}
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;;;;;;;;GAQG;AAEH,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAOhE,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,cAAc,CAAC,MAAM,CAAC,CAAC;QAClD,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,cAAc,CAAC,KAAK,CAAC,GAAQ,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { execSync } from "node:child_process";
3
+ import { basename } from "node:path";
4
+ import { Box, Text } from "ink";
5
+ import { PixelC } from "./PixelC.js";
6
+ /**
7
+ * Best-effort git probe for the welcome banner. Returns null if the
8
+ * cwd isn't a git repo (or if `git` isn't on PATH), so non-git
9
+ * projects get a cleaner banner instead of an empty line. We swallow
10
+ * all errors — the banner is decorative; a slow / failing git
11
+ * shouldn't block startup.
12
+ */
13
+ function readGitInfo(cwd) {
14
+ try {
15
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
16
+ cwd,
17
+ encoding: "utf8",
18
+ stdio: ["ignore", "pipe", "ignore"],
19
+ }).trim();
20
+ if (!branch)
21
+ return null;
22
+ const status = execSync("git status --porcelain", {
23
+ cwd,
24
+ encoding: "utf8",
25
+ stdio: ["ignore", "pipe", "ignore"],
26
+ });
27
+ const dirty = status.split("\n").filter((l) => l.trim().length > 0).length;
28
+ return { branch, dirty };
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ /** Humanize an absolute timestamp into "5m ago" / "3h ago" / "2d ago" — sub-minute reads as "just now". */
35
+ function formatAgo(ts) {
36
+ const sec = Math.max(0, Math.floor((Date.now() - ts) / 1000));
37
+ if (sec < 60)
38
+ return "just now";
39
+ if (sec < 3600)
40
+ return `${Math.floor(sec / 60)}m ago`;
41
+ if (sec < 86400)
42
+ return `${Math.floor(sec / 3600)}h ago`;
43
+ return `${Math.floor(sec / 86400)}d ago`;
44
+ }
45
+ /**
46
+ * Empty-state banner shown above the input while the transcript is
47
+ * empty. Pixel-C logo on the left, contextual info + tips on the
48
+ * right. Renders once and gets pushed up by the first user message —
49
+ * not Static-rendered, but only a few rows so it's cheap.
50
+ */
51
+ export function Welcome({ modelName, source, cwd, resumedFrom }) {
52
+ const cwdLabel = basename(cwd) || cwd;
53
+ const sourceLabel = source === "proxy" ? "signed in via codebase.design" : source === "byok" ? "BYOK" : `${source}`;
54
+ const gitInfo = readGitInfo(cwd);
55
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { marginRight: 2, children: _jsx(PixelC, {}) }), _jsxs(Box, { flexDirection: "column", justifyContent: "center", children: [_jsx(Text, { bold: true, color: "cyan", children: "codebase" }), _jsx(Text, { dimColor: true, children: modelName }), _jsxs(Text, { dimColor: true, children: [cwdLabel, " \u00B7 ", sourceLabel] }), gitInfo ? (_jsxs(Text, { dimColor: true, children: [gitInfo.branch, gitInfo.dirty > 0
56
+ ? ` · ${gitInfo.dirty} uncommitted change${gitInfo.dirty === 1 ? "" : "s"}`
57
+ : " · clean"] })) : null] })] }), resumedFrom ? (_jsxs(Box, { marginTop: 1, children: [_jsxs(Text, { color: "cyan", children: ["\u21BB Resumed from ", formatAgo(resumedFrom.updatedAt)] }), _jsxs(Text, { dimColor: true, children: [" ", "\u00B7 ", resumedFrom.messageCount, " message", resumedFrom.messageCount === 1 ? "" : "s"] })] })) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Ask me to read code, edit files, run commands, or anything in between." }), _jsxs(Text, { dimColor: true, children: [_jsx(Text, { color: "cyan", children: "/" }), " commands \u00B7 ", _jsx(Text, { color: "cyan", children: "!" }), "shell \u00B7 ", _jsx(Text, { color: "cyan", children: "\u2191\u2193" }), " ", "history \u00B7 ", _jsx(Text, { color: "cyan", children: "Tab" }), " complete \u00B7 ", _jsx(Text, { color: "cyan", children: "\\" }), "+Enter for newline"] }), _jsx(Text, { dimColor: true, children: "Ctrl-C twice to exit." })] })] }));
58
+ }
59
+ //# sourceMappingURL=Welcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Welcome.js","sourceRoot":"","sources":["../../src/ui/Welcome.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { readFileSync, statSync } from "node:fs";
2
+ import { isAbsolute, join } from "node:path";
3
+ export const MAX_ATTACHMENT_BYTES = 128 * 1024;
4
+ export const MAX_ATTACHMENTS = 8;
5
+ /**
6
+ * Scan the prompt for `@<path>` tokens and resolve each to a readable
7
+ * file under (or adjacent to) the cwd. Returns one entry per resolved
8
+ * file; unresolved `@` mentions don't appear here and stay as literal
9
+ * text — we never silently drop or rewrite user input.
10
+ *
11
+ * Skip rules:
12
+ * - tokens without a slash or dot (email-style @alice mentions)
13
+ * - paths over 256 chars (clearly not a real path)
14
+ * - non-files (directories, sockets, ...)
15
+ * - files larger than MAX_ATTACHMENT_BYTES
16
+ * - past MAX_ATTACHMENTS total attachments per prompt
17
+ */
18
+ export function collectAttachments(text, cwd) {
19
+ const out = [];
20
+ const seen = new Set();
21
+ const pattern = /@([A-Za-z0-9_./-]+)/g;
22
+ for (const match of text.matchAll(pattern)) {
23
+ if (out.length >= MAX_ATTACHMENTS)
24
+ break;
25
+ const rel = match[1];
26
+ if (!rel || rel.length > 256)
27
+ continue;
28
+ if (!rel.includes("/") && !rel.includes("."))
29
+ continue;
30
+ const abs = isAbsolute(rel) ? rel : join(cwd, rel);
31
+ if (seen.has(abs))
32
+ continue;
33
+ seen.add(abs);
34
+ try {
35
+ const stat = statSync(abs);
36
+ if (!stat.isFile())
37
+ continue;
38
+ if (stat.size > MAX_ATTACHMENT_BYTES)
39
+ continue;
40
+ const content = readFileSync(abs, "utf8");
41
+ out.push({ token: match[0], relPath: rel, absPath: abs, content });
42
+ }
43
+ catch {
44
+ // File doesn't exist or isn't readable — leave the token in text.
45
+ }
46
+ }
47
+ return out;
48
+ }
49
+ /**
50
+ * Build the agent-bound prompt with attachments inlined as fenced code
51
+ * blocks above the user's actual ask. The original `@path` tokens stay
52
+ * in the text so the model can correlate the references with the
53
+ * attached content.
54
+ */
55
+ export function buildAttachmentPrompt(text, attachments) {
56
+ const parts = ["Attached files (auto-inlined from @ mentions):", ""];
57
+ for (const a of attachments) {
58
+ parts.push(`### ${a.relPath}`);
59
+ parts.push("```");
60
+ parts.push(a.content);
61
+ parts.push("```");
62
+ parts.push("");
63
+ }
64
+ parts.push("---");
65
+ parts.push(text);
66
+ return parts.join("\n");
67
+ }
68
+ //# sourceMappingURL=attachments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachments.js","sourceRoot":"","sources":["../../src/ui/attachments.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAS7C,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,GAAG,IAAI,CAAC;AAC/C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,GAAW;IAC3D,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,sBAAsB,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,IAAI,GAAG,CAAC,MAAM,IAAI,eAAe;YAAE,MAAM;QACzC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG;YAAE,SAAS;QACvC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACvD,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC7B,IAAI,IAAI,CAAC,IAAI,GAAG,oBAAoB;gBAAE,SAAS;YAC/C,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACR,kEAAkE;QACnE,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,WAAkC;IACrF,MAAM,KAAK,GAAa,CAAC,gDAAgD,EAAE,EAAE,CAAC,CAAC;IAC/E,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ let logPath = null;
5
+ let warned = false;
6
+ export function isDebugInputEnabled() {
7
+ return process.env.CODEBASE_DEBUG_INPUT === "1";
8
+ }
9
+ function resolveLogPath() {
10
+ if (logPath)
11
+ return logPath;
12
+ const dir = join(homedir(), ".codebase", "logs");
13
+ try {
14
+ mkdirSync(dir, { recursive: true });
15
+ }
16
+ catch {
17
+ // The fs error is non-fatal; the appendFileSync below will throw
18
+ // the same problem and we'll surface it once via the `warned`
19
+ // guard, not on every keystroke.
20
+ }
21
+ logPath = join(dir, "input.log");
22
+ return logPath;
23
+ }
24
+ export function logInputEvent(input, key) {
25
+ if (!isDebugInputEnabled())
26
+ return;
27
+ try {
28
+ const entry = {
29
+ t: new Date().toISOString(),
30
+ // Show the actual code points so a stray \x7f or \x1b is visible.
31
+ input,
32
+ codes: Array.from(input).map((ch) => ch.charCodeAt(0)),
33
+ key,
34
+ };
35
+ appendFileSync(resolveLogPath(), `${JSON.stringify(entry)}\n`);
36
+ }
37
+ catch (err) {
38
+ if (warned)
39
+ return;
40
+ warned = true;
41
+ process.stderr.write(`\n[debug-input] failed to write log: ${err instanceof Error ? err.message : String(err)}\n`);
42
+ }
43
+ }
44
+ //# sourceMappingURL=debug-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-input.js","sourceRoot":"","sources":["../../src/ui/debug-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA8BjC,IAAI,OAAO,GAAkB,IAAI,CAAC;AAClC,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,MAAM,UAAU,mBAAmB;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG,CAAC;AACjD,CAAC;AAED,SAAS,cAAc;IACtB,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC;QACJ,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACR,iEAAiE;QACjE,8DAA8D;QAC9D,iCAAiC;IAClC,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACjC,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,GAAgB;IAC5D,IAAI,CAAC,mBAAmB,EAAE;QAAE,OAAO;IACnC,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG;YACb,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC3B,kEAAkE;YAClE,KAAK;YACL,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACtD,GAAG;SACH,CAAC;QACF,cAAc,CAAC,cAAc,EAAE,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,OAAO,CAAC,MAAM,CAAC,KAAK,CACnB,wCAAwC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAC5F,CAAC;IACH,CAAC;AACF,CAAC"}
@@ -0,0 +1,324 @@
1
+ /**
2
+ * Tiny regex-based syntax highlighter for code blocks inside markdown.
3
+ * Each language is a flat list of `(regex, kind)` rules tried in order;
4
+ * the first match wins, the matched span is emitted as a typed token,
5
+ * and the scan resumes after it. Anything not matched falls through as
6
+ * plain text.
7
+ *
8
+ * We deliberately do *not* take a 6 MB dep (highlight.js, prismjs) just
9
+ * to colorize terminal code blocks — these rules handle 95% of what an
10
+ * LLM emits and stay easy to read. If a language isn't in `LANGS`, the
11
+ * caller renders the code block as plain text.
12
+ */
13
+ const TS_KEYWORDS = [
14
+ "abstract",
15
+ "as",
16
+ "async",
17
+ "await",
18
+ "break",
19
+ "case",
20
+ "catch",
21
+ "class",
22
+ "const",
23
+ "continue",
24
+ "debugger",
25
+ "declare",
26
+ "default",
27
+ "delete",
28
+ "do",
29
+ "else",
30
+ "enum",
31
+ "export",
32
+ "extends",
33
+ "finally",
34
+ "for",
35
+ "from",
36
+ "function",
37
+ "get",
38
+ "if",
39
+ "implements",
40
+ "import",
41
+ "in",
42
+ "infer",
43
+ "instanceof",
44
+ "interface",
45
+ "is",
46
+ "keyof",
47
+ "let",
48
+ "namespace",
49
+ "new",
50
+ "null",
51
+ "of",
52
+ "package",
53
+ "private",
54
+ "protected",
55
+ "public",
56
+ "readonly",
57
+ "return",
58
+ "set",
59
+ "static",
60
+ "super",
61
+ "switch",
62
+ "this",
63
+ "throw",
64
+ "true",
65
+ "false",
66
+ "try",
67
+ "type",
68
+ "typeof",
69
+ "undefined",
70
+ "var",
71
+ "void",
72
+ "while",
73
+ "with",
74
+ "yield",
75
+ ];
76
+ const PY_KEYWORDS = [
77
+ "and",
78
+ "as",
79
+ "assert",
80
+ "async",
81
+ "await",
82
+ "break",
83
+ "class",
84
+ "continue",
85
+ "def",
86
+ "del",
87
+ "elif",
88
+ "else",
89
+ "except",
90
+ "False",
91
+ "finally",
92
+ "for",
93
+ "from",
94
+ "global",
95
+ "if",
96
+ "import",
97
+ "in",
98
+ "is",
99
+ "lambda",
100
+ "None",
101
+ "nonlocal",
102
+ "not",
103
+ "or",
104
+ "pass",
105
+ "raise",
106
+ "return",
107
+ "True",
108
+ "try",
109
+ "while",
110
+ "with",
111
+ "yield",
112
+ ];
113
+ const GO_KEYWORDS = [
114
+ "break",
115
+ "case",
116
+ "chan",
117
+ "const",
118
+ "continue",
119
+ "default",
120
+ "defer",
121
+ "else",
122
+ "fallthrough",
123
+ "for",
124
+ "func",
125
+ "go",
126
+ "goto",
127
+ "if",
128
+ "import",
129
+ "interface",
130
+ "map",
131
+ "package",
132
+ "range",
133
+ "return",
134
+ "select",
135
+ "struct",
136
+ "switch",
137
+ "type",
138
+ "var",
139
+ "nil",
140
+ "true",
141
+ "false",
142
+ ];
143
+ const SH_KEYWORDS = [
144
+ "if",
145
+ "then",
146
+ "else",
147
+ "elif",
148
+ "fi",
149
+ "for",
150
+ "in",
151
+ "do",
152
+ "done",
153
+ "while",
154
+ "until",
155
+ "case",
156
+ "esac",
157
+ "function",
158
+ "return",
159
+ "exit",
160
+ "break",
161
+ "continue",
162
+ "local",
163
+ "export",
164
+ "readonly",
165
+ "declare",
166
+ "set",
167
+ "unset",
168
+ "shift",
169
+ ];
170
+ const TS_RULES = [
171
+ { pattern: /^\/\/[^\n]*/, kind: "comment" },
172
+ { pattern: /^\/\*[\s\S]*?\*\//, kind: "comment" },
173
+ { pattern: /^`(?:[^`\\]|\\.)*`/, kind: "string" },
174
+ { pattern: /^"(?:[^"\\\n]|\\.)*"/, kind: "string" },
175
+ { pattern: /^'(?:[^'\\\n]|\\.)*'/, kind: "string" },
176
+ { pattern: /^\b(?:0x[0-9a-fA-F]+|0b[01]+|\d+\.?\d*(?:[eE][+-]?\d+)?)\b/, kind: "number" },
177
+ { pattern: new RegExp(`^\\b(?:${TS_KEYWORDS.join("|")})\\b`), kind: "keyword" },
178
+ { pattern: /^\b[A-Z][A-Za-z0-9_]*\b/, kind: "type" },
179
+ { pattern: /^[A-Za-z_$][\w$]*(?=\s*\()/, kind: "function" },
180
+ { pattern: /^[A-Za-z_$][\w$]*(?=\s*:)/, kind: "property" },
181
+ { pattern: /^[+\-*/%=<>!&|^~?:]+/, kind: "operator" },
182
+ { pattern: /^[{}[\]().,;]/, kind: "punctuation" },
183
+ ];
184
+ const PY_RULES = [
185
+ { pattern: /^#[^\n]*/, kind: "comment" },
186
+ { pattern: /^"""[\s\S]*?"""/, kind: "string" },
187
+ { pattern: /^'''[\s\S]*?'''/, kind: "string" },
188
+ { pattern: /^"(?:[^"\\\n]|\\.)*"/, kind: "string" },
189
+ { pattern: /^'(?:[^'\\\n]|\\.)*'/, kind: "string" },
190
+ { pattern: /^\b\d+\.?\d*(?:[eE][+-]?\d+)?\b/, kind: "number" },
191
+ { pattern: new RegExp(`^\\b(?:${PY_KEYWORDS.join("|")})\\b`), kind: "keyword" },
192
+ { pattern: /^\b[A-Z][A-Za-z0-9_]*\b/, kind: "type" },
193
+ { pattern: /^[A-Za-z_][\w]*(?=\s*\()/, kind: "function" },
194
+ { pattern: /^[+\-*/%=<>!&|^~]+/, kind: "operator" },
195
+ { pattern: /^[{}[\]().,:;]/, kind: "punctuation" },
196
+ ];
197
+ const GO_RULES = [
198
+ { pattern: /^\/\/[^\n]*/, kind: "comment" },
199
+ { pattern: /^\/\*[\s\S]*?\*\//, kind: "comment" },
200
+ { pattern: /^`[\s\S]*?`/, kind: "string" },
201
+ { pattern: /^"(?:[^"\\\n]|\\.)*"/, kind: "string" },
202
+ { pattern: /^'(?:[^'\\]|\\.)*'/, kind: "string" },
203
+ { pattern: /^\b\d+\.?\d*\b/, kind: "number" },
204
+ { pattern: new RegExp(`^\\b(?:${GO_KEYWORDS.join("|")})\\b`), kind: "keyword" },
205
+ { pattern: /^\b[A-Z][A-Za-z0-9_]*\b/, kind: "type" },
206
+ { pattern: /^[A-Za-z_][\w]*(?=\s*\()/, kind: "function" },
207
+ { pattern: /^[+\-*/%=<>!&|^~]+/, kind: "operator" },
208
+ { pattern: /^[{}[\]().,;:]/, kind: "punctuation" },
209
+ ];
210
+ const SH_RULES = [
211
+ { pattern: /^#[^\n]*/, kind: "comment" },
212
+ { pattern: /^"(?:[^"\\\n]|\\.)*"/, kind: "string" },
213
+ { pattern: /^'[^'\n]*'/, kind: "string" },
214
+ { pattern: /^\$[A-Za-z_][\w]*/, kind: "property" },
215
+ { pattern: /^\$\{[^}]*\}/, kind: "property" },
216
+ { pattern: /^\b\d+\b/, kind: "number" },
217
+ { pattern: new RegExp(`^\\b(?:${SH_KEYWORDS.join("|")})\\b`), kind: "keyword" },
218
+ { pattern: /^-{1,2}[A-Za-z][\w-]*/, kind: "operator" },
219
+ { pattern: /^[|&;<>(){}]+/, kind: "punctuation" },
220
+ ];
221
+ const JSON_RULES = [
222
+ { pattern: /^"(?:[^"\\\n]|\\.)*"(?=\s*:)/, kind: "property" },
223
+ { pattern: /^"(?:[^"\\\n]|\\.)*"/, kind: "string" },
224
+ { pattern: /^\b(?:true|false|null)\b/, kind: "keyword" },
225
+ { pattern: /^-?\b\d+\.?\d*(?:[eE][+-]?\d+)?\b/, kind: "number" },
226
+ { pattern: /^[{}[\],]/, kind: "punctuation" },
227
+ { pattern: /^:/, kind: "operator" },
228
+ ];
229
+ const LANGS = {
230
+ ts: TS_RULES,
231
+ tsx: TS_RULES,
232
+ js: TS_RULES,
233
+ jsx: TS_RULES,
234
+ javascript: TS_RULES,
235
+ typescript: TS_RULES,
236
+ py: PY_RULES,
237
+ python: PY_RULES,
238
+ go: GO_RULES,
239
+ golang: GO_RULES,
240
+ sh: SH_RULES,
241
+ bash: SH_RULES,
242
+ zsh: SH_RULES,
243
+ shell: SH_RULES,
244
+ json: JSON_RULES,
245
+ };
246
+ /** Get the rule set for a language slug, or null if unsupported. */
247
+ export function rulesFor(lang) {
248
+ if (!lang)
249
+ return null;
250
+ return LANGS[lang.toLowerCase()] ?? null;
251
+ }
252
+ /**
253
+ * Tokenize `code` according to `lang`. Returns one big flat token list
254
+ * with whitespace and unmatched content emitted as `text`. The caller
255
+ * is responsible for rendering each token in its kind's color.
256
+ */
257
+ export function highlight(code, lang) {
258
+ const rules = rulesFor(lang);
259
+ if (!rules)
260
+ return [{ kind: "text", text: code }];
261
+ const out = [];
262
+ let buffer = "";
263
+ let i = 0;
264
+ while (i < code.length) {
265
+ // Eat whitespace into the rolling text buffer — saves work and keeps
266
+ // indentation intact in the output.
267
+ const ch = code[i];
268
+ if (ch === " " || ch === "\t" || ch === "\n" || ch === "\r") {
269
+ buffer += ch;
270
+ i++;
271
+ continue;
272
+ }
273
+ const slice = code.slice(i);
274
+ let matched = null;
275
+ for (const rule of rules) {
276
+ const m = slice.match(rule.pattern);
277
+ if (m && m.index === 0) {
278
+ matched = { kind: rule.kind, len: m[0].length };
279
+ break;
280
+ }
281
+ }
282
+ if (matched) {
283
+ if (buffer) {
284
+ out.push({ kind: "text", text: buffer });
285
+ buffer = "";
286
+ }
287
+ out.push({ kind: matched.kind, text: slice.slice(0, matched.len) });
288
+ i += matched.len;
289
+ continue;
290
+ }
291
+ // No match — accumulate one char into the plain-text buffer.
292
+ buffer += ch;
293
+ i++;
294
+ }
295
+ if (buffer)
296
+ out.push({ kind: "text", text: buffer });
297
+ return out;
298
+ }
299
+ /** Map a token kind to an Ink color. Returns undefined for plain text. */
300
+ export function colorForKind(kind) {
301
+ switch (kind) {
302
+ case "keyword":
303
+ return "magenta";
304
+ case "string":
305
+ return "green";
306
+ case "number":
307
+ return "yellow";
308
+ case "comment":
309
+ return "gray";
310
+ case "type":
311
+ return "cyan";
312
+ case "function":
313
+ return "blue";
314
+ case "property":
315
+ return "cyan";
316
+ case "regex":
317
+ return "yellow";
318
+ case "operator":
319
+ case "punctuation":
320
+ case "text":
321
+ return undefined;
322
+ }
323
+ }
324
+ //# sourceMappingURL=highlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlight.js","sourceRoot":"","sources":["../../src/ui/highlight.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ const MAX_HISTORY = 200;
6
+ /**
7
+ * Per-cwd prompt history persisted to ~/.codebase/projects/<hash>/history.json.
8
+ * Keeps the most recent MAX_HISTORY entries, oldest first; identical to
9
+ * SessionStore's hashing so we share the project directory layout.
10
+ *
11
+ * Stored as a JSON array of strings. No metadata, no timestamps — the
12
+ * Input component just needs the chronological list for ↑/↓ recall.
13
+ */
14
+ export class HistoryStore {
15
+ path;
16
+ max;
17
+ constructor(options) {
18
+ const dataRoot = options.dataRoot ?? join(homedir(), ".codebase");
19
+ const hash = createHash("sha256").update(options.cwd).digest("hex").slice(0, 8);
20
+ this.path = join(dataRoot, "projects", hash, "history.json");
21
+ this.max = options.max ?? MAX_HISTORY;
22
+ }
23
+ get filePath() {
24
+ return this.path;
25
+ }
26
+ load() {
27
+ if (!existsSync(this.path))
28
+ return [];
29
+ try {
30
+ const raw = readFileSync(this.path, "utf8");
31
+ const parsed = JSON.parse(raw);
32
+ if (!Array.isArray(parsed))
33
+ return [];
34
+ return parsed.filter((s) => typeof s === "string");
35
+ }
36
+ catch {
37
+ return [];
38
+ }
39
+ }
40
+ /** Append `entry`. Collapses adjacent dupes so ↑↑↑ doesn't dwell. */
41
+ append(entry) {
42
+ const trimmed = entry.trim();
43
+ if (!trimmed)
44
+ return;
45
+ const current = this.load();
46
+ if (current[current.length - 1] === trimmed)
47
+ return;
48
+ const next = [...current, trimmed];
49
+ const sliced = next.length > this.max ? next.slice(next.length - this.max) : next;
50
+ const dir = join(this.path, "..");
51
+ try {
52
+ mkdirSync(dir, { recursive: true });
53
+ writeFileSync(this.path, JSON.stringify(sliced), { mode: 0o600 });
54
+ }
55
+ catch {
56
+ // best-effort — losing one history write isn't worth surfacing an error.
57
+ }
58
+ }
59
+ }
60
+ //# sourceMappingURL=history-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-store.js","sourceRoot":"","sources":["../../src/ui/history-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,WAAW,GAAG,GAAG,CAAC;AAQxB;;;;;;;GAOG;AACH,MAAM,OAAO,YAAY;IACP,IAAI,CAAS;IACb,GAAG,CAAS;IAE7B,YAAY,OAA4B;QACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAC7D,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC;IACvC,CAAC;IAED,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,IAAI;QACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QACtC,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,CAAC;YACtC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IAED,qEAAqE;IACrE,MAAM,CAAC,KAAa;QACnB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,OAAO;YAAE,OAAO;QACpD,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClF,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC;YACJ,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACR,yEAAyE;QAC1E,CAAC;IACF,CAAC;CACD"}