@fenglimg/fabric-cli 2.2.0 → 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.
Files changed (74) hide show
  1. package/README.md +2 -2
  2. package/dist/audit-PURSJJFH.js +734 -0
  3. package/dist/{chunk-QPAW6IYT.js → chunk-7V4XMLQ2.js} +3 -3
  4. package/dist/{chunk-7ZDXBOOU.js → chunk-ACSMNX3V.js} +44 -128
  5. package/dist/{chunk-PTGQAZEW.js → chunk-GGDVZCD6.js} +2 -4
  6. package/dist/{chunk-EOT63RDH.js → chunk-I5F5BHWI.js} +9 -0
  7. package/dist/chunk-PP7QVRXH.js +565 -0
  8. package/dist/chunk-SL77FXX7.js +54 -0
  9. package/dist/{chunk-3D7B2UAZ.js → chunk-VQKXTMWH.js} +44 -4
  10. package/dist/doctor-S6KPGS35.js +27 -0
  11. package/dist/index.js +90 -80
  12. package/dist/{info-7FKBTMVO.js → info-NJEY26H6.js} +91 -46
  13. package/dist/{context-UJCGYOT6.js → inspect-5YZMJPFM.js} +10 -10
  14. package/dist/{install-v2-3KJX3YRO.js → install-v2-KGIDII4H.js} +163 -364
  15. package/dist/{store-HOCORVL3.js → store-GF4SFBMJ.js} +155 -57
  16. package/dist/{sync-DT5UJMMR.js → sync-3XCIRDPK.js} +3 -4
  17. package/dist/{uninstall-IFN2KYBK.js → uninstall-BG4ML4FC.js} +39 -10
  18. package/package.json +3 -7
  19. package/templates/hooks/cite-policy-evict.cjs +1 -1
  20. package/templates/hooks/configs/claude-code.json +1 -5
  21. package/templates/hooks/configs/codex-hooks.json +1 -5
  22. package/templates/hooks/fabric-hint.cjs +67 -41
  23. package/templates/hooks/knowledge-hint-broad.cjs +82 -24
  24. package/templates/hooks/knowledge-hint-narrow.cjs +3 -3
  25. package/templates/hooks/knowledge-pretooluse.cjs +111 -0
  26. package/templates/hooks/lib/banner-i18n.cjs +12 -11
  27. package/templates/hooks/lib/bindings-snapshot-reader.cjs +1 -1
  28. package/templates/hooks/lib/event-writer.cjs +79 -0
  29. package/templates/hooks/lib/nudge-policy.cjs +11 -0
  30. package/templates/hooks/lib/theme.cjs +62 -0
  31. package/templates/hooks/post-tooluse-mutation.cjs +28 -39
  32. package/templates/skills/fabric-archive/SKILL.md +29 -12
  33. package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
  34. package/templates/skills/fabric-archive/ref/i18n-policy.md +1 -1
  35. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +5 -5
  36. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +2 -2
  37. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
  38. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +1 -1
  39. package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +1 -1
  40. package/templates/skills/fabric-archive/ref/phase-3-classify.md +1 -1
  41. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +1 -1
  42. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +6 -5
  43. package/templates/skills/{fabric-import/ref/checkpoint-state.md → fabric-archive/ref/source-checkpoint.md} +3 -3
  44. package/templates/skills/{fabric-import/ref/phase-3-dedup.md → fabric-archive/ref/source-dedup.md} +4 -4
  45. package/templates/skills/{fabric-import/ref/phase-2-mining.md → fabric-archive/ref/source-mining.md} +20 -20
  46. package/templates/skills/{fabric-import/ref/output-contract.md → fabric-archive/ref/source-output-contract.md} +3 -3
  47. package/templates/skills/{fabric-import/ref/state-recovery.md → fabric-archive/ref/source-state-recovery.md} +2 -2
  48. package/templates/skills/{fabric-import/ref/worked-examples.md → fabric-archive/ref/source-worked-examples.md} +10 -10
  49. package/templates/skills/fabric-archive/ref/worked-examples.md +3 -3
  50. package/templates/skills/fabric-review/SKILL.md +19 -15
  51. package/templates/skills/fabric-review/ref/cite-contract.md +2 -2
  52. package/templates/skills/fabric-review/ref/modify-flow.md +13 -1
  53. package/templates/skills/fabric-review/ref/per-mode-flows.md +5 -5
  54. package/templates/skills/fabric-review/ref/relate-mode.md +33 -0
  55. package/templates/skills/fabric-review/ref/retire-mode.md +47 -0
  56. package/templates/skills/fabric-review/ref/semantic-check.md +1 -1
  57. package/templates/skills/fabric-review/ref/worked-examples.md +5 -5
  58. package/templates/skills/fabric-store/SKILL.md +12 -27
  59. package/templates/skills/fabric-sync/SKILL.md +16 -35
  60. package/templates/skills/lib/shared-policy.md +6 -4
  61. package/dist/chunk-27HK6H5Y.js +0 -69
  62. package/dist/chunk-E7HJUU34.js +0 -1096
  63. package/dist/chunk-NLNH64A3.js +0 -43
  64. package/dist/chunk-QFIVFZRH.js +0 -13
  65. package/dist/doctor-MDTZWKBK.js +0 -24
  66. package/dist/metrics-HMFH4YHK.js +0 -135
  67. package/dist/scope-explain-HLJZ2M33.js +0 -48
  68. package/dist/status-4R3TM4FJ.js +0 -37
  69. package/dist/whoami-ITGEFWH4.js +0 -49
  70. package/templates/skills/fabric/SKILL.md +0 -100
  71. package/templates/skills/fabric-audit/SKILL.md +0 -63
  72. package/templates/skills/fabric-connect/SKILL.md +0 -48
  73. package/templates/skills/fabric-import/SKILL.md +0 -151
  74. package/templates/skills/fabric-import/ref/i18n-policy.md +0 -78
