@astralyn/pi 1.4.2 → 1.4.4

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 (262) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/bundle/chunks/{chunk-FGPSYHTQ.js → chunk-SBVVM3NV.js} +117 -117
  3. package/dist/bundle/chunks/{chunk-HXKY52DF.js → chunk-VGSZTBVJ.js} +1 -1
  4. package/dist/bundle/chunks/{virtual-modules-5NSVVTKO.js → virtual-modules-ETYFHSUG.js} +1 -1
  5. package/dist/bundle/cli.js +1 -1
  6. package/dist/bundle/index.js +1 -1
  7. package/dist/bundle/rpc-entry.js +1 -1
  8. package/dist/core/agent-session.d.ts +15 -1
  9. package/dist/core/agent-session.d.ts.map +1 -1
  10. package/dist/core/agent-session.js +1 -8
  11. package/dist/core/agent-session.js.map +1 -1
  12. package/dist/core/extensions/distribution-api.d.ts +1 -1
  13. package/dist/core/extensions/distribution-api.d.ts.map +1 -1
  14. package/dist/core/extensions/distribution-api.js.map +1 -1
  15. package/dist/core/extensions/index.d.ts +2 -2
  16. package/dist/core/extensions/index.d.ts.map +1 -1
  17. package/dist/core/extensions/index.js.map +1 -1
  18. package/dist/core/extensions/runner.d.ts.map +1 -1
  19. package/dist/core/extensions/runner.js +4 -2
  20. package/dist/core/extensions/runner.js.map +1 -1
  21. package/dist/core/extensions/types.d.ts +14 -1
  22. package/dist/core/extensions/types.d.ts.map +1 -1
  23. package/dist/core/extensions/types.js.map +1 -1
  24. package/dist/core/keybinding-registry.d.ts +16 -1
  25. package/dist/core/keybinding-registry.d.ts.map +1 -1
  26. package/dist/core/keybinding-registry.js +20 -0
  27. package/dist/core/keybinding-registry.js.map +1 -1
  28. package/dist/core/keybindings-schema.d.ts.map +1 -1
  29. package/dist/core/keybindings-schema.js +2 -1
  30. package/dist/core/keybindings-schema.js.map +1 -1
  31. package/dist/core/keybindings.d.ts +4 -106
  32. package/dist/core/keybindings.d.ts.map +1 -1
  33. package/dist/core/keybindings.js +0 -13
  34. package/dist/core/keybindings.js.map +1 -1
  35. package/dist/core/slash-commands.d.ts.map +1 -1
  36. package/dist/core/slash-commands.js +0 -1
  37. package/dist/core/slash-commands.js.map +1 -1
  38. package/dist/core/tasks/format.d.ts.map +1 -1
  39. package/dist/core/tasks/format.js +10 -4
  40. package/dist/core/tasks/format.js.map +1 -1
  41. package/dist/core/tasks/limits.d.ts +5 -0
  42. package/dist/core/tasks/limits.d.ts.map +1 -0
  43. package/dist/core/tasks/limits.js +5 -0
  44. package/dist/core/tasks/limits.js.map +1 -0
  45. package/dist/core/tasks/runtime.d.ts +1 -0
  46. package/dist/core/tasks/runtime.d.ts.map +1 -1
  47. package/dist/core/tasks/runtime.js +7 -3
  48. package/dist/core/tasks/runtime.js.map +1 -1
  49. package/dist/core/tasks/session.d.ts +1 -1
  50. package/dist/core/tasks/session.d.ts.map +1 -1
  51. package/dist/core/tasks/session.js +10 -2
  52. package/dist/core/tasks/session.js.map +1 -1
  53. package/dist/core/tasks/types.d.ts +13 -0
  54. package/dist/core/tasks/types.d.ts.map +1 -1
  55. package/dist/core/tasks/types.js.map +1 -1
  56. package/dist/core/tools/bash.d.ts +98 -9
  57. package/dist/core/tools/bash.d.ts.map +1 -1
  58. package/dist/core/tools/bash.js +308 -11
  59. package/dist/core/tools/bash.js.map +1 -1
  60. package/dist/core/tools/index.d.ts +5 -4
  61. package/dist/core/tools/index.d.ts.map +1 -1
  62. package/dist/core/tools/index.js +3 -11
  63. package/dist/core/tools/index.js.map +1 -1
  64. package/dist/core/tools/powershell.d.ts +2 -1
  65. package/dist/core/tools/powershell.d.ts.map +1 -1
  66. package/dist/core/tools/powershell.js +2 -1
  67. package/dist/core/tools/powershell.js.map +1 -1
  68. package/dist/core/tools/renderers/bash.d.ts +1 -1
  69. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  70. package/dist/core/tools/renderers/bash.js.map +1 -1
  71. package/dist/core/tools/renderers/index.d.ts.map +1 -1
  72. package/dist/core/tools/renderers/index.js +7 -5
  73. package/dist/core/tools/renderers/index.js.map +1 -1
  74. package/dist/core/tools/shell-execution.d.ts +2 -2
  75. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  76. package/dist/core/tools/shell-execution.js +0 -21
  77. package/dist/core/tools/shell-execution.js.map +1 -1
  78. package/dist/core/tools/shell-operations.d.ts +12 -0
  79. package/dist/core/tools/shell-operations.d.ts.map +1 -0
  80. package/dist/core/tools/shell-operations.js +38 -0
  81. package/dist/core/tools/shell-operations.js.map +1 -0
  82. package/dist/core/tools/shell-tool.d.ts +8 -64
  83. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  84. package/dist/core/tools/shell-tool.js +27 -125
  85. package/dist/core/tools/shell-tool.js.map +1 -1
  86. package/dist/extensions/index.d.ts +1 -0
  87. package/dist/extensions/index.d.ts.map +1 -1
  88. package/dist/extensions/index.js +5 -0
  89. package/dist/extensions/index.js.map +1 -1
  90. package/dist/extensions/keybindings.d.ts +6 -0
  91. package/dist/extensions/keybindings.d.ts.map +1 -0
  92. package/dist/extensions/keybindings.js +6 -0
  93. package/dist/extensions/keybindings.js.map +1 -0
  94. package/dist/extensions/provider/store.d.ts +2 -0
  95. package/dist/extensions/provider/store.d.ts.map +1 -1
  96. package/dist/extensions/provider/store.js +4 -0
  97. package/dist/extensions/provider/store.js.map +1 -1
  98. package/dist/extensions/provider/ui/editor.d.ts +7 -9
  99. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  100. package/dist/extensions/provider/ui/editor.js +103 -48
  101. package/dist/extensions/provider/ui/editor.js.map +1 -1
  102. package/dist/extensions/provider/ui/provider-list.d.ts.map +1 -1
  103. package/dist/extensions/provider/ui/provider-list.js +13 -19
  104. package/dist/extensions/provider/ui/provider-list.js.map +1 -1
  105. package/dist/extensions/run-summary/format.d.ts +2 -0
  106. package/dist/extensions/run-summary/format.d.ts.map +1 -0
  107. package/dist/extensions/run-summary/format.js +11 -0
  108. package/dist/extensions/run-summary/format.js.map +1 -0
  109. package/dist/extensions/run-summary/index.d.ts +4 -0
  110. package/dist/extensions/run-summary/index.d.ts.map +1 -0
  111. package/dist/extensions/run-summary/index.js +48 -0
  112. package/dist/extensions/run-summary/index.js.map +1 -0
  113. package/dist/extensions/run-summary/record.d.ts +11 -0
  114. package/dist/extensions/run-summary/record.d.ts.map +1 -0
  115. package/dist/extensions/run-summary/record.js +29 -0
  116. package/dist/extensions/run-summary/record.js.map +1 -0
  117. package/dist/extensions/tasks/index.d.ts +5 -0
  118. package/dist/extensions/tasks/index.d.ts.map +1 -0
  119. package/dist/extensions/tasks/index.js +42 -0
  120. package/dist/extensions/tasks/index.js.map +1 -0
  121. package/dist/extensions/tasks/keybindings.d.ts +19 -0
  122. package/dist/extensions/tasks/keybindings.d.ts.map +1 -0
  123. package/dist/extensions/tasks/keybindings.js +30 -0
  124. package/dist/extensions/tasks/keybindings.js.map +1 -0
  125. package/dist/{core/tools/tasks → extensions/tasks/tool}/actions.d.ts +2 -2
  126. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -0
  127. package/dist/{core/tools/tasks → extensions/tasks/tool}/actions.js +4 -4
  128. package/dist/extensions/tasks/tool/actions.js.map +1 -0
  129. package/dist/{core/tools/tasks → extensions/tasks/tool}/constants.d.ts +1 -3
  130. package/dist/extensions/tasks/tool/constants.d.ts.map +1 -0
  131. package/dist/{core/tools/tasks → extensions/tasks/tool}/constants.js +1 -3
  132. package/dist/extensions/tasks/tool/constants.js.map +1 -0
  133. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -0
  134. package/dist/{core/tools/tasks → extensions/tasks/tool}/schema.js +5 -4
  135. package/dist/extensions/tasks/tool/schema.js.map +1 -0
  136. package/dist/{core/tools/tasks → extensions/tasks/tool}/types.d.ts +1 -1
  137. package/dist/extensions/tasks/tool/types.d.ts.map +1 -0
  138. package/dist/extensions/tasks/tool/types.js.map +1 -0
  139. package/dist/extensions/tasks/tool.d.ts +6 -0
  140. package/dist/extensions/tasks/tool.d.ts.map +1 -0
  141. package/dist/{core/tools/tasks.js → extensions/tasks/tool.js} +6 -10
  142. package/dist/extensions/tasks/tool.js.map +1 -0
  143. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/completion-render.d.ts +1 -1
  144. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -0
  145. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/completion-render.js +2 -2
  146. package/dist/extensions/tasks/ui/completion-render.js.map +1 -0
  147. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/index.d.ts +1 -1
  148. package/dist/extensions/tasks/ui/index.d.ts.map +1 -0
  149. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/index.js +4 -4
  150. package/dist/extensions/tasks/ui/index.js.map +1 -0
  151. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/inspector.d.ts +1 -1
  152. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -0
  153. package/dist/extensions/tasks/ui/inspector.js.map +1 -0
  154. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/layout.d.ts +1 -1
  155. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -0
  156. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/layout.js +1 -1
  157. package/dist/extensions/tasks/ui/layout.js.map +1 -0
  158. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/list.d.ts +1 -1
  159. package/dist/extensions/tasks/ui/list.d.ts.map +1 -0
  160. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/list.js +1 -1
  161. package/dist/extensions/tasks/ui/list.js.map +1 -0
  162. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/manager.d.ts +2 -1
  163. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -0
  164. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/manager.js +2 -1
  165. package/dist/extensions/tasks/ui/manager.js.map +1 -0
  166. package/dist/extensions/tasks/ui/model.d.ts.map +1 -0
  167. package/dist/extensions/tasks/ui/model.js.map +1 -0
  168. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/render.d.ts +3 -3
  169. package/dist/extensions/tasks/ui/render.d.ts.map +1 -0
  170. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/render.js +2 -2
  171. package/dist/extensions/tasks/ui/render.js.map +1 -0
  172. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/task-view.d.ts +1 -1
  173. package/dist/extensions/tasks/ui/task-view.d.ts.map +1 -0
  174. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/task-view.js +1 -1
  175. package/dist/extensions/tasks/ui/task-view.js.map +1 -0
  176. package/dist/extensions/tasks/ui/text.d.ts.map +1 -0
  177. package/dist/extensions/tasks/ui/text.js.map +1 -0
  178. package/dist/extensions/tasks/ui/tree.d.ts +7 -0
  179. package/dist/extensions/tasks/ui/tree.d.ts.map +1 -0
  180. package/dist/{modes/interactive/tasks/host-hooks.js → extensions/tasks/ui/tree.js} +1 -18
  181. package/dist/extensions/tasks/ui/tree.js.map +1 -0
  182. package/dist/extensions/tasks/ui/viewport.d.ts.map +1 -0
  183. package/dist/extensions/tasks/ui/viewport.js.map +1 -0
  184. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/views.d.ts +1 -1
  185. package/dist/extensions/tasks/ui/views.d.ts.map +1 -0
  186. package/dist/{modes/interactive/tasks → extensions/tasks/ui}/views.js +1 -1
  187. package/dist/extensions/tasks/ui/views.js.map +1 -0
  188. package/dist/index.d.ts +2 -2
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js.map +1 -1
  191. package/dist/modes/interactive/components/assistant-message.d.ts +3 -2
  192. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  193. package/dist/modes/interactive/components/assistant-message.js +65 -18
  194. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  195. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  196. package/dist/modes/interactive/components/custom-message.js +1 -3
  197. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  198. package/dist/modes/interactive/interactive-mode.d.ts +16 -4
  199. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  200. package/dist/modes/interactive/interactive-mode.js +73 -33
  201. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  202. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  203. package/dist/modes/rpc/rpc-mode.js +3 -0
  204. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  205. package/docs/bundled/README.md +2 -4
  206. package/docs/bundled/extensions/provider.md +9 -7
  207. package/docs/bundled/extensions/run-summary.md +17 -0
  208. package/docs/bundled/tasks.md +3 -3
  209. package/docs/docs.json +4 -0
  210. package/docs/extensions.md +10 -3
  211. package/docs/settings.md +1 -1
  212. package/docs/tui.md +13 -0
  213. package/npm-shrinkwrap.json +2 -2
  214. package/package.json +1 -1
  215. package/schemas/keybindings.schema.json +84 -52
  216. package/dist/core/tools/tasks/actions.d.ts.map +0 -1
  217. package/dist/core/tools/tasks/actions.js.map +0 -1
  218. package/dist/core/tools/tasks/constants.d.ts.map +0 -1
  219. package/dist/core/tools/tasks/constants.js.map +0 -1
  220. package/dist/core/tools/tasks/schema.d.ts.map +0 -1
  221. package/dist/core/tools/tasks/schema.js.map +0 -1
  222. package/dist/core/tools/tasks/types.d.ts.map +0 -1
  223. package/dist/core/tools/tasks/types.js.map +0 -1
  224. package/dist/core/tools/tasks.d.ts +0 -14
  225. package/dist/core/tools/tasks.d.ts.map +0 -1
  226. package/dist/core/tools/tasks.js.map +0 -1
  227. package/dist/modes/interactive/tasks/completion-render.d.ts.map +0 -1
  228. package/dist/modes/interactive/tasks/completion-render.js.map +0 -1
  229. package/dist/modes/interactive/tasks/host-hooks.d.ts +0 -14
  230. package/dist/modes/interactive/tasks/host-hooks.d.ts.map +0 -1
  231. package/dist/modes/interactive/tasks/host-hooks.js.map +0 -1
  232. package/dist/modes/interactive/tasks/index.d.ts.map +0 -1
  233. package/dist/modes/interactive/tasks/index.js.map +0 -1
  234. package/dist/modes/interactive/tasks/inspector.d.ts.map +0 -1
  235. package/dist/modes/interactive/tasks/inspector.js.map +0 -1
  236. package/dist/modes/interactive/tasks/layout.d.ts.map +0 -1
  237. package/dist/modes/interactive/tasks/layout.js.map +0 -1
  238. package/dist/modes/interactive/tasks/list.d.ts.map +0 -1
  239. package/dist/modes/interactive/tasks/list.js.map +0 -1
  240. package/dist/modes/interactive/tasks/manager.d.ts.map +0 -1
  241. package/dist/modes/interactive/tasks/manager.js.map +0 -1
  242. package/dist/modes/interactive/tasks/model.d.ts.map +0 -1
  243. package/dist/modes/interactive/tasks/model.js.map +0 -1
  244. package/dist/modes/interactive/tasks/render.d.ts.map +0 -1
  245. package/dist/modes/interactive/tasks/render.js.map +0 -1
  246. package/dist/modes/interactive/tasks/task-view.d.ts.map +0 -1
  247. package/dist/modes/interactive/tasks/task-view.js.map +0 -1
  248. package/dist/modes/interactive/tasks/text.d.ts.map +0 -1
  249. package/dist/modes/interactive/tasks/text.js.map +0 -1
  250. package/dist/modes/interactive/tasks/viewport.d.ts.map +0 -1
  251. package/dist/modes/interactive/tasks/viewport.js.map +0 -1
  252. package/dist/modes/interactive/tasks/views.d.ts.map +0 -1
  253. package/dist/modes/interactive/tasks/views.js.map +0 -1
  254. /package/dist/{core/tools/tasks → extensions/tasks/tool}/schema.d.ts +0 -0
  255. /package/dist/{core/tools/tasks → extensions/tasks/tool}/types.js +0 -0
  256. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/inspector.js +0 -0
  257. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/model.d.ts +0 -0
  258. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/model.js +0 -0
  259. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/text.d.ts +0 -0
  260. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/text.js +0 -0
  261. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/viewport.d.ts +0 -0
  262. /package/dist/{modes/interactive/tasks → extensions/tasks/ui}/viewport.js +0 -0
