@gajae-code/coding-agent 0.5.1 → 0.5.3

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 (165) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -1
  3. package/dist/types/async/job-manager.d.ts +6 -0
  4. package/dist/types/cli/setup-cli.d.ts +8 -1
  5. package/dist/types/commands/setup.d.ts +7 -0
  6. package/dist/types/config/file-lock.d.ts +24 -2
  7. package/dist/types/config/model-registry.d.ts +4 -0
  8. package/dist/types/config/models-config-schema.d.ts +5 -0
  9. package/dist/types/config/settings-schema.d.ts +62 -0
  10. package/dist/types/dap/client.d.ts +2 -1
  11. package/dist/types/edit/read-file.d.ts +6 -0
  12. package/dist/types/eval/js/context-manager.d.ts +3 -0
  13. package/dist/types/eval/js/executor.d.ts +1 -0
  14. package/dist/types/exec/bash-executor.d.ts +2 -0
  15. package/dist/types/gjc-runtime/state-writer.d.ts +64 -2
  16. package/dist/types/gjc-runtime/tmux-sessions.d.ts +7 -1
  17. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +10 -0
  18. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +29 -0
  19. package/dist/types/lsp/types.d.ts +2 -0
  20. package/dist/types/modes/bridge/bridge-mode.d.ts +1 -0
  21. package/dist/types/modes/components/model-selector.d.ts +2 -0
  22. package/dist/types/modes/components/oauth-selector.d.ts +1 -0
  23. package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
  24. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +1 -0
  25. package/dist/types/modes/components/tool-execution.d.ts +1 -0
  26. package/dist/types/modes/interactive-mode.d.ts +1 -1
  27. package/dist/types/modes/rpc/rpc-mode.d.ts +56 -1
  28. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
  29. package/dist/types/modes/theme/defaults/index.d.ts +302 -0
  30. package/dist/types/modes/theme/theme.d.ts +1 -0
  31. package/dist/types/modes/types.d.ts +1 -1
  32. package/dist/types/runtime/process-lifecycle.d.ts +108 -0
  33. package/dist/types/runtime-mcp/transports/stdio.d.ts +1 -0
  34. package/dist/types/runtime-mcp/types.d.ts +2 -0
  35. package/dist/types/session/agent-session.d.ts +17 -1
  36. package/dist/types/session/artifacts.d.ts +4 -1
  37. package/dist/types/session/history-storage.d.ts +2 -2
  38. package/dist/types/session/session-manager.d.ts +10 -1
  39. package/dist/types/session/streaming-output.d.ts +5 -0
  40. package/dist/types/setup/credential-import.d.ts +79 -0
  41. package/dist/types/slash-commands/helpers/fast-status-report.d.ts +76 -0
  42. package/dist/types/task/executor.d.ts +1 -0
  43. package/dist/types/task/render.d.ts +1 -1
  44. package/dist/types/tools/bash.d.ts +1 -0
  45. package/dist/types/tools/browser/tab-supervisor.d.ts +9 -0
  46. package/dist/types/tools/sqlite-reader.d.ts +2 -1
  47. package/dist/types/tools/subagent-render.d.ts +7 -1
  48. package/dist/types/tools/subagent.d.ts +21 -0
  49. package/dist/types/tools/ultragoal-ask-guard.d.ts +5 -0
  50. package/dist/types/web/search/index.d.ts +4 -4
  51. package/dist/types/web/search/provider.d.ts +16 -20
  52. package/dist/types/web/search/providers/base.d.ts +2 -1
  53. package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
  54. package/dist/types/web/search/types.d.ts +14 -2
  55. package/package.json +7 -7
  56. package/scripts/build-binary.ts +7 -0
  57. package/src/async/job-manager.ts +153 -39
  58. package/src/cli/args.ts +2 -0
  59. package/src/cli/fast-help.ts +2 -0
  60. package/src/cli/setup-cli.ts +138 -3
  61. package/src/commands/setup.ts +5 -1
  62. package/src/commands/ultragoal.ts +3 -1
  63. package/src/config/file-lock-gc.ts +14 -2
  64. package/src/config/file-lock.ts +63 -13
  65. package/src/config/model-profile-activation.ts +15 -3
  66. package/src/config/model-profiles.ts +15 -15
  67. package/src/config/model-registry.ts +21 -1
  68. package/src/config/models-config-schema.ts +1 -0
  69. package/src/config/settings-schema.ts +62 -0
  70. package/src/dap/client.ts +105 -64
  71. package/src/dap/session.ts +44 -7
  72. package/src/defaults/gjc/skills/ultragoal/SKILL.md +30 -8
  73. package/src/edit/read-file.ts +19 -1
  74. package/src/eval/js/context-manager.ts +228 -65
  75. package/src/eval/js/executor.ts +2 -0
  76. package/src/eval/js/index.ts +1 -0
  77. package/src/eval/js/worker-core.ts +10 -6
  78. package/src/eval/py/executor.ts +68 -19
  79. package/src/eval/py/kernel.ts +46 -22
  80. package/src/eval/py/runner.py +68 -14
  81. package/src/exec/bash-executor.ts +49 -13
  82. package/src/gjc-runtime/deep-interview-recorder.ts +40 -0
  83. package/src/gjc-runtime/launch-tmux.ts +3 -4
  84. package/src/gjc-runtime/ralplan-runtime.ts +174 -12
  85. package/src/gjc-runtime/state-runtime.ts +2 -1
  86. package/src/gjc-runtime/state-writer.ts +254 -7
  87. package/src/gjc-runtime/tmux-gc.ts +88 -38
  88. package/src/gjc-runtime/tmux-sessions.ts +44 -6
  89. package/src/gjc-runtime/ultragoal-guard.ts +155 -0
  90. package/src/gjc-runtime/ultragoal-runtime.ts +1227 -31
  91. package/src/gjc-runtime/workflow-manifest.generated.json +44 -0
  92. package/src/gjc-runtime/workflow-manifest.ts +12 -0
  93. package/src/harness-control-plane/owner.ts +3 -2
  94. package/src/harness-control-plane/rpc-adapter.ts +1 -1
  95. package/src/hooks/skill-state.ts +121 -2
  96. package/src/internal-urls/artifact-protocol.ts +10 -1
  97. package/src/internal-urls/docs-index.generated.ts +14 -10
  98. package/src/lsp/client.ts +64 -26
  99. package/src/lsp/defaults.json +1 -0
  100. package/src/lsp/index.ts +2 -1
  101. package/src/lsp/lspmux.ts +33 -9
  102. package/src/lsp/types.ts +2 -0
  103. package/src/main.ts +14 -4
  104. package/src/modes/acp/acp-agent.ts +4 -2
  105. package/src/modes/bridge/bridge-mode.ts +23 -1
  106. package/src/modes/components/assistant-message.ts +10 -2
  107. package/src/modes/components/bash-execution.ts +5 -1
  108. package/src/modes/components/eval-execution.ts +5 -1
  109. package/src/modes/components/history-search.ts +5 -2
  110. package/src/modes/components/model-selector.ts +60 -2
  111. package/src/modes/components/oauth-selector.ts +5 -0
  112. package/src/modes/components/provider-onboarding-selector.ts +6 -1
  113. package/src/modes/components/runtime-mcp-add-wizard.ts +58 -7
  114. package/src/modes/components/skill-message.ts +24 -16
  115. package/src/modes/components/tool-execution.ts +6 -0
  116. package/src/modes/controllers/extension-ui-controller.ts +33 -6
  117. package/src/modes/controllers/input-controller.ts +5 -0
  118. package/src/modes/controllers/selector-controller.ts +86 -2
  119. package/src/modes/interactive-mode.ts +11 -1
  120. package/src/modes/rpc/rpc-mode.ts +132 -18
  121. package/src/modes/shared/agent-wire/command-dispatch.ts +5 -2
  122. package/src/modes/shared/agent-wire/host-tool-bridge.ts +3 -0
  123. package/src/modes/shared/agent-wire/unattended-session.ts +16 -1
  124. package/src/modes/theme/defaults/claude-code.json +100 -0
  125. package/src/modes/theme/defaults/codex.json +100 -0
  126. package/src/modes/theme/defaults/index.ts +6 -0
  127. package/src/modes/theme/defaults/opencode.json +102 -0
  128. package/src/modes/theme/theme.ts +2 -2
  129. package/src/modes/types.ts +1 -1
  130. package/src/modes/utils/ui-helpers.ts +5 -2
  131. package/src/prompts/agents/executor.md +5 -2
  132. package/src/runtime/process-lifecycle.ts +400 -0
  133. package/src/runtime-mcp/manager.ts +164 -50
  134. package/src/runtime-mcp/transports/http.ts +12 -11
  135. package/src/runtime-mcp/transports/stdio.ts +64 -38
  136. package/src/runtime-mcp/types.ts +3 -0
  137. package/src/sdk.ts +39 -1
  138. package/src/session/agent-session.ts +190 -33
  139. package/src/session/artifacts.ts +17 -2
  140. package/src/session/blob-store.ts +36 -2
  141. package/src/session/history-storage.ts +32 -11
  142. package/src/session/session-manager.ts +99 -31
  143. package/src/session/streaming-output.ts +54 -3
  144. package/src/setup/credential-import.ts +429 -0
  145. package/src/skill-state/deep-interview-mutation-guard.ts +2 -1
  146. package/src/slash-commands/builtin-registry.ts +30 -3
  147. package/src/slash-commands/helpers/fast-status-report.ts +111 -0
  148. package/src/task/executor.ts +7 -1
  149. package/src/task/render.ts +18 -7
  150. package/src/tools/archive-reader.ts +10 -1
  151. package/src/tools/ask.ts +4 -2
  152. package/src/tools/bash.ts +11 -4
  153. package/src/tools/browser/tab-supervisor.ts +22 -0
  154. package/src/tools/browser.ts +38 -4
  155. package/src/tools/cron.ts +1 -1
  156. package/src/tools/read.ts +11 -12
  157. package/src/tools/sqlite-reader.ts +19 -5
  158. package/src/tools/subagent-render.ts +119 -29
  159. package/src/tools/subagent.ts +147 -7
  160. package/src/tools/ultragoal-ask-guard.ts +39 -0
  161. package/src/web/search/index.ts +25 -25
  162. package/src/web/search/provider.ts +178 -87
  163. package/src/web/search/providers/base.ts +2 -1
  164. package/src/web/search/providers/openai-compatible.ts +151 -0
  165. package/src/web/search/types.ts +47 -22
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import type { ExtensionUIContext, ExtensionUIDialogOptions } from "../../extensibility/extensions";
14
14
  import type { AgentSession } from "../../session/agent-session";
