@deftai/directive-core 0.104.0 → 0.106.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 +1108 -67
- package/dist/check/cached-orchestrator.d.ts +1 -1
- package/dist/check/cached-orchestrator.js +2 -2
- package/dist/check/named-cause.d.ts +1 -1
- package/dist/check/named-cause.js +34 -4
- package/dist/codebase/default-extractor.d.ts +5 -0
- package/dist/codebase/default-extractor.js +7 -15
- package/dist/deposit/copy-tree.js +60 -0
- package/dist/deposit/python-free.js +26 -18
- package/dist/doctor/checks.d.ts +8 -0
- package/dist/doctor/checks.js +37 -25
- package/dist/doctor/doctor-state.d.ts +4 -0
- package/dist/doctor/doctor-state.js +7 -1
- package/dist/doctor/main.js +9 -19
- package/dist/doctor/types.d.ts +9 -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/fs/contained-write.d.ts +115 -1
- package/dist/fs/contained-write.js +241 -5
- package/dist/fs/mutation-ledger.d.ts +54 -0
- package/dist/fs/mutation-ledger.js +133 -0
- package/dist/fs/non-product-dirs.d.ts +79 -0
- package/dist/fs/non-product-dirs.js +96 -0
- package/dist/hooks/dispatcher.d.ts +3 -1
- package/dist/hooks/dispatcher.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +18 -16
- package/dist/init-deposit/core-guard-pin-content.d.ts +7 -0
- package/dist/init-deposit/core-guard-pin-content.js +393 -0
- package/dist/init-deposit/gitignore.js +9 -0
- package/dist/init-deposit/hygiene.d.ts +47 -11
- package/dist/init-deposit/hygiene.js +172 -37
- package/dist/init-deposit/legacy-detect.js +6 -2
- package/dist/init-deposit/refresh.d.ts +21 -1
- package/dist/init-deposit/refresh.js +106 -9
- package/dist/init-deposit/scaffold.js +28 -279
- package/dist/init-deposit/slash-deposit.js +13 -7
- package/dist/init-deposit/xbrief-projections.d.ts +8 -1
- package/dist/init-deposit/xbrief-projections.js +24 -11
- package/dist/intake/clause-derivation.d.ts +47 -1
- package/dist/intake/clause-derivation.js +238 -9
- package/dist/intake/issue-ingest.d.ts +3 -1
- package/dist/intake/issue-ingest.js +35 -6
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
- 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 +10 -0
- package/dist/literal-acceptance/capture.js +226 -77
- package/dist/literal-acceptance/evaluate.d.ts +29 -4
- package/dist/literal-acceptance/evaluate.js +70 -2
- package/dist/literal-acceptance/index.d.ts +3 -3
- package/dist/literal-acceptance/index.js +3 -3
- package/dist/literal-acceptance/safety.d.ts +41 -0
- package/dist/literal-acceptance/safety.js +126 -2
- package/dist/literal-acceptance/types.d.ts +8 -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/orphan-active/evaluate.d.ts +7 -1
- package/dist/orphan-active/evaluate.js +102 -23
- package/dist/platform/platform-capabilities.js +2 -3
- package/dist/policy/base-branch.d.ts +37 -0
- package/dist/policy/base-branch.js +114 -0
- package/dist/policy/branch-sync.d.ts +80 -0
- package/dist/policy/branch-sync.js +211 -0
- package/dist/policy/ceremony-dial-escalation.js +1 -0
- package/dist/policy/ceremony-dial.js +11 -21
- package/dist/policy/delivery-branch.d.ts +5 -3
- package/dist/policy/delivery-branch.js +7 -3
- package/dist/policy/file-size-thresholds.d.ts +24 -0
- package/dist/policy/file-size-thresholds.js +23 -0
- package/dist/policy/forge-outage-retry.d.ts +47 -0
- package/dist/policy/forge-outage-retry.js +157 -0
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- package/dist/policy/index.d.ts +7 -0
- package/dist/policy/index.js +66 -7
- 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/project-invariants.d.ts +50 -0
- package/dist/policy/project-invariants.js +205 -0
- 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/sync-default.d.ts +129 -0
- package/dist/policy/sync-default.js +452 -0
- package/dist/policy/sync-max-files.d.ts +93 -0
- package/dist/policy/sync-max-files.js +192 -0
- package/dist/policy/value-feedback.js +7 -8
- package/dist/pr-monitor/absent-required.d.ts +11 -0
- package/dist/pr-monitor/absent-required.js +61 -0
- package/dist/pr-monitor/constants.d.ts +7 -0
- package/dist/pr-monitor/constants.js +7 -0
- package/dist/pr-monitor/index.d.ts +2 -1
- package/dist/pr-monitor/index.js +2 -1
- package/dist/pr-monitor/main.js +4 -0
- package/dist/pr-monitor/monitor.js +24 -1
- package/dist/pr-wait-mergeable/classify.js +6 -0
- package/dist/preflight/evaluate.d.ts +4 -0
- package/dist/preflight/evaluate.js +35 -1
- package/dist/preflight/index.d.ts +4 -0
- package/dist/preflight/index.js +2 -0
- package/dist/preflight/intended-placement.d.ts +62 -0
- package/dist/preflight/intended-placement.js +275 -0
- package/dist/preflight/project-invariants-gate.d.ts +29 -0
- package/dist/preflight/project-invariants-gate.js +82 -0
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +15 -1
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/acceptance-resolver.d.ts +128 -0
- package/dist/product-first-done-gate/acceptance-resolver.js +144 -0
- package/dist/product-first-done-gate/acceptance.d.ts +7 -4
- package/dist/product-first-done-gate/acceptance.js +79 -8
- package/dist/product-first-done-gate/empty-resolution.d.ts +4 -1
- package/dist/product-first-done-gate/empty-resolution.js +12 -1
- package/dist/product-first-done-gate/evaluate.d.ts +16 -0
- package/dist/product-first-done-gate/evaluate.js +298 -34
- package/dist/product-first-done-gate/index.d.ts +2 -0
- package/dist/product-first-done-gate/index.js +1 -0
- package/dist/release/build-dist.d.ts +101 -0
- package/dist/release/build-dist.js +428 -46
- 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/emit.d.ts +16 -10
- package/dist/run-summary/emit.js +26 -15
- package/dist/run-summary/index.d.ts +3 -2
- package/dist/run-summary/index.js +2 -1
- package/dist/run-summary/session-id.d.ts +21 -0
- package/dist/run-summary/session-id.js +92 -0
- package/dist/run-summary/types.d.ts +33 -4
- package/dist/run-summary/types.js +1 -0
- package/dist/scope/acceptance-evidence.d.ts +19 -7
- package/dist/scope/acceptance-evidence.js +38 -11
- package/dist/scope/delivery-evidence.d.ts +3 -3
- package/dist/scope/delivery-evidence.js +22 -27
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/main.js +15 -5
- package/dist/scope/parent-lineage.js +7 -6
- package/dist/scope/project-invariant-coverage.d.ts +54 -0
- package/dist/scope/project-invariant-coverage.js +322 -0
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope/transition.js +1 -1
- package/dist/scope-provenance/compare-intent.d.ts +27 -0
- package/dist/scope-provenance/compare-intent.js +233 -0
- package/dist/scope-provenance/digest.d.ts +18 -1
- package/dist/scope-provenance/digest.js +16 -11
- package/dist/scope-provenance/evaluate.d.ts +5 -1
- package/dist/scope-provenance/evaluate.js +67 -7
- package/dist/scope-provenance/extract-intent.d.ts +43 -0
- package/dist/scope-provenance/extract-intent.js +262 -0
- package/dist/scope-provenance/index.d.ts +7 -1
- package/dist/scope-provenance/index.js +7 -1
- package/dist/scope-provenance/intent-digest.d.ts +12 -0
- package/dist/scope-provenance/intent-digest.js +33 -0
- package/dist/scope-provenance/intent-evaluate.d.ts +43 -0
- package/dist/scope-provenance/intent-evaluate.js +149 -0
- package/dist/scope-provenance/json-tokenizer.d.ts +19 -0
- package/dist/scope-provenance/json-tokenizer.js +225 -0
- package/dist/scope-provenance/known-machine.d.ts +38 -0
- package/dist/scope-provenance/known-machine.js +157 -0
- package/dist/scope-provenance/mint-artifacts.d.ts +102 -0
- package/dist/scope-provenance/mint-artifacts.js +425 -0
- package/dist/session/ac-pass-banking.d.ts +9 -36
- package/dist/session/ac-pass-banking.js +33 -79
- package/dist/session/ac-pass-reuse.d.ts +53 -0
- package/dist/session/ac-pass-reuse.js +95 -0
- package/dist/session/git.js +19 -4
- package/dist/session/index.d.ts +4 -0
- package/dist/session/index.js +4 -0
- package/dist/session/occupancy-stress-worker.d.ts +7 -0
- package/dist/session/occupancy-stress-worker.js +36 -0
- package/dist/session/occupancy.d.ts +97 -0
- package/dist/session/occupancy.js +422 -0
- package/dist/session/openclaw-soft-rebind-deposit.js +6 -6
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.d.ts +26 -0
- package/dist/session/product-state-hash.js +700 -0
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-ready.d.ts +2 -0
- package/dist/session/session-ready.js +52 -30
- package/dist/session/session-start.d.ts +13 -0
- package/dist/session/session-start.js +103 -9
- package/dist/session/verify-ac-session-cache.d.ts +42 -0
- package/dist/session/verify-ac-session-cache.js +126 -0
- package/dist/session/verify-session-ritual.d.ts +28 -0
- package/dist/session/verify-session-ritual.js +97 -5
- package/dist/slash/openclaw-deposit.js +13 -9
- package/dist/slice/constants.d.ts +2 -2
- package/dist/slice/constants.js +2 -2
- package/dist/slice/existing.js +9 -3
- package/dist/slice/lock.d.ts +16 -1
- package/dist/slice/lock.js +137 -11
- package/dist/story-ready/evaluate.d.ts +2 -0
- package/dist/story-ready/evaluate.js +13 -0
- package/dist/swarm/complete-cohort.d.ts +3 -0
- package/dist/swarm/complete-cohort.js +59 -11
- 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 +47 -4
- package/dist/swarm/launch.d.ts +22 -0
- package/dist/swarm/launch.js +155 -0
- package/dist/swarm/routing-set-cli.d.ts +11 -1
- package/dist/swarm/routing-set-cli.js +15 -3
- package/dist/swarm/routing-verify.d.ts +13 -1
- package/dist/swarm/routing-verify.js +60 -21
- package/dist/swarm/routing.d.ts +14 -0
- package/dist/swarm/routing.js +53 -3
- package/dist/telemetry-coverage/fake-trial.js +10 -0
- package/dist/telemetry-coverage/kinds.js +2 -0
- package/dist/triage/actions/index.js +4 -1
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/help/registry-data.d.ts +1 -1
- package/dist/triage/help/registry-data.js +1 -1
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/ts-check-lane/index.d.ts +3 -0
- package/dist/ts-check-lane/index.js +2 -0
- package/dist/ts-check-lane/progress-reporter.d.ts +17 -0
- package/dist/ts-check-lane/progress-reporter.js +38 -0
- package/dist/ts-check-lane/progress.d.ts +32 -0
- package/dist/ts-check-lane/progress.js +57 -0
- package/dist/ts-check-lane/run-lane.d.ts +3 -1
- package/dist/ts-check-lane/run-lane.js +8 -6
- package/dist/validate-content/validate-links.d.ts +8 -0
- package/dist/validate-content/validate-links.js +9 -15
- package/dist/value/feedback-file.js +12 -2
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-build/index.d.ts +1 -0
- package/dist/vbrief-build/index.js +1 -0
- package/dist/vbrief-build/project-invariants-io.d.ts +16 -0
- package/dist/vbrief-build/project-invariants-io.js +41 -0
- package/dist/vbrief-reconcile/graph.js +18 -1
- package/dist/vbrief-reconcile/index.d.ts +1 -1
- package/dist/vbrief-reconcile/index.js +1 -1
- package/dist/vbrief-reconcile/types.d.ts +13 -0
- package/dist/vbrief-reconcile/umbrellas.d.ts +14 -0
- package/dist/vbrief-reconcile/umbrellas.js +261 -26
- package/dist/vbrief-validate/index.d.ts +1 -1
- package/dist/vbrief-validate/index.js +1 -1
- package/dist/vbrief-validate/plan-hooks.d.ts +4 -0
- package/dist/vbrief-validate/plan-hooks.js +68 -0
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/verify-ac/evaluate.d.ts +7 -1
- package/dist/verify-ac/evaluate.js +34 -26
- package/dist/verify-ac/flag.d.ts +4 -0
- package/dist/verify-ac/flag.js +16 -0
- package/dist/verify-ac/index.d.ts +2 -2
- package/dist/verify-ac/index.js +2 -2
- 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/verify-source/contained-writes.js +2 -0
- package/dist/verify-source/verify-stubs.d.ts +15 -1
- package/dist/verify-source/verify-stubs.js +20 -16
- package/dist/vitest-runner/win32-coverage-tmp-setup.d.ts +5 -6
- package/dist/vitest-runner/win32-coverage-tmp-setup.js +5 -6
- package/dist/xbrief-migrate/migrate-project.js +2 -5
- package/package.json +7 -3
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public compare entry for extracted intent (#3376 R2 / R5 / #3385 F1–F2).
|
|
3
|
+
*
|
|
4
|
+
* Scalars are byte-equal after canonicalize. Decisions and references[] are
|
|
5
|
+
* guarded-append. Unclassified key only when unknown AND absent from base.
|
|
6
|
+
*/
|
|
7
|
+
import { DECISION_FILE_SUFFIX, DECISIONS_DIR_REL } from "../decision/schema.js";
|
|
8
|
+
import { GITHUB_ISSUE_REF_TYPES } from "../intake/reconcile-issues.js";
|
|
9
|
+
import { slugFromGithubIssueUri } from "./extract-intent.js";
|
|
10
|
+
import { sortKeysDeep } from "./intent-digest.js";
|
|
11
|
+
import { classifyPlanPath } from "./known-machine.js";
|
|
12
|
+
const EM_DASH = "\u2014";
|
|
13
|
+
const DECISION_LINE = new RegExp(`^- (${DECISIONS_DIR_REL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/[^\\s]+${DECISION_FILE_SUFFIX.replace(".", "\\.")}) ${EM_DASH} (.+)$`);
|
|
14
|
+
function canon(value) {
|
|
15
|
+
return JSON.stringify(sortKeysDeep(value));
|
|
16
|
+
}
|
|
17
|
+
function asRecord(value) {
|
|
18
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
19
|
+
return null;
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
function splitDecisionLines(raw) {
|
|
23
|
+
if (typeof raw !== "string")
|
|
24
|
+
return [];
|
|
25
|
+
return raw
|
|
26
|
+
.split(/\r?\n/)
|
|
27
|
+
.map((l) => l.trim())
|
|
28
|
+
.filter((l) => l.length > 0);
|
|
29
|
+
}
|
|
30
|
+
function refKey(ref) {
|
|
31
|
+
return `${String(ref.type ?? "")}\n${String(ref.uri ?? "")}`;
|
|
32
|
+
}
|
|
33
|
+
function narrativesOf(plan) {
|
|
34
|
+
return asRecord(plan.narratives) ?? {};
|
|
35
|
+
}
|
|
36
|
+
function compareScalars(basePlan, livePlan, findings) {
|
|
37
|
+
const skip = new Set(["references", "narratives", "items", "parentId"]);
|
|
38
|
+
const keys = new Set([...Object.keys(basePlan), ...Object.keys(livePlan)]);
|
|
39
|
+
for (const key of keys) {
|
|
40
|
+
if (skip.has(key))
|
|
41
|
+
continue;
|
|
42
|
+
if (key === "metadata") {
|
|
43
|
+
if (canon(basePlan.metadata) !== canon(livePlan.metadata)) {
|
|
44
|
+
findings.push({
|
|
45
|
+
kind: "intent-drift",
|
|
46
|
+
path: "metadata",
|
|
47
|
+
detail: "extracted metadata drifted from the base preimage",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (canon(basePlan[key]) !== canon(livePlan[key])) {
|
|
53
|
+
findings.push({
|
|
54
|
+
kind: "intent-drift",
|
|
55
|
+
path: key,
|
|
56
|
+
detail: `extracted ${key} drifted from the base preimage`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function compareItems(baseItems, liveItems, findings) {
|
|
62
|
+
if (canon(baseItems ?? []) !== canon(liveItems ?? [])) {
|
|
63
|
+
findings.push({
|
|
64
|
+
kind: "intent-drift",
|
|
65
|
+
path: "items",
|
|
66
|
+
detail: "extracted items drifted from the base preimage",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function compareNarratives(basePlan, livePlan, options, findings) {
|
|
71
|
+
const baseN = narrativesOf(basePlan);
|
|
72
|
+
const liveN = narrativesOf(livePlan);
|
|
73
|
+
const keys = new Set([...Object.keys(baseN), ...Object.keys(liveN)]);
|
|
74
|
+
for (const key of keys) {
|
|
75
|
+
if (key === "Decisions")
|
|
76
|
+
continue;
|
|
77
|
+
if (canon(baseN[key]) !== canon(liveN[key])) {
|
|
78
|
+
findings.push({
|
|
79
|
+
kind: "intent-drift",
|
|
80
|
+
path: `narratives.${key}`,
|
|
81
|
+
detail: `extracted narratives.${key} drifted from the base preimage`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const baseLines = splitDecisionLines(baseN.Decisions);
|
|
86
|
+
const liveLines = splitDecisionLines(liveN.Decisions);
|
|
87
|
+
if (liveLines.length < baseLines.length) {
|
|
88
|
+
findings.push({
|
|
89
|
+
kind: "decisions-mutation",
|
|
90
|
+
path: "narratives.Decisions",
|
|
91
|
+
detail: "Decisions lines were deleted; preimage lines are law",
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < baseLines.length; i += 1) {
|
|
96
|
+
if (liveLines[i] !== baseLines[i]) {
|
|
97
|
+
findings.push({
|
|
98
|
+
kind: "decisions-mutation",
|
|
99
|
+
path: "narratives.Decisions",
|
|
100
|
+
detail: "existing Decisions lines were edited; only append is allowed",
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const changed = new Set((options.changedFiles ?? []).map((p) => p.replace(/\\/g, "/")));
|
|
106
|
+
for (const line of liveLines.slice(baseLines.length)) {
|
|
107
|
+
const m = DECISION_LINE.exec(line);
|
|
108
|
+
if (m === null) {
|
|
109
|
+
findings.push({
|
|
110
|
+
kind: "decisions-mutation",
|
|
111
|
+
path: "narratives.Decisions",
|
|
112
|
+
detail: `appended Decisions line is not '- <${DECISIONS_DIR_REL}>/…${DECISION_FILE_SUFFIX} ${EM_DASH} <summary>'`,
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const rel = m[1] ?? "";
|
|
117
|
+
const onBaseOrChange = changed.has(rel) || Boolean(options.decisionExists?.(rel));
|
|
118
|
+
if (!onBaseOrChange) {
|
|
119
|
+
findings.push({
|
|
120
|
+
kind: "decision-pointer-missing",
|
|
121
|
+
path: "narratives.Decisions",
|
|
122
|
+
detail: `Decisions pointer ${rel} is not on base and not in the change set`,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function compareReferences(base, live, findings) {
|
|
128
|
+
const baseRefs = Array.isArray(base.plan.references)
|
|
129
|
+
? base.plan.references
|
|
130
|
+
: [];
|
|
131
|
+
const liveRefs = Array.isArray(live.plan.references)
|
|
132
|
+
? live.plan.references
|
|
133
|
+
: [];
|
|
134
|
+
const liveByKey = new Map();
|
|
135
|
+
for (const ref of liveRefs) {
|
|
136
|
+
liveByKey.set(refKey(ref), ref);
|
|
137
|
+
}
|
|
138
|
+
for (const ref of baseRefs) {
|
|
139
|
+
const key = refKey(ref);
|
|
140
|
+
const liveRef = liveByKey.get(key);
|
|
141
|
+
if (liveRef === undefined) {
|
|
142
|
+
findings.push({
|
|
143
|
+
kind: "reference-mutation",
|
|
144
|
+
path: "references",
|
|
145
|
+
detail: `origin reference removed: ${String(ref.uri ?? "")}`,
|
|
146
|
+
});
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (canon(ref) !== canon(liveRef)) {
|
|
150
|
+
findings.push({
|
|
151
|
+
kind: "reference-mutation",
|
|
152
|
+
path: "references",
|
|
153
|
+
detail: `origin reference edited: ${String(ref.uri ?? "")}`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const baseKeys = new Set(baseRefs.map(refKey));
|
|
158
|
+
const approved = new Set(base.approvedRepos.map((s) => s.toLowerCase()));
|
|
159
|
+
for (const ref of liveRefs) {
|
|
160
|
+
if (baseKeys.has(refKey(ref)))
|
|
161
|
+
continue;
|
|
162
|
+
const type = String(ref.type ?? "");
|
|
163
|
+
if (!GITHUB_ISSUE_REF_TYPES.has(type)) {
|
|
164
|
+
findings.push({
|
|
165
|
+
kind: "ref-type-not-appendable",
|
|
166
|
+
path: "references",
|
|
167
|
+
detail: `appended reference type ${JSON.stringify(type)} is not in GITHUB_ISSUE_REF_TYPES`,
|
|
168
|
+
});
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const uri = typeof ref.uri === "string" ? ref.uri : "";
|
|
172
|
+
const slug = slugFromGithubIssueUri(uri);
|
|
173
|
+
if (slug === null || !approved.has(slug)) {
|
|
174
|
+
findings.push({
|
|
175
|
+
kind: "repo-not-approved",
|
|
176
|
+
path: "references",
|
|
177
|
+
detail: `appended github-issue URL is not in the base preimage approvedRepos: ${uri}`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function compareUnknownKeys(base, live, findings) {
|
|
183
|
+
const baseUnknown = new Set(base.unknownPaths);
|
|
184
|
+
const basePlan = asRecord(base.plan) ?? {};
|
|
185
|
+
for (const path of live.unknownPaths) {
|
|
186
|
+
if (baseUnknown.has(path))
|
|
187
|
+
continue;
|
|
188
|
+
const top = path.split(".")[0] ?? path;
|
|
189
|
+
if (top in basePlan && classifyPlanPath(top) === "unknown")
|
|
190
|
+
continue;
|
|
191
|
+
const parts = path.split(".");
|
|
192
|
+
let cursor = base.plan;
|
|
193
|
+
let present = true;
|
|
194
|
+
for (const part of parts) {
|
|
195
|
+
const rec = asRecord(cursor);
|
|
196
|
+
if (rec === null || !(part in rec)) {
|
|
197
|
+
present = false;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
cursor = rec[part];
|
|
201
|
+
}
|
|
202
|
+
if (present)
|
|
203
|
+
continue;
|
|
204
|
+
findings.push({
|
|
205
|
+
kind: "unclassified-key",
|
|
206
|
+
path,
|
|
207
|
+
detail: `unclassified key ${path} is absent from the base preimage`,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Compare a live extraction to the base-committed preimage.
|
|
213
|
+
* One entry point covers scalar equality and guarded append (R2 / R5).
|
|
214
|
+
*/
|
|
215
|
+
export function compareExtractedIntent(base, live, options = {}) {
|
|
216
|
+
const findings = [];
|
|
217
|
+
const basePlan = asRecord(base.plan) ?? {};
|
|
218
|
+
const livePlan = asRecord(live.plan) ?? {};
|
|
219
|
+
if (canon(basePlan.parentId) !== canon(livePlan.parentId)) {
|
|
220
|
+
findings.push({
|
|
221
|
+
kind: "intent-drift",
|
|
222
|
+
path: "parentId",
|
|
223
|
+
detail: "parent identity changed (silent reparent)",
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
compareScalars(basePlan, livePlan, findings);
|
|
227
|
+
compareItems(basePlan.items, livePlan.items, findings);
|
|
228
|
+
compareNarratives(basePlan, livePlan, options, findings);
|
|
229
|
+
compareReferences(base, live, findings);
|
|
230
|
+
compareUnknownKeys(base, live, findings);
|
|
231
|
+
return { ok: findings.length === 0, findings };
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=compare-intent.js.map
|
|
@@ -27,8 +27,15 @@ export interface ApprovedScopeRecord {
|
|
|
27
27
|
readonly mintedAt: string;
|
|
28
28
|
readonly mintedVia?: string;
|
|
29
29
|
};
|
|
30
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Legacy optional body digest. Wave 1 (#3384 F4) does not write this on new
|
|
32
|
+
* records. Do not treat it as authority (Wave 2 #3385 / R6).
|
|
33
|
+
*/
|
|
31
34
|
readonly xbriefBodyDigest?: string;
|
|
35
|
+
/** Checksum of the base-committed `.intent.json` preimage (#3385). */
|
|
36
|
+
readonly intentDigest?: string;
|
|
37
|
+
/** Digest algorithm name; Wave 2 writes `intent-extract-v1`. */
|
|
38
|
+
readonly digestAlgo?: string;
|
|
32
39
|
}
|
|
33
40
|
export declare const APPROVED_SCOPE_DIR = ".deft/approved-scope";
|
|
34
41
|
/** Normalize and sort scope paths for stable digests. */
|
|
@@ -42,14 +49,24 @@ export declare function extractFileScope(payload: unknown): string[];
|
|
|
42
49
|
/** Extract plan.id from an xBRIEF payload. */
|
|
43
50
|
export declare function extractPlanId(payload: unknown): string | null;
|
|
44
51
|
export declare function approvedScopeDir(projectRoot: string): string;
|
|
52
|
+
export declare function approvedScopeSafePlanId(planId: string): string;
|
|
45
53
|
export declare function approvedScopeRecordPath(projectRoot: string, planId: string): string;
|
|
54
|
+
/** Repo-relative preimage path. */
|
|
55
|
+
export declare function approvedScopeIntentRel(planId: string): string;
|
|
56
|
+
export declare function approvedScopeIntentPath(projectRoot: string, planId: string): string;
|
|
46
57
|
/** Build an ApprovedScopeRecord from xBRIEF payload + metadata. */
|
|
47
58
|
export declare function buildApprovedScopeRecord(input: {
|
|
48
59
|
readonly xbriefRelPath: string;
|
|
49
60
|
readonly payload: unknown;
|
|
50
61
|
readonly approvedAt?: string;
|
|
51
62
|
readonly humanApproval?: ApprovedScopeRecord["humanApproval"];
|
|
63
|
+
/**
|
|
64
|
+
* Ignored. Wave 1 (#3384 F4) no longer writes `xbriefBodyDigest` on new records.
|
|
65
|
+
* Kept so existing callers do not have to drop the field in the same change.
|
|
66
|
+
*/
|
|
52
67
|
readonly xbriefRawText?: string;
|
|
68
|
+
readonly intentDigest?: string;
|
|
69
|
+
readonly digestAlgo?: string;
|
|
53
70
|
}): ApprovedScopeRecord;
|
|
54
71
|
/** Persist approved-scope record (activation / renewed human approval). */
|
|
55
72
|
export declare function writeApprovedScopeRecord(projectRoot: string, record: ApprovedScopeRecord): string;
|
|
@@ -69,9 +69,18 @@ export function extractPlanId(payload) {
|
|
|
69
69
|
export function approvedScopeDir(projectRoot) {
|
|
70
70
|
return join(resolve(projectRoot), ...APPROVED_SCOPE_DIR.split("/"));
|
|
71
71
|
}
|
|
72
|
+
export function approvedScopeSafePlanId(planId) {
|
|
73
|
+
return planId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
74
|
+
}
|
|
72
75
|
export function approvedScopeRecordPath(projectRoot, planId) {
|
|
73
|
-
|
|
74
|
-
|
|
76
|
+
return join(approvedScopeDir(projectRoot), `${approvedScopeSafePlanId(planId)}.json`);
|
|
77
|
+
}
|
|
78
|
+
/** Repo-relative preimage path. */
|
|
79
|
+
export function approvedScopeIntentRel(planId) {
|
|
80
|
+
return `.deft/approved-scope/${approvedScopeSafePlanId(planId)}.intent.json`;
|
|
81
|
+
}
|
|
82
|
+
export function approvedScopeIntentPath(projectRoot, planId) {
|
|
83
|
+
return join(approvedScopeDir(projectRoot), `${approvedScopeSafePlanId(planId)}.intent.json`);
|
|
75
84
|
}
|
|
76
85
|
/** Build an ApprovedScopeRecord from xBRIEF payload + metadata. */
|
|
77
86
|
export function buildApprovedScopeRecord(input) {
|
|
@@ -87,17 +96,13 @@ export function buildApprovedScopeRecord(input) {
|
|
|
87
96
|
fileScope,
|
|
88
97
|
fileScopeDigest,
|
|
89
98
|
};
|
|
99
|
+
const withIntent = input.intentDigest !== undefined
|
|
100
|
+
? { ...record, intentDigest: input.intentDigest, digestAlgo: input.digestAlgo }
|
|
101
|
+
: record;
|
|
90
102
|
if (input.humanApproval !== undefined) {
|
|
91
|
-
return {
|
|
92
|
-
...record,
|
|
93
|
-
humanApproval: input.humanApproval,
|
|
94
|
-
xbriefBodyDigest: input.xbriefRawText !== undefined ? computeTextDigest(input.xbriefRawText) : undefined,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
if (input.xbriefRawText !== undefined) {
|
|
98
|
-
return { ...record, xbriefBodyDigest: computeTextDigest(input.xbriefRawText) };
|
|
103
|
+
return { ...withIntent, humanApproval: input.humanApproval };
|
|
99
104
|
}
|
|
100
|
-
return
|
|
105
|
+
return withIntent;
|
|
101
106
|
}
|
|
102
107
|
/** Persist approved-scope record (activation / renewed human approval). */
|
|
103
108
|
export function writeApprovedScopeRecord(projectRoot, record) {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Migration: missing approved-scope records → warn (exit 0) unless --enforce.
|
|
10
10
|
*/
|
|
11
11
|
import { type ApprovedScopeRecord } from "./digest.js";
|
|
12
|
-
export type ScopeProvenanceViolationKind = "self-authorizing-scope-expansion" | "active-xbrief-modified-without-digest" | "digest-mismatch-without-renewal";
|
|
12
|
+
export type ScopeProvenanceViolationKind = "self-authorizing-scope-expansion" | "active-xbrief-modified-without-digest" | "digest-mismatch-without-renewal" | "intent-drift" | "unclassified-key" | "intent-digest-mismatch" | "duplicate-key" | "duplicate-item-id" | "same-pr-intent-rewrite" | "first-activation-missing-intent-pin" | "legacy-intent-edit" | "intent-parse-error";
|
|
13
13
|
export interface ScopeProvenanceFinding {
|
|
14
14
|
readonly xbriefRelPath: string;
|
|
15
15
|
readonly planId: string;
|
|
@@ -39,6 +39,10 @@ export interface ScopeProvenanceOptions {
|
|
|
39
39
|
readonly approvedRecords?: readonly ApprovedScopeRecord[];
|
|
40
40
|
/** Inject renewed-approval stamps keyed by planId (test seam). */
|
|
41
41
|
readonly renewedApprovals?: ReadonlyMap<string, ApprovedScopeRecord["humanApproval"]>;
|
|
42
|
+
/** Inject `git show <base>:<rel>` (test seam; never working-tree). */
|
|
43
|
+
readonly readAtBase?: (relPath: string) => string | null;
|
|
44
|
+
/** Optional repo slug seed for live extract (mint uses resolveProjectRepo). */
|
|
45
|
+
readonly approvedReposSeed?: readonly string[];
|
|
42
46
|
}
|
|
43
47
|
/**
|
|
44
48
|
* Resolve a PR-aware base ref. Bare `HEAD` only shows uncommitted changes, so
|
|
@@ -12,7 +12,9 @@ import { spawnSync } from "node:child_process";
|
|
|
12
12
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
13
13
|
import { join, resolve } from "node:path";
|
|
14
14
|
import { GitCommandError, GitNotFoundError } from "../encoding/git.js";
|
|
15
|
-
import { computeFileScopeDigest, extractFileScope, extractPlanId, isHumanApprovalStamp, listApprovedScopeRecords, normalizeFileScope, readApprovedScopeRecord, scopeExpansion, } from "./digest.js";
|
|
15
|
+
import { approvedScopeIntentRel, computeFileScopeDigest, extractFileScope, extractPlanId, isHumanApprovalStamp, listApprovedScopeRecords, normalizeFileScope, readApprovedScopeRecord, scopeExpansion, } from "./digest.js";
|
|
16
|
+
import { bodyDigestIsAuthority, evaluateIntentForXbrief } from "./intent-evaluate.js";
|
|
17
|
+
import { recoverApprovedScopePairs } from "./mint-artifacts.js";
|
|
16
18
|
function git(args, projectRoot) {
|
|
17
19
|
const result = spawnSync("git", args, {
|
|
18
20
|
cwd: projectRoot,
|
|
@@ -203,7 +205,7 @@ function listActiveXbriefPaths(projectRoot) {
|
|
|
203
205
|
}
|
|
204
206
|
function remediationForExpansion() {
|
|
205
207
|
return ("Renew human approval: re-record the approved-scope digest after operator review " +
|
|
206
|
-
"(`task scope:record-approved-scope -- <xbrief-path> --actor <you
|
|
208
|
+
"(`task scope:record-approved-scope -- <xbrief-path> --actor <you> --confirm` writes " +
|
|
207
209
|
"`.deft/approved-scope/<plan-id>.json` with a humanApproval stamp). Commit that " +
|
|
208
210
|
"approval on the merge base (or a prior PR) before expanding or activating the " +
|
|
209
211
|
"scoped xBRIEF in the implementation change set. Editing the active xBRIEF alone " +
|
|
@@ -236,6 +238,8 @@ export function parseApprovedScopeRecordRaw(raw) {
|
|
|
236
238
|
const expected = computeFileScopeDigest(scopePaths);
|
|
237
239
|
if (rec.fileScopeDigest !== expected)
|
|
238
240
|
return null;
|
|
241
|
+
// xbriefBodyDigest is never authority (#3385 F4 / R6) — ignored if present.
|
|
242
|
+
bodyDigestIsAuthority(data);
|
|
239
243
|
return data;
|
|
240
244
|
}
|
|
241
245
|
catch {
|
|
@@ -340,7 +344,7 @@ export function evaluateOneScopeProvenance(input) {
|
|
|
340
344
|
detail: "active xBRIEF modified with a non-human (agent/missing) approved-scope stamp; " +
|
|
341
345
|
"only humanApproval stamps authorize non-empty file_scope",
|
|
342
346
|
remediation: "Record a human-origin approval via `task scope:record-approved-scope -- " +
|
|
343
|
-
"<xbrief-path> --actor <you
|
|
347
|
+
"<xbrief-path> --actor <you> --confirm` (#3145 / #3205).",
|
|
344
348
|
};
|
|
345
349
|
}
|
|
346
350
|
}
|
|
@@ -357,7 +361,7 @@ export function evaluateOneScopeProvenance(input) {
|
|
|
357
361
|
detail: "active xBRIEF modified with a non-human approved-scope stamp (scope shrink/noise path); " +
|
|
358
362
|
"only humanApproval stamps authorize non-empty file_scope",
|
|
359
363
|
remediation: "Record a human-origin approval via `task scope:record-approved-scope -- " +
|
|
360
|
-
"<xbrief-path> --actor <you
|
|
364
|
+
"<xbrief-path> --actor <you> --confirm` (#3145 / #3205).",
|
|
361
365
|
};
|
|
362
366
|
}
|
|
363
367
|
return null;
|
|
@@ -379,6 +383,7 @@ export function evaluateOneScopeProvenance(input) {
|
|
|
379
383
|
export function evaluateScopeProvenance(projectRoot, options = {}) {
|
|
380
384
|
const root = resolve(projectRoot);
|
|
381
385
|
const enforce = options.enforce ?? false;
|
|
386
|
+
recoverApprovedScopePairs(root);
|
|
382
387
|
let changed;
|
|
383
388
|
/** Merge-base ref used for changed-file discovery (null when files injected). */
|
|
384
389
|
let discoveryBaseRef = null;
|
|
@@ -523,6 +528,17 @@ export function evaluateScopeProvenance(projectRoot, options = {}) {
|
|
|
523
528
|
return (n.includes("/approved-scope/") &&
|
|
524
529
|
(n.endsWith(`/${safe}.json`) || n.endsWith(`${safe}.json`)));
|
|
525
530
|
});
|
|
531
|
+
const preimageRel = planId !== null ? approvedScopeIntentRel(planId) : null;
|
|
532
|
+
const preimageInGitChange = preimageRel !== null &&
|
|
533
|
+
[...changedSet].some((p) => {
|
|
534
|
+
const n = normalizeRepoRelPath(p);
|
|
535
|
+
if (n === preimageRel || n.endsWith(`/${preimageRel}`))
|
|
536
|
+
return true;
|
|
537
|
+
if (planId === null)
|
|
538
|
+
return false;
|
|
539
|
+
const safe = planId.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
540
|
+
return n.includes("/approved-scope/") && n.endsWith(`/${safe}.intent.json`);
|
|
541
|
+
});
|
|
526
542
|
// Disk-only / concurrent-rewrite inference (#3205):
|
|
527
543
|
// Authority is the *approval record on the merge base*, not whether the
|
|
528
544
|
// active xBRIEF path existed there. pending→active leaves the active path
|
|
@@ -555,7 +571,7 @@ export function evaluateScopeProvenance(projectRoot, options = {}) {
|
|
|
555
571
|
}
|
|
556
572
|
}
|
|
557
573
|
}
|
|
558
|
-
const approvalRecordRewritten = approvalInGitChange || approvalDiskOnly;
|
|
574
|
+
const approvalRecordRewritten = approvalInGitChange || approvalDiskOnly || preimageInGitChange;
|
|
559
575
|
const recordMatchesCurrent = approved !== null &&
|
|
560
576
|
!approvalRecordRewritten &&
|
|
561
577
|
approved.fileScopeDigest ===
|
|
@@ -570,11 +586,11 @@ export function evaluateScopeProvenance(projectRoot, options = {}) {
|
|
|
570
586
|
planId: planId ?? rel,
|
|
571
587
|
kind: "self-authorizing-scope-expansion",
|
|
572
588
|
expandedPaths: currentScope,
|
|
573
|
-
detail: "approved-scope record rewritten in the same change set as the active xBRIEF; " +
|
|
589
|
+
detail: "approved-scope record or preimage rewritten in the same change set as the active xBRIEF; " +
|
|
574
590
|
"cannot self-authorize via concurrent approval rewrite",
|
|
575
591
|
remediation: "Commit human approval via `task scope:record-approved-scope` on the merge base " +
|
|
576
592
|
"(or a prior PR), then activate/expand without rewriting the approval in this " +
|
|
577
|
-
"change set. Same-PR approval rewrites do not authorize expansion (#3145 / #3205).",
|
|
593
|
+
"change set. Same-PR approval rewrites do not authorize expansion (#3145 / #3205 / #3385).",
|
|
578
594
|
});
|
|
579
595
|
continue;
|
|
580
596
|
}
|
|
@@ -586,6 +602,50 @@ export function evaluateScopeProvenance(projectRoot, options = {}) {
|
|
|
586
602
|
enforce,
|
|
587
603
|
renewedHumanApproval: renewed ?? (recordMatchesCurrent ? approved?.humanApproval : null),
|
|
588
604
|
});
|
|
605
|
+
const readAtBase = (baseRel) => {
|
|
606
|
+
if (options.readAtBase !== undefined)
|
|
607
|
+
return options.readAtBase(baseRel);
|
|
608
|
+
if (discoveryBaseRef === null || discoveryBaseRef === "")
|
|
609
|
+
return null;
|
|
610
|
+
try {
|
|
611
|
+
return readRepoFileAtRef(root, discoveryBaseRef, baseRel);
|
|
612
|
+
}
|
|
613
|
+
catch {
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
const intentHits = evaluateIntentForXbrief({
|
|
618
|
+
projectRoot: root,
|
|
619
|
+
xbriefRelPath: rel,
|
|
620
|
+
liveRaw: raw,
|
|
621
|
+
livePayload: payload,
|
|
622
|
+
planId: planId ?? rel,
|
|
623
|
+
approved,
|
|
624
|
+
xbriefModified: modified,
|
|
625
|
+
approvalRewritten: approvalRecordRewritten,
|
|
626
|
+
preimageRewritten: preimageInGitChange,
|
|
627
|
+
currentScopeNonEmpty: normalizeFileScope(extractFileScope(payload)).length > 0,
|
|
628
|
+
baseRef: discoveryBaseRef,
|
|
629
|
+
changedFiles: changed,
|
|
630
|
+
readAtBase,
|
|
631
|
+
approvedReposSeed: options.approvedReposSeed,
|
|
632
|
+
});
|
|
633
|
+
for (const hit of intentHits) {
|
|
634
|
+
const mapped = {
|
|
635
|
+
xbriefRelPath: hit.xbriefRelPath,
|
|
636
|
+
planId: hit.planId,
|
|
637
|
+
kind: hit.kind,
|
|
638
|
+
expandedPaths: [],
|
|
639
|
+
detail: hit.detail,
|
|
640
|
+
remediation: hit.remediation,
|
|
641
|
+
};
|
|
642
|
+
if (hit.warnOnly) {
|
|
643
|
+
softFindings.push(mapped);
|
|
644
|
+
}
|
|
645
|
+
else {
|
|
646
|
+
findings.push(mapped);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
589
649
|
if (finding === null)
|
|
590
650
|
continue;
|
|
591
651
|
// Soft migration: body-only edits (empty file_scope) without digest when !enforce.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract intent preimage from a live xBRIEF (#3376 R1–R5 / #3385 F1–F2).
|
|
3
|
+
*
|
|
4
|
+
* Unknown plan.* keys are extracted (pinned), not rejected. Known-machine keys
|
|
5
|
+
* are omitted. plan.tags is machine; plan.edges is extracted.
|
|
6
|
+
*/
|
|
7
|
+
import { GITHUB_ISSUE_REF_TYPES } from "../intake/reconcile-issues.js";
|
|
8
|
+
import { INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
9
|
+
export declare const INTENT_PREIMAGE_SCHEMA: 1;
|
|
10
|
+
export interface IntentPreimage {
|
|
11
|
+
readonly schemaVersion: typeof INTENT_PREIMAGE_SCHEMA;
|
|
12
|
+
readonly algo: typeof INTENT_DIGEST_ALGO;
|
|
13
|
+
readonly plan: Record<string, unknown>;
|
|
14
|
+
readonly approvedRepos: readonly string[];
|
|
15
|
+
/** Paths classified unknown at extract (for verify unclassified-key). */
|
|
16
|
+
readonly unknownPaths: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
export interface ExtractIntentOk {
|
|
19
|
+
readonly ok: true;
|
|
20
|
+
readonly preimage: IntentPreimage;
|
|
21
|
+
}
|
|
22
|
+
export interface ExtractIntentErr {
|
|
23
|
+
readonly ok: false;
|
|
24
|
+
readonly error: string;
|
|
25
|
+
}
|
|
26
|
+
export type ExtractIntentResult = ExtractIntentOk | ExtractIntentErr;
|
|
27
|
+
export interface ExtractIntentOptions {
|
|
28
|
+
readonly projectRoot?: string;
|
|
29
|
+
readonly approvedReposSeed?: readonly string[];
|
|
30
|
+
readonly readFile?: (absPath: string) => string | null;
|
|
31
|
+
}
|
|
32
|
+
export declare function slugFromGithubIssueUri(uri: string): string | null;
|
|
33
|
+
export declare function resolveParentPlanId(planRef: string, projectRoot: string, readFile?: (absPath: string) => string | null): {
|
|
34
|
+
id: string;
|
|
35
|
+
} | {
|
|
36
|
+
error: string;
|
|
37
|
+
};
|
|
38
|
+
/** Extract from a parsed payload (tokenizer already applied). */
|
|
39
|
+
export declare function extractIntentFromPayload(payload: unknown, options?: ExtractIntentOptions): ExtractIntentResult;
|
|
40
|
+
/** Parse raw text (duplicate-key reject) then extract. */
|
|
41
|
+
export declare function extractIntentFromRaw(raw: string, options?: ExtractIntentOptions): ExtractIntentResult;
|
|
42
|
+
export { GITHUB_ISSUE_REF_TYPES };
|
|
43
|
+
//# sourceMappingURL=extract-intent.d.ts.map
|