@@ -1,28 +1,11 @@
1
- import { constants } from "node:fs";
2
- import { access as fsAccess } from "node:fs/promises";
3
- import { constants as osConstants } from "node:os";
4
- import { spawn } from "child_process";
5
1
  import { Type } from "typebox";
6
- import { waitForChildProcess } from "../../utils/child-process.js";
7
- import { getShellEnv, killProcessTree, trackDetachedChildPid, untrackDetachedChildPid, } from "../../utils/shell.js";
8
2
  import { TaskExecutionError } from "../tasks/types.js";
3
+ import { resolveSpawnContext, resolveTimeoutMs, } from "./bash.js";
9
4
  import { createShellRenderers } from "./renderers/bash.js";
10
5
  import { runShellCommand } from "./shell-execution.js";
6
+ import { createLocalBashOperations } from "./shell-operations.js";
7
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
11
8
  import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "./truncate.js";
12
- const MAX_TIMEOUT_MS = 2_147_483_647;
13
- const MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;
14
- function resolveTimeoutMs(timeout) {
15
- if (timeout === undefined)
16
- return undefined;
17
- if (!Number.isFinite(timeout) || timeout <= 0) {
18
- throw new Error("Invalid timeout: must be a finite number of seconds");
19
- }
20
- const timeoutMs = timeout * 1000;
21
- if (timeoutMs > MAX_TIMEOUT_MS) {
22
- throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);
23
- }
24
- return timeoutMs;
25
- }
26
9
  const bashSchema = Type.Object({
27
10
  command: Type.String({ description: "Shell command to execute" }),
28
11
  timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
@@ -46,111 +29,6 @@ const bashOutputSchema = Type.Union([
46
29
  }),
47
30
  Type.Object({ task_id: Type.String(), status: Type.String() }),
48
31
  ]);
49
- /** Shared process execution used by the built-in shell tools. */
50
- export function createLocalShellOperations(shellName, resolveShellConfig, normalizeCommand = (command) => command) {
51
- return {
52
- exec: async (command, cwd, { onData, signal, timeout, env }) => {
53
- const timeoutMs = resolveTimeoutMs(timeout);
54
- if (signal?.aborted) {
55
- throw new Error("aborted");
56
- }
57
- const shellConfig = resolveShellConfig();
58
- try {
59
- await fsAccess(cwd, constants.F_OK);
60
- }
61
- catch {
62
- throw new Error(`Working directory does not exist: ${cwd}\nCannot execute ${shellName} commands.`);
63
- }
64
- if (signal?.aborted)
65
- throw new Error("aborted");
66
- const commandFromStdin = shellConfig.commandTransport === "stdin";
67
- const normalizedCommand = normalizeCommand(command);
68
- const child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, normalizedCommand], {
69
- cwd,
70
- detached: process.platform !== "win32",
71
- env: env ?? getShellEnv(),
72
- stdio: [commandFromStdin ? "pipe" : "ignore", "pipe", "pipe"],
73
- windowsHide: true,
74
- });
75
- if (commandFromStdin) {
76
- child.stdin?.on("error", () => { });
77
- child.stdin?.end(normalizedCommand);
78
- }
79
- if (child.pid)
80
- trackDetachedChildPid(child.pid);
81
- let timedOut = false;
82
- let timeoutHandle;
83
- const onAbort = () => {
84
- if (child.pid)
85
- killProcessTree(child.pid);
86
- };
87
- try {
88
- // Set timeout if provided.
89
- if (timeoutMs !== undefined) {
90
- timeoutHandle = setTimeout(() => {
91
- timedOut = true;
92
- if (child.pid)
93
- killProcessTree(child.pid);
94
- }, timeoutMs);
95
- }
96
- // Stream stdout and stderr.
97
- child.stdout?.on("data", onData);
98
- child.stderr?.on("data", onData);
99
- // Handle abort signal by killing the entire process tree.
100
- if (signal) {
101
- if (signal.aborted)
102
- onAbort();
103
- else
104
- signal.addEventListener("abort", onAbort, { once: true });
105
- }
106
- // Handle shell spawn errors and wait for the process to terminate without hanging
107
- // on inherited stdio handles held by detached descendants.
108
- const exitCode = await waitForChildProcess(child);
109
- if (signal?.aborted) {
110
- throw new Error("aborted");
111
- }
112
- if (timedOut) {
113
- throw new Error(`timeout:${timeout}`);
114
- }
115
- // A signal-killed shell has no exit code. Use the standard shell convention so
116
- // callers do not mistake the termination for a successful command.
117
- const signalCode = child.signalCode;
118
- return { exitCode: exitCode ?? (signalCode ? 128 + (osConstants.signals[signalCode] ?? 0) : 1) };
119
- }
120
- finally {
121
- if (child.pid)
122
- untrackDetachedChildPid(child.pid);
123
- if (timeoutHandle)
124
- clearTimeout(timeoutHandle);
125
- if (signal)
126
- signal.removeEventListener("abort", onAbort);
127
- }
128
- },
129
- };
130
- }
131
- export function resolveSpawnContext(command, cwd, spawnHook, exposeSessionEnvironment, ctx) {
132
- const env = { ...getShellEnv() };
133
- delete env.PI_SESSION_ID;
134
- delete env.PI_SESSION_FILE;
135
- delete env.PI_PROVIDER;
136
- delete env.PI_MODEL;
137
- delete env.PI_REASONING_LEVEL;
138
- if (exposeSessionEnvironment && ctx) {
139
- const model = ctx.model;
140
- env.PI_SESSION_ID = ctx.sessionManager.getSessionId();
141
- const sessionFile = ctx.sessionManager.getSessionFile();
142
- if (sessionFile)
143
- env.PI_SESSION_FILE = sessionFile;
144
- if (model) {
145
- env.PI_PROVIDER = model.provider;
146
- env.PI_MODEL = model.id;
147
- }
148
- if (ctx.thinkingLevel)
149
- env.PI_REASONING_LEVEL = ctx.thinkingLevel;
150
- }
151
- const baseContext = { command, cwd, env };
152
- return spawnHook ? spawnHook(baseContext) : baseContext;
153
- }
154
32
  /** Translate terminal shell failures to the native foreground tool contract once. */
155
33
  function shellToolResult(completion, managed) {
156
34
  const status = completion.status;
@@ -253,4 +131,28 @@ export function createShellToolDefinition(cwd, config, options) {
253
131
  ...createShellRenderers(config),
254
132
  };
255
133
  }
