@gajae-code/coding-agent 0.13.1 → 0.13.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 (45) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/types/config/model-registry.d.ts +1 -0
  3. package/dist/types/config/settings-schema.d.ts +3 -3
  4. package/dist/types/main.d.ts +1 -0
  5. package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
  6. package/dist/types/modes/components/gajae-pet-widget.d.ts +5 -5
  7. package/dist/types/modes/components/pet-capability.d.ts +5 -5
  8. package/dist/types/modes/components/settings-selector.d.ts +5 -0
  9. package/dist/types/modes/theme/defaults/index.d.ts +118 -0
  10. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
  11. package/dist/types/session/internal/managed-session-storage.d.ts +13 -0
  12. package/dist/types/session/session-manager.d.ts +7 -0
  13. package/dist/types/tools/image-gen.d.ts +1 -0
  14. package/package.json +8 -8
  15. package/src/config/model-profile-activation.ts +3 -1
  16. package/src/config/model-profiles.ts +59 -2
  17. package/src/config/model-registry.ts +16 -1
  18. package/src/config/settings-schema.ts +1 -1
  19. package/src/coordinator-mcp/server.ts +3 -0
  20. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
  21. package/src/internal-urls/docs-index.generated.ts +7 -6
  22. package/src/main.ts +4 -0
  23. package/src/modes/components/chrome.ts +4 -3
  24. package/src/modes/components/dynamic-theme-text.ts +22 -0
  25. package/src/modes/components/gajae-pet-widget.ts +130 -42
  26. package/src/modes/components/model-selector.ts +1 -6
  27. package/src/modes/components/pet-capability.ts +10 -5
  28. package/src/modes/components/settings-selector.ts +20 -5
  29. package/src/modes/components/status-line/segments.ts +3 -3
  30. package/src/modes/controllers/selector-controller.ts +61 -5
  31. package/src/modes/interactive-mode.ts +4 -0
  32. package/src/modes/theme/defaults/index.ts +2 -0
  33. package/src/modes/theme/defaults/ouroboros.json +118 -0
  34. package/src/sdk/broker/process-incarnation.ts +6 -1
  35. package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
  36. package/src/sdk/bus/telegram-daemon.ts +51 -43
  37. package/src/session/agent-session.ts +39 -0
  38. package/src/session/internal/managed-session-storage.ts +162 -40
  39. package/src/session/session-manager.ts +28 -0
  40. package/src/slash-commands/builtin-registry.ts +62 -8
  41. package/src/task/index.ts +5 -2
  42. package/src/tools/bash.ts +11 -9
  43. package/src/tools/image-gen.ts +322 -126
  44. package/src/tools/todo-contract.ts +55 -3
  45. package/src/tools/todo-write.ts +4 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,44 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.13.3] - 2026-08-15
