@vess-id/vess 0.0.0-dev-20261015070513 → 0.0.0-dev-20261015130518

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.
@@ -23,7 +23,10 @@
23
23
  import type { AgentdGatewayClient, DelegatedApprovalView } from '../gateway/gateway-client';
24
24
  /** What the pull hands to a holder: the API's row, nothing from an LLM. */
25
25
  export type ApprovedRow = Pick<DelegatedApprovalView, 'id' | 'action' | 'actionParams'>;
26
- /** `executed` = the PEP ran it; `failed` = presented and failed; `skipped` = nothing was run. */
26
+ /**
27
+ * `executed` = it ran; `failed` = it was issued but did not run successfully (presented and failed, or
28
+ * refused at presentation); `skipped` = nothing was asked or run.
29
+ */
27
30
  export type PullOutcome = 'executed' | 'failed' | 'skipped';
28
31
  /** A holder that runs in this process (an `ExecutionEngine`). */
29
32
  export interface PullHolder {
@@ -1 +1 @@
1
- {"version":3,"file":"approval-pull.d.ts","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAE3F,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,EAAE,IAAI,GAAG,QAAQ,GAAG,cAAc,CAAC,CAAA;AAEvF,iGAAiG;AACjG,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE3D,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,gFAAgF;IAChF,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACxD;AASD,qBAAa,YAAY;IAWrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAZtB,MAAM,CAAC,QAAQ,CAAC,WAAW,SAAS;IACpC,OAAO,CAAC,KAAK,CAAC,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAQ;IAEvB;;;;OAIG;gBAEgB,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,EAC3D,OAAO,EAAE,MAAM,SAAS,UAAU,EAAE,EACpC,GAAG,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAe;IAGzD,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;IAKZ,sFAAsF;IAChF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBb,OAAO;CAqBtB"}
1
+ {"version":3,"file":"approval-pull.d.ts","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAE3F,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,qBAAqB,EAAE,IAAI,GAAG,QAAQ,GAAG,cAAc,CAAC,CAAA;AAEvF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE3D,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,gFAAgF;IAChF,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACxD;AASD,qBAAa,YAAY;IAWrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAZtB,MAAM,CAAC,QAAQ,CAAC,WAAW,SAAS;IACpC,OAAO,CAAC,KAAK,CAAC,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAQ;IAEvB;;;;OAIG;gBAEgB,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,EAC3D,OAAO,EAAE,MAAM,SAAS,UAAU,EAAE,EACpC,GAAG,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAe;IAGzD,KAAK,IAAI,IAAI;IAOb,IAAI,IAAI,IAAI;IAKZ,sFAAsF;IAChF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBb,OAAO;CAqBtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"approval-pull.js","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"approval-pull.js","sourceRoot":"","sources":["../../src/core/approval-pull.ts"],"names":[],"mappings":"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"}
@@ -120,8 +120,11 @@ export declare class ExecutionEngine {
120
120
  * question — an approval card the owner never asked for, every 10 s.
121
121
  * ðŸ”ī Only `allow` runs. `in_flight` / `done` (another path got there first), `closed`, `ask`, a
122
122
  * refusal or a failure run nothing; the issuer's CAS is what keeps a row to one execution.
123
- * ðŸŠĪ Local actions (`os.*`) stay on the legacy path until B3b: not asked, not run.
124
- * The PEP records the outcome against the credential, which is what `aidentity_get_result` reads.
123
+ * ðŸ”ī Local actions (`os.*`, B3b) take the same route; `allow` is then presented at `local/present`
124
+ * and the executor runs that answer's arguments (`executeLocalDelegated`). A permanent present
125
+ * failure closes the row, so it is not pulled again.
126
+ * The PEP (the api, or agentd for a local action via `local/result`) records the outcome against the
127
+ * credential, which is what `aidentity_get_result` reads.
125
128
  */
126
129
  executeApproved(row: ApprovedRow): Promise<PullOutcome>;
127
130
  /**
@@ -161,7 +164,6 @@ export declare class ExecutionEngine {
161
164
  */
162
165
  private isPolicyForbiddenError;
163
166
  private policyForbiddenReason;
164
- private executeLocal;
165
167
  /**
166
168
  * Execute locally with an already-acquired VC (skips ensureVC).
167
169
  * Used by both the normal path (after ensureVC) and handleApprovalResponse (after quickApprove).
@@ -185,6 +187,8 @@ export declare class ExecutionEngine {
185
187
  * not decided in time → `pending` + `request_id` (read later with `aidentity_get_result`);
186
188
  * 3. `allow` → present the credential and call the PEP with `allow.actionParams` only
187
189
  * (`executeWithCredential`; `FrozenParams` makes the LLM input unpassable).
190
+ * A local action (`os.*`, PR B3b) takes this same route; its `allow` is presented at
191
+ * `local/present` and run here with that answer's arguments (`executeLocalDelegated`).
188
192
  * ðŸ”ī No legacy endpoint is reached from here: no wallet VC, no auto-issue / claim / OOB request /
189
193
  * resource resolution, no in-band approval token. Only the issuer raises approval requests.
190
194
  */
@@ -200,6 +204,26 @@ export declare class ExecutionEngine {
200
204
  private auditHandoffRefused;
201
205
  /** One audit entry for a call that ended without execution on the delegated arm. */
202
206
  private auditNotExecuted;
207
+ /** Audit kind of the delegated arms: a local action is executed (and enforced) on this machine. */
208
+ private delegatedAuditKind;
209
+ /** `allow` from the issuer: a local action is presented and run here, a gateway action at the PEP. */
210
+ private executeAllowed;
211
+ /**
212
+ * A local action (`os.*`) after the issuer's `allow` (plan B, PR B3b): present the credential at
213
+ * `local/present`, run EXACTLY the arguments it returns, write the outcome once
214
+ * (`core/local-invoke.ts`). No wallet, no `verify-authorize`, no offline arm.
215
+ */
216
+ private executeLocalDelegated;
217
+ /**
218
+ * Run the local executor on the present answer's arguments.
219
+ * ðŸ”ī `params` is the only input (`FrozenParams`): the env profile, the working directory, the file
220
+ * path and the content all come from it.
221
+ * ðŸ”ī `approvedResource` = the frozen `file_path`: the executor resolves the path again right before it
222
+ * reads / writes and refuses if it now points elsewhere (a symlink swapped in after the approval,
223
+ * plan B I-E). `approvedFingerprint` (inode binding) is not passed — Q21 default (a), the same
224
+ * protection as the legacy path.
225
+ */
226
+ private runLocalExecutor;
203
227
  /** Present the credential and call the PEP with the issuer's arguments (`FrozenParams`). */
204
228
  private executeDelegated;
205
229
  /** The issuer refused (403 = the owner's settings forbid it: terminal) or could not be reached. */
@@ -243,8 +267,11 @@ export declare class ExecutionEngine {
243
267
  private createInBandApprovalResponse;
244
268
  /**
245
269
  * Pre-request permissions for multiple actions (batch).
246
- * Triggers VC acquisition for each action without executing.
247
- * This allows the user to approve multiple actions at once.
270
+ * ðŸ”ī There is no pre-approval any more (B1 for gateway actions, B3b for local ones): every
271
+ * credential is issued per call by the api's issuer (`aidentity_call_tool` → `pending` +
272
+ * `request_id` when the owner must approve). Raising a legacy approval request here would create
273
+ * a card that no new build ever executes. Only the device's own deny is reported (a local action
274
+ * that the local / org policy forbids would be refused before the issuer is asked).
248
275
  */
249
276
  requestPermissions(actions: string[]): Promise<ExecuteResult>;
250
277
  listAvailableTools(): Promise<ListToolsResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"execution-engine.d.ts","sourceRoot":"","sources":["../../src/core/execution-engine.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAuC,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EACL,mBAAmB,EAMpB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAUjE,OAAO,EACL,cAAc,EACd,aAAa,EACb,eAAe,EACf,gBAAgB,EAIjB,MAAM,SAAS,CAAA;AAEhB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAmDrD,qBAAa,eAAe;IAgCxB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;IAtCjC,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,UAAU,CAAC,CAAmC;IACtD,OAAO,CAAC,eAAe,CAAQ;IAC/B;;;;OAIG;IACH,OAAO,CAAC,yBAAyB,CAAI;IACrC;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,iBAAiB,CAA4B;IACrD,+FAA+F;IAC/F,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAS;IAChD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAO;IAC/C;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAQ;gBAG3C,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,aAAa,EAAE,mBAAmB,EAClC,OAAO,EAAE,gBAAgB,EACzB,YAAY,EAAE,oBAAoB,EAClC,aAAa,CAAC,EAAE,aAAa,YAAA;IAGhD;;OAEG;IACH,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIzC;;;OAGG;IACH,aAAa,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAI5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,OAAO,CAAC,qBAAqB;IAgG7B;;;;;;;;;;OAUG;IACH,IAAI,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAE/C;IAED;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA4G9D,qFAAqF;IACrF,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED;;;;;;;;;;;OAWG;IACG,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAqD7D;;;;;OAKG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA4D1D;;;;;;;;;;;;;;;OAeG;YACW,QAAQ;IA2JtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,qBAAqB;YAoBf,YAAY;IAiD1B;;;OAGG;YACW,kBAAkB;IAmMhC;;;;;;;OAOG;YACW,mBAAmB;IAqHjC;;;;;;;;;;;OAWG;YACW,iBAAiB;IAmF/B;;;OAGG;IACH,OAAO,CAAC,SAAS;IAejB,iFAAiF;YACnE,MAAM;IAyCpB,8FAA8F;IAC9F,OAAO,CAAC,mBAAmB;IAY3B,oFAAoF;IACpF,OAAO,CAAC,gBAAgB;IAYxB,4FAA4F;YAC9E,gBAAgB;IA6C9B,mGAAmG;IACnG,OAAO,CAAC,aAAa;IAuDrB;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAehB,4EAA4E;IAC5E,OAAO,CAAC,QAAQ;YAaF,uBAAuB;IAwRrC;;OAEG;YACW,qBAAqB;IA0NnC;;;;;;;;;;OAUG;YACW,wBAAwB;IAmDtC;;;;;OAKG;YACW,kCAAkC;IA8ChD;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAgDpC;;;;OAIG;IACG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAyI7D,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC;IAYpD;;;OAGG;YACW,iBAAiB;IA2B/B,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,eAAe;YAUT,sBAAsB;IAkPpC,OAAO,CAAC,eAAe;IASvB;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IAiBlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,OAAO,CAAC,+BAA+B;IAOvC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,uBAAuB;IAkB/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,OAAO,CAAC,2BAA2B;IASnC,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,eAAe;IAavB,iHAAiH;YACnG,cAAc;YA4Bd,sBAAsB;IA8CpC,OAAO,CAAC,QAAQ;CA4CjB"}
1
+ {"version":3,"file":"execution-engine.d.ts","sourceRoot":"","sources":["../../src/core/execution-engine.ts"],"names":[],"mappings":"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"}
@@ -57,6 +57,7 @@ const fs = __importStar(require("fs"));
57
57
  const wallet_1 = require("../wallet/wallet");
58
58
  const gateway_client_1 = require("../gateway/gateway-client");
59
59
  const delegated_invoke_1 = require("./delegated-invoke");
60
+ const local_invoke_1 = require("./local-invoke");
60
61
  const call_budget_1 = require("./call-budget");
61
62
  const resource_canonicalizer_1 = require("../utils/resource-canonicalizer");
62
63
  const vc_utils_1 = require("../utils/vc-utils");
@@ -84,6 +85,19 @@ const POLICY_SYNC_TTL_MS = 30 * 60 * 1000;
84
85
  /** Fallback OOB approval expiration (seconds) when the API doesn't return a value.
85
86
  * Kept short (5 min) so the agent doesn't wait on a possibly-expired request. */
86
87
  const OOB_APPROVAL_DEFAULT_EXPIRES_IN_SECONDS = 300;
88
+ /**
89
+ * The resource of a local action for the audit log (same rule as `execute()`): the file path, or the
90
+ * command line of `os.process.run`. Only the path / command — never `content`.
91
+ */
92
+ function localAuditResource(action, params) {
93
+ if (typeof params.file_path === 'string' && params.file_path !== '') {
94
+ return { requestedResource: params.file_path, normalizedResource: params.file_path };
95
+ }
96
+ if (action === 'os.process.run' && Array.isArray(params.command)) {
97
+ return { requestedResource: params.command.map(String).join(' ') };
98
+ }
99
+ return {};
100
+ }
87
101
  class ExecutionEngine {
88
102
  policyEvaluator;
89
103
  wallet;
@@ -296,11 +310,10 @@ class ExecutionEngine {
296
310
  return { success: false, error: LEGACY_HANDOFF_REFUSED };
297
311
  }
298
312
  const { action, input } = request;
299
- // ðŸ”ī `pendingRequestId` (claim of a legacy OOB approval) is refused for gateway actions: the gateway
300
- // arm only executes approvals the issuer hands back for THIS holder. Local actions (`os.*`)
301
- // keep the legacy claim until B3b (they are all high / critical risk and approved by a human
302
- // in the browser; the claim is not a self-approval).
303
- if (request.pendingRequestId && !(0, executor_registry_1.isLocalAction)(action)) {
313
+ // ðŸ”ī `pendingRequestId` (claim of a legacy OOB approval) is refused for EVERY action (B1 for gateway
314
+ // actions, B3b for local ones): both arms only execute approvals the issuer hands back for THIS
315
+ // holder, and an approved call runs without being resent (the pull, B2).
316
+ if (request.pendingRequestId) {
304
317
  this.auditHandoffRefused(action, 'pendingRequestId');
305
318
  return { success: false, error: LEGACY_HANDOFF_REFUSED };
306
319
  }
@@ -315,11 +328,9 @@ class ExecutionEngine {
315
328
  // (incl. local os.* actions) pass through unchanged. Skipped on the
316
329
  // approval-retry / pending-approval paths, which carry the already
317
330
  // validated original input plus an approval token / request id.
318
- if (!request.pendingRequestId) {
319
- const inputCheck = (0, ai_identity_1.validateActionInput)(action, input ?? {});
320
- if (!inputCheck.valid) {
321
- return { success: false, error: inputCheck.errors.join(' ') };
322
- }
331
+ const inputCheck = (0, ai_identity_1.validateActionInput)(action, input ?? {});
332
+ if (!inputCheck.valid) {
333
+ return { success: false, error: inputCheck.errors.join(' ') };
323
334
  }
324
335
  // 1. Extract provider from action (e.g., 'os' from 'os.secret.read')
325
336
  const provider = action.split('.')[0];
@@ -352,19 +363,20 @@ class ExecutionEngine {
352
363
  });
353
364
  return { success: false, error: `Action denied by policy: ${policyResult.reason}` };
354
365
  }
355
- // Handle OOB approval polling (pendingRequestId) — local actions only (checked above).
356
- if (request.pendingRequestId) {
357
- return this.handlePendingApproval(request);
358
- }
359
366
  // 4. Determine execution routing
360
367
  const routing = (0, executor_registry_1.determineRouting)(provider, action);
361
- // 5. Execute based on routing
368
+ // 5. Both arms ask the api's issuer (B1 gateway, B3b local). ðŸ”ī A local action asks with the
369
+ // RESOLVED path (`canonicalizePath`: `~`, `..`, symlinks): the issued digest, the approval row's
370
+ // frozen arguments and the approval card all carry the real file, and the executor compares
371
+ // that path again at execution time (`approvedResource`, plan B I-E).
362
372
  if (routing.executor === 'local') {
363
- return this.executeLocal(action, input, provider, normalizedResource, resourceFingerprint, requestedResource);
364
- }
365
- else {
366
- return this.executeViaGateway(provider, action, input, startedAt);
373
+ if (!(0, executor_registry_1.getLocalExecutor)(action)) {
374
+ return { success: false, error: `No local executor for action: ${action}` };
375
+ }
376
+ const sent = normalizedResource ? { ...input, file_path: normalizedResource } : input;
377
+ return this.executeViaGateway(provider, action, sent, startedAt);
367
378
  }
379
+ return this.executeViaGateway(provider, action, input, startedAt);
368
380
  }
369
381
  /** The holder DID of this engine (the approval pull lists approved rows per DID). */
370
382
  get agentDid() {
@@ -379,13 +391,14 @@ class ExecutionEngine {
379
391
  * question — an approval card the owner never asked for, every 10 s.
380
392
  * ðŸ”ī Only `allow` runs. `in_flight` / `done` (another path got there first), `closed`, `ask`, a
381
393
  * refusal or a failure run nothing; the issuer's CAS is what keeps a row to one execution.
382
- * ðŸŠĪ Local actions (`os.*`) stay on the legacy path until B3b: not asked, not run.
383
- * The PEP records the outcome against the credential, which is what `aidentity_get_result` reads.
394
+ * ðŸ”ī Local actions (`os.*`, B3b) take the same route; `allow` is then presented at `local/present`
395
+ * and the executor runs that answer's arguments (`executeLocalDelegated`). A permanent present
396
+ * failure closes the row, so it is not pulled again.
397
+ * The PEP (the api, or agentd for a local action via `local/result`) records the outcome against the
398
+ * credential, which is what `aidentity_get_result` reads.
384
399
  */
385
400
  async executeApproved(row) {
386
401
  const { id, action } = row;
387
- if ((0, executor_registry_1.isLocalAction)(action))
388
- return 'skipped';
389
402
  // ðŸ”ī Never ask unnamed: an empty id would read as "no approval named" and raise a NEW question.
390
403
  if (typeof id !== 'string' || id === '')
391
404
  return 'skipped';
@@ -411,7 +424,7 @@ class ExecutionEngine {
411
424
  decisionSource: 'local_policy',
412
425
  decisionReason: `approval_pull ${id}: ${policyResult.reason}`,
413
426
  ...(typeof filePath === 'string' ? { requestedResource: filePath } : {}),
414
- executionType: 'gateway',
427
+ executionType: (0, executor_registry_1.isLocalAction)(action) ? 'local' : 'gateway',
415
428
  });
416
429
  }
417
430
  return 'skipped';
@@ -427,7 +440,7 @@ class ExecutionEngine {
427
440
  }
428
441
  if (answer.status !== 'allow')
429
442
  return 'skipped';
430
- const result = await this.executeDelegated(provider, action, answer);
443
+ const result = await this.executeAllowed(provider, action, answer);
431
444
  return result.success ? 'executed' : 'failed';
432
445
  }
433
446
  /**
@@ -471,8 +484,21 @@ class ExecutionEngine {
471
484
  break;
472
485
  }
473
486
  const outcome = r.execution?.outcome;
474
- if (outcome === 'executed')
487
+ if (outcome === 'executed') {
488
+ // ðŸ”ī No stored content (a secret read keeps none, owner decision 2): say it ran, and that the
489
+ // content is not available — never an empty value the LLM could read as "the file is empty".
490
+ if (r.result === null || r.result === undefined) {
491
+ return {
492
+ success: true,
493
+ data: {
494
+ status: 'executed',
495
+ request_id: requestId,
496
+ note: 'It was carried out; no result content is stored for it, so none can be returned here.',
497
+ },
498
+ };
499
+ }
475
500
  return { success: true, data: r.result };
501
+ }
476
502
  // ðŸ”ī `expired` = not executed: unanswered until it expired / closed after approval without running /
477
503
  // withdrawn. An executed row is `consumed` + `executed` (the branch above).
478
504
  if (r.status === 'expired') {
@@ -676,36 +702,6 @@ class ExecutionEngine {
676
702
  // ===========================================================================
677
703
  // Local execution with VP verification (spec §7.4)
678
704
  // ===========================================================================
679
- async executeLocal(action, params, provider, normalizedResource, resourceFingerprint, requestedResource) {
680
- const resourceInfo = normalizedResource && resourceFingerprint
681
- ? { normalizedResource, fingerprint: resourceFingerprint }
682
- : undefined;
683
- // 1. Ensure VC (4-step acquisition)
684
- const vcResult = await this.ensureVC(action, provider, resourceInfo, params);
685
- if ('approvalRequired' in vcResult) {
686
- return { success: false, approvalRequired: vcResult.approvalRequired };
687
- }
688
- if ('waitingForApproval' in vcResult) {
689
- return { success: false, waitingForApproval: vcResult.waitingForApproval };
690
- }
691
- if ('denied' in vcResult) {
692
- this.logAudit({
693
- action,
694
- provider,
695
- decision: 'deny',
696
- enforcementType: 'local',
697
- decisionSource: 'local_policy',
698
- decisionReason: vcResult.reason,
699
- requestedResource,
700
- normalizedResource,
701
- resourceFingerprint,
702
- executionType: 'local',
703
- });
704
- return { success: false, error: `Permission denied: ${vcResult.reason}` };
705
- }
706
- // 2. Execute with the acquired VC
707
- return this.executeLocalWithVC(action, params, provider, vcResult, normalizedResource, resourceFingerprint, requestedResource);
708
- }
709
705
  /**
710
706
  * Execute locally with an already-acquired VC (skips ensureVC).
711
707
  * Used by both the normal path (after ensureVC) and handleApprovalResponse (after quickApprove).
@@ -972,6 +968,8 @@ class ExecutionEngine {
972
968
  * not decided in time → `pending` + `request_id` (read later with `aidentity_get_result`);
973
969
  * 3. `allow` → present the credential and call the PEP with `allow.actionParams` only
974
970
  * (`executeWithCredential`; `FrozenParams` makes the LLM input unpassable).
971
+ * A local action (`os.*`, PR B3b) takes this same route; its `allow` is presented at
972
+ * `local/present` and run here with that answer's arguments (`executeLocalDelegated`).
975
973
  * ðŸ”ī No legacy endpoint is reached from here: no wallet VC, no auto-issue / claim / OOB request /
976
974
  * resource resolution, no in-band approval token. Only the issuer raises approval requests.
977
975
  */
@@ -1021,7 +1019,7 @@ class ExecutionEngine {
1021
1019
  }
1022
1020
  if (second.status === 'ask') {
1023
1021
  // The approved row could not be used and a different question stands. Do not execute.
1024
- return this.deferred(second.approvalId, second.approvalUrl);
1022
+ return this.deferred(second.approvalId, second.approvalUrl, action);
1025
1023
  }
1026
1024
  return this.settle(provider, action, second);
1027
1025
  }
@@ -1048,7 +1046,7 @@ class ExecutionEngine {
1048
1046
  return this.inFlight(first.approvalId);
1049
1047
  default:
1050
1048
  // Still pending, or no time was left to wait.
1051
- return this.deferred(first.approvalId, first.approvalUrl);
1049
+ return this.deferred(first.approvalId, first.approvalUrl, action);
1052
1050
  }
1053
1051
  }
1054
1052
  /**
@@ -1069,7 +1067,7 @@ class ExecutionEngine {
1069
1067
  async settle(provider, action, answer) {
1070
1068
  switch (answer.status) {
1071
1069
  case 'allow':
1072
- return this.executeDelegated(provider, action, answer);
1070
+ return this.executeAllowed(provider, action, answer);
1073
1071
  case 'done':
1074
1072
  return { success: true, data: answer.result };
1075
1073
  case 'not_executed':
@@ -1117,10 +1115,97 @@ class ExecutionEngine {
1117
1115
  action,
1118
1116
  provider,
1119
1117
  decision: 'deny',
1120
- enforcementType: 'gateway',
1118
+ ...this.delegatedAuditKind(action),
1121
1119
  decisionSource: 'delegated_issuer',
1122
1120
  decisionReason: reason,
1123
- executionType: 'gateway',
1121
+ });
1122
+ }
1123
+ /** Audit kind of the delegated arms: a local action is executed (and enforced) on this machine. */
1124
+ delegatedAuditKind(action) {
1125
+ return (0, executor_registry_1.isLocalAction)(action)
1126
+ ? { enforcementType: 'gateway_verified_local', executionType: 'local' }
1127
+ : { enforcementType: 'gateway', executionType: 'gateway' };
1128
+ }
1129
+ /** `allow` from the issuer: a local action is presented and run here, a gateway action at the PEP. */
1130
+ executeAllowed(provider, action, allow) {
1131
+ return (0, executor_registry_1.isLocalAction)(action)
1132
+ ? this.executeLocalDelegated(provider, action, allow)
1133
+ : this.executeDelegated(provider, action, allow);
1134
+ }
1135
+ /**
1136
+ * A local action (`os.*`) after the issuer's `allow` (plan B, PR B3b): present the credential at
1137
+ * `local/present`, run EXACTLY the arguments it returns, write the outcome once
1138
+ * (`core/local-invoke.ts`). No wallet, no `verify-authorize`, no offline arm.
1139
+ */
1140
+ async executeLocalDelegated(provider, action, allow) {
1141
+ // No executor → do not present (presenting consumes the credential and burns the approval).
1142
+ if (!(0, executor_registry_1.getLocalExecutor)(action)) {
1143
+ await this.gatewayClient
1144
+ .delegatedRelease({ vcJti: allow.vcJti, subjectDid: this.context.agentDid })
1145
+ .catch(err => {
1146
+ process.stderr.write(`[vess] release of ${allow.vcJti} failed: ${err instanceof Error ? err.message : String(err)}\n`);
1147
+ });
1148
+ this.logAudit({
1149
+ action,
1150
+ provider,
1151
+ decision: 'deny',
1152
+ enforcementType: 'gateway_verified_local',
1153
+ decisionSource: 'delegated_issuer',
1154
+ decisionReason: 'no_local_executor',
1155
+ executionType: 'local',
1156
+ credentialId: allow.vcJti,
1157
+ });
1158
+ return { success: false, error: `No local executor for action: ${action}` };
1159
+ }
1160
+ const execution = await (0, local_invoke_1.executeLocalWithCredential)({ gateway: this.gatewayClient, vpBuilder: this.vpBuilder }, {
1161
+ agentDid: this.context.agentDid,
1162
+ projectId: this.context.projectId,
1163
+ agentPrivateKeyJwk: this.context.agentPrivateKeyJwk,
1164
+ gatewayUrl: this.context.gatewayUrl,
1165
+ }, action, allow, params => this.runLocalExecutor(action, params));
1166
+ this.logAudit({
1167
+ action,
1168
+ provider,
1169
+ decision: execution.success ? 'allow' : 'deny',
1170
+ enforcementType: 'gateway_verified_local',
1171
+ decisionSource: 'delegated_issuer',
1172
+ decisionReason: execution.success
1173
+ ? undefined
1174
+ : `${execution.outcome}: ${execution.error ?? ''}`,
1175
+ executionType: 'local',
1176
+ credentialId: allow.vcJti,
1177
+ // ðŸ”ī Which file / command: what RAN (the present's answer), or what was asked for when nothing ran.
1178
+ ...localAuditResource(action, execution.ran ?? allow.actionParams),
1179
+ ...(execution.normalizedResource ? { normalizedResource: execution.normalizedResource } : {}),
1180
+ ...(execution.resourceFingerprint
1181
+ ? { resourceFingerprint: execution.resourceFingerprint }
1182
+ : {}),
1183
+ });
1184
+ if (execution.success)
1185
+ return { success: true, data: execution.data };
1186
+ return { success: false, data: execution.data, error: execution.error };
1187
+ }
1188
+ /**
1189
+ * Run the local executor on the present answer's arguments.
1190
+ * ðŸ”ī `params` is the only input (`FrozenParams`): the env profile, the working directory, the file
1191
+ * path and the content all come from it.
1192
+ * ðŸ”ī `approvedResource` = the frozen `file_path`: the executor resolves the path again right before it
1193
+ * reads / writes and refuses if it now points elsewhere (a symlink swapped in after the approval,
1194
+ * plan B I-E). `approvedFingerprint` (inode binding) is not passed — Q21 default (a), the same
1195
+ * protection as the legacy path.
1196
+ */
1197
+ async runLocalExecutor(action, params) {
1198
+ const executor = (0, executor_registry_1.getLocalExecutor)(action);
1199
+ if (!executor)
1200
+ return { success: false, error: `No local executor for action: ${action}` };
1201
+ const args = params;
1202
+ if (action === 'os.process.run') {
1203
+ const resolvedEnv = await this.resolveProcessEnv(args);
1204
+ return executor(args, { resolvedEnv });
1205
+ }
1206
+ return executor(args, {
1207
+ rootDid: this.context.rootDid,
1208
+ approvedResource: typeof args.file_path === 'string' ? args.file_path : undefined,
1124
1209
  });
1125
1210
  }
1126
1211
  /** Present the credential and call the PEP with the issuer's arguments (`FrozenParams`). */
@@ -1172,10 +1257,9 @@ class ExecutionEngine {
1172
1257
  action,
1173
1258
  provider,
1174
1259
  decision: 'deny',
1175
- enforcementType: 'gateway',
1176
1260
  decisionSource: 'delegated_issuer',
1177
1261
  decisionReason: `refused: ${reason}`,
1178
- executionType: 'gateway',
1262
+ ...this.delegatedAuditKind(action),
1179
1263
  });
1180
1264
  return { success: false, error: `"${action}" was refused: ${reason}. Nothing was done.` };
1181
1265
  }
@@ -1185,10 +1269,9 @@ class ExecutionEngine {
1185
1269
  action,
1186
1270
  provider,
1187
1271
  decision: 'deny',
1188
- enforcementType: 'gateway',
1189
1272
  decisionSource: 'delegated_issuer',
1190
1273
  decisionReason: `policy_forbidden: ${reason}`,
1191
- executionType: 'gateway',
1274
+ ...this.delegatedAuditKind(action),
1192
1275
  });
