@sema-agent/core 7.44.0 → 7.45.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 +172 -0
- package/dist/agents/subagent.js +33 -14
- package/dist/agents/tool-filter.d.ts +65 -4
- package/dist/agents/tool-filter.js +127 -4
- package/dist/core/agent-definition.d.ts +2 -2
- package/dist/core/allow-entry.d.ts +25 -1
- package/dist/core/allow-entry.js +29 -4
- package/dist/core/ask-origin.d.ts +23 -4
- package/dist/core/ask-origin.js +10 -4
- package/dist/core/checkpoint-store.d.ts +2 -2
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/effective-path-target.d.ts +7 -6
- package/dist/core/effective-path-target.js +3 -7
- package/dist/core/engine-notice.d.ts +20 -3
- package/dist/core/engine-notice.js +12 -6
- package/dist/core/gate-lanes.js +2 -0
- package/dist/core/gate-outcome.d.ts +5 -0
- package/dist/core/gate-outcome.js +2 -0
- package/dist/core/hooks.d.ts +2 -0
- package/dist/core/memory-engine/content-origin.d.ts +0 -34
- package/dist/core/memory-engine/content-origin.js +9 -4
- package/dist/core/memory-engine/layout.d.ts +5 -1
- package/dist/core/memory-engine/layout.js +1 -0
- package/dist/core/permission-rules.d.ts +4 -0
- package/dist/core/permission-rules.js +5 -2
- package/dist/core/real-approval.d.ts +9 -6
- package/dist/core/real-approval.js +5 -5
- package/dist/core/runner/child-tree.d.ts +13 -0
- package/dist/core/runner/child-tree.js +3 -0
- package/dist/core/runner/contracts.d.ts +8 -2
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
- package/dist/core/runner/prepare-ask-lane.js +2 -2
- package/dist/core/runner/prepare-config-doors.js +3 -1
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
- package/dist/core/runner/prepare-gate-stations.js +2 -1
- package/dist/core/runner/prepare-listings.d.ts +4 -4
- package/dist/core/runner/prepare-listings.js +2 -22
- package/dist/core/runner/prepare-park-ask.d.ts +2 -0
- package/dist/core/runner/prepare-park-ask.js +2 -2
- package/dist/core/runner/prepare-policy-chain.d.ts +2 -0
- package/dist/core/runner/prepare-policy-chain.js +4 -2
- package/dist/core/runner/prepare-task.js +10 -6
- package/dist/core/runner/resume-policy-outcome.js +2 -1
- package/dist/core/runner/run-leg.js +1 -1
- package/dist/core/runner/run-notification-lane.js +2 -2
- package/dist/core/runner/runtask.d.ts +2 -0
- package/dist/core/runner/runtask.js +2 -0
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +32 -0
- package/dist/core/runner/sub-agent-deny-lists.js +121 -0
- package/dist/core/runner/synthetic-tools.d.ts +1 -1
- package/dist/core/runner/synthetic-tools.js +3 -2
- package/dist/core/session-policy-store.d.ts +6 -2
- package/dist/core/session-policy-store.js +2 -1
- package/dist/core/skill-grant.d.ts +10 -2
- package/dist/core/skill-grant.js +20 -4
- package/dist/core/task-notification.d.ts +12 -1
- package/dist/core/task-notification.js +13 -1
- package/dist/core/task-spec.d.ts +5 -3
- package/dist/core/tool-policy.d.ts +15 -4
- package/dist/core/tool-policy.js +9 -13
- package/dist/core/tool-spec.d.ts +20 -2
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.js +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +5 -3
- package/dist/orchestration/workflow.js +2 -1
- package/dist/tools/fs/removal-targets.d.ts +82 -0
- package/dist/tools/fs/removal-targets.js +236 -0
- package/dist/tools/fs/shell-read-write-targets.d.ts +27 -0
- package/dist/tools/fs/shell-read-write-targets.js +1 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +33 -1
- package/wire-changes/core@7.45.0.json +1084 -0
package/dist/core/tool-policy.js
CHANGED
|
@@ -21,6 +21,7 @@ import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermission
|
|
|
21
21
|
import { protocolOf } from "./protocol-table.js";
|
|
22
22
|
import { isAbsoluteForFamily, isAbsolutePathForm, joinForFamily, normalizeAbsPathLexically, pathFamilyOf, writeTargetPath } from "../tools/fs/safety.js";
|
|
23
23
|
import { ASSIGNMENT_PREFIX, writtenAssignmentPrefix } from "../tools/fs/bash-program-position.js";
|
|
24
|
+
import { removalReadingOf } from "../tools/fs/removal-targets.js";
|
|
24
25
|
const nameListHolds = (set, req) => heldBy("policy.nameLists", set, req);
|
|
25
26
|
const shellToolsListHolds = (set, req) => heldBy("policy.shellToolsList", set, req);
|
|
26
27
|
export function advertisedWritableRootsSeat(seat) {
|
|
@@ -920,28 +921,23 @@ function hasRecursiveForce(argvTail) {
|
|
|
920
921
|
export function createUnverifiableDeletePolicy(opts) {
|
|
921
922
|
const safeVars = new Set([...UNVERIFIABLE_DELETE_SAFE_VARS, ...(opts?.safeVars ?? [])]);
|
|
922
923
|
const shellTools = canonicalToolNameSet(opts?.tools);
|
|
924
|
+
const unverifiable = (command, finding = findUnverifiableRecursiveDelete(command, safeVars)) => (finding === undefined ? ALLOW : removalAsk("unverifiable_delete", finding));
|
|
923
925
|
return brandPolicyAskClass({
|
|
924
|
-
check(req) {
|
|
926
|
+
check(req, signal) {
|
|
925
927
|
if (!shellToolsListHolds(shellTools, req))
|
|
926
928
|
return ALLOW;
|
|
927
929
|
const command = req.args?.command;
|
|
928
930
|
if (typeof command !== "string")
|
|
929
931
|
return ALLOW;
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
return ALLOW;
|
|
933
|
-
return {
|
|
934
|
-
action: "ask",
|
|
935
|
-
decisionReason: "safety",
|
|
936
|
-
requiresRealApproval: true,
|
|
937
|
-
guard: "unverifiable_delete",
|
|
938
|
-
message: `Unverifiable recursive delete (fail-closed unless cleared): ${finding}. ` +
|
|
939
|
-
`Re-run the delete with the resolved literal path written into the command itself ` +
|
|
940
|
-
`(or assign the variable in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`,
|
|
941
|
-
};
|
|
932
|
+
const removal = removalReadingOf(command, req, opts?.removalSeat);
|
|
933
|
+
return removal === undefined ? unverifiable(command) : removal.judge(signal).then((found) => (found === undefined ? unverifiable(command) : removalAsk(found.guard, found.text)));
|
|
942
934
|
},
|
|
943
935
|
}, "external_authority");
|
|
944
936
|
}
|
|
937
|
+
function removalAsk(guard, text) {
|
|
938
|
+
const message = guard === "dangerous_delete" ? `Dangerous removal: ${text}. No permission mode, allow rule or classifier clears this — only a person confirming this call does.` : `Unverifiable recursive delete (fail-closed unless cleared): ${text}. Re-run the delete with the resolved literal path written into the command itself (or assign the variable a literal path in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`;
|
|
939
|
+
return { action: "ask", decisionReason: "safety", requiresRealApproval: true, guard, message };
|
|
940
|
+
}
|
|
945
941
|
function pathSegments(p) {
|
|
946
942
|
return p.split(/[\\/]/).filter(Boolean);
|
|
947
943
|
}
|
package/dist/core/tool-spec.d.ts
CHANGED
|
@@ -175,18 +175,36 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
|
|
|
175
175
|
* offered pool a child of that type actually mounts. Filled by `createSubagentTool` beside
|
|
176
176
|
* `agentListing`; a type with neither list gets the whole offered pool.
|
|
177
177
|
*
|
|
178
|
-
* Read by
|
|
178
|
+
* Read by the memory content-origin face, which classifies a delegation RESULT by the
|
|
179
179
|
* child's tool face. A child that can reach a network or protocol tool returns content from outside
|
|
180
180
|
* the trust boundary just as surely as calling that tool here would, and the parent's transcript is
|
|
181
181
|
* where it lands. Static by construction — the child's face is known from its definition, so no
|
|
182
|
-
* runtime tracking of what the child actually did is involved (that is the v2 ticket).
|
|
182
|
+
* runtime tracking of what the child actually did is involved (that is the v2 ticket). `authored`
|
|
183
|
+
* marks the entries minted from a definition a caller wrote on a tool a deployment mounted (not the
|
|
184
|
+
* engine's built-ins, the general-purpose alias, fork, or the engine's nested copy of the tool for a
|
|
185
|
+
* delegated child); prepare's deny-name check judges only those.
|
|
183
186
|
*/
|
|
184
187
|
agentToolFaces?: ReadonlyArray<{
|
|
185
188
|
name: string;
|
|
186
189
|
allowTools?: readonly string[];
|
|
187
190
|
denyTools?: readonly string[];
|
|
188
191
|
canRedelegate?: boolean;
|
|
192
|
+
authored?: true;
|
|
189
193
|
}>;
|
|
194
|
+
/**
|
|
195
|
+
* The tool-level `denyTools` list of the delegation tool (`SubagentToolOptions.denyTools`, applied when no agent definition is
|
|
196
|
+
* selected), exactly as written, filled by `createSubagentTool` beside {@link agentToolFaces}; absent when none was written
|
|
197
|
+
* and on the engine's nested copy for a delegated child. Read by prepare's deny-name check, which judges it with
|
|
198
|
+
* the `authored` entries of the faces.
|
|
199
|
+
*/
|
|
200
|
+
agentToolLevelDenyTools?: readonly string[];
|
|
201
|
+
/**
|
|
202
|
+
* The tool-level `allowTools` list of the delegation tool (`SubagentToolOptions.allowTools`, applied when no agent definition is
|
|
203
|
+
* selected), as the tool copied it, filled by `createSubagentTool` beside {@link agentToolLevelDenyTools}; absent when none was
|
|
204
|
+
* written and on the engine's nested copy for a delegated child. Read by prepare's allowed-list judgment: a value that is not a
|
|
205
|
+
* list of strings is refused before the run.
|
|
206
|
+
*/
|
|
207
|
+
agentToolLevelAllowTools?: readonly string[];
|
|
190
208
|
/**
|
|
191
209
|
* design/178 §3 (ruled 2026-08-08) — the POOL a delegated child draws from, as the delegation tool
|
|
192
210
|
* captured it. Read together with {@link agentToolFaces} by the memory content-origin face: the face
|
package/dist/core/types.d.ts
CHANGED
|
@@ -30,5 +30,5 @@ export type { BackgroundChildEvent, DelegationLifecycleEvent } from "./delegatio
|
|
|
30
30
|
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
31
31
|
export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
|
|
32
32
|
export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
|
|
33
|
-
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES } from "./engine-notice.js";
|
|
33
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
|
34
34
|
export type { AgentTool, Model, StreamFn, ThinkingLevel, ToolInputValidationContext, ToolInputVerdict };
|
package/dist/core/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { MODEL_ROLES } from "./model-seat.js";
|
|
2
2
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
3
3
|
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
4
|
-
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES } from "./engine-notice.js";
|
|
4
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
|
|
|
63
63
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice, type McpInjectionDropReason, type McpInjectionDropFacts } from "./core/mcp-injection-drop.js";
|
|
64
64
|
export { askUnresolvableNotice, type AskUnresolvableFacts } from "./core/ask-unresolvable-notice.js";
|
|
65
65
|
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
66
|
-
export { USER_INPUT_UNDRAINED_CAUSES, type UserInputUndrainedCause } from "./core/engine-notice.js";
|
|
66
|
+
export { USER_INPUT_UNDRAINED_CAUSES, type UserInputUndrainedCause, USER_INPUT_UNDRAINED_FAMILIES } from "./core/engine-notice.js";
|
|
67
67
|
export { STEER_REPLAY_FACETS, type SteerReplayFacet } from "./core/steer-replay.js";
|
|
68
68
|
export { TOOL_TURN_INCOMPLETE_CAUSES, type ToolTurnIncompleteCause } from "./internal/llm.js";
|
|
69
69
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
@@ -146,7 +146,7 @@ export { judgeRuleToolName, RULE_TOOL_NAME_VERDICTS, type RuleToolNameVerdict }
|
|
|
146
146
|
export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
|
|
147
147
|
export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, type NotificationInjectionOutcome, // the injector's outcome words (`parked_durably` = the session's durable box took the frame)
|
|
148
148
|
NOTIFICATION_INJECTION_OUTCOMES, // …and their value half + guard, so a host wiring its own uplink validates a reported outcome without duplicating the vocabulary
|
|
149
|
-
isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
|
|
149
|
+
isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, injectionLaneOf, type UserInputLane, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
|
|
150
150
|
export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
|
|
151
151
|
export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
|
|
152
152
|
export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
|
|
@@ -207,7 +207,8 @@ export { ALLOW_RULE_MEMBERS, type AllowRuleMember, type AllowRuleShadow } from "
|
|
|
207
207
|
export { mintNamespacePrefix } from "./core/protocol-naming.js";
|
|
208
208
|
export { readDenyClassifierRules, renderClassifierDenyRules, type DerivedDenyRule } from "./core/auto-mode-prompt.js";
|
|
209
209
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource, type AutoModeDenySource } from "./core/runtime-caps.js";
|
|
210
|
-
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";
|
|
210
|
+
export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_PARTIES, type SettlementParty, isSettlementParty, HOST_DECIDERS, type HostDecider, isHostDecider, 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";
|
|
211
|
+
export { policyCannotAnswer, type HeldQuestion } from "./core/real-approval.js";
|
|
211
212
|
export { type AskCarry } from "./core/hooks.js";
|
|
212
213
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
|
|
213
214
|
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";
|
|
@@ -253,6 +254,7 @@ export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreTo
|
|
|
253
254
|
export { HOOK_FAMILIES, HOOKS_INVALID_CODE, type HookFamily, type WiringManifestHookEntry } from "./core/hook-seats.js";
|
|
254
255
|
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, type NormalizedMemorySpec, type MemorySpecInput, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, type Embedder, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, MemoryProjectionError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, type UtilityGate, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryNoteType, type StructuredNoteInput, MEMORY_PROJECT_KEY_ABSENT_REASONS, type MemoryProjectKeyAbsentReason, type MemoryProjectKey, } from "./core/memory.js";
|
|
255
256
|
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, writableRootOf, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_ORIGIN_CAUSES, committedOriginOf, originEquals, consolidationExposedFrontmatter, ambiguousOriginRepresentation, type OriginClearanceRow, type OriginClearanceEvent, type OriginClearanceShadow, committedDistilledOf, distilledEquals, type MemoryEntryDistilled, type MemoryEntryDistilledInput, CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, deriveShadowedSet, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, type ConsolidationGateRead, type ConsolidationGateRow, type ConsolidationIntent, type ConsolidationIntentCredentialRow, type ConsolidationLeaseSeat, type ConsolidationProductProposal, type ConsolidationProposal, type MemoryConsolidationOptions, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, type ConsolidationPlanFoldEvidence, type SessionMemoryStatus, DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, type CleanArmLeakFinding, type CleanArmLeakVerdict, type MemoryDistillerPurityContract, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, type ConsolidationDistillFn, type ConsolidationDriveCycleRow, type ConsolidationDriveEngine, type ConsolidationDriveResult, type ConsolidationFoldState, type DistillerCandidate, type DistillerChatAnswer, type DistillerChatFn, type DistillerChatRequest, type FuseSchedule, type LlmConsolidationPlan, type LlmConsolidationPlanArm, type LlmConsolidationPlanProduct, type LlmDistillerContract, type MintLlmConsolidationPlanResult, type PlanParseRepairs, type SanitizedLlmGroups, CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, CONSOLIDATION_RUN_STOP_REASONS, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, type ConsolidationDriverEngine, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type ConsolidationRunStopReason, type RunMemoryConsolidationOptions, isInstructionEntry, type MemoryEntryOrigin, type MemoryOriginCause, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, type SessionCaptureOptOutRecord, type SessionCaptureOptOutMarkOutcome, type SessionCaptureRecordStore, readV2HeaderHints, type V2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type CleanMemorySearchHit, type ExposedMemorySearchHit, MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, memoryExposureIndexRow, type MemoryGetDetails, type MemoryIndexDetails, type MemoryIndexRow, type CleanMemoryIndexRow, type ExposedMemoryIndexRow, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, computeMemoryBundleHash, type MemoryExportBundle, type MemoryImportReport, type MemoryExportSnapshot, type MemoryBundleImportPlan, type BundleChallengeRow, type BundleLineageRow, type BundlePollutedSession, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type MemoryScopeEnumeration, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
|
|
257
|
+
export { STORE_FORM_REFUSAL_CODES, TARGET_OUTSIDE_STORE, SCOPE_HOME_NOT_DIRECTORY, SCOPE_HOME_FORMS, type StoreFormRefusalCode, type StoreFormRefusalDetail, type StoreFormRefusal, type ScopeHomeForm } from "./core/memory-engine/layout.js";
|
|
256
258
|
export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, type SharedMemoryStoreProvider, type SharedMemoryStoreReader, type SharedMemoryPagedList, type SharedMemoryStoreInfo, type SharedMemoryDocumentEntry, type SharedMemorySnapshot, type SharedMemoryRequestContext, type MemoryListDetails, type MemoryReadDetails, } from "./core/shared-memory/types.js";
|
|
257
259
|
export { sharedMemoryStoreContract, type SharedMemoryFixture, type SharedMemoryStoreContractHooks, } from "./core/shared-memory/contract.js";
|
|
258
260
|
export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
|
package/dist/index.js
CHANGED
|
@@ -49,7 +49,7 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
|
|
|
49
49
|
export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice } from "./core/mcp-injection-drop.js";
|
|
50
50
|
export { askUnresolvableNotice } from "./core/ask-unresolvable-notice.js";
|
|
51
51
|
export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
|
|
52
|
-
export { USER_INPUT_UNDRAINED_CAUSES } from "./core/engine-notice.js";
|
|
52
|
+
export { USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./core/engine-notice.js";
|
|
53
53
|
export { STEER_REPLAY_FACETS } from "./core/steer-replay.js";
|
|
54
54
|
export { TOOL_TURN_INCOMPLETE_CAUSES } from "./internal/llm.js";
|
|
55
55
|
export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
|
|
@@ -118,7 +118,7 @@ export { createFsWriteGatePolicy, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE } from "./co
|
|
|
118
118
|
export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
|
|
119
119
|
export { judgeRuleToolName, RULE_TOOL_NAME_VERDICTS } from "./core/tool-name-aliases.js";
|
|
120
120
|
export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
|
|
121
|
-
export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
|
|
121
|
+
export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, injectionLaneOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
|
|
122
122
|
export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
|
|
123
123
|
export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
|
|
124
124
|
export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
|
|
@@ -169,7 +169,8 @@ export { ALLOW_RULE_MEMBERS } from "./core/allow-rule-shadow.js";
|
|
|
169
169
|
export { mintNamespacePrefix } from "./core/protocol-naming.js";
|
|
170
170
|
export { readDenyClassifierRules, renderClassifierDenyRules } from "./core/auto-mode-prompt.js";
|
|
171
171
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./core/runtime-caps.js";
|
|
172
|
-
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";
|
|
172
|
+
export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_PARTIES, isSettlementParty, HOST_DECIDERS, isHostDecider, 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";
|
|
173
|
+
export { policyCannotAnswer } from "./core/real-approval.js";
|
|
173
174
|
export {} from "./core/hooks.js";
|
|
174
175
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
|
|
175
176
|
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";
|
|
@@ -199,6 +200,7 @@ export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreTo
|
|
|
199
200
|
export { HOOK_FAMILIES, HOOKS_INVALID_CODE } from "./core/hook-seats.js";
|
|
200
201
|
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, MemoryProjectionError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, MEMORY_PROJECT_KEY_ABSENT_REASONS, } from "./core/memory.js";
|
|
201
202
|
export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, writableRootOf, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_ORIGIN_CAUSES, committedOriginOf, originEquals, consolidationExposedFrontmatter, ambiguousOriginRepresentation, committedDistilledOf, distilledEquals, CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, deriveShadowedSet, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, CONSOLIDATION_RUN_STOP_REASONS, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, isInstructionEntry, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, readV2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, memoryExposureIndexRow, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, erasureSelectHash, computeMemoryBundleHash, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
|
|
203
|
+
export { STORE_FORM_REFUSAL_CODES, TARGET_OUTSIDE_STORE, SCOPE_HOME_NOT_DIRECTORY, SCOPE_HOME_FORMS } from "./core/memory-engine/layout.js";
|
|
202
204
|
export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, } from "./core/shared-memory/types.js";
|
|
203
205
|
export { sharedMemoryStoreContract, } from "./core/shared-memory/contract.js";
|
|
204
206
|
export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
|
|
@@ -19,6 +19,7 @@ import { boundInputHashOf } from "../core/canonical-json.js";
|
|
|
19
19
|
import { boundedRedactedSummary } from "../core/untrusted-egress.js";
|
|
20
20
|
import { delimitUntrusted } from "../core/untrusted-text.js";
|
|
21
21
|
import { OUTPUT_TOOL_NAME } from "../core/runner/synthetic-tools.js";
|
|
22
|
+
import { deniedToolNamesOf } from "../core/runner/sub-agent-deny-lists.js";
|
|
22
23
|
import { compileOutputSchema } from "../core/runner/strict-output-schema.js";
|
|
23
24
|
import { WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentBlockedError, WorkflowAgentParkedError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowMaxAgentsError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } from "./workflow-types.js";
|
|
24
25
|
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
@@ -118,7 +119,7 @@ export function applyWorkflowAgentType(spec, agentType, registry) {
|
|
|
118
119
|
if (out.memoryPersistenceCapable === undefined && def.memoryPersistenceCapable !== undefined)
|
|
119
120
|
out.memoryPersistenceCapable = def.memoryPersistenceCapable;
|
|
120
121
|
if (def.allowTools !== undefined || def.denyTools !== undefined) {
|
|
121
|
-
const perType = createAllowDenyPolicy({ ...(def.allowTools ? { allow: def.allowTools } : {}), ...(def.denyTools ? { deny: def.denyTools } : {}), scope: "narrowing" });
|
|
122
|
+
const perType = createAllowDenyPolicy({ ...(def.allowTools ? { allow: def.allowTools } : {}), ...(def.denyTools ? { deny: deniedToolNamesOf(`workflow agentType "${def.name}"`, def.denyTools) } : {}), scope: "narrowing" });
|
|
122
123
|
out.toolPolicy = out.toolPolicy ? combinePolicies(out.toolPolicy, perType) : perType;
|
|
123
124
|
}
|
|
124
125
|
return out;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type EstablishedPlan } from "./shell-read-establish.js";
|
|
2
|
+
import type { ExecutionEnv } from "../../internal/harness-types.js";
|
|
3
|
+
import type { ToolCallRequest } from "../../core/tool-policy.js";
|
|
4
|
+
/** The REMOVAL programs — the reference implementation's dangerous-removal arm reads `rm` and `rmdir`, with or without a
|
|
5
|
+
* recursive option (removing an empty home or the task root is still removing it). */
|
|
6
|
+
export declare const SHELL_REMOVAL_COMMANDS: readonly ["rm", "rmdir"];
|
|
7
|
+
export type ShellRemovalCommand = (typeof SHELL_REMOVAL_COMMANDS)[number];
|
|
8
|
+
/** What makes a removal target dangerous, in the order a card names it. `runtime_script`: a shell's script text is built
|
|
9
|
+
* only when the command runs, and what it may run includes a removal nobody can read before it does. */
|
|
10
|
+
export type DangerousRemovalKind = "filesystem_root" | "home" | "workspace" | "top_level" | "runtime_script";
|
|
11
|
+
/** The protected locations a removal is judged against. `homes`: the environment's declared home and every other spelling
|
|
12
|
+
* of it (its canonical one); `workspace`: the task root, the working directory, the additional working directories. */
|
|
13
|
+
export interface RemovalSeat {
|
|
14
|
+
readonly homes: readonly string[];
|
|
15
|
+
readonly workspace: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
/** One dangerous removal a command makes: the program (the removal program, or the shell a runtime-built script is handed
|
|
18
|
+
* to), the operand as written, the target as established (the script word as written, for `runtime_script`). */
|
|
19
|
+
export interface DangerousRemoval {
|
|
20
|
+
readonly kind: DangerousRemovalKind;
|
|
21
|
+
readonly program: string;
|
|
22
|
+
readonly operand: string;
|
|
23
|
+
readonly target: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The ONE dangerous-removal predicate: is removing this absolute path removing a protected location? The reference
|
|
27
|
+
* implementation's set (cli 2.1.291 `dme` / `xW`) — the filesystem root (a drive root, a UNC share root), a home directory
|
|
28
|
+
* (every spelling the seat holds), a workspace directory or any of its ANCESTORS (the task root, the working directory, an
|
|
29
|
+
* additional working directory — whether the home lies inside the task root or the task root inside the home), a top-level
|
|
30
|
+
* directory (one segment below the root). `undefined` for a relative path or any other target.
|
|
31
|
+
*/
|
|
32
|
+
export declare function dangerousRemovalOf(path: string, seat: RemovalSeat): DangerousRemovalKind | undefined;
|
|
33
|
+
/** What one removal finding asks: a protected location (`dangerous_delete`), or a target the command builds from a value
|
|
34
|
+
* of its own that the guard cannot read (`unverifiable_delete`). */
|
|
35
|
+
export type RemovalFinding = (DangerousRemoval & {
|
|
36
|
+
readonly guard: "dangerous_delete";
|
|
37
|
+
}) | {
|
|
38
|
+
readonly guard: "unverifiable_delete";
|
|
39
|
+
readonly program: string;
|
|
40
|
+
readonly operand: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The removal findings of an established plan — ONE walk, nested plans included (a `bash -c` / `sh -c` text, a substitution
|
|
45
|
+
* body), two words. For every `rm` / `rmdir` segment, each of its OPERANDS (every write target that is not one of its
|
|
46
|
+
* option words, read off its argv with {@link REMOVAL_GRAMMAR}) as the plan established it on the WRITE face (the entry the
|
|
47
|
+
* program unlinks, and the deny-floor shadow of a home word the plan did not place) is judged by {@link dangerousRemovalOf};
|
|
48
|
+
* an operand the plan could not place that expands a name the command itself binds is judged in every spelling those
|
|
49
|
+
* bindings give it ({@link boundSpellingsOf}), and one with a binding this reading cannot read is an unverifiable target (a
|
|
50
|
+
* recursive force `rm`). A shell handed a script built only when the command runs is a dangerous removal of its own
|
|
51
|
+
* ({@link runtimeScriptOf}). The read-face copy of an operand is not judged: it follows a link the removal does not follow.
|
|
52
|
+
*/
|
|
53
|
+
export declare function removalFindingsOf(established: EstablishedPlan, seat: RemovalSeat): RemovalFinding[];
|
|
54
|
+
/** Does any segment of this plan (nested plans included) run a removal program, or hand a shell a script built when it
|
|
55
|
+
* runs? The guard establishes nothing for a command that does neither. */
|
|
56
|
+
export declare function planRunsRemoval(plan: EstablishedPlan["plan"]): boolean;
|
|
57
|
+
/** What the removal guard asks for one command: the guard word and its sentence's account — the first protected location
|
|
58
|
+
* (the program, the location, the target), else the first bound value the guard cannot read; `undefined` when neither. */
|
|
59
|
+
export interface RemovalVerdict {
|
|
60
|
+
readonly guard: RemovalFinding["guard"];
|
|
61
|
+
readonly text: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The seat the dangerous-removal arm of the removal guard (`createUnverifiableDeletePolicy`, tool-policy.ts) reads, beside the request's own `root` /
|
|
65
|
+
* `cwd` (the task root and the live working directory): the execution environment (its declared home — the `HOME` the
|
|
66
|
+
* shell child receives, the same seat the read station folds `~` / `$HOME` with — and its resolver, so a target that
|
|
67
|
+
* resolves through a link is judged where it lands), and the leg's additional working directories.
|
|
68
|
+
*/
|
|
69
|
+
export interface RemovalGuardSeat {
|
|
70
|
+
readonly env?: ExecutionEnv;
|
|
71
|
+
readonly additionalRoots?: () => readonly string[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The dangerous-removal READING of one command — undefined when no segment of it (nested shell text included) runs a
|
|
75
|
+
* removal program, so a command that removes nothing costs the gate no suspension. Otherwise `judge` establishes the plan
|
|
76
|
+
* the read station plans (the same planner, the same write-target reading) lexically against the request's `cwd` and the
|
|
77
|
+
* seat's home, and — where an environment is seated — through its resolver too, and returns what either establishment
|
|
78
|
+
* finds ({@link removalFindingsOf}: the protected-location word first, then the unverifiable one).
|
|
79
|
+
*/
|
|
80
|
+
export declare function removalReadingOf(command: string, req: Pick<ToolCallRequest, "cwd" | "root">, seat: RemovalGuardSeat | undefined): {
|
|
81
|
+
judge(signal?: AbortSignal): Promise<RemovalVerdict | undefined>;
|
|
82
|
+
} | undefined;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { planShellReads } from "./shell-read-plan.js";
|
|
2
|
+
import { createShellReadEstablisher, establishShellReadsLexically } from "./shell-read-establish.js";
|
|
3
|
+
import { isAbsolutePathForm, isWinFormPath, normalizeAbsPathLexically } from "./safety.js";
|
|
4
|
+
import { reentryText } from "./shell-reentry-text.js";
|
|
5
|
+
import { bashClassifyDefaultAllow, SHELL_REENTRY_PROGRAM_RE } from "./bash-readonly-classifier.js";
|
|
6
|
+
import { programArgs, readArgv } from "./shell-read-write-targets.js";
|
|
7
|
+
import { inlineUntrusted } from "../../core/untrusted-text.js";
|
|
8
|
+
export const SHELL_REMOVAL_COMMANDS = Object.freeze(["rm", "rmdir"]);
|
|
9
|
+
const REMOVAL_COMMAND_SET = new Set(SHELL_REMOVAL_COMMANDS);
|
|
10
|
+
const REMOVAL_GRAMMAR = { required: "", optional: "", longRequired: [] };
|
|
11
|
+
function removalKey(path) {
|
|
12
|
+
let k = normalizeAbsPathLexically(path.normalize("NFC")).replace(/\\/g, "/").toLowerCase();
|
|
13
|
+
k = k.replace(/(?:\/+\*+)+\/*$/, "");
|
|
14
|
+
const drive = driveOf(path, k);
|
|
15
|
+
let rest = k.slice(drive.length);
|
|
16
|
+
if (rest === "")
|
|
17
|
+
rest = "/";
|
|
18
|
+
if (rest.length > 1)
|
|
19
|
+
rest = rest.replace(/\/+$/, "");
|
|
20
|
+
return drive + rest.replace(/^\/private\/(etc|var|tmp|home)(?=\/|$)/, "/$1");
|
|
21
|
+
}
|
|
22
|
+
function driveOf(path, key) {
|
|
23
|
+
return isWinFormPath(path) && key.length >= 2 && key[1] === ":" ? key.slice(0, 2) : "";
|
|
24
|
+
}
|
|
25
|
+
export function dangerousRemovalOf(path, seat) {
|
|
26
|
+
if (!isAbsolutePathForm(path))
|
|
27
|
+
return undefined;
|
|
28
|
+
const k = removalKey(path);
|
|
29
|
+
const rest = k.slice(driveOf(path, k).length);
|
|
30
|
+
if (rest === "/" || /^\/\/[^/]+\/[^/]+$/.test(k))
|
|
31
|
+
return "filesystem_root";
|
|
32
|
+
if (seat.homes.some((h) => isAbsolutePathForm(h) && removalKey(h) === k))
|
|
33
|
+
return "home";
|
|
34
|
+
const prefix = k.endsWith("/") ? k : `${k}/`;
|
|
35
|
+
if (seat.workspace.some((w) => isAbsolutePathForm(w) && (removalKey(w) === k || removalKey(w).startsWith(prefix))))
|
|
36
|
+
return "workspace";
|
|
37
|
+
if (/^\/[^/]+$/.test(rest))
|
|
38
|
+
return "top_level";
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
function tildeNamesAHome(spelled) {
|
|
42
|
+
const m = /^~([^/]*)(\/.*)?$/.exec(spelled);
|
|
43
|
+
if (m === null)
|
|
44
|
+
return false;
|
|
45
|
+
const key = removalKey(`/~home${m[2] ?? ""}`);
|
|
46
|
+
return key === "/~home" || !key.startsWith("/~home/");
|
|
47
|
+
}
|
|
48
|
+
function removalKindOf(read, seat) {
|
|
49
|
+
const floors = read.established === "unestablishable" && read.candidate.bases === "unmodelled" ? read.spellings : [];
|
|
50
|
+
for (const view of [read.target, read.origin, ...floors]) {
|
|
51
|
+
const kind = view === undefined ? undefined : dangerousRemovalOf(view, seat);
|
|
52
|
+
if (kind !== undefined)
|
|
53
|
+
return kind;
|
|
54
|
+
}
|
|
55
|
+
return read.established === "unestablishable" && tildeNamesAHome(read.candidate.spelled) ? "home" : undefined;
|
|
56
|
+
}
|
|
57
|
+
function literalOf(pieces) {
|
|
58
|
+
return pieces.every((q) => q.literal !== undefined) ? pieces.map((q) => q.literal).join("") : undefined;
|
|
59
|
+
}
|
|
60
|
+
const NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
61
|
+
const NAME_BINDERS = new Set(["unset", "local", "declare", "typeset", "readonly", "export", "read"]);
|
|
62
|
+
function bindingsOf(plan) {
|
|
63
|
+
const out = new Map();
|
|
64
|
+
const bind = (name, value) => {
|
|
65
|
+
out.set(name, [...(out.get(name) ?? []), value]);
|
|
66
|
+
};
|
|
67
|
+
for (const segment of plan.segments) {
|
|
68
|
+
for (const w of segment.argv)
|
|
69
|
+
if (w.assignment !== undefined)
|
|
70
|
+
bind(w.assignment.name, w.assignment.settlesWholeName ? literalOf(w.assignment.value.pieces) : undefined);
|
|
71
|
+
const [head, name] = segment.argv;
|
|
72
|
+
if ((head?.folded === "for" || head?.folded === "select") && name !== undefined && NAME.test(name.folded)) {
|
|
73
|
+
const at = segment.argv.findIndex((w, i) => i > 1 && w.folded === "in");
|
|
74
|
+
const words = at < 0 ? [undefined] : segment.argv.slice(at + 1).map((w) => literalOf(w.pieces));
|
|
75
|
+
for (const v of words.length > 0 ? words : [undefined])
|
|
76
|
+
bind(name.folded, v);
|
|
77
|
+
}
|
|
78
|
+
if (head !== undefined && NAME_BINDERS.has(head.folded))
|
|
79
|
+
for (const w of segment.argv.slice(1))
|
|
80
|
+
if (w.assignment === undefined && NAME.test(w.folded))
|
|
81
|
+
bind(w.folded, undefined);
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
const BOUND_SPELLINGS_MAX = 64;
|
|
86
|
+
function boundSpellingsOf(word, bindings) {
|
|
87
|
+
const named = word.pieces.filter((q) => q.literal === undefined);
|
|
88
|
+
if (named.length === 0 || !named.some((q) => q.expansion?.kind === "parameter" && q.expansion.name !== undefined && bindings.has(q.expansion.name)))
|
|
89
|
+
return undefined;
|
|
90
|
+
let spellings = [""];
|
|
91
|
+
for (const q of word.pieces) {
|
|
92
|
+
if (q.literal !== undefined) {
|
|
93
|
+
spellings = spellings.map((sp) => sp + q.literal);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const name = q.expansion?.kind === "parameter" && (q.expansion.body === undefined || q.expansion.body === q.expansion.name) ? q.expansion.name : undefined;
|
|
97
|
+
const values = name !== undefined ? bindings.get(name) : undefined;
|
|
98
|
+
if (name === undefined || values === undefined)
|
|
99
|
+
return { unreadable: q.expansion?.name ?? word.raw };
|
|
100
|
+
if (values.some((v) => v === undefined || (q.quotedBy === undefined && /\s/.test(v))))
|
|
101
|
+
return { unreadable: name };
|
|
102
|
+
spellings = spellings.flatMap((sp) => values.map((v) => sp + v));
|
|
103
|
+
if (spellings.length > BOUND_SPELLINGS_MAX)
|
|
104
|
+
return { unreadable: name };
|
|
105
|
+
}
|
|
106
|
+
return { spellings };
|
|
107
|
+
}
|
|
108
|
+
function recursiveForce(args) {
|
|
109
|
+
const { options } = readArgv(args, REMOVAL_GRAMMAR);
|
|
110
|
+
const has = (long, short) => options.some((o) => (o.long ? long.startsWith(o.name) : short.test(o.name)));
|
|
111
|
+
return has("recursive", /^[rR]$/) && has("force", /^f$/);
|
|
112
|
+
}
|
|
113
|
+
export function removalFindingsOf(established, seat) {
|
|
114
|
+
const out = [];
|
|
115
|
+
const bindings = bindingsOf(established.plan);
|
|
116
|
+
for (const segment of established.plan.segments) {
|
|
117
|
+
const program = segment.verb?.basename;
|
|
118
|
+
if (program !== undefined && REMOVAL_COMMAND_SET.has(program)) {
|
|
119
|
+
const args = programArgs(segment);
|
|
120
|
+
const operands = new Set(readArgv(args, REMOVAL_GRAMMAR).operands);
|
|
121
|
+
const options = new Set(args.filter((w) => !operands.has(w)).map((w) => w.raw));
|
|
122
|
+
for (const read of established.reads.get(segment) ?? []) {
|
|
123
|
+
if (read.candidate.face !== "write" || options.has(read.candidate.raw))
|
|
124
|
+
continue;
|
|
125
|
+
const kind = removalKindOf(read, seat);
|
|
126
|
+
if (kind !== undefined) {
|
|
127
|
+
out.push({ guard: "dangerous_delete", kind, program, operand: read.candidate.raw, target: read.target ?? read.candidate.floorSpelled ?? read.candidate.spelled });
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (read.established !== "unestablishable")
|
|
131
|
+
continue;
|
|
132
|
+
const word = segment.argv.find((w) => w.raw === read.candidate.raw);
|
|
133
|
+
const bound = word === undefined ? undefined : boundSpellingsOf(word, bindings);
|
|
134
|
+
if (bound === undefined)
|
|
135
|
+
continue;
|
|
136
|
+
if ("unreadable" in bound) {
|
|
137
|
+
if (program === "rm" && recursiveForce(args))
|
|
138
|
+
out.push({ guard: "unverifiable_delete", program, operand: read.candidate.raw, name: bound.unreadable });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const bases = segment.bases === "unmodelled" ? (read.candidate.floorBases ?? []) : segment.bases;
|
|
142
|
+
for (const spelled of bound.spellings) {
|
|
143
|
+
const views = isAbsolutePathForm(spelled) ? [spelled] : bases.map((base) => `${base}/${spelled}`);
|
|
144
|
+
for (const view of views) {
|
|
145
|
+
const hit = dangerousRemovalOf(view, seat);
|
|
146
|
+
if (hit === undefined)
|
|
147
|
+
continue;
|
|
148
|
+
out.push({ guard: "dangerous_delete", kind: hit, program, operand: read.candidate.raw, target: normalizeAbsPathLexically(view) });
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const script = runtimeScriptOf(segment);
|
|
155
|
+
if (script !== undefined && program !== undefined)
|
|
156
|
+
out.push({ guard: "dangerous_delete", kind: "runtime_script", program, operand: script, target: script });
|
|
157
|
+
for (const nested of segment.nested) {
|
|
158
|
+
const sub = established.nested.get(nested);
|
|
159
|
+
if (sub !== undefined)
|
|
160
|
+
out.push(...removalFindingsOf(sub, seat));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
function runtimeScriptOf(segment) {
|
|
166
|
+
const program = segment.verb;
|
|
167
|
+
if (segment.reentry !== "shell" || program === undefined || !SHELL_REENTRY_PROGRAM_RE.test(program.basename))
|
|
168
|
+
return undefined;
|
|
169
|
+
const at = segment.argv.findIndex((w) => w.folded === program.name);
|
|
170
|
+
if (at < 0)
|
|
171
|
+
return undefined;
|
|
172
|
+
const MARK = "\u0000";
|
|
173
|
+
const words = segment.argv.slice(at + 1).map((w) => literalOf(w.pieces) ?? `${MARK}${w.raw}`);
|
|
174
|
+
const text = reentryText(program.basename, words);
|
|
175
|
+
return text === undefined || !text.includes(MARK) ? undefined : text.split(MARK).join("");
|
|
176
|
+
}
|
|
177
|
+
export function planRunsRemoval(plan) {
|
|
178
|
+
return plan.segments.some((s) => (s.verb !== undefined && REMOVAL_COMMAND_SET.has(s.verb.basename)) || runtimeScriptOf(s) !== undefined || s.nested.some(planRunsRemoval));
|
|
179
|
+
}
|
|
180
|
+
const DANGEROUS_REMOVAL_SENTENCE = {
|
|
181
|
+
filesystem_root: (p, t) => `\`${p}\` would remove the filesystem root (${t})`,
|
|
182
|
+
home: (p, t) => `\`${p}\` would remove a home directory (${t})`,
|
|
183
|
+
workspace: (p, t) => `\`${p}\` would remove a workspace directory — the task root, the working directory or an additional working directory — or one of its ancestors (${t})`,
|
|
184
|
+
top_level: (p, t) => `\`${p}\` would remove a top-level system directory (${t})`,
|
|
185
|
+
runtime_script: (p, t) => `\`${p}\` runs a script built only when the command runs (${t}), and it may remove the filesystem root, a home directory or the task's directories before anyone can read it`,
|
|
186
|
+
};
|
|
187
|
+
function verdictOf(findings) {
|
|
188
|
+
for (const f of findings)
|
|
189
|
+
if (f.guard === "dangerous_delete")
|
|
190
|
+
return { guard: f.guard, text: DANGEROUS_REMOVAL_SENTENCE[f.kind](f.program, inlineUntrusted(f.target, 200)) };
|
|
191
|
+
for (const f of findings)
|
|
192
|
+
if (f.guard === "unverifiable_delete")
|
|
193
|
+
return { guard: f.guard, text: `\`${f.program}\` recursive+force target ${inlineUntrusted(f.operand, 200)} takes ${f.name}'s value, which this command sets in a form the guard cannot read (an expansion, an unset or bare declaration, a \`read\`, a loop over unread words) — the deleted path cannot be verified from this command` };
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
const REMOVAL_RESOLVE_TIMEOUT_MS = 10_000;
|
|
197
|
+
export function removalReadingOf(command, req, seat) {
|
|
198
|
+
const homeDir = seat?.env?.homeDir;
|
|
199
|
+
const cwd = req.cwd ?? req.root ?? "";
|
|
200
|
+
const roots = req.root !== undefined ? [req.root] : cwd !== "" ? [cwd] : [];
|
|
201
|
+
const boundary = { roots, ...(cwd !== "" ? { cwd } : {}), ...(homeDir !== undefined ? { homeDir } : {}) };
|
|
202
|
+
const plan = planShellReads(command, { readers: new Set(bashClassifyDefaultAllow()), cwd, roots, ...(homeDir !== undefined ? { homeDir } : {}) });
|
|
203
|
+
if (!planRunsRemoval(plan))
|
|
204
|
+
return undefined;
|
|
205
|
+
return {
|
|
206
|
+
async judge(signal) {
|
|
207
|
+
const env = seat?.env;
|
|
208
|
+
const resolved = env !== undefined && homeDir !== undefined ? await resolvedOrUndefined(env.canonicalPath(homeDir, signal), signal) : undefined;
|
|
209
|
+
const removalSeat = {
|
|
210
|
+
homes: [...(homeDir !== undefined ? [homeDir] : []), ...(resolved !== undefined && resolved.ok ? [resolved.value] : [])],
|
|
211
|
+
workspace: [...(req.root !== undefined ? [req.root] : []), ...(req.cwd !== undefined ? [req.cwd] : []), ...(seat?.additionalRoots?.() ?? [])],
|
|
212
|
+
};
|
|
213
|
+
const lexical = removalFindingsOf(establishShellReadsLexically(plan, boundary), removalSeat);
|
|
214
|
+
if (lexical.some((f) => f.guard === "dangerous_delete") || env === undefined || roots.length === 0)
|
|
215
|
+
return verdictOf(lexical);
|
|
216
|
+
const established = await resolvedOrUndefined(createShellReadEstablisher(env, roots, { rootsCanonical: true }).establish(plan, boundary, signal), signal);
|
|
217
|
+
return verdictOf(established === undefined ? lexical : [...removalFindingsOf(established, removalSeat), ...lexical]);
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
async function resolvedOrUndefined(leg, signal) {
|
|
222
|
+
let timer;
|
|
223
|
+
try {
|
|
224
|
+
return await Promise.race([
|
|
225
|
+
leg.catch(() => undefined),
|
|
226
|
+
new Promise((resolve) => {
|
|
227
|
+
timer = setTimeout(() => resolve(undefined), REMOVAL_RESOLVE_TIMEOUT_MS);
|
|
228
|
+
signal?.addEventListener("abort", () => resolve(undefined), { once: true });
|
|
229
|
+
}),
|
|
230
|
+
]);
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
if (timer !== undefined)
|
|
234
|
+
clearTimeout(timer);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -27,6 +27,32 @@ export interface ArgWord {
|
|
|
27
27
|
}
|
|
28
28
|
/** The words a segment hands its program — the argv after the program word (a launcher's own words are not the program's). */
|
|
29
29
|
export declare function programArgs(segment: ShellReadSegment): ArgWord[];
|
|
30
|
+
/**
|
|
31
|
+
* One program's option GRAMMAR, as its getopt reads it: the short letters taking a REQUIRED value (the rest of the word,
|
|
32
|
+
* or the next word), those taking an OPTIONAL one (the rest of the word only), and the long names taking a required value
|
|
33
|
+
* (any unambiguous prefix; `=` or the next word) — absent for a program with no long options (a `--name` word is then an
|
|
34
|
+
* error the program stops on, and names nothing here). The GNU and BSD programs of one name read the same argv
|
|
35
|
+
* differently (`sed -l` takes a value in GNU and none in BSD; `cp -S` a suffix in GNU and none in BSD), so every question
|
|
36
|
+
* below reads the argv under BOTH grammars and takes the union of what they name.
|
|
37
|
+
*/
|
|
38
|
+
export interface OptionGrammar {
|
|
39
|
+
readonly required: string;
|
|
40
|
+
readonly optional: string;
|
|
41
|
+
readonly longRequired?: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
/** One option read off an argv: a short letter or a long name as written (a prefix), and its value when it has one. */
|
|
44
|
+
interface OptionRead {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly long: boolean;
|
|
47
|
+
readonly value?: ArgWord;
|
|
48
|
+
}
|
|
49
|
+
/** An argv read under one grammar: its options in order, and its operands (every word after `--` included). Options are
|
|
50
|
+
* read anywhere among the operands, as GNU getopt permutes them — for a BSD getopt, which stops at the first operand,
|
|
51
|
+
* that is a superset of its options (the tightening direction). */
|
|
52
|
+
export declare function readArgv(words: readonly ArgWord[], grammar: OptionGrammar): {
|
|
53
|
+
readonly options: readonly OptionRead[];
|
|
54
|
+
readonly operands: readonly ArgWord[];
|
|
55
|
+
};
|
|
30
56
|
/** What a `sed` invocation's option words say about writing, under either grammar ({@link SED_GRAMMARS}): whether it edits
|
|
31
57
|
* in place (`-i` / `-I` / `--in-place`), the backup suffixes it is given (their values; an empty value keeps no backup),
|
|
32
58
|
* and whether GNU `--follow-symlinks` is on. */
|
|
@@ -71,3 +97,4 @@ export interface JudgedCandidate {
|
|
|
71
97
|
* lists it among the reads), plus its WRITE targets for the write face ({@link writeTargetsOf}), plus the deny-floor
|
|
72
98
|
* shadow of every unplaced home word ({@link denyFloorShadowsOf}) on both faces. */
|
|
73
99
|
export declare function judgedCandidatesOf(segment: ShellReadSegment): readonly JudgedCandidate[];
|
|
100
|
+
export {};
|
|
@@ -21,7 +21,7 @@ const COPY_GRAMMARS = [
|
|
|
21
21
|
{ required: "St", optional: "", longRequired: ["target-directory", "suffix", "no-preserve", "sparse"] },
|
|
22
22
|
{ required: "", optional: "" },
|
|
23
23
|
];
|
|
24
|
-
function readArgv(words, grammar) {
|
|
24
|
+
export function readArgv(words, grammar) {
|
|
25
25
|
const options = [];
|
|
26
26
|
const operands = [];
|
|
27
27
|
let endOfOptions = false;
|