@aexol/spectral 0.7.8 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/dist/agent/agents.js +4 -4
  2. package/dist/agent/index.js +8 -8
  3. package/dist/cli.js +1 -1
  4. package/dist/commands/serve.js +1 -1
  5. package/dist/extensions/kanban-bridge.js +668 -0
  6. package/dist/extensions/spectral-vision-fallback.js +84 -46
  7. package/dist/mcp/agent-dir.js +1 -1
  8. package/dist/mcp/config.js +3 -3
  9. package/dist/mcp/init.js +1 -9
  10. package/dist/mcp/sampling-handler.js +1 -1
  11. package/dist/mcp/server-manager.js +5 -1
  12. package/dist/memory/commands/status.js +1 -1
  13. package/dist/memory/compaction.js +2 -2
  14. package/dist/memory/config.js +3 -3
  15. package/dist/memory/debug-log.js +1 -1
  16. package/dist/memory/index.js +2 -0
  17. package/dist/memory/observer.js +2 -2
  18. package/dist/memory/tokens.js +1 -1
  19. package/dist/memory/tools/read-project-observations.js +2 -2
  20. package/dist/memory/tools/recall-observation.js +2 -2
  21. package/dist/memory/tools/write-project-observation.js +60 -0
  22. package/dist/relay/auto-research.js +57 -23
  23. package/dist/relay/dispatcher.js +28 -2
  24. package/dist/relay/models-fetch.js +2 -2
  25. package/dist/{pi → sdk}/ai/env-api-keys.js +9 -49
  26. package/dist/{pi → sdk}/ai/utils/oauth/anthropic.js +1 -1
  27. package/dist/{pi → sdk}/ai/utils/oauth/openai-codex.js +1 -1
  28. package/dist/{pi → sdk}/coding-agent/config.js +11 -78
  29. package/dist/{pi → sdk}/coding-agent/core/agent-session.js +2 -0
  30. package/dist/{pi → sdk}/coding-agent/core/compaction/compaction.js +161 -5
  31. package/dist/{pi → sdk}/coding-agent/core/extensions/loader.js +2 -35
  32. package/dist/{pi → sdk}/coding-agent/core/extensions/runner.js +1 -2
  33. package/dist/{pi → sdk}/coding-agent/core/model-registry.js +11 -4
  34. package/dist/sdk/coding-agent/core/model-resolver-utils.js +8 -0
  35. package/dist/{pi → sdk}/coding-agent/core/model-resolver.js +1 -1
  36. package/dist/{pi → sdk}/coding-agent/core/package-manager.js +5 -5
  37. package/dist/{pi → sdk}/coding-agent/core/resource-loader.js +1 -1
  38. package/dist/{pi → sdk}/coding-agent/core/sdk.js +1 -1
  39. package/dist/{pi → sdk}/coding-agent/core/session-manager.js +4 -4
  40. package/dist/{pi → sdk}/coding-agent/core/settings-manager.js +1 -170
  41. package/dist/{pi → sdk}/coding-agent/core/system-prompt.js +3 -1
  42. package/dist/{pi → sdk}/coding-agent/core/telemetry.js +1 -1
  43. package/dist/sdk/coding-agent/core/theme.js +202 -0
  44. package/dist/{pi → sdk}/coding-agent/core/tools/bash.js +17 -18
  45. package/dist/{pi → sdk}/coding-agent/core/tools/edit.js +7 -8
  46. package/dist/{pi → sdk}/coding-agent/core/tools/find.js +9 -13
  47. package/dist/{pi → sdk}/coding-agent/core/tools/grep.js +10 -14
  48. package/dist/{pi → sdk}/coding-agent/core/tools/ls.js +9 -10
  49. package/dist/{pi → sdk}/coding-agent/core/tools/read.js +15 -25
  50. package/dist/{pi/coding-agent/modes/interactive/components/diff.js → sdk/coding-agent/core/tools/render-diff.js} +18 -31
  51. package/dist/{pi → sdk}/coding-agent/core/tools/write.js +10 -11
  52. package/dist/{pi → sdk}/coding-agent/index.js +7 -5
  53. package/dist/{pi → sdk}/coding-agent/migrations.js +3 -3
  54. package/dist/{pi → sdk}/coding-agent/modes/index.js +0 -1
  55. package/dist/{pi → sdk}/coding-agent/modes/rpc/rpc-mode.js +2 -2
  56. package/dist/{pi → sdk}/coding-agent/utils/photon.js +2 -10
  57. package/dist/sdk/coding-agent/utils/pi-user-agent.js +3 -0
  58. package/dist/{pi → sdk}/coding-agent/utils/tools-manager.js +1 -1
  59. package/dist/{pi → sdk}/coding-agent/utils/version-check.js +2 -2
  60. package/dist/{pi → sdk}/coding-agent/utils/windows-self-update.js +1 -1
  61. package/dist/server/{pi-bridge.js → agent-bridge.js} +114 -97
  62. package/dist/server/handlers/sessions.js +21 -0
  63. package/dist/server/session-stream.js +5 -5
  64. package/package.json +6 -3
  65. package/dist/pi/coding-agent/bun/cli.js +0 -7
  66. package/dist/pi/coding-agent/bun/restore-sandbox-env.js +0 -31
  67. package/dist/pi/coding-agent/cli/args.js +0 -340
  68. package/dist/pi/coding-agent/cli/file-processor.js +0 -82
  69. package/dist/pi/coding-agent/cli/initial-message.js +0 -21
  70. package/dist/pi/coding-agent/core/footer-data-provider.js +0 -309
  71. package/dist/pi/coding-agent/modes/interactive/components/keybinding-hints.js +0 -35
  72. package/dist/pi/coding-agent/modes/interactive/components/visual-truncate.js +0 -26
  73. package/dist/pi/coding-agent/modes/interactive/interactive-mode.js +0 -3
  74. package/dist/pi/coding-agent/modes/interactive/theme/theme.js +0 -1022
  75. package/dist/pi/coding-agent/utils/pi-user-agent.js +0 -4
  76. /package/dist/{pi → sdk}/agent-core/agent-loop.js +0 -0
  77. /package/dist/{pi → sdk}/agent-core/agent.js +0 -0
  78. /package/dist/{pi → sdk}/agent-core/harness/agent-harness.js +0 -0
  79. /package/dist/{pi → sdk}/agent-core/harness/compaction/branch-summarization.js +0 -0
  80. /package/dist/{pi → sdk}/agent-core/harness/compaction/compaction.js +0 -0
  81. /package/dist/{pi → sdk}/agent-core/harness/compaction/utils.js +0 -0
  82. /package/dist/{pi → sdk}/agent-core/harness/env/nodejs.js +0 -0
  83. /package/dist/{pi → sdk}/agent-core/harness/messages.js +0 -0
  84. /package/dist/{pi → sdk}/agent-core/harness/prompt-templates.js +0 -0
  85. /package/dist/{pi → sdk}/agent-core/harness/session/jsonl-repo.js +0 -0
  86. /package/dist/{pi → sdk}/agent-core/harness/session/jsonl-storage.js +0 -0
  87. /package/dist/{pi → sdk}/agent-core/harness/session/memory-repo.js +0 -0
  88. /package/dist/{pi → sdk}/agent-core/harness/session/memory-storage.js +0 -0
  89. /package/dist/{pi → sdk}/agent-core/harness/session/repo-utils.js +0 -0
  90. /package/dist/{pi → sdk}/agent-core/harness/session/session.js +0 -0
  91. /package/dist/{pi → sdk}/agent-core/harness/session/uuid.js +0 -0
  92. /package/dist/{pi → sdk}/agent-core/harness/skills.js +0 -0
  93. /package/dist/{pi → sdk}/agent-core/harness/system-prompt.js +0 -0
  94. /package/dist/{pi → sdk}/agent-core/harness/types.js +0 -0
  95. /package/dist/{pi → sdk}/agent-core/harness/utils/shell-output.js +0 -0
  96. /package/dist/{pi → sdk}/agent-core/harness/utils/truncate.js +0 -0
  97. /package/dist/{pi → sdk}/agent-core/index.js +0 -0
  98. /package/dist/{pi → sdk}/agent-core/node.js +0 -0
  99. /package/dist/{pi → sdk}/agent-core/proxy.js +0 -0
  100. /package/dist/{pi → sdk}/agent-core/types.js +0 -0
  101. /package/dist/{pi → sdk}/ai/api-registry.js +0 -0
  102. /package/dist/{pi → sdk}/ai/cli.js +0 -0
  103. /package/dist/{pi → sdk}/ai/image-models.generated.js +0 -0
  104. /package/dist/{pi → sdk}/ai/image-models.js +0 -0
  105. /package/dist/{pi → sdk}/ai/images-api-registry.js +0 -0
  106. /package/dist/{pi → sdk}/ai/images.js +0 -0
  107. /package/dist/{pi → sdk}/ai/index.js +0 -0
  108. /package/dist/{pi → sdk}/ai/models.generated.js +0 -0
  109. /package/dist/{pi → sdk}/ai/models.js +0 -0
  110. /package/dist/{pi → sdk}/ai/oauth.js +0 -0
  111. /package/dist/{pi → sdk}/ai/providers/anthropic.js +0 -0
  112. /package/dist/{pi → sdk}/ai/providers/faux.js +0 -0
  113. /package/dist/{pi → sdk}/ai/providers/github-copilot-headers.js +0 -0
  114. /package/dist/{pi → sdk}/ai/providers/openai-completions.js +0 -0
  115. /package/dist/{pi → sdk}/ai/providers/openai-prompt-cache.js +0 -0
  116. /package/dist/{pi → sdk}/ai/providers/register-builtins.js +0 -0
  117. /package/dist/{pi → sdk}/ai/providers/simple-options.js +0 -0
  118. /package/dist/{pi → sdk}/ai/providers/transform-messages.js +0 -0
  119. /package/dist/{pi → sdk}/ai/session-resources.js +0 -0
  120. /package/dist/{pi → sdk}/ai/stream.js +0 -0
  121. /package/dist/{pi → sdk}/ai/types.js +0 -0
  122. /package/dist/{pi → sdk}/ai/utils/diagnostics.js +0 -0
  123. /package/dist/{pi → sdk}/ai/utils/event-stream.js +0 -0
  124. /package/dist/{pi → sdk}/ai/utils/hash.js +0 -0
  125. /package/dist/{pi → sdk}/ai/utils/headers.js +0 -0
  126. /package/dist/{pi → sdk}/ai/utils/json-parse.js +0 -0
  127. /package/dist/{pi → sdk}/ai/utils/node-http-proxy.js +0 -0
  128. /package/dist/{pi → sdk}/ai/utils/oauth/device-code.js +0 -0
  129. /package/dist/{pi → sdk}/ai/utils/oauth/github-copilot.js +0 -0
  130. /package/dist/{pi → sdk}/ai/utils/oauth/index.js +0 -0
  131. /package/dist/{pi → sdk}/ai/utils/oauth/oauth-page.js +0 -0
  132. /package/dist/{pi → sdk}/ai/utils/oauth/pkce.js +0 -0
  133. /package/dist/{pi → sdk}/ai/utils/oauth/types.js +0 -0
  134. /package/dist/{pi → sdk}/ai/utils/overflow.js +0 -0
  135. /package/dist/{pi → sdk}/ai/utils/sanitize-unicode.js +0 -0
  136. /package/dist/{pi → sdk}/ai/utils/typebox-helpers.js +0 -0
  137. /package/dist/{pi → sdk}/ai/utils/validation.js +0 -0
  138. /package/dist/{pi → sdk}/coding-agent/cli.js +0 -0
  139. /package/dist/{pi → sdk}/coding-agent/core/agent-session-runtime.js +0 -0
  140. /package/dist/{pi → sdk}/coding-agent/core/agent-session-services.js +0 -0
  141. /package/dist/{pi → sdk}/coding-agent/core/auth-guidance.js +0 -0
  142. /package/dist/{pi → sdk}/coding-agent/core/auth-storage.js +0 -0
  143. /package/dist/{pi → sdk}/coding-agent/core/bash-executor.js +0 -0
  144. /package/dist/{pi → sdk}/coding-agent/core/compaction/branch-summarization.js +0 -0
  145. /package/dist/{pi → sdk}/coding-agent/core/compaction/index.js +0 -0
  146. /package/dist/{pi → sdk}/coding-agent/core/compaction/utils.js +0 -0
  147. /package/dist/{pi → sdk}/coding-agent/core/defaults.js +0 -0
  148. /package/dist/{pi → sdk}/coding-agent/core/diagnostics.js +0 -0
  149. /package/dist/{pi → sdk}/coding-agent/core/event-bus.js +0 -0
  150. /package/dist/{pi → sdk}/coding-agent/core/exec.js +0 -0
  151. /package/dist/{pi → sdk}/coding-agent/core/extensions/index.js +0 -0
  152. /package/dist/{pi → sdk}/coding-agent/core/extensions/types.js +0 -0
  153. /package/dist/{pi → sdk}/coding-agent/core/extensions/wrapper.js +0 -0
  154. /package/dist/{pi → sdk}/coding-agent/core/http-dispatcher.js +0 -0
  155. /package/dist/{pi → sdk}/coding-agent/core/index.js +0 -0
  156. /package/dist/{pi → sdk}/coding-agent/core/keybindings.js +0 -0
  157. /package/dist/{pi → sdk}/coding-agent/core/messages.js +0 -0
  158. /package/dist/{pi → sdk}/coding-agent/core/output-guard.js +0 -0
  159. /package/dist/{pi → sdk}/coding-agent/core/prompt-templates.js +0 -0
  160. /package/dist/{pi → sdk}/coding-agent/core/provider-display-names.js +0 -0
  161. /package/dist/{pi → sdk}/coding-agent/core/resolve-config-value.js +0 -0
  162. /package/dist/{pi → sdk}/coding-agent/core/session-cwd.js +0 -0
  163. /package/dist/{pi → sdk}/coding-agent/core/skills.js +0 -0
  164. /package/dist/{pi → sdk}/coding-agent/core/slash-commands.js +0 -0
  165. /package/dist/{pi → sdk}/coding-agent/core/source-info.js +0 -0
  166. /package/dist/{pi → sdk}/coding-agent/core/timings.js +0 -0
  167. /package/dist/{pi → sdk}/coding-agent/core/tools/edit-diff.js +0 -0
  168. /package/dist/{pi → sdk}/coding-agent/core/tools/file-mutation-queue.js +0 -0
  169. /package/dist/{pi → sdk}/coding-agent/core/tools/index.js +0 -0
  170. /package/dist/{pi → sdk}/coding-agent/core/tools/output-accumulator.js +0 -0
  171. /package/dist/{pi → sdk}/coding-agent/core/tools/path-utils.js +0 -0
  172. /package/dist/{pi → sdk}/coding-agent/core/tools/render-utils.js +0 -0
  173. /package/dist/{pi → sdk}/coding-agent/core/tools/tool-definition-wrapper.js +0 -0
  174. /package/dist/{pi → sdk}/coding-agent/core/tools/truncate.js +0 -0
  175. /package/dist/{pi → sdk}/coding-agent/main.js +0 -0
  176. /package/dist/{pi → sdk}/coding-agent/modes/print-mode.js +0 -0
  177. /package/dist/{pi → sdk}/coding-agent/modes/rpc/jsonl.js +0 -0
  178. /package/dist/{pi → sdk}/coding-agent/modes/rpc/rpc-client.js +0 -0
  179. /package/dist/{pi → sdk}/coding-agent/modes/rpc/rpc-types.js +0 -0
  180. /package/dist/{pi → sdk}/coding-agent/utils/ansi.js +0 -0
  181. /package/dist/{pi → sdk}/coding-agent/utils/changelog.js +0 -0
  182. /package/dist/{pi → sdk}/coding-agent/utils/child-process.js +0 -0
  183. /package/dist/{pi → sdk}/coding-agent/utils/clipboard-image.js +0 -0
  184. /package/dist/{pi → sdk}/coding-agent/utils/clipboard-native.js +0 -0
  185. /package/dist/{pi → sdk}/coding-agent/utils/clipboard.js +0 -0
  186. /package/dist/{pi → sdk}/coding-agent/utils/exif-orientation.js +0 -0
  187. /package/dist/{pi → sdk}/coding-agent/utils/frontmatter.js +0 -0
  188. /package/dist/{pi → sdk}/coding-agent/utils/fs-watch.js +0 -0
  189. /package/dist/{pi → sdk}/coding-agent/utils/git.js +0 -0
  190. /package/dist/{pi → sdk}/coding-agent/utils/html.js +0 -0
  191. /package/dist/{pi → sdk}/coding-agent/utils/image-convert.js +0 -0
  192. /package/dist/{pi → sdk}/coding-agent/utils/image-resize.js +0 -0
  193. /package/dist/{pi → sdk}/coding-agent/utils/mime.js +0 -0
  194. /package/dist/{pi → sdk}/coding-agent/utils/paths.js +0 -0
  195. /package/dist/{pi → sdk}/coding-agent/utils/shell.js +0 -0
  196. /package/dist/{pi → sdk}/coding-agent/utils/sleep.js +0 -0
  197. /package/dist/{pi → sdk}/coding-agent/utils/syntax-highlight.js +0 -0
