@deftai/directive-core 0.105.0 → 0.106.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authz/classify.js +591 -34
- package/dist/check/named-cause.js +1 -1
- package/dist/forward-coverage/diff-coverage.d.ts +39 -0
- package/dist/forward-coverage/diff-coverage.js +112 -0
- package/dist/forward-coverage/diff-lines.d.ts +19 -0
- package/dist/forward-coverage/diff-lines.js +173 -0
- package/dist/forward-coverage/evaluate.d.ts +24 -9
- package/dist/forward-coverage/evaluate.js +125 -19
- package/dist/init-deposit/agent-hooks.d.ts +1 -1
- package/dist/init-deposit/agent-hooks.js +1 -1
- package/dist/intake/clause-derivation.d.ts +9 -0
- package/dist/intake/clause-derivation.js +30 -3
- package/dist/lifecycle-visible/evaluate.d.ts +98 -0
- package/dist/lifecycle-visible/evaluate.js +710 -0
- package/dist/lifecycle-visible/index.d.ts +2 -0
- package/dist/lifecycle-visible/index.js +2 -0
- package/dist/literal-acceptance/capture.js +3 -3
- package/dist/orchestration/judgment-policy.d.ts +13 -0
- package/dist/orchestration/judgment-policy.js +15 -0
- package/dist/orchestration/probe-session.js +13 -8
- package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
- package/dist/orchestration/verify-judgment-gates.js +43 -11
- package/dist/policy/ceremony-dial.js +7 -7
- package/dist/policy/host-hooks.d.ts +20 -0
- package/dist/policy/host-hooks.js +121 -2
- package/dist/policy/org-force-on-migration.js +2 -1
- package/dist/policy/plan-extensions.d.ts +1 -1
- package/dist/policy/plan-extensions.js +2 -0
- package/dist/policy/product-signal.js +6 -7
- package/dist/policy/require-human-merge.js +8 -6
- package/dist/policy/resolve.d.ts +7 -2
- package/dist/policy/resolve.js +25 -8
- package/dist/policy/value-feedback.js +7 -8
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +15 -1
- package/dist/preflight-cache/index.d.ts +1 -1
- package/dist/preflight-cache/index.js +1 -1
- package/dist/product-first-done-gate/evaluate.d.ts +4 -0
- package/dist/product-first-done-gate/evaluate.js +46 -5
- package/dist/release/closed-verb-gate.d.ts +12 -0
- package/dist/release/closed-verb-gate.js +51 -0
- package/dist/release/index.d.ts +1 -0
- package/dist/release/index.js +1 -0
- package/dist/release/pipeline.js +7 -0
- package/dist/release/types.d.ts +12 -0
- package/dist/render/constants.d.ts +2 -1
- package/dist/render/constants.js +2 -1
- package/dist/render/framework-commands.js +4 -0
- package/dist/render/spec-validate.js +23 -12
- package/dist/run-summary/types.d.ts +4 -0
- package/dist/scope/main.js +15 -5
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope-provenance/evaluate.js +3 -3
- package/dist/session/ac-pass-banking.d.ts +5 -0
- package/dist/session/ac-pass-banking.js +3 -2
- package/dist/session/process-cost.d.ts +32 -10
- package/dist/session/process-cost.js +189 -1
- package/dist/session/product-state-hash.js +41 -24
- package/dist/session/ritual-entrypoint.js +16 -1
- package/dist/session/session-start.d.ts +6 -0
- package/dist/session/session-start.js +32 -2
- package/dist/session/verify-session-ritual.d.ts +24 -1
- package/dist/session/verify-session-ritual.js +89 -6
- package/dist/swarm/finalize-cohort-cli.d.ts +7 -2
- package/dist/swarm/finalize-cohort-cli.js +165 -35
- package/dist/swarm/finalize-cohort.d.ts +1 -0
- package/dist/swarm/finalize-cohort.js +14 -2
- package/dist/swarm/routing-set-cli.js +2 -0
- package/dist/swarm/routing-verify.d.ts +1 -1
- package/dist/swarm/routing-verify.js +2 -2
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/help/registry-data.d.ts +1 -1
- package/dist/triage/help/registry-data.js +1 -1
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/verify-env/agent-hook-readiness.d.ts +2 -2
- package/dist/verify-env/agent-hook-readiness.js +12 -8
- package/dist/verify-env/agent-hooks-live-probe.d.ts +5 -1
- package/dist/verify-env/agent-hooks-live-probe.js +26 -5
- package/dist/verify-env/agent-hooks.js +3 -4
- package/package.json +7 -3
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
1
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
2
3
|
import { readCorePackageVersion } from "../engine-version.js";
|
|
4
|
+
import { hasArtifactSuffix } from "../layout/resolve.js";
|
|
5
|
+
import { readPlanSequence } from "../plan-sequence/store.js";
|
|
3
6
|
import { formatFrameworkCommand } from "../render/framework-commands.js";
|
|
4
7
|
import { checkActiveCliAgainstTarget, } from "./active-cli.js";
|
|
5
8
|
import { defaultGitRunner, gitHead, gitIsAncestor, worktreePath } from "./git.js";
|
|
@@ -17,6 +20,64 @@ export const GATED_ENTRYPOINT_COMMANDS = {
|
|
|
17
20
|
doctor: ["doctor"],
|
|
18
21
|
cache_fresh: ["verify:cache-fresh"],
|
|
19
22
|
};
|
|
23
|
+
/** Explicit skip flag threaded through the gated `cache_fresh` argv (#3507). */
|
|
24
|
+
export const SKIP_DRIFT_PROBE_FLAG = "--skip-drift-probe";
|
|
25
|
+
/** Explicit work-selection flag threaded through the gated `cache_fresh` argv (#3507). */
|
|
26
|
+
export const WORK_SELECTION_FLAG = "--work-selection";
|
|
27
|
+
/** Distinct ritual-state field — never `deferred_reason` (#3507). */
|
|
28
|
+
export const DRIFT_PROBE_SKIPPED_NO_WORK_SELECTION = "skipped-no-work-selection";
|
|
29
|
+
function hasActiveStoryArtifact(projectRoot) {
|
|
30
|
+
for (const dirName of ["xbrief", "vbrief"]) {
|
|
31
|
+
const activeDir = join(projectRoot, dirName, "active");
|
|
32
|
+
try {
|
|
33
|
+
for (const entry of readdirSync(activeDir, { withFileTypes: true })) {
|
|
34
|
+
if (entry.isFile() && hasArtifactSuffix(entry.name))
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* missing or unreadable active folder is not work selection */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function hasUnexhaustedPlanSequence(projectRoot) {
|
|
45
|
+
try {
|
|
46
|
+
const sequence = readPlanSequence(projectRoot);
|
|
47
|
+
if (sequence === null || sequence.exhausted === true)
|
|
48
|
+
return null;
|
|
49
|
+
return sequence.sequence_kind === "triage" ? "triage-queue" : "ordered-plan";
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Default work-selection detector for the gated `cache_fresh` seam (#3507).
|
|
57
|
+
* Active story xBRIEF (scope:activate residue), unexhausted ordered-plan /
|
|
58
|
+
* triage sequence. `--for-issue` is a positive evaluate override, not this
|
|
59
|
+
* detector — the gated argv never carries it.
|
|
60
|
+
*/
|
|
61
|
+
export function detectWorkSelection(projectRoot) {
|
|
62
|
+
if (hasActiveStoryArtifact(projectRoot)) {
|
|
63
|
+
return { inPlay: true, kind: "active-story" };
|
|
64
|
+
}
|
|
65
|
+
const planKind = hasUnexhaustedPlanSequence(projectRoot);
|
|
66
|
+
if (planKind !== null) {
|
|
67
|
+
return { inPlay: true, kind: planKind };
|
|
68
|
+
}
|
|
69
|
+
return { inPlay: false, kind: "none" };
|
|
70
|
+
}
|
|
71
|
+
export function resolveGatedEntrypointCommand(stepName, projectRoot, detect = detectWorkSelection) {
|
|
72
|
+
const base = [...GATED_ENTRYPOINT_COMMANDS[stepName]];
|
|
73
|
+
if (stepName !== "cache_fresh")
|
|
74
|
+
return base;
|
|
75
|
+
const selection = detect(projectRoot);
|
|
76
|
+
if (selection.inPlay) {
|
|
77
|
+
return [...base, WORK_SELECTION_FLAG];
|
|
78
|
+
}
|
|
79
|
+
return [...base, SKIP_DRIFT_PROBE_FLAG];
|
|
80
|
+
}
|
|
20
81
|
function truthy(raw) {
|
|
21
82
|
return new Set(["1", "true", "yes", "on"]).has((raw ?? "").trim().toLowerCase());
|
|
22
83
|
}
|
|
@@ -25,6 +86,7 @@ function stepPasses(step) {
|
|
|
25
86
|
return false;
|
|
26
87
|
if (step.deferred_reason)
|
|
27
88
|
return true;
|
|
89
|
+
// `drift_probe` is a distinct diagnostic; it must never satisfy a step (#3507).
|
|
28
90
|
return step.ok === true;
|
|
29
91
|
}
|
|
30
92
|
function failedStepMessage(tierName, stepName, step) {
|
|
@@ -52,14 +114,29 @@ export function formatRitualRecoveryInstruction(tier = "cold") {
|
|
|
52
114
|
}
|
|
53
115
|
/**
|
|
54
116
|
* Sanctioned audited defer copy for gated `cache_fresh` failure (#3506 / #3507).
|
|
55
|
-
*
|
|
117
|
+
* Independent of the #3507 work-selection argv seam — defer is still the
|
|
118
|
+
* operator-audited escape, not the drift-probe skip.
|
|
56
119
|
*/
|
|
57
120
|
export function formatCacheFreshDeferSoftPath() {
|
|
58
121
|
const cmd = formatFrameworkCommand(["session:start", "--", "--defer", "cache_fresh=<reason>"]);
|
|
59
122
|
return `Soft path (audited): \`${cmd}\`.`;
|
|
60
123
|
}
|
|
61
|
-
function
|
|
62
|
-
|
|
124
|
+
function applyCacheFreshDriftProbeField(payload, command) {
|
|
125
|
+
if (command.includes(SKIP_DRIFT_PROBE_FLAG)) {
|
|
126
|
+
payload.drift_probe = DRIFT_PROBE_SKIPPED_NO_WORK_SELECTION;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (payload.drift_probe === DRIFT_PROBE_SKIPPED_NO_WORK_SELECTION) {
|
|
130
|
+
delete payload.drift_probe;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function shouldRearmDriftProbe(payload, projectRoot, detect) {
|
|
134
|
+
if (payload.drift_probe !== DRIFT_PROBE_SKIPPED_NO_WORK_SELECTION)
|
|
135
|
+
return false;
|
|
136
|
+
return detect(projectRoot).inPlay;
|
|
137
|
+
}
|
|
138
|
+
function runGatedStep(projectRoot, payload, stepName, runner, now, detect = detectWorkSelection) {
|
|
139
|
+
const command = resolveGatedEntrypointCommand(stepName, projectRoot, detect);
|
|
63
140
|
const { code, stdout, stderr } = runner(command, projectRoot);
|
|
64
141
|
const message = stdout.trim() || stderr.trim() || `${command[0]} exited ${code}`;
|
|
65
142
|
const gated = payload.gated_steps ?? {};
|
|
@@ -71,6 +148,9 @@ function runGatedStep(projectRoot, payload, stepName, runner, now) {
|
|
|
71
148
|
command,
|
|
72
149
|
});
|
|
73
150
|
payload.gated_steps = gated;
|
|
151
|
+
if (stepName === "cache_fresh") {
|
|
152
|
+
applyCacheFreshDriftProbeField(payload, command);
|
|
153
|
+
}
|
|
74
154
|
try {
|
|
75
155
|
writeRitualState(projectRoot, payload);
|
|
76
156
|
}
|
|
@@ -361,6 +441,7 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
361
441
|
payload.gated_steps = gated;
|
|
362
442
|
const runCmd = options.runner ?? defaultRitualRunner;
|
|
363
443
|
const forced = new Set(options.forceGatedSteps ?? []);
|
|
444
|
+
const detect = options.detectWorkSelection ?? detectWorkSelection;
|
|
364
445
|
for (const stepName of GATED_STEPS) {
|
|
365
446
|
const step = gated[stepName];
|
|
366
447
|
if (step?.deferred_reason && stepName !== "agent_hooks")
|
|
@@ -368,9 +449,11 @@ export function verifySessionRitual(projectRoot, options = {}) {
|
|
|
368
449
|
// Hook readiness is a live mutation prerequisite, not a cacheable doctor
|
|
369
450
|
// result. Re-run it at every gated boundary so registration/shim drift
|
|
370
451
|
// cannot remain hidden behind an earlier green ritual record.
|
|
371
|
-
|
|
452
|
+
const rearmDrift = stepName === "cache_fresh" && shouldRearmDriftProbe(payload, projectRoot, detect);
|
|
453
|
+
if (stepName !== "agent_hooks" && stepPasses(step) && !forced.has(stepName) && !rearmDrift) {
|
|
372
454
|
continue;
|
|
373
|
-
|
|
455
|
+
}
|
|
456
|
+
const writeError = runGatedStep(projectRoot, payload, stepName, runCmd, instant, detect);
|
|
374
457
|
if (writeError !== null) {
|
|
375
458
|
return {
|
|
376
459
|
code: 2,
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
export
|
|
2
|
+
import { type FinalizeCohortArgs } from "./finalize-cohort.js";
|
|
3
|
+
export interface ParsedFinalizeCohortArgv extends FinalizeCohortArgs {
|
|
4
|
+
readonly help: boolean;
|
|
5
|
+
readonly error: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare const FINALIZE_COHORT_USAGE = "Usage: task swarm:finalize-cohort -- [--pr <n>[,<n>...]] [--stories <ids|paths>] [options]\n\nAfter cohort PRs merge, sweep story briefs active/ -> completed/ and open the lifecycle PR.\n\nOptions:\n --pr <n>[,<n>...] Merged PR numbers (closing issues map to active stories)\n --stories <ids|paths> Explicit story tokens (repeatable)\n --repo OWNER/REPO GitHub repo (or $GH_REPO)\n --project-root <path> Project root (default: cwd)\n --base-branch <name> Sweep/PR base (default: resolved delivery branch)\n --delivery-branch <name> Delivery-branch override when policy is untyped\n --label <name> Feature-branch label\n --dry-run Print plan; no git mutation\n --no-commit Sweep without committing / opening a PR\n --no-open-pr Commit without opening a PR\n --json Machine-readable result\n -h, --help Show this help\n";
|
|
8
|
+
export declare function parseFinalizeCohortArgv(argv: readonly string[]): ParsedFinalizeCohortArgv;
|
|
4
9
|
export declare function finalizeCohortMain(argv?: string[]): number;
|
|
5
10
|
//# sourceMappingURL=finalize-cohort-cli.d.ts.map
|
|
@@ -1,67 +1,181 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { EXIT_CONFIG_ERROR, EXIT_OK } from "./constants.js";
|
|
3
4
|
import { finalizeCohort } from "./finalize-cohort.js";
|
|
5
|
+
export const FINALIZE_COHORT_USAGE = `Usage: task swarm:finalize-cohort -- [--pr <n>[,<n>...]] [--stories <ids|paths>] [options]
|
|
6
|
+
|
|
7
|
+
After cohort PRs merge, sweep story briefs active/ -> completed/ and open the lifecycle PR.
|
|
8
|
+
|
|
9
|
+
Options:
|
|
10
|
+
--pr <n>[,<n>...] Merged PR numbers (closing issues map to active stories)
|
|
11
|
+
--stories <ids|paths> Explicit story tokens (repeatable)
|
|
12
|
+
--repo OWNER/REPO GitHub repo (or $GH_REPO)
|
|
13
|
+
--project-root <path> Project root (default: cwd)
|
|
14
|
+
--base-branch <name> Sweep/PR base (default: resolved delivery branch)
|
|
15
|
+
--delivery-branch <name> Delivery-branch override when policy is untyped
|
|
16
|
+
--label <name> Feature-branch label
|
|
17
|
+
--dry-run Print plan; no git mutation
|
|
18
|
+
--no-commit Sweep without committing / opening a PR
|
|
19
|
+
--no-open-pr Commit without opening a PR
|
|
20
|
+
--json Machine-readable result
|
|
21
|
+
-h, --help Show this help
|
|
22
|
+
`;
|
|
23
|
+
function equalsValue(arg, flag) {
|
|
24
|
+
return arg.slice(flag.length + 1);
|
|
25
|
+
}
|
|
26
|
+
function parsePrList(raw, flag, prNumbers, reject) {
|
|
27
|
+
if (raw.trim().length === 0) {
|
|
28
|
+
reject(flag);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const piece of raw.split(",")) {
|
|
32
|
+
const trimmed = piece.trim();
|
|
33
|
+
if (trimmed.length === 0) {
|
|
34
|
+
reject(flag);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
38
|
+
reject(flag);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
prNumbers.push(Number.parseInt(trimmed, 10));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
4
44
|
export function parseFinalizeCohortArgv(argv) {
|
|
5
45
|
const prNumbers = [];
|
|
6
46
|
const storyTokens = [];
|
|
7
47
|
let repo = null;
|
|
8
48
|
let projectRoot = ".";
|
|
9
|
-
let baseBranch
|
|
49
|
+
let baseBranch;
|
|
10
50
|
let deliveryBranch = null;
|
|
11
51
|
let label = null;
|
|
12
52
|
let dryRun = false;
|
|
13
53
|
let noCommit = false;
|
|
14
54
|
let noOpenPr = false;
|
|
15
55
|
let emitJson = false;
|
|
56
|
+
let help = false;
|
|
57
|
+
let error = null;
|
|
58
|
+
const reject = (arg) => {
|
|
59
|
+
error ??= `unrecognized argument: ${arg}`;
|
|
60
|
+
};
|
|
61
|
+
const takeValue = (flag, nextValue) => {
|
|
62
|
+
if (nextValue === undefined || nextValue.startsWith("-")) {
|
|
63
|
+
reject(flag);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
return nextValue;
|
|
67
|
+
};
|
|
16
68
|
for (let i = 0; i < argv.length; i += 1) {
|
|
17
69
|
const arg = argv[i];
|
|
18
70
|
const next = argv[i + 1];
|
|
19
|
-
if (arg === "--
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
71
|
+
if (arg === "--help" || arg === "-h") {
|
|
72
|
+
help = true;
|
|
73
|
+
}
|
|
74
|
+
else if (arg === "--pr") {
|
|
75
|
+
const value = takeValue(arg, next);
|
|
76
|
+
if (value !== null) {
|
|
77
|
+
parsePrList(value, arg, prNumbers, reject);
|
|
78
|
+
i += 1;
|
|
25
79
|
}
|
|
26
|
-
i += 1;
|
|
27
80
|
}
|
|
28
81
|
else if (arg?.startsWith("--pr=")) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
82
|
+
parsePrList(equalsValue(arg, "--pr"), arg, prNumbers, reject);
|
|
83
|
+
}
|
|
84
|
+
else if (arg === "--stories") {
|
|
85
|
+
const value = takeValue(arg, next);
|
|
86
|
+
if (value !== null) {
|
|
87
|
+
storyTokens.push(value);
|
|
88
|
+
i += 1;
|
|
34
89
|
}
|
|
35
90
|
}
|
|
36
|
-
else if (arg
|
|
37
|
-
|
|
38
|
-
|
|
91
|
+
else if (arg?.startsWith("--stories=")) {
|
|
92
|
+
const value = equalsValue(arg, "--stories");
|
|
93
|
+
if (value.length === 0) {
|
|
94
|
+
reject(arg);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
storyTokens.push(value);
|
|
98
|
+
}
|
|
39
99
|
}
|
|
40
|
-
else if (arg === "--repo"
|
|
41
|
-
|
|
42
|
-
|
|
100
|
+
else if (arg === "--repo") {
|
|
101
|
+
const value = takeValue(arg, next);
|
|
102
|
+
if (value !== null) {
|
|
103
|
+
repo = value;
|
|
104
|
+
i += 1;
|
|
105
|
+
}
|
|
43
106
|
}
|
|
44
107
|
else if (arg?.startsWith("--repo=")) {
|
|
45
|
-
|
|
108
|
+
const value = equalsValue(arg, "--repo");
|
|
109
|
+
if (value.length === 0) {
|
|
110
|
+
reject(arg);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
repo = value;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (arg === "--project-root") {
|
|
117
|
+
const value = takeValue(arg, next);
|
|
118
|
+
if (value !== null) {
|
|
119
|
+
projectRoot = value;
|
|
120
|
+
i += 1;
|
|
121
|
+
}
|
|
46
122
|
}
|
|
47
|
-
else if (arg
|
|
48
|
-
|
|
49
|
-
|
|
123
|
+
else if (arg?.startsWith("--project-root=")) {
|
|
124
|
+
const value = equalsValue(arg, "--project-root");
|
|
125
|
+
if (value.length === 0) {
|
|
126
|
+
reject(arg);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
projectRoot = value;
|
|
130
|
+
}
|
|
50
131
|
}
|
|
51
|
-
else if (arg === "--base-branch"
|
|
52
|
-
|
|
53
|
-
|
|
132
|
+
else if (arg === "--base-branch") {
|
|
133
|
+
const value = takeValue(arg, next);
|
|
134
|
+
if (value !== null) {
|
|
135
|
+
baseBranch = value;
|
|
136
|
+
i += 1;
|
|
137
|
+
}
|
|
54
138
|
}
|
|
55
|
-
else if (arg
|
|
56
|
-
|
|
57
|
-
|
|
139
|
+
else if (arg?.startsWith("--base-branch=")) {
|
|
140
|
+
const value = equalsValue(arg, "--base-branch");
|
|
141
|
+
if (value.length === 0) {
|
|
142
|
+
reject(arg);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
baseBranch = value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (arg === "--delivery-branch") {
|
|
149
|
+
const value = takeValue(arg, next);
|
|
150
|
+
if (value !== null) {
|
|
151
|
+
deliveryBranch = value;
|
|
152
|
+
i += 1;
|
|
153
|
+
}
|
|
58
154
|
}
|
|
59
155
|
else if (arg?.startsWith("--delivery-branch=")) {
|
|
60
|
-
|
|
156
|
+
const value = equalsValue(arg, "--delivery-branch");
|
|
157
|
+
if (value.length === 0) {
|
|
158
|
+
reject(arg);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
deliveryBranch = value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (arg === "--label") {
|
|
165
|
+
const value = takeValue(arg, next);
|
|
166
|
+
if (value !== null) {
|
|
167
|
+
label = value;
|
|
168
|
+
i += 1;
|
|
169
|
+
}
|
|
61
170
|
}
|
|
62
|
-
else if (arg
|
|
63
|
-
|
|
64
|
-
|
|
171
|
+
else if (arg?.startsWith("--label=")) {
|
|
172
|
+
const value = equalsValue(arg, "--label");
|
|
173
|
+
if (value.length === 0) {
|
|
174
|
+
reject(arg);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
label = value;
|
|
178
|
+
}
|
|
65
179
|
}
|
|
66
180
|
else if (arg === "--dry-run") {
|
|
67
181
|
dryRun = true;
|
|
@@ -78,23 +192,37 @@ export function parseFinalizeCohortArgv(argv) {
|
|
|
78
192
|
else if (arg !== undefined && !arg.startsWith("-")) {
|
|
79
193
|
storyTokens.push(arg);
|
|
80
194
|
}
|
|
195
|
+
else if (arg !== undefined) {
|
|
196
|
+
reject(arg);
|
|
197
|
+
}
|
|
81
198
|
}
|
|
82
199
|
return {
|
|
83
200
|
prNumbers,
|
|
84
201
|
storyTokens,
|
|
85
202
|
repo,
|
|
86
203
|
projectRoot,
|
|
87
|
-
baseBranch,
|
|
204
|
+
...(baseBranch !== undefined ? { baseBranch } : {}),
|
|
88
205
|
deliveryBranch,
|
|
89
206
|
label,
|
|
90
207
|
dryRun,
|
|
91
208
|
noCommit,
|
|
92
209
|
noOpenPr,
|
|
93
210
|
emitJson,
|
|
211
|
+
help,
|
|
212
|
+
error,
|
|
94
213
|
};
|
|
95
214
|
}
|
|
96
215
|
export function finalizeCohortMain(argv = process.argv.slice(2)) {
|
|
97
|
-
const
|
|
216
|
+
const parsed = parseFinalizeCohortArgv(argv);
|
|
217
|
+
if (parsed.help) {
|
|
218
|
+
process.stdout.write(FINALIZE_COHORT_USAGE);
|
|
219
|
+
return EXIT_OK;
|
|
220
|
+
}
|
|
221
|
+
if (parsed.error !== null) {
|
|
222
|
+
process.stderr.write(`${parsed.error}\n`);
|
|
223
|
+
return EXIT_CONFIG_ERROR;
|
|
224
|
+
}
|
|
225
|
+
const result = finalizeCohort(parsed);
|
|
98
226
|
if (result.stdout.length > 0) {
|
|
99
227
|
process.stdout.write(result.stdout);
|
|
100
228
|
}
|
|
@@ -103,7 +231,9 @@ export function finalizeCohortMain(argv = process.argv.slice(2)) {
|
|
|
103
231
|
}
|
|
104
232
|
return result.exitCode;
|
|
105
233
|
}
|
|
234
|
+
/* v8 ignore start -- entry guard */
|
|
106
235
|
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
107
236
|
process.exit(finalizeCohortMain());
|
|
108
237
|
}
|
|
238
|
+
/* v8 ignore stop */
|
|
109
239
|
//# sourceMappingURL=finalize-cohort-cli.js.map
|
|
@@ -13,6 +13,7 @@ export interface FinalizeCohortResult {
|
|
|
13
13
|
readonly branch: string | null;
|
|
14
14
|
readonly pr_url: string | null;
|
|
15
15
|
readonly delivery_branch: string | null;
|
|
16
|
+
readonly sweep_base: string;
|
|
16
17
|
readonly delivery_errors: readonly string[];
|
|
17
18
|
readonly errors: readonly string[];
|
|
18
19
|
readonly warnings: readonly string[];
|
|
@@ -327,8 +327,6 @@ export function finalizeCohort(args) {
|
|
|
327
327
|
const prNumbers = [...(args.prNumbers ?? [])].sort((a, b) => a - b);
|
|
328
328
|
const storyTokens = splitCsv(args.storyTokens ?? []);
|
|
329
329
|
const repo = args.repo ?? process.env.GH_REPO ?? null;
|
|
330
|
-
// baseBranch is for the lifecycle sweep PR only — not delivery proof (#3041).
|
|
331
|
-
const baseBranch = args.baseBranch ?? "master";
|
|
332
330
|
const dryRun = args.dryRun ?? false;
|
|
333
331
|
const noCommit = args.noCommit ?? false;
|
|
334
332
|
const noOpenPr = args.noOpenPr ?? false;
|
|
@@ -351,6 +349,12 @@ export function finalizeCohort(args) {
|
|
|
351
349
|
const deliveryBranch = policyDelivery.source === "typed"
|
|
352
350
|
? policyDelivery.branch
|
|
353
351
|
: (cliDelivery ?? policyDelivery.branch);
|
|
352
|
+
// Sweep/PR base is distinct from delivery proof (#3041). Default via the resolved
|
|
353
|
+
// delivery branch — never a hardcoded "master". --base-branch remains the override.
|
|
354
|
+
const explicitSweepBase = args.baseBranch !== undefined && args.baseBranch !== null && args.baseBranch.trim().length > 0
|
|
355
|
+
? args.baseBranch.trim()
|
|
356
|
+
: null;
|
|
357
|
+
const baseBranch = explicitSweepBase ?? deliveryBranch;
|
|
354
358
|
if (!existsSync(projectRoot)) {
|
|
355
359
|
return buildResponse({
|
|
356
360
|
projectRoot,
|
|
@@ -364,6 +368,7 @@ export function finalizeCohort(args) {
|
|
|
364
368
|
branch: null,
|
|
365
369
|
prUrl: null,
|
|
366
370
|
deliveryBranch,
|
|
371
|
+
sweepBase: baseBranch,
|
|
367
372
|
deliveryErrors: [],
|
|
368
373
|
errors: [`project root does not exist: ${projectRoot}`],
|
|
369
374
|
warnings: [],
|
|
@@ -385,6 +390,7 @@ export function finalizeCohort(args) {
|
|
|
385
390
|
branch: null,
|
|
386
391
|
prUrl: null,
|
|
387
392
|
deliveryBranch,
|
|
393
|
+
sweepBase: baseBranch,
|
|
388
394
|
deliveryErrors: [],
|
|
389
395
|
errors: [`no xbrief/ directory under project root: ${projectRoot}`],
|
|
390
396
|
warnings: [],
|
|
@@ -546,6 +552,7 @@ export function finalizeCohort(args) {
|
|
|
546
552
|
branch: null,
|
|
547
553
|
prUrl: null,
|
|
548
554
|
deliveryBranch,
|
|
555
|
+
sweepBase: baseBranch,
|
|
549
556
|
deliveryErrors,
|
|
550
557
|
errors,
|
|
551
558
|
warnings,
|
|
@@ -572,6 +579,7 @@ export function finalizeCohort(args) {
|
|
|
572
579
|
branch: null,
|
|
573
580
|
prUrl: null,
|
|
574
581
|
deliveryBranch,
|
|
582
|
+
sweepBase: baseBranch,
|
|
575
583
|
deliveryErrors,
|
|
576
584
|
errors,
|
|
577
585
|
warnings,
|
|
@@ -673,6 +681,7 @@ export function finalizeCohort(args) {
|
|
|
673
681
|
branch: null,
|
|
674
682
|
prUrl: null,
|
|
675
683
|
deliveryBranch,
|
|
684
|
+
sweepBase: baseBranch,
|
|
676
685
|
deliveryErrors,
|
|
677
686
|
errors,
|
|
678
687
|
warnings,
|
|
@@ -712,6 +721,7 @@ export function finalizeCohort(args) {
|
|
|
712
721
|
branch,
|
|
713
722
|
prUrl,
|
|
714
723
|
deliveryBranch,
|
|
724
|
+
sweepBase: baseBranch,
|
|
715
725
|
deliveryErrors,
|
|
716
726
|
errors,
|
|
717
727
|
warnings,
|
|
@@ -733,6 +743,7 @@ function buildResponse(input) {
|
|
|
733
743
|
branch: input.branch,
|
|
734
744
|
pr_url: input.prUrl,
|
|
735
745
|
delivery_branch: input.deliveryBranch,
|
|
746
|
+
sweep_base: input.sweepBase,
|
|
736
747
|
delivery_errors: input.deliveryErrors,
|
|
737
748
|
errors: input.errors,
|
|
738
749
|
warnings: input.warnings,
|
|
@@ -754,6 +765,7 @@ function buildResponse(input) {
|
|
|
754
765
|
if (input.deliveryBranch !== null) {
|
|
755
766
|
lines.push(` Delivery branch: ${input.deliveryBranch}`);
|
|
756
767
|
}
|
|
768
|
+
lines.push(` Sweep base: ${input.sweepBase}`);
|
|
757
769
|
if (input.prNumbers.length > 0) {
|
|
758
770
|
lines.push(` PRs: ${input.prNumbers.map((n) => `#${n}`).join(", ")}`);
|
|
759
771
|
}
|
|
@@ -22,6 +22,8 @@ export function routingSetMain(argv = process.argv.slice(2), environ = process.e
|
|
|
22
22
|
let harnessDefault = false;
|
|
23
23
|
for (let i = 0; i < argv.length; i += 1) {
|
|
24
24
|
const arg = argv[i];
|
|
25
|
+
if (arg === "--")
|
|
26
|
+
continue;
|
|
25
27
|
if (arg === "--project-root" && argv[i + 1] !== undefined) {
|
|
26
28
|
projectRoot = argv[i + 1] ?? ".";
|
|
27
29
|
i += 1;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RoutingFile } from "./routing.js";
|
|
2
|
-
export declare const ROUTING_SET_CMD = "
|
|
2
|
+
export declare const ROUTING_SET_CMD = "deft swarm:routing-set --role <role> --model <slug> (or --harness-default)";
|
|
3
3
|
/** Roles the pre-dispatch gate checks by default: the actual model lever. */
|
|
4
4
|
export declare const DEFAULT_GATED_ROLES: readonly ["leaf-implementation"];
|
|
5
5
|
export interface VerifyRoutingOptions {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { EXIT_CONFIG_ERROR, EXIT_GATE_FAILED, EXIT_OK } from "./constants.js";
|
|
14
14
|
import { dispatchProviderFromRuntime, emptyHostDetectProbes, HARNESS_BOUND_PROVIDERS, loadRoutingFile, ROUTING_MODE_HARNESS_DEFAULT, resolveDispatchProvider, resolveModelRoute, resolveRoutingPath, } from "./routing.js";
|
|
15
|
-
export const ROUTING_SET_CMD = "
|
|
15
|
+
export const ROUTING_SET_CMD = "deft swarm:routing-set --role <role> --model <slug> (or --harness-default)";
|
|
16
16
|
/** Roles the pre-dispatch gate checks by default: the actual model lever. */
|
|
17
17
|
export const DEFAULT_GATED_ROLES = ["leaf-implementation"];
|
|
18
18
|
function resolveProvider(options) {
|
|
@@ -105,7 +105,7 @@ export function verifyRouting(options) {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
if (options.advise) {
|
|
108
|
-
const note = "[deft routing] NOTE: plan.policy.swarmSubagentBackend enum is deprecated (#1891); use '
|
|
108
|
+
const note = "[deft routing] NOTE: plan.policy.swarmSubagentBackend enum is deprecated (#1891); use 'deft swarm:routing-set' / .deft/routing.local.json instead.";
|
|
109
109
|
let body;
|
|
110
110
|
if (undecided.length === 0 && invalid.length === 0) {
|
|
111
111
|
body = `[deft routing] provider '${provider}': all ${roles.length} gated role(s) decided.`;
|
|
@@ -370,12 +370,12 @@ export function formatSummary(result) {
|
|
|
370
370
|
if (result.exitCode === 0) {
|
|
371
371
|
lines.push("");
|
|
372
372
|
lines.push("Next steps:");
|
|
373
|
-
lines.push("
|
|
374
|
-
lines.push("
|
|
375
|
-
lines.push("
|
|
376
|
-
lines.push("
|
|
377
|
-
lines.push("
|
|
378
|
-
lines.push("
|
|
373
|
+
lines.push(" deft cache:fetch-all --source=github-issue --repo OWNER/NAME # refresh the cache (#883 Story 2)");
|
|
374
|
+
lines.push(" deft cache:get github-issue OWNER/NAME/<N> # inspect cached issue N");
|
|
375
|
+
lines.push(" deft triage:accept --issue <N> --repo OWNER/NAME # accept issue N (#845 Story 3)");
|
|
376
|
+
lines.push(" deft triage:reject --issue <N> --repo OWNER/NAME --reason 'why' # reject issue N");
|
|
377
|
+
lines.push(" deft triage:bulk-accept --repo OWNER/NAME --label adoption-blocker # bulk accept");
|
|
378
|
+
lines.push(" deft triage:refresh-active # pre-swarm freshness gate");
|
|
379
379
|
}
|
|
380
380
|
return lines.join("\n");
|
|
381
381
|
}
|
|
@@ -357,7 +357,7 @@ export declare const registryData: {
|
|
|
357
357
|
readonly name: "task triage:metrics";
|
|
358
358
|
readonly summary: "Attributed-value trend from the events ledger";
|
|
359
359
|
readonly refs: "(#1709)";
|
|
360
|
-
readonly description: "Report value-feedback attribution trends from .deft-cache/events.jsonl: total signal count plus per-class (value, bypass, adoption, friction) and per-event breakdowns over a time window. Alias of the value:show handler.
|
|
360
|
+
readonly description: "Report value-feedback attribution trends from .deft-cache/events.jsonl: total signal count plus per-class (value, bypass, adoption, friction) and per-event breakdowns over a time window. Also composes a ceremony-cost rollup (#3508): last cold vs re-arm CLI process time, per-step ms, blocked-ritual count, recovery-tier distribution. Alias of the value:show handler. Attribution requires plan.policy.valueFeedback.enabled (default OFF) — exits blocked when disabled, but still prints the ceremony-cost section. An empty attribution ledger prints a no-signals message. In the maintainer repo, attribution is skipped unless DEFT_VALUE_SELF_DOGFOOD=1.";
|
|
361
361
|
readonly usage: "task triage:metrics [-- --window=7d] [--format=text|json]";
|
|
362
362
|
readonly flags: readonly [readonly ["--window WINDOW", "7d", "Time window (e.g. 7d, 30d, 24h)."], readonly ["--format text|json", "text", "Output shape (json emits the full trend object)."]];
|
|
363
363
|
readonly examples: readonly ["task triage:metrics", "task triage:metrics -- --window=30d --format=json"];
|
|
@@ -628,7 +628,7 @@ export const registryData = {
|
|
|
628
628
|
name: "task triage:metrics",
|
|
629
629
|
summary: "Attributed-value trend from the events ledger",
|
|
630
630
|
refs: "(#1709)",
|
|
631
|
-
description: "Report value-feedback attribution trends from .deft-cache/events.jsonl: total signal count plus per-class (value, bypass, adoption, friction) and per-event breakdowns over a time window. Alias of the value:show handler.
|
|
631
|
+
description: "Report value-feedback attribution trends from .deft-cache/events.jsonl: total signal count plus per-class (value, bypass, adoption, friction) and per-event breakdowns over a time window. Also composes a ceremony-cost rollup (#3508): last cold vs re-arm CLI process time, per-step ms, blocked-ritual count, recovery-tier distribution. Alias of the value:show handler. Attribution requires plan.policy.valueFeedback.enabled (default OFF) — exits blocked when disabled, but still prints the ceremony-cost section. An empty attribution ledger prints a no-signals message. In the maintainer repo, attribution is skipped unless DEFT_VALUE_SELF_DOGFOOD=1.",
|
|
632
632
|
usage: "task triage:metrics [-- --window=7d] [--format=text|json]",
|
|
633
633
|
flags: [
|
|
634
634
|
["--window WINDOW", "7d", "Time window (e.g. 7d, 30d, 24h)."],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function appendAuditEntry(projectRoot: string, entry: string): string;
|
|
1
|
+
export declare function appendAuditEntry(projectRoot: string, entry: string, changed?: boolean): string;
|
|
2
2
|
export declare function writeTriageScope(projectRoot: string, rules: Array<Record<string, unknown>>, options?: {
|
|
3
3
|
presetLabel: string;
|
|
4
4
|
actor?: string;
|