@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
@@ -3,9 +3,11 @@ import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import { logger, resolveEquivalentPath } from "@gajae-code/utils";
5
5
  import {
6
+ canonicalSessionCwd,
6
7
  SessionIndex as DefaultSessionIndex,
7
8
  type IndexedSession,
8
9
  isSessionAuthorityEligible,
10
+ resolveSessionLocator,
9
11
  type SessionIndex,
10
12
  } from "../broker/session-index";
11
13
  import { cancellableSleep, lifecycleRequestTimeoutMs } from "../broker/startup-budget";
@@ -258,6 +260,8 @@ export type SessionRouterProviderDeps = Pick<
258
260
 
259
261
  export interface SessionRouterOptions {
260
262
  agentDir: string;
263
+ /** Limits attachment to exact ids selected by a Broker-scoped operation. */
264
+ sessionIds?: readonly string[];
261
265
  deps?: SessionRouterDeps;
262
266
  /** Runtime-specific identity validation; Router supplies a conservative fallback. */
263
267
  correlateFrame?: SessionRouterFrameCorrelator;
@@ -446,6 +450,10 @@ async function lstatEndpoint(file: string): Promise<SessionEndpointIdentity | un
446
450
  };
447
451
  }
448
452
 
453
+ function warningAffectsSession(warning: string, sessionId: string): boolean {
454
+ return !warning.startsWith("Session ") || warning.includes(`Session ${sessionId} `);
455
+ }
456
+
449
457
  function sameEndpointIdentity(expected: SessionEndpointIdentity, current: SessionEndpointIdentity): boolean {
450
458
  return (
451
459
  expected.mtimeMs === current.mtimeMs &&
@@ -565,6 +573,7 @@ type AdoptedSession = {
565
573
  */
566
574
  export class SessionRouter {
567
575
  readonly #agentDir: string;
576
+ readonly #sessionIds: ReadonlySet<string> | undefined;
568
577
  readonly #deps: SessionRouterDeps;
569
578
  readonly #correlateFrame: SessionRouterFrameCorrelator;
570
579
  readonly #index: SessionIndex;
@@ -603,6 +612,7 @@ export class SessionRouter {
603
612
 
604
613
  constructor(options: SessionRouterOptions) {
605
614
  this.#agentDir = options.agentDir;
615
+ this.#sessionIds = options.sessionIds === undefined ? undefined : new Set(options.sessionIds);
606
616
  this.#deps = options.deps ?? {};
607
617
  this.#correlateFrame = options.correlateFrame ?? fallbackCorrelation;
608
618
  this.#index = this.#deps.createIndex?.(options.agentDir) ?? new DefaultSessionIndex(options.agentDir);
@@ -753,11 +763,11 @@ export class SessionRouter {
753
763
  "pre_send",
754
764
  "Broker lifecycle result omitted an exact session endpoint authority.",
755
765
  );
756
- const repo = path.resolve(fallback.cwd);
757
- const stateRoot = path.join(repo, ".gjc", "state");
766
+ const cwd = await canonicalSessionCwd(fallback.cwd);
767
+ const stateRoot = path.join(cwd, ".gjc", "state");
758
768
  const indexed: IndexedSession = {
759
769
  sessionId,
760
- locator: { repo, stateRoot },
770
+ locator: await resolveSessionLocator(cwd, stateRoot),
761
771
  endpointGeneration,
762
772
  pid,
763
773
  endpointMtimeMs,
@@ -780,8 +790,9 @@ export class SessionRouter {
780
790
  if (!attached || !current || !capability)
781
791
  throw new SessionRouterError("pre_send", "Broker session endpoint could not be attached.");
782
792
  const listing = this.#index.listSessions();
783
- const indexedCurrent =
784
- listing.warnings.length === 0 ? listing.sessions.find(item => item.sessionId === sessionId) : undefined;
793
+ const indexedCurrent = listing.warnings.some(warning => warningAffectsSession(warning, sessionId))
794
+ ? undefined
795
+ : listing.sessions.find(item => item.sessionId === sessionId);
785
796
  if (indexedCurrent && sameIndexedAuthority(indexed, indexedCurrent))
786
797
  await this.#serialReconcile(this.#runEpoch, true, true);
787
798
  return capability;
@@ -953,7 +964,7 @@ export class SessionRouter {
953
964
  try {
954
965
  await this.#index.refresh();
955
966
  const listing = this.#index.listSessions();
956
- if (listing.warnings.length > 0) return undefined;
967
+ if (listing.warnings.some(warning => warningAffectsSession(warning, sessionId))) return undefined;
957
968
  indexed = listing.sessions.find(candidate => candidate.sessionId === sessionId);
958
969
  } catch {
959
970
  return undefined;
@@ -1025,7 +1036,7 @@ export class SessionRouter {
1025
1036
  await this.#index.open();
1026
1037
  await this.#index.refresh();
1027
1038
  const listing = this.#index.listSessions();
1028
- if (listing.warnings.length > 0)
1039
+ if (listing.warnings.some(warning => warningAffectsSession(warning, sessionId)))
1029
1040
  throw new SessionActivationError(
1030
1041
  "session_not_live",
1031
1042
  "Session activation requires an intact session index.",
@@ -1203,50 +1214,51 @@ export class SessionRouter {
1203
1214
  return;
1204
1215
  }
1205
1216
  const indexed = this.#index.listSessions();
1206
- const live =
1207
- indexed.warnings.length === 0
1208
- ? indexed.sessions.filter(
1209
- session => session.live && isSessionAuthorityEligible(session) && !session.terminalUncertain,
1210
- )
1211
- : [];
1217
+ const live = indexed.sessions.filter(
1218
+ session =>
1219
+ !indexed.warnings.some(warning => warningAffectsSession(warning, session.sessionId)) &&
1220
+ session.live &&
1221
+ isSessionAuthorityEligible(session) &&
1222
+ !session.terminalUncertain &&
1223
+ (this.#sessionIds === undefined || this.#sessionIds.has(session.sessionId)),
1224
+ );
1212
1225
  const liveIds = new Set(live.map(session => session.sessionId));
1213
1226
  const attachedIds = new Set<string>();
1214
- if (indexed.warnings.length === 0) {
1215
- for (const [sessionId, adopted] of [...this.#adopted]) {
1216
- const attached = this.#sessions.get(sessionId);
1217
- const indexedSession = indexed.sessions.find(session => session.sessionId === sessionId);
1218
- if (!attached || attached.capability !== adopted.attachment) {
1219
- this.#adopted.delete(sessionId);
1220
- continue;
1221
- }
1222
- const exactIndex =
1223
- indexedSession?.live === true &&
1224
- isSessionAuthorityEligible(indexedSession) &&
1225
- !indexedSession.terminalUncertain &&
1226
- indexedSession.endpointGeneration === adopted.generation &&
1227
- indexedSession.pid === adopted.pid &&
1228
- indexedSession.endpointMtimeMs === adopted.endpointMtimeMs;
1229
- const endpoint = exactIndex ? await this.#readEndpoint(indexedSession).catch(() => null) : null;
1230
- if (
1231
- !exactIndex ||
1232
- !endpoint ||
1233
- endpoint.pid !== adopted.pid ||
1234
- endpoint.url !== attached.endpoint.url ||
1235
- endpoint.token !== attached.endpoint.token
1236
- ) {
1237
- this.#adopted.delete(sessionId);
1238
- await this.#retireAttachment(attached);
1239
- continue;
1240
- }
1241
- try {
1242
- if (await this.#publishAttachment(attached, true)) {
1243
- this.#adopted.delete(sessionId);
1244
- attachedIds.add(sessionId);
1245
- }
1246
- } catch {
1227
+ for (const [sessionId, adopted] of [...this.#adopted]) {
1228
+ if (indexed.warnings.some(warning => warningAffectsSession(warning, sessionId))) continue;
1229
+ const attached = this.#sessions.get(sessionId);
1230
+ const indexedSession = indexed.sessions.find(session => session.sessionId === sessionId);
1231
+ if (!attached || attached.capability !== adopted.attachment) {
1232
+ this.#adopted.delete(sessionId);
1233
+ continue;
1234
+ }
1235
+ const exactIndex =
1236
+ indexedSession?.live === true &&
1237
+ isSessionAuthorityEligible(indexedSession) &&
1238
+ !indexedSession.terminalUncertain &&
1239
+ indexedSession.endpointGeneration === adopted.generation &&
1240
+ indexedSession.pid === adopted.pid &&
1241
+ indexedSession.endpointMtimeMs === adopted.endpointMtimeMs;
1242
+ const endpoint = exactIndex ? await this.#readEndpoint(indexedSession).catch(() => null) : null;
1243
+ if (
1244
+ !exactIndex ||
1245
+ !endpoint ||
1246
+ endpoint.pid !== adopted.pid ||
1247
+ endpoint.url !== attached.endpoint.url ||
1248
+ endpoint.token !== attached.endpoint.token
1249
+ ) {
1250
+ this.#adopted.delete(sessionId);
1251
+ await this.#retireAttachment(attached);
1252
+ continue;
1253
+ }
1254
+ try {
1255
+ if (await this.#publishAttachment(attached, true)) {
1247
1256
  this.#adopted.delete(sessionId);
1248
- await this.#retireAttachment(attached);
1257
+ attachedIds.add(sessionId);
1249
1258
  }
1259
+ } catch {
1260
+ this.#adopted.delete(sessionId);
1261
+ await this.#retireAttachment(attached);
1250
1262
  }
1251
1263
  }
1252
1264
  let nextAttachment = 0;
@@ -1361,15 +1373,11 @@ export class SessionRouter {
1361
1373
  indexed: IndexedSession,
1362
1374
  ): Promise<{ endpoint: SdkSessionEndpoint; identity: SessionEndpointIdentity } | null> {
1363
1375
  if (!isSessionAuthorityEligible(indexed)) return null;
1364
- const repo = path.resolve(indexed.locator.repo);
1365
- const defaultStateRoot = path.join(repo, ".gjc", "state");
1366
- // The session index stores the lifecycle caller's lexical cwd in `locator.repo`
1367
- // (reconcileReadyScope re-scopes only that field) while `locator.stateRoot` is
1368
- // the host process's physical path, because process.cwd() resolves symlinks.
1369
- // The scope test therefore compares path identity, not spelling: a lexical
1370
- // match fails for every symlinked cwd (macOS /var -> /private/var,
1371
- // /home/jun/desk -> /data/Lina-Desk), the adopted attachment is retired on
1372
- // reconcile, and session/new surfaces "lost exact Router authority".
1376
+ const cwd = indexed.locator.cwd;
1377
+ const defaultStateRoot = path.join(cwd, ".gjc", "state");
1378
+ // Locator cwd is already canonical. `stateRoot` remains the host-provided
1379
+ // authority path, so this comparison resolves equivalent paths only for the
1380
+ // state-root identity boundary; cwd never retains lexical symlink spellings.
1373
1381
  const indexedStateRoot = resolveEquivalentPath(indexed.locator.stateRoot);
1374
1382
  const scope =
1375
1383
  indexedStateRoot === resolveEquivalentPath(defaultStateRoot)
@@ -1378,9 +1386,9 @@ export class SessionRouter {
1378
1386
  ? "chat"
1379
1387
  : undefined;
1380
1388
  if (!scope || indexed.endpointMtimeMs === undefined || !Number.isFinite(indexed.endpointMtimeMs)) return null;
1381
- const endpointPath = path.join(endpointDirectory(repo, scope), `${indexed.sessionId}.json`);
1389
+ const endpointPath = path.join(endpointDirectory(cwd, scope), `${indexed.sessionId}.json`);
1382
1390
  const endpointIdentity = await lstatEndpoint(endpointPath);
1383
- const endpoint = await readSdkSessionEndpoint(repo, indexed.sessionId, scope);
1391
+ const endpoint = await readSdkSessionEndpoint(cwd, indexed.sessionId, scope);
1384
1392
  if (!endpoint || endpoint.stale || endpoint.pid !== indexed.pid) return null;
1385
1393
  if (!endpointIdentity || endpointIdentity.mtimeMs !== indexed.endpointMtimeMs) return null;
1386
1394
  // Identity is proven INSIDE this authority read (#4730 review): sampling it
@@ -1413,7 +1421,7 @@ export class SessionRouter {
1413
1421
  return null;
1414
1422
  await this.#index.refresh();
1415
1423
  const listing = this.#index.listSessions();
1416
- if (listing.warnings.length > 0) return null;
1424
+ if (listing.warnings.some(warning => warningAffectsSession(warning, indexed.sessionId))) return null;
1417
1425
  const current = listing.sessions.find(session => session.sessionId === indexed.sessionId);
1418
1426
  if (!current || !sameIndexedAuthority(indexed, current)) return null;
1419
1427
  return { endpoint, identity: provenIdentity };