@gajae-code/coding-agent 0.12.11 → 0.12.12

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 (112) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/types/cli/notify-cli.d.ts +42 -1
  3. package/dist/types/cli/update-cli.d.ts +9 -3
  4. package/dist/types/commands/notify.d.ts +6 -0
  5. package/dist/types/config/file-lock.d.ts +3 -0
  6. package/dist/types/coordinator/contract.d.ts +1 -1
  7. package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
  8. package/dist/types/extensibility/extensions/index.d.ts +1 -0
  9. package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
  10. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
  11. package/dist/types/extensibility/extensions/types.d.ts +2 -0
  12. package/dist/types/main.d.ts +6 -2
  13. package/dist/types/modes/components/session-selector.d.ts +1 -1
  14. package/dist/types/modes/utils/host-status.d.ts +23 -0
  15. package/dist/types/runtime-mcp/types.d.ts +2 -0
  16. package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
  17. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
  18. package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
  19. package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
  20. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
  21. package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
  22. package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
  23. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
  24. package/dist/types/sdk/bus/notification-service.d.ts +10 -0
  25. package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
  26. package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
  27. package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
  28. package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
  29. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
  30. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +24 -7
  31. package/dist/types/sdk/bus/telegram-daemon.d.ts +104 -16
  32. package/dist/types/sdk/bus/telegram-reference.d.ts +10 -1
  33. package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
  34. package/dist/types/sdk/host/host.d.ts +52 -0
  35. package/dist/types/sdk/lifecycle-session.d.ts +6 -0
  36. package/dist/types/sdk/session-activation.d.ts +41 -0
  37. package/dist/types/sdk/session.d.ts +18 -0
  38. package/dist/types/sdk/startup-capability.d.ts +8 -1
  39. package/dist/types/session/agent-session.d.ts +7 -0
  40. package/dist/types/session/artifacts.d.ts +2 -2
  41. package/dist/types/session/session-manager.d.ts +23 -5
  42. package/dist/types/tools/index.d.ts +8 -0
  43. package/dist/types/utils/npm-registry.d.ts +71 -0
  44. package/examples/extensions/README.md +38 -4
  45. package/examples/extensions/ooo-bridge.ts +15 -0
  46. package/package.json +8 -8
  47. package/scripts/generate-sdk-operation-inventory.ts +4 -0
  48. package/src/async/job-manager.ts +9 -2
  49. package/src/cli/notify-cli.ts +226 -2
  50. package/src/cli/update-cli.ts +90 -23
  51. package/src/commands/notify.ts +27 -3
  52. package/src/commands/sdk.ts +1 -0
  53. package/src/config/file-lock-gc.ts +18 -0
  54. package/src/config/file-lock.ts +61 -16
  55. package/src/config/model-profiles.ts +31 -15
  56. package/src/coordinator/contract.ts +1 -0
  57. package/src/coordinator-mcp/question-state.ts +2 -0
  58. package/src/coordinator-mcp/server.ts +358 -7
  59. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
  60. package/src/extensibility/extensions/index.ts +1 -0
  61. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
  62. package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
  63. package/src/extensibility/extensions/runner.ts +15 -2
  64. package/src/extensibility/extensions/types.ts +2 -0
  65. package/src/gjc-runtime/launch-tmux.ts +53 -1
  66. package/src/internal-urls/docs-index.generated.ts +11 -10
  67. package/src/main.ts +203 -67
  68. package/src/modes/DESIGN.md +8 -5
  69. package/src/modes/components/footer.ts +10 -18
  70. package/src/modes/components/session-selector.ts +26 -3
  71. package/src/modes/components/status-line/gh.ts +23 -2
  72. package/src/modes/controllers/event-controller.ts +3 -0
  73. package/src/modes/controllers/extension-ui-controller.ts +2 -0
  74. package/src/modes/controllers/input-controller.ts +11 -0
  75. package/src/modes/controllers/selector-controller.ts +8 -2
  76. package/src/modes/interactive-mode.ts +7 -1
  77. package/src/modes/utils/host-status.ts +38 -0
  78. package/src/runtime-mcp/types.ts +2 -0
  79. package/src/sdk/broker/lifecycle.ts +60 -3
  80. package/src/sdk/bus/chat-daemon-cli.ts +42 -0
  81. package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
  82. package/src/sdk/bus/chat-daemon-control.ts +16 -3
  83. package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
  84. package/src/sdk/bus/control-plane-frames.ts +51 -0
  85. package/src/sdk/bus/conversation-store.ts +29 -1
  86. package/src/sdk/bus/existing-thread-readiness.ts +155 -0
  87. package/src/sdk/bus/index.ts +70 -0
  88. package/src/sdk/bus/notification-service.ts +28 -1
  89. package/src/sdk/bus/rich-render.ts +3 -2
  90. package/src/sdk/bus/slack-daemon.ts +99 -4
  91. package/src/sdk/bus/slack-live-provider.ts +32 -2
  92. package/src/sdk/bus/slack-provider.ts +11 -0
  93. package/src/sdk/bus/slack-thread-binding.ts +641 -0
  94. package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
  95. package/src/sdk/bus/telegram-daemon-contract.ts +24 -7
  96. package/src/sdk/bus/telegram-daemon.ts +1961 -497
  97. package/src/sdk/bus/telegram-reference.ts +42 -6
  98. package/src/sdk/bus/topic-registry.ts +674 -181
  99. package/src/sdk/host/host.ts +180 -1
  100. package/src/sdk/lifecycle-session.ts +8 -2
  101. package/src/sdk/protocol/operation-inventory.generated.json +22 -0
  102. package/src/sdk/session-activation.ts +127 -0
  103. package/src/sdk/session.ts +139 -28
  104. package/src/sdk/startup-capability.ts +10 -1
  105. package/src/session/agent-session.ts +220 -9
  106. package/src/session/artifacts.ts +56 -13
  107. package/src/session/internal/managed-session-storage.ts +206 -7
  108. package/src/session/session-manager.ts +148 -38
  109. package/src/setup/provider-presets.json +1 -1
  110. package/src/task/index.ts +92 -44
  111. package/src/tools/index.ts +8 -0
  112. package/src/utils/npm-registry.ts +660 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.12.12] - 2026-08-05
