@hediet/linkrpc-cli 0.0.3-next.20260926.7 → 0.0.3-next.20260927.1

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 CHANGED
@@ -439,7 +439,11 @@ hub --endpoint unix:/run/hub.sock json-rpc-stdio language-server
439
439
 
440
440
  These commands resolve the same persistent identity selected by the global
441
441
  `--principal` option and endpoint configuration. Approval commands discover and
442
- validate Hub access manifests through the shared Hub approver client. The
442
+ validate Hub access manifests through the shared observable approval client in
443
+ `@hediet/linkrpc-infra/approval`. The CLI owns formatting and the terminal UI;
444
+ its interactive adapter supplies `createTerminalConsentPrompt` from
445
+ `@hediet/linkrpc-hub` when no prompt is provided. Generic infrastructure callers
446
+ must pass an explicit `ConsentPrompt` to `runInteractive(signal, prompt)`. The
443
447
  resolved identity acts as the capability issuer/root: commands only show or
444
448
  decide requests whose `acceptableRootIds` allow that root, while minted
445
449
  capabilities retain the request consumer as their audience.
@@ -1,6 +1,6 @@
1
- import { A as connectViaRootOverlay, C as findMethodInSchema, D as formatPrincipalSource, E as logoutCliIdentity, F as describeSchema, H as mcpForwardInterface, I as explainValidation, L as validateValueAgainstSchema, M as resolveTargetEndpoint, N as resolvedEndpointToConfig, O as parsePrincipalSpec, P as describeObjectParams, S as fetchSchema$1, V as MethodRefWithOptHash, a as resolveStaticHubSchemaSource, b as setupSigning, c as resolveInvocationEndpoint, d as formatContextReference, i as loadStaticHubSchema, j as connectViaTransport, k as connect, l as validationDefault, n as StaticHubReflection, o as mutationReference, p as resolveCliInvocation, r as withStaticHubReflection, s as resolveInvocationContext, t as completeForLine, u as ContextStore, v as requestReflectionAccess, w as walkHub, x as fetchDefaults, y as requestTopologyAccess, z as mergeParams } from "./runComplete-F95L0neY.js";
1
+ import { A as connectViaRootOverlay, C as findMethodInSchema, D as formatPrincipalSource, E as logoutCliIdentity, F as describeSchema, H as mcpForwardInterface, I as explainValidation, L as validateValueAgainstSchema, M as resolveTargetEndpoint, N as resolvedEndpointToConfig, O as parsePrincipalSpec, P as describeObjectParams, S as fetchSchema$1, V as MethodRefWithOptHash, a as resolveStaticHubSchemaSource, b as setupSigning, c as resolveInvocationEndpoint, d as formatContextReference, i as loadStaticHubSchema, j as connectViaTransport, k as connect, l as validationDefault, n as StaticHubReflection, o as mutationReference, p as resolveCliInvocation, r as withStaticHubReflection, s as resolveInvocationContext, t as completeForLine, u as ContextStore, v as requestReflectionAccess, w as walkHub, x as fetchDefaults, y as requestTopologyAccess, z as mergeParams } from "./runComplete-CM1sMWnI.js";
2
2
  import { a as derived, i as autorun, r as observableValue } from "./dist-BOcSU4-O.js";
3
- import { ErrorCode, INTERFACE_TEMPLATES_EXTENSION, LinkRpcConnection, RpcError, TransportPair, computeInterfaceHash, connectTransports, createSchemaToZod, exportStaticHubSchema, generateTsContract, generateTsInterface, interfaceTemplateArgumentsEquivalent, interfaceTemplateMemberName, isAssignable, jcsCanonicalize } from "@hediet/linkrpc";
3
+ import { ErrorCode, INTERFACE_TEMPLATES_EXTENSION, LinkRpcConnection, RpcError, computeInterfaceHash, connectTransports, createSchemaToZod, exportStaticHubSchema, generateTsContract, generateTsInterface, interfaceTemplateArgumentsEquivalent, interfaceTemplateMemberName, isAssignable, jcsCanonicalize } from "@hediet/linkrpc";
4
4
  import { WebSocketTransport, connectNdjson, formatEndpointUri, isHubEndpoint, openWebSocket, parseEndpointUri, runInitializeHandshake, traceMessageTransport as traceMessageTransport$1 } from "@hediet/linkrpc/node";