@@ -4,16 +4,13 @@ import {
4
4
  installArchiveHintHook,
5
5
  installCitePolicyEvictHook,
6
6
  installFabricArchiveSkill,
7
- installFabricAuditSkill,
8
- installFabricConnectSkill,
9
- installFabricImportSkill,
10
7
  installFabricReviewSkill,
11
- installFabricRouterSkill,
12
8
  installFabricStoreSkill,
13
9
  installFabricSyncSkill,
14
10
  installHookLibs,
15
11
  installKnowledgeHintBroadHook,
16
12
  installKnowledgeHintNarrowHook,
13
+ installKnowledgePretoolUseHook,
17
14
  installPostTooluseMutationHook,
18
15
  installSessionEndMarkerHook,
19
16
  installSharedSkillLib,
@@ -22,38 +19,39 @@ import {
22
19
  writeClaudeBootstrapThinShell,
23
20
  writeCodexBootstrapManagedBlock,
24
21
  writeFabricAgentsSnapshot
25
- } from "./chunk-7ZDXBOOU.js";
22
+ } from "./chunk-ACSMNX3V.js";
23
+ import {
24
+ installMcpClients
25
+ } from "./chunk-2KBCTMID.js";
26
+ import {
27
+ detectClientSupports
28
+ } from "./chunk-3IOLS5EK.js";
26
29
  import {
27
30
  ensureStoreProjectBinding,
31
+ grid,
28
32
  migrateRootConfig,
29
33
  normalizeStoreProjectId,
30
- suggestStoreProjectId
31
- } from "./chunk-3D7B2UAZ.js";
34
+ suggestStoreProjectId,
35
+ tree
36
+ } from "./chunk-VQKXTMWH.js";
32
37
  import {
33
38
  createDebugLogger,
34
39
  resolveDevMode
35
40
  } from "./chunk-WA3DYGSY.js";