15
- import type { RpcExtensionUIRequest, RpcExtensionUIResponse, RpcHostToolCallRequest, RpcHostToolCancelRequest, RpcHostUriCancelRequest, RpcHostUriRequest, RpcResponse } from "./rpc-types";
15
+ import type { RpcCommand, RpcExtensionUIRequest, RpcExtensionUIResponse, RpcHostToolCallRequest, RpcHostToolCancelRequest, RpcHostUriCancelRequest, RpcHostUriRequest, RpcResponse } from "./rpc-types";
16
16
  export type * from "./rpc-types";
17
17
  export type PendingExtensionRequest = {
18
18
  resolve: (response: RpcExtensionUIResponse) => void;
@@ -20,6 +20,61 @@ export type PendingExtensionRequest = {
20
20
  };
21
21
  type RpcOutput = (obj: RpcResponse | RpcExtensionUIRequest | RpcHostToolCallRequest | RpcHostToolCancelRequest | RpcHostUriRequest | RpcHostUriCancelRequest | object) => void;
22
22
  export declare function shouldEmitRpcTitlesForTest(): boolean;
23
+ /**
24
+ * Cancellation commands bypass the ordered serial chain because they must
25
+ * interrupt in-flight work — they cannot wait behind the very command they are
26
+ * meant to abort.
27
+ */
28
+ export declare const RPC_CANCELLATION_COMMANDS: ReadonlySet<RpcCommand["type"]>;
29
+ /**
30
+ * Safe read-only commands that bypass the ordered serial chain so they never
31
+ * head-of-line-block behind a long-running ordered command like
32
+ * `bash`/`compact`/`handoff`/`login` (#606, issue 13 — the partial fix only
33
+ * fast-laned cancellation).
34
+ *
35
+ * Every command listed here has a dispatch handler that is **fully synchronous
36
+ * and side-effect-free**: on the single-threaded event loop it runs to
37
+ * completion between the await points of any in-flight ordered command, reading
38
+ * live state without mutating it. Because such a read performs no causal write,
39
+ * jumping ahead of an earlier *queued* ordered command is observably harmless —
40
+ * there is no state change to reorder. Read payloads are additionally
41
+ * snapshotted inside the handler (e.g. `get_messages` returns a shallow copy of
42
+ * `session.messages`) so a fast-lane read can never serialize a half-mutated
43
+ * array that an ordered turn/compaction is rewriting in place.
44
+ *
45
+ * Deliberately excluded (kept ordered): every async/long command and every
46
+ * mutating command. In particular the control-flag setters (`set_thinking_level`,
47
+ * `cycle_thinking_level`, `set_steering_mode`, `set_follow_up_mode`,
48
+ * `set_interrupt_mode`, `set_auto_compaction`, `set_auto_retry`) stay ordered.
49
+ * Their handlers are synchronous, so fast-laning one ahead of an already-queued
50
+ * `prompt`/`bash` would apply the new mode *before* that earlier command runs —
51
+ * the earlier command would then observe the later setter's value, a
52
+ * causal-order (arrival-order) regression. Mutations therefore stay on the
53
+ * chain, and new command types default to ordered (fail-safe).
54
+ */
55
+ export declare const RPC_SAFE_READ_CONTROL_COMMANDS: ReadonlySet<RpcCommand["type"]>;
56
+ /** True when a command may bypass the ordered serial chain and run immediately. */
57
+ export declare function isFastLaneRpcCommand(type: RpcCommand["type"]): boolean;
58
+ /**
59
+ * Schedules inbound RPC commands: fast-lane commands run immediately while
60
+ * everything else runs through a serial chain so causal order is preserved. The
61
+ * read loop never blocks, which is what lets a fast-lane command reach a
62
+ * long-running ordered command instead of being head-of-line-blocked behind it.
63
+ */
64
+ export declare function createRpcCommandScheduler(run: (command: RpcCommand) => Promise<void>, track: (task: Promise<void>) => void): {
65
+ dispatch: (command: RpcCommand) => void;
66
+ };
67
+ export declare class RpcListenRefusedError extends Error {
68
+ constructor(socketPath: string);
69
+ }
70
+ /**
71
+ * Probe whether a unix-domain socket path has a live server accepting
72
+ * connections. Returns `true` when a connection succeeds (a previous owner is
73
+ * still alive), and returns `false` only for known missing/stale endpoints
74
+ * (ENOENT / ECONNREFUSED). Unexpected probe failures fail closed as "alive" so
75
+ * `--listen` startup refuses to unlink a path it could not safely classify.
76
+ */
77
+ export declare function isUnixSocketAlive(socketPath: string): Promise<boolean>;
23
78
  export declare function requestRpcEditor(pendingRequests: Map<string, PendingExtensionRequest>, output: RpcOutput, title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
24
79
  promptStyle?: boolean;
25
80
  }): Promise<string | undefined>;
