@sema-agent/core 7.19.0 → 7.20.1
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 +199 -2
- package/dist/agents/subagent.js +12 -20
- package/dist/agents/teacher.js +2 -5
- package/dist/agents/verify.js +21 -10
- package/dist/brain/anthropic.js +3 -1
- package/dist/brain/open-responses.js +4 -2
- package/dist/brain/openai.js +3 -1
- package/dist/brain/stream-engine.d.ts +4 -0
- package/dist/brain/stream-engine.js +4 -0
- package/dist/core/auto-mode.d.ts +37 -18
- package/dist/core/auto-mode.js +1 -1
- package/dist/core/child-clamp-seats.d.ts +79 -0
- package/dist/core/child-clamp-seats.js +29 -0
- package/dist/core/engine-notice.d.ts +76 -49
- package/dist/core/fs-write-gate-policy.d.ts +17 -9
- package/dist/core/fs-write-gate-policy.js +51 -4
- package/dist/core/gate-bounded-await.d.ts +38 -0
- package/dist/core/gate-bounded-await.js +53 -0
- package/dist/core/gate-fold.js +16 -48
- package/dist/core/gate-lanes.js +11 -3
- package/dist/core/gate-outcome.d.ts +9 -6
- package/dist/core/governance-codes.d.ts +16 -1
- package/dist/core/governance-codes.js +14 -0
- package/dist/core/hooks.d.ts +8 -8
- package/dist/core/memory-engine/engine.d.ts +14 -9
- package/dist/core/memory-engine/engine.js +21 -8
- package/dist/core/memory-engine/layout.d.ts +31 -0
- package/dist/core/memory-engine/layout.js +68 -3
- package/dist/core/memory-engine/tools.js +6 -0
- package/dist/core/memory-engine/types.d.ts +24 -0
- package/dist/core/memory.d.ts +19 -0
- package/dist/core/memory.js +12 -0
- package/dist/core/remote-env.d.ts +32 -0
- package/dist/core/remote-env.js +4 -1
- package/dist/core/runner/advertised-writable-dirs.d.ts +59 -1
- package/dist/core/runner/advertised-writable-dirs.js +51 -3
- package/dist/core/runner/announce-once-ledger.d.ts +15 -0
- package/dist/core/runner/announce-once-ledger.js +8 -0
- package/dist/core/runner/classifier-ladder.d.ts +5 -0
- package/dist/core/runner/classifier-ladder.js +13 -2
- package/dist/core/runner/contracts.d.ts +44 -1
- package/dist/core/runner/denial-limit-arms.d.ts +14 -1
- package/dist/core/runner/denial-limit-arms.js +5 -4
- package/dist/core/runner/env-capability-census.d.ts +30 -0
- package/dist/core/runner/env-capability-census.js +38 -0
- package/dist/core/runner/forward-sink.d.ts +32 -0
- package/dist/core/runner/forward-sink.js +41 -0
- package/dist/core/runner/gate-exit.d.ts +4 -0
- package/dist/core/runner/gate-exit.js +4 -1
- package/dist/core/runner/git-status-frame.d.ts +0 -9
- package/dist/core/runner/listing-fold.d.ts +57 -0
- package/dist/core/runner/listing-fold.js +75 -0
- package/dist/core/runner/prepare-execution-env.d.ts +1 -1
- package/dist/core/runner/prepare-execution-env.js +2 -0
- package/dist/core/runner/prepare-gate-stations.d.ts +6 -0
- package/dist/core/runner/prepare-gate-stations.js +1 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -0
- package/dist/core/runner/prepare-hands-readface.js +3 -5
- package/dist/core/runner/prepare-listings.d.ts +3 -0
- package/dist/core/runner/prepare-listings.js +4 -2
- package/dist/core/runner/prepare-memory.js +7 -1
- package/dist/core/runner/prepare-policy-chain.js +5 -5
- package/dist/core/runner/prepare-prompt-inputs.d.ts +2 -2
- package/dist/core/runner/prepare-run-refs.d.ts +4 -2
- package/dist/core/runner/prepare-run-refs.js +5 -4
- package/dist/core/runner/prepare-task.js +8 -6
- package/dist/core/runner/prepare-wiring-manifest.d.ts +8 -1
- package/dist/core/runner/prepare-wiring-manifest.js +5 -2
- package/dist/core/runner/run-clock-and-content.js +3 -7
- package/dist/core/runner/run-harness-handlers.js +10 -10
- package/dist/core/runner/run-leg.js +28 -19
- package/dist/core/runner/run-settle-and-teardown.js +2 -5
- package/dist/core/runner/run-turn-boundary.js +44 -33
- package/dist/core/runner/runtask.js +2 -1
- package/dist/core/runner/synthetic-tools.d.ts +13 -39
- package/dist/core/runner/synthetic-tools.js +15 -59
- package/dist/core/runner/task-root-canonical.d.ts +45 -0
- package/dist/core/runner/task-root-canonical.js +18 -0
- package/dist/core/runner/turn-attachments.d.ts +125 -49
- package/dist/core/runner/turn-attachments.js +124 -66
- package/dist/core/runner/write-protection-station.d.ts +59 -0
- package/dist/core/runner/write-protection-station.js +32 -0
- package/dist/core/safe-notify.d.ts +5 -0
- package/dist/core/safe-notify.js +24 -2
- package/dist/core/sensitive-path-policy.d.ts +53 -27
- package/dist/core/sensitive-path-policy.js +16 -26
- package/dist/core/skill-listing-budget.d.ts +34 -40
- package/dist/core/skill-listing-budget.js +25 -26
- package/dist/core/skills-directory.js +17 -10
- package/dist/core/task-registry.js +2 -1
- package/dist/core/task-spec.d.ts +8 -7
- package/dist/core/tool-policy.d.ts +12 -1
- package/dist/core/tool-policy.js +39 -25
- package/dist/core/wiring-manifest.d.ts +31 -0
- package/dist/core/wiring-manifest.js +1 -0
- package/dist/core/write-protect.d.ts +124 -18
- package/dist/core/write-protect.js +91 -34
- package/dist/index.d.ts +6 -5
- package/dist/index.js +6 -5
- package/dist/orchestration/workflow-primitives.js +10 -20
- package/dist/stores/file/memory-store.d.ts +5 -2
- package/dist/stores/file/memory-store.js +8 -4
- package/dist/tools/fs/bash-readonly-classifier.d.ts +13 -2
- package/dist/tools/fs/bash-readonly-classifier.js +318 -36
- package/dist/tools/fs/fs-bash.d.ts +1 -1
- package/dist/tools/fs/fs-bash.js +12 -25
- package/dist/tools/fs/fs-shared.d.ts +22 -0
- package/dist/tools/fs/fs-shared.js +30 -0
- package/dist/tools/fs/index.d.ts +1 -1
- package/dist/tools/fs/index.js +1 -1
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +25 -3
- package/wire-changes/core@7.20.0.json +568 -0
- package/wire-changes/core@7.20.1.json +183 -0
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ export { getShellConfig, isWslBashLauncher } from "./engine/execution-env/node-e
|
|
|
71
71
|
export { isSecretEnvKey, scrubSecretEnv } from "./core/secret-env.js";
|
|
72
72
|
export { MAX_EXEC_OUTPUT_BYTES, RollingTailBuffer, markTruncated } from "./core/exec-output-tail.js";
|
|
73
73
|
export { physicalPathOf, physicalPathOfExisting } from "./core/physical-path.js";
|
|
74
|
-
export { RemoteExecutionError, hasDestroy, isRemoteExecutionEnv, isSuspendable, isIsolated, missingRestoreSurface, isRetryableRemoteErrorCode, RETRYABLE_REMOTE_ERROR_CODES, } from "./core/remote-env.js";
|
|
74
|
+
export { RemoteExecutionError, hasDestroy, isRemoteExecutionEnv, isSuspendable, isIsolated, canonicalPathIsAuthoritative, missingRestoreSurface, isRetryableRemoteErrorCode, RETRYABLE_REMOTE_ERROR_CODES, } from "./core/remote-env.js";
|
|
75
75
|
export { withRetry } from "./core/with-retry.js";
|
|
76
76
|
export { addWorktree, pruneWorktrees, WORKTREE_PARENT } from "./core/git-worktree-env.js";
|
|
77
77
|
export { runExecGate } from "./core/exec-gate.js";
|
|
@@ -83,7 +83,7 @@ export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, }
|
|
|
83
83
|
export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
|
|
84
84
|
export { READ_FACE_DEFAULT_DENY_ENTRIES, READ_FACE_BUILTIN_DENY_TABLE, READ_DENY_BUILTIN_TIERS, READ_DENY_DEFAULT_TIERS, resolveReadDenyBuiltins, compileReadDeny, } from "./tools/fs/index.js";
|
|
85
85
|
export { deploymentFaceClampNotice, resolveContainmentFace, } from "./tools/fs/index.js";
|
|
86
|
-
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, } from "./core/write-protect.js";
|
|
86
|
+
export { WRITE_PROTECTED_DEFAULT_TABLE, resolveWriteProtectedTable, compileWriteProtection, WRITE_PROTECTION_TARGET_VIEWS, } from "./core/write-protect.js";
|
|
87
87
|
export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, toolResultContentSegment, MAX_MINTED_TOOL_RESULT_REF_CHARS, assertToolResultProvenanceMatch, normalizeToolResultProvenance, toolResultProvenanceOf, ToolResultRefConflictError, TOOL_RESULT_REF_CONFLICT_CODE, } from "./core/tool-result-store.js";
|
|
88
88
|
export { InMemoryCheckpointStore, CheckpointError, mintCheckpointId, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, REAL_APPROVAL_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, realApprovalOrgFact, resolveCheckpointStore, checkpointStoreExecutionUndeclared, } from "./core/checkpoint-store.js";
|
|
89
89
|
export { EXECUTION_OUTCOME_RECORD_WORDS, EXECUTION_RECORD_LEAVES_ROW_UNRECORDED, ExecutionOutcomeConflictError, checkpointExecutionRecorded, executionRecordDisposition, sameExecutionRecord, executionVerdict, } from "./core/checkpoint-execution-record.js";
|
|
@@ -103,8 +103,8 @@ export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemorySto
|
|
|
103
103
|
export { CacheBreakDetector } from "./core/cache-break-detector.js";
|
|
104
104
|
export { maybeCompact } from "./core/auto-compaction.js";
|
|
105
105
|
export { brainToRuntime } from "./core/runtime.js";
|
|
106
|
-
export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS
|
|
107
|
-
export { createFsWriteGatePolicy } from "./core/fs-write-gate-policy.js";
|
|
106
|
+
export { createSensitivePathPolicy, RECOMMENDED_SENSITIVE_PATTERNS } from "./core/sensitive-path-policy.js";
|
|
107
|
+
export { createFsWriteGatePolicy, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE } from "./core/fs-write-gate-policy.js";
|
|
108
108
|
export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
|
|
109
109
|
export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
|
|
110
110
|
export { renderTaskNotificationXml, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, } from "./core/task-notification.js";
|
|
@@ -152,6 +152,7 @@ export {} from "./core/hooks.js";
|
|
|
152
152
|
export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
|
|
153
153
|
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";
|
|
154
154
|
export { AUTO_MODE_DENIAL_LIMIT_DEFAULTS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "./core/auto-mode-defaults.js";
|
|
155
|
+
export { classifierSeatModel } from "./core/runner/classifier-ladder.js";
|
|
155
156
|
export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, } from "./core/auto-mode-prompt.js";
|
|
156
157
|
export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
|
|
157
158
|
export { AUTO_MODE_ARMING_RECIPE_VERSION, autoModeArmingRecipeOf, sanitizeAutoModeArmingRecipe, foldAutoModeArming, } from "./core/auto-mode-arming.js";
|
|
@@ -174,7 +175,7 @@ export { AdoptionError, assertAdoptionBootGate, readRootAdoptionFile, writeRootA
|
|
|
174
175
|
export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdoptionQuarantine, readAdoptionStatus, } from "./stores/file/adoption/adopt.js";
|
|
175
176
|
export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, normalizePersistedRuleHit, } from "./core/hooks.js";
|
|
176
177
|
export { HOOK_FAMILIES, HOOKS_INVALID_CODE } from "./core/hook-seats.js";
|
|
177
|
-
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, } from "./core/memory.js";
|
|
178
|
+
export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, MemoryProjectionError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, } from "./core/memory.js";
|
|
178
179
|
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, 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";
|
|
179
180
|
export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, } from "./core/shared-memory/types.js";
|
|
180
181
|
export { sharedMemoryStoreContract, } from "./core/shared-memory/contract.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { assertSupportedAgentIsolation } from "./workflow.js";
|
|
2
|
+
import { childClampSeats } from "../core/child-clamp-seats.js";
|
|
2
3
|
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
3
4
|
import { buildGovernedChildSpec, emitIgnoredAgentOptionsNotice, overlayWorktreeBaseline, MAX_ANNOUNCED_KEYS, SPEC_KEY_ALIASES, WHITELIST_KEYS, } from "./workflow-governance.js";
|
|
4
5
|
const ACCEPTED_AGENT_OPTION_KEYS = ["label", "phase", "schema", "agentType", "isolation"];
|
|
@@ -77,27 +78,16 @@ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentChe
|
|
|
77
78
|
if (parentCheckpointStore !== undefined && (parentCheckpointStore === "disabled" || childSpec.checkpointStore === undefined)) {
|
|
78
79
|
childSpec.checkpointStore = parentCheckpointStore;
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
if (parentReadDenyPatterns) {
|
|
91
|
-
const pd = parentReadDenyPatterns();
|
|
92
|
-
if (pd !== undefined && pd.length > 0) {
|
|
93
|
-
childSpec.readDenyPatterns = childSpec.readDenyPatterns !== undefined ? [...childSpec.readDenyPatterns, ...pd] : [...pd];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (parentHandsReadOnly === true) {
|
|
97
|
-
childSpec.handsReadOnly = true;
|
|
98
|
-
}
|
|
81
|
+
const pd = parentReadDenyPatterns?.();
|
|
82
|
+
const workflowChildClamps = childClampSeats({
|
|
83
|
+
handsReadOnly: parentHandsReadOnly,
|
|
84
|
+
interactiveTools: parentInteractiveToolsOff === true ? false : undefined,
|
|
85
|
+
readFace: parentReadFace?.() === "roots" ? "roots" : childSpec.readFace,
|
|
86
|
+
writeFace: parentWriteFace?.() === "roots" ? "roots" : childSpec.writeFace,
|
|
87
|
+
readDenyPatterns: pd !== undefined && pd.length > 0 ? [...(childSpec.readDenyPatterns ?? []), ...pd] : childSpec.readDenyPatterns,
|
|
88
|
+
});
|
|
89
|
+
Object.assign(childSpec, workflowChildClamps);
|
|
99
90
|
if (parentInteractiveToolsOff === true) {
|
|
100
|
-
childSpec.interactiveTools = false;
|
|
101
91
|
if (childSpec.interactionPosture === "interactive")
|
|
102
92
|
delete childSpec.interactionPosture;
|
|
103
93
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { type Embedder, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type StructuredNoteInput } from "../../core/memory.js";
|
|
2
2
|
export declare class FileMemoryStore implements MemoryStore {
|
|
3
3
|
private readonly root;
|
|
4
|
-
private readonly tmpDir;
|
|
5
4
|
/** Optional injected embedder (design/81 Slice 5). When present, note bodies are embedded (in the background,
|
|
6
5
|
* after the durable note write) into a rebuildable sidecar index and `searchScored` ranks by cosine distance
|
|
7
6
|
* (portable / in-process, mirrors PgMemoryStore's jsonb mode). Absent ⇒ lexical, byte-identical to before. */
|
|
@@ -59,7 +58,11 @@ export declare class FileMemoryStore implements MemoryStore {
|
|
|
59
58
|
* Only when an embedder is injected; a failure/timeout leaves the row lexical (fail-open). The durable note
|
|
60
59
|
* write has ALREADY happened before this is called, so this never gates durability. */
|
|
61
60
|
private queueEmbed;
|
|
62
|
-
/** Rewrite the derived `MEMORY.md` projection atomically (CC markdown parity)
|
|
61
|
+
/** Rewrite the derived `MEMORY.md` projection atomically (CC markdown parity), STAGED IN THE TARGET'S
|
|
62
|
+
* OWN DIRECTORY: `rename(2)` is defined only within one filesystem, so staging beside the target makes
|
|
63
|
+
* the two share a mount by construction where a fixed scratch dir elsewhere made it deployment luck (a
|
|
64
|
+
* memory tree on its own device took `EXDEV` on every note). EVERY caller is POST-DURABLE, so a failure
|
|
65
|
+
* here cannot mean the note was lost: it is {@link MemoryProjectionError}, that phase's one name. */
|
|
63
66
|
private writeProjection;
|
|
64
67
|
read(scope: string): string | null;
|
|
65
68
|
append(scope: string, note: string): string | void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { uuidv7 } from "../../internal/harness.js";
|
|
3
|
-
import { firstSentence, lexicalSearchMatch, parseNoteTimestamp, } from "../../core/memory.js";
|
|
3
|
+
import { firstSentence, lexicalSearchMatch, parseNoteTimestamp, MemoryProjectionError, } from "../../core/memory.js";
|
|
4
4
|
import { cosineDistance, jaccardDistance, termSet } from "../../core/memory-vector.js";
|
|
5
5
|
import { canonicalStoreKey, AppendLog, atomicWriteFile, ensureDir, readJsonlRecords, sanitizeScope, } from "./fs-atomic.js";
|
|
6
6
|
import { assertAdoptionBootGate } from "./adoption/marker.js";
|
|
@@ -8,7 +8,6 @@ const MAX_OPEN_MEMORY_SCOPES = 64;
|
|
|
8
8
|
const sharedMemoryDirs = new Map();
|
|
9
9
|
export class FileMemoryStore {
|
|
10
10
|
root;
|
|
11
|
-
tmpDir;
|
|
12
11
|
embedder;
|
|
13
12
|
embedTimeoutMs;
|
|
14
13
|
pending = new Set();
|
|
@@ -31,7 +30,6 @@ export class FileMemoryStore {
|
|
|
31
30
|
this.sharedScopes = { scopes: new Map(), refs: 1, openLogs: new Set() };
|
|
32
31
|
sharedMemoryDirs.set(this.scopeKey, this.sharedScopes);
|
|
33
32
|
}
|
|
34
|
-
this.tmpDir = join(root, "tmp");
|
|
35
33
|
this.embedder = opts.embedder;
|
|
36
34
|
this.embedTimeoutMs = Math.max(0, opts.embedTimeoutMs ?? 10_000);
|
|
37
35
|
ensureDir(this.root);
|
|
@@ -148,7 +146,13 @@ export class FileMemoryStore {
|
|
|
148
146
|
}
|
|
149
147
|
writeProjection(state) {
|
|
150
148
|
const body = state.entries.map(renderBullet).join("\n");
|
|
151
|
-
|
|
149
|
+
const target = join(state.dir, "MEMORY.md");
|
|
150
|
+
try {
|
|
151
|
+
atomicWriteFile(state.dir, target, body ? `${body}\n` : "");
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
throw new MemoryProjectionError(target, err);
|
|
155
|
+
}
|
|
152
156
|
}
|
|
153
157
|
read(scope) {
|
|
154
158
|
const { entries } = this.scopeState(scope);
|
|
@@ -35,7 +35,7 @@ export { NOT_AUTO_ALLOWED } from "./bash-program-position.js";
|
|
|
35
35
|
export type { ShellSegmentConnector } from "./bash-lexer.js";
|
|
36
36
|
export declare const BASH_READONLY_DEFAULT_ALLOW: readonly string[];
|
|
37
37
|
/**
|
|
38
|
-
* The CLASSIFY face
|
|
38
|
+
* The verbs the CLASSIFY face admits ON TOP of the shared list ({@link bashClassifyDefaultAllow}) —
|
|
39
39
|
* admissible only where the compound classifier's per-verb judgment runs, and NOT on the shared list's
|
|
40
40
|
* other consumer faces:
|
|
41
41
|
* · `find` — read-only only when no CC `aCy` dangerous predicate token is present (guard arm);
|
|
@@ -54,7 +54,18 @@ export declare const BASH_READONLY_DEFAULT_ALLOW: readonly string[];
|
|
|
54
54
|
* poll-loop face inherits the guard arms for free: its body vetting delegates to the same compound
|
|
55
55
|
* classifier.
|
|
56
56
|
*/
|
|
57
|
-
export declare const
|
|
57
|
+
export declare const BASH_CLASSIFY_EXTRA_ALLOW: readonly string[];
|
|
58
|
+
/** A verb only the classify face admits. */
|
|
59
|
+
export type BashClassifyExtraVerb = (typeof BASH_CLASSIFY_EXTRA_ALLOW)[number];
|
|
60
|
+
/**
|
|
61
|
+
* @contract shell.classify_allow.one_union_point — the classify face's default allow set is the union of
|
|
62
|
+
* two SPELLED-OUT tables ({@link BASH_READONLY_DEFAULT_ALLOW} ∪ {@link BASH_CLASSIFY_EXTRA_ALLOW}) and
|
|
63
|
+
* this function is its only assembly point; no call site composes its own. Both halves stay arrays of
|
|
64
|
+
* string literals so a static reader can enumerate them: a vocabulary derived in place
|
|
65
|
+
* (`[...TABLE, "extra"]`) is invisible to the release's wire-change manifest, so a verb added to or
|
|
66
|
+
* dropped from this security-relevant set would move nothing a downstream reader could see.
|
|
67
|
+
*/
|
|
68
|
+
export declare function bashClassifyDefaultAllow(): readonly string[];
|
|
58
69
|
/**
|
|
59
70
|
* G2 — options for {@link parseLeadingCommandName}. Omitting them keeps the parser byte-identical to
|
|
60
71
|
* what every existing caller (the `bash_readonly` declaration face, the coarse command-name policy, the
|
|
@@ -8,7 +8,10 @@ export const BASH_READONLY_DEFAULT_ALLOW = [
|
|
|
8
8
|
"cal", "uptime", "id", "groups", "nproc", "locale", "free", "realpath", "readlink",
|
|
9
9
|
"true", "false", "seq", "expr", "type", "sleep", "diff", "cmp", "comm",
|
|
10
10
|
];
|
|
11
|
-
export const
|
|
11
|
+
export const BASH_CLASSIFY_EXTRA_ALLOW = ["find", "sed", "cd"];
|
|
12
|
+
export function bashClassifyDefaultAllow() {
|
|
13
|
+
return [...BASH_READONLY_DEFAULT_ALLOW, ...BASH_CLASSIFY_EXTRA_ALLOW];
|
|
14
|
+
}
|
|
12
15
|
const SHELL_OPERATORS = /[;&|<>$()`\n\r\\]/;
|
|
13
16
|
function hasBareShellOperator(s, quotedOperatorsAreText) {
|
|
14
17
|
if (!quotedOperatorsAreText)
|
|
@@ -304,7 +307,7 @@ function refusedCommandExempt(command, allow, boundary, depth, baseMovedOutside
|
|
|
304
307
|
const resolved = resolveOperandLexically(boundary.cwd ?? boundary.roots[0], word, boundary.homeDir);
|
|
305
308
|
if (resolved === undefined || boundary.denyMatch?.(resolved) != null)
|
|
306
309
|
return false;
|
|
307
|
-
return withinAnyRoot(boundary.roots, resolved);
|
|
310
|
+
return boundary.face === "open" || withinAnyRoot(boundary.roots, resolved);
|
|
308
311
|
};
|
|
309
312
|
const unlistedSegmentJudgedInside = (words, from) => {
|
|
310
313
|
if (boundary === undefined)
|
|
@@ -446,18 +449,6 @@ function isGrepPatternFlagToken(tok) {
|
|
|
446
449
|
}
|
|
447
450
|
return /^-[A-Za-z0-9]*[ef]/.test(tok);
|
|
448
451
|
}
|
|
449
|
-
function isGrepPatternPayloadLongOption(tok) {
|
|
450
|
-
if (!tok.includes("="))
|
|
451
|
-
return false;
|
|
452
|
-
const name = longOptionNameOf(tok);
|
|
453
|
-
return name !== undefined && isLongOptionAbbrevOf(name, "regexp");
|
|
454
|
-
}
|
|
455
|
-
function isCutDelimiterPayloadLongOption(tok) {
|
|
456
|
-
if (!tok.includes("="))
|
|
457
|
-
return false;
|
|
458
|
-
const name = longOptionNameOf(tok);
|
|
459
|
-
return name !== undefined && (isLongOptionAbbrevOf(name, "delimiter") || isLongOptionAbbrevOf(name, "output-delimiter"));
|
|
460
|
-
}
|
|
461
452
|
function isGrepClusterFileStdin(tok) {
|
|
462
453
|
if (tok.startsWith("--") || !/^-[A-Za-z0-9]/.test(tok))
|
|
463
454
|
return false;
|
|
@@ -472,6 +463,283 @@ function isGrepClusterFileStdin(tok) {
|
|
|
472
463
|
}
|
|
473
464
|
return false;
|
|
474
465
|
}
|
|
466
|
+
function valueNamesAFile(kind) {
|
|
467
|
+
return kind === "path" || kind === "indirect" || kind === "form" || kind === "header" || kind === "url";
|
|
468
|
+
}
|
|
469
|
+
function widestValueKind(kinds) {
|
|
470
|
+
if (kinds.has("indirect"))
|
|
471
|
+
return "indirect";
|
|
472
|
+
if (kinds.has("path"))
|
|
473
|
+
return "path";
|
|
474
|
+
if (kinds.has("form"))
|
|
475
|
+
return "form";
|
|
476
|
+
if (kinds.has("header"))
|
|
477
|
+
return "header";
|
|
478
|
+
if (kinds.has("url"))
|
|
479
|
+
return "url";
|
|
480
|
+
return [...kinds][0];
|
|
481
|
+
}
|
|
482
|
+
const VERB_OPTION_SLOTS = {
|
|
483
|
+
head: {
|
|
484
|
+
shortValue: { c: "count", n: "count" },
|
|
485
|
+
shortPlain: "qvz",
|
|
486
|
+
longValue: { bytes: "count", lines: "count" },
|
|
487
|
+
longOptionalValue: {},
|
|
488
|
+
longPlain: ["help", "quiet", "silent", "verbose", "version", "zero-terminated"],
|
|
489
|
+
},
|
|
490
|
+
tail: {
|
|
491
|
+
shortValue: { b: "count", c: "count", n: "count", s: "count" },
|
|
492
|
+
shortPlain: "fFqvz",
|
|
493
|
+
longValue: { bytes: "count", lines: "count", "max-unchanged-stats": "count", pid: "count", "sleep-interval": "count" },
|
|
494
|
+
longOptionalValue: { follow: "label" },
|
|
495
|
+
longPlain: ["help", "quiet", "retry", "silent", "verbose", "version", "zero-terminated"],
|
|
496
|
+
},
|
|
497
|
+
cut: {
|
|
498
|
+
shortValue: { b: "count", c: "count", d: "delimiter", f: "count" },
|
|
499
|
+
shortPlain: "nsz",
|
|
500
|
+
longValue: { bytes: "count", characters: "count", delimiter: "delimiter", fields: "count", "output-delimiter": "delimiter" },
|
|
501
|
+
longOptionalValue: {},
|
|
502
|
+
longPlain: ["complement", "help", "only-delimited", "version", "zero-terminated"],
|
|
503
|
+
},
|
|
504
|
+
grep: {
|
|
505
|
+
shortValue: { A: "count", B: "count", C: "count", D: "label", d: "label", e: "pattern", f: "path", m: "count" },
|
|
506
|
+
shortPlain: "0123456789abcEFGhHiIlLnoPqrRsUvVwxyzZ",
|
|
507
|
+
longValue: {
|
|
508
|
+
"after-context": "count",
|
|
509
|
+
"before-context": "count",
|
|
510
|
+
"binary-files": "label",
|
|
511
|
+
devices: "label",
|
|
512
|
+
directories: "label",
|
|
513
|
+
exclude: "name-pattern",
|
|
514
|
+
"exclude-dir": "name-pattern",
|
|
515
|
+
"exclude-from": "path",
|
|
516
|
+
file: "path",
|
|
517
|
+
"group-separator": "label",
|
|
518
|
+
include: "name-pattern",
|
|
519
|
+
label: "label",
|
|
520
|
+
"max-count": "count",
|
|
521
|
+
regexp: "pattern",
|
|
522
|
+
},
|
|
523
|
+
longOptionalValue: { color: "label", colour: "label", context: "count" },
|
|
524
|
+
longPlain: [
|
|
525
|
+
"basic-regexp", "byte-offset", "count", "dereference-recursive", "extended-regexp",
|
|
526
|
+
"files-with-matches", "files-without-match", "fixed-strings", "help", "ignore-case", "initial-tab",
|
|
527
|
+
"invert-match", "line-buffered", "line-number", "line-regexp", "no-filename", "no-group-separator",
|
|
528
|
+
"no-messages", "null", "null-data", "only-matching", "perl-regexp", "quiet", "recursive", "silent",
|
|
529
|
+
"text", "version", "with-filename", "word-regexp",
|
|
530
|
+
],
|
|
531
|
+
},
|
|
532
|
+
diff: {
|
|
533
|
+
shortValue: { C: "count", D: "label", F: "pattern", I: "pattern", L: "label", S: "path", U: "count", W: "count", X: "path", x: "name-pattern" },
|
|
534
|
+
shortPlain: "abBcdeEHilnNpqrstTuvwyZ",
|
|
535
|
+
longValue: {
|
|
536
|
+
exclude: "name-pattern",
|
|
537
|
+
"exclude-from": "path",
|
|
538
|
+
"from-file": "path",
|
|
539
|
+
"horizon-lines": "count",
|
|
540
|
+
ifdef: "label",
|
|
541
|
+
"ignore-matching-lines": "pattern",
|
|
542
|
+
label: "label",
|
|
543
|
+
"show-function-line": "pattern",
|
|
544
|
+
"starting-file": "path",
|
|
545
|
+
tabsize: "count",
|
|
546
|
+
"to-file": "path",
|
|
547
|
+
width: "count",
|
|
548
|
+
},
|
|
549
|
+
longOptionalValue: { color: "label", context: "count", unified: "count" },
|
|
550
|
+
longPlain: [
|
|
551
|
+
"brief", "ed", "expand-tabs", "help", "ignore-all-space", "ignore-blank-lines", "ignore-case",
|
|
552
|
+
"ignore-space-change", "ignore-tab-expansion", "ignore-trailing-space", "initial-tab", "minimal",
|
|
553
|
+
"new-file", "normal", "paginate", "recursive", "report-identical-files", "rcs", "show-c-function",
|
|
554
|
+
"side-by-side", "speed-large-files", "suppress-blank-empty", "text", "version",
|
|
555
|
+
],
|
|
556
|
+
},
|
|
557
|
+
cmp: {
|
|
558
|
+
shortValue: { i: "count", n: "count" },
|
|
559
|
+
shortPlain: "blsv",
|
|
560
|
+
longValue: { bytes: "count", "ignore-initial": "count" },
|
|
561
|
+
longOptionalValue: {},
|
|
562
|
+
longPlain: ["help", "print-bytes", "quiet", "silent", "verbose", "version"],
|
|
563
|
+
},
|
|
564
|
+
sed: {
|
|
565
|
+
shortValue: { e: "script", f: "path" },
|
|
566
|
+
shortPlain: "nrEszu",
|
|
567
|
+
longValue: { expression: "script", file: "path", "line-length": "count" },
|
|
568
|
+
longOptionalValue: { "in-place": "label" },
|
|
569
|
+
longPlain: [
|
|
570
|
+
"debug", "follow-symlinks", "help", "null-data", "posix", "quiet", "regexp-extended", "sandbox",
|
|
571
|
+
"separate", "silent", "unbuffered", "version", "zero-terminated",
|
|
572
|
+
],
|
|
573
|
+
},
|
|
574
|
+
date: {
|
|
575
|
+
shortValue: { d: "count", f: "path", r: "path", s: "count" },
|
|
576
|
+
shortPlain: "uR",
|
|
577
|
+
longValue: { date: "count", file: "path", reference: "path", "rfc-3339": "count", set: "count" },
|
|
578
|
+
longOptionalValue: { "iso-8601": "label" },
|
|
579
|
+
longPlain: ["debug", "help", "rfc-822", "rfc-email", "universal", "utc", "version"],
|
|
580
|
+
},
|
|
581
|
+
tar: {
|
|
582
|
+
shortValue: { b: "count", C: "path", f: "path", T: "path", X: "path" },
|
|
583
|
+
shortPlain: "acdhjJkmOpPrStuvwWxzZ",
|
|
584
|
+
longValue: {
|
|
585
|
+
"blocking-factor": "count",
|
|
586
|
+
directory: "path",
|
|
587
|
+
exclude: "name-pattern",
|
|
588
|
+
"exclude-from": "path",
|
|
589
|
+
file: "path",
|
|
590
|
+
"files-from": "path",
|
|
591
|
+
"strip-components": "count",
|
|
592
|
+
},
|
|
593
|
+
longOptionalValue: {},
|
|
594
|
+
longPlain: [
|
|
595
|
+
"absolute-names", "append", "create", "dereference", "extract", "get", "help", "interactive",
|
|
596
|
+
"keep-old-files", "list", "preserve-permissions", "sparse", "to-stdout", "touch", "update",
|
|
597
|
+
"verbose", "verify", "version",
|
|
598
|
+
],
|
|
599
|
+
},
|
|
600
|
+
curl: {
|
|
601
|
+
shortValue: {
|
|
602
|
+
A: "label", b: "indirect", C: "count", c: "path", D: "path", d: "indirect", E: "path", e: "label",
|
|
603
|
+
F: "form", H: "header", K: "path", m: "count", o: "path", P: "label", Q: "label", r: "count",
|
|
604
|
+
T: "path", t: "label", U: "label", u: "label", w: "indirect", X: "label", x: "label", Y: "count",
|
|
605
|
+
y: "count", z: "path",
|
|
606
|
+
},
|
|
607
|
+
shortPlain: "#0123456aBfgGhiIjJklLMnNOpqRsSvVZ",
|
|
608
|
+
longValue: {
|
|
609
|
+
cacert: "path",
|
|
610
|
+
capath: "path",
|
|
611
|
+
cert: "path",
|
|
612
|
+
config: "path",
|
|
613
|
+
"connect-timeout": "count",
|
|
614
|
+
cookie: "indirect",
|
|
615
|
+
"cookie-jar": "path",
|
|
616
|
+
data: "indirect",
|
|
617
|
+
"data-ascii": "indirect",
|
|
618
|
+
"data-binary": "indirect",
|
|
619
|
+
"data-raw": "label",
|
|
620
|
+
"data-urlencode": "form",
|
|
621
|
+
"dump-header": "path",
|
|
622
|
+
form: "form",
|
|
623
|
+
"form-string": "label",
|
|
624
|
+
header: "header",
|
|
625
|
+
key: "path",
|
|
626
|
+
"max-time": "count",
|
|
627
|
+
"netrc-file": "path",
|
|
628
|
+
output: "path",
|
|
629
|
+
proxy: "label",
|
|
630
|
+
range: "count",
|
|
631
|
+
referer: "label",
|
|
632
|
+
request: "label",
|
|
633
|
+
resolve: "label",
|
|
634
|
+
trace: "path",
|
|
635
|
+
"time-cond": "path",
|
|
636
|
+
"trace-ascii": "path",
|
|
637
|
+
"upload-file": "path",
|
|
638
|
+
url: "url",
|
|
639
|
+
user: "label",
|
|
640
|
+
"user-agent": "label",
|
|
641
|
+
"write-out": "indirect",
|
|
642
|
+
},
|
|
643
|
+
longOptionalValue: {},
|
|
644
|
+
longPlain: [
|
|
645
|
+
"append", "compressed", "disable", "fail", "get", "globoff", "head", "help", "include", "insecure",
|
|
646
|
+
"junk-session-cookies", "list-only", "location", "manual", "netrc", "next", "no-buffer", "parallel",
|
|
647
|
+
"proxytunnel", "remote-header-name", "remote-name", "remote-time", "show-error", "silent",
|
|
648
|
+
"use-ascii", "verbose", "version",
|
|
649
|
+
],
|
|
650
|
+
},
|
|
651
|
+
};
|
|
652
|
+
function readVerbOptionSlot(name, tok) {
|
|
653
|
+
const row = VERB_OPTION_SLOTS[name];
|
|
654
|
+
if (row === undefined)
|
|
655
|
+
return undefined;
|
|
656
|
+
if (!tok.startsWith("-") || tok === "-" || tok === "--")
|
|
657
|
+
return { form: "unexplained" };
|
|
658
|
+
if (tok.startsWith("--")) {
|
|
659
|
+
const long = longOptionNameOf(tok);
|
|
660
|
+
if (long === undefined)
|
|
661
|
+
return { form: "unexplained" };
|
|
662
|
+
const eq = tok.indexOf("=");
|
|
663
|
+
const attached = eq >= 0 ? tok.slice(eq + 1) : undefined;
|
|
664
|
+
const withValue = (kind) => attached !== undefined ? { form: "attached", value: attached, kind } : { form: "separated", kind };
|
|
665
|
+
const exact = row.longValue[long];
|
|
666
|
+
if (exact !== undefined)
|
|
667
|
+
return withValue(exact);
|
|
668
|
+
const exactOptional = row.longOptionalValue[long];
|
|
669
|
+
if (exactOptional !== undefined)
|
|
670
|
+
return attached !== undefined ? { form: "attached", value: attached, kind: exactOptional } : { form: "no-value" };
|
|
671
|
+
if (row.longPlain.includes(long))
|
|
672
|
+
return attached === undefined ? { form: "no-value" } : { form: "unexplained" };
|
|
673
|
+
const valueNames = [
|
|
674
|
+
...Object.keys(row.longValue),
|
|
675
|
+
...(attached !== undefined ? Object.keys(row.longOptionalValue) : []),
|
|
676
|
+
].filter((full) => isLongOptionAbbrevOf(long, full));
|
|
677
|
+
const plainNames = [
|
|
678
|
+
...row.longPlain,
|
|
679
|
+
...(attached === undefined ? Object.keys(row.longOptionalValue) : []),
|
|
680
|
+
].filter((full) => isLongOptionAbbrevOf(long, full));
|
|
681
|
+
if (valueNames.length === 0)
|
|
682
|
+
return plainNames.length > 0 && attached === undefined ? { form: "no-value" } : { form: "unexplained" };
|
|
683
|
+
const kinds = new Set(valueNames.map((full) => (row.longValue[full] ?? row.longOptionalValue[full])));
|
|
684
|
+
if (attached !== undefined)
|
|
685
|
+
return { form: "attached", value: attached, kind: widestValueKind(kinds) };
|
|
686
|
+
if (plainNames.length > 0 || kinds.size !== 1)
|
|
687
|
+
return { form: "unexplained" };
|
|
688
|
+
return withValue([...kinds][0]);
|
|
689
|
+
}
|
|
690
|
+
for (let i = 1; i < tok.length; i++) {
|
|
691
|
+
const ch = tok[i];
|
|
692
|
+
const kind = row.shortValue[ch];
|
|
693
|
+
if (kind !== undefined) {
|
|
694
|
+
const rest = tok.slice(i + 1);
|
|
695
|
+
return rest !== "" ? { form: "attached", value: rest, kind } : { form: "separated", kind };
|
|
696
|
+
}
|
|
697
|
+
if (!row.shortPlain.includes(ch))
|
|
698
|
+
return { form: "unexplained" };
|
|
699
|
+
}
|
|
700
|
+
return { form: "no-value" };
|
|
701
|
+
}
|
|
702
|
+
function localFileUrlPath(value) {
|
|
703
|
+
const m = /^file:(?:\/\/[^/?#]*)?(\/[^?#]*)/i.exec(value.trim());
|
|
704
|
+
if (m === null)
|
|
705
|
+
return undefined;
|
|
706
|
+
const raw = m[1];
|
|
707
|
+
try {
|
|
708
|
+
return decodeURIComponent(raw);
|
|
709
|
+
}
|
|
710
|
+
catch {
|
|
711
|
+
return raw;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
function formSpecFileNames(value) {
|
|
715
|
+
const out = [];
|
|
716
|
+
const after = (s) => {
|
|
717
|
+
const at = s.search(/[@<]/);
|
|
718
|
+
if (at !== -1 && at < s.length - 1)
|
|
719
|
+
out.push(s.slice(at + 1));
|
|
720
|
+
};
|
|
721
|
+
after(value);
|
|
722
|
+
for (const part of value.split(/[;,]/))
|
|
723
|
+
after(part);
|
|
724
|
+
return [...new Set(out)];
|
|
725
|
+
}
|
|
726
|
+
function slotValueCandidates(value, kind) {
|
|
727
|
+
if (!valueNamesAFile(kind))
|
|
728
|
+
return [];
|
|
729
|
+
if (kind === "url") {
|
|
730
|
+
const local = localFileUrlPath(value);
|
|
731
|
+
return local !== undefined ? [local] : [];
|
|
732
|
+
}
|
|
733
|
+
if (kind === "form")
|
|
734
|
+
return formSpecFileNames(value).map(literalTildeSpelling);
|
|
735
|
+
const named = value.startsWith("@") && value.length > 1 ? literalTildeSpelling(value.slice(1)) : undefined;
|
|
736
|
+
if (kind === "header")
|
|
737
|
+
return named !== undefined ? [value, named] : [];
|
|
738
|
+
const out = [value];
|
|
739
|
+
if (kind === "indirect" && named !== undefined)
|
|
740
|
+
out.push(named);
|
|
741
|
+
return out;
|
|
742
|
+
}
|
|
475
743
|
const SEPARATED_VALUE_OPTIONS = {
|
|
476
744
|
head: { short: "cn", long: ["bytes", "lines"] },
|
|
477
745
|
tail: { short: "cns", long: ["bytes", "lines", "sleep-interval", "pid", "max-unchanged-stats"] },
|
|
@@ -1248,17 +1516,6 @@ function isGrepFileStdinLongOption(tok) {
|
|
|
1248
1516
|
return name !== undefined && isLongOptionAbbrevOf(name, "file");
|
|
1249
1517
|
}
|
|
1250
1518
|
const CLUSTER_OPTION_CHAR = /[A-Za-z0-9]/;
|
|
1251
|
-
function grepClusterValueOwner(tok) {
|
|
1252
|
-
if (!tok.startsWith("-") || tok.startsWith("--") || !CLUSTER_OPTION_CHAR.test(tok[1] ?? ""))
|
|
1253
|
-
return undefined;
|
|
1254
|
-
for (const ch of tok.slice(1)) {
|
|
1255
|
-
if (ch === "e" || ch === "f")
|
|
1256
|
-
return ch;
|
|
1257
|
-
if (!CLUSTER_OPTION_CHAR.test(ch))
|
|
1258
|
-
return undefined;
|
|
1259
|
-
}
|
|
1260
|
-
return undefined;
|
|
1261
|
-
}
|
|
1262
1519
|
function attachedOptionPayloads(tok) {
|
|
1263
1520
|
const literal = literalTildeSpelling;
|
|
1264
1521
|
const out = [];
|
|
@@ -1282,6 +1539,7 @@ function attachedOptionPayloads(tok) {
|
|
|
1282
1539
|
}
|
|
1283
1540
|
function collectSegmentBoundaryFindings(tokens, boundary) {
|
|
1284
1541
|
const name = tokens.folded[0];
|
|
1542
|
+
const slotVerb = tokens.slotVerb ?? name;
|
|
1285
1543
|
if (NO_PATH_OPERAND_COMMANDS.has(name))
|
|
1286
1544
|
return [];
|
|
1287
1545
|
const args = tokens.folded.slice(1);
|
|
@@ -1328,6 +1586,8 @@ function collectSegmentBoundaryFindings(tokens, boundary) {
|
|
|
1328
1586
|
const eoo = args.indexOf("--");
|
|
1329
1587
|
const patternSuppliedByFlag = name === "grep" && (eoo === -1 ? args : args.slice(0, eoo)).some(isGrepPatternFlagToken);
|
|
1330
1588
|
let sawOperand = false;
|
|
1589
|
+
const argvOperandsStartAt = tokens.slotVerb !== undefined ? 1 : 0;
|
|
1590
|
+
let sawArgvOperand = false;
|
|
1331
1591
|
let endOfOptions = false;
|
|
1332
1592
|
for (let k = 0; k < args.length; k++) {
|
|
1333
1593
|
const t = args[k];
|
|
@@ -1338,15 +1598,35 @@ function collectSegmentBoundaryFindings(tokens, boundary) {
|
|
|
1338
1598
|
endOfOptions = true;
|
|
1339
1599
|
continue;
|
|
1340
1600
|
}
|
|
1341
|
-
if (name === "cut" && (t === "-d" || t === "--delimiter" || t === "--output-delimiter")) {
|
|
1342
|
-
k++;
|
|
1343
|
-
continue;
|
|
1344
|
-
}
|
|
1345
|
-
if (name === "cut" && (/^-d./.test(t) || isCutDelimiterPayloadLongOption(t)))
|
|
1346
|
-
continue;
|
|
1347
|
-
if (name === "grep" && (grepClusterValueOwner(t) === "e" || isGrepPatternPayloadLongOption(t)))
|
|
1348
|
-
continue;
|
|
1349
1601
|
if (t.startsWith("-") && t !== "-") {
|
|
1602
|
+
const slot = readVerbOptionSlot(slotVerb, t);
|
|
1603
|
+
if (sawArgvOperand) {
|
|
1604
|
+
judgeOperand(t, argGlobs(k));
|
|
1605
|
+
if (slot !== undefined && slot.form === "separated") {
|
|
1606
|
+
const ahead = args[k + 1];
|
|
1607
|
+
if (ahead !== undefined && !expandingArgs.has(k + 1)) {
|
|
1608
|
+
for (const c of slotValueCandidates(ahead, slot.kind))
|
|
1609
|
+
judgeOperand(c, argGlobs(k + 1));
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
if (slot !== undefined && slot.form !== "unexplained" && !(slot.form === "separated" && sawArgvOperand)) {
|
|
1614
|
+
if (slot.form === "attached") {
|
|
1615
|
+
for (const c of slotValueCandidates(literalTildeSpelling(slot.value), slot.kind))
|
|
1616
|
+
judgeOperand(c, argGlobs(k));
|
|
1617
|
+
}
|
|
1618
|
+
else if (slot.form === "separated") {
|
|
1619
|
+
const value = args[++k];
|
|
1620
|
+
if (value !== undefined && !expandingArgs.has(k)) {
|
|
1621
|
+
const named = slotValueCandidates(value, slot.kind);
|
|
1622
|
+
for (const c of named)
|
|
1623
|
+
judgeOperand(c, argGlobs(k));
|
|
1624
|
+
if (named.length > 0)
|
|
1625
|
+
positionalOperands.push(value);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
continue;
|
|
1629
|
+
}
|
|
1350
1630
|
for (const payload of attachedOptionPayloads(t))
|
|
1351
1631
|
judgeOperand(payload, argGlobs(k));
|
|
1352
1632
|
continue;
|
|
@@ -1354,6 +1634,8 @@ function collectSegmentBoundaryFindings(tokens, boundary) {
|
|
|
1354
1634
|
}
|
|
1355
1635
|
const isGrepPatternSlot = name === "grep" && !patternSuppliedByFlag && !sawOperand;
|
|
1356
1636
|
sawOperand = true;
|
|
1637
|
+
if (k >= argvOperandsStartAt)
|
|
1638
|
+
sawArgvOperand = true;
|
|
1357
1639
|
if (t === "-") {
|
|
1358
1640
|
if (isGrepPatternSlot)
|
|
1359
1641
|
continue;
|
|
@@ -1584,7 +1866,7 @@ export function classifyCompoundReadonlyDetailed(command, allow, boundary, opts)
|
|
|
1584
1866
|
const unlisted = tokenizeSegment(segments[si]);
|
|
1585
1867
|
if (unlisted.folded.length === 0)
|
|
1586
1868
|
continue;
|
|
1587
|
-
foldedSegments.push({ folded: [LAUNCHER_SCAN_HEAD, ...unlisted.folded], raw: [LAUNCHER_SCAN_HEAD, ...unlisted.raw] });
|
|
1869
|
+
foldedSegments.push({ folded: [LAUNCHER_SCAN_HEAD, ...unlisted.folded], raw: [LAUNCHER_SCAN_HEAD, ...unlisted.raw], slotVerb: programBasename(unlisted.folded[0]) });
|
|
1588
1870
|
pushReach();
|
|
1589
1871
|
continue;
|
|
1590
1872
|
}
|
|
@@ -1734,7 +2016,7 @@ function evaluateReadBoundary(foldedSegments, boundary, mintGrantCandidate, reac
|
|
|
1734
2016
|
if (si > 0 && reach?.[si]?.andJoined !== true)
|
|
1735
2017
|
andRunStart = reach?.[si]?.orBroken === true ? si + 1 : si;
|
|
1736
2018
|
const reachable = candidates.filter((c) => c.skippedCd < andRunStart);
|
|
1737
|
-
const row = findingsRowFor(JSON.stringify([toks.folded, toks.raw]));
|
|
2019
|
+
const row = findingsRowFor(JSON.stringify([toks.folded, toks.raw, toks.slotVerb]));
|
|
1738
2020
|
for (const { base: currentBase } of reachable) {
|
|
1739
2021
|
for (const finding of findingsFor(row, toks, currentBase)) {
|
|
1740
2022
|
if (finding.kind === "unresolvable") {
|
|
@@ -1929,7 +2211,7 @@ export function classifyOutOfRootReadGate(command, allow, boundary) {
|
|
|
1929
2211
|
if (UNMODELLED_BASE_MOVERS.has(name))
|
|
1930
2212
|
baseMoved = true;
|
|
1931
2213
|
if (!allow.has(name) && name !== "cd") {
|
|
1932
|
-
pushReader({ folded: [LAUNCHER_SCAN_HEAD, ...toks.folded.slice(i)], raw: [LAUNCHER_SCAN_HEAD, ...toks.raw.slice(i)] });
|
|
2214
|
+
pushReader({ folded: [LAUNCHER_SCAN_HEAD, ...toks.folded.slice(i)], raw: [LAUNCHER_SCAN_HEAD, ...toks.raw.slice(i)], slotVerb: name });
|
|
1933
2215
|
continue;
|
|
1934
2216
|
}
|
|
1935
2217
|
pushReader(i === 0 && name === written ? toks : { folded: [name, ...toks.folded.slice(i + 1)], raw: [toks.raw[i] ?? name, ...toks.raw.slice(i + 1)] });
|
|
@@ -100,7 +100,7 @@ export declare function bashReversibilityProbe(allow?: readonly string[], bounda
|
|
|
100
100
|
* add a mandate to an ask, never originate one). The poll-loop face's structured verdict
|
|
101
101
|
* ({@link classifyBoundedReadonlyPollLoopDetailed}) is read the same three ways as the compound face's.
|
|
102
102
|
*
|
|
103
|
-
* The reader set is the engine's classify set ({@link
|
|
103
|
+
* The reader set is the engine's classify set ({@link bashClassifyDefaultAllow}) — here it is NOT an
|
|
104
104
|
* auto-allow list but the set of programs whose operands the faces read; a wider set means more reads are
|
|
105
105
|
* judged, never that more runs are vouched.
|
|
106
106
|
*
|