@gajae-code/coding-agent 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/dist/types/async/job-manager.d.ts +17 -3
  3. package/dist/types/config/settings-schema.d.ts +56 -2
  4. package/dist/types/exa/mcp-client.d.ts +10 -1
  5. package/dist/types/exec/bash-executor.d.ts +45 -12
  6. package/dist/types/extensibility/extensions/types.d.ts +16 -2
  7. package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
  8. package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
  9. package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
  10. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
  11. package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
  12. package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
  13. package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
  14. package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
  15. package/dist/types/gjc-runtime/ralplan-review-conflicts.d.ts +114 -0
  16. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +23 -3
  17. package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
  18. package/dist/types/gjc-runtime/team-runtime.d.ts +25 -0
  19. package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
  20. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +10 -0
  21. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +37 -80
  22. package/dist/types/modes/acp/acp-agent.d.ts +2 -19
  23. package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
  24. package/dist/types/modes/components/irc-sidebar.d.ts +16 -0
  25. package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
  26. package/dist/types/modes/components/session-observer-overlay.d.ts +18 -0
  27. package/dist/types/modes/components/settings-selector.d.ts +9 -0
  28. package/dist/types/modes/components/status-line/gh.d.ts +5 -0
  29. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
  30. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  31. package/dist/types/modes/controllers/event-controller.d.ts +1 -1
  32. package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -1
  33. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  34. package/dist/types/modes/interactive-mode.d.ts +9 -0
  35. package/dist/types/modes/theme/theme.d.ts +3 -1
  36. package/dist/types/modes/types.d.ts +32 -0
  37. package/dist/types/reminders/star-reminder.d.ts +3 -13
  38. package/dist/types/runtime-mcp/manager.d.ts +1 -0
  39. package/dist/types/sdk/acp/adapter.d.ts +3 -1
  40. package/dist/types/sdk/broker/transport.d.ts +2 -0
  41. package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
  42. package/dist/types/sdk/bus/chat-daemon-control.d.ts +5 -1
  43. package/dist/types/sdk/bus/config.d.ts +6 -2
  44. package/dist/types/sdk/bus/index.d.ts +29 -0
  45. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +8 -1
  46. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  47. package/dist/types/sdk/bus/reconciliation-store.d.ts +7 -3
  48. package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
  49. package/dist/types/sdk/bus/rich-render.d.ts +2 -0
  50. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
  51. package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
  52. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -4
  53. package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
  54. package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
  55. package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
  56. package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
  57. package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
  58. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  59. package/dist/types/sdk/prompt-status.d.ts +23 -3
  60. package/dist/types/sdk/session.d.ts +6 -0
  61. package/dist/types/session/agent-session.d.ts +40 -2
  62. package/dist/types/session/artifacts.d.ts +8 -0
  63. package/dist/types/session/blob-store.d.ts +57 -4
  64. package/dist/types/session/internal/managed-session-storage.d.ts +30 -4
  65. package/dist/types/session/session-manager.d.ts +23 -6
  66. package/dist/types/session/session-storage.d.ts +4 -0
  67. package/dist/types/session/streaming-output.d.ts +36 -7
  68. package/dist/types/setup/credential-import.d.ts +12 -0
  69. package/dist/types/skill-state/active-state.d.ts +12 -0
  70. package/dist/types/skill-state/workflow-hud.d.ts +6 -0
  71. package/dist/types/task/executor.d.ts +3 -2
  72. package/dist/types/task/index.d.ts +7 -1
  73. package/dist/types/task/output-manager.d.ts +1 -0
  74. package/dist/types/task/provider-retry-status.d.ts +8 -0
  75. package/dist/types/task/receipt.d.ts +9 -1
  76. package/dist/types/task/types.d.ts +23 -0
  77. package/dist/types/tools/ask-answer-registry.d.ts +2 -2
  78. package/dist/types/tools/bash-interactive.d.ts +4 -1
  79. package/dist/types/tools/bash.d.ts +3 -1
  80. package/dist/types/tools/image-gen.d.ts +4 -0
  81. package/dist/types/tools/index.d.ts +6 -0
  82. package/dist/types/tools/output-meta.d.ts +23 -2
  83. package/dist/types/tools/path-utils.d.ts +1 -0
  84. package/dist/types/tools/read.d.ts +0 -6
  85. package/dist/types/tools/review.d.ts +5 -7
  86. package/dist/types/tools/subagent.d.ts +2 -0
  87. package/dist/types/utils/gh.d.ts +13 -0
  88. package/dist/types/utils/image-resize.d.ts +1 -0
  89. package/dist/types/web/search/providers/kimi.d.ts +2 -0
  90. package/dist/types/web/search/providers/searxng.d.ts +7 -0
  91. package/dist/types/web/search/providers/xai.d.ts +2 -0
  92. package/package.json +10 -8
  93. package/scripts/acp-conformance-agent.ts +218 -0
  94. package/scripts/capture-gjc-bundle-settings.ts +306 -0
  95. package/scripts/dogfood-ralplan-review-conflicts.ts +272 -0
  96. package/scripts/generate-sdk-operation-inventory.ts +5 -0
  97. package/scripts/resident-memory-bench.ts +1341 -0
  98. package/scripts/run-acp-conformance.ts +290 -0
  99. package/src/async/job-manager.ts +99 -39
  100. package/src/cli/fast-help.ts +1 -1
  101. package/src/cli/plugin-cli.ts +176 -18
  102. package/src/commands/team.ts +19 -1
  103. package/src/config/file-lock.ts +11 -2
  104. package/src/config/settings-schema.ts +53 -2
  105. package/src/coordinator-mcp/question-gate-codec.ts +1 -1
  106. package/src/coordinator-mcp/server.ts +5 -12
  107. package/src/debug/index.ts +42 -17
  108. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -0
  109. package/src/defaults/gjc/skills/ralplan/SKILL.md +25 -20
  110. package/src/defaults/gjc/skills/team/SKILL.md +2 -0
  111. package/src/defaults/gjc/skills/ultragoal/SKILL.md +39 -26
  112. package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
  113. package/src/defaults/gjc-defaults.ts +4 -4
  114. package/src/exa/mcp-client.ts +12 -3
  115. package/src/exec/bash-executor.ts +144 -27
  116. package/src/extensibility/extensions/runner.ts +15 -0
  117. package/src/extensibility/extensions/types.ts +18 -1
  118. package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
  119. package/src/extensibility/gjc-plugins/index.ts +19 -2
  120. package/src/extensibility/gjc-plugins/installer.ts +189 -50
  121. package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
  122. package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
  123. package/src/extensibility/gjc-plugins/observability.ts +3 -3
  124. package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
  125. package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
  126. package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
  127. package/src/extensibility/gjc-plugins/schema.ts +84 -12
  128. package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
  129. package/src/extensibility/gjc-plugins/types.ts +141 -0
  130. package/src/extensibility/gjc-plugins/validation.ts +9 -0
  131. package/src/gjc-runtime/launch-tmux.ts +25 -6
  132. package/src/gjc-runtime/launch-worktree.ts +103 -1
  133. package/src/gjc-runtime/ledger-event-renderer.ts +1 -0
  134. package/src/gjc-runtime/managed-owner-admission.ts +1 -1
  135. package/src/gjc-runtime/ralplan-review-conflicts.ts +472 -0
  136. package/src/gjc-runtime/ralplan-runtime.ts +491 -27
  137. package/src/gjc-runtime/team-launch.ts +8 -0
  138. package/src/gjc-runtime/team-runtime.ts +140 -32
  139. package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
  140. package/src/gjc-runtime/tmux-owner-isolation.ts +10 -0
  141. package/src/gjc-runtime/tmux-sessions.ts +58 -13
  142. package/src/gjc-runtime/ultragoal-evidence.ts +6 -74
  143. package/src/gjc-runtime/ultragoal-runtime.ts +635 -612
  144. package/src/gjc-runtime/workflow-manifest.generated.json +37 -99
  145. package/src/gjc-runtime/workflow-manifest.ts +21 -70
  146. package/src/internal-urls/docs-index.generated.ts +16 -16
  147. package/src/modes/DESIGN.md +104 -0
  148. package/src/modes/acp/acp-agent.ts +298 -186
  149. package/src/modes/components/gjc-bundle-settings.ts +508 -0
  150. package/src/modes/components/irc-sidebar.ts +30 -1
  151. package/src/modes/components/notifications-settings-editor.ts +12 -1
  152. package/src/modes/components/oauth-selector.ts +68 -30
  153. package/src/modes/components/session-observer-overlay.ts +305 -86
  154. package/src/modes/components/settings-selector.ts +56 -5
  155. package/src/modes/components/status-line/gh.ts +16 -0
  156. package/src/modes/components/tool-status-header.ts +3 -15
  157. package/src/modes/components/transcript-viewer-overlay.ts +99 -24
  158. package/src/modes/controllers/command-controller.ts +42 -34
  159. package/src/modes/controllers/event-controller.ts +27 -16
  160. package/src/modes/controllers/extension-ui-controller.ts +193 -34
  161. package/src/modes/controllers/selector-controller.ts +160 -22
  162. package/src/modes/interactive-mode.ts +189 -62
  163. package/src/modes/jobs-observer.ts +1 -1
  164. package/src/modes/runtime-init.ts +3 -0
  165. package/src/modes/theme/theme.ts +11 -9
  166. package/src/modes/types.ts +88 -0
  167. package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
  168. package/src/prompts/system/eager-todo.md +8 -4
  169. package/src/prompts/system/system-prompt.md +11 -4
  170. package/src/prompts/tools/bash.md +5 -5
  171. package/src/prompts/tools/search-tool-bm25.md +5 -0
  172. package/src/prompts/tools/task.md +1 -1
  173. package/src/reminders/star-reminder.ts +4 -42
  174. package/src/runtime-mcp/manager.ts +19 -4
  175. package/src/sdk/acp/adapter.ts +22 -6
  176. package/src/sdk/broker/lifecycle.ts +18 -13
  177. package/src/sdk/broker/transport.ts +35 -3
  178. package/src/sdk/bus/attachment-registry.ts +5 -1
  179. package/src/sdk/bus/chat-daemon-cli.ts +4 -39
  180. package/src/sdk/bus/chat-daemon-control.ts +7 -3
  181. package/src/sdk/bus/config.ts +18 -2
  182. package/src/sdk/bus/index.ts +661 -126
  183. package/src/sdk/bus/kind-aware-reconciliation.ts +148 -73
  184. package/src/sdk/bus/lifecycle-commands.ts +4 -1
  185. package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
  186. package/src/sdk/bus/reconciliation-store.ts +95 -16
  187. package/src/sdk/bus/rich-draft.ts +1 -1
  188. package/src/sdk/bus/rich-render.ts +2 -2
  189. package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
  190. package/src/sdk/bus/telegram-cli.ts +33 -8
  191. package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
  192. package/src/sdk/bus/telegram-daemon-contract.ts +12 -4
  193. package/src/sdk/bus/telegram-daemon.ts +916 -23
  194. package/src/sdk/bus/telegram-reference.ts +40 -3
  195. package/src/sdk/bus/threaded-render.ts +48 -3
  196. package/src/sdk/bus/topic-registry.ts +20 -0
  197. package/src/sdk/host/query/revision-store.ts +36 -2
  198. package/src/sdk/host/reverse-leases.ts +44 -7
  199. package/src/sdk/prompt-status.ts +16 -3
  200. package/src/sdk/protocol/operation-inventory.generated.json +33 -0
  201. package/src/sdk/session.ts +89 -9
  202. package/src/session/agent-session.ts +844 -173
  203. package/src/session/artifacts.ts +22 -0
  204. package/src/session/auth-broker-config.ts +10 -3
  205. package/src/session/blob-store.ts +915 -24
  206. package/src/session/internal/managed-session-scope.ts +200 -111
  207. package/src/session/internal/managed-session-storage.ts +492 -62
  208. package/src/session/session-manager.ts +1614 -435
  209. package/src/session/session-storage.ts +38 -45
  210. package/src/session/streaming-output.ts +238 -68
  211. package/src/setup/credential-import.ts +75 -13
  212. package/src/skill-state/active-state.ts +32 -0
  213. package/src/skill-state/workflow-hud.ts +17 -0
  214. package/src/skill-state/workflow-mutation-guard.ts +496 -2
  215. package/src/task/executor.ts +122 -39
  216. package/src/task/index.ts +280 -45
  217. package/src/task/output-manager.ts +24 -14
  218. package/src/task/provider-retry-status.ts +16 -0
  219. package/src/task/receipt.ts +34 -8
  220. package/src/task/render.ts +6 -2
  221. package/src/task/types.ts +108 -0
  222. package/src/tools/ask-answer-registry.ts +12 -6
  223. package/src/tools/ask.ts +86 -55
  224. package/src/tools/ast-edit.ts +1 -0
  225. package/src/tools/ast-grep.ts +1 -0
  226. package/src/tools/bash-interactive.ts +8 -3
  227. package/src/tools/bash.ts +503 -60
  228. package/src/tools/find.ts +1 -0
  229. package/src/tools/image-gen.ts +29 -5
  230. package/src/tools/index.ts +6 -0
  231. package/src/tools/output-meta.ts +108 -14
  232. package/src/tools/path-utils.ts +3 -2
  233. package/src/tools/read.ts +18 -0
  234. package/src/tools/review.ts +5 -7
  235. package/src/tools/search.ts +1 -0
  236. package/src/tools/subagent-render.ts +6 -2
  237. package/src/tools/subagent.ts +6 -0
  238. package/src/tools/telegram-send.ts +6 -3
  239. package/src/utils/gh.ts +39 -0
  240. package/src/utils/image-resize.ts +3 -0
  241. package/src/web/search/providers/anthropic.ts +4 -4
  242. package/src/web/search/providers/kimi.ts +15 -5
  243. package/src/web/search/providers/searxng.ts +47 -4
  244. package/src/web/search/providers/xai.ts +7 -2
  245. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
  246. package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
  247. package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