@@ -14,10 +14,20 @@
14
14
  * Also implements the dispatch-facing {@link RpcUnattendedControlPlane} so the
15
15
  * RPC server can route `negotiate_unattended` + `workflow_gate_response` here.
16
16
  */
17
+ import type { Model } from "@gajae-code/ai";
17
18
  import type { RpcCommand, RpcUnattendedAccepted, RpcUnattendedDeclaration, RpcWorkflowGate, RpcWorkflowGateResolution, RpcWorkflowGateResponse } from "../../rpc/rpc-types";
18
19
  import type { RpcUnattendedControlPlane } from "./command-dispatch";
19
20
  import { type UnattendedAbortHooks, type UnattendedAuditEvent, UnattendedRunController } from "./unattended-run-controller";
20
21
  import { type GateStore, type OpenGateInput } from "./workflow-gate-broker";
22
+ /**
23
+ * Derive an explicit `providerSupportsTokenCostMetrics` capability from the
24
+ * active model so unattended negotiation fails closed when token/cost usage
25
+ * cannot be accounted for (#606). Callers that omit a model — or whose model is
26
+ * configured to suppress streaming usage (`compat.supportsUsageInStreaming:
27
+ * false`) — get `false`, which the controller refuses with
28
+ * `unsupported_budget_metric`.
29
+ */
30
+ export declare function modelSupportsTokenCostMetrics(model: Model | undefined): boolean;
21
31
  /** Minimal surface a skill runtime / ask tool uses to emit a gate and await its answer. */
