@sema-agent/core 5.56.0 → 5.58.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 +122 -0
- package/dist/agents/cascade.d.ts +1 -1
- package/dist/agents/cumulative-stats.d.ts +1 -1
- package/dist/agents/observer.d.ts +2 -2
- package/dist/agents/peer-admission.d.ts +1 -1
- package/dist/agents/retain-ledger.d.ts +2 -2
- package/dist/agents/roster-store.d.ts +8 -8
- package/dist/agents/send-message-tool.d.ts +13 -2
- package/dist/agents/send-message-tool.js +34 -12
- package/dist/agents/subagent-steps.d.ts +1 -1
- package/dist/agents/subagent.d.ts +13 -13
- package/dist/agents/team.d.ts +15 -6
- package/dist/agents/team.js +1 -0
- package/dist/agents/tool-filter.d.ts +2 -2
- package/dist/agents/verify.d.ts +1 -1
- package/dist/bench/metrics.d.ts +35 -35
- package/dist/brain/anthropic.js +15 -5
- package/dist/brain/circuit-breaker.js +2 -1
- package/dist/brain/degrading.d.ts +1 -1
- package/dist/brain/degrading.js +4 -1
- package/dist/brain/errors.d.ts +3 -3
- package/dist/brain/failover.js +16 -1
- package/dist/brain/open-responses.js +15 -5
- package/dist/brain/openai.js +16 -5
- package/dist/brain/reasoning.d.ts +2 -2
- package/dist/brain/repetition.d.ts +1 -1
- package/dist/brain/request-params.d.ts +30 -27
- package/dist/brain/request-params.js +1 -7
- package/dist/brain/route-adjudicator.d.ts +190 -0
- package/dist/brain/route-adjudicator.js +189 -0
- package/dist/brain/route-conformance.d.ts +55 -0
- package/dist/brain/route-conformance.js +136 -0
- package/dist/brain/routing.js +8 -3
- package/dist/brain/status-sink.d.ts +2 -2
- package/dist/brain/stream-shared.d.ts +1 -1
- package/dist/config/catalog.d.ts +5 -5
- package/dist/core/arg-summary.d.ts +4 -4
- package/dist/core/ask-class.d.ts +2 -2
- package/dist/core/ask-question.d.ts +1 -1
- package/dist/core/auto-compaction.d.ts +15 -15
- package/dist/core/auto-mode.d.ts +5 -5
- package/dist/core/background-agent-store.d.ts +20 -20
- package/dist/core/background-shell.d.ts +4 -4
- package/dist/core/checkpoint-store.d.ts +35 -27
- package/dist/core/context-edit.d.ts +1 -1
- package/dist/core/context-guard.d.ts +1 -1
- package/dist/core/exec-output-tail.d.ts +6 -6
- package/dist/core/file-snapshot-store.d.ts +8 -8
- package/dist/core/git-worktree-env.d.ts +3 -3
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hooks.d.ts +73 -33
- package/dist/core/hooks.js +87 -25
- package/dist/core/image-downsample.d.ts +1 -1
- package/dist/core/locked-config.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mailbox-store.d.ts +1 -1
- package/dist/core/mcp.d.ts +3 -3
- package/dist/core/mcp.js +4 -4
- package/dist/core/memory-engine/consolidation-driver.d.ts +207 -0
- package/dist/core/memory-engine/consolidation-driver.js +378 -0
- package/dist/core/memory-engine/consolidation.d.ts +46 -2
- package/dist/core/memory-engine/consolidation.js +1 -0
- package/dist/core/memory-engine/data-plane.d.ts +1 -1
- package/dist/core/memory-engine/distiller.d.ts +550 -0
- package/dist/core/memory-engine/distiller.js +598 -0
- package/dist/core/memory-engine/dual-root.d.ts +1 -1
- package/dist/core/memory-engine/engine.d.ts +62 -8
- package/dist/core/memory-engine/engine.js +40 -4
- package/dist/core/memory-engine/file-backend.d.ts +1 -1
- package/dist/core/memory-engine/index.d.ts +4 -2
- package/dist/core/memory-engine/index.js +4 -2
- package/dist/core/memory-engine/origin-clearance.d.ts +1 -1
- package/dist/core/memory-engine/scope-contract.d.ts +4 -4
- package/dist/core/memory-engine/sync-client.d.ts +16 -16
- package/dist/core/memory-engine/sync.d.ts +4 -4
- package/dist/core/memory-recall.d.ts +1 -1
- package/dist/core/memory.d.ts +2 -2
- package/dist/core/permission-rule-consent.d.ts +230 -36
- package/dist/core/permission-rule-consent.js +258 -54
- package/dist/core/permission-rule-model.d.ts +295 -97
- package/dist/core/permission-rule-model.js +132 -41
- package/dist/core/permission-rules.d.ts +9 -9
- package/dist/core/remote-env.d.ts +8 -8
- package/dist/core/roles.d.ts +3 -3
- package/dist/core/roles.js +1 -0
- package/dist/core/runner/assemble-result.d.ts +2 -2
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/memory-consolidation-driver.d.ts +49 -0
- package/dist/core/runner/memory-consolidation-driver.js +60 -0
- package/dist/core/runner/memory-consolidation.d.ts +1 -1
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-task.d.ts +21 -21
- package/dist/core/runner/prepare-task.js +54 -18
- package/dist/core/runner/prepare-workspace-restore.d.ts +2 -2
- package/dist/core/runner/runtask.d.ts +15 -12
- package/dist/core/runner/runtask.js +48 -0
- package/dist/core/runner/session-rule-policy.d.ts +1 -1
- package/dist/core/runner/teardown-bounded.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.d.ts +2 -2
- package/dist/core/runner/turn-attachments.d.ts +11 -11
- package/dist/core/scheduler.d.ts +10 -5
- package/dist/core/secret-env.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/session-policy-store.d.ts +2 -2
- package/dist/core/session-reconcile.d.ts +2 -2
- package/dist/core/session-store.d.ts +3 -3
- package/dist/core/session.d.ts +1 -1
- package/dist/core/shutdown-debug.d.ts +2 -2
- package/dist/core/side-query.d.ts +14 -7
- package/dist/core/spec-contract.d.ts +1 -1
- package/dist/core/store-contracts/contract-harness.d.ts +2 -2
- package/dist/core/store-contracts/contract-kit-version.d.ts +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +1 -1
- package/dist/core/store-contracts/mailbox-store-contract.js +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +12 -12
- package/dist/core/task-registry-monitor.d.ts +1 -1
- package/dist/core/task-registry-shared.d.ts +41 -41
- package/dist/core/task-registry.d.ts +12 -12
- package/dist/core/tool-detach.d.ts +2 -2
- package/dist/core/tool-errors.d.ts +3 -3
- package/dist/core/tool-policy.d.ts +55 -28
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +2 -2
- package/dist/core/tools.d.ts +1 -1
- package/dist/core/trace.d.ts +26 -23
- package/dist/core/types.d.ts +155 -70
- package/dist/core/untrusted-egress.d.ts +1 -1
- package/dist/core/untrusted-text.d.ts +7 -7
- package/dist/core/wiring-manifest.d.ts +5 -5
- package/dist/core/workflow-journal-store.d.ts +14 -14
- package/dist/core/workflow-run-store-contract.d.ts +1 -1
- package/dist/core/workflow-run-store-contract.js +1 -1
- package/dist/core/workflow-run-store.d.ts +4 -4
- package/dist/engine/compaction/compaction.d.ts +3 -3
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/execution-env/kill-tree.d.ts +1 -1
- package/dist/engine/execution-env/node-execution-env.d.ts +8 -8
- package/dist/engine/harness/agent-harness.d.ts +6 -6
- package/dist/engine/harness/agent-harness.js +26 -1
- package/dist/engine/harness/messages.d.ts +1 -1
- package/dist/engine/harness/types.d.ts +15 -11
- package/dist/engine/llm/types.d.ts +79 -14
- package/dist/engine/loop/agent-loop.d.ts +3 -3
- package/dist/engine/loop/types.d.ts +4 -4
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
- package/dist/engine/session/import-validate.d.ts +1 -1
- package/dist/engine/session/log-digest.d.ts +1 -1
- package/dist/engine/session/memory-repo.d.ts +2 -2
- package/dist/engine/session/session.d.ts +4 -4
- package/dist/fixtures/index.d.ts +4 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +5 -2
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/goal.d.ts +1 -1
- package/dist/orchestration/run-spec.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +12 -12
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-observe.d.ts +1 -1
- package/dist/orchestration/workflow-script-runner.d.ts +1 -1
- package/dist/orchestration/workflow-script-store.d.ts +9 -9
- package/dist/orchestration/workflow-size-guideline.d.ts +1 -1
- package/dist/orchestration/workflow-types.d.ts +5 -5
- package/dist/orchestration/workflow.d.ts +10 -10
- package/dist/prompt-assembly/artifact-store.d.ts +1 -1
- package/dist/prompt-assembly/artifact.d.ts +1 -1
- package/dist/prompt-assembly/assemble.d.ts +1 -1
- package/dist/prompt-assembly/composer.d.ts +2 -2
- package/dist/prompt-assembly/epoch.d.ts +2 -2
- package/dist/prompt-assembly/event-registry.d.ts +1 -1
- package/dist/prompt-assembly/explain.d.ts +3 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +1 -1
- package/dist/prompt-assembly/turn-snapshot.d.ts +4 -4
- package/dist/prompt-assembly/types.d.ts +12 -12
- package/dist/prompts/coordinator.d.ts +1 -1
- package/dist/prompts/default.d.ts +10 -10
- package/dist/prompts/default.js +2 -0
- package/dist/prompts/simple-sections.d.ts +3 -3
- package/dist/prompts/supervisor.d.ts +2 -2
- package/dist/scenarios/full-body.d.ts +3 -3
- package/dist/scenarios/scenario-registry.d.ts +6 -2
- package/dist/scenarios/scenario-registry.js +4 -2
- package/dist/stores/cc/sidecar-transcript.d.ts +3 -3
- package/dist/stores/file/fs-atomic.d.ts +2 -2
- package/dist/stores/file/index.d.ts +1 -1
- package/dist/stores/file/session-store.d.ts +2 -2
- package/dist/stores/file/workflow-journal-store.d.ts +4 -4
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/encoding.d.ts +4 -4
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-pdf.d.ts +1 -1
- package/dist/tools/fs/fs-shared.d.ts +6 -6
- package/dist/tools/fs/index.d.ts +2 -2
- package/dist/tools/fs/index.js +8 -1
- package/dist/tools/fs/notebook.d.ts +1 -1
- package/dist/tools/fs/pdf.d.ts +1 -1
- package/dist/tools/fs/read-deny.d.ts +1 -1
- package/dist/tools/fs/safety.d.ts +9 -9
- package/dist/tools/fs/search.d.ts +2 -2
- package/dist/tools/monitor.d.ts +3 -3
- package/dist/tools/scheduler-tools.js +28 -6
- package/dist/tools/task-list.d.ts +2 -2
- package/dist/tools/web.d.ts +19 -4
- package/dist/tools/web.js +8 -2
- package/dist/tools/worktree.d.ts +5 -5
- package/dist/tools/worktree.js +2 -2
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +74 -3
|
@@ -16,15 +16,27 @@
|
|
|
16
16
|
* write gate not covering the shell tool, stripping would turn a rule as innocuous as `Bash(ls)` into a
|
|
17
17
|
* licence for `ls > ~/.ssh/authorized_keys`).
|
|
18
18
|
*
|
|
19
|
-
* CONNECTORS are the one construct the lane does speak for,
|
|
20
|
-
* build && ./gradlew test` is one thing a person reads
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
19
|
+
* CONNECTORS are the one construct the lane does speak for, in two forms. The EXACT form spells a
|
|
20
|
+
* whole chain and admits exactly it: `./gradlew build && ./gradlew test` is one thing a person reads
|
|
21
|
+
* and approves in one glance, and nothing is admitted that the rule text does not spell out end to
|
|
22
|
+
* end. The COMPOUND-PREFIX form (`Bash(cd /tmp && adb pull:*)`) widens that by ONE seam and no other:
|
|
23
|
+
* every leading segment — connectors included — is matched byte-for-byte like an exact rule, and only
|
|
24
|
+
* the FINAL segment takes appended arguments, so the rule text still reads as the concrete combination
|
|
25
|
+
* the person saw, with the last command's arguments free. A SINGLE-COMMAND prefix body stays
|
|
26
|
+
* single-command on the match side (`Bash(npm:*)` does not admit `npm test && curl evil.example`) —
|
|
27
|
+
* the matcher requires the command to read as exactly as many segments as the rule body names, which
|
|
28
|
+
* is that historical line and the compound form's own containment in one predicate. The compound-prefix
|
|
29
|
+
* rule TEXT is a registered divergence from upstream, which has no compound rule form at all: upstream
|
|
30
|
+
* reaches compound coverage through a per-segment evaluation of its full decision chain, where a
|
|
31
|
+
* segment DENY is returned strictly before any whole-string allow; this lane's equivalent is that the
|
|
32
|
+
* deny/ask layer (`permission-rule-org.ts`) judges every segment and runs ahead of the allow lane at
|
|
33
|
+
* the gate — a compound-prefix allow can therefore never outrun a deny on any segment it admits.
|
|
34
|
+
*
|
|
35
|
+
* design/375 adds upstream's OTHER half of that per-segment evaluation on the allow side: a compound
|
|
36
|
+
* whose EVERY segment is admitted by some eligible rule is covered by the CONJUNCTION of those rules
|
|
37
|
+
* (`findAdmittingRule` answers with the coverage SET). No single rule widens: the matcher predicates
|
|
38
|
+
* above are untouched, and the set form is the decision layer's answer, fenced by the same
|
|
39
|
+
* ahead-running per-segment deny/ask layer.
|
|
28
40
|
*
|
|
29
41
|
* The floor is `parseLeadingCommandName` + `splitShellCompoundSegments` — the one simple-command parser
|
|
30
42
|
* and the one segmentation, both already shared with the read-only classifier, the reversibility probe,
|
|
@@ -92,7 +104,9 @@ export interface RuleAdd {
|
|
|
92
104
|
* Organization rules have the opposite polarity (deny/ask only) and never enter this type.
|
|
93
105
|
*/
|
|
94
106
|
export interface PersistedAllowRule {
|
|
95
|
-
/** Canonical rule text: `Bash(git status)` (exact) or `Bash(git status:*)` (prefix).
|
|
107
|
+
/** Canonical rule text: `Bash(git status)` (exact) or `Bash(git status:*)` (prefix). A prefix body
|
|
108
|
+
* may itself be a connector chain (`Bash(cd /tmp && adb pull:*)`) — see the module note on
|
|
109
|
+
* connectors for what such a rule reaches. */
|
|
96
110
|
rule: string;
|
|
97
111
|
tool: PersistedRuleTool;
|
|
98
112
|
match: PersistedRuleMatch;
|
|
@@ -145,6 +159,16 @@ export declare const MAX_RULE_TEXT_CHARS = 512;
|
|
|
145
159
|
* `python manage.py migrate:*` (which an import reports as skipped rather than dropping silently), and
|
|
146
160
|
* an EXACT rule naming a whole interpreter command line stays legal, since it authorizes one command.
|
|
147
161
|
*
|
|
162
|
+
* TWO READERS, and they consult this table with DIFFERENT questions — do not read either as the other.
|
|
163
|
+
* {@link parseAllowRuleText} asks "is this rule TEXT's own head a row?" and compares the basename as
|
|
164
|
+
* SPELLED, so an alias spelling (`SSH host:*`, `ssh.exe host:*`) is a different name to it and enters
|
|
165
|
+
* the store like any other rule. {@link genericPrefixBody} asks "should the engine PROPOSE a body with
|
|
166
|
+
* this head?" and normalizes first ({@link screenedHeadName}: case, trailing periods, executable
|
|
167
|
+
* suffix), because a proposal is the engine's own act and must not hand a person an alias of a row.
|
|
168
|
+
* The asymmetry is deliberate — normalizing at the validator would also refuse rule texts already
|
|
169
|
+
* stored, imported or hand-authored — and it is the reason the residual paragraph below is about this
|
|
170
|
+
* table's reach rather than about either reader.
|
|
171
|
+
*
|
|
148
172
|
* TWO groups, and the distinction matters when the table is next edited:
|
|
149
173
|
* · LANGUAGE interpreters (`node`, `python`, `ruby`, …) — the argument IS a program. This half is
|
|
150
174
|
* wider than upstream's own set, deliberately, and is the argument the paragraph above makes.
|
|
@@ -197,50 +221,49 @@ export declare const BARE_INTERPRETER_NAMES: ReadonlySet<string>;
|
|
|
197
221
|
*/
|
|
198
222
|
export declare const SHELL_RESERVED_WORDS: ReadonlySet<string>;
|
|
199
223
|
/**
|
|
200
|
-
* design/185 §1 — the
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* the
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* loosening; the other against a person being misled.
|
|
224
|
+
* design/185 §1 — the DEEPER-THAN-TWO-WORDS half of the prefix suggestion grammar.
|
|
225
|
+
*
|
|
226
|
+
* The prefix candidate itself is produced by {@link genericPrefixBody}: a general two-word rule that
|
|
227
|
+
* covers every command whose second token reads as a subcommand. This table exists for the one thing
|
|
228
|
+
* that rule cannot express — a body DEEPER than two words — so every row here makes a suggestion
|
|
229
|
+
* NARROWER than it would otherwise be, and never wider.
|
|
230
|
+
*
|
|
231
|
+
* A flat set of BODIES — word sequences, each at least THREE words. A body takes the seat iff it is a
|
|
232
|
+
* word-boundary prefix of the command's folded form, and the LONGEST hit wins; with no hit the
|
|
233
|
+
* two-word generic body is used, and with neither there is no prefix candidate at all.
|
|
234
|
+
*
|
|
235
|
+
* Review criterion, one axis, and it is a PRECISION axis rather than a safety one: list a deeper body
|
|
236
|
+
* when the two-word form names a NAMESPACE rather than an action. `gh pr`, `kubectl rollout`,
|
|
237
|
+
* `docker compose`, `git stash`, `go mod`, `git submodule` and `yarn workspaces` are families of
|
|
238
|
+
* verbs, and the verb is what a person reads as the thing they are approving. Listing a row costs
|
|
239
|
+
* nothing and narrows one family; NOT listing one is not a refusal, since the generic two-word body
|
|
240
|
+
* still fills the seat.
|
|
241
|
+
*
|
|
242
|
+
* WHAT THIS TABLE NO LONGER DOES, stated because two review axes used to live here and their removal
|
|
243
|
+
* is a WIDENING no reader should have to reconstruct. Rows were once gated on "runs what it is told
|
|
244
|
+
* to" (`docker run`, `npm exec`, `cargo install`, `gh extension`) and on "rewrites what others
|
|
245
|
+
* execute" (`git config`, `kubectl config`, `npm config`, `go env`), and a head outside the table
|
|
246
|
+
* produced NO prefix at all. Under the generic rule those bodies are produced like any other, which
|
|
247
|
+
* is upstream's own behaviour and the adjudicated form: a positive table of two-word bodies cannot
|
|
248
|
+
* cover the long tail of real CLIs, and the price of its closure was saying nothing at all for
|
|
249
|
+
* everything outside nine families — the field report that drove this change was every `adb`,
|
|
250
|
+
* `gradle` and `terraform` invocation asking forever, with an exact rule for one full command line as
|
|
251
|
+
* the only offer and no reuse the moment an argument changed.
|
|
252
|
+
*
|
|
253
|
+
* What carries that residue is therefore NOT this table, and never was — it is the three standing
|
|
254
|
+
* fences: the org deny/ask layer runs ahead of the rule lane and cannot be silenced by it; a mandated
|
|
255
|
+
* ask (egress/irreversibility marks, shellGate:"always") is not rule-clearable either; and the
|
|
256
|
+
* narrower exact candidate — plus minting no rule at all — is always on the same card. A prefix rule
|
|
257
|
+
* also still admits ANY arguments after its body and never a second command, which is the property
|
|
258
|
+
* that makes a body's width readable off its text.
|
|
259
|
+
*
|
|
260
|
+
* Maintenance: adding a row is a one-line narrowing of one family. The integrity pins (every body
|
|
261
|
+
* ≥ 3 words, lowercase word shape, no interpreter heads, no duplicates) are enforced by this module's
|
|
262
|
+
* test suite. This table and the read-only classifier's allowlists are DIFFERENT instruments and must
|
|
263
|
+
* never be merged or cross-referenced: that one is a machine auto-allow face whose criterion is
|
|
264
|
+
* "provably read-only"; this one is a human suggestion face whose criterion is "width a person can
|
|
265
|
+
* read off the rule text". One guards against a machine loosening; the other against a person being
|
|
266
|
+
* misled.
|
|
244
267
|
*/
|
|
245
268
|
export declare const SUGGESTION_LEXICON: readonly string[];
|
|
246
269
|
/**
|
|
@@ -259,6 +282,16 @@ export declare const SUGGESTION_LEXICON: readonly string[];
|
|
|
259
282
|
* through, so an ordinary rule text reads normally. The result is length-bounded.
|
|
260
283
|
*/
|
|
261
284
|
export declare function escapeForDisclosure(value: unknown): string;
|
|
285
|
+
/**
|
|
286
|
+
* Does this text carry a character of the class {@link escapeForDisclosure} exists for — the class
|
|
287
|
+
* {@link CONTROL_CHARS_RE} names? Asked by a caller that must REFUSE such a value rather than render
|
|
288
|
+
* it: the two answers to "these bytes cannot honestly ride a display line" are escape it or do not
|
|
289
|
+
* take it, and a call site with nothing to display picks the second. Reads the same source regex as
|
|
290
|
+
* the escape pass, so the screen and the escape cannot drift into two character classes.
|
|
291
|
+
*
|
|
292
|
+
* Not part of the package's public surface — an internal screen for lane entry points.
|
|
293
|
+
*/
|
|
294
|
+
export declare function hasUnrenderableCharacters(text: string): boolean;
|
|
262
295
|
/**
|
|
263
296
|
* Parse one rule text into its canonical shape, or refuse it with a reason.
|
|
264
297
|
*
|
|
@@ -288,12 +321,15 @@ export declare function formatAllowRuleText(command: string, match: PersistedRul
|
|
|
288
321
|
* caller can match a command this lane has not read. Returns false for every redirection, substitution,
|
|
289
322
|
* subshell, backgrounded or escaped form.
|
|
290
323
|
*
|
|
291
|
-
* **A
|
|
292
|
-
* widening, and it is checked on the MATCH side rather than left to
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
324
|
+
* **A prefix rule reaches past its body only inside its FINAL segment.** This is the single
|
|
325
|
+
* load-bearing line of the connector widening, and it is checked on the MATCH side rather than left to
|
|
326
|
+
* the mint side: the command must read as exactly as many segments as the rule's own body. For the
|
|
327
|
+
* single-command body that is the historical contract verbatim — `Bash(npm:*)` is an ordinary,
|
|
328
|
+
* legitimately mintable rule, and if the "does this command start with `npm `" arm were allowed to see
|
|
329
|
+
* a compound at all, that rule would admit `npm test && curl evil.example` — one stored yes to a build
|
|
330
|
+
* command turned into a standing yes to whatever is chained behind it. For a compound-prefix body the
|
|
331
|
+
* same count equality is the containment: `Bash(a && b:*)` admits `a && b x`, never `a && b x && c`.
|
|
332
|
+
* An EXACT rule has no such reach by construction: it admits one string, the one it spells.
|
|
297
333
|
*/
|
|
298
334
|
export declare function ruleAdmitsCommand(rule: Pick<PersistedAllowRule, "match" | "command">, command: string): boolean;
|
|
299
335
|
/**
|
|
@@ -337,50 +373,196 @@ export declare function scopeCoversCwd(scope: RuleScope, cwd: string | undefined
|
|
|
337
373
|
* when tombstones are applied, so a rule with an empty `adds` is a rule that no longer exists. */
|
|
338
374
|
export declare function isRuleLive(rule: PersistedAllowRule): boolean;
|
|
339
375
|
/**
|
|
340
|
-
*
|
|
376
|
+
* design/375 §5.1 — MAY this rule speak about this call's CONTEXT? Tool identity plus scope coverage,
|
|
377
|
+
* and nothing about the rule's liveness: the CONTEXT question is the half a not-yet-persisted rule (a
|
|
378
|
+
* card's proposed candidate, which has no add dots yet) can already answer.
|
|
341
379
|
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
380
|
+
* The tool conjunct is not decoration: more than one tool takes a shell command string, and matching on
|
|
381
|
+
* the command alone would let an approval given on one surface resolve a call on another. The scope
|
|
382
|
+
* conjunct is the project fence — project A's approval is not project B's, and a project rule with no
|
|
383
|
+
* cwd to compare against covers nothing (fail-closed, {@link scopeCoversCwd}).
|
|
384
|
+
*
|
|
385
|
+
* `scope` rides beside the rule rather than inside it for the PROPOSED half's sake: a
|
|
386
|
+
* {@link ParsedAllowRule} carries no scope, so a proposal is judged against the scope it would LAND in.
|
|
387
|
+
*/
|
|
388
|
+
export declare function eligibleContext(rule: {
|
|
389
|
+
tool: string;
|
|
390
|
+
scope: RuleScope;
|
|
391
|
+
}, call: {
|
|
392
|
+
tool: string;
|
|
393
|
+
cwd: string | undefined;
|
|
394
|
+
}): boolean;
|
|
395
|
+
/**
|
|
396
|
+
* design/375 §5.1 — MAY this PERSISTED rule participate in admitting this call at all? The liveness
|
|
397
|
+
* layer on top of {@link eligibleContext}: a tombstoned rule (zero surviving adds) is a rule that no
|
|
398
|
+
* longer exists and must not count as coverage anywhere.
|
|
399
|
+
*
|
|
400
|
+
* THE single eligibility predicate for every consumer that reads the persisted store — the gate's
|
|
401
|
+
* conjunction arm and its coverage-set selection here, the suggestion face's coverage judgement and the
|
|
402
|
+
* consent prepare's ({@link segmentCoverageOf} is the shared instrument). One predicate, so a rule that
|
|
403
|
+
* one consumer refuses cannot be a rule another counts: the historically inlined trio of checks
|
|
404
|
+
* (live / tool / scope) is this function, verbatim.
|
|
405
|
+
*/
|
|
406
|
+
export declare function eligiblePersisted(rule: PersistedAllowRule, call: {
|
|
407
|
+
tool: string;
|
|
408
|
+
cwd: string | undefined;
|
|
409
|
+
}): boolean;
|
|
410
|
+
/**
|
|
411
|
+
* Find the rules that admit this command for a task in `cwd`, or `undefined`.
|
|
412
|
+
*
|
|
413
|
+
* THE ANSWER IS A COVERAGE SET (design/375 §5.1, the upstream per-segment form): a single rule that
|
|
414
|
+
* admits the whole command is a one-element set — the historical arm, table order preserved verbatim —
|
|
415
|
+
* and a COMPOUND whose every segment is admitted by some eligible rule is covered by the CONJUNCTION of
|
|
416
|
+
* those rules, returned as the set that covered it. The judging ladder, in order:
|
|
417
|
+
* 1. the fail-closed floor (a shape the lane cannot read matches nothing), evaluated once;
|
|
418
|
+
* 2. the single-rule arm — whole-string exact, single/compound-prefix — exactly the historical loop:
|
|
419
|
+
* first table-order match wins and is what the decision names. A single rule naming the command is
|
|
420
|
+
* found BEFORE any conjunction: reporting one rule is narrower than reporting a set;
|
|
421
|
+
* 3. the conjunction arm, compounds only: every segment must be admitted by some eligible rule under
|
|
422
|
+
* the MATCH reading (the allow side's own under-approximating instrument — never the deny side's
|
|
423
|
+
* wider PROGRAM_RUNS reading). Per segment the FIRST table-order admitting rule is selected, and
|
|
424
|
+
* the coverage set is those selections in segment order, de-duplicated — the same command against
|
|
425
|
+
* the same rule table always names the same set (reporting-order determinism, the historical
|
|
426
|
+
* "order is defined only for reporting" contract extended to sets).
|
|
427
|
+
*
|
|
428
|
+
* What the conjunction arm deliberately does NOT change: {@link ruleAdmitsCommand} itself. A
|
|
429
|
+
* single-command prefix body still never admits a chain — `Bash(npm:*)` does not admit
|
|
430
|
+
* `npm test && curl evil.example` — but the chain is now admitted when EVERY segment has a standing
|
|
431
|
+
* yes, which is the upstream decision form (per-segment allow, any-segment deny decided strictly
|
|
432
|
+
* earlier at the gate's org layer). A trailing-terminator spelling (`a && b ;`) keeps the conservative
|
|
433
|
+
* answer by construction: under the MATCH reading its tail is an empty segment the floor refuses, so
|
|
434
|
+
* the whole command is outside the lane and asks.
|
|
435
|
+
*
|
|
436
|
+
* Order is defined only for reporting (what the decision names); no rule is stronger than another —
|
|
437
|
+
* they are all the same one answer, "the person already said yes to this".
|
|
345
438
|
*/
|
|
346
439
|
export declare function findAdmittingRule(rules: readonly PersistedAllowRule[], call: {
|
|
347
440
|
tool: string;
|
|
348
441
|
command: string;
|
|
349
442
|
cwd: string | undefined;
|
|
350
|
-
}): PersistedAllowRule | undefined;
|
|
351
|
-
/**
|
|
352
|
-
|
|
443
|
+
}): readonly PersistedAllowRule[] | undefined;
|
|
444
|
+
/**
|
|
445
|
+
* design/375 §5.2 — the per-segment coverage table for `command`: which segments an eligible rule
|
|
446
|
+
* already admits, judged with the SAME split, the same MATCH reading and the same eligibility
|
|
447
|
+
* predicates as the gate's conjunction arm — one instrument, so the suggestion face and the consent
|
|
448
|
+
* prepare can never call a segment covered that the gate would ask about (or vice versa).
|
|
449
|
+
*
|
|
450
|
+
* TWO SOURCES, two predicates, and the seat labels are the contract:
|
|
451
|
+
* · `persisted` — rules already in the store, judged {@link eligiblePersisted} ∧ admit: a tombstoned
|
|
452
|
+
* rule, another project's rule and another tool's rule are uniformly NOT coverage;
|
|
453
|
+
* · `proposed` — rules of the CURRENT batch that are not yet persisted (no add dots yet), judged
|
|
454
|
+
* {@link eligibleContext} ∧ admit against the scope each would land in. Judging these with the
|
|
455
|
+
* persisted predicate would make "this batch, once redeemed, covers the command" permanently false
|
|
456
|
+
* — the liveness layer is the one thing a proposal legitimately lacks.
|
|
457
|
+
*
|
|
458
|
+
* Returns `undefined` for a command the lane cannot read at all (the fail-closed floor — the caller's
|
|
459
|
+
* honest answer is then "no coverage table", which every consumer must treat as all-uncovered). The
|
|
460
|
+
* reported `segment` texts are the FOLDED spellings, trimmed — display/correlation seats, never
|
|
461
|
+
* adjudication inputs.
|
|
462
|
+
*/
|
|
463
|
+
export declare function segmentCoverageOf(command: string, rules: {
|
|
464
|
+
persisted: readonly PersistedAllowRule[];
|
|
465
|
+
proposed?: readonly {
|
|
466
|
+
rule: ParsedAllowRule;
|
|
467
|
+
scope: RuleScope;
|
|
468
|
+
}[];
|
|
469
|
+
}, call: {
|
|
470
|
+
tool: string;
|
|
471
|
+
cwd: string | undefined;
|
|
472
|
+
}): readonly SegmentCoverage[] | undefined;
|
|
473
|
+
/** One row of a per-segment coverage table (see {@link segmentCoverageOf}): the FOLDED, trimmed
|
|
474
|
+
* segment text (a display/correlation seat, never adjudication input) and whether an eligible rule
|
|
475
|
+
* already admits it. */
|
|
476
|
+
export interface SegmentCoverage {
|
|
477
|
+
readonly segment: string;
|
|
478
|
+
readonly covered: boolean;
|
|
479
|
+
}
|
|
480
|
+
/** One member of a {@link RuleOffer} batch: a rule the engine offers to mint for ONE segment of a
|
|
481
|
+
* compound command. `segment` is the FOLDED segment text the member was minted from — a rendering
|
|
482
|
+
* seat, never adjudication input. */
|
|
483
|
+
export interface SegmentRuleSuggestion {
|
|
353
484
|
/** The canonical rule text the host would redeem. */
|
|
354
|
-
rule: string;
|
|
355
|
-
match: PersistedRuleMatch;
|
|
485
|
+
readonly rule: string;
|
|
486
|
+
readonly match: PersistedRuleMatch;
|
|
356
487
|
/** The command pattern in the rule, for a host that wants to render it without re-parsing. */
|
|
357
|
-
command: string;
|
|
488
|
+
readonly command: string;
|
|
489
|
+
/** The (folded) segment this suggestion came from. Raw post-rewrite command bytes — a substring
|
|
490
|
+
* of the same call's `args`/`command` values riding beside it on every surface that carries
|
|
491
|
+
* this seat — so render it with contextual escaping, exactly like those. */
|
|
492
|
+
readonly segment: string;
|
|
358
493
|
}
|
|
359
494
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* `
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* `
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
495
|
+
* design/375 §3.1 — ONE "don't ask again" option on an approval card. A CLOSED discriminated union
|
|
496
|
+
* (`kind`); consumers parse it per element, and an element whose `kind` they do not know is dropped
|
|
497
|
+
* (single-row degrade) while keeping the ORIGINAL wire index for every element they keep — selection
|
|
498
|
+
* and redemption are keyed on original indices, so a consumer that cannot preserve the mapping must
|
|
499
|
+
* suppress its persistence actions entirely (fail toward asking).
|
|
500
|
+
*
|
|
501
|
+
* · `kind: "single"` — one rule covering the WHOLE command (the exact spelling, or a broader
|
|
502
|
+
* reviewed prefix form for a simple command).
|
|
503
|
+
* · `kind: "batch"` — a CONJUNCTION batch of per-segment rules for a compound command. Choosing it
|
|
504
|
+
* is one yes to ALL of `rules` at once — there is no per-member selection inside a batch; a
|
|
505
|
+
* consumer that wants a narrower answer picks the single offer or approves once without a rule.
|
|
506
|
+
* `rules` has 1..5 members (the card-lane minting cap), in segment order, deduplicated by rule
|
|
507
|
+
* text. `uncoveredSegments` is the honest surplus disclosure of the cap: judged at MINT time
|
|
508
|
+
* against the coverage snapshot the card was drawn from ∪ this batch's FINAL (deduplicated,
|
|
509
|
+
* capped) rules, it counts the violating segments still admitted by neither — 0 means "once this
|
|
510
|
+
* batch is redeemed, this compound is fully covered by that snapshot's lights". It is a statement
|
|
511
|
+
* about the minting snapshot, not a standing guarantee: a concurrent rule removal can date it.
|
|
512
|
+
*
|
|
513
|
+
* Array contract (`ruleOffers`, the durable park row, and the consent record's projection while
|
|
514
|
+
* the card is PENDING all share it): at most 2 offers; the whole-string exact single is index 0
|
|
515
|
+
* whenever present; the batch offer — at most one — is always last. It is a draw-time contract,
|
|
516
|
+
* not a settled-record invariant: confirming an EDITED candidate appends a third single offer
|
|
517
|
+
* AFTER the batch in the same write that settles the record, so a SETTLED record's projection may
|
|
518
|
+
* carry it. ADVISORY display metadata, never adjudication input, and never a
|
|
519
|
+
* rule by itself: minting is a separate act that goes through the approval-record protocol, so a
|
|
520
|
+
* surface that ignores offers entirely changes nothing about what is allowed. The authoritative
|
|
521
|
+
* render source for a card is the PREPARED record's own offers (record-is-what-you-see); the ask-time
|
|
522
|
+
* projection here may drift from it across a coverage change, and the drift direction is harmless
|
|
523
|
+
* (the record is what gets confirmed).
|
|
524
|
+
*/
|
|
525
|
+
export type RuleOffer = {
|
|
526
|
+
readonly kind: "single";
|
|
527
|
+
/** The canonical rule text the host would redeem. */
|
|
528
|
+
readonly rule: string;
|
|
529
|
+
readonly match: PersistedRuleMatch;
|
|
530
|
+
/** The command pattern in the rule, for a host that wants to render it without re-parsing. */
|
|
531
|
+
readonly command: string;
|
|
532
|
+
} | {
|
|
533
|
+
readonly kind: "batch";
|
|
534
|
+
/** 1..5 per-segment rules, segment order, deduplicated by rule text. */
|
|
535
|
+
readonly rules: readonly SegmentRuleSuggestion[];
|
|
536
|
+
/** Mint-time honest surplus: violating segments admitted by neither the coverage snapshot nor
|
|
537
|
+
* this batch's final rules (see the union doc above for the exact arithmetic). */
|
|
538
|
+
readonly uncoveredSegments: number;
|
|
539
|
+
};
|
|
540
|
+
/**
|
|
541
|
+
* The offers presented on an approval card for `command` (design/375 §5.2).
|
|
542
|
+
*
|
|
543
|
+
* **Array order is a documented CONTRACT, not an implementation accident** (see {@link RuleOffer}):
|
|
544
|
+
* the whole-string EXACT single is index 0 whenever present; a SIMPLE command may carry a broader
|
|
545
|
+
* reviewed PREFIX single after it; a COMPOUND carries at most one BATCH offer, always last.
|
|
546
|
+
* Selection indices are keyed against this order, so consumers may rely on it; redemption TICKETS
|
|
547
|
+
* are NOT — they key on the consent record's flat CANDIDATE list, and a chosen offer is redeemed
|
|
548
|
+
* via `redeemRuleBatch` (see the consent record's own doc for the two index spaces).
|
|
549
|
+
*
|
|
550
|
+
* The prefix single is the LONGEST body two sources agree to offer: {@link SUGGESTION_LEXICON}'s
|
|
551
|
+
* deeper-than-two-words rows first, and otherwise {@link genericPrefixBody}'s general two-word form
|
|
552
|
+
* (`argv[0]` + a token shaped like a subcommand). Read those two for the grammar, its adopted origin,
|
|
553
|
+
* and the operand false positive it accepts; the short version is that a bare verb (`git`), an
|
|
554
|
+
* interpreter or wrapper head (`sudo apt`, `node build.js`), a flag in second position
|
|
555
|
+
* (`git -C /repo status`) and a quoted or dotted token all still yield NO prefix. Naive spacing note:
|
|
556
|
+
* `folded` keeps quoted whitespace, so splitting on single spaces can shear a quoted segment —
|
|
557
|
+
* harmless in this direction, because the sheared pieces carry quote characters and can therefore
|
|
558
|
+
* match neither a lexicon word nor the generic subcommand shape; every suspicious form lands on
|
|
559
|
+
* "no prefix".
|
|
379
560
|
*
|
|
380
561
|
* Every produced candidate must survive the round trip — parse as a rule, come back as the match form
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
* redemption would refuse is worse
|
|
562
|
+
* its seat is offering, AND admit the very text it was minted from (the whole command for a single,
|
|
563
|
+
* its own segment for a batch member). Enforced on EVERY seat, fail-closed: a candidate that would
|
|
564
|
+
* not round-trip is silently not offered, since offering an option redemption would refuse is worse
|
|
565
|
+
* than offering one fewer.
|
|
384
566
|
*
|
|
385
567
|
* The FORM half of that check is not decoration. A command may end in the rule grammar's own prefix
|
|
386
568
|
* marker — `rm :*` is a legal thing to type — and wrapping it as an exact rule produces the text
|
|
@@ -390,13 +572,29 @@ export interface RuleSuggestion {
|
|
|
390
572
|
* for a lexicon command like `git status :*`, emitted twice — once mislabelled, once as the real prefix
|
|
391
573
|
* candidate). The seat therefore believes the PARSER about what it got back, never its own request.
|
|
392
574
|
*
|
|
393
|
-
* A COMPOUND (`./gradlew build && ./gradlew test`) fills the exact
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
575
|
+
* A COMPOUND (`./gradlew build && ./gradlew test`) fills the exact single — the offered rule spells
|
|
576
|
+
* the whole chain and admits exactly it — and a BATCH offer besides: every segment NOT already
|
|
577
|
+
* covered (per `ctx.coverage`) yields its own single-segment best form — a prefix when the
|
|
578
|
+
* single-command grammar grants one for that segment's tokens (the interception screens apply
|
|
579
|
+
* unchanged), otherwise the segment's exact — deduplicated by rule text in segment order and capped
|
|
580
|
+
* at FIVE (upstream's own batch cap; the overflow is disclosed via `uncoveredSegments` rather than
|
|
581
|
+
* silently truncated away). A segment whose every form the floor refuses simply contributes no
|
|
582
|
+
* member (and stays counted as uncovered — the honest gap). The COMPOUND-PREFIX candidate this seat
|
|
583
|
+
* used to mint here is deliberately NO LONGER OFFERED (design/375 §5.3): the batch takes its card
|
|
584
|
+
* position, while the compound-prefix GRAMMAR remains a fully supported rule family — the matcher,
|
|
585
|
+
* the hand-written/edited/import channels and every persisted such rule are untouched.
|
|
586
|
+
*
|
|
587
|
+
* `ctx.coverage` is the per-segment coverage table minted by the SAME store read that adjudicated
|
|
588
|
+
* the call (see {@link segmentCoverageOf} and the gate's engine-stamped seat) — positional over this
|
|
589
|
+
* function's own folded segments, belt-checked by text: a table whose length or segment texts do not
|
|
590
|
+
* line up is discarded whole, and an absent or discarded table reads as ALL-UNCOVERED (fail toward
|
|
591
|
+
* over-offering; every offered rule still passes the validator at redemption, so an over-offer widens
|
|
592
|
+
* nothing).
|
|
397
593
|
*
|
|
398
594
|
* Returns an empty array for anything the rule lane cannot speak for (redirections, substitutions,
|
|
399
595
|
* subshells, backgrounding) — the card then simply carries no "don't ask again" option, which is the
|
|
400
596
|
* honest answer.
|
|
401
597
|
*/
|
|
402
|
-
export declare function suggestRulesForCommand(command: string
|
|
598
|
+
export declare function suggestRulesForCommand(command: string, ctx?: {
|
|
599
|
+
readonly coverage?: readonly SegmentCoverage[];
|
|
600
|
+
}): RuleOffer[];
|