@gajae-code/coding-agent 0.18.5 → 0.18.7

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 (133) hide show
  1. package/CHANGELOG.md +140 -0
  2. package/dist/types/capability/types.d.ts +4 -0
  3. package/dist/types/cli-commands.d.ts +10 -0
  4. package/dist/types/cli-ordinary.d.ts +13 -0
  5. package/dist/types/cli.d.ts +12 -3
  6. package/dist/types/commands/contribution-prep.d.ts +0 -3
  7. package/dist/types/commands/sdk.d.ts +3 -0
  8. package/dist/types/commands/update.d.ts +1 -0
  9. package/dist/types/config/model-profile-activation.d.ts +19 -0
  10. package/dist/types/config/settings.d.ts +4 -0
  11. package/dist/types/coordinator-mcp/session-reaper.d.ts +5 -0
  12. package/dist/types/discovery/helpers.d.ts +2 -2
  13. package/dist/types/edit/modes/replace.d.ts +3 -3
  14. package/dist/types/edit/streaming.d.ts +2 -2
  15. package/dist/types/exec/bash-shell-supervisor.d.ts +12 -0
  16. package/dist/types/runtime-mcp/elicitation.d.ts +12 -0
  17. package/dist/types/sdk/broker/discovery.d.ts +8 -0
  18. package/dist/types/sdk/broker/ensure.d.ts +1 -0
  19. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +4 -0
  20. package/dist/types/sdk/broker/lifecycle.d.ts +9 -0
  21. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  22. package/dist/types/sdk/broker/task-artifact-owner-validation.d.ts +55 -0
  23. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  24. package/dist/types/sdk/bus/telegram-daemon.d.ts +4 -2
  25. package/dist/types/sdk/cli/diagnostics-cli.d.ts +18 -0
  26. package/dist/types/sdk/diagnostics/observe-broker.d.ts +185 -0
  27. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  28. package/dist/types/sdk/host/host.d.ts +6 -0
  29. package/dist/types/sdk/index.d.ts +1 -0
  30. package/dist/types/sdk/router/session-router.d.ts +9 -0
  31. package/dist/types/sdk/session.d.ts +13 -0
  32. package/dist/types/session/agent-session.d.ts +5 -1
  33. package/dist/types/session/internal/managed-session-storage.d.ts +11 -1
  34. package/dist/types/session/internal/task-artifact-owner-access.d.ts +17 -0
  35. package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +3 -0
  36. package/dist/types/session/session-retirement.d.ts +47 -0
  37. package/dist/types/session/session-storage.d.ts +0 -46
  38. package/dist/types/session/session-transcript-header.d.ts +2 -0
  39. package/dist/types/session/task-artifact-owner-codec.d.ts +107 -0
  40. package/dist/types/session/task-artifact-owner-retirement.d.ts +7 -0
  41. package/dist/types/session/task-artifact-owner.d.ts +10 -0
  42. package/dist/types/tools/ask-contract.d.ts +75 -254
  43. package/dist/types/tools/bash.d.ts +1 -1
  44. package/package.json +7 -7
  45. package/scripts/build-sdk-package-smoke.ts +5 -0
  46. package/scripts/resident-memory-bench.ts +174 -20
  47. package/src/capability/index.ts +1 -0
  48. package/src/capability/types.ts +4 -0
  49. package/src/cli/config-cli.ts +8 -18
  50. package/src/cli/public-command-entry.ts +5 -0
  51. package/src/cli/ssh-cli.ts +6 -3
  52. package/src/cli/web-search-cli.ts +9 -3
  53. package/src/cli-commands.ts +14 -0
  54. package/src/cli-main.ts +7 -8
  55. package/src/cli-ordinary.ts +197 -0
  56. package/src/cli.ts +25 -182
  57. package/src/commands/contribution-prep.ts +1 -3
  58. package/src/commands/sdk.ts +171 -21
  59. package/src/commands/update.ts +15 -1
  60. package/src/config/file-lock.ts +91 -2
  61. package/src/config/model-profile-activation.ts +70 -4
  62. package/src/config/model-profile-contract.ts +4 -1
  63. package/src/config/model-profiles.ts +23 -31
  64. package/src/config/model-resolver.ts +9 -1
  65. package/src/config/settings.ts +44 -4
  66. package/src/coordinator-mcp/event-webhook.ts +19 -14
  67. package/src/coordinator-mcp/policy.ts +14 -4
  68. package/src/coordinator-mcp/server.ts +142 -7
  69. package/src/coordinator-mcp/session-reaper.ts +9 -1
  70. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  71. package/src/discovery/helpers.ts +9 -3
  72. package/src/discovery/ssh.ts +8 -3
  73. package/src/edit/modes/replace.ts +6 -6
  74. package/src/edit/streaming.ts +15 -15
  75. package/src/exec/bash-shell-supervisor.ts +60 -3
  76. package/src/gjc-runtime/gc-runtime.ts +2 -1
  77. package/src/hindsight/config.ts +9 -3
  78. package/src/internal-urls/docs-index.generated.ts +11 -10
  79. package/src/memories/index.ts +8 -2
  80. package/src/modes/acp/acp-agent.ts +724 -370
  81. package/src/modes/components/tool-execution.ts +1 -1
  82. package/src/prompts/tools/ask.md +2 -0
  83. package/src/runtime-mcp/client.ts +13 -4
  84. package/src/runtime-mcp/elicitation.ts +142 -0
  85. package/src/sdk/broker/broker.ts +54 -1
  86. package/src/sdk/broker/daemon-entry.ts +67 -6
  87. package/src/sdk/broker/discovery.ts +8 -0
  88. package/src/sdk/broker/ensure.ts +156 -20
  89. package/src/sdk/broker/lifecycle-ledger.ts +110 -12
  90. package/src/sdk/broker/lifecycle.ts +334 -348
  91. package/src/sdk/broker/runtime.ts +5 -1
  92. package/src/sdk/broker/task-artifact-owner-validation.ts +259 -0
  93. package/src/sdk/broker/transport.ts +5 -1
  94. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  95. package/src/sdk/bus/chat-daemon-runtime.ts +3 -0
  96. package/src/sdk/bus/index.ts +3 -3
  97. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  98. package/src/sdk/bus/telegram-daemon-control.ts +15 -12
  99. package/src/sdk/bus/telegram-daemon.ts +38 -3
  100. package/src/sdk/cli/diagnostics-cli.ts +247 -0
  101. package/src/sdk/diagnostics/observe-broker.ts +654 -0
  102. package/src/sdk/host/control/dispatch.ts +52 -4
  103. package/src/sdk/host/control/operations.ts +1 -1
  104. package/src/sdk/host/host.ts +6 -0
  105. package/src/sdk/host/session-runtime.test.ts +83 -4
  106. package/src/sdk/host/session-runtime.ts +15 -7
  107. package/src/sdk/index.ts +1 -0
  108. package/src/sdk/lifecycle-session.ts +1 -0
  109. package/src/sdk/mcp/server.ts +15 -3
  110. package/src/sdk/protocol/operation-registry.ts +1 -1
  111. package/src/sdk/router/session-router.ts +26 -3
  112. package/src/sdk/session.ts +51 -8
  113. package/src/session/agent-session.ts +169 -43
  114. package/src/session/blob-store.ts +78 -33
  115. package/src/session/internal/managed-session-storage.ts +203 -4
  116. package/src/session/internal/task-artifact-owner-access.ts +229 -0
  117. package/src/session/internal/task-artifact-owner-transcript.ts +68 -0
  118. package/src/session/session-retirement.ts +155 -0
  119. package/src/session/session-storage.ts +1 -160
  120. package/src/session/session-transcript-header.ts +17 -0
  121. package/src/session/task-artifact-owner-codec.ts +578 -0
  122. package/src/session/task-artifact-owner-retirement.ts +475 -0
  123. package/src/session/task-artifact-owner.ts +289 -0
  124. package/src/setup/hermes/templates/operator-instructions.v1.md +19 -1
  125. package/src/setup/hermes-setup.ts +4 -1
  126. package/src/slash-commands/builtin-registry.ts +8 -5
  127. package/src/tools/ask-contract.test.ts +76 -1
  128. package/src/tools/ask-contract.ts +57 -6
  129. package/src/tools/ask.ts +16 -7
  130. package/src/tools/bash.ts +38 -29
  131. package/src/tools/descriptors.test.ts +29 -0
  132. package/src/tools/tool-catalog.generated.ts +7 -4
  133. package/src/web/search/index.ts +2 -2
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Observation-only broker diagnostics facade (SPEC "Result contract").
3
+ *
4
+ * The publication is read ONLY through the approved read-only native lease
5
+ * (`loadDiagnosticNativeReadOnly` -> `openDiagnosticSnapshot` -> bounded read ->
6
+ * revalidate -> close), so every ancestor ACL/owner/mode and filesystem check of the
7
+ * earlier slices governs this route too. Ordinary discovery is deliberately not used: it
8
+ * would bypass that gate. An unsupported runtime tuple or artifact resolves to
9
+ * `unsupported` BEFORE any publication access. The facade then opens exactly ONE client
10
+ * connection with no reconnect attempts, asks the broker for its published diagnostics
11
+ * and returns a detached frozen snapshot. It never ensures, starts, recovers, retires or spawns
12
+ * anything, never touches the session index, ledger or evidence store, and never hands
13
+ * the caller a token, socket coordinate, path, pid or environment value.
14
+ */
15
+ /** Allowed unavailability reasons; messages are fixed literals keyed by the enum. */
16
+ export type BrokerObservationUnavailableReason = "absent" | "stale" | "incompatible" | "authentication_failed" | "unsupported" | "generation_mismatch" | "transport_unavailable" | "timeout" | "invalid_response" | "unsafe_discovery";
17
+ export interface BrokerObservationBuild {
18
+ readonly packageVersion: string;
19
+ readonly buildId: string | null;
20
+ }
21
+ export interface BrokerObservationSuccess {
22
+ readonly schema: "gjc.broker-observation";
23
+ readonly version: 1;
24
+ readonly ok: true;
25
+ readonly observedAt: string;
26
+ readonly broker: {
27
+ readonly generation: string;
28
+ readonly build: BrokerObservationBuild;
29
+ readonly diagnosticProtocol: 1;
30
+ };
31
+ }
32
+ export interface BrokerObservationUnavailable {
33
+ readonly schema: "gjc.broker-observation";
34
+ readonly version: 1;
35
+ readonly ok: false;
36
+ readonly observedAt: string;
37
+ readonly unavailable: {
38
+ readonly reason: BrokerObservationUnavailableReason;
39
+ readonly message: string;
40
+ };
41
+ }
42
+ export type BrokerObservation = BrokerObservationSuccess | BrokerObservationUnavailable;
43
+ export interface ObserveExistingBrokerOptions {
44
+ readonly agentDir: string;
45
+ readonly expectedGeneration?: string;
46
+ readonly timeoutMs?: number;
47
+ }
48
+ /** The broker's published diagnostics operation. */
49
+ export declare const BROKER_DIAGNOSTICS_OPERATION = "broker.diagnostics";
50
+ /** The only diagnostic protocol this client understands. */
51
+ export declare const BROKER_DIAGNOSTIC_PROTOCOL = 1;
52
+ /** Contract timeout: default 2000 ms, accepted range 1..10000 ms. */
53
+ export declare const OBSERVATION_TIMEOUT_DEFAULT_MS = 2000;
54
+ export declare const OBSERVATION_TIMEOUT_MIN_MS = 1;
55
+ export declare const OBSERVATION_TIMEOUT_MAX_MS = 10000;
56
+ export declare function setObservationClockForTest(clock: (() => number) | null): void;
57
+ /**
58
+ * Test-only observers for the native stage boundary. Production installs none, and the
59
+ * hooks never change a branch, a budget or an outcome: they only report what the
60
+ * observation did (`onNativeOpen`) and give a test a point to disturb the environment
61
+ * between the first publication read and the connection (`afterInitialRead`), which is how
62
+ * the pre-socket identity recheck is proven instead of argued.
63
+ */
64
+ export interface ObservationTestHooks {
65
+ onNativeOpen?: (info: {
66
+ agentDir: string;
67
+ budgetMs: number;
68
+ }) => void;
69
+ afterInitialRead?: () => void;
70
+ /** Reports that the retained lease was released, on every exit path. */
71
+ onLeaseClosed?: () => void;
72
+ /**
73
+ * Decorates the retained lease so a test can identify the real operation phases and make
74
+ * a chosen phase refuse or throw. Production installs none.
75
+ */
76
+ wrapLease?: (lease: DiagnosticSnapshotLease) => DiagnosticSnapshotLease;
77
+ /** Replaces the loader result so loader-stage outcomes can be observed deterministically. */
78
+ loaderOverride?: () => DiagnosticNativeLoad;
79
+ }
80
+ /** Minimal shapes this facade relies on from the approved read-only loader. */
81
+ interface DiagnosticSnapshotRead {
82
+ readonly ok: boolean;
83
+ readonly reason?: string | null;
84
+ readonly bytes?: Uint8Array | null;
85
+ }
86
+ interface DiagnosticSnapshotStatus {
87
+ readonly ok: boolean;
88
+ readonly reason?: string | null;
89
+ }
90
+ interface DiagnosticSnapshotLease {
91
+ readonly ok: boolean;
92
+ readonly reason?: string | null;
93
+ read(): DiagnosticSnapshotRead;
94
+ revalidate(): DiagnosticSnapshotStatus;
95
+ close(): void;
96
+ }
97
+ type DiagnosticNativeLoad = {
98
+ ok: true;
99
+ value: {
100
+ openDiagnosticSnapshot(agentDir: string, budgetMs: number): DiagnosticSnapshotLease;
101
+ };
102
+ } | {
103
+ ok: false;
104
+ reason: string;
105
+ };
106
+ export declare function setObservationTestHooksForTest(hooks: ObservationTestHooks | null): void;
107
+ /** Malformed arguments are a typed caller error, never an observed unavailability. */
108
+ export declare class DiagnosticOptionsError extends Error {
109
+ readonly code: "invalid_arguments";
110
+ readonly field: string;
111
+ constructor(field: string);
112
+ }
113
+ export type ObservationOptionsVerdict = {
114
+ ok: true;
115
+ value: {
116
+ agentDir: string;
117
+ expectedGeneration?: string;
118
+ timeoutMs: number;
119
+ };
120
+ } | {
121
+ ok: false;
122
+ error: {
123
+ code: "invalid_arguments";
124
+ field: string;
125
+ };
126
+ };
127
+ /** Validate the caller's options against the exact contract. Pure and total. */
128
+ export declare function validateObservationOptions(options: unknown): ObservationOptionsVerdict;
129
+ /** Whether the endpoint is the canonical owned loopback endpoint with an in-range port. */
130
+ export declare function canonicalLoopbackEndpoint(url: string): boolean;
131
+ /**
132
+ * Parse verdicts for the publication bytes. A publication that is well formed but
133
+ * carries no diagnostic capability is NOT malformed: an old broker like that is
134
+ * `unsupported`, never `invalid_response` and never `absent`.
135
+ */
136
+ export type PublicationVerdict = {
137
+ kind: "ok";
138
+ value: ObservedPublication;
139
+ } | {
140
+ kind: "no-capability";
141
+ } | {
142
+ kind: "malformed";
143
+ };
144
+ /** The publication fields this route reads; every other field is ignored, never trusted. */
145
+ export interface ObservedPublication {
146
+ readonly url: string;
147
+ readonly token: string;
148
+ readonly ownerId: string;
149
+ readonly pid: number;
150
+ readonly incarnation: string | null;
151
+ readonly agentRoot: string | null;
152
+ readonly generation: string;
153
+ readonly diagnosticProtocol: number;
154
+ }
155
+ /** Parse the publication bytes the native lease returned. Strict, bounded, total. */
156
+ export declare function parsePublicationVerdict(bytes: Uint8Array): PublicationVerdict;
157
+ /** Convenience wrapper for callers that only need the accepted shape. */
158
+ export declare function parsePublication(bytes: Uint8Array): ObservedPublication | null;
159
+ /** The exact answered payload this client accepts; unknown fields are refused. */
160
+ interface AnsweredDiagnostics {
161
+ readonly generation: string;
162
+ readonly build: BrokerObservationBuild;
163
+ readonly identity: {
164
+ readonly ownerId: string;
165
+ readonly pid: number;
166
+ readonly agentRoot: string;
167
+ };
168
+ }
169
+ /** Strictly validate the broker's answer, mapping every refusal onto the reason enum. */
170
+ export declare function parseAnsweredDiagnostics(response: unknown): {
171
+ kind: "ok";
172
+ value: AnsweredDiagnostics;
173
+ } | {
174
+ kind: "unavailable";
175
+ reason: BrokerObservationUnavailableReason;
176
+ };
177
+ /** Two publication observations describe the same authority. */
178
+ export declare function sameAuthority(first: ObservedPublication, second: ObservedPublication): boolean;
179
+ /** The broker's answer agrees with the publication on generation and identity. */
180
+ export declare function answerMatchesAuthority(answer: AnsweredDiagnostics, publication: ObservedPublication): boolean;
181
+ /**
182
+ * Observe an already running broker. Never starts, ensures, recovers or retires one.
183
+ */
184
+ export declare function observeExistingBroker(options: ObserveExistingBrokerOptions | unknown): Promise<BrokerObservation>;
185
+ export {};
@@ -20,7 +20,7 @@ export type ControlInput = Record<string, unknown>;
20
20
  */
