@visual-z/xeno 0.8.3 → 0.9.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 (348) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +31 -746
  3. package/bin/xeno.exe +26 -0
  4. package/install.cjs +88 -0
  5. package/package.json +18 -48
  6. package/docs/app-server.md +0 -115
  7. package/docs/foundations.md +0 -88
  8. package/docs/install.md +0 -244
  9. package/docs/providers.md +0 -172
  10. package/docs/research/foundation-clients-2026-10-09.md +0 -27
  11. package/docs/research/foundation-editing-2026-10-09.md +0 -56
  12. package/docs/research/foundation-network-2026-10-09.md +0 -37
  13. package/docs/research/foundation-workflow-2026-10-09.md +0 -37
  14. package/src/apps/acp-server.ts +0 -41
  15. package/src/apps/agent-profiles.ts +0 -19
  16. package/src/apps/app-server.ts +0 -30
  17. package/src/apps/approve.ts +0 -49
  18. package/src/apps/cli.ts +0 -99
  19. package/src/apps/commands.ts +0 -319
  20. package/src/apps/completions.ts +0 -87
  21. package/src/apps/control-transport.ts +0 -90
  22. package/src/apps/export-cli.ts +0 -24
  23. package/src/apps/goal-flow.ts +0 -70
  24. package/src/apps/image-draft.ts +0 -46
  25. package/src/apps/input.ts +0 -312
  26. package/src/apps/model-catalog.ts +0 -69
  27. package/src/apps/preferences.ts +0 -20
  28. package/src/apps/project-trust.ts +0 -9
  29. package/src/apps/provider-connect.ts +0 -346
  30. package/src/apps/question-ui.ts +0 -27
  31. package/src/apps/render.ts +0 -181
  32. package/src/apps/resources.ts +0 -66
  33. package/src/apps/review.ts +0 -109
  34. package/src/apps/session-hub.ts +0 -96
  35. package/src/apps/session-lifecycle.ts +0 -64
  36. package/src/apps/shell.ts +0 -2066
  37. package/src/apps/startup-input.ts +0 -135
  38. package/src/apps/startup.ts +0 -1677
  39. package/src/apps/ui/app.ts +0 -1713
  40. package/src/apps/ui/control-model.ts +0 -43
  41. package/src/apps/ui/extension-host.ts +0 -194
  42. package/src/apps/ui/image-cache.ts +0 -121
  43. package/src/apps/ui/palette.ts +0 -88
  44. package/src/apps/ui/project.ts +0 -127
  45. package/src/apps/ui/standalone.ts +0 -148
  46. package/src/apps/ui/status-model.ts +0 -68
  47. package/src/apps/ui/surface.ts +0 -91
  48. package/src/apps/ui/theme.ts +0 -86
  49. package/src/apps/update-check.ts +0 -112
  50. package/src/apps/workflow.ts +0 -58
  51. package/src/core/acceptance.ts +0 -139
  52. package/src/core/action-defaults.ts +0 -58
  53. package/src/core/activity-status.ts +0 -52
  54. package/src/core/agent-profile.ts +0 -130
  55. package/src/core/attachment-input.ts +0 -17
  56. package/src/core/blind-checks.ts +0 -72
  57. package/src/core/boundary.ts +0 -174
  58. package/src/core/branch-receipt.ts +0 -26
  59. package/src/core/catalog-merge.ts +0 -19
  60. package/src/core/checkpoints.ts +0 -85
  61. package/src/core/churn.ts +0 -61
  62. package/src/core/command-artifacts.ts +0 -94
  63. package/src/core/command-contract.ts +0 -151
  64. package/src/core/completion-action.ts +0 -20
  65. package/src/core/completion-review.ts +0 -98
  66. package/src/core/context-detail.ts +0 -37
  67. package/src/core/context-policy.ts +0 -133
  68. package/src/core/context-window.ts +0 -54
  69. package/src/core/continuation.ts +0 -130
  70. package/src/core/control-protocol.ts +0 -69
  71. package/src/core/control-view.ts +0 -39
  72. package/src/core/cycle.ts +0 -17
  73. package/src/core/data-query.ts +0 -201
  74. package/src/core/deadline.ts +0 -40
  75. package/src/core/derive.ts +0 -516
  76. package/src/core/draft-images.ts +0 -56
  77. package/src/core/edit-plan.ts +0 -200
  78. package/src/core/environment.ts +0 -181
  79. package/src/core/event-validation.ts +0 -220
  80. package/src/core/events.ts +0 -670
  81. package/src/core/evidence-ladder.ts +0 -62
  82. package/src/core/evidence-links.ts +0 -68
  83. package/src/core/evidence.ts +0 -240
  84. package/src/core/execution.ts +0 -18
  85. package/src/core/exhaustive.ts +0 -18
  86. package/src/core/export.ts +0 -179
  87. package/src/core/extension-flags.ts +0 -14
  88. package/src/core/external-effects.ts +0 -488
  89. package/src/core/failure-recovery.ts +0 -173
  90. package/src/core/file-precondition.ts +0 -78
  91. package/src/core/file-references.ts +0 -35
  92. package/src/core/frontmatter.ts +0 -213
  93. package/src/core/git-status.ts +0 -29
  94. package/src/core/goal-view.ts +0 -64
  95. package/src/core/goal.ts +0 -200
  96. package/src/core/handoff.ts +0 -479
  97. package/src/core/history-query.ts +0 -139
  98. package/src/core/history.ts +0 -237
  99. package/src/core/image-limits.ts +0 -72
  100. package/src/core/images.ts +0 -46
  101. package/src/core/integration-health.ts +0 -34
  102. package/src/core/json-event.ts +0 -131
  103. package/src/core/json-pointer.ts +0 -46
  104. package/src/core/keymap.ts +0 -153
  105. package/src/core/lsp-framing.ts +0 -34
  106. package/src/core/mcp-config.ts +0 -68
  107. package/src/core/model-picker.ts +0 -64
  108. package/src/core/model-preferences.ts +0 -28
  109. package/src/core/model-replay.ts +0 -22
  110. package/src/core/model-scope.ts +0 -53
  111. package/src/core/note-guidance.ts +0 -34
  112. package/src/core/oauth-fields.ts +0 -44
  113. package/src/core/observation-view.ts +0 -152
  114. package/src/core/outcome.ts +0 -44
  115. package/src/core/overflow.ts +0 -59
  116. package/src/core/packages.ts +0 -47
  117. package/src/core/patch.ts +0 -130
  118. package/src/core/path-suggestions.ts +0 -59
  119. package/src/core/permissions.ts +0 -410
  120. package/src/core/process-receipt.ts +0 -105
  121. package/src/core/process-state.ts +0 -37
  122. package/src/core/program-status.ts +0 -40
  123. package/src/core/progress.ts +0 -150
  124. package/src/core/project.ts +0 -431
  125. package/src/core/prompt-policy.ts +0 -46
  126. package/src/core/prompts.ts +0 -111
  127. package/src/core/question.ts +0 -94
  128. package/src/core/queue.ts +0 -78
  129. package/src/core/read-bounds.ts +0 -24
  130. package/src/core/read-observation.ts +0 -106
  131. package/src/core/recovery-sources.ts +0 -74
  132. package/src/core/regex-dialect.ts +0 -25
  133. package/src/core/request-budget.ts +0 -23
  134. package/src/core/request-progress.ts +0 -87
  135. package/src/core/request-state.ts +0 -273
  136. package/src/core/resource-selection.ts +0 -36
  137. package/src/core/response-recovery.ts +0 -59
  138. package/src/core/resume.ts +0 -59
  139. package/src/core/review.ts +0 -68
  140. package/src/core/ripgrep-release.ts +0 -64
  141. package/src/core/runtime-target.ts +0 -94
  142. package/src/core/scheduling.ts +0 -8
  143. package/src/core/search-observation.ts +0 -97
  144. package/src/core/secrets.ts +0 -188
  145. package/src/core/session-archive.ts +0 -4
  146. package/src/core/session-browser.ts +0 -82
  147. package/src/core/session-entry.ts +0 -61
  148. package/src/core/session-exit.ts +0 -42
  149. package/src/core/session-format.ts +0 -169
  150. package/src/core/session-position.ts +0 -26
  151. package/src/core/session-tree.ts +0 -147
  152. package/src/core/settings.ts +0 -192
  153. package/src/core/skills.ts +0 -165
  154. package/src/core/sql-query.ts +0 -211
  155. package/src/core/stall.ts +0 -128
  156. package/src/core/stop-report.ts +0 -68
  157. package/src/core/text-normalize.ts +0 -81
  158. package/src/core/theme.ts +0 -166
  159. package/src/core/thinking.ts +0 -26
  160. package/src/core/tokens.ts +0 -151
  161. package/src/core/tool-contract.ts +0 -153
  162. package/src/core/tool-discovery.ts +0 -87
  163. package/src/core/tool-failure.ts +0 -81
  164. package/src/core/tool-input.ts +0 -44
  165. package/src/core/transcript.ts +0 -108
  166. package/src/core/tui-mode.ts +0 -29
  167. package/src/core/update-check.ts +0 -157
  168. package/src/core/version.ts +0 -55
  169. package/src/core/web-content.ts +0 -80
  170. package/src/core/work-state.ts +0 -154
  171. package/src/core/workflow-mode.ts +0 -34
  172. package/src/core/working-set.ts +0 -119
  173. package/src/core/yaml.ts +0 -282
  174. package/src/runtime/acp-agent.ts +0 -289
  175. package/src/runtime/agent-profiles.ts +0 -21
  176. package/src/runtime/auth.ts +0 -367
  177. package/src/runtime/blind-check.ts +0 -36
  178. package/src/runtime/branch-jobs.ts +0 -36
  179. package/src/runtime/catalog.ts +0 -285
  180. package/src/runtime/clipboard.ts +0 -125
  181. package/src/runtime/command-artifacts.ts +0 -64
  182. package/src/runtime/connection-reuse.ts +0 -40
  183. package/src/runtime/control-client.ts +0 -149
  184. package/src/runtime/control-connection.ts +0 -139
  185. package/src/runtime/counter-check.ts +0 -74
  186. package/src/runtime/environment-tools.ts +0 -60
  187. package/src/runtime/evidence-notes.ts +0 -35
  188. package/src/runtime/exec-sessions.ts +0 -456
  189. package/src/runtime/execution-control.ts +0 -40
  190. package/src/runtime/extension-loader.ts +0 -37
  191. package/src/runtime/extension-ui.ts +0 -47
  192. package/src/runtime/extensions.ts +0 -370
  193. package/src/runtime/formatter-tool.ts +0 -38
  194. package/src/runtime/formatter.ts +0 -50
  195. package/src/runtime/foundation.ts +0 -116
  196. package/src/runtime/history-cache.ts +0 -57
  197. package/src/runtime/history-tools.ts +0 -168
  198. package/src/runtime/images.ts +0 -80
  199. package/src/runtime/integrations.ts +0 -216
  200. package/src/runtime/loop.ts +0 -3001
  201. package/src/runtime/lsp-client.ts +0 -201
  202. package/src/runtime/mcp-client.ts +0 -264
  203. package/src/runtime/mcp-oauth.ts +0 -168
  204. package/src/runtime/mcp-schema.ts +0 -51
  205. package/src/runtime/model-config.ts +0 -232
  206. package/src/runtime/model-data.LICENSE +0 -27
  207. package/src/runtime/model-data.ts +0 -21
  208. package/src/runtime/model-discovery.ts +0 -208
  209. package/src/runtime/model-replay.ts +0 -10
  210. package/src/runtime/model-scope.ts +0 -20
  211. package/src/runtime/model-sources.ts +0 -151
  212. package/src/runtime/model.ts +0 -686
  213. package/src/runtime/models-fetch.ts +0 -57
  214. package/src/runtime/oauth-device.ts +0 -86
  215. package/src/runtime/oauth.ts +0 -853
  216. package/src/runtime/open-image.ts +0 -42
  217. package/src/runtime/openai-responses.ts +0 -304
  218. package/src/runtime/openai.ts +0 -697
  219. package/src/runtime/output-schema.ts +0 -26
  220. package/src/runtime/package-manager.ts +0 -125
  221. package/src/runtime/patch-tool.ts +0 -38
  222. package/src/runtime/permission-resources.ts +0 -18
  223. package/src/runtime/pi-provider.ts +0 -423
  224. package/src/runtime/program-status.ts +0 -38
  225. package/src/runtime/progress.ts +0 -26
  226. package/src/runtime/provider-access.ts +0 -21
  227. package/src/runtime/provider-connect.ts +0 -109
  228. package/src/runtime/provider-presets.ts +0 -98
  229. package/src/runtime/provider-protocols.ts +0 -29
  230. package/src/runtime/provider-request.ts +0 -87
  231. package/src/runtime/provider-tool-policy.ts +0 -33
  232. package/src/runtime/provider.ts +0 -580
  233. package/src/runtime/question-tool.ts +0 -62
  234. package/src/runtime/retry.ts +0 -447
  235. package/src/runtime/review-tool.ts +0 -48
  236. package/src/runtime/rich-text.ts +0 -36
  237. package/src/runtime/runtime-target.ts +0 -149
  238. package/src/runtime/secrets.ts +0 -79
  239. package/src/runtime/self-update.ts +0 -74
  240. package/src/runtime/session-control.ts +0 -265
  241. package/src/runtime/session-hub.ts +0 -85
  242. package/src/runtime/stream-idle.ts +0 -80
  243. package/src/runtime/tool-broker.ts +0 -137
  244. package/src/runtime/tool-discovery.ts +0 -58
  245. package/src/runtime/tool-queue.ts +0 -77
  246. package/src/runtime/tools.ts +0 -1820
  247. package/src/runtime/turn-effects.ts +0 -31
  248. package/src/runtime/update-check.ts +0 -48
  249. package/src/runtime/usage.ts +0 -253
  250. package/src/runtime/version.ts +0 -12
  251. package/src/runtime/web-http.ts +0 -56
  252. package/src/runtime/web-tools.ts +0 -88
  253. package/src/runtime/working-notes.ts +0 -60
  254. package/src/runtime/workspace-lifecycle.ts +0 -141
  255. package/src/store/acceptance.ts +0 -15
  256. package/src/store/agent-profile-files.ts +0 -13
  257. package/src/store/atomic.ts +0 -31
  258. package/src/store/auth-store.ts +0 -50
  259. package/src/store/blind-checks.ts +0 -32
  260. package/src/store/blobs.ts +0 -143
  261. package/src/store/checkpoint-history.ts +0 -32
  262. package/src/store/command-artifacts.ts +0 -96
  263. package/src/store/command.ts +0 -111
  264. package/src/store/config.ts +0 -69
  265. package/src/store/context-files.ts +0 -436
  266. package/src/store/file-checkpoints.ts +0 -108
  267. package/src/store/file-index.ts +0 -174
  268. package/src/store/foundation-config.ts +0 -24
  269. package/src/store/git-checkpoints.ts +0 -67
  270. package/src/store/git-status.ts +0 -15
  271. package/src/store/history-search.ts +0 -19
  272. package/src/store/log.ts +0 -725
  273. package/src/store/lsp-document.ts +0 -30
  274. package/src/store/mcp-credentials.ts +0 -85
  275. package/src/store/models.ts +0 -60
  276. package/src/store/observations.ts +0 -224
  277. package/src/store/packages.ts +0 -98
  278. package/src/store/patch.ts +0 -92
  279. package/src/store/permission-paths.ts +0 -34
  280. package/src/store/process-receipts.ts +0 -34
  281. package/src/store/query-source.ts +0 -49
  282. package/src/store/recovery.ts +0 -44
  283. package/src/store/replay.ts +0 -76
  284. package/src/store/resource-index.ts +0 -170
  285. package/src/store/resources.ts +0 -285
  286. package/src/store/restore.ts +0 -110
  287. package/src/store/review.ts +0 -109
  288. package/src/store/runtime-target.ts +0 -64
  289. package/src/store/search.ts +0 -728
  290. package/src/store/secrets.ts +0 -44
  291. package/src/store/serial.ts +0 -13
  292. package/src/store/session-archive.ts +0 -165
  293. package/src/store/session-browser.ts +0 -68
  294. package/src/store/session-position.ts +0 -27
  295. package/src/store/sessions.ts +0 -525
  296. package/src/store/source-cancellation.ts +0 -6
  297. package/src/store/tool-binaries.ts +0 -90
  298. package/src/store/trust.ts +0 -82
  299. package/src/store/update-cache.ts +0 -36
  300. package/src/store/user-settings.ts +0 -30
  301. package/src/store/workspace-clone.ts +0 -42
  302. package/src/store/workspace-observation.ts +0 -113
  303. package/src/store/workspace.ts +0 -115
  304. package/src/store/worktree.ts +0 -278
  305. package/src/tui/ansi-spans.ts +0 -126
  306. package/src/tui/diff.ts +0 -160
  307. package/src/tui/exhaustive.ts +0 -14
  308. package/src/tui/fuzzy.ts +0 -75
  309. package/src/tui/style.ts +0 -208
  310. package/src/tui/ui/atomic-draft.ts +0 -121
  311. package/src/tui/ui/canvas.ts +0 -96
  312. package/src/tui/ui/colors.ts +0 -70
  313. package/src/tui/ui/composer.ts +0 -200
  314. package/src/tui/ui/control-panel.ts +0 -25
  315. package/src/tui/ui/control-sidebar.ts +0 -49
  316. package/src/tui/ui/dialog.ts +0 -398
  317. package/src/tui/ui/draft.ts +0 -23
  318. package/src/tui/ui/duration.ts +0 -16
  319. package/src/tui/ui/edge.ts +0 -186
  320. package/src/tui/ui/image-size.ts +0 -44
  321. package/src/tui/ui/ink.ts +0 -210
  322. package/src/tui/ui/items.ts +0 -42
  323. package/src/tui/ui/keys.ts +0 -40
  324. package/src/tui/ui/layout.ts +0 -74
  325. package/src/tui/ui/list-model.ts +0 -86
  326. package/src/tui/ui/list-view.ts +0 -172
  327. package/src/tui/ui/mascot.ts +0 -67
  328. package/src/tui/ui/messages.ts +0 -518
  329. package/src/tui/ui/motion.ts +0 -28
  330. package/src/tui/ui/paths.ts +0 -10
  331. package/src/tui/ui/pictures.ts +0 -108
  332. package/src/tui/ui/screen.ts +0 -548
  333. package/src/tui/ui/status.ts +0 -403
  334. package/src/tui/ui/styled.ts +0 -85
  335. package/src/tui/ui/tool-card.ts +0 -150
  336. package/src/tui/width.ts +0 -567
  337. package/src/vendor/pi-rich/LICENSE.upstream +0 -21
  338. package/src/vendor/pi-rich/UPSTREAM.json +0 -17
  339. package/src/vendor/pi-rich/clipboard-command.ts +0 -44
  340. package/src/vendor/pi-rich/exif-orientation.ts +0 -182
  341. package/src/vendor/pi-rich/html.ts +0 -51
  342. package/src/vendor/pi-rich/image-convert.ts +0 -49
  343. package/src/vendor/pi-rich/image-resize-core.ts +0 -164
  344. package/src/vendor/pi-rich/image-resize-worker.ts +0 -42
  345. package/src/vendor/pi-rich/image-resize.ts +0 -123
  346. package/src/vendor/pi-rich/mime.ts +0 -116
  347. package/src/vendor/pi-rich/photon.ts +0 -139
  348. package/src/vendor/pi-rich/syntax-highlight.ts +0 -214
