@gajae-code/coding-agent 0.15.6 → 0.16.0

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 (167) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/dist/types/cli/args.d.ts +2 -0
  3. package/dist/types/cli/root-flags.d.ts +14 -0
  4. package/dist/types/cli/update-cli.d.ts +13 -0
  5. package/dist/types/cli.d.ts +7 -0
  6. package/dist/types/commands/launch.d.ts +10 -0
  7. package/dist/types/config/autorouting-tier-map.d.ts +24 -0
  8. package/dist/types/config/file-lock.d.ts +5 -0
  9. package/dist/types/config/model-registry.d.ts +6 -0
  10. package/dist/types/config/settings-schema.d.ts +10 -1
  11. package/dist/types/config/settings.d.ts +2 -0
  12. package/dist/types/coordinator-mcp/projection-scan.d.ts +8 -0
  13. package/dist/types/crash/record-loader.d.ts +15 -0
  14. package/dist/types/gjc-runtime/launch-worktree-reservation.d.ts +21 -0
  15. package/dist/types/gjc-runtime/managed-owner-supervisor.d.ts +2 -0
  16. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +66 -1
  17. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +1 -0
  18. package/dist/types/gjc-runtime/tmux-sessions.d.ts +27 -0
  19. package/dist/types/master-mode/context.d.ts +21 -0
  20. package/dist/types/master-mode/first-request.d.ts +34 -0
  21. package/dist/types/master-mode/snapshot.d.ts +32 -0
  22. package/dist/types/modes/components/frictionless-onboarding-selector.d.ts +10 -0
  23. package/dist/types/modes/components/oauth-selector.d.ts +1 -0
  24. package/dist/types/modes/components/status-line/model-name.d.ts +18 -0
  25. package/dist/types/modes/components/status-line/priority-row.d.ts +34 -0
  26. package/dist/types/modes/components/status-line/segments.d.ts +10 -0
  27. package/dist/types/modes/print-mode.d.ts +17 -0
  28. package/dist/types/modes/ui-language.d.ts +7 -1
  29. package/dist/types/sdk/broker/broker.d.ts +77 -1
  30. package/dist/types/sdk/broker/endpoint-authority.d.ts +24 -0
  31. package/dist/types/sdk/broker/index.d.ts +3 -0
  32. package/dist/types/sdk/broker/lifecycle.d.ts +26 -0
  33. package/dist/types/sdk/broker/master-capability.d.ts +10 -0
  34. package/dist/types/sdk/broker/session-index.d.ts +40 -11
  35. package/dist/types/sdk/broker/session-scope.d.ts +72 -0
  36. package/dist/types/sdk/broker/spawn-authority.d.ts +201 -0
  37. package/dist/types/sdk/broker/spawn-substrate.d.ts +30 -0
  38. package/dist/types/sdk/broker/state-version.d.ts +4 -1
  39. package/dist/types/sdk/broker/worktree-occupancy.d.ts +28 -0
  40. package/dist/types/sdk/bus/chat-daemon-control.d.ts +3 -0
  41. package/dist/types/sdk/bus/index.d.ts +6 -0
  42. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  43. package/dist/types/sdk/cli/index.d.ts +1 -0
  44. package/dist/types/sdk/cli/master-cli.d.ts +63 -0
  45. package/dist/types/sdk/cli/rows.d.ts +4 -3
  46. package/dist/types/sdk/cli/session-cli.d.ts +18 -2
  47. package/dist/types/sdk/client/client.d.ts +3 -2
  48. package/dist/types/sdk/host/control/dispatch.d.ts +10 -0
  49. package/dist/types/sdk/host/control/index.d.ts +1 -1
  50. package/dist/types/sdk/host/control/operations.d.ts +2 -0
  51. package/dist/types/sdk/host/control/runtime-gate.d.ts +21 -7
  52. package/dist/types/sdk/host/host.d.ts +10 -0
  53. package/dist/types/sdk/host/session-runtime.d.ts +52 -0
  54. package/dist/types/sdk/lifecycle/broker-client.d.ts +6 -0
  55. package/dist/types/sdk/lifecycle/service.d.ts +15 -3
  56. package/dist/types/sdk/lifecycle-session.d.ts +2 -0
  57. package/dist/types/sdk/router/session-router.d.ts +2 -0
  58. package/dist/types/sdk/session.d.ts +16 -0
  59. package/dist/types/sdk/startup-capability.d.ts +2 -1
  60. package/dist/types/session/agent-session.d.ts +5 -0
  61. package/dist/types/session/credential-store-errors.d.ts +1 -0
  62. package/dist/types/session/session-manager.d.ts +65 -0
  63. package/dist/types/session/yield-queue.d.ts +5 -4
  64. package/dist/types/setup/frictionless-onboarding.d.ts +1 -0
  65. package/dist/types/tools/bash.d.ts +4 -0
  66. package/dist/types/tools/gh.d.ts +8 -0
  67. package/dist/types/tools/index.d.ts +4 -0
  68. package/package.json +7 -7
  69. package/scripts/generate-sdk-operation-inventory.ts +6 -0
  70. package/scripts/verify-gjc-sdk-canonicalization.ts +35 -1
  71. package/src/cli/accounts-cli.ts +9 -5
  72. package/src/cli/args.ts +17 -0
  73. package/src/cli/fast-help.ts +1 -0
  74. package/src/cli/root-flags.ts +5 -0
  75. package/src/cli/update-cli.ts +77 -11
  76. package/src/commands/launch.ts +86 -18
  77. package/src/commands/sdk.ts +113 -21
  78. package/src/config/autorouting-tier-map.ts +12 -0
  79. package/src/config/file-lock.ts +158 -83
  80. package/src/config/model-preset-registry.ts +1 -5
  81. package/src/config/model-profiles.ts +5 -5
  82. package/src/config/model-registry.ts +23 -0
  83. package/src/config/model-resolver.ts +5 -0
  84. package/src/config/settings-schema.ts +8 -1
  85. package/src/config/settings.ts +5 -0
  86. package/src/coordinator-mcp/projection-scan.ts +21 -0
  87. package/src/coordinator-mcp/question-state.ts +9 -11
  88. package/src/coordinator-mcp/server.ts +94 -20
  89. package/src/crash/index-store.ts +2 -0
  90. package/src/crash/record-loader.ts +10 -0
  91. package/src/gjc-runtime/launch-worktree-reservation.ts +242 -0
  92. package/src/gjc-runtime/managed-owner-supervisor.ts +63 -51
  93. package/src/gjc-runtime/session-state-lock.ts +79 -6
  94. package/src/gjc-runtime/session-state-sidecar.ts +929 -23
  95. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +4 -7
  96. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -2
  97. package/src/gjc-runtime/tmux-sessions.ts +252 -13
  98. package/src/hooks/skill-state.ts +6 -0
  99. package/src/internal-urls/docs-index.generated.ts +7 -7
  100. package/src/internal-urls/issue-pr-protocol.ts +4 -2
  101. package/src/main.ts +57 -2
  102. package/src/master-mode/context.ts +50 -0
  103. package/src/master-mode/first-request.ts +65 -0
  104. package/src/master-mode/snapshot.ts +205 -0
  105. package/src/modes/acp/acp-agent.ts +605 -156
  106. package/src/modes/components/footer.ts +4 -2
  107. package/src/modes/components/frictionless-onboarding-selector.ts +48 -2
  108. package/src/modes/components/oauth-selector.ts +6 -1
  109. package/src/modes/components/settings-selector.ts +1 -0
  110. package/src/modes/components/status-line/model-name.ts +53 -0
  111. package/src/modes/components/status-line/priority-row.ts +107 -0
  112. package/src/modes/components/status-line/segments.ts +23 -9
  113. package/src/modes/components/tool-status-header.ts +151 -15
  114. package/src/modes/controllers/input-controller.ts +28 -0
  115. package/src/modes/controllers/selector-controller.ts +191 -96
  116. package/src/modes/print-mode.ts +64 -0
  117. package/src/modes/ui-language.ts +49 -2
  118. package/src/prompts/system/master-mode.md +28 -0
  119. package/src/sdk/broker/broker.ts +1636 -26
  120. package/src/sdk/broker/endpoint-authority.ts +86 -0
  121. package/src/sdk/broker/ensure.ts +5 -0
  122. package/src/sdk/broker/index.ts +3 -0
  123. package/src/sdk/broker/lifecycle.ts +186 -41
  124. package/src/sdk/broker/master-capability.ts +232 -0
  125. package/src/sdk/broker/session-index.ts +121 -17
  126. package/src/sdk/broker/session-scope.ts +272 -0
  127. package/src/sdk/broker/spawn-authority.ts +1031 -0
  128. package/src/sdk/broker/spawn-substrate.ts +548 -0
  129. package/src/sdk/broker/state-version.ts +26 -14
  130. package/src/sdk/broker/transport.ts +1 -0
  131. package/src/sdk/broker/worktree-occupancy.ts +90 -0
  132. package/src/sdk/bus/chat-daemon-control.ts +5 -2
  133. package/src/sdk/bus/chat-daemon-runtime.ts +35 -4
  134. package/src/sdk/bus/index.ts +51 -4
  135. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  136. package/src/sdk/cli/index.ts +1 -0
  137. package/src/sdk/cli/master-cli.ts +259 -0
  138. package/src/sdk/cli/rows.ts +11 -8
  139. package/src/sdk/cli/session-cli.ts +264 -5
  140. package/src/sdk/client/client.ts +14 -8
  141. package/src/sdk/host/control/dispatch.ts +99 -38
  142. package/src/sdk/host/control/index.ts +2 -0
  143. package/src/sdk/host/control/operations.ts +2 -0
  144. package/src/sdk/host/control/runtime-gate.ts +203 -11
  145. package/src/sdk/host/host.ts +27 -2
  146. package/src/sdk/host/session-runtime.test.ts +210 -6
  147. package/src/sdk/host/session-runtime.ts +291 -49
  148. package/src/sdk/lifecycle/broker-client.ts +28 -0
  149. package/src/sdk/lifecycle/service.ts +279 -20
  150. package/src/sdk/lifecycle-session.ts +10 -2
  151. package/src/sdk/protocol/operation-inventory.generated.json +51 -0
  152. package/src/sdk/protocol/operation-registry.ts +13 -3
  153. package/src/sdk/router/session-router.ts +67 -59
  154. package/src/sdk/session.ts +357 -155
  155. package/src/sdk/startup-capability.ts +1 -0
  156. package/src/session/agent-session.ts +640 -103
  157. package/src/session/blob-store.ts +15 -5
  158. package/src/session/credential-store-errors.ts +2 -0
  159. package/src/session/internal/managed-session-storage.ts +153 -78
  160. package/src/session/session-manager.ts +337 -24
  161. package/src/session/yield-queue.ts +24 -10
  162. package/src/setup/frictionless-onboarding.ts +2 -0
  163. package/src/telemetry/events.ts +1138 -12
  164. package/src/tools/bash.ts +256 -42
  165. package/src/tools/gh.ts +104 -48
  166. package/src/tools/github-cache.ts +2 -2
  167. package/src/tools/index.ts +4 -0
