@sema-agent/core 7.49.5 → 7.50.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 +138 -0
- package/dist/agents/observer.js +3 -10
- package/dist/agents/subagent-steps.d.ts +6 -14
- package/dist/agents/subagent-steps.js +3 -17
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/core/allow-entry.d.ts +1 -1
- package/dist/core/allow-entry.js +1 -1
- package/dist/core/ask-origin.d.ts +15 -11
- package/dist/core/ask-origin.js +6 -14
- package/dist/core/auto-mode-prompt.js +6 -2
- package/dist/core/checkpoint-store.d.ts +6 -4
- package/dist/core/checkpoint-store.js +1 -1
- package/dist/core/context-edit.d.ts +2 -2
- package/dist/core/decision-receipt.d.ts +2 -2
- package/dist/core/decision-receipt.js +30 -11
- package/dist/core/delegation-frames.d.ts +66 -18
- package/dist/core/delegation-frames.js +22 -0
- package/dist/core/engine-notice.d.ts +7 -5
- package/dist/core/frame-settlement.d.ts +6 -1
- package/dist/core/gate-fold.js +19 -13
- package/dist/core/gate-lanes.js +12 -11
- package/dist/core/gate-outcome.d.ts +2 -2
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +28 -20
- package/dist/core/human-input-projection.js +2 -0
- package/dist/core/lsp-diagnostics.d.ts +3 -0
- package/dist/core/lsp-diagnostics.js +6 -0
- package/dist/core/lsp-session.d.ts +39 -17
- package/dist/core/lsp-session.js +118 -58
- package/dist/core/lsp.d.ts +83 -3
- package/dist/core/lsp.js +146 -16
- package/dist/core/mcp.js +2 -1
- package/dist/core/media-byte-cap.d.ts +14 -0
- package/dist/core/media-byte-cap.js +15 -3
- package/dist/core/memory-engine/consolidation-driver.d.ts +23 -1
- package/dist/core/memory-engine/consolidation-driver.js +54 -6
- package/dist/core/memory-engine/consolidation-write-gate.d.ts +46 -0
- package/dist/core/memory-engine/consolidation-write-gate.js +82 -0
- package/dist/core/memory-engine/consolidation.d.ts +17 -0
- package/dist/core/memory-engine/consolidation.js +1 -0
- package/dist/core/memory-engine/distiller.d.ts +8 -2
- package/dist/core/memory-engine/distiller.js +8 -6
- package/dist/core/memory-engine/engine.d.ts +37 -4
- package/dist/core/memory-engine/engine.js +127 -38
- package/dist/core/memory-engine/file-backend.d.ts +8 -3
- package/dist/core/memory-engine/file-backend.js +44 -16
- package/dist/core/memory-engine/index.d.ts +2 -2
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/landing-admission.d.ts +65 -0
- package/dist/core/memory-engine/landing-admission.js +68 -0
- package/dist/core/memory-engine/types.d.ts +23 -0
- package/dist/core/mode-policy.d.ts +3 -2
- package/dist/core/mode-policy.js +2 -0
- package/dist/core/permission-rule-model.d.ts +19 -13
- package/dist/core/permission-rule-model.js +7 -4
- package/dist/core/permission-rule-provider.d.ts +11 -0
- package/dist/core/permission-rules.d.ts +1 -1
- package/dist/core/permission-rules.js +5 -2
- package/dist/core/persisted-rule-arms.d.ts +15 -7
- package/dist/core/persisted-rule-arms.js +13 -6
- package/dist/core/reminder-mint.d.ts +5 -0
- package/dist/core/reminder-mint.js +1 -0
- package/dist/core/retired-keys.d.ts +8 -0
- package/dist/core/retired-keys.js +4 -0
- package/dist/core/rule-lane-reads.d.ts +4 -4
- package/dist/core/rule-lane-reads.js +10 -1
- package/dist/core/runner/construction-doors.d.ts +10 -4
- package/dist/core/runner/construction-doors.js +25 -2
- package/dist/core/runner/contracts.d.ts +20 -3
- package/dist/core/runner/env-capability-census.js +1 -1
- package/dist/core/runner/gate-exit.js +2 -1
- package/dist/core/runner/memory-consolidation-driver.d.ts +6 -4
- package/dist/core/runner/memory-consolidation-driver.js +5 -2
- package/dist/core/runner/memory-consolidation-write-judge.d.ts +17 -0
- package/dist/core/runner/memory-consolidation-write-judge.js +14 -0
- package/dist/core/runner/permission-rule-lanes.d.ts +16 -22
- package/dist/core/runner/permission-rule-lanes.js +13 -43
- package/dist/core/runner/person-path-rows.d.ts +244 -0
- package/dist/core/runner/person-path-rows.js +387 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +8 -1
- package/dist/core/runner/prepare-artifact.d.ts +5 -3
- package/dist/core/runner/prepare-artifact.js +2 -8
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -3
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-context-lane.js +2 -2
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -3
- package/dist/core/runner/prepare-gate-stations.js +1 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +19 -10
- package/dist/core/runner/prepare-hands-readface.js +57 -43
- package/dist/core/runner/prepare-lsp.d.ts +15 -13
- package/dist/core/runner/prepare-lsp.js +11 -11
- package/dist/core/runner/prepare-policy-chain.d.ts +8 -4
- package/dist/core/runner/prepare-policy-chain.js +6 -7
- package/dist/core/runner/prepare-run-refs.js +1 -1
- package/dist/core/runner/prepare-task.js +24 -16
- package/dist/core/runner/prepare-turn-wiring.d.ts +13 -6
- package/dist/core/runner/prepare-turn-wiring.js +19 -8
- package/dist/core/runner/read-root-grant.d.ts +1 -25
- package/dist/core/runner/read-root-grant.js +1 -17
- package/dist/core/runner/retired-runner-deps.d.ts +2 -2
- package/dist/core/runner/run-brain-sinks.d.ts +1 -5
- package/dist/core/runner/run-brain-sinks.js +2 -4
- package/dist/core/runner/run-harness-handlers.js +5 -4
- package/dist/core/runner/run-identity-wiring.d.ts +4 -4
- package/dist/core/runner/run-identity-wiring.js +10 -1
- package/dist/core/runner/run-leg.d.ts +1 -1
- package/dist/core/runner/run-leg.js +22 -9
- package/dist/core/runner/run-settle-and-teardown.d.ts +0 -4
- package/dist/core/runner/run-settle-and-teardown.js +7 -4
- package/dist/core/runner/run-terminal-adoption.d.ts +1 -1
- package/dist/core/runner/run-terminal-adoption.js +1 -1
- package/dist/core/runner/run-turn-boundary.js +2 -2
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-file-state-replay.d.ts +14 -4
- package/dist/core/runner/session-file-state-replay.js +8 -0
- package/dist/core/runner/stream-steer-verb.js +3 -0
- package/dist/core/runner/tool-end-body.d.ts +5 -4
- package/dist/core/runner/tool-end-body.js +4 -4
- package/dist/core/runner/tool-output-projection.d.ts +6 -4
- package/dist/core/runner/tool-output-projection.js +66 -47
- package/dist/core/runner-deps.d.ts +6 -3
- package/dist/core/shared-memory/types.d.ts +2 -2
- package/dist/core/shell-read-silence.d.ts +23 -0
- package/dist/core/shell-read-silence.js +18 -0
- package/dist/core/synthetic-read-verdict.d.ts +80 -21
- package/dist/core/synthetic-read-verdict.js +89 -18
- package/dist/core/task-event.d.ts +113 -25
- package/dist/core/task-spec.d.ts +44 -0
- package/dist/core/task-tool-shape.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +16 -2
- package/dist/core/tool-policy.d.ts +25 -15
- package/dist/core/tool-policy.js +9 -13
- package/dist/core/trace.d.ts +3 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +2 -2
- package/dist/core/user-attachment.d.ts +164 -0
- package/dist/core/user-attachment.js +437 -0
- package/dist/engine/compaction/compaction.js +10 -3
- package/dist/engine/compaction/utils.js +6 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +19 -1
- package/dist/engine/execution-env/node-execution-env.js +125 -0
- package/dist/engine/harness/agent-harness.d.ts +12 -2
- package/dist/engine/harness/agent-harness.js +15 -3
- package/dist/engine/harness/types.d.ts +21 -0
- package/dist/engine/llm/content-block-render.d.ts +15 -0
- package/dist/engine/llm/content-block-render.js +10 -0
- package/dist/engine/llm/index.d.ts +1 -0
- package/dist/engine/llm/index.js +1 -0
- package/dist/engine/llm/types.d.ts +80 -4
- package/dist/engine/llm/types.js +43 -1
- package/dist/engine/session/import-validate.js +2 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -1
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/workflow.d.ts +4 -5
- package/dist/orchestration/workflow.js +2 -2
- package/dist/prompts/default.d.ts +1 -1
- package/dist/tools/artifact/artifact-tool.js +1 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/dir-entries.d.ts +4 -10
- package/dist/tools/fs/dir-entries.js +4 -11
- package/dist/tools/fs/file-read-check.js +3 -3
- package/dist/tools/fs/fs-pdf.js +2 -4
- package/dist/tools/fs/fs-read.d.ts +47 -4
- package/dist/tools/fs/fs-read.js +63 -19
- package/dist/tools/fs/fs-search-tools.d.ts +3 -3
- package/dist/tools/fs/fs-search-tools.js +7 -2
- package/dist/tools/fs/fs-write.d.ts +1 -1
- package/dist/tools/fs/fs-write.js +7 -6
- package/dist/tools/fs/index.d.ts +7 -1
- package/dist/tools/fs/index.js +56 -34
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +32 -22
- package/dist/tools/fs/read-deny.d.ts +14 -0
- package/dist/tools/fs/read-deny.js +8 -0
- package/dist/tools/fs/repo-map.d.ts +3 -2
- package/dist/tools/fs/repo-map.js +11 -3
- package/dist/tools/fs/safety.d.ts +41 -2
- package/dist/tools/fs/safety.js +12 -3
- package/dist/tools/fs/shell-read-check.d.ts +12 -3
- package/dist/tools/fs/shell-read-check.js +28 -15
- package/dist/tools/fs/shell-read-device.d.ts +1 -1
- package/dist/tools/fs/shell-read-judge.d.ts +9 -4
- package/dist/tools/fs/shell-read-judge.js +1 -1
- package/dist/tools/loop-tick.d.ts +2 -2
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +39 -1
- package/wire-changes/core@7.50.0.json +1699 -0
- package/dist/core/runner/persisted-path-rows.d.ts +0 -88
- package/dist/core/runner/persisted-path-rows.js +0 -108
|
@@ -20,7 +20,8 @@ import { RosterBuilder } from "../tool-roster.js";
|
|
|
20
20
|
import type { AgentTool, RunnerDeps } from "../types.js";
|
|
21
21
|
import type { ContainmentFace } from "../../tools/fs/index.js";
|
|
22
22
|
import type { PlacedReadDenyMatcher } from "../../tools/fs/read-deny-home.js";
|
|
23
|
-
import {
|
|
23
|
+
import type { ArtifactStoreRef } from "./read-root-grant.js";
|
|
24
|
+
import type { ReadRootsSeat } from "./person-path-rows.js";
|
|
24
25
|
import type { Prepared } from "./contracts.js";
|
|
25
26
|
import type { ToolOccurrenceTable } from "./tool-occurrence.js";
|
|
26
27
|
export interface PrepareArtifactInput {
|
|
@@ -48,8 +49,9 @@ export interface PrepareArtifactInput {
|
|
|
48
49
|
/** borrowed-readonly — the canonical task root the fs fence contains reads to; undefined ⇒ no local-file publish. */
|
|
49
50
|
rootCanonical: string | undefined;
|
|
50
51
|
/** borrowed-readonly — the extra containment roots (write and read-only) the fence admits, read per call (the run's
|
|
51
|
-
* live set: an in-flight read-root grant widens it)
|
|
52
|
-
|
|
52
|
+
* live set: an in-flight read-root grant widens it); `ready` settles once the run's newest tables are compiled — this
|
|
53
|
+
* reader is no call, and reads them only then. */
|
|
54
|
+
additionalRootsCanonical: (() => readonly string[]) & Pick<ReadRootsSeat, "ready">;
|
|
53
55
|
/** borrowed-readonly — the read-deny matcher in force for the run, when any. */
|
|
54
56
|
readDenyMatcher: PlacedReadDenyMatcher | undefined;
|
|
55
57
|
/** borrowed-readonly — the resolved read face (`"open"` lifts root containment for reads). */
|
|
@@ -5,9 +5,7 @@ import { RosterBuilder } from "../tool-roster.js";
|
|
|
5
5
|
import { defineTool } from "../tools.js";
|
|
6
6
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
7
7
|
import { physicalPathOfExisting } from "../physical-path.js";
|
|
8
|
-
import { resolveKey, violationDetails, violationText } from "../../tools/fs/safety.js";
|
|
9
|
-
import { rootAdmittingArtifactStore, withdrawStandingGrantsAdmitting } from "./read-root-grant.js";
|
|
10
|
-
import { emitTrace } from "../trace.js";
|
|
8
|
+
import { resolveKey, rootAdmittingArtifactStore, violationDetails, violationText } from "../../tools/fs/safety.js";
|
|
11
9
|
import { createArtifactTool } from "../../tools/artifact/artifact-tool.js";
|
|
12
10
|
import { thrownText } from "../thrown-value.js";
|
|
13
11
|
export function prepareArtifact(input) {
|
|
@@ -30,11 +28,6 @@ export function prepareArtifact(input) {
|
|
|
30
28
|
const storePhysical = storageDir !== undefined && rootCanonical !== undefined ? physicalPathOfExisting(storageDir) : undefined;
|
|
31
29
|
if (artifactStoreRef !== undefined)
|
|
32
30
|
artifactStoreRef.current = storePhysical;
|
|
33
|
-
if (artifactStoreRef !== undefined && storePhysical !== undefined) {
|
|
34
|
-
for (const entry of withdrawStandingGrantsAdmitting(storePhysical, artifactStoreRef)) {
|
|
35
|
-
emitTrace(deps.tracer, () => ({ kind: "config.additional_directory_skipped", version: 1, taskId, entry, field: "persistedReadRule", reason: `admits_artifact_store: the local artifact store ${storageDir} lies inside it or it inside the store — the Artifact tool's ledger and stored files stay outside every root the file tools reach`, ts: Date.now() }));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
31
|
if (storePhysical !== undefined && rootCanonical !== undefined) {
|
|
39
32
|
const overlapping = rootAdmittingArtifactStore(storePhysical, [rootCanonical, ...additionalRootsCanonical()]);
|
|
40
33
|
if (overlapping !== undefined)
|
|
@@ -49,6 +42,7 @@ export function prepareArtifact(input) {
|
|
|
49
42
|
const readLocalFile = async (path, maxBytes, signal) => {
|
|
50
43
|
if (rootCanonical === undefined)
|
|
51
44
|
return { ok: false, reason: "refused", text: "Error (Artifact): this task has no filesystem root, so a local file cannot be published." };
|
|
45
|
+
await additionalRootsCanonical.ready(signal);
|
|
52
46
|
const rk = await resolveKey(executionEnv, rootCanonical, path, signal, handsCwdRef?.current, additionalRootsCanonical, undefined, readDenyMatcher, resolvedReadFace);
|
|
53
47
|
if (!rk.ok)
|
|
54
48
|
return { ok: false, reason: "refused", text: violationText("Artifact", rk.violation), details: violationDetails(rk.violation) };
|
|
@@ -114,8 +114,9 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
114
114
|
* arming facts (the deny bits, the face, the re-entrant arm) are bound onto it here. */
|
|
115
115
|
permissionMode: PermissionModeController;
|
|
116
116
|
/** borrowed-readonly — LATE-BOUND: the effective read-deny table the hands phase compiles (the rows the classifier's deny
|
|
117
|
-
* paragraph renders); read at ARMING, which the driver runs after that phase — never at this phase's own call
|
|
118
|
-
|
|
117
|
+
* paragraph renders); read at ARMING, which the driver runs after that phase — never at this phase's own call — once the
|
|
118
|
+
* run's newest tables are compiled (an arming is no call). */
|
|
119
|
+
readDenyEntries: () => Promise<{
|
|
119
120
|
readonly entries: ReadonlyArray<{
|
|
120
121
|
readonly pattern: string;
|
|
121
122
|
readonly caseSensitive?: boolean;
|
|
@@ -124,7 +125,7 @@ export interface PrepareCapsAndWorkflowInput {
|
|
|
124
125
|
readonly tool: string;
|
|
125
126
|
readonly pattern: string;
|
|
126
127
|
}>;
|
|
127
|
-
}
|
|
128
|
+
}>;
|
|
128
129
|
/** borrowed-readonly — the peer lane's mount verdict (the classifier's cross-session rule fills only while mounted). */
|
|
129
130
|
peerLaneActive: boolean;
|
|
130
131
|
/** borrowed-readonly — the leg's effective delegation fact (`effectiveDelegationFacts`): the classifier window shows its user lane as the launching agent's. */
|
|
@@ -226,7 +226,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
226
226
|
}
|
|
227
227
|
announceClassifierRoleDefaulted({ onNotice: deps.onNotice, seat: { ...classifierSeat, model: classifierModel }, ...(sessionId !== undefined ? { sessionId } : {}), ...(runId !== undefined ? { runId } : {}) });
|
|
228
228
|
const classifierLaneRule = peerLaneActive && peerSendMessageBuiltIn;
|
|
229
|
-
const table = readDenyEntries();
|
|
229
|
+
const table = await readDenyEntries();
|
|
230
230
|
const derivedDenyRules = readDenyClassifierRules(table.entries, table.ruleRows);
|
|
231
231
|
let classifierSystemPromptMemo;
|
|
232
232
|
const classifierSystemPrompt = () => (classifierSystemPromptMemo ??= buildAutoModePrompt({ ...am, derivedDenyRules, ...(classifierLaneRule ? { crossSessionMessagesRule: CROSS_SESSION_CLASSIFIER_RULE } : {}) }));
|
|
@@ -2,7 +2,7 @@ import { DEFAULT_CHARS_PER_TOKEN, estimateContextTokens } from "../../internal/h
|
|
|
2
2
|
import { TOOL_TURN_REPAIR_DROPS } from "../../internal/llm.js";
|
|
3
3
|
import { clearStaleToolResults, createClearedProjectionLedger, dropEmptyFailureAssistants, editBudget, replayClearedProjection, resolveTriggerWindow } from "../context-edit.js";
|
|
4
4
|
import { guardBudget, insertTrimNotice, protectGitFrame, trimToBudget } from "../context-guard.js";
|
|
5
|
-
import {
|
|
5
|
+
import { capAggregateMediaBytes, mediaBudgetBytes } from "../media-byte-cap.js";
|
|
6
6
|
import { capAggregateToolResults } from "../tool-result-budget.js";
|
|
7
7
|
import { createOffloadPersist } from "../tool-result-store.js";
|
|
8
8
|
import { emitTrace } from "../trace.js";
|
|
@@ -50,7 +50,7 @@ export function prepareContextLane(input) {
|
|
|
50
50
|
}))),
|
|
51
51
|
});
|
|
52
52
|
const mediaCapped = capAggregateMediaBytes(capped, {
|
|
53
|
-
limitBytes: deps.mediaByteCapBytes
|
|
53
|
+
limitBytes: mediaBudgetBytes(deps.mediaByteCapBytes),
|
|
54
54
|
onStripped: (info) => {
|
|
55
55
|
const onMediaStripped = deps.onMediaStripped;
|
|
56
56
|
if (onMediaStripped !== undefined)
|
|
@@ -155,9 +155,9 @@ export interface PrepareGateStationsInput {
|
|
|
155
155
|
handsCwdRef: CwdRef | undefined;
|
|
156
156
|
/** borrowed-readonly — the leg's target-reading stamp, or undefined (hands-less): the gate stamps its request with it. */
|
|
157
157
|
stampCallTarget: CallTargetStamp | undefined;
|
|
158
|
-
/** borrowed-readonly — the
|
|
159
|
-
* beside them (the deployment's and the task's patterns, the read-face rule rows). Empty ⇒ no table. */
|
|
160
|
-
readDenyInForce: () => {
|
|
158
|
+
/** borrowed-readonly — the read-deny table the released call was judged with, read at its release: the active built-in
|
|
159
|
+
* tiers and the rows beside them (the deployment's and the task's patterns, the read-face rule rows). Empty ⇒ no table. */
|
|
160
|
+
readDenyInForce: (toolCallId: string) => {
|
|
161
161
|
readonly tiers: readonly string[];
|
|
162
162
|
readonly rows: readonly string[];
|
|
163
163
|
};
|
|
@@ -50,7 +50,7 @@ export function prepareGateStations(input) {
|
|
|
50
50
|
const gatePreToolUse = ownGatePreToolUse !== undefined ? (name, args, ctx) => ownGatePreToolUse(name, args, { ...ctx, permissionMode: permissionMode.observed }) : undefined;
|
|
51
51
|
const releasesAnnounced = new Map();
|
|
52
52
|
const onModeReleased = (info) => {
|
|
53
|
-
const table = info.readUnestablished === true ? input.readDenyInForce() : undefined;
|
|
53
|
+
const table = info.readUnestablished === true ? input.readDenyInForce(info.toolCallId) : undefined;
|
|
54
54
|
if (table !== undefined && table.tiers.length + table.rows.length > 0) {
|
|
55
55
|
const named = [...(table.tiers.length > 0 ? [`built-in tiers ${table.tiers.join(", ")}`] : []), ...table.rows.slice(0, 8), ...(table.rows.length > 8 ? [`${table.rows.length - 8} more`] : [])].join("; ");
|
|
56
56
|
deliverEngineNotice(deps.onNotice, {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type BeforeWriteHook, type CwdRef, type PathRuleDenyRow, type ContainmentFace } from "../../tools/fs/index.js";
|
|
2
2
|
import { type ReadFileState } from "../../tools/fs/safety.js";
|
|
3
|
-
import { type
|
|
3
|
+
import { type PathTablesFacade, type PersonPathRows, type ReadRootsSeat } from "./person-path-rows.js";
|
|
4
4
|
import type { HeadLeads } from "../path-rule-binding.js";
|
|
5
5
|
import { type ShellReadAdmission, type ShellReadCheck } from "../../tools/fs/shell-read-check.js";
|
|
6
6
|
import type { ShellReadBoundary } from "../../tools/fs/shell-read-judge.js";
|
|
@@ -56,19 +56,17 @@ export interface PrepareHandsReadFaceInput {
|
|
|
56
56
|
/** borrowed-readonly — the registry scope (`internals?.registryScope ?? spec.principal ??
|
|
57
57
|
* "default"`, computed in the driver); the band's task-registry scope. */
|
|
58
58
|
taskScope: string;
|
|
59
|
-
/** borrowed-readonly — the
|
|
60
|
-
*
|
|
61
|
-
* read face's matcher and to the shell station's write face. */
|
|
59
|
+
/** borrowed-readonly — the leg's own deny-table rows: the face-keyed path deny rules of the leg's caller policy and of every
|
|
60
|
+
* ancestor's, each bound where it was installed (`toolPolicyPathRules`); the person's join them per read ({@link personRows}). */
|
|
62
61
|
denyRuleRows: readonly PathRuleDenyRow[];
|
|
62
|
+
/** borrowed-readonly — the run's one reader of the person's rules: the run's tables are compiled here over it. */
|
|
63
|
+
personRows: PersonPathRows;
|
|
63
64
|
/** borrowed-readonly — the leg's one resolution of where rule heads lead (the rows' twins, the same the gate's lanes read). */
|
|
64
65
|
headLeads: HeadLeads;
|
|
65
66
|
/** borrowed-readonly — the ONE judgment a shell command's write targets meet for the mode's file-command placement: the
|
|
66
67
|
* leg's write judgment over the write-protection table and the chain's guarded write rows (read per judgment — it is
|
|
67
68
|
* compiled at the manifest phase, before any gate is mounted). Absent ⇒ none (a standalone phase drive). */
|
|
68
69
|
writeTargetJudge?: () => ShellReadBoundary["writeTargetJudge"];
|
|
69
|
-
/** borrowed-readonly — the directories of the person's persisted `Read(//dir/**)` allow rows: read directories of this
|
|
70
|
-
* run, canonicalized and admitted exactly as `additionalReadDirectories` entries are. */
|
|
71
|
-
persistedReadDirectories?: readonly string[];
|
|
72
70
|
/** borrowed-readonly — the leg's mode seat, read LIVE by the write face ({@link writeFaceReader}): its mode's face
|
|
73
71
|
* is the resolver's row 3′ on every write. */
|
|
74
72
|
permissionMode: {
|
|
@@ -160,6 +158,11 @@ export interface PrepareHandsReadFaceInput {
|
|
|
160
158
|
* band's Read/notebook/PDF trailer outlets bump keys on it at tool-execute time (the driver owns
|
|
161
159
|
* the object and folds it into result stats). */
|
|
162
160
|
reminderDisclosureCounts: import("../reminder-disclosure.js").ReminderDisclosureCounts;
|
|
161
|
+
/** borrowed-mutable — where the band hands out the leg's one file reader (the Read tool's), for the leg's other
|
|
162
|
+
* carriers of a file (attachment frames): written once at mount, left empty when hands do not mount. */
|
|
163
|
+
modelFileReaderSeat?: {
|
|
164
|
+
current?: import("../../tools/fs/fs-read.js").ModelFileReader;
|
|
165
|
+
};
|
|
163
166
|
/** borrowed-readonly — the first-touch history hook prepare built (present iff the run records file history into a
|
|
164
167
|
* wired store and mounts a real fs env); threaded to the write band's trackFileEdit seat. */
|
|
165
168
|
trackFileEdit?: import("../types.js").TrackFileEditHook;
|
|
@@ -218,6 +221,8 @@ export interface PrepareHandsReadFaceResult {
|
|
|
218
221
|
/** owned — the same station's pre-spawn ADMISSION, published for the P11 face that spawns a shell command
|
|
219
222
|
* and mounts LATER than the band (`Monitor`): the SAME function the band's shell faces got. ⇔ a real shell. */
|
|
220
223
|
shellReadAdmission: ShellReadAdmission | undefined;
|
|
224
|
+
/** owned — the file read station's admission (`FileReadStation.admitted`) the band's read tools got, for the read tools mounted later (LSP). */
|
|
225
|
+
readAdmission: ((toolCallId: string | undefined, canonicalKey: string) => boolean) | undefined;
|
|
221
226
|
/** write-back (D-3 hold) — the run's RESOLVED read face where hands mount; undefined ⇔ no hands
|
|
222
227
|
* (the hands-less value lives in `handsLessResolvedFace`). The driver assigns this onto its
|
|
223
228
|
* outer `let` for the call-time closures (ctx enrichment / checkpoint mint / envFacts). */
|
|
@@ -258,9 +263,13 @@ export interface PrepareHandsReadFaceResult {
|
|
|
258
263
|
/** owned — the canonical containment root, published so the working-file ATTACHMENT
|
|
259
264
|
* reader applies the same containment the hands tools do. Undefined ⇔ hands-less. */
|
|
260
265
|
attachmentRootCanonical: string | undefined;
|
|
261
|
-
/** owned — the
|
|
262
|
-
*
|
|
263
|
-
readDenyMatcher:
|
|
266
|
+
/** owned — the run's read deny table ({@link pathTables}' facade: the run's latest, `forCall` a call's own). Undefined ⇔
|
|
267
|
+
* hands-less (its consumers only exist with hands). */
|
|
268
|
+
readDenyMatcher: PathTablesFacade["readDeny"] | undefined;
|
|
269
|
+
/** owned — the read face's root set per judgment: write roots, read roots with grants, the person's read directories. */
|
|
270
|
+
readRoots: ReadRootsSeat;
|
|
271
|
+
/** owned — the run's path tables ({@link PathTablesFacade}); undefined ⇔ hands-less. */
|
|
272
|
+
pathTables: PathTablesFacade | undefined;
|
|
264
273
|
/** owned — the shell-seat PROVENANCE set: the shell-running tools whose tier the engine's shell seat (read
|
|
265
274
|
* boundary + shape tier + shellGate floor) is the SOLE POSITIVE source of — no explicit deployment mark on that name.
|
|
266
275
|
* The one seat every consumer reads (risk grading, the gate's tighten attribution, the persisted-rule mandate
|
|
@@ -2,17 +2,19 @@ import { emitTrace } from "../trace.js";
|
|
|
2
2
|
import { StubExecutionEnv } from "../stub-env.js";
|
|
3
3
|
import { hasBackgroundShell } from "../background-shell.js";
|
|
4
4
|
import { defaultTaskRegistry } from "../task-registry.js";
|
|
5
|
-
import { bashReversibilityProbe, activeReadDenyBuiltinTiers, readDenyBuiltinConfigOf, compileReadDeny,
|
|
6
|
-
import { resolveKey, sha256 } from "../../tools/fs/safety.js";
|
|
7
|
-
import {
|
|
5
|
+
import { bashReversibilityProbe, activeReadDenyBuiltinTiers, readDenyBuiltinConfigOf, compileReadDeny, createHandsToolkit, deploymentFaceClampNotice, pdfModelCapabilitiesOf, inheritSessionReadFileState, backgroundOutputReadExemption, resolveContainmentFace, seedReadFileStateFromContext, seedReadFileStateFromTranscript, } from "../../tools/fs/index.js";
|
|
6
|
+
import { resolveKey, rootAdmittingArtifactStore, sha256 } from "../../tools/fs/safety.js";
|
|
7
|
+
import { thrownText } from "../thrown-value.js";
|
|
8
|
+
import { carryReadFace } from "../../tools/fs/read-deny-home.js";
|
|
9
|
+
import { EMPTY_READ_ROOTS, afterCallTables, denySeatsOf, onPinnedRead, pathTablesCompile, readRootsOver } from "./person-path-rows.js";
|
|
8
10
|
import { createShellOverflowSpoolFence } from "../../tools/fs/fs-shared.js";
|
|
9
11
|
import { createShellReadStation } from "../../tools/fs/shell-read-check.js";
|
|
10
|
-
import {
|
|
12
|
+
import { createFileReadStation } from "../../tools/fs/file-read-check.js";
|
|
11
13
|
import { isShellFaceToolName, predictMountedToolNames, readTargetToolNames } from "../tool-registry.js";
|
|
12
14
|
import { normalizeFileText } from "../../tools/fs/encoding.js";
|
|
13
15
|
import { wholeFileRecordsFromTranscript } from "./session-file-state-replay.js";
|
|
14
16
|
import { deliverEngineNotice } from "../types.js";
|
|
15
|
-
import { readRootGrantOver
|
|
17
|
+
import { readRootGrantOver } from "./read-root-grant.js";
|
|
16
18
|
import { sessionSeatAnchorHolds } from "./session-read-file-states.js";
|
|
17
19
|
import { rebaseWorkspacePath } from "./workspace-path.js";
|
|
18
20
|
import { RosterBuilder } from "../tool-roster.js";
|
|
@@ -101,6 +103,7 @@ export function resolveHandsLessReadFace(input) {
|
|
|
101
103
|
shellReadCheck: undefined,
|
|
102
104
|
shellReadStationArmed: false,
|
|
103
105
|
shellReadAdmission: undefined,
|
|
106
|
+
readAdmission: undefined,
|
|
104
107
|
resolvedReadFace: undefined,
|
|
105
108
|
resolvedWriteFace: undefined,
|
|
106
109
|
readDenyAdditionsNormalized,
|
|
@@ -113,6 +116,8 @@ export function resolveHandsLessReadFace(input) {
|
|
|
113
116
|
artifactStoreRef: undefined,
|
|
114
117
|
attachmentRootCanonical: undefined,
|
|
115
118
|
readDenyMatcher: undefined,
|
|
119
|
+
readRoots: EMPTY_READ_ROOTS,
|
|
120
|
+
pathTables: undefined,
|
|
116
121
|
envHandToolNames: new Set(),
|
|
117
122
|
shellGatedTools: new Set(),
|
|
118
123
|
sealReadStateSeat: undefined,
|
|
@@ -148,6 +153,8 @@ export async function prepareHandsMount(input) {
|
|
|
148
153
|
const artifactStoreRef = { current: undefined };
|
|
149
154
|
let attachmentRootCanonical;
|
|
150
155
|
let readDenyMatcher;
|
|
156
|
+
let pathTables;
|
|
157
|
+
let readRoots = EMPTY_READ_ROOTS;
|
|
151
158
|
if (handsEnabled) {
|
|
152
159
|
const rootCanonical = taskRootCanonical;
|
|
153
160
|
attachmentRootCanonical = rootCanonical;
|
|
@@ -178,10 +185,6 @@ export async function prepareHandsMount(input) {
|
|
|
178
185
|
};
|
|
179
186
|
await canonicalizeExtraDirs(spec.additionalDirectories, "additionalDirectories", additionalRootsCanonical);
|
|
180
187
|
await canonicalizeExtraDirs(spec.additionalReadDirectories, "additionalReadDirectories", additionalReadRootsCanonical);
|
|
181
|
-
const standingCanonical = [];
|
|
182
|
-
await canonicalizeExtraDirs(input.persistedReadDirectories, "persistedReadRule", standingCanonical);
|
|
183
|
-
artifactStoreRef.standing = { keys: standingCanonical.filter((k) => !additionalReadRootsCanonical.includes(k) && !additionalRootsCanonical.includes(k)), readRoots: additionalReadRootsCanonical };
|
|
184
|
-
additionalReadRootsCanonical.push(...standingCanonical);
|
|
185
188
|
if (advertisedWritableDirs !== undefined) {
|
|
186
189
|
if (spec.envFacts?.scratchpadDir)
|
|
187
190
|
await advertisedWritableDirs.admit({ path: spec.envFacts.scratchpadDir, advertiser: "scratchpad", materializeMarker: ".sema-scratchpad" });
|
|
@@ -194,7 +197,7 @@ export async function prepareHandsMount(input) {
|
|
|
194
197
|
readFileStateForCheckpoint = readFileState;
|
|
195
198
|
seedContextFiles = async (files) => {
|
|
196
199
|
for (const f of files) {
|
|
197
|
-
const rk = await resolveKey(executionEnv, rootCanonical, f.path, undefined, undefined,
|
|
200
|
+
const rk = await readRoots.ready().then(() => resolveKey(executionEnv, rootCanonical, f.path, undefined, undefined, readRoots(), undefined, undefined, resolvedReadFace));
|
|
198
201
|
if (rk.ok)
|
|
199
202
|
seedReadFileStateFromContext(readFileState, rk.key, f.content);
|
|
200
203
|
}
|
|
@@ -220,9 +223,12 @@ export async function prepareHandsMount(input) {
|
|
|
220
223
|
const seedReadFaceSection = resume?.seed.readFace;
|
|
221
224
|
const readDenyAdditions = unionAddOnly("readDenyPatterns", deps.readDenyPatterns, spec.readDenyPatterns, seedReadFaceSection?.denyEntries);
|
|
222
225
|
const readDenyBuiltinCfg = readDenyBuiltinConfigOf({ tiers: deps.readDenyBuiltinTiers, exclude: deps.readDenyBuiltinExclude });
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
+
const canonicalize = async (dirs) => { const out = []; for (const d of dirs)
|
|
227
|
+
await canonicalizeExtraDirs([d], "persistedReadRule", out).catch((err) => deps.onError?.(new Error(`persistedReadRule entry skipped (its lookup threw): ${d}: ${thrownText(err)}`), { phase: "config", sessionId })); return out; };
|
|
228
|
+
const tables = (pathTables = await input.personRows.attachTables(pathTablesCompile({ env: executionEnv, additions: readDenyAdditions, builtin: readDenyBuiltinCfg, legRows: input.denyRuleRows, leads: input.headLeads, configRoot: deps.agentConfigDir, canonicalize })));
|
|
229
|
+
readDenyMatcher = tables.readDeny;
|
|
230
|
+
readRoots = readRootsOver({ own: () => [...additionalRootsCanonical, ...additionalReadRootsCanonical], tables, ready: input.personRows.tablesReady, store: () => artifactStoreRef.current,
|
|
231
|
+
onHeld: (entry, store) => emitTrace(deps.tracer, () => ({ kind: "config.additional_directory_skipped", version: 1, taskId: hostTaskId, entry, field: "persistedReadRule", reason: `admits_artifact_store: the local artifact store ${store} lies inside it or it inside the store — the Artifact tool's ledger and stored files stay outside every root the file tools reach`, ts: Date.now() })) });
|
|
226
232
|
readDenyBuiltinTiersActive = activeReadDenyBuiltinTiers(readDenyBuiltinCfg);
|
|
227
233
|
readDenyAdditionsNormalized = compileReadDeny(readDenyAdditions, "readDenyPatterns", { tiers: [] }).entries;
|
|
228
234
|
let liveReadFace = resolveContainmentFace({
|
|
@@ -247,7 +253,7 @@ export async function prepareHandsMount(input) {
|
|
|
247
253
|
seatLeafId = undefined;
|
|
248
254
|
}
|
|
249
255
|
const judgeKey = async (path) => {
|
|
250
|
-
const rk = await resolveKey(executionEnv, rootCanonical, path, undefined, undefined,
|
|
256
|
+
const rk = await readRoots.ready().then(() => resolveKey(executionEnv, rootCanonical, path, undefined, undefined, readRoots(), undefined, undefined, liveReadFace));
|
|
251
257
|
return rk.ok ? rk.key : undefined;
|
|
252
258
|
};
|
|
253
259
|
if (resume === undefined && spec.sessionId !== undefined) {
|
|
@@ -262,8 +268,12 @@ export async function prepareHandsMount(input) {
|
|
|
262
268
|
const prior = await session.buildContext().catch(() => undefined);
|
|
263
269
|
for (const rec of wholeFileRecordsFromTranscript(prior?.messages ?? [])) {
|
|
264
270
|
const rk = await judgeKey(rec.path);
|
|
265
|
-
if (rk
|
|
271
|
+
if (rk === undefined)
|
|
272
|
+
continue;
|
|
273
|
+
if ("content" in rec)
|
|
266
274
|
seedReadFileStateFromTranscript(readFileState, rk, rec.content, rec.at);
|
|
275
|
+
else
|
|
276
|
+
readFileState.set(rk, { ...rec.observation, lastReadAt: rec.at });
|
|
267
277
|
}
|
|
268
278
|
}
|
|
269
279
|
}
|
|
@@ -290,30 +300,36 @@ export async function prepareHandsMount(input) {
|
|
|
290
300
|
sessionSeats.reanchor(sessionId, readFileState, ownCommittedTailEntryId);
|
|
291
301
|
}
|
|
292
302
|
: undefined;
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
303
|
+
const shellReadBoundary = (toolCallId) => {
|
|
304
|
+
const { read: denySeat, write: writeDenySeat } = denySeatsOf(tables.forCall(toolCallId));
|
|
305
|
+
return {
|
|
306
|
+
roots: [rootCanonical, ...readRoots.forCall(toolCallId)()],
|
|
307
|
+
...(handsCwdRef?.current !== undefined ? { cwd: handsCwdRef.current } : {}),
|
|
308
|
+
...(executionEnv.homeDir !== undefined ? { homeDir: executionEnv.homeDir } : {}),
|
|
309
|
+
...denySeat,
|
|
310
|
+
...writeDenySeat,
|
|
311
|
+
...(input.personRows.unreadFor(toolCallId) ? { unreadPartitions: true } : {}),
|
|
312
|
+
writeRoots: [rootCanonical, ...additionalRootsCanonical],
|
|
313
|
+
...(resolvedWriteFace !== undefined ? { writeFace: resolvedWriteFace.inForce() } : {}),
|
|
314
|
+
...((judge) => (judge !== undefined ? { writeTargetJudge: judge } : {}))(input.writeTargetJudge?.()),
|
|
315
|
+
...(resolvedReadFace !== undefined ? { face: resolvedReadFace } : {}),
|
|
316
|
+
};
|
|
317
|
+
};
|
|
307
318
|
if (handsIncludeShell) {
|
|
308
319
|
const spoolFence = handsReadOnly ? createShellOverflowSpoolFence(executionEnv) : undefined;
|
|
309
|
-
const readonlyBoundary = () =>
|
|
320
|
+
const readonlyBoundary = (toolCallId) => {
|
|
321
|
+
if (spoolFence === undefined)
|
|
322
|
+
return undefined;
|
|
323
|
+
const { read: denySeat, write: writeDenySeat } = denySeatsOf(tables.forCall(toolCallId));
|
|
324
|
+
return { roots: [rootCanonical, ...readRoots.forCall(toolCallId)()], cwd: rootCanonical, ...denySeat, ...writeDenySeat, ...(input.personRows.unreadFor(toolCallId) ? { unreadPartitions: true } : {}), alsoInside: spoolFence };
|
|
325
|
+
};
|
|
310
326
|
shellReadTools = new Set(shellFaceHere);
|
|
311
327
|
shellReadStation = createShellReadStation({
|
|
312
328
|
env: executionEnv,
|
|
313
329
|
tools: shellReadTools,
|
|
314
330
|
seatOf: () => (handsReadOnly ? "readonly" : "full_shell"),
|
|
315
|
-
boundaryOf: () => readonlyBoundary() ?? shellReadBoundary(), rootsCanonical: true,
|
|
316
|
-
homeViews:
|
|
331
|
+
boundaryOf: (_tool, _cwd, toolCallId) => readonlyBoundary(toolCallId) ?? shellReadBoundary(toolCallId), rootsCanonical: true,
|
|
332
|
+
homeViews: tables.readDeny.homeViews,
|
|
317
333
|
onAdmissionRefused: (toolCallId) => void input.toolOccurrences.refuse(toolCallId, "read_boundary"),
|
|
318
334
|
});
|
|
319
335
|
}
|
|
@@ -322,8 +338,8 @@ export async function prepareHandsMount(input) {
|
|
|
322
338
|
fileReadStation = createFileReadStation({
|
|
323
339
|
env: executionEnv,
|
|
324
340
|
rootCanonical,
|
|
325
|
-
roots:
|
|
326
|
-
|
|
341
|
+
roots: readRoots,
|
|
342
|
+
readDeny: tables.readDeny,
|
|
327
343
|
...(liveReadFace !== undefined ? { readFace: liveReadFace } : {}),
|
|
328
344
|
...("homeDir" in executionEnv && executionEnv.homeDir !== undefined ? { homeDir: executionEnv.homeDir } : {}),
|
|
329
345
|
tools: readTargetToolNames(),
|
|
@@ -333,17 +349,12 @@ export async function prepareHandsMount(input) {
|
|
|
333
349
|
}
|
|
334
350
|
const band = createHandsToolkit(executionEnv, readFileState, rootCanonical, {
|
|
335
351
|
...(additionalRootsCanonical.length > 0 ? { additionalRoots: additionalRootsCanonical } : {}),
|
|
336
|
-
|
|
337
|
-
...(readDenyAdditions.length > 0 ? { readDenyPatterns: readDenyAdditions } : {}),
|
|
338
|
-
...(denyRuleRows.length > 0 ? { pathDenyRules: denyRuleRows } : {}),
|
|
339
|
-
readDenyHomes: readDenyPlacement.homes,
|
|
340
|
-
readDenyHomeLinks: readDenyPlacement.linked,
|
|
341
|
-
...(readDenyBuiltinCfg.tiers !== undefined ? { readDenyBuiltinTiers: readDenyBuiltinCfg.tiers } : {}),
|
|
342
|
-
...(readDenyBuiltinCfg.exclude !== undefined ? { readDenyBuiltinExclude: readDenyBuiltinCfg.exclude } : {}),
|
|
352
|
+
readDenyHomes: carryReadFace([], { readDeny: tables.readDeny, writeDeny: tables.writeDeny, readRoots }),
|
|
343
353
|
readFace: liveReadFace,
|
|
344
354
|
writeFaceLive: resolvedWriteFace.inForce,
|
|
345
355
|
reminderMark: input.reminderMark,
|
|
346
356
|
reminderDisclosureCounts: input.reminderDisclosureCounts,
|
|
357
|
+
...(input.modelFileReaderSeat !== undefined ? { modelFileReaderSeat: input.modelFileReaderSeat } : {}),
|
|
347
358
|
...(input.trackFileEdit !== undefined ? { trackFileEdit: input.trackFileEdit } : {}),
|
|
348
359
|
...(input.onFileEdited !== undefined ? { onFileEdited: input.onFileEdited } : {}),
|
|
349
360
|
includeShell: handsIncludeShell,
|
|
@@ -387,7 +398,7 @@ export async function prepareHandsMount(input) {
|
|
|
387
398
|
deps.onError?.(new Error(`spec.tools ${shadowed.length > 1 ? "entries" : "entry"} ${names} collide${shadowed.length > 1 ? "" : "s"} with the built-in hands tool band — the built-in wins (registered later; the harness tool Map is last-write-wins) and the caller tool never dispatches this task. Rename the caller tool, or don't inject executionEnv if you intend to replace the band.`), { phase: "config", sessionId });
|
|
388
399
|
}
|
|
389
400
|
}
|
|
390
|
-
roster.mountAll(band.map((t) => (envHandToolNames.add(t.name), firstPartyOffload(t))), { source: "builtin", mountedBy: "hands" });
|
|
401
|
+
roster.mountAll(band.map((t) => (envHandToolNames.add(t.name), firstPartyOffload(afterCallTables(input.personRows, t)))), { source: "builtin", mountedBy: "hands" });
|
|
391
402
|
const shellFloor = effectiveShellGate;
|
|
392
403
|
if (!(executionEnv instanceof StubExecutionEnv) && spec.handsReadOnly !== true) {
|
|
393
404
|
const installShellSeat = (name) => {
|
|
@@ -413,9 +424,10 @@ export async function prepareHandsMount(input) {
|
|
|
413
424
|
wsSnapshot,
|
|
414
425
|
rebaseWsPath,
|
|
415
426
|
backgroundTaskToolsActive,
|
|
416
|
-
shellReadCheck:
|
|
427
|
+
shellReadCheck: onPinnedRead(input.personRows, [...(shellReadStation !== undefined ? [{ check: shellReadStation.check, tools: shellReadTools }] : []), ...(fileReadStation !== undefined ? [fileReadStation] : [])]),
|
|
417
428
|
shellReadStationArmed: shellReadStation !== undefined,
|
|
418
429
|
shellReadAdmission: shellReadStation?.admit,
|
|
430
|
+
readAdmission: fileReadStation?.admitted,
|
|
419
431
|
resolvedReadFace,
|
|
420
432
|
resolvedWriteFace,
|
|
421
433
|
handsLessResolvedWriteFace,
|
|
@@ -428,6 +440,8 @@ export async function prepareHandsMount(input) {
|
|
|
428
440
|
artifactStoreRef,
|
|
429
441
|
attachmentRootCanonical,
|
|
430
442
|
readDenyMatcher,
|
|
443
|
+
readRoots,
|
|
444
|
+
pathTables,
|
|
431
445
|
envHandToolNames,
|
|
432
446
|
shellGatedTools,
|
|
433
447
|
sealReadStateSeat,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PrepareTask's LSP phase, verbatim from the driver: the manager fold (spec > deps), the
|
|
3
|
-
* LSP tool mount over the per-task env with its git-ignore filter, the diagnostics lane behind its
|
|
4
|
-
* preconditions (a manager whose sessions feed a registry, write-capable hands, not opted out), the run-scoped
|
|
3
|
+
* LSP tool mount over the per-task env with its git-ignore filter and the leg's read face, the diagnostics lane behind its
|
|
4
|
+
* four preconditions (a manager whose sessions feed a registry, write-capable hands, not opted out), the run-scoped
|
|
5
5
|
* registry key, and the edit nudge (raw path → the SAME resolution the tool leg uses → registry reset +
|
|
6
|
-
* session didChange). No manager, or no hands
|
|
7
|
-
* both lane seats are undefined. The interface is the dependency list the
|
|
6
|
+
* session didChange through the read face). No manager, or no read face (a hands-less leg; the manifest still reports the
|
|
7
|
+
* seat, `mounted: false`), ⇒ nothing mounts and both lane seats are undefined. The interface is the dependency list the
|
|
8
|
+
* segment had implicitly.
|
|
8
9
|
*
|
|
9
10
|
* SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await, so the phase adds no yield between the
|
|
10
11
|
* fork-governance note before it and the memory trio's occupancy read after it (a stretch
|
|
@@ -12,9 +13,9 @@
|
|
|
12
13
|
* Read-stability of the host handles for the call: {@link RunInternals} (`@contract prepare.deps-read-stable`).
|
|
13
14
|
*/
|
|
14
15
|
import type { ExecutionEnv } from "../../internal/harness.js";
|
|
16
|
+
import { type LspListedWithholding, type LspReadFace } from "../lsp.js";
|
|
15
17
|
import type { LspDiagnosticsRegistry } from "../lsp-diagnostics.js";
|
|
16
18
|
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
17
|
-
import type { Prepared } from "./contracts.js";
|
|
18
19
|
import { RosterBuilder } from "../tool-roster.js";
|
|
19
20
|
export interface PrepareLspInput {
|
|
20
21
|
/** borrowed-readonly — the REBOUND spec. Read: `lspManager` (the per-task manager, outranks the deployment's),
|
|
@@ -25,18 +26,16 @@ export interface PrepareLspInput {
|
|
|
25
26
|
/** borrowed-readonly — the run's resolved env: the tool's in-env server and git-ignore filter, and the
|
|
26
27
|
* session lookup the nudge performs. */
|
|
27
28
|
executionEnv: ExecutionEnv;
|
|
28
|
-
/** borrowed-readonly — the SETTLED task root: the tool's git-ignore root
|
|
29
|
-
* no cwd is tracked. */
|
|
29
|
+
/** borrowed-readonly — the SETTLED task root: the tool's git-ignore root. */
|
|
30
30
|
taskRootFinal: string;
|
|
31
|
-
/** borrowed-readonly —
|
|
32
|
-
|
|
31
|
+
/** borrowed-readonly — the leg's read face (the hands phase's root, read roots, deny table, containment face, tracked
|
|
32
|
+
* cwd and file read station admission), present exactly when hands mounted: LSP mounts only under it, and the tool,
|
|
33
|
+
* the nudge and the diagnostics lane read every file through it. */
|
|
34
|
+
readFace: LspReadFace | undefined;
|
|
33
35
|
/** borrowed-readonly — the acquired session id: the run's key into the deployment-shared registry. */
|
|
34
36
|
sessionId: string;
|
|
35
|
-
/** borrowed-readonly — the tracked-cwd cell the hands band writes; the nudge READS `current` per call as its
|
|
36
|
-
* resolution base (identity is the contract — the band's `cd` handling writes this exact cell). */
|
|
37
|
-
handsCwdRef: Prepared["cwdRef"];
|
|
38
37
|
/** borrowed-mutable — the run's roster builder (identity is the contract). Writer here: ONE mount (the LSP tool)
|
|
39
|
-
* when a manager
|
|
38
|
+
* when a manager and a read face exist. */
|
|
40
39
|
roster: RosterBuilder;
|
|
41
40
|
/** borrowed-mutable — the env-hand membership set the read-posture observer projects; writer here: `add("LSP")`
|
|
42
41
|
* on the mount. */
|
|
@@ -48,6 +47,9 @@ export interface PrepareLspResult {
|
|
|
48
47
|
lspDiagnostics: LspDiagnosticsRegistry | undefined;
|
|
49
48
|
/** owned — the edit nudge (raw path in), or undefined when the lane is not live. */
|
|
50
49
|
nudgeLspOnEdit: ((rawPath: string) => void) | undefined;
|
|
50
|
+
/** owned — the files of a drain the read face withholds (`lspListedWithheld`: every view, fail-closed; kept files
|
|
51
|
+
* absent), or undefined when the lane is not live. */
|
|
52
|
+
withheldDiagnosticsOf: ((uris: readonly string[]) => Promise<ReadonlyMap<string, LspListedWithholding>>) | undefined;
|
|
51
53
|
/** borrowed-readonly — the run's registry key (= the session id): one run per session, released at the terminal. */
|
|
52
54
|
lspRunIdent: string;
|
|
53
55
|
/** Did a MANAGER seat resolve? The manifest's LSP-section presence condition, from the ONE fold that decided the mount. */ managerWired: boolean;
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
1
|
+
import { createLspTool, gitCheckIgnoreFilter, lspBaseOf, lspListedWithheld, lspReadGateOf, resolveLspPath } from "../lsp.js";
|
|
2
2
|
import { pathToUri } from "../lsp-protocol.js";
|
|
3
3
|
import { RosterBuilder } from "../tool-roster.js";
|
|
4
4
|
export function prepareLsp(input) {
|
|
5
|
-
const { spec, deps, executionEnv, taskRootFinal,
|
|
5
|
+
const { spec, deps, executionEnv, taskRootFinal, readFace, sessionId, roster, envHandToolNames } = input;
|
|
6
6
|
const lspManager = spec.lspManager ?? deps.lspManager;
|
|
7
|
-
if (lspManager &&
|
|
8
|
-
|
|
9
|
-
roster.mount(createLspTool(lspManager, { isPathIgnored: gitCheckIgnoreFilter(executionEnv, lspRoot), env: executionEnv }), { source: "builtin", mountedBy: "hands" });
|
|
7
|
+
if (lspManager && readFace) {
|
|
8
|
+
roster.mount(createLspTool(lspManager, { isPathIgnored: gitCheckIgnoreFilter(executionEnv, taskRootFinal), env: executionEnv, readFace }), { source: "builtin", mountedBy: "hands" });
|
|
10
9
|
envHandToolNames.add("LSP");
|
|
11
10
|
}
|
|
12
|
-
const lspDiagnostics = spec.lspDiagnostics !== false && lspManager?.diagnostics !== undefined &&
|
|
11
|
+
const lspDiagnostics = spec.lspDiagnostics !== false && lspManager?.diagnostics !== undefined && readFace !== undefined && spec.handsReadOnly !== true
|
|
13
12
|
? lspManager.diagnostics
|
|
14
13
|
: undefined;
|
|
15
14
|
const lspRunIdent = sessionId;
|
|
16
|
-
const nudgeLspOnEdit = lspDiagnostics
|
|
15
|
+
const nudgeLspOnEdit = lspDiagnostics && readFace
|
|
17
16
|
? (rawPath) => {
|
|
18
|
-
const
|
|
19
|
-
const filePath = resolveLspPath(rawPath, baseDir);
|
|
17
|
+
const filePath = resolveLspPath(rawPath, lspBaseOf(readFace));
|
|
20
18
|
lspDiagnostics.fileEdited(lspRunIdent, pathToUri(filePath));
|
|
19
|
+
const gate = lspReadGateOf(executionEnv, readFace);
|
|
21
20
|
void lspManager
|
|
22
21
|
.sessionFor(filePath, undefined, executionEnv)
|
|
23
|
-
.then((session) => session?.notifyFileChanged?.(filePath))
|
|
22
|
+
.then((session) => session?.notifyFileChanged?.(filePath, undefined, gate))
|
|
24
23
|
.catch(() => undefined);
|
|
25
24
|
}
|
|
26
25
|
: undefined;
|
|
27
|
-
|
|
26
|
+
const withheldDiagnosticsOf = lspDiagnostics && readFace ? (uris) => lspListedWithheld(executionEnv, readFace, uris) : undefined;
|
|
27
|
+
return { lspDiagnostics, nudgeLspOnEdit, withheldDiagnosticsOf, lspRunIdent, managerWired: lspManager !== undefined };
|
|
28
28
|
}
|
|
@@ -104,10 +104,11 @@ export interface PreparePolicyChainInput {
|
|
|
104
104
|
handsCwdRef: CwdRef | undefined;
|
|
105
105
|
/** borrowed-readonly — the compiled read-deny judge, or undefined (the offer factory's directory negative control). */
|
|
106
106
|
readDenyMatcher: ReadDenyMatcher | undefined;
|
|
107
|
-
/** borrowed-readonly — the run's one
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
/** borrowed-readonly — the run's one reader of the person's rules (`person-path-rows.ts`): the lanes take each call's
|
|
108
|
+
* pinned read from it. */
|
|
109
|
+
personRows: import("./person-path-rows.js").PersonPathRows;
|
|
110
|
+
/** borrowed-readonly — a reader of the same rows the run's cut does not end (the same notices), for the lane asked after the run. */
|
|
111
|
+
personRowsBeyondRun: import("./person-path-rows.js").PersonPathRows;
|
|
111
112
|
/** borrowed-readonly — whether the question tool mounted (the lanes' question-tool exclusion). */
|
|
112
113
|
questionToolMounted: boolean;
|
|
113
114
|
/** borrowed-readonly — the resolved per-principal entitlements; only `forceDurableGate` (the mandate-park facility and
|
|
@@ -240,6 +241,9 @@ export interface PreparePolicyChainResult {
|
|
|
240
241
|
grantBindingOf: GrantBindingOf;
|
|
241
242
|
/** owned — the personal permission-rule lane, or undefined. */
|
|
242
243
|
permissionRuleLane: PermissionRuleLanes["personal"];
|
|
244
|
+
/** owned — the same two lanes (personal and org) over the reader the run's cut does not end, for the one judgment asked after the
|
|
245
|
+
* run has ended (the synthetic write face). */
|
|
246
|
+
ruleLanesBeyondRun: PermissionRuleLanes;
|
|
243
247
|
/** owned — the org permission-rule lane (`Prepared.permissionRuleOrg`), or undefined. */
|
|
244
248
|
permissionRuleOrgLane: PermissionRuleLanes["org"];
|
|
245
249
|
/** owned — whether the sandbox-admission mode armed (declared isolation with its park prerequisites). */
|
|
@@ -26,7 +26,7 @@ import { createLiveSessionRules, createSessionRulePolicy } from "./session-rule-
|
|
|
26
26
|
import { thrownText } from "../thrown-value.js";
|
|
27
27
|
import { heldBy, heldValues, seatOf, wireOf } from "../tool-name-readings.js";
|
|
28
28
|
export async function preparePolicyChain(input) {
|
|
29
|
-
const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, pathRuleAnchors, headLeads, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher,
|
|
29
|
+
const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, additionalRootsCanonical, executionEnv, lockedPreflight, pathRuleAnchors, headLeads, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, toolMarkSources, envHandToolNames, handsCwdRef, readDenyMatcher, personRows, personRowsBeyondRun, questionToolMounted, runtimeCaps, inheritedAncestorRules, ancestorSessionRulesRef, inheritedParentConstraints, seedInheritedGate, skillGrants, skillSpecs, allowedToolTables, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, readFace, permissionMode, scratchpadDir, toolRosterDeltas, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef } = input;
|
|
30
30
|
const ancestorArbitrations = new Map();
|
|
31
31
|
const arbitrateInherited = (ask, toolCallId, judged) => {
|
|
32
32
|
const verdict = arbitrateByMode(permissionMode.current, judged.classification, { origin: judged.origin, ...askMandateMember(ancestorFacts(judged.ask.action === "ask" ? judged.ask : undefined)) });
|
|
@@ -321,7 +321,7 @@ export async function preparePolicyChain(input) {
|
|
|
321
321
|
const listFacts = { root: taskRootFinal, sessionId, liveCwd: () => handsCwdRef?.current, anchors: pathRuleAnchors.leg };
|
|
322
322
|
const skillGrantLane = skillGrants.lane(listFacts);
|
|
323
323
|
const allowEntryLanes = { request: allowedToolTables.request.lane(listFacts), deployment: allowedToolTables.deployment.lane(listFacts) };
|
|
324
|
-
const
|
|
324
|
+
const ruleLaneConfig = {
|
|
325
325
|
provider: deps.permissionRuleStore,
|
|
326
326
|
localOwnerDeclared: deps.localOwnerRules === true,
|
|
327
327
|
principal: spec.principal,
|
|
@@ -336,11 +336,10 @@ export async function preparePolicyChain(input) {
|
|
|
336
336
|
questionToolName: ASK_USER_QUESTION_TOOL_NAME,
|
|
337
337
|
onRevisionDefect: (message) => deps.onError?.(new Error(message), { phase: "config", sessionId }),
|
|
338
338
|
onDisclosure: (message) => emitTrace(deps.tracer, () => ({ kind: "permission.rule_store_unreadable", version: 1, taskId: hostTaskId, message, ts: Date.now() })),
|
|
339
|
-
onStoreUnreadable: announceRuleStoreSkipped,
|
|
340
|
-
onRowsDropped: announceRuleRowsDropped,
|
|
341
|
-
signal: abortController.signal,
|
|
342
339
|
stripsAllow: (rule, req) => permissionMode.current === "auto" && autoStrippedRule(rule, req),
|
|
343
|
-
}
|
|
340
|
+
};
|
|
341
|
+
const { personal: permissionRuleLane, org: permissionRuleOrgLane } = createPermissionRuleLanes({ ...ruleLaneConfig, rows: personRows });
|
|
342
|
+
const ruleLanesBeyondRun = createPermissionRuleLanes({ ...ruleLaneConfig, rows: personRowsBeyondRun });
|
|
344
343
|
const ruleOffersOf = createRuleOffersOf({
|
|
345
344
|
laneArmed: permissionRuleLane !== undefined,
|
|
346
345
|
principal: spec.principal,
|
|
@@ -678,7 +677,7 @@ export async function preparePolicyChain(input) {
|
|
|
678
677
|
return decision;
|
|
679
678
|
})
|
|
680
679
|
: foldedPolicy;
|
|
681
|
-
return { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, grantBindingOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations };
|
|
680
|
+
return { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, skillGrantLane, allowEntryLanes, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, grantBindingOf, permissionRuleLane, ruleLanesBeyondRun, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions, ancestorArbitrations };
|
|
682
681
|
}
|
|
683
682
|
const advisedPolicyNames = new WeakMap();
|
|
684
683
|
const ADVISED_KEYS_CAP = 64;
|