@deftai/directive 0.62.0 → 0.63.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/{branch-parity.d.ts → branch-fixtures.d.ts} +1 -3
- package/dist/{branch-parity.js → branch-fixtures.js} +3 -110
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +0 -1
- package/dist/orchestration-cli/coverage-map.js +1 -1
- package/dist/{policy-parity.d.ts → policy-fixtures.d.ts} +1 -3
- package/dist/{policy-parity.js → policy-fixtures.js} +4 -100
- package/dist/{release-e2e-parity.d.ts → release-e2e-fixtures.d.ts} +1 -3
- package/dist/release-e2e-fixtures.js +38 -0
- package/dist/{story-ready-parity.d.ts → story-ready-fixtures.d.ts} +1 -3
- package/dist/{story-ready-parity.js → story-ready-fixtures.js} +4 -121
- package/dist/{triage-aux-a-parity.d.ts → triage-aux-a-fixtures.d.ts} +1 -3
- package/dist/{triage-aux-a-parity.js → triage-aux-a-fixtures.js} +3 -73
- package/dist/{triage-aux-b-parity.d.ts → triage-aux-b-fixtures.d.ts} +1 -3
- package/dist/triage-aux-b-fixtures.js +167 -0
- package/dist/{triage-bootstrap-parity.d.ts → triage-bootstrap-fixtures.d.ts} +1 -3
- package/dist/{triage-bootstrap-parity.js → triage-bootstrap-fixtures.js} +4 -91
- package/dist/{triage-classify-parity.d.ts → triage-classify-fixtures.d.ts} +1 -3
- package/dist/{triage-classify-parity.js → triage-classify-fixtures.js} +4 -94
- package/dist/{triage-queue-parity.d.ts → triage-queue-fixtures.d.ts} +1 -3
- package/dist/{triage-queue-parity.js → triage-queue-fixtures.js} +4 -86
- package/dist/{triage-scope-parity.d.ts → triage-scope-fixtures.d.ts} +1 -3
- package/dist/{triage-scope-parity.js → triage-scope-fixtures.js} +4 -91
- package/dist/{vbrief-preflight-parity.d.ts → vbrief-preflight-fixtures.d.ts} +1 -3
- package/dist/vbrief-preflight-fixtures.js +79 -0
- package/dist/{wip-cap-parity.d.ts → wip-cap-fixtures.d.ts} +1 -3
- package/dist/{wip-cap-parity.js → wip-cap-fixtures.js} +4 -91
- package/package.json +4 -15
- package/dist/cache-parity.d.ts +0 -36
- package/dist/cache-parity.js +0 -165
- package/dist/codebase-parity.d.ts +0 -31
- package/dist/codebase-parity.js +0 -303
- package/dist/doc-cli-parity.d.ts +0 -29
- package/dist/doc-cli-parity.js +0 -159
- package/dist/doctor-parity.d.ts +0 -42
- package/dist/doctor-parity.js +0 -157
- package/dist/intake-parity.d.ts +0 -30
- package/dist/intake-parity.js +0 -203
- package/dist/lifecycle-packs-parity.d.ts +0 -30
- package/dist/lifecycle-packs-parity.js +0 -377
- package/dist/orchestration-parity.d.ts +0 -38
- package/dist/orchestration-parity.js +0 -364
- package/dist/parity.d.ts +0 -36
- package/dist/parity.js +0 -176
- package/dist/platform-parity.d.ts +0 -26
- package/dist/platform-parity.js +0 -309
- package/dist/pr-closing-keywords-parity.d.ts +0 -45
- package/dist/pr-closing-keywords-parity.js +0 -259
- package/dist/pr-merge-readiness-parity.d.ts +0 -44
- package/dist/pr-merge-readiness-parity.js +0 -296
- package/dist/pr-monitor-parity.d.ts +0 -44
- package/dist/pr-monitor-parity.js +0 -283
- package/dist/pr-protected-issues-parity.d.ts +0 -41
- package/dist/pr-protected-issues-parity.js +0 -220
- package/dist/pr-wait-mergeable-parity.d.ts +0 -45
- package/dist/pr-wait-mergeable-parity.js +0 -340
- package/dist/release-e2e-parity.js +0 -114
- package/dist/release-parity.d.ts +0 -40
- package/dist/release-parity.js +0 -226
- package/dist/release-publish-parity.d.ts +0 -36
- package/dist/release-publish-parity.js +0 -138
- package/dist/release-rollback-parity.d.ts +0 -37
- package/dist/release-rollback-parity.js +0 -161
- package/dist/render-parity.d.ts +0 -36
- package/dist/render-parity.js +0 -385
- package/dist/scm-parity.d.ts +0 -39
- package/dist/scm-parity.js +0 -181
- package/dist/scope-lifecycle-parity.d.ts +0 -35
- package/dist/scope-lifecycle-parity.js +0 -177
- package/dist/session-parity.d.ts +0 -39
- package/dist/session-parity.js +0 -262
- package/dist/slice-parity.d.ts +0 -36
- package/dist/slice-parity.js +0 -304
- package/dist/swarm-parity.d.ts +0 -28
- package/dist/swarm-parity.js +0 -327
- package/dist/triage-actions-parity.d.ts +0 -36
- package/dist/triage-actions-parity.js +0 -357
- package/dist/triage-aux-b-parity.js +0 -308
- package/dist/triage-summary-parity.d.ts +0 -50
- package/dist/triage-summary-parity.js +0 -306
- package/dist/validate-content-parity.d.ts +0 -33
- package/dist/validate-content-parity.js +0 -356
- package/dist/vbrief-activate-parity.d.ts +0 -39
- package/dist/vbrief-activate-parity.js +0 -216
- package/dist/vbrief-build-parity.d.ts +0 -28
- package/dist/vbrief-build-parity.js +0 -399
- package/dist/vbrief-preflight-parity.js +0 -163
- package/dist/vbrief-reconcile-parity.d.ts +0 -23
- package/dist/vbrief-reconcile-parity.js +0 -609
- package/dist/vbrief-validate-parity.d.ts +0 -27
- package/dist/vbrief-validate-parity.js +0 -122
- package/dist/vbrief-validation-parity.d.ts +0 -28
- package/dist/vbrief-validation-parity.js +0 -645
- package/dist/verify-env-parity.d.ts +0 -28
- package/dist/verify-env-parity.js +0 -272
- package/dist/verify-source-parity.d.ts +0 -26
- package/dist/verify-source-parity.js +0 -178
package/dist/cache-parity.js
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Golden-output parity harness (#1728): runs BOTH the Python oracle
|
|
4
|
-
* (`scripts/cache.py`) and the ported TS cache CLI with identical argv,
|
|
5
|
-
* then diffs exit codes and normalised stdout/stderr. Exit 0 only on
|
|
6
|
-
* identical results. Each scenario uses an isolated temp cwd (cache-off).
|
|
7
|
-
*
|
|
8
|
-
* Exit codes: 0 parity / 1 divergence / 2 harness setup error.
|
|
9
|
-
*/
|
|
10
|
-
import { spawnSync } from "node:child_process";
|
|
11
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
12
|
-
import { tmpdir } from "node:os";
|
|
13
|
-
import { dirname, join, resolve } from "node:path";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
15
|
-
/** Validation-only scenarios (no live gh network). */
|
|
16
|
-
export const PARITY_SCENARIOS = [
|
|
17
|
-
{ name: "usage-no-cmd", argv: [] },
|
|
18
|
-
{ name: "put-missing-args", argv: ["put"] },
|
|
19
|
-
{ name: "get-invalid-key", argv: ["get", "github-issue", "bad/key"] },
|
|
20
|
-
{
|
|
21
|
-
name: "put-missing-raw-file",
|
|
22
|
-
argv: ["put", "github-issue", "deftai/directive/1", "--raw-file", "/nonexistent"],
|
|
23
|
-
},
|
|
24
|
-
{ name: "get-miss", argv: ["get", "github-issue", "deftai/directive/999"] },
|
|
25
|
-
{
|
|
26
|
-
name: "invalidate-missing",
|
|
27
|
-
argv: ["invalidate", "github-issue", "deftai/directive/999"],
|
|
28
|
-
},
|
|
29
|
-
{ name: "prune-dry-run-empty", argv: ["prune", "--dry-run"] },
|
|
30
|
-
{
|
|
31
|
-
name: "fetch-all-invalid-repo",
|
|
32
|
-
argv: ["fetch-all", "--source", "github-issue", "--repo", "bad"],
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: "fetch-all-batch-size-zero",
|
|
36
|
-
argv: [
|
|
37
|
-
"fetch-all",
|
|
38
|
-
"--source",
|
|
39
|
-
"github-issue",
|
|
40
|
-
"--repo",
|
|
41
|
-
"deftai/directive",
|
|
42
|
-
"--batch-size",
|
|
43
|
-
"0",
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
name: "fetch-all-delay-negative",
|
|
48
|
-
argv: [
|
|
49
|
-
"fetch-all",
|
|
50
|
-
"--source",
|
|
51
|
-
"github-issue",
|
|
52
|
-
"--repo",
|
|
53
|
-
"deftai/directive",
|
|
54
|
-
"--delay-ms",
|
|
55
|
-
"-1",
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{ name: "prune-to-cap-dry-run", argv: ["prune", "--to-cap", "--dry-run"] },
|
|
59
|
-
];
|
|
60
|
-
function runCapture(cmd, args, cwd) {
|
|
61
|
-
const result = spawnSync(cmd, args, {
|
|
62
|
-
cwd,
|
|
63
|
-
encoding: "utf8",
|
|
64
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
65
|
-
});
|
|
66
|
-
return {
|
|
67
|
-
status: result.status ?? 2,
|
|
68
|
-
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
69
|
-
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/** Normalise gate output for comparison. */
|
|
73
|
-
export function normaliseMessage(stdout, stderr, exitCode) {
|
|
74
|
-
const raw = exitCode === 0 ? stdout : stderr;
|
|
75
|
-
return raw
|
|
76
|
-
.split("\n")
|
|
77
|
-
.filter((line) => !line.startsWith("Using CPython") &&
|
|
78
|
-
!line.startsWith("Creating virtual environment") &&
|
|
79
|
-
!line.startsWith("Installed "))
|
|
80
|
-
.join("\n")
|
|
81
|
-
.trim()
|
|
82
|
-
.replace(/\s+/g, " ");
|
|
83
|
-
}
|
|
84
|
-
function resolveDeftRoot() {
|
|
85
|
-
if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
|
|
86
|
-
return resolve(process.env.DEFT_ROOT);
|
|
87
|
-
}
|
|
88
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
89
|
-
}
|
|
90
|
-
function runScenario(deftRoot, scenario) {
|
|
91
|
-
const cwd = mkdtempSync(join(tmpdir(), "deft-cache-parity-"));
|
|
92
|
-
try {
|
|
93
|
-
const pyArgs = ["run", "python", join(deftRoot, "scripts", "cache.py"), ...scenario.argv];
|
|
94
|
-
const tsArgs = [join(deftRoot, "packages", "cli", "dist", "cache.js"), ...scenario.argv];
|
|
95
|
-
const py = runCapture("uv", pyArgs, cwd);
|
|
96
|
-
const ts = runCapture("node", tsArgs, cwd);
|
|
97
|
-
return {
|
|
98
|
-
python: { name: scenario.name, exitCode: py.status, stdout: py.stdout, stderr: py.stderr },
|
|
99
|
-
ts: { name: scenario.name, exitCode: ts.status, stdout: ts.stdout, stderr: ts.stderr },
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
finally {
|
|
103
|
-
rmSync(cwd, { recursive: true, force: true });
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
export function diffParity(python, ts) {
|
|
107
|
-
const pythonMessage = normaliseMessage(python.stdout, python.stderr, python.exitCode);
|
|
108
|
-
const tsMessage = normaliseMessage(ts.stdout, ts.stderr, ts.exitCode);
|
|
109
|
-
return {
|
|
110
|
-
exitMismatch: python.exitCode !== ts.exitCode,
|
|
111
|
-
messageMismatch: pythonMessage !== tsMessage,
|
|
112
|
-
pythonMessage,
|
|
113
|
-
tsMessage,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
export function runParity() {
|
|
117
|
-
const deftRoot = resolveDeftRoot();
|
|
118
|
-
const scenarios = [];
|
|
119
|
-
for (const scenario of PARITY_SCENARIOS) {
|
|
120
|
-
const ran = runScenario(deftRoot, scenario);
|
|
121
|
-
scenarios.push({
|
|
122
|
-
name: scenario.name,
|
|
123
|
-
pythonExit: ran.python.exitCode,
|
|
124
|
-
tsExit: ran.ts.exitCode,
|
|
125
|
-
...diffParity(ran.python, ran.ts),
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
const ok = scenarios.every((s) => !s.exitMismatch && !s.messageMismatch);
|
|
129
|
-
return { ok, scenarios };
|
|
130
|
-
}
|
|
131
|
-
export function renderReport(result) {
|
|
132
|
-
if (result.ok) {
|
|
133
|
-
return `cache parity: CLEAN -- Python and TS agree on ${result.scenarios.length} scenario(s).`;
|
|
134
|
-
}
|
|
135
|
-
const lines = ["cache parity: DIVERGENCE"];
|
|
136
|
-
for (const s of result.scenarios) {
|
|
137
|
-
if (s.exitMismatch || s.messageMismatch) {
|
|
138
|
-
lines.push(` scenario: ${s.name}`);
|
|
139
|
-
if (s.exitMismatch)
|
|
140
|
-
lines.push(` exit mismatch: python=${s.pythonExit} ts=${s.tsExit}`);
|
|
141
|
-
if (s.messageMismatch) {
|
|
142
|
-
lines.push(` python: ${s.pythonMessage}`);
|
|
143
|
-
lines.push(` ts: ${s.tsMessage}`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return lines.join("\n");
|
|
148
|
-
}
|
|
149
|
-
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
150
|
-
try {
|
|
151
|
-
const result = runParity();
|
|
152
|
-
if (result.ok) {
|
|
153
|
-
process.stdout.write(`${renderReport(result)}\n`);
|
|
154
|
-
process.exit(0);
|
|
155
|
-
}
|
|
156
|
-
process.stderr.write(`${renderReport(result)}\n`);
|
|
157
|
-
process.exit(1);
|
|
158
|
-
}
|
|
159
|
-
catch (err) {
|
|
160
|
-
const msg = String(err).replace(/\r?\n/g, " ");
|
|
161
|
-
process.stderr.write(`cache parity: harness error -- ${msg}\n`);
|
|
162
|
-
process.exit(2);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
//# sourceMappingURL=cache-parity.js.map
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export interface CommandCapture {
|
|
3
|
-
readonly exitCode: number;
|
|
4
|
-
readonly stdout: string;
|
|
5
|
-
readonly stderr: string;
|
|
6
|
-
}
|
|
7
|
-
export interface ParityCase {
|
|
8
|
-
readonly name: string;
|
|
9
|
-
readonly script: string;
|
|
10
|
-
readonly argv: string[];
|
|
11
|
-
readonly setup?: (root: string) => void;
|
|
12
|
-
readonly env?: Record<string, string | undefined>;
|
|
13
|
-
}
|
|
14
|
-
export interface ParityDiff {
|
|
15
|
-
readonly caseName: string;
|
|
16
|
-
readonly exitMismatch: boolean;
|
|
17
|
-
readonly stdoutMismatch: boolean;
|
|
18
|
-
readonly stderrMismatch: boolean;
|
|
19
|
-
readonly pythonExit: number;
|
|
20
|
-
readonly tsExit: number;
|
|
21
|
-
}
|
|
22
|
-
export interface ParityResult {
|
|
23
|
-
readonly ok: boolean;
|
|
24
|
-
readonly diffs: ParityDiff[];
|
|
25
|
-
}
|
|
26
|
-
export declare const PARITY_CASES: readonly ParityCase[];
|
|
27
|
-
export declare function normalizeOutput(text: string): string;
|
|
28
|
-
export declare function diffCase(python: CommandCapture, ts: CommandCapture, caseName: string): ParityDiff;
|
|
29
|
-
export declare function runParity(): ParityResult;
|
|
30
|
-
export declare function renderReport(result: ParityResult): string;
|
|
31
|
-
//# sourceMappingURL=codebase-parity.d.ts.map
|
package/dist/codebase-parity.js
DELETED
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Golden-output parity harness (#1786): runs BOTH the frozen Python codebase/capacity
|
|
4
|
-
* modules and the ported TS CLIs over shared fixtures, cache-off.
|
|
5
|
-
*
|
|
6
|
-
* Exit codes: 0 parity / 1 divergence / 2 harness setup error.
|
|
7
|
-
*/
|
|
8
|
-
import { execFileSync } from "node:child_process";
|
|
9
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
10
|
-
import { tmpdir } from "node:os";
|
|
11
|
-
import { dirname, join, resolve } from "node:path";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
|
-
import { runCodebaseMapCli } from "@deftai/directive-core/codebase";
|
|
14
|
-
function runCapture(cmd, args, cwd, env = {}) {
|
|
15
|
-
const merged = { ...process.env, ...env };
|
|
16
|
-
for (const key of Object.keys(merged)) {
|
|
17
|
-
if (merged[key] === undefined)
|
|
18
|
-
delete merged[key];
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
21
|
-
const stdout = execFileSync(cmd, args, {
|
|
22
|
-
cwd,
|
|
23
|
-
encoding: "utf8",
|
|
24
|
-
env: merged,
|
|
25
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
26
|
-
});
|
|
27
|
-
return { status: 0, stdout, stderr: "" };
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
const e = err;
|
|
31
|
-
return {
|
|
32
|
-
status: typeof e.status === "number" ? e.status : 2,
|
|
33
|
-
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
34
|
-
stderr: typeof e.stderr === "string" ? e.stderr : "",
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
function resolveDeftRoot() {
|
|
39
|
-
if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
|
|
40
|
-
return resolve(process.env.DEFT_ROOT);
|
|
41
|
-
}
|
|
42
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
43
|
-
}
|
|
44
|
-
const TS_CLI = {
|
|
45
|
-
codebase_projection_registry: "codebase-projection-registry.js",
|
|
46
|
-
codebase_default_extractor: "codebase-default-extractor.js",
|
|
47
|
-
codebase_provider: "codebase-provider.js",
|
|
48
|
-
codebase_map: "codebase-map.js",
|
|
49
|
-
codebase_map_fresh: "codebase-map-fresh.js",
|
|
50
|
-
capacity_show: "capacity-show.js",
|
|
51
|
-
capacity_backfill: "capacity-backfill.js",
|
|
52
|
-
};
|
|
53
|
-
const NO_PROJECT_ROOT = new Set(["codebase_projection_registry"]);
|
|
54
|
-
function runPython(deftRoot, script, repo, argv) {
|
|
55
|
-
const args = ["run", "python", join(deftRoot, "scripts", `${script}.py`), ...argv];
|
|
56
|
-
if (!NO_PROJECT_ROOT.has(script)) {
|
|
57
|
-
args.push("--project-root", repo);
|
|
58
|
-
}
|
|
59
|
-
const cap = runCapture("uv", args, deftRoot);
|
|
60
|
-
return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
61
|
-
}
|
|
62
|
-
function runTs(deftRoot, script, repo, argv) {
|
|
63
|
-
const cli = TS_CLI[script];
|
|
64
|
-
if (cli === undefined) {
|
|
65
|
-
throw new Error(`no TS CLI mapped for ${script}`);
|
|
66
|
-
}
|
|
67
|
-
const args = [join(deftRoot, "packages", "cli", "dist", cli), ...argv];
|
|
68
|
-
if (!NO_PROJECT_ROOT.has(script)) {
|
|
69
|
-
args.push("--project-root", repo);
|
|
70
|
-
}
|
|
71
|
-
const cap = runCapture("node", args, deftRoot);
|
|
72
|
-
return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
73
|
-
}
|
|
74
|
-
function writeCapacityProject(root) {
|
|
75
|
-
const vbrief = join(root, "vbrief");
|
|
76
|
-
for (const folder of ["proposed", "pending", "active", "completed", "cancelled"]) {
|
|
77
|
-
mkdirSync(join(vbrief, folder), { recursive: true });
|
|
78
|
-
}
|
|
79
|
-
writeFileSync(join(vbrief, "PROJECT-DEFINITION.vbrief.json"), `${JSON.stringify({
|
|
80
|
-
vBRIEFInfo: { version: "0.6" },
|
|
81
|
-
plan: {
|
|
82
|
-
title: "Capacity parity",
|
|
83
|
-
status: "running",
|
|
84
|
-
items: [],
|
|
85
|
-
policy: {
|
|
86
|
-
capacityAllocation: {
|
|
87
|
-
unit: "vbrief-count",
|
|
88
|
-
window: 30,
|
|
89
|
-
enforcement: "advise",
|
|
90
|
-
minSampleSize: 2,
|
|
91
|
-
defaultBucket: "feature",
|
|
92
|
-
buckets: [
|
|
93
|
-
{ id: "debt", target: 0.4, match: { labels: { "any-of": ["tech-debt"] } } },
|
|
94
|
-
{ id: "feature", target: 0.6, match: { labels: { "any-of": ["feature"] } } },
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
}, null, 2)}\n`, { encoding: "utf8" });
|
|
100
|
-
}
|
|
101
|
-
function writeCodeStructureProject(root) {
|
|
102
|
-
const vbrief = join(root, "vbrief");
|
|
103
|
-
mkdirSync(vbrief, { recursive: true });
|
|
104
|
-
writeFileSync(join(vbrief, "PROJECT-DEFINITION.vbrief.json"), `${JSON.stringify({
|
|
105
|
-
vBRIEFInfo: { version: "0.6" },
|
|
106
|
-
plan: {
|
|
107
|
-
title: "Fixture",
|
|
108
|
-
status: "running",
|
|
109
|
-
architecture: {
|
|
110
|
-
codeStructure: {
|
|
111
|
-
version: "0.1",
|
|
112
|
-
modules: [
|
|
113
|
-
{
|
|
114
|
-
id: "app",
|
|
115
|
-
name: "App",
|
|
116
|
-
purpose: "Application entry points.",
|
|
117
|
-
pathGlobs: ["app/**/*.py"],
|
|
118
|
-
},
|
|
119
|
-
],
|
|
120
|
-
pathOwnership: [],
|
|
121
|
-
allowedPatterns: [],
|
|
122
|
-
projectionManifest: [],
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
}, null, 2)}\n`, { encoding: "utf8" });
|
|
127
|
-
mkdirSync(join(root, "app"), { recursive: true });
|
|
128
|
-
writeFileSync(join(root, "app", "main.py"), "from lib.util import thing\n", { encoding: "utf8" });
|
|
129
|
-
}
|
|
130
|
-
function writeCodeStructureProjectNonAscii(root) {
|
|
131
|
-
const vbrief = join(root, "vbrief");
|
|
132
|
-
mkdirSync(vbrief, { recursive: true });
|
|
133
|
-
writeFileSync(join(vbrief, "PROJECT-DEFINITION.vbrief.json"), `${JSON.stringify({
|
|
134
|
-
vBRIEFInfo: { version: "0.6" },
|
|
135
|
-
plan: {
|
|
136
|
-
title: "Fixture",
|
|
137
|
-
status: "running",
|
|
138
|
-
architecture: {
|
|
139
|
-
codeStructure: {
|
|
140
|
-
version: "0.1",
|
|
141
|
-
modules: [
|
|
142
|
-
{
|
|
143
|
-
id: "app",
|
|
144
|
-
name: "Café App — naïve façade",
|
|
145
|
-
purpose: "Entrée points with non-ASCII glyphs: \u00e9 \u00f1 \u2014 \ud83d\ude80.",
|
|
146
|
-
pathGlobs: ["app/**/*.py"],
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
|
-
pathOwnership: [],
|
|
150
|
-
allowedPatterns: [],
|
|
151
|
-
projectionManifest: [],
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
}, null, 2)}\n`, { encoding: "utf8" });
|
|
156
|
-
mkdirSync(join(root, "app"), { recursive: true });
|
|
157
|
-
writeFileSync(join(root, "app", "main.py"), "from lib.util import thing\n", { encoding: "utf8" });
|
|
158
|
-
}
|
|
159
|
-
function writeFreshCodebaseMapProject(root) {
|
|
160
|
-
writeCodeStructureProject(root);
|
|
161
|
-
const result = runCodebaseMapCli(["--project-root", root]);
|
|
162
|
-
if (result.exitCode !== 0) {
|
|
163
|
-
throw new Error(`failed to write MAP fixture: ${result.stderr || result.stdout}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
export const PARITY_CASES = [
|
|
167
|
-
{
|
|
168
|
-
name: "projection-registry-list",
|
|
169
|
-
script: "codebase_projection_registry",
|
|
170
|
-
argv: ["--list"],
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
name: "projection-registry-kind",
|
|
174
|
-
script: "codebase_projection_registry",
|
|
175
|
-
argv: ["--kind", "codebase-map"],
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: "default-extractor-curated",
|
|
179
|
-
script: "codebase_default_extractor",
|
|
180
|
-
argv: [],
|
|
181
|
-
setup: writeCodeStructureProject,
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: "provider-default-fallback",
|
|
185
|
-
script: "codebase_provider",
|
|
186
|
-
argv: [],
|
|
187
|
-
setup: writeCodeStructureProject,
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
name: "map-stdout",
|
|
191
|
-
script: "codebase_map",
|
|
192
|
-
argv: ["--stdout"],
|
|
193
|
-
setup: writeCodeStructureProject,
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
name: "map-stdout-nonascii",
|
|
197
|
-
script: "codebase_map",
|
|
198
|
-
argv: ["--stdout"],
|
|
199
|
-
setup: writeCodeStructureProjectNonAscii,
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
name: "map-fresh-missing",
|
|
203
|
-
script: "codebase_map_fresh",
|
|
204
|
-
argv: [],
|
|
205
|
-
setup: writeCodeStructureProject,
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
name: "map-fresh-current",
|
|
209
|
-
script: "codebase_map_fresh",
|
|
210
|
-
argv: [],
|
|
211
|
-
setup: writeFreshCodebaseMapProject,
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
name: "capacity-show-advisory",
|
|
215
|
-
script: "capacity_show",
|
|
216
|
-
argv: [],
|
|
217
|
-
setup: writeCapacityProject,
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
name: "capacity-backfill-dry-run",
|
|
221
|
-
script: "capacity_backfill",
|
|
222
|
-
argv: [],
|
|
223
|
-
setup: writeCapacityProject,
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
name: "capacity-backfill-json",
|
|
227
|
-
script: "capacity_backfill",
|
|
228
|
-
argv: ["--json"],
|
|
229
|
-
setup: writeCapacityProject,
|
|
230
|
-
},
|
|
231
|
-
];
|
|
232
|
-
export function normalizeOutput(text) {
|
|
233
|
-
return text
|
|
234
|
-
.replace(/(?:\/private)?\/var\/folders\/[^\s"')]+\/deft-codebase-parity-[^\s"')]+/g, "<TMP>")
|
|
235
|
-
.replace(/\/tmp\/deft-codebase-parity-[^\s"')]+/g, "<TMP>");
|
|
236
|
-
}
|
|
237
|
-
export function diffCase(python, ts, caseName) {
|
|
238
|
-
const pythonStdout = normalizeOutput(python.stdout);
|
|
239
|
-
const pythonStderr = normalizeOutput(python.stderr);
|
|
240
|
-
const tsStdout = normalizeOutput(ts.stdout);
|
|
241
|
-
const tsStderr = normalizeOutput(ts.stderr);
|
|
242
|
-
return {
|
|
243
|
-
caseName,
|
|
244
|
-
exitMismatch: python.exitCode !== ts.exitCode,
|
|
245
|
-
stdoutMismatch: pythonStdout !== tsStdout,
|
|
246
|
-
stderrMismatch: pythonStderr !== tsStderr,
|
|
247
|
-
pythonExit: python.exitCode,
|
|
248
|
-
tsExit: ts.exitCode,
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
export function runParity() {
|
|
252
|
-
const deftRoot = resolveDeftRoot();
|
|
253
|
-
const diffs = [];
|
|
254
|
-
for (const testCase of PARITY_CASES) {
|
|
255
|
-
const repo = mkdtempSync(join(tmpdir(), "deft-codebase-parity-"));
|
|
256
|
-
try {
|
|
257
|
-
testCase.setup?.(repo);
|
|
258
|
-
const argv = testCase.argv.filter((a) => a !== "--project-root");
|
|
259
|
-
const python = runPython(deftRoot, testCase.script, repo, argv);
|
|
260
|
-
const ts = runTs(deftRoot, testCase.script, repo, argv);
|
|
261
|
-
diffs.push(diffCase(python, ts, testCase.name));
|
|
262
|
-
}
|
|
263
|
-
finally {
|
|
264
|
-
rmSync(repo, { recursive: true, force: true });
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
const ok = diffs.every((d) => !d.exitMismatch && !d.stdoutMismatch && !d.stderrMismatch);
|
|
268
|
-
return { ok, diffs };
|
|
269
|
-
}
|
|
270
|
-
export function renderReport(result) {
|
|
271
|
-
if (result.ok) {
|
|
272
|
-
return `codebase parity: CLEAN -- Python and TS agree on ${PARITY_CASES.length} cases.`;
|
|
273
|
-
}
|
|
274
|
-
const lines = ["codebase parity: DIVERGENCE"];
|
|
275
|
-
for (const d of result.diffs) {
|
|
276
|
-
if (d.exitMismatch || d.stdoutMismatch || d.stderrMismatch) {
|
|
277
|
-
lines.push(` case: ${d.caseName}`);
|
|
278
|
-
if (d.exitMismatch)
|
|
279
|
-
lines.push(` exit: python=${d.pythonExit} ts=${d.tsExit}`);
|
|
280
|
-
if (d.stdoutMismatch)
|
|
281
|
-
lines.push(" stdout mismatch");
|
|
282
|
-
if (d.stderrMismatch)
|
|
283
|
-
lines.push(" stderr mismatch");
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
return lines.join("\n");
|
|
287
|
-
}
|
|
288
|
-
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
289
|
-
try {
|
|
290
|
-
const result = runParity();
|
|
291
|
-
if (result.ok) {
|
|
292
|
-
process.stdout.write(`${renderReport(result)}\n`);
|
|
293
|
-
process.exit(0);
|
|
294
|
-
}
|
|
295
|
-
process.stderr.write(`${renderReport(result)}\n`);
|
|
296
|
-
process.exit(1);
|
|
297
|
-
}
|
|
298
|
-
catch (err) {
|
|
299
|
-
process.stderr.write(`codebase parity: harness error -- ${String(err)}\n`);
|
|
300
|
-
process.exit(2);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
//# sourceMappingURL=codebase-parity.js.map
|
package/dist/doc-cli-parity.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Doc ↔ CLI parity gate (#1996).
|
|
3
|
-
*
|
|
4
|
-
* Extracts npm-canonical CLI invocations from UPGRADING.md and the AGENTS.md
|
|
5
|
-
* managed-section template, then asserts each resolves through the top-level
|
|
6
|
-
* router to a registered dispatcher verb (or an explicitly allowlisted legacy
|
|
7
|
-
* back-compat surface documented post-#1912).
|
|
8
|
-
*/
|
|
9
|
-
/** Documented legacy surfaces that remain in prose but are not npm-router verbs. */
|
|
10
|
-
export declare const LEGACY_DOC_VERB_KEYS: Set<string>;
|
|
11
|
-
export interface DocCliReference {
|
|
12
|
-
readonly source: string;
|
|
13
|
-
readonly raw: string;
|
|
14
|
-
readonly normalized: string;
|
|
15
|
-
}
|
|
16
|
-
export interface DocCliParityFailure {
|
|
17
|
-
readonly source: string;
|
|
18
|
-
readonly raw: string;
|
|
19
|
-
readonly reason: string;
|
|
20
|
-
}
|
|
21
|
-
/** Pull CLI command references from UPGRADING.md + agents-entry managed section. */
|
|
22
|
-
export declare function extractDocCliReferences(repoRoot?: string): DocCliReference[];
|
|
23
|
-
/** Strip flags/placeholders; return null when the literal is not a CLI verb invocation. */
|
|
24
|
-
export declare function normalizeDocCommand(raw: string): string | null;
|
|
25
|
-
/** Validate one normalized doc command against the router + registeredVerbs(). */
|
|
26
|
-
export declare function validateDocCliCommand(normalized: string): string | null;
|
|
27
|
-
/** Run the parity gate; returns failure rows (empty == pass). */
|
|
28
|
-
export declare function collectDocCliParityFailures(repoRoot?: string): DocCliParityFailure[];
|
|
29
|
-
//# sourceMappingURL=doc-cli-parity.d.ts.map
|
package/dist/doc-cli-parity.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Doc ↔ CLI parity gate (#1996).
|
|
3
|
-
*
|
|
4
|
-
* Extracts npm-canonical CLI invocations from UPGRADING.md and the AGENTS.md
|
|
5
|
-
* managed-section template, then asserts each resolves through the top-level
|
|
6
|
-
* router to a registered dispatcher verb (or an explicitly allowlisted legacy
|
|
7
|
-
* back-compat surface documented post-#1912).
|
|
8
|
-
*/
|
|
9
|
-
import { readFileSync } from "node:fs";
|
|
10
|
-
import { join, resolve } from "node:path";
|
|
11
|
-
import { hasCommand } from "@deftai/directive-core/render";
|
|
12
|
-
import { routeArgv } from "./cli-router/route-argv.js";
|
|
13
|
-
import { registeredVerbs, resolveCanonicalVerb, VERB_ALIASES } from "./dispatch.js";
|
|
14
|
-
/** Documented legacy surfaces that remain in prose but are not npm-router verbs. */
|
|
15
|
-
export const LEGACY_DOC_VERB_KEYS = new Set(["setup", "upgrade", "relocate"]);
|
|
16
|
-
const CLI_PREFIX_RE = /^(?:directive|deft|npx @deftai\/directive)\s+/;
|
|
17
|
-
const BACKTICK_COMMAND_RE = /`((?:directive|deft|npx @deftai\/directive)\s+[^`]+)`/g;
|
|
18
|
-
const TOP_LEVEL_UX = new Set(["init", "update", "migrate", "bootstrap"]);
|
|
19
|
-
function repoRootFromModule() {
|
|
20
|
-
return resolve(import.meta.dirname, "..", "..", "..");
|
|
21
|
-
}
|
|
22
|
-
function extractManagedSection(text) {
|
|
23
|
-
const open = text.indexOf("<!-- deft:managed-section");
|
|
24
|
-
if (open < 0)
|
|
25
|
-
return text;
|
|
26
|
-
const close = text.indexOf("<!-- /deft:managed-section -->", open);
|
|
27
|
-
if (close < 0)
|
|
28
|
-
return text.slice(open);
|
|
29
|
-
return text.slice(open, close);
|
|
30
|
-
}
|
|
31
|
-
/** Pull CLI command references from UPGRADING.md + agents-entry managed section. */
|
|
32
|
-
export function extractDocCliReferences(repoRoot = repoRootFromModule()) {
|
|
33
|
-
const sources = [
|
|
34
|
-
["content/UPGRADING.md", readFileSync(join(repoRoot, "content/UPGRADING.md"), "utf8")],
|
|
35
|
-
[
|
|
36
|
-
"content/templates/agents-entry.md",
|
|
37
|
-
extractManagedSection(readFileSync(join(repoRoot, "content/templates/agents-entry.md"), "utf8")),
|
|
38
|
-
],
|
|
39
|
-
];
|
|
40
|
-
const seen = new Set();
|
|
41
|
-
const out = [];
|
|
42
|
-
for (const [source, text] of sources) {
|
|
43
|
-
for (const match of text.matchAll(BACKTICK_COMMAND_RE)) {
|
|
44
|
-
const raw = match[1]?.trim() ?? "";
|
|
45
|
-
if (!CLI_PREFIX_RE.test(raw))
|
|
46
|
-
continue;
|
|
47
|
-
const normalized = normalizeDocCommand(raw);
|
|
48
|
-
if (normalized === null)
|
|
49
|
-
continue;
|
|
50
|
-
const key = `${source}\0${normalized}`;
|
|
51
|
-
if (seen.has(key))
|
|
52
|
-
continue;
|
|
53
|
-
seen.add(key);
|
|
54
|
-
out.push({ source, raw, normalized });
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return out.sort((a, b) => a.source.localeCompare(b.source) || a.normalized.localeCompare(b.normalized));
|
|
58
|
-
}
|
|
59
|
-
function stripAnglePlaceholders(text) {
|
|
60
|
-
let out = text;
|
|
61
|
-
let start = out.indexOf("<");
|
|
62
|
-
while (start >= 0) {
|
|
63
|
-
const end = out.indexOf(">", start + 1);
|
|
64
|
-
if (end < 0)
|
|
65
|
-
break;
|
|
66
|
-
out = `${out.slice(0, start)}${out.slice(end + 1)}`;
|
|
67
|
-
start = out.indexOf("<");
|
|
68
|
-
}
|
|
69
|
-
return out.trim();
|
|
70
|
-
}
|
|
71
|
-
/** Strip flags/placeholders; return null when the literal is not a CLI verb invocation. */
|
|
72
|
-
export function normalizeDocCommand(raw) {
|
|
73
|
-
let rest = raw.replace(CLI_PREFIX_RE, "").trim();
|
|
74
|
-
if (rest.length === 0)
|
|
75
|
-
return null;
|
|
76
|
-
const dd = rest.indexOf(" --");
|
|
77
|
-
if (dd >= 0)
|
|
78
|
-
rest = rest.slice(0, dd).trim();
|
|
79
|
-
rest = rest.replace(/\s+\[[^\]]*\]/g, "").trim();
|
|
80
|
-
rest = rest.replace(/\s+--[^\s]+(\s+[^\s]+)?/g, "").trim();
|
|
81
|
-
rest = stripAnglePlaceholders(rest);
|
|
82
|
-
if (rest.includes("/") || rest.includes(".md") || rest.includes("*"))
|
|
83
|
-
return null;
|
|
84
|
-
if (/^deft-install\b/.test(rest))
|
|
85
|
-
return null;
|
|
86
|
-
if (/^deft-directive\b/.test(rest))
|
|
87
|
-
return null;
|
|
88
|
-
if (/^deftai\b/.test(rest))
|
|
89
|
-
return null;
|
|
90
|
-
const first = rest.split(/\s+/)[0] ?? "";
|
|
91
|
-
if (!/^[\w:-]+$/.test(first))
|
|
92
|
-
return null;
|
|
93
|
-
if (first.includes(":")) {
|
|
94
|
-
return first;
|
|
95
|
-
}
|
|
96
|
-
return first;
|
|
97
|
-
}
|
|
98
|
-
function tokenizeDocVerb(normalized) {
|
|
99
|
-
if (normalized.includes(":")) {
|
|
100
|
-
const colon = normalized.indexOf(":");
|
|
101
|
-
return [normalized.slice(0, colon), normalized.slice(colon + 1)];
|
|
102
|
-
}
|
|
103
|
-
return [normalized];
|
|
104
|
-
}
|
|
105
|
-
function colonKeyFromNormalized(normalized) {
|
|
106
|
-
if (normalized.includes(":"))
|
|
107
|
-
return normalized;
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
function isRegisteredHandler(flatVerb) {
|
|
111
|
-
const verbs = new Set(registeredVerbs());
|
|
112
|
-
if (verbs.has(flatVerb))
|
|
113
|
-
return true;
|
|
114
|
-
const canon = resolveCanonicalVerb(flatVerb);
|
|
115
|
-
return canon !== null && verbs.has(canon);
|
|
116
|
-
}
|
|
117
|
-
/** Validate one normalized doc command against the router + registeredVerbs(). */
|
|
118
|
-
export function validateDocCliCommand(normalized) {
|
|
119
|
-
const colonKey = colonKeyFromNormalized(normalized);
|
|
120
|
-
if (colonKey !== null) {
|
|
121
|
-
if (LEGACY_DOC_VERB_KEYS.has(colonKey)) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
if (colonKey in VERB_ALIASES || hasCommand(colonKey)) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
else if (LEGACY_DOC_VERB_KEYS.has(normalized)) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
const tokens = tokenizeDocVerb(normalized);
|
|
132
|
-
const routed = routeArgv(tokens);
|
|
133
|
-
if (routed.kind === "stub") {
|
|
134
|
-
return routed.stubMessage ?? "routes to stub handler";
|
|
135
|
-
}
|
|
136
|
-
const head = routed.argv[0];
|
|
137
|
-
if (head === undefined || head.length === 0) {
|
|
138
|
-
return "router produced empty argv";
|
|
139
|
-
}
|
|
140
|
-
if (TOP_LEVEL_UX.has(head)) {
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
if (isRegisteredHandler(head)) {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
return `unregistered handler '${head}' (tokens=${JSON.stringify(tokens)}, routed=${JSON.stringify(routed.argv.slice(0, 3))})`;
|
|
147
|
-
}
|
|
148
|
-
/** Run the parity gate; returns failure rows (empty == pass). */
|
|
149
|
-
export function collectDocCliParityFailures(repoRoot = repoRootFromModule()) {
|
|
150
|
-
const failures = [];
|
|
151
|
-
for (const ref of extractDocCliReferences(repoRoot)) {
|
|
152
|
-
const reason = validateDocCliCommand(ref.normalized);
|
|
153
|
-
if (reason !== null) {
|
|
154
|
-
failures.push({ source: ref.source, raw: ref.raw, reason });
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return failures;
|
|
158
|
-
}
|
|
159
|
-
//# sourceMappingURL=doc-cli-parity.js.map
|