36
- import {
37
- installMcpClients
38
- } from "./chunk-2KBCTMID.js";
39
- import {
40
- detectClientSupports
41
- } from "./chunk-3IOLS5EK.js";
42
41
  import {
43
42
  paint
44
- } from "./chunk-NLNH64A3.js";
45
- import "./chunk-PTGQAZEW.js";
46
- import "./chunk-EOT63RDH.js";
43
+ } from "./chunk-SL77FXX7.js";
44
+ import "./chunk-GGDVZCD6.js";
47
45
  import {
48
46
  storeCreate,
49
47
  storeList,
50
48
  storeProjectList,
51
49
  syncStoreAliasLinks,
52
50
  unboundAvailableStores
53
- } from "./chunk-QPAW6IYT.js";
51
+ } from "./chunk-7V4XMLQ2.js";
54
52
  import {
55
53
  loadProjectConfig
56
- } from "./chunk-QFIVFZRH.js";
54
+ } from "./chunk-I5F5BHWI.js";
57
55
  import {
58
56
  globalConfigPath,
59
57
  loadGlobalConfig,
@@ -1142,17 +1140,17 @@ async function analyzeImports(relativePath, snippet) {
1142
1140
  }
1143
1141
  async function extractImports(source, languageKind) {
1144
1142
  const { parser } = await loadTreeSitter(languageKind);
1145
- let tree = null;
1143
+ let tree2 = null;
1146
1144
  try {
1147
- tree = parser.parse(source);
1148
- if (tree === null || tree.rootNode.hasError) {
1145
+ tree2 = parser.parse(source);
1146
+ if (tree2 === null || tree2.rootNode.hasError) {
1149
1147
  throw new Error("tree-sitter parse failed");
1150
1148
  }
1151
1149
  const imports = [];
1152
- collectImportSources(tree.rootNode, imports);
1150
+ collectImportSources(tree2.rootNode, imports);
1153
1151
  return compactPatternNames(imports);
1154
1152
  } finally {
1155
- tree?.delete();
1153
+ tree2?.delete();
1156
1154
  }
1157
1155
  }
1158
1156
  async function loadTreeSitter(languageKind) {
@@ -1738,7 +1736,7 @@ function readProjectName(target) {
1738
1736
  return basename(target);
1739
1737
  }
1740
1738
  function getCliVersion() {
1741
- return true ? "2.2.0" : "unknown";
1739
+ return true ? "2.3.0-rc.1" : "unknown";
1742
1740
  }
1743
1741
  function sortRecord(record) {
1744
1742
  return Object.fromEntries(Object.entries(record).sort(([left], [right]) => left.localeCompare(right)));
@@ -1848,15 +1846,9 @@ var EnvStage = class {
1848
1846
  maintenance_hint_cooldown_days: 7,
1849
1847
  archive_edit_threshold: 20,
1850
1848
  underseed_node_threshold: 10,
1851
- import_window_first_run_months: 60,
1852
- import_window_rerun_months: 2,
1853
- import_max_pending_per_run: 10,
1854
- import_max_commits_scan: 500,
1855
- import_skip_canonical_threshold: 50,
1856
- archive_max_candidates_per_batch: 8,
1857
- archive_max_recent_paths: 20,
1858
- archive_digest_max_sessions: 10,
1859
- review_topic_result_cap: 8,
1849
+ // ux-w2-3: import_*/archive_max_*/review_topic_result_cap skill thresholds
1850
+ // hardcoded (✂ census Table 1) — no longer scaffolded; skills fall to a
1851
+ // built-in default when the key is absent.
1860
1852
  review_stale_pending_days: 14
1861
1853
  };
1862
1854
  mkdirSync2(fabricDir, { recursive: true });
@@ -2296,6 +2288,8 @@ function validateHookPaths(projectRoot) {
2296
2288
  { stepSuffix: "", hookFile: "fabric-hint.cjs" },
2297
2289
  { stepSuffix: "-broad", hookFile: "knowledge-hint-broad.cjs" },
2298
2290
  { stepSuffix: "-narrow", hookFile: "knowledge-hint-narrow.cjs" },
2291
+ // ux-w2-6: single PreToolUse orchestrator (merges narrow + cite).
2292
+ { stepSuffix: "-pretooluse", hookFile: "knowledge-pretooluse.cjs" },
2299
2293
  // lifecycle-refactor W2-T2/T3: SessionEnd + PostToolUse marker hooks.
2300
2294
  { stepSuffix: "-session-end", hookFile: "session-end-marker.cjs" },
2301
2295
  { stepSuffix: "-post-tooluse", hookFile: "post-tooluse-mutation.cjs" }
@@ -2357,19 +2351,16 @@ var HooksStage = class {
2357
2351
  const target = context.target;
2358
2352
  const installResults = [];
2359
2353
  installResults.push(...await this.runBestEffort("skill-deprecated-cleanup", () => cleanupDeprecatedSkills(target)));
2360
- installResults.push(...await this.runBestEffort("skill-router-install", () => installFabricRouterSkill(target)));
2361
2354
  installResults.push(...await this.runBestEffort("skill-install", () => installFabricArchiveSkill(target)));
2362
2355
  installResults.push(...await this.runBestEffort("skill-review-install", () => installFabricReviewSkill(target)));
2363
- installResults.push(...await this.runBestEffort("skill-import-install", () => installFabricImportSkill(target)));
2364
2356
  installResults.push(...await this.runBestEffort("skill-sync-install", () => installFabricSyncSkill(target)));
2365
2357
  installResults.push(...await this.runBestEffort("skill-store-install", () => installFabricStoreSkill(target)));
2366
- installResults.push(...await this.runBestEffort("skill-audit-install", () => installFabricAuditSkill(target)));
2367
- installResults.push(...await this.runBestEffort("skill-connect-install", () => installFabricConnectSkill(target)));
2368
2358
  installResults.push(...await this.runBestEffort("skill-shared-lib", () => installSharedSkillLib(target)));
2369
2359
  installResults.push(...await this.runBestEffort("hook-script", () => installArchiveHintHook(target)));
2370
2360
  installResults.push(...await this.runBestEffort("hook-broad-script", () => installKnowledgeHintBroadHook(target)));
2371
2361
  installResults.push(...await this.runBestEffort("hook-narrow-script", () => installKnowledgeHintNarrowHook(target)));
2372
2362
  installResults.push(...await this.runBestEffort("hook-cite-policy-evict-script", () => installCitePolicyEvictHook(target)));
2363
+ installResults.push(...await this.runBestEffort("hook-pretooluse-script", () => installKnowledgePretoolUseHook(target)));
2373
2364
  installResults.push(...await this.runBestEffort("hook-session-end-script", () => installSessionEndMarkerHook(target)));
2374
2365
  installResults.push(...await this.runBestEffort("hook-post-tooluse-script", () => installPostTooluseMutationHook(target)));
2375
2366
  installResults.push(...await this.runBestEffort("hook-lib", () => installHookLibs(target)));
@@ -2794,235 +2785,12 @@ var GuidanceStage = class {
2794
2785
  }
2795
2786
  };
2796
2787
 
2797
- // src/tui/StepCounter.tsx
2798
- import { Box, Text } from "ink";
2799
- import { jsx, jsxs } from "react/jsx-runtime";
2800
- var statusColors = {
2801
- pending: "gray",
2802
- running: "cyan",
2803
- success: "green",
2804
- error: "red",
2805
- skipped: "yellow"
2806
- };
2807
- var statusSymbols = {
2808
- pending: "\u25CB",
2809
- running: "\u25CF",
2810
- success: "\u2713",
2811
- error: "\u2717",
2812
- skipped: "\u25CB"
2813
- };
2814
- function StepCounter({
2815
- current,
2816
- total,
2817
- label,
2818
- status = "running"
2819
- }) {
2820
- const color = statusColors[status] || "cyan";
2821
- const symbol = statusSymbols[status] || "\u25CF";
2822
- return /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
2823
- /* @__PURE__ */ jsx(Text, { color, bold: true, children: symbol }),
2824
- /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
2825
- "(",
2826
- current,
2827
- "/",
2828
- total,
2829
- ")"
2830
- ] }),
2831
- /* @__PURE__ */ jsx(Text, { bold: true, children: label })
2832
- ] });
2833
- }
2834
-
2835
- // src/tui/StatusMessage.tsx
2836
- import { Box as Box2, Text as Text2 } from "ink";
2837
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2838
- var typeColors = {
2839
- success: "green",
2840
- error: "red",
2841
- warning: "yellow",
2842
- info: "blue"
2843
- };
2844
- var typeLabels = {
2845
- success: "\u2713",
2846
- error: "\u2717",
2847
- warning: "!",
2848
- info: "\u2139"
2849
- };
2850
- function StatusMessage({
2851
- message,
2852
- type,
2853
- timestamp = false
2854
- }) {
2855
- const color = typeColors[type] || "white";
2856
- const label = typeLabels[type] || "\u2022";
2857
- const timeStr = timestamp ? `[${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] ` : "";
2858
- return /* @__PURE__ */ jsxs2(Box2, { gap: 1, children: [
2859
- /* @__PURE__ */ jsx2(Text2, { color, bold: true, children: label }),
2860
- timestamp && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: timeStr }),
2861
- /* @__PURE__ */ jsx2(Text2, { color: type === "error" ? "red" : void 0, children: message })
2862
- ] });
2863
- }
2864
-
2865
- // src/tui/SummaryCard.tsx
2866
- import { Box as Box3, Text as Text3 } from "ink";
2867
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2868
- function DetailStatus({ status }) {
2869
- if (!status) return null;
2870
- const indicators = {
2871
- success: { symbol: "\u2713", color: "green" },
2872
- error: { symbol: "\u2717", color: "red" },
2873
- skipped: { symbol: "\u25CB", color: "yellow" },
2874
- info: { symbol: "\u2139", color: "blue" }
2875
- };
2876
- const { symbol, color } = indicators[status] || { symbol: "\u2022", color: "white" };
2877
- return /* @__PURE__ */ jsx3(Text3, { color, bold: true, children: symbol });
2878
- }
2879
- function SummaryCard({ summary }) {
2880
- const { title, successCount, skippedCount = 0, errorCount = 0, details = [] } = summary;
2881
- const totalCount = successCount + skippedCount + errorCount;
2882
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [
2883
- /* @__PURE__ */ jsx3(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: "cyan", children: title }) }),
2884
- /* @__PURE__ */ jsxs3(Box3, { gap: 3, children: [
2885
- successCount > 0 && /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
2886
- /* @__PURE__ */ jsx3(Text3, { color: "green", bold: true, children: "\u2713" }),
2887
- /* @__PURE__ */ jsxs3(Text3, { children: [
2888
- successCount,
2889
- " succeeded"
2890
- ] })
2891
- ] }),
2892
- skippedCount > 0 && /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
2893
- /* @__PURE__ */ jsx3(Text3, { color: "yellow", bold: true, children: "\u25CB" }),
2894
- /* @__PURE__ */ jsxs3(Text3, { children: [
2895
- skippedCount,
2896
- " skipped"
2897
- ] })
2898
- ] }),
2899
- errorCount > 0 && /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
2900
- /* @__PURE__ */ jsx3(Text3, { color: "red", bold: true, children: "\u2717" }),
2901
- /* @__PURE__ */ jsxs3(Text3, { children: [
2902
- errorCount,
2903
- " failed"
2904
- ] })
2905
- ] })
2906
- ] }),
2907
- details.length > 0 && /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginTop: 1, children: details.map((detail, index) => /* @__PURE__ */ jsxs3(Box3, { gap: 1, children: [
2908
- /* @__PURE__ */ jsx3(DetailStatus, { status: detail.status }),
2909
- /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
2910
- detail.label,
2911
- ":"
2912
- ] }),
2913
- /* @__PURE__ */ jsx3(Text3, { children: detail.value })
2914
- ] }, index)) }),
2915
- /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: totalCount === successCount ? "All steps completed successfully" : errorCount > 0 ? `${errorCount} step${errorCount > 1 ? "s" : ""} failed` : `${successCount}/${totalCount} steps completed` }) })
2916
- ] });
2917
- }
2918
-
2919
- // src/tui/ErrorBox.tsx
2920
- import { Box as Box4, Text as Text4 } from "ink";
2921
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2922
- function ErrorBox({ error, showStack = false }) {
2923
- const title = error.title || "Error";
2924
- const code = "code" in error ? error.code : void 0;
2925
- const hint = "hint" in error ? error.hint : void 0;
2926
- const stack = "stack" in error ? error.stack : void 0;
2927
- return /* @__PURE__ */ jsxs4(
2928
- Box4,
2929
- {
2930
- flexDirection: "column",
2931
- borderStyle: "round",
2932
- borderColor: "red",
2933
- paddingX: 1,
2934
- children: [
2935
- /* @__PURE__ */ jsxs4(Box4, { gap: 1, children: [
2936
- /* @__PURE__ */ jsxs4(Text4, { color: "red", bold: true, children: [
2937
- "\u2717 ",
2938
- title
2939
- ] }),
2940
- code && /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
2941
- "(",
2942
- code,
2943
- ")"
2944
- ] })
2945
- ] }),
2946
- /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "red", children: error.message }) }),
2947
- hint && /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
2948
- "\u{1F4A1} ",
2949
- hint
2950
- ] }) }),
2951
- showStack && stack && /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginTop: 1, children: [
2952
- /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "Stack trace:" }),
2953
- /* @__PURE__ */ jsx4(Box4, { marginLeft: 2, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, color: "gray", children: stack.split("\n").slice(0, 5).join("\n") }) })
2954
- ] })
2955
- ]
2956
- }
2957
- );
2958
- }
2959
- function toErrorInfo(error) {
2960
- if ("title" in error) {
2961
- return error;
2962
- }
2963
- return {
2964
- title: error.name || "Error",
2965
- message: error.message,
2966
- stack: error.stack
2967
- };
2968
- }
2969
-
2970
- // src/tui/Spinner.tsx
2971
- import { useState, useEffect } from "react";
2972
- import { Text as Text5 } from "ink";
2973
- import { jsxs as jsxs5 } from "react/jsx-runtime";
2974
- var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
2975
- function Spinner({ label }) {
2976
- const [frame, setFrame] = useState(0);
2977
- useEffect(() => {
2978
- const timer = setInterval(() => {
2979
- setFrame((prev) => (prev + 1) % FRAMES.length);
2980
- }, 80);
2981
- return () => clearInterval(timer);
2982
- }, []);
2983
- return /* @__PURE__ */ jsxs5(Text5, { color: "cyan", children: [
2984
- FRAMES[frame],
2985
- " ",
2986
- label || "Loading..."
2987
- ] });
2988
- }
2989
-
2990
- // src/tui/ProgressBar.tsx
2991
- import { Box as Box5, Text as Text6 } from "ink";
2992
- import { jsx as jsx5, jsxs as jsxs6 } from "react/jsx-runtime";
2993
-
2994
- // src/tui/SectionHeader.tsx
2995
- import { Box as Box6, Text as Text7 } from "ink";
2996
- import { jsx as jsx6, jsxs as jsxs7 } from "react/jsx-runtime";
2997
- function SectionHeader({ title, subtitle }) {
2998
- return /* @__PURE__ */ jsxs7(Box6, { flexDirection: "column", marginBottom: 1, children: [
2999
- /* @__PURE__ */ jsx6(Box6, { borderStyle: "classic", borderColor: "gray", children: /* @__PURE__ */ jsx6(Box6, { paddingX: 1, children: /* @__PURE__ */ jsx6(Text7, { bold: true, color: "cyan", children: title }) }) }),
3000
- subtitle && /* @__PURE__ */ jsx6(Box6, { marginLeft: 2, children: /* @__PURE__ */ jsx6(Text7, { dimColor: true, children: subtitle }) })
3001
- ] });
3002
- }
3003
-
3004
- // src/tui/StoreWizard.tsx
3005
- import { useState as useState2 } from "react";
3006
- import { Box as Box7, Text as Text8, useInput } from "ink";
3007
- import { jsx as jsx7, jsxs as jsxs8 } from "react/jsx-runtime";
3008
-
3009
- // src/tui/InputField.tsx
3010
- import { useState as useState3 } from "react";
3011
- import { Box as Box8, Text as Text9, useInput as useInput2, useApp } from "ink";
3012
- import { jsx as jsx8, jsxs as jsxs9 } from "react/jsx-runtime";
3013
-
3014
- // src/tui/StoreWizardFlow.tsx
3015
- import { useState as useState4, useCallback } from "react";
3016
- import { render } from "ink";
3017
- import { jsx as jsx9 } from "react/jsx-runtime";
3018
-
3019
- // src/tui/InkOutputRenderer.ts
3020
- import { render as render2 } from "ink";
3021
- import React2 from "react";
3022
- var InkOutputRenderer = class {
2788
+ // src/tui/ConsoleOutputRenderer.ts
2789
+ import { paint as paint2, symbol, sectionBar, isColorEnabled } from "@fenglimg/fabric-shared/theme";
2790
+ var ConsoleOutputRenderer = class {
3023
2791
  config;
2792
+ colorOn;
3024
2793
  currentStep = null;
3025
- inkInstances = [];
3026
2794
  constructor(config = {}) {
3027
2795
  this.config = {
3028
2796
  colors: true,
@@ -3030,129 +2798,160 @@ var InkOutputRenderer = class {
3030
2798
  timestamps: false,
3031
2799
  ...config
3032
2800
  };
2801
+ this.colorOn = this.config.colors === false ? false : isColorEnabled(process.env, process.stdout.isTTY);
2802
+ }
2803
+ write(line) {
2804
+ console.log(line);
2805
+ }
2806
+ /** Status-message marker by type (StatusMessage glyph + role color, mapped down). */
2807
+ statusMarker(type) {
2808
+ switch (type) {
2809
+ case "success":
2810
+ return symbol("ok", this.colorOn);
2811
+ case "error":
2812
+ return symbol("error", this.colorOn);
2813
+ case "warning":
2814
+ return symbol("warn", this.colorOn);
2815
+ case "info":
2816
+ default:
2817
+ return paint2("ai", "\u2139", this.colorOn);
2818
+ }
3033
2819
  }
3034
- /**
3035
- * Render a React component and wait for it to render
3036
- */
3037
- renderComponent(node) {
3038
- const { unmount } = render2(node);
3039
- this.inkInstances.push({ unmount });
2820
+ renderStatus(message, type) {
2821
+ const marker = this.statusMarker(type);
2822
+ const body = type === "error" ? paint2("error", message, this.colorOn) : message;
2823
+ this.write(`${marker} ${body}`);
3040
2824
  }
3041
- /**
3042
- * Render a step progress indicator
3043
- */
3044
2825
  renderStep(step) {
3045
2826
  this.currentStep = step;
3046
- if (step.status === "running") {
3047
- this.renderComponent(
3048
- React2.createElement(Spinner, { label: step.name })
3049
- );
3050
- } else {
3051
- this.renderComponent(
3052
- React2.createElement(StepCounter, {
3053
- current: step.current,
3054
- total: step.total,
3055
- label: step.name,
3056
- status: step.status
3057
- })
3058
- );
3059
- }
2827
+ this.write(buildStepLine(step, this.colorOn));
3060
2828
  if (step.detail) {
3061
- this.renderComponent(
3062
- React2.createElement(StatusMessage, {
3063
- message: step.detail,
3064
- type: step.status === "error" ? "error" : "info"
3065
- })
3066
- );
2829
+ this.renderStatus(step.detail, step.status === "error" ? "error" : "info");
3067
2830
  }
3068
2831
  }
3069
- /**
3070
- * Render a success message
3071
- */
3072
2832
  renderSuccess(message) {
3073
- this.renderComponent(
3074
- React2.createElement(StatusMessage, {
3075
- message,
3076
- type: "success"
3077
- })
3078
- );
2833
+ this.renderStatus(message, "success");
3079
2834
  }
3080
- /**
3081
- * Render an error
3082
- */
3083
2835
  renderError(error) {
3084
- const errorInfo = error instanceof Error ? toErrorInfo(error) : error;
3085
- this.renderComponent(
3086
- React2.createElement(ErrorBox, {
3087
- error: errorInfo,
3088
- showStack: this.config.verbose
3089
- })
3090
- );
2836
+ const info = error instanceof Error ? toErrorInfo(error) : error;
2837
+ this.write(buildErrorBlock(info, Boolean(this.config.verbose), this.colorOn));
3091
2838
  }
3092
- /**
3093
- * Render a warning message
3094
- */
3095
2839
  renderWarning(message) {
3096
- this.renderComponent(
3097
- React2.createElement(StatusMessage, {
3098
- message,
3099
- type: "warning"
3100
- })
3101
- );
2840
+ this.renderStatus(message, "warning");
3102
2841
  }
3103
- /**
3104
- * Render an info message
3105
- */
3106
2842
  renderInfo(message) {
3107
- this.renderComponent(
3108
- React2.createElement(StatusMessage, {
3109
- message,
3110
- type: "info"
3111
- })
3112
- );
2843
+ this.renderStatus(message, "info");
3113
2844
  }
3114
- /**
3115
- * Render a summary card
3116
- */
3117
2845
  renderSummaryCard(summary) {
3118
- this.renderComponent(
3119
- React2.createElement(SummaryCard, { summary })
3120
- );
2846
+ this.write(sectionBar(summary.title, this.colorOn));
2847
+ this.write(buildSummaryBlock(summary, this.colorOn));
3121
2848
  }
3122
- /**
3123
- * Render a section header
3124
- */
3125
2849
  renderSection(title) {
3126
- this.renderComponent(
3127
- React2.createElement(SectionHeader, { title })
3128
- );
2850
+ this.write("");
2851
+ this.write(sectionBar(title, this.colorOn));
3129
2852
  }
3130
- /**
3131
- * Render a final completion message
3132
- */
3133
2853
  renderComplete() {
3134
- this.renderComponent(
3135
- React2.createElement(StatusMessage, {
3136
- message: "Done!",
3137
- type: "success"
3138
- })
3139
- );
2854
+ this.renderStatus("Done!", "success");
3140
2855
  }
3141
- /**
3142
- * Clean up any pending renders
3143
- */
3144
2856
  async cleanup() {
3145
- for (const instance of this.inkInstances) {
3146
- try {
3147
- instance.unmount();
3148
- } catch {
3149
- }
3150
- }
3151
- this.inkInstances = [];
2857
+ this.currentStep = null;
3152
2858
  }
3153
2859
  };
3154
- function createInkRenderer(config) {
3155
- return new InkOutputRenderer(config);
2860
+ function toErrorInfo(error) {
2861
+ if ("title" in error) {
2862
+ return error;
2863
+ }
2864
+ return {
2865
+ title: error.name || "Error",
2866
+ message: error.message,
2867
+ stack: error.stack
2868
+ };
2869
+ }
2870
+ function stepBadge(status, colorOn) {
2871
+ switch (status) {
2872
+ case "success":
2873
+ return symbol("ok", colorOn);
2874
+ case "error":
2875
+ return symbol("error", colorOn);
2876
+ case "skipped":
2877
+ return symbol("warn", colorOn);
2878
+ case "running":
2879
+ return paint2("ai", "[..]", colorOn);
2880
+ case "pending":
2881
+ default:
2882
+ return paint2("muted", "[--]", colorOn);
2883
+ }
2884
+ }
2885
+ function buildStepLine(step, colorOn) {
2886
+ const badge = stepBadge(step.status, colorOn);
2887
+ const counter = paint2("muted", `(${step.current}/${step.total})`, colorOn);
2888
+ const name = step.name || (step.status === "running" ? "Loading..." : "");
2889
+ const last = step.total > 0 && step.current >= step.total;
2890
+ const text3 = `${badge} ${name} ${counter}`.replace(/\s+$/u, "");
2891
+ if (last) {
2892
+ return tree([{ text: text3 }]);
2893
+ }
2894
+ return tree([{ text: text3 }, { text: "" }]).split("\n")[0];
2895
+ }
2896
+ function detailMarker(status, colorOn) {
2897
+ switch (status) {
2898
+ case "success":
2899
+ return paint2("success", "\u2713", colorOn);
2900
+ case "error":
2901
+ return paint2("error", "\u2717", colorOn);
2902
+ case "skipped":
2903
+ return paint2("warn", "\u25CB", colorOn);
2904
+ case "info":
2905
+ return paint2("ai", "\u2139", colorOn);
2906
+ default:
2907
+ return null;
2908
+ }
2909
+ }
2910
+ function buildSummaryBlock(summary, colorOn) {
2911
+ const { successCount, skippedCount = 0, errorCount = 0, details = [] } = summary;
2912
+ const totalCount = successCount + skippedCount + errorCount;
2913
+ const lines = [];
2914
+ const countCells = [
2915
+ `${paint2("success", "\u2713", colorOn)} ${successCount} succeeded`,
2916
+ `${paint2("warn", "\u25CB", colorOn)} ${skippedCount} skipped`,
2917
+ `${paint2("error", "\u2717", colorOn)} ${errorCount} failed`
2918
+ ];
2919
+ lines.push(` ${grid([countCells], { gap: 4 })}`);
2920
+ for (const detail of details) {
2921
+ const marker = detailMarker(detail.status, colorOn);
2922
+ const label = paint2("muted", `${detail.label}:`, colorOn);
2923
+ lines.push(` ${marker ? `${marker} ` : ""}${label} ${detail.value}`);
2924
+ }
2925
+ const summaryLine = totalCount === successCount ? "All steps completed successfully" : errorCount > 0 ? `${errorCount} step${errorCount > 1 ? "s" : ""} failed` : `${successCount}/${totalCount} steps completed`;
2926
+ lines.push(` ${paint2("muted", summaryLine, colorOn)}`);
2927
+ return lines.join("\n");
2928
+ }
2929
+ function leftBar(colorOn) {
2930
+ return colorOn ? paint2("accent", "\u2502", colorOn) + " " : "| ";
2931
+ }
2932
+ function buildErrorBlock(info, verbose, colorOn) {
2933
+ const title = info.title || "Error";
2934
+ const code = info.code;
2935
+ const hint = info.hint;
2936
+ const stack = info.stack;
2937
+ const header = sectionBar(`[err] ${title}`, colorOn);
2938
+ const bar = leftBar(colorOn);
2939
+ const lines = [header, ""];
2940
+ const message = code ? `${info.message} ${paint2("muted", `(${code})`, colorOn)}` : info.message;
2941
+ lines.push(` ${bar}${paint2("error", message, colorOn)}`);
2942
+ if (hint) {
2943
+ lines.push(` ${bar.trimEnd()}`);
2944
+ lines.push(` ${bar}${paint2("muted", `\u{1F4A1} ${hint}`, colorOn)}`);
2945
+ }
2946
+ if (verbose && stack) {
2947
+ for (const frame of stack.split("\n").slice(0, 5)) {
2948
+ lines.push(` ${bar}${paint2("muted", `\u21B3 ${frame.trim()}`, colorOn)}`);
2949
+ }
2950
+ }
2951
+ return lines.join("\n");
2952
+ }
2953
+ function createInstallRenderer(config) {
2954
+ return new ConsoleOutputRenderer(config);
3156
2955
  }
3157
2956
 
3158
2957
  // src/commands/install-v2.ts
@@ -3225,7 +3024,7 @@ async function runInitCommand(args) {
3225
3024
  logger(step);
3226
3025
  }
3227
3026
  const terminalInteractive = isInteractiveInit();
3228
- const renderer = shouldUseInstallRenderer(args, terminalInteractive) ? createInkRenderer({ verbose: args.debug }) : void 0;
3027
+ const renderer = shouldUseInstallRenderer(args, terminalInteractive) ? createInstallRenderer({ verbose: args.debug }) : void 0;
3229
3028
  const context = createInstallContext(args, resolution.target, renderer);
3230
3029
  const pipeline = new InstallPipeline().addStage(new PreflightStage()).addStage(new EnvStage()).addStage(new StoreStage()).addStage(new HooksStage()).addStage(new McpStage()).addStage(new ValidateStage()).addStage(new GuidanceStage());
3231
3030
  const result = await pipeline.execute(context);