22
32
  export interface WorkflowGateEmitter {
23
33
  /** True only when unattended mode has been negotiated. */
@@ -125,6 +125,308 @@ export declare const defaultThemes: {
125
125
  };
126
126
  };
127
127
  };
128
+ "claude-code": {
129
+ $schema: string;
130
+ name: string;
131
+ vars: {
132
+ "bg": string;
133
+ "surface": string;
134
+ "surfaceSubtle": string;
135
+ "separator": string;
136
+ "fg": string;
137
+ "muted": string;
138
+ "dim": string;
139
+ "brandTerracotta": string;
140
+ "shimmerTerracotta": string;
141
+ "toolPink": string;
142
+ "lavender": string;
143
+ "autoAcceptPurple": string;
144
+ "successGreen": string;
145
+ "warningAmber": string;
146
+ "errorSoftRed": string;
147
+ "diffAddedBg": string;
148
+ "diffRemovedBg": string;
149
+ "diffRemovedFg": string;
150
+ };
151
+ colors: {
152
+ "accent": string;
153
+ "border": string;
154
+ "borderAccent": string;
155
+ "borderMuted": string;
156
+ "success": string;
157
+ "error": string;
158
+ "warning": string;
159
+ "muted": string;
160
+ "dim": string;
161
+ "text": string;
162
+ "thinkingText": string;
163
+ "selectedBg": string;
164
+ "userMessageBg": string;
165
+ "userMessageText": string;
166
+ "customMessageBg": string;
167
+ "customMessageText": string;
168
+ "customMessageLabel": string;
169
+ "toolPendingBg": string;
170
+ "toolSuccessBg": string;
171
+ "toolErrorBg": string;
172
+ "toolTitle": string;
173
+ "toolOutput": string;
174
+ "mdHeading": string;
175
+ "mdLink": string;
176
+ "mdLinkUrl": string;
177
+ "mdCode": string;
178
+ "mdCodeBlock": string;
179
+ "mdCodeBlockBorder": string;
180
+ "mdQuote": string;
181
+ "mdQuoteBorder": string;
182
+ "mdHr": string;
183
+ "mdListBullet": string;
184
+ "toolDiffAdded": string;
185
+ "toolDiffRemoved": string;
186
+ "toolDiffContext": string;
187
+ "syntaxComment": string;
188
+ "syntaxKeyword": string;
189
+ "syntaxFunction": string;
190
+ "syntaxVariable": string;
191
+ "syntaxString": string;
192
+ "syntaxNumber": string;
193
+ "syntaxType": string;
194
+ "syntaxOperator": string;
195
+ "syntaxPunctuation": string;
196
+ "thinkingOff": string;
197
+ "thinkingMinimal": string;
198
+ "thinkingLow": string;
199
+ "thinkingMedium": string;
200
+ "thinkingHigh": string;
201
+ "thinkingXhigh": string;
202
+ "bashMode": string;
203
+ "pythonMode": string;
204
+ "statusLineBg": string;
205
+ "statusLineSep": string;
206
+ "statusLineModel": string;
207
+ "statusLinePath": string;
208
+ "statusLineGitClean": string;
209
+ "statusLineGitDirty": string;
210
+ "statusLineContext": string;
211
+ "statusLineSpend": string;
212
+ "statusLineStaged": string;
213
+ "statusLineDirty": string;
214
+ "statusLineUntracked": string;
215
+ "statusLineOutput": string;
216
+ "statusLineCost": string;
217
+ "statusLineSubagents": string;
218
+ };
219
+ export: {
220
+ "pageBg": string;
221
+ "cardBg": string;
222
+ "infoBg": string;
223
+ };
224
+ symbols: {
225
+ "preset": string;
226
+ };
227
+ };
228
+ codex: {
229
+ $schema: string;
230
+ name: string;
231
+ vars: {
232
+ "bg": string;
233
+ "surface": string;
234
+ "surfaceBright": string;
235
+ "selection": string;
236
+ "fg": string;
237
+ "muted": string;
238
+ "dim": string;
239
+ "borderNeutral": string;
240
+ "ansiCyan": string;
241
+ "cyanSoft": string;
242
+ "brandMagenta": string;
243
+ "magentaSoft": string;
244
+ "successGreen": string;
245
+ "errorRed": string;
246
+ "warningOrange": string;
247
+ "diffRemovalRed": string;
248
+ "toolSuccessBg": string;
249
+ "toolErrorBg": string;
250
+ };
251
+ colors: {
252
+ "accent": string;
253
+ "border": string;
254
+ "borderAccent": string;
255
+ "borderMuted": string;
256
+ "success": string;
257
+ "error": string;
258
+ "warning": string;
259
+ "muted": string;
260
+ "dim": string;
261
+ "text": string;
262
+ "thinkingText": string;
263
+ "selectedBg": string;
264
+ "userMessageBg": string;
265
+ "userMessageText": string;
266
+ "customMessageBg": string;
267
+ "customMessageText": string;
268
+ "customMessageLabel": string;
269
+ "toolPendingBg": string;
270
+ "toolSuccessBg": string;
271
+ "toolErrorBg": string;
272
+ "toolTitle": string;
273
+ "toolOutput": string;
274
+ "mdHeading": string;
275
+ "mdLink": string;
276
+ "mdLinkUrl": string;
277
+ "mdCode": string;
278
+ "mdCodeBlock": string;
279
+ "mdCodeBlockBorder": string;
280
+ "mdQuote": string;
281
+ "mdQuoteBorder": string;
282
+ "mdHr": string;
283
+ "mdListBullet": string;
284
+ "toolDiffAdded": string;
285
+ "toolDiffRemoved": string;
286
+ "toolDiffContext": string;
287
+ "syntaxComment": string;
288
+ "syntaxKeyword": string;
289
+ "syntaxFunction": string;
290
+ "syntaxVariable": string;
291
+ "syntaxString": string;
292
+ "syntaxNumber": string;
293
+ "syntaxType": string;
294
+ "syntaxOperator": string;
295
+ "syntaxPunctuation": string;
296
+ "thinkingOff": string;
297
+ "thinkingMinimal": string;
298
+ "thinkingLow": string;
299
+ "thinkingMedium": string;
300
+ "thinkingHigh": string;
301
+ "thinkingXhigh": string;
302
+ "bashMode": string;
303
+ "pythonMode": string;
304
+ "statusLineBg": string;
305
+ "statusLineSep": string;
306
+ "statusLineModel": string;
307
+ "statusLinePath": string;
308
+ "statusLineGitClean": string;
309
+ "statusLineGitDirty": string;
310
+ "statusLineContext": string;
311
+ "statusLineSpend": string;
312
+ "statusLineStaged": string;
313
+ "statusLineDirty": string;
314
+ "statusLineUntracked": string;
315
+ "statusLineOutput": string;
316
+ "statusLineCost": string;
317
+ "statusLineSubagents": string;
318
+ };
319
+ export: {
320
+ "pageBg": string;
321
+ "cardBg": string;
322
+ "infoBg": string;
323
+ };
324
+ symbols: {
325
+ "preset": string;
326
+ };
327
+ };
328
+ opencode: {
329
+ $schema: string;
330
+ name: string;
331
+ vars: {
332
+ "background": string;
333
+ "currentLine": string;
334
+ "selection": string;
335
+ "backgroundDarker": string;
336
+ "foreground": string;
337
+ "comment": string;
338
+ "primary": string;
339
+ "secondary": string;
340
+ "accentPurple": string;
341
+ "errorRed": string;
342
+ "warningOrange": string;
343
+ "successGreen": string;
344
+ "infoCyan": string;
345
+ "emphasizedYellow": string;
346
+ "border": string;
347
+ "diffAdded": string;
348
+ "diffRemoved": string;
349
+ "diffContext": string;
350
+ "addedBg": string;
351
+ "removedBg": string;
352
+ };
353
+ colors: {
354
+ "accent": string;
355
+ "border": string;
356
+ "borderAccent": string;
357
+ "borderMuted": string;
358
+ "success": string;
359
+ "error": string;
360
+ "warning": string;
361
+ "muted": string;
362
+ "dim": string;
363
+ "text": string;
364
+ "thinkingText": string;
365
+ "selectedBg": string;
366
+ "userMessageBg": string;
367
+ "userMessageText": string;
368
+ "customMessageBg": string;
369
+ "customMessageText": string;
370
+ "customMessageLabel": string;
371
+ "toolPendingBg": string;
372
+ "toolSuccessBg": string;
373
+ "toolErrorBg": string;
374
+ "toolTitle": string;
375
+ "toolOutput": string;
376
+ "mdHeading": string;
377
+ "mdLink": string;
378
+ "mdLinkUrl": string;
379
+ "mdCode": string;
380
+ "mdCodeBlock": string;
381
+ "mdCodeBlockBorder": string;
382
+ "mdQuote": string;
383
+ "mdQuoteBorder": string;
384
+ "mdHr": string;
385
+ "mdListBullet": string;
386
+ "toolDiffAdded": string;
387
+ "toolDiffRemoved": string;
388
+ "toolDiffContext": string;
389
+ "syntaxComment": string;
390
+ "syntaxKeyword": string;
391
+ "syntaxFunction": string;
392
+ "syntaxVariable": string;
393
+ "syntaxString": string;
394
+ "syntaxNumber": string;
395
+ "syntaxType": string;
396
+ "syntaxOperator": string;
397
+ "syntaxPunctuation": string;
398
+ "thinkingOff": string;
399
+ "thinkingMinimal": string;
400
+ "thinkingLow": string;
401
+ "thinkingMedium": string;
402
+ "thinkingHigh": string;
403
+ "thinkingXhigh": string;
404
+ "bashMode": string;
405
+ "pythonMode": string;
406
+ "statusLineBg": string;
407
+ "statusLineSep": string;
408
+ "statusLineModel": string;
409
+ "statusLinePath": string;
410
+ "statusLineGitClean": string;
411
+ "statusLineGitDirty": string;
412
+ "statusLineContext": string;
413
+ "statusLineSpend": string;
414
+ "statusLineStaged": string;
415
+ "statusLineDirty": string;
416
+ "statusLineUntracked": string;
417
+ "statusLineOutput": string;
418
+ "statusLineCost": string;
419
+ "statusLineSubagents": string;
420
+ };
421
+ export: {
422
+ "pageBg": string;
423
+ "cardBg": string;
424
+ "infoBg": string;
425
+ };
426
+ symbols: {
427
+ "preset": string;
428
+ };
429
+ };
128
430
  "red-claw": {
129
431
  $schema: string;
130
432
  name: string;
@@ -8,6 +8,7 @@ export type SymbolPreset = "unicode" | "nerd" | "ascii";
8
8
  */
9
9
  export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.folder" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.max" | "checkbox.checked" | "checkbox.unchecked" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.editing" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers";
10
10
  export type SpinnerType = "status" | "activity";
11
+ export declare const THEME_COLOR_KEYS: readonly ["accent", "border", "borderAccent", "borderMuted", "success", "error", "warning", "muted", "dim", "text", "thinkingText", "selectedBg", "userMessageBg", "userMessageText", "customMessageBg", "customMessageText", "customMessageLabel", "toolPendingBg", "toolSuccessBg", "toolErrorBg", "toolTitle", "toolOutput", "mdHeading", "mdLink", "mdLinkUrl", "mdCode", "mdCodeBlock", "mdCodeBlockBorder", "mdQuote", "mdQuoteBorder", "mdHr", "mdListBullet", "toolDiffAdded", "toolDiffRemoved", "toolDiffContext", "syntaxComment", "syntaxKeyword", "syntaxFunction", "syntaxVariable", "syntaxString", "syntaxNumber", "syntaxType", "syntaxOperator", "syntaxPunctuation", "thinkingOff", "thinkingMinimal", "thinkingLow", "thinkingMedium", "thinkingHigh", "thinkingXhigh", "bashMode", "pythonMode", "statusLineBg", "statusLineSep", "statusLineModel", "statusLinePath", "statusLineGitClean", "statusLineGitDirty", "statusLineContext", "statusLineSpend", "statusLineStaged", "statusLineDirty", "statusLineUntracked", "statusLineOutput", "statusLineCost", "statusLineSubagents"];
11
12
  export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "bashMode" | "pythonMode" | "statusLineSep" | "statusLineModel" | "statusLinePath" | "statusLineGitClean" | "statusLineGitDirty" | "statusLineContext" | "statusLineSpend" | "statusLineStaged" | "statusLineDirty" | "statusLineUntracked" | "statusLineOutput" | "statusLineCost" | "statusLineSubagents";
12
13
  /** Check if a string is a valid ThemeColor value */
13
14
  export declare function isValidThemeColor(color: string): color is ThemeColor;
@@ -93,7 +93,7 @@ export interface InteractiveModeContext {
93
93
  retryLoader: Loader | undefined;
94
94
  autoCompactionEscapeHandler?: () => void;
95
95
  retryEscapeHandler?: () => void;
96
- retryCountdownTimer?: ReturnType<typeof setInterval>;
96
+ retryCountdownTimer?: NodeJS.Timeout;
97
97
  unsubscribe?: () => void;
98
98
  onInputCallback?: (input: SubmittedUserInput) => void;
99
99
  optimisticUserMessageSignature: string | undefined;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Shared runtime lifecycle foundation.
3
+ *
4
+ * Two minimal, deliberately small primitives that subsystem runtimes
5
+ * (DAP/LSP/MCP stdio, eval workers, etc.) adopt so spawned children and
6
+ * non-process resources cannot outlive their owner:
7
+ *
8
+ * F1(a) `spawnOwnedProcess` — wraps `ptree.spawn` with explicit
9
+ * process-group ownership, escalating (SIGTERM -> grace -> SIGKILL)
10
+ * tree termination, bounded `awaitExit`, abort-listener cleanup on
11
+ * settle, idempotent `dispose`, and a single postmortem hook that
12
+ * reaps every still-live owned process group on fatal/normal shutdown.
13
+ *
14
+ * F1(b) `registerResourceOwner` — a generic, idempotent postmortem adapter
15
+ * for non-process resources (Bun Workers, VM contexts, timers,
16
+ * sockets) built on the existing `postmortem.register` facility.
17
+ *
18
+ * Ownership is keyed to the *process group*, not the root process. A root that
19
+ * exits after backgrounding descendants (`sh -c "worker & exit 0"`) keeps the
20
+ * owner registered until the group is actually gone, so the descendant tree is
21
+ * still reaped by `dispose()`/postmortem.
22
+ *
23
+ * This module intentionally owns only these primitives. It does not migrate
24
+ * existing call sites; subsystem PRs adopt it incrementally.
25
+ *
26
+ * Note: `ptree.spawn` always pipes stdout/stderr. Adopters that expect output
27
+ * (DAP/LSP/MCP protocol servers) must consume `owner.child.stdout`; F1 does not
28
+ * drain it, so a chatty child whose stdout is never read can still block on a
29
+ * full pipe. That draining is the adopter's responsibility.
30
+ */
31
+ import { ptree } from "@gajae-code/utils";
32
+ /** Options for {@link spawnOwnedProcess}. */
33
+ export interface SpawnOwnedOptions {
34
+ cwd?: string;
35
+ env?: Record<string, string | undefined>;
36
+ /** stdin mode passed through to the child. Defaults to `"ignore"`. */
37
+ stdin?: "pipe" | "ignore";
38
+ /** When aborted, the owned process tree is disposed (escalating kill). */
39
+ signal?: AbortSignal;
40
+ /** Grace period (ms) between SIGTERM and SIGKILL on dispose. Default 2000. */
41
+ gracefulMs?: number;
42
+ /**
43
+ * Spawn the child as its own process-group leader so the whole descendant
44
+ * tree can be signalled on dispose. Defaults to `true` on POSIX. Has no
45
+ * effect on Windows, where teardown falls back to single-process kill.
46
+ */
47
+ processGroup?: boolean;
48
+ /** Label used in diagnostics. */
49
+ name?: string;
50
+ }
51
+ /** Result of a bounded {@link OwnedProcess.awaitExit}. */
52
+ export interface AwaitExitResult {
53
+ /** `true` when the process has exited; `false` when the timeout fired first. */
54
+ exited: boolean;
55
+ /** Exit code if known, else `null`. */
56
+ code: number | null;
57
+ }
58
+ /** A spawned child process owned by the runtime with guaranteed teardown. */
59
+ export interface OwnedProcess {
60
+ readonly child: ptree.ChildProcess;
61
+ readonly pid: number | undefined;
62
+ /** Resolves/rejects when the root child exits (mirrors ptree's `exited`). */
63
+ readonly exited: Promise<number>;
64
+ /** `true` once `dispose()` has started. */
65
+ readonly disposed: boolean;
66
+ /**
67
+ * Wait for the root child to exit, optionally bounded by `timeoutMs`. With no
68
+ * timeout it resolves only when the child exits. Never rejects.
69
+ */
70
+ awaitExit(opts?: {
71
+ timeoutMs?: number;
72
+ }): Promise<AwaitExitResult>;
73
+ /**
74
+ * Idempotently terminate the owned process *group*: SIGTERM the group, wait
75
+ * `gracefulMs`, then SIGKILL, polling group liveness throughout. Removes the
76
+ * abort listener and deregisters from the live-owner set only after teardown
77
+ * has completed. Repeated/concurrent calls return the same in-flight promise.
78
+ */
79
+ dispose(): Promise<void>;
80
+ }
81
+ /**
82
+ * Spawn a child process owned by the runtime. The returned {@link OwnedProcess}
83
+ * is registered for postmortem cleanup and tears down its whole process group
84
+ * on dispose/abort.
85
+ */
86
+ export declare function spawnOwnedProcess(cmd: string[], opts?: SpawnOwnedOptions): OwnedProcess;
87
+ /** Number of currently live owned processes. Exposed for leak assertions/tests. */
88
+ export declare function liveOwnedProcessCount(): number;
89
+ /** Dispose every live owned process. For owner-scoped teardown and tests. */
90
+ export declare function disposeAllOwnedProcesses(): Promise<void>;
91
+ type ResourceDisposer = () => void | Promise<void>;
92
+ /**
93
+ * Register a non-process resource for postmortem/fatal-exit cleanup.
94
+ *
95
+ * Idempotent by `name`: re-registering the same name replaces the prior
96
+ * disposer (last wins). Returns an unregister function that removes the owner
97
+ * only while it is still the active registration for that name.
98
+ */
99
+ export declare function registerResourceOwner(name: string, disposer: ResourceDisposer): () => void;
100
+ /** Number of registered resource owners. Exposed for leak assertions/tests. */
101
+ export declare function resourceOwnerCount(): number;
102
+ /**
103
+ * Run and clear every registered resource disposer. Attempts all disposers even
104
+ * if some throw, then surfaces the failures as an `AggregateError` so callers
105
+ * can distinguish "all closed" from "a resource may still be alive".
106
+ */
107
+ export declare function disposeAllResourceOwners(): Promise<void>;
108
+ export {};
@@ -14,6 +14,7 @@ export declare class StdioTransport implements MCPTransport {
14
14
  onRequest?: (method: string, params: unknown) => Promise<unknown>;
15
15
  constructor(config: MCPStdioServerConfig);
16
16
  get connected(): boolean;
17
+ get closeBeforeReconnect(): true;
17
18
  /**
18
19
  * Start the subprocess and begin reading.
19
20
  */
@@ -185,6 +185,8 @@ export interface MCPTransport {
185
185
  notify(method: string, params?: Record<string, unknown>): Promise<void>;
186
186
  /** Close the transport */
187
187
  close(): Promise<void>;
188
+ /** Whether close must finish before reconnect can safely spawn a replacement. */
189
+ readonly closeBeforeReconnect?: boolean;
188
190
  /** Whether the transport is connected */
189
191
  readonly connected: boolean;
190
192
  /** Event handlers */
@@ -13,7 +13,7 @@
13
13
  * Modes use this class and add their own I/O layer on top.
14
14
  */
15
15
  import { type Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, type StablePrefixSnapshot, ThinkingLevel } from "@gajae-code/agent-core";
16
- import { type CompactionResult } from "@gajae-code/agent-core/compaction";
16
+ import { type CompactionResult, type EmergencyCompactionSample } from "@gajae-code/agent-core/compaction";
17
17
  import type { AssistantMessage, Effort, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@gajae-code/ai";
18
18
  export interface ForkContextSeedMetadata {
19
19
  sourceSessionId: string;
@@ -726,6 +726,20 @@ export declare class AgentSession {
726
726
  * {@link isFastModeActive} instead — that one respects the model's provider.
727
727
  */
728
728
  isFastModeEnabled(): boolean;
729
+ /**
730
+ * True when the configured `serviceTier` resolves to `"priority"` for the
731
+ * given model `provider`. Returns false for scoped tiers that don't match
732
+ * (e.g. `"openai-only"` on an anthropic provider) and when `provider` is
733
+ * undefined. This is the canonical provider-aware fast-mode predicate.
734
+ */
735
+ isFastForProvider(provider?: string): boolean;
736
+ /**
737
+ * Provider-aware fast-mode predicate for task-tool subagent roles, evaluated
738
+ * against the effective subagent tier (`task.serviceTier`) rather than the
739
+ * main session tier. Use this for `task.agentModelOverrides` role rows so the
740
+ * ⚡ glyph reflects the tier the subagent actually runs under.
741
+ */
742
+ isFastForSubagentProvider(provider?: string): boolean;
729
743
  /**
730
744
  * True when the configured `serviceTier` resolves to `"priority"` for the
731
745
  * *currently selected model's provider*. Returns false for scoped tiers
@@ -789,6 +803,8 @@ export declare class AgentSession {
789
803
  */
790
804
  handoff(customInstructions?: string, options?: SessionHandoffOptions): Promise<HandoffResult | undefined>;
791
805
  prepareContributionPrep(options?: ContributionPrepOptions): Promise<ContributionPrepResult>;
806
+ /** Test seam: override the emergency-compaction resource sampler so tests never read real RSS. */
807
+ setResourceSampler(sampler: () => EmergencyCompactionSample): void;
792
808
  /**
793
809
  * Toggle auto-compaction setting.
794
810
  */
@@ -1,3 +1,6 @@
1
+ export interface ArtifactSaveOptions {
2
+ maxBytes?: number;
3
+ }
1
4
  /**
2
5
  * Manages artifact storage for a session.
3
6
  *
@@ -40,7 +43,7 @@ export declare class ArtifactManager {
40
43
  * @param toolType Tool name for file extension (e.g., "bash", "read")
41
44
  * @returns Artifact ID (numeric string)
42
45
  */
43
- save(content: string, toolType: string): Promise<string>;
46
+ save(content: string, toolType: string, options?: ArtifactSaveOptions): Promise<string>;
44
47
  /**
45
48
  * Check if an artifact exists.
46
49
  * @param id Artifact ID (numeric string)
@@ -11,6 +11,6 @@ export declare class HistoryStorage {
11
11
  /** @internal Reset the singleton — test-only. */
12
12
  static resetInstance(): void;
13
13
  add(prompt: string, cwd?: string): Promise<void>;
14
- getRecent(limit: number): HistoryEntry[];
15
- search(query: string, limit: number): HistoryEntry[];
14
+ getRecent(limit: number, cwd?: string): HistoryEntry[];
15
+ search(query: string, limit: number, cwd?: string): HistoryEntry[];
16
16
  }
@@ -1,7 +1,7 @@
1
1
  import type { AgentMessage } from "@gajae-code/agent-core";
2
2
  import type { ImageContent, Message, MessageAttribution, ServiceTier, TextContent } from "@gajae-code/ai";
3
3
  import { ArtifactManager } from "./artifacts";
4
- import { type BlobPutResult } from "./blob-store";
4
+ import { type BlobPutResult, BlobStore } from "./blob-store";
5
5
  import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages";
6
6
  import type { SessionStorage } from "./session-storage";
7
7
  export declare const CURRENT_SESSION_VERSION = 3;
@@ -234,6 +234,15 @@ declare class RecentSessionInfo {
234
234
  export declare function recoverOrphanedBackups(sessionDir: string, storage: SessionStorage): Promise<void>;
235
235
  /** Exported for testing */
236
236
  export declare function findMostRecentSession(sessionDir: string, storage?: SessionStorage): Promise<string | null>;
237
+ declare const RESIDENT_BLOB_SENTINEL_KEY = "__gjcResidentBlob";
238
+ type ResidentBlobKind = "text" | "imageUrl" | "imageData";
239
+ interface ResidentBlobSentinel {
240
+ [RESIDENT_BLOB_SENTINEL_KEY]: true;
241
+ kind: ResidentBlobKind;
242
+ ref: string;
243
+ }
244
+ export declare function residentBlobSentinelForTests(kind: ResidentBlobKind, ref: string): ResidentBlobSentinel;
245
+ export declare function materializeResidentEntriesForPersistenceForTests<T>(entries: T[], textStore: BlobStore, imageStore?: BlobStore): T[];
237
246
  /** Get recent sessions for display in welcome screen */
238
247
  export declare function getRecentSessions(sessionDir: string, limit?: number, storage?: SessionStorage): Promise<RecentSessionInfo[]>;
239
248
  /**