@fenglimg/fabric-cli 2.0.1 → 2.2.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.
Files changed (40) hide show
  1. package/dist/{chunk-PWLW3B57.js → chunk-2CY4BMTH.js} +5 -1
  2. package/dist/{chunk-D25XJ4BC.js → chunk-2R55HNVD.js} +105 -5
  3. package/dist/chunk-4R2CYEA4.js +116 -0
  4. package/dist/{chunk-BATF4PEJ.js → chunk-AOE6AYI7.js} +2 -2
  5. package/dist/{chunk-WWNXR34K.js → chunk-BO4XIZWZ.js} +8 -1
  6. package/dist/chunk-L4Q55UC4.js +52 -0
  7. package/dist/chunk-LFIKMVY7.js +27 -0
  8. package/dist/chunk-RYAFBNES.js +33 -0
  9. package/dist/chunk-T5RPGCCM.js +40 -0
  10. package/dist/chunk-WU6GAPKH.js +36 -0
  11. package/dist/{chunk-MF3OTILQ.js → chunk-XC5RUHLK.js} +29 -8
  12. package/dist/{config-XJIPZNUP.js → config-XYRBZJDU.js} +3 -3
  13. package/dist/{doctor-EJDSEJSS.js → doctor-YONYXDX6.js} +147 -24
  14. package/dist/index.js +58 -10
  15. package/dist/{install-EKWMFLUU.js → install-74ANPCCP.js} +320 -75
  16. package/dist/{metrics-ACEQFPDU.js → metrics-RER6NLFC.js} +22 -9
  17. package/dist/{onboard-coverage-MFCAEBDO.js → onboard-coverage-JWQWDZW7.js} +1 -1
  18. package/dist/scope-explain-CDIZESP5.js +37 -0
  19. package/dist/status-GLQWLWH6.js +23 -0
  20. package/dist/store-XB3ADT65.js +144 -0
  21. package/dist/sync-UJ4BBCZJ.js +251 -0
  22. package/dist/{uninstall-MH7ZIB6M.js → uninstall-C3QXKOO6.js} +47 -7
  23. package/dist/whoami-2MLO4Y37.js +36 -0
  24. package/package.json +3 -3
  25. package/templates/hooks/fabric-hint.cjs +139 -7
  26. package/templates/hooks/knowledge-hint-broad.cjs +204 -9
  27. package/templates/hooks/knowledge-hint-narrow.cjs +49 -4
  28. package/templates/hooks/lib/bindings-snapshot-reader.cjs +81 -0
  29. package/templates/hooks/lib/cite-contract-reminder.cjs +15 -9
  30. package/templates/hooks/lib/cite-line-parser.cjs +48 -26
  31. package/templates/hooks/lib/injection-log.cjs +91 -0
  32. package/templates/hooks/lib/state-store.cjs +30 -11
  33. package/templates/skills/fabric-archive/SKILL.md +4 -0
  34. package/templates/skills/fabric-audit/SKILL.md +53 -0
  35. package/templates/skills/fabric-connect/SKILL.md +48 -0
  36. package/templates/skills/fabric-import/SKILL.md +4 -0
  37. package/templates/skills/fabric-review/SKILL.md +6 -0
  38. package/templates/skills/fabric-review/ref/cite-contract.md +56 -0
  39. package/templates/skills/fabric-store/SKILL.md +44 -0
  40. package/templates/skills/fabric-sync/SKILL.md +46 -0
@@ -2,14 +2,24 @@
2
2
  import {
3
3
  paint,
4
4
  symbol
5
- } from "./chunk-WWNXR34K.js";
5
+ } from "./chunk-BO4XIZWZ.js";
6
6
  import {
7
7
  resolveDevMode
8
8
  } from "./chunk-COI5VDFU.js";
9
+ import {
10
+ missingRequiredStores
11
+ } from "./chunk-4R2CYEA4.js";
9
12
  import {
10
13
  getDoctorTranslator,
11
14
  t
12
- } from "./chunk-PWLW3B57.js";
15
+ } from "./chunk-2CY4BMTH.js";
16
+ import {
17
+ loadProjectConfig
18
+ } from "./chunk-LFIKMVY7.js";
19
+ import {
20
+ loadGlobalConfig,
21
+ resolveGlobalRoot
22
+ } from "./chunk-RYAFBNES.js";
13
23
 