1193
1276
  // ðŸ”ī Terminal: an approval cannot lift it, so no approval URL is offered.
1194
1277
  return {
@@ -1202,14 +1285,15 @@ class ExecutionEngine {
1202
1285
  action,
1203
1286
  provider,
1204
1287
  decision: 'deny',
1205
- enforcementType: 'gateway',
1206
1288
  decisionSource: 'delegated_issuer',
1207
1289
  decisionReason: `Gateway unreachable: ${msg}`,
1208
- executionType: 'gateway',
1290
+ ...this.delegatedAuditKind(action),
1209
1291
  });
1210
1292
  return {
1211
1293
  success: false,
1212
- error: `Gateway required for SaaS operations but unreachable: ${msg}. Nothing was done.`,
1294
+ error: (0, executor_registry_1.isLocalAction)(action)
1295
+ ? `Gateway required to authorize local actions but unreachable: ${msg}. Nothing was done.`
1296
+ : `Gateway required for SaaS operations but unreachable: ${msg}. Nothing was done.`,
1213
1297
  };
1214
1298
  }
1215
1299
  /**
@@ -1217,7 +1301,7 @@ class ExecutionEngine {
1217
1301
  * "call again once approved": an approved call is executed with the frozen arguments, and a resend
1218
1302
  * whose arguments differ by one character is a different question.
1219
1303
  */
