@gajae-code/coding-agent 0.18.5 → 0.18.6

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 (91) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/types/cli-commands.d.ts +10 -0
  3. package/dist/types/cli-ordinary.d.ts +13 -0
  4. package/dist/types/cli.d.ts +12 -3
  5. package/dist/types/commands/contribution-prep.d.ts +0 -3
  6. package/dist/types/commands/sdk.d.ts +3 -0
  7. package/dist/types/commands/update.d.ts +1 -0
  8. package/dist/types/config/model-profile-activation.d.ts +19 -0
  9. package/dist/types/coordinator-mcp/session-reaper.d.ts +5 -0
  10. package/dist/types/edit/modes/replace.d.ts +3 -3
  11. package/dist/types/edit/streaming.d.ts +2 -2
  12. package/dist/types/exec/bash-shell-supervisor.d.ts +12 -0
  13. package/dist/types/sdk/broker/discovery.d.ts +8 -0
  14. package/dist/types/sdk/broker/ensure.d.ts +1 -0
  15. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +4 -0
  16. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  17. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  18. package/dist/types/sdk/bus/telegram-daemon.d.ts +1 -0
  19. package/dist/types/sdk/cli/diagnostics-cli.d.ts +18 -0
  20. package/dist/types/sdk/diagnostics/observe-broker.d.ts +185 -0
  21. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  22. package/dist/types/sdk/index.d.ts +1 -0
  23. package/dist/types/sdk/router/session-router.d.ts +2 -0
  24. package/dist/types/sdk/session.d.ts +13 -0
  25. package/dist/types/session/agent-session.d.ts +5 -1
  26. package/dist/types/tools/ask-contract.d.ts +75 -254
  27. package/dist/types/tools/bash.d.ts +1 -1
  28. package/package.json +7 -7
  29. package/scripts/build-sdk-package-smoke.ts +5 -0
  30. package/src/cli/public-command-entry.ts +5 -0
  31. package/src/cli/ssh-cli.ts +6 -3
  32. package/src/cli/web-search-cli.ts +9 -3
  33. package/src/cli-commands.ts +14 -0
  34. package/src/cli-ordinary.ts +197 -0
  35. package/src/cli.ts +25 -182
  36. package/src/commands/contribution-prep.ts +1 -3
  37. package/src/commands/sdk.ts +59 -0
  38. package/src/commands/update.ts +15 -1
  39. package/src/config/file-lock.ts +91 -2
  40. package/src/config/model-profile-activation.ts +70 -4
  41. package/src/config/model-profile-contract.ts +4 -1
  42. package/src/config/model-profiles.ts +23 -31
  43. package/src/config/model-resolver.ts +9 -1
  44. package/src/coordinator-mcp/event-webhook.ts +19 -14
  45. package/src/coordinator-mcp/policy.ts +14 -4
  46. package/src/coordinator-mcp/server.ts +142 -7
  47. package/src/coordinator-mcp/session-reaper.ts +9 -1
  48. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  49. package/src/edit/modes/replace.ts +6 -6
  50. package/src/edit/streaming.ts +15 -15
  51. package/src/exec/bash-shell-supervisor.ts +60 -3
  52. package/src/internal-urls/docs-index.generated.ts +10 -9
  53. package/src/memories/index.ts +8 -2
  54. package/src/modes/acp/acp-agent.ts +649 -367
  55. package/src/modes/components/tool-execution.ts +1 -1
  56. package/src/prompts/tools/ask.md +2 -0
  57. package/src/sdk/broker/broker.ts +46 -0
  58. package/src/sdk/broker/daemon-entry.ts +67 -6
  59. package/src/sdk/broker/discovery.ts +8 -0
  60. package/src/sdk/broker/ensure.ts +156 -20
  61. package/src/sdk/broker/lifecycle-ledger.ts +110 -12
  62. package/src/sdk/broker/lifecycle.ts +225 -341
  63. package/src/sdk/broker/runtime.ts +5 -1
  64. package/src/sdk/broker/transport.ts +5 -1
  65. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  66. package/src/sdk/bus/telegram-daemon-control.ts +15 -12
  67. package/src/sdk/bus/telegram-daemon.ts +34 -1
  68. package/src/sdk/cli/diagnostics-cli.ts +247 -0
  69. package/src/sdk/diagnostics/observe-broker.ts +654 -0
  70. package/src/sdk/host/control/dispatch.ts +52 -4
  71. package/src/sdk/host/control/operations.ts +1 -1
  72. package/src/sdk/host/session-runtime.test.ts +40 -2
  73. package/src/sdk/host/session-runtime.ts +13 -5
  74. package/src/sdk/index.ts +1 -0
  75. package/src/sdk/lifecycle-session.ts +1 -0
  76. package/src/sdk/protocol/operation-registry.ts +1 -1
  77. package/src/sdk/router/session-router.ts +7 -1
  78. package/src/sdk/session.ts +37 -8
  79. package/src/session/agent-session.ts +114 -39
  80. package/src/session/blob-store.ts +78 -33
  81. package/src/session/internal/managed-session-storage.ts +96 -3
  82. package/src/setup/hermes/templates/operator-instructions.v1.md +19 -1
  83. package/src/setup/hermes-setup.ts +4 -1
  84. package/src/slash-commands/builtin-registry.ts +8 -5
  85. package/src/tools/ask-contract.test.ts +76 -1
  86. package/src/tools/ask-contract.ts +57 -6
  87. package/src/tools/ask.ts +16 -7
  88. package/src/tools/bash.ts +38 -29
  89. package/src/tools/descriptors.test.ts +29 -0
  90. package/src/tools/tool-catalog.generated.ts +7 -4
  91. package/src/web/search/index.ts +2 -2
