@deftai/directive-core 0.72.0 → 0.73.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/branch/evaluate.js +2 -1
- package/dist/category-b-namespace/index.js +16 -2
- package/dist/codebase/default-extractor.js +9 -1
- package/dist/codebase/map.js +1 -1
- package/dist/deposit/copy-tree.js +31 -7
- package/dist/doctor/checks.d.ts +9 -0
- package/dist/doctor/checks.js +85 -5
- package/dist/doctor/main.js +2 -1
- package/dist/eval/health.js +7 -1
- package/dist/eval/readback.js +7 -1
- package/dist/init-deposit/gitignore.js +6 -0
- package/dist/init-deposit/hygiene.d.ts +30 -0
- package/dist/init-deposit/hygiene.js +60 -1
- package/dist/init-deposit/refresh.d.ts +16 -2
- package/dist/init-deposit/refresh.js +162 -52
- package/dist/init-deposit/scaffold.d.ts +11 -1
- package/dist/init-deposit/scaffold.js +9 -8
- package/dist/integration-e2e/helpers.js +7 -7
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/index.js +1 -1
- package/dist/layout/resolve.d.ts +47 -31
- package/dist/layout/resolve.js +93 -36
- package/dist/lifecycle/lifecycle-hygiene.d.ts +1 -1
- package/dist/lifecycle/lifecycle-hygiene.js +1 -1
- package/dist/migrate-preflight/index.js +10 -10
- package/dist/policy/disclosure.d.ts +1 -0
- package/dist/policy/disclosure.js +1 -0
- package/dist/policy/index.d.ts +1 -0
- package/dist/policy/index.js +1 -0
- package/dist/policy/policy-invocation.d.ts +5 -0
- package/dist/policy/policy-invocation.js +9 -0
- package/dist/policy/resolve.d.ts +2 -2
- package/dist/policy/resolve.js +15 -5
- package/dist/policy/value-feedback.js +6 -3
- package/dist/policy/wip.d.ts +1 -1
- package/dist/policy/wip.js +15 -3
- package/dist/preflight-cache/evaluate.js +1 -1
- package/dist/release/native-steps.js +14 -2
- package/dist/render/export-spec.js +2 -2
- package/dist/render/project-render.js +40 -9
- package/dist/scope/decompose.js +12 -2
- package/dist/session/resume-conditions.js +2 -2
- package/dist/session/ritual-sentinel.d.ts +1 -1
- package/dist/session/ritual-sentinel.js +6 -4
- package/dist/slice/constants.d.ts +1 -1
- package/dist/slice/constants.js +1 -1
- package/dist/slice/project-context.js +1 -1
- package/dist/spec-authority/resolver.js +9 -2
- package/dist/swarm/complete-cohort.js +14 -1
- package/dist/swarm/constants.d.ts +1 -1
- package/dist/swarm/constants.js +2 -1
- package/dist/swarm/readiness.js +33 -3
- package/dist/swarm/subagent-backend.js +2 -1
- package/dist/task-surface/index.js +3 -3
- package/dist/triage/actions/candidates-log.d.ts +1 -1
- package/dist/triage/bootstrap/gitignore.js +22 -10
- package/dist/triage/bootstrap/index.d.ts +1 -1
- package/dist/triage/bootstrap/index.js +9 -3
- package/dist/triage/cache-path.d.ts +1 -1
- package/dist/triage/cache-path.js +32 -6
- package/dist/triage/classify/index.d.ts +1 -1
- package/dist/triage/classify/index.js +11 -4
- package/dist/triage/help/registry-data.d.ts +2 -2
- package/dist/triage/help/registry-data.js +2 -2
- package/dist/triage/queue/constants.d.ts +4 -4
- package/dist/triage/queue/constants.js +4 -4
- package/dist/triage/queue/scope-walk.js +7 -1
- package/dist/triage/reconcile/reconcile.js +23 -3
- package/dist/triage/reconcile/types.d.ts +1 -1
- package/dist/triage/reconcile/types.js +1 -1
- package/dist/triage/refresh/refresh.js +9 -2
- package/dist/triage/scope/constants.d.ts +2 -2
- package/dist/triage/scope/constants.js +2 -2
- package/dist/triage/scope/renderers.js +7 -1
- package/dist/triage/smoketest/index.js +9 -6
- package/dist/triage/subscribe/index.d.ts +2 -2
- package/dist/triage/subscribe/index.js +2 -2
- package/dist/triage/summary/index.d.ts +2 -2
- package/dist/triage/summary/index.js +1 -1
- package/dist/triage/summary/reconcilable.d.ts +1 -1
- package/dist/triage/welcome/constants.d.ts +2 -2
- package/dist/triage/welcome/constants.js +2 -2
- package/dist/triage/welcome/onboard.js +8 -1
- package/dist/triage/welcome/prior-state.js +14 -2
- package/dist/triage/welcome/summary.js +14 -2
- package/dist/triage/welcome/writers.js +7 -1
- package/dist/ts-check-lane/run-lane.d.ts +4 -0
- package/dist/ts-check-lane/run-lane.js +20 -6
- package/dist/validate-content/validate-strategy-output.js +11 -1
- package/dist/value/feedback-file.js +3 -2
- package/dist/value/readback.js +3 -2
- package/dist/vbrief-build/parity-scenarios.js +3 -3
- package/dist/vbrief-reconcile/labels.js +16 -1
- package/dist/vbrief-reconcile/parity-scenarios.js +10 -10
- package/dist/vbrief-reconcile/umbrellas.js +16 -1
- package/dist/vbrief-validate/main.js +13 -1
- package/dist/vbrief-validate/precutover.js +33 -5
- package/dist/vbrief-validate/staleness.d.ts +1 -1
- package/dist/vbrief-validate/staleness.js +5 -2
- package/dist/verify-source/code-structure-validate.js +7 -1
- package/dist/xbrief-migrate/signpost.d.ts +4 -4
- package/dist/xbrief-migrate/signpost.js +11 -15
- package/package.json +3 -3
|
@@ -40,7 +40,13 @@ export function findReconcilable(projectRoot, options = {}) {
|
|
|
40
40
|
const items = [];
|
|
41
41
|
const seen = new Set();
|
|
42
42
|
for (const folderName of BACKFILL_FOLDERS) {
|
|
43
|
-
|
|
43
|
+
let folderPath;
|
|
44
|
+
try {
|
|
45
|
+
folderPath = resolveLifecycleFolder(root, folderName);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
continue; // No xbrief/ layout; skip this folder.
|
|
49
|
+
}
|
|
44
50
|
for (const [refRepo, number, path] of scanLifecycleRefs(folderPath)) {
|
|
45
51
|
const effectiveRepo = refRepo ?? defaultRepo;
|
|
46
52
|
if (effectiveRepo === null)
|
|
@@ -65,7 +71,14 @@ function countSkippedExisting(projectRoot, defaultRepo, auditPath) {
|
|
|
65
71
|
let count = 0;
|
|
66
72
|
const root = resolve(projectRoot);
|
|
67
73
|
for (const folderName of BACKFILL_FOLDERS) {
|
|
68
|
-
|
|
74
|
+
let folderPath;
|
|
75
|
+
try {
|
|
76
|
+
folderPath = resolveLifecycleFolder(root, folderName);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
continue; // No xbrief/ layout; skip this folder.
|
|
80
|
+
}
|
|
81
|
+
for (const [refRepo, number] of scanLifecycleRefs(folderPath)) {
|
|
69
82
|
const effectiveRepo = refRepo ?? defaultRepo;
|
|
70
83
|
if (effectiveRepo === null)
|
|
71
84
|
continue;
|
|
@@ -88,7 +101,14 @@ function countNoRepo(projectRoot, defaultRepo, auditPath) {
|
|
|
88
101
|
let count = 0;
|
|
89
102
|
const root = resolve(projectRoot);
|
|
90
103
|
for (const folderName of BACKFILL_FOLDERS) {
|
|
91
|
-
|
|
104
|
+
let folderPath;
|
|
105
|
+
try {
|
|
106
|
+
folderPath = resolveLifecycleFolder(root, folderName);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
continue; // No xbrief/ layout; skip this folder.
|
|
110
|
+
}
|
|
111
|
+
for (const [refRepo, number] of scanLifecycleRefs(folderPath)) {
|
|
92
112
|
if ((refRepo ?? defaultRepo) === null && !existingNumbers.has(number))
|
|
93
113
|
count += 1;
|
|
94
114
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const AUDIT_LOG_RELPATH = "
|
|
1
|
+
export declare const AUDIT_LOG_RELPATH = "xbrief/.triage-cache/candidates.jsonl";
|
|
2
2
|
export declare const BACKFILL_FOLDERS: readonly ["proposed", "pending", "active"];
|
|
3
3
|
export declare const RECONCILE_ACTOR = "agent:reconcile";
|
|
4
4
|
export interface ReconcileItem {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const AUDIT_LOG_RELPATH = "
|
|
1
|
+
export const AUDIT_LOG_RELPATH = "xbrief/.triage-cache/candidates.jsonl";
|
|
2
2
|
export const BACKFILL_FOLDERS = ["proposed", "pending", "active"];
|
|
3
3
|
export const RECONCILE_ACTOR = "agent:reconcile";
|
|
4
4
|
export function reconcileSummary(result) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
2
|
import { resolveLifecycleFolder } from "../../layout/resolve.js";
|
|
3
3
|
import { detectDrift } from "./drift.js";
|
|
4
4
|
import { iterActiveVbriefs } from "./extract.js";
|
|
@@ -21,7 +21,14 @@ function defaultAuditWriter(repo, issueNumber, annotation, log) {
|
|
|
21
21
|
}
|
|
22
22
|
export function refreshActive(projectRoot, options = {}) {
|
|
23
23
|
const root = resolve(projectRoot);
|
|
24
|
-
|
|
24
|
+
let defaultActiveDir;
|
|
25
|
+
try {
|
|
26
|
+
defaultActiveDir = resolveLifecycleFolder(root, "active");
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
defaultActiveDir = join(root, "xbrief", "active"); // No xbrief/ layout; use canonical path.
|
|
30
|
+
}
|
|
31
|
+
const activeDir = options.activeDir ?? defaultActiveDir;
|
|
25
32
|
const log = options.log ?? ((line) => process.stdout.write(`${line}\n`));
|
|
26
33
|
const inputFn = options.inputFn ?? (() => "");
|
|
27
34
|
const refreshLocal = options.refreshLocal ?? (() => { });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Framework default when plan.policy.triageScope is unset (#1131). */
|
|
2
2
|
export declare const DEFAULT_TRIAGE_SCOPE: ReadonlyArray<Record<string, unknown>>;
|
|
3
|
-
export declare const PROJECT_DEFINITION_REL_PATH = "
|
|
3
|
+
export declare const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
|
|
4
4
|
export declare const CACHE_DIR_NAME = ".deft-cache";
|
|
5
5
|
export declare const COVERAGE_FILENAME = "coverage.json";
|
|
6
6
|
export declare const ENV_COVERAGE_TTL_HOURS = "DEFT_COVERAGE_MAX_AGE_HOURS";
|
|
@@ -11,6 +11,6 @@ export declare const VALID_IGNORE_KEYS: Set<string>;
|
|
|
11
11
|
export declare const VALID_IGNORE_RULES: Set<string>;
|
|
12
12
|
export declare const REFERENCED_BY_VBRIEF_SCOPES: Set<string>;
|
|
13
13
|
export declare const SLICED_FROM_SCOPES: Set<string>;
|
|
14
|
-
export declare const SUBSCRIPTION_HISTORY_REL_PATH = "
|
|
14
|
+
export declare const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
|
|
15
15
|
export declare const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
|
|
16
16
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Framework default when plan.policy.triageScope is unset (#1131). */
|
|
2
2
|
export const DEFAULT_TRIAGE_SCOPE = [{ rule: "all-open" }];
|
|
3
|
-
export const PROJECT_DEFINITION_REL_PATH = "
|
|
3
|
+
export const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
|
|
4
4
|
export const CACHE_DIR_NAME = ".deft-cache";
|
|
5
5
|
export const COVERAGE_FILENAME = "coverage.json";
|
|
6
6
|
export const ENV_COVERAGE_TTL_HOURS = "DEFT_COVERAGE_MAX_AGE_HOURS";
|
|
@@ -20,6 +20,6 @@ export const VALID_IGNORE_KEYS = new Set(["label", "milestone"]);
|
|
|
20
20
|
export const VALID_IGNORE_RULES = new Set(["author"]);
|
|
21
21
|
export const REFERENCED_BY_VBRIEF_SCOPES = new Set(["any", "active"]);
|
|
22
22
|
export const SLICED_FROM_SCOPES = new Set(["any-umbrella-in-cache"]);
|
|
23
|
-
export const SUBSCRIPTION_HISTORY_REL_PATH = "
|
|
23
|
+
export const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
|
|
24
24
|
export const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
|
|
25
25
|
//# sourceMappingURL=constants.js.map
|
|
@@ -6,7 +6,13 @@ import { subscriptionHash } from "./normalize.js";
|
|
|
6
6
|
import { pyListRepr } from "./python-repr.js";
|
|
7
7
|
const LIFECYCLE_FOLDERS = ["proposed", "pending", "active", "completed", "cancelled"];
|
|
8
8
|
export function extractReferencedIssues(projectRoot, lifecycleFolders = LIFECYCLE_FOLDERS) {
|
|
9
|
-
|
|
9
|
+
let root;
|
|
10
|
+
try {
|
|
11
|
+
root = resolveLifecycleRoot(projectRoot);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return { any: new Set(), active: new Set() };
|
|
15
|
+
}
|
|
10
16
|
const anySet = new Set();
|
|
11
17
|
const activeSet = new Set();
|
|
12
18
|
if (!existsSync(root))
|
|
@@ -119,21 +119,24 @@ function defaultScriptRunner(scriptsDir) {
|
|
|
119
119
|
export function copyFixtureToTmp(fixtureRoot, tmpRoot) {
|
|
120
120
|
const project = tmpRoot;
|
|
121
121
|
mkdirSync(project, { recursive: true });
|
|
122
|
-
mkdirSync(join(project, "
|
|
123
|
-
|
|
122
|
+
mkdirSync(join(project, "xbrief"), { recursive: true });
|
|
123
|
+
const srcPD = join(fixtureRoot, "PROJECT-DEFINITION.xbrief.json");
|
|
124
|
+
if (existsSync(srcPD)) {
|
|
125
|
+
copyFileSync(srcPD, join(project, "xbrief", "PROJECT-DEFINITION.xbrief.json"));
|
|
126
|
+
}
|
|
124
127
|
for (const sub of ["active", "proposed", "pending", "completed", "cancelled"]) {
|
|
125
|
-
const srcDir = join(fixtureRoot, "
|
|
126
|
-
const dstDir = join(project, "
|
|
128
|
+
const srcDir = join(fixtureRoot, "xbrief", sub);
|
|
129
|
+
const dstDir = join(project, "xbrief", sub);
|
|
127
130
|
mkdirSync(dstDir, { recursive: true });
|
|
128
131
|
if (existsSync(srcDir)) {
|
|
129
132
|
for (const name of readdirSync(srcDir)) {
|
|
130
|
-
if (name.endsWith(".
|
|
133
|
+
if (name.endsWith(".xbrief.json")) {
|
|
131
134
|
copyFileSync(join(srcDir, name), join(dstDir, name));
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
|
-
mkdirSync(join(project, "
|
|
139
|
+
mkdirSync(join(project, "xbrief", ".eval"), { recursive: true });
|
|
137
140
|
return project;
|
|
138
141
|
}
|
|
139
142
|
function defaultInlineRunner() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export declare const SUBSCRIPTION_HISTORY_REL_PATH = "
|
|
1
|
+
export declare const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
|
|
2
2
|
export declare const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
|
|
3
|
-
export declare const PROJECT_DEFINITION_REL_PATH = "
|
|
3
|
+
export declare const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
|
|
4
4
|
/** Python ``!r``-style quoting for parity with triage_subscribe.py messages. */
|
|
5
5
|
export declare function pyRepr(value: string): string;
|
|
6
6
|
export declare class ProjectDefinitionIOError extends Error {
|
|
@@ -5,9 +5,9 @@ import { resolveProjectDefinitionPath } from "../../layout/resolve.js";
|
|
|
5
5
|
import { migrateLegacyPolicyKey, PLAN_POLICY_KEY } from "../../policy/plan-extensions.js";
|
|
6
6
|
import { projectDefinitionMutationLock } from "../../vbrief-build/project-definition-io.js";
|
|
7
7
|
import { resolveTriageCachePath } from "../cache-path.js";
|
|
8
|
-
export const SUBSCRIPTION_HISTORY_REL_PATH = "
|
|
8
|
+
export const SUBSCRIPTION_HISTORY_REL_PATH = "xbrief/.triage-cache/subscription-history.jsonl";
|
|
9
9
|
export const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
|
|
10
|
-
export const PROJECT_DEFINITION_REL_PATH = "
|
|
10
|
+
export const PROJECT_DEFINITION_REL_PATH = "xbrief/PROJECT-DEFINITION.xbrief.json";
|
|
11
11
|
/** Python ``!r``-style quoting for parity with triage_subscribe.py messages. */
|
|
12
12
|
export function pyRepr(value) {
|
|
13
13
|
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
@@ -4,9 +4,9 @@ export declare const MAX_LINE_CHARS = 120;
|
|
|
4
4
|
export { DEFAULT_WIP_CAP, PROJECT_DEFINITION_REL_PATH };
|
|
5
5
|
export declare const CACHE_DIR_NAME = ".deft-cache";
|
|
6
6
|
export declare const CACHE_SOURCE = "github-issue";
|
|
7
|
-
export declare const CANDIDATES_LOG_REL_PATH = "
|
|
7
|
+
export declare const CANDIDATES_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
|
|
8
8
|
export { latestDecisions, readAuditLog } from "../actions/candidates-log.js";
|
|
9
|
-
export declare const SUMMARY_HISTORY_REL_PATH = "
|
|
9
|
+
export declare const SUMMARY_HISTORY_REL_PATH = "xbrief/.triage-cache/summary-history.jsonl";
|
|
10
10
|
export declare const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
11
11
|
/** D2 repeat-suppression window for session-start triage one-liner (#1122 / #1279). */
|
|
12
12
|
export declare const D2_SUPPRESSION_WINDOW_HOURS = 4;
|
|
@@ -18,7 +18,7 @@ export const CACHE_DIR_NAME = ".deft-cache";
|
|
|
18
18
|
export const CACHE_SOURCE = "github-issue";
|
|
19
19
|
export const CANDIDATES_LOG_REL_PATH = AUDIT_LOG_REL_PATH;
|
|
20
20
|
export { latestDecisions, readAuditLog } from "../actions/candidates-log.js";
|
|
21
|
-
export const SUMMARY_HISTORY_REL_PATH = "
|
|
21
|
+
export const SUMMARY_HISTORY_REL_PATH = "xbrief/.triage-cache/summary-history.jsonl";
|
|
22
22
|
export const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
23
23
|
/** D2 repeat-suppression window for session-start triage one-liner (#1122 / #1279). */
|
|
24
24
|
export const D2_SUPPRESSION_WINDOW_HOURS = 4;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Lifecycle folders scanned for reconcilable vBRIEFs (#1468). */
|
|
2
2
|
export declare const BACKFILL_FOLDERS: readonly ["proposed", "pending", "active"];
|
|
3
|
-
export declare const CANDIDATES_LOG_REL_PATH = "
|
|
3
|
+
export declare const CANDIDATES_LOG_REL_PATH = "xbrief/.triage-cache/candidates.jsonl";
|
|
4
4
|
/**
|
|
5
5
|
* Count reconcilable issues (#1468) — mirrors `triage_reconcile.count_reconcilable`.
|
|
6
6
|
*/
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export declare const CACHE_DIR_NAME = ".deft-cache";
|
|
2
2
|
export declare const CACHE_SOURCE = "github-issue";
|
|
3
|
-
export declare const CANDIDATES_RELPATH: readonly ["
|
|
3
|
+
export declare const CANDIDATES_RELPATH: readonly ["xbrief", ".triage-cache", "candidates.jsonl"];
|
|
4
4
|
export declare const WIP_LIFECYCLE_DIRS: readonly ["pending", "active"];
|
|
5
5
|
export declare const AUDIT_LOG_REL_PATH = "meta/policy-changes.log";
|
|
6
6
|
export declare const DEFAULT_WIP_CAP = 20;
|
|
7
7
|
export declare const DEFAULT_RELIEF_AGE_DAYS = 30;
|
|
8
8
|
export declare const TRIAGE_SKILL_PATH = "skills/deft-directive-triage/SKILL.md";
|
|
9
9
|
export declare const WELCOME_AUDIT_TAG = "triage-welcome";
|
|
10
|
-
export declare const SUMMARY_HISTORY_REL_PATH = "
|
|
10
|
+
export declare const SUMMARY_HISTORY_REL_PATH = "xbrief/.triage-cache/summary-history.jsonl";
|
|
11
11
|
export declare const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
12
12
|
export declare const EMPTY_CACHE_LINE = "[triage] cache empty -- run task triage:bootstrap";
|
|
13
13
|
export declare const MAX_LINE_CHARS = 120;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export const CACHE_DIR_NAME = ".deft-cache";
|
|
2
2
|
export const CACHE_SOURCE = "github-issue";
|
|
3
|
-
export const CANDIDATES_RELPATH = ["
|
|
3
|
+
export const CANDIDATES_RELPATH = ["xbrief", ".triage-cache", "candidates.jsonl"];
|
|
4
4
|
export const WIP_LIFECYCLE_DIRS = ["pending", "active"];
|
|
5
5
|
export const AUDIT_LOG_REL_PATH = "meta/policy-changes.log";
|
|
6
6
|
export const DEFAULT_WIP_CAP = 20;
|
|
7
7
|
export const DEFAULT_RELIEF_AGE_DAYS = 30;
|
|
8
8
|
export const TRIAGE_SKILL_PATH = "skills/deft-directive-triage/SKILL.md";
|
|
9
9
|
export const WELCOME_AUDIT_TAG = "triage-welcome";
|
|
10
|
-
export const SUMMARY_HISTORY_REL_PATH = "
|
|
10
|
+
export const SUMMARY_HISTORY_REL_PATH = "xbrief/.triage-cache/summary-history.jsonl";
|
|
11
11
|
export const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
12
12
|
export const EMPTY_CACHE_LINE = "[triage] cache empty -- run task triage:bootstrap";
|
|
13
13
|
export const MAX_LINE_CHARS = 120;
|
|
@@ -43,7 +43,14 @@ export function runOnboardMode(projectRoot, options = {}) {
|
|
|
43
43
|
out(`[welcome] --wip-cap must be a positive integer, got ${JSON.stringify(options.wipCap)}.`);
|
|
44
44
|
return failure(2);
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
let pdPath;
|
|
47
|
+
try {
|
|
48
|
+
pdPath = resolveProjectDefinitionPath(projectRoot);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
out(`[welcome] No xbrief/ layout found at ${projectRoot}. Run \`deft migrate:xbrief\` to convert your project from the legacy vbrief/ layout, or run project setup first (deft-directive-setup).`);
|
|
52
|
+
return failure(2);
|
|
53
|
+
}
|
|
47
54
|
if (!existsSync(pdPath)) {
|
|
48
55
|
out(`[welcome] No project definition found at ${pdPath}. Run project setup first (deft-directive-setup) before onboarding triage.`);
|
|
49
56
|
return failure(2);
|
|
@@ -5,7 +5,13 @@ import { readPlanPolicy } from "../../policy/plan-extensions.js";
|
|
|
5
5
|
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
6
6
|
import { CACHE_DIR_NAME, CACHE_SOURCE, DEFAULT_WIP_CAP, SUBSCRIPTION_PRESETS, WIP_LIFECYCLE_DIRS, } from "./constants.js";
|
|
7
7
|
function loadProjectDefinition(projectRoot) {
|
|
8
|
-
|
|
8
|
+
let path;
|
|
9
|
+
try {
|
|
10
|
+
path = resolveProjectDefinitionPath(projectRoot);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null; // No xbrief/ layout; no project definition.
|
|
14
|
+
}
|
|
9
15
|
if (!existsSync(path))
|
|
10
16
|
return null;
|
|
11
17
|
try {
|
|
@@ -44,7 +50,13 @@ export function candidatesLogPath(projectRoot) {
|
|
|
44
50
|
}
|
|
45
51
|
function countWip(projectRoot) {
|
|
46
52
|
let total = 0;
|
|
47
|
-
|
|
53
|
+
let root;
|
|
54
|
+
try {
|
|
55
|
+
root = resolveLifecycleRoot(projectRoot);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return 0; // No xbrief/ layout; no WIP.
|
|
59
|
+
}
|
|
48
60
|
for (const sub of WIP_LIFECYCLE_DIRS) {
|
|
49
61
|
const folder = join(root, sub);
|
|
50
62
|
if (!existsSync(folder))
|
|
@@ -74,7 +74,13 @@ function latestDecisions(entries) {
|
|
|
74
74
|
return out;
|
|
75
75
|
}
|
|
76
76
|
function countFilesystemInFlight(projectRoot) {
|
|
77
|
-
|
|
77
|
+
let activeDir;
|
|
78
|
+
try {
|
|
79
|
+
activeDir = resolveLifecycleFolder(projectRoot, "active");
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return 0; // No xbrief/ layout; nothing in-flight.
|
|
83
|
+
}
|
|
78
84
|
if (!existsSync(activeDir))
|
|
79
85
|
return 0;
|
|
80
86
|
let count = 0;
|
|
@@ -94,7 +100,13 @@ function countFilesystemInFlight(projectRoot) {
|
|
|
94
100
|
return count;
|
|
95
101
|
}
|
|
96
102
|
function isTriageScopeConfigured(projectRoot) {
|
|
97
|
-
|
|
103
|
+
let path;
|
|
104
|
+
try {
|
|
105
|
+
path = resolveProjectDefinitionPath(projectRoot);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false; // No xbrief/ layout; triage scope not configured.
|
|
109
|
+
}
|
|
98
110
|
if (!existsSync(path))
|
|
99
111
|
return false;
|
|
100
112
|
try {
|
|
@@ -143,7 +143,13 @@ function daysInPending(path, now) {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
export function previewWipRelief(projectRoot, olderThanDays = DEFAULT_RELIEF_AGE_DAYS) {
|
|
146
|
-
|
|
146
|
+
let pendingDir;
|
|
147
|
+
try {
|
|
148
|
+
pendingDir = resolveLifecycleFolder(projectRoot, "pending");
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return { olderThanDays, eligibleCount: 0, eligibleFiles: [], skippedCount: 0 };
|
|
152
|
+
}
|
|
147
153
|
if (!existsSync(pendingDir)) {
|
|
148
154
|
return { olderThanDays, eligibleCount: 0, eligibleFiles: [], skippedCount: 0 };
|
|
149
155
|
}
|
|
@@ -25,6 +25,8 @@ export declare const SKIP_NOTICE: string;
|
|
|
25
25
|
/** Result of a single lane command invocation. Mirrors a subset of SpawnSyncReturns. */
|
|
26
26
|
export interface RunnerResult {
|
|
27
27
|
readonly status: number | null;
|
|
28
|
+
readonly signal?: NodeJS.Signals | null;
|
|
29
|
+
readonly error?: Error;
|
|
28
30
|
}
|
|
29
31
|
export type LaneRunner = (argv: readonly string[], cwd: string) => RunnerResult;
|
|
30
32
|
export interface RunTsLaneOptions {
|
|
@@ -35,6 +37,8 @@ export interface RunTsLaneOptions {
|
|
|
35
37
|
/** Injected sink for human-facing notices (defaults to stdout). */
|
|
36
38
|
readonly out?: (message: string) => void;
|
|
37
39
|
}
|
|
40
|
+
/** Windows command shims (.cmd/.bat) need a shell; native executables do not. */
|
|
41
|
+
export declare function shouldUseShellForCommand(command: string, platform?: NodeJS.Platform): boolean;
|
|
38
42
|
export interface ResolvePnpmOptions {
|
|
39
43
|
readonly env?: NodeJS.ProcessEnv;
|
|
40
44
|
readonly platform?: NodeJS.Platform;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import { spawnSync } from "node:child_process";
|
|
20
20
|
import { existsSync } from "node:fs";
|
|
21
|
-
import {
|
|
21
|
+
import { posix, win32 } from "node:path";
|
|
22
22
|
/**
|
|
23
23
|
* Run order is deliberate: lint (cheapest, catches the biome class first),
|
|
24
24
|
* then build, then the test suite.
|
|
@@ -31,11 +31,20 @@ export const LANE_COMMANDS = [
|
|
|
31
31
|
export const SKIP_NOTICE = "[ts:check-lane] pnpm not found on PATH -- skipping the TypeScript lane " +
|
|
32
32
|
"(build/lint/test). The TS engine stays validated by the dedicated CI job. " +
|
|
33
33
|
"Install the Node toolchain (pnpm) to run the TS lane locally.";
|
|
34
|
-
/**
|
|
34
|
+
/** Windows command shims (.cmd/.bat) need a shell; native executables do not. */
|
|
35
|
+
export function shouldUseShellForCommand(command, platform = process.platform) {
|
|
36
|
+
return platform === "win32" && /\.(?:cmd|bat)$/i.test(command);
|
|
37
|
+
}
|
|
38
|
+
/** Default runner: an inherited-stdio pnpm invocation. */
|
|
35
39
|
function defaultRunner(argv, cwd) {
|
|
36
40
|
const [command, ...rest] = argv;
|
|
37
|
-
const
|
|
38
|
-
|
|
41
|
+
const commandPath = command ?? "";
|
|
42
|
+
const result = spawnSync(commandPath, rest, {
|
|
43
|
+
cwd,
|
|
44
|
+
stdio: "inherit",
|
|
45
|
+
shell: shouldUseShellForCommand(commandPath),
|
|
46
|
+
});
|
|
47
|
+
return { error: result.error, signal: result.signal, status: result.status };
|
|
39
48
|
}
|
|
40
49
|
/** Resolve the pnpm executable path, or null when it is not installed. */
|
|
41
50
|
export function resolvePnpm(options = {}) {
|
|
@@ -49,11 +58,12 @@ export function resolvePnpm(options = {}) {
|
|
|
49
58
|
const isWindows = platform === "win32";
|
|
50
59
|
const exts = isWindows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";") : [""];
|
|
51
60
|
const sep = isWindows ? ";" : ":";
|
|
61
|
+
const joinPath = isWindows ? win32.join : posix.join;
|
|
52
62
|
for (const dir of pathValue.split(sep)) {
|
|
53
63
|
if (dir === "")
|
|
54
64
|
continue;
|
|
55
65
|
for (const ext of exts) {
|
|
56
|
-
const candidate =
|
|
66
|
+
const candidate = joinPath(dir, `pnpm${ext}`);
|
|
57
67
|
if (exists(candidate)) {
|
|
58
68
|
return candidate;
|
|
59
69
|
}
|
|
@@ -85,7 +95,11 @@ export function runTsLane(projectRoot, options) {
|
|
|
85
95
|
// failure -- this mirrors the Python oracle, whose returncode is negative
|
|
86
96
|
// (non-zero) for a signal-killed process.
|
|
87
97
|
if (code === null) {
|
|
88
|
-
|
|
98
|
+
if (result.error) {
|
|
99
|
+
out(`[ts:check-lane] \`pnpm ${command.join(" ")}\` failed to start: ${result.error.message}`);
|
|
100
|
+
return 1;
|
|
101
|
+
}
|
|
102
|
+
out(`[ts:check-lane] \`pnpm ${command.join(" ")}\` was killed by ${result.signal ?? "a signal"} before exit -- treating as failure.`);
|
|
89
103
|
return 1;
|
|
90
104
|
}
|
|
91
105
|
if (code !== 0) {
|
|
@@ -29,7 +29,17 @@ export function validateStrategyOutput(projectRoot, strict = false) {
|
|
|
29
29
|
const errors = [];
|
|
30
30
|
// Layout-aware (#2109 part 2a): resolve the lifecycle dir/suffix dynamically;
|
|
31
31
|
// identical to vbrief/ on today's tree.
|
|
32
|
-
|
|
32
|
+
let layout;
|
|
33
|
+
try {
|
|
34
|
+
layout = resolveLifecycleLayout(root);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
if (strict) {
|
|
38
|
+
errors.push("xbrief/ directory missing entirely. v0.20 strategies must emit at least " +
|
|
39
|
+
"xbrief/proposed/ (with date-prefixed files) + PROJECT-DEFINITION.xbrief.json.");
|
|
40
|
+
}
|
|
41
|
+
return errors;
|
|
42
|
+
}
|
|
33
43
|
const vbriefDir = layout.root;
|
|
34
44
|
if (!existsSync(vbriefDir)) {
|
|
35
45
|
if (strict) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { isFrameworkRepoRoot } from "../check/orchestrator.js";
|
|
4
|
+
import { policyColonInvocation } from "../policy/policy-invocation.js";
|
|
4
5
|
import { isValueFeedbackPathAllowed, resolveValueFeedback } from "../policy/value-feedback.js";
|
|
5
6
|
import { GhRestError, restCreateIssue, restIssueListPaginated, } from "../scm/gh-rest.js";
|
|
6
7
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
@@ -146,8 +147,8 @@ export function runFeedbackFile(options) {
|
|
|
146
147
|
body,
|
|
147
148
|
repo,
|
|
148
149
|
message: "[deft feedback] Blocked: plan.policy.valueFeedback upstreamPrompt is OFF. " +
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
`Enable with \`${policyColonInvocation("enable-value-feedback", " -- --confirm")}\` and set upstreamPrompt, ` +
|
|
151
|
+
`or inspect via \`${policyColonInvocation("show", " --field=valueFeedback")}\`.\n`,
|
|
151
152
|
};
|
|
152
153
|
}
|
|
153
154
|
const offline = isOffline();
|
package/dist/value/readback.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join, resolve } from "node:path";
|
|
|
3
3
|
import { runningInsideDeftRepo } from "../doctor/paths.js";
|
|
4
4
|
import { ALL_ATTRIBUTION_EVENT_NAMES } from "../events/attribution-constants.js";
|
|
5
5
|
import { DEFAULT_EVENT_LOG, readEvents } from "../lifecycle/events.js";
|
|
6
|
+
import { policyColonInvocation } from "../policy/policy-invocation.js";
|
|
6
7
|
import { isValueFeedbackPathAllowed, resolveValueFeedback, } from "../policy/value-feedback.js";
|
|
7
8
|
import { resolveProjectRoot } from "../scope/project-context.js";
|
|
8
9
|
import { MAX_LINE_CHARS } from "../triage/welcome/constants.js";
|
|
@@ -364,7 +365,7 @@ export function formatValueShowReport(trend) {
|
|
|
364
365
|
if (trend.total === 0) {
|
|
365
366
|
return (`[value] No attributed signals in the last ${trend.windowLabel} ` +
|
|
366
367
|
"(ledger empty for this window).\n" +
|
|
367
|
-
|
|
368
|
+
`Inspect policy: \`${policyColonInvocation("show", " --field=valueFeedback")}\`.\n`);
|
|
368
369
|
}
|
|
369
370
|
const classParts = ["value", "bypass", "adoption", "friction"]
|
|
370
371
|
.filter((key) => trend.byClass[key] > 0)
|
|
@@ -409,7 +410,7 @@ export function runValueShow(options) {
|
|
|
409
410
|
gated: true,
|
|
410
411
|
empty: true,
|
|
411
412
|
text: "[value] Blocked: plan.policy.valueFeedback is OFF. " +
|
|
412
|
-
|
|
413
|
+
`Enable with \`${policyColonInvocation("enable-value-feedback", " -- --confirm")}\`.\n`,
|
|
413
414
|
trend: null,
|
|
414
415
|
};
|
|
415
416
|
}
|
|
@@ -195,10 +195,10 @@ export function runParityScenario(name, ctx) {
|
|
|
195
195
|
}, { ipIndex: 1, dependencies: ["ip-0"], specRef: "../specification.vbrief.json" }),
|
|
196
196
|
};
|
|
197
197
|
case "project-definition-roundtrip": {
|
|
198
|
-
const vbriefDir = join(ctx.fixtureRoot, "
|
|
198
|
+
const vbriefDir = join(ctx.fixtureRoot, "xbrief");
|
|
199
199
|
mkdirSync(vbriefDir, { recursive: true });
|
|
200
200
|
const seed = {
|
|
201
|
-
|
|
201
|
+
xBRIEFInfo: { version: "0.8" },
|
|
202
202
|
plan: {
|
|
203
203
|
title: "Parity project",
|
|
204
204
|
status: "running",
|
|
@@ -206,7 +206,7 @@ export function runParityScenario(name, ctx) {
|
|
|
206
206
|
items: [],
|
|
207
207
|
},
|
|
208
208
|
};
|
|
209
|
-
const pdPath = join(vbriefDir, "PROJECT-DEFINITION.
|
|
209
|
+
const pdPath = join(vbriefDir, "PROJECT-DEFINITION.xbrief.json");
|
|
210
210
|
writeFileSync(pdPath, pythonJsonPretty(seed), "utf8");
|
|
211
211
|
let roundtrip = {};
|
|
212
212
|
projectDefinitionMutationLock(ctx.fixtureRoot, () => {
|
|
@@ -84,7 +84,22 @@ function hasUnresolvedDeps(swarm, knownIds) {
|
|
|
84
84
|
}
|
|
85
85
|
export function reconcileLabels(projectRoot, options = {}) {
|
|
86
86
|
const root = resolve(projectRoot);
|
|
87
|
-
|
|
87
|
+
let vbriefDir;
|
|
88
|
+
try {
|
|
89
|
+
vbriefDir = resolveLifecycleRoot(root);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return [
|
|
93
|
+
2,
|
|
94
|
+
{
|
|
95
|
+
changed: [],
|
|
96
|
+
unchanged: [],
|
|
97
|
+
skipped_no_ref: [],
|
|
98
|
+
errors: [],
|
|
99
|
+
dry_run: options.dryRun ?? false,
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
}
|
|
88
103
|
if (!existsSync(vbriefDir)) {
|
|
89
104
|
return [
|
|
90
105
|
2,
|
|
@@ -79,8 +79,8 @@ function specWith(items) {
|
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
function writeBrief(root, storyId, folder, extra = {}) {
|
|
82
|
-
const path = join(root, "
|
|
83
|
-
mkdirSync(join(root, "
|
|
82
|
+
const path = join(root, "xbrief", folder, `2026-05-21-${storyId}.xbrief.json`);
|
|
83
|
+
mkdirSync(join(root, "xbrief", folder), { recursive: true });
|
|
84
84
|
const statusMap = {
|
|
85
85
|
proposed: "proposed",
|
|
86
86
|
pending: "pending",
|
|
@@ -89,7 +89,7 @@ function writeBrief(root, storyId, folder, extra = {}) {
|
|
|
89
89
|
cancelled: "cancelled",
|
|
90
90
|
};
|
|
91
91
|
const data = {
|
|
92
|
-
|
|
92
|
+
xBRIEFInfo: { version: "0.8" },
|
|
93
93
|
plan: {
|
|
94
94
|
id: storyId,
|
|
95
95
|
title: storyId,
|
|
@@ -215,7 +215,7 @@ export function runParityScenario(name, options) {
|
|
|
215
215
|
};
|
|
216
216
|
}
|
|
217
217
|
case "graph-dry-run": {
|
|
218
|
-
mkdirSync(join(root, "
|
|
218
|
+
mkdirSync(join(root, "xbrief", "proposed"), { recursive: true });
|
|
219
219
|
writeBrief(root, "dep-done", "completed");
|
|
220
220
|
writeBrief(root, "child", "proposed", {
|
|
221
221
|
metadata: {
|
|
@@ -246,7 +246,7 @@ export function runParityScenario(name, options) {
|
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
case "graph-cycle": {
|
|
249
|
-
mkdirSync(join(root, "
|
|
249
|
+
mkdirSync(join(root, "xbrief", "proposed"), { recursive: true });
|
|
250
250
|
for (const id of ["a", "b"]) {
|
|
251
251
|
writeBrief(root, id, "proposed", {
|
|
252
252
|
metadata: {
|
|
@@ -274,12 +274,12 @@ export function runParityScenario(name, options) {
|
|
|
274
274
|
};
|
|
275
275
|
}
|
|
276
276
|
case "graph-missing-proposed": {
|
|
277
|
-
mkdirSync(join(root, "
|
|
277
|
+
mkdirSync(join(root, "xbrief"), { recursive: true });
|
|
278
278
|
const [code] = reconcileGraph(root, { dryRun: true });
|
|
279
279
|
return { scenario: name, ok: true, payload: { exitCode: code } };
|
|
280
280
|
}
|
|
281
281
|
case "labels-blocked-dry-run": {
|
|
282
|
-
mkdirSync(join(root, "
|
|
282
|
+
mkdirSync(join(root, "xbrief", "active"), { recursive: true });
|
|
283
283
|
writeBrief(root, "blk", "active", {
|
|
284
284
|
status: "blocked",
|
|
285
285
|
references: [
|
|
@@ -303,7 +303,7 @@ export function runParityScenario(name, options) {
|
|
|
303
303
|
};
|
|
304
304
|
}
|
|
305
305
|
case "labels-utf8-dry-run": {
|
|
306
|
-
mkdirSync(join(root, "
|
|
306
|
+
mkdirSync(join(root, "xbrief", "active"), { recursive: true });
|
|
307
307
|
writeBrief(root, "utf8", "active", {
|
|
308
308
|
references: [
|
|
309
309
|
{
|
|
@@ -322,7 +322,7 @@ export function runParityScenario(name, options) {
|
|
|
322
322
|
};
|
|
323
323
|
}
|
|
324
324
|
case "umbrellas-create-dry-run": {
|
|
325
|
-
mkdirSync(join(root, "
|
|
325
|
+
mkdirSync(join(root, "xbrief", "active"), { recursive: true });
|
|
326
326
|
writeBrief(root, "child-a", "active", {
|
|
327
327
|
metadata: { kind: "story", swarm: { depends_on: [] } },
|
|
328
328
|
});
|
|
@@ -350,7 +350,7 @@ export function runParityScenario(name, options) {
|
|
|
350
350
|
};
|
|
351
351
|
}
|
|
352
352
|
case "umbrellas-unchanged": {
|
|
353
|
-
mkdirSync(join(root, "
|
|
353
|
+
mkdirSync(join(root, "xbrief", "active"), { recursive: true });
|
|
354
354
|
writeBrief(root, "child-b", "active", {
|
|
355
355
|
metadata: { kind: "story", swarm: { depends_on: [] } },
|
|
356
356
|
});
|