134
+ const bashToolConfig = {
135
+ name: "bash",
136
+ label: "bash",
137
+ shellName: "bash",
138
+ prompt: "$",
139
+ promptSnippet: bashToolSystemPromptContribution.snippet,
140
+ promptGuidelines: bashToolSystemPromptContribution.guidelines,
141
+ tempFilePrefix: "pi-bash",
142
+ };
143
+ export function createBashToolDefinition(cwd, options) {
144
+ return createShellToolDefinition(cwd, bashToolConfig, {
145
+ ...options,
146
+ operations: options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath }),
147
+ });
148
+ }
149
+ export function createBashTool(cwd, options) {
150
+ const definition = createBashToolDefinition(cwd, options);
151
+ const tool = wrapToolDefinition(definition);
152
+ Object.assign(tool, {
153
+ promptSnippet: definition.promptSnippet,
154
+ promptGuidelines: definition.promptGuidelines,
155
+ });
156
+ return tool;
157
+ }
256
158
  //# sourceMappingURL=shell-tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-tool.js","sourceRoot":"","sources":["../../../src/core/tools/shell-tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport { constants as osConstants } from \"node:os\";\nimport { spawn } from \"child_process\";\nimport { type Static, Type } from \"typebox\";\nimport { waitForChildProcess } from \"../../utils/child-process.ts\";\nimport {\n\tgetShellEnv,\n\tkillProcessTree,\n\ttype ShellConfig,\n\ttrackDetachedChildPid,\n\tuntrackDetachedChildPid,\n} from \"../../utils/shell.ts\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { type TaskCompletion, TaskExecutionError } from \"../tasks/types.ts\";\nimport { createShellRenderers } from \"./renderers/bash.ts\";\nimport { type ManagedShellExecution, runShellCommand } from \"./shell-execution.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult } from \"./truncate.ts\";\n\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nfunction resolveTimeoutMs(timeout: number | undefined): number | undefined {\n\tif (timeout === undefined) return undefined;\n\tif (!Number.isFinite(timeout) || timeout <= 0) {\n\t\tthrow new Error(\"Invalid timeout: must be a finite number of seconds\");\n\t}\n\n\tconst timeoutMs = timeout * 1000;\n\tif (timeoutMs > MAX_TIMEOUT_MS) {\n\t\tthrow new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n\t}\n\treturn timeoutMs;\n}\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"true returns a managed task ID immediately and runs the command in the background, and you are notified when it completes — do not poll for its result; omit or false to block until exit\",\n\t\t}),\n\t),\n});\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands, foreground or background\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nconst bashOutputSchema = Type.Union([\n\tType.Object({\n\t\toutput: Type.String({\n\t\t\tdescription: \"Combined stdout and stderr, up to 1 MiB, keeping head and tail when truncated.\",\n\t\t}),\n\t\ttruncated: Type.Boolean(),\n\t\tfull_output_path: Type.Optional(Type.String()),\n\t\texit_code: Type.Number(),\n\t\twall_time_seconds: Type.Number(),\n\t}),\n\tType.Object({ task_id: Type.String(), status: Type.String() }),\n]);\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Settled handoff snapshot, not a command completion or exit code. */\n\tbackground?: { kind: \"background\"; taskId: string };\n}\n\n/**\n * Pluggable operations for the bash tool.\n * Override these to delegate command execution to remote systems (for example SSH).\n */\nexport interface BashOperations {\n\t/**\n\t * Execute a command and stream output.\n\t * @param command The command to execute\n\t * @param cwd Working directory\n\t * @param options Execution options\n\t * @returns Promise resolving to the exit code. Report signal terminations as 128 + signal number;\n\t * a null exit code is treated as a failed command.\n\t *\n\t * Error contract: reject with `new Error(\"aborted\")` when aborted via `signal`,\n\t * and `new Error(\"timeout:<seconds>\")` on timeout expiry. The shared shell\n\t * execution pipeline classifies outcomes from these exact markers.\n\t */\n\texec: (\n\t\tcommand: string,\n\t\tcwd: string,\n\t\toptions: {\n\t\t\tonData: (data: Buffer) => void;\n\t\t\tsignal?: AbortSignal;\n\t\t\ttimeout?: number;\n\t\t\tenv?: NodeJS.ProcessEnv;\n\t\t},\n\t) => Promise<{ exitCode: number | null }>;\n}\n\n/** Shared process execution used by the built-in shell tools. */\nexport function createLocalShellOperations(\n\tshellName: string,\n\tresolveShellConfig: () => ShellConfig,\n\tnormalizeCommand: (command: string) => string = (command) => command,\n): BashOperations {\n\treturn {\n\t\texec: async (command, cwd, { onData, signal, timeout, env }) => {\n\t\t\tconst timeoutMs = resolveTimeoutMs(timeout);\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t}\n\t\t\tconst shellConfig = resolveShellConfig();\n\t\t\ttry {\n\t\t\t\tawait fsAccess(cwd, constants.F_OK);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Working directory does not exist: ${cwd}\\nCannot execute ${shellName} commands.`);\n\t\t\t}\n\n\t\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\t\t\tconst commandFromStdin = shellConfig.commandTransport === \"stdin\";\n\t\t\tconst normalizedCommand = normalizeCommand(command);\n\t\t\tconst child = spawn(\n\t\t\t\tshellConfig.shell,\n\t\t\t\tcommandFromStdin ? shellConfig.args : [...shellConfig.args, normalizedCommand],\n\t\t\t\t{\n\t\t\t\t\tcwd,\n\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\tenv: env ?? getShellEnv(),\n\t\t\t\t\tstdio: [commandFromStdin ? \"pipe\" : \"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\twindowsHide: true,\n\t\t\t\t},\n\t\t\t);\n\t\t\tif (commandFromStdin) {\n\t\t\t\tchild.stdin?.on(\"error\", () => {});\n\t\t\t\tchild.stdin?.end(normalizedCommand);\n\t\t\t}\n\t\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\t\tlet timedOut = false;\n\t\t\tlet timeoutHandle: NodeJS.Timeout | undefined;\n\t\t\tconst onAbort = () => {\n\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t};\n\n\t\t\ttry {\n\t\t\t\t// Set timeout if provided.\n\t\t\t\tif (timeoutMs !== undefined) {\n\t\t\t\t\ttimeoutHandle = setTimeout(() => {\n\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\t\t\t}, timeoutMs);\n\t\t\t\t}\n\t\t\t\t// Stream stdout and stderr.\n\t\t\t\tchild.stdout?.on(\"data\", onData);\n\t\t\t\tchild.stderr?.on(\"data\", onData);\n\t\t\t\t// Handle abort signal by killing the entire process tree.\n\t\t\t\tif (signal) {\n\t\t\t\t\tif (signal.aborted) onAbort();\n\t\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\t\t\t\t// Handle shell spawn errors and wait for the process to terminate without hanging\n\t\t\t\t// on inherited stdio handles held by detached descendants.\n\t\t\t\tconst exitCode = await waitForChildProcess(child);\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"aborted\");\n\t\t\t\t}\n\t\t\t\tif (timedOut) {\n\t\t\t\t\tthrow new Error(`timeout:${timeout}`);\n\t\t\t\t}\n\t\t\t\t// A signal-killed shell has no exit code. Use the standard shell convention so\n\t\t\t\t// callers do not mistake the termination for a successful command.\n\t\t\t\tconst signalCode = child.signalCode;\n\t\t\t\treturn { exitCode: exitCode ?? (signalCode ? 128 + (osConstants.signals[signalCode] ?? 0) : 1) };\n\t\t\t} finally {\n\t\t\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\t\t\tif (timeoutHandle) clearTimeout(timeoutHandle);\n\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t}\n\t\t},\n\t};\n}\n\n/**\n * Create bash operations using pi's built-in local shell execution backend.\n *\n * This is useful for extensions that intercept user_bash and still want pi's\n * standard local shell behavior while wrapping or rewriting commands.\n */\n\nexport interface BashSpawnContext {\n\tcommand: string;\n\tcwd: string;\n\tenv: NodeJS.ProcessEnv;\n}\n\nexport type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;\n\nexport function resolveSpawnContext(\n\tcommand: string,\n\tcwd: string,\n\tspawnHook: BashSpawnHook | undefined,\n\texposeSessionEnvironment: boolean,\n\tctx: ExtensionContext | undefined,\n): BashSpawnContext {\n\tconst env = { ...getShellEnv() };\n\tdelete env.PI_SESSION_ID;\n\tdelete env.PI_SESSION_FILE;\n\tdelete env.PI_PROVIDER;\n\tdelete env.PI_MODEL;\n\tdelete env.PI_REASONING_LEVEL;\n\tif (exposeSessionEnvironment && ctx) {\n\t\tconst model = ctx.model;\n\t\tenv.PI_SESSION_ID = ctx.sessionManager.getSessionId();\n\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\tif (sessionFile) env.PI_SESSION_FILE = sessionFile;\n\t\tif (model) {\n\t\t\tenv.PI_PROVIDER = model.provider;\n\t\t\tenv.PI_MODEL = model.id;\n\t\t}\n\t\tif (ctx.thinkingLevel) env.PI_REASONING_LEVEL = ctx.thinkingLevel;\n\t}\n\tconst baseContext: BashSpawnContext = { command, cwd, env };\n\treturn spawnHook ? spawnHook(baseContext) : baseContext;\n}\n\nexport interface BashToolOptions {\n\t/** Custom operations for command execution. Default: local shell */\n\toperations?: BashOperations;\n\t/** Command prefix prepended to every command (for example shell setup commands) */\n\tcommandPrefix?: string;\n\t/** Optional explicit shell path from settings */\n\tshellPath?: string;\n\t/** Expose current Pi session metadata as PI_* environment variables. Default: true */\n\texposeSessionEnvironment?: boolean;\n\t/** Hook to adjust command, cwd, or env before execution */\n\tspawnHook?: BashSpawnHook;\n}\n\nexport type BashRenderState = {\n\tdispose?: () => void;\n};\n\nexport interface ShellToolConfig {\n\tname: string;\n\tlabel: string;\n\tshellName: string;\n\tprompt: string;\n\tpromptSnippet: string;\n\tpromptGuidelines?: readonly string[];\n\ttempFilePrefix: string;\n}\n\n/** Translate terminal shell failures to the native foreground tool contract once. */\nfunction shellToolResult(completion: TaskCompletion<BashToolDetails | undefined>, managed: boolean) {\n\tconst status = completion.status;\n\tif (completion.result.structuredContent) return completion.result;\n\tif (status === \"failed\" || status === \"timeout\" || status === \"cancelled\") {\n\t\tconst text = completion.result.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tconst message = completion.error ? text || completion.error : `${text ? `${text}\\n\\n` : \"\"}Command ${status}`;\n\t\tthrow managed ? new TaskExecutionError(message, status) : new Error(message);\n\t}\n\treturn completion.result;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions: BashToolOptions & { operations: BashOperations },\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options.operations;\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use tasks read to inspect output, tasks wait with an ID for one task or without one for any running task, and tasks kill to stop it. Steering interrupts only a wait, never execution. Background output is limited to 20 MiB; an expired tasks wait window never stops the command.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\toutputSchema: bashOutputSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{ command, timeout, background }: BashToolInput,\n\t\t\tparentSignal?: AbortSignal,\n\t\t\toriginalUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst host = ctx?.tasks;\n\t\t\tif (host?.closed) throw new Error(\"Task service is closed\");\n\t\t\tconst run = async (managed?: ManagedShellExecution): Promise<TaskCompletion<BashToolDetails | undefined>> => {\n\t\t\t\tconst signal = managed?.control.signal ?? parentSignal;\n\t\t\t\ttry {\n\t\t\t\t\tif (managed) {\n\t\t\t\t\t\tif (signal?.aborted) throw new Error(\"Command aborted\");\n\t\t\t\t\t\tresolveTimeoutMs(timeout);\n\t\t\t\t\t}\n\t\t\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\t\t\tconst spawnContext = resolveSpawnContext(\n\t\t\t\t\t\tresolvedCommand,\n\t\t\t\t\t\tctx?.cwd || cwd,\n\t\t\t\t\t\tspawnHook,\n\t\t\t\t\t\texposeSessionEnvironment,\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn await runShellCommand({\n\t\t\t\t\t\toperations: ops,\n\t\t\t\t\t\tcontext: spawnContext,\n\t\t\t\t\t\ttempFilePrefix: config.tempFilePrefix,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\t\t\tmanaged,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Setup and cleanup exceptions carry an explicit terminal status.\n\t\t\t\t\tif (!managed) throw error;\n\t\t\t\t\tthrow new TaskExecutionError(\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmanaged.control.signal.aborted ? \"cancelled\" : \"failed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (!host) {\n\t\t\t\tif (background)\n\t\t\t\t\tthrow new Error(\"Background execution is not available in this host. No command was started.\");\n\t\t\t\treturn shellToolResult(await run(), false);\n\t\t\t}\n\t\t\tconst outcome = await host.execute<BashToolDetails | undefined>({\n\t\t\t\tkind: config.name,\n\t\t\t\ttitle: command,\n\t\t\t\ttoolCallId,\n\t\t\t\tcommand,\n\t\t\t\tcwd: ctx?.cwd || cwd,\n\t\t\t\tbackground,\n\t\t\t\tsignal: parentSignal,\n\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\trun: (control) => run({ control }),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return shellToolResult(outcome, true);\n\t\t\tconst tail = `Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives automatically as a notification — do not poll or immediately wait on it; continue with other work or hand back to the user. Use tasks read to inspect output, tasks wait only when your next step is blocked on a result (one ID or any running task; prefer foreground next time in that case), or tasks kill to stop it.`;\n\t\t\t// Shell execution can become background work in two ways, and the model has to know which\n\t\t\t// one it got: a submitted background command starts from an empty log, while a detached\n\t\t\t// one already holds output and keeps its original timeout.\n\t\t\tconst handoff =\n\t\t\t\tbackground === true\n\t\t\t\t\t? `Command handed to background. ${tail}`\n\t\t\t\t\t: `Command moved to the background while it was running, by the user. The execution continues unchanged — no restart, and a supplied timeout is still measured from command startup. Output produced so far is already in the log, so tasks read now returns partial output, not a fresh start. ${tail}`;\n\t\t\treturn {\n\t\t\t\tstructuredContent: { task_id: outcome.task.id, status: outcome.task.status },\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `${handoff}${outcome.task.outputPath ? `\\nFull output: ${outcome.task.outputPath}` : \"\"}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: {\n\t\t\t\t\tbackground: { kind: \"background\", taskId: outcome.task.id },\n\t\t\t\t\tfullOutputPath: outcome.task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t...createShellRenderers(config),\n\t};\n}\n"]}
