@deftai/directive-core 0.70.0 → 0.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/branch/evaluate.js +7 -0
- package/dist/doctor/doctor-state.js +2 -2
- package/dist/eval/crud-telemetry.d.ts +59 -0
- package/dist/eval/crud-telemetry.js +307 -0
- package/dist/eval/health.d.ts +52 -0
- package/dist/eval/health.js +240 -0
- package/dist/eval/readback.d.ts +38 -0
- package/dist/eval/readback.js +209 -0
- package/dist/eval/report.d.ts +53 -0
- package/dist/eval/report.js +161 -0
- package/dist/eval/run.d.ts +79 -0
- package/dist/eval/run.js +309 -0
- package/dist/events/attribution-constants.d.ts +13 -0
- package/dist/events/attribution-constants.js +18 -0
- package/dist/events/attribution-ledger.d.ts +43 -0
- package/dist/events/attribution-ledger.js +61 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/init-deposit/gitignore.js +5 -5
- package/dist/layout/resolve.d.ts +2 -2
- package/dist/layout/resolve.js +2 -2
- package/dist/lifecycle/events.js +2 -0
- package/dist/policy/index.d.ts +2 -1
- package/dist/policy/index.js +15 -2
- package/dist/policy/value-feedback.d.ts +56 -0
- package/dist/policy/value-feedback.js +284 -0
- package/dist/preflight-cache/evaluate.js +4 -3
- package/dist/scope/audit-log.js +3 -3
- package/dist/scope/transition.js +16 -5
- package/dist/session/session-start.js +20 -0
- package/dist/slice/record.js +3 -3
- package/dist/triage/actions/candidates-log.d.ts +4 -4
- package/dist/triage/actions/candidates-log.js +4 -7
- package/dist/triage/bootstrap/gitignore.d.ts +7 -3
- package/dist/triage/bootstrap/gitignore.js +67 -37
- package/dist/triage/bootstrap/index.d.ts +1 -1
- package/dist/triage/bootstrap/index.js +4 -3
- package/dist/triage/bulk/index.js +2 -2
- package/dist/triage/cache-path.d.ts +39 -0
- package/dist/triage/cache-path.js +98 -0
- package/dist/triage/help/registry-data.d.ts +48 -15
- package/dist/triage/help/registry-data.js +86 -15
- package/dist/triage/index.d.ts +2 -0
- package/dist/triage/index.js +2 -0
- package/dist/triage/queue/audit.js +2 -2
- package/dist/triage/queue/cache.js +2 -2
- package/dist/triage/reconcile/reconcile.js +4 -3
- package/dist/triage/scope/mutations-core.js +3 -2
- package/dist/triage/subscribe/index.d.ts +1 -1
- package/dist/triage/subscribe/index.js +4 -3
- package/dist/triage/summary/index.d.ts +2 -2
- package/dist/triage/summary/index.js +4 -3
- package/dist/triage/summary/reconcilable.d.ts +1 -1
- package/dist/triage/summary/reconcilable.js +3 -2
- package/dist/triage/welcome/constants.d.ts +2 -2
- package/dist/triage/welcome/constants.js +2 -2
- package/dist/triage/welcome/prior-state.js +3 -2
- package/dist/triage/welcome/summary.js +5 -4
- package/dist/value/adoption-emit.d.ts +14 -0
- package/dist/value/adoption-emit.js +67 -0
- package/dist/value/adoption-registry.d.ts +62 -0
- package/dist/value/adoption-registry.js +214 -0
- package/dist/value/feedback-file.d.ts +67 -0
- package/dist/value/feedback-file.js +353 -0
- package/dist/value/friction-emit.d.ts +10 -0
- package/dist/value/friction-emit.js +24 -0
- package/dist/value/readback.d.ts +86 -0
- package/dist/value/readback.js +503 -0
- package/dist/vbrief-validate/decomposition.js +1 -1
- package/dist/wip-cap/evaluate.js +3 -0
- package/package.json +35 -3
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { runningInsideDeftRepo } from "../doctor/paths.js";
|
|
3
|
+
import { emitSessionEvalReadback } from "../eval/readback.js";
|
|
3
4
|
import { MIGRATE_COMPLETION_NUDGE, shouldEmitMigrateNudge } from "../init-deposit/migrate.js";
|
|
4
5
|
import { disclosureLine } from "../policy/disclosure.js";
|
|
5
6
|
import { resolvePolicy } from "../policy/resolve.js";
|
|
6
7
|
import { runDefaultMode } from "../triage/welcome/default-mode.js";
|
|
7
8
|
import { resolveUserMdPath } from "../user-config/resolve-user-md.js";
|
|
9
|
+
import { emitSessionValueReadback } from "../value/readback.js";
|
|
8
10
|
import { verifyRequiredTools } from "../verify-env/verify-tools.js";
|
|
9
11
|
import { defaultGitRunner, gitHead, worktreePath } from "./git.js";
|
|
10
12
|
import { newRitualStatePayload, ritualStatePath, ritualStep, writeRitualState, } from "./ritual-sentinel.js";
|
|
@@ -289,6 +291,24 @@ export function runSessionStart(projectRoot, options = {}) {
|
|
|
289
291
|
if (!runningInsideDeftRepo(projectRoot) && shouldEmitMigrateNudge(projectRoot)) {
|
|
290
292
|
lines.push(MIGRATE_COMPLETION_NUDGE);
|
|
291
293
|
}
|
|
294
|
+
try {
|
|
295
|
+
emitSessionValueReadback(projectRoot, {
|
|
296
|
+
output: (line) => lines.push(line),
|
|
297
|
+
writeHistory: options.writeHistory !== false,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
// observability only — session start must not abort on transient readback I/O
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
emitSessionEvalReadback(projectRoot, {
|
|
305
|
+
output: (line) => lines.push(line),
|
|
306
|
+
writeHistory: options.writeHistory !== false,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// observability only — session start must not abort on transient eval readback I/O
|
|
311
|
+
}
|
|
292
312
|
const payload = newRitualStatePayload({
|
|
293
313
|
sessionId: (options.newSessionId ?? randomUUID)(),
|
|
294
314
|
gitHead: gitHeadValue,
|
package/dist/slice/record.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { appendFileSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, } from "node:fs";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveTriageCachePath } from "../triage/cache-path.js";
|
|
5
5
|
import { pythonJsonStringify } from "./json.js";
|
|
6
6
|
import { withAppendLock } from "./lock.js";
|
|
7
7
|
import { validateRecord } from "./validate.js";
|
|
@@ -16,7 +16,7 @@ const defaultDeps = {
|
|
|
16
16
|
withLock: withAppendLock,
|
|
17
17
|
};
|
|
18
18
|
function resolvePath(path) {
|
|
19
|
-
return path !== undefined ? resolve(path) :
|
|
19
|
+
return path !== undefined ? resolve(path) : resolveTriageCachePath(process.cwd(), "slices.jsonl");
|
|
20
20
|
}
|
|
21
21
|
export function newSliceId() {
|
|
22
22
|
return randomUUID();
|
|
@@ -134,6 +134,6 @@ export function findByUmbrella(umbrella, options = {}) {
|
|
|
134
134
|
return readAll(options).filter((record) => record.umbrella === umbrella);
|
|
135
135
|
}
|
|
136
136
|
export function slicesPath(projectRoot) {
|
|
137
|
-
return
|
|
137
|
+
return resolveTriageCachePath(projectRoot, "slices.jsonl");
|
|
138
138
|
}
|
|
139
139
|
//# sourceMappingURL=record.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
1
2
|
import type { AuditEntry, CandidatesLog } from "./types.js";
|
|
2
|
-
/** Display/back-compat constant; resolution flows through
|
|
3
|
-
export declare const AUDIT_LOG_REL_PATH = "vbrief/.
|
|
4
|
-
|
|
5
|
-
export declare function resolveCandidatesLogPath(projectRoot: string): string;
|
|
3
|
+
/** Display/back-compat constant; resolution flows through resolveTriageCachePath (#1703). */
|
|
4
|
+
export declare const AUDIT_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
5
|
+
export { resolveCandidatesLogPath };
|
|
6
6
|
/** Read every well-formed audit-log row in insertion order (#1698 shared reader). */
|
|
7
7
|
export declare function readAuditLog(logPath: string, repo?: string | null): AuditEntry[];
|
|
8
8
|
/** Return every entry for ``(repo, issue_number)`` in insertion order. */
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveCandidatesLogPath, TRIAGE_CANDIDATES_LOG_REL_PATH } from "../cache-path.js";
|
|
5
5
|
import { CandidatesLogError } from "./errors.js";
|
|
6
|
-
/** Display/back-compat constant; resolution flows through
|
|
7
|
-
export const AUDIT_LOG_REL_PATH =
|
|
8
|
-
|
|
9
|
-
export function resolveCandidatesLogPath(projectRoot) {
|
|
10
|
-
return resolveEvalPath(projectRoot, "candidates.jsonl");
|
|
11
|
-
}
|
|
6
|
+
/** Display/back-compat constant; resolution flows through resolveTriageCachePath (#1703). */
|
|
7
|
+
export const AUDIT_LOG_REL_PATH = TRIAGE_CANDIDATES_LOG_REL_PATH;
|
|
8
|
+
export { resolveCandidatesLogPath };
|
|
12
9
|
const VALID_DECISIONS = new Set([
|
|
13
10
|
"accept",
|
|
14
11
|
"reject",
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import type { StepOutcome } from "./types.js";
|
|
2
2
|
export declare const GITIGNORE_LINE = ".deft-cache/";
|
|
3
3
|
export declare const GITIGNORE_DEFT_RUNTIME_SENTINELS: readonly string[];
|
|
4
|
+
/** Legacy static vbrief paths kept for tests referencing the pre-#1703 constant shape. */
|
|
4
5
|
export declare const GITIGNORE_EVAL_ENTRIES: readonly string[];
|
|
5
|
-
|
|
6
|
+
/** Layout-aware gitignore lines for triage working-set files (#1703). */
|
|
7
|
+
export declare function gitignoreTriageCacheEntries(projectRoot: string): readonly string[];
|
|
8
|
+
export declare function gitattributesTriageCacheGlob(projectRoot: string): string;
|
|
9
|
+
export declare const GITATTRIBUTES_EVAL_RULE = "vbrief/.triage-cache/*.jsonl merge=union";
|
|
6
10
|
export declare const FORBIDDEN_BLANKET_EVAL_LINES: readonly string[];
|
|
7
|
-
export declare const EVAL_README_BODY = "# `vbrief/.
|
|
11
|
+
export declare const EVAL_README_BODY = "# `vbrief/.triage-cache/` -- triage working-set artefacts\n\nThis directory holds the append-only JSON-lines logs that the triage and\nslicing skills emit. The framework governs which files in here are tracked\nby git versus gitignored using a **hybrid policy** (#1144, child of #1119).\n\n## Tracking policy\n\n| File | Tracked? | Why |\n| --- | --- | --- |\n| `slices.jsonl` | Yes -- **committed** | Team-shared cohort records produced by slicing skills (D13 / #1132). New operators joining the team need to see prior cohort outputs to detect orphans and avoid re-slicing the same scope. |\n| `candidates.jsonl` | No -- **gitignored** | Operator-private triage decisions (#845 Story 2). Each operator's local accept / defer / reject stream is per-machine state; sharing it would conflate operators' timing + identity across the team. Re-derive on a fresh clone via `task triage:bootstrap`. |\n| `summary-history.jsonl` | No -- **gitignored** | Operator-private observability for `task triage:summary` output time-series. Not load-bearing for any decision. |\n| `scope-lifecycle.jsonl` | No -- **gitignored** | Operator-private scope-lifecycle audit decisions (D1 / #1121). Each demote (`task scope:demote`) appends one entry including a `demote_meta` block (`was_promoted`, `original_promotion_decision_id`, `days_in_pending`, `demote_reason`, `demoted_from`). Per-operator stream; sharing would conflate operators' demote timing across the team. Lightweight metrics over this log are tracked separately at #1180. |\n| `decompositions/` | No -- **gitignored** | Temporary story-decomposition proposal drafts. These JSON drafts are local scratch artifacts, not vBRIEFs; generated child story vBRIEFs are created by `task scope:decompose` in lifecycle folders, defaulting to `vbrief/pending/`. |\n| `doctor-state.json` | No -- **gitignored** | Per-machine `task doctor` throttle state (last exit code + timestamps) persisted to gate the 24h/4h re-probe window (#1308 / #1464). Local to each clone; never committed. |\n\nThe gitignore lines live in the repo-root `.gitignore` (`vbrief/.triage-cache/candidates.jsonl`,\n`vbrief/.triage-cache/summary-history.jsonl`, `vbrief/.triage-cache/scope-lifecycle.jsonl`,\n`vbrief/.triage-cache/decompositions/`, and `vbrief/.triage-cache/doctor-state.json`). All paths\nnot listed above remain committed by default.\n\n## Fresh-clone regeneration\n\nOn a fresh clone (or any machine that has never run triage), `candidates.jsonl`\nis absent. Regenerate it with:\n\n```\ntask triage:bootstrap\n```\n\nThe bootstrap path detects the missing file, runs the auto-classifier, and\nwrites a fresh `vbrief/.triage-cache/candidates.jsonl`. It does NOT touch the tracked\n`slices.jsonl`; cohort records remain a team-shared resource.\n\n## `merge=union` policy for `*.jsonl`\n\nThe repo-root `.gitattributes` declares:\n\n```\nvbrief/.triage-cache/*.jsonl merge=union\n```\n\nThe `union` merge driver concatenates both sides' appended lines on\nauto-merge, so two branches that each appended a different record to the\nsame JSON-lines file rebase cleanly without operator surgery. Two things\noperators should know:\n\n- **Concatenation, not set-union.** When two branches append DIFFERENT\n records to the file, the merge driver concatenates both sides' lines\n -- there is no smart deduplication of \"semantically similar\" records.\n (Identical line-for-line appends collapse because git's three-way\n merge sees them as the same change, but distinct records always\n survive verbatim, even if a downstream reader would consider them\n redundant.) The append-only writers in `scripts/candidates_log.py`\n mint a fresh `decision_id` per call, so genuinely duplicate records\n are not the expected case, but downstream readers MUST tolerate\n multiple records describing the same logical decision.\n- **Single-operator scope only.** This is the foundational rebase\n ergonomic for the single-operator case (operator A rebases their\n feature branch onto a master that grew while they were AFK).\n Multi-operator merge-conflict resolution is explicitly out of scope per\n #1119 R4 (tracked separately as M1-M4 in #1183).\n\n## See also\n\n- Current Shape comment on #1144 for the canonical decisions (the source\n of truth this README documents).\n- `.gitignore` -- selective gitignore entries for the operator-private\n files.\n- `.gitattributes` -- the `merge=union` rule.\n- `scripts/candidates_log.py` -- the writer for `candidates.jsonl`.\n";
|
|
8
12
|
/** Strip an inline `# ...` comment from a gitignore line. */
|
|
9
13
|
export declare function stripGitignoreInlineComment(line: string): string;
|
|
10
14
|
/** Append `.deft-cache/` to `.gitignore` when absent. */
|
|
11
15
|
export declare function stepEnsureGitignoreEntry(projectRoot: string): StepOutcome;
|
|
12
16
|
/** Ensure the #1144 hybrid policy is encoded in the repo (idempotent). */
|
|
13
17
|
export declare function stepEnsureGitignoreEvalEntries(projectRoot: string): StepOutcome;
|
|
14
|
-
/** Ensure `vbrief/.
|
|
18
|
+
/** Ensure `vbrief/.triage-cache/candidates.jsonl` exists (#1240 option A). */
|
|
15
19
|
export declare function stepSeedCandidatesLog(projectRoot: string): StepOutcome;
|
|
16
20
|
//# sourceMappingURL=gitignore.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, relative } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveLifecycleLayout } from "../../layout/resolve.js";
|
|
4
|
+
import { resolveCandidatesLogPath, resolveTriageCachePath, TRIAGE_CACHE_DIR_NAME, triageCacheRelPath, } from "../cache-path.js";
|
|
4
5
|
/** POSIX-style display path for `absPath` relative to `projectRoot` (#2109). */
|
|
5
6
|
function evalRelDisplay(projectRoot, absPath) {
|
|
6
7
|
return relative(projectRoot, absPath).split(/[\\/]/).join("/");
|
|
@@ -10,21 +11,41 @@ export const GITIGNORE_DEFT_RUNTIME_SENTINELS = [
|
|
|
10
11
|
".deft/ritual-state.json",
|
|
11
12
|
".deft/last-session.json",
|
|
12
13
|
];
|
|
14
|
+
/** Legacy static vbrief paths kept for tests referencing the pre-#1703 constant shape. */
|
|
13
15
|
export const GITIGNORE_EVAL_ENTRIES = [
|
|
14
|
-
"vbrief/.
|
|
15
|
-
"vbrief/.
|
|
16
|
-
"vbrief/.
|
|
17
|
-
"vbrief/.
|
|
18
|
-
"vbrief/.
|
|
16
|
+
"vbrief/.triage-cache/candidates.jsonl",
|
|
17
|
+
"vbrief/.triage-cache/summary-history.jsonl",
|
|
18
|
+
"vbrief/.triage-cache/scope-lifecycle.jsonl",
|
|
19
|
+
"vbrief/.triage-cache/decompositions/",
|
|
20
|
+
"vbrief/.triage-cache/doctor-state.json",
|
|
21
|
+
];
|
|
22
|
+
/** Layout-aware gitignore lines for triage working-set files (#1703). */
|
|
23
|
+
export function gitignoreTriageCacheEntries(projectRoot) {
|
|
24
|
+
const decomp = triageCacheRelPath(projectRoot, "decompositions");
|
|
25
|
+
return [
|
|
26
|
+
triageCacheRelPath(projectRoot, "candidates.jsonl"),
|
|
27
|
+
triageCacheRelPath(projectRoot, "summary-history.jsonl"),
|
|
28
|
+
triageCacheRelPath(projectRoot, "scope-lifecycle.jsonl"),
|
|
29
|
+
decomp.endsWith("/") ? decomp : `${decomp}/`,
|
|
30
|
+
triageCacheRelPath(projectRoot, "doctor-state.json"),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
export function gitattributesTriageCacheGlob(projectRoot) {
|
|
34
|
+
const layout = resolveLifecycleLayout(projectRoot);
|
|
35
|
+
return `${layout.artifactDir}/${TRIAGE_CACHE_DIR_NAME}/*.jsonl`;
|
|
36
|
+
}
|
|
37
|
+
export const GITATTRIBUTES_EVAL_RULE = "vbrief/.triage-cache/*.jsonl merge=union";
|
|
38
|
+
export const FORBIDDEN_BLANKET_EVAL_LINES = [
|
|
39
|
+
"vbrief/.triage-cache/",
|
|
40
|
+
"vbrief/.triage-cache",
|
|
41
|
+
"vbrief/.triage-cache/",
|
|
42
|
+
"vbrief/.eval",
|
|
19
43
|
];
|
|
20
|
-
export const GITATTRIBUTES_EVAL_RULE = "vbrief/.eval/*.jsonl merge=union";
|
|
21
|
-
export const FORBIDDEN_BLANKET_EVAL_LINES = ["vbrief/.eval/", "vbrief/.eval"];
|
|
22
|
-
const GITATTRIBUTES_EVAL_GLOB = "vbrief/.eval/*.jsonl";
|
|
23
44
|
const DEFT_CACHE_RATIONALE = "\n# Triage v1 local content cache (#845, #883). Mirrors upstream\n" +
|
|
24
45
|
"# issues into .deft-cache/github-issue/<owner>/<repo>/<N>/. See\n" +
|
|
25
46
|
"# docs/privacy-nfr.md for the gitignore-default + opt-in-commit-cache\n" +
|
|
26
47
|
"# contract. Comment this line out to opt in to committing the cache.\n";
|
|
27
|
-
const EVAL_ENTRIES_RATIONALE = "\n# vbrief/.
|
|
48
|
+
const EVAL_ENTRIES_RATIONALE = "\n# vbrief/.triage-cache/ tracking governance (#1144, N4 of #1119).\n" +
|
|
28
49
|
"# Hybrid policy from the Current Shape comment on #1144:\n" +
|
|
29
50
|
"# - candidates.jsonl -> gitignored (operator-private triage\n" +
|
|
30
51
|
"# decisions; re-derive via\n" +
|
|
@@ -50,15 +71,15 @@ const EVAL_ENTRIES_RATIONALE = "\n# vbrief/.eval/ tracking governance (#1144, N4
|
|
|
50
71
|
"# - slices.jsonl -> TRACKED (team-shared cohort records\n" +
|
|
51
72
|
"# produced by slicing skills; see\n" +
|
|
52
73
|
"# #1132 / D13).\n" +
|
|
53
|
-
"# See vbrief/.
|
|
74
|
+
"# See vbrief/.triage-cache/README.md for the full policy + merge=union\n" +
|
|
54
75
|
"# rebase note.\n";
|
|
55
|
-
const GITATTRIBUTES_EVAL_RATIONALE = "\n# Append-only JSON-lines logs under vbrief/.
|
|
76
|
+
const GITATTRIBUTES_EVAL_RATIONALE = "\n# Append-only JSON-lines logs under vbrief/.triage-cache/ use the union merge driver\n" +
|
|
56
77
|
"# (#1144, N4 of #1119). Both branches' appended lines are concatenated on\n" +
|
|
57
78
|
"# auto-merge so single-operator rebases of two append branches resolve\n" +
|
|
58
79
|
"# without manual conflict surgery. Note: merge=union does NOT dedupe; see\n" +
|
|
59
|
-
"# vbrief/.
|
|
60
|
-
const EVAL_ENTRIES_RATIONALE_SENTINEL = "# vbrief/.
|
|
61
|
-
export const EVAL_README_BODY = `# \`vbrief/.
|
|
80
|
+
"# vbrief/.triage-cache/README.md for the operator-facing semantics.\n";
|
|
81
|
+
const EVAL_ENTRIES_RATIONALE_SENTINEL = "# vbrief/.triage-cache/ tracking governance (#1144, N4 of #1119).";
|
|
82
|
+
export const EVAL_README_BODY = `# \`vbrief/.triage-cache/\` -- triage working-set artefacts
|
|
62
83
|
|
|
63
84
|
This directory holds the append-only JSON-lines logs that the triage and
|
|
64
85
|
slicing skills emit. The framework governs which files in here are tracked
|
|
@@ -75,9 +96,9 @@ by git versus gitignored using a **hybrid policy** (#1144, child of #1119).
|
|
|
75
96
|
| \`decompositions/\` | No -- **gitignored** | Temporary story-decomposition proposal drafts. These JSON drafts are local scratch artifacts, not vBRIEFs; generated child story vBRIEFs are created by \`task scope:decompose\` in lifecycle folders, defaulting to \`vbrief/pending/\`. |
|
|
76
97
|
| \`doctor-state.json\` | No -- **gitignored** | Per-machine \`task doctor\` throttle state (last exit code + timestamps) persisted to gate the 24h/4h re-probe window (#1308 / #1464). Local to each clone; never committed. |
|
|
77
98
|
|
|
78
|
-
The gitignore lines live in the repo-root \`.gitignore\` (\`vbrief/.
|
|
79
|
-
\`vbrief/.
|
|
80
|
-
\`vbrief/.
|
|
99
|
+
The gitignore lines live in the repo-root \`.gitignore\` (\`vbrief/.triage-cache/candidates.jsonl\`,
|
|
100
|
+
\`vbrief/.triage-cache/summary-history.jsonl\`, \`vbrief/.triage-cache/scope-lifecycle.jsonl\`,
|
|
101
|
+
\`vbrief/.triage-cache/decompositions/\`, and \`vbrief/.triage-cache/doctor-state.json\`). All paths
|
|
81
102
|
not listed above remain committed by default.
|
|
82
103
|
|
|
83
104
|
## Fresh-clone regeneration
|
|
@@ -90,7 +111,7 @@ task triage:bootstrap
|
|
|
90
111
|
\`\`\`
|
|
91
112
|
|
|
92
113
|
The bootstrap path detects the missing file, runs the auto-classifier, and
|
|
93
|
-
writes a fresh \`vbrief/.
|
|
114
|
+
writes a fresh \`vbrief/.triage-cache/candidates.jsonl\`. It does NOT touch the tracked
|
|
94
115
|
\`slices.jsonl\`; cohort records remain a team-shared resource.
|
|
95
116
|
|
|
96
117
|
## \`merge=union\` policy for \`*.jsonl\`
|
|
@@ -98,7 +119,7 @@ writes a fresh \`vbrief/.eval/candidates.jsonl\`. It does NOT touch the tracked
|
|
|
98
119
|
The repo-root \`.gitattributes\` declares:
|
|
99
120
|
|
|
100
121
|
\`\`\`
|
|
101
|
-
vbrief/.
|
|
122
|
+
vbrief/.triage-cache/*.jsonl merge=union
|
|
102
123
|
\`\`\`
|
|
103
124
|
|
|
104
125
|
The \`union\` merge driver concatenates both sides' appended lines on
|
|
@@ -217,10 +238,10 @@ export function stepEnsureGitignoreEntry(projectRoot) {
|
|
|
217
238
|
function formatBlanketWarning(blanketPresent) {
|
|
218
239
|
if (!blanketPresent)
|
|
219
240
|
return "";
|
|
220
|
-
return (" WARNING: stale blanket vbrief/.
|
|
241
|
+
return (" WARNING: stale blanket vbrief/.triage-cache/ line detected in .gitignore -- " +
|
|
221
242
|
"remove it manually (it hides tracked slices.jsonl from git per #1251)");
|
|
222
243
|
}
|
|
223
|
-
function gitattributesHasEvalMergeUnion(body) {
|
|
244
|
+
function gitattributesHasEvalMergeUnion(body, glob) {
|
|
224
245
|
for (const raw of body.split("\n")) {
|
|
225
246
|
const stripped = raw.trim();
|
|
226
247
|
if (stripped.length === 0 || stripped.startsWith("#"))
|
|
@@ -228,14 +249,14 @@ function gitattributesHasEvalMergeUnion(body) {
|
|
|
228
249
|
const parts = stripped.split(/\s+/);
|
|
229
250
|
if (parts.length === 0)
|
|
230
251
|
continue;
|
|
231
|
-
if (parts[0] !==
|
|
252
|
+
if (parts[0] !== glob)
|
|
232
253
|
continue;
|
|
233
254
|
if (parts.slice(1).includes("merge=union"))
|
|
234
255
|
return true;
|
|
235
256
|
}
|
|
236
257
|
return false;
|
|
237
258
|
}
|
|
238
|
-
function ensureGitignoreSelectiveEntries(gitignorePath, stepName) {
|
|
259
|
+
function ensureGitignoreSelectiveEntries(gitignorePath, stepName, entries) {
|
|
239
260
|
let existing;
|
|
240
261
|
try {
|
|
241
262
|
existing = readFileSync(gitignorePath, { encoding: "utf8" });
|
|
@@ -249,7 +270,7 @@ function ensureGitignoreSelectiveEntries(gitignorePath, stepName) {
|
|
|
249
270
|
.filter((stripped) => stripped.length > 0));
|
|
250
271
|
const blanketPresent = FORBIDDEN_BLANKET_EVAL_LINES.some((forbidden) => existingLines.has(forbidden));
|
|
251
272
|
const rationaleAlreadyPresent = existing.includes(EVAL_ENTRIES_RATIONALE_SENTINEL);
|
|
252
|
-
const missing =
|
|
273
|
+
const missing = entries.filter((entry) => !existingLines.has(entry));
|
|
253
274
|
const blanketWarning = formatBlanketWarning(blanketPresent);
|
|
254
275
|
if (missing.length === 0) {
|
|
255
276
|
return stepOutcome(stepName, true, `all #1144 selective entries already in .gitignore (no-op)${blanketWarning}`, {
|
|
@@ -277,7 +298,7 @@ function ensureGitignoreSelectiveEntries(gitignorePath, stepName) {
|
|
|
277
298
|
rationale_already_present: rationaleAlreadyPresent,
|
|
278
299
|
});
|
|
279
300
|
}
|
|
280
|
-
function ensureGitattributesMergeUnion(gitattributesPath, stepName) {
|
|
301
|
+
function ensureGitattributesMergeUnion(gitattributesPath, stepName, glob, ruleLine) {
|
|
281
302
|
if (existsSync(gitattributesPath)) {
|
|
282
303
|
let existing;
|
|
283
304
|
try {
|
|
@@ -286,30 +307,36 @@ function ensureGitattributesMergeUnion(gitattributesPath, stepName) {
|
|
|
286
307
|
catch (exc) {
|
|
287
308
|
return stepOutcome(stepName, false, "could not read .gitattributes", { gitattributes_appended: false }, String(exc));
|
|
288
309
|
}
|
|
289
|
-
if (gitattributesHasEvalMergeUnion(existing)) {
|
|
290
|
-
return stepOutcome(stepName, true,
|
|
310
|
+
if (gitattributesHasEvalMergeUnion(existing, glob)) {
|
|
311
|
+
return stepOutcome(stepName, true, `${glob} merge=union already in .gitattributes (no-op)`, {
|
|
291
312
|
gitattributes_appended: false,
|
|
292
313
|
gitattributes_already_present: true,
|
|
293
314
|
});
|
|
294
315
|
}
|
|
295
316
|
const suffix = existing.endsWith("\n") || existing === "" ? "" : "\n";
|
|
296
|
-
const newContent = `${existing + suffix + GITATTRIBUTES_EVAL_RATIONALE +
|
|
317
|
+
const newContent = `${existing + suffix + GITATTRIBUTES_EVAL_RATIONALE + ruleLine}\n`;
|
|
297
318
|
try {
|
|
298
319
|
writeFileSync(gitattributesPath, newContent, { encoding: "utf8" });
|
|
299
320
|
}
|
|
300
321
|
catch (exc) {
|
|
301
322
|
return stepOutcome(stepName, false, "could not write .gitattributes", { gitattributes_appended: false }, String(exc));
|
|
302
323
|
}
|
|
303
|
-
return stepOutcome(stepName, true,
|
|
324
|
+
return stepOutcome(stepName, true, `appended ${glob} merge=union to .gitattributes`, {
|
|
325
|
+
gitattributes_appended: true,
|
|
326
|
+
gitattributes_created: false,
|
|
327
|
+
});
|
|
304
328
|
}
|
|
305
|
-
const newContent = `${GITATTRIBUTES_EVAL_RATIONALE +
|
|
329
|
+
const newContent = `${GITATTRIBUTES_EVAL_RATIONALE + ruleLine}\n`;
|
|
306
330
|
try {
|
|
307
331
|
writeFileSync(gitattributesPath, newContent, { encoding: "utf8" });
|
|
308
332
|
}
|
|
309
333
|
catch (exc) {
|
|
310
334
|
return stepOutcome(stepName, false, "could not create .gitattributes", { gitattributes_appended: false }, String(exc));
|
|
311
335
|
}
|
|
312
|
-
return stepOutcome(stepName, true,
|
|
336
|
+
return stepOutcome(stepName, true, `created .gitattributes with ${glob} merge=union`, {
|
|
337
|
+
gitattributes_appended: true,
|
|
338
|
+
gitattributes_created: true,
|
|
339
|
+
});
|
|
313
340
|
}
|
|
314
341
|
function ensureEvalReadme(readmePath, readmeRel, stepName) {
|
|
315
342
|
try {
|
|
@@ -339,17 +366,20 @@ export function stepEnsureGitignoreEvalEntries(projectRoot) {
|
|
|
339
366
|
const gitattributesPath = `${projectRoot}/.gitattributes`;
|
|
340
367
|
// Layout-aware (#2109): resolve the README under the active lifecycle `.eval`
|
|
341
368
|
// dir (xbrief/ when migrated, else vbrief/) instead of a hardcoded vbrief/ path.
|
|
342
|
-
const readmePath =
|
|
369
|
+
const readmePath = resolveTriageCachePath(projectRoot, "README.md");
|
|
343
370
|
const readmeRel = evalRelDisplay(projectRoot, readmePath);
|
|
371
|
+
const entries = gitignoreTriageCacheEntries(projectRoot);
|
|
372
|
+
const glob = gitattributesTriageCacheGlob(projectRoot);
|
|
373
|
+
const ruleLine = `${glob} merge=union`;
|
|
344
374
|
const stepName = "ensure_gitignore_eval_entries";
|
|
345
375
|
const details = {};
|
|
346
|
-
const giResult = ensureGitignoreSelectiveEntries(gitignorePath, stepName);
|
|
376
|
+
const giResult = ensureGitignoreSelectiveEntries(gitignorePath, stepName, entries);
|
|
347
377
|
if (!giResult.ok) {
|
|
348
378
|
Object.assign(details, giResult.details);
|
|
349
379
|
return stepOutcome(stepName, false, giResult.message, details, giResult.error ?? null);
|
|
350
380
|
}
|
|
351
381
|
Object.assign(details, giResult.details);
|
|
352
|
-
const gaResult = ensureGitattributesMergeUnion(gitattributesPath, stepName);
|
|
382
|
+
const gaResult = ensureGitattributesMergeUnion(gitattributesPath, stepName, glob, ruleLine);
|
|
353
383
|
if (!gaResult.ok) {
|
|
354
384
|
Object.assign(details, gaResult.details);
|
|
355
385
|
return stepOutcome(stepName, false, gaResult.message, details, gaResult.error ?? null);
|
|
@@ -386,11 +416,11 @@ export function stepEnsureGitignoreEvalEntries(projectRoot) {
|
|
|
386
416
|
message += formatBlanketWarning(Boolean(details.blanket_present));
|
|
387
417
|
return stepOutcome(stepName, true, message, details);
|
|
388
418
|
}
|
|
389
|
-
/** Ensure `vbrief/.
|
|
419
|
+
/** Ensure `vbrief/.triage-cache/candidates.jsonl` exists (#1240 option A). */
|
|
390
420
|
export function stepSeedCandidatesLog(projectRoot) {
|
|
391
421
|
// Layout-aware (#2109): seed under the active lifecycle `.eval` dir (xbrief/
|
|
392
422
|
// when migrated, else vbrief/) instead of a hardcoded vbrief/ path.
|
|
393
|
-
const auditPath =
|
|
423
|
+
const auditPath = resolveCandidatesLogPath(projectRoot);
|
|
394
424
|
const auditRel = evalRelDisplay(projectRoot, auditPath);
|
|
395
425
|
const auditDir = dirname(auditPath);
|
|
396
426
|
try {
|
|
@@ -2,7 +2,7 @@ import type { BootstrapResult, CacheModule, RunBootstrapOptions, StepOutcome } f
|
|
|
2
2
|
export * from "./gitignore.js";
|
|
3
3
|
export * from "./types.js";
|
|
4
4
|
export declare const CACHE_DIR_NAME = ".deft-cache";
|
|
5
|
-
export declare const AUDIT_LOG_RELPATH = "vbrief/.
|
|
5
|
+
export declare const AUDIT_LOG_RELPATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
6
6
|
export declare const BACKFILL_FOLDERS: readonly ["proposed", "pending", "active"];
|
|
7
7
|
export declare const BOOTSTRAP_ACTOR = "agent:bootstrap";
|
|
8
8
|
export declare const DEFAULT_FETCH_TIMEOUT_S = 3600;
|
|
@@ -3,14 +3,15 @@ import { randomUUID } from "node:crypto";
|
|
|
3
3
|
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
|
-
import { hasArtifactSuffix,
|
|
6
|
+
import { hasArtifactSuffix, resolveLifecycleRoot } from "../../layout/resolve.js";
|
|
7
7
|
import { SUBPROCESS_MAX_BUFFER } from "../../subprocess/max-buffer.js";
|
|
8
|
+
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
8
9
|
import { stepEnsureGitignoreEntry, stepEnsureGitignoreEvalEntries, stepSeedCandidatesLog, } from "./gitignore.js";
|
|
9
10
|
import { PROGRESS_DEFAULT } from "./types.js";
|
|
10
11
|
export * from "./gitignore.js";
|
|
11
12
|
export * from "./types.js";
|
|
12
13
|
export const CACHE_DIR_NAME = ".deft-cache";
|
|
13
|
-
export const AUDIT_LOG_RELPATH = "vbrief/.
|
|
14
|
+
export const AUDIT_LOG_RELPATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
14
15
|
export const BACKFILL_FOLDERS = ["proposed", "pending", "active"];
|
|
15
16
|
export const BOOTSTRAP_ACTOR = "agent:bootstrap";
|
|
16
17
|
export const DEFAULT_FETCH_TIMEOUT_S = 3600;
|
|
@@ -377,7 +378,7 @@ export function stepBackfillAuditLog(projectRoot, repo, options = {}) {
|
|
|
377
378
|
if (!existsSync(vbriefRoot)) {
|
|
378
379
|
return stepOutcome("backfill_audit_log", true, `skipped (no vbrief/ directory under ${projectRoot})`, { skipped: "no-vbrief" });
|
|
379
380
|
}
|
|
380
|
-
const auditPath =
|
|
381
|
+
const auditPath = resolveCandidatesLogPath(projectRoot);
|
|
381
382
|
const alreadyLogged = existingAuditIssueNumbers(auditPath);
|
|
382
383
|
const nowIso = options.nowIso ?? nowIsoDefault;
|
|
383
384
|
const appendEntry = options.appendAuditEntry ?? appendAuditEntryDefault;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
|
-
import { resolveEvalPath } from "../../layout/resolve.js";
|
|
5
4
|
import { createDefaultDeps, accept as nativeAccept, deferAction as nativeDefer, needsAc as nativeNeedsAc, reject as nativeReject, } from "../actions/index.js";
|
|
5
|
+
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
6
6
|
export const ACTION_FN_NAMES = {
|
|
7
7
|
accept: "accept",
|
|
8
8
|
reject: "reject",
|
|
@@ -377,7 +377,7 @@ export function createFilesystemCacheModule() {
|
|
|
377
377
|
CacheError,
|
|
378
378
|
};
|
|
379
379
|
}
|
|
380
|
-
export function createFilesystemCandidatesLogModule(logPath =
|
|
380
|
+
export function createFilesystemCandidatesLogModule(logPath = resolveCandidatesLogPath(process.cwd())) {
|
|
381
381
|
return {
|
|
382
382
|
readAll(options) {
|
|
383
383
|
if (!existsSync(logPath)) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout-aware triage working-set cache paths (#1703 namespace cleanup).
|
|
3
|
+
*
|
|
4
|
+
* Triage append-only logs and scratch dirs live under `.triage-cache/` so the
|
|
5
|
+
* `.eval/` namespace can be reclaimed for version-eval results (#1703 Tier 2).
|
|
6
|
+
*/
|
|
7
|
+
/** Directory name for the triage working-set cache (not version-eval results). */
|
|
8
|
+
export declare const TRIAGE_CACHE_DIR_NAME = ".triage-cache";
|
|
9
|
+
/** Legacy directory that previously held triage cache files before #1703. */
|
|
10
|
+
export declare const LEGACY_TRIAGE_EVAL_DIR_NAME = ".eval";
|
|
11
|
+
/** Known triage-cache file basenames migrated off the legacy `.eval/` tree. */
|
|
12
|
+
export declare const TRIAGE_CACHE_FILE_NAMES: readonly ["candidates.jsonl", "summary-history.jsonl", "scope-lifecycle.jsonl", "subscription-history.jsonl", "slices.jsonl", "doctor-state.json", "README.md"];
|
|
13
|
+
/** Known triage-cache directory names migrated off the legacy `.eval/` tree. */
|
|
14
|
+
export declare const TRIAGE_CACHE_DIR_NAMES: readonly ["decompositions"];
|
|
15
|
+
export interface TriageCacheMigrationResult {
|
|
16
|
+
readonly migratedFiles: readonly string[];
|
|
17
|
+
readonly skippedFiles: readonly string[];
|
|
18
|
+
readonly migratedDirs: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
/** Absolute path to the layout-aware `.triage-cache/` directory. */
|
|
21
|
+
export declare function resolveTriageCacheDir(projectRoot: string): string;
|
|
22
|
+
/** POSIX-style path relative to project root (e.g. `xbrief/.triage-cache/foo`). */
|
|
23
|
+
export declare function triageCacheRelPath(projectRoot: string, ...segments: string[]): string;
|
|
24
|
+
/**
|
|
25
|
+
* Idempotently move triage working-set artefacts from legacy `.eval/` into
|
|
26
|
+
* `.triage-cache/` when the new location is absent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function migrateLegacyTriageCacheFromEval(projectRoot: string): TriageCacheMigrationResult;
|
|
29
|
+
/** Resolve a path under `.triage-cache/`, migrating legacy `.eval/` files first. */
|
|
30
|
+
export declare function resolveTriageCachePath(projectRoot: string, ...segments: string[]): string;
|
|
31
|
+
/** Display helper: project-root-relative POSIX path for logs and gitignore copy. */
|
|
32
|
+
export declare function triageCacheDisplayPath(projectRoot: string, absPath: string): string;
|
|
33
|
+
/** Back-compat display constant; resolution flows through `resolveTriageCachePath`. */
|
|
34
|
+
export declare const TRIAGE_CANDIDATES_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
35
|
+
/** Layout-aware candidates audit-log path. */
|
|
36
|
+
export declare function resolveCandidatesLogPath(projectRoot: string): string;
|
|
37
|
+
/** Ensure the triage cache directory exists (post-migration). */
|
|
38
|
+
export declare function ensureTriageCacheDir(projectRoot: string): string;
|
|
39
|
+
//# sourceMappingURL=cache-path.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout-aware triage working-set cache paths (#1703 namespace cleanup).
|
|
3
|
+
*
|
|
4
|
+
* Triage append-only logs and scratch dirs live under `.triage-cache/` so the
|
|
5
|
+
* `.eval/` namespace can be reclaimed for version-eval results (#1703 Tier 2).
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, renameSync } from "node:fs";
|
|
8
|
+
import { join, relative } from "node:path";
|
|
9
|
+
import { resolveEvalDir, resolveLifecycleLayout, resolveLifecycleRoot } from "../layout/resolve.js";
|
|
10
|
+
/** Directory name for the triage working-set cache (not version-eval results). */
|
|
11
|
+
export const TRIAGE_CACHE_DIR_NAME = ".triage-cache";
|
|
12
|
+
/** Legacy directory that previously held triage cache files before #1703. */
|
|
13
|
+
export const LEGACY_TRIAGE_EVAL_DIR_NAME = ".eval";
|
|
14
|
+
/** Known triage-cache file basenames migrated off the legacy `.eval/` tree. */
|
|
15
|
+
export const TRIAGE_CACHE_FILE_NAMES = [
|
|
16
|
+
"candidates.jsonl",
|
|
17
|
+
"summary-history.jsonl",
|
|
18
|
+
"scope-lifecycle.jsonl",
|
|
19
|
+
"subscription-history.jsonl",
|
|
20
|
+
"slices.jsonl",
|
|
21
|
+
"doctor-state.json",
|
|
22
|
+
"README.md",
|
|
23
|
+
];
|
|
24
|
+
/** Known triage-cache directory names migrated off the legacy `.eval/` tree. */
|
|
25
|
+
export const TRIAGE_CACHE_DIR_NAMES = ["decompositions"];
|
|
26
|
+
/** Absolute path to the layout-aware `.triage-cache/` directory. */
|
|
27
|
+
export function resolveTriageCacheDir(projectRoot) {
|
|
28
|
+
return join(resolveLifecycleRoot(projectRoot), TRIAGE_CACHE_DIR_NAME);
|
|
29
|
+
}
|
|
30
|
+
/** POSIX-style path relative to project root (e.g. `xbrief/.triage-cache/foo`). */
|
|
31
|
+
export function triageCacheRelPath(projectRoot, ...segments) {
|
|
32
|
+
const layout = resolveLifecycleLayout(projectRoot);
|
|
33
|
+
return [layout.artifactDir, TRIAGE_CACHE_DIR_NAME, ...segments].join("/");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Idempotently move triage working-set artefacts from legacy `.eval/` into
|
|
37
|
+
* `.triage-cache/` when the new location is absent.
|
|
38
|
+
*/
|
|
39
|
+
export function migrateLegacyTriageCacheFromEval(projectRoot) {
|
|
40
|
+
const legacyDir = resolveEvalDir(projectRoot);
|
|
41
|
+
const targetDir = resolveTriageCacheDir(projectRoot);
|
|
42
|
+
const migratedFiles = [];
|
|
43
|
+
const skippedFiles = [];
|
|
44
|
+
const migratedDirs = [];
|
|
45
|
+
if (!existsSync(legacyDir)) {
|
|
46
|
+
return { migratedFiles, skippedFiles, migratedDirs };
|
|
47
|
+
}
|
|
48
|
+
mkdirSync(targetDir, { recursive: true });
|
|
49
|
+
for (const name of TRIAGE_CACHE_FILE_NAMES) {
|
|
50
|
+
const legacyPath = join(legacyDir, name);
|
|
51
|
+
const targetPath = join(targetDir, name);
|
|
52
|
+
if (!existsSync(legacyPath)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (existsSync(targetPath)) {
|
|
56
|
+
skippedFiles.push(name);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
renameSync(legacyPath, targetPath);
|
|
60
|
+
migratedFiles.push(name);
|
|
61
|
+
}
|
|
62
|
+
for (const name of TRIAGE_CACHE_DIR_NAMES) {
|
|
63
|
+
const legacyPath = join(legacyDir, name);
|
|
64
|
+
const targetPath = join(targetDir, name);
|
|
65
|
+
if (!existsSync(legacyPath)) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (existsSync(targetPath)) {
|
|
69
|
+
skippedFiles.push(`${name}/`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
renameSync(legacyPath, targetPath);
|
|
73
|
+
migratedDirs.push(name);
|
|
74
|
+
}
|
|
75
|
+
return { migratedFiles, skippedFiles, migratedDirs };
|
|
76
|
+
}
|
|
77
|
+
/** Resolve a path under `.triage-cache/`, migrating legacy `.eval/` files first. */
|
|
78
|
+
export function resolveTriageCachePath(projectRoot, ...segments) {
|
|
79
|
+
migrateLegacyTriageCacheFromEval(projectRoot);
|
|
80
|
+
return join(resolveTriageCacheDir(projectRoot), ...segments);
|
|
81
|
+
}
|
|
82
|
+
/** Display helper: project-root-relative POSIX path for logs and gitignore copy. */
|
|
83
|
+
export function triageCacheDisplayPath(projectRoot, absPath) {
|
|
84
|
+
return relative(projectRoot, absPath).split(/[\\/]/).join("/");
|
|
85
|
+
}
|
|
86
|
+
/** Back-compat display constant; resolution flows through `resolveTriageCachePath`. */
|
|
87
|
+
export const TRIAGE_CANDIDATES_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
88
|
+
/** Layout-aware candidates audit-log path. */
|
|
89
|
+
export function resolveCandidatesLogPath(projectRoot) {
|
|
90
|
+
return resolveTriageCachePath(projectRoot, "candidates.jsonl");
|
|
91
|
+
}
|
|
92
|
+
/** Ensure the triage cache directory exists (post-migration). */
|
|
93
|
+
export function ensureTriageCacheDir(projectRoot) {
|
|
94
|
+
const dir = resolveTriageCacheDir(projectRoot);
|
|
95
|
+
mkdirSync(dir, { recursive: true });
|
|
96
|
+
return dir;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=cache-path.js.map
|