@@ -1,5 +1,9 @@
1
+ /**
2
+ * Plain-text diff rendering for LLM consumption.
3
+ * Extracted from the TUI interactive mode diff renderer, with all ANSI
4
+ * styling removed — the output is plain text suitable for LLM input.
5
+ */
1
6
  import * as Diff from "diff";
2
- import { theme } from "../theme/theme.js";
3
7
  /**
4
8
  * Parse diff line to extract prefix, line number, and content.
5
9
  * Format: "+123 content" or "-123 content" or " 123 content" or " ..."
@@ -10,17 +14,9 @@ function parseDiffLine(line) {
10
14
  return null;
11
15
  return { prefix: match[1], lineNum: match[2], content: match[3] };
12
16
  }
13
- /**
14
- * Replace tabs with spaces for consistent rendering.
15
- */
16
17
  function replaceTabs(text) {
17
18
  return text.replace(/\t/g, " ");
18
19
  }
19
- /**
20
- * Compute word-level diff and render with inverse on changed parts.
21
- * Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.
22
- * Strips leading whitespace from inverse to avoid highlighting indentation.
23
- */
24
20
  function renderIntraLineDiff(oldContent, newContent) {
25
21
  const wordDiff = Diff.diffWords(oldContent, newContent);
26
22
  let removedLine = "";
@@ -30,7 +26,6 @@ function renderIntraLineDiff(oldContent, newContent) {
30
26
  for (const part of wordDiff) {
31
27
  if (part.removed) {
32
28
  let value = part.value;
33
- // Strip leading whitespace from the first removed part
34
29
  if (isFirstRemoved) {
35
30
  const leadingWs = value.match(/^(\s*)/)?.[1] || "";
36
31
  value = value.slice(leadingWs.length);
@@ -38,12 +33,11 @@ function renderIntraLineDiff(oldContent, newContent) {
38
33
  isFirstRemoved = false;
39
34
  }
40
35
  if (value) {
41
- removedLine += theme.inverse(value);
36
+ removedLine += `<REMOVED>${value}</REMOVED>`;
42
37
  }
43
38
  }
44
39
  else if (part.added) {
45
40
  let value = part.value;
46
- // Strip leading whitespace from the first added part
47
41
  if (isFirstAdded) {
48
42
  const leadingWs = value.match(/^(\s*)/)?.[1] || "";
49
43
  value = value.slice(leadingWs.length);
@@ -51,7 +45,7 @@ function renderIntraLineDiff(oldContent, newContent) {
51
45
  isFirstAdded = false;
52
46
  }
53
47
  if (value) {
54
- addedLine += theme.inverse(value);
48
+ addedLine += `<ADDED>${value}</ADDED>`;
55
49
  }
56
50
  }
57
51
  else {
@@ -62,10 +56,10 @@ function renderIntraLineDiff(oldContent, newContent) {
62
56
  return { removedLine, addedLine };
63
57
  }
64
58
  /**
65
- * Render a diff string with colored lines and intra-line change highlighting.
66
- * - Context lines: dim/gray
67
- * - Removed lines: red, with inverse on changed tokens
68
- * - Added lines: green, with inverse on changed tokens
59
+ * Render a diff string as plain text with markers.
60
+ * - Context lines: unchanged
61
+ * - Removed lines: prefixed with "-"
62
+ * - Added lines: prefixed with "+"
69
63
  */
70
64
  export function renderDiff(diffText, _options = {}) {
71
65
  const lines = diffText.split("\n");
@@ -75,12 +69,11 @@ export function renderDiff(diffText, _options = {}) {
75
69
  const line = lines[i];
76
70
  const parsed = parseDiffLine(line);
77
71
  if (!parsed) {
78
- result.push(theme.fg("toolDiffContext", line));
72
+ result.push(line);
79
73
  i++;
80
74
  continue;
81
75
  }
82
76
  if (parsed.prefix === "-") {
83
- // Collect consecutive removed lines
84
77
  const removedLines = [];
85
78
  while (i < lines.length) {
86
79
  const p = parseDiffLine(lines[i]);
@@ -89,7 +82,6 @@ export function renderDiff(diffText, _options = {}) {
89
82
  removedLines.push({ lineNum: p.lineNum, content: p.content });
90
83
  i++;
91
84
  }
92
- // Collect consecutive added lines
93
85
  const addedLines = [];
94
86
  while (i < lines.length) {
95
87
  const p = parseDiffLine(lines[i]);
@@ -98,33 +90,28 @@ export function renderDiff(diffText, _options = {}) {
98
90
  addedLines.push({ lineNum: p.lineNum, content: p.content });
99
91
  i++;
100
92
  }
101
- // Only do intra-line diffing when there's exactly one removed and one added line
102
- // (indicating a single line modification). Otherwise, show lines as-is.
103
93
  if (removedLines.length === 1 && addedLines.length === 1) {
104
94
  const removed = removedLines[0];
105
95
  const added = addedLines[0];
106
96
  const { removedLine, addedLine } = renderIntraLineDiff(replaceTabs(removed.content), replaceTabs(added.content));
107
- result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${removedLine}`));
108
- result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${addedLine}`));
97
+ result.push(`-${removed.lineNum} ${removedLine}`);
98
+ result.push(`+${added.lineNum} ${addedLine}`);
109
99
  }
110
100
  else {
111
- // Show all removed lines first, then all added lines
112
101
  for (const removed of removedLines) {
113
- result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${replaceTabs(removed.content)}`));
102
+ result.push(`-${removed.lineNum} ${replaceTabs(removed.content)}`);
114
103
  }
115
104
  for (const added of addedLines) {
116
- result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${replaceTabs(added.content)}`));
105
+ result.push(`+${added.lineNum} ${replaceTabs(added.content)}`);
117
106
  }
118
107
  }
119
108
  }
120
109
  else if (parsed.prefix === "+") {
121
- // Standalone added line
122
- result.push(theme.fg("toolDiffAdded", `+${parsed.lineNum} ${replaceTabs(parsed.content)}`));
110
+ result.push(`+${parsed.lineNum} ${replaceTabs(parsed.content)}`);
123
111
  i++;
124
112
  }
125
113
  else {
126
- // Context line
127
- result.push(theme.fg("toolDiffContext", ` ${parsed.lineNum} ${replaceTabs(parsed.content)}`));
114
+ result.push(` ${parsed.lineNum} ${replaceTabs(parsed.content)}`);
128
115
  i++;
129
116
  }
130
117
  }
@@ -1,11 +1,10 @@
1
1
  import { mkdir as fsMkdir, writeFile as fsWriteFile } from "fs/promises";
2
2
  import { dirname } from "path";
3
3
  import { Type } from "typebox";
4
- import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
5
- import { getLanguageFromPath, highlightCode } from "../../modes/interactive/theme/theme.js";
4
+ import { getLanguageFromPath, highlightCode } from "../theme.js";
6
5
  import { withFileMutationQueue } from "./file-mutation-queue.js";
7
6
  import { resolveToCwd } from "./path-utils.js";
8
- import { invalidArgText, normalizeDisplayText, replaceTabs, shortenPath, str } from "./render-utils.js";
7
+ import { normalizeDisplayText, replaceTabs, shortenPath, str } from "./render-utils.js";
9
8
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
10
9
  const writeSchema = Type.Object({
11
10
  path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
@@ -22,14 +21,14 @@ function trimTrailingEmptyLines(lines) {
22
21
  }
23
22
  return lines.slice(0, end);
24
23
  }
25
- function formatWriteCall(args, options, theme) {
24
+ function formatWriteCall(args, options, _theme) {
26
25
  const rawPath = str(args?.file_path ?? args?.path);
27
26
  const fileContent = str(args?.content);
28
27
  const path = rawPath !== null ? shortenPath(rawPath) : null;
29
- const invalidArg = invalidArgText(theme);
30
- let text = `${theme.fg("toolTitle", theme.bold("write"))} ${path === null ? invalidArg : path ? theme.fg("accent", path) : theme.fg("toolOutput", "...")}`;
28
+ const pathDisplay = path === null ? "[invalid]" : path || "...";
29
+ let text = `write ${pathDisplay}`;
31
30
  if (fileContent === null) {
32
- text += `\n\n${theme.fg("error", "[invalid content arg - expected string]")}`;
31
+ text += `\n\n[invalid content arg - expected string]`;
33
32
  }
34
33
  else if (fileContent) {
35
34
  const lang = rawPath ? getLanguageFromPath(rawPath) : undefined;
@@ -41,14 +40,14 @@ function formatWriteCall(args, options, theme) {
41
40
  const maxLines = options.expanded ? lines.length : 10;
42
41
  const displayLines = lines.slice(0, maxLines);
43
42
  const remaining = lines.length - maxLines;
44
- text += `\n\n${displayLines.map((line) => (lang ? line : theme.fg("toolOutput", replaceTabs(line)))).join("\n")}`;
43
+ text += `\n\n${displayLines.join("\n")}`;
45
44
  if (remaining > 0) {
46
- text += `${theme.fg("muted", `\n... (${remaining} more lines, ${totalLines} total,`)} ${keyHint("app.tools.expand", "to expand")})`;
45
+ text += `\n... (${remaining} more lines, ${totalLines} total)`;
47
46
  }
48
47
  }
49
48
  return text;
50
49
  }
51
- function formatWriteResult(result, theme) {
50
+ function formatWriteResult(result, _theme) {
52
51
  if (!result.isError) {
53
52
  return undefined;
54
53
  }
@@ -59,7 +58,7 @@ function formatWriteResult(result, theme) {
59
58
  if (!output) {
60
59
  return undefined;
61
60
  }
62
- return `\n${theme.fg("error", output)}`;
61
+ return `\n${output}`;
63
62
  }
64
63
  export function createWriteToolDefinition(cwd, options) {
65
64
  const ops = options?.operations ?? defaultWriteOperations;
@@ -8,6 +8,8 @@ export { AuthStorage, FileAuthStorageBackend, InMemoryAuthStorageBackend, } from
8
8
  export { calculateContextTokens, collectEntriesForBranchSummary, compact, DEFAULT_COMPACTION_SETTINGS, estimateTokens, findCutPoint, findTurnStartIndex, generateBranchSummary, generateSummary, getLastAssistantUsage, prepareBranchEntries, serializeConversation, shouldCompact, } from "./core/compaction/index.js";
9
9
  export { createEventBus } from "./core/event-bus.js";
10
10
  export { createExtensionRuntime, defineTool, discoverAndLoadExtensions, ExtensionRunner, isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isToolCallEventType, isWriteToolResult, wrapRegisteredTool, wrapRegisteredTools, } from "./core/extensions/index.js";
11
+ // Footer data provider — no longer exported (TUI-only, serve/relay uses no-ops)
12
+ // export type { ReadonlyFooterDataProvider } from "./core/footer-data-provider.js";
11
13
  export { convertToLlm } from "./core/messages.js";
12
14
  export { ModelRegistry } from "./core/model-registry.js";
13
15
  export { DefaultPackageManager } from "./core/package-manager.js";
@@ -28,11 +30,11 @@ export { createBashToolDefinition, createEditToolDefinition, createFindToolDefin
28
30
  // Main entry point
29
31
  // main.ts removed (interactive-only, not used in SDK mode)
30
32
  // Run modes for programmatic SDK usage
31
- export { InteractiveMode, RpcClient, runPrintMode, runRpcMode, } from "./modes/index.js";
32
- // UI components for extensions
33
- // Interactive components removed (not used in SDK mode, TUI dependencies stripped)
34
- // Theme utilities for custom tools and extensions
35
- export { getLanguageFromPath, getMarkdownTheme, getSelectListTheme, getSettingsListTheme, highlightCode, initTheme, Theme, } from "./modes/interactive/theme/theme.js";
33
+ // InteractiveMode removed (TUI-only, not used in serve/relay mode)
34
+ export { RpcClient, runRpcMode, } from "./modes/index.js";
35
+ export { runPrintMode } from "./modes/print-mode.js";
36
+ // Theme utilities for syntax highlighting (serve/relay compatible)
37
+ export { getLanguageFromPath, highlightCode, loadThemeFromPath } from "./core/theme.js";
36
38
  // Clipboard utilities
37
39
  export { copyToClipboard } from "./utils/clipboard.js";
38
40
  export { parseFrontmatter, stripFrontmatter } from "./utils/frontmatter.js";
@@ -64,10 +64,10 @@ export function migrateAuthToAuthJson() {
64
64
  return providers;
65
65
  }
66
66
  /**
67
- * Migrate sessions from ~/.pi/agent/*.jsonl to proper session directories.
67
+ * Migrate sessions from ~/.spectral/agent/*.jsonl to proper session directories.
68
68
  *
69
- * Bug in v0.30.0: Sessions were saved to ~/.pi/agent/ instead of
70
- * ~/.pi/agent/sessions/<encoded-cwd>/. This migration moves them
69
+ * Bug in v0.30.0: Sessions were saved to ~/.spectral/agent/ instead of
70
+ * ~/.spectral/agent/sessions/<encoded-cwd>/. This migration moves them
71
71
  * to the correct location based on the cwd in their session header.
72
72
  *
73
73
  * See: https://github.com/earendil-works/pi-mono/issues/320
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Run modes for the coding agent.
3
3
  */
4
- export { InteractiveMode } from "./interactive/interactive-mode.js";
5
4
  export { runPrintMode } from "./print-mode.js";
6
5
  export { RpcClient } from "./rpc/rpc-client.js";
7
6
  export { runRpcMode } from "./rpc/rpc-mode.js";
@@ -13,7 +13,6 @@
13
13
  import * as crypto from "node:crypto";
14
14
  import { takeOverStdout, writeRawStdout } from "../../core/output-guard.js";
15
15
  import { killTrackedDetachedChildren } from "../../utils/shell.js";
16
- import { theme } from "../interactive/theme/theme.js";
17
16
  import { attachJsonlLineReader, serializeJsonLine } from "./jsonl.js";
18
17
  /**
19
18
  * Run in RPC mode.
@@ -200,7 +199,8 @@ export async function runRpcMode(runtimeHost) {
200
199
  return undefined;
201
200
  },
202
201
  get theme() {
203
- return theme;
202
+ // Theme not available in RPC mode; return a stub.
203
+ return {};
204
204
  },
205
205
  getAllThemes() {
206
206
  return [];
@@ -1,16 +1,8 @@
1
1
  /**
2
2
  * Photon image processing wrapper.
3
3
  *
4
- * This module provides a unified interface to @silvia-odwyer/photon-node that works in:
5
- * 1. Node.js (development, npm run build)
6
- * 2. Bun compiled binaries (standalone distribution)
7
- *
8
- * The challenge: photon-node's CJS entry uses fs.readFileSync(__dirname + '/photon_rs_bg.wasm')
9
- * which bakes the build machine's absolute path into Bun compiled binaries.
10
- *
11
- * Solution:
12
- * 1. Patch fs.readFileSync to redirect missing photon_rs_bg.wasm reads
13
- * 2. Copy photon_rs_bg.wasm next to the executable in build:binary
4
+ * This module provides a unified interface to @silvia-odwyer/photon-node for
5
+ * use in Node.js (development, npm run build).
14
6
  */
15
7
  import { createRequire } from "module";
16
8
  import * as path from "path";
@@ -0,0 +1,3 @@
1
+ export function getPiUserAgent(version) {
2
+ return `pi/${version} (${process.platform}; node/${process.version}; ${process.arch})`;
3
+ }
@@ -10,7 +10,7 @@ const TOOLS_DIR = getBinDir();
10
10
  const NETWORK_TIMEOUT_MS = 10_000;
11
11
  const DOWNLOAD_TIMEOUT_MS = 120_000;
12
12
  function isOfflineModeEnabled() {
13
- const value = process.env.PI_OFFLINE;
13
+ const value = process.env.SPECTRAL_OFFLINE;
14
14
  if (!value)
15
15
  return false;
16
16
  return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
@@ -1,5 +1,5 @@
1
1
  import { getPiUserAgent } from "./pi-user-agent.js";
2
- const LATEST_VERSION_URL = "https://pi.dev/api/latest-version";
2
+ const LATEST_VERSION_URL = "https://spectral.dev/api/latest-version";
3
3
  const DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;
4
4
  function parsePackageVersion(version) {
5
5
  const match = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/);
@@ -41,7 +41,7 @@ export function isNewerPackageVersion(candidateVersion, currentVersion) {
41
41
  return candidateVersion.trim() !== currentVersion.trim();
42
42
  }
43
43
  export async function getLatestPiRelease(currentVersion, options = {}) {
44
- if (process.env.PI_SKIP_VERSION_CHECK || process.env.PI_OFFLINE)
44
+ if (process.env.SPECTRAL_SKIP_VERSION_CHECK || process.env.SPECTRAL_OFFLINE)
45
45
  return undefined;
46
46
  const response = await fetch(LATEST_VERSION_URL, {
47
47
  headers: {
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { copyFileSync, existsSync, mkdirSync, renameSync, rmSync } from "node:fs";
3
3
  import { basename, dirname, join, relative, resolve, toNamespacedPath } from "node:path";
4
4
  import { getCwdRelativePath } from "./paths.js";
5
- const QUARANTINE_DIR_NAME = ".pi-native-quarantine";
5
+ const QUARANTINE_DIR_NAME = ".spectral-native-quarantine";
6
6
  function normalizePath(path) {
7
7
  return toNamespacedPath(resolve(path));
8
8
  }