@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
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { SDK_STATE_VERSION } from "../broker/state-version";
|
|
2
|
+
import { type ElevationOperation } from "./digest";
|
|
3
|
+
import { type ElevationAnswerAuthority, type ElevationClaimIdentity, type ElevationDispatchOutcome, type ElevationDispatchReceipt } from "./dispatch-receipt";
|
|
4
|
+
import { type BrokerOwnerPrincipal, classifyProcessIncarnationLiveness } from "./owner";
|
|
5
|
+
/**
|
|
6
|
+
* Broker-owned elevation grant ledger.
|
|
7
|
+
*
|
|
8
|
+
* Durable state machine (per elevation request):
|
|
9
|
+
* `requested -> granted -> claimed -> dispatched(outcome)`; terminal
|
|
10
|
+
* `denied`/`expired`/`misused`/`target_unavailable`; crash truth
|
|
11
|
+
* `consumed` (claimed but outcome unknown). Grants are single-use: the claim
|
|
12
|
+
* CAS consumes the grant before dispatch, and a crash between consume and
|
|
13
|
+
* dispatch is replayed truthfully as `consumed` with outcome `unknown`
|
|
14
|
+
* (retry requires a new grant — fail closed).
|
|
15
|
+
*
|
|
16
|
+
* All mutations and reads serialize on one elevation-local
|
|
17
|
+
* `withFileLock` transaction covering grants (`grants.jsonl`), dispatch
|
|
18
|
+
* receipts (`receipts.jsonl`), the issue index (`index.json`), and the
|
|
19
|
+
* audit trail (`audit.jsonl`), so a claim, its receipt, and the issue
|
|
20
|
+
* sequence commit together.
|
|
21
|
+
*
|
|
22
|
+
* The answer boundary is internal operator-only: there is no public
|
|
23
|
+
* `elevation.answer` operation; answers are admitted only from the internal
|
|
24
|
+
* operator attestation, so requester self-approval is impossible by
|
|
25
|
+
* construction.
|
|
26
|
+
*/
|
|
27
|
+
export type ElevationGrantState = "requested" | "granted" | "claimed" | "dispatched" | "consumed" | "denied" | "expired" | "misused" | "target_unavailable";
|
|
28
|
+
export interface ElevationSessionIdentity {
|
|
29
|
+
sessionId: string;
|
|
30
|
+
/** Exact endpoint state root bound at issue time; never the repo root. */
|
|
31
|
+
endpointStateRoot: string;
|
|
32
|
+
endpointGeneration: number;
|
|
33
|
+
endpointIncarnation: string;
|
|
34
|
+
}
|
|
35
|
+
/** Audit-only requester binding; never an identity claim. */
|
|
36
|
+
export interface ElevationRequester {
|
|
37
|
+
source: "broker_connection";
|
|
38
|
+
connectionId: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ElevationGrantRecord {
|
|
41
|
+
version: typeof SDK_STATE_VERSION;
|
|
42
|
+
/** Durable correlation ID; UUID, path-safe. */
|
|
43
|
+
elevationRequestId: string;
|
|
44
|
+
/** Monotonic path-safe issue sequence, allocated under the ledger lock. */
|
|
45
|
+
issueIndex: number;
|
|
46
|
+
state: ElevationGrantState;
|
|
47
|
+
operation: ElevationOperation;
|
|
48
|
+
requestDigest: string;
|
|
49
|
+
sessionIdentity: ElevationSessionIdentity;
|
|
50
|
+
principal: BrokerOwnerPrincipal;
|
|
51
|
+
requester: ElevationRequester;
|
|
52
|
+
requestedAt: number;
|
|
53
|
+
expiresAt: number;
|
|
54
|
+
outcome?: ElevationDispatchOutcome;
|
|
55
|
+
ts: number;
|
|
56
|
+
}
|
|
57
|
+
export type ElevationErrorCode = "not_found" | "invalid_input" | "idempotency_conflict" | "grant_spent" | "elevation_claim_in_progress" | "elevation_required" | "elevation_unavailable" | "elevation_not_required" | "endpoint_stale" | "target_unavailable" | "expired" | "misused" | "duplicate_answer" | "terminal_uncertain" | (string & {});
|
|
58
|
+
export type ElevationResult<T> = {
|
|
59
|
+
ok: true;
|
|
60
|
+
value: T;
|
|
61
|
+
} | {
|
|
62
|
+
ok: false;
|
|
63
|
+
error: {
|
|
64
|
+
code: ElevationErrorCode;
|
|
65
|
+
message: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
export interface ElevationIssueParams {
|
|
69
|
+
/** Optional caller-supplied correlation ID for idempotent retry; the broker generates a UUID otherwise. */
|
|
70
|
+
elevationRequestId?: string;
|
|
71
|
+
operation: ElevationOperation;
|
|
72
|
+
input: Record<string, unknown>;
|
|
73
|
+
sessionIdentity: ElevationSessionIdentity;
|
|
74
|
+
principal: BrokerOwnerPrincipal;
|
|
75
|
+
requester: ElevationRequester;
|
|
76
|
+
expiresInMs?: number;
|
|
77
|
+
}
|
|
78
|
+
export interface ElevationIssueValue {
|
|
79
|
+
replay: boolean;
|
|
80
|
+
elevationRequestId: string;
|
|
81
|
+
issueIndex: number;
|
|
82
|
+
requestDigest: string;
|
|
83
|
+
state: ElevationGrantState;
|
|
84
|
+
requestedAt: number;
|
|
85
|
+
expiresAt: number;
|
|
86
|
+
grant: ElevationGrantRecord;
|
|
87
|
+
}
|
|
88
|
+
export interface ElevationAnswerParams {
|
|
89
|
+
elevationRequestId: string;
|
|
90
|
+
answer: "approve" | "deny";
|
|
91
|
+
/** Digest the answering surface presented from the gate payload. */
|
|
92
|
+
presentedDigest: string;
|
|
93
|
+
/** Broker-owner principal attesting the answer authority. */
|
|
94
|
+
principal: BrokerOwnerPrincipal;
|
|
95
|
+
answerer: ElevationAnswerAuthority;
|
|
96
|
+
/** Current broker-resolved target identity; undefined means the session is unreachable. */
|
|
97
|
+
currentSessionIdentity?: ElevationSessionIdentity;
|
|
98
|
+
}
|
|
99
|
+
export type ElevationAnswerOutcome = "granted" | "denied" | "expired" | "misused" | "target_unavailable" | "duplicate_answer";
|
|
100
|
+
export interface ElevationAnswerValue {
|
|
101
|
+
outcome: ElevationAnswerOutcome;
|
|
102
|
+
grant: ElevationGrantRecord;
|
|
103
|
+
}
|
|
104
|
+
export interface ElevationClaimParams {
|
|
105
|
+
elevationRequestId: string;
|
|
106
|
+
claimIdentity: ElevationClaimIdentity;
|
|
107
|
+
/** Current broker-resolved target identity; undefined means the session is unreachable. */
|
|
108
|
+
currentSessionIdentity?: ElevationSessionIdentity;
|
|
109
|
+
}
|
|
110
|
+
export interface ElevationClaimValue {
|
|
111
|
+
grant: ElevationGrantRecord;
|
|
112
|
+
receipt: ElevationDispatchReceipt;
|
|
113
|
+
}
|
|
114
|
+
export interface ElevationDispatchParams {
|
|
115
|
+
elevationRequestId: string;
|
|
116
|
+
dispatchIdentity: ElevationClaimIdentity;
|
|
117
|
+
outcome: ElevationDispatchOutcome;
|
|
118
|
+
}
|
|
119
|
+
export interface ElevationDispatchValue {
|
|
120
|
+
grant: ElevationGrantRecord;
|
|
121
|
+
receipt: ElevationDispatchReceipt;
|
|
122
|
+
}
|
|
123
|
+
export interface ElevationReadValue {
|
|
124
|
+
grant: ElevationGrantRecord;
|
|
125
|
+
receipt?: ElevationDispatchReceipt;
|
|
126
|
+
}
|
|
127
|
+
export interface ElevationListValue {
|
|
128
|
+
grants: ElevationReadValue[];
|
|
129
|
+
}
|
|
130
|
+
export interface ElevationLedgerOptions {
|
|
131
|
+
/** Defaults to the GJC_SDK_ELEVATION_ENABLED environment flag. */
|
|
132
|
+
enabled?: boolean;
|
|
133
|
+
/** Request lifetime before the grant expires. */
|
|
134
|
+
ttlMs?: number;
|
|
135
|
+
/** Injectable clock. */
|
|
136
|
+
now?: () => number;
|
|
137
|
+
/**
|
|
138
|
+
* Injectable tri-state process-incarnation liveness classifier (defaults to
|
|
139
|
+
* `classifyProcessIncarnationLiveness`). Test seam for crash-state replay:
|
|
140
|
+
* "unknown" must always fail closed as `elevation_claim_in_progress`.
|
|
141
|
+
*/
|
|
142
|
+
classifyLiveness?: typeof classifyProcessIncarnationLiveness;
|
|
143
|
+
}
|
|
144
|
+
declare function isElevationOperation(value: unknown): value is ElevationOperation;
|
|
145
|
+
declare function isElevationGrantRecord(value: unknown): value is ElevationGrantRecord;
|
|
146
|
+
export declare class ElevationLedger {
|
|
147
|
+
#private;
|
|
148
|
+
constructor(agentDir: string, options?: ElevationLedgerOptions);
|
|
149
|
+
get warnings(): readonly string[];
|
|
150
|
+
open(): Promise<this>;
|
|
151
|
+
assertSupportedStateVersions(): Promise<void>;
|
|
152
|
+
issue(params: ElevationIssueParams): Promise<ElevationResult<ElevationIssueValue>>;
|
|
153
|
+
answer(params: ElevationAnswerParams): Promise<ElevationResult<ElevationAnswerValue>>;
|
|
154
|
+
claim(params: ElevationClaimParams): Promise<ElevationResult<ElevationClaimValue>>;
|
|
155
|
+
dispatch(params: ElevationDispatchParams): Promise<ElevationResult<ElevationDispatchValue>>;
|
|
156
|
+
/** Pure read without reconciliation writes; used before actions. */
|
|
157
|
+
get(elevationRequestId: string): Promise<ElevationResult<ElevationReadValue>>;
|
|
158
|
+
/** Truthful read: reconciles expiry and crash-state claims before returning. */
|
|
159
|
+
resolve(elevationRequestId: string, claimIdentity: ElevationClaimIdentity): Promise<ElevationResult<ElevationReadValue>>;
|
|
160
|
+
/** Truthful listing: reconciles every grant before returning. */
|
|
161
|
+
list(claimIdentity: ElevationClaimIdentity): Promise<ElevationResult<ElevationListValue>>;
|
|
162
|
+
}
|
|
163
|
+
export { isElevationGrantRecord, isElevationOperation };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Broker-owner principal.
|
|
3
|
+
*
|
|
4
|
+
* The elevation authority is the broker itself under the existing loopback
|
|
5
|
+
* trust model: one local OS-user/broker authority derived entirely from
|
|
6
|
+
* broker-owned state, never from caller input. `agentDirUid` is the uid that
|
|
7
|
+
* owns the agent directory, `brokerPid`/`brokerIncarnation` identify the
|
|
8
|
+
* broker process tenure so a restarted broker cannot attest the same
|
|
9
|
+
* authority.
|
|
10
|
+
*/
|
|
11
|
+
export interface BrokerOwnerPrincipal {
|
|
12
|
+
kind: "broker_owner";
|
|
13
|
+
owner: {
|
|
14
|
+
agentDirUid: number;
|
|
15
|
+
brokerPid: number;
|
|
16
|
+
brokerIncarnation: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export declare function isBrokerOwnerPrincipal(value: unknown): value is BrokerOwnerPrincipal;
|
|
20
|
+
export declare function sameBrokerOwnerPrincipal(left: BrokerOwnerPrincipal, right: BrokerOwnerPrincipal): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Reads the broker-owner principal from broker-owned state. Throws when the
|
|
23
|
+
* broker cannot attest a canonical process incarnation (the broker refuses to
|
|
24
|
+
* start in that case anyway), so callers treat a throw as "authority
|
|
25
|
+
* unavailable".
|
|
26
|
+
*/
|
|
27
|
+
export declare function readBrokerOwnerPrincipal(agentDir: string, brokerPid: number, brokerIncarnation: string): Promise<BrokerOwnerPrincipal>;
|
|
28
|
+
export type ProcessIncarnationLiveness = "alive" | "dead" | "unknown";
|
|
29
|
+
/**
|
|
30
|
+
* Tri-state liveness of a process incarnation.
|
|
31
|
+
*
|
|
32
|
+
* - `alive`: the pid is running and its current incarnation matches the
|
|
33
|
+
* stored one, so the original process tenure is still live.
|
|
34
|
+
* - `dead`: ESRCH (the pid is provably gone — independent of any persisted
|
|
35
|
+
* incarnation text), or the pid is running under a *different* canonical
|
|
36
|
+
* incarnation (PID reuse), which provably means the original process
|
|
37
|
+
* ended.
|
|
38
|
+
* - `unknown`: the pid is malformed, the persisted or observed incarnation
|
|
39
|
+
* is malformed/undefined, or the current incarnation cannot be read.
|
|
40
|
+
* Unknown never implies death: elevation claims must fail closed with
|
|
41
|
+
* `elevation_claim_in_progress` instead of terminalizing state on
|
|
42
|
+
* unprovable liveness.
|
|
43
|
+
*
|
|
44
|
+
* ESRCH is independent positive death proof: a pid that provably does not
|
|
45
|
+
* exist is dead regardless of the persisted incarnation text, so a corrupt
|
|
46
|
+
* persisted incarnation can never stall recovery forever.
|
|
47
|
+
*/
|
|
48
|
+
export declare function classifyProcessIncarnationLiveness(pid: unknown, incarnation: unknown): ProcessIncarnationLiveness;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { SDK_STATE_VERSION } from "../broker/state-version";
|
|
2
|
+
import { type GuideEntryV1, type GuideManifestV1 } from "./manifest";
|
|
3
|
+
import { type GuideVerificationErrorCode } from "./verify";
|
|
4
|
+
/**
|
|
5
|
+
* Verified on-disk cache for trusted advisory guides.
|
|
6
|
+
*
|
|
7
|
+
* Layout under `<agentDir>/sdk/guides/cache/` (mode 0700):
|
|
8
|
+
* meta.json — atomic commit pointer {version, manifestId, sequence, generation, installedAt}
|
|
9
|
+
* meta.json.lock — cross-process install lock (project `withFileLock` convention)
|
|
10
|
+
* generations/<generation>/manifest.json — canonical manifest bytes
|
|
11
|
+
* generations/<generation>/manifest.sig — detached Ed25519 signature
|
|
12
|
+
* generations/<generation>/guides/<sha256> — immutable advisory text
|
|
13
|
+
*
|
|
14
|
+
* A complete generation is written and fsynced before `meta.json` is atomically
|
|
15
|
+
* replaced under the install lock. Readers follow only the committed
|
|
16
|
+
* generation, so an interrupted install cannot expose a new manifest with
|
|
17
|
+
* stale metadata or disturb the previously valid cache.
|
|
18
|
+
*/
|
|
19
|
+
export interface GuideCacheMetaV1 {
|
|
20
|
+
version: typeof SDK_STATE_VERSION;
|
|
21
|
+
manifestId: string;
|
|
22
|
+
sequence: number;
|
|
23
|
+
installedAt: number;
|
|
24
|
+
generation: string;
|
|
25
|
+
}
|
|
26
|
+
export interface GuideCacheGuideV1 {
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
sha256: string;
|
|
30
|
+
text: string;
|
|
31
|
+
}
|
|
32
|
+
export interface VerifiedGuideCache {
|
|
33
|
+
manifest: GuideManifestV1;
|
|
34
|
+
signatureBytes: Uint8Array;
|
|
35
|
+
meta: GuideCacheMetaV1;
|
|
36
|
+
guides: GuideCacheGuideV1[];
|
|
37
|
+
}
|
|
38
|
+
export type GuideCacheReadResult = {
|
|
39
|
+
ok: true;
|
|
40
|
+
value: VerifiedGuideCache;
|
|
41
|
+
} | {
|
|
42
|
+
ok: false;
|
|
43
|
+
error: {
|
|
44
|
+
code: "missing_cache" | "corrupt_cache" | "expired_cache" | "unsupported_state_version";
|
|
45
|
+
message: string;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export type GuideCacheInstallResult = {
|
|
49
|
+
ok: true;
|
|
50
|
+
value: VerifiedGuideCache;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
error: {
|
|
54
|
+
code: GuideVerificationErrorCode | "invalid_input" | "io_error";
|
|
55
|
+
message: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export declare function guideCacheDir(agentDir: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Reads and re-verifies the cache end to end: manifest parse, meta commit
|
|
61
|
+
* record, detached signature, expiry against `now`, and every advisory hash.
|
|
62
|
+
* Any failure is reported as `corrupt_cache` (or `expired_cache` when the
|
|
63
|
+
* signature is valid but stale) and the cache is left untouched — a corrupt
|
|
64
|
+
* entry never destroys the data a future, still-valid install may replace.
|
|
65
|
+
*/
|
|
66
|
+
export declare function readGuideCache(params: {
|
|
67
|
+
agentDir: string;
|
|
68
|
+
now: number;
|
|
69
|
+
}): Promise<GuideCacheReadResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Installs a verified manifest plus its advisory content into the cache.
|
|
72
|
+
*
|
|
73
|
+
* Order of operations:
|
|
74
|
+
* 1. Verify the manifest signature, expiry, and every advisory hash before
|
|
75
|
+
* any write — a tampered or expired payload never touches disk.
|
|
76
|
+
* 2. Under the cache's cross-process install lock, enforce the monotonic
|
|
77
|
+
* version floor against the committed meta record (`rollback` when the
|
|
78
|
+
* candidate does not advance the channel).
|
|
79
|
+
* 3. Write and fsync a complete immutable generation, then atomically replace
|
|
80
|
+
* `meta.json` as the only commit pointer.
|
|
81
|
+
*
|
|
82
|
+
* Steps 2–3 are serialized with `<cacheDir>/meta.json.lock` (the project's
|
|
83
|
+
* `withFileLock` convention): the floor is re-read under the same lock that
|
|
84
|
+
* guards the commit pointer replacement, so a concurrent install can never
|
|
85
|
+
* read an older floor, observe a newer commit, and then downgrade the channel.
|
|
86
|
+
* Any failure aborts before the commit, leaving the prior valid cache fully
|
|
87
|
+
* intact and readable.
|
|
88
|
+
*/
|
|
89
|
+
export declare function installGuideCache(params: {
|
|
90
|
+
agentDir: string;
|
|
91
|
+
manifest: GuideManifestV1;
|
|
92
|
+
signatureBytes: Uint8Array;
|
|
93
|
+
advisories: readonly {
|
|
94
|
+
entry: GuideEntryV1;
|
|
95
|
+
text: Uint8Array;
|
|
96
|
+
}[];
|
|
97
|
+
now: number;
|
|
98
|
+
}): Promise<GuideCacheInstallResult>;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { type VerifiedGuideCache } from "./cache";
|
|
2
|
+
import { type GuideManifestV1 } from "./manifest";
|
|
3
|
+
/**
|
|
4
|
+
* HTTPS-only, allowlisted, credential-free fetch boundary for advisory guides.
|
|
5
|
+
*
|
|
6
|
+
* The catalog refuses any URL that is not https, whose host is not in the
|
|
7
|
+
* allowlist, whose path is outside the allowlisted prefix, or that carries
|
|
8
|
+
* userinfo. Every request uses `credentials: "omit"`, no authorization or
|
|
9
|
+
* cookie headers, and `redirect: "error"` so a redirect can never escape the
|
|
10
|
+
* allowlist. Responses are bounded by byte caps and a timeout. This boundary
|
|
11
|
+
* is the only network surface of the guide subsystem — advisories are fetched
|
|
12
|
+
* as data, verified against the signed manifest, and never executed.
|
|
13
|
+
*/
|
|
14
|
+
export interface GuideFetchAllowlistEntry {
|
|
15
|
+
host: string;
|
|
16
|
+
/** Every fetched path must start with this prefix. */
|
|
17
|
+
pathPrefix: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const GUIDE_FETCH_ALLOWLIST: readonly GuideFetchAllowlistEntry[];
|
|
20
|
+
export declare const GUIDE_FETCH_TIMEOUT_MS = 10000;
|
|
21
|
+
export declare const GUIDE_FETCH_MAX_MANIFEST_BYTES: number;
|
|
22
|
+
export declare const GUIDE_FETCH_MAX_SIGNATURE_BYTES = 1024;
|
|
23
|
+
export declare const GUIDE_FETCH_USER_AGENT = "gajae-code-sdk-guides/1";
|
|
24
|
+
export interface GuideFetchPolicy {
|
|
25
|
+
httpsOnly: true;
|
|
26
|
+
credentials: "omit";
|
|
27
|
+
redirect: "error";
|
|
28
|
+
allowlist: readonly GuideFetchAllowlistEntry[];
|
|
29
|
+
maxManifestBytes: number;
|
|
30
|
+
maxSignatureBytes: number;
|
|
31
|
+
timeoutMs: number;
|
|
32
|
+
userAgent: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function guideFetchPolicy(): GuideFetchPolicy;
|
|
35
|
+
/** True when a URL satisfies the HTTPS allowlist boundary. */
|
|
36
|
+
export declare function isGuideFetchUrlAllowed(url: string): boolean;
|
|
37
|
+
export type GuideFetchErrorCode = "fetch_forbidden" | "fetch_failed" | "oversize" | "timeout" | "network_error" | "invalid_manifest" | "unsupported_version" | (string & {});
|
|
38
|
+
export interface GuideOnlineManifest {
|
|
39
|
+
url: string;
|
|
40
|
+
manifest: GuideManifestV1;
|
|
41
|
+
signatureBytes: Uint8Array;
|
|
42
|
+
fetchedAt: number;
|
|
43
|
+
}
|
|
44
|
+
export type GuideFetchResult = {
|
|
45
|
+
ok: true;
|
|
46
|
+
value: GuideOnlineManifest;
|
|
47
|
+
} | {
|
|
48
|
+
ok: false;
|
|
49
|
+
error: {
|
|
50
|
+
code: GuideFetchErrorCode;
|
|
51
|
+
message: string;
|
|
52
|
+
status?: number;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Fetches the manifest at `url` and its detached signature at `<url>.sig`,
|
|
57
|
+
* bounded by the HTTPS allowlist policy. The manifest is parsed and shape
|
|
58
|
+
* validated here; signature verification and advisory hash checks happen in
|
|
59
|
+
* the caller so a rejected refresh can fall back to cache/bundled.
|
|
60
|
+
*/
|
|
61
|
+
export declare function fetchGuideManifestOnline(params: {
|
|
62
|
+
url: string;
|
|
63
|
+
timeoutMs?: number;
|
|
64
|
+
fetchImpl?: typeof fetch;
|
|
65
|
+
now?: number;
|
|
66
|
+
}): Promise<GuideFetchResult>;
|
|
67
|
+
/**
|
|
68
|
+
* Trusted-by-compilation bundled manifests. The seed manifest is signed by the
|
|
69
|
+
* bundled pinned key (`verify.ts`), and every bundled advisory ships its text
|
|
70
|
+
* so fresh-install `list`/`show` work offline with no cache. The seed is
|
|
71
|
+
* selected only when no valid online or cached manifest exists; because the
|
|
72
|
+
* bundled manifest is itself signature-verified at module load, bundling the
|
|
73
|
+
* signature here preserves the normal verify path for bundled content.
|
|
74
|
+
*/
|
|
75
|
+
export declare const BUNDLED_GUIDE_MANIFESTS: readonly GuideManifestV1[];
|
|
76
|
+
export type GuideCatalogSource = "online" | "cache" | "bundled";
|
|
77
|
+
export interface GuideCatalogGuideV1 {
|
|
78
|
+
id: string;
|
|
79
|
+
title: string;
|
|
80
|
+
sha256: string;
|
|
81
|
+
/** Advisory text; undefined when the bundled manifest does not ship content for this guide. */
|
|
82
|
+
text: string | undefined;
|
|
83
|
+
}
|
|
84
|
+
export interface GuideCatalogSelection {
|
|
85
|
+
source: GuideCatalogSource;
|
|
86
|
+
manifest: GuideManifestV1;
|
|
87
|
+
guides: GuideCatalogGuideV1[];
|
|
88
|
+
/** Present when the selection is served from (or was installed into) the verified cache. */
|
|
89
|
+
cache?: VerifiedGuideCache;
|
|
90
|
+
/** Online provenance. */
|
|
91
|
+
url?: string;
|
|
92
|
+
fetchedAt?: number;
|
|
93
|
+
/** Non-fatal provenance notes (e.g. an online refresh was rejected and selection fell back). */
|
|
94
|
+
warnings: string[];
|
|
95
|
+
}
|
|
96
|
+
export type GuideCatalogResult = {
|
|
97
|
+
ok: true;
|
|
98
|
+
value: GuideCatalogSelection;
|
|
99
|
+
} | {
|
|
100
|
+
ok: false;
|
|
101
|
+
error: {
|
|
102
|
+
code: string;
|
|
103
|
+
message: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export interface GuideCatalogOptions {
|
|
107
|
+
agentDir: string;
|
|
108
|
+
/** Online manifest URL; undefined disables the network entirely. */
|
|
109
|
+
onlineUrl?: string;
|
|
110
|
+
now?: () => number;
|
|
111
|
+
fetchImpl?: typeof fetch;
|
|
112
|
+
timeoutMs?: number;
|
|
113
|
+
/** Trusted-by-compilation bundled manifests; defaults to `BUNDLED_GUIDE_MANIFESTS`. */
|
|
114
|
+
disableBundled?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Advisory guide catalog service.
|
|
118
|
+
*
|
|
119
|
+
* Selection precedence is `valid online -> valid cache -> bundled`: a freshly
|
|
120
|
+
* fetched, verified manifest wins; otherwise the verified cache; otherwise the
|
|
121
|
+
* bundled seed. Verification failures never throw — they surface as warnings
|
|
122
|
+
* (for online) or as selection fallback, and the cache is never destroyed.
|
|
123
|
+
*/
|
|
124
|
+
export declare class GuideCatalog {
|
|
125
|
+
#private;
|
|
126
|
+
constructor(options: GuideCatalogOptions);
|
|
127
|
+
/**
|
|
128
|
+
* Fetches, verifies, and installs the online manifest when `onlineUrl` is
|
|
129
|
+
* configured, then selects per the online/cache/bundled precedence. The
|
|
130
|
+
* verified cache is always the source of advisory text for online and
|
|
131
|
+
* cached selections, so a single verified read path serves both.
|
|
132
|
+
*/
|
|
133
|
+
refresh(): Promise<GuideCatalogResult>;
|
|
134
|
+
/** Offline selection: verified cache first, then bundled. Never touches the network. */
|
|
135
|
+
load(): Promise<GuideCatalogResult>;
|
|
136
|
+
/**
|
|
137
|
+
* Returns the advisory text for a guide in the currently selected
|
|
138
|
+
* manifest. Advisory text is data only: it is rendered and never executed
|
|
139
|
+
* or applied as configuration.
|
|
140
|
+
*/
|
|
141
|
+
advisory(guideId: string): Promise<{
|
|
142
|
+
ok: true;
|
|
143
|
+
value: {
|
|
144
|
+
source: GuideCatalogSource;
|
|
145
|
+
guideId: string;
|
|
146
|
+
title: string;
|
|
147
|
+
text: string;
|
|
148
|
+
};
|
|
149
|
+
} | {
|
|
150
|
+
ok: false;
|
|
151
|
+
error: {
|
|
152
|
+
code: string;
|
|
153
|
+
message: string;
|
|
154
|
+
};
|
|
155
|
+
}>;
|
|
156
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `gjc sdk guides` command family (routing lives in `src/commands/sdk.ts`).
|
|
3
|
+
*
|
|
4
|
+
* Verbs:
|
|
5
|
+
* refresh --url <https url> fetch + verify the online manifest and advisory
|
|
6
|
+
* text, install the verified cache, report selection.
|
|
7
|
+
* Fails operationally (exit 1) whenever the online
|
|
8
|
+
* manifest is not selected: fallback cache/bundled
|
|
9
|
+
* content is reported as a failure, never as a
|
|
10
|
+
* successful refresh
|
|
11
|
+
* list offline selection: verified cache, else bundled
|
|
12
|
+
* show <guideId> render the advisory text for one guide (data only)
|
|
13
|
+
* status selection provenance, cache health, fetch policy
|
|
14
|
+
* trust pinned key ids and the no-credential fetch boundary
|
|
15
|
+
*
|
|
16
|
+
* The subsystem is advisory-text only: it never executes guide content, never
|
|
17
|
+
* mutates configuration, and never accepts or emits credentials. The only
|
|
18
|
+
* state it writes is the verified guide cache during `refresh`.
|
|
19
|
+
*/
|
|
20
|
+
export type SdkGuidesCliAction = "refresh" | "list" | "show" | "status" | "trust";
|
|
21
|
+
export interface SdkGuidesCliArgs {
|
|
22
|
+
action?: string;
|
|
23
|
+
/** Guide id for `show`. */
|
|
24
|
+
guideId?: string;
|
|
25
|
+
/** Online manifest URL for `refresh`; must satisfy the HTTPS allowlist. */
|
|
26
|
+
url?: string;
|
|
27
|
+
agentDir?: string;
|
|
28
|
+
/** Bounded fetch timeout for `refresh`. */
|
|
29
|
+
timeoutMs?: number;
|
|
30
|
+
/** Fetch implementation override for `refresh` (test seam); defaults to the global fetch. */
|
|
31
|
+
fetchImpl?: typeof fetch;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Runs the `gjc sdk guides` command family. Exported for command routing from
|
|
35
|
+
* `src/commands/sdk.ts` and for direct service use; the injected `write` /
|
|
36
|
+
* `setExitCode` hooks keep the surface testable without touching stdout or
|
|
37
|
+
* the process exit code.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runSdkGuidesCli(args: SdkGuidesCliArgs, writeOutput?: (value: unknown) => void, setExitCode?: (exitCode: 1 | 2) => void): Promise<void>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trusted advisory guide manifest: types, canonical encoding, and parsing.
|
|
3
|
+
*
|
|
4
|
+
* A manifest is a signed, time-boxed bundle of advisory guide bindings. Each
|
|
5
|
+
* entry binds a stable guide id to the SHA-256 digest of its advisory text, so
|
|
6
|
+
* the advisory content can be fetched separately and verified against the
|
|
7
|
+
* signed manifest. Manifests are advisory text only: they never carry
|
|
8
|
+
* instructions to execute or configuration to apply.
|
|
9
|
+
*/
|
|
10
|
+
export declare const GUIDES_MANIFEST_VERSION = 1;
|
|
11
|
+
/** Maximum byte length of a single advisory text file. */
|
|
12
|
+
export declare const GUIDE_ADVISORY_MAX_BYTES: number;
|
|
13
|
+
/** Maximum number of guides bound by a single manifest. */
|
|
14
|
+
export declare const GUIDE_MANIFEST_MAX_ENTRIES = 256;
|
|
15
|
+
/** Maximum manifest JSON byte length (enforced at fetch and cache read time). */
|
|
16
|
+
export declare const GUIDE_MANIFEST_MAX_BYTES: number;
|
|
17
|
+
export declare const GUIDE_ID_MAX_LENGTH = 128;
|
|
18
|
+
export declare const GUIDE_TITLE_MAX_LENGTH = 256;
|
|
19
|
+
export interface GuideEntryV1 {
|
|
20
|
+
/** Path-safe, stable guide id, e.g. "troubleshooting/socket". */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Human-readable advisory title. */
|
|
23
|
+
title: string;
|
|
24
|
+
/** Hex SHA-256 of the advisory text bytes; binds content to the signed manifest. */
|
|
25
|
+
sha256: string;
|
|
26
|
+
}
|
|
27
|
+
export interface GuideManifestV1 {
|
|
28
|
+
version: 1;
|
|
29
|
+
/** Stable channel identity the signature binds to; the rollback floor is per manifestId. */
|
|
30
|
+
manifestId: string;
|
|
31
|
+
/** Key id of the pinned Ed25519 public key that detached-signed the canonical manifest bytes. */
|
|
32
|
+
keyId: string;
|
|
33
|
+
/** Monotonic per-manifestId sequence; the cache refuses installs at or below the floor. */
|
|
34
|
+
sequence: number;
|
|
35
|
+
/** Milliseconds since epoch; the manifest is not authoritative before this instant. */
|
|
36
|
+
issuedAt: number;
|
|
37
|
+
/** Milliseconds since epoch; the manifest is not authoritative after this instant. */
|
|
38
|
+
expiresAt: number;
|
|
39
|
+
/** Minimum SDK advisory client version required to consume this manifest. */
|
|
40
|
+
minimumSdkVersion: number;
|
|
41
|
+
guides: GuideEntryV1[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Deterministic UTF-8 encoding of a guide manifest. Object keys are sorted,
|
|
45
|
+
* separators are compact, and the output is byte-identical for semantically
|
|
46
|
+
* equal manifests regardless of the original JSON formatting. The detached
|
|
47
|
+
* Ed25519 signature is verified over exactly these bytes, so a re-formatted
|
|
48
|
+
* manifest file still verifies while any semantic change breaks the signature.
|
|
49
|
+
*/
|
|
50
|
+
export declare function canonicalGuideManifestBytes(manifest: GuideManifestV1): Buffer;
|
|
51
|
+
export type GuideManifestParseResult = {
|
|
52
|
+
ok: true;
|
|
53
|
+
manifest: GuideManifestV1;
|
|
54
|
+
} | {
|
|
55
|
+
ok: false;
|
|
56
|
+
error: {
|
|
57
|
+
code: "invalid_manifest" | "unsupported_version";
|
|
58
|
+
message: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Strict shape validation for a parsed manifest value. Fails closed on any
|
|
63
|
+
* out-of-bounds field; a manifest for a newer format version is refused with
|
|
64
|
+
* `unsupported_version` so callers can distinguish "too new" from "malformed".
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseGuideManifest(value: unknown): GuideManifestParseResult;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type GuideEntryV1, type GuideManifestV1 } from "./manifest";
|
|
2
|
+
/**
|
|
3
|
+
* Version of the SDK advisory guide client. Manifests carry a
|
|
4
|
+
* `minimumSdkVersion` compatibility floor; a manifest that requires a newer
|
|
5
|
+
* client is refused (`incompatible`) instead of being partially understood.
|
|
6
|
+
*/
|
|
7
|
+
export declare const GUIDE_CLIENT_VERSION = 1;
|
|
8
|
+
/** Ed25519 detached signatures are always exactly 64 bytes. */
|
|
9
|
+
export declare const GUIDE_SIGNATURE_BYTES = 64;
|
|
10
|
+
export interface GuidePinnedKey {
|
|
11
|
+
keyId: string;
|
|
12
|
+
/** DER-encoded SPKI public key, hex. */
|
|
13
|
+
spkiDerHex: string;
|
|
14
|
+
source: "bundled";
|
|
15
|
+
}
|
|
16
|
+
export declare const GUIDE_PINNED_KEYS: readonly GuidePinnedKey[];
|
|
17
|
+
export declare const GUIDE_PINNED_KEY_IDS: readonly string[];
|
|
18
|
+
export type GuideVerificationErrorCode = "invalid_manifest" | "unsupported_version" | "unknown_key" | "corrupt_signature" | "invalid_signature" | "not_yet_valid" | "expired" | "incompatible" | "rollback" | "hash_mismatch" | (string & {});
|
|
19
|
+
export type GuideVerificationResult<T> = {
|
|
20
|
+
ok: true;
|
|
21
|
+
value: T;
|
|
22
|
+
} | {
|
|
23
|
+
ok: false;
|
|
24
|
+
error: {
|
|
25
|
+
code: GuideVerificationErrorCode;
|
|
26
|
+
message: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** Test-only override: installs an additional trusted key for deterministic tests. */
|
|
30
|
+
export declare function addTestGuidePinnedKey(key: GuidePinnedKey): void;
|
|
31
|
+
/** Test-only override: removes a previously installed test key. */
|
|
32
|
+
export declare function removeTestGuidePinnedKey(keyId: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Verifies a guide manifest end to end and fails closed on the first broken
|
|
35
|
+
* property. Order matters: identity and tamper checks (unknown key, malformed
|
|
36
|
+
* or mismatched signature) run before temporal and compatibility checks, so a
|
|
37
|
+
* tampered or untrusted manifest is never masked by an expiry message.
|
|
38
|
+
*/
|
|
39
|
+
export declare function verifyGuideManifest(params: {
|
|
40
|
+
manifest: GuideManifestV1;
|
|
41
|
+
signatureBytes: Uint8Array;
|
|
42
|
+
now: number;
|
|
43
|
+
}): GuideVerificationResult<{
|
|
44
|
+
keyId: string;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Monotonic floor check: a candidate manifest for a channel must strictly
|
|
48
|
+
* advance that channel's sequence, otherwise an older (but still validly
|
|
49
|
+
* signed) manifest is refused as a rollback.
|
|
50
|
+
*/
|
|
51
|
+
export declare function guideRollbackCheck(previous: {
|
|
52
|
+
manifestId: string;
|
|
53
|
+
sequence: number;
|
|
54
|
+
} | undefined, candidate: GuideManifestV1): GuideVerificationResult<{
|
|
55
|
+
monotonic: boolean;
|
|
56
|
+
}>;
|
|
57
|
+
export declare function guideAdvisoryDigest(text: Uint8Array): string;
|
|
58
|
+
/**
|
|
59
|
+
* Per-guide SHA-256 binding: the advisory text must match the digest the
|
|
60
|
+
* signed manifest binds for that guide id. This is the tamper check for the
|
|
61
|
+
* advisory payload itself — the manifest signature cannot cover content that
|
|
62
|
+
* is fetched separately, so every advisory is hash-verified against it.
|
|
63
|
+
*/
|
|
64
|
+
export declare function verifyGuideAdvisoryText(entry: GuideEntryV1, text: Uint8Array): GuideVerificationResult<{
|
|
65
|
+
sha256: string;
|
|
66
|
+
}>;
|
|
@@ -7,6 +7,8 @@ export interface ControlRequest {
|
|
|
7
7
|
expectedRevision?: string;
|
|
8
8
|
idempotencyKey?: string;
|
|
9
9
|
confirm?: boolean;
|
|
10
|
+
/** Top-level elevation claim selector, preserved from the control frame. */
|
|
11
|
+
elevationRequestId?: string;
|
|
10
12
|
}
|
|
11
13
|
export type ControlErrorCode = string;
|
|
12
14
|
export interface ControlError {
|
|
@@ -30,5 +32,11 @@ export declare class TypedControlError extends Error {
|
|
|
30
32
|
export declare class BusyError extends TypedControlError {
|
|
31
33
|
constructor(message?: string);
|
|
32
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Build the typed control request from a wire frame. Every runtime transport
|
|
37
|
+
* mapper uses this helper so the top-level elevation claim selector cannot
|
|
38
|
+
* drift between callsites.
|
|
39
|
+
*/
|
|
40
|
+
export declare function controlRequestFromFrame(frame: Record<string, unknown>): ControlRequest;
|
|
33
41
|
/** Dispatches a registry-defined per-session control operation. */
|
|
34
42
|
export declare function dispatchControl(surface: ControlSurface, registryRow: Operation | undefined, request: ControlRequest): Promise<ControlResponse>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { BusyError, type ControlError, type ControlErrorCode, type ControlRequest, type ControlResponse, dispatchControl, TypedControlError, } from "./dispatch";
|
|
1
|
+
export { BusyError, type ControlError, type ControlErrorCode, type ControlRequest, type ControlResponse, controlRequestFromFrame, dispatchControl, TypedControlError, } from "./dispatch";
|
|
2
2
|
export type { ControlInput, ControlSurface, ControlValue } from "./operations";
|