@@ -74,6 +74,8 @@ export interface LifecycleDurableEffectsReceipt {
74
74
  export interface LifecycleLedgerEntry {
75
75
  operationKey?: string;
76
76
  fingerprint?: string;
77
+ /** True only when a session.close request supplied immutable generation authority. */
78
+ closeAuthorityBound?: boolean;
77
79
  version: typeof SDK_STATE_VERSION;
78
80
  identity: string;
79
81
  requestHash: string;
@@ -213,6 +215,20 @@ function pendingCleanupSessionId(response: unknown): string | undefined {
213
215
  return canonicalCleanupSessionId(cleanup?.sessionId) ? cleanup.sessionId : undefined;
214
216
  }
215
217
 
218
+ function retirementCreateIdentity(response: unknown): string | undefined {
219
+ if (!response || typeof response !== "object") return undefined;
220
+ const error = (response as { error?: unknown }).error;
221
+ if (!error || typeof error !== "object") return undefined;
222
+ const cleanup = (error as { cleanup?: unknown }).cleanup;
223
+ if (!cleanup || typeof cleanup !== "object") return undefined;
224
+ const receipt = (cleanup as { uncertainRetirement?: unknown }).uncertainRetirement;
225
+ if (!receipt || typeof receipt !== "object") return undefined;
226
+ const identity = (receipt as { identity?: unknown }).identity;
227
+ if (!identity || typeof identity !== "object") return undefined;
228
+ const createIdentity = (identity as { createIdentity?: unknown }).createIdentity;
229
+ return typeof createIdentity === "string" && createIdentity.length > 0 ? createIdentity : undefined;
230
+ }
231
+
216
232
  function hasValidTerminalDigests(entry: LifecycleLedgerEntry): boolean {
217
233
  const response = entry.response as { ok?: unknown; error?: { code?: unknown; cleanup?: unknown } } | undefined;
218
234
  const cleanupPendingResponse =
@@ -646,23 +662,91 @@ export class LifecycleLedger {
646
662
  await directory.close();
647
663
  }
648
664
  }
649
- async #compact(replacement?: LifecycleLedgerEntry): Promise<boolean> {
665
+ async #compact(
666
+ replacement?: LifecycleLedgerEntry,
667
+ incoming?: { readonly bytes: number; readonly rows: number },
668
+ ): Promise<boolean> {
650
669
  const anchors = new Map<string, LifecycleLedgerEntry>();
651
670
  for (const entry of this.#entries) {
652
671
  const latest = replacement?.identity === entry.identity ? replacement : this.#byIdentity.get(entry.identity);
653
672
  if (entry.state === "accepted" && !anchors.has(entry.identity) && entry.requestHash === latest?.requestHash)
654
673
  anchors.set(entry.identity, entry);
655
674
  }
656
- const snapshot: LifecycleLedgerEntry[] = [];
657
675
  const compacted = new Map(this.#byIdentity);
658
676
  if (replacement) compacted.set(replacement.identity, replacement);
659
- for (const [identity, latest] of compacted) {
660
- const anchor = anchors.get(identity);
661
- if (!anchor) throw new Error("Lifecycle ledger compaction requires an accepted identity anchor.");
662
- snapshot.push(replacement?.identity === identity && latest.state === "accepted" ? latest : anchor);
663
- if (latest.state !== "accepted") snapshot.push(latest);
677
+ const buildSnapshot = (): LifecycleLedgerEntry[] => {
678
+ const next: LifecycleLedgerEntry[] = [];
679
+ for (const [identity, latest] of compacted) {
680
+ const anchor = anchors.get(identity);
681
+ if (!anchor) throw new Error("Lifecycle ledger compaction requires an accepted identity anchor.");
682
+ next.push(replacement?.identity === identity && latest.state === "accepted" ? latest : anchor);
683
+ if (latest.state !== "accepted") next.push(latest);
684
+ }
685
+ return next;
686
+ };
687
+ let snapshot = buildSnapshot();
688
+ let contents = Buffer.from(snapshot.map(entry => `${JSON.stringify(entry)}\n`).join(""));
689
+ const needsEviction = incoming
690
+ ? snapshot.length + incoming.rows > this.#limits.maxRows ||
691
+ contents.length + incoming.bytes > this.#limits.maxBytes
692
+ : replacement === undefined
693
+ ? snapshot.length >= this.#limits.maxRows || contents.length >= this.#limits.maxBytes
694
+ : snapshot.length > this.#limits.maxRows || contents.length > this.#limits.maxBytes;
695
+ if (needsEviction) {
696
+ const protectedCreateIdentities = new Set<string>();
697
+ for (const entry of compacted.values()) {
698
+ const createIdentity =
699
+ retirementCreateIdentity(entry.response) ?? retirementCreateIdentity(entry.unresolvedCleanupResponse);
700
+ if (createIdentity !== undefined) protectedCreateIdentities.add(createIdentity);
701
+ }
702
+ const evictable = [...compacted.values()]
703
+ .filter(
704
+ latest =>
705
+ latest.identity !== replacement?.identity &&
706
+ terminal(latest.state) &&
707
+ latest.operationKey !== undefined &&
708
+ latest.fingerprint !== undefined &&
709
+ (!latest.operationKey.startsWith("session.close\u0000") || latest.closeAuthorityBound === true) &&
710
+ !protectedCreateIdentities.has(latest.identity) &&
711
+ pendingCleanupSessionId(latest.response) === undefined &&
712
+ pendingCleanupSessionId(latest.unresolvedCleanupResponse) === undefined,
713
+ )
714
+ .sort((left, right) => left.ts - right.ts);
715
+ const rowsByIdentity = new Map<string, number>();
716
+ const bytesByIdentity = new Map<string, number>();
717
+ for (const entry of snapshot) {
718
+ rowsByIdentity.set(entry.identity, (rowsByIdentity.get(entry.identity) ?? 0) + 1);
719
+ bytesByIdentity.set(
720
+ entry.identity,
721
+ (bytesByIdentity.get(entry.identity) ?? 0) + Buffer.byteLength(`${JSON.stringify(entry)}\n`),
722
+ );
723
+ }
724
+ let remainingRows = snapshot.length;
725
+ let remainingBytes = contents.length;
726
+ const evicted = new Set<string>();
727
+ for (const latest of evictable) {
728
+ if (
729
+ remainingRows <= this.#limits.maxRows / 2 &&
730
+ remainingBytes <= this.#limits.maxBytes / 2 &&
731
+ remainingRows + (incoming?.rows ?? 0) <= this.#limits.maxRows &&
732
+ remainingBytes + (incoming?.bytes ?? 0) <= this.#limits.maxBytes
733
+ )
734
+ break;
735
+ evicted.add(latest.identity);
736
+ remainingRows -= rowsByIdentity.get(latest.identity) ?? 0;
737
+ remainingBytes -= bytesByIdentity.get(latest.identity) ?? 0;
738
+ }
739
+ for (const identity of evicted) compacted.delete(identity);
740
+ snapshot = buildSnapshot();
741
+ contents = Buffer.from(snapshot.map(entry => `${JSON.stringify(entry)}\n`).join(""));
742
+ // Replay is guaranteed only for identities retained in the compacted ledger.
664
743
  }
665
- const contents = Buffer.from(snapshot.map(entry => `${JSON.stringify(entry)}\n`).join(""));
744
+ if (
745
+ incoming &&
746
+ (snapshot.length + incoming.rows > this.#limits.maxRows ||
747
+ contents.length + incoming.bytes > this.#limits.maxBytes)
748
+ )
749
+ throw new Error("Lifecycle ledger append exceeds configured bounds.");
666
750
  if (
667
751
  snapshot.length > this.#limits.maxRows ||
668
752
  contents.length > this.#limits.maxBytes ||
@@ -735,7 +819,7 @@ export class LifecycleLedger {
735
819
  async migrateIdentity(
736
820
  from: string,
737
821
  to: string,
738
- metadata: { operationKey: string; fingerprint: string },
822
+ metadata: { operationKey: string; fingerprint: string; closeAuthorityBound?: boolean },
739
823
  ): Promise<LifecycleLedgerEntry | undefined> {
740
824
  return this.#mutate(async () => {
741
825
  const existing = this.#byIdentity.get(to);
@@ -776,9 +860,12 @@ export class LifecycleLedger {
776
860
  );
777
861
  if (line.length - 1 > this.#limits.maxLineBytes)
778
862
  throw new Error("Lifecycle ledger row exceeds the maximum byte length.");
863
+ if (line.length > this.#limits.maxBytes) throw new Error("Lifecycle ledger append exceeds configured bounds.");
779
864
  let replacementCompacted = false;
780
865
  if (this.#rowCount + 1 > this.#limits.maxRows || this.#byteCount + line.length > this.#limits.maxBytes)
781
- replacementCompacted = await this.#compact(this.#byIdentity.has(entry.identity) ? entry : undefined);
866
+ replacementCompacted = this.#byIdentity.has(entry.identity)
867
+ ? await this.#compact(entry)
868
+ : await this.#compact(undefined, { bytes: line.length, rows: 1 });
782
869
  if (replacementCompacted) return entry;
783
870
  if (this.#rowCount + 1 > this.#limits.maxRows || this.#byteCount + line.length > this.#limits.maxBytes)
784
871
  throw new Error("Lifecycle ledger append exceeds configured bounds.");
@@ -798,7 +885,12 @@ export class LifecycleLedger {
798
885
  async begin(
799
886
  identity: string,
800
887
  requestHash: string,
801
- metadata: { operationKey?: string; fingerprint?: string; intendedSessionId?: string } = {},
888
+ metadata: {
889
+ operationKey?: string;
890
+ fingerprint?: string;
891
+ intendedSessionId?: string;
892
+ closeAuthorityBound?: boolean;
893
+ } = {},
802
894
  ): Promise<BeginResult> {
803
895
  return this.#mutate(async () => this.#begin(identity, requestHash, metadata));
804
896
  }
@@ -806,7 +898,12 @@ export class LifecycleLedger {
806
898
  async #begin(
807
899
  identity: string,
808
900
  requestHash: string,
809
- metadata: { operationKey?: string; fingerprint?: string; intendedSessionId?: string },
901
+ metadata: {
902
+ operationKey?: string;
903
+ fingerprint?: string;
904
+ intendedSessionId?: string;
905
+ closeAuthorityBound?: boolean;
906
+ },
810
907
  ): Promise<BeginResult> {
811
908
  const prior = this.#byIdentity.get(identity);
812
909
  if (!prior)
@@ -819,6 +916,7 @@ export class LifecycleLedger {
819
916
  operationKey: metadata.operationKey,
820
917
  fingerprint: metadata.fingerprint,
821
918
  intendedSessionId: metadata.intendedSessionId,
919
+ closeAuthorityBound: metadata.closeAuthorityBound,
822
920
  state: "accepted",
823
921
  ts: Date.now(),
824
922
  }),