@@ -14,6 +14,7 @@ export declare class OAuthSelectorComponent extends Container {
14
14
  #private;
15
15
  constructor(mode: "login" | "logout", authStorage: AuthStorage, onSelect: (providerId: string) => void, onCancel: () => void, options?: {
16
16
  validateAuth?: (providerId: string) => Promise<boolean>;
17
+ onValidationError?: (error: unknown) => boolean;
17
18
  requestRender?: () => void;
18
19
  externalCredentialCandidates?: ImportableCredential[];
19
20
  } & Partial<OAuthSelectorAccountOptions>);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shortest recognizable model label, derived purely from the model id.
3
+ *
4
+ * The rail and the footer both render this form, so a narrow terminal spends
5
+ * its cells on the part of the id that actually identifies the model:
6
+ *
7
+ * `anthropic/claude-sonnet-4-5-20250929` -> `sonnet-4.5`
8
+ * `openai/gpt-4o-2024-05-13` -> `gpt-4o`
9
+ * `google/gemini-3-pro` -> `gemini-3-pro`
10
+ * `qwen2.5:7b` -> `qwen2.5:7b`
11
+ *
12
+ * Deliberately a pure heuristic with no curated override table: every provider
13
+ * in `models.json` must degrade sanely without per-model maintenance. The
14
+ * function never returns an empty string — an id that the heuristic would
15
+ * strip to nothing falls back to the previous, longer form.
16
+ */
17
+ export declare const NO_MODEL_LABEL = "no-model";
18
+ export declare function shortenModelId(rawId: string | undefined | null): string;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Narrow-width survival row for the status rail.
3
+ *
4
+ * The rail evicts segments continuously as the terminal narrows. Without this
5
+ * row the last thing left at very small widths is the `…+N` overflow marker —
6
+ * the three things a user actually needs (how much context is left, whether a
7
+ * goal is running, which model is answering) are exactly what the generic
8
+ * eviction throws away first or last by accident.
9
+ *
10
+ * This row keeps them, in priority order, by stepping each item down its own
11
+ * ladder instead of dropping it:
12
+ *
13
+ * full form -> shortened form -> single glyph -> dropped
14
+ *
15
+ * Context % is never dropped and is the last survivor; the model name is
16
+ * dropped first of the three. The row is rendered as bare colored text with no
17
+ * group padding or end caps, so — like the overflow marker — it can survive at
18
+ * widths where a normal segment group cannot.
19
+ */
20
+ import type { SegmentContext } from "./types";
21
+ /** Which priority items the active layout is supposed to be carrying. */
22
+ export interface PriorityItemSet {
23
+ context: boolean;
24
+ goal: boolean;
25
+ model: boolean;
26
+ }
27
+ /**
28
+ * Widest priority row that fits `width`, or null when even the minimal form
29
+ * cannot fit (callers then fall back to the overflow marker).
30
+ *
31
+ * Returns null when neither context nor goal is available: the model name alone
32
+ * is the lowest-priority item and never justifies replacing the normal rail.
33
+ */
34
+ export declare function buildPriorityRow(ctx: SegmentContext, width: number, include: PriorityItemSet): string | null;
@@ -1,5 +1,15 @@
1
+ import { type ThemeColor } from "../../../modes/theme/theme";
1
2
  import type { RenderedSegment, SegmentContext, StatusLineSegment, StatusLineSegmentId } from "./types";
2
3
  export type { SegmentContext } from "./types";
4
+ /**
5
+ * Icon and color for the active goal indicator, or null when goal mode is not
6
+ * showing. Shared with the narrow-width priority row so the compact glyph keeps
7
+ * the same status color as the full label.
8
+ */
9
+ export declare function goalStatusDisplay(ctx: SegmentContext): {
10
+ icon: string;
11
+ color: ThemeColor;
12
+ } | null;
3
13
  export declare const SEGMENTS: Record<StatusLineSegmentId, StatusLineSegment>;
4
14
  export declare function renderSegment(id: StatusLineSegmentId, ctx: SegmentContext): RenderedSegment;
5
15
  export declare const ALL_SEGMENT_IDS: StatusLineSegmentId[];
@@ -5,6 +5,7 @@
5
5
  * - `gjc -p "prompt"` - text output
6
6
  * - `gjc --mode json "prompt"` - JSON event stream
7
7
  */
8
+ import type { AgentMessage } from "@gajae-code/agent-core";
8
9
  import { type ImageContent } from "@gajae-code/ai/core";
9
10
  import type { AgentSession } from "../session/agent-session";
10
11
  /**
@@ -37,8 +38,24 @@ export interface PrintModeOptions {
37
38
  * it is intentionally NOT covered by this exit code.
38
39
  */
39
40
  export declare const CONTEXT_OVERFLOW_EXIT_CODE = 78;
41
+ declare const EMPTY_TURN_ERROR: {
42
+ readonly code: "empty_response";
43
+ readonly message: "Turn completed without assistant text.";
44
+ };
45
+ export type PrintTerminalDisposition = {
46
+ status: "success";
47
+ assistantText: true;
48
+ } | {
49
+ status: "failure";
50
+ error: typeof EMPTY_TURN_ERROR | {
51
+ code: "assistant_error";
52
+ message: string;
53
+ };
54
+ };
55
+ export declare function resolvePrintTerminalDisposition(messages: readonly AgentMessage[], submittedPrompt: boolean, turnStartIndex?: number): PrintTerminalDisposition | undefined;
40
56
  /**
41
57
  * Run in print (single-shot) mode.
42
58
  * Sends prompts to the agent and outputs the result.
43
59
  */
44
60
  export declare function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise<void>;
61
+ export {};
@@ -1,4 +1,4 @@
1
- export declare const UI_LANGUAGES: readonly ["en", "ko", "ja"];
1
+ export declare const UI_LANGUAGES: readonly ["en", "ko", "zh", "ja"];
2
2
  export type UiLanguage = (typeof UI_LANGUAGES)[number];
3
3
  declare const ENGLISH_STRINGS: {
4
4
  readonly "settings.title": "Settings";
@@ -21,6 +21,7 @@ declare const ENGLISH_STRINGS: {
21
21
  readonly "settings.language.description": "Language for human-facing interactive UI text";
22
22
  readonly "settings.language.english": "English";
23
23
  readonly "settings.language.korean": "Korean (한국어)";
24
+ readonly "settings.language.chinese": "Chinese (简体中文)";
24
25
  readonly "settings.language.japanese": "Japanese (日本語)";
25
26
  readonly "language.current": "Current UI language:";
26
27
  readonly "language.changed": "UI language changed to";
@@ -29,6 +30,11 @@ declare const ENGLISH_STRINGS: {
29
30
  export type UiStringKey = keyof typeof ENGLISH_STRINGS;
30
31
  /** User selection is authoritative; invalid or unavailable values deterministically fall back to English. */
31
32
  export declare function resolveUiLanguage(value: unknown): UiLanguage;
33
+ /** Resolve explicit startup preference without allowing an invalid value to block startup. */
34
+ export declare function resolveExplicitUiLanguage(configuredValue: unknown, environmentValue: string | undefined): {
35
+ language: UiLanguage;
36
+ hasPreference: boolean;
37
+ };
32
38
  export declare function uiString(language: unknown, key: UiStringKey): string;
33
39
  /** Endonym shown by `/language` and the language submenu. */
34
40
  export declare const UI_LANGUAGE_LABELS: Record<UiLanguage, string>;
@@ -5,6 +5,7 @@ import { type DirectoryMigrationPolicy } from "../session-directory";
5
5
  import { type BrokerDiscovery, type BrokerPublicationObservation, type RedactedBrokerDiscovery } from "./discovery";
6
6
  import { type LifecycleDurableEffectsReceipt, LifecycleLedger, type LifecycleStartupFailureReceipt } from "./lifecycle-ledger";
7
7
  import { SessionIndex } from "./session-index";
8
+ import { type MasterCapabilityVerifier, type SpawnSubstrateFailure, type SpawnSubstrateProvider } from "./spawn-authority";
8
9
  export interface BrokerSettings {
9
10
  agentDir: string;
10
11
  packageGeneration?: string;
@@ -12,6 +13,14 @@ export interface BrokerSettings {
12
13
  heartbeatTtlMs?: number;
13
14
  /** Broker-owned migration policy. Client lifecycle frames cannot select it. */
14
15
  resolveDirectoryMigration?: (_cwd: string) => Promise<DirectoryMigrationPolicy>;
16
+ /** Exact managed-substrate authority. Tests inject an in-memory provider. */
17
+ spawnSubstrateProvider?: SpawnSubstrateProvider;
18
+ /** Ordered Q26 host control seam; production uses exact endpoint attachments. */
19
+ spawnPromptLayer?: SpawnPromptLayer;
20
+ /** Live-only, host-mediated capability verifier. It retains no request input. */
21
+ masterCapabilityVerifier?: MasterCapabilityVerifier;
22
+ /** Grace before an orphaned spawn child closes; schema-bounded in production. */
23
+ masterOrphanGraceMs?: number;
15
24
  /** Host model resolver override for lifecycle tests and embedders. */
16
25
  resolveModelPin?: SdkHostModelResolver;
17
26
  }
@@ -21,6 +30,10 @@ type ResolvedBrokerSettings = {
21
30
  port: number;
22
31
  heartbeatTtlMs: number;
23
32
  resolveDirectoryMigration: (_cwd: string) => Promise<DirectoryMigrationPolicy>;
33
+ masterCapabilityVerifier?: MasterCapabilityVerifier;
34
+ spawnSubstrateProvider?: SpawnSubstrateProvider;
35
+ spawnPromptLayer?: SpawnPromptLayer;
36
+ masterOrphanGraceMs: number;
24
37
  };
25
38
  export type BrokerErrorCode = "idempotency_conflict" | "terminal_uncertain" | "broker_restarting" | "unavailable" | "endpoint_stale" | "resource_gone" | "invalid_input" | "spawn_failed" | "ready_then_exited" | "endpoint_unreadable" | "startup_admission_timeout" | "startup_admission_refused" | "readiness_timeout" | "close_refused" | "not_found" | "live_session" | "cleanup_pending" | (string & {});
26
39
  export type BrokerCleanupIdentity = {
@@ -115,7 +128,7 @@ export type BrokerResponse = {
115
128
  error: {
116
129
  code: BrokerErrorCode;
117
130
  message: string;
118
- details?: ModelProfileErrorDetails;
131
+ details?: ModelProfileErrorDetails | SpawnSubstrateFailure;
119
132
  endpoint?: "unavailable";
120
133
  cleanup?: BrokerCleanupEvidence;
121
134
  };
@@ -123,6 +136,58 @@ export type BrokerResponse = {
123
136
  durableEffects?: LifecycleDurableEffectsReceipt;
124
137
  startupFailure?: LifecycleStartupFailureReceipt;
125
138
  };
139
+ /** Complete five-leg child endpoint pin captured at registration. */
140
+ export type SpawnHostRegistration = {
141
+ sessionId: string;
142
+ endpointGeneration: number;
143
+ pid: number;
144
+ processIncarnation: string;
145
+ /** Workspace the child was launched into; bound so a colliding pid elsewhere cannot pass. */
146
+ cwd: string;
147
+ stateRoot: string;
148
+ };
149
+ export type SpawnPromptDispatch = {
150
+ kind: "accepted";
151
+ commandId: string;
152
+ turnId: string;
153
+ acceptedAt: number;
154
+ } | {
155
+ kind: "pre_send_rejected";
156
+ } | {
157
+ kind: "uncertain";
158
+ };
159
+ export type SpawnQ26Reconciliation = {
160
+ status: "accepted" | "in_flight" | "terminal_ok" | "failed" | "unknown";
161
+ clientRef?: string;
162
+ commandId?: string;
163
+ turnId?: string;
164
+ acceptedAt?: number;
165
+ };
166
+ /** Q26-only host control seam. It never receives or returns durable request material. */
167
+ export interface SpawnPromptLayer {
168
+ awaitRegistration(input: {
169
+ childId: string;
170
+ cwd: string;
171
+ stateRoot: string;
172
+ }): Promise<{
173
+ ok: true;
174
+ registration: SpawnHostRegistration;
175
+ } | {
176
+ ok: false;
177
+ }>;
178
+ dispatch(input: {
179
+ sessionId: string;
180
+ task: string;
181
+ clientRef: string;
182
+ /** Endpoint identity proven at registration; implementations must not talk to another endpoint. */
183
+ pinned: SpawnHostRegistration;
184
+ }): Promise<SpawnPromptDispatch>;
185
+ reconcile(input: {
186
+ sessionId: string;
187
+ clientRef: string;
188
+ pinned: SpawnHostRegistration;
189
+ }): Promise<SpawnQ26Reconciliation>;
190
+ }
126
191
  /** Test seam for lifecycle serialization identity. */
127
192
  export declare function lifecycleTargetForTest(operation: string, input: Record<string, unknown>): unknown;
128
193
  /** Tombstone prefix used by {@link Broker.reclaimStaleLock} when a dead owner's lock is renamed aside. */
@@ -203,6 +268,17 @@ export declare class Broker {
203
268
  readonly ledger: LifecycleLedger;
204
269
  discovery: BrokerDiscovery | null;
205
270
  constructor(settings: BrokerSettings);
271
+ /** Host capability validation is live-only; no request material is retained. */
272
+ verifyMasterCapability(ownerSessionId: string, rawCapability: string, attestationEpoch: string): Promise<{
273
+ allowed: boolean;
274
+ }>;
275
+ /**
276
+ * Replays pending exact closes, then reaps children after confirmed master
277
+ * loss. Orphan clocks survive recovery and expiry converges through the same
278
+ * exact close path for only the matching owned child.
279
+ */
280
+ /** Deterministic single reap pass; used by maintenance paths and tests. */
281
+ reapSpawnOrphansOnce(): Promise<void>;
206
282
  runStartup<T>(queueWaitMs: number, timing: StartupAdmissionTiming, task: (admittedAt: number) => Promise<T>): Promise<StartupAdmissionResult<T>>;
207
283
  start(): Promise<BrokerDiscovery>;
208
284
  get ownsDiscovery(): boolean;
@@ -0,0 +1,24 @@
1
+ import * as fs from "node:fs/promises";
2
+ export type EndpointFileRead = {
3
+ source: string;
4
+ dev: bigint;
5
+ ino: bigint;
6
+ nlink: bigint;
7
+ size: bigint;
8
+ mtimeNs: bigint;
9
+ mtimeMs: number;
10
+ };
11
+ export type EndpointAuthorityFilesystem = Pick<typeof fs, "open">;
12
+ export type IndexedEndpointAuthority = {
13
+ endpointMtimeMs?: number;
14
+ endpointFileId?: string;
15
+ };
16
+ /**
17
+ * Reads one endpoint from the descriptor opened for its pathname. The opened
18
+ * object must remain a small, singly-linked regular file with stable identity
19
+ * and metadata for the whole read; a pathname replacement cannot affect the
20
+ * bytes returned by this function.
21
+ */
22
+ export declare function readEndpointFile(filePath: string, filesystem?: EndpointAuthorityFilesystem): Promise<EndpointFileRead | undefined>;
23
+ /** Match a descriptor-bound endpoint read to the index representation. */
24
+ export declare function matchesIndexedEndpointFile(file: Pick<EndpointFileRead, "dev" | "ino" | "mtimeMs">, authority: IndexedEndpointAuthority): boolean;
@@ -4,6 +4,9 @@ export * from "./ensure";
4
4
  export * from "./identity";
5
5
  export * from "./lifecycle";
6
6
  export * from "./lifecycle-ledger";
7
+ export * from "./master-capability";
7
8
  export * from "./session-index";
9
+ export * from "./spawn-authority";
10
+ export * from "./spawn-substrate";
8
11
  export * from "./startup-budget";
9
12
  export * from "./transport";
@@ -5,6 +5,7 @@ import type { Broker, BrokerCleanupEvidence, BrokerResponse } from "./broker";
5
5
  import type { LifecycleDurableEffectsReceipt, LifecycleStartupFailureReceipt } from "./lifecycle-ledger";
6
6
  import { type ProcessIncarnationCommandRunner, type ProcessIncarnationOptions, parseDarwinProcessIncarnation, processIncarnation } from "./process-incarnation";
7
7
  import { type SdkInternalSpawnCommand } from "./runtime";
8
+ import { type IndexedSession } from "./session-index";
8
9
  export { type ProcessIncarnationCommandRunner, type ProcessIncarnationOptions, parseDarwinProcessIncarnation, processIncarnation, };
9
10
  export declare function terminalUncertainStartupMessage(response: BrokerResponse): string;
10
11
  export declare function waitForChildSpawn(spawned: Pick<ChildProcess, "off" | "on" | "once">, onPostSpawnError?: (error: Error) => void): Promise<void>;
@@ -111,12 +112,35 @@ export type SessionLifecycleLaunchRequest = SessionLifecycleLaunchRequestBase &
111
112
  });
112
113
  export declare function readSessionLifecycleLaunchRequest(value: string | undefined, now?: number): SessionLifecycleLaunchRequest;
113
114
  type CleanupEvidence = BrokerCleanupEvidence;
115
+ export declare function validateBrokerModelPresetSync(agentDir: string, requestedProfile: string): string | BrokerResponse;
114
116
  export declare function validateBrokerModelPresetForTest(agentDir: string, requestedProfile: string): string | BrokerResponse;
115
117
  /** Test seam: the session-host command override as resolved from trusted env. */
116
118
  export declare function sdkSessionCommandOverrideForTest(): {
117
119
  file: string;
118
120
  args: string[];
119
121
  } | undefined;
122
+ /**
123
+ * Reuses the ordinary lifecycle host bootstrap without performing its direct
124
+ * process spawn. Broker-owned substrate providers receive this exact argv and
125
+ * split inherited/child-specific environment contract as their only launch
126
+ * authority for session.spawn.
127
+ */
128
+ export type SpawnChildHostLaunch = {
129
+ childId: string;
130
+ cwd: string;
131
+ stateRoot: string;
132
+ argv: readonly string[];
133
+ inheritedEnv: Readonly<Record<string, string>>;
134
+ env: Readonly<Record<string, string>>;
135
+ effectMarker: string;
136
+ };
137
+ export declare function prepareSpawnChildHostLaunch(broker: Broker, input: {
138
+ cwd: string;
139
+ modelId?: string;
140
+ modelPreset?: string;
141
+ childId?: string;
142
+ receivedAt?: number;
143
+ }): SpawnChildHostLaunch;
120
144
  type EffectMarker = {
121
145
  pid: number;
122
146
  effectMarker: string;
@@ -187,6 +211,8 @@ export declare function probePublishedReadyAuthorityForTest(root: string, id: st
187
211
  * by a reused pid (#4712 review).
188
212
  */
189
213
  export declare function removeOwnedLifecycleArtifactsForTest(root: string, id: string, expected: EffectMarker): Promise<boolean>;
214
+ /** Test seam for the worktree occupancy boundary. */
215
+ export declare function worktreeOccupantForTest(sessions: IndexedSession[], worktreePath: string, observe?: (pid: number, expectedIncarnation: string | undefined) => ProcessObservation): string | null;
190
216
  export declare function canonicalDeleteLocatorPath(pathname: string): string;
191
217
  export interface LifecycleExecutionOutcome {
192
218
  response: BrokerResponse;
@@ -0,0 +1,10 @@
1
+ import { type IndexedSession, type SessionIndex } from "./session-index";
2
+ import type { MasterCapabilityVerifier } from "./spawn-authority";
3
+ export type SessionEndpoint = {
4
+ url: string;
5
+ token: string;
6
+ };
7
+ /** Reads and validates a registered host's authenticated endpoint record. */
8
+ export declare function readEndpoint(record: IndexedSession): Promise<SessionEndpoint | undefined>;
9
+ /** Creates the ephemeral effective-host verifier used by broker spawn admission. */
10
+ export declare function createMasterCapabilityVerifier(index: SessionIndex): MasterCapabilityVerifier;
@@ -1,4 +1,4 @@
1
- import { SDK_STATE_VERSION } from "./state-version";
1
+ import { SDK_STATE_VERSION, SESSION_INDEX_EVENT_VERSION } from "./state-version";
2
2
  export type SessionIndexEventType = "host_registered" | "host_heartbeat" | "host_unregistered" | "lifecycle_started" | "lifecycle_terminal" | "session_closed" | "session_deleted" | "record_reconciled";
3
3
  export type SessionActivityState = "active" | "idle";
4
4
  /** Coalesced broker-owned heartbeat checkpoint (C2): state plus the observation time. */
@@ -28,15 +28,41 @@ export interface SessionIndexProcessObservation {
28
28
  readonly incarnation: string;
29
29
  readonly isRunning: () => boolean;
30
30
  }
31
+ /**
32
+ * Canonical location facts for one SDK session.
33
+ *
34
+ * `cwd` is always a realpath-canonicalized directory. `worktreeRoot` is the
35
+ * canonical Git worktree root when `cwd` is in a worktree, otherwise `null`.
36
+ * `stateRoot` retains its host-provided authority spelling and is never derived
37
+ * from either canonical path.
38
+ */
39
+ export type SessionLocatorV2 = {
40
+ cwd: string;
41
+ worktreeRoot: string | null;
42
+ stateRoot: string;
43
+ };
44
+ /** Durable master-role facts. `attestationEpoch` is opaque random broker state. */
45
+ export type MasterRoleAttestationV2 = {
46
+ version: 2;
47
+ ownerSessionId: string;
48
+ launchPid: number;
49
+ launchProcessIncarnation: string;
50
+ role: "master";
51
+ attestationEpoch: string;
52
+ };
53
+ export declare function newMasterAttestationEpoch(): string;
54
+ /** Canonicalize a cwd without making an unavailable path a launch failure. */
55
+ export declare function canonicalSessionCwd(cwd: string): Promise<string>;
56
+ /** Resolve the canonical worktree root; non-Git and probe failures are `null`. */
57
+ export declare function sessionWorktreeRoot(cwd: string): Promise<string | null>;
58
+ /** Build the only permitted locator shape for a newly registered session. */
59
+ export declare function resolveSessionLocator(cwd: string, stateRoot: string): Promise<SessionLocatorV2>;
31
60
  export interface SessionIndexEvent {
32
- version: typeof SDK_STATE_VERSION;
61
+ version: typeof SDK_STATE_VERSION | typeof SESSION_INDEX_EVENT_VERSION;
33
62
  indexSeq: number;
34
63
  type: SessionIndexEventType;
35
64
  sessionId: string;
36
- locator: {
37
- repo: string;
38
- stateRoot: string;
39
- };
65
+ locator: SessionLocatorV2;
40
66
  endpointGeneration: number;
41
67
  pid: number;
42
68
  /**
@@ -47,26 +73,28 @@ export interface SessionIndexEvent {
47
73
  */
48
74
  processIncarnation?: string;
49
75
  endpointMtimeMs?: number;
76
+ /** Immutable endpoint file identity captured by the broker at registration. */
77
+ endpointFileId?: string;
50
78
  lifecycleRequestId?: string;
51
79
  terminalUncertain?: boolean;
52
80
  /** OS process incarnation (C1); absent on legacy v1/v2 events. */
53
81
  hostIncarnation?: string;
54
82
  /** Present on host_heartbeat checkpoints (C2). */
55
83
  activity?: SessionActivity;
84
+ masterRole?: MasterRoleAttestationV2;
56
85
  ts: number;
57
86
  checksum: string;
58
87
  }
59
88
  export interface IndexedSession {
60
89
  sessionId: string;
61
- locator: {
62
- repo: string;
63
- stateRoot: string;
64
- };
90
+ locator: SessionLocatorV2;
65
91
  endpointGeneration: number;
66
92
  pid: number;
67
93
  /** OS start incarnation of `pid` as published by its own host at registration. */
68
94
  processIncarnation?: string;
69
95
  endpointMtimeMs?: number;
96
+ /** Immutable endpoint file identity captured by the broker at registration. */
97
+ endpointFileId?: string;
70
98
  live: boolean;
71
99
  indexSeq: number;
72
100
  lifecycleRequestId?: string;
@@ -76,6 +104,7 @@ export interface IndexedSession {
76
104
  activity?: SessionActivity;
77
105
  /** Wall-clock timestamp of the latest admitted heartbeat, when one exists. */
78
106
  lastHeartbeatAt?: number;
107
+ masterRole?: MasterRoleAttestationV2;
79
108
  /** True when more than one unresolved authority-fencing state-root identity claims this session id. */
80
109
  ambiguous: boolean;
81
110
  /** True when the identity's latest event is terminal (DR-1 retains stopped rows for inspection/offline tail). */
@@ -118,7 +147,7 @@ export interface SessionIndexRepairResult extends SessionIndexDiagnosis {
118
147
  quarantinePath?: string;
119
148
  }
120
149
  /** Admission-fence rejection codes recorded in the durable index audit (C5/C4). */
121
- export type SessionIndexAuditCode = "rejected_superseded_incarnation" | "rejected_after_tombstone";
150
+ export type SessionIndexAuditCode = "rejected_superseded_incarnation" | "rejected_after_tombstone" | "rejected_legacy_locator";
122
151
  export interface SessionIndexAuditRecord {
123
152
  version: typeof SDK_STATE_VERSION;
124
153
  code: SessionIndexAuditCode;
@@ -0,0 +1,72 @@
1
+ import { type SessionLocatorV2 } from "./session-index";
2
+ export type ScopeNameV1 = "repo" | "pwd" | "global";
3
+ export type ScopeRequestV1 = {
4
+ version: 1;
5
+ requested: ScopeNameV1;
6
+ requestAnchor: {
7
+ cwd: string;
8
+ worktreeRoot: string | null;
9
+ };
10
+ };
11
+ export type ResolvedScopeV1 = {
12
+ version: 1;
13
+ requested: ScopeNameV1;
14
+ requestAnchor: {
15
+ cwd: string;
16
+ worktreeRoot: string | null;
17
+ };
18
+ resolved: {
19
+ kind: "repo";
20
+ worktreeRoot: string;
21
+ } | {
22
+ kind: "pwd";
23
+ cwd: string;
24
+ } | {
25
+ kind: "global";
26
+ visibility: "current-broker";
27
+ } | null;
28
+ resolution: "resolved" | "not-in-git-worktree";
29
+ };
30
+ export type SdkSearchRowV1 = {
31
+ id: string;
32
+ locator: {
33
+ cwd: string;
34
+ worktreeRoot: string | null;
35
+ stateRoot: string;
36
+ };
37
+ live: boolean;
38
+ probe?: "reachable" | "unreachable" | "stale";
39
+ };
40
+ export type SdkSearchResultV1 = {
41
+ version: 1;
42
+ scope: ResolvedScopeV1;
43
+ status: "populated" | "empty" | "not-in-git-worktree" | "unavailable";
44
+ observedAt: string;
45
+ indexSeq?: number;
46
+ rows: readonly SdkSearchRowV1[];
47
+ cursor?: string;
48
+ warnings: readonly string[];
49
+ error?: {
50
+ code: string;
51
+ message: string;
52
+ };
53
+ };
54
+ export declare class ScopeRequestValidationError extends Error {
55
+ constructor(message: string);
56
+ }
57
+ /** Strictly validates the versioned request shape before canonical resolution. */
58
+ export declare function scopeRequestV1(value: unknown): ScopeRequestV1 | undefined;
59
+ /** Strictly validates a resolved descriptor returned by Broker pages. */
60
+ export declare function resolvedScopeV1(value: unknown): ResolvedScopeV1 | undefined;
61
+ /** Strictly validates a safe broker-search row. */
62
+ export declare function sdkSearchRowV1(value: unknown): SdkSearchRowV1 | undefined;
63
+ /** Strictly validates the aggregate credential-free search envelope. */
64
+ export declare function sdkSearchResultV1(value: unknown): SdkSearchResultV1 | undefined;
65
+ /** Resolves and validates an anchor against its canonical cwd worktree identity. */
66
+ export declare function resolveScopeRequest(request: ScopeRequestV1): Promise<ResolvedScopeV1>;
67
+ export declare function scopeMatchesLocator(scope: ResolvedScopeV1, locator: Pick<SessionLocatorV2, "cwd" | "worktreeRoot">): boolean;
68
+ export declare function searchRowV1(session: {
69
+ sessionId: string;
70
+ locator: SessionLocatorV2;
71
+ live: boolean;
72
+ }): SdkSearchRowV1;