@fenglimg/fabric-cli 2.0.0-rc.23 → 2.0.0-rc.25

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.
@@ -20,6 +20,7 @@ import {
20
20
  checkLockOrThrow,
21
21
  enrichDescriptions,
22
22
  runDoctorApplyLint as runDoctorFixKnowledge,
23
+ runDoctorArchiveHistory,
23
24
  runDoctorCiteCoverage,
24
25
  runDoctorFix,
25
26
  runDoctorReport
@@ -89,6 +90,15 @@ var doctorCommand = defineCommand({
89
90
  default: "all",
90
91
  valueHint: "cc|codex|cursor|all"
91
92
  },
93
+ // v2.0.0-rc.24 TASK-10: --layer filter for the cite contract audit. Pairs
94
+ // with --cite-coverage. Validated against {'team','personal','all'} at
95
+ // command entry; rejects 'both' (rc.20 plan-context vocabulary) explicitly.
96
+ layer: {
97
+ type: "string",
98
+ description: t("cli.doctor.args.layer.description"),
99
+ default: "all",
100
+ valueHint: "team|personal|all"
101
+ },
92
102
  // rc.23 TASK-007 (a-C2): description-grade back-fill flag set. Read-side
93
103
  // by default; `--auto` flips the writer arm on. Mutually exclusive with
94
104
  // --fix / --fix-knowledge / --cite-coverage (different mutation surfaces).
@@ -106,6 +116,14 @@ var doctorCommand = defineCommand({
106
116
  type: "boolean",
107
117
  description: t("cli.doctor.args.dry-run.description"),
108
118
  default: false
119
+ },
120
+ // v2.0.0-rc.25 TASK-10: --archive-history flag (parallel to rc.20
121
+ // --cite-coverage). Read-only; reads session_archive_attempted events
122
+ // and renders a per-session table. Pairs with the shared `--since` flag.
123
+ "archive-history": {
124
+ type: "boolean",
125
+ description: t("cli.doctor.args.archive-history.description"),
126
+ default: false
109
127
  }
110
128
  },
111
129
  async run({ args }) {
@@ -124,6 +142,32 @@ var doctorCommand = defineCommand({
124
142
  const fix = args.fix === true;
125
143
  const citeCoverage = args["cite-coverage"] === true;
126
144
  const enrichDesc = args["enrich-descriptions"] === true;
145
+ const archiveHistory = args["archive-history"] === true;
146
+ if (archiveHistory) {
147
+ if (fix || fixKnowledge || citeCoverage || enrichDesc) {
148
+ writeStderr(t("cli.doctor.errors.archive-history-mutex"));
149
+ process.exitCode = 1;
150
+ return;
151
+ }
152
+ const sinceInput = args.since ?? "7d";
153
+ let sinceMs;
154
+ try {
155
+ sinceMs = parseSinceDuration(sinceInput);
156
+ } catch {
157
+ writeStderr(t("cli.doctor.errors.invalid-since", { input: sinceInput }));
158
+ process.exitCode = 1;
159
+ return;
160
+ }
161
+ const report2 = await runDoctorArchiveHistory(resolution.target, {
162
+ since: sinceMs
163
+ });
164
+ if (args.json === true) {
165
+ writeStdout(JSON.stringify(report2, null, 2));
166
+ } else {
167
+ renderArchiveHistoryReport(report2, sinceInput);
168
+ }
169
+ return;
170
+ }
127
171
  if (enrichDesc) {
128
172
  if (fix || fixKnowledge || citeCoverage) {
129
173
  writeStderr(t("cli.doctor.errors.enrich-descriptions-mutex"));
@@ -163,9 +207,16 @@ var doctorCommand = defineCommand({
163
207
  process.exitCode = 1;
164
208
  return;
165
209
  }
210
+ const layerFilter = args.layer ?? "all";
211
+ if (!isValidLayerFilter(layerFilter)) {
212
+ writeStderr(t("cli.doctor.errors.invalid-layer", { input: layerFilter }));
213
+ process.exitCode = 1;
214
+ return;
215
+ }
166
216
  const report2 = await runDoctorCiteCoverage(resolution.target, {
167
217
  since: sinceMs,
168
- client: clientFilter
218
+ client: clientFilter,
219
+ layer: layerFilter
169
220
  });
170
221
  renderCiteCoverageReport(report2, args.json === true);
171
222
  return;
@@ -377,6 +428,14 @@ var CITE_COVERAGE_CLIENT_FILTERS = /* @__PURE__ */ new Set([
377
428
  function isValidClientFilter(input) {
378
429
  return CITE_COVERAGE_CLIENT_FILTERS.has(input);
379
430
  }
431
+ var CITE_COVERAGE_LAYER_FILTERS = /* @__PURE__ */ new Set([
432
+ "team",
433
+ "personal",
434
+ "all"
435
+ ]);
436
+ function isValidLayerFilter(input) {
437
+ return CITE_COVERAGE_LAYER_FILTERS.has(input);
438
+ }
380
439
  function renderCiteCoverageReport(report, jsonMode) {
381
440
  if (jsonMode) {
382
441
  writeStdout(JSON.stringify(report, null, 2));
@@ -427,8 +486,83 @@ function renderCiteCoverageReport(report, jsonMode) {
427
486
  lines.push(` ${label}: ${count}`);
428
487
  }
429
488
  }
489
+ appendContractSection(lines, report);
430
490
  writeStdout(lines.join("\n"));
431
491
  }
492
+ function appendContractSection(lines, report) {
493
+ const status = report.contract_metrics_status;
494
+ if (status === void 0) {
495
+ return;
496
+ }
497
+ const metrics = report.contract_metrics;
498
+ const perLayerType = report.per_layer_type;
499
+ 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;
500
+ if (status === "awaiting_marker" && allCountsZero) {
501
+ return;
502
+ }
503
+ lines.push("");
504
+ lines.push(`### ${t("cite-coverage.contract.header")}`);
505
+ if (status === "skipped:bootstrap_drift") {
506
+ lines.push(` ${t("cite-coverage.contract.status.skipped_bootstrap_drift")}`);
507
+ return;
508
+ }
509
+ const statusKey = status === "ok" ? "cite-coverage.contract.status.ok" : "cite-coverage.contract.status.awaiting_marker";
510
+ lines.push(` status: ${t(statusKey)}`);
511
+ if (typeof report.contract_marker_ts === "number" && report.contract_marker_ts > 0) {
512
+ lines.push(` since: ${new Date(report.contract_marker_ts).toISOString()}`);
513
+ }
514
+ if (report.layer_filter !== void 0) {
515
+ lines.push(` layer filter: ${report.layer_filter}`);
516
+ }
517
+ if (metrics !== void 0) {
518
+ lines.push(` ${t("cite-coverage.contract.decisions_cited")}: ${metrics.decisions_cited}`);
519
+ lines.push(` ${t("cite-coverage.contract.pitfalls_cited")}: ${metrics.pitfalls_cited}`);
520
+ lines.push(` ${t("cite-coverage.contract.with")}: ${metrics.contract_with}`);
521
+ lines.push(` ${t("cite-coverage.contract.missing")}: ${metrics.contract_missing}`);
522
+ if (metrics.hard_violated > 0) {
523
+ const layerSuffix = report.layer_filter === "personal" ? t("cite-coverage.layer.personal_fyi") : t("cite-coverage.layer.team_review");
524
+ lines.push(
525
+ ` ${t("cite-coverage.contract.hard_violated")} ${layerSuffix}: ${metrics.hard_violated}`
526
+ );
527
+ }
528
+ }
529
+ if (perLayerType !== void 0) {
530
+ const teamKeys = Object.keys(perLayerType.team).filter(
531
+ (k) => perLayerType.team[k] > 0
532
+ );
533
+ const personalKeys = Object.keys(perLayerType.personal).filter(
534
+ (k) => perLayerType.personal[k] > 0
535
+ );
536
+ if (teamKeys.length > 0 || personalKeys.length > 0) {
537
+ lines.push("");
538
+ lines.push(`#### ${t("cite-coverage.layer.team")} \xD7 ${t("cite-coverage.layer.personal")}`);
539
+ for (const key of teamKeys) {
540
+ const label = t(`cite-coverage.contract.type.${key}`);
541
+ lines.push(` ${t("cite-coverage.layer.team")} \u2014 ${label}: ${perLayerType.team[key]}`);
542
+ }
543
+ for (const key of personalKeys) {
544
+ const label = t(`cite-coverage.contract.type.${key}`);
545
+ lines.push(
546
+ ` ${t("cite-coverage.layer.personal")} \u2014 ${label}: ${perLayerType.personal[key]}`
547
+ );
548
+ }
549
+ }
550
+ }
551
+ if (metrics !== void 0 && Object.keys(metrics.skip_count).length > 0) {
552
+ lines.push("");
553
+ lines.push(`#### ${t("cite-coverage.contract.skip_count")}`);
554
+ for (const [reason, count] of Object.entries(metrics.skip_count)) {
555
+ const label = t(`cite-coverage.skip.${reason}`);
556
+ lines.push(` ${label}: ${count}`);
557
+ }
558
+ }
559
+ if (metrics !== void 0 && metrics.cite_id_unresolved > 0) {
560
+ lines.push("");
561
+ lines.push(
562
+ `${symbol.warn} ${t("cite-coverage.contract.cite_id_unresolved")}: ${metrics.cite_id_unresolved}`
563
+ );
564
+ }
565
+ }
432
566
  function renderEnrichDescriptionsReport(report) {
433
567
  const header = `${symbol.ok} ${paint.ai("fab doctor --enrich-descriptions")} mode=${report.mode}${report.dryRun ? " (dry-run)" : ""} scanned=${report.scanned} modified=${report.modified} skipped=${report.skipped}`;
434
568
  writeStdout(header);
@@ -477,6 +611,44 @@ function parseSinceDuration(input) {
477
611
  }
478
612
  throw new Error(`invalid --since value: ${input}`);
479
613
  }
614
+ function renderArchiveHistoryReport(report, sinceLabel) {
615
+ if (report.entries.length === 0) {
616
+ writeStdout(t("doctor.archive-history.empty", { sinceLabel }));
617
+ return;
618
+ }
619
+ const lines = [];
620
+ lines.push(
621
+ t("doctor.archive-history.header", {
622
+ sinceLabel,
623
+ count: String(report.total),
624
+ plural: report.total === 1 ? "" : "s"
625
+ })
626
+ );
627
+ lines.push("");
628
+ lines.push(
629
+ `| ${t("doctor.archive-history.table.session")} | ${t(
630
+ "doctor.archive-history.table.lastAttempt"
631
+ )} | ${t("doctor.archive-history.table.outcome")} | ${t(
632
+ "doctor.archive-history.table.candidates"
633
+ )} | ${t("doctor.archive-history.table.coveredGap")} |`
634
+ );
635
+ lines.push("| ------- | ---------------- | -------- | ---------- | ----------- |");
636
+ for (const entry of report.entries) {
637
+ const lastAttempt = formatTimestampForTable(entry.last_attempted_at);
638
+ lines.push(
639
+ `| ${entry.session_id_short} | ${lastAttempt} | ${entry.outcome} | ${entry.candidates_proposed} | ${entry.age_since_covered_hours}h |`
640
+ );
641
+ }
642
+ writeStdout(lines.join("\n"));
643
+ }
644
+ function formatTimestampForTable(iso) {
645
+ const d = new Date(iso);
646
+ if (Number.isNaN(d.getTime())) return iso;
647
+ const pad = (n) => n < 10 ? `0${n}` : `${n}`;
648
+ return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(
649
+ d.getUTCHours()
650
+ )}:${pad(d.getUTCMinutes())}`;
651
+ }
480
652
  export {
481
653
  doctor_default as default,
482
654
  doctorCommand,
package/dist/index.js CHANGED
@@ -11,8 +11,8 @@ import { defineCommand, runMain } from "citty";
11
11
 
12
12
  // src/commands/index.ts
13
13
  var allCommands = {
14
- install: () => import("./install-TDZYZV54.js").then((module) => module.default),
15
- doctor: () => import("./doctor-R2E2XO6A.js").then((module) => module.default),
14
+ install: () => import("./install-S2J76N2B.js").then((module) => module.default),
15
+ doctor: () => import("./doctor-DXKPYPRC.js").then((module) => module.default),
16
16
  serve: () => import("./serve-NPCI342P.js").then((module) => module.default),
17
17
  uninstall: () => import("./uninstall-MQM6NUFM.js").then((module) => module.default),
18
18
  config: () => import("./config-XGUUAYX6.js").then((module) => module.default),
@@ -26,7 +26,7 @@ var allCommands = {
26
26
  var main = defineCommand({
27
27
  meta: {
28
28
  name: "fabric",
29
- version: "2.0.0-rc.23",
29
+ version: "2.0.0-rc.25",
30
30
  description: t("cli.main.description")
31
31
  },
32
32
  subCommands: allCommands
@@ -1348,7 +1348,7 @@ function readProjectName(target) {
1348
1348
  return basename(target);
1349
1349
  }
1350
1350
  function getCliVersion() {
1351
- return true ? "2.0.0-rc.23" : "unknown";
1351
+ return true ? "2.0.0-rc.25" : "unknown";
1352
1352
  }
1353
1353
  function sortRecord(record) {
1354
1354
  return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fenglimg/fabric-cli",
3
- "version": "2.0.0-rc.23",
3
+ "version": "2.0.0-rc.25",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "fab": "dist/index.js",
@@ -20,8 +20,8 @@
20
20
  "tree-sitter-javascript": "^0.25.0",
21
21
  "tree-sitter-typescript": "^0.23.2",
22
22
  "web-tree-sitter": "^0.26.8",
23
- "@fenglimg/fabric-server": "2.0.0-rc.23",
24
- "@fenglimg/fabric-shared": "2.0.0-rc.23"
23
+ "@fenglimg/fabric-server": "2.0.0-rc.25",
24
+ "@fenglimg/fabric-shared": "2.0.0-rc.25"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@types/node": "^22.15.0",