5
5
  import { SocketServer } from "@hediet/linkrpc-hub/hub/server/node";
6
6
  import { randomBytes, randomUUID } from "node:crypto";
@@ -11,19 +11,19 @@ import { spawnCommand } from "@hediet/linkrpc-hub/spawn";
11
11
  import { tapTransport } from "@hediet/linkrpc-hub/hub/server/transit";
12
12
  import * as net from "node:net";
13
13
  import { mkdir, open, readFile, writeFile } from "node:fs/promises";
14
- import { DEFAULT_WALK_DEPTH, HubDirectoryExplorer, fetchSchema, hubAccessManifestInterface, hubGrantedServiceIdInterface, hubServiceIdRegistryInterface } from "@hediet/linkrpc/hub/common";
14
+ import { DEFAULT_WALK_DEPTH, HubDirectoryExplorer, fetchSchema, hubGrantedServiceIdInterface, hubServiceIdRegistryInterface } from "@hediet/linkrpc/hub/common";
15
15
  import { Command, InvalidArgumentError } from "commander";
16
+ import { bootstrapApprovalCapability, createHubApprovalClient } from "@hediet/linkrpc-infra/approval";
16
17
  import { connectionTokenBinderInterface } from "@hediet/linkrpc-hub/hub/server/connection-token-binder";
17
18
  import { spawn } from "node:child_process";
18
19
  import { TopologyClient, TopologyNetworkClient, TrafficClient } from "@hediet/linkrpc-infra/inspection";
19
20
  import { createInterface } from "node:readline/promises";
20
21
  import { stdin, stdout } from "node:process";
21
- import { AggregatingHubAccessManifest, ApproveClient, TrafficFlowAggregator, buildSlotPermissions, formatFlowSummary, registerAggregatingManifest, runManifestApprover, toSignedPermissions } from "@hediet/linkrpc-hub";
22
+ import { TrafficFlowAggregator, createTerminalConsentPrompt, formatFlowSummary } from "@hediet/linkrpc-hub";
22
23
  import { loadHubConfig, printHubConfigSchema } from "@hediet/linkrpc-hub/config-file";
23
24
  import * as readline from "node:readline";
24
25
  import { emitKeypressEvents } from "node:readline";
25
26
  import { connectJsonRpcTransports, connectRawJsonRpcTransport, createNdjsonJsonRpcTransport, jsonRpcConnectionInterface } from "@hediet/linkrpc-infra/json-rpc";
26
- import { CapabilityProposalIssuer, candidatesForSlot, durationToExp } from "@hediet/linkrpc-hub/hub/server";
27
27
  import { GRAPH_INTERFACE_TAG, IMMUTABLE_GRAPH_INTERFACE_ID, ROOT_WATCH_INTERFACE_ID, evaluateGraphPresentation, graphPresentationInterface, graphPresentationSchema, isGraphRef, standardGraphRuntimeOptions, validateGraphInterfaceSchema } from "@hediet/linkrpc-infra/graph";
28
28
  import React from "react";
29
29
  import { Box, Text, measureElement, render } from "ink";
@@ -2958,340 +2958,13 @@ function durationTone(duration) {
2958
2958
  }
2959
2959
  //#endregion
2960
2960
  //#region src/commands/approval.ts