@@ -1,4 +1,4 @@
1
- import { type SingleResult, type TaskToolDetails } from "./types";
1
+ import { type ReviewFindingsArtifactRef, type SingleResult, type TaskToolDetails } from "./types";
2
2
  export interface TaskRoi {
3
3
  tokens: number;
4
4
  contextTokens?: number;
@@ -29,6 +29,7 @@ export interface TaskResultReceipt {
29
29
  contextWindow?: number;
30
30
  modelOverride?: string | string[];
31
31
  modelSubstitutionWarning?: SingleResult["modelSubstitutionWarning"];
32
+ fastMode?: boolean;
32
33
  usage?: SingleResult["usage"];
33
34
  cost?: number;
34
35
  usageCostBreakdownComplete?: true;
@@ -37,6 +38,9 @@ export interface TaskResultReceipt {
37
38
  attempt: number;
38
39
  errorSummary: string;
39
40
  };
41
+ setupFailure?: {
42
+ summary: string;
43
+ };
40
44
  errorSummary?: string;
41
45
  abortSummary?: string;
42
46
  preview: string;
@@ -46,6 +50,8 @@ export interface TaskResultReceipt {
46
50
  sizeBytes: number;
47
51
  lineCount: number;
48
52
  sha256?: string;
53
+ /** Output remains readable for the parent session lifetime (and same-session descendants). */
54
+ durability?: "session";
49
55
  };
50
56
  outputUnavailable?: boolean;
51
57
  review?: {
@@ -55,6 +61,8 @@ export interface TaskResultReceipt {
55
61
  severity?: string;
56
62
  summary: string;
57
63
  }>;
64
+ /** Canonical full-fidelity findings; inline summaries are display-only. */
65
+ findingsRef?: ReviewFindingsArtifactRef;
58
66
  };
59
67
  extractedToolCounts?: Record<string, number>;
60
68
  forkContext?: SingleResult["forkContext"];
@@ -368,6 +368,13 @@ export interface ReviewFinding {
368
368
  line_start: number;
369
369
  line_end: number;
370
370
  }
371
+ /** Durable full-fidelity review findings artifact associated with a task result. */
372
+ export interface ReviewFindingsArtifactRef {
373
+ uri: `artifact://${string}`;
374
+ sizeBytes: number;
375
+ sha256: string;
376
+ findingCount: number;
377
+ }
371
378
  /** Review summary submitted by the reviewer agent */
372
379
  export interface ReviewSummary {
373
380
  overall_correctness: "correct" | "incorrect";
@@ -439,6 +446,8 @@ export interface AgentProgress {
439
446
  durationMs: number;
440
447
  modelOverride?: string | string[];
441
448
  modelSubstitutionWarning?: ModelSubstitutionWarning;
449
+ /** Whether the resolved subagent model runs under the effective fast service tier. */
450
+ fastMode?: boolean;
442
451
  /** Data extracted by registered subprocess tool handlers (keyed by tool name) */
443
452
  extractedToolData?: Record<string, unknown[]>;
444
453
  /**
@@ -469,6 +478,8 @@ export interface AgentProgress {
469
478
  attempt: number;
470
479
  errorMessage: string;
471
480
  };
481
+ /** Safe diagnostic retained in terminal progress when setup fails before the first LLM request. */
482
+ setupFailure?: SetupFailureSummary;
472
483
  /**
473
484
  * Snapshot of the most recent `task` tool call's in-flight `TaskToolDetails`,
474
485
  * captured from `tool_execution_update`. Lets the parent UI surface live
@@ -478,6 +489,12 @@ export interface AgentProgress {
478
489
  */
479
490
  inflightTaskDetails?: TaskToolDetails;
480
491
  }
492
+ /** Bounded diagnostic retained when subagent setup fails before an LLM request starts. */
493
+ export interface SetupFailureSummary {
494
+ summary: string;
495
+ }
496
+ /** Create a bounded diagnostic that preserves a setup failure's cause without exposing credentials or local paths. */
497
+ export declare function createSetupFailureSummary(error: unknown): SetupFailureSummary;
481
498
  /** Result from a single agent execution */
482
499
  export interface SingleResult {
483
500
  index: number;
@@ -501,7 +518,11 @@ export interface SingleResult {
501
518
  contextWindow?: number;
502
519
  modelOverride?: string | string[];
503
520
  modelSubstitutionWarning?: ModelSubstitutionWarning;
521
+ /** Whether the resolved subagent model ran under the effective fast service tier. */
522
+ fastMode?: boolean;
504
523
  error?: string;
524
+ /** Safe diagnostic for a failure before the subagent sent its first LLM request. */
525
+ setupFailure?: SetupFailureSummary;
505
526
  aborted?: boolean;
506
527
  abortReason?: string;
507
528
  paused?: boolean;
@@ -521,6 +542,8 @@ export interface SingleResult {
521
542
  producedChanges?: boolean;
522
543
  /** Data extracted by registered subprocess tool handlers (keyed by tool name) */
523
544
  extractedToolData?: Record<string, unknown[]>;
545
+ /** Full wrapper-owned review evidence, kept separate from caller completion data. */
546
+ reviewFindingsRef?: ReviewFindingsArtifactRef;
524
547
  /**
525
548
  * Terminal retry failure, when the subagent exited because the auto-retry
526
549
  * loop gave up (retry-after exceeded the cap, or all attempts exhausted).
@@ -8,9 +8,9 @@
8
8
  */
9
9
  import type { WorkflowGateEmitter } from "../modes/shared/agent-wire/workflow-gate-broker";
10
10
  import type { AskAnswerSource } from "./index";
11
- /** Register `source` for `sessionId`. Returns a disposer that clears it. */
11
+ /** Register `source` for `sessionId`. Returns a disposer that restores the prior source. */
12
12
  export declare function registerAskAnswerSource(sessionId: string, source: AskAnswerSource): () => void;
13
- /** The answer source for `sessionId`, if one is registered. */
13
+ /** The highest-priority answer source for `sessionId`, if one is registered. */
14
14
  export declare function getAskAnswerSource(sessionId: string): AskAnswerSource | undefined;
15
15
  /** Publish a session's current workflow-gate emitter after mode initialization. */
16
16
  export declare function notifyWorkflowGateEmitterChanged(sessionId: string, emitter: WorkflowGateEmitter | undefined): void;
@@ -1,5 +1,5 @@
1
1
  import type { AgentToolContext } from "@gajae-code/agent-core";
2
- import { type OutputSummary } from "../session/streaming-output";
2
+ import { type OutputSummary, type TerminalArtifactPublisher } from "../session/streaming-output";
3
3
  export interface BashInteractiveResult extends OutputSummary {
4
4
  exitCode: number | undefined;
5
5
  cancelled: boolean;
@@ -13,4 +13,7 @@ export declare function runInteractiveBashPty(ui: NonNullable<AgentToolContext["
13
13
  env?: Record<string, string>;
14
14
  artifactPath?: string;
15
15
  artifactId?: string;
16
+ artifactPublisher?: TerminalArtifactPublisher;
17
+ spillThreshold?: number;
18
+ headBytes?: number;
16
19
  }): Promise<BashInteractiveResult>;
@@ -1,12 +1,14 @@
1
1
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
2
2
  import type { Component } from "@gajae-code/tui";
3
3
  import * as z from "zod/v4";
4
+ import { type BashArtifactSaveResult } from "../exec/bash-executor";
4
5
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
5
6
  import { type Theme } from "../modes/theme/theme";
6
7
  import type { ToolSession } from ".";
7
8
  import { type OutputMeta } from "./output-meta";
8
9
  export declare const BASH_DEFAULT_PREVIEW_LINES = 10;
9
- export declare function saveBashOriginalArtifactForTests(session: ToolSession, originalText: string): Promise<string | undefined>;
10
+ export type BashOriginalArtifactSaveResult = BashArtifactSaveResult;
11
+ export declare function saveBashOriginalArtifactForTests(session: ToolSession, originalText: string, onResult?: (result: BashOriginalArtifactSaveResult) => void): Promise<string | undefined>;
10
12
  declare const bashSchemaBase: z.ZodObject<{
11
13
  command: z.ZodString;
12
14
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -134,7 +134,11 @@ export declare function setConfiguredImageModel(config: ImageProviderConfig | nu
134
134
  export declare function getConfiguredImageModel(): ImageProviderConfig | null;
135
135
  /** Resolve the effective image model for a configured provider */
136
136
  export declare function resolveImageModel(provider: string, modelOverride: string | null): string;
137
+ /** Test seam: the Google image key fallback as resolved from trusted env. */
138
+ export declare function googleImageApiKeyFromEnvForTest(): string | undefined;
137
139
  export declare function isOpenAIHostedImageModel(model: Model | undefined): model is Model;
140
+ /** Test seam: the image-request base URL as resolved from trusted env. */
141
+ export declare function getOpenAIImageBaseUrlForTest(model: Model, authCredentialType?: "api_key" | "oauth"): string;
138
142
  export declare const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails>;
139
143
  export declare function getImageGenTools(modelRegistry?: ModelRegistry, activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
140
144
  export declare function getImageGenToolsWithRegistry(modelRegistry: ModelRegistry, activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
@@ -215,8 +215,12 @@ export interface ToolSession {
215
215
  strictToolNames?: boolean;
216
216
  /** Get artifacts directory for artifact:// URLs */
217
217
  getArtifactsDir?: () => string | null;
218
+ /** Additional artifacts directories explicitly authorized for this session's tree (parent/child/sibling reads). Derived only from the explicitly adopted/shared `ArtifactManager`; never enumerates unrelated live sessions. */
219
+ getAuthorizedArtifactsDirs?: () => readonly string[];
218
220
  /** Get the ArtifactManager backing this session (shared across parent + subagents). */
219
221
  getArtifactManager?: () => ArtifactManager | null;
222
+ /** Register teardown work owned by the current logical session. */
223
+ registerSessionCleanup?: (cleanup: () => Promise<void> | void) => () => void;
220
224
  /** Allocate a new artifact path and ID for session-scoped truncated output. */
221
225
  allocateOutputArtifact?: (toolType: string) => Promise<{
222
226
  id?: string;
@@ -240,6 +244,8 @@ export interface ToolSession {
240
244
  settings: Settings;
241
245
  /** Live service-tier intent of the parent session, inherited by `inherit` subagents. */
242
246
  serviceTier?: ServiceTier;
247
+ /** Whether the effective subagent tier grants fast mode for a resolved provider. */
248
+ isFastForSubagentProvider?: (provider?: string) => boolean;
243
249
  /** Plan mode state (if active) */
244
250
  getPlanModeState?: () => PlanModeState | undefined;
245
251
  /** Goal mode state (if active or paused) */
@@ -46,8 +46,12 @@ export interface TruncationMeta {
46
46
  elidedBytes?: number;
47
47
  /** Lines elided from the middle. */
48
48
  elidedLines?: number;
49
- /** Artifact ID if full output was saved */
49
+ /** Artifact ID when output was persisted; completeness is tracked separately below. */
50
50
  artifactId?: string;
51
+ /** Bytes omitted from an artifact after its hard storage cap was reached. */
52
+ artifactTruncatedBytes?: number;
53
+ /** Bounded diagnostic when artifact writer creation, write, or finalization failed. */
54
+ artifactFailureDiagnostic?: string;
51
55
  /** Next offset for pagination (head truncation only) */
52
56
  nextOffset?: number;
53
57
  }
@@ -145,7 +149,7 @@ export declare class OutputMetaBuilder {
145
149
  maxBytes?: number;
146
150
  rangeBase?: "file" | "window";
147
151
  }): this;
148
- /** Add truncation info from OutputSummary. No-op if not truncated. */
152
+ /** Add truncation info from OutputSummary. No-op if not truncated or artifact evidence is absent. */
149
153
  truncationFromSummary(summary: OutputSummary, options: TruncationSummaryOptions): this;
150
154
  /** Add truncation info from truncated output text. No-op if truncation not detected. */
151
155
  truncationFromText(text: string, options: TruncationTextOptions): this;
@@ -178,6 +182,10 @@ export declare class OutputMetaBuilder {
178
182
  /** Create a new OutputMetaBuilder. */
179
183
  export declare function outputMeta(): OutputMetaBuilder;
180
184
  export declare function formatFullOutputReference(artifactId: string): string;
185
+ /**
186
+ * Format an artifact reference without claiming completeness when storage was hard-capped.
187
+ */
188
+ export declare function formatArtifactReference(artifactId: string, artifactTruncatedBytes?: number): string;
181
189
  export declare function formatTruncationMetaNotice(truncation: TruncationMeta): string;
182
190
  /**
183
191
  * Format styled artifact reference with warning color and brackets.
@@ -211,6 +219,19 @@ export declare function stripOutputNotice(text: string, meta: OutputMeta | undef
211
219
  * middle elision with the same per-user configuration.
212
220
  */
213
221
  export declare function resolveOutputSinkHeadBytes(s: Settings | undefined): number;
222
+ export declare const BASH_DEFAULT_OUTPUT_TAIL_BYTES = 1024;
223
+ /**
224
+ * Bash uses a deliberately small tail window to nudge callers toward focused
225
+ * commands and dedicated search tools. An explicitly configured shared tail
226
+ * budget still wins.
227
+ */
228
+ export declare function resolveBashOutputSinkTailBytes(s: Settings): number;
229
+ /**
230
+ * Bash keeps only the tail unless the user explicitly opts into the shared
231
+ * head-retention setting. Schema defaults still apply to other streaming
232
+ * tools without silently turning Bash back into middle-elision mode.
233
+ */
234
+ export declare function resolveBashOutputSinkHeadBytes(s: Settings): number;
214
235
  /**
215
236
  * Resolve the per-line column cap from session settings. Shared by streaming
216
237
  * executors (bash/python/ssh/eval via OutputSink) and the `read` tool's
@@ -112,6 +112,7 @@ export interface ToolScopeOptions {
112
112
  rawPaths: string[];
113
113
  cwd: string;
114
114
  getArtifactsDir?: () => string | null;
115
+ getAuthorizedArtifactsDirs?: () => readonly string[];
115
116
  /** Verb used in the "Cannot {action} internal URL without a backing file: …" message. */
116
117
  internalUrlAction: string;
117
118
  /** Collect absolute paths flagged immutable by their internal-URL handler. */
@@ -84,12 +84,6 @@ export interface ReadToolDetails {
84
84
  conflictCount?: number;
85
85
  }
86
86
  type ReadParams = ReadToolInput;
87
- /**
88
- * Read tool implementation.
89
- *
90
- * Reads files with support for images, converted documents (via markit), and text.
91
- * Directories return a formatted listing with modification times.
92
- */
93
87
  export declare class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
94
88
  #private;
95
89
  private readonly session;
@@ -50,14 +50,12 @@ export interface SubmitReviewDetails {
50
50
  }
51
51
  export type { ReportFindingDetails };
52
52
  /**
53
- * Coerce a tool-side `ReportFindingDetails` into the cross-boundary
54
- * `ReviewFinding` shape consumed by the reviewer agent's JTD output schema.
53
+ * Convert tool-side `ReportFindingDetails` into the numeric-priority
54
+ * `ReviewFinding` shape used by caller-owned reviewer payloads.
55
55
  *
56
56
  * The `report_finding` tool exposes `priority` as a string enum (`"P0".."P3"`)
57
- * for ergonomics, but the bundled reviewer schema (and every custom review
58
- * agent that mirrors it) declares `priority: number`. Without this coercion
59
- * the auto-populated `findings[]` fails JTD validation and every review run
60
- * that surfaces a finding is rejected with `findings.0.priority: expected
61
- * number, received string`.
57
+ * for ergonomics, while reviewer schemas may explicitly declare numeric
58
+ * priorities. This pure conversion does not add findings to completion data;
59
+ * callers that include `findings` own both that field and its output schema.
62
60
  */
63
61
  export declare function toReviewFinding(details: ReportFindingDetails): ReviewFinding;
@@ -38,6 +38,8 @@ export interface SubagentSnapshot {
38
38
  durationMs: number;
39
39
  resultText?: string;
40
40
  errorText?: string;
41
+ /** Safe setup failure cause retained from the executor launch path. */
42
+ setupFailureSummary?: string;
41
43
  resultPreview?: string;
42
44
  outputRef?: string;
43
45
  truncated?: boolean;
@@ -0,0 +1,13 @@
1
+ export interface GhResult {
2
+ exitCode: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ timedOut?: boolean;
6
+ }
7
+ export type RunGh = (args: string[], options?: {
8
+ timeoutMs?: number;
9
+ }) => Promise<GhResult>;
10
+ /** Run GitHub CLI without allowing it to consume the parent terminal's input. */
11
+ export declare function runGhDefault(args: string[], options?: {
12
+ timeoutMs?: number;
13
+ }): Promise<GhResult>;
@@ -5,6 +5,7 @@ export interface ImageResizeOptions {
5
5
  maxBytes?: number;
6
6
  jpegQuality?: number;
7
7
  excludeWebP?: boolean;
8
+ forceReencode?: boolean;
8
9
  }
9
10
  export interface ResizedImage {
10
11
  buffer: Uint8Array;
@@ -16,6 +16,8 @@ export interface KimiSearchParams {
16
16
  authStorage: AuthStorage;
17
17
  sessionId?: string;
18
18
  }
19
+ /** Test seam: the Kimi search base URL as resolved from trusted env. */
20
+ export declare function resolveKimiSearchBaseUrlForTest(): string;
19
21
  /** Execute Kimi web search. */
20
22
  export declare function searchKimi(params: KimiSearchParams): Promise<SearchResponse>;
21
23
  /** Search provider for Kimi web search. */
@@ -28,6 +28,13 @@ import type { AuthStorage } from "@gajae-code/ai";
28
28
  import type { SearchResponse } from "../../../web/search/types";
29
29
  import type { SearchParams } from "./base";
30
30
  import { SearchProvider } from "./base";
31
+ /** Test seam: the SearXNG endpoint and auth material as resolved from trusted env. */
32
+ export declare function resolveSearxngConfigForTest(): {
33
+ endpoint: string | null;
34
+ token: string | null;
35
+ basicUsername: string | null;
36
+ basicPassword: string | null;
37
+ };
31
38
  /** Execute SearXNG web search. */
32
39
  export declare function searchSearXNG(params: {
33
40
  query: string;
@@ -32,6 +32,8 @@ export interface XaiSearchParams {
32
32
  authStorage: AuthStorage;
33
33
  sessionId?: string;
34
34
  }
35
+ /** Test seam: the xAI search base URL as resolved from trusted env. */
36
+ export declare function resolveXaiSearchBaseUrlForTest(): string;
35
37
  export declare function buildXaiRequestBody(params: {
36
38
  query: string;
37
39
  systemPrompt: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.12.0",
4
+ "version": "0.12.2",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -53,13 +53,13 @@
53
53
  "@agentclientprotocol/sdk": "1.3.0",
54
54
  "@babel/parser": "^7.29.3",
55
55
  "@mozilla/readability": "^0.6.0",
56
- "@gajae-code/stats": "0.12.0",
57
- "@gajae-code/agent-core": "0.12.0",
58
- "@gajae-code/ai": "0.12.0",
59
- "@gajae-code/bridge-client": "0.12.0",
60
- "@gajae-code/natives": "0.12.0",
61
- "@gajae-code/tui": "0.12.0",
62
- "@gajae-code/utils": "0.12.0",
56
+ "@gajae-code/stats": "0.12.2",
57
+ "@gajae-code/agent-core": "0.12.2",
58
+ "@gajae-code/ai": "0.12.2",
59
+ "@gajae-code/bridge-client": "0.12.2",
60
+ "@gajae-code/natives": "0.12.2",
61
+ "@gajae-code/tui": "0.12.2",
62
+ "@gajae-code/utils": "0.12.2",
63
63
  "@puppeteer/browsers": "^2.13.0",
64
64
  "@types/turndown": "5.0.6",
65
65
  "@xterm/headless": "^6.0.0",
@@ -327,6 +327,8 @@
327
327
  "types": "./dist/types/export/html/*.d.ts",
328
328
  "import": "./src/export/html/*.ts"
329
329
  },
330
+ "./extensibility/gjc-plugins/installer": null,
331
+ "./extensibility/gjc-plugins/registry": null,
330
332
  "./extensibility/*": {
331
333
  "types": "./dist/types/extensibility/*.d.ts",
332
334
  "import": "./src/extensibility/*.ts"
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Credential-free ACP fixture launcher. The loopback endpoint is deliberately
5
+ * deterministic; the child remains the production `gjc --mode acp` surface.
6
+ */
7
+ import * as fs from "node:fs/promises";
8
+ import * as os from "node:os";
9
+ import * as path from "node:path";
10
+
11
+ const root = path.resolve(import.meta.dir, "..", "..", "..");
12
+ const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "gjc-acp-conformance-"));
13
+ let child: ReturnType<typeof Bun.spawn> | undefined;
14
+ let server: ReturnType<typeof Bun.serve> | undefined;
15
+
16
+ /**
17
+ * Deterministic replies for the pinned `acp-core-v1` corpus. Each branch mirrors one
18
+ * upstream case expectation; nothing here reaches the network.
19
+ */
20
+ function response(prompt: string): string {
21
+ if (prompt.includes("inspect-prompt")) return `received blocks: {"type":"resource"}`;
22
+ if (prompt.includes("this-command-does-not-exist")) return "unrecognized prompt";
23
+ if (/^\s*read\b/m.test(prompt)) return "read README.md: acpx";
24
+ if (/^\s*write\b/m.test(prompt)) {
25
+ const target = /write\s+(\S+)/.exec(prompt)?.[1] ?? "file";
26
+ return `wrote ${target}`;
27
+ }
28
+ const echo = /^\s*echo\s*(.*)$/m.exec(prompt);
29
+ if (echo) return echo[1] || "echo";
30
+ return "ok";
31
+ }
32
+
33
+ function sse(value: unknown): string {
34
+ return `data: ${JSON.stringify(value)}\n\n`;
35
+ }
36
+
37
+ function completion(delta: Record<string, unknown>, finishReason: string | null = null): string {
38
+ return sse({ id: "gjc-conformance", choices: [{ delta, finish_reason: finishReason }] });
39
+ }
40
+
41
+ function toolCall(name: "read" | "write", arguments_: Record<string, string>): string {
42
+ return completion(
43
+ {
44
+ tool_calls: [
45
+ {
46
+ index: 0,
47
+ id: `conformance-${name}`,
48
+ type: "function",
49
+ function: { name, arguments: JSON.stringify(arguments_) },
50
+ },
51
+ ],
52
+ },
53
+ "tool_calls",
54
+ );
55
+ }
56
+
57
+ function textCompletion(text: string): string {
58
+ return `${completion({ content: text })}${completion({}, "stop")}data: [DONE]\n\n`;
59
+ }
60
+
61
+ async function cleanup(code = 0): Promise<never> {
62
+ server?.stop(true);
63
+ if (child && child.exitCode === null) child.kill();
64
+ await fs.rm(agentDir, { recursive: true, force: true });
65
+ process.exit(code);
66
+ }
67
+
68
+ server = Bun.serve({
69
+ hostname: "127.0.0.1",
70
+ port: 0,
71
+ async fetch(request) {
72
+ const body = (await request.json().catch(() => ({}))) as {
73
+ messages?: Array<{ role?: string; content?: unknown }>;
74
+ };
75
+ // OpenAI-style content is either a plain string or an array of typed blocks.
76
+ const textOf = (content: unknown): string =>
77
+ typeof content === "string"
78
+ ? content
79
+ : Array.isArray(content)
80
+ ? content
81
+ .map(block =>
82
+ typeof block === "object" &&
83
+ block !== null &&
84
+ typeof (block as { text?: unknown }).text === "string"
85
+ ? (block as { text: string }).text
86
+ : "",
87
+ )
88
+ .join("")
89
+ : "";
90
+ const messages = body.messages ?? [];
91
+ const prompt =
92
+ [...messages]
93
+ .reverse()
94
+ .filter(message => message.role === "user")
95
+ .map(message => textOf(message.content))
96
+ .find(text => text.length > 0) ?? "";
97
+ const hasToolResult = messages.some(message => message.role === "tool");
98
+ const isRead = /^\s*read\b/m.test(prompt);
99
+ const isWrite = /^\s*write\b/m.test(prompt);
100
+ const isLateTool = prompt.includes("late-tool 40 follow-up");
101
+
102
+ if (prompt.includes("sleep")) {
103
+ const requested = Number(/\bsleep\s+(\d+)/.exec(prompt)?.[1] ?? 0);
104
+ const delay = Math.min(Math.max(requested, 0), 30_000);
105
+ const stream = new ReadableStream<Uint8Array>({
106
+ start(controller) {
107
+ let closed = false;
108
+ const close = () => {
109
+ if (closed) return;
110
+ closed = true;
111
+ controller.close();
112
+ };
113
+ request.signal.addEventListener("abort", close, { once: true });
114
+ void Bun.sleep(delay).then(() => {
115
+ if (closed) return;
116
+ controller.enqueue(new TextEncoder().encode(textCompletion("slept")));
117
+ close();
118
+ });
119
+ },
120
+ });
121
+ return new Response(stream, { headers: { "content-type": "text/event-stream" } });
122
+ }
123
+
124
+ if ((isRead || isWrite || isLateTool) && !hasToolResult) {
125
+ if (isLateTool) {
126
+ const prefix = `${completion({ content: "preparing" })}${completion({ content: " writing now" })}${completion({ content: " before tool" })}`;
127
+ return new Response(
128
+ `${prefix}${toolCall("write", { path: ".acpx-conformance-late.txt", content: "late" })}data: [DONE]\n\n`,
129
+ {
130
+ headers: { "content-type": "text/event-stream" },
131
+ },
132
+ );
133
+ }
134
+ // Neutral pre-tool text: every corpus assertion below must come from the real
135
+ // tool result, never from a marker announced before the tool ran.
136
+ const provisional = isRead ? "checking the requested file" : "applying the requested write";
137
+ return new Response(
138
+ `${completion({ content: provisional })}${toolCall(
139
+ isRead ? "read" : "write",
140
+ isRead
141
+ ? { path: "README.md" }
142
+ : {
143
+ path: /write\s+(\S+)/.exec(prompt)?.[1] ?? "file",
144
+ content: /write\s+\S+\s*(.*)/.exec(prompt)?.[1] ?? "",
145
+ },
146
+ )}data: [DONE]\n\n`,
147
+ { headers: { "content-type": "text/event-stream" } },
148
+ );
149
+ }
150
+
151
+ // Derive the reply from what the tool actually returned so a broken permission
152
+ // bridge, filesystem bridge, or tool result cannot still satisfy the corpus.
153
+ const toolText = messages
154
+ .filter(message => message.role === "tool")
155
+ .map(message => textOf(message.content))
156
+ .join("\n");
157
+ const toolDenied = /rejected by user|permission denied|not permitted/i.test(toolText);
158
+ const reply = toolDenied
159
+ ? `permission denied: ${toolText.slice(0, 200)}`
160
+ : isRead
161
+ ? `read README.md: ${toolText.trim().slice(0, 200)}`
162
+ : isWrite
163
+ ? `wrote ${/write\s+(\S+)/.exec(prompt)?.[1] ?? "file"}: ${toolText.trim().slice(0, 120)}`
164
+ : isLateTool
165
+ ? `writing now: ${toolText.trim().slice(0, 120)}`
166
+ : response(prompt);
167
+ return new Response(textCompletion(reply), { headers: { "content-type": "text/event-stream" } });
168
+ },
169
+ });
170
+
171
+ await Bun.write(
172
+ path.join(agentDir, "models.json"),
173
+ JSON.stringify({
174
+ providers: {
175
+ conformance: {
176
+ api: "openai-completions",
177
+ baseUrl: `http://127.0.0.1:${server.port}/v1`,
178
+ auth: "none",
179
+ models: [{ id: "fixture", name: "fixture", input: ["text"], contextWindow: 1_000_000, maxTokens: 8192 }],
180
+ },
181
+ },
182
+ }),
183
+ );
184
+
185
+ // The pinned corpus reads `README.md` from the session cwd the runner passes on
186
+ // `session/new`. The runner creates that directory but seeds no content, so seed it
187
+ // here (never inside the upstream corpus) when the harness names it.
188
+ const scratchCwd = process.env.GJC_ACP_CONFORMANCE_CWD?.trim();
189
+ if (scratchCwd) {
190
+ const scratchReadme = path.join(scratchCwd, "README.md");
191
+ if (!(await Bun.file(scratchReadme).exists())) await Bun.write(scratchReadme, "acpx conformance workspace\n");
192
+ }
193
+
194
+ child = Bun.spawn(
195
+ [
196
+ "bun",
197
+ path.join(root, "packages", "coding-agent", "src", "cli.ts"),
198
+ "--mode",
199
+ "acp",
200
+ "--model",
201
+ "conformance/fixture",
202
+ ],
203
+ {
204
+ cwd: root,
205
+ env: { ...process.env, GJC_CODING_AGENT_DIR: agentDir, PI_CODING_AGENT_DIR: agentDir },
206
+ stdin: "inherit",
207
+ stdout: "inherit",
208
+ stderr: "inherit",
209
+ },
210
+ );
211
+ process.once("SIGTERM", () => {
212
+ void cleanup(0);
213
+ });
214
+ process.once("SIGINT", () => {
215
+ void cleanup(0);
216
+ });
217
+ await child.exited;
218
+ await cleanup(child.exitCode ?? 1);