@sema-agent/core 7.0.2 → 7.2.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 +58 -0
- package/dist/agents/cross-session-envelope.d.ts +138 -0
- package/dist/agents/cross-session-envelope.js +191 -0
- package/dist/agents/cross-session-judge.d.ts +119 -0
- package/dist/agents/cross-session-judge.js +184 -0
- package/dist/agents/cross-session-ref.d.ts +52 -0
- package/dist/agents/cross-session-ref.js +64 -0
- package/dist/agents/repair-loop.d.ts +8 -7
- package/dist/agents/roster-store.d.ts +7 -2
- package/dist/agents/send-message-tool.d.ts +13 -0
- package/dist/agents/send-message-tool.js +36 -12
- package/dist/brain/errors.d.ts +18 -0
- package/dist/brain/errors.js +3 -0
- package/dist/brain/stream-engine.js +6 -4
- package/dist/core/checkpoint-store.d.ts +189 -3
- package/dist/core/checkpoint-store.js +56 -16
- package/dist/core/context-edit.d.ts +3 -0
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +4 -0
- package/dist/core/hooks.d.ts +34 -7
- package/dist/core/hooks.js +14 -8
- package/dist/core/image-downsample.d.ts +4 -3
- package/dist/core/permission-rule-consent.d.ts +72 -23
- package/dist/core/permission-rule-consent.js +115 -26
- package/dist/core/permission-rule-model.d.ts +245 -51
- package/dist/core/permission-rule-model.js +312 -54
- package/dist/core/permission-rule-org.js +13 -6
- package/dist/core/remote-env.d.ts +8 -1
- package/dist/core/roles.d.ts +30 -8
- package/dist/core/roles.js +12 -8
- package/dist/core/runner/assemble-result.js +2 -1
- package/dist/core/runner/prepare-task.d.ts +41 -2
- package/dist/core/runner/prepare-task.js +353 -152
- package/dist/core/runner/prepare-workspace-restore.d.ts +6 -1
- package/dist/core/runner/prepare-workspace-restore.js +2 -1
- package/dist/core/runner/runtask.d.ts +12 -3
- package/dist/core/runner/runtask.js +45 -7
- package/dist/core/safety-axis-vocab.d.ts +1 -1
- package/dist/core/strategy-store.d.ts +4 -1
- package/dist/core/task-notification.d.ts +64 -5
- package/dist/core/task-notification.js +25 -4
- package/dist/core/task-registry-shared.d.ts +7 -3
- package/dist/core/tool-errors.d.ts +1 -1
- package/dist/core/tool-policy.d.ts +51 -7
- package/dist/core/tool-policy.js +63 -9
- package/dist/core/types.d.ts +110 -9
- package/dist/core/untrusted-text.js +17 -1
- package/dist/engine/compaction/compaction.js +6 -2
- package/dist/engine/harness/agent-harness.d.ts +28 -6
- package/dist/engine/harness/agent-harness.js +34 -2
- package/dist/engine/harness/messages.js +4 -0
- package/dist/engine/harness/types.d.ts +37 -0
- package/dist/engine/harness/types.js +5 -0
- package/dist/engine/session/session.js +3 -2
- package/dist/index.d.ts +6 -3
- package/dist/index.js +5 -2
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/orchestration/builtin-workflows.d.ts +17 -9
- package/dist/orchestration/run-workflow-tool.js +7 -2
- package/dist/orchestration/workflow-governance.js +1 -1
- package/dist/orchestration/workflow-types.d.ts +1 -0
- package/dist/orchestration/workflow.js +1 -1
- package/dist/stores/file/mailbox-store.d.ts +2 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +125 -1
|
@@ -58,16 +58,37 @@
|
|
|
58
58
|
* here) and no leading-env-assignment stripping (`FOO=1 git status` simply does not match
|
|
59
59
|
* `Bash(git status:*)`) — the last two are strict-side divergences from upstream, registered as such.
|
|
60
60
|
*/
|
|
61
|
-
/** The
|
|
61
|
+
/** The tools the rule lane speaks for. `"Bash"` is the historical member; `"Read"` (design/382 §2.2)
|
|
62
|
+
* speaks EXACTLY ONE grammar — the double-slash directory form `Read(//abs/**)`, the directory
|
|
63
|
+
* read-authorization a compound card's cd segment mints — and its admission is the CLOSED two-point
|
|
64
|
+
* one on {@link directoryRuleAdmits}: a Read tool call under the directory, and a compound's cd
|
|
65
|
+
* segment resolving into it. Nothing else — never a write, never a whole Bash command, never a
|
|
66
|
+
* non-cd segment.
|
|
62
67
|
*
|
|
63
68
|
* design/276 §3.3 (doctrine, for whoever widens this set): a future `SendMessage(…)`-form rule MAY
|
|
64
69
|
* clear the peer-referral ask — that ask is classifier hesitation by construction (#144: allow rules
|
|
65
70
|
* silence the classifier's questions, never a mandated one), so a recorded human yes is exactly what
|
|
66
71
|
* clears it. The org/hook/matchedAskRule immunities stay: those conjuncts live in the gate's
|
|
67
72
|
* persisted-rule lane and do not loosen with this set. */
|
|
68
|
-
export type PersistedRuleTool = "Bash";
|
|
69
|
-
/**
|
|
70
|
-
|
|
73
|
+
export type PersistedRuleTool = "Bash" | "Read";
|
|
74
|
+
/**
|
|
75
|
+
* Match forms. Four members, two of them one predicate:
|
|
76
|
+
* · `exact` — admits the one string the rule spells.
|
|
77
|
+
* · `wildcard` — the TRAILING SPACE-STAR spelling (`Bash(npm run *)`): the body, or the body followed
|
|
78
|
+
* by a space and more, inside the body's own segment count. This is the spelling upstream itself
|
|
79
|
+
* mints for its prefix suggestions (its classifier compiles one trailing ` *` into an optional
|
|
80
|
+
* suffix `^body( .*)?$`), so it is the form this lane's SUGGESTION face mints too (#510).
|
|
81
|
+
* · `prefix` — the historical COLON-STAR spelling (`Bash(npm run:*)`), match-equivalent to `wildcard`
|
|
82
|
+
* on the single-command body. Kept as a fully supported COMPATIBILITY READ — stored rules are never
|
|
83
|
+
* migrated or rewritten — and it remains the ONLY spelling of the compound-prefix form
|
|
84
|
+
* (`Bash(cd /tmp && adb pull:*)`): the trailing-star form deliberately has no compound reading
|
|
85
|
+
* (see {@link parseAllowRuleText}), because upstream's own trailing-star pattern is inert on a
|
|
86
|
+
* compound and importing/minting one as a chain licence would grant what nobody approved.
|
|
87
|
+
* · `subpath` — the Read directory form (design/382 §2.2): `Read(//abs/**)`, admitting reads under
|
|
88
|
+
* one absolute directory. Never admits any command; its one predicate is
|
|
89
|
+
* {@link directoryRuleAdmits}.
|
|
90
|
+
*/
|
|
91
|
+
export type PersistedRuleMatch = "exact" | "prefix" | "wildcard" | "subpath";
|
|
71
92
|
/**
|
|
72
93
|
* Where a rule applies — design/382 §4.1, the THREE consent dimensions.
|
|
73
94
|
*
|
|
@@ -155,8 +176,11 @@ export interface RuleTombstone {
|
|
|
155
176
|
/** The delete operation's own dot — the operation's persistent identity. */
|
|
156
177
|
deletedBy: RuleDot;
|
|
157
178
|
}
|
|
158
|
-
/** Why a rule text was refused. Codes are stable so an import report can group by them.
|
|
159
|
-
|
|
179
|
+
/** Why a rule text was refused. Codes are stable so an import report can group by them.
|
|
180
|
+
* `invalid.path_traversal` (design/382 §2.2, B5): a Read directory body carrying a `.` or `..`
|
|
181
|
+
* segment — the lexical-normal spelling is the ONLY spelling, so a traversal segment is not
|
|
182
|
+
* normalized away but refused. */
|
|
183
|
+
export type RuleRejectCode = "invalid.grammar" | "invalid.empty_command" | "invalid.not_simple_command" | "invalid.bare_interpreter_prefix" | "invalid.unbalanced_quotes" | "invalid.control_chars" | "invalid.too_long" | "invalid.path_traversal" | "unsupported.tool" | "unsupported.wildcard";
|
|
160
184
|
export interface RuleReject {
|
|
161
185
|
code: RuleRejectCode;
|
|
162
186
|
message: string;
|
|
@@ -371,49 +395,10 @@ export declare function parseAllowRuleText(text: string, opts?: {
|
|
|
371
395
|
} | {
|
|
372
396
|
reject: RuleReject;
|
|
373
397
|
};
|
|
374
|
-
/** The canonical spelling of a rule for a (already folded) command and match form.
|
|
398
|
+
/** The canonical spelling of a rule for a (already folded) command and match form. For `subpath` the
|
|
399
|
+
* command is the lexical-normal absolute directory (one leading slash), re-spelled in the
|
|
400
|
+
* double-slash directory form. */
|
|
375
401
|
export declare function formatAllowRuleText(command: string, match: PersistedRuleMatch): string;
|
|
376
|
-
/**
|
|
377
|
-
* #490 件4 — read ANOTHER product's `Bash(<body> *)` SPACE-STAR spelling as this lane's colon-star
|
|
378
|
-
* prefix rule, for the IMPORT door only.
|
|
379
|
-
*
|
|
380
|
-
* Why a translation is owed at all: the other product mints its prefix suggestions in that spelling
|
|
381
|
-
* (its own classifier reads `X:*` as its earlier prefix form and anything else containing an unescaped star as
|
|
382
|
-
* a wildcard), so a person migrating settings had EVERY prefix rule they had ever approved refused as
|
|
383
|
-
* `unsupported.wildcard` — the import silently emptied out exactly the rules that were the point of it.
|
|
384
|
-
*
|
|
385
|
-
* Translated ONLY for the ONE spelling whose semantics this lane can state exactly: content ending in
|
|
386
|
-
* ` *` with that star the only unescaped one. Upstream compiles a single trailing ` *` into an
|
|
387
|
-
* OPTIONAL suffix (`^body( .*)?$`), which is precisely "the body, or the body followed by a space and
|
|
388
|
-
* more" — this lane's prefix predicate. Any other star placement compiles to a real glob with no rule
|
|
389
|
-
* form here, and a bare `*` is a whole-tool grant that must never become a command rule; both are
|
|
390
|
-
* refused with a reason of their own so the import can DISCLOSE them rather than drop them.
|
|
391
|
-
*
|
|
392
|
-
* WHAT THE TRANSLATED RULE GRANTS, against the source spelling, axis by axis (the direction matters,
|
|
393
|
-
* and it is one-way with one named exception): identical on the bare body, on body-plus-arguments, on
|
|
394
|
-
* the word boundary (`npm run` never reaches `npm run-x`) and on compounds (both sides refuse a chain
|
|
395
|
-
* against a single-command body). NARROWER here on four axes, because upstream normalizes the
|
|
396
|
-
* CANDIDATE before matching and this lane never does: a candidate carrying a redirection, wrapped in
|
|
397
|
-
* `timeout`/`nice`/`nohup`-style words, fed through `xargs`, or prefixed with a `VAR=value` assignment
|
|
398
|
-
* matches there and matches nothing here. WIDER on exactly one: this lane folds runs of whitespace on
|
|
399
|
-
* both sides, so `npm run build` matches the imported rule where upstream's wildcard arm (which does
|
|
400
|
-
* not fold) would refuse it. That axis is NOT introduced by this translation — whitespace folding is
|
|
401
|
-
* this lane's universal reading and already applies to every imported EXACT rule, against an upstream
|
|
402
|
-
* exact arm that is byte-strict — so it is disclosed as a lane property rather than treated as a
|
|
403
|
-
* translation defect. Every other difference runs toward granting less.
|
|
404
|
-
*
|
|
405
|
-
* Returns `undefined` when the text is not a Bash wildcard spelling at all (nothing to translate; the
|
|
406
|
-
* caller proceeds with the text as written), `{ rule }` with the spelling to parse INSTEAD, or
|
|
407
|
-
* `{ skip }` with the reason a star spelling has no form here. Never bypasses the validator: the
|
|
408
|
-
* returned text goes through {@link parseAllowRuleText} exactly like a hand-written one, so the
|
|
409
|
-
* interpreter-head refusal, the control-character screen and the length bound all still apply — a
|
|
410
|
-
* translated `Bash(node *)` is refused `invalid.bare_interpreter_prefix` just as a typed one is.
|
|
411
|
-
*/
|
|
412
|
-
export declare function translateImportedWildcardRule(text: string): {
|
|
413
|
-
rule: string;
|
|
414
|
-
} | {
|
|
415
|
-
skip: string;
|
|
416
|
-
} | undefined;
|
|
417
402
|
/**
|
|
418
403
|
* Does this rule's command pattern admit `command`?
|
|
419
404
|
*
|
|
@@ -447,6 +432,44 @@ export declare function ruleAdmitsCommand(rule: Pick<PersistedAllowRule, "match"
|
|
|
447
432
|
* see — the inversion this whole ticket exists to prevent.
|
|
448
433
|
*/
|
|
449
434
|
export declare function ruleAdmitsProgramRun(rule: Pick<PersistedAllowRule, "match" | "command">, command: string): boolean;
|
|
435
|
+
/** design/382 §3.3-5 — one BREADTH note about a rule a person is about to persist: which wide shape
|
|
436
|
+
* it has, said in words a surface can show beside the input line. A warning is never a refusal —
|
|
437
|
+
* the closed refusal set is untouched — and never adjudication input. */
|
|
438
|
+
export interface EditedRuleBreadthWarning {
|
|
439
|
+
readonly code: "broad_prefix" | "compound_prefix";
|
|
440
|
+
/** The baseline sentence (a surface may reword it, never invert it — the same contract as the
|
|
441
|
+
* §3.5 reason baselines). */
|
|
442
|
+
readonly message: string;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* design/382 §3.3-5 — the breadth classifier behind the card-edit face's warning seat: does this
|
|
446
|
+
* (accepted) rule carry a width worth saying out loud before a person persists it?
|
|
447
|
+
*
|
|
448
|
+
* · `broad_prefix` — a prefix rule whose body is a SINGLE token (a bare verb, `Bash(mkdir:*)`):
|
|
449
|
+
* it admits every argument form of that command, not just the one on the card. This is the
|
|
450
|
+
* legal wide grant of §3.4 — the offer face deliberately never proposes it, the edit /
|
|
451
|
+
* hand-written channels legally accept it, and this sentence is what makes that acceptance an
|
|
452
|
+
* INFORMED one.
|
|
453
|
+
* · `compound_prefix` — a prefix rule whose body is a connector CHAIN (`Bash(cd /tmp && npm:*)`):
|
|
454
|
+
* one rule admitting several program runs, with anything extending its final segment.
|
|
455
|
+
*
|
|
456
|
+
* Judged on the CANONICAL rule (post-normalization, the spelling that would persist), with the
|
|
457
|
+
* lane's own instruments — the same shape reader the matcher uses, never a second grammar. A body
|
|
458
|
+
* this lane cannot read yields no warning: every such spelling is already the validator's refusal,
|
|
459
|
+
* and a warning beside a refusal would be noise about a rule that is not going to exist.
|
|
460
|
+
*
|
|
461
|
+
* An EXACT rule never warns (it admits one string, the one it spells — there is no width to name),
|
|
462
|
+
* and a SUBPATH rule is not this classifier's subject (no command reach at all). The two
|
|
463
|
+
* reach-bearing forms take the same two questions: `prefix` (colon-star) and `wildcard`
|
|
464
|
+
* (trailing space-star, #510 — match-equivalent reach on a single-command body; its grammar has no
|
|
465
|
+
* chain reading, so only the single-token question can fire for it).
|
|
466
|
+
* MAINTENANCE DUTY, stated where it binds: every match form with PREFIX REACH belongs here — a
|
|
467
|
+
* new reach-bearing member added to {@link PersistedRuleMatch} owes this classifier its arm, judged
|
|
468
|
+
* by the same "single token / chain body" questions (an exact-only form never warns).
|
|
469
|
+
* The upstream editor validates edited text but shows no breadth evidence at all; this seat is a
|
|
470
|
+
* superset disclosure (registered divergence, design/382 §6-4).
|
|
471
|
+
*/
|
|
472
|
+
export declare function ruleBreadthWarningsOf(rule: Pick<PersistedAllowRule, "match" | "command">): readonly EditedRuleBreadthWarning[];
|
|
450
473
|
/**
|
|
451
474
|
* The segments of `command` as the deny/ask layer must judge them, or `undefined` for a command this
|
|
452
475
|
* lane cannot read.
|
|
@@ -466,6 +489,35 @@ export declare function ruleLaneSegmentsOf(command: string): readonly string[] |
|
|
|
466
489
|
* not contain `/ab`. Both sides are expected to be canonical already.
|
|
467
490
|
*/
|
|
468
491
|
export declare function pathWithinRoot(path: string, root: string): boolean;
|
|
492
|
+
/**
|
|
493
|
+
* The LEXICAL NORMALIZER for a CALL's target path (design/382 §2.2 — the rule family's one path
|
|
494
|
+
* identity is the lexical normal form, zero IO): collapse slash runs and `.` segments, resolve `..`
|
|
495
|
+
* segments textually, and answer the one-leading-slash absolute spelling — or `undefined` when no
|
|
496
|
+
* such spelling exists (a relative path, a `..` climbing past the root, an empty result). RULE
|
|
497
|
+
* bodies never come through here (their canonical spelling is unique and non-normal spellings are
|
|
498
|
+
* refused at the validator); this is for the comparison INPUT a caller derives from a live call.
|
|
499
|
+
*/
|
|
500
|
+
export declare function lexicalNormalAbsolutePathOf(path: string): string | undefined;
|
|
501
|
+
/**
|
|
502
|
+
* design/382 §2.5 — the ONE admission predicate of the Read directory rule family, beside
|
|
503
|
+
* {@link ruleAdmitsCommand} as its path-lane sibling. Four consumers share it (the minting round
|
|
504
|
+
* trip, the coverage table, the gate conjunction arm, and the gate's Read lane) so there is no
|
|
505
|
+
* second fact source anywhere.
|
|
506
|
+
*
|
|
507
|
+
* `path` is the caller's ALREADY-RESOLVED lexical-normal absolute path — the same path identity the
|
|
508
|
+
* deployment's read adjudication judged the call with (for the Read tool face), or the cd resolver's
|
|
509
|
+
* output (for the Bash cd-segment face). This predicate NORMALIZES NOTHING: a non-normal spelling
|
|
510
|
+
* (a `.`/`..` segment, a doubled slash, a relative path) is refused outright, fail-closed, so a
|
|
511
|
+
* caller cannot smuggle a second path identity through the comparison. Containment is the
|
|
512
|
+
* word-boundary one ({@link pathWithinRoot}: `/a` never reaches `/ab`).
|
|
513
|
+
*
|
|
514
|
+
* What it never does, stated as loudly as what it does (§2.5): admits READS ONLY — a rule of this
|
|
515
|
+
* family never admits a write, never a whole Bash command, never a non-cd segment — and it clears
|
|
516
|
+
* ASKS only, never a filesystem fence: workspace containment, the sensitive-read deny face and every
|
|
517
|
+
* violation refusal judge exactly as they would without the rule (a fence refusal is structural, not
|
|
518
|
+
* an ask, so there is nothing here for it to clear).
|
|
519
|
+
*/
|
|
520
|
+
export declare function directoryRuleAdmits(rule: Pick<PersistedAllowRule, "tool" | "match" | "command">, path: string): boolean;
|
|
469
521
|
/** Does a rule's scope cover a task running in `cwd` (and, for the session dimension, in the session
|
|
470
522
|
* named by `sessionId`)? A project rule needs a cwd to compare against; without one it covers nothing
|
|
471
523
|
* (fail-closed). A session rule (design/382 §4.3) covers a call iff the call's `sessionId` equals the
|
|
@@ -556,6 +608,11 @@ export declare function findAdmittingRule(rules: readonly PersistedAllowRule[],
|
|
|
556
608
|
command: string;
|
|
557
609
|
cwd: string | undefined;
|
|
558
610
|
sessionId?: string;
|
|
611
|
+
/** The directory RELATIVE cd targets resolve against — the live TRACKED working directory of the
|
|
612
|
+
* execution seat (adversarial-review P1: after an earlier observable `cd`, the shell resolves
|
|
613
|
+
* `./x` against the moved cursor, not the task root). Defaults to `cwd`; the scope/eligibility
|
|
614
|
+
* axis stays `cwd` either way. */
|
|
615
|
+
execCwd?: string;
|
|
559
616
|
}): readonly PersistedAllowRule[] | undefined;
|
|
560
617
|
/**
|
|
561
618
|
* design/375 §5.2 — the per-segment coverage table for `command`: which segments an eligible rule
|
|
@@ -597,6 +654,9 @@ export declare function segmentCoverageOf(command: string, rules: {
|
|
|
597
654
|
tool: string;
|
|
598
655
|
cwd: string | undefined;
|
|
599
656
|
sessionId?: string;
|
|
657
|
+
/** The relative-cd resolution base (see {@link findAdmittingRule}'s member of the same name) —
|
|
658
|
+
* defaults to `cwd`; scope/eligibility stays `cwd`. */
|
|
659
|
+
execCwd?: string;
|
|
600
660
|
}): readonly SegmentCoverage[] | undefined;
|
|
601
661
|
/** One row of a per-segment coverage table (see {@link segmentCoverageOf}): the FOLDED, trimmed
|
|
602
662
|
* segment text (a display/correlation seat, never adjudication input) and whether an eligible rule
|
|
@@ -626,6 +686,34 @@ export interface SegmentRuleSuggestion {
|
|
|
626
686
|
* show a reader something other than what they authorize. */
|
|
627
687
|
readonly segment: string;
|
|
628
688
|
}
|
|
689
|
+
/**
|
|
690
|
+
* design/382 §2.3 (B3, BREAKING) — one member of a batch offer, a DISCRIMINATED union keyed by
|
|
691
|
+
* `kind`:
|
|
692
|
+
*
|
|
693
|
+
* · `kind: "command"` — the historical shape: a per-segment Bash rule
|
|
694
|
+
* ({@link SegmentRuleSuggestion}'s four seats, plus the discriminant).
|
|
695
|
+
* · `kind: "directoryRead"` — a DIRECTORY READ AUTHORIZATION minted from a cd segment (the §2.4
|
|
696
|
+
* floor): `rule` is the canonical `Read(//dir/**)` text, `directory` the lexical-normal absolute
|
|
697
|
+
* directory (a render seat, spared a re-parse), `segment` the folded cd segment it came from (a
|
|
698
|
+
* rendering-context seat like its command sibling's — never adjudication input).
|
|
699
|
+
*
|
|
700
|
+
* CONSUMER DEGRADE ARM (normative, design/382 §2.3): a batch member whose `kind` is outside this set
|
|
701
|
+
* drops the WHOLE batch offer — never the single member (a conjunction batch silently one member
|
|
702
|
+
* short renders "yes to N" as "yes to N−1", worse than not rendering), and never the whole card (the
|
|
703
|
+
* exact single beside it is intact and honest). Selection indices stay keyed on the ORIGINAL wire
|
|
704
|
+
* offer order.
|
|
705
|
+
*/
|
|
706
|
+
export type RuleOfferBatchMember = (SegmentRuleSuggestion & {
|
|
707
|
+
readonly kind: "command";
|
|
708
|
+
}) | {
|
|
709
|
+
readonly kind: "directoryRead";
|
|
710
|
+
/** The canonical rule text the host would redeem — `Read(//a/b/**)`. */
|
|
711
|
+
readonly rule: string;
|
|
712
|
+
/** The lexical-normal absolute directory the rule names — a render seat, no re-parse needed. */
|
|
713
|
+
readonly directory: string;
|
|
714
|
+
/** The (folded) cd segment this authorization came from — rendering context, never adjudication input. */
|
|
715
|
+
readonly segment: string;
|
|
716
|
+
};
|
|
629
717
|
/**
|
|
630
718
|
* design/375 §3.1 — ONE "don't ask again" option on an approval card. A CLOSED discriminated union
|
|
631
719
|
* (`kind`); consumers parse it per element, and an element whose `kind` they do not know is dropped
|
|
@@ -639,7 +727,10 @@ export interface SegmentRuleSuggestion {
|
|
|
639
727
|
* is one yes to ALL of `rules` at once — there is no per-member selection inside a batch; a
|
|
640
728
|
* consumer that wants a narrower answer picks the single offer or approves once without a rule.
|
|
641
729
|
* `rules` has 1..5 members (the card-lane minting cap), in segment order, deduplicated by rule
|
|
642
|
-
* text
|
|
730
|
+
* text, each a {@link RuleOfferBatchMember} (design/382 B3: the member form is a discriminated
|
|
731
|
+
* union — a cd segment of a project-scope card mints a `directoryRead` member, one accept lands
|
|
732
|
+
* commands and directory authorization together, the upstream single-line merged-consent form).
|
|
733
|
+
* `uncoveredSegments` is the honest surplus disclosure of the cap: judged at MINT time
|
|
643
734
|
* against the coverage snapshot the card was drawn from ∪ this batch's FINAL (deduplicated,
|
|
644
735
|
* capped) rules, it counts the violating segments still admitted by neither — 0 means "once this
|
|
645
736
|
* batch is redeemed, this compound is fully covered by that snapshot's lights". It is a statement
|
|
@@ -666,12 +757,72 @@ export type RuleOffer = {
|
|
|
666
757
|
readonly command: string;
|
|
667
758
|
} | {
|
|
668
759
|
readonly kind: "batch";
|
|
669
|
-
/** 1..5 per-segment
|
|
670
|
-
|
|
760
|
+
/** 1..5 per-segment members, segment order, deduplicated by rule text (design/382 B3: the
|
|
761
|
+
* member form is the {@link RuleOfferBatchMember} discriminated union). */
|
|
762
|
+
readonly rules: readonly RuleOfferBatchMember[];
|
|
671
763
|
/** Mint-time honest surplus: violating segments admitted by neither the coverage snapshot nor
|
|
672
764
|
* this batch's final rules (see the union doc above for the exact arithmetic). */
|
|
673
765
|
readonly uncoveredSegments: number;
|
|
766
|
+
/**
|
|
767
|
+
* design/382 §3.5 — WHY each of those segments stays uncovered, one row per counted segment,
|
|
768
|
+
* segment order (same text repeated = two rows; the correspondence is positional, never a raw
|
|
769
|
+
* text dedup). Minted in the SAME pass as `uncoveredSegments` off the same snapshot, so
|
|
770
|
+
* `uncoveredDetail.length === uncoveredSegments` whenever the seat is present; the count seat
|
|
771
|
+
* stays the truth source, and ABSENCE (an older minter, a degraded consumer's re-emit) is not
|
|
772
|
+
* a claim. `segment` is the folded, trimmed segment text — a display/correlation seat carrying
|
|
773
|
+
* raw command bytes (render like its siblings, {@link renderUntrustedCommandText}); `reason`
|
|
774
|
+
* is the closed set {@link UncoveredSegmentDetail} documents. Additive on the wire (an unknown
|
|
775
|
+
* key inside a known kind — old consumers read the batch exactly as before); on the CONSENT
|
|
776
|
+
* RECORD's card batch the seat is REQUIRED (schema: 3) — see the record's own contract.
|
|
777
|
+
*/
|
|
778
|
+
readonly uncoveredDetail?: readonly UncoveredSegmentDetail[];
|
|
674
779
|
};
|
|
780
|
+
/** design/382 §3.5 — the closed reason set for one uncovered segment of a batch offer.
|
|
781
|
+
*
|
|
782
|
+
* · `"redirection"` — the segment carries a shell redirection: refused by discipline (#490 修①,
|
|
783
|
+
* §3.2), PERMANENTLY per-ask — no rule text can cover this spelling; the honest outlet is a rule
|
|
784
|
+
* for its redirection-free form, if the person trusts that form.
|
|
785
|
+
* · `"no_rule_form"` — neither the segment's prefix nor its exact form survives the mint round
|
|
786
|
+
* trip (a glob argument, an over-length line): nothing coverable exists for these bytes, and
|
|
787
|
+
* guidance deliberately does NOT point at hand-writing a rule — the same grammar refuses the
|
|
788
|
+
* same text on every door.
|
|
789
|
+
* · `"cap_overflow"` — the segment minted a rule, but the batch's dedup+cap left it out and no
|
|
790
|
+
* surviving member admits it: covered next time it comes up, asked about until then.
|
|
791
|
+
*
|
|
792
|
+
* These are WIRE-STRUCTURED facts, and that is the whole §3.6 point (recorded here so the design's
|
|
793
|
+
* half-radius is visible in the code): the reader is not only a person. A model or harness that
|
|
794
|
+
* keeps meeting `redirection` on a spelling it retries can re-run the redirection-free form —
|
|
795
|
+
* which HAS a coverable rule — with zero new mechanism on this side; a structured honest refusal
|
|
796
|
+
* is programmable, exactly like a loud bad-value error. The baseline person-facing sentences are
|
|
797
|
+
* {@link UNCOVERED_SEGMENT_REASON_BASELINE}. */
|
|
798
|
+
export interface UncoveredSegmentDetail {
|
|
799
|
+
/** The folded, trimmed segment text — raw post-rewrite command bytes, same contract as
|
|
800
|
+
* {@link SegmentRuleSuggestion.segment}. */
|
|
801
|
+
readonly segment: string;
|
|
802
|
+
readonly reason: "redirection" | "no_rule_form" | "cap_overflow";
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* design/382 §3.5-2 — the BASELINE "why + outlet" sentence per uncovered-segment reason: the
|
|
806
|
+
* one-source copy a surface renders beside the §3.5 detail rows. A surface may reword these, never
|
|
807
|
+
* invert them (the same contract as {@link renderUntrustedCommandText}: adopt the baseline, or own
|
|
808
|
+
* an equivalent-strength rewrite). Load-bearing asymmetries, deliberate:
|
|
809
|
+
* · `redirection` points at the redirection-FREE form's outlets (that form is coverable);
|
|
810
|
+
* · `no_rule_form` points at NOTHING but per-use approval — hand-writing is not suggested,
|
|
811
|
+
* because the same grammar refuses the same text on every door, and pointing a person at a rule
|
|
812
|
+
* that can never take effect is the exact defect this surface exists to remove;
|
|
813
|
+
* · `cap_overflow` promises only honesty: not covered by this batch, asked again when met.
|
|
814
|
+
*/
|
|
815
|
+
export declare const UNCOVERED_SEGMENT_REASON_BASELINE: Readonly<Record<UncoveredSegmentDetail["reason"], string>>;
|
|
816
|
+
/**
|
|
817
|
+
* design/382 §3.5-2 — the BASELINE sentence per card-level offer-ABSENCE reason (#490 修②'s typed
|
|
818
|
+
* seat: `ruleOffersAbsence` on the ask and its durable park twin; the closed vocabulary is declared
|
|
819
|
+
* literally at those two faces, and this table spells the same literals — the copy row is data, not
|
|
820
|
+
* the type's home). Same reword-never-invert contract as the table above. The load-bearing
|
|
821
|
+
* asymmetry: `mandated` must NOT point at writing rules — on a mandated ask no rule is consulted,
|
|
822
|
+
* and directing a person to mint one that can never take effect is the #457④ anti-shape; the other
|
|
823
|
+
* two reasons name their real outlets.
|
|
824
|
+
*/
|
|
825
|
+
export declare const RULE_OFFERS_ABSENCE_BASELINE: Readonly<Record<"mandated" | "lane_cannot_speak" | "shadowed", string>>;
|
|
675
826
|
/**
|
|
676
827
|
* The offers presented on an approval card for `command` (design/375 §5.2).
|
|
677
828
|
*
|
|
@@ -740,4 +891,47 @@ export type RuleOffer = {
|
|
|
740
891
|
*/
|
|
741
892
|
export declare function suggestRulesForCommand(command: string, ctx?: {
|
|
742
893
|
readonly coverage?: readonly SegmentCoverage[];
|
|
894
|
+
/**
|
|
895
|
+
* design/382 §2.4-7 — the SCOPE the card's candidates would land in, the directoryRead mint
|
|
896
|
+
* gate's first input: a cd segment mints a directory member ONLY when this scope is a PROJECT
|
|
897
|
+
* or SESSION scope that also COVERS the adjudicated call (the second conjunct, through the one
|
|
898
|
+
* scope predicate — a scope that does not cover the deciding call would mint a member that is
|
|
899
|
+
* never eligible where it was minted, the offer-that-never-works shape). The SESSION arm is the
|
|
900
|
+
* §8-Q3 re-ruling (opened at final sign-off: the upstream session destination is exactly this
|
|
901
|
+
* grant's home, and a session-scope member is a pure narrowing of the project one). GLOBAL
|
|
902
|
+
* stays closed — a directory grant is place-and-time consent, and the everywhere spelling is
|
|
903
|
+
* the explicit channels' business. Absent ⇒ the gate is closed and a cd segment falls back to
|
|
904
|
+
* its command member (the pre-382 behaviour, byte-for-byte).
|
|
905
|
+
*/
|
|
906
|
+
readonly scope?: RuleScope;
|
|
907
|
+
/**
|
|
908
|
+
* The adjudicated call's working directory (threaded from the original call context, never the
|
|
909
|
+
* process — the same value the coverage read and the gate judged with). Two consumers: the
|
|
910
|
+
* `./`-relative cd resolution, and the scope gate's coverage conjunct. Absent ⇒ no relative cd
|
|
911
|
+
* resolves and a project-scope gate is closed.
|
|
912
|
+
*/
|
|
913
|
+
readonly cwd?: string;
|
|
914
|
+
/**
|
|
915
|
+
* The relative-cd RESOLUTION base — the live tracked working directory of the execution seat
|
|
916
|
+
* (adversarial-review P1: after an earlier observable `cd`, the shell resolves `./x` against the
|
|
917
|
+
* moved cursor, not the task root — a member minted off the wrong base names a directory the cd
|
|
918
|
+
* never enters). Defaults to `cwd`; the scope gate's coverage conjunct stays on `cwd`.
|
|
919
|
+
*/
|
|
920
|
+
readonly execCwd?: string;
|
|
921
|
+
/**
|
|
922
|
+
* The adjudicated call's SESSION identity (threaded like `cwd`, never inferred) — the session
|
|
923
|
+
* arm's coverage conjunct: a session-scope card mints a directory member only when its scope
|
|
924
|
+
* names THIS session. Absent ⇒ no session scope covers anything (fail-closed, the shared
|
|
925
|
+
* predicate's own arm).
|
|
926
|
+
*/
|
|
927
|
+
readonly sessionId?: string;
|
|
928
|
+
/**
|
|
929
|
+
* design/382 §2.4-6 — the deployment's sensitive-read negative control, SAME-SOURCE with its
|
|
930
|
+
* compiled read-deny judge (`ReadDenyMatcher.matchPath !== null` is the canonical wiring): the
|
|
931
|
+
* engine never PROPOSES a directory authorization for a directory this judge names. Absent ⇒
|
|
932
|
+
* the built-in default deny table stands in (refusal-only; a deployment with a wired judge
|
|
933
|
+
* passes its own so the two faces cannot disagree). Explicit-consent doors (hand-written,
|
|
934
|
+
* import) are deliberately NOT behind this — they have their own preview and validation.
|
|
935
|
+
*/
|
|
936
|
+
readonly deniesDirectoryRead?: (directory: string) => boolean;
|
|
743
937
|
}): RuleOffer[];
|