2961
- /**
2962
- * The only authority an approval command needs for inspecting and updating
2963
- * manifests across a federated Hub.
2964
- */
2965
- const approvalCommandPermissions = [{
2966
- target: {
2967
- serviceId: { prefix: "" },
2968
- interfaceId: { exact: "hubAccessManifest" },
2969
- members: [{ prefix: "" }]
2970
- },
2971
- canInvoke: true
2972
- }, {
2973
- target: {
2974
- serviceId: { prefix: "" },
2975
- interfaceId: { exact: "hubrpc.directory" },
2976
- members: [{ prefix: "" }]
2977
- },
2978
- canInvoke: true
2979
- }];
2980
- const approvalCommandPermissionsJson = jcsCanonicalize(approvalCommandPermissions);
2981
- /**
2982
- * Installs the root identity's narrowly scoped self-capability used by the
2983
- * approval scanner. Reusing the non-expiring exact grant prevents repeated
2984
- * commands from growing the principal's durable capability bag.
2985
- */
2986
- async function bootstrapApprovalCommandCapability(principal) {
2987
- const existing = principal.capBag.capabilities.find((capability) => capability.issuer === principal.id && capability.audience === principal.id && capability.expiresAtMs === void 0 && capability.parentHash === void 0 && jcsCanonicalize(capability.permissions) === approvalCommandPermissionsJson);
2988
- if (existing) return existing;
2989
- const capability = await new CapabilityProposalIssuer(principal.identity).mint({
2990
- audience: principal.id,
2991
- permissions: approvalCommandPermissions
2992
- });
2993
- await principal.capBag.add(capability);
2994
- return capability;
2995
- }
2996
- const MANIFEST_INTERFACE_ID = hubAccessManifestInterface.info.id;
2997
- const AGGREGATE_SERVICE_ID = "linkrpc-cli.approvals";
2998
- const EXTERNAL_ID_PREFIX = "ar1_";
2999
- /**
3000
- * CLI-facing approval operations over the hub's shared manifest frontend.
3001
- * The underlying {@link ApproveClient} remains authoritative for snapshots and
3002
- * acknowledgement. One-shot commands mint before calling its acknowledged
3003
- * decision path; {@link runManifestApprover} drives the interactive UI.
3004
- */
3005
- var ApprovalCommandClient = class {
3006
- _principalId;
3007
- _manifest;
3008
- _client;
3009
- _issuer;
3010
- _fetchDirectory;
3011
- _log;
3012
- _disposeExtra;
3013
- _lastClientError;
3014
- _disposed = false;
3015
- constructor(options) {
3016
- this._principalId = options.identity.publicSigningIdentity.principal;
3017
- this._manifest = options.manifest;
3018
- this._issuer = new CapabilityProposalIssuer(options.identity);
3019
- this._fetchDirectory = options.fetchDirectory;
3020
- this._log = options.log ?? (() => {});
3021
- this._disposeExtra = options.dispose;
3022
- this._client = new ApproveClient({
3023
- manifest: this._manifest,
3024
- ownPrincipalId: this._principalId,
3025
- timeoutMs: options.timeoutMs,
3026
- log: (line) => {
3027
- this._lastClientError = line;
3028
- this._log(line);
3029
- }
3030
- });
3031
- }
3032
- get principalId() {
3033
- return this._principalId;
3034
- }
3035
- async requests() {
3036
- return this._toPendingRequests(await this._currentRequests());
3037
- }
3038
- /**
3039
- * Subscribe to the authoritative manifest snapshot. The callback is invoked
3040
- * immediately and whenever the watch reconnects or the request set changes.
3041
- */
3042
- watch(listener) {
3043
- return autorun((reader) => {
3044
- const state = this._client.state.read(reader);
3045
- listener({
3046
- state,
3047
- requests: this._toPendingRequests(this._client.requests.read(reader)),
3048
- ...state === "stale" && this._lastClientError !== void 0 ? { error: this._lastClientError } : {}
3049
- });
3050
- });
3051
- }
3052
- /** Force an immediate manifest reconciliation. */
3053
- async refresh() {
3054
- await this._currentRequests();
3055
- }
3056
- async deny(externalId, reason, expected) {
3057
- const internalId = decodeApprovalRequestId(externalId);
3058
- const pending = await this._requirePending(internalId, externalId);
3059
- if (expected !== void 0) this._requireUnchanged(pending, expected);
3060
- const result = await this._client.decide(internalId, {
3061
- status: "denied",
3062
- ...reason !== void 0 ? { reason } : {}
3063
- });
3064
- if (result === "gone") throw new Error(`approval request '${externalId}' is no longer pending`);
3065
- return result;
3066
- }
3067
- async approve(externalId) {
3068
- return this.approvePrepared(await this.prepareApproval(externalId));
3069
- }
3070
- /**
3071
- * Resolve the exact authority that an approval will mint. Interactive
3072
- * surfaces render this result before asking for confirmation.
3073
- */
3074
- async prepareApproval(externalId) {
3075
- const internalId = decodeApprovalRequestId(externalId);
3076
- const pending = await this._requirePending(internalId, externalId);
3077
- const resolved = await this._resolveRequest(pending.request);
3078
- if ("denied" in resolved) throw new Error(`approval request '${externalId}' cannot be granted: ${resolved.denied}`);
3079
- const sourceServiceId = approvalRequestSource(internalId);
3080
- return {
3081
- pending: {
3082
- id: externalId,
3083
- request: pending.request,
3084
- revision: pending.revision,
3085
- ...sourceServiceId === void 0 ? {} : { sourceServiceId }
3086
- },
3087
- permissions: await toSignedPermissions(resolved.permissions, pending.request.consumer.principal, pending.request.duration),
3088
- ...resolved.resolvedSlot === void 0 ? {} : { resolvedSlot: resolved.resolvedSlot }
3089
- };
3090
- }
3091
- /** Approve only if the request is still exactly the one that was reviewed. */
3092
- async approvePrepared(prepared) {
3093
- const externalId = prepared.pending.id;
3094
- const internalId = decodeApprovalRequestId(externalId);
3095
- const pending = await this._requirePending(internalId, externalId);
3096
- this._requireUnchanged(pending, prepared.pending);
3097
- const decision = await this._grantDecision(prepared);
3098
- const result = await this._client.decide(internalId, decision);
3099
- if (result === "gone") throw new Error(`approval request '${externalId}' is no longer pending`);
3100
- if (decision.status !== "granted") throw new Error(`approval request '${externalId}' could not be granted` + (decision.reason !== void 0 ? `: ${decision.reason}` : ""));
3101
- return result;
3102
- }
3103
- async runInteractive(signal, prompt) {
3104
- await this._currentRequests();
3105
- const approver = runManifestApprover({
3106
- manifest: this._manifest,
3107
- issuer: this._issuer,
3108
- ownPrincipalId: this._principalId,
3109
- ...this._fetchDirectory !== void 0 ? { fetchDirectory: this._fetchDirectory } : {},
3110
- ...prompt !== void 0 ? { prompt } : {},
3111
- log: this._log
3112
- });
3113
- try {
3114
- await waitForAbort(signal);
3115
- } finally {
3116
- approver.dispose();
3117
- }
3118
- }
3119
- dispose() {
3120
- if (this._disposed) return;
3121
- this._disposed = true;
3122
- this._client.dispose();
3123
- this._disposeExtra?.();
3124
- }
3125
- async _currentRequests() {
3126
- await this._client.refresh();
3127
- if (this._client.state.get() === "stale") throw new Error(this._lastClientError ?? "could not read pending approval requests");
3128
- return this._client.requests.get();
3129
- }
3130
- _toPendingRequests(requests) {
3131
- return requests.map(({ id, request, revision }) => {
3132
- const sourceServiceId = approvalRequestSource(id);
3133
- return {
3134
- id: encodeApprovalRequestId(id),
3135
- request,
3136
- revision,
3137
- ...sourceServiceId === void 0 ? {} : { sourceServiceId }
3138
- };
3139
- }).sort((a, b) => a.id.localeCompare(b.id));
3140
- }
3141
- async _requirePending(internalId, externalId) {
3142
- const pending = (await this._currentRequests()).find((request) => request.id === internalId);
3143
- if (!pending) throw new Error(`approval request '${externalId}' is not pending for principal '${this._principalId}'`);
3144
- return pending;
3145
- }
3146
- _requireUnchanged(actual, expected) {
3147
- if (jcsCanonicalize(actual.request) !== jcsCanonicalize(expected.request)) throw new Error(`approval request '${expected.id}' changed after it was reviewed; review it again`);
3148
- }
3149
- async _resolveRequest(request) {
3150
- let permissions;
3151
- let resolvedSlot;
3152
- if (request.kind === "direct") permissions = request.permissions;
3153
- else {
3154
- if (this._fetchDirectory === void 0) return { denied: "no directory available to resolve discover candidates" };
3155
- const slot = {
3156
- interfaces: request.interfaces.map((item) => ({
3157
- id: item.id,
3158
- required: item.required !== false,
3159
- ...item.hash !== void 0 ? { hash: item.hash } : {}
3160
- })),
3161
- members: request.members.map((item) => ({
3162
- interfaceId: item.interfaceId,
3163
- member: item.member,
3164
- required: item.required !== false
3165
- }))
3166
- };
3167
- const candidate = candidatesForSlot(slot, await this._fetchDirectory())[0];
3168
- if (!candidate) return { denied: "no candidate service satisfies the requested interfaces" };
3169
- const present = new Set(candidate.satisfiedInterfaces.map((item) => item.id));
3170
- permissions = buildSlotPermissions(candidate.serviceId, slot.interfaces, slot.members, present);
3171
- resolvedSlot = {
3172
- serviceId: candidate.serviceId,
3173
- satisfiedInterfaces: candidate.satisfiedInterfaces.map((item) => item.id)
3174
- };
3175
- }
3176
- return {
3177
- permissions,
3178
- ...resolvedSlot === void 0 ? {} : { resolvedSlot }
3179
- };
3180
- }
3181
- async _grantDecision(prepared) {
3182
- const request = prepared.pending.request;
3183
- const capability = await this._issuer.mint({
3184
- audience: request.consumer.principal,
3185
- permissions: prepared.permissions,
3186
- expiresAtMs: durationToExp(request.duration)
3187
- });
3188
- return {
3189
- status: "granted",
3190
- granted: prepared.resolvedSlot === void 0 ? {
3191
- kind: "direct",
3192
- capabilities: [capability]
3193
- } : {
3194
- kind: "discover",
3195
- serviceId: prepared.resolvedSlot.serviceId,
3196
- satisfiedInterfaces: [...prepared.resolvedSlot.satisfiedInterfaces],
3197
- capabilities: [capability]
3198
- }
3199
- };
3200
- }
3201
- };
3202
- /**
3203
- * Discover every manifest in the connected hub and expose it through one
3204
- * validated, namespaced aggregate. This is the same discovery/validation path
3205
- * used by the hub's approval UI.
3206
- */
3207
- function createHubApprovalCommandClient(connection, identity, log) {
3208
- const explorer = new HubDirectoryExplorer(connection.channel);
3209
- const sourceCache = /* @__PURE__ */ new Map();
3210
- let directoryChanged;
3211
- const watchStarted = explorer.watch(() => directoryChanged?.());
3212
- const fetchDirectory = async () => {
3213
- await watchStarted;
3214
- return explorer.result.listings.map((entry) => ({
3215
- serviceId: entry.serviceId,
3216
- interfaceId: entry.interfaceId,
3217
- hash: entry.hash,
3218
- ...entry.serviceDescription === void 0 ? {} : { serviceDescription: entry.serviceDescription },
3219
- ...entry.rootPrincipalSets === void 0 ? {} : { rootPrincipalSets: entry.rootPrincipalSets }
3220
- }));
3221
- };
3222
- const resolveSources = async () => {
3223
- const directory = await fetchDirectory();
3224
- const serviceIds = [...new Set(directory.filter((entry) => entry.interfaceId === MANIFEST_INTERFACE_ID).map((entry) => entry.serviceId))].sort();
3225
- log?.(`approval: discovered ${serviceIds.length} manifest source${serviceIds.length === 1 ? "" : "s"}${serviceIds.length > 0 ? `: ${serviceIds.join(", ")}` : ""}`);
3226
- const active = new Set(serviceIds);
3227
- for (const serviceId of sourceCache.keys()) if (!active.has(serviceId)) sourceCache.delete(serviceId);
3228
- return serviceIds.map((serviceId) => {
3229
- const cached = sourceCache.get(serviceId);
3230
- if (cached !== void 0) return cached;
3231
- const source = {
3232
- tag: serviceId,
3233
- manifest: withApprovalSourceLogging(serviceId === "" ? connection.get(hubAccessManifestInterface) : connection.service(serviceId).get(hubAccessManifestInterface), serviceId, log),
3234
- preserveOrigin: false
3235
- };
3236
- sourceCache.set(serviceId, source);
3237
- return source;
3238
- });
3239
- };
3240
- const aggregate = new AggregatingHubAccessManifest({
3241
- resolveSources,
3242
- watchSources: (onChange) => {
3243
- directoryChanged = onChange;
3244
- return () => {
3245
- if (directoryChanged === onChange) directoryChanged = void 0;
3246
- };
3247
- },
3248
- log
2961
+ function createHubApprovalCommandClient(...args) {
2962
+ const client = createHubApprovalClient(...args);
2963
+ const runInteractive = client.runInteractive.bind(client);
2964
+ return Object.assign(client, {
2965
+ watch: (listener) => autorun((reader) => listener(client.snapshot.read(reader))),
2966
+ runInteractive: (signal, prompt = createTerminalConsentPrompt()) => runInteractive(signal, prompt)
3249
2967
  });
3250
- const pair = new TransportPair();
3251
- const aggregateServer = LinkRpcConnection.fromTransport(pair.a);
3252
- const aggregateClient = LinkRpcConnection.fromTransport(pair.b);
3253
- registerAggregatingManifest(aggregateServer, aggregate, { serviceId: AGGREGATE_SERVICE_ID });
3254
- return new ApprovalCommandClient({
3255
- manifest: aggregateClient.service(AGGREGATE_SERVICE_ID).get(hubAccessManifestInterface),
3256
- identity,
3257
- fetchDirectory,
3258
- log,
3259
- dispose: () => {
3260
- aggregate.dispose();
3261
- watchStarted.then((stop) => stop(), () => void 0);
3262
- explorer.dispose();
3263
- aggregateClient.close();
3264
- aggregateServer.close();
3265
- }
3266
- });
3267
- }
3268
- function withApprovalSourceLogging(manifest, serviceId, log) {
3269
- if (!log) return manifest;
3270
- const getDesired = manifest.getDesired.bind(manifest);
3271
- return new Proxy(manifest, { get: (target, property, receiver) => {
3272
- if (property !== "getDesired") return Reflect.get(target, property, receiver);
3273
- return async (...args) => {
3274
- const result = await getDesired(...args);
3275
- const count = Object.keys(result.requested).length;
3276
- log(`approval: source '${serviceId || "<root>"}' has ${count} pending request` + (count === 1 ? "" : "s"));
3277
- return result;
3278
- };
3279
- } });
3280
- }
3281
- function encodeApprovalRequestId(internalId) {
3282
- if (internalId.length === 0) throw new Error("cannot encode an empty approval request id");
3283
- return `${EXTERNAL_ID_PREFIX}${Buffer.from(internalId, "utf8").toString("base64url")}`;
3284
- }
3285
- function decodeApprovalRequestId(externalId) {
3286
- if (!new RegExp(`^${EXTERNAL_ID_PREFIX}[A-Za-z0-9_-]+$`).test(externalId)) throw new Error(`invalid approval request id '${externalId}'`);
3287
- const encoded = externalId.slice(4);
3288
- const decoded = Buffer.from(encoded, "base64url").toString("utf8");
3289
- if (decoded.length === 0 || encodeApprovalRequestId(decoded) !== externalId) throw new Error(`invalid approval request id '${externalId}'`);
3290
- return decoded;
3291
- }
3292
- function approvalRequestSource(internalId) {
3293
- const separator = internalId.indexOf("\0");
3294
- return separator < 0 ? void 0 : internalId.slice(0, separator);
3295
2968
  }
3296
2969
  function formatApprovalRequests(requests, principalId, json = false) {
3297
2970
  if (json) return formatJson({
@@ -3321,10 +2994,6 @@ function formatApprovalDecision(action, id, principalId, json = false, outcome =
3321
2994
  });
3322
2995
  return outcome === "applied" ? `${action === "approved" ? "Approved" : "Denied"} ${id}.` : `${action === "approved" ? "Approval" : "Denial"} decision accepted for ${id}, but a matching request is still pending; the consumer may have retried.`;
3323
2996
  }
3324
- function waitForAbort(signal) {
3325
- if (signal.aborted) return Promise.resolve();
3326
- return new Promise((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
3327
- }
3328
2997
  //#endregion
3329
2998
  //#region src/commands/identity.ts
3330
2999
  function cliIdentity(session) {
@@ -7250,7 +6919,7 @@ Batch options:
7250
6919
  process.once("SIGINT", onSignal);
7251
6920
  process.once("SIGTERM", onSignal);
7252
6921
  try {
7253
- const { runApprovalUi } = await import("./runApprovalUi-Kt6FnH9y.js");
6922
+ const { runApprovalUi } = await import("./runApprovalUi-eLDf_5ZN.js");
7254
6923
  await runApprovalUi({
7255
6924
  client,
7256
6925
  signal: stop.signal
@@ -7265,7 +6934,7 @@ Batch options:
7265
6934
  registerViewCommands(program, (action) => withChannel(endpoint, getPrincipalSpec(), action));
7266
6935
  program.command("ui").description("Launch the terminal UI (form-based browser of services + methods).").action(async () => {
7267
6936
  const acquired = await acquireConnection(endpoint);
7268
- const { runUi } = await import("./runUi-DD7DYroJ.js");
6937
+ const { runUi } = await import("./runUi-DF_HTMk9.js");
7269
6938
  try {
7270
6939
  await runUi({
7271
6940
  endpoint: acquired.ep,
@@ -7531,8 +7200,8 @@ async function withResolvedSigning(endpoint, principalSpec, fn) {
7531
7200
  async function withApprovalClient(endpoint, principalSpec, fn, log = (line) => process.stderr.write(`linkrpc: ${line}\n`)) {
7532
7201
  await withResolvedSigning(endpoint, principalSpec, async (conn, session) => {
7533
7202
  reportIdentity(session);
7534
- await bootstrapApprovalCommandCapability(session.principal);
7535
- const client = createHubApprovalCommandClient(new LinkRpcConnection(conn.rpcChannel), session.principal.identity, log);
7203
+ await bootstrapApprovalCapability(session.principal);
7204
+ const client = createHubApprovalCommandClient(new LinkRpcConnection(conn.rpcChannel), session.principal.identity, log, () => session.principal.capBag.capabilities, () => bootstrapApprovalCapability(session.principal, log));
7536
7205
  try {
7537
7206
  await fn(client);
7538
7207
  } finally {
@@ -7698,4 +7367,4 @@ function safeJson(value) {
7698
7367
  //#endregion
7699
7368
  export { formatCommandLegend as a, safeTerminalText as c, interfaceTarget as d, matchesTarget as f, dispatchHostKey as i, resolveViewTarget as l, approvalDetailLines as m, views as n, hostCommands as o, targetId as p, ViewFrame as r, matchesKey as s, runCli as t, formatCondition as u };
7700
7369
 
7701
- //# sourceMappingURL=cli-IfKpF0E1.js.map
7370
+ //# sourceMappingURL=cli-yDtBqjCT.js.map