@gajae-code/coding-agent 0.12.21 → 0.13.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.
- package/CHANGELOG.md +67 -2
- package/dist/types/cli/args.d.ts +5 -2
- package/dist/types/cli/root-flags.d.ts +246 -0
- package/dist/types/cli.d.ts +11 -19
- package/dist/types/commands/daemon.d.ts +0 -30
- package/dist/types/commands/launch.d.ts +11 -19
- package/dist/types/commands/quick-lane.d.ts +32 -0
- package/dist/types/commands/sdk.d.ts +21 -15
- package/dist/types/config/file-lock-gc.d.ts +2 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-profile-activation.d.ts +62 -17
- package/dist/types/config/model-profiles.d.ts +10 -0
- package/dist/types/config/model-registry.d.ts +68 -1
- package/dist/types/config/model-resolver.d.ts +15 -4
- package/dist/types/config/models-config-schema.d.ts +7 -2
- package/dist/types/config/provider-selection-policy.d.ts +62 -0
- package/dist/types/config/settings-schema.d.ts +36 -78
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/edit/renderer.d.ts +5 -2
- package/dist/types/edit/streaming.d.ts +13 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -0
- package/dist/types/extensibility/extensions/compact-handler.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +19 -5
- package/dist/types/internal-urls/local-protocol.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +0 -2
- package/dist/types/modes/components/provider-order-context.d.ts +45 -0
- package/dist/types/modes/components/provider-order-editor.d.ts +24 -0
- package/dist/types/modes/components/settings-defs.d.ts +5 -1
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/quick-lane/classify.d.ts +40 -0
- package/dist/types/runtime/stt-settings-setup.d.ts +18 -0
- package/dist/types/sdk/broker/broker.d.ts +56 -2
- package/dist/types/sdk/broker/operation-receipt-ledger.d.ts +25 -0
- package/dist/types/sdk/broker/session-index.d.ts +83 -2
- package/dist/types/sdk/broker/state-version.d.ts +1 -1
- package/dist/types/sdk/bus/notification-service.d.ts +6 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +8 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +4 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +26 -0
- package/dist/types/sdk/cli/rows.d.ts +98 -0
- package/dist/types/sdk/cli/session-cli.d.ts +35 -3
- package/dist/types/sdk/elevation/allowlist.d.ts +20 -0
- package/dist/types/sdk/elevation/audit.d.ts +93 -0
- package/dist/types/sdk/elevation/capability.d.ts +3 -0
- package/dist/types/sdk/elevation/digest.d.ts +72 -0
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +85 -0
- package/dist/types/sdk/elevation/grant-ledger.d.ts +163 -0
- package/dist/types/sdk/elevation/owner.d.ts +48 -0
- package/dist/types/sdk/guides/cache.d.ts +98 -0
- package/dist/types/sdk/guides/catalog.d.ts +156 -0
- package/dist/types/sdk/guides/cli.d.ts +39 -0
- package/dist/types/sdk/guides/manifest.d.ts +66 -0
- package/dist/types/sdk/guides/verify.d.ts +66 -0
- package/dist/types/sdk/host/control/dispatch.d.ts +8 -0
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +3 -2
- package/dist/types/sdk/host/query/cursor.d.ts +10 -0
- package/dist/types/sdk/host/query/handlers.d.ts +21 -0
- package/dist/types/sdk/host/session-runtime.d.ts +9 -0
- package/dist/types/sdk/mcp/server.d.ts +2 -2
- package/dist/types/sdk/prompt-status.d.ts +11 -0
- package/dist/types/sdk/session.d.ts +4 -0
- package/dist/types/sdk/transport/index.d.ts +1 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +20 -1
- package/dist/types/session/agent-session.d.ts +32 -18
- package/dist/types/session/blob-store.d.ts +13 -7
- package/dist/types/session/fallback-chain-controller.d.ts +15 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +25 -1
- package/dist/types/session/internal/session-memory-sidecar.d.ts +5 -5
- package/dist/types/session/session-manager.d.ts +139 -10
- package/dist/types/session/session-storage.d.ts +48 -0
- package/dist/types/setup/provider-onboarding.d.ts +7 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +14 -0
- package/dist/types/stt/setup.d.ts +2 -0
- package/dist/types/task/executor.d.ts +10 -2
- package/dist/types/tools/browser/runtime-diagnostics.d.ts +65 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +4 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +2 -0
- package/dist/types/tools/browser/tab-worker.d.ts +2 -0
- package/dist/types/tools/browser.d.ts +2 -0
- package/dist/types/tools/image-gen.d.ts +14 -18
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/resource-gc.d.ts +2 -0
- package/dist/types/utils/pasted-image-path.d.ts +6 -0
- package/package.json +9 -9
- package/scripts/generate-sdk-operation-inventory.ts +8 -0
- package/scripts/run-test-manifest.ts +61 -21
- package/scripts/verify-gjc-sdk-canonicalization.ts +9 -4
- package/src/cli/args.ts +62 -9
- package/src/cli/completion-cli.ts +1 -0
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/root-flags.ts +100 -0
- package/src/cli/setup-cli.ts +6 -2
- package/src/cli.ts +42 -65
- package/src/commands/acp.ts +1 -1
- package/src/commands/daemon.ts +2 -31
- package/src/commands/gc.ts +1 -1
- package/src/commands/launch.ts +8 -129
- package/src/commands/quick-lane.ts +51 -0
- package/src/commands/sdk.ts +200 -26
- package/src/commands/setup.ts +4 -2
- package/src/config/file-lock-gc.ts +4 -1
- package/src/config/model-equivalence.ts +76 -7
- package/src/config/model-profile-activation.ts +1115 -265
- package/src/config/model-profiles.ts +134 -2
- package/src/config/model-registry.ts +352 -50
- package/src/config/model-resolver.ts +289 -38
- package/src/config/models-config-schema.ts +11 -4
- package/src/config/provider-selection-policy.ts +146 -0
- package/src/config/settings-schema.ts +50 -77
- package/src/config/settings.ts +40 -0
- package/src/coordinator-mcp/server.ts +32 -2
- package/src/edit/renderer.ts +175 -223
- package/src/edit/streaming.ts +108 -1
- package/src/export/html/index.ts +57 -7
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/extensions/compact-handler.ts +3 -2
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/gjc-runtime/gc-runtime.ts +379 -20
- package/src/gjc-runtime/launch-worktree.ts +5 -1
- package/src/gjc-runtime/team-runtime.ts +59 -2
- package/src/gjc-runtime/tmux-owner-isolation.ts +19 -0
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +16 -1
- package/src/internal-urls/docs-index.generated.ts +17 -13
- package/src/internal-urls/local-protocol.ts +1 -0
- package/src/main.ts +40 -3
- package/src/memories/index.ts +4 -2
- package/src/modes/acp/acp-agent.ts +235 -91
- package/src/modes/components/model-selector.ts +206 -42
- package/src/modes/components/provider-order-context.ts +197 -0
- package/src/modes/components/provider-order-editor.ts +441 -0
- package/src/modes/components/settings-defs.ts +21 -1
- package/src/modes/components/settings-selector.ts +45 -2
- package/src/modes/components/tool-execution.ts +47 -15
- package/src/modes/controllers/command-controller.ts +6 -3
- package/src/modes/controllers/extension-ui-controller.ts +2 -0
- package/src/modes/controllers/input-controller.ts +73 -2
- package/src/modes/controllers/selector-controller.ts +260 -153
- package/src/modes/prompt-suggestion-controller.ts +1 -1
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +18 -0
- package/src/prompts/tools/browser.md +1 -0
- package/src/quick-lane/classify.ts +257 -0
- package/src/rlm/index.ts +1 -1
- package/src/runtime/stt-settings-setup.ts +57 -0
- package/src/sdk/acp/adapter.ts +2 -1
- package/src/sdk/broker/broker.ts +780 -12
- package/src/sdk/broker/lifecycle.ts +70 -29
- package/src/sdk/broker/operation-receipt-ledger.ts +144 -0
- package/src/sdk/broker/session-index.ts +463 -48
- package/src/sdk/broker/state-version.ts +13 -9
- package/src/sdk/broker/transport.ts +14 -1
- package/src/sdk/bus/index.ts +34 -13
- package/src/sdk/bus/kind-aware-reconciliation.ts +21 -2
- package/src/sdk/bus/notification-service.ts +47 -1
- package/src/sdk/bus/prompt-reconciliation.ts +22 -3
- package/src/sdk/bus/telegram-daemon-contract.ts +4 -1
- package/src/sdk/bus/telegram-daemon.ts +54 -3
- package/src/sdk/cli/rows.ts +247 -0
- package/src/sdk/cli/session-cli.ts +930 -79
- package/src/sdk/elevation/allowlist.ts +54 -0
- package/src/sdk/elevation/audit.ts +208 -0
- package/src/sdk/elevation/capability.ts +41 -0
- package/src/sdk/elevation/digest.ts +129 -0
- package/src/sdk/elevation/dispatch-receipt.ts +184 -0
- package/src/sdk/elevation/grant-ledger.ts +1142 -0
- package/src/sdk/elevation/owner.ts +109 -0
- package/src/sdk/guides/cache.ts +363 -0
- package/src/sdk/guides/catalog.ts +554 -0
- package/src/sdk/guides/cli.ts +235 -0
- package/src/sdk/guides/manifest.ts +152 -0
- package/src/sdk/guides/verify.ts +178 -0
- package/src/sdk/host/control/dispatch.ts +49 -1
- package/src/sdk/host/control/index.ts +1 -0
- package/src/sdk/host/control/operations.ts +8 -1
- package/src/sdk/host/query/cursor.ts +47 -3
- package/src/sdk/host/query/handlers.ts +155 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -0
- package/src/sdk/host/session-runtime.test.ts +391 -1
- package/src/sdk/host/session-runtime.ts +308 -73
- package/src/sdk/host/surface-policy.ts +3 -0
- package/src/sdk/host/websocket-transport.ts +7 -1
- package/src/sdk/mcp/server.ts +88 -15
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/protocol/operation-inventory.generated.json +62 -0
- package/src/sdk/protocol/operation-registry.ts +3 -2
- package/src/sdk/session.ts +87 -39
- package/src/sdk/transport/index.ts +1 -0
- package/src/sdk/transport/relay.ts +3 -0
- package/src/sdk/transport/serve-cli.ts +111 -24
- package/src/secrets/obfuscator.ts +92 -12
- package/src/session/agent-session.ts +322 -93
- package/src/session/blob-store.ts +60 -8
- package/src/session/fallback-chain-controller.ts +35 -0
- package/src/session/internal/managed-session-scope.ts +25 -3
- package/src/session/internal/managed-session-storage.ts +574 -73
- package/src/session/internal/session-memory-sidecar.ts +19 -29
- package/src/session/session-manager.ts +2166 -743
- package/src/session/session-storage.ts +715 -48
- package/src/setup/provider-onboarding.ts +19 -3
- package/src/setup/provider-presets.json +3 -1
- package/src/slash-commands/builtin-registry.ts +85 -3
- package/src/stt/downloader.ts +2 -3
- package/src/stt/setup.ts +29 -4
- package/src/task/executor.ts +22 -18
- package/src/task/index.ts +24 -1
- package/src/tools/archive-reader.ts +11 -2
- package/src/tools/browser/runtime-diagnostics.ts +249 -0
- package/src/tools/browser/tab-protocol.ts +4 -0
- package/src/tools/browser/tab-supervisor.ts +5 -0
- package/src/tools/browser/tab-worker.ts +36 -1
- package/src/tools/browser.ts +7 -0
- package/src/tools/image-gen.ts +110 -166
- package/src/tools/index.ts +2 -0
- package/src/tools/read.ts +1 -1
- package/src/tools/resource-gc.ts +6 -1
- package/src/tools/tool-catalog.generated.ts +5 -1
- package/src/utils/pasted-image-path.ts +93 -0
- package/src/web/search/index.ts +3 -3
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
import { SDK_STATE_VERSION } from "./state-version";
|
|
2
|
-
export type SessionIndexEventType = "host_registered" | "host_heartbeat" | "host_unregistered" | "lifecycle_started" | "lifecycle_terminal" | "session_closed" | "record_reconciled";
|
|
2
|
+
export type SessionIndexEventType = "host_registered" | "host_heartbeat" | "host_unregistered" | "lifecycle_started" | "lifecycle_terminal" | "session_closed" | "session_deleted" | "record_reconciled";
|
|
3
|
+
export type SessionActivityState = "active" | "idle";
|
|
4
|
+
/** Coalesced broker-owned heartbeat checkpoint (C2): state plus the observation time. */
|
|
5
|
+
export interface SessionActivity {
|
|
6
|
+
state: SessionActivityState;
|
|
7
|
+
at: number;
|
|
8
|
+
}
|
|
9
|
+
/** Events persisted without an OS process incarnation (v1/v2 era) are legacy provenance. */
|
|
10
|
+
export type SessionIdentityProvenance = "composite" | "legacy";
|
|
11
|
+
export type SessionTombstoneRule = "retain" | "expire";
|
|
12
|
+
/**
|
|
13
|
+
* Injected retention policy (C3). The broker schedules compaction independently of
|
|
14
|
+
* rotation; settings apply at the next scheduled compaction. `clock` drives both
|
|
15
|
+
* retention expiry and heartbeat-freshness liveness reads.
|
|
16
|
+
*/
|
|
17
|
+
export interface RetentionPolicy {
|
|
18
|
+
clock?: () => number;
|
|
19
|
+
maxAgeMs?: number;
|
|
20
|
+
maxRows?: number;
|
|
21
|
+
tombstoneRule?: SessionTombstoneRule;
|
|
22
|
+
}
|
|
3
23
|
export interface SessionIndexEvent {
|
|
4
24
|
version: typeof SDK_STATE_VERSION;
|
|
5
25
|
indexSeq: number;
|
|
@@ -11,9 +31,20 @@ export interface SessionIndexEvent {
|
|
|
11
31
|
};
|
|
12
32
|
endpointGeneration: number;
|
|
13
33
|
pid: number;
|
|
34
|
+
/**
|
|
35
|
+
* OS start incarnation of `pid`, published by the host that owns that pid. A
|
|
36
|
+
* pid is reusable, so teardown needs this binding to prove the pid is still
|
|
37
|
+
* the same process; keeping it here, in broker-owned storage, is what lets
|
|
38
|
+
* that proof outlive the session's own workspace.
|
|
39
|
+
*/
|
|
40
|
+
processIncarnation?: string;
|
|
14
41
|
endpointMtimeMs?: number;
|
|
15
42
|
lifecycleRequestId?: string;
|
|
16
43
|
terminalUncertain?: boolean;
|
|
44
|
+
/** OS process incarnation (C1); absent on legacy v1/v2 events. */
|
|
45
|
+
hostIncarnation?: string;
|
|
46
|
+
/** Present on host_heartbeat checkpoints (C2). */
|
|
47
|
+
activity?: SessionActivity;
|
|
17
48
|
ts: number;
|
|
18
49
|
checksum: string;
|
|
19
50
|
}
|
|
@@ -25,11 +56,22 @@ export interface IndexedSession {
|
|
|
25
56
|
};
|
|
26
57
|
endpointGeneration: number;
|
|
27
58
|
pid: number;
|
|
59
|
+
/** OS start incarnation of `pid` as published by its own host at registration. */
|
|
60
|
+
processIncarnation?: string;
|
|
28
61
|
endpointMtimeMs?: number;
|
|
29
62
|
live: boolean;
|
|
30
63
|
indexSeq: number;
|
|
31
64
|
lifecycleRequestId?: string;
|
|
32
65
|
terminalUncertain?: boolean;
|
|
66
|
+
hostIncarnation?: string;
|
|
67
|
+
identityProvenance: SessionIdentityProvenance;
|
|
68
|
+
activity?: SessionActivity;
|
|
69
|
+
/** Wall-clock timestamp of the latest admitted heartbeat, when one exists. */
|
|
70
|
+
lastHeartbeatAt?: number;
|
|
71
|
+
/** True when the same sessionId maps to more than one stateRoot (cross-repo duplicate). */
|
|
72
|
+
ambiguous: boolean;
|
|
73
|
+
/** True when the identity's latest event is host_unregistered or session_closed (DR-1: stopped rows are retained). */
|
|
74
|
+
terminal: boolean;
|
|
33
75
|
}
|
|
34
76
|
export interface SessionList {
|
|
35
77
|
indexSeq: number;
|
|
@@ -46,10 +88,30 @@ export interface SessionIndexRepairResult extends SessionIndexDiagnosis {
|
|
|
46
88
|
repaired: boolean;
|
|
47
89
|
quarantinePath?: string;
|
|
48
90
|
}
|
|
91
|
+
/** Admission-fence rejection codes recorded in the durable index audit (C5/C4). */
|
|
92
|
+
export type SessionIndexAuditCode = "rejected_superseded_incarnation" | "rejected_after_tombstone";
|
|
93
|
+
export interface SessionIndexAuditRecord {
|
|
94
|
+
version: typeof SDK_STATE_VERSION;
|
|
95
|
+
code: SessionIndexAuditCode;
|
|
96
|
+
/** indexSeq of the rejected event (unique per record; used for idempotent dedupe). */
|
|
97
|
+
indexSeq: number;
|
|
98
|
+
sessionId: string;
|
|
99
|
+
endpointGeneration: number;
|
|
100
|
+
stateRoot: string;
|
|
101
|
+
hostIncarnation?: string;
|
|
102
|
+
supersededByIncarnation?: string;
|
|
103
|
+
/** indexSeq of the superseding registration, or of the tombstone for post-delete rejections. */
|
|
104
|
+
supersededByIndexSeq: number;
|
|
105
|
+
ts: number;
|
|
106
|
+
}
|
|
49
107
|
export declare const sessionIndexChecksum: (event: Omit<SessionIndexEvent, "checksum">) => string;
|
|
108
|
+
/** Coalesced heartbeat checkpoint rate cap (C2): at most one per session per minute. */
|
|
109
|
+
export declare const SESSION_HEARTBEAT_INTERVAL_MS = 60000;
|
|
110
|
+
export declare const DEFAULT_SESSION_RETENTION_MAX_AGE_MS: number;
|
|
111
|
+
export declare const DEFAULT_SESSION_RETENTION_MAX_ROWS = 25000;
|
|
50
112
|
export declare class SessionIndex {
|
|
51
113
|
#private;
|
|
52
|
-
constructor(agentDir: string);
|
|
114
|
+
constructor(agentDir: string, policy?: RetentionPolicy);
|
|
53
115
|
open(): Promise<this>;
|
|
54
116
|
replay(): Promise<void>;
|
|
55
117
|
diagnose(): Promise<SessionIndexDiagnosis>;
|
|
@@ -57,8 +119,27 @@ export declare class SessionIndex {
|
|
|
57
119
|
refresh(): Promise<void>;
|
|
58
120
|
get indexSeq(): number;
|
|
59
121
|
append(input: Omit<SessionIndexEvent, "version" | "indexSeq" | "checksum" | "ts"> & Partial<Pick<SessionIndexEvent, "ts">>): Promise<SessionIndexEvent>;
|
|
122
|
+
/** Hold the canonical index lock across an authority-sensitive operation. */
|
|
123
|
+
withLocked<T>(callback: () => Promise<T>): Promise<T>;
|
|
60
124
|
snapshot(): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Broker-scheduled compaction (C3), independent of rotation size: applies the
|
|
127
|
+
* injected retention policy to a fresh snapshot and truncates the log.
|
|
128
|
+
*/
|
|
129
|
+
compact(): Promise<void>;
|
|
61
130
|
listSessions(): SessionList;
|
|
131
|
+
/**
|
|
132
|
+
* Production coalesced heartbeat checkpoint pass (C2): appends one
|
|
133
|
+
* `host_heartbeat` per session at most once per {@link SESSION_HEARTBEAT_INTERVAL_MS}.
|
|
134
|
+
* The pass observes liveness the same way the projection does — the host process
|
|
135
|
+
* must be alive and, for composite identities, still carry the recorded OS process
|
|
136
|
+
* incarnation (a reused PID is never checkpointed). Stopped/terminal rows and rows
|
|
137
|
+
* whose heartbeat is still fresh are skipped. After a broker restart, sessions whose
|
|
138
|
+
* host survived are re-observed as live on the first pass; sessions whose host died
|
|
139
|
+
* while the broker was down keep their stale or missing heartbeat and read as
|
|
140
|
+
* unknown/not-live (never fresh forever). Returns the number of checkpoints written.
|
|
141
|
+
*/
|
|
142
|
+
checkpointLiveHeartbeats(now?: number): Promise<number>;
|
|
62
143
|
hostUnregisteredAfter(registration: Pick<IndexedSession, "sessionId" | "endpointGeneration" | "pid" | "indexSeq" | "lifecycleRequestId">): {
|
|
63
144
|
indexSeq: number;
|
|
64
145
|
lifecycleRequestId?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const SDK_STATE_VERSION = 1;
|
|
2
|
-
export declare const SESSION_INDEX_SNAPSHOT_VERSION =
|
|
2
|
+
export declare const SESSION_INDEX_SNAPSHOT_VERSION = 3;
|
|
3
3
|
export declare class UnsupportedStateVersionError extends Error {
|
|
4
4
|
readonly file: string;
|
|
5
5
|
readonly version: number;
|
|
@@ -170,6 +170,12 @@ export interface DaemonHealth {
|
|
|
170
170
|
stopped: boolean;
|
|
171
171
|
heartbeatAt: number | undefined;
|
|
172
172
|
heartbeatAgeMs: number | undefined;
|
|
173
|
+
/**
|
|
174
|
+
* Session endpoints the live owner reported an OPEN socket to in its latest
|
|
175
|
+
* matching heartbeat sidecar. `undefined` means the owner never published the
|
|
176
|
+
* field (older daemon, no stable owner tag, no matching sidecar): unknown, not zero.
|
|
177
|
+
*/
|
|
178
|
+
attachedEndpoints: number | undefined;
|
|
173
179
|
generation: number | undefined;
|
|
174
180
|
currentGeneration: number;
|
|
175
181
|
generationRelation: DaemonGenerationRelation;
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
* Session-scoped durable retention (kind-aware store) is provided by reconciliation-store.ts (#3032).
|
|
17
17
|
* - The clientRef index is session-runtime scoped; a ref conflicts only while
|
|
18
18
|
* retained and must never be reused as a retry mechanism.
|
|
19
|
-
* - Terminal transitions settle once:
|
|
19
|
+
* - Terminal transitions settle once: first terminal outcome wins. A late
|
|
20
|
+
* `agent_failed` may still attach its sanitized reason to an already-terminal
|
|
21
|
+
* record that has none, but never changes status, terminalAt, or retention.
|
|
20
22
|
*/
|
|
21
23
|
import { PROMPT_FAILURE_CODE_MAX, sanitizePromptFailure } from "../prompt-failure";
|
|
22
24
|
export { PROMPT_FAILURE_CODE_MAX, sanitizePromptFailure };
|
|
@@ -60,6 +62,11 @@ export type TurnPromptReconciliation = {
|
|
|
60
62
|
acceptedAt: number;
|
|
61
63
|
startedAt?: number;
|
|
62
64
|
terminalAt: number;
|
|
65
|
+
/** Present when a late `agent_failed` supplied the only failure reason. */
|
|
66
|
+
error?: {
|
|
67
|
+
code: string;
|
|
68
|
+
message: string;
|
|
69
|
+
};
|
|
63
70
|
} | {
|
|
64
71
|
status: "failed";
|
|
65
72
|
commandId: string;
|
|
@@ -91,8 +91,11 @@ export declare const NOTIFICATION_PROTOCOL_VERSION = 3;
|
|
|
91
91
|
* later session from creating a topic or replaying notifications. Generation
|
|
92
92
|
* 58 preserves that invariant during durable-fence load promotion and restores
|
|
93
93
|
* the exact grace deadline when a failed archive publication rolls back.
|
|
94
|
+
* Generation 59 publishes the owner's attached OPEN-socket count in the
|
|
95
|
+
* heartbeat sidecar so `gjc notify health` can report a live daemon that is
|
|
96
|
+
* attached to no registered endpoint (#4128).
|
|
94
97
|
*/
|
|
95
|
-
export declare const DAEMON_GENERATION =
|
|
98
|
+
export declare const DAEMON_GENERATION = 59;
|
|
96
99
|
/**
|
|
97
100
|
* Serving-compatibility boundary for daemon lifecycle requests. Epoch 5
|
|
98
101
|
* requires the complete generation-36 topic authority contract, so older
|
|
@@ -273,11 +273,23 @@ type OwnerHeartbeatSidecar = {
|
|
|
273
273
|
ownerId: string;
|
|
274
274
|
acquisitionId: string;
|
|
275
275
|
heartbeatAt: number;
|
|
276
|
+
/**
|
|
277
|
+
* Session endpoints this owner had an OPEN WebSocket to when the heartbeat was
|
|
278
|
+
* published. Optional: a sidecar written by an older daemon omits it and must
|
|
279
|
+
* read back as unknown, never as zero.
|
|
280
|
+
*/
|
|
281
|
+
attachedEndpoints?: number;
|
|
276
282
|
};
|
|
277
283
|
export interface OwnerFreshnessSnapshot {
|
|
278
284
|
ownerTag: Pick<OwnerHeartbeatSidecar, "pid" | "incarnation" | "ownerId" | "acquisitionId"> | null;
|
|
279
285
|
effectiveHeartbeatAt: number | undefined;
|
|
280
286
|
legacyEmbedded: boolean;
|
|
287
|
+
/**
|
|
288
|
+
* Session endpoints the current owner reported as attached in its latest matching
|
|
289
|
+
* heartbeat sidecar. `undefined` means the owner never published the field (older
|
|
290
|
+
* daemon, no stable owner tag, or no matching sidecar) — that is unknown, not zero.
|
|
291
|
+
*/
|
|
292
|
+
attachedEndpoints: number | undefined;
|
|
281
293
|
state: DaemonState | undefined;
|
|
282
294
|
}
|
|
283
295
|
export declare function readOwnerFreshnessSnapshot(input: {
|
|
@@ -293,6 +305,12 @@ export declare function renewOwnerHeartbeatSidecar(input: {
|
|
|
293
305
|
now?: () => number;
|
|
294
306
|
pid?: number;
|
|
295
307
|
pidIncarnation?: (pid: number) => string | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* Session endpoints the caller currently holds an OPEN WebSocket to. Omitted by
|
|
310
|
+
* non-daemon callers (bootstrap/proof paths) so their sidecar reports unknown
|
|
311
|
+
* rather than falsely claiming zero attachments.
|
|
312
|
+
*/
|
|
313
|
+
attachedEndpoints?: number;
|
|
296
314
|
}): Promise<boolean>;
|
|
297
315
|
export interface NotificationRootRegistration {
|
|
298
316
|
root?: string;
|
|
@@ -1252,6 +1270,14 @@ export declare class TelegramNotificationDaemon {
|
|
|
1252
1270
|
private notifyThreadedFallback;
|
|
1253
1271
|
private startFlushTimer;
|
|
1254
1272
|
private stopFlushTimer;
|
|
1273
|
+
/**
|
|
1274
|
+
* Sessions this owner can actually deliver to right now. Only `WebSocket.OPEN`
|
|
1275
|
+
* counts: a CONNECTING socket is constructed but cannot carry a frame, and
|
|
1276
|
+
* CLOSING/CLOSED ones are gone. Every delivery path in this daemon refuses to
|
|
1277
|
+
* send unless `readyState === WebSocket.OPEN`, so OPEN is exactly the state
|
|
1278
|
+
* that means a notification can leave this process for that session.
|
|
1279
|
+
*/
|
|
1280
|
+
private attachedEndpointCount;
|
|
1255
1281
|
private renewOwnershipHeartbeat;
|
|
1256
1282
|
/**
|
|
1257
1283
|
* Ownership must be renewed independently of Telegram's 25-second long poll:
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Versioned DTO rows for `gjc sdk session` semantic verbs (row DTO v1, DR-12).
|
|
3
|
+
*
|
|
4
|
+
* Every semantic verb renders its output through these rows so machine
|
|
5
|
+
* consumers get one deterministic, versioned envelope per verb. Credentials
|
|
6
|
+
* are never part of the row schema: broker `session.list` rows carry no
|
|
7
|
+
* credentials, offline inspect rows are projected from endpoint discovery
|
|
8
|
+
* records with secret-shaped fields stripped before they can reach a row, and
|
|
9
|
+
* pass-through host payloads are redacted recursively before rendering.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SESSION_ROWS_VERSION = 1;
|
|
12
|
+
export type SdkSessionActivityState = "active" | "idle";
|
|
13
|
+
export interface SdkSessionActivityV1 {
|
|
14
|
+
state: SdkSessionActivityState;
|
|
15
|
+
at: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SdkSessionRowV1 {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
locator: {
|
|
20
|
+
repo: string;
|
|
21
|
+
stateRoot: string;
|
|
22
|
+
};
|
|
23
|
+
endpointGeneration: number;
|
|
24
|
+
/** Process-bound incarnation of the hosting process (C1); absent for legacy-provenance rows. */
|
|
25
|
+
hostIncarnation?: string;
|
|
26
|
+
pid: number;
|
|
27
|
+
live: boolean;
|
|
28
|
+
/** Tombstone flag (C4): deleted sessions are excluded from list/endpoint/resumable surfaces. */
|
|
29
|
+
deleted: boolean;
|
|
30
|
+
indexSeq: number;
|
|
31
|
+
terminalUncertain?: boolean;
|
|
32
|
+
lifecycleRequestId?: string;
|
|
33
|
+
endpointMtimeMs?: number;
|
|
34
|
+
/** Coalesced broker-owned heartbeat checkpoint (C2). */
|
|
35
|
+
activity?: SdkSessionActivityV1;
|
|
36
|
+
/** Wall-clock timestamp of the latest admitted heartbeat, when one exists. */
|
|
37
|
+
lastHeartbeatAt?: number;
|
|
38
|
+
/** "legacy" for v1/v2-era rows that predate process-incarnation identity. */
|
|
39
|
+
identityProvenance?: "composite" | "legacy";
|
|
40
|
+
/** True when the same sessionId maps to more than one stateRoot (cross-repo duplicate). */
|
|
41
|
+
ambiguous?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface SdkCheckpointRecordV1 {
|
|
44
|
+
revision: number;
|
|
45
|
+
generation: number;
|
|
46
|
+
seq: number;
|
|
47
|
+
}
|
|
48
|
+
export interface SdkRetentionGapV1 {
|
|
49
|
+
code: "retention_gap";
|
|
50
|
+
missing?: {
|
|
51
|
+
from: number;
|
|
52
|
+
to: number;
|
|
53
|
+
};
|
|
54
|
+
resync?: SdkCheckpointRecordV1;
|
|
55
|
+
}
|
|
56
|
+
/** One tail item: a retained transcript entry or a live event-ring event. */
|
|
57
|
+
export interface SdkTailItemV1 {
|
|
58
|
+
/** "transcript" for retained transcript entries, otherwise the event-ring kind. */
|
|
59
|
+
kind: string;
|
|
60
|
+
id?: string;
|
|
61
|
+
generation?: number;
|
|
62
|
+
seq?: number;
|
|
63
|
+
payload: unknown;
|
|
64
|
+
}
|
|
65
|
+
export interface SdkTailEnvelopeV1 {
|
|
66
|
+
version: typeof SESSION_ROWS_VERSION;
|
|
67
|
+
source: "session" | "offline";
|
|
68
|
+
session: SdkSessionRowV1;
|
|
69
|
+
checkpoint?: SdkCheckpointRecordV1;
|
|
70
|
+
gap?: SdkRetentionGapV1;
|
|
71
|
+
items: SdkTailItemV1[];
|
|
72
|
+
}
|
|
73
|
+
/** Recursively removes secret-shaped fields (defense in depth for DTO output). */
|
|
74
|
+
export declare function stripSecretFields(value: unknown): unknown;
|
|
75
|
+
/**
|
|
76
|
+
* Projects one broker `session.list` row into the credential-free v1 row DTO.
|
|
77
|
+
* The row is a superset-tolerant projection: identity fields introduced by
|
|
78
|
+
* later index versions (hostIncarnation, activity, deleted) pass through when
|
|
79
|
+
* present and are omitted otherwise, so the same mapper serves both v2 and v3
|
|
80
|
+
* index shapes.
|
|
81
|
+
*/
|
|
82
|
+
export declare function toSessionRowV1(value: unknown): SdkSessionRowV1;
|
|
83
|
+
/**
|
|
84
|
+
* Offline inspect row projected from a local SDK endpoint discovery record.
|
|
85
|
+
* The discovery record carries the endpoint credential (`url`/`token`); neither
|
|
86
|
+
* is ever projected into the row. `path` is the endpoint file
|
|
87
|
+
* `<stateRoot>/sdk/<sessionId>.json`, so the state root is recovered from the
|
|
88
|
+
* path when the layout matches.
|
|
89
|
+
*/
|
|
90
|
+
export declare function toOfflineSessionRowV1(value: unknown): SdkSessionRowV1;
|
|
91
|
+
export declare function toCheckpointRecordV1(value: unknown): SdkCheckpointRecordV1 | undefined;
|
|
92
|
+
export declare function toRetentionGapV1(value: unknown): SdkRetentionGapV1 | undefined;
|
|
93
|
+
/** Projects a transcript entry or ring event into a tail item with dedupe keys. */
|
|
94
|
+
export declare function toTailItemV1(value: unknown, fallback: {
|
|
95
|
+
kind: string;
|
|
96
|
+
generation?: number;
|
|
97
|
+
seq?: number;
|
|
98
|
+
}): SdkTailItemV1;
|
|
@@ -1,19 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
import { type OperationKind } from "../protocol/operation-registry";
|
|
2
|
+
export type SdkSessionCliAction = "list" | "inspect" | "send" | "status" | "tail" | "elevate" | "raw";
|
|
3
|
+
export type SdkSessionCliRawKind = "control" | "query" | "global";
|
|
2
4
|
export interface SdkSessionCliArgs {
|
|
3
5
|
action?: string;
|
|
6
|
+
/** Raw dispatch kind when action is "raw" (control | query | global). */
|
|
7
|
+
rawAction?: string;
|
|
4
8
|
sessionId?: string;
|
|
9
|
+
/** Caller-chosen operation reference (ULID) for `send`; required target for `status`. */
|
|
10
|
+
opRef?: string;
|
|
5
11
|
operation?: string;
|
|
6
12
|
query?: string;
|
|
13
|
+
/** Convenience `send` body: forwarded as the `text` field of turn.prompt. */
|
|
14
|
+
text?: string;
|
|
7
15
|
jsonInput?: string;
|
|
8
16
|
jsonInputFile?: string;
|
|
9
|
-
idempotencyKey?: string;
|
|
10
17
|
jsonInputStdin?: boolean;
|
|
18
|
+
idempotencyKey?: string;
|
|
19
|
+
elevationRequestId?: string;
|
|
20
|
+
operationKind?: OperationKind;
|
|
11
21
|
confirm?: boolean;
|
|
22
|
+
/** Raw query continuation cursor, or a saved checkpoint token to resume `tail` from (re-minted per connection). */
|
|
12
23
|
cursor?: string;
|
|
13
24
|
showEndpointCredential?: boolean;
|
|
14
25
|
yes?: boolean;
|
|
26
|
+
/** `send --wait`: poll turn.prompt_status until terminal or the wait window elapses. */
|
|
27
|
+
wait?: boolean;
|
|
28
|
+
/** Bounded wait for `send --wait`, `status`, and live `tail` follow. */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
/** `tail --strict`: fail closed on retention gaps (exit 1 retention_gap). */
|
|
31
|
+
strict?: boolean;
|
|
32
|
+
/** `tail --until-idle`: exit once the observed event stream reaches a terminal turn state. */
|
|
33
|
+
untilIdle?: boolean;
|
|
34
|
+
/** `tail --all-events`: include every event-ring kind instead of the tail subset. */
|
|
35
|
+
allEvents?: boolean;
|
|
15
36
|
repo?: string;
|
|
16
37
|
agentDir?: string;
|
|
17
38
|
}
|
|
18
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Time-ordered operation reference (ULID): 48-bit millisecond timestamp plus
|
|
41
|
+
* 80 bits of randomness, Crockford base32, lowercase. The ref is used as the
|
|
42
|
+
* `turn.prompt` clientRef so `send`/`status` correlate without a broker round
|
|
43
|
+
* trip, and matches the plan's durable op-ref ledger shape (C7).
|
|
44
|
+
*/
|
|
45
|
+
export declare function createOperationRef(now?: number): string;
|
|
46
|
+
export declare function runTail(repo: string, agentDir: string, sessionId: string, args: SdkSessionCliArgs): Promise<unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Runs the `gjc sdk session` command family: semantic verbs (list, inspect,
|
|
49
|
+
* send, status, tail) plus the explicit raw control/query/global hatch.
|
|
50
|
+
*/
|
|
19
51
|
export declare function runSdkSessionCli(args: SdkSessionCliArgs, writeOutput?: (value: unknown) => void, setExitCode?: (exitCode: 1 | 2) => void): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact elevation-gated allowlist, fully qualified and enumerative.
|
|
3
|
+
*
|
|
4
|
+
* The elevation allowlist is the exact set of registry operations below (the
|
|
5
|
+
* raw destructive lifecycle and workflow-approval operations). It is declared
|
|
6
|
+
* ONCE here as a `Set<string>` of `"kind:sdkId"` keys and mechanically pinned
|
|
7
|
+
* against `operation-registry.ts` by the allowlist unit test: every key must
|
|
8
|
+
* resolve via `findOperation(kind, sdkId)` and no elevatable operation may be
|
|
9
|
+
* silently missing. Any operation NOT in this set is rejected at issue with
|
|
10
|
+
* `elevation_not_allowlisted` before any ledger reservation. There is no
|
|
11
|
+
* generalized policy engine: this is the deterministic predicate.
|
|
12
|
+
*/
|
|
13
|
+
export declare const ELEVATION_ALLOWLIST_KEYS: readonly ["global:session.close", "global:session.delete", "control:session.delete", "control:session.close", "control:context.clear", "control:session.cwd.move", "control:compaction.run", "control:bash.execute", "control:bash.background", "control:queue.message.remove", "control:queue.message.update", "control:retry.abort", "control:retry.now", "control:bash.abort", "control:retry.auto.set", "control:compaction.auto.set", "control:extension.set_enabled", "control:queue.interrupt_mode.set", "control:queue.follow_up_mode.set", "control:queue.steering_mode.set", "control:tools.active.set", "control:permission_mode.set", "control:service_tier.set", "control:workflow.gate_answer", "control:workflow.plan_approve"];
|
|
14
|
+
/**
|
|
15
|
+
* Whether `(kind, sdkId)` is the fully qualified identity of an allowlisted
|
|
16
|
+
* elevation-gated operation. The pair is validated against the operation
|
|
17
|
+
* registry before any elevation is admitted, so a key can never name an
|
|
18
|
+
* operation that does not exist.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isElevationAllowlisted(kind: unknown, sdkId: unknown): boolean;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SDK_STATE_VERSION } from "../broker/state-version";
|
|
2
|
+
import { classifyProcessIncarnationLiveness } from "./owner";
|
|
3
|
+
/**
|
|
4
|
+
* Durable elevation audit trail.
|
|
5
|
+
*
|
|
6
|
+
* Append-only JSONL under the same elevation-local lock as the grant ledger,
|
|
7
|
+
* mode 0600. Every state transition of a grant — issue, operator answer,
|
|
8
|
+
* expiry, misuse, duplicate answer, claim, and dispatch outcome — is
|
|
9
|
+
* recorded with the exact identity evidence the transition consumed, so an
|
|
10
|
+
* auditor can reproduce why a grant reached its terminal state without
|
|
11
|
+
* trusting in-memory state.
|
|
12
|
+
*
|
|
13
|
+
* The audit stream is an evidence trail, never an authority: audit rows are
|
|
14
|
+
* append-only, are never re-read to drive decisions, and a corrupted row is
|
|
15
|
+
* quarantined (like ledger rows) instead of failing the ledger.
|
|
16
|
+
*/
|
|
17
|
+
export type ElevationAuditEvent = {
|
|
18
|
+
kind: "issued";
|
|
19
|
+
} | {
|
|
20
|
+
kind: "answered";
|
|
21
|
+
outcome: "granted" | "denied" | "expired" | "misused" | "target_unavailable" | "duplicate_answer";
|
|
22
|
+
} | {
|
|
23
|
+
kind: "expired";
|
|
24
|
+
} | {
|
|
25
|
+
kind: "misused";
|
|
26
|
+
} | {
|
|
27
|
+
kind: "duplicate_answer";
|
|
28
|
+
} | {
|
|
29
|
+
kind: "claimed";
|
|
30
|
+
claim: {
|
|
31
|
+
ownerId: string;
|
|
32
|
+
epoch: number;
|
|
33
|
+
pid: number;
|
|
34
|
+
incarnation: string;
|
|
35
|
+
};
|
|
36
|
+
} | {
|
|
37
|
+
kind: "dispatched";
|
|
38
|
+
dispatch: {
|
|
39
|
+
ownerId: string;
|
|
40
|
+
epoch: number;
|
|
41
|
+
dispatchedAt: number;
|
|
42
|
+
};
|
|
43
|
+
outcome: {
|
|
44
|
+
status: "ok" | "failed";
|
|
45
|
+
code?: string;
|
|
46
|
+
message?: string;
|
|
47
|
+
dispatchedAt: number;
|
|
48
|
+
};
|
|
49
|
+
} | {
|
|
50
|
+
kind: "consumed";
|
|
51
|
+
message: string;
|
|
52
|
+
} | {
|
|
53
|
+
kind: "unavailable";
|
|
54
|
+
reason: string;
|
|
55
|
+
};
|
|
56
|
+
export interface ElevationAuditEntry {
|
|
57
|
+
version: typeof SDK_STATE_VERSION;
|
|
58
|
+
ts: number;
|
|
59
|
+
elevationRequestId: string;
|
|
60
|
+
issueIndex: number;
|
|
61
|
+
event: ElevationAuditEvent;
|
|
62
|
+
}
|
|
63
|
+
export type ElevationAuditEventName = ElevationAuditEvent["kind"];
|
|
64
|
+
export declare function isElevationAuditEntry(value: unknown): value is ElevationAuditEntry;
|
|
65
|
+
export interface ElevationAuditOptions {
|
|
66
|
+
/** Injectable clock. */
|
|
67
|
+
now?: () => number;
|
|
68
|
+
/**
|
|
69
|
+
* Injectable tri-state process-incarnation liveness classifier, defaulting
|
|
70
|
+
* to `classifyProcessIncarnationLiveness`. The audit trail records the
|
|
71
|
+
* liveness verdict behind `consumed`/`unavailable` settlements so the
|
|
72
|
+
* crash-truth settlement is reproducible; the verdict never drives the
|
|
73
|
+
* settlement itself (that lives in the ledger).
|
|
74
|
+
*/
|
|
75
|
+
classifyLiveness?: typeof classifyProcessIncarnationLiveness;
|
|
76
|
+
}
|
|
77
|
+
export declare class ElevationAudit {
|
|
78
|
+
#private;
|
|
79
|
+
constructor(agentDir: string, options?: ElevationAuditOptions);
|
|
80
|
+
get warnings(): readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* Appends one audit row for an elevation grant transition. Callers MUST
|
|
83
|
+
* hold the same elevation-local lock that guards the grant ledger; the
|
|
84
|
+
* audit row and the grant row therefore commit together.
|
|
85
|
+
*/
|
|
86
|
+
append(entry: Omit<ElevationAuditEntry, "version">): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Opens the audit stream: creates the 0600 directory/file if absent and
|
|
89
|
+
* quarantines any corrupt tail so subsequent appends are always readable.
|
|
90
|
+
* Called under the same lock as `ElevationLedger.open()`.
|
|
91
|
+
*/
|
|
92
|
+
open(): Promise<this>;
|
|
93
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function signElevationCapability(authorityToken: string, requestId: string, sdkId: string, input: Record<string, unknown>): string;
|
|
2
|
+
export declare function verifyElevationCapability(authorityToken: string, capability: string, sdkId: string, input: Record<string, unknown>): boolean;
|
|
3
|
+
export declare function elevationAuthorityPath(stateRoot: string, sessionId: string): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fully qualified elevation request digest.
|
|
3
|
+
*
|
|
4
|
+
* An elevation grant binds the exact operation the operator approved. The
|
|
5
|
+
* digest covers the complete `{kind, sdkId, input}` triple so substituting a
|
|
6
|
+
* different operation or different input bytes changes the digest and the
|
|
7
|
+
* gate presentation fails closed (`misused`). The top-level
|
|
8
|
+
* `elevationRequestId` correlation field is deliberately excluded: it is the
|
|
9
|
+
* durable correlation ID assigned to a request, not part of the approved
|
|
10
|
+
* content, and the same content re-issued under a new ID must produce the
|
|
11
|
+
* same digest.
|
|
12
|
+
*
|
|
13
|
+
* Only allowlisted operations can be elevated; anything else is refused so a
|
|
14
|
+
* caller cannot mint a grant for an operation outside the elevation policy.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ELEVATION_OPERATION_KINDS: readonly ["control", "query", "global"];
|
|
17
|
+
export type ElevationOperationKind = (typeof ELEVATION_OPERATION_KINDS)[number];
|
|
18
|
+
export interface ElevationOperation {
|
|
19
|
+
kind: ElevationOperationKind;
|
|
20
|
+
sdkId: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Operations that require an elevation grant. Default SDK scope
|
|
24
|
+
* (list/query/send/tail) stays grant-free; destructive lifecycle operations
|
|
25
|
+
* and workflow approval operations are elevatable and therefore gated.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ELEVATION_ALLOWLIST: readonly {
|
|
28
|
+
kind: ElevationOperationKind;
|
|
29
|
+
sdkId: string;
|
|
30
|
+
}[];
|
|
31
|
+
export declare function isElevatableOperation(kind: unknown, sdkId: unknown): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the `(kind, sdkId)` pair names a registry operation that the
|
|
34
|
+
* elevation allowlist recognizes. Used by the ledger row validator so a
|
|
35
|
+
* persisted row can never bind an operation outside the allowlist.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isKnownElevationOperation(kind: unknown, sdkId: unknown): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Canonical JSON encoding for elevation digest leaves.
|
|
40
|
+
*
|
|
41
|
+
* Intentionally byte-compatible with the broker's identity canonicalization
|
|
42
|
+
* (`canonicalJson` in `sdk/broker/broker.ts`): object keys sorted, compact
|
|
43
|
+
* separators, `undefined` fields preserved verbatim, arrays joined without
|
|
44
|
+
* separators. The broker computes the request digest at issue time and the
|
|
45
|
+
* ledger recomputes/compares the same encoding, so digest verification is
|
|
46
|
+
* stable across issue, gate presentation, and answer.
|
|
47
|
+
*/
|
|
48
|
+
export declare function canonicalElevationJson(value: unknown): string;
|
|
49
|
+
export type ElevationDigestResult = {
|
|
50
|
+
ok: true;
|
|
51
|
+
digest: string;
|
|
52
|
+
} | {
|
|
53
|
+
ok: false;
|
|
54
|
+
error: {
|
|
55
|
+
code: string;
|
|
56
|
+
message: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Computes the fully qualified digest for an elevation request.
|
|
61
|
+
*
|
|
62
|
+
* `input` is digested exactly as supplied except that a top-level
|
|
63
|
+
* `elevationRequestId` field is removed first (it is the correlation ID, not
|
|
64
|
+
* approved content). Operations outside `ELEVATION_ALLOWLIST` are refused
|
|
65
|
+
* with `elevation_not_required` so the broker never mints a grant for an
|
|
66
|
+
* operation that does not need one.
|
|
67
|
+
*/
|
|
68
|
+
export declare function elevationRequestDigest(request: {
|
|
69
|
+
kind: unknown;
|
|
70
|
+
sdkId: unknown;
|
|
71
|
+
input: unknown;
|
|
72
|
+
}): ElevationDigestResult;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export declare const ELEVATION_RECEIPT_VERSION = 1;
|
|
2
|
+
/**
|
|
3
|
+
* Identity of the broker tenure that claims a grant and dispatches it.
|
|
4
|
+
*
|
|
5
|
+
* `ownerId` is the broker instance owner id and `epoch` increments per broker
|
|
6
|
+
* start, so a restart (even of the same object) yields a new tenure. `pid` and
|
|
7
|
+
* `incarnation` are retained for truthful tri-state liveness replay.
|
|
8
|
+
*/
|
|
9
|
+
export interface ElevationClaimIdentity {
|
|
10
|
+
ownerId: string;
|
|
11
|
+
epoch: number;
|
|
12
|
+
pid: number;
|
|
13
|
+
incarnation: string;
|
|
14
|
+
}
|
|
15
|
+
export type ElevationReceiptState = "claimed" | "dispatched" | "uncertain";
|
|
16
|
+
/**
|
|
17
|
+
* Durable dispatch outcome. `unknown` is the crash truth: the grant was
|
|
18
|
+
* consumed by a claim but the dispatch outcome is not knowable, so retry
|
|
19
|
+
* requires a new grant.
|
|
20
|
+
*/
|
|
21
|
+
export type ElevationDispatchOutcome = {
|
|
22
|
+
status: "ok";
|
|
23
|
+
dispatchedAt: number;
|
|
24
|
+
} | {
|
|
25
|
+
status: "failed";
|
|
26
|
+
code: string;
|
|
27
|
+
message: string;
|
|
28
|
+
dispatchedAt: number;
|
|
29
|
+
} | {
|
|
30
|
+
status: "unknown";
|
|
31
|
+
message: string;
|
|
32
|
+
dispatchedAt: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Owner/epoch-bound dispatch receipt.
|
|
36
|
+
*
|
|
37
|
+
* State machine: `claimed` (grant spent, dispatch in flight, bound to the
|
|
38
|
+
* claiming broker tenure) -> `dispatched` (terminal, outcome recorded) or
|
|
39
|
+
* `uncertain` (terminal truth: the claim's outcome is unknowable after its
|
|
40
|
+
* broker tenure died). Replay never fabricates an outcome: a receipt left in
|
|
41
|
+
* `claimed` by a dead tenure is truthfully terminalized to `uncertain`.
|
|
42
|
+
*/
|
|
43
|
+
export interface ElevationDispatchReceipt {
|
|
44
|
+
version: typeof ELEVATION_RECEIPT_VERSION;
|
|
45
|
+
elevationRequestId: string;
|
|
46
|
+
issueIndex: number;
|
|
47
|
+
state: ElevationReceiptState;
|
|
48
|
+
claim: ElevationClaimIdentity & {
|
|
49
|
+
claimedAt: number;
|
|
50
|
+
};
|
|
51
|
+
dispatch?: {
|
|
52
|
+
ownerId: string;
|
|
53
|
+
epoch: number;
|
|
54
|
+
dispatchedAt: number;
|
|
55
|
+
};
|
|
56
|
+
outcome?: ElevationDispatchOutcome;
|
|
57
|
+
ts: number;
|
|
58
|
+
}
|
|
59
|
+
export declare function isElevationRequestId(value: unknown): value is string;
|
|
60
|
+
export declare function isElevationClaimIdentity(value: unknown): value is ElevationClaimIdentity;
|
|
61
|
+
export declare function isElevationDispatchOutcome(value: unknown): value is ElevationDispatchOutcome;
|
|
62
|
+
export declare function isElevationDispatchReceipt(value: unknown): value is ElevationDispatchReceipt;
|
|
63
|
+
export declare function claimReceipt(requestId: string, issueIndex: number, claim: ElevationClaimIdentity, claimedAt: number): ElevationDispatchReceipt;
|
|
64
|
+
export declare function dispatchReceipt(receipt: ElevationDispatchReceipt, dispatch: {
|
|
65
|
+
ownerId: string;
|
|
66
|
+
epoch: number;
|
|
67
|
+
dispatchedAt: number;
|
|
68
|
+
}, outcome: ElevationDispatchOutcome): ElevationDispatchReceipt;
|
|
69
|
+
export declare function uncertainReceipt(receipt: ElevationDispatchReceipt, at: number): ElevationDispatchReceipt;
|
|
70
|
+
export declare function receiptClaimMatches(receipt: ElevationDispatchReceipt, identity: ElevationClaimIdentity): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Who may answer an elevation gate.
|
|
73
|
+
*
|
|
74
|
+
* Internal operator-only: the answer boundary is the broker's internal
|
|
75
|
+
* operator attestation (`local_operator`), reached only through broker-owned
|
|
76
|
+
* surfaces. There is no public `elevation.answer` operation and no
|
|
77
|
+
* requester-correlation check: the answerer is structurally an operator
|
|
78
|
+
* attestation, so requester self-approval is impossible by construction.
|
|
79
|
+
*/
|
|
80
|
+
export type ElevationAnswerAuthority = {
|
|
81
|
+
source: "local_operator";
|
|
82
|
+
attestedBy: string;
|
|
83
|
+
};
|
|
84
|
+
/** Structural guard for the internal operator attestation. */
|
|
85
|
+
export declare function isElevationAnswerAuthority(value: unknown): value is ElevationAnswerAuthority;
|