@sema-agent/core 7.45.0 → 7.47.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 +298 -1
- package/dist/agents/extra-tool-names.d.ts +65 -0
- package/dist/agents/extra-tool-names.js +124 -0
- package/dist/agents/subagent.d.ts +17 -5
- package/dist/agents/subagent.js +33 -25
- package/dist/agents/tool-filter.d.ts +17 -1
- package/dist/agents/tool-filter.js +7 -0
- package/dist/core/agent-config-dir.d.ts +20 -0
- package/dist/core/agent-config-dir.js +49 -0
- package/dist/core/allow-entry.d.ts +6 -4
- package/dist/core/allow-entry.js +6 -5
- package/dist/core/ask-origin.d.ts +35 -12
- package/dist/core/ask-origin.js +24 -7
- package/dist/core/checkpoint-store.d.ts +39 -2
- package/dist/core/effective-path-target.d.ts +136 -4
- package/dist/core/effective-path-target.js +110 -2
- package/dist/core/engine-notice.d.ts +12 -4
- package/dist/core/gate-fold.js +5 -2
- package/dist/core/gate-lanes.js +11 -4
- package/dist/core/gate-outcome.d.ts +4 -2
- package/dist/core/gate-outcome.js +2 -2
- package/dist/core/governance-codes.d.ts +3 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/hooks.d.ts +3 -0
- package/dist/core/path-rule-binding.d.ts +65 -0
- package/dist/core/path-rule-binding.js +99 -0
- package/dist/core/permission-rule-model.d.ts +59 -24
- package/dist/core/permission-rule-model.js +48 -44
- package/dist/core/permission-rule-provider.d.ts +7 -0
- package/dist/core/permission-rule-provider.js +10 -3
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +6 -2
- package/dist/core/permission-rule-sync.js +2 -2
- package/dist/core/permission-rules.d.ts +26 -45
- package/dist/core/permission-rules.js +77 -57
- package/dist/core/runner/child-tree.d.ts +97 -0
- package/dist/core/runner/child-tree.js +104 -0
- package/dist/core/runner/construction-doors.d.ts +5 -0
- package/dist/core/runner/construction-doors.js +6 -0
- package/dist/core/runner/contracts.d.ts +46 -0
- package/dist/core/runner/gate-exit.d.ts +4 -1
- package/dist/core/runner/gate-exit.js +5 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
- package/dist/core/runner/permission-rule-lanes.js +18 -12
- package/dist/core/runner/persisted-path-rows.d.ts +31 -7
- package/dist/core/runner/persisted-path-rows.js +31 -12
- package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
- package/dist/core/runner/prepare-ask-lane.js +4 -2
- package/dist/core/runner/prepare-execution-env.d.ts +5 -2
- package/dist/core/runner/prepare-execution-env.js +10 -3
- 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-hands-readface.d.ts +8 -4
- package/dist/core/runner/prepare-hands-readface.js +11 -11
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
- package/dist/core/runner/prepare-inherited-gate.js +8 -2
- package/dist/core/runner/prepare-park-ask.d.ts +3 -0
- package/dist/core/runner/prepare-park-ask.js +5 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
- package/dist/core/runner/prepare-policy-chain.js +13 -5
- package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -1
- package/dist/core/runner/prepare-task.js +37 -18
- package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
- package/dist/core/runner/prepare-turn-wiring.js +2 -1
- package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
- package/dist/core/runner/prepare-workspace-restore.js +1 -0
- package/dist/core/runner/resume-apply.js +17 -3
- package/dist/core/runner/resume-checkpoint-screen.js +13 -0
- package/dist/core/runner/run-leg.js +5 -1
- package/dist/core/runner/runtask.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +3 -2
- package/dist/core/runner/write-protection-station.js +1 -0
- package/dist/core/runner-deps.d.ts +14 -0
- package/dist/core/sensitive-path-policy.d.ts +8 -0
- package/dist/core/sensitive-path-policy.js +18 -2
- package/dist/core/shell-wrapper-projection.d.ts +11 -0
- package/dist/core/shell-wrapper-projection.js +56 -0
- package/dist/core/shell-wrapper-table.d.ts +144 -34
- package/dist/core/shell-wrapper-table.js +40 -20
- package/dist/core/synthetic-read-verdict.d.ts +3 -0
- package/dist/core/synthetic-read-verdict.js +3 -1
- package/dist/core/tool-catalog-entries.d.ts +21 -0
- package/dist/core/tool-catalog-entries.js +12 -2
- package/dist/core/tool-face.d.ts +10 -1
- package/dist/core/tool-name-readings.d.ts +8 -0
- package/dist/core/tool-name-readings.js +2 -0
- package/dist/core/tool-policy.d.ts +40 -17
- package/dist/core/tool-policy.js +11 -9
- package/dist/core/tool-registry.d.ts +9 -0
- package/dist/core/tool-registry.js +10 -0
- package/dist/core/tool-spec.d.ts +3 -2
- package/dist/core/write-protect.d.ts +14 -3
- package/dist/core/write-protect.js +41 -10
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/orchestration/run-spec.js +8 -7
- package/dist/orchestration/workflow.js +1 -1
- package/dist/shell/lex.d.ts +22 -0
- package/dist/shell/lex.js +75 -13
- package/dist/tools/fs/bash-program-position.d.ts +14 -90
- package/dist/tools/fs/bash-program-position.js +41 -74
- package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
- package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
- package/dist/tools/fs/index.d.ts +3 -2
- package/dist/tools/fs/program-read-model.d.ts +711 -0
- package/dist/tools/fs/program-read-model.js +1259 -0
- package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
- package/dist/tools/fs/program-read-model.rows.js +624 -0
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +62 -24
- package/dist/tools/fs/read-deny.d.ts +54 -14
- package/dist/tools/fs/read-deny.js +104 -50
- package/dist/tools/fs/removal-targets.d.ts +7 -6
- package/dist/tools/fs/removal-targets.js +34 -24
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +10 -3
- package/dist/tools/fs/shell-read-argv.d.ts +86 -0
- package/dist/tools/fs/shell-read-argv.js +388 -0
- package/dist/tools/fs/shell-read-bindings.d.ts +300 -0
- package/dist/tools/fs/shell-read-bindings.js +755 -0
- package/dist/tools/fs/shell-read-check.js +23 -15
- package/dist/tools/fs/shell-read-establish.js +82 -8
- package/dist/tools/fs/shell-read-judge.d.ts +11 -1
- package/dist/tools/fs/shell-read-judge.js +9 -1
- package/dist/tools/fs/shell-read-plan.d.ts +33 -8
- package/dist/tools/fs/shell-read-plan.js +309 -407
- package/dist/tools/fs/shell-read-word.d.ts +60 -26
- package/dist/tools/fs/shell-read-word.js +47 -37
- package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
- package/dist/tools/fs/shell-read-write-targets.js +85 -137
- package/dist/tools/fs/shell-reentry-text.d.ts +136 -6
- package/dist/tools/fs/shell-reentry-text.js +203 -53
- package/dist/tools/monitor.d.ts +3 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +25 -5
- package/wire-changes/core@7.46.0.json +1522 -0
- package/wire-changes/core@7.47.0.json +412 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { releasableAskClassesFor } from "./ask-origin.js";
|
|
1
2
|
import { canonicalizeTarget, isWinFormPath, writeTargetPath, isUncPath, isAbsoluteForFamily, joinForFamily, pathFamilyOf } from "../tools/fs/safety.js";
|
|
2
3
|
import { protectivePathTargetOf } from "./tool-registry.js";
|
|
3
4
|
import { pathTargetBaseOf } from "./effective-path-target.js";
|
|
4
5
|
import { canonicalDataRootKeys, dataRootSpellings, relativeUnderRoot } from "./sensitive-path-policy.js";
|
|
5
6
|
import { symlinkChainHops } from "./path-identity.js";
|
|
6
7
|
import { readDenyPatternRun } from "../tools/fs/read-deny.js";
|
|
8
|
+
import { agentConfigDirSegments, agentConfigDirTail } from "./agent-config-dir.js";
|
|
7
9
|
import { thrownText } from "./thrown-value.js";
|
|
8
10
|
const freezeTable = (rows) => Object.freeze(rows.map((r) => Object.freeze(r)));
|
|
9
11
|
export const WRITE_PROTECTED_DEFAULT_TABLE = freezeTable([
|
|
@@ -196,6 +198,7 @@ export function compileWriteProtection(entries, opts) {
|
|
|
196
198
|
const basenames = new Map();
|
|
197
199
|
const segments = new Map();
|
|
198
200
|
const runs = [];
|
|
201
|
+
const configTails = [];
|
|
199
202
|
for (const row of rows) {
|
|
200
203
|
const folded = foldWriteProtectName(row.name);
|
|
201
204
|
if (row.kind === "basename") {
|
|
@@ -209,8 +212,23 @@ export function compileWriteProtection(entries, opts) {
|
|
|
209
212
|
else {
|
|
210
213
|
runs.push({ name: row.name, parts: folded.split("/").filter((s) => s.length > 0) });
|
|
211
214
|
}
|
|
215
|
+
const tail = row.kind === "basename" ? undefined : agentConfigDirTail(row.name);
|
|
216
|
+
if (tail !== undefined && opts?.agentConfigDir !== undefined)
|
|
217
|
+
configTails.push({ hit: { name: row.name, kind: row.kind }, tail: foldWriteProtectName(tail).split("/").filter((s) => s.length > 0) });
|
|
212
218
|
}
|
|
213
|
-
const
|
|
219
|
+
const configRootSpelled = opts?.agentConfigDir === undefined ? [] : [agentConfigDirSegments(opts.agentConfigDir)];
|
|
220
|
+
const judgeAtConfigRoots = (segs, roots) => {
|
|
221
|
+
for (const root of roots) {
|
|
222
|
+
const at = root.map(foldWriteProtectSegment);
|
|
223
|
+
if (segs.length < at.length || !at.every((a, i) => segs[i] === a))
|
|
224
|
+
continue;
|
|
225
|
+
for (const { hit, tail } of configTails)
|
|
226
|
+
if (segs.length >= at.length + tail.length && tail.every((t, i) => segs[at.length + i] === t))
|
|
227
|
+
return hit;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
};
|
|
231
|
+
const judgeSegments = (raw, configRoots) => {
|
|
214
232
|
if (raw.length === 0)
|
|
215
233
|
return null;
|
|
216
234
|
const segs = raw.map(foldWriteProtectSegment);
|
|
@@ -229,23 +247,26 @@ export function compileWriteProtection(entries, opts) {
|
|
|
229
247
|
return { name: run.name, kind: "segment-run" };
|
|
230
248
|
}
|
|
231
249
|
}
|
|
232
|
-
return null;
|
|
250
|
+
return configTails.length === 0 ? null : judgeAtConfigRoots(segs, configRoots);
|
|
233
251
|
};
|
|
234
|
-
const judgeViews = (spelling) => {
|
|
235
|
-
const posix = judgeSegments(pathViewSegments(spelling, "literal", POSIX_SEPARATOR_FAMILY, uncAnchorSegments(spelling)));
|
|
252
|
+
const judgeViews = (spelling, configRoots = configRootSpelled) => {
|
|
253
|
+
const posix = judgeSegments(pathViewSegments(spelling, "literal", POSIX_SEPARATOR_FAMILY, uncAnchorSegments(spelling)), configRoots);
|
|
236
254
|
if (posix !== null)
|
|
237
255
|
return posix;
|
|
238
|
-
const bothSeparators = judgeSegments(pathViewSegments(spelling, "literal"));
|
|
256
|
+
const bothSeparators = judgeSegments(pathViewSegments(spelling, "literal"), configRoots);
|
|
239
257
|
if (bothSeparators !== null)
|
|
240
258
|
return bothSeparators;
|
|
241
259
|
for (const normalization of WIN32_NORMALIZATIONS) {
|
|
242
|
-
const hit = judgeSegments(pathViewSegments(spelling, normalization));
|
|
260
|
+
const hit = judgeSegments(pathViewSegments(spelling, normalization), configRoots);
|
|
243
261
|
if (hit !== null)
|
|
244
262
|
return hit;
|
|
245
263
|
}
|
|
246
264
|
return null;
|
|
247
265
|
};
|
|
248
|
-
const judgeSpelled = (spelled) =>
|
|
266
|
+
const judgeSpelled = (spelled) => {
|
|
267
|
+
const remainder = relativeUnderDataRoot(spelled, rootViews);
|
|
268
|
+
return remainder === null ? judgeViews(spelled) : judgeViews(remainder, []);
|
|
269
|
+
};
|
|
249
270
|
const judgeSpelling = (path, cwd) => {
|
|
250
271
|
const base = typeof cwd === "string" && cwd.length > 0 ? cwd : undefined;
|
|
251
272
|
const family = pathFamilyOf({ cwd: base });
|
|
@@ -291,7 +312,8 @@ export function compileWriteProtection(entries, opts) {
|
|
|
291
312
|
}
|
|
292
313
|
try {
|
|
293
314
|
if (canonKey !== undefined) {
|
|
294
|
-
const
|
|
315
|
+
const canonicalRoots = configTails.length === 0 || opts?.agentConfigDir === undefined ? [] : (await canonicalDataRootKeys(env, [opts.agentConfigDir], ctx.signal)).map(agentConfigDirSegments);
|
|
316
|
+
const byTarget = judgeViews(canonKey, [...configRootSpelled, ...canonicalRoots]);
|
|
295
317
|
if (byTarget !== null) {
|
|
296
318
|
for (const rootKey of await canonicalDataRootKeys(env, dataRootPaths, ctx.signal)) {
|
|
297
319
|
const relative = relativeUnderRoot(canonKey, rootKey);
|
|
@@ -299,7 +321,7 @@ export function compileWriteProtection(entries, opts) {
|
|
|
299
321
|
continue;
|
|
300
322
|
if (relative === "")
|
|
301
323
|
return { kind: "clear" };
|
|
302
|
-
const remainder = judgeViews(relative);
|
|
324
|
+
const remainder = judgeViews(relative, []);
|
|
303
325
|
return remainder === null ? { kind: "clear" } : { kind: "hit", hit: remainder, via: "target" };
|
|
304
326
|
}
|
|
305
327
|
return { kind: "hit", hit: byTarget, via: "target" };
|
|
@@ -325,7 +347,7 @@ export function compileWriteProtection(entries, opts) {
|
|
|
325
347
|
},
|
|
326
348
|
};
|
|
327
349
|
}
|
|
328
|
-
export function writeProtectionTightenDecision(toolName, verdict) {
|
|
350
|
+
export function writeProtectionTightenDecision(toolName, verdict, face) {
|
|
329
351
|
if (verdict.kind === "hit") {
|
|
330
352
|
return {
|
|
331
353
|
action: "ask",
|
|
@@ -338,6 +360,15 @@ export function writeProtectionTightenDecision(toolName, verdict) {
|
|
|
338
360
|
};
|
|
339
361
|
}
|
|
340
362
|
if (verdict.kind === "unresolvable") {
|
|
363
|
+
if (releasableAskClassesFor(face).includes("write_protection_unresolved")) {
|
|
364
|
+
return {
|
|
365
|
+
action: "ask",
|
|
366
|
+
message: verdict.unresolvedSymlink
|
|
367
|
+
? `tool "${toolName}" writes to a symlink whose real target could not be resolved, so the write-protection judge cannot tell whether it lands on a protected path (${verdict.cause}) — explicit approval required`
|
|
368
|
+
: `tool "${toolName}" writes to a target that could not be resolved on this tree, so the write-protection judge cannot tell whether it lands on a protected path (${verdict.cause}) — explicit approval required`,
|
|
369
|
+
decisionReason: "safety",
|
|
370
|
+
};
|
|
371
|
+
}
|
|
341
372
|
return {
|
|
342
373
|
action: "deny",
|
|
343
374
|
message: verdict.unresolvedSymlink
|
package/dist/index.d.ts
CHANGED
|
@@ -151,7 +151,8 @@ export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES
|
|
|
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";
|
|
153
153
|
export { type ToolCallFace } from "./core/tool-policy.js";
|
|
154
|
-
export { effectivePathTargetOf, pathTargetBaseOf, type ToolPathBases, type PathTargetReading } from "./core/effective-path-target.js";
|
|
154
|
+
export { effectivePathTargetOf, pathTargetBaseOf, type ToolPathBases, type PathTargetReading, type CallTargetReading, type CallTargetView } from "./core/effective-path-target.js";
|
|
155
|
+
export { type BoundPathRule, type PathRuleSpec } from "./core/path-rule-binding.js";
|
|
155
156
|
export { pathFamilyOf, isAbsoluteForFamily, pathIdentityOf, win32NamespaceScreen, WIN32_NAMESPACE_REFUSALS, type PathFamily, type PathIdentity, type PathIdentityReading, type Win32NamespaceRefusal } from "./tools/fs/safety.js";
|
|
156
157
|
export { judgeShellRead, type ShellReadJudgeInput, type ShellReadJudgment, type ShellReadVerdict, type ShellReadStationSeat, type ShellReadAdmission, } from "./tools/fs/shell-read-check.js";
|
|
157
158
|
export { SHELL_READ_FINDINGS, SHELL_READ_SEATS, SHELL_READ_DECISION, SHELL_READ_FINDING_RANK, type ShellReadFinding, type ShellReadSeat, type ShellReadDisposition, type ShellReadBoundary, type ReadEstablishment, type EstablishedRead, type ReadFinding, } from "./tools/fs/shell-read-judge.js";
|
|
@@ -193,21 +194,22 @@ export { createAllowDenyPolicy, createApprovalPolicy,
|
|
|
193
194
|
* members that seat has no lane for (`"unavailable"`, a routing answer; `updatedInput`, an operator edit a
|
|
194
195
|
* policy verdict cannot get re-adjudicated). Exported so a host can NAME it instead of deriving it through
|
|
195
196
|
* `Parameters<typeof createApprovalPolicy>[0]["approve"]`. */
|
|
196
|
-
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, abortedSeatDeny, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets,
|
|
197
|
+
type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, abortedSeatDeny, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathRules, 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";
|
|
197
198
|
export { type ReadRootGrantScreen } from "./core/read-root-grant-screen.js";
|
|
198
199
|
export { type AskOrigin, ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, type PersistedRuleMandate, isPersistedRuleMandate, screenAskClassMembers } from "./core/ask-origin.js";
|
|
199
|
-
export { PERMISSION_MODES, type PermissionMode, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, type AskClass, isAskClass, MODE_ARBITRATION, type ModeArbitrationRow,
|
|
200
|
+
export { PERMISSION_MODES, type PermissionMode, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, type AskClass, isAskClass, MODE_ARBITRATION, type ModeArbitrationRow, ASK_FACES, type AskFace, askFaceOf, releasableAskClassesFor, 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";
|
|
200
201
|
export { modePolicyOf, type ModePolicy, PERMISSION_MODE_FOLD_REASONS, type PermissionModeFoldReason, type PermissionModeReceipt, ACCEPT_EDITS_FILE_COMMANDS, modeAcceptsFileCommand } from "./core/mode-policy.js";
|
|
201
202
|
export type { PermissionSeatInputs, PermissionSeatReading } from "./core/mode-policy.js";
|
|
202
203
|
export type { SkillGateSeats, SkillGrantHit, SkillGrantLane, SkillGrantOrigin, SkillGrantRecord } from "./core/skill-grant.js";
|
|
203
204
|
export { SKILL_GRANT_ORIGINS } from "./core/skill-grant.js";
|
|
204
205
|
export type { BoundSkillGrants } from "./core/skill-grant-binding.js";
|
|
205
|
-
export { ALLOW_ENTRY_INERT_REASONS, compileAllowEntry, compileAllowList, type AllowEntryInertReason, type CompiledAllowEntry, type AllowEntryGateSeats, type AllowEntryLane, type AllowEntryHit } from "./core/allow-entry.js";
|
|
206
|
+
export { ALLOW_ENTRY_INERT_REASONS, compileAllowEntry, compileAllowList, renderListEntry, type AllowEntryInertReason, type CompiledAllowEntry, type AllowEntryGateSeats, type AllowEntryLane, type AllowEntryHit } from "./core/allow-entry.js";
|
|
206
207
|
export { ALLOW_RULE_MEMBERS, type AllowRuleMember, type AllowRuleShadow } from "./core/allow-rule-shadow.js";
|
|
207
208
|
export { mintNamespacePrefix } from "./core/protocol-naming.js";
|
|
208
209
|
export { readDenyClassifierRules, renderClassifierDenyRules, type DerivedDenyRule } from "./core/auto-mode-prompt.js";
|
|
209
210
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource, type AutoModeDenySource } from "./core/runtime-caps.js";
|
|
210
211
|
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";
|
|
212
|
+
export { ENGINE_BUILTIN_TOOL_NAMES, isEngineBuiltinToolName } from "./core/tool-catalog-entries.js";
|
|
211
213
|
export { policyCannotAnswer, type HeldQuestion } from "./core/real-approval.js";
|
|
212
214
|
export { type AskCarry } from "./core/hooks.js";
|
|
213
215
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
|
package/dist/index.js
CHANGED
|
@@ -124,6 +124,7 @@ export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRule
|
|
|
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";
|
|
125
125
|
export {} from "./core/tool-policy.js";
|
|
126
126
|
export { effectivePathTargetOf, pathTargetBaseOf } from "./core/effective-path-target.js";
|
|
127
|
+
export {} from "./core/path-rule-binding.js";
|
|
127
128
|
export { pathFamilyOf, isAbsoluteForFamily, pathIdentityOf, win32NamespaceScreen, WIN32_NAMESPACE_REFUSALS } from "./tools/fs/safety.js";
|
|
128
129
|
export { judgeShellRead, } from "./tools/fs/shell-read-check.js";
|
|
129
130
|
export { SHELL_READ_FINDINGS, SHELL_READ_SEATS, SHELL_READ_DECISION, SHELL_READ_FINDING_RANK, } from "./tools/fs/shell-read-judge.js";
|
|
@@ -158,18 +159,19 @@ export { hasScheduler, isValidCronExpr, SchedulerError } from "./core/scheduler.
|
|
|
158
159
|
export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
|
|
159
160
|
export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
|
|
160
161
|
export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
|
|
161
|
-
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, abortedSeatDeny, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets,
|
|
162
|
+
export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, abortedSeatDeny, receiveHookResult, isEngineRefusal, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
|
|
162
163
|
export {} from "./core/read-root-grant-screen.js";
|
|
163
164
|
export { ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, isPersistedRuleMandate, screenAskClassMembers } from "./core/ask-origin.js";
|
|
164
|
-
export { PERMISSION_MODES, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, isAskClass, MODE_ARBITRATION,
|
|
165
|
+
export { PERMISSION_MODES, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, isAskClass, MODE_ARBITRATION, ASK_FACES, askFaceOf, releasableAskClassesFor, MODE_RELEASE_REASONS, isModeReleaseReason, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, arbitrateByMode, fileCommandOptionsSentence } from "./core/ask-origin.js";
|
|
165
166
|
export { modePolicyOf, PERMISSION_MODE_FOLD_REASONS, ACCEPT_EDITS_FILE_COMMANDS, modeAcceptsFileCommand } from "./core/mode-policy.js";
|
|
166
167
|
export { SKILL_GRANT_ORIGINS } from "./core/skill-grant.js";
|
|
167
|
-
export { ALLOW_ENTRY_INERT_REASONS, compileAllowEntry, compileAllowList } from "./core/allow-entry.js";
|
|
168
|
+
export { ALLOW_ENTRY_INERT_REASONS, compileAllowEntry, compileAllowList, renderListEntry } from "./core/allow-entry.js";
|
|
168
169
|
export { ALLOW_RULE_MEMBERS } from "./core/allow-rule-shadow.js";
|
|
169
170
|
export { mintNamespacePrefix } from "./core/protocol-naming.js";
|
|
170
171
|
export { readDenyClassifierRules, renderClassifierDenyRules } from "./core/auto-mode-prompt.js";
|
|
171
172
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./core/runtime-caps.js";
|
|
172
173
|
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";
|
|
174
|
+
export { ENGINE_BUILTIN_TOOL_NAMES, isEngineBuiltinToolName } from "./core/tool-catalog-entries.js";
|
|
173
175
|
export { policyCannotAnswer } from "./core/real-approval.js";
|
|
174
176
|
export {} from "./core/hooks.js";
|
|
175
177
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
|
|
@@ -5,7 +5,8 @@ import { combinePolicies } from "../core/tool-policy.js";
|
|
|
5
5
|
import { delimitUntrusted } from "../core/untrusted-text.js";
|
|
6
6
|
import { isDurablePause } from "../agents/suspend-guard.js";
|
|
7
7
|
import { terminalProjection } from "../core/runner/terminal-projection.js";
|
|
8
|
-
import {
|
|
8
|
+
import { writeTargetPath } from "../tools/fs/safety.js";
|
|
9
|
+
import { callTargetViewsOf } from "../core/effective-path-target.js";
|
|
9
10
|
import { captureBaseline, resolveFrozenPaths, restoreFrozenPaths, runOracle, snapshotFrozenPaths, specError, } from "../core/spec-contract.js";
|
|
10
11
|
import { isProtectedWrite } from "../core/tool-registry.js";
|
|
11
12
|
const CASE_INSENSITIVE_FS = process.platform === "darwin" || process.platform === "win32";
|
|
@@ -21,13 +22,13 @@ export function frozenDenyPolicy(rootDir, frozenResolved) {
|
|
|
21
22
|
check(req) {
|
|
22
23
|
if (!isProtectedWrite(req))
|
|
23
24
|
return { action: "allow" };
|
|
24
|
-
const
|
|
25
|
-
if (
|
|
25
|
+
const views = callTargetViewsOf(req, "tighten", { root: rootDir });
|
|
26
|
+
if (views === undefined || views.spellings.length === 0)
|
|
26
27
|
return { action: "allow" };
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
return { action: "deny", message: `${raw} is part of the frozen specification surface (read-only).` };
|
|
28
|
+
const raw = writeTargetPath(req);
|
|
29
|
+
const hit = views.spellings.some((v) => frozen.has(pathKey(v)));
|
|
30
|
+
if (hit) {
|
|
31
|
+
return { action: "deny", message: `${typeof raw === "string" && raw.length > 0 ? raw : views.spellings[0]} is part of the frozen specification surface (read-only).` };
|
|
31
32
|
}
|
|
32
33
|
return { action: "allow" };
|
|
33
34
|
},
|
|
@@ -1579,7 +1579,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1579
1579
|
opts.onForwardEvent(e.type === "task_progress" ? { ...e, workflowRunId: runId, workflowAgentLabel: label } : e);
|
|
1580
1580
|
}
|
|
1581
1581
|
: undefined;
|
|
1582
|
-
const baseInternals = { ...(agentOpts.isolation ? { isolation: agentOpts.isolation } : {}), ...(opts.parentCwd !== undefined ? { parentCwd: opts.parentCwd } : {}), ...spawnAttribution, ...(await captureFloorSeatsNow()), ...(enrichedForward !== undefined ? { onForwardEvent: enrichedForward } : {}), delegationTaskType: "workflow", agentName: label, onWorkspaceResolved: createWorkspaceObserver(rec) };
|
|
1582
|
+
const baseInternals = { ...(agentOpts.isolation ? { isolation: agentOpts.isolation } : {}), ...(opts.parentCwd !== undefined ? { parentCwd: opts.parentCwd, callerRoot: opts.parentCwd } : {}), ...spawnAttribution, ...(await captureFloorSeatsNow()), ...(enrichedForward !== undefined ? { onForwardEvent: enrichedForward } : {}), delegationTaskType: "workflow", agentName: label, onWorkspaceResolved: createWorkspaceObserver(rec) };
|
|
1583
1583
|
let attempts = 0;
|
|
1584
1584
|
let throttleRetried = false;
|
|
1585
1585
|
let lastAttemptReason;
|
package/dist/shell/lex.d.ts
CHANGED
|
@@ -103,6 +103,17 @@ export interface WordExpansion {
|
|
|
103
103
|
readonly body?: string;
|
|
104
104
|
/** The parameter name, where the expansion names one. */
|
|
105
105
|
readonly name?: string;
|
|
106
|
+
/** A glob's pattern — absent where an expansion stands inside it (its text is not the pattern): `folded`, what the
|
|
107
|
+
* program receives where it matches nothing — quotes removed, the spelling {@link LexedWord.folded} carries at its place
|
|
108
|
+
* (`[^.]`); `written`, as written, quoting kept (`[^\.]`, `["!"a]`) — the text a shell re-reading it matches by;
|
|
109
|
+
* `judged`, the spelling a reader judges the names it matches by — `folded`, save a class the judge reads as any one
|
|
110
|
+
* character: one holding a quoted or escaped character (its quote-removed text reads another class: `["!"a]` is not
|
|
111
|
+
* the negation `[!a]`) or a `[:…:]` / `[=…=]` / `[.….]` unit — spelled `?`, a superset of its members. */
|
|
112
|
+
readonly pattern?: {
|
|
113
|
+
readonly folded: string;
|
|
114
|
+
readonly written: string;
|
|
115
|
+
readonly judged: string;
|
|
116
|
+
};
|
|
106
117
|
}
|
|
107
118
|
export interface QuotedSpan {
|
|
108
119
|
/** Offsets into {@link LexedWord.raw}, `[start, end)`; the quote characters belong to their span. */
|
|
@@ -143,6 +154,10 @@ export interface LexedWord {
|
|
|
143
154
|
readonly kind: "word";
|
|
144
155
|
readonly raw: string;
|
|
145
156
|
readonly folded: string;
|
|
157
|
+
/** The spelling a reader judges the word's names by, where it is not `folded`: each bracket class holding a quoted or
|
|
158
|
+
* escaped character or a `[:…:]` / `[=…=]` / `[.….]` unit spelled `?` (`["!"a]*`, `[[:alpha:]]*` ⇒ `?*`,
|
|
159
|
+
* {@link WordExpansion.pattern}). */
|
|
160
|
+
readonly judged?: string;
|
|
146
161
|
readonly pieces: readonly WordPiece[];
|
|
147
162
|
readonly quotedSpans: readonly QuotedSpan[];
|
|
148
163
|
/** The pieces that carry an expansion, in order. */
|
|
@@ -248,6 +263,13 @@ export declare function substitutionsInHeredocBody(body: string): {
|
|
|
248
263
|
readonly body: string;
|
|
249
264
|
readonly kind: "command" | "arithmetic";
|
|
250
265
|
}[] | undefined;
|
|
266
|
+
/** The text a word's pieces hand the program when every piece is literal; `undefined` when one is an expansion or
|
|
267
|
+
* unresolved. */
|
|
268
|
+
export declare function literalTextOf(pieces: readonly WordPiece[]): string | undefined;
|
|
269
|
+
/** The text an UNQUOTED here-document body delivers when the shell expands nothing in it: a backslash before `$`, a
|
|
270
|
+
* backquote or a backslash is removed (a line continuation was joined when the body was read), every other character
|
|
271
|
+
* stands. `undefined` when an unescaped `$` or backquote stands in it: the program reads what the expansion makes. */
|
|
272
|
+
export declare function literalHeredocBody(body: string): string | undefined;
|
|
251
273
|
/** Lex a command: its segments, or the one reason bash (or this lexer) cannot delimit them. */
|
|
252
274
|
export declare function lexShell(source: string): ShellLex;
|
|
253
275
|
/**
|
package/dist/shell/lex.js
CHANGED
|
@@ -319,6 +319,23 @@ export function substitutionsInHeredocBody(body) {
|
|
|
319
319
|
}
|
|
320
320
|
return out;
|
|
321
321
|
}
|
|
322
|
+
export function literalTextOf(pieces) {
|
|
323
|
+
return pieces.every((q) => q.literal !== undefined) ? pieces.map((q) => q.literal).join("") : undefined;
|
|
324
|
+
}
|
|
325
|
+
export function literalHeredocBody(body) {
|
|
326
|
+
let out = "";
|
|
327
|
+
for (let i = 0; i < body.length; i++) {
|
|
328
|
+
const ch = body[i];
|
|
329
|
+
if (ch === "$" || ch === "`")
|
|
330
|
+
return undefined;
|
|
331
|
+
if (ch === "\\" && i + 1 < body.length && "$`\\".includes(body[i + 1])) {
|
|
332
|
+
out += body[++i];
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
out += ch;
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
322
339
|
const BLANK = /[ \t]/;
|
|
323
340
|
const fail = (reason, at) => ({ parseFailure: { reason, at } });
|
|
324
341
|
const publicPiece = (p) => ({
|
|
@@ -340,6 +357,7 @@ class WordBuilder {
|
|
|
340
357
|
marks = [];
|
|
341
358
|
subscript;
|
|
342
359
|
compound = false;
|
|
360
|
+
widenedClasses = [];
|
|
343
361
|
begin(src) { if (!this.started)
|
|
344
362
|
this.at = src; }
|
|
345
363
|
push(w, f, by, src) {
|
|
@@ -385,6 +403,17 @@ class WordBuilder {
|
|
|
385
403
|
mark(reason, rawAt) { this.marks.push({ at: rawAt, reason }); }
|
|
386
404
|
inSubscript() { return this.subscript !== undefined && this.subscript.rawEnd === undefined; }
|
|
387
405
|
foldedOf(r) { return r >= this.foldedAt.length ? this.folded.length : this.foldedAt[r]; }
|
|
406
|
+
classSpelled(from, to) {
|
|
407
|
+
let out = "";
|
|
408
|
+
let at = from;
|
|
409
|
+
for (const [a, b] of this.widenedClasses) {
|
|
410
|
+
if (a < at || b > to)
|
|
411
|
+
continue;
|
|
412
|
+
out += `${this.folded.slice(at, a)}?`;
|
|
413
|
+
at = b;
|
|
414
|
+
}
|
|
415
|
+
return out + this.folded.slice(at, to);
|
|
416
|
+
}
|
|
388
417
|
slice(from, to) {
|
|
389
418
|
const out = [];
|
|
390
419
|
for (const p of this.pieces) {
|
|
@@ -502,9 +531,23 @@ class WordBuilder {
|
|
|
502
531
|
else if (stack.length > 0 && (d === "," || (d === "." && this.raw[j + 1] === ".")))
|
|
503
532
|
stack[stack.length - 1].listed = true;
|
|
504
533
|
}
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
534
|
+
const text = this.folded;
|
|
535
|
+
const nf = text.length;
|
|
536
|
+
const readableAt = (f) => f < nf && readable(this.rawOfFolded[f]);
|
|
537
|
+
const unitClose = (d) => {
|
|
538
|
+
const at = new Array(nf + 2).fill(-1);
|
|
539
|
+
for (let f = nf - 2; f >= 0; f--)
|
|
540
|
+
at[f] = readableAt(f) && readableAt(f + 1) && text[f] === d && text[f + 1] === "]" ? f : at[f + 1];
|
|
541
|
+
return at;
|
|
542
|
+
};
|
|
543
|
+
const unitCloses = new Map([":", "=", "."].map((d) => [d, unitClose(d)]));
|
|
544
|
+
const nextBracketClose = new Array(nf + 2).fill(-1);
|
|
545
|
+
const nextSlash = new Array(nf + 1).fill(nf);
|
|
546
|
+
for (let f = nf - 1; f >= 0; f--) {
|
|
547
|
+
const unitEnd = readableAt(f) && text[f] === "[" && readableAt(f + 1) ? unitCloses.get(text[f + 1] ?? "")?.[f + 2] ?? -1 : -1;
|
|
548
|
+
nextBracketClose[f] = readableAt(f) && text[f] === "]" ? f : unitEnd >= 0 ? nextBracketClose[unitEnd + 2] : nextBracketClose[f + 1];
|
|
549
|
+
nextSlash[f] = text[f] === "/" ? f : nextSlash[f + 1];
|
|
550
|
+
}
|
|
508
551
|
const ranges = [];
|
|
509
552
|
for (let k = 0; k < n; k++) {
|
|
510
553
|
if (!readable(k))
|
|
@@ -519,19 +562,35 @@ class WordBuilder {
|
|
|
519
562
|
continue;
|
|
520
563
|
}
|
|
521
564
|
if (c === "*" || c === "?") {
|
|
522
|
-
ranges.push({ from: k, to: k + 1, exp: { kind: "glob", yields: "many" } });
|
|
565
|
+
ranges.push({ from: k, to: k + 1, exp: { kind: "glob", yields: "many", pattern: { folded: c, written: c, judged: c } } });
|
|
523
566
|
continue;
|
|
524
567
|
}
|
|
525
568
|
if (c === "[") {
|
|
526
|
-
|
|
527
|
-
|
|
569
|
+
if (this.rawOfFolded[this.foldedOf(k)] !== k)
|
|
570
|
+
continue;
|
|
571
|
+
let j = this.foldedOf(k) + 1;
|
|
572
|
+
if ((text[j] === "!" || text[j] === "^") && readableAt(j))
|
|
528
573
|
j++;
|
|
529
|
-
if (
|
|
574
|
+
if (text[j] === "]" && readableAt(j))
|
|
530
575
|
j++;
|
|
531
|
-
const
|
|
532
|
-
if (
|
|
576
|
+
const closeAt = j < nf ? nextBracketClose[j] : -1;
|
|
577
|
+
if (closeAt < 0 || nextSlash[j] < closeAt)
|
|
533
578
|
continue;
|
|
534
|
-
|
|
579
|
+
const close = this.rawOfFolded[closeAt];
|
|
580
|
+
let expands = false;
|
|
581
|
+
for (let m = k + 1; m < close && !expands; m++)
|
|
582
|
+
expands = inExp[m] || braceClose.get(m)?.listed === true;
|
|
583
|
+
let widened = false;
|
|
584
|
+
for (let m = k + 1; m < close && !widened; m++)
|
|
585
|
+
widened = this.rawQuoted[m] !== undefined;
|
|
586
|
+
for (let f = j; f < closeAt && !widened; f++)
|
|
587
|
+
widened = readableAt(f) && text[f] === "[" && readableAt(f + 1) && (unitCloses.get(text[f + 1] ?? "")?.[f + 2] ?? -1) >= 0;
|
|
588
|
+
const from = this.foldedOf(k);
|
|
589
|
+
const to = this.foldedOf(close + 1);
|
|
590
|
+
if (!expands && widened)
|
|
591
|
+
this.widenedClasses.push([from, to]);
|
|
592
|
+
const pattern = expands ? {} : { pattern: { folded: this.folded.slice(from, to), written: this.raw.slice(k, close + 1), judged: widened ? "?" : this.folded.slice(from, to) } };
|
|
593
|
+
ranges.push({ from: k, to: close + 1, exp: { kind: "glob", yields: "many", body: this.raw.slice(k + 1, close), ...pattern } });
|
|
535
594
|
k = close;
|
|
536
595
|
}
|
|
537
596
|
}
|
|
@@ -630,18 +689,20 @@ class WordBuilder {
|
|
|
630
689
|
}
|
|
631
690
|
finish(atCommandPosition, tildeSpelling = true) {
|
|
632
691
|
const rawText = this.raw;
|
|
633
|
-
let
|
|
692
|
+
let literalTilde = false;
|
|
634
693
|
let assignment;
|
|
635
694
|
const tildeEnd = this.tildePrefixEnd(0, false);
|
|
636
695
|
if (tildeEnd !== undefined)
|
|
637
696
|
this.carveTilde(0, tildeEnd);
|
|
638
697
|
else {
|
|
639
|
-
|
|
640
|
-
foldedText = literalTildeSpelling(foldedText);
|
|
698
|
+
literalTilde = tildeSpelling;
|
|
641
699
|
assignment = this.readAssignment();
|
|
642
700
|
}
|
|
643
701
|
if (!(assignment !== undefined && assignment.bare && atCommandPosition))
|
|
644
702
|
this.carveBraceAndGlob();
|
|
703
|
+
const spelled = (text) => (literalTilde ? literalTildeSpelling(text) : text);
|
|
704
|
+
const foldedText = spelled(this.folded);
|
|
705
|
+
const judged = this.widenedClasses.length > 0 ? spelled(this.classSpelled(0, this.folded.length)) : undefined;
|
|
645
706
|
if (assignment !== undefined && this.subscript?.text)
|
|
646
707
|
this.mark("subscript_text", this.subscript.rawStart);
|
|
647
708
|
const marks = this.marks.filter((m) => m.reason !== "subscript_text" || assignment?.subscript !== undefined).sort((a, b) => a.at - b.at);
|
|
@@ -662,6 +723,7 @@ class WordBuilder {
|
|
|
662
723
|
kind: "word",
|
|
663
724
|
raw: rawText,
|
|
664
725
|
folded: foldedText,
|
|
726
|
+
...(judged !== undefined ? { judged } : {}),
|
|
665
727
|
pieces,
|
|
666
728
|
quotedSpans: spans,
|
|
667
729
|
expansions: pieces.filter((p) => p.expansion !== undefined),
|
|
@@ -31,8 +31,6 @@ export declare function writtenAssignmentPrefix(token: string): {
|
|
|
31
31
|
readonly settlesWholeName: boolean;
|
|
32
32
|
} | undefined;
|
|
33
33
|
export { SHELL_CONTROL_PREFIXES };
|
|
34
|
-
/** Shell block words that name no command of their own (a loop head, a block close, a case head). */
|
|
35
|
-
export declare const SHELL_BLOCK_WORDS: ReadonlySet<string>;
|
|
36
34
|
/** A control word is a keyword only when bash sees it BARE: `'if'` / `"do"` / `\\!` are command names (a program
|
|
37
35
|
* looked up on PATH, whose failure changes nothing), so a quoted or escaped spelling never counts as one. */
|
|
38
36
|
export declare function isBareControlWord(words: readonly LexedWord[], i: number, set: ReadonlySet<string>): boolean;
|
|
@@ -43,88 +41,6 @@ export declare function isBareControlWord(words: readonly LexedWord[], i: number
|
|
|
43
41
|
* over control words and earlier assignments re-traces). One fact, two readers that must agree.
|
|
44
42
|
*/
|
|
45
43
|
export declare function isLeadingAssignmentWord(words: readonly LexedWord[], i: number): boolean;
|
|
46
|
-
/**
|
|
47
|
-
* Programs that turn their STANDARD INPUT into the OPERANDS of another program, and EXEC that program directly.
|
|
48
|
-
*
|
|
49
|
-
* The same class as the shell re-entry programs, one level down: there the unseen text is COMMANDS; here the
|
|
50
|
-
* command's name IS visible and its argv is not — `echo <path> | xargs cat` opens a file no token of this walk
|
|
51
|
-
* ever named, because the operand arrives on a stream. The membership criterion is that behaviour and only that
|
|
52
|
-
* behaviour; a program that consumes stdin as DATA (`sort`, `wc`, a reader the deployment never listed) is NOT a
|
|
53
|
-
* member, because its stdin never becomes a filename. Spelled as a pattern — these are program names, never tool
|
|
54
|
-
* names.
|
|
55
|
-
*
|
|
56
|
-
* "EXECS DIRECTLY" is what separates this class from the shell re-entry class, and it is why GNU `parallel` is
|
|
57
|
-
* NOT a member: parallel BUILDS A COMMAND LINE and hands it to a shell, and with no command word at all it runs
|
|
58
|
-
* each input line as a command — so parallel belongs to the shell re-entry class and is refused whole with no
|
|
59
|
-
* exemption at all. A spelling this file has no name for (an aliased or wrapped `xargs`) is judged as any other
|
|
60
|
-
* unlisted program is — the name-table floor the re-entry class records for itself.
|
|
61
|
-
*/
|
|
62
|
-
export declare const ARGV_REENTRY_PROGRAM_RE: RegExp;
|
|
63
|
-
/** The program an {@link ARGV_REENTRY_PROGRAM_RE} launcher runs when the chain names none: `xargs` defaults to
|
|
64
|
-
* `echo`, which is why a bare one reads nothing. */
|
|
65
|
-
export declare const ARGV_REENTRY_DEFAULT_PROGRAM = "echo";
|
|
66
|
-
/**
|
|
67
|
-
* What a launcher declares about its OWN options: each exact spelling with its ARITY — `0` for a switch, `1` for an
|
|
68
|
-
* option whose value is the next token. Every spelling not in the map falls to the refusal (the conservative side,
|
|
69
|
-
* and the verdict those spellings always had); a `1` with no token left to take is not readable either.
|
|
70
|
-
*
|
|
71
|
-
* THREE SPELLINGS OF ONE DECLARATION, because getopt has three: an arity-1 entry is honoured separated (`-k 5`),
|
|
72
|
-
* fused to its long name (`--signal=TERM`) and fused to its short letter (`-k5`), and an arity-0 short entry inside
|
|
73
|
-
* a cluster of arity-0 letters (`-pv`). Reading only the exact spelling made one program two.
|
|
74
|
-
*
|
|
75
|
-
* WHAT A ROW MAY NOT GET WRONG: declaring an arity-1 option as arity 0 steps onto its VALUE and reads the value as
|
|
76
|
-
* the program — the one direction that turns a refusal into a wrong answer rather than a lost one. A row carries
|
|
77
|
-
* only options whose arity every supported implementation agrees on; a flag no row declares still refuses.
|
|
78
|
-
*/
|
|
79
|
-
export interface LauncherRow {
|
|
80
|
-
/** Consulted ONLY for the launcher the command line itself names — a bare keyword in front of the command
|
|
81
|
-
* (`time -p …`) or the written command word (`"time" -p …`, `X=1 time -p …`, `/usr/bin/time -p …`). A launcher
|
|
82
|
-
* nested behind another (`env time -p …`) is that launcher's operand, and its options refuse: resolving past
|
|
83
|
-
* them would turn a whole refusal into an ordinary walked segment — a widening, where every other read of this
|
|
84
|
-
* table only ever finds MORE program to judge. */
|
|
85
|
-
readonly optionArity: ReadonlyMap<string, 0 | 1>;
|
|
86
|
-
/** A bare NEGATIVE integer in this launcher's option section is its OWN argument (`nice -5 <cmd>`), not a flag
|
|
87
|
-
* the table cannot read. Per row: elsewhere a dash-leading token is an option, and reading one as a number
|
|
88
|
-
* would step over a flag whose meaning this table does not know. */
|
|
89
|
-
readonly negativeIntegerIsOwnArgument?: true;
|
|
90
|
-
/** Positional operands the launcher takes BEFORE the program, consumed whatever they spell (`timeout DURATION
|
|
91
|
-
* COMMAND`); a spelling-based reading under-accepted, and every spelling it missed became the program word. */
|
|
92
|
-
readonly requiredOperands?: number;
|
|
93
|
-
/** The launcher reads NAME=VALUE operands with ITS OWN name grammar (`env 1=x …`), wider than the shell's. */
|
|
94
|
-
readonly assignmentOperands?: true;
|
|
95
|
-
/** The launcher hands its operands to a SHELL as text (`watch "cat /x"` runs `sh -c`): no program word to read. */
|
|
96
|
-
readonly shellText?: true;
|
|
97
|
-
/** With no program word the launcher runs a SHELL: piped text would reach it, so an empty program position refuses. */
|
|
98
|
-
readonly whenNoProgram?: "shell";
|
|
99
|
-
/** Options whose value is a WHOLE COMMAND LINE the launcher splits and runs (`env -S "cmd arg"`,
|
|
100
|
-
* `--split-string=…`). Not an arity this reader steps over — the program is inside the value, so the
|
|
101
|
-
* program-position walk still refuses here — but the candidate extraction reads the value as nested shell
|
|
102
|
-
* text instead of as one opaque word. */
|
|
103
|
-
readonly commandString?: readonly string[];
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* The ONE launcher truth: programs that RUN ANOTHER PROGRAM named in ordinary argv tokens, so a declared reader can
|
|
107
|
-
* sit behind one (`env cat <path>`, `sudo cat <path>`, `timeout 5 cat <path>`), each with the option grammar this
|
|
108
|
-
* file reads for it.
|
|
109
|
-
*
|
|
110
|
-
* Membership is the key set. A row with no declared options means every option-shaped word after that launcher
|
|
111
|
-
* refuses ("which program runs is not readable without the launcher's option table") — the answer every launcher
|
|
112
|
-
* but `time` has always had, now stated per row rather than by omission. Declaring a row's options is a behaviour
|
|
113
|
-
* decision with its own criteria; adding a launcher is a row.
|
|
114
|
-
*
|
|
115
|
-
* `time` carries both spellings a deployment can meet: the shell builtin takes `-p` alone, and the standalone
|
|
116
|
-
* program adds a format, an output file, and three switches.
|
|
117
|
-
*
|
|
118
|
-
* A deliberate SUBSET of the rule lane's own `BARE_INTERPRETER_NAMES`, mirrored rather than imported because that
|
|
119
|
-
* module imports the classifier — the dependency runs that way, and a cycle is a worse problem than a mirror whose
|
|
120
|
-
* subset relation is pinned by test. GNU `parallel` is absent for the reason the shells are absent: it does not run
|
|
121
|
-
* a program named in token-visible argv — it BUILDS a command line and hands it to a shell — so it is a shell
|
|
122
|
-
* re-entry member instead. Language interpreters and shells are excluded as a scope statement: their program
|
|
123
|
-
* argument is a script path or a quoted code string, not a token-visible program with token-visible operands.
|
|
124
|
-
*/
|
|
125
|
-
export declare const LAUNCHER_TABLE: ReadonlyMap<string, LauncherRow>;
|
|
126
|
-
/** The launcher names — derived from the table, never kept beside it. */
|
|
127
|
-
export declare const COMMAND_LAUNCHERS: ReadonlySet<string>;
|
|
128
44
|
export declare const PROGRAM_POSITION_REFUSAL_KINDS: readonly ["option_at_program_position", "control_syntax_at_program_position"];
|
|
129
45
|
export type ProgramPositionRefusalKind = (typeof PROGRAM_POSITION_REFUSAL_KINDS)[number];
|
|
130
46
|
/** Why the program could not be read — a closed set, each member minted into one sentence. `owner` is the word
|
|
@@ -137,9 +53,15 @@ export type ProgramPositionRefusal = {
|
|
|
137
53
|
readonly kind: "control_syntax_at_program_position";
|
|
138
54
|
readonly owner: string;
|
|
139
55
|
readonly word: string;
|
|
140
|
-
/** Not a DECLINE ({@link programPositionRunsShell}): the row WAS read and a SHELL
|
|
141
|
-
*
|
|
142
|
-
|
|
56
|
+
/** Not a DECLINE ({@link programPositionRunsShell}): the row WAS read and a SHELL — or a program the launcher
|
|
57
|
+
* names by an option of its own (`su -s PROGRAM`) — stands at the program position, run by the launcher at argv
|
|
58
|
+
* index `launcher` and handed the words from index `from` on (none where `from` is the argv's end: `sudo -s`,
|
|
59
|
+
* `chroot DIR`), as that launcher's row composes them (`launchedCommands`, shell-reentry-text.ts). Absent ⇒
|
|
60
|
+
* genuine control syntax, which IS one. */
|
|
61
|
+
readonly runsShell?: {
|
|
62
|
+
readonly launcher: number;
|
|
63
|
+
readonly from: number;
|
|
64
|
+
};
|
|
143
65
|
};
|
|
144
66
|
export interface ProgramPosition {
|
|
145
67
|
/** Indices of the bare control words stripped in front (`!`, `if`, `time`, …), in order; their declared options
|
|
@@ -159,6 +81,8 @@ export interface ProgramPosition {
|
|
|
159
81
|
readonly argvFromStdin: boolean;
|
|
160
82
|
/** The chain ends ON the re-entry program (nothing follows it), so it runs its default program. */
|
|
161
83
|
readonly runsDefaultProgram: boolean;
|
|
84
|
+
/** The program the stream-fed chain member runs when the chain names none (`xargs` runs `echo`). */
|
|
85
|
+
readonly defaultProgram?: string;
|
|
162
86
|
/** The program bash RUNS: the first word past the chain. `name` is the folded word as written, `basename` what
|
|
163
87
|
* bash resolves (`/usr/bin/cat` is `cat`). `undefined` when the chain names none or the read was refused. */
|
|
164
88
|
readonly program: {
|
|
@@ -184,7 +108,7 @@ export declare function readProgramPosition(words: readonly LexedWord[]): Progra
|
|
|
184
108
|
/** Does this program position hand a program operands the walk cannot see? True when the chain re-enters through
|
|
185
109
|
* stdin AND the program it runs is not one the caller accepts as a stream target. ONE reading, shared by every
|
|
186
110
|
* consumer; WHICH targets are accepted is the caller's declaration, not this reader's. */
|
|
187
|
-
export declare function argvReentryUnjudged(pos: ProgramPosition,
|
|
111
|
+
export declare function argvReentryUnjudged(pos: ProgramPosition, acceptsTarget: (basename: string) => boolean): boolean;
|
|
188
112
|
/**
|
|
189
113
|
* The two ways this reader DECLINES rather than judges — a CLOSED set (`docs/CLOSED-SETS.md`), because what a
|
|
190
114
|
* seat does with a declined segment is a ROW of the shell read decision table (`shell-read-judge.ts`, the
|
|
@@ -197,9 +121,9 @@ export type ShellScanDecline = (typeof SHELL_SCAN_DECLINES)[number];
|
|
|
197
121
|
/** Does a SHELL stand where this segment's program would be — as the program itself (`sh -c`), or as a launcher
|
|
198
122
|
* ROW handing its operands to one (`watch "…"`)? ONE predicate for the re-entry class, so the two spellings
|
|
199
123
|
* cannot be answered differently; which names are shells is the caller's declaration. Not a decline. */
|
|
200
|
-
export declare function programPositionRunsShell(pos: ProgramPosition,
|
|
124
|
+
export declare function programPositionRunsShell(pos: ProgramPosition, runsShell: (basename: string) => boolean): boolean;
|
|
201
125
|
/** Which decline, if any, this program position raises — ONE reading of the two facts above, so no consumer
|
|
202
126
|
* re-derives either. A refusal that says a SHELL runs is NOT one: it names what runs. */
|
|
203
|
-
export declare function shellScanDeclineOf(pos: ProgramPosition,
|
|
127
|
+
export declare function shellScanDeclineOf(pos: ProgramPosition, acceptsStreamTarget: (basename: string) => boolean): ShellScanDecline | undefined;
|
|
204
128
|
/** ONE sentence per refusal kind, minted here and nowhere else. */
|
|
205
129
|
export declare function programPositionRefusalSentence(refusal: ProgramPositionRefusal): string;
|