@deftai/directive-core 0.103.0 → 0.105.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 +682 -35
- package/dist/check/cached-orchestrator.d.ts +1 -1
- package/dist/check/cached-orchestrator.js +2 -2
- package/dist/check/gate-lists.d.ts +3 -2
- package/dist/check/gate-lists.js +5 -2
- package/dist/check/index.d.ts +1 -0
- package/dist/check/index.js +1 -0
- package/dist/check/named-cause.d.ts +1 -1
- package/dist/check/named-cause.js +33 -3
- package/dist/check/session-completed-ac.d.ts +39 -0
- package/dist/check/session-completed-ac.js +198 -0
- 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 -14
- package/dist/doctor/types.d.ts +9 -0
- package/dist/fs/contained-write.d.ts +115 -1
- package/dist/fs/contained-write.js +242 -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 +2 -0
- package/dist/index.js +3 -0
- package/dist/init-deposit/agent-hooks.js +17 -15
- 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 +74 -0
- package/dist/intake/clause-derivation.js +409 -0
- package/dist/intake/index.d.ts +1 -0
- package/dist/intake/index.js +1 -0
- package/dist/intake/issue-ingest.d.ts +3 -1
- package/dist/intake/issue-ingest.js +36 -43
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +5 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +85 -18
- package/dist/literal-acceptance/capture.d.ts +10 -0
- package/dist/literal-acceptance/capture.js +224 -75
- 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/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 +4 -14
- 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/index.d.ts +7 -0
- package/dist/policy/index.js +66 -7
- package/dist/policy/project-invariants.d.ts +50 -0
- package/dist/policy/project-invariants.js +205 -0
- 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/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 +9 -0
- package/dist/preflight/evaluate.js +49 -1
- package/dist/preflight/index.d.ts +5 -1
- 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/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 +5 -2
- package/dist/product-first-done-gate/empty-resolution.js +13 -2
- package/dist/product-first-done-gate/evaluate.d.ts +29 -0
- package/dist/product-first-done-gate/evaluate.js +307 -33
- package/dist/product-first-done-gate/index.d.ts +3 -1
- package/dist/product-first-done-gate/index.js +2 -1
- package/dist/release/build-dist.d.ts +101 -0
- package/dist/release/build-dist.js +428 -46
- package/dist/run-summary/emit.d.ts +50 -4
- package/dist/run-summary/emit.js +262 -26
- 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/share.d.ts +1 -1
- package/dist/run-summary/share.js +2 -2
- package/dist/run-summary/types.d.ts +38 -6
- package/dist/run-summary/types.js +1 -0
- package/dist/scope/acceptance-activate-gate.d.ts +1 -1
- package/dist/scope/acceptance-activate-gate.js +4 -4
- package/dist/scope/acceptance-evidence.d.ts +27 -0
- package/dist/scope/acceptance-evidence.js +66 -0
- package/dist/scope/capacity-stamp.d.ts +2 -0
- package/dist/scope/capacity-stamp.js +4 -0
- package/dist/scope/delivery-evidence.d.ts +9 -3
- package/dist/scope/delivery-evidence.js +39 -27
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- 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/transition.js +66 -4
- 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 +64 -4
- 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 +4 -36
- package/dist/session/ac-pass-banking.js +30 -77
- package/dist/session/ac-pass-reuse.d.ts +53 -0
- package/dist/session/ac-pass-reuse.js +95 -0
- package/dist/session/ceremony-dial-evidence.d.ts +42 -0
- package/dist/session/ceremony-dial-evidence.js +194 -0
- package/dist/session/git.js +19 -4
- package/dist/session/index.d.ts +5 -0
- package/dist/session/index.js +5 -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/product-state-hash.d.ts +26 -0
- package/dist/session/product-state-hash.js +683 -0
- package/dist/session/session-ready.d.ts +2 -0
- package/dist/session/session-ready.js +52 -30
- package/dist/session/session-start.d.ts +7 -0
- package/dist/session/session-start.js +88 -5
- 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 +5 -0
- package/dist/session/verify-session-ritual.js +9 -0
- 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 +21 -4
- package/dist/slice/lock.d.ts +16 -1
- package/dist/slice/lock.js +137 -11
- package/dist/slice/record.d.ts +8 -5
- package/dist/slice/record.js +21 -13
- 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.js +33 -2
- 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 +13 -3
- package/dist/swarm/routing-verify.d.ts +12 -0
- package/dist/swarm/routing-verify.js +59 -20
- package/dist/swarm/routing.d.ts +14 -0
- package/dist/swarm/routing.js +53 -3
- package/dist/telemetry-coverage/evaluate.d.ts +42 -0
- package/dist/telemetry-coverage/evaluate.js +148 -0
- package/dist/telemetry-coverage/fake-trial.d.ts +45 -0
- package/dist/telemetry-coverage/fake-trial.js +204 -0
- package/dist/telemetry-coverage/index.d.ts +5 -0
- package/dist/telemetry-coverage/index.js +5 -0
- package/dist/telemetry-coverage/kinds.d.ts +19 -0
- package/dist/telemetry-coverage/kinds.js +54 -0
- package/dist/telemetry-coverage/scan-callers.d.ts +25 -0
- package/dist/telemetry-coverage/scan-callers.js +168 -0
- package/dist/triage/actions/index.js +4 -1
- 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/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 +3 -1
- package/dist/vbrief-reconcile/index.js +2 -1
- package/dist/vbrief-reconcile/origin-freshness.d.ts +44 -0
- package/dist/vbrief-reconcile/origin-freshness.js +221 -0
- 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/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-source/contained-writes.js +2 -0
- package/dist/verify-source/index.d.ts +1 -0
- package/dist/verify-source/index.js +1 -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 +3 -3
|
@@ -0,0 +1,262 @@
|
|
|
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 { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { basename, join } from "node:path";
|
|
9
|
+
import { GITHUB_ISSUE_REF_TYPES } from "../intake/reconcile-issues.js";
|
|
10
|
+
import { stripArtifactSuffix } from "../layout/resolve.js";
|
|
11
|
+
import { resolveParentPathFromRef } from "../scope/parent-lineage.js";
|
|
12
|
+
import { extractPlanId } from "./digest.js";
|
|
13
|
+
import { INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
14
|
+
import { parseJsonRejectingDuplicateKeys } from "./json-tokenizer.js";
|
|
15
|
+
import { classifyItemKey, classifyPlanPath, classifyReferenceKey, ITEM_EXTRACT_KEYS, } from "./known-machine.js";
|
|
16
|
+
export const INTENT_PREIMAGE_SCHEMA = 1;
|
|
17
|
+
const ISSUE_URL_RE = /https?:\/\/(?:www\.)?github\.com\/([^/\s]+)\/([^/\s]+)\/issues\/(\d+)/i;
|
|
18
|
+
export function slugFromGithubIssueUri(uri) {
|
|
19
|
+
const m = ISSUE_URL_RE.exec(uri);
|
|
20
|
+
if (m === null)
|
|
21
|
+
return null;
|
|
22
|
+
return `${m[1]}/${m[2]}`.toLowerCase();
|
|
23
|
+
}
|
|
24
|
+
function asRecord(value) {
|
|
25
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
26
|
+
return null;
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function itemId(item) {
|
|
30
|
+
return typeof item.id === "string" ? item.id : "";
|
|
31
|
+
}
|
|
32
|
+
function readText(abs, reader) {
|
|
33
|
+
if (reader !== undefined)
|
|
34
|
+
return reader(abs);
|
|
35
|
+
if (!existsSync(abs))
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
return readFileSync(abs, "utf8");
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function resolveParentPlanId(planRef, projectRoot, readFile) {
|
|
45
|
+
const roots = [join(projectRoot, "xbrief"), join(projectRoot, "vbrief")];
|
|
46
|
+
for (const lifecycleRoot of roots) {
|
|
47
|
+
const resolved = resolveParentPathFromRef(planRef, lifecycleRoot);
|
|
48
|
+
if (resolved.path === null)
|
|
49
|
+
continue;
|
|
50
|
+
const raw = readText(resolved.path, readFile);
|
|
51
|
+
if (raw === null)
|
|
52
|
+
continue;
|
|
53
|
+
let payload;
|
|
54
|
+
try {
|
|
55
|
+
payload = JSON.parse(raw);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { error: `unresolvable parent at mint: ${planRef} is not valid JSON` };
|
|
59
|
+
}
|
|
60
|
+
const id = extractPlanId(payload) ?? stripArtifactSuffix(basename(resolved.path));
|
|
61
|
+
if (id.trim().length === 0) {
|
|
62
|
+
return { error: `unresolvable parent at mint: ${planRef} has no plan.id` };
|
|
63
|
+
}
|
|
64
|
+
return { id: id.trim() };
|
|
65
|
+
}
|
|
66
|
+
return { error: `unresolvable parent at mint: ${planRef}` };
|
|
67
|
+
}
|
|
68
|
+
function extractReferences(refs) {
|
|
69
|
+
if (!Array.isArray(refs))
|
|
70
|
+
return { refs: [] };
|
|
71
|
+
const out = [];
|
|
72
|
+
for (const ref of refs) {
|
|
73
|
+
const rec = asRecord(ref);
|
|
74
|
+
if (rec === null)
|
|
75
|
+
continue;
|
|
76
|
+
const extracted = {};
|
|
77
|
+
for (const [key, value] of Object.entries(rec)) {
|
|
78
|
+
const cls = classifyReferenceKey(key);
|
|
79
|
+
if (cls === "machine")
|
|
80
|
+
continue;
|
|
81
|
+
extracted[key] = value;
|
|
82
|
+
}
|
|
83
|
+
out.push(extracted);
|
|
84
|
+
}
|
|
85
|
+
return { refs: out };
|
|
86
|
+
}
|
|
87
|
+
function extractItems(items, projectRoot, readFile, unknownPaths) {
|
|
88
|
+
if (!Array.isArray(items))
|
|
89
|
+
return { items: [] };
|
|
90
|
+
const out = [];
|
|
91
|
+
const ids = new Set();
|
|
92
|
+
for (const item of items) {
|
|
93
|
+
const rec = asRecord(item);
|
|
94
|
+
if (rec === null)
|
|
95
|
+
continue;
|
|
96
|
+
const extracted = {};
|
|
97
|
+
for (const key of ITEM_EXTRACT_KEYS) {
|
|
98
|
+
if (rec[key] !== undefined)
|
|
99
|
+
extracted[key] = rec[key];
|
|
100
|
+
}
|
|
101
|
+
for (const [key, value] of Object.entries(rec)) {
|
|
102
|
+
if (ITEM_EXTRACT_KEYS.includes(key))
|
|
103
|
+
continue;
|
|
104
|
+
const cls = classifyItemKey(key);
|
|
105
|
+
if (cls === "machine")
|
|
106
|
+
continue;
|
|
107
|
+
extracted[key] = value;
|
|
108
|
+
unknownPaths.push(`items[].${key}`);
|
|
109
|
+
}
|
|
110
|
+
if (typeof rec.planRef === "string" && rec.planRef.trim().length > 0) {
|
|
111
|
+
if (projectRoot === undefined) {
|
|
112
|
+
return { items: [], error: `unresolvable parent at mint: ${rec.planRef}` };
|
|
113
|
+
}
|
|
114
|
+
const parent = resolveParentPlanId(rec.planRef, projectRoot, readFile);
|
|
115
|
+
if ("error" in parent)
|
|
116
|
+
return { items: [], error: parent.error };
|
|
117
|
+
extracted.parentId = parent.id;
|
|
118
|
+
}
|
|
119
|
+
const id = itemId(extracted);
|
|
120
|
+
if (id.length > 0) {
|
|
121
|
+
if (ids.has(id)) {
|
|
122
|
+
return { items: [], error: `duplicate items[].id ${JSON.stringify(id)}` };
|
|
123
|
+
}
|
|
124
|
+
ids.add(id);
|
|
125
|
+
}
|
|
126
|
+
out.push(extracted);
|
|
127
|
+
}
|
|
128
|
+
out.sort((a, b) => itemId(a).localeCompare(itemId(b)));
|
|
129
|
+
return { items: out };
|
|
130
|
+
}
|
|
131
|
+
function copyUnknownSubtree(value) {
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
function extractMetadata(metadata, unknownPaths) {
|
|
135
|
+
const out = {};
|
|
136
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
137
|
+
const path = `metadata.${key}`;
|
|
138
|
+
const cls = classifyPlanPath(path);
|
|
139
|
+
if (cls === "machine")
|
|
140
|
+
continue;
|
|
141
|
+
if (key === "swarm") {
|
|
142
|
+
const swarm = asRecord(value);
|
|
143
|
+
if (swarm === null)
|
|
144
|
+
continue;
|
|
145
|
+
const swarmOut = {};
|
|
146
|
+
for (const [sKey, sVal] of Object.entries(swarm)) {
|
|
147
|
+
const sPath = `metadata.swarm.${sKey}`;
|
|
148
|
+
const sCls = classifyPlanPath(sPath);
|
|
149
|
+
if (sCls === "machine")
|
|
150
|
+
continue;
|
|
151
|
+
swarmOut[sKey] = sVal;
|
|
152
|
+
if (sCls === "unknown")
|
|
153
|
+
unknownPaths.push(sPath);
|
|
154
|
+
}
|
|
155
|
+
if (Object.keys(swarmOut).length > 0)
|
|
156
|
+
out.swarm = swarmOut;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (cls === "unknown") {
|
|
160
|
+
out[key] = copyUnknownSubtree(value);
|
|
161
|
+
unknownPaths.push(path);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
out[key] = value;
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
function seedApprovedRepos(seed, refs) {
|
|
169
|
+
const out = new Set();
|
|
170
|
+
for (const s of seed ?? []) {
|
|
171
|
+
const t = s.trim().toLowerCase();
|
|
172
|
+
if (t.includes("/"))
|
|
173
|
+
out.add(t);
|
|
174
|
+
}
|
|
175
|
+
for (const ref of refs) {
|
|
176
|
+
if (typeof ref.uri !== "string")
|
|
177
|
+
continue;
|
|
178
|
+
const slug = slugFromGithubIssueUri(ref.uri);
|
|
179
|
+
if (slug !== null)
|
|
180
|
+
out.add(slug);
|
|
181
|
+
}
|
|
182
|
+
return [...out].sort((a, b) => a.localeCompare(b));
|
|
183
|
+
}
|
|
184
|
+
/** Extract from a parsed payload (tokenizer already applied). */
|
|
185
|
+
export function extractIntentFromPayload(payload, options = {}) {
|
|
186
|
+
const root = asRecord(payload);
|
|
187
|
+
if (root === null)
|
|
188
|
+
return { ok: false, error: "xBRIEF is not an object" };
|
|
189
|
+
const plan = asRecord(root.plan);
|
|
190
|
+
if (plan === null)
|
|
191
|
+
return { ok: false, error: "xBRIEF plan is missing" };
|
|
192
|
+
const unknownPaths = [];
|
|
193
|
+
const extracted = {};
|
|
194
|
+
if (typeof plan.planRef === "string" && plan.planRef.trim().length > 0) {
|
|
195
|
+
if (options.projectRoot === undefined) {
|
|
196
|
+
return { ok: false, error: `unresolvable parent at mint: ${plan.planRef}` };
|
|
197
|
+
}
|
|
198
|
+
const parent = resolveParentPlanId(plan.planRef, options.projectRoot, options.readFile);
|
|
199
|
+
if ("error" in parent)
|
|
200
|
+
return { ok: false, error: parent.error };
|
|
201
|
+
extracted.parentId = parent.id;
|
|
202
|
+
}
|
|
203
|
+
for (const [key, value] of Object.entries(plan)) {
|
|
204
|
+
const cls = classifyPlanPath(key);
|
|
205
|
+
if (cls === "machine")
|
|
206
|
+
continue;
|
|
207
|
+
if (key === "items") {
|
|
208
|
+
const items = extractItems(value, options.projectRoot, options.readFile, unknownPaths);
|
|
209
|
+
if (items.error !== undefined)
|
|
210
|
+
return { ok: false, error: items.error };
|
|
211
|
+
extracted.items = items.items;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (key === "references") {
|
|
215
|
+
const refs = extractReferences(value);
|
|
216
|
+
if (refs.error !== undefined)
|
|
217
|
+
return { ok: false, error: refs.error };
|
|
218
|
+
extracted.references = refs.refs;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (key === "metadata") {
|
|
222
|
+
const meta = asRecord(value);
|
|
223
|
+
if (meta === null)
|
|
224
|
+
continue;
|
|
225
|
+
const extractedMeta = extractMetadata(meta, unknownPaths);
|
|
226
|
+
if (Object.keys(extractedMeta).length > 0)
|
|
227
|
+
extracted.metadata = extractedMeta;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (cls === "unknown") {
|
|
231
|
+
extracted[key] = copyUnknownSubtree(value);
|
|
232
|
+
unknownPaths.push(key);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
extracted[key] = value;
|
|
236
|
+
}
|
|
237
|
+
const refs = Array.isArray(extracted.references)
|
|
238
|
+
? extracted.references
|
|
239
|
+
: [];
|
|
240
|
+
const approvedRepos = seedApprovedRepos(options.approvedReposSeed, refs);
|
|
241
|
+
const uniqueUnknown = [...new Set(unknownPaths)].sort((a, b) => a.localeCompare(b));
|
|
242
|
+
return {
|
|
243
|
+
ok: true,
|
|
244
|
+
preimage: {
|
|
245
|
+
schemaVersion: INTENT_PREIMAGE_SCHEMA,
|
|
246
|
+
algo: INTENT_DIGEST_ALGO,
|
|
247
|
+
plan: extracted,
|
|
248
|
+
approvedRepos,
|
|
249
|
+
unknownPaths: uniqueUnknown,
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/** Parse raw text (duplicate-key reject) then extract. */
|
|
254
|
+
export function extractIntentFromRaw(raw, options = {}) {
|
|
255
|
+
const parsed = parseJsonRejectingDuplicateKeys(raw);
|
|
256
|
+
if (!parsed.ok) {
|
|
257
|
+
return { ok: false, error: parsed.error };
|
|
258
|
+
}
|
|
259
|
+
return extractIntentFromPayload(parsed.value, options);
|
|
260
|
+
}
|
|
261
|
+
export { GITHUB_ISSUE_REF_TYPES };
|
|
262
|
+
//# sourceMappingURL=extract-intent.js.map
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* scope-provenance package surface (#3145).
|
|
3
3
|
*/
|
|
4
|
-
export {
|
|
4
|
+
export { compareExtractedIntent } from "./compare-intent.js";
|
|
5
|
+
export { APPROVED_SCOPE_DIR, type ApprovedScopeRecord, approvedScopeDir, approvedScopeIntentPath, approvedScopeIntentRel, approvedScopeRecordPath, buildApprovedScopeRecord, computeFileScopeDigest, computeTextDigest, extractFileScope, extractPlanId, isHumanApprovalStamp, listApprovedScopeRecords, normalizeFileScope, readApprovedScopeRecord, scopeExpansion, writeApprovedScopeRecord, } from "./digest.js";
|
|
5
6
|
export { baseApprovalAuthorizesCurrent, evaluateOneScopeProvenance, evaluateScopeProvenance, parseApprovedScopeRecordRaw, resolveDefaultBaseRef, type ScopeProvenanceFinding, type ScopeProvenanceOptions, type ScopeProvenanceResult, type ScopeProvenanceViolationKind, } from "./evaluate.js";
|
|
7
|
+
export { extractIntentFromPayload, extractIntentFromRaw, GITHUB_ISSUE_REF_TYPES, type IntentPreimage, } from "./extract-intent.js";
|
|
8
|
+
export { computeIntentDigest, INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
9
|
+
export { parseJsonRejectingDuplicateKeys } from "./json-tokenizer.js";
|
|
10
|
+
export { allKnownMachineLeaves, KNOWN_MACHINE_WRITERS } from "./known-machine.js";
|
|
11
|
+
export { mintApprovedScopeArtifacts, recoverApprovedScopePairs, recoverIncompleteApprovedScopePair, } from "./mint-artifacts.js";
|
|
6
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* scope-provenance package surface (#3145).
|
|
3
3
|
*/
|
|
4
|
-
export {
|
|
4
|
+
export { compareExtractedIntent } from "./compare-intent.js";
|
|
5
|
+
export { APPROVED_SCOPE_DIR, approvedScopeDir, approvedScopeIntentPath, approvedScopeIntentRel, approvedScopeRecordPath, buildApprovedScopeRecord, computeFileScopeDigest, computeTextDigest, extractFileScope, extractPlanId, isHumanApprovalStamp, listApprovedScopeRecords, normalizeFileScope, readApprovedScopeRecord, scopeExpansion, writeApprovedScopeRecord, } from "./digest.js";
|
|
5
6
|
export { baseApprovalAuthorizesCurrent, evaluateOneScopeProvenance, evaluateScopeProvenance, parseApprovedScopeRecordRaw, resolveDefaultBaseRef, } from "./evaluate.js";
|
|
7
|
+
export { extractIntentFromPayload, extractIntentFromRaw, GITHUB_ISSUE_REF_TYPES, } from "./extract-intent.js";
|
|
8
|
+
export { computeIntentDigest, INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
9
|
+
export { parseJsonRejectingDuplicateKeys } from "./json-tokenizer.js";
|
|
10
|
+
export { allKnownMachineLeaves, KNOWN_MACHINE_WRITERS } from "./known-machine.js";
|
|
11
|
+
export { mintApprovedScopeArtifacts, recoverApprovedScopePairs, recoverIncompleteApprovedScopePair, } from "./mint-artifacts.js";
|
|
6
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* intent-extract-v1 digest (#3376 R2 / #3385).
|
|
3
|
+
*
|
|
4
|
+
* sortKeysDeep, items[] by id (done at extract), NFC, compact stringify, sha256.
|
|
5
|
+
*/
|
|
6
|
+
export declare const INTENT_DIGEST_ALGO: "intent-extract-v1";
|
|
7
|
+
export declare function nfcString(value: string): string;
|
|
8
|
+
/** Deep-sort object keys and NFC-normalize strings. Arrays keep order. */
|
|
9
|
+
export declare function sortKeysDeep(value: unknown): unknown;
|
|
10
|
+
/** sha256 hex of the canonical preimage. */
|
|
11
|
+
export declare function computeIntentDigest(preimage: unknown): string;
|
|
12
|
+
//# sourceMappingURL=intent-digest.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* intent-extract-v1 digest (#3376 R2 / #3385).
|
|
3
|
+
*
|
|
4
|
+
* sortKeysDeep, items[] by id (done at extract), NFC, compact stringify, sha256.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
export const INTENT_DIGEST_ALGO = "intent-extract-v1";
|
|
8
|
+
export function nfcString(value) {
|
|
9
|
+
return value.normalize("NFC");
|
|
10
|
+
}
|
|
11
|
+
/** Deep-sort object keys and NFC-normalize strings. Arrays keep order. */
|
|
12
|
+
export function sortKeysDeep(value) {
|
|
13
|
+
if (typeof value === "string")
|
|
14
|
+
return nfcString(value);
|
|
15
|
+
if (Array.isArray(value))
|
|
16
|
+
return value.map(sortKeysDeep);
|
|
17
|
+
if (value !== null && typeof value === "object") {
|
|
18
|
+
const rec = value;
|
|
19
|
+
const out = {};
|
|
20
|
+
for (const key of Object.keys(rec).sort((a, b) => a.localeCompare(b))) {
|
|
21
|
+
out[key] = sortKeysDeep(rec[key]);
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
/** sha256 hex of the canonical preimage. */
|
|
28
|
+
export function computeIntentDigest(preimage) {
|
|
29
|
+
const canonical = sortKeysDeep(preimage);
|
|
30
|
+
const payload = JSON.stringify(canonical);
|
|
31
|
+
return createHash("sha256").update(payload, "utf8").digest("hex");
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=intent-digest.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify-time intent pin evaluation (#3376 R2–R6 / #3385).
|
|
3
|
+
*
|
|
4
|
+
* Reads base-committed record + preimage (never working-tree copies).
|
|
5
|
+
* Legacy records (no intentDigest) authorize paths only; intent edits warn.
|
|
6
|
+
* xbriefBodyDigest is never authority.
|
|
7
|
+
*/
|
|
8
|
+
import { type ApprovedScopeRecord } from "./digest.js";
|
|
9
|
+
import { type IntentPreimage } from "./extract-intent.js";
|
|
10
|
+
export type IntentViolationKind = "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";
|
|
11
|
+
export interface IntentFinding {
|
|
12
|
+
readonly kind: IntentViolationKind;
|
|
13
|
+
readonly planId: string;
|
|
14
|
+
readonly xbriefRelPath: string;
|
|
15
|
+
readonly detail: string;
|
|
16
|
+
readonly remediation: string;
|
|
17
|
+
readonly warnOnly: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface IntentEvaluateInput {
|
|
20
|
+
readonly projectRoot: string;
|
|
21
|
+
readonly xbriefRelPath: string;
|
|
22
|
+
readonly liveRaw: string;
|
|
23
|
+
readonly livePayload: unknown;
|
|
24
|
+
readonly planId: string;
|
|
25
|
+
readonly approved: ApprovedScopeRecord | null;
|
|
26
|
+
readonly xbriefModified: boolean;
|
|
27
|
+
readonly approvalRewritten: boolean;
|
|
28
|
+
readonly preimageRewritten: boolean;
|
|
29
|
+
readonly currentScopeNonEmpty: boolean;
|
|
30
|
+
readonly baseRef: string | null;
|
|
31
|
+
readonly changedFiles: readonly string[];
|
|
32
|
+
readonly readAtBase?: (relPath: string) => string | null;
|
|
33
|
+
readonly approvedReposSeed?: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
export declare function parseIntentPreimageRaw(raw: string): IntentPreimage | null;
|
|
36
|
+
/**
|
|
37
|
+
* Evaluate intent pin for one modified active xBRIEF.
|
|
38
|
+
* Returns [] when intent is not in play (unmodified, or nothing to check).
|
|
39
|
+
*/
|
|
40
|
+
export declare function evaluateIntentForXbrief(input: IntentEvaluateInput): IntentFinding[];
|
|
41
|
+
/** Explicit: never treat xbriefBodyDigest as authority. */
|
|
42
|
+
export declare function bodyDigestIsAuthority(_rec: ApprovedScopeRecord | null): false;
|
|
43
|
+
//# sourceMappingURL=intent-evaluate.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify-time intent pin evaluation (#3376 R2–R6 / #3385).
|
|
3
|
+
*
|
|
4
|
+
* Reads base-committed record + preimage (never working-tree copies).
|
|
5
|
+
* Legacy records (no intentDigest) authorize paths only; intent edits warn.
|
|
6
|
+
* xbriefBodyDigest is never authority.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
10
|
+
import { compareExtractedIntent } from "./compare-intent.js";
|
|
11
|
+
import { approvedScopeIntentRel } from "./digest.js";
|
|
12
|
+
import { extractIntentFromPayload, extractIntentFromRaw, } from "./extract-intent.js";
|
|
13
|
+
import { computeIntentDigest, INTENT_DIGEST_ALGO } from "./intent-digest.js";
|
|
14
|
+
import { parseJsonRejectingDuplicateKeys } from "./json-tokenizer.js";
|
|
15
|
+
export function parseIntentPreimageRaw(raw) {
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(raw);
|
|
18
|
+
if (data === null || typeof data !== "object" || Array.isArray(data))
|
|
19
|
+
return null;
|
|
20
|
+
const rec = data;
|
|
21
|
+
if (rec.schemaVersion !== 1)
|
|
22
|
+
return null;
|
|
23
|
+
if (rec.algo !== INTENT_DIGEST_ALGO)
|
|
24
|
+
return null;
|
|
25
|
+
if (rec.plan === null || typeof rec.plan !== "object" || Array.isArray(rec.plan))
|
|
26
|
+
return null;
|
|
27
|
+
if (!Array.isArray(rec.approvedRepos))
|
|
28
|
+
return null;
|
|
29
|
+
return data;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function remint() {
|
|
36
|
+
return ("Remint via `task scope:record-approved-scope -- <xbrief-path> --actor <you> --confirm` " +
|
|
37
|
+
"and commit `.deft/approved-scope/<plan-id>.json` plus `.intent.json` on the merge base. " +
|
|
38
|
+
"Read the preimage before committing (#3385).");
|
|
39
|
+
}
|
|
40
|
+
function mapCompare(f) {
|
|
41
|
+
if (f.kind === "unclassified-key")
|
|
42
|
+
return "unclassified-key";
|
|
43
|
+
return "intent-drift";
|
|
44
|
+
}
|
|
45
|
+
function finding(input, kind, detail, warnOnly = false) {
|
|
46
|
+
return {
|
|
47
|
+
kind,
|
|
48
|
+
planId: input.planId,
|
|
49
|
+
xbriefRelPath: input.xbriefRelPath,
|
|
50
|
+
detail,
|
|
51
|
+
remediation: remint(),
|
|
52
|
+
warnOnly,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function readBase(input, rel) {
|
|
56
|
+
if (input.readAtBase !== undefined)
|
|
57
|
+
return input.readAtBase(rel);
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
function decisionExists(input, rel) {
|
|
61
|
+
const fromBase = readBase(input, rel);
|
|
62
|
+
if (fromBase !== null)
|
|
63
|
+
return true;
|
|
64
|
+
const full = join(resolve(input.projectRoot), ...rel.split("/"));
|
|
65
|
+
return existsSync(full);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Evaluate intent pin for one modified active xBRIEF.
|
|
69
|
+
* Returns [] when intent is not in play (unmodified, or nothing to check).
|
|
70
|
+
*/
|
|
71
|
+
export function evaluateIntentForXbrief(input) {
|
|
72
|
+
if (!input.xbriefModified)
|
|
73
|
+
return [];
|
|
74
|
+
const parsed = parseJsonRejectingDuplicateKeys(input.liveRaw);
|
|
75
|
+
if (!parsed.ok) {
|
|
76
|
+
return [finding(input, "duplicate-key", parsed.error)];
|
|
77
|
+
}
|
|
78
|
+
const liveExtract = extractIntentFromPayload(parsed.value, {
|
|
79
|
+
projectRoot: input.projectRoot,
|
|
80
|
+
approvedReposSeed: input.approvedReposSeed,
|
|
81
|
+
});
|
|
82
|
+
if (!liveExtract.ok) {
|
|
83
|
+
if (liveExtract.error.includes("duplicate items[].id")) {
|
|
84
|
+
return [finding(input, "duplicate-item-id", liveExtract.error)];
|
|
85
|
+
}
|
|
86
|
+
return [finding(input, "intent-parse-error", liveExtract.error)];
|
|
87
|
+
}
|
|
88
|
+
if (input.approvalRewritten || input.preimageRewritten) {
|
|
89
|
+
return [
|
|
90
|
+
finding(input, "same-pr-intent-rewrite", "approved-scope record or preimage rewritten in the same change set; " +
|
|
91
|
+
"cannot self-authorize intent"),
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
const hasIntent = input.approved !== null &&
|
|
95
|
+
typeof input.approved.intentDigest === "string" &&
|
|
96
|
+
input.approved.intentDigest.length > 0;
|
|
97
|
+
if (!hasIntent) {
|
|
98
|
+
return evaluateLegacyIntent(input, liveExtract.preimage);
|
|
99
|
+
}
|
|
100
|
+
const preimageRel = approvedScopeIntentRel(input.planId);
|
|
101
|
+
const basePreimageRaw = readBase(input, preimageRel);
|
|
102
|
+
if (basePreimageRaw === null) {
|
|
103
|
+
if (input.currentScopeNonEmpty) {
|
|
104
|
+
return [
|
|
105
|
+
finding(input, "first-activation-missing-intent-pin", "first activation with nonempty scope requires a base-committed record + preimage"),
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
const basePreimage = parseIntentPreimageRaw(basePreimageRaw);
|
|
111
|
+
if (basePreimage === null) {
|
|
112
|
+
return [finding(input, "intent-digest-mismatch", "base preimage is malformed")];
|
|
113
|
+
}
|
|
114
|
+
const expected = computeIntentDigest(basePreimage);
|
|
115
|
+
if (expected !== input.approved?.intentDigest) {
|
|
116
|
+
return [
|
|
117
|
+
finding(input, "intent-digest-mismatch", "base preimage digest does not match record intentDigest"),
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
const compared = compareExtractedIntent(basePreimage, liveExtract.preimage, {
|
|
121
|
+
changedFiles: input.changedFiles,
|
|
122
|
+
decisionExists: (rel) => decisionExists(input, rel),
|
|
123
|
+
});
|
|
124
|
+
return compared.findings.map((f) => finding(input, mapCompare(f), f.detail));
|
|
125
|
+
}
|
|
126
|
+
function evaluateLegacyIntent(input, live) {
|
|
127
|
+
const baseRaw = readBase(input, input.xbriefRelPath);
|
|
128
|
+
if (baseRaw === null) {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
const baseExtract = extractIntentFromRaw(baseRaw, {
|
|
132
|
+
projectRoot: input.projectRoot,
|
|
133
|
+
approvedReposSeed: input.approvedReposSeed,
|
|
134
|
+
});
|
|
135
|
+
if (!baseExtract.ok)
|
|
136
|
+
return [];
|
|
137
|
+
const compared = compareExtractedIntent(baseExtract.preimage, live, {
|
|
138
|
+
changedFiles: input.changedFiles,
|
|
139
|
+
decisionExists: (rel) => decisionExists(input, rel),
|
|
140
|
+
});
|
|
141
|
+
if (compared.ok)
|
|
142
|
+
return [];
|
|
143
|
+
return compared.findings.map((f) => finding(input, "legacy-intent-edit", f.detail, true));
|
|
144
|
+
}
|
|
145
|
+
/** Explicit: never treat xbriefBodyDigest as authority. */
|
|
146
|
+
export function bodyDigestIsAuthority(_rec) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=intent-evaluate.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validating JSON tokenizer for scope-provenance intent parse (#3385 F3 / E9).
|
|
3
|
+
*
|
|
4
|
+
* JSON.parse collapses duplicate object keys; a reviver never sees them.
|
|
5
|
+
* This scanner rejects duplicate keys (including nested) and does not treat
|
|
6
|
+
* JSON-looking text inside string values as structure.
|
|
7
|
+
*/
|
|
8
|
+
export interface JsonParseOk {
|
|
9
|
+
readonly ok: true;
|
|
10
|
+
readonly value: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface JsonParseErr {
|
|
13
|
+
readonly ok: false;
|
|
14
|
+
readonly error: string;
|
|
15
|
+
}
|
|
16
|
+
export type JsonParseResult = JsonParseOk | JsonParseErr;
|
|
17
|
+
/** Parse JSON and reject duplicate object keys (nested included). */
|
|
18
|
+
export declare function parseJsonRejectingDuplicateKeys(text: string): JsonParseResult;
|
|
19
|
+
//# sourceMappingURL=json-tokenizer.d.ts.map
|