21
21
  export interface ControlSurface {
22
22
  prompt(text: string, images?: ControlValue, clientRef?: string): Promise<ControlValue> | ControlValue;
23
- steer(text: string, clientRef?: string): Promise<ControlValue> | ControlValue;
23
+ steer(text: string, clientRef?: string, expectedSdkRunToken?: string): Promise<ControlValue> | ControlValue;
24
24
  followUp(text: string): Promise<ControlValue> | ControlValue;
25
25
  abort(): Promise<ControlValue> | ControlValue;
26
26
  /** Terminal abort: stop the current root turn (and optionally exact owned work). */
@@ -85,6 +85,12 @@ export declare const TOOL_ACTIVITY_CAPABILITY = "tool_activity_v2";
85
85
  export declare const TURN_STREAM_CAPABILITY = "turn_stream";
86
86
  /** Capability used by notification adapters that observe a host without owning its work. */
87
87
  export declare const SESSION_HOST_OBSERVER_CAPABILITY = "session_host_observer_v1";
88
+ /**
89
+ * Opts notification adapters into positioned-only delivery for matching live
90
+ * effects: the host excludes a negotiating connection from the raw native leg
91
+ * of every frame its positioned envelope already reached.
92
+ */
93
+ export declare const POSITIONED_NOTIFICATION_EFFECTS_CAPABILITY = "positioned_notification_effects_v1";
88
94
  export declare const CAP_GATED_FRAME_KINDS: ReadonlySet<string>;
89
95
  /** Keep live delivery and replay on one capability gate. */
90
96
  export declare function canDeliverSdkEvent(kind: string, capabilities: ReadonlySet<string> | undefined): boolean;
@@ -1,6 +1,7 @@
1
1
  export { MODEL_PROFILE_DISCOVERY_QUERY, MODEL_PROFILE_ERROR_DETAIL_MAX_BYTES, type ModelProfileCatalogItem, type ModelProfileErrorCode, type ModelProfileErrorDetails, ModelProfileRegistryError, type ModelProfileRegistryErrorDetails, type UnknownModelProfileDetails, UnknownModelProfileError, } from "../config/model-profile-contract";
2
2
  export type { QueuedInputAdmission, QueuedInputDelivery, QueuedInputExecution, QueuedInputQueuePolicy, QueuedInputRemovalReason, QueuedInputSubmission, QueuedInputTerminal, SendUserMessageOptions, TrackedSendUserMessageOptions, } from "../session/agent-session";
3
3
  export * as bus from "./bus";
4
+ export * from "./diagnostics/observe-broker";
4
5
  export * as host from "./host";
5
6
  export * as lifecycle from "./lifecycle";
6
7
  export * as mcp from "./mcp";
@@ -177,8 +177,17 @@ export interface SessionRouterOptions {
177
177
  agentDir: string;
178
178
  /** Limits attachment to exact ids selected by a Broker-scoped operation. */
179
179
  sessionIds?: readonly string[];
180
+ /** Dynamically limits attachment to sessions currently owned by the caller. */
181
+ attachFilter?: (sessionId: string) => boolean;
180
182
  /** Marks default SDK clients as notification-only observers; demanding by default. */
181
183
  observer?: boolean;
184
+ /**
185
+ * Negotiates positioned-only notification effects on default SDK clients, so the
186
+ * host stops sending them the raw native copy of frames whose positioned
187
+ * envelope already reached them. Only notification-effect publishers opt in;
188
+ * ordinary SDK observers keep both public surfaces.
189
+ */
190
+ positionedNotificationEffects?: boolean;
182
191
  deps?: SessionRouterDeps;
183
192
  /** Runtime-specific identity validation; Router supplies a conservative fallback. */
184
193
  correlateFrame?: SessionRouterFrameCorrelator;
@@ -188,6 +188,12 @@ export interface CreateAgentSessionOptions {
188
188
  * @internal CLI-only ordering guard; SDK callers retain immediate startup by default.
189
189
  */
190
190
  deferMemoryBackendStartup?: boolean;
191
+ /**
192
+ * Skip optional model-catalog discovery during lifecycle startup. ACP hosts must
193
+ * publish their endpoint before unrelated provider credential refreshes begin.
194
+ * @internal lifecycle-only startup guard.
195
+ */
196
+ deferOptionalModelRefresh?: boolean;
191
197
  /** Enable LSP integration (tool, formatting, diagnostics, warmup). Default: true */
192
198
  enableLsp?: boolean;
193
199
  /** Skip Python kernel availability check and prelude warmup */
@@ -297,6 +303,13 @@ export interface CreateAgentSessionResult {
297
303
  */
298
304
  gjcRuntimeSnapshot?: GjcRuntimeSnapshotProvider;
299
305
  }
306
+ /**
307
+ * Start optional provider/model discovery only when it is safe to add work to
308
+ * the caller's startup graph. Lifecycle hosts deliberately skip this during
309
+ * construction: discovery preflights every configured provider and may refresh
310
+ * an unrelated OAuth credential while several hosts are opening the same DB.
311
+ */
312
+ export declare function startOptionalModelRefresh(modelRegistry: Pick<ModelRegistry, "refreshInBackground">, credentialSessionId: string | undefined, deferred: boolean): boolean;
300
313
  export interface DeferredMcpConfigStartupResult {
301
314
  loadedToolCount: number;
302
315
  hasErrors: boolean;
@@ -1111,7 +1111,11 @@ export declare class AgentSession {
1111
1111
  get sessionWorkLease(): SessionWorkLease;
1112
1112
  /** Stable resource ownership identifier for the active prompt run. */
1113
1113
  get activePromptHandle(): string | undefined;
1114
- /** All messages including custom types like BashExecutionMessage */
1114
+ /**
1115
+ * All messages including custom types like BashExecutionMessage. Request-scoped
1116
+ * ephemeral copies are retained only in `agent.state.messages` to keep the provider
1117
+ * cache prefix stable; they are never part of this public view.
1118
+ */
1115
1119
  get messages(): AgentMessage[];
1116
1120
  get transcriptPromptGeneration(): number;
1117
1121
  static restoreFromMemoryGuardCheckpoint(input: AgentSessionMemoryGuardRestoreInput): Promise<AgentMemoryGuardRestoreResult>;
@@ -174,7 +174,7 @@ export declare class ManagedSessionDescendantStore {
174
174
  constructor(root: ManagedDirectoryRoot, baseDir: string, retained?: {
175
175
  authority: RecoveryFsRoot;
176
176
  authorityBaseDir: string;
177
- }, policy?: ManagedSessionSecurityPolicy, profileAgentDir?: string);
177
+ }, policy?: ManagedSessionSecurityPolicy, profileAgentDir?: string, expectedSubtreeRoot?: ManagedDirectoryRoot);
178
178
  get dir(): string;
179
179
  get rootAuthority(): ManagedDirectoryRoot;
180
180
  get subtreeRootAuthority(): ManagedDirectoryRoot;
@@ -189,6 +189,11 @@ export declare class ManagedSessionDescendantStore {
189
189
  close(): void;
190
190
  assertBound(): void;
191
191
  verifyRootSecurity(): void;
192
+ /** Capture a directory identity through this store's retained managed root without repairing it. */
193
+ captureDirectoryIdentity(relativePath: string): {
194
+ dev: string;
195
+ ino: string;
196
+ };
192
197
  ensureDirectory(relativePath?: string): ManagedDirectoryRoot;
193
198
  publishNoReplace(relativePath: string, bytes: Uint8Array): Promise<void>;
194
199
  publishNoReplaceSync(relativePath: string, bytes: Uint8Array): void;
@@ -240,6 +245,11 @@ export declare class ManagedSessionDescendantStore {
240
245
  sourceStoreRelativePath: string;
241
246
  }): ManagedFileSnapshot;
242
247
  removeTreeExpected(relativePath: string, expected: NativeDirectoryTreeSnapshot): void;
248
+ /** Remove one exact managed tree through the parent-identity-bound native protocol. */
249
+ removeTreeExpectedWithParentIdentity(relativePath: string, expected: NativeDirectoryTreeSnapshot, parentIdentity: {
250
+ dev: bigint;
251
+ ino: bigint;
252
+ }): NativeExactUnlinkResult;
243
253
  fsyncTree(): NativeDirectoryTreeSnapshot;
244
254
  }
245
255
  export declare function shouldFsyncManagedDirectory(platform?: NodeJS.Platform): boolean;
@@ -0,0 +1,17 @@
1
+ import type { NativeDirectoryTreeSnapshot } from "@gajae-code/natives";
2
+ import { type TaskArtifactOwnerDeletionEvidence, type TaskArtifactOwnerLocator, type TaskArtifactOwnerStorageContext } from "../task-artifact-owner-codec";
3
+ import { ManagedSessionDescendantStore } from "./managed-session-storage";
4
+ export interface OwnerManifest extends TaskArtifactOwnerLocator {
5
+ readonly sessionId: string;
6
+ }
7
+ export declare function newSessionRootStore(context: TaskArtifactOwnerStorageContext): ManagedSessionDescendantStore;
8
+ export declare function readOwnerManifest(store: ManagedSessionDescendantStore, locator: TaskArtifactOwnerLocator, relativePath?: string): OwnerManifest;
9
+ export declare function assertOwnerDirectoryExists(context: TaskArtifactOwnerStorageContext, ownerId: string): void;
10
+ export declare function assertOwnerIdentity(store: ManagedSessionDescendantStore, locator: TaskArtifactOwnerLocator): void;
11
+ export declare function openOwnerStore(context: TaskArtifactOwnerStorageContext, rootStore: ManagedSessionDescendantStore, locator: TaskArtifactOwnerLocator, sessionId: string): ManagedSessionDescendantStore;
12
+ export declare function locatorFromManifest(manifest: OwnerManifest): TaskArtifactOwnerLocator;
13
+ export declare function captureValidatedOwnerTree(context: TaskArtifactOwnerStorageContext, rootStore: ManagedSessionDescendantStore, sessionId: string, locator: TaskArtifactOwnerLocator): NativeDirectoryTreeSnapshot;
14
+ export declare function captureOwnerTreeIfPresent(context: TaskArtifactOwnerStorageContext, rootStore: ManagedSessionDescendantStore, ownerId: string, pathname: string): NativeDirectoryTreeSnapshot | undefined;
15
+ export declare function ownerTreeHasPendingManagedPublication(snapshot: NativeDirectoryTreeSnapshot): boolean;
16
+ /** Capture exact owner evidence without repairing its security, timestamps, or namespace. */
17
+ export declare function captureTaskArtifactOwnerDeletionEvidence(context: TaskArtifactOwnerStorageContext, sessionId: string, locatorValue: unknown): TaskArtifactOwnerDeletionEvidence | undefined;
@@ -0,0 +1,3 @@
1
+ import { type TaskArtifactOwnerLocator } from "../task-artifact-owner-codec";
2
+ /** Resolve the path-free owner locator using transcript replay's header-patch semantics. */
3
+ export declare function taskArtifactOwnerLocatorFromTranscriptBytes(bytes: Uint8Array, expectedSessionId: string): TaskArtifactOwnerLocator | undefined;
@@ -0,0 +1,47 @@
1
+ import { type FileSessionStorage } from "./session-storage";
2
+ /**
3
+ * Outcome of a disk-retention retirement attempt.
4
+ *
5
+ * `kept` means the transcript survived and nothing of the session was
6
+ * destroyed, with the exact reason so `gjc gc --disk` can report it.
7
+ * `cleanup_pending` means the delete authority already detached or removed the
8
+ * session's artifact tree (or quarantined the transcript) before it stopped:
9
+ * the record survives, the session does not, and a caller must NOT report that
10
+ * as an ordinary keep.
11
+ */
12
+ export type SessionRetirementOutcome = {
13
+ kind: "retired";
14
+ } | {
15
+ kind: "kept";
16
+ reason: string;
17
+ } | {
18
+ kind: "cleanup_pending";
19
+ reason: string;
20
+ };
21
+ /**
22
+ * Non-mutating projection of {@link retireSessionTranscript}: would the
23
+ * retention pass's own preconditions let this transcript be retired at all?
24
+ *
25
+ * `gjc gc --disk` runs it so a dry run reports the verdict a prune would reach
26
+ * instead of promising bytes the delete authority will refuse to release. The
27
+ * authority's verdict (containment, identity, artifact tree) is deliberately
28
+ * not predicted here — it is re-derived against live state at delete time.
29
+ */
30
+ export declare function probeSessionRetirement(storage: FileSessionStorage, sessionsRoot: string, transcriptPath: string): {
31
+ kind: "retirable";
32
+ } | {
33
+ kind: "kept";
34
+ reason: string;
35
+ };
36
+ /**
37
+ * Retire one managed session transcript through the verified hard-delete
38
+ * authority.
39
+ *
40
+ * This is the only supported way for a retention pass to remove a transcript:
41
+ * identity, containment, header id/cwd, artifact tree and parent directory are
42
+ * all re-verified inside {@link FileSessionStorage.deleteSessionVerified}, and
43
+ * anything ambiguous fails closed as `kept` rather than deleting bytes. The
44
+ * caller owns the retention policy; this function owns nothing but the delete
45
+ * authority.
46
+ */
47
+ export declare function retireSessionTranscript(storage: FileSessionStorage, sessionsRoot: string, transcriptPath: string): Promise<SessionRetirementOutcome>;
@@ -512,50 +512,4 @@ export declare class MemorySessionStorage implements SessionStorage {
512
512
  openBufferedWriter(path: string, options?: SessionStorageWriterOpenOptions): SessionStorageBufferedWriter;
513
513
  openStagedWriter(path: string): StagedStreamingWriter;
514
514
  }
515
- /**
516
- * Outcome of a disk-retention retirement attempt.
517
- *
518
- * `kept` means the transcript survived and nothing of the session was
519
- * destroyed, with the exact reason so `gjc gc --disk` can report it.
520
- * `cleanup_pending` means the delete authority already detached or removed the
521
- * session's artifact tree (or quarantined the transcript) before it stopped:
522
- * the record survives, the session does not, and a caller must NOT report that
523
- * as an ordinary keep.
524
- */
525
- export type SessionRetirementOutcome = {
526
- kind: "retired";
527
- } | {
528
- kind: "kept";
529
- reason: string;
530
- } | {
531
- kind: "cleanup_pending";
532
- reason: string;
533
- };
534
- /**
535
- * Non-mutating projection of {@link retireSessionTranscript}: would the
536
- * retention pass's own preconditions let this transcript be retired at all?
537
- *
538
- * `gjc gc --disk` runs it so a dry run reports the verdict a prune would reach
539
- * instead of promising bytes the delete authority will refuse to release. The
540
- * authority's verdict (containment, identity, artifact tree) is deliberately
541
- * not predicted here — it is re-derived against live state at delete time.
542
- */
543
- export declare function probeSessionRetirement(storage: FileSessionStorage, sessionsRoot: string, transcriptPath: string): {
544
- kind: "retirable";
545
- } | {
546
- kind: "kept";
547
- reason: string;
548
- };
549
- /**
550
- * Retire one managed session transcript through the verified hard-delete
551
- * authority.
552
- *
553
- * This is the only supported way for a retention pass to remove a transcript:
554
- * identity, containment, header id/cwd, artifact tree and parent directory are
555
- * all re-verified inside {@link FileSessionStorage.deleteSessionVerified}, and
556
- * anything ambiguous fails closed as `kept` rather than deleting bytes. The
557
- * caller owns the retention policy; this function owns nothing but the delete
558
- * authority.
559
- */
560
- export declare function retireSessionTranscript(storage: FileSessionStorage, sessionsRoot: string, transcriptPath: string): Promise<SessionRetirementOutcome>;
561
515
  export {};
@@ -0,0 +1,2 @@
1
+ /** Parse the first JSONL line as a generic record; returns undefined on parse failure. */
2
+ export declare function parseFirstJsonlLine(bytes: Uint8Array): Record<string, unknown> | undefined;
@@ -0,0 +1,107 @@
1
+ import type { NativeExactUnlinkResult } from "@gajae-code/natives";
2
+ import type { ManagedDirectoryRoot, ManagedSessionSecurityPolicy } from "./internal/managed-session-storage";
3
+ import type { NativeDirectoryTreeSnapshot } from "./session-storage";
4
+ export declare const OWNER_DIRECTORY = ".task-artifact-owners";
5
+ export declare const OWNER_LOCK_DIRECTORY = ".task-artifact-owner-locks";
6
+ export declare const OWNER_MANIFEST = ".gjc-task-artifact-owner-v1.json";
7
+ export declare const OWNER_SCHEMA_VERSION: 1;
8
+ export declare const OWNER_DELETION_SCHEMA_VERSION: 2;
9
+ export declare const OWNER_RETIREMENT_SCHEMA_VERSION: 1;
10
+ export declare const EMPTY_PAYLOAD_SHA256: string;
11
+ export interface TaskArtifactOwnerLocator {
12
+ readonly schemaVersion: typeof OWNER_SCHEMA_VERSION;
13
+ readonly ownerId: string;
14
+ readonly directoryDev: string;
15
+ readonly directoryIno: string;
16
+ }
17
+ export interface TaskArtifactOwnerStorageContext {
18
+ readonly rootAuthority: ManagedDirectoryRoot;
19
+ readonly sessionsRoot: string;
20
+ readonly securityPolicy: ManagedSessionSecurityPolicy;
21
+ readonly profileAgentDir: string;
22
+ }
23
+ /** Exact parent directory identity authorizing direct native owner-tree removal. */
24
+ export interface TaskArtifactOwnerParentIdentity {
25
+ readonly dev: string;
26
+ readonly ino: string;
27
+ }
28
+ /** Immutable exact deletion input retained by managed lifecycle tombstones and retries. */
29
+ export interface TaskArtifactOwnerDeletionEvidence {
30
+ readonly schemaVersion: typeof OWNER_DELETION_SCHEMA_VERSION;
31
+ readonly sessionId: string;
32
+ readonly locator: TaskArtifactOwnerLocator;
33
+ readonly parentIdentity: TaskArtifactOwnerParentIdentity;
34
+ readonly treeSnapshot: NativeDirectoryTreeSnapshot;
35
+ }
36
+ /** Native retained-root and side-path state safe to persist for a later retirement attempt. */
37
+ export interface TaskArtifactOwnerRetirementContinuation {
38
+ readonly schemaVersion: typeof OWNER_RETIREMENT_SCHEMA_VERSION;
39
+ /** Must remain equal to the immutable evidence's managed owner-parent identity. */
40
+ readonly parentIdentity: TaskArtifactOwnerParentIdentity;
41
+ /** Only the original owner root or its native `.removing` sibling is actionable. */
42
+ readonly retainedRootPath: string;
43
+ /** Last identity-checked tree snapshot; it may only shrink from the original evidence. */
44
+ readonly retainedTreeSnapshot: NativeDirectoryTreeSnapshot;
45
+ /** Historical exact native detached-root roles; these paths are diagnostics, not extra authority. */
46
+ readonly detachedPaths?: readonly string[];
47
+ readonly nativeCodes?: readonly string[];
48
+ readonly payloadDurable?: boolean;
49
+ readonly retainedSuccessorPaths?: readonly string[];
50
+ readonly retainedPlaceholderPaths?: readonly string[];
51
+ readonly retainedUnknownPaths?: readonly string[];
52
+ readonly windowsErrorCodes?: readonly string[];
53
+ }
54
+ /** `completed` is decoded persisted data, not proof of physical retirement or writer closure. */
55
+ export type TaskArtifactOwnerRetirementOutcome = {
56
+ readonly kind: "completed";
57
+ readonly evidence: TaskArtifactOwnerDeletionEvidence;
58
+ readonly nativeOutcome?: NativeExactUnlinkResult;
59
+ } | {
60
+ /** Live payload is durably destroyed; native namespace cleanup remains pending. */
61
+ readonly kind: "payload_retired";
62
+ readonly namespace: "retained";
63
+ readonly evidence: TaskArtifactOwnerDeletionEvidence;
64
+ readonly continuation: TaskArtifactOwnerRetirementContinuation;
65
+ readonly nativeOutcome: NativeExactUnlinkResult;
66
+ } | {
67
+ /** Native explicitly retained cleanup state with a validated, non-expanding continuation. */
68
+ readonly kind: "cleanup_pending";
69
+ readonly evidence: TaskArtifactOwnerDeletionEvidence;
70
+ readonly continuation: TaskArtifactOwnerRetirementContinuation;
71
+ readonly nativeOutcome?: NativeExactUnlinkResult;
72
+ } | {
73
+ /** No safe completion proof exists; callers must retain evidence and continuation. */
74
+ readonly kind: "uncertain";
75
+ readonly evidence: TaskArtifactOwnerDeletionEvidence;
76
+ readonly continuation: TaskArtifactOwnerRetirementContinuation;
77
+ readonly reason: string;
78
+ readonly nativeOutcome?: NativeExactUnlinkResult;
79
+ };
80
+ /** True only for canonical unsigned decimal strings within the native u64 range. */
81
+ export declare function isCanonicalDecimal(value: unknown): value is string;
82
+ export declare function isCanonicalNativeId(value: unknown): value is string;
83
+ /** Deterministic owner identity bound to one non-empty logical session ID. */
84
+ export declare function ownerIdForSession(sessionId: string): string;
85
+ export declare function ownerRelativePath(ownerId: string): string;
86
+ export declare function manifestRelativePath(ownerId: string): string;
87
+ export declare function assertSafeRelativePath(relativePath: string): void;
88
+ export declare function assertSessionRoot(context: TaskArtifactOwnerStorageContext): void;
89
+ export declare function freezeTreeSnapshot(snapshot: NativeDirectoryTreeSnapshot): NativeDirectoryTreeSnapshot;
90
+ export declare function retainedTreeDoesNotExpandAuthority(expected: NativeDirectoryTreeSnapshot, retained: NativeDirectoryTreeSnapshot): boolean;
91
+ export declare function sameTreeContents(left: NativeDirectoryTreeSnapshot, right: NativeDirectoryTreeSnapshot): boolean;
92
+ export declare function sameOwnerParentIdentity(left: TaskArtifactOwnerParentIdentity, right: TaskArtifactOwnerParentIdentity): boolean;
93
+ export declare function immutableDeletionEvidence(sessionId: string, locatorValue: TaskArtifactOwnerLocator, parentIdentityValue: TaskArtifactOwnerParentIdentity, treeSnapshotValue: NativeDirectoryTreeSnapshot): TaskArtifactOwnerDeletionEvidence;
94
+ /** Parse a persisted locator. Missing metadata returns undefined; malformed metadata fails closed. */
95
+ export declare function parseTaskArtifactOwnerLocator(value: unknown): TaskArtifactOwnerLocator | undefined;
96
+ /** Validate JSON-restored tombstone evidence before it is used for exact retirement. */
97
+ export declare function parseTaskArtifactOwnerDeletionEvidence(value: unknown): TaskArtifactOwnerDeletionEvidence;
98
+ export declare function ownerAbsolutePath(context: TaskArtifactOwnerStorageContext, ownerId: string): string;
99
+ export declare function isOwnerRetainedRoot(context: TaskArtifactOwnerStorageContext, ownerId: string, pathname: string): boolean;
100
+ export declare function isKnownNativeSidePath(context: TaskArtifactOwnerStorageContext, ownerId: string, pathname: string): boolean;
101
+ /** Validate JSON-restored native continuation data against immutable owner authorization. */
102
+ export declare function parseTaskArtifactOwnerRetirementContinuation(context: TaskArtifactOwnerStorageContext, evidenceValue: TaskArtifactOwnerDeletionEvidence, value: unknown): TaskArtifactOwnerRetirementContinuation;
103
+ /**
104
+ * Strictly decode persisted managed-journal data. Parsing does not establish current physical retirement,
105
+ * payload destruction, or writer quiescence.
106
+ */
107
+ export declare function parseTaskArtifactOwnerRetirementOutcome(context: TaskArtifactOwnerStorageContext, evidence: TaskArtifactOwnerDeletionEvidence, value: unknown): TaskArtifactOwnerRetirementOutcome;
@@ -0,0 +1,7 @@
1
+ import { type TaskArtifactOwnerDeletionEvidence, type TaskArtifactOwnerRetirementContinuation, type TaskArtifactOwnerRetirementOutcome, type TaskArtifactOwnerStorageContext } from "./task-artifact-owner-codec";
2
+ /** Confirm physical completion from a managed native proof, never from canonical absence alone. */
3
+ export declare function verifyTaskArtifactOwnerPhysicalRetirement(context: TaskArtifactOwnerStorageContext, evidence: TaskArtifactOwnerDeletionEvidence, value: unknown): void;
4
+ /** Revalidate a persisted remnant through managed authority without mutation or new payload proof. */
5
+ export declare function verifyTaskArtifactOwnerRetirementContinuation(context: TaskArtifactOwnerStorageContext, evidenceValue: TaskArtifactOwnerDeletionEvidence, value: unknown): TaskArtifactOwnerRetirementContinuation;
6
+ /** Continue exact native removal without widening the original owner-tree authority. */
7
+ export declare function retireTaskArtifactOwner(context: TaskArtifactOwnerStorageContext, evidenceValue: TaskArtifactOwnerDeletionEvidence, continuationValue?: unknown): TaskArtifactOwnerRetirementOutcome;
@@ -0,0 +1,10 @@
1
+ import { ArtifactManager } from "./artifacts";
2
+ import { type TaskArtifactOwnerLocator, type TaskArtifactOwnerStorageContext } from "./task-artifact-owner-codec";
3
+ export interface ManagedTaskArtifactOwner {
4
+ readonly locator: TaskArtifactOwnerLocator;
5
+ readonly manager: ArtifactManager;
6
+ }
7
+ /** Reopen an owner only beneath the captured managed sessions-root authority. */
8
+ export declare function restoreManagedTaskArtifactOwner(context: TaskArtifactOwnerStorageContext, sessionId: string, locatorValue: unknown): ManagedTaskArtifactOwner;
9
+ /** Establish or restore the logical-session owner under the captured managed sessions authority. */
10
+ export declare function ensureManagedTaskArtifactOwner(context: TaskArtifactOwnerStorageContext, sessionId: string, locatorValue: unknown, legacyArtifactRelativePath?: string): Promise<ManagedTaskArtifactOwner>;