@fenglimg/fabric-cli 2.2.0-rc.9 → 2.3.0-rc.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/README.md +2 -2
- package/dist/audit-PURSJJFH.js +734 -0
- package/dist/{chunk-YM4XATJF.js → chunk-722JU5BP.js} +2 -0
- package/dist/{chunk-QPAW6IYT.js → chunk-7V4XMLQ2.js} +3 -3
- package/dist/{chunk-7ZDXBOOU.js → chunk-ACSMNX3V.js} +44 -128
- package/dist/{chunk-PTGQAZEW.js → chunk-GGDVZCD6.js} +2 -4
- package/dist/{chunk-EOT63RDH.js → chunk-I5F5BHWI.js} +9 -0
- package/dist/chunk-PP7QVRXH.js +565 -0
- package/dist/chunk-SL77FXX7.js +54 -0
- package/dist/{chunk-3D7B2UAZ.js → chunk-VQKXTMWH.js} +44 -4
- package/dist/doctor-S6KPGS35.js +27 -0
- package/dist/index.js +91 -81
- package/dist/{info-7FKBTMVO.js → info-NJEY26H6.js} +91 -46
- package/dist/{context-7NUKXDB6.js → inspect-5YZMJPFM.js} +11 -11
- package/dist/{install-v2-I6PJ6IFT.js → install-v2-KGIDII4H.js} +163 -364
- package/dist/{plan-context-hint-G75R4P4J.js → plan-context-hint-5TNGH3R4.js} +1 -1
- package/dist/{store-HOCORVL3.js → store-GF4SFBMJ.js} +155 -57
- package/dist/{sync-DT5UJMMR.js → sync-3XCIRDPK.js} +3 -4
- package/dist/{uninstall-IFN2KYBK.js → uninstall-BG4ML4FC.js} +39 -10
- package/package.json +3 -7
- package/templates/hooks/cite-policy-evict.cjs +1 -1
- package/templates/hooks/configs/claude-code.json +1 -5
- package/templates/hooks/configs/codex-hooks.json +1 -5
- package/templates/hooks/fabric-hint.cjs +346 -138
- package/templates/hooks/knowledge-hint-broad.cjs +265 -75
- package/templates/hooks/knowledge-hint-narrow.cjs +3 -3
- package/templates/hooks/knowledge-pretooluse.cjs +111 -0
- package/templates/hooks/lib/banner-i18n.cjs +31 -12
- package/templates/hooks/lib/bindings-snapshot-reader.cjs +1 -1
- package/templates/hooks/lib/event-writer.cjs +79 -0
- package/templates/hooks/lib/nudge-policy.cjs +11 -0
- package/templates/hooks/lib/theme.cjs +62 -0
- package/templates/hooks/post-tooluse-mutation.cjs +28 -39
- package/templates/skills/fabric-archive/SKILL.md +43 -12
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +5 -5
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -2
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-classify.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +6 -5
- package/templates/skills/{fabric-import/ref/checkpoint-state.md → fabric-archive/ref/source-checkpoint.md} +3 -3
- package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md} +4 -4
- package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md} +20 -20
- package/templates/skills/{fabric-import/ref/output-contract.md → fabric-archive/ref/source-output-contract.md} +3 -3
- package/templates/skills/{fabric-import/ref/state-recovery.md → fabric-archive/ref/source-state-recovery.md} +2 -2
- package/templates/skills/{fabric-import/ref/worked-examples.md → fabric-archive/ref/source-worked-examples.md} +10 -10
- package/templates/skills/fabric-archive/ref/worked-examples.md +3 -3
- package/templates/skills/fabric-review/SKILL.md +28 -15
- package/templates/skills/fabric-review/ref/cite-contract.md +2 -2
- package/templates/skills/fabric-review/ref/modify-flow.md +13 -1
- package/templates/skills/fabric-review/ref/per-mode-flows.md +5 -5
- package/templates/skills/fabric-review/ref/relate-mode.md +33 -0
- package/templates/skills/fabric-review/ref/retire-mode.md +47 -0
- package/templates/skills/fabric-review/ref/semantic-check.md +1 -1
- package/templates/skills/fabric-review/ref/worked-examples.md +5 -5
- package/templates/skills/fabric-store/SKILL.md +12 -27
- package/templates/skills/fabric-sync/SKILL.md +16 -35
- package/templates/skills/lib/shared-policy.md +6 -4
- package/dist/chunk-27HK6H5Y.js +0 -69
- package/dist/chunk-E7HJUU34.js +0 -1096
- package/dist/chunk-NLNH64A3.js +0 -43
- package/dist/chunk-QFIVFZRH.js +0 -13
- package/dist/doctor-MDTZWKBK.js +0 -24
- package/dist/metrics-HMFH4YHK.js +0 -135
- package/dist/scope-explain-HLJZ2M33.js +0 -48
- package/dist/status-4R3TM4FJ.js +0 -37
- package/dist/whoami-ITGEFWH4.js +0 -49
- package/templates/skills/fabric/SKILL.md +0 -100
- package/templates/skills/fabric-audit/SKILL.md +0 -63
- package/templates/skills/fabric-connect/SKILL.md +0 -48
- package/templates/skills/fabric-import/SKILL.md +0 -151
- package/templates/skills/fabric-import/ref/i18n-policy.md +0 -78
|
@@ -0,0 +1,734 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveDevMode
|
|
4
|
+
} from "./chunk-WA3DYGSY.js";
|
|
5
|
+
import {
|
|
6
|
+
paint,
|
|
7
|
+
symbol
|
|
8
|
+
} from "./chunk-SL77FXX7.js";
|
|
9
|
+
import {
|
|
10
|
+
getDoctorTranslator,
|
|
11
|
+
getProjectTranslator
|
|
12
|
+
} from "./chunk-HORSMSZL.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/audit.ts
|
|
15
|
+
import { defineCommand as defineCommand2 } from "citty";
|
|
16
|
+
import {
|
|
17
|
+
enrichDescriptions,
|
|
18
|
+
explainWhyNotSurfaced,
|
|
19
|
+
inspectRetiredReferences,
|
|
20
|
+
runDoctorArchiveHistory,
|
|
21
|
+
runDoctorCiteCoverage,
|
|
22
|
+
runDoctorConflictLint,
|
|
23
|
+
runDoctorHistoryAll
|
|
24
|
+
} from "@fenglimg/fabric-server";
|
|
25
|
+
|
|
26
|
+
// src/commands/metrics.ts
|
|
27
|
+
import { resolve } from "path";
|
|
28
|
+
import { defineCommand } from "citty";
|
|
29
|
+
import { readMetrics } from "@fenglimg/fabric-server";
|
|
30
|
+
function parseSinceArg(raw, t2) {
|
|
31
|
+
if (raw === void 0 || raw.length === 0) return 0;
|
|
32
|
+
const match = /^(\d+)([smhd]?)$/u.exec(raw);
|
|
33
|
+
if (match === null) {
|
|
34
|
+
throw new Error(t2("cli.metrics.invalid-since", { raw }));
|
|
35
|
+
}
|
|
36
|
+
const n = Number.parseInt(match[1], 10);
|
|
37
|
+
const unit = match[2] ?? "s";
|
|
38
|
+
const multipliers = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
|
|
39
|
+
return n * (multipliers[unit] ?? 1e3);
|
|
40
|
+
}
|
|
41
|
+
function aggregate(rows, sinceMs, now) {
|
|
42
|
+
const cutoff = sinceMs > 0 ? now.getTime() - sinceMs : 0;
|
|
43
|
+
const filtered = rows.filter((r) => {
|
|
44
|
+
if (cutoff === 0) return true;
|
|
45
|
+
const ts = Date.parse(r.timestamp);
|
|
46
|
+
return Number.isFinite(ts) && ts >= cutoff;
|
|
47
|
+
});
|
|
48
|
+
const totals = {};
|
|
49
|
+
const perEntryConsumed = {};
|
|
50
|
+
for (const row of filtered) {
|
|
51
|
+
for (const [name, count] of Object.entries(row.counters)) {
|
|
52
|
+
if (name.startsWith("knowledge_consumed:")) {
|
|
53
|
+
const id = name.slice("knowledge_consumed:".length);
|
|
54
|
+
perEntryConsumed[id] = (perEntryConsumed[id] ?? 0) + count;
|
|
55
|
+
totals["knowledge_consumed"] = (totals["knowledge_consumed"] ?? 0) + count;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
totals[name] = (totals[name] ?? 0) + count;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
// Stable token (NOT localized) so the --json contract is locale-independent;
|
|
63
|
+
// renderText localizes "all-time" at presentation time only.
|
|
64
|
+
windowDescription: sinceMs > 0 ? formatDuration(sinceMs) : "all-time",
|
|
65
|
+
rowCount: filtered.length,
|
|
66
|
+
totals,
|
|
67
|
+
perEntryConsumed,
|
|
68
|
+
rangeStart: filtered[0]?.timestamp ?? null,
|
|
69
|
+
rangeEnd: filtered[filtered.length - 1]?.timestamp ?? null
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function formatDuration(ms) {
|
|
73
|
+
if (ms >= 864e5) return `${Math.round(ms / 864e5)}d`;
|
|
74
|
+
if (ms >= 36e5) return `${Math.round(ms / 36e5)}h`;
|
|
75
|
+
if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
|
|
76
|
+
return `${Math.round(ms / 1e3)}s`;
|
|
77
|
+
}
|
|
78
|
+
function renderText(agg, t2) {
|
|
79
|
+
const lines = [];
|
|
80
|
+
const windowDisplay = agg.windowDescription === "all-time" ? t2("cli.metrics.window-all-time") : agg.windowDescription;
|
|
81
|
+
lines.push(t2("cli.metrics.window", { window: windowDisplay }));
|
|
82
|
+
if (agg.rangeStart && agg.rangeEnd) {
|
|
83
|
+
lines.push(
|
|
84
|
+
t2("cli.metrics.rows-range", {
|
|
85
|
+
count: String(agg.rowCount),
|
|
86
|
+
start: agg.rangeStart,
|
|
87
|
+
end: agg.rangeEnd
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
} else {
|
|
91
|
+
lines.push(t2("cli.metrics.rows", { count: String(agg.rowCount) }));
|
|
92
|
+
}
|
|
93
|
+
lines.push("");
|
|
94
|
+
if (Object.keys(agg.totals).length === 0) {
|
|
95
|
+
lines.push(t2("cli.metrics.no-activity"));
|
|
96
|
+
return lines.join("\n");
|
|
97
|
+
}
|
|
98
|
+
lines.push(" counter total");
|
|
99
|
+
lines.push(" ------------------------------------ ----------");
|
|
100
|
+
const sorted = Object.entries(agg.totals).sort((a, b) => b[1] - a[1]);
|
|
101
|
+
for (const [name, count] of sorted) {
|
|
102
|
+
lines.push(` ${name.padEnd(36)} ${String(count).padStart(10)}`);
|
|
103
|
+
}
|
|
104
|
+
const perEntrySorted = Object.entries(agg.perEntryConsumed).sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
105
|
+
if (perEntrySorted.length > 0) {
|
|
106
|
+
lines.push("");
|
|
107
|
+
lines.push(" Top per-entry consumed (knowledge_consumed:<id>)");
|
|
108
|
+
lines.push(" ------------------------------------ ----------");
|
|
109
|
+
for (const [id, count] of perEntrySorted) {
|
|
110
|
+
lines.push(` ${id.padEnd(36)} ${String(count).padStart(10)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return lines.join("\n");
|
|
114
|
+
}
|
|
115
|
+
var metricsCommand = defineCommand({
|
|
116
|
+
meta: {
|
|
117
|
+
name: "metrics",
|
|
118
|
+
description: "Print a text dashboard of Fabric counter activity from .fabric/metrics.jsonl",
|
|
119
|
+
hidden: true
|
|
120
|
+
},
|
|
121
|
+
args: {
|
|
122
|
+
json: {
|
|
123
|
+
type: "boolean",
|
|
124
|
+
description: "Emit machine-readable JSON instead of the text table.",
|
|
125
|
+
default: false
|
|
126
|
+
},
|
|
127
|
+
target: {
|
|
128
|
+
type: "string",
|
|
129
|
+
description: "Project root (defaults to the current working directory)."
|
|
130
|
+
},
|
|
131
|
+
since: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Limit to rows within a recent window. Examples: 24h, 7d, 30m, 90s. Omit for all-time."
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
async run({ args }) {
|
|
137
|
+
const projectRoot = resolve(args.target ?? process.cwd());
|
|
138
|
+
const t2 = getProjectTranslator(projectRoot);
|
|
139
|
+
const sinceMs = parseSinceArg(args.since, t2);
|
|
140
|
+
const rows = await readMetrics(projectRoot);
|
|
141
|
+
const aggregated = aggregate(rows, sinceMs, /* @__PURE__ */ new Date());
|
|
142
|
+
if (args.json === true) {
|
|
143
|
+
process.stdout.write(`${JSON.stringify(aggregated)}
|
|
144
|
+
`);
|
|
145
|
+
} else {
|
|
146
|
+
process.stdout.write(`${renderText(aggregated, t2)}
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
var metrics_default = metricsCommand;
|
|
152
|
+
|
|
153
|
+
// src/commands/audit.ts
|
|
154
|
+
function writeStdout(message) {
|
|
155
|
+
process.stdout.write(`${message}
|
|
156
|
+
`);
|
|
157
|
+
}
|
|
158
|
+
function writeStderr(message) {
|
|
159
|
+
process.stderr.write(`${message}
|
|
160
|
+
`);
|
|
161
|
+
}
|
|
162
|
+
function parseSinceDuration(input) {
|
|
163
|
+
const trimmed = input.trim();
|
|
164
|
+
if (trimmed.length === 0) {
|
|
165
|
+
throw new Error(`invalid --since value: ${input}`);
|
|
166
|
+
}
|
|
167
|
+
const durationMatch = /^(\d+)([dhm])$/.exec(trimmed);
|
|
168
|
+
if (durationMatch !== null) {
|
|
169
|
+
const value = Number.parseInt(durationMatch[1], 10);
|
|
170
|
+
const unit = durationMatch[2];
|
|
171
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
172
|
+
throw new Error(`invalid --since value: ${input}`);
|
|
173
|
+
}
|
|
174
|
+
const unitMs = unit === "d" ? 864e5 : unit === "h" ? 36e5 : 6e4;
|
|
175
|
+
return Date.now() - value * unitMs;
|
|
176
|
+
}
|
|
177
|
+
if (/^\d+$/.test(trimmed)) {
|
|
178
|
+
const value = Number.parseInt(trimmed, 10);
|
|
179
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
180
|
+
throw new Error(`invalid --since value: ${input}`);
|
|
181
|
+
}
|
|
182
|
+
return value;
|
|
183
|
+
}
|
|
184
|
+
throw new Error(`invalid --since value: ${input}`);
|
|
185
|
+
}
|
|
186
|
+
var CITE_COVERAGE_CLIENT_FILTERS = /* @__PURE__ */ new Set([
|
|
187
|
+
"cc",
|
|
188
|
+
"codex",
|
|
189
|
+
"all"
|
|
190
|
+
]);
|
|
191
|
+
function isValidClientFilter(input) {
|
|
192
|
+
return CITE_COVERAGE_CLIENT_FILTERS.has(input);
|
|
193
|
+
}
|
|
194
|
+
var CITE_COVERAGE_LAYER_FILTERS = /* @__PURE__ */ new Set([
|
|
195
|
+
"team",
|
|
196
|
+
"personal",
|
|
197
|
+
"all"
|
|
198
|
+
]);
|
|
199
|
+
function isValidLayerFilter(input) {
|
|
200
|
+
return CITE_COVERAGE_LAYER_FILTERS.has(input);
|
|
201
|
+
}
|
|
202
|
+
function renderCiteCoverageReport(report, jsonMode, dt) {
|
|
203
|
+
if (jsonMode) {
|
|
204
|
+
writeStdout(JSON.stringify(report, null, 2));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (report.status === "skipped") {
|
|
208
|
+
writeStdout(dt("doctor.cite.status.skipped"));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const lines = [];
|
|
212
|
+
lines.push(dt("doctor.section.cite-coverage"));
|
|
213
|
+
lines.push(
|
|
214
|
+
dt("doctor.cite.header", {
|
|
215
|
+
since: new Date(report.since_ts).toISOString(),
|
|
216
|
+
marker: new Date(report.marker_ts).toISOString()
|
|
217
|
+
})
|
|
218
|
+
);
|
|
219
|
+
if (report.marker_emitted_now) {
|
|
220
|
+
lines.push(dt("doctor.cite.warning.justActivated"));
|
|
221
|
+
}
|
|
222
|
+
lines.push("");
|
|
223
|
+
lines.push(` ${dt("doctor.cite.metric.editsTouched")}: ${report.metrics.edits_touched}`);
|
|
224
|
+
lines.push(` ${dt("doctor.cite.metric.qualifyingCites")}: ${report.metrics.qualifying_cites}`);
|
|
225
|
+
lines.push(` ${dt("doctor.cite.metric.recalledUnverified")}: ${report.metrics.recalled_unverified}`);
|
|
226
|
+
lines.push(` ${dt("doctor.cite.metric.expectedButMissed")}: ${report.metrics.expected_but_missed}`);
|
|
227
|
+
lines.push(` ${dt("doctor.cite.metric.totalTurns")}: ${report.metrics.total_turns}`);
|
|
228
|
+
const complianceRate = report.metrics.cite_compliance_rate;
|
|
229
|
+
const complianceStr = complianceRate === null || complianceRate === void 0 ? dt("doctor.cite.metric.complianceNA") : `${(complianceRate * 100).toFixed(1)}% (${report.metrics.compliant_cites ?? 0}/${(report.metrics.compliant_cites ?? 0) + (report.metrics.noncompliant_cites ?? 0)})`;
|
|
230
|
+
lines.push(` ${dt("doctor.cite.metric.complianceRate")}: ${complianceStr}`);
|
|
231
|
+
const recallRate = report.metrics.recall_coverage_rate;
|
|
232
|
+
const recallStr = recallRate === null || recallRate === void 0 ? dt("doctor.cite.metric.recallCoverageNA") : `${(recallRate * 100).toFixed(1)}% (${report.metrics.recall_backed_edits ?? 0}/${report.metrics.edits_touched})`;
|
|
233
|
+
lines.push(` ${dt("doctor.cite.metric.recallCoverage")}: ${recallStr}`);
|
|
234
|
+
const uncorrelatable = report.metrics.uncorrelatable_edits ?? 0;
|
|
235
|
+
if (uncorrelatable > 0) {
|
|
236
|
+
lines.push(` ${dt("doctor.cite.metric.uncorrelatableEdits")}: ${uncorrelatable}`);
|
|
237
|
+
}
|
|
238
|
+
if (report.metrics.exposed_and_mutated !== void 0) {
|
|
239
|
+
lines.push(
|
|
240
|
+
` ${dt("doctor.cite.metric.exposedAndMutated")}: ${report.metrics.exposed_and_mutated.count}`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (report.metrics.mutations_observed !== void 0) {
|
|
244
|
+
lines.push(
|
|
245
|
+
` ${dt("doctor.cite.metric.mutationsObserved")}: ${report.metrics.mutations_observed.count}`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
if (report.metrics.mutation_pool !== void 0) {
|
|
249
|
+
lines.push(
|
|
250
|
+
` ${dt("doctor.cite.metric.mutationPool")}: ${report.metrics.mutation_pool.attributed} / ${report.metrics.mutation_pool.unattributed_workspace_dirty} (attributed / unattributed_workspace_dirty)`
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (report.metrics.sessions_closed !== void 0) {
|
|
254
|
+
lines.push(
|
|
255
|
+
` ${dt("doctor.cite.metric.sessionsClosed")}: ${report.metrics.sessions_closed.count}`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
if (report.metrics.by_store !== void 0) {
|
|
259
|
+
const storeKeys = Object.keys(report.metrics.by_store).sort();
|
|
260
|
+
if (storeKeys.length > 0) {
|
|
261
|
+
lines.push(` ${dt("doctor.cite.metric.byStore")}:`);
|
|
262
|
+
for (const store of storeKeys) {
|
|
263
|
+
lines.push(` ${store}: ${report.metrics.by_store[store].qualifying_cites}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (report.per_client !== void 0 && Object.keys(report.per_client).length > 1) {
|
|
268
|
+
lines.push("");
|
|
269
|
+
lines.push(`### ${dt("doctor.cite.section.perClient")}`);
|
|
270
|
+
for (const [client, metrics] of Object.entries(report.per_client)) {
|
|
271
|
+
const summary = Object.entries(metrics).map(([k, v]) => `${k}=${v}`).join(" / ");
|
|
272
|
+
lines.push(` ${client}: ${summary}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (report.dismissed_reason_histogram !== void 0 && Object.keys(report.dismissed_reason_histogram).length > 0) {
|
|
276
|
+
lines.push("");
|
|
277
|
+
lines.push(`### ${dt("doctor.cite.section.dismissedReasons")}`);
|
|
278
|
+
for (const [reason, count] of Object.entries(report.dismissed_reason_histogram)) {
|
|
279
|
+
const label = dt(`doctor.cite.dismissed.${reason}`);
|
|
280
|
+
lines.push(` ${label}: ${count}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (report.none_reason_histogram !== void 0 && Object.keys(report.none_reason_histogram).length > 0) {
|
|
284
|
+
lines.push("");
|
|
285
|
+
lines.push(`### ${dt("doctor.cite.section.noneReasons")}`);
|
|
286
|
+
for (const [reason, count] of Object.entries(report.none_reason_histogram)) {
|
|
287
|
+
const label = dt(`doctor.cite.none.${reason}`);
|
|
288
|
+
lines.push(` ${label}: ${count}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
appendContractSection(lines, report, dt);
|
|
292
|
+
writeStdout(lines.join("\n"));
|
|
293
|
+
}
|
|
294
|
+
function appendContractSection(lines, report, dt) {
|
|
295
|
+
const status = report.contract_metrics_status;
|
|
296
|
+
if (status === void 0) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const metrics = report.contract_metrics;
|
|
300
|
+
const perLayerType = report.per_layer_type;
|
|
301
|
+
const allCountsZero = metrics === void 0 || metrics.decisions_cited === 0 && metrics.pitfalls_cited === 0 && metrics.contract_with === 0 && metrics.contract_missing === 0 && metrics.hard_violated === 0 && metrics.cite_id_unresolved === 0 && Object.keys(metrics.skip_count).length === 0;
|
|
302
|
+
if (status === "awaiting_marker" && allCountsZero) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
lines.push("");
|
|
306
|
+
lines.push(`### ${dt("cite-coverage.contract.header")}`);
|
|
307
|
+
if (status === "skipped:bootstrap_drift") {
|
|
308
|
+
lines.push(` ${dt("cite-coverage.contract.status.skipped_bootstrap_drift")}`);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const statusKey = status === "ok" ? "cite-coverage.contract.status.ok" : "cite-coverage.contract.status.awaiting_marker";
|
|
312
|
+
lines.push(` status: ${dt(statusKey)}`);
|
|
313
|
+
if (typeof report.contract_marker_ts === "number" && report.contract_marker_ts > 0) {
|
|
314
|
+
lines.push(` since: ${new Date(report.contract_marker_ts).toISOString()}`);
|
|
315
|
+
}
|
|
316
|
+
if (report.layer_filter !== void 0) {
|
|
317
|
+
lines.push(` layer filter: ${report.layer_filter}`);
|
|
318
|
+
}
|
|
319
|
+
if (metrics !== void 0) {
|
|
320
|
+
lines.push(` ${dt("cite-coverage.contract.decisions_cited")}: ${metrics.decisions_cited}`);
|
|
321
|
+
lines.push(` ${dt("cite-coverage.contract.pitfalls_cited")}: ${metrics.pitfalls_cited}`);
|
|
322
|
+
lines.push(` ${dt("cite-coverage.contract.with")}: ${metrics.contract_with}`);
|
|
323
|
+
lines.push(` ${dt("cite-coverage.contract.missing")}: ${metrics.contract_missing}`);
|
|
324
|
+
if (metrics.hard_violated > 0) {
|
|
325
|
+
const layerSuffix = report.layer_filter === "personal" ? dt("cite-coverage.layer.personal_fyi") : dt("cite-coverage.layer.team_review");
|
|
326
|
+
lines.push(
|
|
327
|
+
` ${dt("cite-coverage.contract.hard_violated")} ${layerSuffix}: ${metrics.hard_violated}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (perLayerType !== void 0) {
|
|
332
|
+
const teamKeys = Object.keys(perLayerType.team).filter((k) => perLayerType.team[k] > 0);
|
|
333
|
+
const personalKeys = Object.keys(perLayerType.personal).filter(
|
|
334
|
+
(k) => perLayerType.personal[k] > 0
|
|
335
|
+
);
|
|
336
|
+
if (teamKeys.length > 0 || personalKeys.length > 0) {
|
|
337
|
+
lines.push("");
|
|
338
|
+
lines.push(`#### ${dt("cite-coverage.layer.team")} \xD7 ${dt("cite-coverage.layer.personal")}`);
|
|
339
|
+
for (const key of teamKeys) {
|
|
340
|
+
const label = dt(`cite-coverage.contract.type.${key}`);
|
|
341
|
+
lines.push(` ${dt("cite-coverage.layer.team")} \u2014 ${label}: ${perLayerType.team[key]}`);
|
|
342
|
+
}
|
|
343
|
+
for (const key of personalKeys) {
|
|
344
|
+
const label = dt(`cite-coverage.contract.type.${key}`);
|
|
345
|
+
lines.push(
|
|
346
|
+
` ${dt("cite-coverage.layer.personal")} \u2014 ${label}: ${perLayerType.personal[key]}`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (metrics !== void 0 && Object.keys(metrics.skip_count).length > 0) {
|
|
352
|
+
lines.push("");
|
|
353
|
+
lines.push(`#### ${dt("cite-coverage.contract.skip_count")}`);
|
|
354
|
+
for (const [reason, count] of Object.entries(metrics.skip_count)) {
|
|
355
|
+
const label = dt(`cite-coverage.skip.${reason}`);
|
|
356
|
+
lines.push(` ${label}: ${count}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (metrics !== void 0 && metrics.cite_id_unresolved > 0) {
|
|
360
|
+
lines.push("");
|
|
361
|
+
lines.push(
|
|
362
|
+
`${symbol.warn} ${dt("cite-coverage.contract.cite_id_unresolved")}: ${metrics.cite_id_unresolved}`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function renderConflictLintReport(report, deepRequested, dt) {
|
|
367
|
+
const lines = [];
|
|
368
|
+
lines.push(dt("doctor.conflict.header"));
|
|
369
|
+
lines.push("");
|
|
370
|
+
if (report.candidate_count === 0) {
|
|
371
|
+
lines.push(` ${symbol.ok} ${dt("doctor.conflict.none")}`);
|
|
372
|
+
writeStdout(lines.join("\n"));
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
lines.push(
|
|
376
|
+
` ${dt("doctor.conflict.summary", {
|
|
377
|
+
candidates: String(report.candidate_count),
|
|
378
|
+
conflicts: String(report.conflict_count),
|
|
379
|
+
threshold: report.threshold.toFixed(2)
|
|
380
|
+
})}`
|
|
381
|
+
);
|
|
382
|
+
if (deepRequested && !report.deep) {
|
|
383
|
+
lines.push(` ${symbol.warn} ${dt("doctor.conflict.deep_no_judge")}`);
|
|
384
|
+
}
|
|
385
|
+
lines.push("");
|
|
386
|
+
for (const pair of report.pairs) {
|
|
387
|
+
const sym = pair.verdict === "conflict" ? symbol.error : symbol.warn;
|
|
388
|
+
const verdictLabel = dt(`doctor.conflict.verdict.${pair.verdict}`);
|
|
389
|
+
const pct = `${(pair.similarity * 100).toFixed(0)}%`;
|
|
390
|
+
let line = ` ${sym} [${pair.a} \u2194 ${pair.b}] (${pair.knowledge_type}/${pair.layer}) ${pct} \u2014 ${verdictLabel}`;
|
|
391
|
+
if (pair.rationale !== void 0 && pair.rationale.length > 0) {
|
|
392
|
+
line += `: ${pair.rationale}`;
|
|
393
|
+
}
|
|
394
|
+
lines.push(line);
|
|
395
|
+
}
|
|
396
|
+
writeStdout(lines.join("\n"));
|
|
397
|
+
}
|
|
398
|
+
function renderEnrichDescriptionsReport(report, dt) {
|
|
399
|
+
const header = `${symbol.ok} ${paint.ai("fabric audit descriptions")} mode=${report.mode}${report.dryRun ? " (dry-run)" : ""} scanned=${report.scanned} modified=${report.modified} skipped=${report.skipped}`;
|
|
400
|
+
writeStdout(header);
|
|
401
|
+
if (report.candidates.length === 0) {
|
|
402
|
+
writeStdout(dt("doctor.enrich.allComplete"));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
writeStdout("");
|
|
406
|
+
for (const candidate of report.candidates) {
|
|
407
|
+
if (candidate.error !== void 0) {
|
|
408
|
+
writeStdout(`${symbol.error} ${candidate.path} \u2014 ${candidate.error}`);
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
const missing = candidate.missing.join(", ");
|
|
412
|
+
if (candidate.modified) {
|
|
413
|
+
const added = candidate.added_fields.join(", ");
|
|
414
|
+
writeStdout(`${symbol.ok} ${candidate.path} \u2014 missing: ${missing} \u2192 added: ${added}`);
|
|
415
|
+
} else {
|
|
416
|
+
writeStdout(`${symbol.warn} ${candidate.path} \u2014 missing: ${missing}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function renderArchiveHistoryReport(report, sinceLabel, dt) {
|
|
421
|
+
if (report.entries.length === 0) {
|
|
422
|
+
writeStdout(dt("doctor.archive-history.empty", { sinceLabel }));
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const lines = [];
|
|
426
|
+
lines.push(
|
|
427
|
+
dt("doctor.archive-history.header", {
|
|
428
|
+
sinceLabel,
|
|
429
|
+
count: String(report.total),
|
|
430
|
+
plural: report.total === 1 ? "" : "s"
|
|
431
|
+
})
|
|
432
|
+
);
|
|
433
|
+
lines.push("");
|
|
434
|
+
lines.push(
|
|
435
|
+
`| ${dt("doctor.archive-history.table.session")} | ${dt(
|
|
436
|
+
"doctor.archive-history.table.lastAttempt"
|
|
437
|
+
)} | ${dt("doctor.archive-history.table.outcome")} | ${dt(
|
|
438
|
+
"doctor.archive-history.table.candidates"
|
|
439
|
+
)} | ${dt("doctor.archive-history.table.coveredGap")} |`
|
|
440
|
+
);
|
|
441
|
+
lines.push("| ------- | ---------------- | -------- | ---------- | ----------- |");
|
|
442
|
+
for (const entry of report.entries) {
|
|
443
|
+
const lastAttempt = formatTimestampForTable(entry.last_attempted_at);
|
|
444
|
+
lines.push(
|
|
445
|
+
`| ${entry.session_id_short} | ${lastAttempt} | ${entry.outcome} | ${entry.candidates_proposed} | ${entry.age_since_covered_hours}h |`
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
writeStdout(lines.join("\n"));
|
|
449
|
+
}
|
|
450
|
+
function renderHistoryAllReport(report, sinceLabel, mode, dt) {
|
|
451
|
+
if (report.rows.length === 0) {
|
|
452
|
+
writeStdout(dt("doctor.history.empty", { sinceLabel, mode }));
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const lines = [];
|
|
456
|
+
lines.push(
|
|
457
|
+
dt("doctor.history.header", {
|
|
458
|
+
sinceLabel,
|
|
459
|
+
mode,
|
|
460
|
+
days: String(report.rows.length)
|
|
461
|
+
})
|
|
462
|
+
);
|
|
463
|
+
lines.push("");
|
|
464
|
+
if (mode === "fix") {
|
|
465
|
+
lines.push("| date | lint | fix | issues | mutations |");
|
|
466
|
+
lines.push("| ---------- | ---- | --- | ------ | --------- |");
|
|
467
|
+
for (const row of report.rows) {
|
|
468
|
+
lines.push(
|
|
469
|
+
`| ${row.date} | ${row.doctor_runs_lint} | ${row.doctor_runs_fix} | ${row.doctor_total_issues} | ${row.doctor_total_mutations} |`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
lines.push("| date | lint | fix | issues | mutations | archive | proposed |");
|
|
474
|
+
lines.push("| ---------- | ---- | --- | ------ | --------- | ------- | -------- |");
|
|
475
|
+
for (const row of report.rows) {
|
|
476
|
+
lines.push(
|
|
477
|
+
`| ${row.date} | ${row.doctor_runs_lint} | ${row.doctor_runs_fix} | ${row.doctor_total_issues} | ${row.doctor_total_mutations} | ${row.archive_attempts} | ${row.archive_proposed} |`
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
writeStdout(lines.join("\n"));
|
|
482
|
+
}
|
|
483
|
+
function formatTimestampForTable(iso) {
|
|
484
|
+
const d = new Date(iso);
|
|
485
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
486
|
+
const pad = (n) => n < 10 ? `0${n}` : `${n}`;
|
|
487
|
+
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(
|
|
488
|
+
d.getUTCHours()
|
|
489
|
+
)}:${pad(d.getUTCMinutes())}`;
|
|
490
|
+
}
|
|
491
|
+
function renderRetiredReport(inspection) {
|
|
492
|
+
if (inspection.status === "skipped") {
|
|
493
|
+
writeStdout(`${symbol.warn} retired-reference scan skipped \u2014 no agent-consumed surfaces found.`);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (inspection.hits.length === 0) {
|
|
497
|
+
writeStdout(
|
|
498
|
+
`${symbol.ok} no retired references \u2014 scanned ${inspection.scannedFiles} agent surface(s).`
|
|
499
|
+
);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
writeStdout(
|
|
503
|
+
`${symbol.error} ${inspection.hits.length} retired reference(s) across ${inspection.scannedFiles} scanned file(s):`
|
|
504
|
+
);
|
|
505
|
+
for (const hit of inspection.hits) {
|
|
506
|
+
const fix = hit.replacement === null ? "(removed)" : `\u2192 ${hit.replacement}`;
|
|
507
|
+
writeStdout(` ${hit.path}:${hit.line} ${hit.token} ${fix}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
function renderWhyNotSurfaced(r) {
|
|
511
|
+
const id = r.localId;
|
|
512
|
+
switch (r.verdict) {
|
|
513
|
+
case "not_found":
|
|
514
|
+
writeStdout(
|
|
515
|
+
`${symbol.error} '${id}' not found in any mounted store. Check the id (try \`fabric store list\`).`
|
|
516
|
+
);
|
|
517
|
+
return;
|
|
518
|
+
case "store_unbound":
|
|
519
|
+
writeStdout(
|
|
520
|
+
`${symbol.error} '${id}' lives in store '${r.storeAlias}', which is NOT bound to this project.`
|
|
521
|
+
);
|
|
522
|
+
writeStdout(` \u2192 bind it: fabric store bind ${r.storeAlias}`);
|
|
523
|
+
return;
|
|
524
|
+
case "project_mismatch":
|
|
525
|
+
writeStdout(
|
|
526
|
+
`${symbol.error} '${id}' is scoped to '${r.semanticScope}', but this repo is bound to 'project:${r.activeProject}'.`
|
|
527
|
+
);
|
|
528
|
+
writeStdout(` \u2192 it surfaces only in repos bound to '${r.semanticScope}' (semantic_scope axis).`);
|
|
529
|
+
return;
|
|
530
|
+
case "narrow_timing":
|
|
531
|
+
writeStdout(
|
|
532
|
+
`${symbol.warn} '${id}' is relevance_scope=narrow \u2014 it surfaces via the PreToolUse hint when you EDIT a matching file, not at SessionStart.`
|
|
533
|
+
);
|
|
534
|
+
writeStdout(` \u2192 broad entries are the always-on spine; narrow ones are edit-time only (timing axis).`);
|
|
535
|
+
return;
|
|
536
|
+
case "should_surface":
|
|
537
|
+
writeStdout(
|
|
538
|
+
`${symbol.ok} '${id}' should be surfacing \u2014 store '${r.storeAlias}' bound, scope matches, relevance_scope=broad.`
|
|
539
|
+
);
|
|
540
|
+
writeStdout(` \u2192 if it isn't, the SessionStart snapshot may be stale: start a fresh session or re-run \`fabric install\`.`);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
var whyNotSurfacedCommand = defineCommand2({
|
|
545
|
+
meta: {
|
|
546
|
+
name: "why-not-surfaced",
|
|
547
|
+
description: "Diagnose why a knowledge entry isn't surfacing (store / scope / timing)"
|
|
548
|
+
},
|
|
549
|
+
args: {
|
|
550
|
+
id: { type: "positional", required: true, description: "Knowledge id (e.g. KT-DEC-0001 or team:KT-DEC-0001)" },
|
|
551
|
+
target: { type: "string", description: "Override project root (defaults to cwd)" },
|
|
552
|
+
json: { type: "boolean", description: "Output as JSON", default: false }
|
|
553
|
+
},
|
|
554
|
+
async run({ args }) {
|
|
555
|
+
const resolution = resolveDevMode(args.target, process.cwd());
|
|
556
|
+
const result = await explainWhyNotSurfaced(resolution.target, String(args.id));
|
|
557
|
+
if (args.json === true) {
|
|
558
|
+
writeStdout(JSON.stringify(result, null, 2));
|
|
559
|
+
} else {
|
|
560
|
+
renderWhyNotSurfaced(result);
|
|
561
|
+
}
|
|
562
|
+
if (result.verdict === "not_found") {
|
|
563
|
+
process.exitCode = 1;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
var citeCommand = defineCommand2({
|
|
568
|
+
meta: { name: "cite", description: "Cite-policy adherence report (read-only)" },
|
|
569
|
+
args: {
|
|
570
|
+
target: { type: "string", description: "Override project root (defaults to cwd)" },
|
|
571
|
+
json: { type: "boolean", description: "Output as JSON", default: false },
|
|
572
|
+
since: { type: "string", description: "Window (e.g. 7d, 24h, 30m)", default: "7d" },
|
|
573
|
+
client: { type: "string", description: "Client filter", default: "all", valueHint: "cc|codex|all" },
|
|
574
|
+
layer: { type: "string", description: "KB layer filter", default: "all", valueHint: "team|personal|all" }
|
|
575
|
+
},
|
|
576
|
+
async run({ args }) {
|
|
577
|
+
const resolution = resolveDevMode(args.target, process.cwd());
|
|
578
|
+
const dt = getDoctorTranslator(resolution.target);
|
|
579
|
+
let sinceMs;
|
|
580
|
+
try {
|
|
581
|
+
sinceMs = parseSinceDuration(args.since ?? "7d");
|
|
582
|
+
} catch {
|
|
583
|
+
writeStderr(dt("cli.doctor.errors.invalid-since", { input: args.since ?? "7d" }));
|
|
584
|
+
process.exitCode = 1;
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const clientFilter = args.client ?? "all";
|
|
588
|
+
if (!isValidClientFilter(clientFilter)) {
|
|
589
|
+
writeStderr(dt("cli.doctor.errors.invalid-client", { input: clientFilter }));
|
|
590
|
+
process.exitCode = 1;
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
const layerFilter = args.layer ?? "all";
|
|
594
|
+
if (!isValidLayerFilter(layerFilter)) {
|
|
595
|
+
writeStderr(dt("cli.doctor.errors.invalid-layer", { input: layerFilter }));
|
|
596
|
+
process.exitCode = 1;
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const report = await runDoctorCiteCoverage(resolution.target, {
|
|
600
|
+
since: sinceMs,
|
|
601
|
+
client: clientFilter,
|
|
602
|
+
layer: layerFilter
|
|
603
|
+
});
|
|
604
|
+
renderCiteCoverageReport(report, args.json === true, dt);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
var conflictsCommand = defineCommand2({
|
|
608
|
+
meta: { name: "conflicts", description: "Knowledge-conflict lint (read-only)" },
|
|
609
|
+
args: {
|
|
610
|
+
target: { type: "string", description: "Override project root (defaults to cwd)" },
|
|
611
|
+
json: { type: "boolean", description: "Output as JSON", default: false },
|
|
612
|
+
deep: { type: "boolean", description: "Reserve the LLM-judge pass (no judge wired yet)", default: false }
|
|
613
|
+
},
|
|
614
|
+
async run({ args }) {
|
|
615
|
+
const resolution = resolveDevMode(args.target, process.cwd());
|
|
616
|
+
const dt = getDoctorTranslator(resolution.target);
|
|
617
|
+
const report = await runDoctorConflictLint(resolution.target, { deep: args.deep === true });
|
|
618
|
+
if (args.json === true) {
|
|
619
|
+
writeStdout(JSON.stringify(report, null, 2));
|
|
620
|
+
} else {
|
|
621
|
+
renderConflictLintReport(report, args.deep === true, dt);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
var historyCommand = defineCommand2({
|
|
626
|
+
meta: { name: "history", description: "Maintenance history rollup (archive | fix | all)" },
|
|
627
|
+
args: {
|
|
628
|
+
mode: { type: "positional", required: false, description: "archive | fix | all", valueHint: "archive|fix|all" },
|
|
629
|
+
target: { type: "string", description: "Override project root (defaults to cwd)" },
|
|
630
|
+
json: { type: "boolean", description: "Output as JSON", default: false },
|
|
631
|
+
since: { type: "string", description: "Window (e.g. 7d, 24h, 30m)", default: "7d" }
|
|
632
|
+
},
|
|
633
|
+
async run({ args }) {
|
|
634
|
+
const resolution = resolveDevMode(args.target, process.cwd());
|
|
635
|
+
const dt = getDoctorTranslator(resolution.target);
|
|
636
|
+
const mode = typeof args.mode === "string" && args.mode.length > 0 ? args.mode : "all";
|
|
637
|
+
if (mode !== "archive" && mode !== "fix" && mode !== "all") {
|
|
638
|
+
writeStderr(dt("cli.doctor.errors.invalid-history-mode", { input: mode }));
|
|
639
|
+
process.exitCode = 1;
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
const sinceInput = args.since ?? "7d";
|
|
643
|
+
let sinceMs;
|
|
644
|
+
try {
|
|
645
|
+
sinceMs = parseSinceDuration(sinceInput);
|
|
646
|
+
} catch {
|
|
647
|
+
writeStderr(dt("cli.doctor.errors.invalid-since", { input: sinceInput }));
|
|
648
|
+
process.exitCode = 1;
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (mode === "archive") {
|
|
652
|
+
const report2 = await runDoctorArchiveHistory(resolution.target, { since: sinceMs });
|
|
653
|
+
if (args.json === true) {
|
|
654
|
+
writeStdout(JSON.stringify(report2, null, 2));
|
|
655
|
+
} else {
|
|
656
|
+
renderArchiveHistoryReport(report2, sinceInput, dt);
|
|
657
|
+
}
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const report = await runDoctorHistoryAll(resolution.target, { since: sinceMs });
|
|
661
|
+
if (args.json === true) {
|
|
662
|
+
writeStdout(JSON.stringify(report, null, 2));
|
|
663
|
+
} else {
|
|
664
|
+
renderHistoryAllReport(report, sinceInput, mode, dt);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
var descriptionsCommand = defineCommand2({
|
|
669
|
+
meta: { name: "descriptions", description: "Back-fill description-grade frontmatter fields" },
|
|
670
|
+
args: {
|
|
671
|
+
target: { type: "string", description: "Override project root (defaults to cwd)" },
|
|
672
|
+
json: { type: "boolean", description: "Output as JSON", default: false },
|
|
673
|
+
auto: { type: "boolean", description: "Write stub values (default: read-only list)", default: false },
|
|
674
|
+
"dry-run": { type: "boolean", description: "Preview --auto changes without writing", default: false }
|
|
675
|
+
},
|
|
676
|
+
async run({ args }) {
|
|
677
|
+
const resolution = resolveDevMode(args.target, process.cwd());
|
|
678
|
+
const dt = getDoctorTranslator(resolution.target);
|
|
679
|
+
const report = await enrichDescriptions(resolution.target, {
|
|
680
|
+
auto: args.auto === true,
|
|
681
|
+
dryRun: args["dry-run"] === true
|
|
682
|
+
});
|
|
683
|
+
if (args.json === true) {
|
|
684
|
+
writeStdout(JSON.stringify(report, null, 2));
|
|
685
|
+
} else {
|
|
686
|
+
renderEnrichDescriptionsReport(report, dt);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
var retiredCommand = defineCommand2({
|
|
691
|
+
meta: { name: "retired", description: "Scan agent surfaces for retired tool/field references" },
|
|
692
|
+
args: {
|
|
693
|
+
target: { type: "string", description: "Override project root (defaults to cwd)" },
|
|
694
|
+
json: { type: "boolean", description: "Output as JSON", default: false }
|
|
695
|
+
},
|
|
696
|
+
async run({ args }) {
|
|
697
|
+
const resolution = resolveDevMode(args.target, process.cwd());
|
|
698
|
+
const inspection = await inspectRetiredReferences(resolution.target);
|
|
699
|
+
if (args.json === true) {
|
|
700
|
+
writeStdout(JSON.stringify(inspection, null, 2));
|
|
701
|
+
} else {
|
|
702
|
+
renderRetiredReport(inspection);
|
|
703
|
+
}
|
|
704
|
+
if (inspection.status === "warn") {
|
|
705
|
+
process.exitCode = 1;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
var auditCommand = defineCommand2({
|
|
710
|
+
meta: {
|
|
711
|
+
name: "audit",
|
|
712
|
+
description: "Knowledge & telemetry audits (cite / conflicts / history / descriptions / metrics / retired)"
|
|
713
|
+
},
|
|
714
|
+
subCommands: {
|
|
715
|
+
cite: citeCommand,
|
|
716
|
+
conflicts: conflictsCommand,
|
|
717
|
+
history: historyCommand,
|
|
718
|
+
descriptions: descriptionsCommand,
|
|
719
|
+
metrics: metrics_default,
|
|
720
|
+
retired: retiredCommand,
|
|
721
|
+
"why-not-surfaced": whyNotSurfacedCommand
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
var audit_default = auditCommand;
|
|
725
|
+
export {
|
|
726
|
+
auditCommand,
|
|
727
|
+
citeCommand,
|
|
728
|
+
conflictsCommand,
|
|
729
|
+
audit_default as default,
|
|
730
|
+
descriptionsCommand,
|
|
731
|
+
historyCommand,
|
|
732
|
+
parseSinceDuration,
|
|
733
|
+
retiredCommand
|
|
734
|
+
};
|