6
+
7
+ ### Added
8
+
9
+ - Interactive turns now announce their state as an OSC 777 sequence (`notify;Terax;gjc;working|attention|finished`), so a hosting terminal can follow the agent without polling. Terminals that do not parse it discard it like any unknown OSC, and print/RPC mode stdout is untouched.
10
+ - Existing Slack threads can now be adopted through an opt-in prepare → bind → activate lifecycle. A prepared session (broker `readiness: "deferred"` / `gjc_coordinator_start_session` with `prepare_existing_thread`, or `GJC_NOTIFY_BIND_EXISTING_THREAD=1` for a manually started one) publishes discoverable endpoint authority while withholding readiness, so no stock root is claimed; `gjc notify bind-thread` then adopts the exact operator-supplied root through the running Slack daemon owner over a new per-request command channel — the CLI is never a direct mapping writer — and `gjc notify activate-thread` / `gjc_coordinator_activate_session` publishes the withheld readiness exactly once behind a gate that proves the daemon-owned mapping at that endpoint generation. Adoption posts zero replacement roots, is fenced on the exact session/generation/daemon-owner tuple, and is idempotent on exact retry. Every mapping mutation passes a two-sided final authority fence inside the store lock — authority is proven, commit authority is taken, and authority is proven again — so a session, endpoint generation, or daemon-owner tuple that rolls while commit authority is being taken leaves no mapping behind. `ChatDaemonRuntime` now drops internal control-plane frames (`session_prepared`, `event_replay_result`, `control_response`, `query_response`, `hello`) before any post, root, mapping, resume, close, or action mutation on both the live and replay paths, and correlates each delivered frame first: an event envelope, its `name`/`kind` aliases, and its payload are representations of one event, so disagreeing spellings, a duplicated `sessionId`/`generation` that is unequal or present-but-malformed, and a reserved lifecycle or control-plane identity carried on only one representation all make the frame inert before any mutation. Because the command channel proves correlation and never authorship, a reported `status:"ok"` that the durable conversation store does not corroborate is reported as `binding_outcome_unknown` instead of success; a storage failure raised after commit authority was granted — the mapping rename applies before its durability barrier — is reported as `binding_outcome_unknown` rather than as a definitive rejection an operator could retry against; and a timeout that wins the single-winner response claim is a definitive, mutation-free failure for that submission's race against a concurrent serve (not durable settlement across a crashed and resurrected daemon). Ordinary sessions keep the stock immediate ready/root behaviour.
11
+
12
+ ### Added
13
+
14
+ - Added a verified, copy-installable `ooo` bridge example: `ooo interview` renders Ouroboros MCP questions in GJC, serializes startup and follow-up answers by session ID, cancellation-fences late settlement, disposes state on GJC session changes and `/clear`, drops queued predecessor-generation starts, releases dead transports and controls, honors `OUROBOROS_CLI`, and loads dependency-free in compiled binaries (#3803).
15
+
16
+ ### Fixed
17
+
18
+ - Automatic session retry now refuses to re-issue a request once the failed attempt carries observable assistant text, thinking, or tool-call content — including under explicit legacy `retry.*` settings. Content-free clean failures keep their existing bounded/unbounded policy; managed provisional discard, credential rotation, first-event timeout scope checks, and manual `/retry` are unchanged (#3791).
19
+
20
+ - Parent sessions and their subagent trees now share one identity-authorized artifact manager across persistent and ephemeral operation. Non-persistent roots are retired on committed session transitions and terminal close, failed transitions retain predecessor ownership, and atomic numeric-ID claims prevent same-root managers from creating ambiguous artifact references (#3813).
21
+
22
+ - Telegram daemon restart now revokes every persisted callback alias before polling. Reconnecting sessions must replay a pending ask to receive fresh, owner-bound aliases; old controls remain stale, and their keyboards are best-effort terminalized when the original Telegram message id is available. Shutdown now fences new session messages and drains every admitted handler before final callback persistence and ownership release, preventing a successful send racing shutdown from publishing alias state after a successor takes ownership (#3727).
23
+ - Extension handler timeout signals now preserve lazy, live context accessors instead of eagerly snapshotting them. Model changes made through SDK controls are immediately visible to later context reads, and unused getters can no longer reject lifecycle emission before the runner's extension error boundary (#3817).
24
+ - Direct interactive launches inside tmux now bind automatic window renames to the originating pane's immutable pane/window identities and observed window index. If that binding changes before mutation, GJC preserves every window name instead of renaming whichever window became active (#3808).
25
+ - `gjc update` and the startup version check now resolve the npm registry from npm configuration — `npm_config_registry` or `BUN_CONFIG_REGISTRY` from the environment, a scoped `@scope:registry` key, and the user and machine-wide `.npmrc` files, including the credentials registered for that registry — instead of always querying `registry.npmjs.org`. On networks that mirror or block the public registry the check failed with an empty `Failed to fetch release info:` even though the install step, which already shells out to bun/npm and therefore honored the configured registry, would have succeeded. Repository-controlled configuration is excluded: a `.npmrc` in the current working directory is not read, the environment is read through `$credentialEnv`, and `npm_config_*` is ignored entirely when GJC is launched by an npm lifecycle, because npm synthesizes those variables from the project `.npmrc` with `${VAR}` already expanded. Credentials are never sent to a remote plaintext `http:` registry, including credentials embedded in the registry URL. Whichever manager will run the install decides Bun-vs-npm config priority, the machine-wide config path is derived from npm's own prefix rather than guessed, and keys inside an ini `[section]` are not treated as top-level config. A registry that is configured but unusable, and a config file that exists but cannot be read, fail loudly instead of silently falling back to the public registry; failures name the URL, the status, and the exact file or environment variable the registry came from — including the case where an intercepting proxy answers 200 with a non-JSON body — and credentials are stripped from a `https://user:pass@host` registry rather than printed with it. `bunfig.toml` is not read. (#3821)
26
+
27
+ ### Fixed
28
+
29
+ - Telegram `notify setup` activation works when `notifications/` is a directory symlink (multi-account shared notification dirs). Transition-lock release previously rejected intermediate directory reparse points, left `telegram-daemon.steal` behind, and failed with "provisional ownership could not be retired safely" while durable settings remained armed. Only intermediate directory components are resolved before native exact unlink; the final basename is rejoined so final-component file symlinks stay `reparse_point` under native `AT_SYMLINK_NOFOLLOW`, including TOCTOU replacement after JS preflight (#3761).
30
+ - A failed `notify setup` no longer reports "Unable to persist and activate Telegram notification settings" when the durable configuration already carries the attempted bot token, chat id, and enabled state. The wording now follows the stored configuration, so it can no longer contradict a follow-up `notify status`; an operator who reads the failure as "nothing was saved" would otherwise leave Telegram armed for a token another poller may own. A commit that was entered and then failed while the stored configuration is also unreadable is reported as undecided, pointing at `notify status`, instead of guessing either outcome (#3761).
31
+ - Continuing a large managed session on Darwin now batches stale OpenAI Responses replay-metadata patches into one transcript append instead of performing one identity-verified whole-file replacement per patch. Interactive startup also renders before exact MCP connection and explicit `--mpreset` activation, gates every provider turn until both are ready, and refreshes models online only after the UI is usable, preventing `gjc -c` from remaining at `GJC warming workspace` with sustained CPU, multi-gigabyte RSS growth, or avoidable network waits (#3793).
32
+ - Slack Web API requests now use form encoding instead of JSON, preventing thread reconciliation through `conversations.replies` from failing with `invalid_arguments`.
33
+
34
+ - Managed replacement cleanup now migrates version-one receipts from earlier releases and recovers canonical exchange placeholders left by interrupted cleanup, so a stale receipt cannot permanently block the next managed session mutation with `managed_replace_cleanup_receipt_invalid`.
35
+
5
36
  ## [0.12.11] - 2026-08-03
6
37
 
7
38
  ### Fixed
@@ -10,6 +41,7 @@
10
41
  - Managed session rewrites and authority-absent Darwin appends now use native identity-verified atomic replacement instead of deterministically failing with `managed_replace_exact_unavailable` or risking a torn JSONL tail; uncertain readable outcomes are re-fsynced and carried through ctime-bound strict adoption before recovery reports them durable. This unblocks Darwin compaction and session append durability when retained native authority is absent (#3742, #3760).
11
42
  - `todo_write` recovery reminders now distinguish rejected payloads from runtime aborts, preserve the available cause, and require durable state reconciliation instead of incorrectly telling the agent to change a valid payload (#3743, #3760).
12
43
  - Authority-absent Darwin `appendSync` regression coverage now exercises the replace-based race window (destination mutation during successor staging) instead of the retired in-place `O_APPEND` open path, and documents that ctime-only destination transitions are tolerated by exact replacement.
44
+ - The legacy interactive footer now uses the session manager's cumulative usage index, so completed task and subagent tokens, premium requests, and estimated costs are included exactly once instead of reporting only the parent agent's assistant messages.
13
45
 
14
46
  ## [0.12.10] - 2026-08-03
15
47
 
@@ -31,6 +63,9 @@
31
63
  - Dead-owner notification recovery now preserves a machine-readable transition block, marker-age diagnostics, and safe force-recovery guidance without weakening ownership proofs (#3762).
32
64
  - Detached SDK session hosts no longer outlive the broker that spawned them. A host whose broker died without teardown (crash, `SIGKILL`, restart without `--close-session-hosts`) previously stayed resident forever, holding its session's memory — hundreds of MB per orphan. Each host now polls the broker discovery publication and, after a bounded grace period with no live broker, disposes itself through the same graceful teardown a `SIGTERM` takes. A replacement broker resets the window, so hosts still survive ordinary broker restarts, and a transient discovery read failure is treated as ambiguity rather than proof of orphanhood.
33
65
  - Syntax highlighting now recognizes special filenames such as `CMakeLists.txt`, `Dockerfile.*`, `Makefile`, and `.env.*` before generic filename extensions.
66
+ ### Changed
67
+
68
+ - Updated the Cursor Eco, Medium, and Pro profiles from Composer 1.5 to distinct Composer 2.5 tiers: standard throughout for Eco, Fast on execution/review/design roles for Medium, and Fast throughout for Pro. Removed inert generic effort suffixes that the Cursor RPC could not transport.
34
69
 
35
70
  ## [0.12.8] - 2026-08-02
36
71
  ### Added
@@ -46,6 +81,7 @@
46
81
 
47
82
  - Windows automatic tmux resolution now selects `psmux` then `pmux` by canonical command order without rejecting distinct lower-priority aliases; it probes `tmux` only when neither named provider is available (#3725).
48
83
  - CI failure extraction now aggregates Bun failure and suite-error summaries across every test invocation in a job log instead of silently using only the first summary.
84
+ - The GitHub status-line lookup now binds terminal links to positive PR numbers and canonical matching HTTP(S) pull-request URLs, rejecting ambiguous or control-bearing targets.
49
85
  - Ordinary `ask` selectors now bound long question premises and page through every premise row without skipping rows hidden by overflow indicators (#3675).
50
86
  - First-event timeout retries now require a typed, content-free failure from the current clean attempt scope, preventing prior or stale extension activity from suppressing or admitting a later request (#3553).
51
87
  - The issue-1979 Korean prose wrap test now cleans up inherited multiplexer env vars (`TMUX`, `TMUX_PANE`, etc.) so it deterministically exercises the plain-terminal render path regardless of the CI runner's terminal session (#1979).
@@ -146,6 +182,8 @@
146
182
 
147
183
  - User-created Telegram forum topics can now start a GJC session by selecting the home folder, choosing a verified recent work folder, or entering an explicit folder path. The selected topic is adopted by the new session without creating or deleting a separate Telegram topic.
148
184
  - The interactive terminal’s responsive IRC/todo work-lane contract now covers exact narrow/wide geometry, requested versus effective IRC visibility, direct-root pin ordering, todo lane bounds, remapped IRC toggles, and live composer shortcut hints.
185
+ - Managed-session startup now preserves bounded Windows ACL and identity failure classifications in path-redacted recovery guidance without broadening permissions, elevation, or unsafe fallback.
186
+ - Telegram topic synchronization now uses generation-CAS shared authority, durable pre-create claims, lease-fenced effects, bounded single-flight archive retries, and an isolated owner-backed validation-supergroup mode without deleting topics.
149
187
 
150
188
  ### Fixed
151
189
 
@@ -1,8 +1,10 @@
1
1
  import { Settings } from "../config/settings";
2
2
  import { type EnsureChatDaemonResult } from "../sdk/bus/chat-daemon-control";
3
+ import { type ActivatedPreparedSession } from "../sdk/bus/existing-thread-readiness";
4
+ import { type BoundSlackThread } from "../sdk/bus/slack-thread-binding";
3
5
  import { type EnsureTelegramDaemonDetailedResult } from "../sdk/bus/telegram-daemon";
4
6
  import { type TelegramSetupPreflight, type TelegramSetupTimers } from "../sdk/bus/telegram-setup";
5
- export type NotifyAction = "setup" | "status" | "health" | "test" | "recovery" | "daemon-internal";
7
+ export type NotifyAction = "setup" | "status" | "health" | "test" | "recovery" | "bind-thread" | "activate-thread" | "daemon-internal";
6
8
  export type NotifySetupProvider = "telegram" | "discord" | "slack";
7
9
  export interface NotifyCommandArgs {
8
10
  action: NotifyAction;
@@ -24,6 +26,8 @@ export interface NotifyCommandArgs {
24
26
  forceDaemonLock?: boolean;
25
27
  probe?: boolean;
26
28
  message?: string;
29
+ sessionId?: string;
30
+ threadTs?: string;
27
31
  }
28
32
  export interface NotifyCommandDeps {
29
33
  fetchImpl?: typeof fetch;
@@ -50,6 +54,15 @@ export interface NotifyCommandDeps {
50
54
  setupPidIncarnation?: (pid: number) => string | undefined;
51
55
  ensureProviderDaemon?: (provider: "discord" | "slack", settings: Settings) => Promise<EnsureChatDaemonResult>;
52
56
  ensureTelegramDaemon?: (settings: Settings) => Promise<EnsureTelegramDaemonDetailedResult>;
57
+ bindSlackThread?: (input: {
58
+ settings: Settings;
59
+ sessionId: string;
60
+ threadTs: string;
61
+ }) => Promise<BoundSlackThread>;
62
+ activatePreparedSession?: (input: {
63
+ settings: Settings;
64
+ sessionId: string;
65
+ }) => Promise<ActivatedPreparedSession>;
53
66
  }
54
67
  export declare function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined;
55
68
  export declare function runNotifyCommand(cmd: NotifyCommandArgs, deps?: NotifyCommandDeps): Promise<void>;
@@ -61,5 +74,33 @@ type TokenPromptInput = NodeJS.ReadStream & {
61
74
  };
62
75
  type TokenPromptOutput = Pick<NodeJS.WriteStream, "write">;
63
76
  export declare function promptForToken(input?: TokenPromptInput, output?: TokenPromptOutput): Promise<string>;
77
+ export interface BindThreadInvocation {
78
+ sessionId: string;
79
+ threadTs: string;
80
+ }
81
+ /**
82
+ * Enforce the exact `bind-thread` grammar at every entrypoint.
83
+ *
84
+ * The command accepts only a session and a root; a positional argument, an
85
+ * unrelated notify flag, or a target/credential input is a rejection rather than
86
+ * something silently ignored, so no other invocation shape can reach the
87
+ * binding authority.
88
+ */
89
+ export declare function assertStrictBindThreadInvocation(cmd: NotifyCommandArgs): BindThreadInvocation;
90
+ /** Confirmation carries identifiers only: no tokens, message bodies, or control secrets. */
91
+ export declare function formatBoundSlackThread(bound: BoundSlackThread): string;
92
+ export interface ActivateThreadInvocation {
93
+ sessionId: string;
94
+ }
95
+ /**
96
+ * Enforce the exact `activate-thread` grammar at every entrypoint.
97
+ *
98
+ * Activation names one prepared session and nothing else: the root it adopts is
99
+ * already the applied binding, so a supplied root, target, or credential is a
100
+ * rejection rather than something silently ignored.
101
+ */
102
+ export declare function assertStrictActivateThreadInvocation(cmd: NotifyCommandArgs): ActivateThreadInvocation;
103
+ /** Confirmation carries identifiers only: no endpoints, tokens, or thread content. */
104
+ export declare function formatActivatedSession(activated: ActivatedPreparedSession): string;
64
105
  export declare function printNotifyHelp(): void;
65
106
  export {};
@@ -1,6 +1,11 @@
1
+ import { type Installer, type NpmRegistryLookupOptions } from "../utils/npm-registry";
1
2
  interface ReleaseInfo {
2
3
  tag: string;
3
4
  version: string;
5
+ /** Registry the version came from. Release binaries still come from GitHub. */
6
+ registry: string;
7
+ /** Config problems that did not stop the lookup but changed its outcome. */
8
+ warnings: string[];
4
9
  }
5
10
  /** Result from running the installed binary and parsing its reported version. */
6
11
  export interface InstalledVersionVerification {
@@ -56,7 +61,8 @@ type PathPlatform = NodeJS.Platform;
56
61
  type PackageExists = (packageName: string, packageRoot: string) => boolean;
57
62
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "npm" | "binary";
58
63
  export declare function resolveNpmManagedTargetForTest(ompPath: string, platform: PathPlatform, packageExists: PackageExists): PackageManagerTarget | undefined;
59
- export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform): string;
64
+ export declare function getLatestReleaseForTest(options: NpmRegistryLookupOptions): Promise<ReleaseInfo>;
65
+ export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform, registryNote?: string): string;
60
66
  export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
61
67
  export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
62
68
  export declare function formatVerificationFailureForTest(result: InstalledVersionVerification, expectedVersion: string): string;
@@ -91,9 +97,9 @@ export declare function runBinaryUpdateFlow(targetPath: string, url: string, exp
91
97
  * Run the update command.
92
98
  */
93
99
  export interface UpdateCommandDependencies {
94
- getLatestRelease?: () => Promise<ReleaseInfo>;
100
+ getLatestRelease?: (installer?: Installer) => Promise<ReleaseInfo>;
95
101
  resolveUpdateTarget?: () => Promise<UpdateTarget>;
96
- performUpdate?: (target: UpdateTarget, expectedVersion: string) => Promise<void>;
102
+ performUpdate?: (target: UpdateTarget, expectedVersion: string, registry?: string) => Promise<void>;
97
103
  refreshInstalledDefaultSkills?: () => Promise<void>;
98
104
  exit?: (code: number) => never;
99
105
  }
@@ -65,6 +65,12 @@ export default class Notify extends Command {
65
65
  message: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
66
66
  description: string;
67
67
  };
68
+ "session-id": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
69
+ description: string;
70
+ };
71
+ "thread-ts": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
72
+ description: string;
73
+ };
68
74
  "owner-id": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
69
75
  description: string;
70
76
  };
@@ -2,6 +2,8 @@ export interface FileLockOptions {
2
2
  staleMs?: number;
3
3
  retries?: number;
4
4
  retryDelayMs?: number;
5
+ /** Stable host identity required to safely reclaim locks on a shared volume. */
6
+ ownerHostId?: string;
5
7
  }
6
8
  export declare const FileLockTestHooks: {
7
9
  afterParentMkdir?: (lockPath: string) => void | Promise<void>;
@@ -18,6 +20,7 @@ export declare function readFileLockInfoForGc(lockDir: string): Promise<FileLock
18
20
  export interface FileLockOwnerToken {
19
21
  pid: number;
20
22
  start_time?: string;
23
+ owner_host_id?: string;
21
24
  timestamp: number;
22
25
  }
23
26
  /** Outcome of a guarded lock-dir removal attempt (`removeFileLockDirForGc`). */
@@ -1,4 +1,4 @@
1
1
  export declare const COORDINATOR_MCP_PROTOCOL_VERSION = "2024-11-05";
2
2
  export declare const COORDINATOR_MCP_SERVER_NAME = "gjc-coordinator-mcp";
3
- export declare const COORDINATOR_MCP_TOOL_NAMES: readonly ["gjc_coordinator_list_sessions", "gjc_coordinator_read_status", "gjc_coordinator_read_tail", "gjc_coordinator_list_questions", "gjc_coordinator_list_artifacts", "gjc_coordinator_read_artifact", "gjc_coordinator_read_coordination_status", "gjc_coordinator_watch_events", "gjc_coordinator_register_session", "gjc_coordinator_start_session", "gjc_coordinator_stop_session", "gjc_coordinator_send_prompt", "gjc_coordinator_submit_question_answer", "gjc_coordinator_read_turn", "gjc_coordinator_await_turn", "gjc_coordinator_report_status", "gjc_delegate_plan", "gjc_delegate_execute", "gjc_delegate_team"];
3
+ export declare const COORDINATOR_MCP_TOOL_NAMES: readonly ["gjc_coordinator_list_sessions", "gjc_coordinator_read_status", "gjc_coordinator_read_tail", "gjc_coordinator_list_questions", "gjc_coordinator_list_artifacts", "gjc_coordinator_read_artifact", "gjc_coordinator_read_coordination_status", "gjc_coordinator_watch_events", "gjc_coordinator_register_session", "gjc_coordinator_start_session", "gjc_coordinator_activate_session", "gjc_coordinator_stop_session", "gjc_coordinator_send_prompt", "gjc_coordinator_submit_question_answer", "gjc_coordinator_read_turn", "gjc_coordinator_await_turn", "gjc_coordinator_report_status", "gjc_delegate_plan", "gjc_delegate_execute", "gjc_delegate_team"];
4
4
  export type CoordinatorToolName = (typeof COORDINATOR_MCP_TOOL_NAMES)[number];
@@ -1,5 +1,7 @@
1
1
  import type { PrivateAskGateCodecV1, PublicReason } from "./question-gate-codec";
2
- export type CoordinatorSessionState = "booting" | "ready_for_input" | "running" | "needs_user_input" | "completed" | "errored" | "stale" | "unknown";
2
+ export type CoordinatorSessionState = "booting"
3
+ /** Live and endpoint-addressable, but withholding readiness until activation. */
4
+ | "prepared" | "ready_for_input" | "running" | "needs_user_input" | "completed" | "errored" | "stale" | "unknown";
3
5
  export interface CanonicalSessionSnapshotV1 {
4
6
  schema_version: 1;
5
7
  namespace_id: string;
@@ -3,6 +3,7 @@
3
3
  */
4
4
  export type { SlashCommandInfo, SlashCommandLocation, SlashCommandSource } from "../slash-commands";
5
5
  export { discoverAndLoadExtensions, ExtensionRuntimeNotInitializedError, loadExtensionFromFactory, loadExtensions, } from "./loader";
6
+ export * from "./ouroboros-ooo-bridge";
6
7
  export * from "./prefix-command-bridge";
7
8
  export * from "./runner";
8
9
  export * from "./types";
@@ -0,0 +1,13 @@
1
+ import { callTool, connectToServer, disconnectServer } from "../../runtime-mcp";
2
+ import type { ExtensionContext, InputEvent, InputEventResult } from "./types";
3
+ interface OuroborosOooBridgeOptions {
4
+ connect?: typeof connectToServer;
5
+ callTool?: typeof callTool;
6
+ disconnect?: typeof disconnectServer;
7
+ }
8
+ interface OuroborosOooBridgeHandler {
9
+ (event: InputEvent, ctx: ExtensionContext): Promise<InputEventResult>;
10
+ reset(): Promise<void>;
11
+ }
12
+ export declare function createOuroborosOooBridge(options?: OuroborosOooBridgeOptions): OuroborosOooBridgeHandler;
13
+ export {};
@@ -32,4 +32,3 @@ export interface ExactPrefixCommandBridgeOptions {
32
32
  * bridge while the child command runs.
33
33
  */
34
34
  export declare function createExactPrefixCommandBridge(options: ExactPrefixCommandBridgeOptions): (event: InputEvent, ctx: ExtensionContext) => Promise<InputEventResult>;
35
- export declare function createOuroborosOooBridge(): (event: InputEvent, ctx: ExtensionContext) => Promise<InputEventResult>;
@@ -239,6 +239,8 @@ export interface ExtensionContext {
239
239
  hasUI: boolean;
240
240
  /** Current working directory */
241
241
  cwd: string;
242
+ /** Aborted when the runner stops waiting for this handler, including handler timeout. */
243
+ signal?: AbortSignal;
242
244
  /** Session manager (read-only) */
243
245
  sessionManager: ReadonlySessionManager;
244
246
  /** Session classification supplied by the SDK for extension policy decisions. */
@@ -16,7 +16,7 @@ import type { PrintModeOptions } from "./modes/print-mode";
16
16
  import { initTheme } from "./modes/theme/theme";
17
17
  import type { SubmittedUserInput } from "./modes/types";
18
18
  import type { MCPManager } from "./runtime-mcp";
19
- import { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage } from "./sdk";
19
+ import { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession, discoverAuthStorage } from "./sdk";
20
20
  import type { AgentSession } from "./session/agent-session";
21
21
  import { type ResumeSessionIdentity, type SessionDestination, type SessionDirectoryMigrationPolicy, type SessionInfo, SessionManager, type StrictSessionOpenResult } from "./session/session-manager";
22
22
  import { runStartupCredentialAutoImportIfNeeded } from "./setup/credential-auto-import";
@@ -55,6 +55,7 @@ type StartupModelProfileArgs = {
55
55
  parsedArgs: Pick<Args, "default" | "model" | "mpreset" | "thinking">;
56
56
  startupModel?: CreateAgentSessionOptions["model"];
57
57
  startupThinkingLevel?: CreateAgentSessionOptions["thinkingLevel"];
58
+ preferCachedModels?: boolean;
58
59
  };
59
60
  export declare function applyStartupModelProfiles(args: StartupModelProfileArgs): Promise<void>;
60
61
  export declare function applyStartupModelProfilesOrExit(args: StartupModelProfileArgs): Promise<void>;
@@ -74,6 +75,9 @@ export declare function applyStartupModelProfilesForRoot(args: StartupModelProfi
74
75
  }): Promise<{
75
76
  recoverableErrors: string[];
76
77
  }>;
78
+ type DeferredModelProfileStartup = () => Promise<{
79
+ recoverableErrors: string[];
80
+ }>;
77
81
  interface InteractiveModeFactoryOptions {
78
82
  session: AgentSession;
79
83
  version: string;
@@ -95,7 +99,7 @@ export declare const BARE_RESUME_INTERACTIVE_ERROR = "--resume requires an inter
95
99
  /** Resolves only the managed agent root needed for pre-consent picker inventory. */
96
100
  export declare function resolveManagedAgentDirForScope(_cwd: string): string;
97
101
  export declare const BARE_RESUME_OPEN_ERROR = "Could not open the selected session. Use --resume <id>.";
98
- export declare function runInteractiveMode(session: AgentSession, version: string, changelogMarkdown: string | undefined, notifs: (InteractiveModeNotify | null)[], startupUpdate: StartupUpdateOrchestrator, initialMessages: string[], setExtensionUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void, lspServers: LspStartupServerInfo[] | undefined, mcpManager: MCPManager | undefined, eventBus?: EventBus, initialMessage?: string, initialImages?: ImageContent[], createInteractiveMode?: CreateInteractiveMode, resumeAction?: "continue-tail" | "open-idle"): Promise<void>;
102
+ export declare function runInteractiveMode(session: AgentSession, version: string, changelogMarkdown: string | undefined, notifs: (InteractiveModeNotify | null)[], startupUpdate: StartupUpdateOrchestrator, initialMessages: string[], setExtensionUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void, lspServers: LspStartupServerInfo[] | undefined, mcpManager: MCPManager | undefined, eventBus?: EventBus, initialMessage?: string, initialImages?: ImageContent[], createInteractiveMode?: CreateInteractiveMode, resumeAction?: "continue-tail" | "open-idle", startDeferredMcpConfig?: CreateAgentSessionResult["startDeferredMcpConfig"], startDeferredModelProfiles?: DeferredModelProfileStartup): Promise<void>;
99
103
  export declare function getChangelogForDisplay(parsed: Args): Promise<string | undefined>;
100
104
  export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings): Promise<SessionManager | undefined>;
101
105
  /**
@@ -35,7 +35,7 @@ export declare class SessionSelectorComponent extends Container {
35
35
  private readonly onDelete?;
36
36
  private readonly inspector?;
37
37
  private readonly onSelection?;
38
- constructor(sessions: SessionInfo[], onSelect: (sessionPath: string) => void, onCancel: () => void, onExit: () => void, onDelete?: ((session: SessionInfo) => Promise<boolean>) | undefined, inspector?: SessionInspector | undefined, onSelection?: ((selection: SessionSelectionResult) => void) | undefined);
38
+ constructor(sessions: SessionInfo[], onSelect: (sessionPath: string) => void | Promise<void>, onCancel: () => void, onExit: () => void, onDelete?: ((session: SessionInfo) => Promise<boolean>) | undefined, inspector?: SessionInspector | undefined, onSelection?: ((selection: SessionSelectionResult) => void) | undefined);
39
39
  setOnRequestRender(callback: () => void): void;
40
40
  handleInput(keyData: string): void;
41
41
  getSessionList(): SessionList;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Host-terminal agent status markers.
3
+ *
4
+ * Interactive turns announce their state as an OSC 777 sequence:
5
+ *
6
+ * ESC ] 777 ; notify;Terax;gjc;<event> BEL
7
+ *
8
+ * A terminal that understands the sequence (Terax reads it to drive its per-tab
9
+ * agent status and header bell) reacts; every other terminal discards the OSC
10
+ * as unknown, exactly like the OSC 133 prompt marks and OSC 7 cwd reports that
11
+ * shells emit unconditionally. So there is no host sniffing and no env gate:
12
+ * any host that wants agent status can parse the stream without gjc knowing it
13
+ * exists.
14
+ *
15
+ * `notify;Terax;` is the wire identifier of the only protocol that currently
16
+ * carries per-turn agent state, not a host check - the payload names gjc as the
17
+ * reporting agent.
18
+ *
19
+ * Interactive TUI only. Print and RPC mode stdout stays byte-for-byte parseable
20
+ * because they never reach these controllers.
21
+ */
22
+ export type HostStatusEvent = "working" | "attention" | "finished";
23
+ export declare function emitHostStatus(event: HostStatusEvent, output?: Pick<NodeJS.WriteStream, "write">): void;
@@ -186,6 +186,8 @@ export type MCPContent = MCPTextContent | MCPImageContent | MCPResourceContent;
186
186
  export interface MCPToolCallResult {
187
187
  content: MCPContent[];
188
188
  isError?: boolean;
189
+ /** MCP result metadata, encoded as `_meta` on the wire. */
190
+ _meta?: Record<string, unknown>;
189
191
  }
190
192
  /** Expected configured-server transport or protocol failure. */
191
193
  export declare class MCPExpectedFailure extends Error {
@@ -48,6 +48,16 @@ export interface SessionLifecycleTranscriptIdentity {
48
48
  mtimeNs: string;
49
49
  sha256: string;
50
50
  }
51
+ /**
52
+ * When a lifecycle-managed session publishes its replayable readiness signal.
53
+ *
54
+ * `immediate` is the stock contract. `deferred` prepares the session instead:
55
+ * the child publishes a distinct prepared signal, keeps `session_ready`
56
+ * withheld, and stays unusable for input until it is explicitly activated. It
57
+ * is broker-issued and session-scoped precisely so a prepared session can never
58
+ * be produced by an inherited process-global flag.
59
+ */
60
+ export type SessionLifecycleReadiness = "immediate" | "deferred";
51
61
  export interface SessionLifecycleLaunchRequest {
52
62
  operation: "session.create" | "session.fork" | "session.resume";
53
63
  sessionId: string;
@@ -64,6 +74,8 @@ export interface SessionLifecycleLaunchRequest {
64
74
  modelPreset?: string;
65
75
  mcpServers?: SessionLifecycleMcpServer[];
66
76
  worktree?: SessionLifecycleWorktreeTarget;
77
+ /** Absent means the stock immediate contract; `deferred` prepares the session. */
78
+ readiness?: SessionLifecycleReadiness;
67
79
  receivedAt: number;
68
80
  requestedReadinessTimeoutMs: number;
69
81
  semanticReadyDeadlineAt: number;
@@ -1,9 +1,12 @@
1
+ import { type ChatDaemonCommandBindInput, type ChatDaemonCommandOutcome } from "./chat-daemon-command-channel";
1
2
  import { type ChatDaemonKind, renewChatDaemonHeartbeat } from "./chat-daemon-control";
2
3
  import { type ChatDaemonRuntimeConfig } from "./chat-daemon-runtime";
3
4
  export interface ChatDaemonRuntimeHandle {
4
5
  start(): Promise<void>;
5
6
  stop(): Promise<void>;
6
7
  transportHealthy?(): boolean;
8
+ /** Executes operator commands that must run inside the owning daemon. */
9
+ bindExistingRoot?(request: ChatDaemonCommandBindInput): Promise<ChatDaemonCommandOutcome>;
7
10
  }
8
11
  export interface RunChatDaemonInternalDeps {
9
12
  processPid?: number;