@deftai/directive-core 0.105.0 → 0.107.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/gate-lists.js +2 -0
- package/dist/check/named-cause.js +1 -1
- package/dist/design-critique/exclusive-chip.d.ts +33 -0
- package/dist/design-critique/exclusive-chip.js +68 -0
- package/dist/design-critique/parent-audit.d.ts +59 -0
- package/dist/design-critique/parent-audit.js +121 -0
- package/dist/doctor/checks.d.ts +6 -0
- package/dist/doctor/checks.js +35 -0
- package/dist/forward-coverage/diff-coverage.d.ts +39 -0
- package/dist/forward-coverage/diff-coverage.js +112 -0
- package/dist/forward-coverage/diff-lines.d.ts +19 -0
- package/dist/forward-coverage/diff-lines.js +173 -0
- package/dist/forward-coverage/evaluate.d.ts +24 -9
- package/dist/forward-coverage/evaluate.js +125 -19
- package/dist/hooks/dest-form.d.ts +46 -0
- package/dist/hooks/dest-form.js +575 -0
- package/dist/hooks/dispatcher.d.ts +17 -1
- package/dist/hooks/dispatcher.js +82 -11
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- 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/intake/github-auth-modes-cli.js +14 -2
- package/dist/intake/github-auth-modes.d.ts +54 -9
- package/dist/intake/github-auth-modes.js +326 -123
- package/dist/lifecycle/completed-tracked-on-delivery.d.ts +26 -0
- package/dist/lifecycle/completed-tracked-on-delivery.js +37 -14
- package/dist/lifecycle/completed-write-guard.d.ts +48 -0
- package/dist/lifecycle/completed-write-guard.js +373 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle-visible/evaluate.d.ts +98 -0
- package/dist/lifecycle-visible/evaluate.js +710 -0
- package/dist/lifecycle-visible/index.d.ts +2 -0
- package/dist/lifecycle-visible/index.js +2 -0
- package/dist/literal-acceptance/capture.d.ts +16 -0
- package/dist/literal-acceptance/capture.js +78 -10
- package/dist/literal-acceptance/evaluate.js +25 -3
- package/dist/literal-acceptance/index.d.ts +2 -2
- package/dist/literal-acceptance/index.js +2 -2
- package/dist/literal-acceptance/run.js +9 -3
- package/dist/literal-acceptance/types.d.ts +6 -0
- package/dist/literal-acceptance/types.js +6 -0
- package/dist/orchestration/judgment-policy.d.ts +13 -0
- package/dist/orchestration/judgment-policy.js +15 -0
- package/dist/orchestration/probe-session.js +13 -8
- package/dist/orchestration/verify-judgment-gates.d.ts +4 -0
- package/dist/orchestration/verify-judgment-gates.js +43 -11
- package/dist/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/runtime-authority.d.ts +18 -0
- package/dist/policy/runtime-authority.js +11 -0
- package/dist/policy/value-feedback.js +7 -8
- package/dist/policy/write-fence.js +3 -0
- package/dist/preflight-cache/evaluate.d.ts +12 -0
- package/dist/preflight-cache/evaluate.js +24 -4
- 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 +82 -10
- 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/scm/design-critique-chip.d.ts +37 -0
- package/dist/scm/design-critique-chip.js +171 -0
- package/dist/scm/index.d.ts +1 -0
- package/dist/scm/index.js +1 -0
- package/dist/scm/main.d.ts +3 -0
- package/dist/scm/main.js +15 -1
- package/dist/scm/readiness-cli.d.ts +2 -0
- package/dist/scm/readiness-cli.js +42 -1
- package/dist/scm/readiness.d.ts +2 -1
- package/dist/scm/readiness.js +7 -1
- package/dist/scope/decompose.js +2 -1
- package/dist/scope/delivery-evidence.d.ts +27 -1
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/lifecycle-write.d.ts +24 -0
- package/dist/scope/lifecycle-write.js +64 -0
- package/dist/scope/main.js +18 -6
- package/dist/scope/promote-from-issue.js +5 -5
- package/dist/scope/transition.js +90 -11
- package/dist/scope-provenance/evaluate.js +8 -4
- package/dist/session/ac-pass-banking.d.ts +5 -0
- package/dist/session/ac-pass-banking.js +3 -2
- package/dist/session/git.d.ts +18 -0
- package/dist/session/git.js +81 -1
- package/dist/session/occupancy.d.ts +2 -1
- package/dist/session/occupancy.js +11 -4
- 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 +18 -0
- package/dist/session/session-start.js +49 -2
- package/dist/session/verify-session-ritual.d.ts +46 -4
- package/dist/session/verify-session-ritual.js +118 -10
- 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/launch.d.ts +69 -0
- package/dist/swarm/launch.js +191 -1
- 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/actions/index.d.ts +4 -0
- package/dist/triage/actions/index.js +6 -0
- package/dist/triage/bootstrap/index.js +6 -6
- package/dist/triage/evaluate/evaluate.d.ts +11 -0
- package/dist/triage/evaluate/evaluate.js +169 -0
- package/dist/triage/evaluate/github.d.ts +16 -0
- package/dist/triage/evaluate/github.js +153 -0
- package/dist/triage/evaluate/index.d.ts +9 -0
- package/dist/triage/evaluate/index.js +8 -0
- package/dist/triage/evaluate/paths.d.ts +7 -0
- package/dist/triage/evaluate/paths.js +25 -0
- package/dist/triage/evaluate/sink.d.ts +5 -0
- package/dist/triage/evaluate/sink.js +52 -0
- package/dist/triage/evaluate/types.d.ts +93 -0
- package/dist/triage/evaluate/types.js +13 -0
- package/dist/triage/evaluate/validity.d.ts +8 -0
- package/dist/triage/evaluate/validity.js +87 -0
- package/dist/triage/evaluate/value.d.ts +12 -0
- package/dist/triage/evaluate/value.js +33 -0
- package/dist/triage/evaluate/wip-census.d.ts +5 -0
- package/dist/triage/evaluate/wip-census.js +39 -0
- package/dist/triage/evaluate/worktrees.d.ts +8 -0
- package/dist/triage/evaluate/worktrees.js +68 -0
- package/dist/triage/evaluate/xbrief-refs.d.ts +8 -0
- package/dist/triage/evaluate/xbrief-refs.js +60 -0
- package/dist/triage/help/registry-data.d.ts +22 -8
- package/dist/triage/help/registry-data.js +54 -6
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/welcome/writers.d.ts +1 -1
- package/dist/triage/welcome/writers.js +10 -5
- package/dist/value/feedback-file.d.ts +17 -2
- package/dist/value/feedback-file.js +80 -6
- package/dist/value/readback.d.ts +4 -1
- package/dist/value/readback.js +51 -12
- package/dist/vbrief-reconcile/labels.d.ts +1 -0
- package/dist/vbrief-reconcile/labels.js +30 -0
- package/dist/vbrief-validate/schema.d.ts +4 -0
- package/dist/vbrief-validate/schema.js +1 -1
- package/dist/vbrief-validation/story-quality.d.ts +7 -0
- package/dist/vbrief-validation/story-quality.js +8 -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/dist/xbrief-migrate/agents-header.js +69 -7
- package/package.json +7 -3
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { listXbriefHits } from "./xbrief-refs.js";
|
|
4
|
+
const ADR_DIR = join("docs", "decisions");
|
|
5
|
+
const CONTRACT_DIR = join("content", "contracts");
|
|
6
|
+
function filesMentionIssue(dir, issue) {
|
|
7
|
+
if (!existsSync(dir)) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const needle = `#${issue}`;
|
|
11
|
+
const hits = [];
|
|
12
|
+
for (const name of readdirSync(dir)) {
|
|
13
|
+
if (!name.endsWith(".md")) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const path = join(dir, name);
|
|
17
|
+
try {
|
|
18
|
+
const text = readFileSync(path, "utf8");
|
|
19
|
+
if (text.includes(needle) || text.includes(`/issues/${issue}`)) {
|
|
20
|
+
hits.push(path);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
}
|
|
25
|
+
return hits;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Evaluator-owned. Reads only `worktreeRoot` (detached origin/master).
|
|
29
|
+
* Must not accept a WIP census argument.
|
|
30
|
+
*/
|
|
31
|
+
export function evaluateValidity(worktreeRoot, issue) {
|
|
32
|
+
const completed = listXbriefHits(worktreeRoot, "completed").filter((hit) => hit.issue === issue);
|
|
33
|
+
const pending = listXbriefHits(worktreeRoot, "pending").filter((hit) => hit.issue === issue);
|
|
34
|
+
const active = listXbriefHits(worktreeRoot, "active").filter((hit) => hit.issue === issue);
|
|
35
|
+
const proposed = listXbriefHits(worktreeRoot, "proposed").filter((hit) => hit.issue === issue);
|
|
36
|
+
const adrHits = filesMentionIssue(join(worktreeRoot, ADR_DIR), issue);
|
|
37
|
+
const contractHits = filesMentionIssue(join(worktreeRoot, CONTRACT_DIR), issue);
|
|
38
|
+
if (completed.length > 0) {
|
|
39
|
+
return {
|
|
40
|
+
state: "likely-shipped",
|
|
41
|
+
evidence: `completed xbrief on origin/master: ${completed[0]?.path}`,
|
|
42
|
+
worktreePath: worktreeRoot,
|
|
43
|
+
sessionStartReadOnly: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (pending.length > 0 || active.length > 0 || proposed.length > 0) {
|
|
47
|
+
const hit = pending[0] ?? active[0] ?? proposed[0];
|
|
48
|
+
return {
|
|
49
|
+
state: "partial",
|
|
50
|
+
evidence: `committed lifecycle xbrief on origin/master: ${hit?.path}`,
|
|
51
|
+
worktreePath: worktreeRoot,
|
|
52
|
+
sessionStartReadOnly: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (adrHits.length > 0 || contractHits.length > 0) {
|
|
56
|
+
return {
|
|
57
|
+
state: "partial",
|
|
58
|
+
evidence: `ADR/contract mention on origin/master: ${adrHits[0] ?? contractHits[0] ?? ""}`,
|
|
59
|
+
worktreePath: worktreeRoot,
|
|
60
|
+
sessionStartReadOnly: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
state: "still-open",
|
|
65
|
+
evidence: "no origin/master lifecycle coverage, ADR, or contract mention",
|
|
66
|
+
worktreePath: worktreeRoot,
|
|
67
|
+
sessionStartReadOnly: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function joinValidityWithGithub(validity, githubState) {
|
|
71
|
+
if (githubState === "closed" && validity.state === "still-open") {
|
|
72
|
+
return {
|
|
73
|
+
...validity,
|
|
74
|
+
state: "likely-shipped",
|
|
75
|
+
evidence: `${validity.evidence}; GitHub issue state=closed`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (githubState === "open" && validity.state === "likely-shipped") {
|
|
79
|
+
return {
|
|
80
|
+
...validity,
|
|
81
|
+
state: "needs-re-scope",
|
|
82
|
+
evidence: `${validity.evidence}; GitHub issue still open`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return validity;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=validity.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type GithubIssueSnapshot, type ValueAdvice } from "./types.js";
|
|
2
|
+
export declare class ReservedClearanceError extends Error {
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function assertNoReservedClearance(text: string, label: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Value MAY recommend critique via `critique-recommend:`.
|
|
8
|
+
* It MUST NOT stamp the reserved ADR-005 clearance grammar.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildValueAdvice(issue: GithubIssueSnapshot | null): ValueAdvice;
|
|
11
|
+
export declare function formatValueField(advice: ValueAdvice): string;
|
|
12
|
+
//# sourceMappingURL=value.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CRITIQUE_RECOMMEND_FIELD, RESERVED_CLEARANCE_RE, } from "./types.js";
|
|
2
|
+
export class ReservedClearanceError extends Error {
|
|
3
|
+
name = "ReservedClearanceError";
|
|
4
|
+
}
|
|
5
|
+
export function assertNoReservedClearance(text, label) {
|
|
6
|
+
if (RESERVED_CLEARANCE_RE.test(text)) {
|
|
7
|
+
throw new ReservedClearanceError(`${label} must not emit the reserved clearance line ` +
|
|
8
|
+
"`design-critique: warranted | not warranted, because …`");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Value MAY recommend critique via `critique-recommend:`.
|
|
13
|
+
* It MUST NOT stamp the reserved ADR-005 clearance grammar.
|
|
14
|
+
*/
|
|
15
|
+
export function buildValueAdvice(issue) {
|
|
16
|
+
const labels = issue?.labels ?? [];
|
|
17
|
+
const stamped = labels.some((label) => label === "design-critique:mechanism-shaped");
|
|
18
|
+
const reason = stamped
|
|
19
|
+
? "GitHub label design-critique:mechanism-shaped is present; author still stamps clearance"
|
|
20
|
+
: "no mechanism-shaped stamp; critique not recommended from evaluation";
|
|
21
|
+
const advice = {
|
|
22
|
+
[CRITIQUE_RECOMMEND_FIELD]: stamped,
|
|
23
|
+
reason,
|
|
24
|
+
};
|
|
25
|
+
assertNoReservedClearance(JSON.stringify(advice), "value advice");
|
|
26
|
+
return advice;
|
|
27
|
+
}
|
|
28
|
+
export function formatValueField(advice) {
|
|
29
|
+
const line = `${CRITIQUE_RECOMMEND_FIELD}: ${advice[CRITIQUE_RECOMMEND_FIELD] ? "true" : "false"}`;
|
|
30
|
+
assertNoReservedClearance(`${line}\n${advice.reason}`, "value field");
|
|
31
|
+
return `${line}\n${advice.reason}`;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=value.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { WipCensus, WipHit } from "./types.js";
|
|
2
|
+
/** Parent-owned. Evaluators must never receive this object. */
|
|
3
|
+
export declare function collectWipCensus(projectRoot: string, issues: readonly number[]): WipCensus;
|
|
4
|
+
export declare function wipHitsForIssue(census: WipCensus, issue: number): WipHit[];
|
|
5
|
+
//# sourceMappingURL=wip-census.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readPlanSequence } from "../../plan-sequence/store.js";
|
|
2
|
+
import { listXbriefHits } from "./xbrief-refs.js";
|
|
3
|
+
function hitsForIssues(hits, issues, kind) {
|
|
4
|
+
return hits
|
|
5
|
+
.filter((hit) => issues.has(hit.issue))
|
|
6
|
+
.map((hit) => ({ kind, path: hit.path, issue: hit.issue }));
|
|
7
|
+
}
|
|
8
|
+
/** Parent-owned. Evaluators must never receive this object. */
|
|
9
|
+
export function collectWipCensus(projectRoot, issues) {
|
|
10
|
+
const wanted = new Set(issues);
|
|
11
|
+
const activeHits = listXbriefHits(projectRoot, "active");
|
|
12
|
+
const pendingHits = listXbriefHits(projectRoot, "pending");
|
|
13
|
+
const planHits = [];
|
|
14
|
+
const sequence = readPlanSequence(projectRoot);
|
|
15
|
+
if (sequence !== null) {
|
|
16
|
+
for (const entry of sequence.entries) {
|
|
17
|
+
const fromField = entry.issue;
|
|
18
|
+
const fromId = Number.parseInt(entry.id.trim().replace(/^#/u, ""), 10);
|
|
19
|
+
const asNumber = typeof fromField === "number" ? fromField : fromId;
|
|
20
|
+
if (!Number.isFinite(asNumber) || !wanted.has(asNumber)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
planHits.push({
|
|
24
|
+
kind: "plan-sequence",
|
|
25
|
+
path: ".deft/plan-sequence.json",
|
|
26
|
+
issue: asNumber,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
active: hitsForIssues(activeHits, wanted, "active-xbrief"),
|
|
32
|
+
pending: hitsForIssues(pendingHits, wanted, "pending-xbrief"),
|
|
33
|
+
planSequence: planHits,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function wipHitsForIssue(census, issue) {
|
|
37
|
+
return [...census.active, ...census.pending, ...census.planSequence].filter((hit) => hit.issue === issue);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=wip-census.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GitRunner } from "./types.js";
|
|
2
|
+
export declare class EvaluatorWorktreeError extends Error {
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function addEvaluatorWorktree(projectRoot: string, issue: number, invocationId: string, originSha: string, git?: GitRunner): string;
|
|
6
|
+
/** Verb-owned remove. Not a shared core git-worktree helper. */
|
|
7
|
+
export declare function removeEvaluatorWorktree(projectRoot: string, worktreePath: string, git?: GitRunner): void;
|
|
8
|
+
//# sourceMappingURL=worktrees.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { defaultGitRunner as swarmGitRunner, } from "../../swarm/worktrees.js";
|
|
4
|
+
import { evaluatorWorktreePath } from "./paths.js";
|
|
5
|
+
export class EvaluatorWorktreeError extends Error {
|
|
6
|
+
name = "EvaluatorWorktreeError";
|
|
7
|
+
}
|
|
8
|
+
function toSwarm(git) {
|
|
9
|
+
return (args, cwd) => git(args, cwd);
|
|
10
|
+
}
|
|
11
|
+
export function addEvaluatorWorktree(projectRoot, issue, invocationId, originSha, git = swarmGitRunner) {
|
|
12
|
+
const sha = originSha.trim();
|
|
13
|
+
if (sha.length === 0) {
|
|
14
|
+
throw new EvaluatorWorktreeError("originSha is required for a detached evaluator worktree");
|
|
15
|
+
}
|
|
16
|
+
const worktreePath = evaluatorWorktreePath(projectRoot, issue, invocationId);
|
|
17
|
+
mkdirSync(dirname(resolve(worktreePath)), { recursive: true });
|
|
18
|
+
const proc = toSwarm(git)(["worktree", "add", "--detach", worktreePath, sha], projectRoot);
|
|
19
|
+
if (proc.returncode !== 0) {
|
|
20
|
+
throw new EvaluatorWorktreeError(`git worktree add --detach failed for issue ${issue}: ${proc.stderr.trim() || "<no stderr>"}`);
|
|
21
|
+
}
|
|
22
|
+
return worktreePath;
|
|
23
|
+
}
|
|
24
|
+
function forceDeleteWorktreeDir(worktreePath) {
|
|
25
|
+
if (!existsSync(worktreePath)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
rmSync(worktreePath, { recursive: true, force: true });
|
|
29
|
+
}
|
|
30
|
+
function worktreeStillRegistered(git, projectRoot, worktreePath) {
|
|
31
|
+
const listed = git(["worktree", "list", "--porcelain"], projectRoot);
|
|
32
|
+
if (listed.returncode !== 0) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
const needle = resolve(worktreePath).replace(/\\/g, "/").toLowerCase();
|
|
36
|
+
for (const line of listed.stdout.split(/\r?\n/u)) {
|
|
37
|
+
if (!line.startsWith("worktree ")) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const listedPath = line.slice("worktree ".length).replace(/\\/g, "/").toLowerCase();
|
|
41
|
+
if (listedPath === needle) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/** Verb-owned remove. Not a shared core git-worktree helper. */
|
|
48
|
+
export function removeEvaluatorWorktree(projectRoot, worktreePath, git = swarmGitRunner) {
|
|
49
|
+
const runner = toSwarm(git);
|
|
50
|
+
const proc = runner(["worktree", "remove", "--force", worktreePath], projectRoot);
|
|
51
|
+
if (proc.returncode === 0) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const firstError = proc.stderr.trim() || "<no stderr>";
|
|
55
|
+
forceDeleteWorktreeDir(worktreePath);
|
|
56
|
+
runner(["worktree", "prune"], projectRoot);
|
|
57
|
+
const retry = runner(["worktree", "remove", "--force", worktreePath], projectRoot);
|
|
58
|
+
if (retry.returncode === 0) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
forceDeleteWorktreeDir(worktreePath);
|
|
62
|
+
runner(["worktree", "prune"], projectRoot);
|
|
63
|
+
if (!worktreeStillRegistered(runner, projectRoot, worktreePath) && !existsSync(worktreePath)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
throw new EvaluatorWorktreeError(`git worktree remove failed for ${worktreePath}: ${firstError}; fallback: ${retry.stderr.trim() || "<no stderr>"}`);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=worktrees.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface XbriefHit {
|
|
2
|
+
readonly issue: number;
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly folder: "active" | "pending" | "proposed" | "completed" | "cancelled";
|
|
5
|
+
}
|
|
6
|
+
export declare function issueNumbersFromXbriefJson(raw: unknown): number[];
|
|
7
|
+
export declare function listXbriefHits(root: string, folder: XbriefHit["folder"]): XbriefHit[];
|
|
8
|
+
//# sourceMappingURL=xbrief-refs.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const ISSUE_URI_RE = /\/issues\/(\d+)\b/u;
|
|
4
|
+
const ISSUE_HASH_RE = /(?:Issue\s+)?#(\d+)\b/u;
|
|
5
|
+
function numbersFromUnknown(value, into) {
|
|
6
|
+
if (typeof value === "string") {
|
|
7
|
+
for (const re of [ISSUE_URI_RE, ISSUE_HASH_RE]) {
|
|
8
|
+
const match = re.exec(value);
|
|
9
|
+
if (match?.[1] !== undefined) {
|
|
10
|
+
into.add(Number.parseInt(match[1], 10));
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
for (const item of value) {
|
|
17
|
+
numbersFromUnknown(item, into);
|
|
18
|
+
}
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (value !== null && typeof value === "object") {
|
|
22
|
+
for (const nested of Object.values(value)) {
|
|
23
|
+
numbersFromUnknown(nested, into);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function issueNumbersFromXbriefJson(raw) {
|
|
28
|
+
const found = new Set();
|
|
29
|
+
if (raw === null || typeof raw !== "object") {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const plan = raw.plan;
|
|
33
|
+
numbersFromUnknown(plan?.references, found);
|
|
34
|
+
return [...found];
|
|
35
|
+
}
|
|
36
|
+
export function listXbriefHits(root, folder) {
|
|
37
|
+
const dir = join(root, "xbrief", folder);
|
|
38
|
+
if (!existsSync(dir)) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const hits = [];
|
|
42
|
+
for (const name of readdirSync(dir)) {
|
|
43
|
+
if (!name.endsWith(".xbrief.json") && !name.endsWith(".vbrief.json")) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const path = join(dir, name);
|
|
47
|
+
let parsed;
|
|
48
|
+
try {
|
|
49
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const issue of issueNumbersFromXbriefJson(parsed)) {
|
|
55
|
+
hits.push({ issue, path, folder });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return hits;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=xbrief-refs.js.map
|
|
@@ -23,6 +23,17 @@ export declare const registryData: {
|
|
|
23
23
|
readonly see_also: readonly ["task triage:bootstrap", "task cache:fetch-all", "#1119 / D5"];
|
|
24
24
|
readonly placeholder: false;
|
|
25
25
|
};
|
|
26
|
+
readonly "task triage:evaluate": {
|
|
27
|
+
readonly name: "task triage:evaluate";
|
|
28
|
+
readonly summary: "Isolated validity + parent WIP census + value advice";
|
|
29
|
+
readonly refs: "(#3648)";
|
|
30
|
+
readonly description: "Stage A issue-eval: detached origin/master worktrees own validity and ADR/contract reads; the parent on the live working set owns WIP census (xbrief/active, xbrief/pending, plan-sequence); GitHub REST owns open PRs/issues/duplicates. Writes a gitignored sink under .deft-scratch/issue-eval/<sha12>/<invocation-id>/. No GitHub writes. No candidates-log row. Value may set critique-recommend: and must not emit the reserved design-critique clearance line. Fan-out default 4, override --concurrency N.";
|
|
31
|
+
readonly usage: "task triage:evaluate -- <N...> [--concurrency N] [--repo OWNER/NAME] [--json]";
|
|
32
|
+
readonly flags: readonly [readonly ["<N...>", "(required)", "Issue numbers to evaluate."], readonly ["--concurrency N", "4", "Parallel evaluator cap (bind, not a measured existing cap)."], readonly ["--repo OWNER/NAME", "(git remote / env)", "Upstream repo for REST reads."], readonly ["--json", "(off)", "Emit the structured EvaluateResult."], readonly ["--project-root PATH", "(cwd)", "Project root override (Taskfile threads USER_WORKING_DIR)."]];
|
|
33
|
+
readonly examples: readonly ["task triage:evaluate -- 3648", "task triage:evaluate -- 10 11 --concurrency 2 --json"];
|
|
34
|
+
readonly see_also: readonly ["task triage:queue", "task triage:accept", "skills/deft-directive-issue-eval/SKILL.md", "#3648"];
|
|
35
|
+
readonly placeholder: false;
|
|
36
|
+
};
|
|
26
37
|
readonly "task triage:accept": {
|
|
27
38
|
readonly name: "task triage:accept";
|
|
28
39
|
readonly summary: "Mark issue accepted; chains into scope:promote w/ flag";
|
|
@@ -357,7 +368,7 @@ export declare const registryData: {
|
|
|
357
368
|
readonly name: "task triage:metrics";
|
|
358
369
|
readonly summary: "Attributed-value trend from the events ledger";
|
|
359
370
|
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.
|
|
371
|
+
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
372
|
readonly usage: "task triage:metrics [-- --window=7d] [--format=text|json]";
|
|
362
373
|
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
374
|
readonly examples: readonly ["task triage:metrics", "task triage:metrics -- --window=30d --format=json"];
|
|
@@ -444,12 +455,12 @@ export declare const registryData: {
|
|
|
444
455
|
readonly "task scope:complete": {
|
|
445
456
|
readonly name: "task scope:complete";
|
|
446
457
|
readonly summary: "active/ -> completed/ (set status completed)";
|
|
447
|
-
readonly refs: "(#845)";
|
|
448
|
-
readonly description: "Mark an active vBRIEF complete and move it to vbrief/completed/. Terminal transition; use scope:undo if you need reversibility (refused on terminal actions per D15).";
|
|
449
|
-
readonly usage: "task scope:complete -- <file>";
|
|
450
|
-
readonly flags: readonly [readonly ["<file>", "(required)", "Path to vBRIEF."], readonly ["--project-root PATH", "(detected)", "Consumer project root override."]];
|
|
451
|
-
readonly examples: readonly ["task scope:complete -- vbrief/active/2026-05-19-foo.vbrief.json"];
|
|
452
|
-
readonly see_also: readonly ["task scope:fail", "task scope:cancel", "#1119 / #845"];
|
|
458
|
+
readonly refs: "(#845, #3041, #3721)";
|
|
459
|
+
readonly description: "Mark an active vBRIEF complete and move it to vbrief/completed/. Terminal transition; use scope:undo if you need reversibility (refused on terminal actions per D15). Code-bearing completion requires delivery evidence: --merge-commit and --pr. Those flags feed the delivery gate; they do not skip literal-AC.";
|
|
460
|
+
readonly usage: "task scope:complete -- <file> [--merge-commit SHA] [--pr N]";
|
|
461
|
+
readonly flags: readonly [readonly ["<file>", "(required)", "Path to vBRIEF."], readonly ["--project-root PATH", "(detected)", "Consumer project root override."], readonly ["--merge-commit SHA", "(required for code-bearing)", "Merge commit SHA for delivery evidence (#3041)."], readonly ["--pr N", "(required for code-bearing)", "Merged PR number for delivery evidence (#3041)."], readonly ["--pr-base BRANCH", "(optional)", "PR base branch for delivery evidence."], readonly ["--delivery-branch BRANCH", "(optional)", "Delivery branch tip for completed-tracked."]];
|
|
462
|
+
readonly examples: readonly ["task scope:complete -- vbrief/active/2026-05-19-foo.vbrief.json", "task scope:complete -- xbrief/active/story.xbrief.json --merge-commit abc123 --pr 42"];
|
|
463
|
+
readonly see_also: readonly ["task scope:fail", "task scope:cancel", "#1119 / #845", "#3041"];
|
|
453
464
|
readonly placeholder: false;
|
|
454
465
|
};
|
|
455
466
|
readonly "task scope:fail": {
|
|
@@ -530,7 +541,7 @@ export declare const registryData: {
|
|
|
530
541
|
readonly placeholder: false;
|
|
531
542
|
};
|
|
532
543
|
};
|
|
533
|
-
readonly categoriesTriage: readonly [readonly ["Session-start", readonly ["task triage:summary", "task verify:cache-fresh"]], readonly ["State verbs (mutate audit log)", readonly ["task triage:accept", "task triage:defer", "task triage:reject", "task triage:needs-ac", "task triage:mark-duplicate", "task triage:reset", "task triage:status", "task triage:history"]], readonly ["Read verbs", readonly ["task triage:queue", "task triage:audit", "task triage:show", "task triage:scope", "task triage:scope-drift", "task triage:classify"]], readonly ["Lifecycle", readonly ["task triage:bootstrap", "task triage:welcome", "task triage:reconcile"]], readonly ["Bulk variants", readonly ["task triage:bulk-accept", "task triage:bulk-reject", "task triage:bulk-defer", "task triage:bulk-needs-ac", "task triage:refresh-active", "task triage:smoketest"]], readonly ["Subscription mutation", readonly ["task triage:subscribe", "task triage:unsubscribe"]], readonly ["Archive / rotation", readonly ["task triage:audit:prune", "task triage:archive-list", "task triage:restore-from-archive", "task triage:audit-log:rotate", "task triage:metrics"]], readonly ["Framework eval (#1703)", readonly ["task eval:health", "task eval:triggers", "task eval:run", "task eval:report"]]];
|
|
544
|
+
readonly categoriesTriage: readonly [readonly ["Session-start", readonly ["task triage:summary", "task verify:cache-fresh"]], readonly ["State verbs (mutate audit log)", readonly ["task triage:accept", "task triage:defer", "task triage:reject", "task triage:needs-ac", "task triage:mark-duplicate", "task triage:reset", "task triage:status", "task triage:history"]], readonly ["Read verbs", readonly ["task triage:queue", "task triage:evaluate", "task triage:audit", "task triage:show", "task triage:scope", "task triage:scope-drift", "task triage:classify"]], readonly ["Lifecycle", readonly ["task triage:bootstrap", "task triage:welcome", "task triage:reconcile"]], readonly ["Bulk variants", readonly ["task triage:bulk-accept", "task triage:bulk-reject", "task triage:bulk-defer", "task triage:bulk-needs-ac", "task triage:refresh-active", "task triage:smoketest"]], readonly ["Subscription mutation", readonly ["task triage:subscribe", "task triage:unsubscribe"]], readonly ["Archive / rotation", readonly ["task triage:audit:prune", "task triage:archive-list", "task triage:restore-from-archive", "task triage:audit-log:rotate", "task triage:metrics"]], readonly ["Framework eval (#1703)", readonly ["task eval:health", "task eval:triggers", "task eval:run", "task eval:report"]]];
|
|
534
545
|
readonly categoriesScope: readonly [readonly ["Promote / demote", readonly ["task scope:promote", "task scope:demote"]], readonly ["Activate / complete", readonly ["task scope:activate", "task scope:complete", "task scope:fail", "task scope:cancel", "task scope:block", "task scope:unblock"]], readonly ["Reversibility", readonly ["task scope:undo", "task scope:restore"]], readonly ["Decomposition", readonly ["task scope:decompose"]]];
|
|
535
546
|
readonly scriptSubcommandMap: {
|
|
536
547
|
readonly triage_actions: {
|
|
@@ -575,6 +586,9 @@ export declare const registryData: {
|
|
|
575
586
|
readonly triage_reconcile: {
|
|
576
587
|
readonly __default__: "task triage:reconcile";
|
|
577
588
|
};
|
|
589
|
+
readonly triage_evaluate: {
|
|
590
|
+
readonly __default__: "task triage:evaluate";
|
|
591
|
+
};
|
|
578
592
|
readonly triage_queue: {
|
|
579
593
|
readonly queue: "task triage:queue";
|
|
580
594
|
readonly show: "task triage:show";
|
|
@@ -34,6 +34,35 @@ export const registryData = {
|
|
|
34
34
|
see_also: ["task triage:bootstrap", "task cache:fetch-all", "#1119 / D5"],
|
|
35
35
|
placeholder: false,
|
|
36
36
|
},
|
|
37
|
+
"task triage:evaluate": {
|
|
38
|
+
name: "task triage:evaluate",
|
|
39
|
+
summary: "Isolated validity + parent WIP census + value advice",
|
|
40
|
+
refs: "(#3648)",
|
|
41
|
+
description: "Stage A issue-eval: detached origin/master worktrees own validity and ADR/contract reads; the parent on the live working set owns WIP census (xbrief/active, xbrief/pending, plan-sequence); GitHub REST owns open PRs/issues/duplicates. Writes a gitignored sink under .deft-scratch/issue-eval/<sha12>/<invocation-id>/. No GitHub writes. No candidates-log row. Value may set critique-recommend: and must not emit the reserved design-critique clearance line. Fan-out default 4, override --concurrency N.",
|
|
42
|
+
usage: "task triage:evaluate -- <N...> [--concurrency N] [--repo OWNER/NAME] [--json]",
|
|
43
|
+
flags: [
|
|
44
|
+
["<N...>", "(required)", "Issue numbers to evaluate."],
|
|
45
|
+
["--concurrency N", "4", "Parallel evaluator cap (bind, not a measured existing cap)."],
|
|
46
|
+
["--repo OWNER/NAME", "(git remote / env)", "Upstream repo for REST reads."],
|
|
47
|
+
["--json", "(off)", "Emit the structured EvaluateResult."],
|
|
48
|
+
[
|
|
49
|
+
"--project-root PATH",
|
|
50
|
+
"(cwd)",
|
|
51
|
+
"Project root override (Taskfile threads USER_WORKING_DIR).",
|
|
52
|
+
],
|
|
53
|
+
],
|
|
54
|
+
examples: [
|
|
55
|
+
"task triage:evaluate -- 3648",
|
|
56
|
+
"task triage:evaluate -- 10 11 --concurrency 2 --json",
|
|
57
|
+
],
|
|
58
|
+
see_also: [
|
|
59
|
+
"task triage:queue",
|
|
60
|
+
"task triage:accept",
|
|
61
|
+
"skills/deft-directive-issue-eval/SKILL.md",
|
|
62
|
+
"#3648",
|
|
63
|
+
],
|
|
64
|
+
placeholder: false,
|
|
65
|
+
},
|
|
37
66
|
"task triage:accept": {
|
|
38
67
|
name: "task triage:accept",
|
|
39
68
|
summary: "Mark issue accepted; chains into scope:promote w/ flag",
|
|
@@ -628,7 +657,7 @@ export const registryData = {
|
|
|
628
657
|
name: "task triage:metrics",
|
|
629
658
|
summary: "Attributed-value trend from the events ledger",
|
|
630
659
|
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.
|
|
660
|
+
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
661
|
usage: "task triage:metrics [-- --window=7d] [--format=text|json]",
|
|
633
662
|
flags: [
|
|
634
663
|
["--window WINDOW", "7d", "Time window (e.g. 7d, 30d, 24h)."],
|
|
@@ -782,15 +811,30 @@ export const registryData = {
|
|
|
782
811
|
"task scope:complete": {
|
|
783
812
|
name: "task scope:complete",
|
|
784
813
|
summary: "active/ -> completed/ (set status completed)",
|
|
785
|
-
refs: "(#845)",
|
|
786
|
-
description: "Mark an active vBRIEF complete and move it to vbrief/completed/. Terminal transition; use scope:undo if you need reversibility (refused on terminal actions per D15).",
|
|
787
|
-
usage: "task scope:complete -- <file>",
|
|
814
|
+
refs: "(#845, #3041, #3721)",
|
|
815
|
+
description: "Mark an active vBRIEF complete and move it to vbrief/completed/. Terminal transition; use scope:undo if you need reversibility (refused on terminal actions per D15). Code-bearing completion requires delivery evidence: --merge-commit and --pr. Those flags feed the delivery gate; they do not skip literal-AC.",
|
|
816
|
+
usage: "task scope:complete -- <file> [--merge-commit SHA] [--pr N]",
|
|
788
817
|
flags: [
|
|
789
818
|
["<file>", "(required)", "Path to vBRIEF."],
|
|
790
819
|
["--project-root PATH", "(detected)", "Consumer project root override."],
|
|
820
|
+
[
|
|
821
|
+
"--merge-commit SHA",
|
|
822
|
+
"(required for code-bearing)",
|
|
823
|
+
"Merge commit SHA for delivery evidence (#3041).",
|
|
824
|
+
],
|
|
825
|
+
[
|
|
826
|
+
"--pr N",
|
|
827
|
+
"(required for code-bearing)",
|
|
828
|
+
"Merged PR number for delivery evidence (#3041).",
|
|
829
|
+
],
|
|
830
|
+
["--pr-base BRANCH", "(optional)", "PR base branch for delivery evidence."],
|
|
831
|
+
["--delivery-branch BRANCH", "(optional)", "Delivery branch tip for completed-tracked."],
|
|
791
832
|
],
|
|
792
|
-
examples: [
|
|
793
|
-
|
|
833
|
+
examples: [
|
|
834
|
+
"task scope:complete -- vbrief/active/2026-05-19-foo.vbrief.json",
|
|
835
|
+
"task scope:complete -- xbrief/active/story.xbrief.json --merge-commit abc123 --pr 42",
|
|
836
|
+
],
|
|
837
|
+
see_also: ["task scope:fail", "task scope:cancel", "#1119 / #845", "#3041"],
|
|
794
838
|
placeholder: false,
|
|
795
839
|
},
|
|
796
840
|
"task scope:fail": {
|
|
@@ -930,6 +974,7 @@ export const registryData = {
|
|
|
930
974
|
"Read verbs",
|
|
931
975
|
[
|
|
932
976
|
"task triage:queue",
|
|
977
|
+
"task triage:evaluate",
|
|
933
978
|
"task triage:audit",
|
|
934
979
|
"task triage:show",
|
|
935
980
|
"task triage:scope",
|
|
@@ -1024,6 +1069,9 @@ export const registryData = {
|
|
|
1024
1069
|
triage_reconcile: {
|
|
1025
1070
|
__default__: "task triage:reconcile",
|
|
1026
1071
|
},
|
|
1072
|
+
triage_evaluate: {
|
|
1073
|
+
__default__: "task triage:evaluate",
|
|
1074
|
+
},
|
|
1027
1075
|
triage_queue: {
|
|
1028
1076
|
queue: "task triage:queue",
|
|
1029
1077
|
show: "task triage:show",
|
package/dist/triage/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * as bulk from "./bulk/index.js";
|
|
|
13
13
|
export * as cachePath from "./cache-path.js";
|
|
14
14
|
export * from "./cache-path.js";
|
|
15
15
|
export * as classify from "./classify/index.js";
|
|
16
|
+
export * as evaluate from "./evaluate/index.js";
|
|
16
17
|
export * as help from "./help/index.js";
|
|
17
18
|
export * as queue from "./queue/index.js";
|
|
18
19
|
export * as reconcile from "./reconcile/index.js";
|
package/dist/triage/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export * as bulk from "./bulk/index.js";
|
|
|
13
13
|
export * as cachePath from "./cache-path.js";
|
|
14
14
|
export * from "./cache-path.js";
|
|
15
15
|
export * as classify from "./classify/index.js";
|
|
16
|
+
export * as evaluate from "./evaluate/index.js";
|
|
16
17
|
export * as help from "./help/index.js";
|
|
17
18
|
export * as queue from "./queue/index.js";
|
|
18
19
|
export * as reconcile from "./reconcile/index.js";
|
|
@@ -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;
|
|
@@ -4,6 +4,7 @@ import { containedWrite } from "../../fs/contained-write.js";
|
|
|
4
4
|
import { assertWriteTargetSafe } from "../../fs/projection-containment.js";
|
|
5
5
|
import { hasArtifactSuffix, resolveLifecycleFolder, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
|
|
6
6
|
import { migrateLegacyPolicyKey, PLAN_ONBOARDING_KEY, PLAN_POLICY_KEY, } from "../../policy/plan-extensions.js";
|
|
7
|
+
import { stampChangedToken } from "../../policy/resolve.js";
|
|
7
8
|
import { projectDefinitionMutationLock } from "../../vbrief-build/project-definition-io.js";
|
|
8
9
|
import { AUDIT_LOG_REL_PATH, DEFAULT_RELIEF_AGE_DAYS, DEFAULT_WIP_CAP, SUBSCRIPTION_PRESETS, WELCOME_AUDIT_TAG, } from "./constants.js";
|
|
9
10
|
function projectDefinitionPath(projectRoot) {
|
|
@@ -12,9 +13,13 @@ function projectDefinitionPath(projectRoot) {
|
|
|
12
13
|
function utcIso() {
|
|
13
14
|
return new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
14
15
|
}
|
|
15
|
-
export function appendAuditEntry(projectRoot, entry) {
|
|
16
|
+
export function appendAuditEntry(projectRoot, entry, changed = true) {
|
|
16
17
|
const root = resolve(projectRoot);
|
|
17
18
|
const logPath = join(root, AUDIT_LOG_REL_PATH);
|
|
19
|
+
const stamped = stampChangedToken(entry, changed);
|
|
20
|
+
if (!changed) {
|
|
21
|
+
return logPath;
|
|
22
|
+
}
|
|
18
23
|
// #2980 wave D: product write sink routes through containedWrite.
|
|
19
24
|
mkdirSync(root, { recursive: true });
|
|
20
25
|
if (!existsSync(logPath)) {
|
|
@@ -28,7 +33,7 @@ export function appendAuditEntry(projectRoot, entry) {
|
|
|
28
33
|
containedWrite({
|
|
29
34
|
root,
|
|
30
35
|
target: AUDIT_LOG_REL_PATH,
|
|
31
|
-
data: `${utcIso()} ${
|
|
36
|
+
data: `${utcIso()} ${stamped}\n`,
|
|
32
37
|
mode: "append",
|
|
33
38
|
});
|
|
34
39
|
return logPath;
|
|
@@ -102,7 +107,7 @@ export function writeTriageScope(projectRoot, rules, options = { presetLabel: "c
|
|
|
102
107
|
`rule_count=${rules.length}`,
|
|
103
108
|
`changed=${changed ? "true" : "false"}`,
|
|
104
109
|
].join(" ");
|
|
105
|
-
appendAuditEntry(projectRoot, auditEntry);
|
|
110
|
+
appendAuditEntry(projectRoot, auditEntry, changed);
|
|
106
111
|
return [changed, auditEntry];
|
|
107
112
|
});
|
|
108
113
|
}
|
|
@@ -153,7 +158,7 @@ export function writeWipCapDecision(projectRoot, options = {}) {
|
|
|
153
158
|
`acceptedDefault=${acceptedDefault ? "true" : "false"}`,
|
|
154
159
|
`changed=${changed ? "true" : "false"}`,
|
|
155
160
|
].join(" ");
|
|
156
|
-
appendAuditEntry(projectRoot, auditEntry);
|
|
161
|
+
appendAuditEntry(projectRoot, auditEntry, changed);
|
|
157
162
|
return [changed, auditEntry];
|
|
158
163
|
});
|
|
159
164
|
}
|
|
@@ -220,7 +225,7 @@ export function writeWipCap(projectRoot, wipCap, options = {}) {
|
|
|
220
225
|
const changed = previous !== wipCap;
|
|
221
226
|
const auditEntry = `actor=${actor} field=plan.policy.wipCap value=${wipCap} previous=${JSON.stringify(previous)} ` +
|
|
222
227
|
`changed=${changed ? "true" : "false"}`;
|
|
223
|
-
appendAuditEntry(projectRoot, auditEntry);
|
|
228
|
+
appendAuditEntry(projectRoot, auditEntry, changed);
|
|
224
229
|
return [changed, auditEntry];
|
|
225
230
|
});
|
|
226
231
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type GhRestSeams } from "../scm/gh-rest.js";
|
|
2
2
|
export declare const DEFAULT_UPSTREAM_REPO = "deftai/directive";
|
|
3
3
|
export declare const FRAMEWORK_GAP_TITLE_PREFIX = "[framework-gap]";
|
|
4
|
+
/** Sole sanctioned title classification (#3713). Does not write `adoption-blocker`. */
|
|
5
|
+
export declare const ADOPTION_BLOCKER_TITLE_TOKEN = "BLOCKER";
|
|
6
|
+
/** Strip source prefix and the optional BLOCKER token so marked/unmarked titles dedup. */
|
|
7
|
+
export declare function stripTitleClassificationTokens(title: string): string;
|
|
4
8
|
export type FeedbackFileOutcome = "draft" | "filed" | "skipped-maintainer" | "blocked-policy" | "blocked-duplicate" | "blocked-no-confirm" | "error-bad-args" | "error-config" | "error-network";
|
|
5
9
|
export interface FeedbackGapInput {
|
|
6
10
|
readonly summary: string;
|
|
@@ -8,6 +12,11 @@ export interface FeedbackGapInput {
|
|
|
8
12
|
readonly expected?: string;
|
|
9
13
|
readonly actual?: string;
|
|
10
14
|
readonly sessionNotes?: string;
|
|
15
|
+
/** Consumer hard-stop judgment. Advisory title token only — never applies a label. */
|
|
16
|
+
readonly adoptionBlocker?: boolean;
|
|
17
|
+
readonly flowAndVersion?: string;
|
|
18
|
+
readonly alternatives?: string;
|
|
19
|
+
readonly recoveryCost?: string;
|
|
11
20
|
}
|
|
12
21
|
export interface FeedbackFileOptions extends FeedbackGapInput {
|
|
13
22
|
readonly projectRoot?: string | null;
|
|
@@ -29,10 +38,12 @@ export interface FeedbackFileResult {
|
|
|
29
38
|
}
|
|
30
39
|
/** True when the resolved project root is the directive maintainer source checkout. */
|
|
31
40
|
export declare function isMaintainerFrameworkRepo(projectRoot: string): boolean;
|
|
32
|
-
/** Normalize a title for duplicate comparison (#1709). */
|
|
41
|
+
/** Normalize a title for duplicate comparison (#1709 / #3713). */
|
|
33
42
|
export declare function normalizeForDedup(title: string): string;
|
|
34
43
|
/** Build the upstream issue title for a framework-gap report. */
|
|
35
|
-
export declare function buildFrameworkGapTitle(summary: string
|
|
44
|
+
export declare function buildFrameworkGapTitle(summary: string, options?: {
|
|
45
|
+
adoptionBlocker?: boolean;
|
|
46
|
+
}): string;
|
|
36
47
|
/** Build the structured framework-gap issue body. */
|
|
37
48
|
export declare function buildFrameworkGapBody(input: FeedbackGapInput): string;
|
|
38
49
|
export interface DuplicateMatch {
|
|
@@ -49,6 +60,10 @@ export interface FeedbackFileCliArgs {
|
|
|
49
60
|
expected?: string;
|
|
50
61
|
actual?: string;
|
|
51
62
|
sessionNotes?: string;
|
|
63
|
+
adoptionBlocker?: boolean;
|
|
64
|
+
flowAndVersion?: string;
|
|
65
|
+
alternatives?: string;
|
|
66
|
+
recoveryCost?: string;
|
|
52
67
|
confirm?: boolean;
|
|
53
68
|
dryRun?: boolean;
|
|
54
69
|
json?: boolean;
|