@deftai/directive-core 0.105.0 → 0.107.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/dist/authz/classify.js +591 -34
- package/dist/check/gate-lists.js +2 -0
- package/dist/check/named-cause.js +1 -1
- package/dist/design-critique/exclusive-chip.d.ts +33 -0
- package/dist/design-critique/exclusive-chip.js +68 -0
- package/dist/design-critique/parent-audit.d.ts +59 -0
- package/dist/design-critique/parent-audit.js +121 -0
- package/dist/doctor/checks.d.ts +6 -0
- package/dist/doctor/checks.js +35 -0
- package/dist/forward-coverage/diff-coverage.d.ts +39 -0
- package/dist/forward-coverage/diff-coverage.js +112 -0
- package/dist/forward-coverage/diff-lines.d.ts +19 -0
- package/dist/forward-coverage/diff-lines.js +173 -0
- package/dist/forward-coverage/evaluate.d.ts +24 -9
- package/dist/forward-coverage/evaluate.js +125 -19
- package/dist/hooks/dest-form.d.ts +46 -0
- package/dist/hooks/dest-form.js +575 -0
- package/dist/hooks/dispatcher.d.ts +17 -1
- package/dist/hooks/dispatcher.js +82 -11
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +1 -1
- package/dist/intake/clause-derivation.d.ts +9 -0
- package/dist/intake/clause-derivation.js +30 -3
- package/dist/intake/github-auth-modes-cli.js +14 -2
- package/dist/intake/github-auth-modes.d.ts +54 -9
- package/dist/intake/github-auth-modes.js +326 -123
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +26 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +37 -14
- package/dist/lifecycle/completed-write-guard.d.ts +48 -0
- package/dist/lifecycle/completed-write-guard.js +373 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle-visible/evaluate.d.ts +98 -0
- package/dist/lifecycle-visible/evaluate.js +710 -0
- package/dist/lifecycle-visible/index.d.ts +2 -0
- package/dist/lifecycle-visible/index.js +2 -0
- package/dist/literal-acceptance/capture.d.ts +16 -0
- package/dist/literal-acceptance/capture.js +78 -10
- package/dist/literal-acceptance/evaluate.js +25 -3
- package/dist/literal-acceptance/index.d.ts +2 -2
- package/dist/literal-acceptance/index.js +2 -2
- package/dist/literal-acceptance/run.js +9 -3
- package/dist/literal-acceptance/types.d.ts +6 -0
- package/dist/literal-acceptance/types.js +6 -0
- package/dist/orchestration/judgment-policy.d.ts +13 -0
- package/dist/orchestration/judgment-policy.js +15 -0
- package/dist/orchestration/probe-session.js +13 -8
- package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
- package/dist/orchestration/verify-judgment-gates.js +43 -11
- package/dist/policy/ceremony-dial.js +7 -7
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- package/dist/policy/org-force-on-migration.js +2 -1
- package/dist/policy/plan-extensions.d.ts +1 -1
- package/dist/policy/plan-extensions.js +2 -0
- package/dist/policy/product-signal.js +6 -7
- package/dist/policy/require-human-merge.js +8 -6
- package/dist/policy/resolve.d.ts +7 -2
- package/dist/policy/resolve.js +25 -8
- package/dist/policy/runtime-authority.d.ts +18 -0
- package/dist/policy/runtime-authority.js +11 -0
- package/dist/policy/value-feedback.js +7 -8
- package/dist/policy/write-fence.js +3 -0
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +24 -4
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +4 -0
- package/dist/product-first-done-gate/evaluate.js +82 -10
- package/dist/release/closed-verb-gate.d.ts +12 -0
- package/dist/release/closed-verb-gate.js +51 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -0
- package/dist/release/pipeline.js +7 -0
- package/dist/release/types.d.ts +12 -0
- package/dist/render/constants.d.ts +2 -1
- package/dist/render/constants.js +2 -1
- package/dist/render/framework-commands.js +4 -0
- package/dist/render/spec-validate.js +23 -12
- package/dist/run-summary/types.d.ts +4 -0
- package/dist/scm/design-critique-chip.d.ts +37 -0
- package/dist/scm/design-critique-chip.js +171 -0
- package/dist/scm/index.d.ts +1 -0
- package/dist/scm/index.js +1 -0
- package/dist/scm/main.d.ts +3 -0
- package/dist/scm/main.js +15 -1
- package/dist/scm/readiness-cli.d.ts +2 -0
- package/dist/scm/readiness-cli.js +42 -1
- package/dist/scm/readiness.d.ts +2 -1
- package/dist/scm/readiness.js +7 -1
- package/dist/scope/decompose.js +2 -1
- package/dist/scope/delivery-evidence.d.ts +27 -1
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/lifecycle-write.d.ts +24 -0
- package/dist/scope/lifecycle-write.js +64 -0
- package/dist/scope/main.js +18 -6
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope/transition.js +90 -11
- package/dist/scope-provenance/evaluate.js +8 -4
- package/dist/session/ac-pass-banking.d.ts +5 -0
- package/dist/session/ac-pass-banking.js +3 -2
- package/dist/session/git.d.ts +18 -0
- package/dist/session/git.js +81 -1
- package/dist/session/occupancy.d.ts +2 -1
- package/dist/session/occupancy.js +11 -4
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.js +41 -24
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-start.d.ts +18 -0
- package/dist/session/session-start.js +49 -2
- package/dist/session/verify-session-ritual.d.ts +46 -4
- package/dist/session/verify-session-ritual.js +118 -10
- package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
- package/dist/swarm/finalize-cohort-cli.js +165 -35
- package/dist/swarm/finalize-cohort.d.ts +1 -0
- package/dist/swarm/finalize-cohort.js +14 -2
- package/dist/swarm/launch.d.ts +69 -0
- package/dist/swarm/launch.js +191 -1
- package/dist/swarm/routing-set-cli.js +2 -0
- package/dist/swarm/routing-verify.d.ts +1 -1
- package/dist/swarm/routing-verify.js +2 -2
- package/dist/triage/actions/index.d.ts +4 -0
- package/dist/triage/actions/index.js +6 -0
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/evaluate/evaluate.d.ts +11 -0
- package/dist/triage/evaluate/evaluate.js +169 -0
- package/dist/triage/evaluate/github.d.ts +16 -0
- package/dist/triage/evaluate/github.js +153 -0
- package/dist/triage/evaluate/index.d.ts +9 -0
- package/dist/triage/evaluate/index.js +8 -0
- package/dist/triage/evaluate/paths.d.ts +7 -0
- package/dist/triage/evaluate/paths.js +25 -0
- package/dist/triage/evaluate/sink.d.ts +5 -0
- package/dist/triage/evaluate/sink.js +52 -0
- package/dist/triage/evaluate/types.d.ts +93 -0
- package/dist/triage/evaluate/types.js +13 -0
- package/dist/triage/evaluate/validity.d.ts +8 -0
- package/dist/triage/evaluate/validity.js +87 -0
- package/dist/triage/evaluate/value.d.ts +12 -0
- package/dist/triage/evaluate/value.js +33 -0
- package/dist/triage/evaluate/wip-census.d.ts +5 -0
- package/dist/triage/evaluate/wip-census.js +39 -0
- package/dist/triage/evaluate/worktrees.d.ts +8 -0
- package/dist/triage/evaluate/worktrees.js +68 -0
- package/dist/triage/evaluate/xbrief-refs.d.ts +8 -0
- package/dist/triage/evaluate/xbrief-refs.js +60 -0
- package/dist/triage/help/registry-data.d.ts +22 -8
- package/dist/triage/help/registry-data.js +54 -6
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/value/feedback-file.d.ts +17 -2
- package/dist/value/feedback-file.js +80 -6
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-reconcile/labels.d.ts +1 -0
- package/dist/vbrief-reconcile/labels.js +30 -0
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/vbrief-validation/story-quality.d.ts +7 -0
- package/dist/vbrief-validation/story-quality.js +8 -1
- package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
- package/dist/verify-env/agent-hook-readiness.js +12 -8
- package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
- package/dist/verify-env/agent-hooks-live-probe.js +26 -5
- package/dist/verify-env/agent-hooks.js +3 -4
- package/dist/xbrief-migrate/agents-header.js +69 -7
- package/package.json +7 -3
package/dist/hooks/dispatcher.js
CHANGED
|
@@ -14,8 +14,9 @@ import { evaluateOccupancyWriteGate } from "../session/occupancy.js";
|
|
|
14
14
|
import { emitSessionRitualBlockedProcessCost } from "../session/process-cost.js";
|
|
15
15
|
import { markRitualStaleAfterCompact } from "../session/ritual-sentinel.js";
|
|
16
16
|
import { runSessionStartHookWrite } from "../session/session-start-hook.js";
|
|
17
|
-
import { formatRitualRecoveryInstruction, verifySessionRitual, } from "../session/verify-session-ritual.js";
|
|
17
|
+
import { formatRitualRecoveryInstruction, verifySessionRitual, writeGateRitualOptions, } from "../session/verify-session-ritual.js";
|
|
18
18
|
import { hookMcpArgsText, hookShellCommand, hookToolName, hookWriteTargetPath, missingToolNameMessage, record, } from "./classify/index.js";
|
|
19
|
+
import { classifyProductDestForms, payloadWithInjectedWriteTarget } from "./dest-form.js";
|
|
19
20
|
import { isAssistPosture, isEphemeralSpawn, isExploreSpawn, isReadOnlyHookContext, } from "./readonly.js";
|
|
20
21
|
import { inspectActiveScope } from "./scope.js";
|
|
21
22
|
import { isDirectWriteTool, isMcpTool, isShellTool, isSpawnTool } from "./tools.js";
|
|
@@ -255,6 +256,17 @@ export function isHookHost(value) {
|
|
|
255
256
|
export function isHookEvent(value) {
|
|
256
257
|
return HOOK_EVENTS.includes(value);
|
|
257
258
|
}
|
|
259
|
+
function scopeNotReadyCoverageHint(toolName) {
|
|
260
|
+
if (isSpawnTool(toolName))
|
|
261
|
+
return "";
|
|
262
|
+
if (isShellTool(toolName)) {
|
|
263
|
+
return (" This deny is the active-scope write gate on a recognized Shell dest-form " +
|
|
264
|
+
"(git checkout --, git restore, rm/rmdir of in-repo paths).");
|
|
265
|
+
}
|
|
266
|
+
return (" This gate covers direct-write tools (Edit/Write) and implementation spawn, " +
|
|
267
|
+
"plus recognized Shell dest-forms (git checkout --, git restore, rm/rmdir). " +
|
|
268
|
+
"Other shell (python -c, cmd /c copy, git status) is not this deny.");
|
|
269
|
+
}
|
|
258
270
|
function deny(input, code, toolName, message, scopePath = null) {
|
|
259
271
|
return {
|
|
260
272
|
verdict: "deny",
|
|
@@ -578,15 +590,18 @@ function inspectMutationGates(input, toolName, seams, options) {
|
|
|
578
590
|
try {
|
|
579
591
|
// Mutation dispatch is a live gated boundary: active verification reruns
|
|
580
592
|
// non-cacheable agent-hook readiness instead of trusting persisted success.
|
|
593
|
+
// Write-surface authority executes agent_hooks only (#3738). cache_fresh
|
|
594
|
+
// is not required and is never executed. doctor is read from the record.
|
|
581
595
|
// Its allow fixture is non-write and its deny fixture is read-only, so the
|
|
582
596
|
// installed-shim probe cannot recurse into this mutation path.
|
|
583
597
|
ritual = (seams.verifyRitual ??
|
|
584
598
|
seams.inspectRitual ??
|
|
585
|
-
((root) => verifySessionRitual(root, {
|
|
586
|
-
tier: "gated",
|
|
587
|
-
posture: "mutation",
|
|
599
|
+
((root) => verifySessionRitual(root, writeGateRitualOptions({
|
|
588
600
|
bypass: false,
|
|
589
|
-
|
|
601
|
+
runner: seams.ritualRunner,
|
|
602
|
+
detectWorkSelection: seams.detectWorkSelection,
|
|
603
|
+
runGit: seams.ritualRunGit,
|
|
604
|
+
}))))(projectRoot);
|
|
590
605
|
}
|
|
591
606
|
catch (cause) {
|
|
592
607
|
// #2994: best-effort local process-cost; never changes deny verdict.
|
|
@@ -705,7 +720,8 @@ function inspectMutationGates(input, toolName, seams, options) {
|
|
|
705
720
|
"assist posture (commands.md #1802) — do not fake `scope:activate` for notes.");
|
|
706
721
|
}
|
|
707
722
|
const denyCode = isSpawnTool(toolName) ? "spawn-not-ready" : "scope-not-ready";
|
|
708
|
-
return deny(input, denyCode, toolName, `Directive denied ${toolName}: ${scope.message}${proposedPathHint}`
|
|
723
|
+
return deny(input, denyCode, toolName, `Directive denied ${toolName}: ${scope.message}${proposedPathHint}` +
|
|
724
|
+
scopeNotReadyCoverageHint(toolName));
|
|
709
725
|
}
|
|
710
726
|
}
|
|
711
727
|
const allowCode = isSpawnTool(toolName) ? "spawn-ready" : "write-ready";
|
|
@@ -742,6 +758,58 @@ function inspectMutationGates(input, toolName, seams, options) {
|
|
|
742
758
|
scopePath: scope.path,
|
|
743
759
|
};
|
|
744
760
|
}
|
|
761
|
+
/**
|
|
762
|
+
* Route recognized Shell dest-forms through inspectMutationGates, then push/merge.
|
|
763
|
+
* Dest-form allow is kept when runtime authority has nothing classifiable.
|
|
764
|
+
*/
|
|
765
|
+
function decideShellDestFormsThenRuntimeAuthority(input, toolName, seams) {
|
|
766
|
+
const command = hookShellCommand(input.payload);
|
|
767
|
+
let destAllow = null;
|
|
768
|
+
let expansionDeny = null;
|
|
769
|
+
// #3438 / #3594: opt-in. `off` (the default) leaves Shell exactly as it was
|
|
770
|
+
// before this gate existed — unrecognized and fail-open — so landing the
|
|
771
|
+
// classifier cannot deny anything a consumer runs today. `enforce` turns on
|
|
772
|
+
// BOTH halves together: resolved dests through inspectMutationGates and
|
|
773
|
+
// fail-closed for targets that cannot be proved. ⊗ Do not split those two:
|
|
774
|
+
// enforcing only resolved dests would allow `cd x && rm y` while denying
|
|
775
|
+
// `rm x/y`, and enforcing only fail-closed would deny the compound while
|
|
776
|
+
// letting the in-scope simple form through unchecked.
|
|
777
|
+
// An unreadable policy resolves to `off`, which is the no-new-denials
|
|
778
|
+
// direction and matches the opt-in default rather than failing closed.
|
|
779
|
+
const destFormsEnforced = loadRuntimeAuthorityPolicySafe(input, seams)?.shellDestForms === "enforce";
|
|
780
|
+
if (command !== null && destFormsEnforced) {
|
|
781
|
+
for (const dest of classifyProductDestForms(command)) {
|
|
782
|
+
if (dest.expansion === true) {
|
|
783
|
+
expansionDeny = deny(input, "scope-not-ready", toolName, `Directive denied ${toolName}: Shell dest-form target is not reconstructable ` +
|
|
784
|
+
"(compound command, glob/variable, leading ~, or a git context option). Name a " +
|
|
785
|
+
"concrete path in ONE simple command — split `cd x && rm y` into a single " +
|
|
786
|
+
"`rm x/y`, or one tool call per command — or use Edit/Write. Only a single simple " +
|
|
787
|
+
"command with an absolute dest is checked soundly; a relative dest assumes the " +
|
|
788
|
+
"shell is at the project root. Everything else stays fail-closed (#3438).");
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
const destInput = {
|
|
792
|
+
...input,
|
|
793
|
+
payload: payloadWithInjectedWriteTarget(input.payload, dest.path),
|
|
794
|
+
};
|
|
795
|
+
const destDecision = inspectMutationGates(destInput, toolName, seams, {
|
|
796
|
+
proposedLifecycleExempt: true,
|
|
797
|
+
});
|
|
798
|
+
if (destDecision.verdict === "deny")
|
|
799
|
+
return destDecision;
|
|
800
|
+
destAllow = destDecision;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const runtime = decideShellOrMcpRuntimeAuthority(input, toolName, seams);
|
|
804
|
+
if (runtime.verdict === "deny")
|
|
805
|
+
return runtime;
|
|
806
|
+
if (expansionDeny !== null)
|
|
807
|
+
return expansionDeny;
|
|
808
|
+
if (destAllow !== null && runtime.code === "shell-op-unclassifiable") {
|
|
809
|
+
return destAllow;
|
|
810
|
+
}
|
|
811
|
+
return runtime;
|
|
812
|
+
}
|
|
745
813
|
/** Decide a normalized event using only the P0 direct-write policy. */
|
|
746
814
|
export function decideHook(input, seams = {}) {
|
|
747
815
|
const projectRoot = resolve(input.projectRoot);
|
|
@@ -930,13 +998,16 @@ export function decideHook(input, seams = {}) {
|
|
|
930
998
|
}
|
|
931
999
|
return inspectMutationGates(input, toolName, seams, { proposedLifecycleExempt: false });
|
|
932
1000
|
}
|
|
933
|
-
// Shell
|
|
1001
|
+
// Shell dest-forms (#3438): recognized product mutations share inspectMutationGates
|
|
1002
|
+
// with Edit/Write (assist/scratch, proposed lifecycle, file_scope). Push/merge stay
|
|
1003
|
+
// on runtimeAuthority (#2711). Non-dest unclassifiable shell (git status) fail-open.
|
|
1004
|
+
if (isShellTool(toolName)) {
|
|
1005
|
+
return decideShellDestFormsThenRuntimeAuthority(input, toolName, seams);
|
|
1006
|
+
}
|
|
1007
|
+
// Classifiable MCP: enforce scopes.push / scopes.merge (#2711).
|
|
934
1008
|
// Route bare push/merge MCP names (merge_pull_request, git_push, …) even when
|
|
935
1009
|
// isMcpTool is false — classifyMcpTool is the gate (dispatcher-side, no tools↔policy cycle).
|
|
936
|
-
|
|
937
|
-
if (isShellTool(toolName) ||
|
|
938
|
-
isMcpTool(toolName) ||
|
|
939
|
-
classifyMcpTool(toolName, hookMcpArgsText(input.payload)) !== null) {
|
|
1010
|
+
if (isMcpTool(toolName) || classifyMcpTool(toolName, hookMcpArgsText(input.payload)) !== null) {
|
|
940
1011
|
return decideShellOrMcpRuntimeAuthority(input, toolName, seams);
|
|
941
1012
|
}
|
|
942
1013
|
if (!isDirectWriteTool(toolName)) {
|
package/dist/hooks/index.d.ts
CHANGED
package/dist/hooks/index.js
CHANGED
|
@@ -16,7 +16,7 @@ export declare const CURSOR_SESSION_HOOK_TIMEOUT_SECONDS = 5;
|
|
|
16
16
|
* Mutation tool.before runs `inspectMutationGates` → gated
|
|
17
17
|
* `verifySessionRitual`, which re-runs non-cacheable agent-hook readiness on
|
|
18
18
|
* every boundary. Live readiness alone has a multi-host fixture ceiling of
|
|
19
|
-
* ~
|
|
19
|
+
* ~24s (`content/contracts/agent-hook-readiness.md`); the historical deposit
|
|
20
20
|
* default of 5s was below that budget. Under Cursor `failClosed: true`, a
|
|
21
21
|
* host timeout kill surfaces as opaque exit-1 with no Directive decision
|
|
22
22
|
* code (#3246 / related #2864). Keep this above the readiness ceiling plus
|
|
@@ -24,7 +24,7 @@ export const CURSOR_SESSION_HOOK_TIMEOUT_SECONDS = 5;
|
|
|
24
24
|
* Mutation tool.before runs `inspectMutationGates` → gated
|
|
25
25
|
* `verifySessionRitual`, which re-runs non-cacheable agent-hook readiness on
|
|
26
26
|
* every boundary. Live readiness alone has a multi-host fixture ceiling of
|
|
27
|
-
* ~
|
|
27
|
+
* ~24s (`content/contracts/agent-hook-readiness.md`); the historical deposit
|
|
28
28
|
* default of 5s was below that budget. Under Cursor `failClosed: true`, a
|
|
29
29
|
* host timeout kill surfaces as opaque exit-1 with no Directive decision
|
|
30
30
|
* code (#3246 / related #2864). Keep this above the readiness ceiling plus
|
|
@@ -23,11 +23,15 @@ export interface ClauseStampPreparation {
|
|
|
23
23
|
readonly ambiguity_attestation?: "none_found";
|
|
24
24
|
readonly remediation?: string;
|
|
25
25
|
}
|
|
26
|
+
export declare const MISSING_AMBIGUITY_ATTESTATION_CAUSE: "missing_ambiguity_attestation";
|
|
27
|
+
export declare const AMBIGUITY_ATTESTATION_REMEDIATION = "record ambiguity readings or attest none_found";
|
|
26
28
|
export interface AmbiguityAttestationCheck {
|
|
27
29
|
readonly ok: boolean;
|
|
28
30
|
readonly attested: boolean;
|
|
29
31
|
readonly kind: "ambiguous-clause" | "none_found" | "missing";
|
|
30
32
|
readonly message: string;
|
|
33
|
+
readonly cause?: typeof MISSING_AMBIGUITY_ATTESTATION_CAUSE;
|
|
34
|
+
readonly remediation?: string;
|
|
31
35
|
}
|
|
32
36
|
/** True when activate/promote must run #3323 (absent, empty none_stated, or command-only). */
|
|
33
37
|
export declare function needsClauseDerivation(acceptance: unknown): boolean;
|
|
@@ -45,6 +49,11 @@ export declare function countClauseProvenance(clauses: readonly TracedAcceptance
|
|
|
45
49
|
export declare function prepareClauseStamp(clauses: readonly AcceptanceClause[], statement: string): ClauseStampPreparation;
|
|
46
50
|
/** Config-error surface for verify:ac: attestation or an ambiguous clause with readings. */
|
|
47
51
|
export declare function evaluateAmbiguityAttestation(acceptance: unknown): AmbiguityAttestationCheck;
|
|
52
|
+
/**
|
|
53
|
+
* Fail-closed check for a *stamped* plan.acceptance (#3559).
|
|
54
|
+
* Command-only / empty floor blocks are not stamps; they keep the empty-resolution path.
|
|
55
|
+
*/
|
|
56
|
+
export declare function stampedAmbiguityAttestationError(acceptance: unknown): AmbiguityAttestationCheck | null;
|
|
48
57
|
/**
|
|
49
58
|
* Annotate stamped clauses with provenance and an ambiguity attestation.
|
|
50
59
|
* An all-implementation stamp is stripped (never sufficient alone).
|
|
@@ -9,6 +9,8 @@ import { ENV_RUN_SUMMARY_PATH, RunSummaryEmitter, } from "../run-summary/index.j
|
|
|
9
9
|
import { deriveAcceptanceClauses, readAcceptanceClauses, serializeAcceptanceClauses, } from "../verify-ac/clauses.js";
|
|
10
10
|
/** One-line remediation when a stamp has no statement-traceable clause (#3398). */
|
|
11
11
|
export const CLAUSE_STAMP_IMPLEMENTATION_ONLY_REMEDIATION = "derive clauses from the statement's testable constraints";
|
|
12
|
+
export const MISSING_AMBIGUITY_ATTESTATION_CAUSE = "missing_ambiguity_attestation";
|
|
13
|
+
export const AMBIGUITY_ATTESTATION_REMEDIATION = "record ambiguity readings or attest none_found";
|
|
12
14
|
const NARRATIVE_KEYS = [
|
|
13
15
|
"Overview",
|
|
14
16
|
"Description",
|
|
@@ -165,12 +167,22 @@ export function prepareClauseStamp(clauses, statement) {
|
|
|
165
167
|
ambiguity_attestation: traced.some(hasAmbiguousReadings) ? undefined : "none_found",
|
|
166
168
|
};
|
|
167
169
|
}
|
|
168
|
-
const AMBIGUITY_ATTESTATION_MISSING =
|
|
170
|
+
const AMBIGUITY_ATTESTATION_MISSING = `verify:ac config error: missing ambiguity attestation; ${AMBIGUITY_ATTESTATION_REMEDIATION}`;
|
|
171
|
+
function missingAttestationCheck() {
|
|
172
|
+
return {
|
|
173
|
+
ok: false,
|
|
174
|
+
attested: false,
|
|
175
|
+
kind: "missing",
|
|
176
|
+
message: AMBIGUITY_ATTESTATION_MISSING,
|
|
177
|
+
cause: MISSING_AMBIGUITY_ATTESTATION_CAUSE,
|
|
178
|
+
remediation: AMBIGUITY_ATTESTATION_REMEDIATION,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
169
181
|
/** Config-error surface for verify:ac: attestation or an ambiguous clause with readings. */
|
|
170
182
|
export function evaluateAmbiguityAttestation(acceptance) {
|
|
171
183
|
const rec = asRecord(acceptance);
|
|
172
184
|
if (rec === null) {
|
|
173
|
-
return
|
|
185
|
+
return missingAttestationCheck();
|
|
174
186
|
}
|
|
175
187
|
const clauses = readAcceptanceClauses(rec);
|
|
176
188
|
if (clauses.some(hasAmbiguousReadings)) {
|
|
@@ -179,7 +191,22 @@ export function evaluateAmbiguityAttestation(acceptance) {
|
|
|
179
191
|
if (rec.ambiguity_attestation === "none_found") {
|
|
180
192
|
return { ok: true, attested: true, kind: "none_found", message: "" };
|
|
181
193
|
}
|
|
182
|
-
return
|
|
194
|
+
return missingAttestationCheck();
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Fail-closed check for a *stamped* plan.acceptance (#3559).
|
|
198
|
+
* Command-only / empty floor blocks are not stamps; they keep the empty-resolution path.
|
|
199
|
+
*/
|
|
200
|
+
export function stampedAmbiguityAttestationError(acceptance) {
|
|
201
|
+
const rec = asRecord(acceptance);
|
|
202
|
+
if (rec === null) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
if (readAcceptanceClauses(rec).length === 0) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const check = evaluateAmbiguityAttestation(rec);
|
|
209
|
+
return check.ok ? null : check;
|
|
183
210
|
}
|
|
184
211
|
function serializeTracedClauses(clauses) {
|
|
185
212
|
return serializeAcceptanceClauses(clauses).map((row, index) => ({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { githubAuthModesMain } from "./github-auth-modes.js";
|
|
3
|
+
import { githubAuthModesMain, INSTALLATION_IDENTITY_ISSUE_URL } from "./github-auth-modes.js";
|
|
4
4
|
function parseArgs(argv) {
|
|
5
5
|
const out = {};
|
|
6
6
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -11,11 +11,23 @@ function parseArgs(argv) {
|
|
|
11
11
|
out.repo = argv[++i];
|
|
12
12
|
else if (arg === "--github-auth-mode")
|
|
13
13
|
out.githubAuthMode = argv[++i];
|
|
14
|
+
else if (arg === "--expected-login")
|
|
15
|
+
out.expectedLogin = argv[++i];
|
|
16
|
+
else if (arg === "--expected-app-slug" || arg === "--expected-installation-id") {
|
|
17
|
+
throw new Error(`${arg} is not accepted; GitHub App installation identity is deferred to ${INSTALLATION_IDENTITY_ISSUE_URL}`);
|
|
18
|
+
}
|
|
14
19
|
}
|
|
15
20
|
return out;
|
|
16
21
|
}
|
|
17
22
|
export function mainEntry(argv = process.argv.slice(2)) {
|
|
18
|
-
|
|
23
|
+
try {
|
|
24
|
+
return githubAuthModesMain(parseArgs(argv));
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
28
|
+
process.stderr.write(`${message}\n`);
|
|
29
|
+
return 2;
|
|
30
|
+
}
|
|
19
31
|
}
|
|
20
32
|
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
21
33
|
process.exit(mainEntry());
|
|
@@ -3,12 +3,23 @@ import { probeRuntimeCapabilities, type RuntimeCapabilityReport } from "./platfo
|
|
|
3
3
|
export declare const GITHUB_AUTH_MODE_INJECTED_TOKEN = "injected-token";
|
|
4
4
|
export declare const GITHUB_AUTH_MODE_HOST_GH = "host-gh";
|
|
5
5
|
export declare const KNOWN_GITHUB_AUTH_MODES: Set<string>;
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const PRINCIPAL_KIND_USER = "user";
|
|
7
7
|
export declare const FAILURE_MISSING_INJECTED_TOKEN = "missing_injected_token";
|
|
8
8
|
export declare const FAILURE_GH_AUTH = "gh_auth_failed";
|
|
9
9
|
export declare const FAILURE_API_UNREACHABLE = "api_unreachable";
|
|
10
10
|
export declare const FAILURE_REPO_ACCESS = "repo_access_denied";
|
|
11
11
|
export declare const FAILURE_INVALID_MODE = "invalid_auth_mode";
|
|
12
|
+
export declare const FAILURE_MISSING_EXPECTED_PRINCIPAL = "missing_expected_principal";
|
|
13
|
+
export declare const FAILURE_PRINCIPAL_MISMATCH = "principal_mismatch";
|
|
14
|
+
export declare const FAILURE_MISSING_TARGET_REPO = "missing_target_repo";
|
|
15
|
+
export declare const FAILURE_INSTALLATION_IDENTITY_UNVERIFIABLE = "installation_identity_unverifiable";
|
|
16
|
+
export declare const ENV_EXPECTED_GITHUB_LOGIN = "DEFT_EXPECTED_GITHUB_LOGIN";
|
|
17
|
+
export declare const INSTALLATION_IDENTITY_ISSUE_URL = "https://github.com/deftai/directive/issues/3693";
|
|
18
|
+
/** GitHub-specific expected worker principal. Not a universal (provider-neutral) identity. */
|
|
19
|
+
export type ExpectedGithubWorkerPrincipal = {
|
|
20
|
+
readonly kind: "user";
|
|
21
|
+
readonly login: string;
|
|
22
|
+
};
|
|
12
23
|
export interface GitHubAuthValidationResult {
|
|
13
24
|
readonly ok: boolean;
|
|
14
25
|
readonly githubAuthMode: string;
|
|
@@ -17,31 +28,63 @@ export interface GitHubAuthValidationResult {
|
|
|
17
28
|
readonly detail: string;
|
|
18
29
|
readonly remediation: string | null;
|
|
19
30
|
readonly login: string | null;
|
|
31
|
+
readonly principal: ExpectedGithubWorkerPrincipal | null;
|
|
32
|
+
readonly validationRepo: string | null;
|
|
20
33
|
}
|
|
21
34
|
export type GhRunner = (args: readonly string[], environ: NodeJS.ProcessEnv) => CompletedProcess;
|
|
22
|
-
export
|
|
23
|
-
export
|
|
24
|
-
export declare function validateInjectedTokenMode(environ: NodeJS.ProcessEnv, options?: {
|
|
35
|
+
export type GitRemoteReader = (cwd?: string) => string | null;
|
|
36
|
+
export interface GithubAuthValidationOptions {
|
|
25
37
|
repo?: string;
|
|
26
38
|
runtimeMode?: string | null;
|
|
27
39
|
runGh?: GhRunner;
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
expectedPrincipal?: ExpectedGithubWorkerPrincipal | null;
|
|
41
|
+
gitRemoteUrl?: string | null;
|
|
42
|
+
readGitRemote?: GitRemoteReader;
|
|
43
|
+
cwd?: string;
|
|
44
|
+
}
|
|
45
|
+
export declare function findInjectedToken(environ: NodeJS.ProcessEnv): string | null;
|
|
46
|
+
export declare function inferGithubAuthMode(runtimeReport: RuntimeCapabilityReport): string;
|
|
47
|
+
export declare function defaultReadGitOriginUrl(cwd?: string): string | null;
|
|
48
|
+
export declare function parseOwnerRepoSlug(input: string): string | null;
|
|
49
|
+
export declare function deriveValidationRepo(options: {
|
|
30
50
|
repo?: string;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
51
|
+
environ?: NodeJS.ProcessEnv;
|
|
52
|
+
gitRemoteUrl?: string | null;
|
|
53
|
+
readGitRemote?: GitRemoteReader;
|
|
54
|
+
cwd?: string;
|
|
55
|
+
}): {
|
|
56
|
+
ok: true;
|
|
57
|
+
repo: string;
|
|
58
|
+
} | {
|
|
59
|
+
ok: false;
|
|
60
|
+
detail: string;
|
|
61
|
+
};
|
|
62
|
+
export declare function resolveExpectedGithubWorkerPrincipal(environ: NodeJS.ProcessEnv, explicit?: ExpectedGithubWorkerPrincipal | null): ExpectedGithubWorkerPrincipal | {
|
|
63
|
+
error: string;
|
|
64
|
+
} | null;
|
|
65
|
+
export declare function isInstallationUserEndpointInapplicable(proc: CompletedProcess): boolean;
|
|
66
|
+
export declare function formatUserApiFailureDetail(mode: string, proc: CompletedProcess): string;
|
|
67
|
+
export declare function validateInjectedTokenMode(environ: NodeJS.ProcessEnv, options?: GithubAuthValidationOptions): GitHubAuthValidationResult;
|
|
68
|
+
export declare function validateHostGhMode(environ: NodeJS.ProcessEnv, options?: GithubAuthValidationOptions): GitHubAuthValidationResult;
|
|
34
69
|
export declare function validateGithubAuth(githubAuthMode: string, options?: {
|
|
35
70
|
environ?: NodeJS.ProcessEnv;
|
|
36
71
|
runtimeReport?: RuntimeCapabilityReport | null;
|
|
37
72
|
repo?: string;
|
|
38
73
|
runGh?: GhRunner;
|
|
74
|
+
expectedPrincipal?: ExpectedGithubWorkerPrincipal | null;
|
|
75
|
+
gitRemoteUrl?: string | null;
|
|
76
|
+
readGitRemote?: GitRemoteReader;
|
|
77
|
+
cwd?: string;
|
|
39
78
|
}): GitHubAuthValidationResult;
|
|
40
79
|
export declare function validateGithubAuthForWorker(githubAuthMode?: string | null, options?: {
|
|
41
80
|
environ?: NodeJS.ProcessEnv;
|
|
42
81
|
runtimeReport?: RuntimeCapabilityReport | null;
|
|
43
82
|
repo?: string;
|
|
44
83
|
runGh?: GhRunner;
|
|
84
|
+
expectedPrincipal?: ExpectedGithubWorkerPrincipal | null;
|
|
85
|
+
gitRemoteUrl?: string | null;
|
|
86
|
+
readGitRemote?: GitRemoteReader;
|
|
87
|
+
cwd?: string;
|
|
45
88
|
}): GitHubAuthValidationResult;
|
|
46
89
|
export declare function resultToDict(result: GitHubAuthValidationResult): Record<string, unknown>;
|
|
47
90
|
export interface GitHubAuthModesCliArgs {
|
|
@@ -49,6 +92,8 @@ export interface GitHubAuthModesCliArgs {
|
|
|
49
92
|
repo?: string;
|
|
50
93
|
json?: boolean;
|
|
51
94
|
runGh?: GhRunner;
|
|
95
|
+
expectedLogin?: string;
|
|
96
|
+
expectedPrincipal?: ExpectedGithubWorkerPrincipal | null;
|
|
52
97
|
}
|
|
53
98
|
export declare function githubAuthModesMain(args: GitHubAuthModesCliArgs): number;
|
|
54
99
|
export { probeRuntimeCapabilities };
|