@gajae-code/coding-agent 0.11.3 → 0.11.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 (82) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/types/cli/worktree-cli.d.ts +8 -25
  3. package/dist/types/commands/gc.d.ts +4 -0
  4. package/dist/types/commands/worktree.d.ts +7 -32
  5. package/dist/types/gjc-runtime/gc-runtime.d.ts +9 -0
  6. package/dist/types/gjc-runtime/state-argv.d.ts +38 -0
  7. package/dist/types/modes/components/custom-editor.d.ts +8 -3
  8. package/dist/types/modes/components/tool-transcript-format.d.ts +19 -0
  9. package/dist/types/modes/controllers/input-controller.d.ts +8 -2
  10. package/dist/types/sdk/broker/broker.d.ts +1 -0
  11. package/dist/types/sdk/broker/discovery.d.ts +10 -0
  12. package/dist/types/sdk/broker/ensure.d.ts +24 -1
  13. package/dist/types/sdk/broker/internal.d.ts +3 -0
  14. package/dist/types/sdk/broker/session-index.d.ts +12 -0
  15. package/dist/types/sdk/broker/state-version.d.ts +2 -1
  16. package/dist/types/tools/ask.d.ts +39 -12
  17. package/dist/types/tools/browser/screenshot-format.d.ts +8 -0
  18. package/dist/types/tools/browser/tab-protocol.d.ts +11 -0
  19. package/dist/types/tools/browser/tab-supervisor.d.ts +1 -1
  20. package/dist/types/tools/browser/tab-worker-path-resolver.d.ts +2 -0
  21. package/dist/types/tools/browser/tab-worker-smoke.d.ts +16 -0
  22. package/dist/types/tools/path-utils.d.ts +9 -14
  23. package/dist/types/tools/render-utils.d.ts +1 -8
  24. package/dist/types/tools/resource-gc.d.ts +14 -0
  25. package/dist/types/utils/image-loading.d.ts +23 -0
  26. package/dist/types/utils/image-resize.d.ts +2 -0
  27. package/dist/types/utils/pasted-image-loading.d.ts +39 -0
  28. package/dist/types/utils/pasted-image-path.d.ts +21 -19
  29. package/dist/types/web/scrapers/html-to-markdown.d.ts +5 -0
  30. package/dist/types/web/scrapers/types.d.ts +1 -5
  31. package/package.json +24 -8
  32. package/scripts/run-threat-model-check.ts +60 -0
  33. package/src/cli/worktree-cli.ts +9 -287
  34. package/src/cli.ts +10 -9
  35. package/src/commands/gc.ts +11 -1
  36. package/src/commands/sdk.ts +3 -2
  37. package/src/commands/worktree.ts +10 -53
  38. package/src/config/model-profiles.ts +15 -15
  39. package/src/eval/js/shared/runtime.ts +1 -1
  40. package/src/gjc-runtime/gc-render.ts +19 -1
  41. package/src/gjc-runtime/gc-runtime.ts +68 -3
  42. package/src/gjc-runtime/state-argv.ts +292 -0
  43. package/src/gjc-runtime/state-runtime.ts +42 -210
  44. package/src/modes/components/custom-editor.ts +103 -32
  45. package/src/modes/components/custom-provider-wizard.ts +26 -1
  46. package/src/modes/components/session-observer-overlay.ts +10 -23
  47. package/src/modes/components/tool-transcript-format.ts +72 -0
  48. package/src/modes/components/transcript-viewer-overlay.ts +42 -2
  49. package/src/modes/controllers/input-controller.ts +98 -37
  50. package/src/modes/controllers/selector-controller.ts +1 -1
  51. package/src/modes/interactive-mode.ts +13 -2
  52. package/src/sdk/broker/broker.ts +139 -32
  53. package/src/sdk/broker/discovery.ts +125 -0
  54. package/src/sdk/broker/ensure.ts +103 -19
  55. package/src/sdk/broker/internal.ts +10 -0
  56. package/src/sdk/broker/session-index.ts +228 -15
  57. package/src/sdk/broker/state-version.ts +5 -2
  58. package/src/sdk/bus/telegram-daemon.ts +50 -10
  59. package/src/session/internal/managed-session-scope.ts +15 -1
  60. package/src/tools/ask.ts +216 -41
  61. package/src/tools/bash-allowed-prefixes.ts +79 -29
  62. package/src/tools/browser/launch.ts +3 -1
  63. package/src/tools/browser/readable.ts +1 -1
  64. package/src/tools/browser/screenshot-format.ts +34 -0
  65. package/src/tools/browser/tab-protocol.ts +3 -0
  66. package/src/tools/browser/tab-supervisor.ts +125 -122
  67. package/src/tools/browser/tab-worker-entry.ts +33 -14
  68. package/src/tools/browser/tab-worker-path-resolver.ts +67 -0
  69. package/src/tools/browser/tab-worker-smoke.ts +87 -0
  70. package/src/tools/browser/tab-worker.ts +7 -5
  71. package/src/tools/path-utils.ts +42 -35
  72. package/src/tools/read.ts +7 -1
  73. package/src/tools/render-utils.ts +1 -27
  74. package/src/tools/resource-gc.ts +123 -34
  75. package/src/utils/image-loading.ts +85 -34
  76. package/src/utils/image-resize.ts +16 -9
  77. package/src/utils/pasted-image-loading.ts +514 -0
  78. package/src/utils/pasted-image-path.ts +223 -98
  79. package/src/web/scrapers/html-to-markdown.ts +68 -0
  80. package/src/web/scrapers/readthedocs.ts +1 -1
  81. package/src/web/scrapers/types.ts +1 -68
  82. package/src/web/search/providers/openai-compatible.ts +76 -23
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.4] - 2026-07-20
6
+ ### Added
7
+ - Bracketed pastes containing complete lists of saved static-image paths can now attach up to 16 images in source order after explicit confirmation. Paste transactions are cancellation-safe, disabled in command modes, enforce source, encoded-output, dimension, and decoded-memory budgets before commit, reject animated, remote, linked, or path-swapped sources, and restore the literal paste on cancellation or failure.
8
+ - Rich tool-call rendering in the transcript viewer: both the session-observer and main-session transcript viewers now share one formatter so tool calls render identically (args summary + intent, then a result block with ✓ done / ✗ error / ⏳ pending states). Fixes a latent bug where a tool call with no result rendered as a false "✓ done"; expanded results cap at 100 source lines with raw/copy exposing the full text (#2656).
9
+
10
+ ### Changed
11
+ - Updated the Kimi Coding Plan Eco, Medium, and Pro presets to Kimi K3 with its supported `low`, `high`, and `max` reasoning efforts.
12
+
13
+ ### Removed
14
+ - Removed the legacy worktree cleanup implementation behind the `@gajae-code/coding-agent/cli/worktree-cli` and `@gajae-code/coding-agent/commands/worktree` package subpaths (base and `.js` forms). The `gjc worktree`/`wt` CLI command has been unregistered since the workflow-surface narrowing; the modules behind it (including the recursive-deletion `clear` path) were only reachable as package imports. The subpaths now resolve to throwing tombstone modules whose error explains the deliberate removal and the supported replacement: inspect leftover managed worktrees under `~/.gjc/wt` manually and use `git worktree remove` / `git worktree prune`.
15
+
16
+ ### Fixed
17
+ - Telegram `/btw` rich-delivery E2E coverage now awaits native and daemon teardown ownership, records exact per-iteration lifecycle phases, and uses an internal exact-tuple terminal-delivery receipt to keep fallback stress deterministic under shard load without extending the original test timeout.
18
+ - Malformed spurious Round-0 review metadata no longer blocks an otherwise valid locked-intent question/gate, while durable intent safety remains fail-closed (#2643).
19
+ - Restricted role-agent `gjc state` command authorization now fails closed on argv-classification disagreement: one shared manifest-aware native state argv grammar (action names, flag arity, positionals, effective modifiers, selector candidates) is consumed by both runtime dispatch and the policy boundary, which rejects ambiguous selectors, malformed flags, destructive actions, and file-backed input (#2665).
20
+ - Browser tab workers now bootstrap through their actual isolated entry without accidentally loading native bindings through broad imports, and startup fails closed instead of falling back to unguarded inline execution; compiled/package smoke now exercises the tab worker, with a PR-head darwin-arm64 CI gate (#2598).
21
+ - Added evidence-preserving recovery for legacy multi-writer SDK session-index corruption: `gjc gc` now diagnoses corrupt prefixes, `--repair-session-index` quarantines the original snapshot/log under the session-index lock before atomically restoring only the checksum-valid monotonic prefix, and append failures point operators to the explicit repair path (#2654).
22
+ - Malformed selectors on internal read URLs now fail explicitly instead of silently falling back to an unbounded resource read.
23
+ - Newly registered earlier resource-GC policies advance the pending sweep without postponing an already earlier sweep.
24
+ - Provider onboarding wizard completion is now deterministic under CI load: duplicate in-flight confirmation is suppressed, success tests await the real refresh/notification/status boundary instead of fixed sleeps, and the newly configured model is verified through the subsequent model selector.
25
+ - OpenAI-compatible web search now turns malformed successful response bodies into bounded provider errors while preserving normal provider fallback (#2593).
26
+ - Windows session storage now keeps a symlink-resolved drive-letter path for Bun filesystem I/O instead of a native Volume GUID identity path, preventing `ENOENT` failures during resident-cache writes that could drop the final assistant message at turn completion.
27
+ - On platforms with verified retained publication identity support, detached SDK broker processes now stop after durable loss or replacement of their owned publication while preserving warm reuse and protocol/state formats (#2583). Bounded-practical limitation: requests admitted before the first definitive loss observation—or after authoritative same-object recovery and before a later loss observation—may still perform pathname-based index, ledger, lifecycle, cleanup, or child effects. A detached session-host child spawned by an admitted request may outlive broker exit and may continue pathname effects for the session lifetime. Broker self-reap does not cancel or signal that child and does not provide absolute hostile replacement isolation.
28
+
5
29
  ## [0.11.3] - 2026-07-19
6
30
 
7
31
  ### Changed
@@ -1,26 +1,9 @@
1
- type WorktreeKind = "pr-checkout" | "task-isolation" | "empty" | "stray";
2
- export interface WorktreeEntry {
3
- /** Absolute path to the worktree dir (or stray container) under `~/.gjc/wt/`. */
4
- path: string;
5
- /** Classification of what we found on disk. */
6
- kind: WorktreeKind;
7
- /** Parent repo root, when this is a registered git worktree. */
8
- parentRepo?: string;
9
- /** Branch name extracted from the parent's tracking file, when available. */
10
- branch?: string;
11
- /** When set, the entry is unhealthy and `gjc worktree clear` will remove it. */
12
- orphanReason?: string;
13
- }
14
- export interface ListWorktreesOptions {
15
- json: boolean;
16
- }
17
- export interface ClearWorktreesOptions {
18
- /** Remove every entry, including live PR-checkout worktrees. */
19
- all: boolean;
20
- /** Print what would be removed without touching the filesystem. */
21
- dryRun: boolean;
22
- json: boolean;
23
- }
24
- export declare function listWorktrees(options: ListWorktreesOptions): Promise<void>;
25
- export declare function clearWorktrees(options: ClearWorktreesOptions): Promise<void>;
1
+ /**
2
+ * Tombstone for the removed legacy worktree cleanup API.
3
+ *
4
+ * The recursive-deletion implementation that previously lived here
5
+ * (`listWorktrees`/`clearWorktrees`) was deliberately removed and does not
6
+ * come back through this subpath. This module exists only to fail imports
7
+ * with actionable migration guidance.
8
+ */
26
9
  export {};
@@ -20,6 +20,10 @@ export default class Gc extends Command {
20
20
  description: string;
21
21
  default: boolean;
22
22
  };
23
+ "repair-session-index": import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
24
+ description: string;
25
+ default: boolean;
26
+ };
23
27
  };
24
28
  static examples: string[];
25
29
  run(): Promise<void>;
@@ -1,34 +1,9 @@
1
1
  /**
2
- * List and clean up agent-managed git worktrees under `~/.gjc/wt`.
2
+ * Tombstone for the removed legacy `worktree` CLI command module.
3
+ *
4
+ * The `gjc worktree`/`wt` command was unregistered during the
5
+ * workflow-surface narrowing and its implementation was deliberately
6
+ * removed. This module exists only to fail imports with actionable
7
+ * migration guidance.
3
8
  */
4
- import { Command } from "@gajae-code/utils/cli";
5
- export default class Worktree extends Command {
6
- static description: string;
7
- static aliases: string[];
8
- static args: {
9
- action: import("@gajae-code/utils/cli").ArgDescriptor & {
10
- description: string;
11
- required: false;
12
- options: string[];
13
- default: string;
14
- };
15
- };
16
- static flags: {
17
- all: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
18
- description: string;
19
- default: boolean;
20
- };
21
- "dry-run": import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
22
- char: string;
23
- description: string;
24
- default: boolean;
25
- };
26
- json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
27
- char: string;
28
- description: string;
29
- default: boolean;
30
- };
31
- };
32
- static examples: string[];
33
- run(): Promise<void>;
34
- }
9
+ export {};
@@ -95,11 +95,20 @@ export interface GcCounts {
95
95
  failed: number;
96
96
  }>;
97
97
  }
98
+ export interface GcSessionIndexHealth {
99
+ status: "healthy" | "corrupt" | "repaired" | "unsupported" | "repair_failed";
100
+ valid_prefix_seq: number;
101
+ snapshot_seq?: number;
102
+ reason?: string;
103
+ quarantine_path?: string;
104
+ }
98
105
  export interface GcReport {
99
106
  dry_run: boolean;
107
+ operation?: "dry_run" | "prune" | "repair_session_index";
100
108
  stores: Record<GcStore, GcRecord[]>;
101
109
  counts: GcCounts;
102
110
  errors: GcError[];
111
+ session_index?: GcSessionIndexHealth;
103
112
  }
104
113
  export interface GcRunResult {
105
114
  stdout: string;
@@ -0,0 +1,38 @@
1
+ export type StateAction = "read" | "write" | "clear" | "contract" | "handoff" | "graph" | "prune" | "gc" | "migrate" | "status" | "doctor";
2
+ export declare const STATE_ACTION_NAMES: ReadonlySet<StateAction>;
3
+ export declare const STATE_FLAGS_WITH_VALUES: ReadonlySet<string>;
4
+ export declare const STATE_BOOLEAN_FLAGS: ReadonlySet<string>;
5
+ export interface StateFlagOccurrence {
6
+ name: string;
7
+ index: number;
8
+ value?: string;
9
+ arity: "boolean" | "value";
10
+ form: "separate" | "attached";
11
+ malformed: boolean;
12
+ }
13
+ export interface StateSelectorCandidate {
14
+ source: "mode" | "positional" | "input.mode" | "input.skill";
15
+ value: string | undefined;
16
+ index: number;
17
+ }
18
+ export type StateInputKind = "empty" | "inline" | "file" | "invalid";
19
+ export interface StateInputClassification {
20
+ index: number;
21
+ raw: string;
22
+ kind: StateInputKind;
23
+ selectors: StateSelectorCandidate[];
24
+ }
25
+ export interface StateArgvClassification {
26
+ argv: readonly string[];
27
+ action: StateAction;
28
+ effectiveAction: StateAction;
29
+ positionalSkill?: string;
30
+ positionals: readonly string[];
31
+ flags: readonly StateFlagOccurrence[];
32
+ unknownFlags: readonly string[];
33
+ inputs: readonly StateInputClassification[];
34
+ runtimeSelectorCandidates: readonly StateSelectorCandidate[];
35
+ selectorCandidates: readonly StateSelectorCandidate[];
36
+ }
37
+ export declare function firstStateFlagValue(classification: StateArgvClassification, name: string): string | undefined;
38
+ export declare function classifyStateArgv(argv: readonly string[]): StateArgvClassification;
@@ -2,6 +2,11 @@ import { Editor, type KeyId } from "@gajae-code/tui";
2
2
  import { type AppKeybinding } from "../../config/keybindings";
3
3
  type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.thinking.cycle" | "app.commandPalette.open" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.message.followUp" | "app.message.queue" | "app.clipboard.pasteImage" | "app.clipboard.copyPrompt">;
4
4
  type PastePendingClearReason = "timeout" | "queue-limit";
5
+ export interface PasteTextContext {
6
+ readonly signal: AbortSignal;
7
+ /** Run one synchronous composer mutation only while this paste transaction is current. */
8
+ commit(commit: () => boolean): boolean;
9
+ }
5
10
  /**
6
11
  * Custom editor that handles configurable app-level shortcuts for coding-agent.
7
12
  */
@@ -35,9 +40,9 @@ export declare class CustomEditor extends Editor {
35
40
  /** Called when the configured image-paste shortcut is pressed. */
36
41
  onPasteImage?: () => Promise<boolean>;
37
42
  /** Called before bracketed paste content is inserted. Return true to consume it. */
38
- onPasteText?: (text: string) => boolean | Promise<boolean>;
39
- /** Called when async paste handling drops queued input instead of replaying it. */
40
- onPastePendingInputCleared?: (reason: PastePendingClearReason, droppedInputCount: number) => void;
43
+ onPasteText?: (text: string, context: PasteTextContext) => boolean | Promise<boolean>;
44
+ /** Called when pending paste handling is cancelled after restoring queued input. */
45
+ onPastePendingInputCleared?: (reason: PastePendingClearReason, restoredInputCount: number) => void;
41
46
  /** Called when the configured dequeue shortcut is pressed. */
42
47
  onDequeue?: () => void;
43
48
  /** Called when the configured queue shortcut is pressed. */
@@ -0,0 +1,19 @@
1
+ export declare const MAX_TOOL_ARGS_CHARS = 500;
2
+ export declare const TOOL_RESULT_MAX_EXPANDED_LINES = 100;
3
+ type ToolCallFields = {
4
+ name: string;
5
+ args: Record<string, unknown>;
6
+ intent?: string;
7
+ };
8
+ type ToolResultFields = {
9
+ resultText: string;
10
+ isError: boolean;
11
+ hasResult: boolean;
12
+ };
13
+ export type ToolTranscriptFields = ToolCallFields & ToolResultFields;
14
+ export declare function formatToolArgs(name: string, args: Record<string, unknown>): string;
15
+ export declare function composeToolCall({ name, args, intent }: ToolCallFields): string;
16
+ export declare function composeToolResult({ resultText, isError, hasResult }: ToolResultFields): string;
17
+ export declare function composeToolText(fields: ToolTranscriptFields): string;
18
+ export declare function toolDisplayText(fields: ToolTranscriptFields, expanded: boolean): string;
19
+ export {};
@@ -1,13 +1,18 @@
1
1
  import { type AutocompleteProvider, type SlashCommand } from "@gajae-code/tui";
2
2
  import { type ComposerSubmissionOptions, type InteractiveModeContext } from "../../modes/types";
3
+ import { loadPastedImageBatch } from "../../utils/pasted-image-loading";
3
4
  import { ActionRegistry } from "../action-registry";
5
+ import type { PasteTextContext } from "../components/custom-editor";
4
6
  export declare const INTERACTIVE_ABORT_CLEANUP_TIMEOUT_MS = 5000;
5
7
  export declare const BACKGROUND_FOLD_DOUBLE_PRESS_MS = 750;
8
+ interface InputControllerDependencies {
9
+ loadPastedImageBatch?: typeof loadPastedImageBatch;
10
+ }
6
11
  export declare class InputController {
7
12
  #private;
8
13
  private ctx;
9
14
  readonly actionRegistry: ActionRegistry<void>;
10
- constructor(ctx: InteractiveModeContext);
15
+ constructor(ctx: InteractiveModeContext, dependencies?: InputControllerDependencies);
11
16
  setupKeyHandlers(): void;
12
17
  setupEditorSubmitHandler(): void;
13
18
  submitText(text: string, composer: ComposerSubmissionOptions): Promise<void>;
@@ -28,7 +33,7 @@ export declare class InputController {
28
33
  }): number;
29
34
  handleBackgroundCommand(): void;
30
35
  handleForegroundToolBackgroundFold(): boolean;
31
- handleTextPaste(text: string): boolean | Promise<boolean>;
36
+ handleTextPaste(text: string, context: PasteTextContext): boolean | Promise<boolean>;
32
37
  handleImagePaste(): Promise<boolean>;
33
38
  createAutocompleteProvider(commands: SlashCommand[], basePath: string): AutocompleteProvider;
34
39
  /** Copy the current editor line to the system clipboard. */
@@ -47,3 +52,4 @@ export declare class InputController {
47
52
  openExternalEditor(): Promise<void>;
48
53
  registerExtensionShortcuts(): void;
49
54
  }
55
+ export {};
@@ -109,6 +109,7 @@ export declare class Broker {
109
109
  constructor(settings: BrokerSettings);
110
110
  start(): Promise<BrokerDiscovery>;
111
111
  get ownsDiscovery(): boolean;
112
+ get completion(): Promise<void>;
112
113
  status(): RedactedBrokerDiscovery | null;
113
114
  heartbeat(): Promise<void>;
114
115
  stop(): Promise<void>;
@@ -1,5 +1,11 @@
1
1
  import { processIncarnation } from "./process-incarnation";
2
2
  import { SDK_STATE_VERSION } from "./state-version";
3
+ export type BrokerPublicationObservation = "owned" | "absent" | "replaced" | "ambiguous";
4
+ export interface RetainedBrokerDiscovery {
5
+ observe(): BrokerPublicationObservation;
6
+ heartbeat(heartbeatAt: number): Promise<boolean>;
7
+ close(): void;
8
+ }
3
9
  export declare const BROKER_HEARTBEAT_TTL_MS = 15000;
4
10
  export interface BrokerDiscovery {
5
11
  version: typeof SDK_STATE_VERSION;
@@ -26,5 +32,9 @@ export declare const newBrokerToken: () => string;
26
32
  export declare const brokerProcessIncarnation: typeof processIncarnation;
27
33
  export declare function isPidAlive(pid: number): boolean;
28
34
  export declare function writeBrokerDiscovery(agentDir: string, discovery: BrokerDiscoveryWrite): Promise<void>;
35
+ /** Publish once by name, then retain no-follow native authority for recurring heartbeats. */
36
+ export declare function publishBrokerDiscovery(agentDir: string, discovery: BrokerDiscoveryWrite, platform?: NodeJS.Platform): Promise<RetainedBrokerDiscovery>;
37
+ /** Heartbeat through retained authority, or the explicit Windows compatibility path. */
38
+ export declare function heartbeatBrokerDiscoveryRetained(publication: RetainedBrokerDiscovery, heartbeatAt: number): Promise<boolean>;
29
39
  export declare function readBrokerDiscovery(agentDir: string, ttlMs?: number): Promise<BrokerDiscovery | null>;
30
40
  export declare function redactBrokerDiscovery(discovery: BrokerDiscovery): RedactedBrokerDiscovery;
@@ -12,11 +12,28 @@ export interface EnsureBrokerSettings {
12
12
  env?: NodeJS.ProcessEnv;
13
13
  }
14
14
  export interface FixtureBrokerLease {
15
+ /** Backward-compatible fixture cleanup alias for exact child termination. */
15
16
  close(): Promise<void>;
16
17
  }
18
+ export interface ExactFixtureBrokerLease extends FixtureBrokerLease {
19
+ /** Observes the retained child only; it never signals a process. */
20
+ waitForExit(timeoutMs: number): Promise<boolean>;
21
+ /** Signals only the retained ChildProcess, never a discovery-derived PID. */
22
+ terminateExactChild(): Promise<void>;
23
+ }
24
+ export interface FixtureBrokerCommand {
25
+ file: string;
26
+ args: readonly string[];
27
+ cwd?: string;
28
+ env?: NodeJS.ProcessEnv;
29
+ }
30
+ export interface StartedFixtureBrokerCommand {
31
+ lease: ExactFixtureBrokerLease;
32
+ control: NodeJS.WritableStream;
33
+ }
17
34
  export interface StartedFixtureBroker {
18
35
  discovery: BrokerDiscovery;
19
- lease: FixtureBrokerLease;
36
+ lease: ExactFixtureBrokerLease;
20
37
  }
21
38
  interface BrokerOwner {
22
39
  stop(): Promise<void>;
@@ -31,6 +48,12 @@ interface ReapTiming {
31
48
  export declare function ensureBroker(settings: EnsureBrokerSettings): Promise<BrokerDiscovery>;
32
49
  /** Starts one fresh fixture broker and returns its sole exact-child close lease. */
33
50
  export declare function startFixtureBrokerWithLeaseForTest(settings: EnsureBrokerSettings): Promise<StartedFixtureBroker>;
51
+ /**
52
+ * Test-only launch surface for topology fixtures. It accepts an already-resolved
53
+ * command and retains the exact spawned child; no production selection path
54
+ * reaches this function.
55
+ */
56
+ export declare function startFixtureBrokerCommandWithLeaseForTest(command: FixtureBrokerCommand): StartedFixtureBrokerCommand;
34
57
  /** Test hook: returns a stop handle for the detached broker this process spawned. */
35
58
  export declare function brokerOwnerForTest(agentDir: string): BrokerOwner | undefined;
36
59
  /** Test hook: drives the detached-broker reap on a controllable child surface. */
@@ -0,0 +1,3 @@
1
+ import type { Broker } from "./broker";
2
+ /** Wait for broker-local completion, then terminate only the current broker process. */
3
+ export declare function completeBrokerProcess(broker: Broker, exit?: (code: number) => never): Promise<never>;
@@ -36,12 +36,24 @@ export interface SessionList {
36
36
  sessions: IndexedSession[];
37
37
  warnings: string[];
38
38
  }
39
+ export interface SessionIndexDiagnosis {
40
+ status: "healthy" | "corrupt" | "unsupported";
41
+ validPrefixSeq: number;
42
+ snapshotSeq: number;
43
+ reason?: string;
44
+ }
45
+ export interface SessionIndexRepairResult extends SessionIndexDiagnosis {
46
+ repaired: boolean;
47
+ quarantinePath?: string;
48
+ }
39
49
  export declare const sessionIndexChecksum: (event: Omit<SessionIndexEvent, "checksum">) => string;
40
50
  export declare class SessionIndex {
41
51
  #private;
42
52
  constructor(agentDir: string);
43
53
  open(): Promise<this>;
44
54
  replay(): Promise<void>;
55
+ diagnose(): Promise<SessionIndexDiagnosis>;
56
+ repair(): Promise<SessionIndexRepairResult>;
45
57
  refresh(): Promise<void>;
46
58
  get indexSeq(): number;
47
59
  append(input: Omit<SessionIndexEvent, "version" | "indexSeq" | "checksum" | "ts"> & Partial<Pick<SessionIndexEvent, "ts">>): Promise<SessionIndexEvent>;
@@ -3,8 +3,9 @@ export declare const SESSION_INDEX_SNAPSHOT_VERSION = 2;
3
3
  export declare class UnsupportedStateVersionError extends Error {
4
4
  readonly file: string;
5
5
  readonly version: number;
6
+ readonly maximumSupportedVersion: number;
6
7
  readonly code = "unsupported_state_version";
7
- constructor(file: string, version: number);
8
+ constructor(file: string, version: number, maximumSupportedVersion?: number);
8
9
  }
9
10
  export declare function assertSupportedStateVersion(file: string, value: unknown): void;
10
11
  export declare function assertSupportedSnapshotVersion(file: string, value: unknown): void;
@@ -15,6 +15,7 @@
15
15
  * - Questions may time out and auto-select the recommended option (configurable, disabled in plan mode)
16
16
  */
17
17
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
18
+ import type { RawArgumentValidationResult } from "@gajae-code/ai/types";
18
19
  import { type Component } from "@gajae-code/tui";
19
20
  import * as z from "zod/v4";
20
21
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
@@ -29,13 +30,19 @@ export declare const askSchema: z.ZodObject<{
29
30
  }, z.core.$strip>>;
30
31
  multi: z.ZodOptional<z.ZodBoolean>;
31
32
  recommended: z.ZodOptional<z.ZodNumber>;
32
- deepInterview: z.ZodOptional<z.ZodObject<{
33
+ deepInterview: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
33
34
  round_id: z.ZodOptional<z.ZodString>;
34
35
  round: z.ZodNumber;
35
36
  component: z.ZodString;
36
37
  dimension: z.ZodString;
37
38
  ambiguity: z.ZodNumber;
38
- intent_contract: z.ZodOptional<z.ZodObject<{
39
+ }, z.core.$strict>, z.ZodObject<{
40
+ round_id: z.ZodOptional<z.ZodString>;
41
+ ambiguity: z.ZodNumber;
42
+ round: z.ZodLiteral<0>;
43
+ component: z.ZodLiteral<"review-topology">;
44
+ dimension: z.ZodLiteral<"topology">;
45
+ intent_contract: z.ZodObject<{
39
46
  items: z.ZodArray<z.ZodObject<{
40
47
  id: z.ZodString;
41
48
  category: z.ZodEnum<{
@@ -47,8 +54,14 @@ export declare const askSchema: z.ZodObject<{
47
54
  statement: z.ZodString;
48
55
  }, z.core.$strict>>;
49
56
  confirmation_options: z.ZodArray<z.ZodString>;
50
- }, z.core.$strict>>;
51
- intent_review: z.ZodOptional<z.ZodObject<{
57
+ }, z.core.$strict>;
58
+ }, z.core.$strict>, z.ZodObject<{
59
+ round_id: z.ZodOptional<z.ZodString>;
60
+ component: z.ZodString;
61
+ dimension: z.ZodString;
62
+ ambiguity: z.ZodNumber;
63
+ round: z.ZodNumber;
64
+ intent_review: z.ZodObject<{
52
65
  observed_items: z.ZodArray<z.ZodObject<{
53
66
  id: z.ZodString;
54
67
  category: z.ZodEnum<{
@@ -65,8 +78,8 @@ export declare const askSchema: z.ZodObject<{
65
78
  rationale: z.ZodString;
66
79
  }, z.core.$strict>>;
67
80
  approval_options: z.ZodArray<z.ZodString>;
68
- }, z.core.$strict>>;
69
- }, z.core.$strict>>;
81
+ }, z.core.$strict>;
82
+ }, z.core.$strict>]>>;
70
83
  workflowGate: z.ZodOptional<z.ZodObject<{
71
84
  stage: z.ZodEnum<{
72
85
  "deep-interview": "deep-interview";
@@ -82,6 +95,7 @@ export declare const askSchema: z.ZodObject<{
82
95
  }, z.core.$strip>>;
83
96
  }, z.core.$strip>;
84
97
  export type AskToolInput = z.infer<typeof askSchema>;
98
+ declare function recoverRoundZeroIntentContract(arguments_: Record<string, unknown>): RawArgumentValidationResult;
85
99
  /** Result for a single question */
86
100
  export interface QuestionResult {
87
101
  id: string;
@@ -149,13 +163,19 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
149
163
  }, z.core.$strip>>;
150
164
  multi: z.ZodOptional<z.ZodBoolean>;
151
165
  recommended: z.ZodOptional<z.ZodNumber>;
152
- deepInterview: z.ZodOptional<z.ZodObject<{
166
+ deepInterview: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
153
167
  round_id: z.ZodOptional<z.ZodString>;
154
168
  round: z.ZodNumber;
155
169
  component: z.ZodString;
156
170
  dimension: z.ZodString;
157
171
  ambiguity: z.ZodNumber;
158
- intent_contract: z.ZodOptional<z.ZodObject<{
172
+ }, z.core.$strict>, z.ZodObject<{
173
+ round_id: z.ZodOptional<z.ZodString>;
174
+ ambiguity: z.ZodNumber;
175
+ round: z.ZodLiteral<0>;
176
+ component: z.ZodLiteral<"review-topology">;
177
+ dimension: z.ZodLiteral<"topology">;
178
+ intent_contract: z.ZodObject<{
159
179
  items: z.ZodArray<z.ZodObject<{
160
180
  id: z.ZodString;
161
181
  category: z.ZodEnum<{
@@ -167,8 +187,14 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
167
187
  statement: z.ZodString;
168
188
  }, z.core.$strict>>;
169
189
  confirmation_options: z.ZodArray<z.ZodString>;
170
- }, z.core.$strict>>;
171
- intent_review: z.ZodOptional<z.ZodObject<{
190
+ }, z.core.$strict>;
191
+ }, z.core.$strict>, z.ZodObject<{
192
+ round_id: z.ZodOptional<z.ZodString>;
193
+ component: z.ZodString;
194
+ dimension: z.ZodString;
195
+ ambiguity: z.ZodNumber;
196
+ round: z.ZodNumber;
197
+ intent_review: z.ZodObject<{
172
198
  observed_items: z.ZodArray<z.ZodObject<{
173
199
  id: z.ZodString;
174
200
  category: z.ZodEnum<{
@@ -185,8 +211,8 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
185
211
  rationale: z.ZodString;
186
212
  }, z.core.$strict>>;
187
213
  approval_options: z.ZodArray<z.ZodString>;
188
- }, z.core.$strict>>;
189
- }, z.core.$strict>>;
214
+ }, z.core.$strict>;
215
+ }, z.core.$strict>]>>;
190
216
  workflowGate: z.ZodOptional<z.ZodObject<{
191
217
  stage: z.ZodEnum<{
192
218
  "deep-interview": "deep-interview";
@@ -201,6 +227,7 @@ export declare class AskTool implements AgentTool<typeof askSchema, AskToolDetai
201
227
  }, z.core.$strip>>;
202
228
  }, z.core.$strip>>;
203
229
  }, z.core.$strip>;
230
+ readonly rawArgumentValidation: typeof recoverRoundZeroIntentContract;
204
231
  readonly strict = true;
205
232
  readonly loadMode = "discoverable";
206
233
  constructor(session: ToolSession);
@@ -0,0 +1,8 @@
1
+ import { type ResizedImage } from "../../utils/image-resize";
2
+ export declare function formatScreenshot(opts: {
3
+ saveFullRes: boolean;
4
+ savedMimeType: string;
5
+ savedByteLength: number;
6
+ dest: string;
7
+ resized: ResizedImage;
8
+ }): string[];
@@ -70,6 +70,10 @@ export type ToolReply = {
70
70
  error: RunErrorPayload;
71
71
  };
72
72
  export type WorkerInbound = {
73
+ type: "bootstrap";
74
+ version: 1;
75
+ mode: "native-free";
76
+ } | {
73
77
  type: "init";
74
78
  payload: WorkerInitPayload;
75
79
  } | {
@@ -112,6 +116,13 @@ export interface RunErrorPayload {
112
116
  isAbort: boolean;
113
117
  }
114
118
  export type WorkerOutbound = {
119
+ type: "bootstrap-ready";
120
+ version: 1;
121
+ mode: "native-free";
122
+ } | {
123
+ type: "bootstrap-failed";
124
+ error: string;
125
+ } | {
115
126
  type: "ready";
116
127
  info: ReadyInfo;
117
128
  } | {
@@ -5,8 +5,8 @@ interface WorkerHandle {
5
5
  send(msg: WorkerInbound, transferList?: Transferable[]): void;
6
6
  onMessage(handler: (msg: WorkerOutbound) => void): () => void;
7
7
  onError(handler: (error: Error) => void): () => void;
8
+ onClose(handler: () => void): () => void;
8
9
  terminate(): Promise<void>;
9
- readonly mode: "worker" | "inline";
10
10
  }
11
11
  export type DialogPolicy = "accept" | "dismiss";
12
12
  export interface PendingRun {
@@ -0,0 +1,2 @@
1
+ /** Resolve filesystem-only worker inputs without evaluating the broad path utility module. */
2
+ export declare function resolveTabWorkerPath(filePath: string, cwd: string): string;
@@ -0,0 +1,16 @@
1
+ import type { WorkerInbound } from "./tab-protocol";
2
+ interface SmokeWorkerHandle {
3
+ postMessage(message: WorkerInbound): void;
4
+ addEventListener(type: string, listener: EventListener): void;
5
+ removeEventListener(type: string, listener: EventListener): void;
6
+ terminate(): void;
7
+ }
8
+ /**
9
+ * Starts the real tab worker entry without connecting to a browser, then proves
10
+ * its bootstrap and shutdown protocol. The compiled branch deliberately keeps
11
+ * a static literal for Bun's --compile worker discovery.
12
+ */
13
+ export declare function smokeTestTabWorker(timeoutMs?: number): Promise<void>;
14
+ /** Test-only: verify the smoke handshake against a controlled worker transport. */
15
+ export declare function smokeTestTabWorkerWithWorkerForTest(worker: SmokeWorkerHandle, timeoutMs: number): Promise<void>;
16
+ export {};
@@ -7,21 +7,16 @@ export declare function splitPathAndSel(rawPath: string): {
7
7
  /**
8
8
  * Variant of {@link splitPathAndSel} for internal URLs (`scheme://...`).
9
9
  *
10
- * The filesystem-path splitter is intentionally conservative: it refuses to
11
- * peel a trailing `:<chunk>` unless that chunk matches the strict selector
12
- * grammar. That rule is right for filesystem paths (a file named `a:1-50` is
13
- * legal) but wrong for internal URLs, where any trailing `:<chunk>` after the
14
- * scheme is unambiguously a read-tool selector — even if malformed (e.g.
15
- * `artifact://3:raw:-100`).
16
- *
17
- * This function iteratively peels selector-shaped chunks (well-formed plus
18
- * common malformed shapes like `:-N`) so the rest of the read tool can pass a
19
- * clean URL to the protocol handler and surface selector errors via parseSel
20
- * instead of as misleading "host invalid" errors from the handler.
21
- *
22
- * Falls back to the input unchanged when nothing matches.
10
+ * Artifact authorities are generated identifiers, so their complete tail is
11
+ * unambiguously a selector and malformed selectors can be rejected before
12
+ * resolving the artifact. Other resources may legitimately use colons in
13
+ * their identities, so they only lose strict, recognized selector suffixes.
14
+ * Skill authorities additionally use the active registry to distinguish a
15
+ * skill name from its selector without making path-utils depend on skills.
23
16
  */
24
- export declare function splitInternalUrlSel(rawPath: string): {
17
+ export declare function splitInternalUrlSel(rawPath: string, options?: {
18
+ activeSkillNames?: readonly string[];
19
+ }): {
25
20
  path: string;
26
21
  sel?: string;
27
22
  };
@@ -8,9 +8,9 @@ import type { ToolCallContext } from "@gajae-code/agent-core";
8
8
  import type { Ellipsis } from "@gajae-code/natives";
9
9
  import type { Component } from "@gajae-code/tui";
10
10
  import type { Theme } from "../modes/theme/theme";
11
- import { type ResizedImage } from "../utils/image-resize";
12
11
  export { Ellipsis } from "@gajae-code/natives";
13
12
  export { replaceTabs, truncateToWidth, wrapTextWithAnsi } from "@gajae-code/tui";
13
+ export { formatScreenshot } from "./browser/screenshot-format";
14
14
  /** Resolve inline image dimension caps from settings and viewport. */
15
15
  export declare function resolveImageOptions(): {
16
16
  maxWidthCells: number;
@@ -107,13 +107,6 @@ export declare function truncateDiffByHunk(diffText: string, maxHunks: number, m
107
107
  };
108
108
  export declare function shortenPath(filePath: string, homeDir?: string): string;
109
109
  export declare function formatToolWorkingDirectory(workdir: string | undefined, projectDir: string): string | undefined;
110
- export declare function formatScreenshot(opts: {
111
- saveFullRes: boolean;
112
- savedMimeType: string;
113
- savedByteLength: number;
114
- dest: string;
115
- resized: ResizedImage;
116
- }): string[];
117
110
  export declare function wrapBrackets(text: string, theme: Theme): string;
118
111
  export declare const PARSE_ERRORS_LIMIT = 20;
119
112
  export declare function dedupeParseErrors(errors: string[] | undefined): string[];