14
24
  // src/commands/doctor.ts
15
25
  import { confirm, isCancel } from "@clack/prompts";
@@ -24,6 +34,53 @@ import {
24
34
  runDoctorHistoryAll,
25
35
  runDoctorReport
26
36
  } from "@fenglimg/fabric-server";
37
+
38
+ // src/store/doctor-checks.ts
39
+ import { join } from "path";
40
+ import { findStoreExecutableViolations, storeRelativePath } from "@fenglimg/fabric-shared";
41
+ function storeDoctorChecks(projectRoot, globalRoot = resolveGlobalRoot()) {
42
+ const diagnostics = [];
43
+ const global = loadGlobalConfig(globalRoot);
44
+ if (global === null) {
45
+ diagnostics.push({
46
+ code: "no_global_config",
47
+ severity: "warn",
48
+ message: "no global Fabric config \u2014 run `fabric install --global <url>`"
49
+ });
50
+ return diagnostics;
51
+ }
52
+ for (const missing of missingRequiredStores(projectRoot, globalRoot)) {
53
+ diagnostics.push({
54
+ code: "missing_required_store",
55
+ severity: "warn",
56
+ ref: missing.id,
57
+ message: `required store '${missing.id}' is not mounted; run \`fabric store add\``
58
+ });
59
+ }
60
+ for (const store of global.stores) {
61
+ if (store.remote === void 0 && store.personal !== true) {
62
+ diagnostics.push({
63
+ code: "local_only_store",
64
+ severity: "info",
65
+ ref: store.alias,
66
+ message: `store '${store.alias}' is local-only; add a git remote to back it up`
67
+ });
68
+ }
69
+ const violations = findStoreExecutableViolations(join(globalRoot, storeRelativePath(store.store_uuid)));
70
+ if (violations.length > 0) {
71
+ diagnostics.push({
72
+ code: "executable_in_store",
73
+ severity: "warn",
74
+ ref: store.alias,
75
+ message: `store '${store.alias}' contains executable/script files (${violations.slice(0, 3).join(", ")}${violations.length > 3 ? ", \u2026" : ""}) \u2014 stores are data-only; Fabric never runs them (S65)`
76
+ });
77
+ }
78
+ }
79
+ return diagnostics;
80
+ }
81
+
82
+ // src/commands/doctor.ts
83
+ import { buildDebugBundle } from "@fenglimg/fabric-shared";
27
84
  var FIX_KNOWLEDGE_CODE_LABELS = {
28
85
  knowledge_orphan_demote_required: "demote (maturity)",
29
86
  knowledge_stale_archive_required: "archive (git mv)",
@@ -62,6 +119,14 @@ var doctorCommand = defineCommand({
62
119
  description: t("cli.doctor.args.strict.description"),
63
120
  default: false
64
121
  },
122
+ // v2.1.0-rc.1 P6 (S40): emit a redacted diagnostic bundle (config + store
123
+ // diagnostics; events excluded by default). Every string is secret-redacted
124
+ // so the bundle is safe to paste into a bug report. Read-only.
125
+ "debug-bundle": {
126
+ type: "boolean",
127
+ description: "Emit a redacted diagnostic bundle (config + store health) for bug reports",
128
+ default: false
129
+ },
65
130
  // rc.7 T11: skip the safety confirm before mutations. Required for any
66
131
  // non-tty invocation that wants to run --fix-knowledge without setting
67
132
  // FABRIC_NONINTERACTIVE=1 in the environment.
@@ -154,6 +219,24 @@ var doctorCommand = defineCommand({
154
219
  const citeCoverage = args["cite-coverage"] === true;
155
220
  const enrichDesc = args["enrich-descriptions"] === true;
156
221
  const archiveHistory = args["archive-history"] === true;
222
+ if (args["debug-bundle"] === true) {
223
+ const globalRoot = resolveGlobalRoot();
224
+ let config = {};
225
+ try {
226
+ config = {
227
+ global: loadGlobalConfig(globalRoot) ?? null,
228
+ project: loadProjectConfig(resolution.target) ?? null
229
+ };
230
+ } catch {
231
+ config = {};
232
+ }
233
+ const bundle = buildDebugBundle({
234
+ config,
235
+ diagnostics: collectStoreDiagnostics(resolution.target)
236
+ });
237
+ writeStdout(JSON.stringify(bundle, null, 2));
238
+ return;
239
+ }
157
240
  if (args.since !== void 0) {
158
241
  try {
159
242
  parseSinceDuration(args.since);
@@ -290,23 +373,30 @@ var doctorCommand = defineCommand({
290
373
  if (fixKnowledge) {
291
374
  const preReport = await runDoctorReport(resolution.target);
292
375
  const plan = computeFixKnowledgePlan(preReport);
293
- const yesFlag = args.yes === true;
294
- const envBypass = process.env.FABRIC_NONINTERACTIVE === "1";
295
- if (plan.totalCount === 0) {
376
+ if (args["dry-run"] === true) {
377
+ if (plan.totalCount > 0) {
378
+ renderFixKnowledgePlan(plan);
379
+ }
380
+ report = preReport;
296
381
  } else {
297
- renderFixKnowledgePlan(plan);
298
- const decision = await resolveFixKnowledgeConsent({
299
- yesFlag,
300
- envBypass,
301
- plan
302
- });
303
- if (decision === "abort") {
304
- process.exitCode = 1;
305
- return;
382
+ const yesFlag = args.yes === true;
383
+ const envBypass = process.env.FABRIC_NONINTERACTIVE === "1";
384
+ if (plan.totalCount === 0) {
385
+ } else {
386
+ renderFixKnowledgePlan(plan);
387
+ const decision = await resolveFixKnowledgeConsent({
388
+ yesFlag,
389
+ envBypass,
390
+ plan
391
+ });
392
+ if (decision === "abort") {
393
+ process.exitCode = 1;
394
+ return;
395
+ }
306
396
  }
397
+ fixKnowledgeReport = await runDoctorFixKnowledge(resolution.target);
398
+ report = fixKnowledgeReport.report;
307
399
  }
308
- fixKnowledgeReport = await runDoctorFixKnowledge(resolution.target);
309
- report = fixKnowledgeReport.report;
310
400
  } else if (fix) {
311
401
  if (args["dry-run"] === true) {
312
402
  report = await runDoctorReport(resolution.target);
@@ -317,8 +407,15 @@ var doctorCommand = defineCommand({
317
407
  } else {
318
408
  report = await runDoctorReport(resolution.target);
319
409
  }
410
+ const storeDiagnostics = collectStoreDiagnostics(resolution.target);
320
411
  if (args.json === true) {
321
- writeStdout(JSON.stringify(fixKnowledgeReport ?? fixReport ?? report, null, 2));
412
+ writeStdout(
413
+ JSON.stringify(
414
+ { ...fixKnowledgeReport ?? fixReport ?? report, store_diagnostics: storeDiagnostics },
415
+ null,
416
+ 2
417
+ )
418
+ );
322
419
  } else {
323
420
  if (fixKnowledgeReport !== null) {
324
421
  writeStdout(fixKnowledgeReport.message);
@@ -328,10 +425,11 @@ var doctorCommand = defineCommand({
328
425
  renderFixKnowledgeMutations(fixKnowledgeReport, dt);
329
426
  } else if (fixReport !== null) {
330
427
  writeStdout(fixReport.message);
331
- } else if (fix && args["dry-run"] === true) {
428
+ } else if ((fix || fixKnowledge) && args["dry-run"] === true) {
332
429
  writeStdout(dt("cli.doctor.fix-dry-run-banner"));
333
430
  }
334
431
  renderHumanReport(report, dt, args.verbose === true);
432
+ renderStoreDiagnostics(storeDiagnostics);
335
433
  }
336
434
  await emitDoctorRunEventBestEffort(resolution.target, {
337
435
  mode: fixKnowledge ? "fix-knowledge" : "lint",
@@ -356,7 +454,7 @@ var doctorCommand = defineCommand({
356
454
  var doctor_default = doctorCommand;
357
455
  function renderHumanReport(report, dt, verbose) {
358
456
  writeStdout(`${renderStatus(report.status)} ${paint.ai("fabric doctor")} ${paint.human(report.summary.target)}`);
359
- renderTldrHeader(report);
457
+ renderTldrHeader(report, dt, verbose);
360
458
  for (const check of report.checks) {
361
459
  writeStdout(`${renderStatus(check.status)} ${check.name}: ${check.message}`);
362
460
  }
@@ -366,6 +464,25 @@ function renderHumanReport(report, dt, verbose) {
366
464
  writeIssueSection(dt("doctor.section.warnings"), report.warnings, opts);
367
465
  renderPayloadLimits(report, dt);
368
466
  }
467
+ function collectStoreDiagnostics(projectRoot) {
468
+ try {
469
+ return storeDoctorChecks(projectRoot);
470
+ } catch {
471
+ return [];
472
+ }
473
+ }
474
+ function renderStoreDiagnostics(diagnostics) {
475
+ if (diagnostics.length === 0) {
476
+ return;
477
+ }
478
+ writeStdout("");
479
+ writeStdout(paint.ai("store health"));
480
+ for (const diagnostic of diagnostics) {
481
+ const mark = diagnostic.severity === "warn" ? symbol.warn : "[info]";
482
+ const ref = diagnostic.ref === void 0 ? "" : ` [${diagnostic.ref}]`;
483
+ writeStdout(`${mark}${ref} ${diagnostic.message}`);
484
+ }
485
+ }
369
486
  function renderPayloadLimits(report, dt) {
370
487
  const limits = report.summary.payload_limits;
371
488
  if (limits === void 0) {
@@ -410,16 +527,16 @@ function writeIssueSection(title, issues, options) {
410
527
  }
411
528
  }
412
529
  }
413
- function renderTldrHeader(report) {
530
+ function renderTldrHeader(report, dt, verbose) {
414
531
  const ranked = [];
415
532
  for (const issue of report.fixable_errors) {
416
- ranked.push({ severity: "fixable", code: issue.code, message: issue.message });
533
+ ranked.push({ severity: "fixable", code: issue.code, message: issue.message, actionHint: issue.actionHint, audience: issue.audience });
417
534
  }
418
535
  for (const issue of report.manual_errors) {
419
- ranked.push({ severity: "manual", code: issue.code, message: issue.message });
536
+ ranked.push({ severity: "manual", code: issue.code, message: issue.message, actionHint: issue.actionHint, audience: issue.audience });
420
537
  }
421
538
  for (const issue of report.warnings) {
422
- ranked.push({ severity: "warn", code: issue.code, message: issue.message });
539
+ ranked.push({ severity: "warn", code: issue.code, message: issue.message, actionHint: issue.actionHint, audience: issue.audience });
423
540
  }
424
541
  if (ranked.length === 0) {
425
542
  writeStdout(`${symbol.ok} TL;DR: all 48 checks green \u2014 nothing to fix.`);
@@ -433,6 +550,11 @@ function renderTldrHeader(report) {
433
550
  const marker = item.severity === "fixable" ? symbol.error : item.severity === "manual" ? symbol.error : symbol.warn;
434
551
  const truncated = item.message.length > 140 ? `${item.message.slice(0, 137)}...` : item.message;
435
552
  writeStdout(` ${marker} ${item.code}: ${truncated}`);
553
+ if (item.actionHint !== void 0 && item.actionHint.length > 0) {
554
+ writeStdout(
555
+ item.audience === "maintainer" && !verbose ? ` \u2192 ${dt("doctor.maintainer-hint-folded")}` : ` \u2192 ${item.actionHint}`
556
+ );
557
+ }
436
558
  }
437
559
  }
438
560
  function renderStatus(status) {
@@ -806,5 +928,6 @@ function formatTimestampForTable(iso) {
806
928
  export {
807
929
  doctor_default as default,
808
930
  doctorCommand,
809
- parseSinceDuration
931
+ parseSinceDuration,
932
+ renderTldrHeader
810
933
  };
package/dist/index.js CHANGED
@@ -1,39 +1,87 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  t
4
- } from "./chunk-PWLW3B57.js";
4
+ } from "./chunk-2CY4BMTH.js";
5
5
 
6
6
  // src/index.ts
7
7
  import { realpathSync } from "fs";
8
8
  import { resolve } from "path";
9
9
  import { fileURLToPath } from "url";
10
- import { defineCommand, runMain } from "citty";
10
+ import { defineCommand, runCommand, runMain } from "citty";
11
11
 
12
12
  // src/commands/index.ts
13
13
  var allCommands = {
14
- install: () => import("./install-EKWMFLUU.js").then((module) => module.default),
15
- doctor: () => import("./doctor-EJDSEJSS.js").then((module) => module.default),
16
- uninstall: () => import("./uninstall-MH7ZIB6M.js").then((module) => module.default),
17
- config: () => import("./config-XJIPZNUP.js").then((module) => module.default),
14
+ install: () => import("./install-74ANPCCP.js").then((module) => module.default),
15
+ // v2.1.0-rc.1 P3: multi-store lifecycle command group (list/add/remove/explain).
16
+ store: () => import("./store-XB3ADT65.js").then((module) => module.default),
17
+ // v2.1.0-rc.1 P3 (S9/S17/S37): multi-store pull --rebase + push, conflict resume.
18
+ sync: () => import("./sync-UJ4BBCZJ.js").then((module) => module.default),
19
+ // v2.1.0-rc.1 P3 (F5): read-only identity/status info commands.
20
+ whoami: () => import("./whoami-2MLO4Y37.js").then((module) => module.default),
21
+ status: () => import("./status-GLQWLWH6.js").then((module) => module.default),
22
+ "scope-explain": () => import("./scope-explain-CDIZESP5.js").then((module) => module.default),
23
+ doctor: () => import("./doctor-YONYXDX6.js").then((module) => module.default),
24
+ uninstall: () => import("./uninstall-C3QXKOO6.js").then((module) => module.default),
25
+ config: () => import("./config-XYRBZJDU.js").then((module) => module.default),
18
26
  "plan-context-hint": () => import("./plan-context-hint-FC6P3WFE.js").then((module) => module.default),
19
27
  // v2.0.0-rc.23 TASK-014 (F8c): S5 onboard-slot coverage. Used by the
20
28
  // fabric-archive Skill's first-run phase to detect unclaimed slots.
21
- "onboard-coverage": () => import("./onboard-coverage-MFCAEBDO.js").then((module) => module.default),
29
+ "onboard-coverage": () => import("./onboard-coverage-JWQWDZW7.js").then((module) => module.default),
22
30
  // v2.0.0-rc.37 NEW-34: text dashboard over .fabric/metrics.jsonl.
23
- metrics: () => import("./metrics-ACEQFPDU.js").then((module) => module.default)
31
+ metrics: () => import("./metrics-RER6NLFC.js").then((module) => module.default)
24
32
  };
25
33
 
34
+ // src/lib/error-render.ts
35
+ function hasActionHint(err) {
36
+ if (err === null || typeof err !== "object") return false;
37
+ const candidate = err;
38
+ return typeof candidate.message === "string" && candidate.message.length > 0 && typeof candidate.actionHint === "string" && candidate.actionHint.length > 0;
39
+ }
40
+ function renderFabricError(err, stream = process.stderr) {
41
+ stream.write(`${err.message}
42
+ `);
43
+ stream.write(` -> ${err.actionHint}
44
+ `);
45
+ }
46
+ function renderTopLevelError(err, stream = process.stderr) {
47
+ if (hasActionHint(err)) {
48
+ renderFabricError(err, stream);
49
+ return "fabric-error";
50
+ }
51
+ return "other";
52
+ }
53
+
26
54
  // src/index.ts
27
55
  var main = defineCommand({
28
56
  meta: {
29
57
  name: "fabric",
30
- version: "2.0.1",
58
+ version: "2.2.0-rc.1",
31
59
  description: t("cli.main.description")
32
60
  },
33
61
  subCommands: allCommands
34
62
  });
35
63
  async function run() {
36
- await runMain(main);
64
+ const rawArgs = process.argv.slice(2);
65
+ const wantsHelp = rawArgs.some((arg) => arg === "--help" || arg === "-h");
66
+ const wantsVersion = rawArgs.length === 1 && (rawArgs[0] === "--version" || rawArgs[0] === "-v");
67
+ if (wantsHelp || wantsVersion) {
68
+ await runMain(main, { rawArgs });
69
+ return;
70
+ }
71
+ try {
72
+ await runCommand(main, { rawArgs });
73
+ } catch (err) {
74
+ if (renderTopLevelError(err) === "fabric-error") {
75
+ process.exit(1);
76
+ }
77
+ const code = err !== null && typeof err === "object" ? err.code : void 0;
78
+ if (typeof code === "string" && code.startsWith("E_")) {
79
+ await runMain(main, { rawArgs });
80
+ return;
81
+ }
82
+ console.error(err, "\n");
83
+ process.exit(1);
84
+ }
37
85
  }
38
86
  var entrypoint = process.argv[1];
39
87
  var currentFilePath = fileURLToPath(import.meta.url);