1220
- deferred(approvalId, approvalUrl) {
1304
+ deferred(approvalId, approvalUrl, action) {
1221
1305
  return {
1222
1306
  success: true,
1223
1307
  data: {
@@ -1226,7 +1310,13 @@ class ExecutionEngine {
1226
1310
  approvalUrl,
1227
1311
  next: 'The owner must approve this at approvalUrl. Show them the URL. Do NOT call ' +
1228
1312
  'aidentity_call_tool again for this action: once approved it runs with exactly the ' +
1229
- 'arguments you sent. Read the outcome with aidentity_get_result { request_id }.',
1313
+ 'arguments you sent. Read the outcome with aidentity_get_result { request_id }.' +
1314
+ // ðŸ”ī Owner decision (2): a secret's content is kept nowhere, so a late approval cannot
1315
+ // deliver it. Say so, or an empty result reads as "the file is empty".
1316
+ (action && (0, local_invoke_1.readsSecret)(action)
1317
+ ? ' This action handles a secret: its content is not kept, so if it is approved after ' +
1318
+ 'this call, aidentity_get_result reports only that it ran, not the content.'
1319
+ : ''),
1230
1320
  },
1231
1321
  };
1232
1322
  }
@@ -1781,112 +1871,32 @@ class ExecutionEngine {
1781
1871
  // ===========================================================================
1782
1872
  /**
1783
1873
  * Pre-request permissions for multiple actions (batch).
1784
- * Triggers VC acquisition for each action without executing.
1785
- * This allows the user to approve multiple actions at once.
1874
+ * ðŸ”ī There is no pre-approval any more (B1 for gateway actions, B3b for local ones): every
1875
+ * credential is issued per call by the api's issuer (`aidentity_call_tool` → `pending` +
1876
+ * `request_id` when the owner must approve). Raising a legacy approval request here would create
1877
+ * a card that no new build ever executes. Only the device's own deny is reported (a local action
1878
+ * that the local / org policy forbids would be refused before the issuer is asked).
1786
1879
  */
1787
1880
  async requestPermissions(actions) {
1788
1881
  const approved = [];
1789
1882
  const denied = [];
1790
1883
  const pending = [];
1791
- // ðŸ”ī B1: gateway actions have no pre-approval. Their credential is issued per call by the api's
1792
- // issuer (`aidentity_call_tool` → `pending` + `request_id` when the owner must approve). Raising a
1793
- // legacy approval request here would create a card that no new build ever executes.
1794
1884
  const callDirectly = [];
1795
1885
  for (const action of actions) {
1796
1886
  const provider = action.split('.')[0];
1797
- if (!(0, executor_registry_1.isLocalAction)(action)) {
1798
- callDirectly.push(action);
1799
- continue;
1800
- }
1801
- // Policy check
1802
- const policyResult = this.policyEvaluator.evaluate(provider, action.replace(`${provider}.`, ''), { type: this.getResourceType(action) });
1803
- if (!policyResult.allowed) {
1804
- denied.push(action);
1805
- continue;
1806
- }
1807
- // Try VC acquisition (steps 1-3 only, no terminal prompt for batch)
1808
- try {
1809
- const walletVC = this.wallet.findCredential(this.context.agentDid, action, this.context.projectId);
1810
- if (walletVC) {
1811
- approved.push(action);
1887
+ if ((0, executor_registry_1.isLocalAction)(action)) {
1888
+ const policyResult = this.policyEvaluator.evaluate(provider, action.replace(`${provider}.`, ''), { type: this.getResourceType(action) });
1889
+ if (!policyResult.allowed) {
1890
+ denied.push(action);
1812
1891
  continue;
1813
1892
  }
1814
- // Try auto-issue
1815
- const autoResult = await this.gatewayClient.autoIssueVC({
1816
- subjectDid: this.context.agentDid,
1817
- projectId: this.context.projectId,
1818
- actions: [action],
1819
- });
1820
- if (autoResult?.autoIssued && autoResult.credential) {
1821
- this.wallet.storeCredential({
1822
- holderDid: this.context.agentDid,
1823
- projectId: this.context.projectId,
1824
- credentialJwt: autoResult.credential.jwt,
1825
- actions: autoResult.actions || [action],
1826
- provider,
1827
- expiresAt: autoResult.credential.expiresAt,
1828
- resources: (0, wallet_1.validateResources)(autoResult.resources),
1829
- metadata: autoResult.metadata,
1830
- });
1831
- approved.push(action);
1832
- continue;
1833
- }
1834
- pending.push(action);
1835
- }
1836
- catch {
1837
- pending.push(action);
1838
1893
  }
1894
+ callDirectly.push(action);
1839
1895
  }
1840
- const allApproved = denied.length === 0 && pending.length === 0 && callDirectly.length === 0;
1841
1896
  const callDirectlyNote = callDirectly.length > 0
1842
1897
  ? ` No pre-approval for [${callDirectly.join(', ')}]: call aidentity_call_tool directly; if the owner ` +
1843
1898
  `must approve, it answers status "pending" with a request_id, read later with aidentity_get_result.`
1844
1899
  : '';
1845
- // Create approval URL for pending actions (matches remote-mcp behavior)
1846
- if (pending.length > 0) {
1847
- try {
1848
- const approvalResult = await this.gatewayClient.createApprovalRequest({
1849
- subjectDid: this.context.agentDid,
1850
- projectId: this.context.projectId,
1851
- actions: pending,
1852
- });
1853
- if (!approvalResult.approvalUrl) {
1854
- throw new Error('Gateway returned empty approval URL');
1855
- }
1856
- return {
1857
- success: true,
1858
- data: {
1859
- approved,
1860
- denied,
1861
- pending,
1862
- ...(callDirectly.length > 0 ? { callDirectly } : {}),
1863
- requestId: approvalResult.requestId,
1864
- approvalUrl: approvalResult.approvalUrl,
1865
- expiresAt: approvalResult.expiresAt,
1866
- status: 'pending',
1867
- message: approved.length > 0
1868
- ? `Approved: [${approved.join(', ')}]. Approval required for: [${pending.join(', ')}]. See approvalUrl field.` +
1869
- callDirectlyNote
1870
- : `Permission required for: [${pending.join(', ')}]. See approvalUrl field.` +
1871
- callDirectlyNote,
1872
- },
1873
- };
1874
- }
1875
- catch (err) {
1876
- // Fallback: return pending without URL if approval request creation fails
1877
- return {
1878
- success: true,
1879
- data: {
1880
- approved,
1881
- denied,
1882
- pending,
1883
- ...(callDirectly.length > 0 ? { callDirectly } : {}),
1884
- status: 'partial',
1885
- message: `Approved: [${approved.join(', ')}]. Pending: [${pending.join(', ')}]. Denied: [${denied.join(', ')}]. Failed to create approval URL: ${err instanceof Error ? err.message : String(err)}. Use aidentity_call_tool for pending actions — you will be prompted to approve.${callDirectlyNote}`,
1886
- },
1887
- };
1888
- }
1889
- }
1890
1900
  return {
1891
1901
  success: true,
1892
1902
  data: {
@@ -1894,11 +1904,9 @@ class ExecutionEngine {
1894
1904
  denied,
1895
1905
  pending,
1896
1906
  ...(callDirectly.length > 0 ? { callDirectly } : {}),
1897
- status: allApproved ? 'approved' : 'partial',
1898
- message: allApproved
1899
- ? 'All requested permissions have been granted. You can now use aidentity_call_tool.'
1900
- : `Approved: [${approved.join(', ')}]. Denied: [${denied.join(', ')}].` +
1901
- callDirectlyNote,
1907
+ // Nothing to call and nothing denied (an empty request) is the only "approved".
1908
+ status: denied.length === 0 && callDirectly.length === 0 ? 'approved' : 'partial',
1909
+ message: `Approved: [${approved.join(', ')}]. Denied: [${denied.join(', ')}].` + callDirectlyNote,
1902
1910
  },
1903
1911
  };
1904
1912
  }