@sema-agent/core 7.53.0 → 7.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +277 -1
- package/LICENSE +3 -1
- package/dist/agents/peer-session-drain.d.ts +0 -1
- package/dist/agents/peer-session-drain.js +0 -2
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +3 -5
- package/dist/agents/subagent.js +18 -11
- package/dist/agents/tool-filter.d.ts +7 -4
- package/dist/agents/tool-filter.js +7 -3
- package/dist/core/a2a.js +4 -2
- package/dist/core/allow-entry.d.ts +1 -0
- package/dist/core/allow-entry.js +1 -0
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +49 -50
- package/dist/core/auto-compaction.js +41 -51
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +33 -18
- package/dist/core/checkpoint-store.js +5 -4
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +3 -0
- package/dist/core/effective-path-target.js +4 -0
- package/dist/core/engine-notice.d.ts +34 -2
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +10 -2
- package/dist/core/gate-lanes.js +30 -21
- package/dist/core/gate-outcome.d.ts +7 -3
- package/dist/core/governance-codes.d.ts +7 -2
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +14 -14
- package/dist/core/hooks.js +1 -2
- package/dist/core/locked-config.d.ts +28 -1
- package/dist/core/locked-config.js +30 -3
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-server-spec.d.ts +66 -9
- package/dist/core/mcp-server-spec.js +52 -19
- package/dist/core/mcp.js +5 -4
- package/dist/core/memory-engine/engine.js +2 -1
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +13 -8
- package/dist/core/mode-policy.js +3 -2
- package/dist/core/mods/kernel/receive.d.ts +2 -1
- package/dist/core/mods/kernel/receive.js +7 -2
- package/dist/core/parent-spec-seat.d.ts +10 -13
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +29 -6
- package/dist/core/permission-rule-model.js +6 -1
- package/dist/core/permission-rule-org.d.ts +37 -0
- package/dist/core/permission-rule-org.js +34 -42
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +33 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +75 -33
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/person-path-rows.d.ts +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +12 -15
- package/dist/core/runner/prepare-config-doors.js +8 -3
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +3 -2
- package/dist/core/runner/prepare-delegation-surface.js +2 -3
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +2 -2
- package/dist/core/runner/prepare-hands-readface.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +1 -0
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.js +2 -7
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +13 -10
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
- package/dist/core/runner/prepare-wiring-manifest.js +2 -2
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.js +9 -9
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/run-leg.js +57 -33
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +15 -4
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +9 -9
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +639 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +6 -4
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +6 -6
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +64 -23
- package/dist/core/tool-policy.js +62 -56
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +7 -0
- package/dist/core/untrusted-text.js +3 -8
- package/dist/core/user-attachment.d.ts +43 -0
- package/dist/core/user-attachment.js +92 -15
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/types.d.ts +7 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +2 -2
- package/dist/index.d.ts +23 -9
- package/dist/index.js +19 -8
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/catalog/schema.d.ts +3 -0
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/overlay.js +2 -2
- package/dist/prompt-assembly/select.js +2 -2
- package/dist/prompts/default.d.ts +1 -1
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/tools/artifact/artifact-tool.js +10 -0
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5654 -5520
- package/wire-changes/core@7.53.0.json +30 -8
- package/wire-changes/core@7.54.0.json +2870 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
package/LICENSE
CHANGED
|
@@ -3,7 +3,9 @@ Business Source License 1.1
|
|
|
3
3
|
Parameters
|
|
4
4
|
|
|
5
5
|
Licensor: clay (github.com/clayboby)
|
|
6
|
-
Licensed Work: @sema-agent/core (sema-core)
|
|
6
|
+
Licensed Work: @sema-agent/core (sema-core) and the satellite packages
|
|
7
|
+
published from this repository (currently
|
|
8
|
+
@sema-agent/mods-kernel)
|
|
7
9
|
(formerly published as @sema-ai/core)
|
|
8
10
|
The Licensed Work is (c) 2026 clay.
|
|
9
11
|
Additional Use Grant: You may make production use of the Licensed Work for
|
|
@@ -276,7 +276,6 @@ export declare function mountListAgents(args: {
|
|
|
276
276
|
name: string;
|
|
277
277
|
aliases?: readonly string[];
|
|
278
278
|
}>;
|
|
279
|
-
toolEffects: Map<string, "read" | "write" | "idempotent">;
|
|
280
279
|
/** The read faces' store seats, handed to the tool unchanged (see {@link ListAgentsReadSeats}). */
|
|
281
280
|
readSeats?: ListAgentsReadSeats;
|
|
282
281
|
}): ReturnType<typeof createListAgentsTool> | undefined;
|
|
@@ -781,8 +781,6 @@ function listAgentsNameFree(specTools) {
|
|
|
781
781
|
export function mountListAgents(args) {
|
|
782
782
|
if (!listAgentsNameFree(args.specTools))
|
|
783
783
|
return undefined;
|
|
784
|
-
args.toolEffects.set(LIST_AGENTS_TOOL_NAME, "read");
|
|
785
|
-
args.toolEffects.set(LIST_AGENTS_TOOL_ALIAS, "read");
|
|
786
784
|
return createListAgentsTool({
|
|
787
785
|
...(args.peerDirectory !== undefined ? { peerDirectory: args.peerDirectory } : {}),
|
|
788
786
|
...(args.freshWindowMs !== undefined ? { freshWindowMs: args.freshWindowMs } : {}),
|
|
@@ -20,6 +20,7 @@ import { thrownText } from "../core/thrown-value.js";
|
|
|
20
20
|
import { assertNoRetiredKeys } from "../core/retired-keys.js";
|
|
21
21
|
import { sliceHeadSafe } from "../core/surrogate-safe-slice.js";
|
|
22
22
|
import { clampValuesOf } from "../core/child-clamp-seats.js";
|
|
23
|
+
import { assertParentSpecSeatCurrent } from "../core/parent-spec-seat.js";
|
|
23
24
|
import { resolveSubagentTranscriptTier } from "../core/wiring-manifest.js";
|
|
24
25
|
export const SEND_MESSAGE_TOOL_NAME = "SendMessage";
|
|
25
26
|
let uplinkSeqGlobal = Date.now();
|
|
@@ -1010,6 +1011,7 @@ export function createSendMessageTool(opts) {
|
|
|
1010
1011
|
]);
|
|
1011
1012
|
if (!l3Verdict.ok)
|
|
1012
1013
|
return admissionRefusal(l3Verdict.reason, who);
|
|
1014
|
+
assertParentSpecSeatCurrent(ctx.parentSpecSeat);
|
|
1013
1015
|
const resume = createSubagentResume({
|
|
1014
1016
|
ledger,
|
|
1015
1017
|
parentToolCallId: resumeToolUseId,
|
|
@@ -1035,10 +1037,7 @@ export function createSendMessageTool(opts) {
|
|
|
1035
1037
|
...(opts.onNotifyError !== undefined ? { onNotifyError: opts.onNotifyError } : {}),
|
|
1036
1038
|
...(opts.notify ? { currentParentNotify: opts.notify } : {}),
|
|
1037
1039
|
...(ctx.onQuestion !== undefined && row.sessionScoped !== true ? { currentOnQuestion: ctx.onQuestion } : {}),
|
|
1038
|
-
currentClamps:
|
|
1039
|
-
...clampValuesOf(ctx, ctx.parentSpecSeat),
|
|
1040
|
-
...(ctx.parentSpecSeat?.memoryOff === true ? { memoryOff: true } : {}),
|
|
1041
|
-
},
|
|
1040
|
+
currentClamps: clampValuesOf(ctx, ctx.parentSpecSeat),
|
|
1042
1041
|
...(ctx.autoModeReview !== undefined ? { currentAutoModeReview: ctx.autoModeReview } : {}),
|
|
1043
1042
|
});
|
|
1044
1043
|
const fromPrefix = senderIsChild ? `(message from teammate "${senderLabel}")\n` : "";
|
|
@@ -428,11 +428,9 @@ export declare function createSubagentResume(deps: {
|
|
|
428
428
|
* resumer driving actions it could not perform itself. The fold is a union of restrictions (either
|
|
429
429
|
* side saying "restricted" wins), never a relaxation: a snapshot clamp is not lifted by a resumer
|
|
430
430
|
* that lacks it. Absent ⇒ the snapshot governs alone (prior behavior). The seats are the clamp table's rows
|
|
431
|
-
* (`ClampValues`: only restricting values
|
|
432
|
-
*
|
|
433
|
-
currentClamps?: import("../core/child-clamp-seats.js").ClampValues
|
|
434
|
-
memoryOff?: true;
|
|
435
|
-
};
|
|
431
|
+
* (`ClampValues`: only restricting values; a field row's is a partial declaration, written onto the snapshot's own
|
|
432
|
+
* declaration, never over it). */
|
|
433
|
+
currentClamps?: import("../core/child-clamp-seats.js").ClampValues;
|
|
436
434
|
/** The RESUMING caller's own handback-review seat (its trusted `ToolExecuteContext.autoModeReview`),
|
|
437
435
|
* same turn-bound reasoning as `currentOnQuestion` above: a resumed cycle is a completion like any
|
|
438
436
|
* other — its work reaches the durable row and the completion notification — and the decider that can
|
package/dist/agents/subagent.js
CHANGED
|
@@ -2,10 +2,10 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { isAbsolute } from "node:path";
|
|
3
3
|
import { backgroundChildTerminal } from "../core/delegation-frames.js";
|
|
4
4
|
import { bindDelegationName } from "../core/delegation-name.js";
|
|
5
|
-
import { resumeStartupCauseOf } from "../core/resume-startup-cause.js";
|
|
6
|
-
import { errorCodeOf } from "../core/runner/terminal-account.js";
|
|
7
|
-
import { applyParentSpecSeat,
|
|
8
|
-
import { assertClampRecord, childClampSeats, clampSeatsOf, clampSourceOf, engineHeadlessLegSeats, foldClampSources, postureUnderClamps } from "../core/child-clamp-seats.js";
|
|
5
|
+
import { resumeRefusalDetailOf, resumeStartupCauseOf } from "../core/resume-startup-cause.js";
|
|
6
|
+
import { errorCodeOf, thrownFailureOf } from "../core/runner/terminal-account.js";
|
|
7
|
+
import { applyParentSpecSeat, parentSpecSeatOfCtx } from "../core/parent-spec-seat.js";
|
|
8
|
+
import { applyClampSeats, assertClampRecord, childClampSeats, clampSeatsOf, clampSourceOf, engineHeadlessLegSeats, foldClampSources, postureUnderClamps } from "../core/child-clamp-seats.js";
|
|
9
9
|
import { assertNoRetiredKeys } from "../core/retired-keys.js";
|
|
10
10
|
import { stripSpawnTurnQuestionFace } from "../core/ask-question.js";
|
|
11
11
|
import { withDelegationProvenance } from "../core/tool-policy.js";
|
|
@@ -510,10 +510,11 @@ function createSteerHandle(stream, parentToolCallId, agentName, settled, retain)
|
|
|
510
510
|
const RETIRED_RESUME_CLAMP_KEYS = Object.freeze({
|
|
511
511
|
"currentClamps.readFaceRoots": 'the waker\'s read-face clamp is `currentClamps.readFace: "roots"` (the clamp table\'s own seat name)',
|
|
512
512
|
"currentClamps.writeFaceRoots": 'the waker\'s write-face clamp is `currentClamps.writeFace: "roots"` (the clamp table\'s own seat name)',
|
|
513
|
+
"currentClamps.memoryOff": "the waker's memory-off floor is `currentClamps.memory: { enabled: false }` (the clamp table's own seat, with the one member it clamps)",
|
|
513
514
|
});
|
|
514
515
|
export function createSubagentResume(deps) {
|
|
515
516
|
assertNoRetiredKeys(deps, RETIRED_RESUME_CLAMP_KEYS, "createSubagentResume");
|
|
516
|
-
assertClampRecord(deps.currentClamps, "createSubagentResume currentClamps"
|
|
517
|
+
assertClampRecord(deps.currentClamps, "createSubagentResume currentClamps");
|
|
517
518
|
const notifier = createSafeNotifier(deps.onNotifyError !== undefined ? { onError: deps.onNotifyError } : undefined);
|
|
518
519
|
const resume = async (content) => {
|
|
519
520
|
const ledger = deps.ledger;
|
|
@@ -573,17 +574,15 @@ export function createSubagentResume(deps) {
|
|
|
573
574
|
entry.resumeCount += 1;
|
|
574
575
|
entry.cycleSeq += 1;
|
|
575
576
|
const wakeClamps = foldClampSources(entry.specSnapshot, deps.currentClamps);
|
|
576
|
-
const resumeSpec = {
|
|
577
|
+
const resumeSpec = applyClampSeats({
|
|
577
578
|
...entry.specSnapshot,
|
|
578
579
|
objective: createResumePrompt(marker, content, deps.peerOrigin !== undefined ? "peer" : "operator"),
|
|
579
580
|
sessionId: entry.childSessionId,
|
|
580
581
|
requireExistingSession: true,
|
|
581
582
|
...(deps.currentOnQuestion !== undefined ? { onQuestion: deps.currentOnQuestion } : {}),
|
|
582
583
|
...childClampSeats(wakeClamps),
|
|
583
|
-
...clampSeatsOf(wakeClamps, "specSeat"),
|
|
584
|
-
...(deps.currentClamps?.memoryOff === true ? { memory: memoryTurnedOff(entry.specSnapshot.memory) } : {}),
|
|
585
584
|
signal: abort.signal,
|
|
586
|
-
};
|
|
585
|
+
}, clampSeatsOf(wakeClamps, "specSeat"));
|
|
587
586
|
if (deps.registry !== undefined && deps.taskId !== undefined && deps.taskAccess !== undefined) {
|
|
588
587
|
const revived = await deps.registry.reviveBackgroundAgent(deps.taskId, deps.taskAccess, abort);
|
|
589
588
|
if (!revived.ok) {
|
|
@@ -2114,6 +2113,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2114
2113
|
...(inheritedSkillGrants.length > 0 ? { inheritedSkillGrants } : {}),
|
|
2115
2114
|
...(inheritedAllowedTools !== undefined && inheritedAllowedTools.length > 0 ? { inheritedAllowedTools: [...inheritedAllowedTools] } : {}),
|
|
2116
2115
|
...(childProvenanceRef !== undefined && provenanceRequest !== undefined ? { delegationProvenance: { ref: childProvenanceRef, contentSafety: provenanceRequest } } : {}),
|
|
2116
|
+
...(reviveClaim === undefined && ctx.crossBoundaryTreeForChildren !== undefined ? { crossBoundaryTree: ctx.crossBoundaryTreeForChildren } : {}),
|
|
2117
2117
|
...(treeScope !== undefined ? { registryScope: treeScope } : {}),
|
|
2118
2118
|
...(ctx.checkpointScopeForChildren !== undefined ? { checkpointScope: ctx.checkpointScopeForChildren } : {}),
|
|
2119
2119
|
...(ctx.inheritedGateForChildren ? { inheritedGate: ctx.inheritedGateForChildren() } : {}),
|
|
@@ -2523,6 +2523,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2523
2523
|
...(rowModelKey !== undefined ? { model: rowModelKey } : {}),
|
|
2524
2524
|
deliveryChannel: "attaching",
|
|
2525
2525
|
toolUseId: ctx.toolCallId,
|
|
2526
|
+
...(ctx.crossBoundaryTreeForChildren !== undefined ? { crossBoundaryTree: ctx.crossBoundaryTreeForChildren } : {}),
|
|
2526
2527
|
...(bg.agentStore !== undefined ? { store: bg.agentStore } : {}),
|
|
2527
2528
|
abort,
|
|
2528
2529
|
});
|
|
@@ -3065,6 +3066,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
3065
3066
|
...(rowModelKey !== undefined ? { model: rowModelKey } : {}),
|
|
3066
3067
|
deliveryChannel: "attaching",
|
|
3067
3068
|
toolUseId: ctx.toolCallId,
|
|
3069
|
+
...(ctx.crossBoundaryTreeForChildren !== undefined ? { crossBoundaryTree: ctx.crossBoundaryTreeForChildren } : {}),
|
|
3068
3070
|
...(bg.agentStore !== undefined ? { store: bg.agentStore } : {}),
|
|
3069
3071
|
abort,
|
|
3070
3072
|
});
|
|
@@ -3667,11 +3669,16 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
3667
3669
|
]);
|
|
3668
3670
|
if (startup === "settled") {
|
|
3669
3671
|
if (parkedResume !== undefined) {
|
|
3670
|
-
const failure = await bgChildPromise.then((r) => ({ err: undefined, cause: resumeStartupCauseOf(r.terminal.kind === "failed" ? r.terminal.code : undefined) }), (e) => ({ err: childThrownText(e), cause: resumeStartupCauseOf(errorCodeOf(e)) }));
|
|
3672
|
+
const failure = await bgChildPromise.then((r) => ({ err: undefined, cause: resumeStartupCauseOf(r.terminal.kind === "failed" ? r.terminal.code : undefined), refusal: undefined }), (e) => ({ err: childThrownText(e), cause: resumeStartupCauseOf(errorCodeOf(e)), refusal: resumeRefusalDetailOf(thrownFailureOf(e, "").detail) }));
|
|
3671
3673
|
return {
|
|
3672
3674
|
isError: true,
|
|
3673
3675
|
content: `Parked resume did not complete: ${(failure.err ?? "the resumed run settled before its delivery lane bound").slice(0, 600)}`,
|
|
3674
|
-
details: {
|
|
3676
|
+
details: {
|
|
3677
|
+
error: "parked_resume.startup_failed",
|
|
3678
|
+
task_id: taskId,
|
|
3679
|
+
...(failure.cause !== undefined ? { cause: failure.cause } : {}),
|
|
3680
|
+
...(failure.refusal !== undefined ? { detail: failure.refusal } : {}),
|
|
3681
|
+
},
|
|
3675
3682
|
};
|
|
3676
3683
|
}
|
|
3677
3684
|
return notStartedResult({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentDefinition, ToolSpec } from "../core/types.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type ToolLegKind, type ToolSelector, type ToolSelectorLayer } from "../core/tool-face.js";
|
|
3
3
|
import { type ProtocolId } from "../core/protocol-table.js";
|
|
4
4
|
import { type ToolNameListReading } from "../core/tool-name-list.js";
|
|
5
5
|
/**
|
|
@@ -121,6 +121,9 @@ type UniverseTool = {
|
|
|
121
121
|
readonly name: string;
|
|
122
122
|
readonly aliases?: readonly string[];
|
|
123
123
|
};
|
|
124
|
+
/** Do the layers ABOVE a leg decide a protocol row of these kinds? Yes when some kind of the row shares its spawner's tool surface
|
|
125
|
+
* ({@link SPAWNER_SURFACE_LEG_KINDS}): the leg holds it exactly when its spawner may. Any other row is the leg's own channel. */
|
|
126
|
+
export declare function protocolRowUnderCeiling(rowLegs: readonly ToolLegKind[]): boolean;
|
|
124
127
|
/** The wire names a leg of these kinds relies on (the catalog's protocol column). */
|
|
125
128
|
export declare function protocolToolNames(legs: readonly ToolLegKind[]): string[];
|
|
126
129
|
/** Is this value a layer — an object (not a list) with the two lists `allow` / `deny`? One that is not admits NOTHING here;
|
|
@@ -130,9 +133,9 @@ export declare function isToolSelectorLayer(layer: unknown): layer is ToolSelect
|
|
|
130
133
|
* Compile ONE run's tool selector from its layers (the ceiling it was spawned under, then its own lists — the LAST layer is its own)
|
|
131
134
|
* and the kinds of leg it is. Each list is read by the one reading ({@link readAllowedToolList} / {@link readDeniedToolList}) and
|
|
132
135
|
* matched by the one matcher ({@link listReaches}); a protocol tool of one of `legs` is admitted whatever the leg's own lists say —
|
|
133
|
-
* and whatever the ceiling says too, unless
|
|
134
|
-
* layers decide it
|
|
135
|
-
* producer passes frozen copies of the lists it read.
|
|
136
|
+
* and whatever the ceiling says too, unless a kind of its row shares its spawner's tool surface ({@link protocolRowUnderCeiling}):
|
|
137
|
+
* the ceiling layers decide it. Whether a list may reach a protocol tool at all is judged at prepare. The layers are kept as handed —
|
|
138
|
+
* the producer passes frozen copies of the lists it read.
|
|
136
139
|
*/
|
|
137
140
|
export declare function compileToolSelector(layers: readonly ToolSelectorLayer[], legs?: readonly ToolLegKind[]): ToolSelector;
|
|
138
141
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { canonicalize, UNCANONICALIZABLE } from "../core/canonical-json.js";
|
|
3
|
+
import { SPAWNER_SURFACE_LEG_KINDS } from "../core/tool-face.js";
|
|
3
4
|
import { ruleSpellingOf } from "../core/permission-rule-syntax.js";
|
|
4
5
|
import { TOOL_CATALOG_ENTRIES } from "../core/tool-catalog-entries.js";
|
|
5
6
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "../core/namespaced-rule-name.js";
|
|
@@ -118,7 +119,10 @@ export function listReaches(reach, tool) {
|
|
|
118
119
|
}
|
|
119
120
|
return false;
|
|
120
121
|
}
|
|
121
|
-
const PROTOCOL_ROWS = Object.freeze(TOOL_CATALOG_ENTRIES.flatMap((e) => (e.protocol !== undefined ? [Object.freeze({ name: e.name, legs: e.protocol
|
|
122
|
+
const PROTOCOL_ROWS = Object.freeze(TOOL_CATALOG_ENTRIES.flatMap((e) => (e.protocol !== undefined ? [Object.freeze({ name: e.name, legs: e.protocol })] : [])));
|
|
123
|
+
export function protocolRowUnderCeiling(rowLegs) {
|
|
124
|
+
return rowLegs.some((l) => SPAWNER_SURFACE_LEG_KINDS.includes(l));
|
|
125
|
+
}
|
|
122
126
|
export function protocolToolNames(legs) {
|
|
123
127
|
return [...new Set(PROTOCOL_ROWS.filter((r) => r.legs.some((l) => legs.includes(l))).map((r) => r.name))];
|
|
124
128
|
}
|
|
@@ -147,7 +151,7 @@ export function compileToolSelector(layers, legs = []) {
|
|
|
147
151
|
const kept = Object.freeze([...layers]);
|
|
148
152
|
const compiled = kept.map((l) => (isToolSelectorLayer(l) ? { allow: readAllowedToolList(l.allow), deny: readDeniedToolList(l.deny) } : NO_TOOL_LAYER));
|
|
149
153
|
const admittedBy = (ls, tool) => ls.every((l) => (l.allow === undefined || listReaches(l.allow, tool)) && !listReaches(l.deny, tool));
|
|
150
|
-
const protocol = new Map(PROTOCOL_ROWS.filter((r) => r.legs.some((l) => legs.includes(l))).map((r) => [r.name, r.
|
|
154
|
+
const protocol = new Map(PROTOCOL_ROWS.filter((r) => r.legs.some((l) => legs.includes(l))).map((r) => [r.name, protocolRowUnderCeiling(r.legs)]));
|
|
151
155
|
return Object.freeze({
|
|
152
156
|
layers: kept,
|
|
153
157
|
admits: (tool) => {
|
|
@@ -182,7 +186,7 @@ export function deniedProtocolTools(layers, legs) {
|
|
|
182
186
|
const reached = (ds) => ds.some((d) => listReaches(d, { name: r.name }));
|
|
183
187
|
if (reached(own))
|
|
184
188
|
hits.set(`own:${r.name}`, { name: r.name, own: true });
|
|
185
|
-
if (!r.
|
|
189
|
+
if (!protocolRowUnderCeiling(r.legs) && reached(inherited))
|
|
186
190
|
hits.set(`inherited:${r.name}`, { name: r.name, own: false });
|
|
187
191
|
}
|
|
188
192
|
return [...hits.values()];
|
package/dist/core/a2a.js
CHANGED
|
@@ -8,6 +8,7 @@ import { A2A_NAMESPACE } from "./protocol-table.js";
|
|
|
8
8
|
import { judgeEntryToolAxes, refusedDeclarer, snapshotDeclaredEntry } from "./locked-config.js";
|
|
9
9
|
import { delimitUntrusted, inlineUntrusted } from "./untrusted-text.js";
|
|
10
10
|
import { thrownText } from "./thrown-value.js";
|
|
11
|
+
import { boundaryFlowFace } from "./cross-boundary-taint.js";
|
|
11
12
|
const A2A_REQUEST_TIMEOUT_MS = 30_000;
|
|
12
13
|
const A2A_CARD_TIMEOUT_MS = 10_000;
|
|
13
14
|
const A2A_CALL_TOTAL_TIMEOUT_MS = 10 * 60_000;
|
|
@@ -567,9 +568,10 @@ async function materializePeer(peer, principal, lifecycle, signal) {
|
|
|
567
568
|
for (const skill of card.skills) {
|
|
568
569
|
if (spec.allowSkills !== undefined && !spec.allowSkills.includes(skill.id))
|
|
569
570
|
continue;
|
|
570
|
-
const
|
|
571
|
+
const declared = declaredAxes?.[skill.id];
|
|
572
|
+
const tool = { ...buildSkillTool(spec, transport, skill, lifecycle), ...boundaryFlowFace(declared) };
|
|
571
573
|
tools.push(tool);
|
|
572
|
-
skillAxes.push(a2aAxisFor(tool.name,
|
|
574
|
+
skillAxes.push(a2aAxisFor(tool.name, declared));
|
|
573
575
|
}
|
|
574
576
|
return {
|
|
575
577
|
tools,
|
|
@@ -276,6 +276,7 @@ export declare const SHADOW_REASON: Readonly<{
|
|
|
276
276
|
readonly denial_limit_fallback: "the auto-mode classifier refused too many calls in a row, so a person decides";
|
|
277
277
|
readonly classifier_no_ruling: "the auto-mode classifier could not judge this call, so a person decides";
|
|
278
278
|
readonly requires_user_interaction: "this tool's server declares that a call must be put to a person";
|
|
279
|
+
readonly cross_boundary: string;
|
|
279
280
|
readonly operator_forced: "this call arrived already marked as requiring confirmation (an earlier layer of this run, or the task that delegated it, judged it so) — it is cleared by confirming this call, never by a standing allow rule";
|
|
280
281
|
readonly shell_floor: string;
|
|
281
282
|
readonly target_unresolved: string;
|
package/dist/core/allow-entry.js
CHANGED
|
@@ -363,6 +363,7 @@ export const SHADOW_REASON = Object.freeze({
|
|
|
363
363
|
denial_limit_fallback: "the auto-mode classifier refused too many calls in a row, so a person decides",
|
|
364
364
|
classifier_no_ruling: "the auto-mode classifier could not judge this call, so a person decides",
|
|
365
365
|
requires_user_interaction: "this tool's server declares that a call must be put to a person",
|
|
366
|
+
cross_boundary: mandateDisclosureOf("cross_boundary_taint"),
|
|
366
367
|
operator_forced: "this call arrived already marked as requiring confirmation (an earlier layer of this run, or the task that delegated it, judged it so) — it is cleared by confirming this call, never by a standing allow rule",
|
|
367
368
|
shell_floor: mandateDisclosureOf("operator_always"),
|
|
368
369
|
target_unresolved: mandateDisclosureOf("target_unresolved"),
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { PendingAction } from "./checkpoint-store.js";
|
|
2
|
+
import type { CallTargetReading } from "./effective-path-target.js";
|
|
3
|
+
import { type SkillGrantSource } from "./skill-grant.js";
|
|
4
|
+
import type { ToolCallPathTarget, ToolFamily } from "./tool-face.js";
|
|
5
|
+
import { type ToolRosterEntry } from "./tool-roster.js";
|
|
6
|
+
type ParkedApproval = Extract<PendingAction, {
|
|
7
|
+
kind: "tool_approval";
|
|
8
|
+
}>;
|
|
9
|
+
/** The readings of a call's path slot a target is bound under ({@link CallTargetReading}'s two directions). */
|
|
10
|
+
export declare const APPROVAL_TARGET_ROLES: readonly ["protective", "declared"];
|
|
11
|
+
export type ApprovalTargetRole = (typeof APPROVAL_TARGET_ROLES)[number];
|
|
12
|
+
/** The row's `targets` member: per role, the location the target RESOLVED to when the card was asked (the canonical
|
|
13
|
+
* view of that reading), or `null` when the environment was asked and did not answer — an unresolved target binds
|
|
14
|
+
* "unresolved", so a later resolution is a move. A role the environment was not asked about is absent; a row with no
|
|
15
|
+
* such role carries none. */
|
|
16
|
+
export type ApprovalTargets = {
|
|
17
|
+
readonly [R in ApprovalTargetRole]?: string | null;
|
|
18
|
+
};
|
|
19
|
+
/** The tool member as the row carries it: every member optional (a row is read, never trusted to be whole). */
|
|
20
|
+
export interface ApprovalTool {
|
|
21
|
+
readonly capabilityId?: string;
|
|
22
|
+
readonly contractId?: string;
|
|
23
|
+
readonly shapeDigest?: string;
|
|
24
|
+
readonly implementationRevision?: string;
|
|
25
|
+
readonly family?: ToolFamily;
|
|
26
|
+
readonly pathTarget?: ToolCallPathTarget;
|
|
27
|
+
}
|
|
28
|
+
export interface ApprovalObject {
|
|
29
|
+
/** Absent on a row minted before the identity members (all four absent): such a row binds the tool's name alone. */
|
|
30
|
+
readonly tool?: ApprovalTool;
|
|
31
|
+
/** The row's member as stored — read, validated, by the judge. */
|
|
32
|
+
readonly targets?: unknown;
|
|
33
|
+
readonly grants?: string;
|
|
34
|
+
}
|
|
35
|
+
/** The view of one parked approval's object. */
|
|
36
|
+
export declare function approvalObjectOf(row: ParkedApproval): ApprovalObject;
|
|
37
|
+
/** The `targets` member of a reading: per role, the canonical view, or `null` for a view the environment was asked for
|
|
38
|
+
* and did not answer; nothing when no role was read either way (or no reading was taken). The park mints it from the
|
|
39
|
+
* gate's reading of the parked bytes; the execution station reads the bytes that will run the same way. */
|
|
40
|
+
export declare function approvalTargetsOf(reading: CallTargetReading | undefined): {
|
|
41
|
+
targets?: ApprovalTargets;
|
|
42
|
+
};
|
|
43
|
+
/** Where a resume judges the object: before the claim (the decided bytes), before the session is touched (the live
|
|
44
|
+
* tool), right before the execution (the tool as mounted then — a host's re-dial can replace it between the two — and the
|
|
45
|
+
* bytes that will run, after every station that can rewrite them). */
|
|
46
|
+
export type ApprovalStation = "claim" | "session" | "execution";
|
|
47
|
+
export type ApprovalMember = "tool" | "targets" | "grants";
|
|
48
|
+
/** THE table: the members each station judges. */
|
|
49
|
+
export declare const APPROVAL_STATION_MEMBERS: {
|
|
50
|
+
readonly [S in ApprovalStation]: readonly ApprovalMember[];
|
|
51
|
+
};
|
|
52
|
+
/** What a station does with a mismatch: refuse with the row still pending (before the claim), reopen it for the
|
|
53
|
+
* original tool, or veto the call (not run, approval spent). */
|
|
54
|
+
export type ApprovalDisposition = "refuse_pending" | "reopen" | "veto";
|
|
55
|
+
export interface ApprovalMismatch {
|
|
56
|
+
readonly member: ApprovalMember;
|
|
57
|
+
readonly disposition: ApprovalDisposition;
|
|
58
|
+
/** The machine word: the reopen codes, `resume.target_moved` on a moved face or target (the vetoed call's
|
|
59
|
+
* `tool_end.errorCode`); absent on a grants veto. */
|
|
60
|
+
readonly code?: "resume.tool_unavailable" | "resume.tool_contract_mismatch" | "resume.target_moved" | "checkpoint.invalid_outcome";
|
|
61
|
+
readonly message: string;
|
|
62
|
+
}
|
|
63
|
+
/** What the station holds of the live call. */
|
|
64
|
+
export interface LiveApprovalObject {
|
|
65
|
+
/** session / execution: the live roster row the leg would run the call as — `undefined` when the tool is not mounted. */
|
|
66
|
+
readonly tool?: ToolRosterEntry | undefined;
|
|
67
|
+
/** claim / execution: the bytes the station judges, the skills this resume serves and the Skill tool's wire name. */
|
|
68
|
+
readonly args?: unknown;
|
|
69
|
+
readonly skills?: readonly SkillGrantSource[];
|
|
70
|
+
readonly skillToolName?: string;
|
|
71
|
+
/** execution: the reading of the bytes that will run, taken at this station (`undefined`: none could be taken). */
|
|
72
|
+
readonly targetReading?: CallTargetReading | undefined;
|
|
73
|
+
/** execution: the bytes the decision rewrote the call to, as the tool reads them; absent when it rewrote nothing. When
|
|
74
|
+
* the row's binding does not cover them ({@link licenseCovers}, the one judge of "are these the approved bytes") the
|
|
75
|
+
* person approved bytes whose target the row never recorded, and the targets member is not judged. */
|
|
76
|
+
readonly decided?: unknown;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* THE judge of a parked approval at one station: `"match"`, or the first member the table names for the station that
|
|
80
|
+
* the live call does not match, with its disposition. Absence is read per member: a tool member with no identity
|
|
81
|
+
* binds the name alone, and one with SOME identity members is a replacement (never a pre-identity row); a grants
|
|
82
|
+
* member is judged whenever the call would activate a skill (a row with no digest cannot cover one); a targets member
|
|
83
|
+
* is judged unless the decision rewrote the bytes to ones the row's binding does not cover, and one that is not a whole
|
|
84
|
+
* role → location record is damage.
|
|
85
|
+
*/
|
|
86
|
+
export declare function judgeApprovalObject(row: ParkedApproval, live: LiveApprovalObject, station: ApprovalStation): "match" | ApprovalMismatch;
|
|
87
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { canonicalize } from "./canonical-json.js";
|
|
2
|
+
import { licenseCovers } from "./tool-policy.js";
|
|
3
|
+
import { parkedSkillApprovalRefusal } from "./skill-grant.js";
|
|
4
|
+
import { toolIdentityOf } from "./tool-roster.js";
|
|
5
|
+
import { inlineUntrusted } from "./untrusted-text.js";
|
|
6
|
+
export const APPROVAL_TARGET_ROLES = Object.freeze(["protective", "declared"]);
|
|
7
|
+
export function approvalObjectOf(row) {
|
|
8
|
+
const { capabilityId, contractId, shapeDigest, implementationRevision, family, pathTarget, targets, boundGrantDigest } = row;
|
|
9
|
+
const carried = [capabilityId, contractId, shapeDigest, implementationRevision].some((m) => m !== undefined);
|
|
10
|
+
return {
|
|
11
|
+
...(carried ? { tool: { capabilityId, contractId, shapeDigest, implementationRevision, family, pathTarget } } : {}),
|
|
12
|
+
...(targets !== undefined ? { targets } : {}),
|
|
13
|
+
...(boundGrantDigest !== undefined ? { grants: boundGrantDigest } : {}),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function approvalTargetsOf(reading) {
|
|
17
|
+
const targets = {};
|
|
18
|
+
for (const role of APPROVAL_TARGET_ROLES) {
|
|
19
|
+
const view = reading?.[role];
|
|
20
|
+
if (view?.kind === "path" && (view.canonical !== undefined || view.unread === true))
|
|
21
|
+
targets[role] = view.canonical ?? null;
|
|
22
|
+
}
|
|
23
|
+
return Object.keys(targets).length > 0 ? { targets } : {};
|
|
24
|
+
}
|
|
25
|
+
export const APPROVAL_STATION_MEMBERS = Object.freeze({
|
|
26
|
+
claim: Object.freeze(["grants"]),
|
|
27
|
+
session: Object.freeze(["tool"]),
|
|
28
|
+
execution: Object.freeze(["tool", "grants", "targets"]),
|
|
29
|
+
});
|
|
30
|
+
const IDENTITY_MEMBERS = Object.freeze(["capabilityId", "contractId", "shapeDigest", "implementationRevision"]);
|
|
31
|
+
const shown = (s) => `"${inlineUntrusted(s, 240)}"`;
|
|
32
|
+
const vetoed = (name, why) => `The approved tool call "${name}" was not executed: ${why}, so the approval does not cover it (resume.target_moved). This approval is spent — the call has to be re-issued: its new card shows what it would act on now.`;
|
|
33
|
+
function faceKey(family, pt) {
|
|
34
|
+
const slot = pt === undefined ? null : { param: pt.param, access: pt.access, aliases: [...(pt.aliases ?? [])], base: pt.base ?? "cwd", absent: pt.absent ?? "none", patternParam: pt.patternParam ?? null, skillScopeEligible: pt.skillScopeEligible === true };
|
|
35
|
+
return canonicalize({ family: family ?? null, pathTarget: slot });
|
|
36
|
+
}
|
|
37
|
+
function judgeTool(row, live) {
|
|
38
|
+
const entry = live.tool;
|
|
39
|
+
if (entry === undefined)
|
|
40
|
+
return { member: "tool", disposition: "reopen", code: "resume.tool_unavailable", message: `the approved tool "${row.toolName}" is no longer available on resume — refusing to continue as if it ran; the checkpoint is reopened for a retry with the tool present` };
|
|
41
|
+
const bound = approvalObjectOf(row).tool;
|
|
42
|
+
if (bound === undefined)
|
|
43
|
+
return undefined;
|
|
44
|
+
const id = toolIdentityOf(entry);
|
|
45
|
+
const differ = IDENTITY_MEMBERS.filter((k) => bound[k] !== id[k]);
|
|
46
|
+
if (differ.length > 0) {
|
|
47
|
+
const named = differ.map((k) => (bound[k] === undefined ? `${k} (missing on the row)` : k)).join(", ");
|
|
48
|
+
return { member: "tool", disposition: "reopen", code: "resume.tool_contract_mismatch", message: `the approved tool "${row.toolName}" on this leg is not the tool the approval was minted against (${named} differ) — refusing to execute a replacement wearing the name; the checkpoint is reopened for a retry with the original tool present` };
|
|
49
|
+
}
|
|
50
|
+
if (faceKey(bound.family, bound.pathTarget) === faceKey(entry.family, entry.pathTarget))
|
|
51
|
+
return undefined;
|
|
52
|
+
return { member: "tool", disposition: "veto", code: "resume.target_moved", message: vetoed(row.toolName, "the tool's face (its display family or the path target it declares) changed after the approval") };
|
|
53
|
+
}
|
|
54
|
+
function judgeTargets(row, live) {
|
|
55
|
+
const bound = row.targets;
|
|
56
|
+
if (bound === undefined || ("decided" in live && !licenseCovers(row.boundInputHash, live.decided)))
|
|
57
|
+
return undefined;
|
|
58
|
+
const roles = typeof bound === "object" && bound !== null && !Array.isArray(bound) ? Object.entries(bound) : [];
|
|
59
|
+
const whole = roles.length > 0 && roles.every(([k, v]) => APPROVAL_TARGET_ROLES.includes(k) && (v === null || (typeof v === "string" && v.length > 0)));
|
|
60
|
+
if (!whole)
|
|
61
|
+
return { member: "targets", disposition: "veto", code: "resume.target_moved", message: vetoed(row.toolName, "the target member of the approval on its checkpoint row is damaged (not a reading → resolved location record)") };
|
|
62
|
+
const now = approvalTargetsOf(live.targetReading).targets ?? {};
|
|
63
|
+
const where = (p) => (p === null ? "did not resolve" : `resolved to ${shown(p)}`);
|
|
64
|
+
for (const [role, was] of roles) {
|
|
65
|
+
const is = now[role];
|
|
66
|
+
if (is === was)
|
|
67
|
+
continue;
|
|
68
|
+
return { member: "targets", disposition: "veto", code: "resume.target_moved", message: vetoed(row.toolName, is === undefined ? `where its target resolves (it ${where(was)} when the card was asked) could not be established on this leg` : `its target ${is === null ? "does not resolve" : `resolves to ${shown(is)}`} now and ${where(was)} when the card was asked`) };
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
function judgeGrants(row, live, station) {
|
|
73
|
+
const refusal = parkedSkillApprovalRefusal(row, live.args, live.skills ?? [], live.skillToolName ?? "", station);
|
|
74
|
+
if (refusal === undefined)
|
|
75
|
+
return undefined;
|
|
76
|
+
return station === "claim" ? { member: "grants", disposition: "refuse_pending", code: "checkpoint.invalid_outcome", message: refusal } : { member: "grants", disposition: "veto", message: refusal };
|
|
77
|
+
}
|
|
78
|
+
export function judgeApprovalObject(row, live, station) {
|
|
79
|
+
for (const member of APPROVAL_STATION_MEMBERS[station]) {
|
|
80
|
+
const miss = member === "tool" ? judgeTool(row, live) : member === "targets" ? judgeTargets(row, live) : judgeGrants(row, live, station === "claim" ? "claim" : "execution");
|
|
81
|
+
if (miss !== undefined)
|
|
82
|
+
return miss;
|
|
83
|
+
}
|
|
84
|
+
return "match";
|
|
85
|
+
}
|
|
@@ -2,8 +2,9 @@ import { type Egress } from "./untrusted-egress.js";
|
|
|
2
2
|
/** A SHORT, SECRET-SCRUBBED primary-arg summary. Abbreviation REDUCES the surface; the `same-principal` tier's pass
|
|
3
3
|
* is the leak boundary, on whichever field the summary came from (the value is PERSISTED + SSE-forwarded and may be
|
|
4
4
|
* read by a platform operator in a multi-tenant deployment). Rules:
|
|
5
|
-
* • command → the command NAME
|
|
6
|
-
*
|
|
5
|
+
* • command → the command NAME: the first segment's written command word past its control words and the
|
|
6
|
+
* assignments bash strips (bail to `undefined` on an unparseable text, a lone assignment, an assignment-shaped
|
|
7
|
+
* or computed command word; basename a path-form command; `+ …` if more follows).
|
|
7
8
|
* • file path → BASENAME only (no host directory layout).
|
|
8
9
|
* • url → `new URL` origin+pathname (drops `user:pass@` userinfo + query/fragment).
|
|
9
10
|
* • else → pattern/query/description, else the first string field whose name is no credential name.
|
package/dist/core/arg-summary.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readProgramPosition } from "../tools/fs/bash-program-position.js";
|
|
2
|
+
import { argvOf, lexShell } from "../shell/lex.js";
|
|
2
3
|
import { isSensitiveRecordKey } from "./credential-vocabulary.js";
|
|
3
4
|
import { egressText } from "./untrusted-egress.js";
|
|
4
5
|
const ACTIVITY_ARG_MAX = 80;
|
|
@@ -17,17 +18,22 @@ export function primaryActivityArg(args) {
|
|
|
17
18
|
const path = str("file_path") ?? str("filePath") ?? str("path") ?? str("notebook_path");
|
|
18
19
|
const url = str("url");
|
|
19
20
|
if (command !== undefined) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
const lexed = lexShell(command);
|
|
22
|
+
if ("parseFailure" in lexed)
|
|
23
|
+
return undefined;
|
|
24
|
+
const named = lexed.segments.map((segment) => {
|
|
25
|
+
const argv = argvOf(segment);
|
|
26
|
+
const pos = readProgramPosition(argv);
|
|
27
|
+
return { segment, word: pos.written === undefined ? undefined : argv[pos.written + pos.assignments.length] };
|
|
28
|
+
}).find((s) => s.word !== undefined);
|
|
29
|
+
if (named?.word === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
const word = named.word;
|
|
32
|
+
if (word.assignment !== undefined || word.expansions.length > 0 || word.unresolved !== undefined)
|
|
28
33
|
return undefined;
|
|
29
|
-
const name = basename(
|
|
30
|
-
|
|
34
|
+
const name = basename(word.folded);
|
|
35
|
+
const more = named.segment.tokens.indexOf(word) < named.segment.tokens.length - 1 || lexed.segments.slice(lexed.segments.indexOf(named.segment) + 1).some((s) => s.tokens.length > 0);
|
|
36
|
+
val = more ? `${name} …` : name;
|
|
31
37
|
}
|
|
32
38
|
else if (path !== undefined) {
|
|
33
39
|
val = basename(path);
|