@deftai/directive 0.55.2 → 0.56.1
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/cli-router/index.js +4 -0
- package/dist/cli-router/route-argv.d.ts +1 -1
- package/dist/cli-router/route-argv.js +2 -1
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +6 -0
- package/dist/gates-cli/verify-bridge-drift.d.ts +11 -0
- package/dist/gates-cli/verify-bridge-drift.js +47 -0
- package/dist/gates-cli/verify-go-freeze.d.ts +11 -0
- package/dist/gates-cli/verify-go-freeze.js +48 -0
- package/dist/init-cli/constants.d.ts +2 -0
- package/dist/init-cli/constants.js +2 -0
- package/dist/init-cli/init.d.ts +1 -1
- package/dist/init-cli/init.js +6 -6
- package/dist/init-cli/migrate.d.ts +3 -0
- package/dist/init-cli/migrate.js +29 -0
- package/dist/init-cli/update.d.ts +1 -1
- package/dist/init-cli/update.js +6 -6
- package/dist/triage-actions-parity.d.ts +3 -0
- package/dist/triage-actions-parity.js +161 -6
- package/dist/triage-actions.d.ts +2 -0
- package/dist/triage-actions.js +71 -3
- package/package.json +3 -2
package/dist/cli-router/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { dispatch } from "../dispatch.js";
|
|
5
5
|
import { runInit } from "../init-cli/init.js";
|
|
6
|
+
import { runMigrate } from "../init-cli/migrate.js";
|
|
6
7
|
import { runUpdate } from "../init-cli/update.js";
|
|
7
8
|
import { routeArgv } from "./route-argv.js";
|
|
8
9
|
function defaultIo() {
|
|
@@ -32,6 +33,9 @@ export async function routeAndDispatch(argv, io) {
|
|
|
32
33
|
if (first === "update") {
|
|
33
34
|
return runUpdate(rest, io ?? defaultIo());
|
|
34
35
|
}
|
|
36
|
+
if (first === "migrate") {
|
|
37
|
+
return runMigrate(rest, io ?? defaultIo());
|
|
38
|
+
}
|
|
35
39
|
return dispatch(routed.argv, io);
|
|
36
40
|
}
|
|
37
41
|
//# sourceMappingURL=index.js.map
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Mirrors the `task <namespace>:<verb>` surface one-to-one.
|
|
4
4
|
*/
|
|
5
5
|
/** Top-level UX verbs promoted above the namespace layer (#1670). */
|
|
6
|
-
export declare const TOP_LEVEL_UX_VERBS: readonly ["init", "update", "bootstrap", "check", "doctor", "version", "feature"];
|
|
6
|
+
export declare const TOP_LEVEL_UX_VERBS: readonly ["init", "update", "migrate", "bootstrap", "check", "doctor", "version", "feature"];
|
|
7
7
|
/** Stubbed until a later story lands the handler (#1670 / #11). */
|
|
8
8
|
export declare const STUBBED_TOP_LEVEL_VERBS: Set<string>;
|
|
9
9
|
/** Registered but not yet implemented as TS handlers. */
|
|
@@ -7,6 +7,7 @@ import { resolveCanonicalVerb } from "../dispatch.js";
|
|
|
7
7
|
export const TOP_LEVEL_UX_VERBS = [
|
|
8
8
|
"init",
|
|
9
9
|
"update",
|
|
10
|
+
"migrate",
|
|
10
11
|
"bootstrap",
|
|
11
12
|
"check",
|
|
12
13
|
"doctor",
|
|
@@ -90,7 +91,7 @@ function routeTopLevel(first, rest) {
|
|
|
90
91
|
if (first === "check" || first === "doctor") {
|
|
91
92
|
return { kind: "dispatch", argv: [first, ...rest] };
|
|
92
93
|
}
|
|
93
|
-
if (first === "init" || first === "update") {
|
|
94
|
+
if (first === "init" || first === "update" || first === "migrate") {
|
|
94
95
|
return { kind: "dispatch", argv: [first, ...rest] };
|
|
95
96
|
}
|
|
96
97
|
if (STUBBED_TOP_LEVEL_VERBS.has(first)) {
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface DispatchIo {
|
|
|
8
8
|
writeErr: (text: string) => void;
|
|
9
9
|
}
|
|
10
10
|
/** CLI modules in packages/cli/src (excluding parity harnesses and bin/index). */
|
|
11
|
-
export declare const CLI_MODULE_VERBS: readonly ["cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "parity", "policy", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "verify-branch", "verify-encoding", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-capacity", "verify-content-manifest", "verify-scm-boundary", "verify-session-ritual", "verify-stubs", "rule-ownership-lint", "verify-story-ready", "verify-tools", "verify-wip-cap"];
|
|
11
|
+
export declare const CLI_MODULE_VERBS: readonly ["cache", "check", "capacity-backfill", "capacity-show", "codebase-default-extractor", "codebase-map", "codebase-map-fresh", "codebase-projection-registry", "codebase-provider", "doctor", "parity", "policy", "pr-closing-keywords", "pr-merge-readiness", "pr-monitor", "pr-protected-issues", "pr-wait-mergeable", "preflight-cache", "preflight-gh", "probe-session", "release", "release-e2e", "release-publish", "release-rollback", "scope-lifecycle", "slice", "subagent-monitor", "toolchain-check", "triage-actions", "triage-bootstrap", "triage-bulk", "triage-classify", "triage-help", "triage-queue", "triage-reconcile", "triage-refresh", "triage-scope", "triage-scope-drift", "triage-smoketest", "triage-subscribe", "triage-summary", "triage-welcome", "ts-check-lane", "vbrief-activate", "vbrief-build", "vbrief-preflight", "vbrief-reconcile", "vbrief-validate", "vbrief-validation", "verify-branch", "verify-encoding", "verify-hooks-installed", "verify-investigation", "verify-judgment-gates", "verify-no-task-runtime", "validate-links", "validate-strategy-output", "verify-bridge-drift", "verify-capacity", "verify-content-manifest", "verify-go-freeze", "verify-scm-boundary", "verify-session-ritual", "verify-stubs", "rule-ownership-lint", "verify-story-ready", "verify-tools", "verify-wip-cap"];
|
|
12
12
|
/** Core-only CLI entrypoints without a packages/cli wrapper. */
|
|
13
13
|
export declare const CORE_MODULE_VERBS: readonly ["scm", "github-auth-modes", "github-body", "issue-emit", "issue-ingest", "reconcile-issues", "swarm-launch", "swarm-complete-cohort", "swarm-readiness", "swarm-routing-verify", "swarm-routing-set", "swarm-verify-review-clean", "swarm-worktrees", "framework-commands", "pack-render", "packs-slice", "prd-render", "project-render", "roadmap-render", "spec-render", "spec-validate", "code-structure-validate", "pack-migrate-skills", "pack-migrate-rules", "pack-migrate-strategies", "pack-migrate-patterns", "pack-migrate-swarm-spec", "policy-set", "scope-undo", "scope-demote", "scope-decompose", "changelog-resolve-unreleased", "architecture-preflight-sor"];
|
|
14
14
|
/** Task-style aliases (framework_commands / Taskfile names). */
|
package/dist/dispatch.js
CHANGED
|
@@ -74,8 +74,10 @@ export const CLI_MODULE_VERBS = [
|
|
|
74
74
|
"verify-no-task-runtime",
|
|
75
75
|
"validate-links",
|
|
76
76
|
"validate-strategy-output",
|
|
77
|
+
"verify-bridge-drift",
|
|
77
78
|
"verify-capacity",
|
|
78
79
|
"verify-content-manifest",
|
|
80
|
+
"verify-go-freeze",
|
|
79
81
|
"verify-scm-boundary",
|
|
80
82
|
"verify-session-ritual",
|
|
81
83
|
"verify-stubs",
|
|
@@ -140,6 +142,8 @@ export const VERB_ALIASES = {
|
|
|
140
142
|
"verify:rule-ownership": "rule-ownership-lint",
|
|
141
143
|
"rule:ownership-lint": "rule-ownership-lint",
|
|
142
144
|
"verify:content-manifest": "verify-content-manifest",
|
|
145
|
+
"verify:go-freeze": "verify-go-freeze",
|
|
146
|
+
"verify:bridge-drift": "verify-bridge-drift",
|
|
143
147
|
"verify:scm-boundary": "verify-scm-boundary",
|
|
144
148
|
"verify:capacity": "verify-capacity",
|
|
145
149
|
"verify:session-ritual": "verify-session-ritual",
|
|
@@ -170,6 +174,8 @@ const SUBDIR_CLI_STEMS = {
|
|
|
170
174
|
"rule-ownership-lint": "verify-source-cli/rule-ownership-lint",
|
|
171
175
|
"verify-content-manifest": "verify-source-cli/verify-content-manifest",
|
|
172
176
|
"verify-scm-boundary": "verify-source-cli/verify-scm-boundary",
|
|
177
|
+
"verify-go-freeze": "gates-cli/verify-go-freeze",
|
|
178
|
+
"verify-bridge-drift": "gates-cli/verify-bridge-drift",
|
|
173
179
|
"validate-links": "content-validate-cli/validate-links",
|
|
174
180
|
"verify-capacity": "content-validate-cli/verify-capacity",
|
|
175
181
|
"validate-strategy-output": "content-validate-cli/validate-strategy-output",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string | null;
|
|
4
|
+
error?: string;
|
|
5
|
+
}
|
|
6
|
+
/** Parse verify-bridge-drift CLI args (#1912). */
|
|
7
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
8
|
+
/** Run the cross-surface drift gate and return the process exit code (three-state). */
|
|
9
|
+
export declare function run(argv: string[]): number;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=verify-bridge-drift.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { evaluateBridgeDrift } from "@deftai/directive-core/legacy-bridge";
|
|
5
|
+
/** Parse verify-bridge-drift CLI args (#1912). */
|
|
6
|
+
export function parseArgs(argv) {
|
|
7
|
+
const parsed = { projectRoot: null };
|
|
8
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
9
|
+
const arg = argv[i];
|
|
10
|
+
if (arg === "--project-root") {
|
|
11
|
+
const value = argv[i + 1];
|
|
12
|
+
if (value === undefined) {
|
|
13
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
14
|
+
}
|
|
15
|
+
parsed.projectRoot = value;
|
|
16
|
+
i += 1;
|
|
17
|
+
}
|
|
18
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
19
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
/** Run the cross-surface drift gate and return the process exit code (three-state). */
|
|
28
|
+
export function run(argv) {
|
|
29
|
+
const args = parseArgs(argv);
|
|
30
|
+
if (args.error !== undefined) {
|
|
31
|
+
process.stderr.write(`verify_bridge_drift: ${args.error}\n`);
|
|
32
|
+
return 2;
|
|
33
|
+
}
|
|
34
|
+
const root = resolve(args.projectRoot ?? ".");
|
|
35
|
+
const result = evaluateBridgeDrift(root);
|
|
36
|
+
if (result.stream === "stdout") {
|
|
37
|
+
process.stdout.write(`${result.message}\n`);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
process.stderr.write(`${result.message}\n`);
|
|
41
|
+
}
|
|
42
|
+
return result.code;
|
|
43
|
+
}
|
|
44
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
45
|
+
process.exit(run(process.argv.slice(2)));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=verify-bridge-drift.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
interface ParsedArgs {
|
|
3
|
+
projectRoot: string | null;
|
|
4
|
+
error?: string;
|
|
5
|
+
}
|
|
6
|
+
/** Parse verify-go-freeze CLI args (#1912). */
|
|
7
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
8
|
+
/** Run the freeze gate and return the process exit code (three-state). */
|
|
9
|
+
export declare function run(argv: string[]): number;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=verify-go-freeze.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { evaluateGoFreeze, FREEZE_BYPASS_ENV } from "@deftai/directive-core/legacy-bridge";
|
|
5
|
+
/** Parse verify-go-freeze CLI args (#1912). */
|
|
6
|
+
export function parseArgs(argv) {
|
|
7
|
+
const parsed = { projectRoot: null };
|
|
8
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
9
|
+
const arg = argv[i];
|
|
10
|
+
if (arg === "--project-root") {
|
|
11
|
+
const value = argv[i + 1];
|
|
12
|
+
if (value === undefined) {
|
|
13
|
+
return { ...parsed, error: "argument --project-root: expected one argument" };
|
|
14
|
+
}
|
|
15
|
+
parsed.projectRoot = value;
|
|
16
|
+
i += 1;
|
|
17
|
+
}
|
|
18
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
19
|
+
parsed.projectRoot = arg.slice("--project-root=".length);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return { ...parsed, error: `unrecognized argument: ${arg}` };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
/** Run the freeze gate and return the process exit code (three-state). */
|
|
28
|
+
export function run(argv) {
|
|
29
|
+
const args = parseArgs(argv);
|
|
30
|
+
if (args.error !== undefined) {
|
|
31
|
+
process.stderr.write(`verify_go_freeze: ${args.error}\n`);
|
|
32
|
+
return 2;
|
|
33
|
+
}
|
|
34
|
+
const root = resolve(args.projectRoot ?? ".");
|
|
35
|
+
const allowBump = process.env[FREEZE_BYPASS_ENV] === "1";
|
|
36
|
+
const result = evaluateGoFreeze(root, { allowBump });
|
|
37
|
+
if (result.stream === "stdout") {
|
|
38
|
+
process.stdout.write(`${result.message}\n`);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
process.stderr.write(`${result.message}\n`);
|
|
42
|
+
}
|
|
43
|
+
return result.code;
|
|
44
|
+
}
|
|
45
|
+
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
46
|
+
process.exit(run(process.argv.slice(2)));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=verify-go-freeze.js.map
|
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
export declare const CANONICAL_INIT_ARGV: readonly ["--yes", "--repo-root", ".", "--json"];
|
|
3
3
|
/** Canonical headless upgrade argv (#1339 / #1409). */
|
|
4
4
|
export declare const CANONICAL_UPDATE_ARGV: readonly ["--yes", "--upgrade", "--repo-root", ".", "--json"];
|
|
5
|
+
/** Canonical migrate argv: defaults to cwd, human-readable unless --json (#1941). */
|
|
6
|
+
export declare const CANONICAL_MIGRATE_ARGV: readonly ["--repo-root", "."];
|
|
5
7
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -2,4 +2,6 @@
|
|
|
2
2
|
export const CANONICAL_INIT_ARGV = ["--yes", "--repo-root", ".", "--json"];
|
|
3
3
|
/** Canonical headless upgrade argv (#1339 / #1409). */
|
|
4
4
|
export const CANONICAL_UPDATE_ARGV = ["--yes", "--upgrade", "--repo-root", ".", "--json"];
|
|
5
|
+
/** Canonical migrate argv: defaults to cwd, human-readable unless --json (#1941). */
|
|
6
|
+
export const CANONICAL_MIGRATE_ARGV = ["--repo-root", "."];
|
|
5
7
|
//# sourceMappingURL=constants.js.map
|
package/dist/init-cli/init.d.ts
CHANGED
package/dist/init-cli/init.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { parseInitArgv, runInitDepositCli } from "@deftai/directive-core/init-deposit";
|
|
1
2
|
import { CANONICAL_INIT_ARGV } from "./constants.js";
|
|
2
|
-
import { runDeftInstall } from "./run-deft-install.js";
|
|
3
3
|
export function runInit(argv, io) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
io,
|
|
4
|
+
const args = parseInitArgv(CANONICAL_INIT_ARGV, argv);
|
|
5
|
+
return runInitDepositCli({
|
|
6
|
+
...args,
|
|
7
|
+
writeOut: io.writeOut,
|
|
8
|
+
writeErr: io.writeErr,
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parseInitArgv, runMigrateCli } from "@deftai/directive-core/init-deposit";
|
|
2
|
+
import { CANONICAL_MIGRATE_ARGV } from "./constants.js";
|
|
3
|
+
/**
|
|
4
|
+
* `directive migrate` (alias `deft migrate`) -- stage-2 provenance verb (#1941):
|
|
5
|
+
* stamp a canonical-vendored `.deft/core` deposit as npm-managed. Thin wrapper
|
|
6
|
+
* over the core orchestrator; maps the three-state result to a 0/1/2 exit code.
|
|
7
|
+
*/
|
|
8
|
+
const NO_EFFECT_CONFIRMATION_FLAGS = new Set([
|
|
9
|
+
"--yes",
|
|
10
|
+
"--non-interactive",
|
|
11
|
+
"/yes",
|
|
12
|
+
"/non-interactive",
|
|
13
|
+
]);
|
|
14
|
+
export function runMigrate(argv, io) {
|
|
15
|
+
const args = parseInitArgv(CANONICAL_MIGRATE_ARGV, argv);
|
|
16
|
+
// `migrate` reuses `parseInitArgv`, which understands the init/update headless
|
|
17
|
+
// confirmation flags. migrate has no interactive prompts, so acknowledge the
|
|
18
|
+
// flag rather than silently swallowing it (a natural reflex from init/update).
|
|
19
|
+
if (argv.some((arg) => NO_EFFECT_CONFIRMATION_FLAGS.has(arg))) {
|
|
20
|
+
io.writeErr("directive migrate: --yes/--non-interactive has no effect (migrate runs non-interactively and never prompts).\n");
|
|
21
|
+
}
|
|
22
|
+
return runMigrateCli({
|
|
23
|
+
projectDir: args.projectDir,
|
|
24
|
+
jsonOut: args.jsonOut,
|
|
25
|
+
writeOut: io.writeOut,
|
|
26
|
+
writeErr: io.writeErr,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=migrate.js.map
|
package/dist/init-cli/update.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { parseUpdateArgv, runRefreshDepositCli } from "@deftai/directive-core/init-deposit";
|
|
1
2
|
import { CANONICAL_UPDATE_ARGV } from "./constants.js";
|
|
2
|
-
import { runDeftInstall } from "./run-deft-install.js";
|
|
3
3
|
export function runUpdate(argv, io) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
io,
|
|
4
|
+
const args = parseUpdateArgv(CANONICAL_UPDATE_ARGV, argv);
|
|
5
|
+
return runRefreshDepositCli({
|
|
6
|
+
...args,
|
|
7
|
+
writeOut: io.writeOut,
|
|
8
|
+
writeErr: io.writeErr,
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=update.js.map
|
|
@@ -7,6 +7,7 @@ export interface CommandCapture {
|
|
|
7
7
|
export interface ParityCase {
|
|
8
8
|
readonly name: string;
|
|
9
9
|
readonly argv: readonly string[];
|
|
10
|
+
readonly seed?: string;
|
|
10
11
|
}
|
|
11
12
|
export interface ParityDiff {
|
|
12
13
|
readonly caseName: string;
|
|
@@ -22,6 +23,8 @@ export interface ParityResult {
|
|
|
22
23
|
}
|
|
23
24
|
/** Strip volatile UUIDs and timestamps before compare. */
|
|
24
25
|
export declare function normalizeOutput(text: string): string;
|
|
26
|
+
/** Keep only operator-facing triage stderr; drop uv/tooling noise from Python spawns. */
|
|
27
|
+
export declare function normalizeStderr(text: string): string;
|
|
25
28
|
/** Build a throwaway project root with an empty audit-log parent directory. */
|
|
26
29
|
export declare function buildFixtureRepo(): string;
|
|
27
30
|
/** Diff one parity case between Python oracle and TS CLI. */
|
|
@@ -11,6 +11,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { dirname, join, resolve } from "node:path";
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { cachePut } from "../../core/dist/cache/operations.js";
|
|
14
15
|
/** Strip volatile UUIDs and timestamps before compare. */
|
|
15
16
|
export function normalizeOutput(text) {
|
|
16
17
|
return text
|
|
@@ -18,10 +19,26 @@ export function normalizeOutput(text) {
|
|
|
18
19
|
.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/g, "<TS>")
|
|
19
20
|
.replace(/Using CPython[^\n]*\n/g, "")
|
|
20
21
|
.replace(/Creating virtual environment[^\n]*\n/g, "")
|
|
21
|
-
.replace(/Installed \d+ packages[^\n]*\n/g, "")
|
|
22
|
+
.replace(/Installed \d+ packages[^\n]*\n/g, "")
|
|
23
|
+
.replace(/Downloading[^\n]*\n/g, "")
|
|
24
|
+
.replace(/Built[^\n]*\n/g, "")
|
|
25
|
+
.replace(/triage_actions: needs-ac comment not posted[^\n]*/g, "triage_actions: needs-ac comment not posted <GH-FAIL>");
|
|
26
|
+
}
|
|
27
|
+
/** Keep only operator-facing triage stderr; drop uv/tooling noise from Python spawns. */
|
|
28
|
+
export function normalizeStderr(text) {
|
|
29
|
+
return normalizeOutput(text)
|
|
30
|
+
.split("\n")
|
|
31
|
+
.filter((line) => line.length === 0 || line.startsWith("triage_actions:"))
|
|
32
|
+
.join("\n");
|
|
22
33
|
}
|
|
23
34
|
function runCapture(cmd, args, cwd, env = {}) {
|
|
24
|
-
const merged = {
|
|
35
|
+
const merged = {
|
|
36
|
+
...process.env,
|
|
37
|
+
...env,
|
|
38
|
+
GITHUB_TOKEN: "",
|
|
39
|
+
GH_TOKEN: "",
|
|
40
|
+
GH_ENTERPRISE_TOKEN: "",
|
|
41
|
+
};
|
|
25
42
|
for (const key of Object.keys(merged)) {
|
|
26
43
|
if (merged[key] === undefined)
|
|
27
44
|
delete merged[key];
|
|
@@ -59,13 +76,19 @@ function pythonWrapperScript(deftRoot, fixtureRoot) {
|
|
|
59
76
|
"sys.path.insert(0, str(deft_root / 'scripts'))",
|
|
60
77
|
"import candidates_log as cl",
|
|
61
78
|
"cl.DEFAULT_LOG_PATH = fixture / 'vbrief/.eval/candidates.jsonl'",
|
|
79
|
+
"import cache as cache_mod",
|
|
80
|
+
"cache_mod.DEFAULT_CACHE_ROOT = fixture / '.deft-cache'",
|
|
62
81
|
"import triage_actions",
|
|
63
82
|
"triage_actions.candidates_log = cl",
|
|
83
|
+
"triage_actions.cache = cache_mod",
|
|
84
|
+
"def _parity_gh(args):",
|
|
85
|
+
" raise triage_actions.UpstreamCloseError('gh disabled for parity')",
|
|
86
|
+
"triage_actions._run_gh = _parity_gh",
|
|
64
87
|
"raise SystemExit(triage_actions.main(sys.argv[1:]))",
|
|
65
88
|
].join("\n");
|
|
66
89
|
}
|
|
67
90
|
function runPythonTriageAction(deftRoot, fixtureRoot, argv) {
|
|
68
|
-
const cap = runCapture("uv", ["run", "python", "-c", pythonWrapperScript(deftRoot, fixtureRoot), ...argv], deftRoot, { TRIAGE_PARITY_FIXTURE: fixtureRoot });
|
|
91
|
+
const cap = runCapture("uv", ["run", "python", "-c", pythonWrapperScript(deftRoot, fixtureRoot), ...argv], deftRoot, { TRIAGE_PARITY_FIXTURE: fixtureRoot, DEFT_TRIAGE_ACTIONS_PARITY: "1" });
|
|
69
92
|
return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
70
93
|
}
|
|
71
94
|
function runTsTriageAction(deftRoot, fixtureRoot, argv) {
|
|
@@ -74,15 +97,15 @@ function runTsTriageAction(deftRoot, fixtureRoot, argv) {
|
|
|
74
97
|
...argv,
|
|
75
98
|
"--project-root",
|
|
76
99
|
fixtureRoot,
|
|
77
|
-
], deftRoot);
|
|
100
|
+
], deftRoot, { DEFT_TRIAGE_ACTIONS_PARITY: "1" });
|
|
78
101
|
return { exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
79
102
|
}
|
|
80
103
|
/** Diff one parity case between Python oracle and TS CLI. */
|
|
81
104
|
export function diffCase(python, ts, caseName) {
|
|
82
105
|
const pyOut = normalizeOutput(python.stdout);
|
|
83
106
|
const tsOut = normalizeOutput(ts.stdout);
|
|
84
|
-
const pyErr =
|
|
85
|
-
const tsErr =
|
|
107
|
+
const pyErr = normalizeStderr(python.stderr);
|
|
108
|
+
const tsErr = normalizeStderr(ts.stderr);
|
|
86
109
|
return {
|
|
87
110
|
caseName,
|
|
88
111
|
exitMismatch: python.exitCode !== ts.exitCode,
|
|
@@ -129,6 +152,71 @@ export const PARITY_CASES = [
|
|
|
129
152
|
name: "accept-idempotent",
|
|
130
153
|
argv: ["accept", "--issue", "9", "--repo", "deftai/directive", "--actor", "agent:test"],
|
|
131
154
|
},
|
|
155
|
+
{
|
|
156
|
+
name: "needs-ac-default",
|
|
157
|
+
argv: ["needs-ac", "--issue", "10", "--repo", "deftai/directive", "--actor", "agent:test"],
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: "status-empty",
|
|
161
|
+
argv: ["status", "--issue", "11", "--repo", "deftai/directive"],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "status-with-defer",
|
|
165
|
+
argv: ["status", "--issue", "12", "--repo", "deftai/directive"],
|
|
166
|
+
seed: "defer-status",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "reset-no-prior",
|
|
170
|
+
argv: ["reset", "--issue", "13", "--repo", "deftai/directive"],
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "reset-success",
|
|
174
|
+
argv: ["reset", "--issue", "14", "--repo", "deftai/directive", "--actor", "agent:test"],
|
|
175
|
+
seed: "defer-reset",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "reset-idempotent",
|
|
179
|
+
argv: ["reset", "--issue", "15", "--repo", "deftai/directive"],
|
|
180
|
+
seed: "reset-idempotent",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "history-empty",
|
|
184
|
+
argv: ["history", "--issue", "16", "--repo", "deftai/directive"],
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "history-multi",
|
|
188
|
+
argv: ["history", "--issue", "17", "--repo", "deftai/directive"],
|
|
189
|
+
seed: "history-multi",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "mark-duplicate-missing-cache",
|
|
193
|
+
argv: ["mark-duplicate", "--issue", "18", "--repo", "deftai/directive", "--of", "99"],
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: "mark-duplicate-success",
|
|
197
|
+
argv: [
|
|
198
|
+
"mark-duplicate",
|
|
199
|
+
"--issue",
|
|
200
|
+
"19",
|
|
201
|
+
"--repo",
|
|
202
|
+
"deftai/directive",
|
|
203
|
+
"--of",
|
|
204
|
+
"20",
|
|
205
|
+
"--actor",
|
|
206
|
+
"agent:test",
|
|
207
|
+
],
|
|
208
|
+
seed: "mark-duplicate-cache",
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: "mark-duplicate-idempotent",
|
|
212
|
+
argv: ["mark-duplicate", "--issue", "21", "--repo", "deftai/directive", "--of", "22"],
|
|
213
|
+
seed: "mark-duplicate-idempotent",
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "mark-duplicate-self",
|
|
217
|
+
argv: ["mark-duplicate", "--issue", "23", "--repo", "deftai/directive", "--of", "23"],
|
|
218
|
+
seed: "mark-duplicate-cache-self",
|
|
219
|
+
},
|
|
132
220
|
];
|
|
133
221
|
function seedAcceptFixture(fixtureRoot) {
|
|
134
222
|
const entry = {
|
|
@@ -141,6 +229,69 @@ function seedAcceptFixture(fixtureRoot) {
|
|
|
141
229
|
};
|
|
142
230
|
writeFileSync(join(fixtureRoot, "vbrief/.eval/candidates.jsonl"), `${JSON.stringify(entry, Object.keys(entry).sort())}\n`, "utf8");
|
|
143
231
|
}
|
|
232
|
+
function seedAuditEntry(fixtureRoot, issueNumber, decision, extras = {}) {
|
|
233
|
+
const entry = {
|
|
234
|
+
actor: "agent:test",
|
|
235
|
+
decision,
|
|
236
|
+
decision_id: "11111111-1111-1111-1111-111111111111",
|
|
237
|
+
issue_number: issueNumber,
|
|
238
|
+
repo: "deftai/directive",
|
|
239
|
+
timestamp: "2026-06-18T12:00:00Z",
|
|
240
|
+
...extras,
|
|
241
|
+
};
|
|
242
|
+
const path = join(fixtureRoot, "vbrief/.eval/candidates.jsonl");
|
|
243
|
+
const line = `${JSON.stringify(entry, Object.keys(entry).sort())}\n`;
|
|
244
|
+
writeFileSync(path, line, { encoding: "utf8", flag: "a" });
|
|
245
|
+
}
|
|
246
|
+
function seedCacheIssue(fixtureRoot, issueNumber) {
|
|
247
|
+
const cacheRoot = join(fixtureRoot, ".deft-cache");
|
|
248
|
+
cachePut("github-issue", `deftai/directive/${issueNumber}`, { number: issueNumber, title: "parity fixture", body: "fixture body" }, { cacheRoot });
|
|
249
|
+
}
|
|
250
|
+
function seedFixture(fixtureRoot, seed) {
|
|
251
|
+
if (seed === undefined)
|
|
252
|
+
return;
|
|
253
|
+
switch (seed) {
|
|
254
|
+
case "defer-status":
|
|
255
|
+
seedAuditEntry(fixtureRoot, 12, "defer", { reason: "later" });
|
|
256
|
+
break;
|
|
257
|
+
case "defer-reset":
|
|
258
|
+
seedAuditEntry(fixtureRoot, 14, "defer", { reason: "later" });
|
|
259
|
+
break;
|
|
260
|
+
case "reset-idempotent":
|
|
261
|
+
seedAuditEntry(fixtureRoot, 15, "reset", {
|
|
262
|
+
decision_id: "22222222-2222-2222-2222-222222222222",
|
|
263
|
+
prior_decision_id: "11111111-1111-1111-1111-111111111111",
|
|
264
|
+
});
|
|
265
|
+
break;
|
|
266
|
+
case "history-multi":
|
|
267
|
+
seedAuditEntry(fixtureRoot, 17, "defer", {
|
|
268
|
+
decision_id: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
|
|
269
|
+
reason: "first",
|
|
270
|
+
timestamp: "2026-06-18T10:00:00Z",
|
|
271
|
+
});
|
|
272
|
+
seedAuditEntry(fixtureRoot, 17, "needs-ac", {
|
|
273
|
+
decision_id: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
|
|
274
|
+
reason: "needs criteria",
|
|
275
|
+
timestamp: "2026-06-18T11:00:00Z",
|
|
276
|
+
});
|
|
277
|
+
break;
|
|
278
|
+
case "mark-duplicate-cache":
|
|
279
|
+
seedCacheIssue(fixtureRoot, 20);
|
|
280
|
+
break;
|
|
281
|
+
case "mark-duplicate-idempotent":
|
|
282
|
+
seedCacheIssue(fixtureRoot, 22);
|
|
283
|
+
seedAuditEntry(fixtureRoot, 21, "mark-duplicate", {
|
|
284
|
+
decision_id: "cccccccc-cccc-cccc-cccc-cccccccccccc",
|
|
285
|
+
linked_to: 22,
|
|
286
|
+
});
|
|
287
|
+
break;
|
|
288
|
+
case "mark-duplicate-cache-self":
|
|
289
|
+
seedCacheIssue(fixtureRoot, 23);
|
|
290
|
+
break;
|
|
291
|
+
default:
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
144
295
|
/** Run all parity cases; returns aggregate result. */
|
|
145
296
|
export function runParity() {
|
|
146
297
|
const deftRoot = resolveDeftRoot();
|
|
@@ -152,6 +303,10 @@ export function runParity() {
|
|
|
152
303
|
seedAcceptFixture(pyFixture);
|
|
153
304
|
seedAcceptFixture(tsFixture);
|
|
154
305
|
}
|
|
306
|
+
else {
|
|
307
|
+
seedFixture(pyFixture, testCase.seed);
|
|
308
|
+
seedFixture(tsFixture, testCase.seed);
|
|
309
|
+
}
|
|
155
310
|
try {
|
|
156
311
|
const python = runPythonTriageAction(deftRoot, pyFixture, testCase.argv);
|
|
157
312
|
const ts = runTsTriageAction(deftRoot, tsFixture, testCase.argv);
|
package/dist/triage-actions.d.ts
CHANGED
package/dist/triage-actions.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { accept, createDefaultDeps, deferAction, reject, TriageError, UpstreamCloseError, } from "../../core/dist/triage/actions/index.js";
|
|
4
|
+
import { accept, createDefaultDeps, deferAction, formatDecision, history, markDuplicate, needsAc, reject, reset, status, TriageError, UpstreamCloseError, } from "../../core/dist/triage/actions/index.js";
|
|
5
|
+
const VALID_CMDS = new Set([
|
|
6
|
+
"accept",
|
|
7
|
+
"reject",
|
|
8
|
+
"defer",
|
|
9
|
+
"needs-ac",
|
|
10
|
+
"mark-duplicate",
|
|
11
|
+
"status",
|
|
12
|
+
"reset",
|
|
13
|
+
"history",
|
|
14
|
+
]);
|
|
5
15
|
/** Parse triage-actions CLI argv mirroring ``triage_actions.py`` argparse. */
|
|
6
16
|
export function parseArgs(argv) {
|
|
7
17
|
const parsed = { projectRoot: process.cwd() };
|
|
@@ -61,6 +71,26 @@ export function parseArgs(argv) {
|
|
|
61
71
|
else if (arg?.startsWith("--actor=")) {
|
|
62
72
|
parsed.actor = arg.slice("--actor=".length);
|
|
63
73
|
}
|
|
74
|
+
else if (arg === "--comment") {
|
|
75
|
+
const value = argv[i + 1];
|
|
76
|
+
if (value === undefined)
|
|
77
|
+
return { ...parsed, error: "argument --comment: expected one argument" };
|
|
78
|
+
parsed.comment = value;
|
|
79
|
+
i += 1;
|
|
80
|
+
}
|
|
81
|
+
else if (arg?.startsWith("--comment=")) {
|
|
82
|
+
parsed.comment = arg.slice("--comment=".length);
|
|
83
|
+
}
|
|
84
|
+
else if (arg === "--of") {
|
|
85
|
+
const value = argv[i + 1];
|
|
86
|
+
if (value === undefined)
|
|
87
|
+
return { ...parsed, error: "argument --of: expected one argument" };
|
|
88
|
+
parsed.ofN = Number.parseInt(value, 10);
|
|
89
|
+
i += 1;
|
|
90
|
+
}
|
|
91
|
+
else if (arg?.startsWith("--of=")) {
|
|
92
|
+
parsed.ofN = Number.parseInt(arg.slice("--of=".length), 10);
|
|
93
|
+
}
|
|
64
94
|
else if (arg === "--project-root") {
|
|
65
95
|
const value = argv[i + 1];
|
|
66
96
|
if (value === undefined)
|
|
@@ -84,7 +114,7 @@ export function run(argv) {
|
|
|
84
114
|
process.stderr.write(`triage_actions: ${args.error}\n`);
|
|
85
115
|
return 2;
|
|
86
116
|
}
|
|
87
|
-
if (
|
|
117
|
+
if (!VALID_CMDS.has(args.cmd ?? "")) {
|
|
88
118
|
process.stderr.write(`triage_actions: unknown subcommand ${args.cmd ?? ""}\n`);
|
|
89
119
|
return 2;
|
|
90
120
|
}
|
|
@@ -104,6 +134,10 @@ export function run(argv) {
|
|
|
104
134
|
process.stderr.write("triage_actions: argument --reason: expected one argument\n");
|
|
105
135
|
return 2;
|
|
106
136
|
}
|
|
137
|
+
if (args.cmd === "mark-duplicate" && (args.ofN === undefined || Number.isNaN(args.ofN))) {
|
|
138
|
+
process.stderr.write("triage_actions: argument --of: expected one argument\n");
|
|
139
|
+
return 2;
|
|
140
|
+
}
|
|
107
141
|
const projectRoot = resolve(args.projectRoot);
|
|
108
142
|
const deps = createDefaultDeps(projectRoot);
|
|
109
143
|
const n = args.issue;
|
|
@@ -120,7 +154,7 @@ export function run(argv) {
|
|
|
120
154
|
});
|
|
121
155
|
process.stdout.write(`reject #${n} (${repo}) -> ${decisionId}\n`);
|
|
122
156
|
}
|
|
123
|
-
else {
|
|
157
|
+
else if (args.cmd === "defer") {
|
|
124
158
|
const decisionId = deferAction(n, repo, args.reason, deps, {
|
|
125
159
|
actor: args.actor,
|
|
126
160
|
resumeOn: args.resumeOn,
|
|
@@ -128,6 +162,40 @@ export function run(argv) {
|
|
|
128
162
|
});
|
|
129
163
|
process.stdout.write(`defer #${n} (${repo}) -> ${decisionId}\n`);
|
|
130
164
|
}
|
|
165
|
+
else if (args.cmd === "needs-ac") {
|
|
166
|
+
const decisionId = needsAc(n, repo, deps, {
|
|
167
|
+
actor: args.actor,
|
|
168
|
+
comment: args.comment,
|
|
169
|
+
projectRoot,
|
|
170
|
+
});
|
|
171
|
+
process.stdout.write(`needs-ac #${n} (${repo}) -> ${decisionId}\n`);
|
|
172
|
+
}
|
|
173
|
+
else if (args.cmd === "mark-duplicate") {
|
|
174
|
+
const ofN = args.ofN;
|
|
175
|
+
const decisionId = markDuplicate(n, repo, ofN, deps, {
|
|
176
|
+
actor: args.actor,
|
|
177
|
+
projectRoot,
|
|
178
|
+
});
|
|
179
|
+
process.stdout.write(`mark-duplicate #${n} -> #${ofN} (${repo}) -> ${decisionId}\n`);
|
|
180
|
+
}
|
|
181
|
+
else if (args.cmd === "status") {
|
|
182
|
+
process.stdout.write(`${formatDecision(status(n, repo, deps, { projectRoot }))}\n`);
|
|
183
|
+
}
|
|
184
|
+
else if (args.cmd === "reset") {
|
|
185
|
+
const decisionId = reset(n, repo, deps, { actor: args.actor, projectRoot });
|
|
186
|
+
process.stdout.write(`reset #${n} (${repo}) -> ${decisionId}\n`);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
const entries = history(n, repo, deps, { projectRoot });
|
|
190
|
+
if (entries.length === 0) {
|
|
191
|
+
process.stdout.write(`${formatDecision(null)}\n`);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
process.stdout.write(`${formatDecision(entry)}\n`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
131
199
|
}
|
|
132
200
|
catch (err) {
|
|
133
201
|
if (err instanceof TriageError || err instanceof UpstreamCloseError) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftai/directive",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.1",
|
|
4
4
|
"description": "Directive CLI — npm install path for the Deft Directive framework.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
"provenance": true
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@deftai/directive-core": "^0.
|
|
45
|
+
"@deftai/directive-core": "^0.56.1",
|
|
46
|
+
"@deftai/directive-content": "^0.56.1"
|
|
46
47
|
},
|
|
47
48
|
"scripts": {
|
|
48
49
|
"build": "tsc -b"
|