@sema-agent/core 7.38.2 → 7.39.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 +175 -6
- package/dist/core/ask-origin.d.ts +16 -7
- package/dist/core/ask-origin.js +4 -2
- package/dist/core/auto-mode-directive.d.ts +114 -19
- package/dist/core/auto-mode-directive.js +67 -19
- package/dist/core/checkpoint-store.d.ts +72 -41
- package/dist/core/checkpoint-store.js +28 -48
- package/dist/core/classifier-unavailable-arm.js +2 -2
- package/dist/core/decision-receipt.d.ts +2 -0
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/engine-notice.d.ts +41 -17
- package/dist/core/engine-notice.js +26 -14
- package/dist/core/gate-outcome.d.ts +80 -42
- package/dist/core/gate-outcome.js +21 -6
- package/dist/core/governance-codes.d.ts +1 -3
- package/dist/core/governance-codes.js +0 -3
- package/dist/core/hooks.d.ts +1 -1
- package/dist/core/hooks.js +2 -2
- package/dist/core/human-input-projection.d.ts +12 -0
- package/dist/core/human-input-projection.js +12 -0
- package/dist/core/memory-engine/engine.js +11 -11
- package/dist/core/memory-engine/layout.d.ts +21 -2
- package/dist/core/memory-engine/layout.js +17 -5
- package/dist/core/mode-policy.d.ts +26 -0
- package/dist/core/mode-policy.js +37 -1
- package/dist/core/output-style.d.ts +21 -0
- package/dist/core/output-style.js +29 -0
- package/dist/core/real-approval.d.ts +25 -0
- package/dist/core/real-approval.js +27 -0
- package/dist/core/reminder-mint.d.ts +0 -9
- package/dist/core/reminder-mint.js +0 -11
- package/dist/core/retired-keys.d.ts +2 -1
- package/dist/core/retired-keys.js +3 -1
- package/dist/core/runner/assemble-result.d.ts +2 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/compaction-restate.d.ts +45 -4
- package/dist/core/runner/compaction-restate.js +89 -11
- package/dist/core/runner/contracts.d.ts +6 -6
- package/dist/core/runner/denial-limit-arms.js +4 -4
- package/dist/core/runner/inherited-ask-grants.d.ts +4 -2
- package/dist/core/runner/inherited-ask-grants.js +0 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +18 -0
- package/dist/core/runner/permission-rule-lanes.js +35 -25
- package/dist/core/runner/prepare-context-lane.d.ts +1 -0
- package/dist/core/runner/prepare-context-lane.js +6 -0
- package/dist/core/runner/prepare-inherited-gate.js +2 -9
- package/dist/core/runner/prepare-task.js +10 -24
- package/dist/core/runner/prepare-wiring-manifest.js +2 -2
- package/dist/core/runner/prompt-block.d.ts +9 -0
- package/dist/core/runner/prompt-block.js +8 -0
- package/dist/core/runner/resume-admission.js +4 -1
- package/dist/core/runner/resume-apply.js +28 -18
- package/dist/core/runner/resume-policy-outcome.js +10 -4
- package/dist/core/runner/run-attachment-seats.js +1 -1
- package/dist/core/runner/run-identity-wiring.js +9 -2
- package/dist/core/runner/run-leg.js +42 -31
- package/dist/core/runner/run-settle-and-teardown.js +4 -3
- package/dist/core/runner/run-turn-boundary.js +4 -3
- package/dist/core/runner/runtask.d.ts +4 -2
- package/dist/core/runner/steer-admission.d.ts +9 -0
- package/dist/core/runner/steer-admission.js +8 -0
- package/dist/core/runner/stream-steer-verb.js +16 -11
- package/dist/core/runner/synthetic-tools.d.ts +4 -0
- package/dist/core/runner/tool-turn-repair-seat.js +1 -1
- package/dist/core/runner/turn-attachments.d.ts +16 -22
- package/dist/core/runner/turn-attachments.js +3 -20
- package/dist/core/runner-deps.d.ts +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +8 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +23 -0
- package/dist/core/task-event.d.ts +7 -2
- package/dist/core/task-spec.d.ts +29 -7
- package/dist/core/terminal-cause.d.ts +44 -3
- package/dist/core/terminal-cause.js +5 -0
- package/dist/core/tool-policy.d.ts +55 -29
- package/dist/core/tool-policy.js +42 -31
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.js +1 -1
- package/dist/core/wiring-manifest.d.ts +17 -3
- package/dist/core/wiring-manifest.js +8 -3
- package/dist/engine/harness/agent-harness.d.ts +10 -0
- package/dist/engine/harness/agent-harness.js +12 -1
- package/dist/engine/llm/tool-turns.d.ts +15 -2
- package/dist/engine/llm/tool-turns.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/prompt-assembly/event-registry.js +2 -1
- package/dist/stores/file/fs-atomic.d.ts +29 -4
- package/dist/stores/file/fs-atomic.js +55 -6
- package/dist/tools/fs/index.d.ts +2 -1
- package/dist/tools/fs/read-deny-home.d.ts +3 -2
- package/dist/tools/fs/read-deny-home.js +6 -4
- package/dist/tools/fs/shell-read-check.d.ts +10 -3
- package/dist/tools/fs/shell-read-check.js +2 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +21 -1
- package/wire-changes/core@7.38.2.json +20 -2
- package/wire-changes/core@7.38.3.json +36 -0
- package/wire-changes/core@7.39.0.json +845 -0
|
@@ -42,7 +42,9 @@ export function resolveSubagentTranscriptTier(agentStoreWired, sessionStore) {
|
|
|
42
42
|
e.code = "config.store_durability_invalid";
|
|
43
43
|
throw e;
|
|
44
44
|
}
|
|
45
|
-
export function deriveAskEffective(form, parkEffective) {
|
|
45
|
+
export function deriveAskEffective(form, parkEffective, mode) {
|
|
46
|
+
if (mode === "dontAsk")
|
|
47
|
+
return "auto_deny";
|
|
46
48
|
switch (form) {
|
|
47
49
|
case "callback":
|
|
48
50
|
return "human_reachable";
|
|
@@ -59,6 +61,9 @@ export function deriveAskEffective(form, parkEffective) {
|
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
63
|
}
|
|
64
|
+
export function askSeatEffective(manifest) {
|
|
65
|
+
return deriveAskEffective(manifest.ask.form, manifest.parkLane.effective);
|
|
66
|
+
}
|
|
62
67
|
export function askReachesPerson(ask) {
|
|
63
68
|
const effective = ask.effective ?? "unresolved";
|
|
64
69
|
switch (effective) {
|
|
@@ -148,7 +153,7 @@ export function deriveWiringManifest(facts) {
|
|
|
148
153
|
ask: {
|
|
149
154
|
form: facts.askForm,
|
|
150
155
|
...(facts.askProvenance !== undefined ? { provenance: facts.askProvenance } : {}),
|
|
151
|
-
...(facts.half === "effective" ? { effective: deriveAskEffective(facts.askForm, parkLane.effective) } : {}),
|
|
156
|
+
...(facts.half === "effective" ? { effective: deriveAskEffective(facts.askForm, parkLane.effective, facts.permissionMode?.effective) } : {}),
|
|
152
157
|
},
|
|
153
158
|
question: {
|
|
154
159
|
wired: questionChannel,
|
|
@@ -200,7 +205,7 @@ export function deriveWiringManifest(facts) {
|
|
|
200
205
|
const { provenance: _askSeat, ...askForHash } = assembly.ask;
|
|
201
206
|
const { provenance: _questionSeat, ...questionForHash } = assembly.question;
|
|
202
207
|
manifest.configFingerprint = createHash("sha256")
|
|
203
|
-
.update(canonicalize({ ...assembly, ask: askForHash, question: questionForHash }))
|
|
208
|
+
.update(canonicalize({ ...assembly, ask: { ...askForHash, effective: deriveAskEffective(facts.askForm, parkLane.effective) }, question: questionForHash }))
|
|
204
209
|
.digest("hex")
|
|
205
210
|
.slice(0, 16);
|
|
206
211
|
}
|
|
@@ -194,6 +194,9 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
|
|
|
194
194
|
* with every request view that needed one (the transcript is never rewritten, so a broken turn is repaired, and
|
|
195
195
|
* reported, on each request; the sink owns its dedup). Advisory: a throwing sink never breaks the request. */
|
|
196
196
|
onToolTurnRepaired?: (repairs: readonly ToolTurnRepair[]) => void;
|
|
197
|
+
/** The assistant messages standing in the transcript when the current run began — what the request view reads as
|
|
198
|
+
* "before this run" (a message is the run's own unless it is in here). */
|
|
199
|
+
private runHistory?;
|
|
197
200
|
/** backlog #259 — USER-authored queue remnants at agent_end: steers/follow-ups whose receipts said
|
|
198
201
|
* "queued" but that no turn will ever drain (the run ended first). The engine-note sweep above
|
|
199
202
|
* hands ENGINE payloads back for redelivery; user inputs have no redelivery semantics (a steer
|
|
@@ -212,6 +215,13 @@ export declare class AgentHarness<TSkill extends Skill = Skill, TPromptTemplate
|
|
|
212
215
|
* Advisory (swallow-guarded at the call sites via the runner's own closure); never re-entered
|
|
213
216
|
* for the same payload — consumption deletes the sidecar entry in the same step. */
|
|
214
217
|
onEngineNoteConsumed?: (payload: unknown) => void;
|
|
218
|
+
/** backlog #1273 — runner-set sink fired ONCE per CALLER frame at the moment the frame is in the transcript (its
|
|
219
|
+
* `message_end` append — the next request carries it), with the opaque park record the frame rode in on
|
|
220
|
+
* ({@link UserMessageProvenance.parkRecord}). The consumption point of a caller input, deliberately NOT the drain:
|
|
221
|
+
* a drained frame can still be dropped before its turn starts (a halt latched or an abort landing after the drain)
|
|
222
|
+
* and goes back into the park / undrained account, so a drain-time report would announce an input the model never
|
|
223
|
+
* saw. Advisory (swallow-guarded); the record is released in the same step, so a delivered frame reports once. */
|
|
224
|
+
onUserInputConsumed?: (parkRecord: unknown) => void;
|
|
215
225
|
/** #1036 — THE RECEIPT SINK: a frame reached the TRANSCRIPT, reported at the `message_end` append
|
|
216
226
|
* that proves it, with its carrier and entry id. Advisory. */
|
|
217
227
|
onFrameCommitted?: (carrier: CommittedFrameCarrier, entryId: string) => void;
|
|
@@ -212,12 +212,14 @@ export class AgentHarness {
|
|
|
212
212
|
thinkingLevel;
|
|
213
213
|
onUndrainedEngineNotes;
|
|
214
214
|
onToolTurnRepaired;
|
|
215
|
+
runHistory;
|
|
215
216
|
onUndrainedUserInputs;
|
|
216
217
|
onEngineNoteConsumed;
|
|
218
|
+
onUserInputConsumed;
|
|
217
219
|
onFrameCommitted;
|
|
218
220
|
engineInjectionsHeld;
|
|
219
221
|
holdToolTurnLaw(messages) {
|
|
220
|
-
const view = ensureToolTurnInvariants(messages);
|
|
222
|
+
const view = ensureToolTurnInvariants(messages, this.runHistory);
|
|
221
223
|
if (view.repairs.length > 0) {
|
|
222
224
|
try {
|
|
223
225
|
this.onToolTurnRepaired?.(view.repairs);
|
|
@@ -603,7 +605,15 @@ export class AgentHarness {
|
|
|
603
605
|
if (!this.drainedPendingInjection.includes(message))
|
|
604
606
|
return;
|
|
605
607
|
this.unbookInFlight([message]);
|
|
608
|
+
const parkRecord = userInputParkRecords.get(message);
|
|
606
609
|
userInputParkRecords.delete(message);
|
|
610
|
+
if (parkRecord !== undefined) {
|
|
611
|
+
try {
|
|
612
|
+
this.onUserInputConsumed?.(parkRecord);
|
|
613
|
+
}
|
|
614
|
+
catch {
|
|
615
|
+
}
|
|
616
|
+
}
|
|
607
617
|
if (entryId !== undefined) {
|
|
608
618
|
const payload = engineNotePayloads.get(message);
|
|
609
619
|
if (payload !== undefined) {
|
|
@@ -878,6 +888,7 @@ export class AgentHarness {
|
|
|
878
888
|
async executeTurn(turnState, text, options, abortController) {
|
|
879
889
|
let activeTurnState = turnState;
|
|
880
890
|
const userMessage = createUserMessage(text, options?.images, options);
|
|
891
|
+
this.runHistory = new WeakSet(turnState.messages.filter((m) => m.role === "assistant"));
|
|
881
892
|
const beforeResult = await this.emitHook({
|
|
882
893
|
type: "before_agent_start",
|
|
883
894
|
prompt: text,
|
|
@@ -43,6 +43,13 @@
|
|
|
43
43
|
* wording, whatever the tool. (The persisted reconcile refines with the run's tool effects — a read-only or
|
|
44
44
|
* idempotent call's close says it may simply be re-issued — and, on a live abort, with the calls it saw start.)
|
|
45
45
|
* Returns the SAME array when nothing needed restoring.
|
|
46
|
+
*
|
|
47
|
+
* RUN OWNERSHIP. The caller may hand over the assistant messages that stood in its transcript before its run began
|
|
48
|
+
* (`priorMessages`, by object). A `missing_result` repair on one of them is marked `beforeRun`: the call went
|
|
49
|
+
* unanswered before this run started, so closing it on the wire is a fact about the transcript the run inherited, not
|
|
50
|
+
* an event of the run. Membership is by message, never by position — a request projection that inserts, drops or
|
|
51
|
+
* replaces other messages cannot move it. The mark says that and nothing else: the repair, the synthesized result and
|
|
52
|
+
* the operator's account of them are the same with or without it. No `priorMessages` ⇒ no mark.
|
|
46
53
|
*/
|
|
47
54
|
import type { AssertAllKeysHandled } from "../../core/ask-origin.js";
|
|
48
55
|
import type { AssistantMessageDiagnostic } from "./diagnostics.js";
|
|
@@ -97,6 +104,9 @@ export interface ToolTurnRepair {
|
|
|
97
104
|
* ids a later call of the message repeated; for `orphan_result` the ids of the results left out, once each, in
|
|
98
105
|
* transcript order; otherwise the calls whose result was moved up, synthesized, or folded with a second one. */
|
|
99
106
|
readonly toolCallIds: readonly string[];
|
|
107
|
+
/** `missing_result` only, and only when the caller handed over its run's prior messages
|
|
108
|
+
* ({@link ensureToolTurnInvariants}'s `priorMessages`): the message holding these calls is one of them. */
|
|
109
|
+
readonly beforeRun?: true;
|
|
100
110
|
}
|
|
101
111
|
export interface ToolTurnView {
|
|
102
112
|
/** The request view — the input array itself when {@link repairs} is empty. */
|
|
@@ -105,5 +115,8 @@ export interface ToolTurnView {
|
|
|
105
115
|
}
|
|
106
116
|
/** The text standing between two results recorded for one call when the view folds them into one. */
|
|
107
117
|
export declare const SECOND_RESULT_SEPARATOR = "[another result was recorded for this same call:]";
|
|
108
|
-
/** Restore the tool-turn law on a provider-bound message list (see the module header).
|
|
109
|
-
|
|
118
|
+
/** Restore the tool-turn law on a provider-bound message list (see the module header). `priorMessages` = the calling
|
|
119
|
+
* run's inherited assistant messages (module header, RUN OWNERSHIP). */
|
|
120
|
+
export declare function ensureToolTurnInvariants(messages: Message[], priorMessages?: {
|
|
121
|
+
has(message: object): boolean;
|
|
122
|
+
}): ToolTurnView;
|
|
@@ -47,7 +47,7 @@ function callsOf(m) {
|
|
|
47
47
|
return m.role === "assistant" && Array.isArray(m.content) ? m.content.filter((c) => c?.type === "toolCall") : [];
|
|
48
48
|
}
|
|
49
49
|
export const SECOND_RESULT_SEPARATOR = "[another result was recorded for this same call:]";
|
|
50
|
-
export function ensureToolTurnInvariants(messages) {
|
|
50
|
+
export function ensureToolTurnInvariants(messages, priorMessages) {
|
|
51
51
|
const anchor = [];
|
|
52
52
|
messages.forEach((m, i) => anchor.push(m.role === "toolResult" && i > 0 ? anchor[i - 1] : i));
|
|
53
53
|
const sites = new Map();
|
|
@@ -132,7 +132,7 @@ export function ensureToolTurnInvariants(messages) {
|
|
|
132
132
|
if (late.length > 0)
|
|
133
133
|
repairs.push({ form: "late_result", toolCallIds: inCallOrder(late) });
|
|
134
134
|
if (missing.length > 0)
|
|
135
|
-
repairs.push({ form: "missing_result", toolCallIds: missing.map((c) => c.id) });
|
|
135
|
+
repairs.push({ form: "missing_result", toolCallIds: missing.map((c) => c.id), ...(priorMessages?.has(m) === true ? { beforeRun: true } : {}) });
|
|
136
136
|
if (duplicate.length > 0)
|
|
137
137
|
repairs.push({ form: "duplicate_result", toolCallIds: inCallOrder(duplicate) });
|
|
138
138
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -66,7 +66,7 @@ export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
|
66
66
|
export { USER_STEER_UNDRAINED_CAUSES, type UserSteerUndrainedCause } from "./core/engine-notice.js";
|
|
67
67
|
export { TOOL_TURN_INCOMPLETE_CAUSES, type ToolTurnIncompleteCause } from "./internal/llm.js";
|
|
68
68
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
69
|
-
export { TERMINAL_CAUSE_IS_REPLAYABLE, type TerminalFailureDetail } from "./core/terminal-cause.js";
|
|
69
|
+
export { TERMINAL_CAUSE_IS_REPLAYABLE, type TerminalFailureDetail, type TerminalBlockedDetail, PROMPT_BLOCK_CAUSES, type PromptBlockCause, isPromptBlockCause } from "./core/terminal-cause.js";
|
|
70
70
|
export { RESERVED_AGENT_NAMES } from "./agents/subagent.js";
|
|
71
71
|
export { WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS } from "./orchestration/workflow-size-guideline.js";
|
|
72
72
|
export { ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./core/untrusted-text.js";
|
|
@@ -191,14 +191,14 @@ export { createAllowDenyPolicy, createApprovalPolicy,
|
|
|
191
191
|
* members that seat has no lane for (`"unavailable"`, a routing answer; `updatedInput`, an operator edit a
|
|
192
192
|
* policy verdict cannot get re-adjudicated). Exported so a host can NAME it instead of deriving it through
|
|
193
193
|
* `Parameters<typeof createApprovalPolicy>[0]["approve"]`. */
|
|
194
|
-
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
194
|
+
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
195
195
|
export { type ReadRootGrantScreen } from "./core/read-root-grant-screen.js";
|
|
196
196
|
export { type AskOrigin, ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, type PersistedRuleMandate, isPersistedRuleMandate, screenAskClassMembers } from "./core/ask-origin.js";
|
|
197
197
|
export { PERMISSION_MODES, type PermissionMode, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, type AskClass, isAskClass, MODE_ARBITRATION, type ModeArbitrationRow, RELEASABLE_ASK_CLASSES, MODE_RELEASE_REASONS, type ModeReleaseReason, isModeReleaseReason, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, type AskClassification, type AskClassFacts, type ToolMarkSource, arbitrateByMode, type Arbitration, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
198
198
|
export { modePolicyOf, type ModePolicy, PERMISSION_MODE_FOLD_REASONS, type PermissionModeFoldReason, type PermissionModeReceipt, ACCEPT_EDITS_FILE_COMMANDS, modeAcceptsFileCommand } from "./core/mode-policy.js";
|
|
199
199
|
export { readDenyClassifierRules, renderClassifierDenyRules, type DerivedDenyRule } from "./core/auto-mode-prompt.js";
|
|
200
200
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource, type AutoModeDenySource } from "./core/runtime-caps.js";
|
|
201
|
-
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, type ModeRelease, type ModeRefusal, screenGateOutcome } from "./core/gate-outcome.js";
|
|
201
|
+
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_PARTIES, type SettlementParty, isSettlementParty, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, type ModeRelease, type ModeRefusal, screenGateOutcome } from "./core/gate-outcome.js";
|
|
202
202
|
export { type AskCarry } from "./core/hooks.js";
|
|
203
203
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
|
|
204
204
|
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, classifierParseFailureDenyMessage, AUTO_MODE_PARSE_FAILURES, isAutoModeParseFailure, type AutoModeParseFailure, type AutoModeUnavailableCause, AUTO_MODE_CLASSIFIER_FALLBACKS, isAutoModeClassifierFallback, AUTO_MODE_FALLBACK_CAUSES, isAutoModeFallbackCause, type AutoModeClassifierFallback, type AutoModeFallbackCause, type AutoModeClassifierRound, type AutoModeLadderRung, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
|
|
@@ -264,6 +264,7 @@ export { buildTurnPromptSnapshot, loweringRecordFor, LOWERING_VERSION, PREFIX_IN
|
|
|
264
264
|
export { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, type PromptArtifactSource, type PromptArtifactStore, type PromptSourceState, type PromptSourceStateStore, } from "./prompt-assembly/artifact-store.js";
|
|
265
265
|
export { stripEngineMetadata } from "./internal/llm.js";
|
|
266
266
|
export { EVENT_PROMPT_REGISTRY, eventDefaultOn, type CompiledEventPrompt, type EventDedupe, type EventDefaultPolicy } from "./prompt-assembly/event-registry.js";
|
|
267
|
+
export { OUTPUT_STYLE_NAME_MAX } from "./core/output-style.js";
|
|
267
268
|
export { contextUsageSections, type ContextUsageSection } from "./prompt-assembly/section-usage.js";
|
|
268
269
|
export type { CompiledSection, ComposedPrompt, PackSectionDeclaration, PromptCacheClass, PromptCarrier, PromptMutability, PromptOwner, PromptPack, PromptRenderCadence, PromptRuntimeFacts, PromptSlot, PromptTrust, SectionRenderInputs, } from "./prompt-assembly/types.js";
|
|
269
270
|
export { type ReasoningIntensity, type ReasoningResolution, type ResolvedReasoning, type ReasoningFormat, DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf, resolveEffort, reasoningEffortLevelsOf, resolveBinary, reasoningBudgetShare, resolveReasoning, thinkingOffSpelled, declaredOffSpelling, type OffCapabilityModel, resolveReasoningProfile, type ReasoningTier, type ReasoningProfileFlags, } from "./brain/reasoning.js";
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
|
52
52
|
export { USER_STEER_UNDRAINED_CAUSES } from "./core/engine-notice.js";
|
|
53
53
|
export { TOOL_TURN_INCOMPLETE_CAUSES } from "./internal/llm.js";
|
|
54
54
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
55
|
-
export { TERMINAL_CAUSE_IS_REPLAYABLE } from "./core/terminal-cause.js";
|
|
55
|
+
export { TERMINAL_CAUSE_IS_REPLAYABLE, PROMPT_BLOCK_CAUSES, isPromptBlockCause } from "./core/terminal-cause.js";
|
|
56
56
|
export { RESERVED_AGENT_NAMES } from "./agents/subagent.js";
|
|
57
57
|
export { WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS } from "./orchestration/workflow-size-guideline.js";
|
|
58
58
|
export { ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./core/untrusted-text.js";
|
|
@@ -156,14 +156,14 @@ export { hasScheduler, isValidCronExpr, SchedulerError } from "./core/scheduler.
|
|
|
156
156
|
export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
|
|
157
157
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
|
|
158
158
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
159
|
-
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
159
|
+
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
160
160
|
export {} from "./core/read-root-grant-screen.js";
|
|
161
161
|
export { ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, isPersistedRuleMandate, screenAskClassMembers } from "./core/ask-origin.js";
|
|
162
162
|
export { PERMISSION_MODES, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, isAskClass, MODE_ARBITRATION, RELEASABLE_ASK_CLASSES, MODE_RELEASE_REASONS, isModeReleaseReason, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, arbitrateByMode, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
163
163
|
export { modePolicyOf, PERMISSION_MODE_FOLD_REASONS, ACCEPT_EDITS_FILE_COMMANDS, modeAcceptsFileCommand } from "./core/mode-policy.js";
|
|
164
164
|
export { readDenyClassifierRules, renderClassifierDenyRules } from "./core/auto-mode-prompt.js";
|
|
165
165
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./core/runtime-caps.js";
|
|
166
|
-
export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, screenGateOutcome } from "./core/gate-outcome.js";
|
|
166
|
+
export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_PARTIES, isSettlementParty, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, screenGateOutcome } from "./core/gate-outcome.js";
|
|
167
167
|
export {} from "./core/hooks.js";
|
|
168
168
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
|
|
169
169
|
export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, classifierParseFailureDenyMessage, AUTO_MODE_PARSE_FAILURES, isAutoModeParseFailure, AUTO_MODE_CLASSIFIER_FALLBACKS, isAutoModeClassifierFallback, AUTO_MODE_FALLBACK_CAUSES, isAutoModeFallbackCause, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, } from "./core/auto-mode.js";
|
|
@@ -212,6 +212,7 @@ export { buildTurnPromptSnapshot, loweringRecordFor, LOWERING_VERSION, PREFIX_IN
|
|
|
212
212
|
export { CenterPromptSource, FilePromptArtifactStore, FilePromptSourceStateStore, MemoryPromptArtifactStore, MemoryPromptSourceStateStore, } from "./prompt-assembly/artifact-store.js";
|
|
213
213
|
export { stripEngineMetadata } from "./internal/llm.js";
|
|
214
214
|
export { EVENT_PROMPT_REGISTRY, eventDefaultOn } from "./prompt-assembly/event-registry.js";
|
|
215
|
+
export { OUTPUT_STYLE_NAME_MAX } from "./core/output-style.js";
|
|
215
216
|
export { contextUsageSections } from "./prompt-assembly/section-usage.js";
|
|
216
217
|
export { DEFAULT_EFFORT_LEVELS, REASONING_BUDGET_SHARE, isThinkingLevel, rankOf, resolveEffort, reasoningEffortLevelsOf, resolveBinary, reasoningBudgetShare, resolveReasoning, thinkingOffSpelled, declaredOffSpelling, resolveReasoningProfile, } from "./brain/reasoning.js";
|
|
217
218
|
export { DESIGN_REVIEW_PROMPTS, CODE_REVIEW_PROMPT, SCENARIO_REGISTRY, runScenario, } from "./scenarios/scenario-registry.js";
|
|
@@ -3,7 +3,7 @@ export const EVENT_PROMPT_REGISTRY = new Map([
|
|
|
3
3
|
{ kind: "task_reminder", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#TASK_REMINDER_BASE" },
|
|
4
4
|
{ kind: "tool_search_usage_reminder", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderToolSearchUsageReminder" },
|
|
5
5
|
{ kind: "changed_files", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderChangedFiles" },
|
|
6
|
-
{ kind: "
|
|
6
|
+
{ kind: "output_style", carrier: "message.user-prefix", trust: "operator", dedupe: "repeat", defaultPolicy: "always", rendererRef: "../output-style.ts#renderOutputStyle" },
|
|
7
7
|
{ kind: "date_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "turn-attachments.ts#renderDateChange" },
|
|
8
8
|
{ kind: "instructions_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", maxBytes: 512, defaultPolicy: "always", rendererRef: "turn-attachments.ts#collectInstructionsChange" },
|
|
9
9
|
{ kind: "workflow_size_guideline_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "run-turn-boundary.ts#workflowSizeGuidelineChangeNotice" },
|
|
@@ -16,6 +16,7 @@ export const EVENT_PROMPT_REGISTRY = new Map([
|
|
|
16
16
|
{ kind: "mcp_instructions", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderMcpInstructionsDelta" },
|
|
17
17
|
{ kind: "mcp_dropped_tools", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderMcpDroppedTools" },
|
|
18
18
|
{ kind: "git_status", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "git-status-frame.ts#renderGitStatusFrameBody" },
|
|
19
|
+
{ kind: "permission_posture", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "../auto-mode-directive.ts#POSTURE_TABLE" },
|
|
19
20
|
{ kind: "limit_approach_converge", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "run-turn-boundary.ts#limitApproachFrames" },
|
|
20
21
|
{ kind: "limit_approach_deliver", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "run-turn-boundary.ts#limitApproachFrames" },
|
|
21
22
|
{ kind: "final_verification", carrier: "message.user-prefix", trust: "operator", dedupe: "once-per-run", defaultPolicy: "always", rendererRef: "runtask.ts#final-verification" },
|
|
@@ -133,10 +133,11 @@ export declare class AppendLog {
|
|
|
133
133
|
* onto the remnant, so replay dropped BOTH — after that second append had returned and fsync'd. Measured:
|
|
134
134
|
* records [1,2,3] + a torn remnant + appends 5,6 replayed as [1,2,3,6].
|
|
135
135
|
*
|
|
136
|
-
* Cost on the healthy path is ONE `fstat` per append (the sizes match and we return); the
|
|
137
|
-
*
|
|
138
|
-
* process under the boot-lock handoff) leaves the file
|
|
139
|
-
*
|
|
136
|
+
* Cost on the healthy path is ONE `fstat` per append (the sizes match and we return); the tail read only
|
|
137
|
+
* happens when the file actually moved off a boundary, and it reads the last segment, not the file. A
|
|
138
|
+
* legitimate concurrent appender (another process under the boot-lock handoff) leaves the file
|
|
139
|
+
* newline-terminated, so it is adopted, not truncated; a whole record it left without its newline is kept
|
|
140
|
+
* and ended, and only a partial one is cut.
|
|
140
141
|
*/
|
|
141
142
|
private repairTail;
|
|
142
143
|
/**
|
|
@@ -171,6 +172,30 @@ export declare class AppendLog {
|
|
|
171
172
|
closeForSwap(): void;
|
|
172
173
|
private releaseFd;
|
|
173
174
|
}
|
|
175
|
+
/** Bytes read per positioned read while a file's tail is walked back to its last newline. */
|
|
176
|
+
export declare const JSONL_TAIL_READ_BLOCK: number;
|
|
177
|
+
/**
|
|
178
|
+
* The longest last segment (in BYTES) a repair station will judge: V8's maximum string length in UTF-16 code units
|
|
179
|
+
* (Node's `buffer.constants.MAX_STRING_LENGTH`). A segment of N bytes decodes to at most N code units, so one within
|
|
180
|
+
* the bound can never make `toString` throw. One past it MAY still decode (multi-byte text has fewer units than
|
|
181
|
+
* bytes) but is left unjudged either way: telling would mean reading and decoding up to three times the bound.
|
|
182
|
+
*/
|
|
183
|
+
export declare const JSONL_TAIL_SEGMENT_LIMIT: number;
|
|
184
|
+
/** A file's last segment (the bytes after its last `\n`, or the whole file when it holds none) — or the fact that it is
|
|
185
|
+
* too long to judge. `start` is the segment's offset; a file that ends on a newline has an empty segment at `size`. */
|
|
186
|
+
export type JsonlTailSegment = {
|
|
187
|
+
unjudgeable: false;
|
|
188
|
+
start: number;
|
|
189
|
+
bytes: Buffer;
|
|
190
|
+
} | {
|
|
191
|
+
unjudgeable: true;
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* The last segment of an open file of `size` bytes, found by walking back from the end one block at a time to the
|
|
195
|
+
* last newline: a read is bounded by the segment's length, never by the file's. The one reader of "what is the tail"
|
|
196
|
+
* for every repair station; whether the segment is a record is {@link jsonlTextFormOf}'s to say.
|
|
197
|
+
*/
|
|
198
|
+
export declare function readTailSegment(fd: number, size: number, limit?: number): JsonlTailSegment;
|
|
174
199
|
/** Why a {@link BootLock}/{@link acquireStoreDirLock} acquisition was refused, as a branchable code. */
|
|
175
200
|
export type FileStoreLockErrorCode =
|
|
176
201
|
/** A LIVE process (this one or another) already holds the directory. Steady state: it ends when that
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { appendFileSync, closeSync, constants as FS, existsSync, fstatSync, ftruncateSync, linkSync, mkdirSync, openSync, readFileSync, readSync, renameSync, truncateSync, unlinkSync, writeFileSync, writeSync, fsyncSync, } from "node:fs";
|
|
2
|
+
import { constants as bufferConstants } from "node:buffer";
|
|
2
3
|
import { homedir, hostname, uptime } from "node:os";
|
|
3
4
|
import { hrtime } from "node:process";
|
|
4
5
|
import { basename, dirname, join, resolve as resolvePath } from "node:path";
|
|
@@ -285,23 +286,71 @@ export class AppendLog {
|
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
288
|
}
|
|
289
|
+
export const JSONL_TAIL_READ_BLOCK = 64 * 1024;
|
|
290
|
+
export const JSONL_TAIL_SEGMENT_LIMIT = bufferConstants.MAX_STRING_LENGTH;
|
|
291
|
+
function readExactly(fd, into, length, position) {
|
|
292
|
+
let got = 0;
|
|
293
|
+
while (got < length) {
|
|
294
|
+
const n = readSync(fd, into, got, length - got, position + got);
|
|
295
|
+
if (n <= 0)
|
|
296
|
+
throw new Error(`jsonl tail: the file ended ${length - got} bytes early while its last line was read — it shrank under the reader`);
|
|
297
|
+
got += n;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
export function readTailSegment(fd, size, limit = JSONL_TAIL_SEGMENT_LIMIT) {
|
|
301
|
+
const block = Buffer.allocUnsafe(Math.min(JSONL_TAIL_READ_BLOCK, size));
|
|
302
|
+
let start = 0;
|
|
303
|
+
for (let end = size; end > 0;) {
|
|
304
|
+
const from = Math.max(0, end - JSONL_TAIL_READ_BLOCK);
|
|
305
|
+
readExactly(fd, block, end - from, from);
|
|
306
|
+
const newline = block.subarray(0, end - from).lastIndexOf(0x0a);
|
|
307
|
+
if (newline >= 0) {
|
|
308
|
+
start = from + newline + 1;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
end = from;
|
|
312
|
+
if (size - end > limit)
|
|
313
|
+
return { unjudgeable: true };
|
|
314
|
+
}
|
|
315
|
+
if (size - start > limit)
|
|
316
|
+
return { unjudgeable: true };
|
|
317
|
+
const bytes = Buffer.allocUnsafe(size - start);
|
|
318
|
+
readExactly(fd, bytes, bytes.length, start);
|
|
319
|
+
return { unjudgeable: false, start, bytes };
|
|
320
|
+
}
|
|
288
321
|
function repairJsonlTail(path) {
|
|
289
|
-
let
|
|
322
|
+
let fd;
|
|
290
323
|
try {
|
|
291
|
-
|
|
324
|
+
fd = openSync(path, "r");
|
|
292
325
|
}
|
|
293
326
|
catch (err) {
|
|
294
327
|
if (err.code === "ENOENT")
|
|
295
328
|
return;
|
|
296
329
|
throw err;
|
|
297
330
|
}
|
|
298
|
-
|
|
331
|
+
let segment;
|
|
332
|
+
try {
|
|
333
|
+
segment = readTailSegment(fd, fstatSync(fd).size);
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
closeSync(fd);
|
|
337
|
+
}
|
|
338
|
+
if (segment.unjudgeable) {
|
|
339
|
+
appendFileSync(path, "\n");
|
|
340
|
+
try {
|
|
341
|
+
console.warn(`[sema] file store: a tail segment larger than the judgeable bound (${JSONL_TAIL_SEGMENT_LIMIT} bytes) was ended as a line, not judged — ` +
|
|
342
|
+
`${path}. Its bytes are untouched; a reader meets it as an ordinary line.`);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (segment.bytes.length === 0)
|
|
299
349
|
return;
|
|
300
|
-
|
|
301
|
-
if (jsonlTextFormOf(bytes.toString("utf8", segmentStart)).form === "record")
|
|
350
|
+
if (jsonlTextFormOf(segment.bytes.toString("utf8")).form === "record")
|
|
302
351
|
appendFileSync(path, "\n");
|
|
303
352
|
else
|
|
304
|
-
truncateSync(path,
|
|
353
|
+
truncateSync(path, segment.start);
|
|
305
354
|
}
|
|
306
355
|
export class FileStoreLockError extends Error {
|
|
307
356
|
code;
|
package/dist/tools/fs/index.d.ts
CHANGED
|
@@ -192,7 +192,8 @@ export interface HandsToolkitOptions {
|
|
|
192
192
|
* not asked and no home is added (each listed home is anchored at its spelling and, where the environment answers one,
|
|
193
193
|
* its canonical spelling), and the band's home views (a path spelled through a firmlink or a bind mount of a home,
|
|
194
194
|
* judged at the home) read this list and the environment's declared home; an entry that is not the declared home is probed once,
|
|
195
|
-
* under a short bound of its own, and a probe of it that fails costs that entry alone.
|
|
195
|
+
* under a short bound of its own, and a probe of it that fails costs that entry alone. The public shell judgment takes the
|
|
196
|
+
* same list as {@link import("./shell-read-check.js").ShellReadJudgeInput.readDenyHomes}. */
|
|
196
197
|
readDenyHomes?: readonly string[];
|
|
197
198
|
/** Where each home-anchored row's literal head leads beyond the home's spellings
|
|
198
199
|
* ({@link import("./read-deny-home.js").readDenyHomeLinksOf}, keyed by the row's pattern) — the Runner passes the
|
|
@@ -100,8 +100,9 @@ export declare function placementViewsOf(homes: readonly string[]): HomeViewSour
|
|
|
100
100
|
* time: no latch). */
|
|
101
101
|
export declare function sayPlacementLost(): void;
|
|
102
102
|
/** The home views over a home list fixed now — a mount that places nothing itself (a toolkit handed its placement, or
|
|
103
|
-
* one whose table has no home-anchored row) and the public shell judgment
|
|
104
|
-
* `homes` that is not the declared home as an auxiliary home,
|
|
103
|
+
* one whose table has no home-anchored row) and the public shell judgment (the `readDenyHomes` its boundary's rows were
|
|
104
|
+
* compiled under): the declared home, and every entry of `homes` that is not the declared home as an auxiliary home,
|
|
105
|
+
* read once, at once. */
|
|
105
106
|
export declare function homeViewsAt(env: HomeViewEnv, homes: readonly string[]): HomeViewSource;
|
|
106
107
|
/** The home views of one judgment, off the judge it judges with: the views of the judge's placement. A judge that
|
|
107
108
|
* carries none (one built outside a mount) reads the declared home alone. */
|
|
@@ -312,10 +312,12 @@ export function sayPlacementLost() {
|
|
|
312
312
|
catch {
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
|
-
|
|
315
|
+
function readAuxiliaryHomes(env, homes, opts, signal) {
|
|
316
316
|
const declared = declaredHomeOf(env);
|
|
317
|
-
|
|
318
|
-
|
|
317
|
+
return [...new Set(homes.filter((h) => isAbsolutePathForm(h) && !isDeclared(declared, h)))].map((home) => readAuxiliaryHome(env, home, opts, signal));
|
|
318
|
+
}
|
|
319
|
+
export function homeViewsAt(env, homes) {
|
|
320
|
+
return homeViewSourceOver(env, readAuxiliaryHomes(env, homes, {}));
|
|
319
321
|
}
|
|
320
322
|
export function homeViewsOf(env, judge, signal) {
|
|
321
323
|
return (judge?.homeViews ?? homeViewsAt(env, [])).views(signal);
|
|
@@ -338,7 +340,7 @@ export async function placeReadDenyAtHome(env, compile, homes, signal) {
|
|
|
338
340
|
return heldAnywhere(false);
|
|
339
341
|
declaredAt = [...new Set([...own, ...ownSpellings.spellings])];
|
|
340
342
|
}
|
|
341
|
-
const auxiliary =
|
|
343
|
+
const auxiliary = readAuxiliaryHomes(env, listed.homes, { entries }, signal);
|
|
342
344
|
const [heads, readings] = await Promise.all([readDenyHomeLinksOf(env, entries, declaredAt, signal), Promise.all(auxiliary)]);
|
|
343
345
|
const at = [...new Set([...declaredAt, ...readings.flatMap((r) => r.place)])];
|
|
344
346
|
const linked = new Map();
|
|
@@ -163,6 +163,12 @@ export interface ShellReadJudgeInput {
|
|
|
163
163
|
readonly readers?: ReadonlySet<string>;
|
|
164
164
|
/** The face named in a refusal sentence. Defaults to `Bash`. */
|
|
165
165
|
readonly tool?: string;
|
|
166
|
+
/** The home list the boundary's deny rows were compiled under (`HandsToolkitOptions.readDenyHomes`'s seat, same list, same
|
|
167
|
+
* meaning: absolute home paths, anything else rejects naming `readDenyHomes`). Present ⇒ the judgment's home views are
|
|
168
|
+
* that table's — the environment's declared home is always among them, every other entry is read once under a short
|
|
169
|
+
* bound of its own — and the account database is not asked and no home is added; `[]` leaves the declared home alone.
|
|
170
|
+
* Absent ⇒ the judgment is its own placement: the declared home and the account's home, asked once for this call. */
|
|
171
|
+
readonly readDenyHomes?: readonly string[];
|
|
166
172
|
/** Handed to the ENVIRONMENT's own primitives (`canonicalPath`, `listDir`) while the reads are
|
|
167
173
|
* established; whether an abort stops one is the adapter's answer, and a walk short enough to finish
|
|
168
174
|
* first finishes. It is NOT a deadline and it does not reach `boundary.alsoInside`, whose signature
|
|
@@ -196,9 +202,10 @@ export interface ShellReadJudgment {
|
|
|
196
202
|
* pattern on its spelling alone, so the two diverge in both directions.
|
|
197
203
|
*
|
|
198
204
|
* A read target is also judged at its HOME VIEW (a path spelled through a firmlink or a bind mount of a home, respelled
|
|
199
|
-
* at the home)
|
|
200
|
-
*
|
|
201
|
-
*
|
|
205
|
+
* at the home). The views read the home list the boundary's rows were compiled under when the input names it
|
|
206
|
+
* ({@link ShellReadJudgeInput.readDenyHomes}); without it this judgment is its own placement — the environment's declared
|
|
207
|
+
* home and the account home the account database answers once, for this call (`readDenyHomesOf`'s homes). Every home
|
|
208
|
+
* beside the declared one waits at most a short bound of its own.
|
|
202
209
|
*
|
|
203
210
|
* It carries NO deadline. Bounding an environment-facing wait and substituting a fail-closed verdict is the
|
|
204
211
|
* gate FOLD's policy on the gate's one deadline seat; the station has never held one on either entry, and a
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { errorResult } from "../../core/tools.js";
|
|
2
2
|
import { BASH_READONLY_CONFINEMENT_NOTE } from "./fs-shared.js";
|
|
3
3
|
import { isAbsoluteForFamily, normalizeAbsPathLexically, pathFamilyOf, violationDetails, withinAnyRoot } from "./safety.js";
|
|
4
|
-
import { fitMiddle, READ_DENY_SENTENCE_PART_MAX, readDenySentence } from "./read-deny.js";
|
|
4
|
+
import { checkedReadDenyHomes, fitMiddle, READ_DENY_SENTENCE_PART_MAX, readDenySentence } from "./read-deny.js";
|
|
5
5
|
import { NOT_AUTO_ALLOWED, programPositionRefusalSentence, readProgramPosition } from "./bash-program-position.js";
|
|
6
6
|
import { bashClassifyDefaultAllow } from "./bash-readonly-classifier.js";
|
|
7
7
|
import { planShellReads } from "./shell-read-plan.js";
|
|
@@ -327,7 +327,7 @@ async function runShellReadStation(tool, command, declared, seat, readers, estab
|
|
|
327
327
|
}
|
|
328
328
|
export async function judgeShellRead(input) {
|
|
329
329
|
const readers = input.readers ?? new Set(bashClassifyDefaultAllow());
|
|
330
|
-
const run = await runShellReadStation(input.tool ?? "Bash", input.command, input.boundary, input.seat, readers, createShellReadEstablisher(input.env, input.boundary.roots, { homeViews: homeViewsAt(input.env, declaredReadDenyHomes(input.env)) }), input.env, input.signal);
|
|
330
|
+
const run = await runShellReadStation(input.tool ?? "Bash", input.command, input.boundary, input.seat, readers, createShellReadEstablisher(input.env, input.boundary.roots, { homeViews: homeViewsAt(input.env, input.readDenyHomes === undefined ? declaredReadDenyHomes(input.env) : checkedReadDenyHomes(input.readDenyHomes)) }), input.env, input.signal);
|
|
331
331
|
const offer = normalizeReadRootCandidate(run.verdict.readRootCandidate);
|
|
332
332
|
return {
|
|
333
333
|
plan: run.plan,
|