@@ -1,152 +0,0 @@
1
- /**
2
- * How a bounded observation is presented to the model.
3
- *
4
- * The complete bytes always live in a blob (D8: reference, never inline), so
5
- * this is only a view -- but it is the view the model reasons from. Keeping
6
- * only the head, as this module's predecessor did, cuts exactly the part a
7
- * failing build or test run prints last: the error and the summary. Codex
8
- * keeps half of each end (`utils/string/src/truncate.rs`); so does this.
9
- */
10
- import type { ArtifactRef } from "./events.ts";
11
-
12
- export interface BytePreview {
13
- unit: "utf8_bytes";
14
- complete: boolean;
15
- visible: readonly (readonly [number, number])[];
16
- next_offset: number | null;
17
- }
18
- const object = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === "object" && !Array.isArray(value);
19
- const natural = (value: unknown): value is number => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
20
- export function isObservationArtifact(value: unknown): value is ArtifactRef {
21
- return object(value) && typeof value["sha256"] === "string" && /^[a-f0-9]{64}$/.test(value["sha256"]) && typeof value["path"] === "string" && natural(value["bytes"]);
22
- }
23
- /** The same coverage invariant serves file reads and search projections. */
24
- export function isBytePreview(value: unknown, total: number): value is BytePreview {
25
- if (!object(value) || value["unit"] !== "utf8_bytes" || typeof value["complete"] !== "boolean" || !Array.isArray(value["visible"])) return false;
26
- let last = 0, prefix = 0;
27
- for (const range of value["visible"]) {
28
- if (!Array.isArray(range) || range.length !== 2 || !natural(range[0]) || !natural(range[1]) || range[0] < last || range[1] <= range[0] || range[1] > total) return false;
29
- if (prefix === range[0]) prefix = range[1];
30
- last = range[1];
31
- }
32
- return value["complete"] === (prefix === total) && value["next_offset"] === (value["complete"] ? null : prefix);
33
- }
34
-
35
- /** A UTF-8 continuation byte: cutting before one would split a character. */
36
- const continuation = (byte: number | undefined) => byte !== undefined && (byte & 0xc0) === 0x80;
37
-
38
- /**
39
- * Head and tail of an observation within `limit` bytes.
40
- *
41
- * `head` is the first bytes and `tail` the last bytes of an observation of
42
- * `total` bytes; each need only be as long as `limit`. When the whole
43
- * observation fits, it is returned unchanged. Otherwise the marker, which is
44
- * given the omitted byte count and the byte offset where the gap starts (so
45
- * the model can page the missing middle back), sits between the two ends.
46
- * Cuts land on character boundaries, which is why a view can come out a few
47
- * bytes under budget but never over it for valid UTF-8 input.
48
- */
49
- export function headTailView(
50
- head: Uint8Array,
51
- tail: Uint8Array,
52
- total: number,
53
- limit: number,
54
- marker: (omitted: number, offset: number) => string,
55
- ): string {
56
- // Legacy command callers require the recovery locator even below its minimum display budget.
57
- return headTailSelection(head, tail, total, limit, marker, true).text;
58
- }
59
-
60
- /** Half-open byte ranges in the original observation, excluding presentation markers. */
61
- export function headTailSelection(
62
- head: Uint8Array, tail: Uint8Array, total: number, limit: number,
63
- marker: (omitted: number, offset: number) => string, allowOversizeMarker = false,
64
- ): { text: string; visible: [number, number][] } {
65
- const decoder = new TextDecoder();
66
- if (total <= limit && head.length >= total) return { text: decoder.decode(head.subarray(0, total)), visible: total ? [[0, total]] : [] };
67
- // Digits of the real numbers never exceed digits of `total`, so this bounds
68
- // the marker before the cut points that decide its numbers are known.
69
- const reserve = new TextEncoder().encode(marker(total, total)).length;
70
- if (reserve > limit && !allowOversizeMarker) {
71
- const bytes = new TextEncoder().encode(marker(total, 0));
72
- let end = Math.max(0, Math.min(Math.floor(limit), bytes.length));
73
- while (end > 0 && continuation(bytes[end])) end--;
74
- return { text: decoder.decode(bytes.subarray(0, end)), visible: [] };
75
- }
76
- const budget = Math.max(0, limit - reserve);
77
- let headEnd = Math.min(Math.floor(budget / 2), head.length);
78
- while (headEnd > 0 && continuation(head[headEnd])) headEnd--;
79
- let tailStart = tail.length - Math.min(budget - headEnd, tail.length);
80
- while (tailStart < tail.length && continuation(tail[tailStart])) tailStart++;
81
- const kept = tail.length - tailStart;
82
- return { text: decoder.decode(head.subarray(0, headEnd)) +
83
- marker(total - headEnd - kept, headEnd) +
84
- decoder.decode(tail.subarray(tailStart)),
85
- visible: [...(headEnd ? [[0, headEnd] as [number, number]] : []), ...(kept ? [[total - kept, total] as [number, number]] : [])] };
86
- }
87
-
88
- /**
89
- * The text a terminal would finally show for output that redraws lines with
90
- * `\r` (progress bars). Within each `\n`-separated line, a carriage return
91
- * moves back to column 0 and the following characters overwrite, one code
92
- * point each; characters not overwritten stay. `\r\n` is thus a plain line
93
- * break. Other control sequences (`ESC[K` and the like) are left as they are.
94
- *
95
- * A view only: the archived bytes keep every frame (D8). Without this a 6.3KB
96
- * brew download of 48 frames reached the model whole (carriage-return-view
97
- * card), though a terminal showed one line.
98
- */
99
- export function foldCarriageReturns(text: string): string {
100
- if (!text.includes("\r")) return text;
101
- return text.split("\n").map(line => {
102
- if (!line.includes("\r")) return line;
103
- let screen: string[] = [];
104
- for (const frame of line.split("\r")) {
105
- const chars = Array.from(frame);
106
- screen = chars.concat(screen.slice(chars.length));
107
- }
108
- return screen.join("");
109
- }).join("\n");
110
- }
111
-
112
- /** Signals a shell reports as 128+n; the common ones a model can act on. */
113
- const SIGNALS: Readonly<Record<number, string>> = {
114
- 1: "SIGHUP", 2: "SIGINT", 6: "SIGABRT", 9: "SIGKILL", 11: "SIGSEGV", 13: "SIGPIPE", 15: "SIGTERM",
115
- };
116
-
117
- const seconds = (ms: number) => `${Number((ms / 1000).toFixed(1))}s`;
118
-
119
- /**
120
- * First line of a command result.
121
- *
122
- * `exit N` stays first because both the TUI and the log readers key on it.
123
- * What follows states facts the exit code alone hides: a timeout reads as
124
- * `exit 143`, which a model otherwise takes for the program's own failure and
125
- * reruns unchanged (codex puts wall time and exit in the same header,
126
- * `core/src/tools/context.rs`).
127
- */
128
- export function commandHeader(input: {
129
- exit: number;
130
- wallMs: number;
131
- stopped?: "timeout" | "cancelled";
132
- /** The timeout actually applied. */
133
- timeoutMs: number;
134
- /** What the model asked for, when that differs from what was applied. */
135
- requestedMs?: number;
136
- managed?: boolean;
137
- }): string {
138
- const parts = [`exit ${input.exit}`, `${(input.wallMs / 1000).toFixed(1)}s`];
139
- if (input.stopped === "timeout") {
140
- const requested = input.requestedMs !== undefined && input.requestedMs !== input.timeoutMs
141
- ? ` (requested ${seconds(input.requestedMs)}, capped)` : "";
142
- // A deadline requests cleanup, but cannot by itself prove absence of
143
- // partial side effects or successful cleanup (R3 / R10).
144
- parts.push(`timed out after ${seconds(input.timeoutMs)}${requested}; process group cleanup requested; ` +
145
- "inspect partial effects and cleanup before deciding on a new invocation or a larger timeout");
146
- } else if (input.stopped === "cancelled") {
147
- parts.push("cancelled; process group cleanup requested");
148
- } else if (input.exit > 128 && SIGNALS[input.exit - 128] !== undefined) {
149
- parts.push(`128+${input.exit - 128}: likely terminated by ${SIGNALS[input.exit - 128]}`);
150
- }
151
- return parts.join(" · ");
152
- }
@@ -1,44 +0,0 @@
1
- /** O.1 / D11: execution termination is a fact, distinct from verified work. */
2
- const STATUS = {
3
- model_end: "completed",
4
- tool_completed: "completed",
5
- cancelled: "cancelled",
6
- not_started: "cancelled",
7
- max_turns: "stopped",
8
- context_budget: "stopped",
9
- stalled: "stopped",
10
- no_progress: "stopped",
11
- output_limit: "stopped",
12
- timeout: "stopped",
13
- model_refusal: "failed",
14
- provider_error: "failed",
15
- execution_error: "failed",
16
- projection_invalid: "failed",
17
- tool_failed: "failed",
18
- unknown: "unknown",
19
- } as const;
20
-
21
- export type ExecutionReason = keyof typeof STATUS;
22
- export type ExecutionOutcome = {
23
- status: (typeof STATUS)[ExecutionReason];
24
- reason: ExecutionReason;
25
- };
26
-
27
- export function executionOutcome(reason: ExecutionReason): ExecutionOutcome {
28
- return { status: STATUS[reason], reason };
29
- }
30
-
31
- /** Unknown/legacy provider reasons never silently turn into success. */
32
- export function modelOutcome(reason: string | null): ExecutionOutcome {
33
- if (reason === "end_turn" || reason === "stop" || reason === "stop_sequence") return executionOutcome("model_end");
34
- if (reason === "max_tokens" || reason === "length") return executionOutcome("output_limit");
35
- if (reason === "refusal" || reason === "content_filter") return executionOutcome("model_refusal");
36
- if (reason === "error") return executionOutcome("provider_error");
37
- return executionOutcome("unknown");
38
- }
39
-
40
- export function isExecutionOutcome(value: unknown): value is ExecutionOutcome {
41
- if (value === null || typeof value !== "object" || !("reason" in value) || !("status" in value)) return false;
42
- return typeof value.reason === "string" && Object.hasOwn(STATUS, value.reason) &&
43
- value.status === STATUS[value.reason as ExecutionReason];
44
- }
@@ -1,59 +0,0 @@
1
- /**
2
- * Whether a provider error means "the prompt does not fit the window".
3
- *
4
- * That failure needs a different remedy from every other one: retrying the
5
- * same request fails the same way (so it must not be retried even when a
6
- * relay reports it as a 5xx), and the only thing that makes it succeed is a
7
- * smaller projection. Providers word it differently and none shares a code,
8
- * so recognition is by message text.
9
- *
10
- * Patterns ported from pi-mono `packages/ai/src/utils/overflow.ts` (MIT,
11
- * commit 6f75515); the provider each one came from is kept beside it. A
12
- * provider not listed here surfaces as an ordinary error, which is the safe
13
- * direction: a missed overflow ends the turn visibly, a false one would cut
14
- * a healthy context.
15
- */
16
- const OVERFLOW_PATTERNS: readonly RegExp[] = [
17
- /prompt (?:is )?too long/i, // Anthropic, z.ai
18
- /request_too_large/i, // Anthropic byte-size overflow (413)
19
- /input is too long for requested model/i, // Amazon Bedrock
20
- /exceeds the context window/i, // OpenAI (Completions & Responses)
21
- /exceeds (?:the )?(?:model'?s )?maximum context length(?: of [\d,]+ tokens?|\s*\([\d,]+\))/i, // OpenAI-compatible proxies
22
- /input token count.*exceeds the maximum/i, // Google Gemini
23
- /maximum prompt length is \d+/i, // xAI
24
- /reduce the length of the messages/i, // Groq
25
- /maximum context length is \d+ tokens/i, // OpenRouter
26
- /exceeds (?:the )?maximum allowed input length of [\d,]+ tokens?/i, // OpenRouter / Poolside
27
- /input \(\d+ tokens\) is longer than the model'?s context length \(\d+ tokens\)/i, // Together AI
28
- /exceeds the limit of \d+/i, // GitHub Copilot
29
- /exceeds the available context size/i, // llama.cpp
30
- /greater than the context length/i, // LM Studio
31
- /context window exceeds limit/i, // MiniMax
32
- /exceeded model token limit/i, // Kimi
33
- /too large for model with \d+ maximum context length/i, // Mistral
34
- /prompt has [\d,]+ tokens?, but the configured context size is [\d,]+ tokens?/i, // DS4
35
- /model_context_window_exceeded/i, // z.ai finish reason surfaced as error text
36
- /prompt too long; exceeded (?:max )?context length/i, // Ollama
37
- /range of input length should be/i, // DashScope / Qwen
38
- /context[_ ]length[_ ]exceeded/i, // generic
39
- /too many tokens/i, // generic
40
- /token limit exceeded/i, // generic
41
- ];
42
-
43
- /** Throttling that happens to mention tokens; excluded even when a pattern above matches. */
44
- const NOT_OVERFLOW: readonly RegExp[] = [
45
- /^(Throttling error|Service unavailable):/i,
46
- /throttl/i,
47
- /rate limit/i,
48
- /too many requests/i,
49
- /please wait/i,
50
- ];
51
-
52
- /** Cerebras answers an oversized request with a bodiless 400 / 413. */
53
- const BODYLESS = /^4(?:00|13)\s*(?:status code)?\s*\(no body\)/i;
54
-
55
- export function isContextOverflow(message: string, status?: number): boolean {
56
- if (status === 429) return false;
57
- if (NOT_OVERFLOW.some((pattern) => pattern.test(message))) return false;
58
- return OVERFLOW_PATTERNS.some((pattern) => pattern.test(message)) || BODYLESS.test(message.trim());
59
- }
@@ -1,47 +0,0 @@
1
- /** Pi package identities and filters, independent of installation and I/O (D13). */
2
- import { parseResourcePattern, type ResourceKind } from "./resource-selection.ts";
3
-
4
- export type PackageDeclaration = string | ({ source: string; autoload?: boolean } & Partial<Record<ResourceKind, readonly string[]>>);
5
- export type PackageSource =
6
- | { kind: "local"; id: string; path: string; source: string; pinned: true }
7
- | { kind: "npm"; id: string; name: string; spec: string; version?: string; source: string; pinned: boolean }
8
- | { kind: "git"; id: string; repo: string; ref?: string; source: string; pinned: boolean };
9
- export function packageDeclaration(value: unknown): value is PackageDeclaration {
10
- if (typeof value === "string") return value.trim().length > 0;
11
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
12
- const entry = value as Record<string, unknown>;
13
- return typeof entry["source"] === "string" && entry["source"].trim().length > 0 &&
14
- (entry["autoload"] === undefined || typeof entry["autoload"] === "boolean") &&
15
- ["extensions", "skills", "prompts", "themes"].every(key => entry[key] === undefined || Array.isArray(entry[key]) && entry[key].every(p => typeof p === "string"));
16
- }
17
- export function packageConfig(value: PackageDeclaration): Exclude<PackageDeclaration, string> { return typeof value === "string" ? { source: value } : value; }
18
- export function parsePackageSource(raw: string, localPath: (path: string) => string): PackageSource {
19
- const source = raw.trim(); if (!source || source.startsWith("-") || /[\x00-\x1f]/.test(source)) throw Error("Invalid package source");
20
- if (source.startsWith("npm:")) {
21
- const spec = source.slice(4), at = spec.lastIndexOf("@"), name = at > 0 ? spec.slice(0, at) : spec, version = at > 0 ? spec.slice(at + 1) : undefined;
22
- if (!/^(?:@[a-zA-Z0-9][a-zA-Z0-9._-]*\/)?[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name) || version === "" || version?.startsWith("-")) throw Error("Invalid npm package source");
23
- return { kind: "npm", id: "npm:" + name, source, name, spec, ...(version === undefined ? {} : { version }), pinned: !!version && /^v?\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(version) };
24
- }
25
- if (/^(git:|git\+|https?:\/\/|ssh:\/\/|git@)/.test(source)) {
26
- let repo = source.replace(/^git:(?!\/\/)/, "").replace(/^git\+/, ""), ref: string | undefined;
27
- const hash = repo.lastIndexOf("#"), at = repo.lastIndexOf("@");
28
- const authorityEnd = /^\w+:\/\//.test(repo) ? repo.indexOf("/",repo.indexOf("://")+3) : repo.startsWith("git@") ? repo.indexOf(":") : repo.indexOf("/");
29
- const split = hash >= 0 ? hash : at > authorityEnd && authorityEnd >= 0 ? at : -1;
30
- if (split >= 0) { ref = repo.slice(split + 1); repo = repo.slice(0, split); if (!ref || ref.startsWith("-")) throw Error("Invalid git ref"); }
31
- if (!/^(\w+:\/\/|git@|\/|\.\.?\/)/.test(repo)) repo = "https://" + repo;
32
- const remote = /^\w+:\/\//.test(repo) ? new URL(repo) : undefined;
33
- const canonical = (remote ? remote.host.toLowerCase()+remote.pathname : repo.replace(/^git@([^:]+):/, "$1/")).replace(/\.git\/?$/, "").replace(/\/$/, "");
34
- if (!canonical.includes("/")) throw Error("Invalid git repository");
35
- return { kind: "git", source, repo, id: "git:" + canonical, ...(ref === undefined ? {} : { ref }), pinned: ref !== undefined };
36
- }
37
- const path = localPath(source); return { kind: "local", id: "local:" + path, source, path, pinned: true };
38
- }
39
-
40
- /** Missing filters inherit; [] excludes all; ordinary positive patterns form a whitelist. */
41
- export function packageResourceEnabled(patterns: readonly string[] | undefined, matches: (pattern: string, exact: boolean) => boolean, inherited = true): boolean {
42
- if (patterns === undefined) return inherited;
43
- if (patterns.length === 0) return false;
44
- let enabled = patterns.some(pattern => !/^[!+-]/.test(pattern)) ? false : inherited;
45
- for (const raw of patterns) { const pattern = parseResourcePattern(raw); if (matches(pattern.pattern,pattern.explicit)) enabled = pattern.enabled; }
46
- return enabled;
47
- }
package/src/core/patch.ts DELETED
@@ -1,130 +0,0 @@
1
- /** Codex patch grammar with exact, unambiguous matching (D9 / R4). No I/O. */
2
- import { assertNever } from "./exhaustive.ts";
3
-
4
- // Assumed resource ceilings, not measured: reject oversized plans before retaining hunks.
5
- export const MAX_PATCH_CHARS = 2 * 1024 * 1024;
6
- export const MAX_PATCH_FILES = 100;
7
- export interface PatchChunk {
8
- oldLines: readonly string[];
9
- newLines: readonly string[];
10
- anchor?: string;
11
- endOfFile: boolean;
12
- }
13
- export type PatchOperation =
14
- | { kind: "add"; path: string; content: string }
15
- | { kind: "delete"; path: string }
16
- | { kind: "update"; path: string; movePath?: string; chunks: readonly PatchChunk[] };
17
- export class PatchError extends Error {
18
- readonly code: "invalid_input" | "not_found" | "ambiguous_edit";
19
- constructor(code: PatchError["code"], message: string) { super(message); this.code = code; }
20
- }
21
- const invalid = (message: string): never => { throw new PatchError("invalid_input", message); };
22
- const pathValue = (text: string): string => {
23
- if (!text.trim() || text.includes("\0")) return invalid("patch paths must be nonempty and contain no NUL");
24
- return text;
25
- };
26
- const fileHeader = (line: string) => /^\*\*\* (?:Add|Delete|Update) File: /.test(line);
27
-
28
- /** Parse all operations before the store resolves any target or changes a byte. */
29
- export function parsePatch(text: string): PatchOperation[] {
30
- if (text.length > MAX_PATCH_CHARS) return invalid("patch exceeds the character budget");
31
- const lines = text.replaceAll("\r\n", "\n").trim().split("\n");
32
- if (lines[0] !== "*** Begin Patch" || lines.at(-1) !== "*** End Patch")
33
- return invalid("patch must begin with *** Begin Patch and end with *** End Patch");
34
- const operations: PatchOperation[] = [];
35
- let index = 1;
36
- while (index < lines.length - 1) {
37
- if (operations.length >= MAX_PATCH_FILES) return invalid("patch exceeds the file budget");
38
- const header = lines[index++]!;
39
- if (header.startsWith("*** Add File: ")) {
40
- const path = pathValue(header.slice("*** Add File: ".length));
41
- const added: string[] = [];
42
- while (index < lines.length - 1 && !fileHeader(lines[index]!)) {
43
- const line = lines[index++]!;
44
- if (!line.startsWith("+")) return invalid(`added lines must start with +: ${path}`);
45
- added.push(line.slice(1));
46
- }
47
- operations.push({ kind: "add", path, content: added.length ? added.join("\n") + "\n" : "" });
48
- continue;
49
- }
50
- if (header.startsWith("*** Delete File: ")) {
51
- operations.push({ kind: "delete", path: pathValue(header.slice("*** Delete File: ".length)) });
52
- continue;
53
- }
54
- if (!header.startsWith("*** Update File: ")) return invalid(`unexpected patch line ${index}: ${header}`);
55
- const path = pathValue(header.slice("*** Update File: ".length));
56
- const moveLine = lines[index];
57
- const movePath = moveLine?.startsWith("*** Move to: ") ? pathValue(moveLine.slice("*** Move to: ".length)) : undefined;
58
- if (movePath !== undefined) index++;
59
- const chunks: PatchChunk[] = [];
60
- while (index < lines.length - 1 && !fileHeader(lines[index]!)) {
61
- const marker = lines[index++]!;
62
- if (marker !== "@@" && !marker.startsWith("@@ ")) return invalid(`update hunks must start with @@: ${path}`);
63
- const oldLines: string[] = [], newLines: string[] = [];
64
- let endOfFile = false, changed = false;
65
- while (index < lines.length - 1 && !fileHeader(lines[index]!) && !lines[index]!.startsWith("@@")) {
66
- const line = lines[index++]!;
67
- if (line === "*** End of File") { endOfFile = true; break; }
68
- const prefix = line[0];
69
- if (prefix !== " " && prefix !== "+" && prefix !== "-") return invalid(`invalid update line: ${path}`);
70
- if (prefix !== "+") oldLines.push(line.slice(1));
71
- if (prefix !== "-") newLines.push(line.slice(1));
72
- if (prefix !== " ") changed = true;
73
- }
74
- if (!changed) return invalid(`update hunk makes no change: ${path}`);
75
- chunks.push({ oldLines, newLines, endOfFile, ...(marker === "@@" ? {} : { anchor: marker.slice(3) }) });
76
- if (endOfFile && index < lines.length - 1 && !fileHeader(lines[index]!)) return invalid(`End of File must finish the update: ${path}`);
77
- }
78
- if (!chunks.length && movePath === undefined) return invalid(`update has no hunks: ${path}`);
79
- operations.push({ kind: "update", path, chunks, ...(movePath === undefined ? {} : { movePath }) });
80
- }
81
- if (!operations.length) return invalid("patch is empty");
82
- return operations;
83
- }
84
-
85
- /** Keep BOM, line endings and final-newline status; ambiguous contexts require a reread. */
86
- export function applyPatchChunks(before: string, chunks: readonly PatchChunk[]): string {
87
- const bom = before.startsWith("\uFEFF") ? "\uFEFF" : "";
88
- const body = before.slice(bom.length);
89
- const ending = body.includes("\r\n") ? "\r\n" : "\n";
90
- const normalized = body.replaceAll("\r\n", "\n");
91
- if (normalized.includes("\r")) return invalid("patch updates do not support bare CR line endings");
92
- if (ending === "\r\n" && body.replaceAll("\r\n", "").includes("\n"))
93
- return invalid("patch updates require a consistent line ending; mixed LF/CRLF bytes were preserved");
94
- const finalNewline = normalized.endsWith("\n");
95
- const lines = normalized ? normalized.split("\n") : [];
96
- if (finalNewline) lines.pop();
97
- let cursor = 0;
98
- for (const chunk of chunks) {
99
- let start = cursor;
100
- if (chunk.anchor !== undefined) {
101
- const anchors = lines.flatMap((line, at) => at >= cursor && line === chunk.anchor ? [at] : []);
102
- if (anchors.length !== 1) throw new PatchError(anchors.length ? "ambiguous_edit" : "not_found", "patch anchor must match exactly once after the preceding hunk");
103
- start = anchors[0]! + 1;
104
- }
105
- const matches: number[] = [];
106
- for (let at = start; at <= lines.length - chunk.oldLines.length; at++) {
107
- if (chunk.endOfFile && at + chunk.oldLines.length !== lines.length) continue;
108
- if (chunk.oldLines.every((line, offset) => lines[at + offset] === line)) matches.push(at);
109
- }
110
- if (!chunk.oldLines.length && !chunk.endOfFile) {
111
- if (chunk.anchor !== undefined || lines.length === 0) matches.splice(0, matches.length, start);
112
- else throw new PatchError("ambiguous_edit", "insertion needs an anchor, End of File, or an empty source");
113
- }
114
- if (matches.length !== 1) throw new PatchError(matches.length ? "ambiguous_edit" : "not_found", "patch context must match exactly once; read current content and add context");
115
- const at = matches[0]!;
116
- lines.splice(at, chunk.oldLines.length, ...chunk.newLines);
117
- cursor = at + chunk.newLines.length;
118
- }
119
- return bom + lines.join(ending) + (finalNewline && lines.length ? ending : "");
120
- }
121
-
122
- export function patchPaths(operations: readonly PatchOperation[]): string[] {
123
- return operations.flatMap(operation => {
124
- switch (operation.kind) {
125
- case "add": case "delete": return [operation.path];
126
- case "update": return operation.movePath === undefined ? [operation.path] : [operation.path, operation.movePath];
127
- default: return assertNever(operation, "patchPaths");
128
- }
129
- });
130
- }
@@ -1,59 +0,0 @@
1
- /**
2
- * Existing paths that a missing one probably meant.
3
- *
4
- * Models guess paths, and most guesses in a reviewed session (flotil: 11 of
5
- * 11 ENOENT) had the right file name in the wrong directory or a near
6
- * spelling. OpenCode's read tool suggests up to three entries of the same
7
- * directory whose name contains, or is contained in, the requested one
8
- * (`packages/opencode/src/tool/read.ts`); that misses a wrong directory, so
9
- * this ranks the whole workspace listing, file name first.
10
- *
11
- * Pure and deterministic: the result depends on the set of candidates, never
12
- * their order, so the same failure always names the same paths.
13
- */
14
- import { editDistance } from "./text-normalize.ts";
15
-
16
- /** OpenCode's count: enough to cover a wrong directory, short enough to read at a glance. */
17
- export const PATH_SUGGESTION_LIMIT = 3;
18
-
19
- /** Containment of a shorter name is too weak a signal below this length (assumed: "a" is in everything). */
20
- const MIN_CONTAINED = 3;
21
-
22
- const baseName = (path: string) => path.slice(path.lastIndexOf("/") + 1);
23
- const stem = (name: string) => { const dot = name.lastIndexOf("."); return dot > 0 ? name.slice(0, dot) : name; };
24
-
25
- /**
26
- * Rank tier of `name` against the wanted file name, or null when unrelated.
27
- * 0: same name; 1: same name without extension; 2: one name contains the
28
- * other; 3: a near spelling (edit distance within a quarter of the length).
29
- */
30
- function tier(name: string, wanted: string, distance: number): number | null {
31
- if (name === wanted) return 0;
32
- if (stem(name) === stem(wanted) && stem(name).length > 0) return 1;
33
- const shorter = name.length < wanted.length ? name : wanted, longer = shorter === name ? wanted : name;
34
- if (shorter.length >= MIN_CONTAINED && longer.includes(shorter)) return 2;
35
- if (distance <= Math.max(1, Math.floor(wanted.length / 4))) return 3;
36
- return null;
37
- }
38
-
39
- /**
40
- * Up to `limit` workspace-relative paths from `candidates` closest to the
41
- * missing `target`, best first. Paths use "/" separators; comparison ignores
42
- * case. The target itself is never suggested.
43
- */
44
- export function nearestPaths(target: string, candidates: readonly string[], limit = PATH_SUGGESTION_LIMIT): string[] {
45
- const wantedPath = target.replace(/^\.\//, "").toLowerCase();
46
- const wanted = baseName(wantedPath);
47
- if (wanted.length === 0 || limit <= 0) return [];
48
- const ranked: { path: string; tier: number; name: number; whole: number }[] = [];
49
- for (const path of new Set(candidates)) {
50
- const lower = path.toLowerCase();
51
- if (lower === wantedPath) continue;
52
- const name = baseName(lower), distance = editDistance(name, wanted);
53
- const rank = tier(name, wanted, distance);
54
- if (rank === null) continue;
55
- ranked.push({ path, tier: rank, name: distance, whole: editDistance(lower, wantedPath) });
56
- }
57
- ranked.sort((a, b) => a.tier - b.tier || a.name - b.name || a.whole - b.whole || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
58
- return ranked.slice(0, limit).map(item => item.path);
59
- }