6
+
7
+ ### Added
8
+ - Added Grok 4.6 to the bundled Grok CLI model catalog with bounded reasoning-effort parsing.
9
+ - Added built-in `grok-46-{eco,medium,pro}` role profiles using the existing xAI OAuth/subscription provider, with supported reasoning-effort selection for Grok 4.5/4.6.
10
+ - Added three provider-agnostic Muse Spark 1.2 presets: Muse Spark across all roles, plus DeepSeek and Luna executor variants.
11
+ - Added the bundled Ouroboros theme and pet, including transactional theme selection and RedGajae fallback (#4468).
12
+ - Gajae Pet now renders in iTerm2 using inline PNG frames, with the same reserved composer-side layout and lifecycle cleanup used by Kitty and Sixel (#4499).
13
+
14
+ ### Fixed
15
+ - Managed sessions recover from `content_too_large` by rewriting live in-memory entries, and proactively compact before the managed transcript limit (#4411).
16
+ - Managed output publication no longer freezes the resident event loop when a no-replace rename stalls in the kernel; async publication uses blocking-pool native boundaries and per-session stores reap scrubbed protocol remnants (#4396).
17
+ - Print mode now requests a governed process exit after successful session teardown, so completed one-shot runs cannot be pinned by residual runtime handles; both stdout and stderr are drained first and the recorded exit code is preserved.
18
+ - `todo_write` no longer rejects a positional task handle without saying how to address a task. Callers reach for `id`/`index` because the tool result renders todos as a list, and raw validation rejects the unknown key before `execute` runs; positional-handle keys now explain that tasks are addressed by exact `task` content or by `phase`.
19
+ - Escaped-non-ASCII tool-call turns in managed fallback are retried on the same model without charging the fallback chain or advancing it — the wire defect is a sampling accident, not provider evidence — bounded to two consecutive retries before the run terminates (#4515).
20
+ - Image generation now redacts API keys, bearer tokens, JWTs, and other credential formats from provider error messages and surfaced metadata, bounds provider response bodies at 64 MiB before buffering, and cancels rejected bodies instead of retaining unbounded streams (#4302).
21
+ - A transient Windows `invalid_request` during managed replacement-receipt reconciliation is now resolved by capturing both the pending and canonical receipt paths: success when another reconciler already moved the pending receipt, fail-closed `managed_replace_cleanup_receipt_invalid` for conflicting destinations, byte-identical copies, or missing receipts (#4373).
22
+ - Status-line scratch roots are resolved at render time instead of process start, so path classification follows the active environment when `HOME`/`TMPDIR` are rewritten after module caching (#4452).
23
+
24
+ ## [0.13.2] - 2026-08-13
25
+
26
+ ### Added
27
+ - Added a portable Stream Deck integration for cmux sessions, including a plugin manifest, reusable profile pages, action icons, installation scripts, and a guided setup document (#4308 by @Yeachan-Heo).
28
+ - `/theme <name>` now switches the theme immediately without opening the selector. The name is validated against built-in and custom themes, persisted to the detected `theme.dark`/`theme.light` slot, and applied to the running session in one step (#4429 by @Yeachan-Heo).
29
+
30
+ ### Fixed
31
+
32
+ - Anthropic thinking blocks emptied by `clear_thinking` now drop stale signatures before replay, preventing every subsequent request from failing with an invalid thinking-block signature (#4247, reported by @probepark).
33
+ - Coalesced double-Esc and triple-Esc input now emits individual Escape presses under tmux and SSH, while split ambiguous Escape sequences stay buffered until a continuation or flush timeout resolves them (#4312 by @Yeachan-Heo).
34
+ - Apple Terminal.app now retains its default keyboard mode when Kitty keyboard support is unavailable, preserving Korean/Hangul IME composition (#4297 by @Yeachan-Heo).
35
+ - Managed output publication no longer freezes the resident event loop when a no-replace rename stalls in the kernel. Async publication now uses asynchronous file operations and native blocking-pool rename/link boundaries, while per-session stores reap scrubbed protocol remnants on a throttled, serialized schedule (#4396 by @Yeachan-Heo; fixes #4394).
36
+ - The Telegram notification daemon now contains transient Windows state and ownership-lock read failures during steady heartbeat renewal instead of terminating its run loop; staging files are cleaned in a `finally` block, and only a proven ownership mismatch stops the owner (by @Yeachan-Heo; issue #4200).
37
+ - Coordinator MCP now answers the standard `ping` keepalive with an empty result instead of `method not found`, preventing liveness clients from reconnecting repeatedly (#4412 by @developjik).
38
+ - Task-launched canonical subagents no longer receive an ACP exact-config `toolsOnly` MCP manager that they are forbidden to reuse, restoring Planner, Architect, Critic, and Ralplan consensus launches (#4419 by @chlee1001).
39
+ - The SDK broker's Windows process-liveness probe no longer opens a console window on every poll; its PowerShell fallback now passes `windowsHide` so a dead or inaccessible process cannot trigger a continuous focus-stealing terminal flash (#4346 by @Dayoooun).
40
+ - Foreground Bash calls that finish before their auto-background deadline now cancel that deadline instead of leaving a sleep behind that keeps compiled print-mode processes alive (#4256 by @probepark).
41
+ - Prompt suggestions now remain visible after cancelling another interactive action and returning to the composer (#4347 by @thegreatesthoneybee).
42
+
5
43
  ## [0.13.1] - 2026-08-11
6
44
 
7
45
  ### Added
@@ -12,6 +50,7 @@
12
50
  - Custom OpenAI-compatible providers can opt into `/fast` forwarding with `compat.supportsServiceTier: true`; first-class OpenCodex discovery enables it automatically so client `service_tier: "priority"` reaches an OpenCodex proxy running in passthrough (`Auto`) mode.
13
51
 
14
52
  ### Fixed
53
+ - Foreground Bash calls that finish before their auto-background deadline now cancel that deadline instead of leaving an uncancellable `Bun.sleep()` behind. In print mode the losing sleep kept the compiled CLI alive for the full command timeout after Bash and subagent work had already completed, which appeared as a shutdown hang with no active Node handles.
15
54
  - A just-created or just-registered SDK session no longer reads as not-live (failing immediate `session.close`/`session.delete`, endpoint resolution, and chat-daemon attachment) for up to one heartbeat interval: the host-written registration now counts as initial liveness evidence, aging out exactly like a heartbeat, with the OS process-incarnation match still required. The broker's shutdown-escalation identity proof also accepts the incarnation the index auto-stamps at registration, and ACP `session/list` no longer advertises or re-adopts closed/unregistered (DR-1 terminal) rows — repeated ACP deletes answer already-gone instead of escalating against a host that no longer exists.
16
55
  - Insane public-route search now cancels and rejects response bodies larger than 1 MiB instead of buffering unbounded feed, HTML, or JSON payloads.
17
56
  - The Telegram notification daemon no longer terminates with an uncaught `EPERM` when publishing its heartbeat sidecar while an external Windows file lock (antivirus, indexer) briefly holds the destination. The rename is retried a bounded number of times under the ownership-lock fence, a still-failing publication is contained as a diagnostic-logged transient (the next heartbeat cycle republishes), and only a proven ownership loss stops the daemon; the stale-writer fence and staging-temp cleanup are preserved on every path (#4200).
@@ -132,6 +171,8 @@
132
171
  - Profile activation/materialization, memory maintenance, interactive selectors, slash-command assignment, model-profile previews, and SDK extension contexts now use the same explicit credential identity as request dispatch; canonical session IDs remain reserved for sticky routing and provider transport/cache identities remain isolated.
133
172
  - Task subagents and branch commit-message generation now inherit the parent's credential identity separately from logical/canonical state. Extension model preflight, custom tools (including image generation and web search), title/prompt maintenance, background ephemeral metadata, and profile materialization use the same credential scope. Preset landing auth now requires usable effective credentials rather than catalog presence alone.
134
173
  - SDK tool sessions, deferred SDK selectors, slash-command aliases, memory role resolution, and provider-order status now carry credential identity. Provider alias invalidation updates canonical storage/backoff/session state, and preset landing availability is derived from actual credential-scoped `getApiKey` results (including keyless providers) rather than credential-type metadata.
174
+ - Prompt suggestions now remain visible after cancelling another interactive action and returning to the composer.
175
+
135
176
  - `todo_write` and `ask` no longer reject valid calls before the tool loads. Both tools carried two independent copies of their raw-argument rules — one in the loaded tool, one in the cold descriptor registry that runs first — and the deferred copies had drifted: `todo_write`'s dropped the `content` synonym for `task` and the `complete`/`completed` aliases for `done`, accepted targetless `complete` entries the loaded tool rejects, and returned every rejection without its correction code, so the model saw a bare "raw arguments rejected before coercion" with nothing to fix and retried the same shape until the turn died. Both also rejected the harness's own injected `_i` intent field, failing any call carrying it with an unknown-root-key error the model could not repair. `todo_write` validation now lives in a single shared contract module (`tools/todo-contract.ts`) used by both paths, and both tools tolerate `_i` at the root while still rejecting genuinely unknown keys.
136
177
  - A stalled ACP session is no longer unrecoverable. The SDK host drops a session whose client has not ponged within `HEARTBEAT_TTL_MS` (20s), but the ACP client inherited the transport's one-shot reconnect defaults — 3 attempts at a 25ms base backoff, a total budget of 175ms — so any event-loop stall long enough for the host to reap the session exceeded the client's entire retry window by two orders of magnitude and surfaced as a terminal `-32603 ACP session transport was lost: SDK WebSocket reconnect attempts exhausted`. Under machine load this killed long-running agent sessions outright while their processes stayed alive. The ACP adapter and the broker connection now share an explicit `ACP_SESSION_RECONNECT` budget derived from `HEARTBEAT_TTL_MS` rather than a magic number: backoff ramps 250ms → 500ms → 1s and holds at a 2s cap for 23 attempts (~41.75s), so the client outlives twice the host TTL while individual sleeps stay short enough to reattach promptly once the host answers again.
137
178
  - Managed scope prepare and legacy-local resume no longer report success while group/other-readable descendants remain on disk (e.g. mode `0o036`/`0o644`): prepare uses a mode-only walk (not `snapshotManagedTree("")`, which races concurrent writers and broke `/move`) to detect drift, re-secures with apply+verify, and retries once; legacy-local capture uses the same resecure helper.
@@ -34,6 +34,7 @@ export interface GjcModelAssignmentTargetInfo extends ModelRoleInfo {
34
34
  }
35
35
  export { GJC_MODEL_ASSIGNMENT_TARGET_IDS };
36
36
  export declare const GJC_MODEL_ASSIGNMENT_TARGETS: Record<GjcModelAssignmentTargetId, GjcModelAssignmentTargetInfo>;
37
+ export declare function requiresExplicitThinkingChoice(model: Model, role: GjcModelAssignmentTargetId | null): boolean;
37
38
  /** Alias for ModelRoleInfo - used for both built-in and custom roles */
38
39
  export type RoleInfo = ModelRoleInfo;
39
40
  /**
@@ -704,18 +704,18 @@ export declare const SETTINGS_SCHEMA: {
704
704
  };
705
705
  readonly "pet.mode": {
706
706
  readonly type: "enum";
707
- readonly values: readonly ["off", "red", "blue"];
707
+ readonly values: readonly ["off", "red", "blue", "ouroboros"];
708
708
  readonly default: "off";
709
709
  readonly ui: {
710
710
  readonly tab: "appearance";
711
711
  readonly label: "Gajae Pet";
712
- readonly description: "16x16 real-pixel gajae living beside the composer (sixel/kitty terminals)";
712
+ readonly description: "Real-pixel pet living beside the composer (sixel/kitty terminals)";
713
713
  readonly options: readonly [{
714
714
  readonly value: "off";
715
715
  readonly label: "Off";
716
716
  readonly description: "No pet";
717
717
  }, ...{
718
- value: "blue" | "red";
718
+ value: "blue" | "ouroboros" | "red";
719
719
  label: string;
720
720
  description: string;
721
721
  }[]];
@@ -132,6 +132,7 @@ export interface RunRootCommandDependencies {
132
132
  getChangelogForDisplay?: typeof getChangelogForDisplay;
133
133
  createInteractiveMode?: CreateInteractiveMode;
134
134
  runPrintMode?: RunPrintMode;
135
+ quit?: (code: number) => Promise<void>;
135
136
  isResumePickerTerminal?: ResumePickerTerminalCheck;
136
137
  listForResumePickerReadOnly?: ListForResumePickerReadOnly;
137
138
  listManagedForResumePickerReadOnly?: ListManagedForResumePickerReadOnly;
@@ -0,0 +1,9 @@
1
+ import { type Component } from "@gajae-code/tui";
2
+ /** Text whose styling is resolved at render time so live theme previews recolor open overlays. */
3
+ export declare class DynamicThemeText implements Component {
4
+ #private;
5
+ private readonly getText;
6
+ constructor(getText: () => string);
7
+ invalidate(): void;
8
+ render(width: number): string[];
9
+ }
@@ -16,8 +16,8 @@ export declare class PetFramedEditor implements Component {
16
16
  render(width: number): string[];
17
17
  }
18
18
  /**
19
- * The gajae pet: a 16x16 real-pixel sprite living in a reserved area beside
20
- * the composer. It is nearest-neighbor scaled to the two terminal rows occupied
19
+ * The gajae pet: a real-pixel sprite living in a reserved area beside the
20
+ * composer. It is nearest-neighbor scaled to the two terminal rows occupied
21
21
  * by an empty one-line composer and lifted one row so its feet meet the input
22
22
  * box's bottom edge.
23
23
  *
@@ -39,15 +39,15 @@ export declare class GajaePetWidget {
39
39
  isWorking: () => boolean;
40
40
  /** Rows rendered below the composer box (pet floor + hook widgets). */
41
41
  getComposerBottomOffset: () => number;
42
- forcePixelProtocol?: "sixel" | "kitty";
42
+ forcePixelProtocol?: "sixel" | "kitty" | "iterm2";
43
43
  /** Random [min, max] ms between auto-flexes; null disables. */
44
44
  autoFlexGapMs?: [number, number] | null;
45
45
  });
46
46
  /** Protocol available for the real-pixel pet, if any. */
47
- static pixelProtocol(): "sixel" | "kitty" | null;
47
+ static pixelProtocol(): "sixel" | "kitty" | "iterm2" | null;
48
48
  get mode(): PetMode;
49
49
  get isFlexing(): boolean;
50
- setMode(mode: PetMode): void;
50
+ setMode(mode: string): void;
51
51
  /** Live preview during a selector: change the sprite without re-mounting the
52
52
  * composer editor (that would tear down the open overlay). After a short idle
53
53
  * eye-roll it fires the signature burst once (RedGajae flex, BlueGajae para-para
@@ -1,10 +1,10 @@
1
1
  import { type SelectItem } from "@gajae-code/tui";
2
- export type PetPixelProtocol = "sixel" | "kitty";
3
- export declare const PET_UNAVAILABLE_DESCRIPTION = "Unavailable: requires compatible Kitty or Sixel overlay rendering";
4
- export declare const PET_SAVED_UNAVAILABLE_DESCRIPTION = "Saved, unavailable \u2014 requires compatible Kitty or Sixel overlay rendering";
5
- export declare const PET_UNAVAILABLE_WARNING = "\u26A0 Pets aren\u2019t available in this terminal. Its image support isn\u2019t compatible with Gajae Pet\u2019s overlay rendering yet. Try Kitty, Ghostty, WezTerm, or a terminal with compatible Sixel support.";
2
+ export type PetPixelProtocol = "sixel" | "kitty" | "iterm2";
3
+ export declare const PET_UNAVAILABLE_DESCRIPTION = "Unavailable: requires compatible Kitty, iTerm2, or Sixel overlay rendering";
4
+ export declare const PET_SAVED_UNAVAILABLE_DESCRIPTION = "Saved, unavailable \u2014 requires compatible Kitty, iTerm2, or Sixel overlay rendering";
5
+ export declare const PET_UNAVAILABLE_WARNING = "\u26A0 Pets aren\u2019t available in this terminal. Its image support isn\u2019t compatible with Gajae Pet\u2019s overlay rendering yet. Try Kitty, Ghostty, WezTerm, iTerm2, or a terminal with compatible Sixel support.";
6
6
  export declare function getPetUnavailableWarning(env?: NodeJS.ProcessEnv): string;
7
- export declare function getPetPixelProtocol(): PetPixelProtocol | null;
7
+ export declare function getPetPixelProtocol(env?: NodeJS.ProcessEnv): PetPixelProtocol | null;
8
8
  export declare function isPetAvailable(): boolean;
9
9
  export declare function createPetSelectItems(options: ReadonlyArray<SelectItem>, currentValue: string, available: boolean): SelectItem[];
10
10
  /**
@@ -52,6 +52,11 @@ export interface SettingsCallbacks {
52
52
  onThemePreview?: (theme: string) => void | Promise<void>;
53
53
  /** Called to restore the rendered theme when theme settings preview is cancelled */
54
54
  onThemePreviewCancel?: (theme: string) => void | Promise<void>;
55
+ /**
56
+ * Atomically apply and persist a theme selection. Returns false when the
57
+ * candidate could not be loaded, leaving the submenu open.
58
+ */
59
+ onThemeCommit?: (path: "theme.dark" | "theme.light", theme: string, previousTheme: string) => Promise<boolean>;
55
60
  /** Called to live-preview the gajae pet skin while browsing the pet setting. */
56
61
  onPetPreview?: (mode: string) => void;
57
62
  /**
@@ -526,6 +526,124 @@ export declare const defaultThemes: {
526
526
  preset: string;
527
527
  };
528
528
  };
529
+ ouroboros: {
530
+ $schema: string;
531
+ name: string;
532
+ vars: {
533
+ cyan: string;
534
+ blue: string;
535
+ green: string;
536
+ red: string;
537
+ yellow: string;
538
+ gray: string;
539
+ dimGray: string;
540
+ darkGray: string;
541
+ accent: string;
542
+ selectedBg: string;
543
+ userMsgBg: string;
544
+ toolPendingBg: string;
545
+ toolSuccessBg: string;
546
+ toolErrorBg: string;
547
+ customMsgBg: string;
548
+ abyss: string;
549
+ deepNavy: string;
550
+ mantle: string;
551
+ surface: string;
552
+ surfaceBright: string;
553
+ ouroTeal: string;
554
+ serpentGreen: string;
555
+ petLime: string;
556
+ ritualGold: string;
557
+ eyeGold: string;
558
+ coolScale: string;
559
+ foam: string;
560
+ mutedScale: string;
561
+ dimScale: string;
562
+ dangerRed: string;
563
+ diffRemovalRed: string;
564
+ };
565
+ colors: {
566
+ accent: string;
567
+ border: string;
568
+ borderAccent: string;
569
+ borderMuted: string;
570
+ success: string;
571
+ error: string;
572
+ warning: string;
573
+ muted: string;
574
+ dim: string;
575
+ text: string;
576
+ thinkingText: string;
577
+ selectedBg: string;
578
+ userMessageBg: string;
579
+ userMessageText: string;
580
+ customMessageBg: string;
581
+ customMessageText: string;
582
+ customMessageLabel: string;
583
+ toolPendingBg: string;
584
+ toolSuccessBg: string;
585
+ toolErrorBg: string;
586
+ toolTitle: string;
587
+ toolOutput: string;
588
+ mdHeading: string;
589
+ mdLink: string;
590
+ mdLinkUrl: string;
591
+ mdCode: string;
592
+ mdCodeBlock: string;
593
+ mdCodeBlockBorder: string;
594
+ mdQuote: string;
595
+ mdQuoteBorder: string;
596
+ mdHr: string;
597
+ mdListBullet: string;
598
+ toolDiffAdded: string;
599
+ toolDiffRemoved: string;
600
+ toolDiffContext: string;
601
+ syntaxComment: string;
602
+ syntaxKeyword: string;
603
+ syntaxFunction: string;
604
+ syntaxVariable: string;
605
+ syntaxString: string;
606
+ syntaxNumber: string;
607
+ syntaxType: string;
608
+ syntaxOperator: string;
609
+ syntaxPunctuation: string;
610
+ thinkingOff: string;
611
+ thinkingMinimal: string;
612
+ thinkingLow: string;
613
+ thinkingMedium: string;
614
+ thinkingHigh: string;
615
+ thinkingXhigh: string;
616
+ bashMode: string;
617
+ statusLineBg: string;
618
+ statusLineSep: string;
619
+ statusLineModel: string;
620
+ statusLinePath: string;
621
+ statusLineGitClean: string;
622
+ statusLineGitDirty: string;
623
+ statusLineContext: string;
624
+ statusLineSpend: string;
625
+ statusLineStaged: string;
626
+ statusLineDirty: string;
627
+ statusLineUntracked: string;
628
+ statusLineOutput: string;
629
+ statusLineCost: string;
630
+ statusLineSubagents: string;
631
+ pythonMode: string;
632
+ };
633
+ export: {
634
+ pageBg: string;
635
+ cardBg: string;
636
+ infoBg: string;
637
+ };
638
+ symbols: {
639
+ preset: string;
640
+ overrides: {
641
+ "icon.pi": string;
642
+ "status.running": string;
643
+ "md.bullet": string;
644
+ };
645
+ };
646
+ };
529
647
  "red-claw": {
530
648
  $schema: string;
531
649
  name: string;
@@ -103,8 +103,10 @@ export declare const NOTIFICATION_PROTOCOL_VERSION = 3;
103
103
  * settles non-forum close responses. Generation 62 rejects replay-gap
104
104
  * authority claims that do not match the requested cursor, answer bounds,
105
105
  * and retained replay suffix.
106
+ * Generation 63 contains transient steady-heartbeat state and ownership-lock
107
+ * read failures and cleans every staged sidecar before retrying (#4200).
106
108
  */
107
- export declare const DAEMON_GENERATION = 62;
109
+ export declare const DAEMON_GENERATION = 63;
108
110
  /**
109
111
  * Serving-compatibility boundary for daemon lifecycle requests. Epoch 5
110
112
  * requires the complete generation-36 topic authority contract, so older
@@ -87,6 +87,10 @@ export interface ManagedBoundedAppendExpectation {
87
87
  readonly ctimeNs: string;
88
88
  readonly sha256: string;
89
89
  }
90
+ export interface ScrubbedProtocolRemnantReapResult {
91
+ readonly reaped: number;
92
+ readonly failures: number;
93
+ }
90
94
  /**
91
95
  * Best-effort removal of scrubbed write-protocol remnants from one managed
92
96
  * directory. Only zero-length, single-link, non-symlink regular files whose
@@ -98,6 +102,15 @@ export interface ManagedBoundedAppendExpectation {
98
102
  * have reconciled any candidate.
99
103
  */
100
104
  export declare function reapScrubbedProtocolRemnantsSync(directory: string, minAgeMs?: number): number;
105
+ /**
106
+ * Async twin of {@link reapScrubbedProtocolRemnantsSync} with the same safety
107
+ * filters (terminal remnant prefix, zero-length, single-link, non-symlink,
108
+ * older than the age gate), yielding between bounded batches. Long-lived
109
+ * processes reap per-session descendant directories through this path so a
110
+ * legacy oversized directory cannot starve timers or sibling subagents while
111
+ * it is being drained (issue #4394).
112
+ */
113
+ export declare function reapScrubbedProtocolRemnants(directory: string, minAgeMs?: number): Promise<ScrubbedProtocolRemnantReapResult>;
101
114
  export declare function validateNativeSecurityResult(value: unknown, operation: "apply" | "verify", kind: "directory" | "file"): NativeOwnerOnlySecurityResult;
102
115
  export interface ManagedLockRetirementTestEvent {
103
116
  readonly path: string;
@@ -1130,6 +1130,13 @@ export declare class SessionManager {
1130
1130
  listForResumePickerReadOnly(): Promise<SessionInfo[]>;
1131
1131
  getSessionId(): string;
1132
1132
  getSessionFile(): string | undefined;
1133
+ /**
1134
+ * On-disk transcript file size in bytes. Returns 0 when the file is
1135
+ * unavailable, unreadable, or no session file is set. The managed-storage
1136
+ * path reads through the descriptor (no full-file scan); the plain-file
1137
+ * path uses statSync.
1138
+ */
1139
+ getTranscriptFileBytes(): number;
1133
1140
  getSessionMemoryStats(): SessionMemoryStats;
1134
1141
  setSessionMemoryMode(mode: SessionMemoryMode): void;
1135
1142
  acquireMemoryGuardParticipantIngressLease(): MemoryGuardParticipantIngressLease;
@@ -3,6 +3,7 @@ import * as z from "zod/v4";
3
3
  import { type ModelRegistry } from "../config/model-registry";
4
4
  import type { Settings } from "../config/settings";
5
5
  import type { CustomTool } from "../extensibility/custom-tools/types";
6
+ export declare function redactImageProviderText(value: unknown, activeApiKey?: string): string;
6
7
  type ImageProvider = "alibaba" | "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter" | (string & {});
7
8
  declare const responseModalitySchema: z.ZodEnum<{
8
9
  IMAGE: "IMAGE";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.13.1",
4
+ "version": "0.13.3",
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",
@@ -54,13 +54,13 @@
54
54
  "@agentclientprotocol/sdk": "1.3.0",
55
55
  "@babel/parser": "^7.29.3",
56
56
  "@mozilla/readability": "^0.6.0",
57
- "@gajae-code/stats": "0.13.1",
58
- "@gajae-code/agent-core": "0.13.1",
59
- "@gajae-code/ai": "0.13.1",
60
- "@gajae-code/bridge-client": "0.13.1",
61
- "@gajae-code/natives": "0.13.1",
62
- "@gajae-code/tui": "0.13.1",
63
- "@gajae-code/utils": "0.13.1",
57
+ "@gajae-code/stats": "0.13.3",
58
+ "@gajae-code/agent-core": "0.13.3",
59
+ "@gajae-code/ai": "0.13.3",
60
+ "@gajae-code/bridge-client": "0.13.3",
61
+ "@gajae-code/natives": "0.13.3",
62
+ "@gajae-code/tui": "0.13.3",
63
+ "@gajae-code/utils": "0.13.3",
64
64
  "@puppeteer/browsers": "^2.13.0",
65
65
  "@types/turndown": "5.0.6",
66
66
  "@xterm/headless": "^6.0.0",
@@ -572,7 +572,9 @@ function rewriteSelectorForProxy(
572
572
  const proxyModels = allModels.filter(model => model.provider === proxyProvider);
573
573
  if (slash < 0) {
574
574
  if (proxyMode === "fallback") return selector;
575
- const matches = proxyModels.filter(model => model.id === baseSelector);
575
+ const exactMatches = proxyModels.filter(model => model.id === baseSelector);
576
+ const finalSegmentMatches = proxyModels.filter(model => model.id.split("/").at(-1) === baseSelector);
577
+ const matches = exactMatches.length > 0 ? exactMatches : finalSegmentMatches;
576
578
  if (matches.length !== 1) {
577
579
  throw new Error(
578
580
  `Configured proxy "${proxyProvider}" does not expose an unambiguous model for "${baseSelector}"`,
@@ -134,6 +134,27 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
134
134
  critic: "gpt-5.6-luna:xhigh",
135
135
  architect: "gpt-5.6-luna:xhigh",
136
136
  }),
137
+ profile("open-weights-spark", [], {
138
+ default: "muse-spark-1.2:medium",
139
+ executor: "muse-spark-1.2:low",
140
+ planner: "muse-spark-1.2:high",
141
+ critic: "muse-spark-1.2:high",
142
+ architect: "muse-spark-1.2:xhigh",
143
+ }),
144
+ profile("open-weights-spark-deepseek", [], {
145
+ default: "muse-spark-1.2:medium",
146
+ executor: "deepseek-v4-flash:high",
147
+ planner: "muse-spark-1.2:high",
148
+ critic: "muse-spark-1.2:high",
149
+ architect: "muse-spark-1.2:xhigh",
150
+ }),
151
+ profile("open-weights-spark-luna", [], {
152
+ default: "muse-spark-1.2:medium",
153
+ executor: "gpt-5.6-luna:high",
154
+ planner: "muse-spark-1.2:high",
155
+ critic: "muse-spark-1.2:high",
156
+ architect: "muse-spark-1.2:xhigh",
157
+ }),
137
158
  profile("open-weights-glm-deepseek", [], {
138
159
  default: "glm-5.2:medium",
139
160
  executor: "deepseek-v4-flash:high",
@@ -279,7 +300,7 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
279
300
  }),
280
301
  profile("grok-45-eco", ["xai"], {
281
302
  default: "xai/grok-4.5:low",
282
- executor: "xai/grok-4.5:minimal",
303
+ executor: "xai/grok-4.5:low",
283
304
  planner: "xai/grok-4.5:low",
284
305
  critic: "xai/grok-4.5:medium",
285
306
  architect: "xai/grok-4.5:high",
@@ -298,6 +319,27 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
298
319
  critic: "xai/grok-4.5:high",
299
320
  architect: "xai/grok-4.5:high",
300
321
  }),
322
+ profile("grok-46-eco", ["xai"], {
323
+ default: "xai/grok-4.6:low",
324
+ executor: "xai/grok-4.6:low",
325
+ planner: "xai/grok-4.6:low",
326
+ critic: "xai/grok-4.6:medium",
327
+ architect: "xai/grok-4.6:high",
328
+ }),
329
+ profile("grok-46-medium", ["xai"], {
330
+ default: "xai/grok-4.6:medium",
331
+ executor: "xai/grok-4.6:low",
332
+ planner: "xai/grok-4.6:medium",
333
+ critic: "xai/grok-4.6:high",
334
+ architect: "xai/grok-4.6:high",
335
+ }),
336
+ profile("grok-46-pro", ["xai"], {
337
+ default: "xai/grok-4.6:xhigh",
338
+ executor: "xai/grok-4.6:medium",
339
+ planner: "xai/grok-4.6:high",
340
+ critic: "xai/grok-4.6:xhigh",
341
+ architect: "xai/grok-4.6:xhigh",
342
+ }),
301
343
  profile("grok-build-pro", ["grok-build"], {
302
344
  default: "grok-build/grok-composer-2.5-fast",
303
345
  executor: "grok-build/grok-build",
@@ -444,6 +486,15 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
444
486
  },
445
487
  "open-weights-kimi": { displayName: "Kimi", providerGroup: "OPEN WEIGHT MODELS (PROVIDER AGNOSTIC)" },
446
488
  "open-weights-luna": { displayName: "Luna", providerGroup: "OPEN WEIGHT MODELS (PROVIDER AGNOSTIC)" },
489
+ "open-weights-spark": { displayName: "Muse Spark", providerGroup: "OPEN WEIGHT MODELS (PROVIDER AGNOSTIC)" },
490
+ "open-weights-spark-deepseek": {
491
+ displayName: "Muse Spark + DeepSeek",
492
+ providerGroup: "OPEN WEIGHT MODELS (PROVIDER AGNOSTIC)",
493
+ },
494
+ "open-weights-spark-luna": {
495
+ displayName: "Muse Spark + Luna",
496
+ providerGroup: "OPEN WEIGHT MODELS (PROVIDER AGNOSTIC)",
497
+ },
447
498
  "open-weights-glm-deepseek": {
448
499
  displayName: "GLM + DeepSeek",
449
500
  providerGroup: "OPEN WEIGHT MODELS (PROVIDER AGNOSTIC)",
@@ -481,6 +532,9 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
481
532
  "grok-45-eco": { displayName: "Grok 4.5 Eco", providerGroup: "GROK" },
482
533
  "grok-45-medium": { displayName: "Grok 4.5 Medium", providerGroup: "GROK" },
483
534
  "grok-45-pro": { displayName: "Grok 4.5 Pro", providerGroup: "GROK" },
535
+ "grok-46-eco": { displayName: "Grok 4.6 Eco", providerGroup: "GROK" },
536
+ "grok-46-medium": { displayName: "Grok 4.6 Medium", providerGroup: "GROK" },
537
+ "grok-46-pro": { displayName: "Grok 4.6 Pro", providerGroup: "GROK" },
484
538
  "grok-build-pro": { displayName: "Grok Build Pro", providerGroup: "GROK" },
485
539
  "cursor-eco": { displayName: "Cursor Eco", providerGroup: "CURSOR" },
486
540
  "cursor-medium": { displayName: "Cursor Medium", providerGroup: "CURSOR" },
@@ -518,6 +572,9 @@ const OPEN_WEIGHT_PROFILE_ORDER = [
518
572
  "open-weights-deepseek",
519
573
  "open-weights-kimi",
520
574
  "open-weights-luna",
575
+ "open-weights-spark",
576
+ "open-weights-spark-deepseek",
577
+ "open-weights-spark-luna",
521
578
  "open-weights-glm-deepseek",
522
579
  "open-weights-kimi-deepseek",
523
580
  "open-weights-kimi-glm",
@@ -536,7 +593,7 @@ const PROFILE_RECOMMENDATIONS: Record<string, string> = {
536
593
  "xiaomi-token-plan-sgp": "mimo-medium",
537
594
  "xiaomi-token-plan-ams": "mimo-medium",
538
595
  "xiaomi-token-plan-cn": "mimo-medium",
539
- xai: "grok-medium",
596
+ xai: "grok-46-medium",
540
597
  "grok-build": "grok-build-pro",
541
598
  cursor: "cursor-medium",
542
599
  "minimax-code": "minimax-medium",
@@ -5,6 +5,7 @@ import {
5
5
  type AssistantMessageEventStream,
6
6
  type AuthCredentialSelector,
7
7
  applyFinalCodexGpt56ContextCap,
8
+ applyGeneratedModelPolicies,
8
9
  type CacheRetention,
9
10
  CODEX_GPT_5_6_CONTEXT_CAP,
10
11
  type Context,
@@ -171,6 +172,17 @@ export const GJC_MODEL_ASSIGNMENT_TARGETS: Record<GjcModelAssignmentTargetId, Gj
171
172
  image: { id: "image", tag: "IMAGE", name: "Image", color: "accent", settingsPath: "modelRoles" },
172
173
  };
173
174
 
175
+ export function requiresExplicitThinkingChoice(model: Model, role: GjcModelAssignmentTargetId | null): boolean {
176
+ if (model.reasoning !== true) return false;
177
+ if (
178
+ model.provider === "openai" ||
179
+ model.provider === "openai-codex" ||
180
+ (model.provider === "xai" && (model.id === "grok-4.5" || model.id === "grok-4.6"))
181
+ )
182
+ return true;
183
+ return role !== null && GJC_MODEL_ASSIGNMENT_TARGETS[role].settingsPath === "task.agentModelOverrides";
184
+ }
185
+
174
186
  /** Alias for ModelRoleInfo - used for both built-in and custom roles */
175
187
  export type RoleInfo = ModelRoleInfo;
176
188
 
@@ -1634,7 +1646,9 @@ export class ModelRegistry {
1634
1646
  const withTransport = providerOverride
1635
1647
  ? models.map(model => this.#applyProviderTransportOverride(model, providerOverride))
1636
1648
  : models;
1637
- cachedModels.push(...this.#applyProviderModelOverrides(descriptor.providerId, withTransport));
1649
+ const normalized = this.#applyProviderModelOverrides(descriptor.providerId, withTransport);
1650
+ applyGeneratedModelPolicies(normalized);
1651
+ cachedModels.push(...normalized);
1638
1652
  }
1639
1653
  return cachedModels;
1640
1654
  }
@@ -1650,6 +1664,7 @@ export class ModelRegistry {
1650
1664
  this.#applyProviderCompat(providerConfig.compat, [...models]),
1651
1665
  ),
1652
1666
  );
1667
+ applyGeneratedModelPolicies(normalized);
1653
1668
  cachedModels.push(...normalized);
1654
1669
  }
1655
1670
  return cachedModels;
@@ -752,7 +752,7 @@ export const SETTINGS_SCHEMA = {
752
752
  ui: {
753
753
  tab: "appearance",
754
754
  label: "Gajae Pet",
755
- description: "16x16 real-pixel gajae living beside the composer (sixel/kitty terminals)",
755
+ description: "Real-pixel pet living beside the composer (sixel/kitty terminals)",
756
756
  options: [
757
757
  { value: "off", label: "Off", description: "No pet" },
758
758
  ...PET_SKIN_IDS.map(id => ({
@@ -5693,6 +5693,9 @@ export function createCoordinatorMcpServer(options: CoordinatorMcpServerOptions
5693
5693
  },
5694
5694
  };
5695
5695
  }
5696
+ if (request.method === "ping") {
5697
+ return { jsonrpc: "2.0", id, result: {} };
5698
+ }
5696
5699
  if (request.method === "tools/list") {
5697
5700
  return { jsonrpc: "2.0", id, result: { tools: COORDINATOR_MCP_TOOL_NAMES.map(toolSchema) } };
5698
5701
  }