@securecoms/agent-bridge 0.29.0 → 0.30.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/README.md +119 -9
- package/dist/bin.d.ts +1 -1
- package/dist/bin.js +2486 -469
- package/dist/bridge-agent.d.ts +209 -2
- package/dist/config.d.ts +7 -0
- package/dist/consumer-grants.d.ts +19 -0
- package/dist/grants/binding.d.ts +58 -0
- package/dist/grants/effective.d.ts +47 -0
- package/dist/grants/manifest.d.ts +68 -0
- package/dist/grants/owner-turn.d.ts +52 -0
- package/dist/grants/persona-render.d.ts +30 -0
- package/dist/grants/pin-command.d.ts +31 -0
- package/dist/grants/pin.d.ts +35 -0
- package/dist/grants/room-search-cap.d.ts +15 -0
- package/dist/grants/voice-fence.d.ts +53 -0
- package/dist/http-server.d.ts +1 -0
- package/dist/index.js +1994 -171
- package/dist/memory/unified/item-book.d.ts +3 -0
- package/dist/memory/unified/migrate.d.ts +11 -0
- package/dist/memory/unified/read-book.d.ts +2 -1
- package/dist/memory/unified/worker-protocol.d.ts +4 -0
- package/dist/memory-taps.d.ts +1 -1
- package/dist/memory-worker.js +18 -3
- package/dist/service/runtime-config-dir.d.ts +15 -0
- package/dist/version.d.ts +1 -1
- package/dist/ws-server.d.ts +1 -1
- package/package.json +1 -1
package/dist/bridge-agent.d.ts
CHANGED
|
@@ -43,11 +43,16 @@ import { type ChatMessage } from "./voice/fast-prompt.js";
|
|
|
43
43
|
import { VOICE_CALL_START_MARKER } from "./voice/prompt-compiler.js";
|
|
44
44
|
import { type VaultListNode, type VaultReadExpectations } from "./vault.js";
|
|
45
45
|
import type { AgentActionNodeType, AgentActionNodeStatus, AgentActionNodeDetail } from "@agentvault/connect-core";
|
|
46
|
+
import { removeManagedLlmSource, writeManagedFiles, writeManifestPolicy } from "./service/runtime-config-dir.js";
|
|
47
|
+
import { bindRuntimeConfig } from "./grants/binding.js";
|
|
46
48
|
import type { RuntimeReplyReceipt } from "./reply-receipts.js";
|
|
47
49
|
export type AgentAudience = "owner_dm" | "team_room" | "partner_room" | "other_human_dm" | "agent_to_agent" | "unknown";
|
|
48
|
-
export type BridgeToolGrant =
|
|
50
|
+
export type BridgeToolGrant =
|
|
51
|
+
/** `source: "manifest"` (owner grants plan 4): issued from an owner-signed manifest; enforced only by a manifest_grants_v1 runtime. */
|
|
52
|
+
{
|
|
49
53
|
readonly tool: string;
|
|
50
54
|
readonly mode: "read";
|
|
55
|
+
readonly source?: "manifest";
|
|
51
56
|
} | {
|
|
52
57
|
readonly tool: string;
|
|
53
58
|
readonly mode: "side_effect";
|
|
@@ -99,6 +104,8 @@ export declare const ROOM_DEFAULT_READ_GRANTS: readonly BridgeToolGrant[];
|
|
|
99
104
|
* construction (daemon startup). Unset or exactly `on` keeps the grants;
|
|
100
105
|
* any other value (`off`, `0`, `false`, empty) sends `[]` on every turn.
|
|
101
106
|
*/
|
|
107
|
+
/** Audit L-2: the owner replay prune runs at most once per this interval. */
|
|
108
|
+
export declare const OWNER_REPLAY_PRUNE_INTERVAL_MS: number;
|
|
102
109
|
export declare function ownerDmDefaultGrantsEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
103
110
|
/**
|
|
104
111
|
* Kill switch for ROOM_DEFAULT_READ_GRANTS (plan OQ-3, RULED), read once at
|
|
@@ -107,6 +114,13 @@ export declare function ownerDmDefaultGrantsEnabled(env?: NodeJS.ProcessEnv): bo
|
|
|
107
114
|
* room turn. It never touches the owner DM.
|
|
108
115
|
*/
|
|
109
116
|
export declare function roomDefaultGrantsEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Owner-signed tool grants kill switch, owner DM (spec §7.4). Read once at startup; unset or exactly
|
|
119
|
+
* "on" keeps. Off gives the fallback (constants ∩ signed, plus current_time), never more.
|
|
120
|
+
*/
|
|
121
|
+
export declare function ownerDmManifestGrantsEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
122
|
+
/** Owner-signed tool grants kill switch, internal rooms (spec §7.4). Same rule as the owner-DM switch. */
|
|
123
|
+
export declare function roomManifestGrantsEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
110
124
|
export interface BridgeAuthorization {
|
|
111
125
|
readonly version: 1;
|
|
112
126
|
readonly audience: AgentAudience;
|
|
@@ -316,7 +330,16 @@ export declare const ROOM_VOICE_GUIDANCE_WITH_RESPONDER = "You are in a group vo
|
|
|
316
330
|
* `voiceDefaultResponder` (never a body-supplied claim).
|
|
317
331
|
*/
|
|
318
332
|
export declare function selectVoiceGuidance(isDm: boolean | undefined, voiceDefaultResponder: boolean | undefined): string;
|
|
333
|
+
/** Owner grants plan 4 Task 11: TEST SEAM for the refetch's writers and binder (call order, throws). Production omits it. */
|
|
334
|
+
export interface GrantWriters {
|
|
335
|
+
writeManifestPolicy?: typeof writeManifestPolicy;
|
|
336
|
+
writeManagedFiles?: typeof writeManagedFiles;
|
|
337
|
+
bindRuntimeConfig?: typeof bindRuntimeConfig;
|
|
338
|
+
removeManagedLlmSource?: typeof removeManagedLlmSource;
|
|
339
|
+
}
|
|
319
340
|
export interface BridgeAgentDeps {
|
|
341
|
+
/** Owner grants plan 4 Task 11: TEST SEAM only (see GrantWriters). */
|
|
342
|
+
grantWriters?: GrantWriters;
|
|
320
343
|
/**
|
|
321
344
|
* Unified memory part 1 (plan Task 8): TEST SEAM ONLY. Production (bin.ts) never passes it, so the compiled
|
|
322
345
|
* UNIFIED_MEMORY_PART1 decides (switch.arch.test.ts pins both).
|
|
@@ -506,6 +529,7 @@ export declare function redeliveryDelayMs(attempts: number): number;
|
|
|
506
529
|
* messages is dead-lettered. Fixed text — it never echoes the message.
|
|
507
530
|
*/
|
|
508
531
|
export declare const DEAD_LETTER_NOTICE = "I couldn't process a message. Please resend it.";
|
|
532
|
+
export declare const ROOM_SEARCH_CAP_NOTICE = "I've used today's web searches for this room. I can still help without searching. Searches are available again tomorrow (UTC).";
|
|
509
533
|
/** At most one {@link DEAD_LETTER_NOTICE} per channel per this window. */
|
|
510
534
|
export declare const DEAD_LETTER_NOTICE_INTERVAL_MS: number;
|
|
511
535
|
/**
|
|
@@ -758,6 +782,30 @@ export declare class BridgeAgent {
|
|
|
758
782
|
private readonly fetchImpl;
|
|
759
783
|
/** Round 5: home for the managed runtime-config directory (test seam). */
|
|
760
784
|
private readonly home;
|
|
785
|
+
private readonly grantWriters;
|
|
786
|
+
/** Owner grants (spec §7.5, OQ-2): the operator cap, read once; the same variable the runtime reads. 0 = no room search. */
|
|
787
|
+
private readonly roomSearchDailyCap;
|
|
788
|
+
/** Review M-3 (ERIC APPROVALS 3): the per-agent total across rooms, read once; the same variable the runtime reads. */
|
|
789
|
+
private readonly agentRoomSearchDailyCap;
|
|
790
|
+
/** `${day}\n${channel}` keys already logged reached today (in memory; the store holds the durable flag). */
|
|
791
|
+
private readonly roomCapLogged;
|
|
792
|
+
/** Rooms whose K-14 send is in flight: a second frame posts nothing more. */
|
|
793
|
+
private readonly roomCapNoticePending;
|
|
794
|
+
/** Held entries whose staged copy lost web_search to the backstop; applied again at release. */
|
|
795
|
+
private readonly backstopStripped;
|
|
796
|
+
/**
|
|
797
|
+
* Owner grants plan 4 Task 11 (P-4, P-6): what the managed directory holds under the current manifest.
|
|
798
|
+
* Manifest grants require state "bound" at the applied counter (Task 13). null at startup, while a
|
|
799
|
+
* refetch narrows it, and after any throw (the fallback).
|
|
800
|
+
*/
|
|
801
|
+
private manifestBinding;
|
|
802
|
+
/** skills.json tools.deny from the latest fetch, manifest or not (spec §5.2 `disabled`). */
|
|
803
|
+
private payloadToolDeny;
|
|
804
|
+
/** Spec §7.7 (OQ-5): the latest fetch's binding outcome, reported in tool_grant_status (Task 15). */
|
|
805
|
+
private configBindingMismatches;
|
|
806
|
+
private targetMismatches;
|
|
807
|
+
/** P-5 (Task 14): the legacy fact decisions the latest bound fetch may apply (assigns verified against the signed set). */
|
|
808
|
+
private boundLegacyDecisions;
|
|
761
809
|
private readonly joinState;
|
|
762
810
|
/**
|
|
763
811
|
* Phase 2: lazy channel-metadata cache (channel_id → { is_dm, name, at }) used
|
|
@@ -1057,11 +1105,27 @@ export declare class BridgeAgent {
|
|
|
1057
1105
|
private readonly ownerDmDefaultGrants;
|
|
1058
1106
|
/** Read once at startup; see roomDefaultGrantsEnabled. */
|
|
1059
1107
|
private readonly roomDefaultGrants;
|
|
1108
|
+
/** Owner grants (spec §7.4): the two manifest switches, read once at construction. */
|
|
1109
|
+
private readonly ownerDmManifestGrants;
|
|
1110
|
+
private readonly roomManifestGrants;
|
|
1060
1111
|
/**
|
|
1061
1112
|
* Audit M-B4: DM channels whose roster was epoch-fresh at THIS ingest
|
|
1062
1113
|
* cycle's refresh (refreshRostersForCycle). Cleared at each cycle's start.
|
|
1063
1114
|
*/
|
|
1064
1115
|
private readonly ownerDmCycleFresh;
|
|
1116
|
+
private toolGrantManifest;
|
|
1117
|
+
private toolGrantCounter;
|
|
1118
|
+
private manifestState;
|
|
1119
|
+
/** Failed owner-turn checks since the last successful runtime-config report (§7.7). */
|
|
1120
|
+
private ownerVerifyFailures;
|
|
1121
|
+
/** Verified owner turns of this ingest cycle, recorded in owner_replay when staged (P-3). */
|
|
1122
|
+
private readonly ownerReplayPending;
|
|
1123
|
+
/** D-9: ids of owner turns that failed verification (never `replay`, audit E-3), id -> channel. Persisted too. */
|
|
1124
|
+
private readonly ownerVerifyFailedIds;
|
|
1125
|
+
private serverOwnerMismatchLogged;
|
|
1126
|
+
/** Audit L-2: the replay prune runs at most once per interval, on a monotonic clock. */
|
|
1127
|
+
private monoNow;
|
|
1128
|
+
private lastOwnerReplayPruneAt;
|
|
1065
1129
|
/**
|
|
1066
1130
|
* Audit M-B1: room-granted turns, keyed by the inbound message id, with the
|
|
1067
1131
|
* channel, MLS group and epoch the room was classified at (review I-1: an
|
|
@@ -1400,6 +1464,20 @@ export declare class BridgeAgent {
|
|
|
1400
1464
|
*/
|
|
1401
1465
|
refetchRuntimeConfig(): Promise<void>;
|
|
1402
1466
|
private refetchRuntimeConfigOnce;
|
|
1467
|
+
/**
|
|
1468
|
+
* Plan 4 Task 11: the refetch under a manifest in force. Returns false when the binding failed (H-4),
|
|
1469
|
+
* after the memory was applied; the caller then writes nothing else. Throws only from a file write, with
|
|
1470
|
+
* the binding left null.
|
|
1471
|
+
*/
|
|
1472
|
+
private applyUnderManifest;
|
|
1473
|
+
/** Spec §7.6 (plan 4 Task 15): content-free. One line per mismatched field, one per dropped target. */
|
|
1474
|
+
private logConfigBinding;
|
|
1475
|
+
/** H-4: the binding could not be computed. The memory still applies, with the signed mode; nothing else is written. */
|
|
1476
|
+
private bindFailed;
|
|
1477
|
+
/** No manifest in force: a manifest-policy.json left by an earlier one is replaced by an empty tool list. */
|
|
1478
|
+
private overwriteStalePolicy;
|
|
1479
|
+
/** The report half of refetchRuntimeConfigOnce (split out for the plan 4 Task 11 bind_failed path). */
|
|
1480
|
+
private postRuntimeConfigReport;
|
|
1403
1481
|
/**
|
|
1404
1482
|
* Enforce the inbound-buffer cap with a DROP-OLDEST policy.
|
|
1405
1483
|
*
|
|
@@ -2079,6 +2157,11 @@ export declare class BridgeAgent {
|
|
|
2079
2157
|
* stale cache is refreshed once; any failure remains a fail-closed denial.
|
|
2080
2158
|
*/
|
|
2081
2159
|
private mayReadOpenClawMemory;
|
|
2160
|
+
/**
|
|
2161
|
+
* Decision D-9 (audit H-3): a turn that failed owner verification gets only
|
|
2162
|
+
* its own text, never the prior-turn history snapshot, for every provider.
|
|
2163
|
+
*/
|
|
2164
|
+
private mayReadHistoryForTurn;
|
|
2082
2165
|
/** An inbound turn may receive OpenClaw memory only from an active owner DM. */
|
|
2083
2166
|
private mayReadOpenClawMemoryForTurn;
|
|
2084
2167
|
/**
|
|
@@ -2087,6 +2170,49 @@ export declare class BridgeAgent {
|
|
|
2087
2170
|
* never falls back to the runtime's retired plaintext JSON files.
|
|
2088
2171
|
*/
|
|
2089
2172
|
private memoryForTurn;
|
|
2173
|
+
/**
|
|
2174
|
+
* Owner grants plan 4 Task 16 (T-30, audit r2 H-1): the voice fence is on whenever a pin is loaded, on EVERY runtime
|
|
2175
|
+
* turn (manifest, fallback, greeting, relayed, constants-only alike). It never depends on a turn's grants.
|
|
2176
|
+
*/
|
|
2177
|
+
private voiceFenceOn;
|
|
2178
|
+
/** The keyed and legacy fast-reply ids of every peer row of the conversation (audit r2 M-1; never the 50-row window). */
|
|
2179
|
+
private fenceContext;
|
|
2180
|
+
/**
|
|
2181
|
+
* Drop agent lines classified fast_path, untrusted or unknown from a turn's memory (every turn of a pinned agent).
|
|
2182
|
+
* `strict` (review H-3, a turn that holds a manifest grant): relay-class peer lines go too (sender not the pinned
|
|
2183
|
+
* owner, or voice modality). Otherwise peer lines are never dropped.
|
|
2184
|
+
*/
|
|
2185
|
+
private fenceMemory;
|
|
2186
|
+
/**
|
|
2187
|
+
* Review H-3: true when a delivered frame holds a line a manifest turn would exclude (a relay-class peer line; agent
|
|
2188
|
+
* lines in a frame are already fenced). Such a turn's reply is recorded "untrusted".
|
|
2189
|
+
*/
|
|
2190
|
+
private frameHoldsRelayClass;
|
|
2191
|
+
/**
|
|
2192
|
+
* Review H-3 attribution: message ids of turns delivered on a pinned agent whose frame held no relay-class line.
|
|
2193
|
+
* A reply is recorded "reply" only when its in-reply-to is here; anything else (tainted, unknown after a restart,
|
|
2194
|
+
* no in-reply-to) is "untrusted". Bounded; the oldest are forgotten first (forgetting only makes a reply untrusted).
|
|
2195
|
+
*/
|
|
2196
|
+
private readonly cleanTurns;
|
|
2197
|
+
private noteDeliveredFrame;
|
|
2198
|
+
private readonly taintedTurns;
|
|
2199
|
+
/**
|
|
2200
|
+
* Review R2-H2: on a pinned agent a 7a note or a unified memory_note is written only from a turn delivered with a clean
|
|
2201
|
+
* frame in the owner DM (cleanTurns, not taintedTurns), so a tainted fallback turn cannot plant a note that a later
|
|
2202
|
+
* manifest turn reads. Taint is noted at delivery, before any note frame for the turn can arrive.
|
|
2203
|
+
*/
|
|
2204
|
+
private noteTurnClean;
|
|
2205
|
+
/**
|
|
2206
|
+
* Review R2-H1: the turn itself is relay-class (its frame memory is prior-turn only, so its own sender is never in it):
|
|
2207
|
+
* a sender that is not the pinned owner, a relay speaker claim, or a voice turn.
|
|
2208
|
+
*/
|
|
2209
|
+
private turnIsRelayClass;
|
|
2210
|
+
/**
|
|
2211
|
+
* R2-M1 ruling: the channel where the H-3 taint and the `untrusted` exclusion apply, on a pinned agent: the signed
|
|
2212
|
+
* owner_dm_channel_id of the manifest in force. Before any manifest is held there is no signed DM, so every channel
|
|
2213
|
+
* not known to be a room counts (fail closed: a reply recorded there before the first manifest must not reach it).
|
|
2214
|
+
*/
|
|
2215
|
+
private taintScope;
|
|
2090
2216
|
/**
|
|
2091
2217
|
* Spec §11.2 (OQ-L), §6.5: apply one parsed `payload.memory`. An unreadable
|
|
2092
2218
|
* value turns notes off and deletes nothing. A readable one goes through
|
|
@@ -2630,6 +2756,41 @@ export declare class BridgeAgent {
|
|
|
2630
2756
|
* cycle. Fail-soft inside refreshChannelRoster (never blocks ingest).
|
|
2631
2757
|
*/
|
|
2632
2758
|
private refreshRostersForCycle;
|
|
2759
|
+
/**
|
|
2760
|
+
* Owner-signed tool grants, step 1 (spec §7.2; decisions D-1, D-2, D-4, D-8,
|
|
2761
|
+
* D-9; audits H-1, M-2, M-4, E-1..E-3). The verdict for one delivered turn.
|
|
2762
|
+
*
|
|
2763
|
+
* `unchecked` when no pin is loaded or the sender is not the pinned owner.
|
|
2764
|
+
* Otherwise, in order, the first failure wins: the identity signature over the
|
|
2765
|
+
* raw payload bytes with the pinned key; the verified bytes must be the
|
|
2766
|
+
* decrypted envelope; in a DM only (D-1), the signed DM channel and the MLS
|
|
2767
|
+
* leaf set; then the replay set and closed epochs, keyed by the agent's OWN
|
|
2768
|
+
* held group (never the backend's row label, M-2). NEVER throws (M-4): any
|
|
2769
|
+
* exception is `failed verify_error`, and the row is acked like any other turn.
|
|
2770
|
+
*/
|
|
2771
|
+
private verifyOwnerTurn;
|
|
2772
|
+
/** Log, count and (except a replay, audit E-3) record one failed owner-turn check. Never throws (audit E-2). */
|
|
2773
|
+
private ownerTurnFailed;
|
|
2774
|
+
/** Review M-A: a verified original of this id was staged and is still pending, or was recorded in the replay set. */
|
|
2775
|
+
private isVerifiedOwnerOriginal;
|
|
2776
|
+
/** Review M-A: a verified original of this id was staged and acked (it is in the replay set, no longer pending). */
|
|
2777
|
+
private isAckedOwnerOriginal;
|
|
2778
|
+
/** D-9: memory first, then the store (a restart before the reply). Unpinned: never. A store read that throws withholds (fail closed). */
|
|
2779
|
+
private isOwnerVerifyFailed;
|
|
2780
|
+
/**
|
|
2781
|
+
* Decision D-2, audit L-2: prune the owner replay set at most once per
|
|
2782
|
+
* OWNER_REPLAY_PRUNE_INTERVAL_MS, keeping each channel's current (group,
|
|
2783
|
+
* epoch). A channel whose held position is unknown is left out (not pruned).
|
|
2784
|
+
*/
|
|
2785
|
+
private maybePruneOwnerReplay;
|
|
2786
|
+
/** start(): drop other keys' manifest state, re-verify the stored one for the pinned key, and prune. */
|
|
2787
|
+
private loadToolGrantState;
|
|
2788
|
+
/**
|
|
2789
|
+
* Spec §7.1: verify and record a served manifest. Never writes a file and
|
|
2790
|
+
* never changes a grant in step 1. A save that throws keeps the old state.
|
|
2791
|
+
*/
|
|
2792
|
+
private applyToolGrantManifest;
|
|
2793
|
+
private logManifest;
|
|
2633
2794
|
/** Classify one inbound turn at the agent's CURRENT epoch for its channel. */
|
|
2634
2795
|
private authorizeTurn;
|
|
2635
2796
|
/**
|
|
@@ -2693,6 +2854,8 @@ export declare class BridgeAgent {
|
|
|
2693
2854
|
* enforcement is attached
|
|
2694
2855
|
* memory_write the turn carries memory_write (Markdown memory
|
|
2695
2856
|
* 7a, spec §8.3): a boolean, never content
|
|
2857
|
+
* grant_source where the grants came from: constant | none in
|
|
2858
|
+
* step 1 (owner-signed tool grants §7.6)
|
|
2696
2859
|
*/
|
|
2697
2860
|
private logAuthzDecision;
|
|
2698
2861
|
/**
|
|
@@ -2860,7 +3023,19 @@ export declare class BridgeAgent {
|
|
|
2860
3023
|
/** Notify-only SSE signal: fired after a buffer push. Listener pulls via takeBuffered. */
|
|
2861
3024
|
subscribe(listener: () => void): () => void;
|
|
2862
3025
|
/** Synchronous splice of buffered messages (all, or one channel). Shared by drain + SSE. */
|
|
3026
|
+
/** Review H-1: every buffer exit narrows manifest grants again to the state at delivery. */
|
|
2863
3027
|
takeBuffered(channelId?: string): BridgeMessage[];
|
|
3028
|
+
takeDeliverable(busyChannels: ReadonlySet<string>): BridgeMessage[];
|
|
3029
|
+
/** Every buffer exit: re-narrow manifest grants (review H-1), then note the frame's attribution class (review H-3). */
|
|
3030
|
+
private delivering;
|
|
3031
|
+
/**
|
|
3032
|
+
* Review H-1 (kill switches reach staged and restored turns): a grant marked source "manifest" survives delivery
|
|
3033
|
+
* only while its audience's manifest switch is on, the binding is bound at the applied counter, and the current
|
|
3034
|
+
* manifest still signs the tool. Otherwise it becomes the fallback: kept unmarked if it is a constant of the
|
|
3035
|
+
* audience that is still signed, else dropped. Only narrows; an unchanged message is returned by reference.
|
|
3036
|
+
*/
|
|
3037
|
+
private renarrowManifestGrants;
|
|
3038
|
+
private takeBufferedRaw;
|
|
2864
3039
|
/**
|
|
2865
3040
|
* Phase 3 F2: per-channel ordered delivery for the /v1/ws runtime consumer.
|
|
2866
3041
|
* Splices out, oldest first, at most ONE buffered message per channel that
|
|
@@ -2870,7 +3045,7 @@ export declare class BridgeAgent {
|
|
|
2870
3045
|
* working on — which it used to refuse with a "busy" reply and ack — and a
|
|
2871
3046
|
* backlog replays one message per channel at a time after a restart.
|
|
2872
3047
|
*/
|
|
2873
|
-
|
|
3048
|
+
private takeDeliverableRaw;
|
|
2874
3049
|
private hasReplyIntent;
|
|
2875
3050
|
/**
|
|
2876
3051
|
* SEC-06 #18: answer a redelivered message from its reply intent. Counts as
|
|
@@ -2911,6 +3086,20 @@ export declare class BridgeAgent {
|
|
|
2911
3086
|
* at most once per channel per hour. Logs carry counts only.
|
|
2912
3087
|
*/
|
|
2913
3088
|
private deadLetter;
|
|
3089
|
+
/** Spec §7.5: the room is capped today: cap 0, reached (by the runtime or the backstop), or at the cap. Fails closed. */
|
|
3090
|
+
private roomSearchCapped;
|
|
3091
|
+
/** Spec §7.5 (T-14c, M-4): the runtime reports an executed-call cap for a room. Never throws. */
|
|
3092
|
+
noteRoomCapReached(channelId: string): void;
|
|
3093
|
+
/** K-14, once per room per UTC day; the flag is persisted only after the send resolves. Called only from noteRoomCapReached. */
|
|
3094
|
+
private noticeRoomSearchCap;
|
|
3095
|
+
private logRoomCap;
|
|
3096
|
+
/**
|
|
3097
|
+
* Spec §7.5 (T-14b, audit r1 H-3): the silent bridge backstop. Counts a team_room turn that actually goes out
|
|
3098
|
+
* to the runtime with web_search, once per message id (callers run it after their runtimePendingIds early
|
|
3099
|
+
* return). Past the cap, and on a store failure (fail closed), the entry loses web_search. Never posts K-14.
|
|
3100
|
+
*/
|
|
3101
|
+
private applyRoomSearchBackstop;
|
|
3102
|
+
private withoutWebSearch;
|
|
2914
3103
|
private noticeDeadLetter;
|
|
2915
3104
|
/** Poke consumers once the earliest redelivery backoff ends. */
|
|
2916
3105
|
private armRedeliveryWake;
|
|
@@ -3056,6 +3245,24 @@ export declare class BridgeAgent {
|
|
|
3056
3245
|
/** Forget `token` when its socket closes; a newer consumer's token is kept. */
|
|
3057
3246
|
clearPerToolConsumer(token: object): void;
|
|
3058
3247
|
perToolConsumerAttached(): boolean;
|
|
3248
|
+
/**
|
|
3249
|
+
* Owner grants (spec §7.9, plan 4 Task 5): the attached per-tool runtime socket whose hello
|
|
3250
|
+
* declared manifest_grants_v1, or null. A manifest grant is issued only while one is attached
|
|
3251
|
+
* (Task 13); every other socket receives manifest grants narrowed to the constants.
|
|
3252
|
+
* Newest wins, like perToolConsumer.
|
|
3253
|
+
*/
|
|
3254
|
+
private manifestConsumer;
|
|
3255
|
+
/** OQ-5: the latest hello's class; "missing" until any hello. Reported in tool_grant_status (Task 15). */
|
|
3256
|
+
private lastConsumerCapability;
|
|
3257
|
+
noteManifestConsumer(token: object): void;
|
|
3258
|
+
clearManifestConsumer(token: object): void;
|
|
3259
|
+
manifestConsumerAttached(): boolean;
|
|
3260
|
+
noteConsumerCapability(state: "ok" | "missing" | "harness_consumer"): void;
|
|
3261
|
+
/**
|
|
3262
|
+
* Harness re-rule (2026-10-12, audit r2 H-3): true exactly when this agent has a pin loaded and a good
|
|
3263
|
+
* manifest. A harness consumer then receives [] in every audience (consumer-grants.ts withHarnessGrants).
|
|
3264
|
+
*/
|
|
3265
|
+
harnessGrantsWithheld(): boolean;
|
|
3059
3266
|
health(): {
|
|
3060
3267
|
status: "ok";
|
|
3061
3268
|
identity_id: string;
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VoiceConfig } from "./voice/persona.js";
|
|
2
|
+
import { type OwnerGrantPinResult } from "./grants/pin.js";
|
|
2
3
|
import { type FastPathMode } from "./voice/defer-intent.js";
|
|
3
4
|
export interface BridgeConfig {
|
|
4
5
|
apiKey: string;
|
|
@@ -47,6 +48,12 @@ export interface BridgeConfig {
|
|
|
47
48
|
modelSource: "download" | "import_only";
|
|
48
49
|
/** Spec section 13 (R-U20): credential `memory.enabled`. Absent or true is on; any other value is off (plan I-9). Local only: the backend cannot set it. */
|
|
49
50
|
memoryEnabled?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Owner-signed tool grants (spec §6.1, §6.5): the grant pin, loaded once here
|
|
53
|
+
* from the credential's `owner_signing_key` and `owner-signing-key.json` beside
|
|
54
|
+
* the credential, never from the backend. Absent means `no_pin`.
|
|
55
|
+
*/
|
|
56
|
+
ownerGrantPin?: OwnerGrantPinResult;
|
|
50
57
|
}
|
|
51
58
|
export declare const REQUIRED: readonly ["api_key", "identity_id", "device_id", "signing_private_key", "enclave_id", "api_base"];
|
|
52
59
|
export declare function loadConfig(opts: {
|
|
@@ -21,3 +21,22 @@ export declare const PER_TOOL_GRANTS_FEATURE = "per_tool_grants";
|
|
|
21
21
|
* no non-per-tool consumer ever receives (Markdown memory 7a, review m-3).
|
|
22
22
|
*/
|
|
23
23
|
export declare function withConsumerGrants(m: BridgeMessage, perToolConsumer: boolean): BridgeMessage;
|
|
24
|
+
/** The /v1/ws hello feature of a runtime that enforces manifest grants (runtime 0.13.0+). Pinned to the runtime's by capability-parity.test.ts. */
|
|
25
|
+
export declare const MANIFEST_GRANTS_FEATURE = "manifest_grants_v1";
|
|
26
|
+
export declare const CONSTANT_TOOL_NAMES: Readonly<Record<"owner_dm" | "team_room", readonly string[]>>;
|
|
27
|
+
/**
|
|
28
|
+
* Spec §7.9: a consumer that did not declare manifest_grants_v1 (runtime 0.12.2, a harness,
|
|
29
|
+
* every HTTP path) never receives a manifest grant. Its grants are narrowed to constants(a):
|
|
30
|
+
* a manifest-marked tool that is also a constant is kept unmarked; any other is dropped.
|
|
31
|
+
* Never mutates `m`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function withManifestCapability(m: BridgeMessage, manifestConsumer: boolean): BridgeMessage;
|
|
34
|
+
/**
|
|
35
|
+
* Harness re-rule (2026-10-12, supersedes P4 OQ-8's "constants ∩ signed"), audit r2 H-3. A harness turns
|
|
36
|
+
* ANY non-empty tool_grants into the owner's whole configured toolset (header of this file), so no
|
|
37
|
+
* non-empty list can stay within what the owner signed. On a pinned agent with a good manifest
|
|
38
|
+
* (`withheld === true`) a harness receives [] in EVERY audience. `withheld === false` (no pin, or no good
|
|
39
|
+
* manifest): `m` unchanged, by reference (today's behaviour). An issued [] is returned by reference.
|
|
40
|
+
* Never mutates `m`. Callers: the three harness delivery paths, after withConsumerGrants.
|
|
41
|
+
*/
|
|
42
|
+
export declare function withHarnessGrants(m: BridgeMessage, withheld: boolean): BridgeMessage;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type ToolGrantManifest } from "./manifest.js";
|
|
2
|
+
import type { ManifestPolicyDoc } from "../service/runtime-config-dir.js";
|
|
3
|
+
export declare const CONFIG_BINDING_FIELDS: readonly ["persona", "memory", "search", "tools_allow", "flags", "llm", "files", "legacy_assign"];
|
|
4
|
+
export type ConfigBindingField = (typeof CONFIG_BINDING_FIELDS)[number];
|
|
5
|
+
export interface BindPayload {
|
|
6
|
+
readonly version?: number;
|
|
7
|
+
readonly files?: Record<string, string>;
|
|
8
|
+
readonly skills_json?: Record<string, unknown>;
|
|
9
|
+
readonly memory?: unknown;
|
|
10
|
+
readonly persona?: unknown;
|
|
11
|
+
/** Raw, unfiltered saved tokens (runtime_config_service.py memory_prunes). Untrusted. */
|
|
12
|
+
readonly memory_prunes?: unknown;
|
|
13
|
+
readonly legacy_memory_fact_decisions?: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** The search block last written under a good search match for this pinned key (Task 11's sealed record); undefined = never. */
|
|
16
|
+
export type AppliedSearch = {
|
|
17
|
+
readonly provider: "brave" | "tavily";
|
|
18
|
+
readonly keyFile?: string;
|
|
19
|
+
} | null;
|
|
20
|
+
export interface BindPrior {
|
|
21
|
+
readonly search: AppliedSearch | undefined;
|
|
22
|
+
}
|
|
23
|
+
export interface BindResult {
|
|
24
|
+
readonly mismatches: readonly ConfigBindingField[];
|
|
25
|
+
readonly targetMismatches: {
|
|
26
|
+
readonly endpoint: number;
|
|
27
|
+
readonly database: number;
|
|
28
|
+
};
|
|
29
|
+
readonly files: Record<string, string>;
|
|
30
|
+
readonly memory: unknown;
|
|
31
|
+
readonly signedTargets: {
|
|
32
|
+
readonly endpoints: number;
|
|
33
|
+
readonly databases: number;
|
|
34
|
+
};
|
|
35
|
+
readonly policy: ManifestPolicyDoc;
|
|
36
|
+
/** Set only when `search` matched: the block written, to be saved as the new last good one after the write succeeds. */
|
|
37
|
+
readonly appliedSearch: AppliedSearch | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* P-5 (Task 14): the decisions to hand applyLegacyMemoryFactDecisions. On a legacy_assign match: the
|
|
40
|
+
* deletes plus each assign whose token, rebuilt from its own fields, is in the verified saved set. On a
|
|
41
|
+
* mismatch: the deletes only.
|
|
42
|
+
*/
|
|
43
|
+
readonly legacyDecisions: unknown[];
|
|
44
|
+
}
|
|
45
|
+
/** P4 OQ-7: hex SHA-256 of JCS(sorted, deduplicated memory_prunes entries that begin "legacy-fact-assign:"). Non-strings are ignored. */
|
|
46
|
+
export declare function legacyAssignSha256(prunes: readonly unknown[]): string;
|
|
47
|
+
/** The backend's assign token (runtime_config_service.py _legacy_memory_fact_decision_token), rebuilt from the fields. */
|
|
48
|
+
export declare function legacyAssignToken(d: {
|
|
49
|
+
source_id: string;
|
|
50
|
+
fact_hash: string;
|
|
51
|
+
channel_id: string;
|
|
52
|
+
}): string;
|
|
53
|
+
export declare function bindRuntimeConfig(manifest: ToolGrantManifest, payload: BindPayload, prior: BindPrior,
|
|
54
|
+
/** Review H-1: the two manifest kill switches; an audience switched off contributes no tool to the policy file. */
|
|
55
|
+
switches?: {
|
|
56
|
+
readonly ownerDm: boolean;
|
|
57
|
+
readonly room: boolean;
|
|
58
|
+
}): BindResult;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The effective grant (owner-signed tool grants, spec §5.2, §5.4, §7.4; plan 4 Task 6).
|
|
3
|
+
* The one formula, pure, so every rule has its own test and the issuing code decides nothing.
|
|
4
|
+
*
|
|
5
|
+
* signed(a) = manifest.grants[a] ∩ TOOL_GRANT_CODE_CEILING[a]
|
|
6
|
+
* effective(a) = signed(a) ∖ disabled, minus http_request with no signed endpoint, minus sql_query
|
|
7
|
+
* with no signed database, minus team_room web_search when capped, ∪ {current_time}
|
|
8
|
+
* (only when every precondition holds: `eligible` and the manifest switch on)
|
|
9
|
+
* fallback(a) = (constants(a) ∩ signed(a)) ∪ {current_time} when a precondition fails
|
|
10
|
+
* = constants(a) by reference with no good manifest
|
|
11
|
+
* [] when today's predicate gives []
|
|
12
|
+
*/
|
|
13
|
+
import { type ToolGrantManifest } from "./manifest.js";
|
|
14
|
+
/** Spec §5.4 code ceiling. The same frozen lists Plan 1 uses to drop unknown entries. */
|
|
15
|
+
export declare const TOOL_GRANT_CODE_CEILING: {
|
|
16
|
+
readonly owner_dm: readonly string[];
|
|
17
|
+
readonly team_room: readonly string[];
|
|
18
|
+
};
|
|
19
|
+
export type GrantAudience = "owner_dm" | "team_room";
|
|
20
|
+
export type GrantSource = "constant" | "manifest" | "fallback" | "none";
|
|
21
|
+
export interface ReadGrant {
|
|
22
|
+
readonly tool: string;
|
|
23
|
+
readonly mode: "read";
|
|
24
|
+
readonly source?: "manifest";
|
|
25
|
+
}
|
|
26
|
+
export interface EffectiveInput {
|
|
27
|
+
readonly audience: GrantAudience;
|
|
28
|
+
/** Today's list from the existing predicate: OWNER_DM_DEFAULT_READ_GRANTS, ROOM_DEFAULT_READ_GRANTS, or a frozen []. */
|
|
29
|
+
readonly base: readonly ReadGrant[];
|
|
30
|
+
/** The last good manifest, or null (no pin, or none verified). */
|
|
31
|
+
readonly manifest: ToolGrantManifest | null;
|
|
32
|
+
/** Every manifest-only precondition held (Task 13 computes it). */
|
|
33
|
+
readonly eligible: boolean;
|
|
34
|
+
readonly manifestSwitchOn: boolean;
|
|
35
|
+
readonly disabled: ReadonlySet<string>;
|
|
36
|
+
readonly signedTargets: {
|
|
37
|
+
readonly endpoints: number;
|
|
38
|
+
readonly databases: number;
|
|
39
|
+
};
|
|
40
|
+
readonly roomSearchCapped: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface EffectiveGrant {
|
|
43
|
+
readonly grants: readonly ReadGrant[];
|
|
44
|
+
readonly source: GrantSource;
|
|
45
|
+
readonly withheldBySearchCap: boolean;
|
|
46
|
+
}
|
|
47
|
+
export declare function effectiveToolGrants(i: EffectiveInput): EffectiveGrant;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type OwnerGrantPin } from "./pin.js";
|
|
2
|
+
export declare const TOOL_GRANTS_DOMAIN = "SECURECOMS-TOOL-GRANTS-V1:";
|
|
3
|
+
export declare const MANIFEST_STATES: readonly ["ok", "unchanged", "no_pin", "no_manifest", "malformed", "unsupported_algo", "bad_signature", "wrong_agent", "wrong_owner", "rollback", "unknown_entry", "kept_last_good"];
|
|
4
|
+
export type ManifestState = (typeof MANIFEST_STATES)[number];
|
|
5
|
+
/** Known names only for dropping unknown entries (§7.1 step 6). These are the §5.4 code-ceiling names; step 4 uses them as the ceiling. */
|
|
6
|
+
export declare const MANIFEST_KNOWN_TOOLS: {
|
|
7
|
+
readonly owner_dm: readonly string[];
|
|
8
|
+
readonly team_room: readonly string[];
|
|
9
|
+
};
|
|
10
|
+
export interface ToolGrantManifest {
|
|
11
|
+
readonly type: "securecoms.tool-grants";
|
|
12
|
+
readonly v: 1;
|
|
13
|
+
readonly agent_identity_id: string;
|
|
14
|
+
readonly owner_identity_id: string;
|
|
15
|
+
readonly owner_dm_channel_id?: string;
|
|
16
|
+
readonly owner_dm_relay_identity_id?: string;
|
|
17
|
+
readonly counter: number;
|
|
18
|
+
readonly grants: {
|
|
19
|
+
readonly owner_dm?: readonly string[];
|
|
20
|
+
readonly team_room?: readonly string[];
|
|
21
|
+
};
|
|
22
|
+
/** Plan 4 Task 7 (spec §8.1): signed targets. Absent in the wrapper = {}. A `headersFile: ""` is dropped (L-4). */
|
|
23
|
+
readonly endpoints: Readonly<Record<string, SignedEndpoint>>;
|
|
24
|
+
readonly databases: Readonly<Record<string, SignedDatabase>>;
|
|
25
|
+
/** Plan 4 Task 7 (spec §8.1, §7.10): the signed values the config binding compares. Required. */
|
|
26
|
+
readonly config: SignedConfig;
|
|
27
|
+
}
|
|
28
|
+
export interface SignedEndpoint {
|
|
29
|
+
readonly baseUrl: string;
|
|
30
|
+
readonly headersFile?: string;
|
|
31
|
+
}
|
|
32
|
+
export type SignedDatabase = {
|
|
33
|
+
readonly sqlite: string;
|
|
34
|
+
} | {
|
|
35
|
+
readonly postgresUrlFile: string;
|
|
36
|
+
};
|
|
37
|
+
export interface SignedConfig {
|
|
38
|
+
readonly persona_sha256: string;
|
|
39
|
+
readonly llm?: {
|
|
40
|
+
readonly provider: string;
|
|
41
|
+
readonly model: string;
|
|
42
|
+
};
|
|
43
|
+
readonly search?: {
|
|
44
|
+
readonly provider: "brave" | "tavily";
|
|
45
|
+
};
|
|
46
|
+
readonly tools_allow?: readonly string[];
|
|
47
|
+
readonly flags: readonly string[];
|
|
48
|
+
readonly memory: {
|
|
49
|
+
readonly mode: "markdown" | "semantic" | "off";
|
|
50
|
+
readonly recall_days?: 30 | 90 | 365;
|
|
51
|
+
};
|
|
52
|
+
readonly legacy_assign_sha256: string;
|
|
53
|
+
}
|
|
54
|
+
export type ManifestVerdict = {
|
|
55
|
+
state: "ok";
|
|
56
|
+
manifest: ToolGrantManifest;
|
|
57
|
+
droppedUnknown: boolean;
|
|
58
|
+
wrapper: unknown;
|
|
59
|
+
} | {
|
|
60
|
+
state: "unchanged" | "malformed" | "unsupported_algo" | "bad_signature" | "wrong_agent" | "wrong_owner" | "rollback";
|
|
61
|
+
};
|
|
62
|
+
/** utf8(TOOL_GRANTS_DOMAIN) || canonicalize(manifest). The domain keeps an envelope signature from ever verifying as a manifest. */
|
|
63
|
+
export declare function manifestSignedBytes(manifest: unknown): Uint8Array;
|
|
64
|
+
export declare function verifyToolGrantManifest(raw: unknown, ctx: {
|
|
65
|
+
pin: OwnerGrantPin;
|
|
66
|
+
agentIdentityId: string;
|
|
67
|
+
storedCounter: number | null;
|
|
68
|
+
}): ManifestVerdict;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { AgentVaultEnvelope } from "@agentvault/connect-core";
|
|
2
|
+
import { type OwnerGrantPin } from "./pin.js";
|
|
3
|
+
export declare const OWNER_VERIFY_STATES: readonly ["ok", "bad_signature", "malformed", "unknown_algo", "no_signature", "not_owner_dm_leaves", "wrong_dm_channel", "replay", "verify_error"];
|
|
4
|
+
export type OwnerVerifyFailure = Exclude<(typeof OWNER_VERIFY_STATES)[number], "ok">;
|
|
5
|
+
export type OwnerTurnVerdict = {
|
|
6
|
+
readonly kind: "unchecked";
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "verified";
|
|
9
|
+
readonly replay: {
|
|
10
|
+
readonly channelId: string;
|
|
11
|
+
readonly groupId: string;
|
|
12
|
+
readonly epoch: number;
|
|
13
|
+
};
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: "constants_only";
|
|
16
|
+
readonly replay: {
|
|
17
|
+
readonly channelId: string;
|
|
18
|
+
readonly groupId: string;
|
|
19
|
+
readonly epoch: number;
|
|
20
|
+
};
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: "failed";
|
|
23
|
+
readonly reason: OwnerVerifyFailure;
|
|
24
|
+
};
|
|
25
|
+
export type OwnerSignatureResult = {
|
|
26
|
+
readonly state: "ok";
|
|
27
|
+
readonly envelope: AgentVaultEnvelope;
|
|
28
|
+
} | {
|
|
29
|
+
readonly state: "no_signature" | "bad_signature" | "malformed" | "unknown_algo";
|
|
30
|
+
};
|
|
31
|
+
export declare function verifyOwnerSignature(entry: {
|
|
32
|
+
readonly payloadHex?: string;
|
|
33
|
+
readonly identitySignature?: string;
|
|
34
|
+
}, pin: OwnerGrantPin): OwnerSignatureResult;
|
|
35
|
+
export type OwnerDmLeafClass = "ok" | "unsigned_relay" | "foreign";
|
|
36
|
+
/**
|
|
37
|
+
* §7.2 check 2, decision D-4. Any number of owner leaves passes (multi-device:
|
|
38
|
+
* leaf credentials encode identity, not device). Fails closed on an empty tree,
|
|
39
|
+
* a non-basic leaf, or no owner leaf. A signed relay is admitted by
|
|
40
|
+
* `relayIdentityId` alone; the roster flag only chooses between
|
|
41
|
+
* `unsigned_relay` (today's constants) and `foreign` (zero), so it can never
|
|
42
|
+
* widen past today's constants.
|
|
43
|
+
*/
|
|
44
|
+
export declare function classifyOwnerDmLeaves(leaves: readonly {
|
|
45
|
+
basic: boolean;
|
|
46
|
+
identity: string | null;
|
|
47
|
+
}[], allowed: {
|
|
48
|
+
ownerIdentityId: string;
|
|
49
|
+
agentIdentityId: string;
|
|
50
|
+
relayIdentityId?: string;
|
|
51
|
+
isServerRelay: (identityId: string) => boolean;
|
|
52
|
+
}): OwnerDmLeafClass;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bridge's persona renderer (owner-signed tool grants, spec §7.12; plan 4 Task 8).
|
|
3
|
+
*
|
|
4
|
+
* Under a manifest the bridge writes IDENTITY.md, SOUL.md and AGENTS.md from the
|
|
5
|
+
* raw persona whose hash the owner signed, never the server's text. It is a port
|
|
6
|
+
* of render_persona (backend/app/services/runtime_config_render.py) and is pinned
|
|
7
|
+
* to it byte for byte by persona-render.vectors.json, which the backend test
|
|
8
|
+
* test_persona_render_vectors.py re-renders with the Python function.
|
|
9
|
+
*
|
|
10
|
+
* Python str.strip() semantics, not JavaScript trim (trim also removes U+FEFF).
|
|
11
|
+
* `tone` is rendered in a fixed field order (TONE_FIELD_ORDER, the JSONB key
|
|
12
|
+
* order the backend reads), never the payload's key order (rulings item 8(a)).
|
|
13
|
+
*/
|
|
14
|
+
export declare const PERSONA_MAX_BYTES = 8192;
|
|
15
|
+
export type PersonaRender = {
|
|
16
|
+
readonly ok: true;
|
|
17
|
+
readonly files: {
|
|
18
|
+
"IDENTITY.md": string;
|
|
19
|
+
"SOUL.md": string;
|
|
20
|
+
"AGENTS.md": string;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
23
|
+
readonly ok: false;
|
|
24
|
+
readonly reason: "shape" | "over_cap";
|
|
25
|
+
};
|
|
26
|
+
/** Postgres JSONB returns object keys shorter-first, then bytewise; render_persona iterates that order. */
|
|
27
|
+
export declare const TONE_FIELD_ORDER: readonly ["humor", "length", "warmth", "formality"];
|
|
28
|
+
export declare function pyStrip(s: string): string;
|
|
29
|
+
/** A port of render_persona(persona, tool_names). Never throws. */
|
|
30
|
+
export declare function renderPersonaFiles(persona: unknown): PersonaRender;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type PinCommandStep = "pin_tmp_written" | "cred_tmp_written" | "pin_renamed" | "cred_renamed";
|
|
2
|
+
export type PinCommandResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
changedKey: boolean;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
reason: "pin_invalid" | "credential_invalid" | "symlink_refused" | "agent_mismatch" | "directory_mismatch" | "io_error";
|
|
8
|
+
};
|
|
9
|
+
export declare const PIN_COPY: {
|
|
10
|
+
readonly saved: string;
|
|
11
|
+
readonly pinInvalid: string;
|
|
12
|
+
readonly credentialInvalid: string;
|
|
13
|
+
readonly symlink: string;
|
|
14
|
+
readonly ioError: string;
|
|
15
|
+
readonly agentMismatch: string;
|
|
16
|
+
readonly directoryMismatch: string;
|
|
17
|
+
readonly announce: (agentIdentityId: string) => string;
|
|
18
|
+
readonly usage: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function runPinCommand(opts: {
|
|
21
|
+
credentialPath: string;
|
|
22
|
+
pinSourcePath: string;
|
|
23
|
+
agentIdentityId: string;
|
|
24
|
+
/** Required. Called exactly once, after every check passes and before the first write, with the credential's identity_id. Never called on a refusal. */
|
|
25
|
+
announce: (agentIdentityId: string) => void;
|
|
26
|
+
afterStep?: (s: PinCommandStep) => void;
|
|
27
|
+
}): PinCommandResult;
|
|
28
|
+
export declare function runPinCli(argv: readonly string[], io: {
|
|
29
|
+
out: (line: string) => void;
|
|
30
|
+
err: (line: string) => void;
|
|
31
|
+
}): 0 | 1 | 2;
|