1
+ {"version":3,"file":"shell-tool.js","sourceRoot":"","sources":["../../../src/core/tools/shell-tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { ExtensionContext, ToolDefinition } from \"../extensions/types.ts\";\nimport { type TaskCompletion, TaskExecutionError } from \"../tasks/types.ts\";\nimport {\n\ttype BashOperations,\n\ttype BashToolOptions,\n\tresolveSpawnContext,\n\tresolveTimeoutMs,\n\ttype ShellToolConfig,\n} from \"./bash.ts\";\nimport { createShellRenderers } from \"./renderers/bash.ts\";\nimport { type ManagedShellExecution, runShellCommand } from \"./shell-execution.ts\";\nimport { createLocalBashOperations } from \"./shell-operations.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult } from \"./truncate.ts\";\n\nconst bashSchema = Type.Object({\n\tcommand: Type.String({ description: \"Shell command to execute\" }),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n\tbackground: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"true returns a managed task ID immediately and runs the command in the background, and you are notified when it completes — do not poll for its result; omit or false to block until exit\",\n\t\t}),\n\t),\n});\n\nexport const bashToolSystemPromptContribution = {\n\tsnippet: \"Execute bash commands, foreground or background\",\n\tguidelines: [\"You can inspect PI_* environment variables for current model and session details.\"],\n} as const;\n\nexport type BashToolInput = Static<typeof bashSchema>;\n\nconst bashOutputSchema = Type.Union([\n\tType.Object({\n\t\toutput: Type.String({\n\t\t\tdescription: \"Combined stdout and stderr, up to 1 MiB, keeping head and tail when truncated.\",\n\t\t}),\n\t\ttruncated: Type.Boolean(),\n\t\tfull_output_path: Type.Optional(Type.String()),\n\t\texit_code: Type.Number(),\n\t\twall_time_seconds: Type.Number(),\n\t}),\n\tType.Object({ task_id: Type.String(), status: Type.String() }),\n]);\n\nexport interface BashToolDetails {\n\ttruncation?: TruncationResult;\n\tfullOutputPath?: string;\n\t/** Settled handoff snapshot, not a command completion or exit code. */\n\tbackground?: { kind: \"background\"; taskId: string };\n}\n\nexport type BashRenderState = {\n\tdispose?: () => void;\n};\n\n/** Translate terminal shell failures to the native foreground tool contract once. */\nfunction shellToolResult(completion: TaskCompletion<BashToolDetails | undefined>, managed: boolean) {\n\tconst status = completion.status;\n\tif (completion.result.structuredContent) return completion.result;\n\tif (status === \"failed\" || status === \"timeout\" || status === \"cancelled\") {\n\t\tconst text = completion.result.content\n\t\t\t.filter((part) => part.type === \"text\")\n\t\t\t.map((part) => part.text)\n\t\t\t.join(\"\\n\");\n\t\tconst message = completion.error ? text || completion.error : `${text ? `${text}\\n\\n` : \"\"}Command ${status}`;\n\t\tthrow managed ? new TaskExecutionError(message, status) : new Error(message);\n\t}\n\treturn completion.result;\n}\n\nexport function createShellToolDefinition(\n\tcwd: string,\n\tconfig: ShellToolConfig,\n\toptions: BashToolOptions & { operations: BashOperations },\n): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState> {\n\tconst ops = options.operations;\n\tconst commandPrefix = options?.commandPrefix;\n\tconst exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;\n\tconst spawnHook = options?.spawnHook;\n\treturn {\n\t\tname: config.name,\n\t\tlabel: config.label,\n\t\tdescription: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr, truncated to the last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first); the full output is saved to a temp file. Optionally provide a timeout in seconds (no default). Choose the mode per call: foreground (default) blocks until the command exits — use it when your next step needs the output; background: true returns immediately with a task ID — use it for long-running work (builds, servers, watchers, big test suites) or when you have independent work to continue. A handoff is not completion: the result arrives later as an automatic completion notification; meanwhile use tasks read to inspect output, tasks wait with an ID for one task or without one for any running task, and tasks kill to stop it. Steering interrupts only a wait, never execution. Background output is limited to 20 MiB; an expired tasks wait window never stops the command.`,\n\t\tpromptSnippet: config.promptSnippet,\n\t\tpromptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,\n\t\tparameters: bashSchema,\n\t\toutputSchema: bashOutputSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{ command, timeout, background }: BashToolInput,\n\t\t\tparentSignal?: AbortSignal,\n\t\t\toriginalUpdate?,\n\t\t\tctx?: ExtensionContext,\n\t\t) {\n\t\t\tconst host = ctx?.tasks;\n\t\t\tif (host?.closed) throw new Error(\"Task service is closed\");\n\t\t\tconst run = async (managed?: ManagedShellExecution): Promise<TaskCompletion<BashToolDetails | undefined>> => {\n\t\t\t\tconst signal = managed?.control.signal ?? parentSignal;\n\t\t\t\ttry {\n\t\t\t\t\tif (managed) {\n\t\t\t\t\t\tif (signal?.aborted) throw new Error(\"Command aborted\");\n\t\t\t\t\t\tresolveTimeoutMs(timeout);\n\t\t\t\t\t}\n\t\t\t\t\tconst resolvedCommand = commandPrefix ? `${commandPrefix}\\n${command}` : command;\n\t\t\t\t\tconst spawnContext = resolveSpawnContext(\n\t\t\t\t\t\tresolvedCommand,\n\t\t\t\t\t\tctx?.cwd || cwd,\n\t\t\t\t\t\tspawnHook,\n\t\t\t\t\t\texposeSessionEnvironment,\n\t\t\t\t\t\tctx,\n\t\t\t\t\t);\n\t\t\t\t\treturn await runShellCommand({\n\t\t\t\t\t\toperations: ops,\n\t\t\t\t\t\tcontext: spawnContext,\n\t\t\t\t\t\ttempFilePrefix: config.tempFilePrefix,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\t\t\tmanaged,\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Setup and cleanup exceptions carry an explicit terminal status.\n\t\t\t\t\tif (!managed) throw error;\n\t\t\t\t\tthrow new TaskExecutionError(\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\tmanaged.control.signal.aborted ? \"cancelled\" : \"failed\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (!host) {\n\t\t\t\tif (background)\n\t\t\t\t\tthrow new Error(\"Background execution is not available in this host. No command was started.\");\n\t\t\t\treturn shellToolResult(await run(), false);\n\t\t\t}\n\t\t\tconst outcome = await host.execute<BashToolDetails | undefined>({\n\t\t\t\tkind: config.name,\n\t\t\t\ttitle: command,\n\t\t\t\ttoolCallId,\n\t\t\t\tcommand,\n\t\t\t\tcwd: ctx?.cwd || cwd,\n\t\t\t\tbackground,\n\t\t\t\tsignal: parentSignal,\n\t\t\t\tonUpdate: originalUpdate,\n\t\t\t\trun: (control) => run({ control }),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return shellToolResult(outcome, true);\n\t\t\tconst tail = `Task ID: ${outcome.task.id}. Status: ${outcome.task.status}. Completion arrives automatically as a notification — do not poll or immediately wait on it; continue with other work or hand back to the user. Use tasks read to inspect output, tasks wait only when your next step is blocked on a result (one ID or any running task; prefer foreground next time in that case), or tasks kill to stop it.`;\n\t\t\t// Shell execution can become background work in two ways, and the model has to know which\n\t\t\t// one it got: a submitted background command starts from an empty log, while a detached\n\t\t\t// one already holds output and keeps its original timeout.\n\t\t\tconst handoff =\n\t\t\t\tbackground === true\n\t\t\t\t\t? `Command handed to background. ${tail}`\n\t\t\t\t\t: `Command moved to the background while it was running, by the user. The execution continues unchanged — no restart, and a supplied timeout is still measured from command startup. Output produced so far is already in the log, so tasks read now returns partial output, not a fresh start. ${tail}`;\n\t\t\treturn {\n\t\t\t\tstructuredContent: { task_id: outcome.task.id, status: outcome.task.status },\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `${handoff}${outcome.task.outputPath ? `\\nFull output: ${outcome.task.outputPath}` : \"\"}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tdetails: {\n\t\t\t\t\tbackground: { kind: \"background\", taskId: outcome.task.id },\n\t\t\t\t\tfullOutputPath: outcome.task.outputPath,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t...createShellRenderers(config),\n\t};\n}\n\nconst bashToolConfig: ShellToolConfig = {\n\tname: \"bash\",\n\tlabel: \"bash\",\n\tshellName: \"bash\",\n\tprompt: \"$\",\n\tpromptSnippet: bashToolSystemPromptContribution.snippet,\n\tpromptGuidelines: bashToolSystemPromptContribution.guidelines,\n\ttempFilePrefix: \"pi-bash\",\n};\n\nexport function createBashToolDefinition(\n\tcwd: string,\n\toptions?: BashToolOptions,\n): ReturnType<typeof createShellToolDefinition> {\n\treturn createShellToolDefinition(cwd, bashToolConfig, {\n\t\t...options,\n\t\toperations: options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath }),\n\t});\n}\n\nexport function createBashTool(cwd: string, options?: BashToolOptions) {\n\tconst definition = createBashToolDefinition(cwd, options);\n\tconst tool = wrapToolDefinition(definition);\n\tObject.assign(tool, {\n\t\tpromptSnippet: definition.promptSnippet,\n\t\tpromptGuidelines: definition.promptGuidelines,\n\t});\n\treturn tool;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import "./keybindings.ts";
1
2
  import type { InlineExtension } from "../core/extensions/types.ts";
2
3
  export declare const builtInExtensions: InlineExtension[];
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAcnE,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAa9C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAgBnE,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAe9C,CAAC"}
@@ -1,3 +1,4 @@
1
+ import "./keybindings.js";
1
2
  import btwExtension from "./btw/index.js";
2
3
  import cachedCompactionExtension from "./cached-compaction/index.js";
3
4
  import codemodeExtension from "./codemode/index.js";
@@ -6,8 +7,10 @@ import llamaExtension from "./llama/index.js";
6
7
  import mcpExtension from "./mcp/index.js";
7
8
  import providerExtension from "./provider/index.js";
8
9
  import questionExtension from "./question/index.js";
10
+ import runSummaryExtension from "./run-summary/index.js";
9
11
  import searchExtension from "./search/index.js";
10
12
  import statuslineExtension from "./statusline/index.js";
13
+ import tasksExtension from "./tasks/index.js";
11
14
  import toolPresentationExtension from "./tool-presentation/index.js";
12
15
  import toolSearchExtension from "./tool-search/index.js";
13
16
  export const builtInExtensions = [
@@ -20,8 +23,10 @@ export const builtInExtensions = [
20
23
  { name: "deepwiki", factory: deepwikiExtension, builtin: true },
21
24
  { name: "provider", factory: providerExtension, builtin: true },
22
25
  { name: "question", factory: questionExtension, builtin: true },
26
+ { name: "run-summary", factory: runSummaryExtension, replaceable: true, builtin: true },
23
27
  { name: "statusline", factory: statuslineExtension, builtin: true },
24
28
  { name: "tool-presentation", factory: toolPresentationExtension, builtin: true },
29
+ { name: "tasks", factory: tasksExtension, replaceable: true, builtin: true },
25
30
  { name: "search", factory: searchExtension, builtin: true },
26
31
  ];
27
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,yBAAyB,MAAM,8BAA8B,CAAC;AACrE,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,yBAAyB,MAAM,8BAA8B,CAAC;AACrE,OAAO,mBAAmB,MAAM,wBAAwB,CAAC;AAEzD,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IACnD,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAClF,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACxE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACvF,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACnG,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;IAC7D,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE;IACrD,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;IAC/D,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;IAC/D,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;IAC/D,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE;IACnE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,IAAI,EAAE;IAChF,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE;CAC3D,CAAC","sourcesContent":["import type { InlineExtension } from \"../core/extensions/types.ts\";\nimport btwExtension from \"./btw/index.ts\";\nimport cachedCompactionExtension from \"./cached-compaction/index.ts\";\nimport codemodeExtension from \"./codemode/index.ts\";\nimport deepwikiExtension from \"./deepwiki/index.ts\";\nimport llamaExtension from \"./llama/index.ts\";\nimport mcpExtension from \"./mcp/index.ts\";\nimport providerExtension from \"./provider/index.ts\";\nimport questionExtension from \"./question/index.ts\";\nimport searchExtension from \"./search/index.ts\";\nimport statuslineExtension from \"./statusline/index.ts\";\nimport toolPresentationExtension from \"./tool-presentation/index.ts\";\nimport toolSearchExtension from \"./tool-search/index.ts\";\n\nexport const builtInExtensions: InlineExtension[] = [\n\t{ name: \"codemode\", factory: codemodeExtension, replaceable: true, builtin: true },\n\t{ name: \"mcp\", factory: mcpExtension, replaceable: true, builtin: true },\n\t{ name: \"tool-search\", factory: toolSearchExtension, replaceable: true, builtin: true },\n\t{ name: \"cached-compaction\", factory: cachedCompactionExtension, replaceable: true, builtin: true },\n\t{ name: \"llama.cpp\", factory: llamaExtension, builtin: true },\n\t{ name: \"btw\", factory: btwExtension, builtin: true },\n\t{ name: \"deepwiki\", factory: deepwikiExtension, builtin: true },\n\t{ name: \"provider\", factory: providerExtension, builtin: true },\n\t{ name: \"question\", factory: questionExtension, builtin: true },\n\t{ name: \"statusline\", factory: statuslineExtension, builtin: true },\n\t{ name: \"tool-presentation\", factory: toolPresentationExtension, builtin: true },\n\t{ name: \"search\", factory: searchExtension, builtin: true },\n];\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,yBAAyB,MAAM,8BAA8B,CAAC;AACrE,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,mBAAmB,MAAM,wBAAwB,CAAC;AACzD,OAAO,eAAe,MAAM,mBAAmB,CAAC;AAChD,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,yBAAyB,MAAM,8BAA8B,CAAC;AACrE,OAAO,mBAAmB,MAAM,wBAAwB,CAAC;AAEzD,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IACnD,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAClF,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACxE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACvF,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,yBAAyB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACnG,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;IAC7D,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE;IACrD,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;IAC/D,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;IAC/D,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE;IAC/D,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IACvF,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE;IACnE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,IAAI,EAAE;IAChF,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAC5E,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE;CAC3D,CAAC","sourcesContent":["import \"./keybindings.ts\";\nimport type { InlineExtension } from \"../core/extensions/types.ts\";\nimport btwExtension from \"./btw/index.ts\";\nimport cachedCompactionExtension from \"./cached-compaction/index.ts\";\nimport codemodeExtension from \"./codemode/index.ts\";\nimport deepwikiExtension from \"./deepwiki/index.ts\";\nimport llamaExtension from \"./llama/index.ts\";\nimport mcpExtension from \"./mcp/index.ts\";\nimport providerExtension from \"./provider/index.ts\";\nimport questionExtension from \"./question/index.ts\";\nimport runSummaryExtension from \"./run-summary/index.ts\";\nimport searchExtension from \"./search/index.ts\";\nimport statuslineExtension from \"./statusline/index.ts\";\nimport tasksExtension from \"./tasks/index.ts\";\nimport toolPresentationExtension from \"./tool-presentation/index.ts\";\nimport toolSearchExtension from \"./tool-search/index.ts\";\n\nexport const builtInExtensions: InlineExtension[] = [\n\t{ name: \"codemode\", factory: codemodeExtension, replaceable: true, builtin: true },\n\t{ name: \"mcp\", factory: mcpExtension, replaceable: true, builtin: true },\n\t{ name: \"tool-search\", factory: toolSearchExtension, replaceable: true, builtin: true },\n\t{ name: \"cached-compaction\", factory: cachedCompactionExtension, replaceable: true, builtin: true },\n\t{ name: \"llama.cpp\", factory: llamaExtension, builtin: true },\n\t{ name: \"btw\", factory: btwExtension, builtin: true },\n\t{ name: \"deepwiki\", factory: deepwikiExtension, builtin: true },\n\t{ name: \"provider\", factory: providerExtension, builtin: true },\n\t{ name: \"question\", factory: questionExtension, builtin: true },\n\t{ name: \"run-summary\", factory: runSummaryExtension, replaceable: true, builtin: true },\n\t{ name: \"statusline\", factory: statuslineExtension, builtin: true },\n\t{ name: \"tool-presentation\", factory: toolPresentationExtension, builtin: true },\n\t{ name: \"tasks\", factory: tasksExtension, replaceable: true, builtin: true },\n\t{ name: \"search\", factory: searchExtension, builtin: true },\n];\n"]}
@@ -0,0 +1,6 @@
1
+ /** Load every bundled extension-owned keybinding before building managers or generated schemas. */
2
+ import "./btw/keybindings.ts";
3
+ import "./provider/keybindings.ts";
4
+ import "./question/keybindings.ts";
5
+ import "./tasks/keybindings.ts";
6
+ //# sourceMappingURL=keybindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../../src/extensions/keybindings.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,sBAAsB,CAAC;AAC9B,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,wBAAwB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** Load every bundled extension-owned keybinding before building managers or generated schemas. */
2
+ import "./btw/keybindings.js";
3
+ import "./provider/keybindings.js";
4
+ import "./question/keybindings.js";
5
+ import "./tasks/keybindings.js";
6
+ //# sourceMappingURL=keybindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../src/extensions/keybindings.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,sBAAsB,CAAC;AAC9B,OAAO,2BAA2B,CAAC;AACnC,OAAO,2BAA2B,CAAC;AACnC,OAAO,wBAAwB,CAAC","sourcesContent":["/** Load every bundled extension-owned keybinding before building managers or generated schemas. */\nimport \"./btw/keybindings.ts\";\nimport \"./provider/keybindings.ts\";\nimport \"./question/keybindings.ts\";\nimport \"./tasks/keybindings.ts\";\n"]}
@@ -102,6 +102,8 @@ export declare class ModelsJsonStore {
102
102
  getModels(providerId: string): ModelsJsonModel[];
103
103
  getModel(providerId: string, modelId: string): ModelsJsonModel | undefined;
104
104
  get pendingCount(): number;
105
+ /** The latest save failed; pending edits remain available for retry. */
106
+ get saveFailed(): boolean;
105
107
  getPendingError(providerId?: string): string | undefined;
106
108
  retrySave(): void;
107
109
  /** Used only after flush, when the user explicitly discards unsaved edits. */
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/extensions/provider/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,EAAe,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AASxG,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,UAAU,MAAM;IACf,GAAG,EAAE,MAAM,CAAC;CACZ;AACD,MAAM,WAAW,UAAW,SAAQ,MAAM;IACzC,IAAI,EAAE,KAAK,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;CACxB;AACD,MAAM,WAAW,UAAW,SAAQ,MAAM;IACzC,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,eAAe,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;CACxB;AACD,MAAM,WAAW,aAAc,SAAQ,MAAM;IAC5C,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,WAAW,aAAc,SAAQ,MAAM;IAC5C,IAAI,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AACD,MAAM,WAAW,gBAAiB,SAAQ,MAAM;IAC/C,IAAI,EAAE,gBAAgB,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,MAAM,EAAE,GAAG,UAAU,GAAG,UAAU,GAAG,aAAa,GAAG,aAAa,GAAG,gBAAgB,CAAC;AAE5F,MAAM,MAAM,UAAU,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,MAAM,MAAM,SAAS,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAY5F,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAc1D;AAqBD,qBAAa,eAAe;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,cAAc,CAAiC;IACvD,sEAAsE;IACtE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAEzD,OAAO;WAMM,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAyBnD,MAAM,IAAI,kBAAkB;IAI5B,cAAc,IAAI,MAAM,EAAE;IAI1B,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI/D,mGAAmG;IACnG,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAM5C,wDAAwD;IACxD,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAI5C,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,EAAE;IAKhD,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI1E,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAQxD,SAAS,IAAI,IAAI;IAIjB,8EAA8E;IAC9E,cAAc,IAAI,IAAI;IAUtB,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,OAAO;IAIf,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAWnF,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAYjG,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI;IAU1D,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAShD,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA6BhG,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAQxC,wFAAwF;IACxF,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,GAAG,IAAI;IAU/B,gGAAgG;IAChG,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAW9C,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,YAAY;IAWpB,iFAAiF;IAC3E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAQd,IAAI;YAoCJ,UAAU;CA6DxB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/extensions/provider/store.ts"],"names":[],"mappings":"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"}
@@ -136,6 +136,10 @@ export class ModelsJsonStore {
136
136
  get pendingCount() {
137
137
  return this.ops.length;
138
138
  }
139
+ /** The latest save failed; pending edits remain available for retry. */
140
+ get saveFailed() {
141
+ return this.lastSaveResult.kind === "error" || this.lastSaveResult.kind === "invalid";
142
+ }
139
143
  getPendingError(providerId) {
140
144
  const pending = this.ops.filter((op) => providerId === undefined || op.providerId === providerId);
141
145
  if (pending.length === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/extensions/provider/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Op-based models.json editing store.\n *\n * Three states are tracked: `baseline` (last known disk content), pending\n * field-level ops, and `view` (baseline + ops, what the UI renders). Every\n * confirmed edit queues an op and schedules a save. A save re-reads the file\n * under a cross-process lock and applies the pending ops onto that freshest\n * content — unrelated external edits are preserved, a same-field race\n * resolves last-writer-wins, and ops targeting externally removed models\n * simply miss. The candidate is validated via ModelConfig on a temp file,\n * backed up once per session, and atomically renamed into place. Failed\n * saves keep the ops pending; closing offers retry or explicit discard.\n * Whole-snapshot blind overwrites are never performed.\n *\n * Comments and custom formatting are normalized to two-space JSON on save;\n * unknown fields anywhere in the document are preserved verbatim.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, realpath, rename, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { ModelConfig, type ModelsJsonModel, type ModelsJsonProvider } from \"../../core/model-config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\nimport { stripJsonComments } from \"../../utils/json.ts\";\nimport { normalizePath } from \"../../utils/paths.ts\";\nimport { stripBom } from \"../../utils/text.ts\";\nimport { hasProviderSettings } from \"./configuration.ts\";\nimport { formatError } from \"./constants.ts\";\nimport { DELETE, setPath } from \"./json-fields.ts\";\n\nexport { DELETE, type DeleteMarker } from \"./json-fields.ts\";\n\nexport interface ModelsJsonDocument {\n\tproviders: Record<string, ModelsJsonProvider>;\n\t[key: string]: unknown;\n}\n\ninterface OpBase {\n\tseq: number;\n}\nexport interface SetFieldOp extends OpBase {\n\tkind: \"set\";\n\tproviderId: string;\n\t/** Undefined for provider-level fields. */\n\tmodelId?: string;\n\t/** Path within the provider/model object, e.g. [\"compat\", \"allowEmptySignature\"]. */\n\tpath: readonly string[];\n\tvalue: unknown;\n\tcreateProvider: boolean;\n}\nexport interface AddModelOp extends OpBase {\n\tkind: \"addModel\";\n\tproviderId: string;\n\tmodel: ModelsJsonModel;\n\tcreateProvider: boolean;\n}\nexport interface RemoveModelOp extends OpBase {\n\tkind: \"removeModel\";\n\tproviderId: string;\n\tmodelId: string;\n}\nexport interface RenameModelOp extends OpBase {\n\tkind: \"renameModel\";\n\tproviderId: string;\n\toldId: string;\n\tnewId: string;\n}\nexport interface RemoveProviderOp extends OpBase {\n\tkind: \"removeProvider\";\n\tproviderId: string;\n}\nexport type Op = SetFieldOp | AddModelOp | RemoveModelOp | RenameModelOp | RemoveProviderOp;\n\nexport type SaveResult =\n\t| { kind: \"clean\" }\n\t| { kind: \"saved\"; applied: number }\n\t| { kind: \"invalid\"; error: string }\n\t| { kind: \"error\"; error: string };\n\nexport type StoreLoad = { ok: true; store: ModelsJsonStore } | { ok: false; error: string };\n\ninterface DiskRead {\n\texists: boolean;\n\tdoc: ModelsJsonDocument;\n\trawText?: string;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Canonical comparison for JSON values, insensitive to object key order. */\nexport function jsonEquals(a: unknown, b: unknown): boolean {\n\tif (a === b) return true;\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\treturn a.length === b.length && a.every((entry, index) => jsonEquals(entry, b[index]));\n\t}\n\tif (isPlainObject(a) && isPlainObject(b)) {\n\t\tconst aKeys = Object.keys(a).sort();\n\t\tconst bKeys = Object.keys(b).sort();\n\t\treturn (\n\t\t\taKeys.length === bKeys.length &&\n\t\t\taKeys.every((key, index) => key === bKeys[index] && jsonEquals(a[key], b[key]))\n\t\t);\n\t}\n\treturn false;\n}\n\nfunction cloneValue(value: unknown): unknown {\n\treturn value === DELETE ? value : structuredClone(value);\n}\n\nasync function readDocument(path: string): Promise<DiskRead> {\n\tlet rawText: string;\n\ttry {\n\t\trawText = await readFile(path, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return { exists: false, doc: { providers: {} } };\n\t\tthrow error;\n\t}\n\tconst parsed: unknown = JSON.parse(stripJsonComments(stripBom(rawText)));\n\tif (!isPlainObject(parsed)) throw new Error(\"models.json root must be a JSON object.\");\n\tconst doc = parsed as ModelsJsonDocument;\n\tif (!isPlainObject(doc.providers)) throw new Error('models.json \"providers\" must be an object.');\n\treturn { exists: true, doc, rawText };\n}\n\nexport class ModelsJsonStore {\n\treadonly path: string;\n\tprivate baseline: ModelsJsonDocument;\n\tprivate ops: Op[] = [];\n\tprivate view: ModelsJsonDocument;\n\tprivate seq = 0;\n\tprivate backedUp = false;\n\tprivate batching = false;\n\tprivate saveChain: Promise<void> = Promise.resolve();\n\tprivate readonly drafts = new Set<string>();\n\tprivate lastSaveResult: SaveResult = { kind: \"clean\" };\n\t/** Called after each save settles (success, conflict, or failure). */\n\tonSaveResult: ((result: SaveResult) => void) | undefined;\n\n\tprivate constructor(path: string, baseline: ModelsJsonDocument) {\n\t\tthis.path = path;\n\t\tthis.baseline = baseline;\n\t\tthis.view = structuredClone(baseline);\n\t}\n\n\tstatic async load(path: string): Promise<StoreLoad> {\n\t\tlet normalized = normalizePath(path);\n\t\tlet disk: DiskRead;\n\t\ttry {\n\t\t\tnormalized = await realpath(normalized).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\tif (error.code === \"ENOENT\") return normalized;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t\tdisk = await readDocument(normalized);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: `Failed to parse models.json: ${formatError(error)}\\n\\nFile: ${normalized}` };\n\t\t}\n\t\tif (disk.exists) {\n\t\t\t// Surface schema errors as a read-only state; never auto-overwrite an invalid file.\n\t\t\tconst check = await ModelConfig.load(normalized);\n\t\t\tconst validationError = check.getError();\n\t\t\tif (validationError) return { ok: false, error: validationError };\n\t\t}\n\t\treturn { ok: true, store: new ModelsJsonStore(normalized, disk.doc) };\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// View access (read-only for the UI; mutations go through the methods)\n\t// ---------------------------------------------------------------------\n\n\tgetDoc(): ModelsJsonDocument {\n\t\treturn this.view;\n\t}\n\n\tgetProviderIds(): string[] {\n\t\treturn [...new Set([...Object.keys(this.view.providers), ...this.ops.map((op) => op.providerId)])];\n\t}\n\n\tgetProvider(providerId: string): ModelsJsonProvider | undefined {\n\t\treturn Object.hasOwn(this.view.providers, providerId) ? this.view.providers[providerId] : undefined;\n\t}\n\n\t/** Materialize a draft provider in the view without queueing an op (never written while empty). */\n\tensureProviderView(providerId: string): void {\n\t\tif (Object.hasOwn(this.view.providers, providerId)) return;\n\t\tthis.drafts.add(providerId);\n\t\tthis.recomputeView();\n\t}\n\n\t/** Provider present in the view but not yet on disk. */\n\tisDraftProvider(providerId: string): boolean {\n\t\treturn !Object.hasOwn(this.baseline.providers, providerId) && Object.hasOwn(this.view.providers, providerId);\n\t}\n\n\tgetModels(providerId: string): ModelsJsonModel[] {\n\t\tconst provider = this.getProvider(providerId);\n\t\treturn Array.isArray(provider?.models) ? provider.models : [];\n\t}\n\n\tgetModel(providerId: string, modelId: string): ModelsJsonModel | undefined {\n\t\treturn this.getModels(providerId).find((model) => model.id === modelId);\n\t}\n\n\tget pendingCount(): number {\n\t\treturn this.ops.length;\n\t}\n\n\tgetPendingError(providerId?: string): string | undefined {\n\t\tconst pending = this.ops.filter((op) => providerId === undefined || op.providerId === providerId);\n\t\tif (pending.length === 0) return undefined;\n\t\tif (this.lastSaveResult.kind === \"error\" || this.lastSaveResult.kind === \"invalid\")\n\t\t\treturn this.lastSaveResult.error;\n\t\treturn `${pending.length} change(s) are not saved; retry or discard before continuing.`;\n\t}\n\n\tretrySave(): void {\n\t\tif (this.ops.length > 0) this.scheduleSave();\n\t}\n\n\t/** Used only after flush, when the user explicitly discards unsaved edits. */\n\tdiscardPending(): void {\n\t\tthis.ops = [];\n\t\tthis.drafts.clear();\n\t\tthis.recomputeView();\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// Mutations (queue an op, refresh the view, schedule a save)\n\t// ---------------------------------------------------------------------\n\n\tprivate enqueue(op: Op): void {\n\t\tthis.ops.push(op);\n\t\tthis.recomputeView();\n\t\tthis.scheduleSave();\n\t}\n\n\tprivate nextSeq(): number {\n\t\treturn ++this.seq;\n\t}\n\n\tsetProviderField(providerId: string, path: readonly string[], value: unknown): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"set\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tpath,\n\t\t\tvalue: cloneValue(value),\n\t\t\tcreateProvider: !Object.hasOwn(this.baseline.providers, providerId),\n\t\t});\n\t}\n\n\tsetModelField(providerId: string, modelId: string, path: readonly string[], value: unknown): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"set\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tmodelId,\n\t\t\tpath,\n\t\t\tvalue: cloneValue(value),\n\t\t\tcreateProvider: !Object.hasOwn(this.baseline.providers, providerId),\n\t\t});\n\t}\n\n\taddModel(providerId: string, model: ModelsJsonModel): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"addModel\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tmodel: structuredClone(model),\n\t\t\tcreateProvider: !Object.hasOwn(this.baseline.providers, providerId),\n\t\t});\n\t}\n\n\tremoveModel(providerId: string, modelId: string): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"removeModel\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tmodelId,\n\t\t});\n\t}\n\n\tasync renameModel(providerId: string, oldId: string, newId: string): Promise<string | undefined> {\n\t\tawait this.flush();\n\t\tconst pendingError = this.getPendingError(providerId);\n\t\tif (pendingError) return pendingError;\n\t\tconst before = this.getModel(providerId, oldId);\n\t\tif (!before) return \"The model no longer exists.\";\n\t\tconst seq = this.nextSeq();\n\t\tthis.enqueue({\n\t\t\tkind: \"renameModel\",\n\t\t\tseq,\n\t\t\tproviderId,\n\t\t\toldId,\n\t\t\tnewId,\n\t\t});\n\t\tawait this.flush();\n\t\tif (this.ops.some((op) => op.seq === seq)) {\n\t\t\t// The save failed; drop the rename rather than surprising the user later.\n\t\t\tthis.ops = this.ops.filter((op) => op.seq !== seq);\n\t\t\tthis.recomputeView();\n\t\t\treturn this.getPendingError(providerId) ?? \"Failed to save models.json.\";\n\t\t}\n\t\t// A settled rename can still have missed when the model moved on disk; never\n\t\t// adopt an unrelated model that already uses the destination id.\n\t\tconst renamed = this.getModel(providerId, newId);\n\t\treturn renamed && jsonEquals(renamed, { ...before, id: newId })\n\t\t\t? undefined\n\t\t\t: \"The model changed on disk; reopen it before renaming.\";\n\t}\n\n\tremoveProvider(providerId: string): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"removeProvider\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t});\n\t}\n\n\t/** Queue several ops but schedule a single save (batch import, built-in data apply). */\n\tbatch(mutate: () => void): void {\n\t\tthis.batching = true;\n\t\ttry {\n\t\t\tmutate();\n\t\t} finally {\n\t\t\tthis.batching = false;\n\t\t}\n\t\tif (this.ops.length > 0) this.scheduleSave();\n\t}\n\n\t/** Drop all pending ops targeting a draft provider (used when leaving its editor untouched). */\n\tdiscardProviderDraft(providerId: string): void {\n\t\tthis.drafts.delete(providerId);\n\t\tif (Object.hasOwn(this.baseline.providers, providerId)) return;\n\t\tthis.ops = this.ops.filter((op) => op.providerId !== providerId);\n\t\tthis.recomputeView();\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// View computation\n\t// ---------------------------------------------------------------------\n\n\tprivate recomputeView(): void {\n\t\tconst view = structuredClone(this.baseline);\n\t\tfor (const id of this.drafts) ensureProvider(view, id);\n\t\tfor (const op of this.ops) applyOp(view, op);\n\t\tthis.view = view;\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// Saving\n\t// ---------------------------------------------------------------------\n\n\tprivate scheduleSave(): void {\n\t\tif (this.batching) return;\n\t\tthis.saveChain = this.saveChain\n\t\t\t.catch(() => {})\n\t\t\t.then(async () => {\n\t\t\t\tconst result = await this.save();\n\t\t\t\tthis.lastSaveResult = result;\n\t\t\t\tif (result.kind !== \"clean\") this.onSaveResult?.(result);\n\t\t\t});\n\t}\n\n\t/** Wait for all scheduled saves; the settled result of the last save, if any. */\n\tasync flush(): Promise<void> {\n\t\tlet pending: Promise<void>;\n\t\tdo {\n\t\t\tpending = this.saveChain;\n\t\t\tawait pending;\n\t\t} while (pending !== this.saveChain);\n\t}\n\n\tprivate async save(): Promise<SaveResult> {\n\t\tif (this.ops.length === 0) return { kind: \"clean\" };\n\t\ttry {\n\t\t\treturn await withFileMutationQueue(this.path, async () => {\n\t\t\t\tawait mkdir(dirname(this.path), { recursive: true });\n\t\t\t\tlet compromised: Error | undefined;\n\t\t\t\tconst release = await lockfile.lock(this.path, {\n\t\t\t\t\trealpath: false,\n\t\t\t\t\tstale: 30_000,\n\t\t\t\t\tretries: { retries: 20, factor: 1.2, minTimeout: 50, maxTimeout: 250 },\n\t\t\t\t\tonCompromised: (error) => {\n\t\t\t\t\t\tcompromised = error;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tlet result: SaveResult;\n\t\t\t\ttry {\n\t\t\t\t\tresult = await this.saveLocked(() => {\n\t\t\t\t\t\tif (compromised) throw compromised;\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tresult = { kind: \"error\", error: `Failed to save models.json: ${formatError(error)}` };\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait release();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!compromised && result.kind !== \"error\" && result.kind !== \"invalid\") {\n\t\t\t\t\t\tresult = { kind: \"error\", error: `Could not release the models.json lock: ${formatError(error)}` };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t});\n\t\t} catch (error) {\n\t\t\treturn { kind: \"error\", error: `Failed to access models.json for saving: ${formatError(error)}` };\n\t\t}\n\t}\n\n\tprivate async saveLocked(assertLock: () => void): Promise<SaveResult> {\n\t\tconst tempPath = join(dirname(this.path), `.models.${randomUUID()}.tmp`);\n\t\ttry {\n\t\t\tassertLock();\n\t\t\tlet disk: DiskRead;\n\t\t\ttry {\n\t\t\t\tdisk = await readDocument(this.path);\n\t\t\t} catch (error) {\n\t\t\t\t// Never clobber a file we cannot parse.\n\t\t\t\treturn { kind: \"error\", error: `models.json changed on disk and is unreadable: ${formatError(error)}` };\n\t\t\t}\n\t\t\tconst working = structuredClone(disk.doc);\n\t\t\tconst batch = this.ops.filter((op) => {\n\t\t\t\tconst provider = this.getProvider(op.providerId);\n\t\t\t\treturn (\n\t\t\t\t\tObject.hasOwn(disk.doc.providers, op.providerId) ||\n\t\t\t\t\t!provider ||\n\t\t\t\t\tObject.keys(provider).length === 0 ||\n\t\t\t\t\thasProviderSettings(provider)\n\t\t\t\t);\n\t\t\t});\n\t\t\t// Apply blindly onto the freshest disk content: unrelated external\n\t\t\t// edits are preserved, a same-field race resolves last-writer-wins,\n\t\t\t// and ops targeting externally removed models simply miss.\n\t\t\tfor (const op of batch) applyOp(working, op);\n\t\t\tpruneEmptyNewProviders(working, disk.doc);\n\t\t\tconst settle = () => {\n\t\t\t\tconst settled = new Set(batch.map((op) => op.seq));\n\t\t\t\tthis.ops = this.ops.filter((op) => !settled.has(op.seq));\n\t\t\t\tthis.recomputeView();\n\t\t\t};\n\t\t\tif (jsonEquals(working, disk.doc)) {\n\t\t\t\t// Ops cancelled each other out or already matched disk; nothing to write.\n\t\t\t\tthis.baseline = disk.doc;\n\t\t\t\tsettle();\n\t\t\t\treturn { kind: \"saved\", applied: batch.length };\n\t\t\t}\n\t\t\tconst candidate = `${JSON.stringify(working, null, 2)}\\n`;\n\t\t\tawait writeFile(tempPath, candidate, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tconst check = await ModelConfig.load(tempPath);\n\t\t\tconst validationError = check.getError();\n\t\t\tif (validationError) {\n\t\t\t\treturn { kind: \"invalid\", error: validationError };\n\t\t\t}\n\t\t\tconst latest = await readDocument(this.path);\n\t\t\tif (latest.exists !== disk.exists || latest.rawText !== disk.rawText) {\n\t\t\t\tthrow new Error(\"models.json changed while saving; the edits were kept for retry.\");\n\t\t\t}\n\t\t\tif (!this.backedUp && disk.exists && disk.rawText !== undefined) {\n\t\t\t\tawait writeFile(`${this.path}.bak`, disk.rawText, { encoding: \"utf8\", mode: 0o600 });\n\t\t\t\tthis.backedUp = true;\n\t\t\t}\n\t\t\tassertLock();\n\t\t\tawait rename(tempPath, this.path);\n\t\t\tthis.baseline = working;\n\t\t\tsettle();\n\t\t\treturn { kind: \"saved\", applied: batch.length };\n\t\t} finally {\n\t\t\tawait rm(tempPath, { force: true }).catch(() => {});\n\t\t}\n\t}\n}\n\n// -------------------------------------------------------------------------\n// Op application\n// -------------------------------------------------------------------------\n\nfunction ensureProvider(doc: ModelsJsonDocument, providerId: string): Record<string, unknown> {\n\tconst existing = Object.hasOwn(doc.providers, providerId) ? doc.providers[providerId] : undefined;\n\tif (existing) return existing;\n\tconst created: Record<string, unknown> = {};\n\tObject.defineProperty(doc.providers, providerId, {\n\t\tvalue: created,\n\t\twritable: true,\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t});\n\treturn created;\n}\n\nfunction applyOp(doc: ModelsJsonDocument, op: Op): void {\n\tswitch (op.kind) {\n\t\tcase \"set\": {\n\t\t\tconst provider = ensureProvider(doc, op.providerId);\n\t\t\tif (op.modelId === undefined) {\n\t\t\t\tsetPath(provider, op.path, op.value);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst models = Array.isArray(provider.models) ? (provider.models as Record<string, unknown>[]) : [];\n\t\t\tconst model = models.find((entry) => entry.id === op.modelId);\n\t\t\tif (model) setPath(model, op.path, op.value);\n\t\t\treturn;\n\t\t}\n\t\tcase \"addModel\": {\n\t\t\tconst provider = ensureProvider(doc, op.providerId);\n\t\t\tconst models = Array.isArray(provider.models) ? (provider.models as Record<string, unknown>[]) : [];\n\t\t\tconst index = models.findIndex((entry) => entry.id === op.model.id);\n\t\t\tconst clone = structuredClone(op.model) as Record<string, unknown>;\n\t\t\tif (index >= 0) models[index] = clone;\n\t\t\telse models.push(clone);\n\t\t\tprovider.models = models;\n\t\t\treturn;\n\t\t}\n\t\tcase \"removeModel\": {\n\t\t\tconst provider = doc.providers[op.providerId] as Record<string, unknown> | undefined;\n\t\t\tconst models = Array.isArray(provider?.models) ? (provider.models as Record<string, unknown>[]) : undefined;\n\t\t\tif (!provider || !models) return;\n\t\t\tprovider.models = models.filter((entry) => entry.id !== op.modelId);\n\t\t\treturn;\n\t\t}\n\t\tcase \"renameModel\": {\n\t\t\tconst provider = doc.providers[op.providerId] as Record<string, unknown> | undefined;\n\t\t\tconst models = Array.isArray(provider?.models) ? (provider.models as Record<string, unknown>[]) : undefined;\n\t\t\tif (!models) return;\n\t\t\tconst model = models.find((entry) => entry.id === op.oldId);\n\t\t\tif (model && !models.some((entry) => entry.id === op.newId)) model.id = op.newId;\n\t\t\treturn;\n\t\t}\n\t\tcase \"removeProvider\": {\n\t\t\tdelete doc.providers[op.providerId];\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/** Remove providers the ops materialized but which ended up with no keys (self-cancelled drafts). */\nfunction pruneEmptyNewProviders(working: ModelsJsonDocument, disk: ModelsJsonDocument): void {\n\tfor (const [providerId, provider] of Object.entries(working.providers)) {\n\t\tif (Object.hasOwn(disk.providers, providerId)) continue;\n\t\tif (isPlainObject(provider) && Object.keys(provider).length === 0) delete working.providers[providerId];\n\t}\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/extensions/provider/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Op-based models.json editing store.\n *\n * Three states are tracked: `baseline` (last known disk content), pending\n * field-level ops, and `view` (baseline + ops, what the UI renders). Every\n * confirmed edit queues an op and schedules a save. A save re-reads the file\n * under a cross-process lock and applies the pending ops onto that freshest\n * content — unrelated external edits are preserved, a same-field race\n * resolves last-writer-wins, and ops targeting externally removed models\n * simply miss. The candidate is validated via ModelConfig on a temp file,\n * backed up once per session, and atomically renamed into place. Failed\n * saves keep the ops pending; closing offers retry or explicit discard.\n * Whole-snapshot blind overwrites are never performed.\n *\n * Comments and custom formatting are normalized to two-space JSON on save;\n * unknown fields anywhere in the document are preserved verbatim.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, realpath, rename, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { ModelConfig, type ModelsJsonModel, type ModelsJsonProvider } from \"../../core/model-config.ts\";\nimport { withFileMutationQueue } from \"../../core/tools/file-mutation-queue.ts\";\nimport { stripJsonComments } from \"../../utils/json.ts\";\nimport { normalizePath } from \"../../utils/paths.ts\";\nimport { stripBom } from \"../../utils/text.ts\";\nimport { hasProviderSettings } from \"./configuration.ts\";\nimport { formatError } from \"./constants.ts\";\nimport { DELETE, setPath } from \"./json-fields.ts\";\n\nexport { DELETE, type DeleteMarker } from \"./json-fields.ts\";\n\nexport interface ModelsJsonDocument {\n\tproviders: Record<string, ModelsJsonProvider>;\n\t[key: string]: unknown;\n}\n\ninterface OpBase {\n\tseq: number;\n}\nexport interface SetFieldOp extends OpBase {\n\tkind: \"set\";\n\tproviderId: string;\n\t/** Undefined for provider-level fields. */\n\tmodelId?: string;\n\t/** Path within the provider/model object, e.g. [\"compat\", \"allowEmptySignature\"]. */\n\tpath: readonly string[];\n\tvalue: unknown;\n\tcreateProvider: boolean;\n}\nexport interface AddModelOp extends OpBase {\n\tkind: \"addModel\";\n\tproviderId: string;\n\tmodel: ModelsJsonModel;\n\tcreateProvider: boolean;\n}\nexport interface RemoveModelOp extends OpBase {\n\tkind: \"removeModel\";\n\tproviderId: string;\n\tmodelId: string;\n}\nexport interface RenameModelOp extends OpBase {\n\tkind: \"renameModel\";\n\tproviderId: string;\n\toldId: string;\n\tnewId: string;\n}\nexport interface RemoveProviderOp extends OpBase {\n\tkind: \"removeProvider\";\n\tproviderId: string;\n}\nexport type Op = SetFieldOp | AddModelOp | RemoveModelOp | RenameModelOp | RemoveProviderOp;\n\nexport type SaveResult =\n\t| { kind: \"clean\" }\n\t| { kind: \"saved\"; applied: number }\n\t| { kind: \"invalid\"; error: string }\n\t| { kind: \"error\"; error: string };\n\nexport type StoreLoad = { ok: true; store: ModelsJsonStore } | { ok: false; error: string };\n\ninterface DiskRead {\n\texists: boolean;\n\tdoc: ModelsJsonDocument;\n\trawText?: string;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Canonical comparison for JSON values, insensitive to object key order. */\nexport function jsonEquals(a: unknown, b: unknown): boolean {\n\tif (a === b) return true;\n\tif (Array.isArray(a) && Array.isArray(b)) {\n\t\treturn a.length === b.length && a.every((entry, index) => jsonEquals(entry, b[index]));\n\t}\n\tif (isPlainObject(a) && isPlainObject(b)) {\n\t\tconst aKeys = Object.keys(a).sort();\n\t\tconst bKeys = Object.keys(b).sort();\n\t\treturn (\n\t\t\taKeys.length === bKeys.length &&\n\t\t\taKeys.every((key, index) => key === bKeys[index] && jsonEquals(a[key], b[key]))\n\t\t);\n\t}\n\treturn false;\n}\n\nfunction cloneValue(value: unknown): unknown {\n\treturn value === DELETE ? value : structuredClone(value);\n}\n\nasync function readDocument(path: string): Promise<DiskRead> {\n\tlet rawText: string;\n\ttry {\n\t\trawText = await readFile(path, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return { exists: false, doc: { providers: {} } };\n\t\tthrow error;\n\t}\n\tconst parsed: unknown = JSON.parse(stripJsonComments(stripBom(rawText)));\n\tif (!isPlainObject(parsed)) throw new Error(\"models.json root must be a JSON object.\");\n\tconst doc = parsed as ModelsJsonDocument;\n\tif (!isPlainObject(doc.providers)) throw new Error('models.json \"providers\" must be an object.');\n\treturn { exists: true, doc, rawText };\n}\n\nexport class ModelsJsonStore {\n\treadonly path: string;\n\tprivate baseline: ModelsJsonDocument;\n\tprivate ops: Op[] = [];\n\tprivate view: ModelsJsonDocument;\n\tprivate seq = 0;\n\tprivate backedUp = false;\n\tprivate batching = false;\n\tprivate saveChain: Promise<void> = Promise.resolve();\n\tprivate readonly drafts = new Set<string>();\n\tprivate lastSaveResult: SaveResult = { kind: \"clean\" };\n\t/** Called after each save settles (success, conflict, or failure). */\n\tonSaveResult: ((result: SaveResult) => void) | undefined;\n\n\tprivate constructor(path: string, baseline: ModelsJsonDocument) {\n\t\tthis.path = path;\n\t\tthis.baseline = baseline;\n\t\tthis.view = structuredClone(baseline);\n\t}\n\n\tstatic async load(path: string): Promise<StoreLoad> {\n\t\tlet normalized = normalizePath(path);\n\t\tlet disk: DiskRead;\n\t\ttry {\n\t\t\tnormalized = await realpath(normalized).catch((error: NodeJS.ErrnoException) => {\n\t\t\t\tif (error.code === \"ENOENT\") return normalized;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t\tdisk = await readDocument(normalized);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, error: `Failed to parse models.json: ${formatError(error)}\\n\\nFile: ${normalized}` };\n\t\t}\n\t\tif (disk.exists) {\n\t\t\t// Surface schema errors as a read-only state; never auto-overwrite an invalid file.\n\t\t\tconst check = await ModelConfig.load(normalized);\n\t\t\tconst validationError = check.getError();\n\t\t\tif (validationError) return { ok: false, error: validationError };\n\t\t}\n\t\treturn { ok: true, store: new ModelsJsonStore(normalized, disk.doc) };\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// View access (read-only for the UI; mutations go through the methods)\n\t// ---------------------------------------------------------------------\n\n\tgetDoc(): ModelsJsonDocument {\n\t\treturn this.view;\n\t}\n\n\tgetProviderIds(): string[] {\n\t\treturn [...new Set([...Object.keys(this.view.providers), ...this.ops.map((op) => op.providerId)])];\n\t}\n\n\tgetProvider(providerId: string): ModelsJsonProvider | undefined {\n\t\treturn Object.hasOwn(this.view.providers, providerId) ? this.view.providers[providerId] : undefined;\n\t}\n\n\t/** Materialize a draft provider in the view without queueing an op (never written while empty). */\n\tensureProviderView(providerId: string): void {\n\t\tif (Object.hasOwn(this.view.providers, providerId)) return;\n\t\tthis.drafts.add(providerId);\n\t\tthis.recomputeView();\n\t}\n\n\t/** Provider present in the view but not yet on disk. */\n\tisDraftProvider(providerId: string): boolean {\n\t\treturn !Object.hasOwn(this.baseline.providers, providerId) && Object.hasOwn(this.view.providers, providerId);\n\t}\n\n\tgetModels(providerId: string): ModelsJsonModel[] {\n\t\tconst provider = this.getProvider(providerId);\n\t\treturn Array.isArray(provider?.models) ? provider.models : [];\n\t}\n\n\tgetModel(providerId: string, modelId: string): ModelsJsonModel | undefined {\n\t\treturn this.getModels(providerId).find((model) => model.id === modelId);\n\t}\n\n\tget pendingCount(): number {\n\t\treturn this.ops.length;\n\t}\n\n\t/** The latest save failed; pending edits remain available for retry. */\n\tget saveFailed(): boolean {\n\t\treturn this.lastSaveResult.kind === \"error\" || this.lastSaveResult.kind === \"invalid\";\n\t}\n\n\tgetPendingError(providerId?: string): string | undefined {\n\t\tconst pending = this.ops.filter((op) => providerId === undefined || op.providerId === providerId);\n\t\tif (pending.length === 0) return undefined;\n\t\tif (this.lastSaveResult.kind === \"error\" || this.lastSaveResult.kind === \"invalid\")\n\t\t\treturn this.lastSaveResult.error;\n\t\treturn `${pending.length} change(s) are not saved; retry or discard before continuing.`;\n\t}\n\n\tretrySave(): void {\n\t\tif (this.ops.length > 0) this.scheduleSave();\n\t}\n\n\t/** Used only after flush, when the user explicitly discards unsaved edits. */\n\tdiscardPending(): void {\n\t\tthis.ops = [];\n\t\tthis.drafts.clear();\n\t\tthis.recomputeView();\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// Mutations (queue an op, refresh the view, schedule a save)\n\t// ---------------------------------------------------------------------\n\n\tprivate enqueue(op: Op): void {\n\t\tthis.ops.push(op);\n\t\tthis.recomputeView();\n\t\tthis.scheduleSave();\n\t}\n\n\tprivate nextSeq(): number {\n\t\treturn ++this.seq;\n\t}\n\n\tsetProviderField(providerId: string, path: readonly string[], value: unknown): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"set\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tpath,\n\t\t\tvalue: cloneValue(value),\n\t\t\tcreateProvider: !Object.hasOwn(this.baseline.providers, providerId),\n\t\t});\n\t}\n\n\tsetModelField(providerId: string, modelId: string, path: readonly string[], value: unknown): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"set\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tmodelId,\n\t\t\tpath,\n\t\t\tvalue: cloneValue(value),\n\t\t\tcreateProvider: !Object.hasOwn(this.baseline.providers, providerId),\n\t\t});\n\t}\n\n\taddModel(providerId: string, model: ModelsJsonModel): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"addModel\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tmodel: structuredClone(model),\n\t\t\tcreateProvider: !Object.hasOwn(this.baseline.providers, providerId),\n\t\t});\n\t}\n\n\tremoveModel(providerId: string, modelId: string): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"removeModel\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t\tmodelId,\n\t\t});\n\t}\n\n\tasync renameModel(providerId: string, oldId: string, newId: string): Promise<string | undefined> {\n\t\tawait this.flush();\n\t\tconst pendingError = this.getPendingError(providerId);\n\t\tif (pendingError) return pendingError;\n\t\tconst before = this.getModel(providerId, oldId);\n\t\tif (!before) return \"The model no longer exists.\";\n\t\tconst seq = this.nextSeq();\n\t\tthis.enqueue({\n\t\t\tkind: \"renameModel\",\n\t\t\tseq,\n\t\t\tproviderId,\n\t\t\toldId,\n\t\t\tnewId,\n\t\t});\n\t\tawait this.flush();\n\t\tif (this.ops.some((op) => op.seq === seq)) {\n\t\t\t// The save failed; drop the rename rather than surprising the user later.\n\t\t\tthis.ops = this.ops.filter((op) => op.seq !== seq);\n\t\t\tthis.recomputeView();\n\t\t\treturn this.getPendingError(providerId) ?? \"Failed to save models.json.\";\n\t\t}\n\t\t// A settled rename can still have missed when the model moved on disk; never\n\t\t// adopt an unrelated model that already uses the destination id.\n\t\tconst renamed = this.getModel(providerId, newId);\n\t\treturn renamed && jsonEquals(renamed, { ...before, id: newId })\n\t\t\t? undefined\n\t\t\t: \"The model changed on disk; reopen it before renaming.\";\n\t}\n\n\tremoveProvider(providerId: string): void {\n\t\tthis.enqueue({\n\t\t\tkind: \"removeProvider\",\n\t\t\tseq: this.nextSeq(),\n\t\t\tproviderId,\n\t\t});\n\t}\n\n\t/** Queue several ops but schedule a single save (batch import, built-in data apply). */\n\tbatch(mutate: () => void): void {\n\t\tthis.batching = true;\n\t\ttry {\n\t\t\tmutate();\n\t\t} finally {\n\t\t\tthis.batching = false;\n\t\t}\n\t\tif (this.ops.length > 0) this.scheduleSave();\n\t}\n\n\t/** Drop all pending ops targeting a draft provider (used when leaving its editor untouched). */\n\tdiscardProviderDraft(providerId: string): void {\n\t\tthis.drafts.delete(providerId);\n\t\tif (Object.hasOwn(this.baseline.providers, providerId)) return;\n\t\tthis.ops = this.ops.filter((op) => op.providerId !== providerId);\n\t\tthis.recomputeView();\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// View computation\n\t// ---------------------------------------------------------------------\n\n\tprivate recomputeView(): void {\n\t\tconst view = structuredClone(this.baseline);\n\t\tfor (const id of this.drafts) ensureProvider(view, id);\n\t\tfor (const op of this.ops) applyOp(view, op);\n\t\tthis.view = view;\n\t}\n\n\t// ---------------------------------------------------------------------\n\t// Saving\n\t// ---------------------------------------------------------------------\n\n\tprivate scheduleSave(): void {\n\t\tif (this.batching) return;\n\t\tthis.saveChain = this.saveChain\n\t\t\t.catch(() => {})\n\t\t\t.then(async () => {\n\t\t\t\tconst result = await this.save();\n\t\t\t\tthis.lastSaveResult = result;\n\t\t\t\tif (result.kind !== \"clean\") this.onSaveResult?.(result);\n\t\t\t});\n\t}\n\n\t/** Wait for all scheduled saves; the settled result of the last save, if any. */\n\tasync flush(): Promise<void> {\n\t\tlet pending: Promise<void>;\n\t\tdo {\n\t\t\tpending = this.saveChain;\n\t\t\tawait pending;\n\t\t} while (pending !== this.saveChain);\n\t}\n\n\tprivate async save(): Promise<SaveResult> {\n\t\tif (this.ops.length === 0) return { kind: \"clean\" };\n\t\ttry {\n\t\t\treturn await withFileMutationQueue(this.path, async () => {\n\t\t\t\tawait mkdir(dirname(this.path), { recursive: true });\n\t\t\t\tlet compromised: Error | undefined;\n\t\t\t\tconst release = await lockfile.lock(this.path, {\n\t\t\t\t\trealpath: false,\n\t\t\t\t\tstale: 30_000,\n\t\t\t\t\tretries: { retries: 20, factor: 1.2, minTimeout: 50, maxTimeout: 250 },\n\t\t\t\t\tonCompromised: (error) => {\n\t\t\t\t\t\tcompromised = error;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tlet result: SaveResult;\n\t\t\t\ttry {\n\t\t\t\t\tresult = await this.saveLocked(() => {\n\t\t\t\t\t\tif (compromised) throw compromised;\n\t\t\t\t\t});\n\t\t\t\t} catch (error) {\n\t\t\t\t\tresult = { kind: \"error\", error: `Failed to save models.json: ${formatError(error)}` };\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait release();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!compromised && result.kind !== \"error\" && result.kind !== \"invalid\") {\n\t\t\t\t\t\tresult = { kind: \"error\", error: `Could not release the models.json lock: ${formatError(error)}` };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t});\n\t\t} catch (error) {\n\t\t\treturn { kind: \"error\", error: `Failed to access models.json for saving: ${formatError(error)}` };\n\t\t}\n\t}\n\n\tprivate async saveLocked(assertLock: () => void): Promise<SaveResult> {\n\t\tconst tempPath = join(dirname(this.path), `.models.${randomUUID()}.tmp`);\n\t\ttry {\n\t\t\tassertLock();\n\t\t\tlet disk: DiskRead;\n\t\t\ttry {\n\t\t\t\tdisk = await readDocument(this.path);\n\t\t\t} catch (error) {\n\t\t\t\t// Never clobber a file we cannot parse.\n\t\t\t\treturn { kind: \"error\", error: `models.json changed on disk and is unreadable: ${formatError(error)}` };\n\t\t\t}\n\t\t\tconst working = structuredClone(disk.doc);\n\t\t\tconst batch = this.ops.filter((op) => {\n\t\t\t\tconst provider = this.getProvider(op.providerId);\n\t\t\t\treturn (\n\t\t\t\t\tObject.hasOwn(disk.doc.providers, op.providerId) ||\n\t\t\t\t\t!provider ||\n\t\t\t\t\tObject.keys(provider).length === 0 ||\n\t\t\t\t\thasProviderSettings(provider)\n\t\t\t\t);\n\t\t\t});\n\t\t\t// Apply blindly onto the freshest disk content: unrelated external\n\t\t\t// edits are preserved, a same-field race resolves last-writer-wins,\n\t\t\t// and ops targeting externally removed models simply miss.\n\t\t\tfor (const op of batch) applyOp(working, op);\n\t\t\tpruneEmptyNewProviders(working, disk.doc);\n\t\t\tconst settle = () => {\n\t\t\t\tconst settled = new Set(batch.map((op) => op.seq));\n\t\t\t\tthis.ops = this.ops.filter((op) => !settled.has(op.seq));\n\t\t\t\tthis.recomputeView();\n\t\t\t};\n\t\t\tif (jsonEquals(working, disk.doc)) {\n\t\t\t\t// Ops cancelled each other out or already matched disk; nothing to write.\n\t\t\t\tthis.baseline = disk.doc;\n\t\t\t\tsettle();\n\t\t\t\treturn { kind: \"saved\", applied: batch.length };\n\t\t\t}\n\t\t\tconst candidate = `${JSON.stringify(working, null, 2)}\\n`;\n\t\t\tawait writeFile(tempPath, candidate, { encoding: \"utf8\", mode: 0o600 });\n\t\t\tconst check = await ModelConfig.load(tempPath);\n\t\t\tconst validationError = check.getError();\n\t\t\tif (validationError) {\n\t\t\t\treturn { kind: \"invalid\", error: validationError };\n\t\t\t}\n\t\t\tconst latest = await readDocument(this.path);\n\t\t\tif (latest.exists !== disk.exists || latest.rawText !== disk.rawText) {\n\t\t\t\tthrow new Error(\"models.json changed while saving; the edits were kept for retry.\");\n\t\t\t}\n\t\t\tif (!this.backedUp && disk.exists && disk.rawText !== undefined) {\n\t\t\t\tawait writeFile(`${this.path}.bak`, disk.rawText, { encoding: \"utf8\", mode: 0o600 });\n\t\t\t\tthis.backedUp = true;\n\t\t\t}\n\t\t\tassertLock();\n\t\t\tawait rename(tempPath, this.path);\n\t\t\tthis.baseline = working;\n\t\t\tsettle();\n\t\t\treturn { kind: \"saved\", applied: batch.length };\n\t\t} finally {\n\t\t\tawait rm(tempPath, { force: true }).catch(() => {});\n\t\t}\n\t}\n}\n\n// -------------------------------------------------------------------------\n// Op application\n// -------------------------------------------------------------------------\n\nfunction ensureProvider(doc: ModelsJsonDocument, providerId: string): Record<string, unknown> {\n\tconst existing = Object.hasOwn(doc.providers, providerId) ? doc.providers[providerId] : undefined;\n\tif (existing) return existing;\n\tconst created: Record<string, unknown> = {};\n\tObject.defineProperty(doc.providers, providerId, {\n\t\tvalue: created,\n\t\twritable: true,\n\t\tenumerable: true,\n\t\tconfigurable: true,\n\t});\n\treturn created;\n}\n\nfunction applyOp(doc: ModelsJsonDocument, op: Op): void {\n\tswitch (op.kind) {\n\t\tcase \"set\": {\n\t\t\tconst provider = ensureProvider(doc, op.providerId);\n\t\t\tif (op.modelId === undefined) {\n\t\t\t\tsetPath(provider, op.path, op.value);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst models = Array.isArray(provider.models) ? (provider.models as Record<string, unknown>[]) : [];\n\t\t\tconst model = models.find((entry) => entry.id === op.modelId);\n\t\t\tif (model) setPath(model, op.path, op.value);\n\t\t\treturn;\n\t\t}\n\t\tcase \"addModel\": {\n\t\t\tconst provider = ensureProvider(doc, op.providerId);\n\t\t\tconst models = Array.isArray(provider.models) ? (provider.models as Record<string, unknown>[]) : [];\n\t\t\tconst index = models.findIndex((entry) => entry.id === op.model.id);\n\t\t\tconst clone = structuredClone(op.model) as Record<string, unknown>;\n\t\t\tif (index >= 0) models[index] = clone;\n\t\t\telse models.push(clone);\n\t\t\tprovider.models = models;\n\t\t\treturn;\n\t\t}\n\t\tcase \"removeModel\": {\n\t\t\tconst provider = doc.providers[op.providerId] as Record<string, unknown> | undefined;\n\t\t\tconst models = Array.isArray(provider?.models) ? (provider.models as Record<string, unknown>[]) : undefined;\n\t\t\tif (!provider || !models) return;\n\t\t\tprovider.models = models.filter((entry) => entry.id !== op.modelId);\n\t\t\treturn;\n\t\t}\n\t\tcase \"renameModel\": {\n\t\t\tconst provider = doc.providers[op.providerId] as Record<string, unknown> | undefined;\n\t\t\tconst models = Array.isArray(provider?.models) ? (provider.models as Record<string, unknown>[]) : undefined;\n\t\t\tif (!models) return;\n\t\t\tconst model = models.find((entry) => entry.id === op.oldId);\n\t\t\tif (model && !models.some((entry) => entry.id === op.newId)) model.id = op.newId;\n\t\t\treturn;\n\t\t}\n\t\tcase \"removeProvider\": {\n\t\t\tdelete doc.providers[op.providerId];\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/** Remove providers the ops materialized but which ended up with no keys (self-cancelled drafts). */\nfunction pruneEmptyNewProviders(working: ModelsJsonDocument, disk: ModelsJsonDocument): void {\n\tfor (const [providerId, provider] of Object.entries(working.providers)) {\n\t\tif (Object.hasOwn(disk.providers, providerId)) continue;\n\t\tif (isPlainObject(provider) && Object.keys(provider).length === 0) delete working.providers[providerId];\n\t}\n}\n"]}
@@ -1,15 +1,11 @@
1
1
  /**
2
2
  * Two-pane provider editor.
3
3
  *
4
- * Left column: API Auth / Fetch Models, the provider's
5
- * models (name → id → "New Model" fallback, one draft at a time), then
6
- * + Add Model and Delete Provider. Right column hosts the selected item's
7
- * field pane and sub-pane stack; both columns keep their own selection and
8
- * scroll position. The frame height is fixed: each column scrolls inside a
9
- * fixed window with a (n/N) position indicator instead of resizing, and the
10
- * selected row stays accent in both panes while the unfocused pane's other
11
- * rows dim back. Typing on a value row overwrites, Enter tweaks or enters,
12
- * ←/→ switch panes, Esc cancels/pops/backs out.
4
+ * Left column groups connection, models, and management actions. The right
5
+ * column hosts the selected item's field pane and sub-pane stack. Both columns
6
+ * scroll inside a fixed-height frame; below the wide-layout threshold, only
7
+ * the focused column is shown. Typing on a value row overwrites, Enter tweaks
8
+ * or enters, ←/→ switch panes, and Esc cancels/pops/backs out.
13
9
  */
14
10
  import "../keybindings.ts";
15
11
  import { type Component, type Focusable, type TUI } from "@earendil-works/pi-tui";
@@ -82,6 +78,8 @@ export declare class ProviderEditorScreen implements Component, Focusable {
82
78
  private commitModelDraft;
83
79
  private refresh;
84
80
  private renderFrame;
81
+ private renderRight;
82
+ private renderPaneTitle;
85
83
  /** Content-driven left width: fits the longest visible label, clamped to 16–40 and 45% of the terminal. */
86
84
  private computeLeftWidth;
87
85
  private renderTitle;