@fenglimg/fabric-cli 2.0.0 → 2.1.0-rc.2

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 (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -5
  3. package/dist/chunk-BATF4PEJ.js +361 -0
  4. package/dist/{chunk-OBQU6NHO.js → chunk-COI5VDFU.js} +0 -18
  5. package/dist/chunk-F46ORPOA.js +903 -0
  6. package/dist/chunk-HFQVXY6P.js +86 -0
  7. package/dist/chunk-L4Q55UC4.js +52 -0
  8. package/dist/chunk-LFIKMVY7.js +27 -0
  9. package/dist/chunk-MF3OTILQ.js +544 -0
  10. package/dist/chunk-PWLW3B57.js +18 -0
  11. package/dist/chunk-RYAFBNES.js +33 -0
  12. package/dist/chunk-T5RPGCCM.js +40 -0
  13. package/dist/chunk-WU6GAPKH.js +36 -0
  14. package/dist/config-XJIPZNUP.js +13 -0
  15. package/dist/doctor-QVNPHLJK.js +920 -0
  16. package/dist/index.js +23 -8
  17. package/dist/{init-BIRSIOXO.js → install-2HDO5FTQ.js} +807 -705
  18. package/dist/metrics-ACEQFPDU.js +122 -0
  19. package/dist/onboard-coverage-MFCAEBDO.js +220 -0
  20. package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-FC6P3WFE.js} +34 -28
  21. package/dist/scope-explain-2F2R5URO.js +33 -0
  22. package/dist/status-GLQWLWH6.js +23 -0
  23. package/dist/store-XTSE5TY6.js +105 -0
  24. package/dist/sync-BJCWDPNC.js +245 -0
  25. package/dist/uninstall-TAXSUSKH.js +1073 -0
  26. package/dist/whoami-B6AEMSEV.js +31 -0
  27. package/package.json +30 -5
  28. package/templates/hooks/cite-policy-evict.cjs +231 -0
  29. package/templates/hooks/configs/README.md +29 -6
  30. package/templates/hooks/configs/claude-code.json +14 -3
  31. package/templates/hooks/configs/codex-hooks.json +6 -3
  32. package/templates/hooks/configs/cursor-hooks.json +8 -10
  33. package/templates/hooks/fabric-hint.cjs +873 -105
  34. package/templates/hooks/knowledge-hint-broad.cjs +549 -135
  35. package/templates/hooks/knowledge-hint-narrow.cjs +830 -26
  36. package/templates/hooks/lib/banner-i18n.cjs +309 -0
  37. package/templates/hooks/lib/bindings-snapshot-reader.cjs +81 -0
  38. package/templates/hooks/lib/cite-contract-reminder.cjs +179 -0
  39. package/templates/hooks/lib/cite-line-parser.cjs +180 -0
  40. package/templates/hooks/lib/client-adapter.cjs +106 -0
  41. package/templates/hooks/lib/config-cache.cjs +107 -0
  42. package/templates/hooks/lib/state-store.cjs +84 -0
  43. package/templates/hooks/lib/summary-fallback.cjs +210 -0
  44. package/templates/skills/fabric-archive/SKILL.md +97 -419
  45. package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
  46. package/templates/skills/fabric-archive/ref/e5-cron-recap.md +58 -0
  47. package/templates/skills/fabric-archive/ref/i18n-policy.md +86 -0
  48. package/templates/skills/fabric-archive/ref/phase-0-range-resolution.md +156 -0
  49. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +218 -0
  50. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +62 -0
  51. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +68 -0
  52. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +108 -0
  53. package/templates/skills/fabric-archive/ref/phase-3-classify.md +63 -0
  54. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +78 -0
  55. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +89 -0
  56. package/templates/skills/fabric-archive/ref/rc-history.md +38 -0
  57. package/templates/skills/fabric-archive/ref/worked-examples.md +78 -0
  58. package/templates/skills/fabric-import/SKILL.md +77 -514
  59. package/templates/skills/fabric-import/ref/checkpoint-state.md +85 -0
  60. package/templates/skills/fabric-import/ref/i18n-policy.md +79 -0
  61. package/templates/skills/fabric-import/ref/output-contract.md +61 -0
  62. package/templates/skills/fabric-import/ref/phase-2-mining.md +213 -0
  63. package/templates/skills/fabric-import/ref/phase-3-dedup.md +75 -0
  64. package/templates/skills/fabric-import/ref/state-recovery.md +57 -0
  65. package/templates/skills/fabric-import/ref/worked-examples.md +127 -0
  66. package/templates/skills/fabric-review/SKILL.md +90 -284
  67. package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
  68. package/templates/skills/fabric-review/ref/i18n-policy.md +111 -0
  69. package/templates/skills/fabric-review/ref/modify-flow.md +103 -0
  70. package/templates/skills/fabric-review/ref/output-contract.md +58 -0
  71. package/templates/skills/fabric-review/ref/per-mode-flows.md +155 -0
  72. package/templates/skills/fabric-review/ref/semantic-check.md +26 -0
  73. package/templates/skills/fabric-review/ref/worked-examples.md +95 -0
  74. package/templates/skills/fabric-sync/SKILL.md +46 -0
  75. package/templates/skills/lib/shared-policy.md +69 -0
  76. package/dist/chunk-6ICJICVU.js +0 -10
  77. package/dist/chunk-74SZWYPH.js +0 -658
  78. package/dist/chunk-EYIDD2YS.js +0 -1000
  79. package/dist/doctor-T7JWODKG.js +0 -282
  80. package/dist/hooks-Y74Y5LQS.js +0 -12
  81. package/dist/scan-LMK3UCWL.js +0 -22
  82. package/dist/serve-H554BHLG.js +0 -124
  83. package/templates/agents-md/AGENTS.md.template +0 -59
  84. package/templates/bootstrap/CLAUDE.md +0 -8
  85. package/templates/bootstrap/codex-AGENTS-header.md +0 -6
  86. package/templates/bootstrap/cursor-fabric-bootstrap.mdc +0 -10
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ regenerateBindingsSnapshot
4
+ } from "./chunk-WU6GAPKH.js";
5
+ import "./chunk-L4Q55UC4.js";
6
+ import "./chunk-LFIKMVY7.js";
7
+ import {
8
+ loadGlobalConfig,
9
+ resolveGlobalRoot
10
+ } from "./chunk-RYAFBNES.js";
11
+
12
+ // src/commands/sync.ts
13
+ import { defineCommand } from "citty";
14
+
15
+ // src/sync/run-sync.ts
16
+ import { execFileSync } from "child_process";
17
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
18
+ import { join } from "path";
19
+ import { GLOBAL_STATE_DIR, storeRelativePath } from "@fenglimg/fabric-shared";
20
+
21
+ // src/sync/state-machine.ts
22
+ function syncTransition(state, event) {
23
+ switch (state) {
24
+ case "pending":
25
+ if (event === "rebase_clean") return "synced";
26
+ if (event === "rebase_conflict") return "conflict";
27
+ if (event === "network_unavailable") return "offline";
28
+ break;
29
+ case "conflict":
30
+ if (event === "user_continue") return "synced";
31
+ if (event === "user_abort") return "aborted";
32
+ break;
33
+ case "offline":
34
+ if (event === "retry" || event === "rebase_clean") return "synced";
35
+ if (event === "rebase_conflict") return "conflict";
36
+ if (event === "network_unavailable") return "offline";
37
+ break;
38
+ case "synced":
39
+ case "aborted":
40
+ break;
41
+ }
42
+ throw new Error(`invalid sync transition: '${state}' --${event}-->`);
43
+ }
44
+ function planSync(stores) {
45
+ return { stores: stores.map((s) => ({ ...s, state: "pending" })) };
46
+ }
47
+ function applySyncEvent(session, alias, event) {
48
+ return {
49
+ stores: session.stores.map(
50
+ (s) => s.alias === alias ? { ...s, state: syncTransition(s.state, event) } : s
51
+ )
52
+ };
53
+ }
54
+ function continueSync(session) {
55
+ const conflicted = session.stores.find((s) => s.state === "conflict");
56
+ if (conflicted === void 0) {
57
+ throw new Error("`sync --continue` with no conflicted store to resume");
58
+ }
59
+ return applySyncEvent(session, conflicted.alias, "user_continue");
60
+ }
61
+ function abortSync(session) {
62
+ const conflicted = session.stores.find((s) => s.state === "conflict");
63
+ if (conflicted === void 0) {
64
+ throw new Error("`sync --abort` with no conflicted store to abort");
65
+ }
66
+ return applySyncEvent(session, conflicted.alias, "user_abort");
67
+ }
68
+ function isSyncSettled(session) {
69
+ return session.stores.every((s) => s.state !== "pending" && s.state !== "conflict");
70
+ }
71
+ function deferredPushStores(session) {
72
+ return session.stores.filter((s) => s.state === "offline");
73
+ }
74
+
75
+ // src/sync/run-sync.ts
76
+ var NO_GLOBAL_CONFIG = "no global Fabric config \u2014 run `fabric install --global <url>` first";
77
+ var NO_SESSION = "no sync in progress \u2014 run `fabric sync` first";
78
+ var NO_CONFLICT = "no conflicted store to resume \u2014 sync is not paused";
79
+ function syncSessionPath(globalRoot) {
80
+ return join(globalRoot, GLOBAL_STATE_DIR, "sync-session.json");
81
+ }
82
+ function loadSession(globalRoot) {
83
+ const path = syncSessionPath(globalRoot);
84
+ if (!existsSync(path)) {
85
+ return null;
86
+ }
87
+ return JSON.parse(readFileSync(path, "utf8"));
88
+ }
89
+ function saveSession(globalRoot, session) {
90
+ const path = syncSessionPath(globalRoot);
91
+ mkdirSync(join(path, ".."), { recursive: true });
92
+ writeFileSync(path, `${JSON.stringify(session, null, 2)}
93
+ `, "utf8");
94
+ }
95
+ function clearSession(globalRoot) {
96
+ rmSync(syncSessionPath(globalRoot), { force: true });
97
+ }
98
+ function defaultPull(storeDir) {
99
+ try {
100
+ execFileSync("git", ["pull", "--rebase"], {
101
+ cwd: storeDir,
102
+ stdio: ["ignore", "pipe", "pipe"]
103
+ });
104
+ return "clean";
105
+ } catch (error) {
106
+ const detail = `${gitErrText(error, "stdout")}${gitErrText(error, "stderr")}`;
107
+ if (/CONFLICT|could not apply|needs merge|rebase --continue/i.test(detail)) {
108
+ return "conflict";
109
+ }
110
+ if (/could not resolve host|could not read from remote|unable to access|connection|network is unreachable|timed out/i.test(
111
+ detail
112
+ )) {
113
+ return "offline";
114
+ }
115
+ throw error;
116
+ }
117
+ }
118
+ function gitErrText(error, key) {
119
+ const value = error[key];
120
+ return typeof value === "string" || Buffer.isBuffer(value) ? String(value) : "";
121
+ }
122
+ function defaultRebaseContinue(storeDir) {
123
+ execFileSync("git", ["rebase", "--continue"], { cwd: storeDir, stdio: "ignore" });
124
+ }
125
+ function defaultRebaseAbort(storeDir) {
126
+ execFileSync("git", ["rebase", "--abort"], { cwd: storeDir, stdio: "ignore" });
127
+ }
128
+ var OUTCOME_EVENT = {
129
+ clean: "rebase_clean",
130
+ conflict: "rebase_conflict",
131
+ offline: "network_unavailable"
132
+ };
133
+ function walkPending(session, storeDirOf, pull) {
134
+ let next = session;
135
+ for (const store of session.stores) {
136
+ if (store.state !== "pending") {
137
+ continue;
138
+ }
139
+ const outcome = pull(storeDirOf(store));
140
+ next = applySyncEvent(next, store.alias, OUTCOME_EVENT[outcome]);
141
+ if (outcome === "conflict") {
142
+ break;
143
+ }
144
+ }
145
+ return next;
146
+ }
147
+ function finalize(session, options, globalRoot) {
148
+ const settled = isSyncSettled(session);
149
+ let snapshotWritten = false;
150
+ if (settled) {
151
+ clearSession(globalRoot);
152
+ const snapshot = regenerateBindingsSnapshot(options.projectRoot, {
153
+ globalRoot,
154
+ now: options.now,
155
+ ...options.writeScope === void 0 ? {} : { writeScope: options.writeScope }
156
+ });
157
+ snapshotWritten = snapshot !== null;
158
+ } else {
159
+ saveSession(globalRoot, session);
160
+ }
161
+ return { session, settled, deferred: deferredPushStores(session), snapshotWritten };
162
+ }
163
+ function runStartSync(options) {
164
+ const globalRoot = options.globalRoot ?? resolveGlobalRoot();
165
+ const config = loadGlobalConfig(globalRoot);
166
+ if (config === null) {
167
+ throw new Error(NO_GLOBAL_CONFIG);
168
+ }
169
+ const syncable = config.stores.filter((store) => store.remote !== void 0);
170
+ const session = planSync(
171
+ syncable.map((store) => ({ alias: store.alias, store_uuid: store.store_uuid }))
172
+ );
173
+ const storeDirOf = (status) => join(globalRoot, storeRelativePath(status.store_uuid));
174
+ const walked = walkPending(session, storeDirOf, options.pull ?? defaultPull);
175
+ return finalize(walked, options, globalRoot);
176
+ }
177
+ function runContinueSync(options) {
178
+ const globalRoot = options.globalRoot ?? resolveGlobalRoot();
179
+ const session = loadSession(globalRoot);
180
+ if (session === null) {
181
+ throw new Error(NO_SESSION);
182
+ }
183
+ const conflicted = session.stores.find((store) => store.state === "conflict");
184
+ if (conflicted === void 0) {
185
+ throw new Error(NO_CONFLICT);
186
+ }
187
+ const storeDirOf = (status) => join(globalRoot, storeRelativePath(status.store_uuid));
188
+ (options.rebaseContinue ?? defaultRebaseContinue)(storeDirOf(conflicted));
189
+ const resumed = walkPending(continueSync(session), storeDirOf, options.pull ?? defaultPull);
190
+ return finalize(resumed, options, globalRoot);
191
+ }
192
+ function runAbortSync(options) {
193
+ const globalRoot = options.globalRoot ?? resolveGlobalRoot();
194
+ const session = loadSession(globalRoot);
195
+ if (session === null) {
196
+ throw new Error(NO_SESSION);
197
+ }
198
+ const conflicted = session.stores.find((store) => store.state === "conflict");
199
+ if (conflicted === void 0) {
200
+ throw new Error(NO_CONFLICT);
201
+ }
202
+ const storeDirOf = (status) => join(globalRoot, storeRelativePath(status.store_uuid));
203
+ (options.rebaseAbort ?? defaultRebaseAbort)(storeDirOf(conflicted));
204
+ const resumed = walkPending(abortSync(session), storeDirOf, options.pull ?? defaultPull);
205
+ return finalize(resumed, options, globalRoot);
206
+ }
207
+
208
+ // src/commands/sync.ts
209
+ function report(result) {
210
+ for (const store of result.session.stores) {
211
+ console.log(`${store.alias} ${store.state}`);
212
+ }
213
+ if (result.deferred.length > 0) {
214
+ console.log(
215
+ `${result.deferred.length} store(s) offline \u2014 push deferred; re-run \`fabric sync\` when online`
216
+ );
217
+ }
218
+ if (!result.settled) {
219
+ console.log(
220
+ "sync paused on a conflict \u2014 resolve it, then run `fabric sync --continue` (or `--abort`)"
221
+ );
222
+ }
223
+ }
224
+ var sync_default = defineCommand({
225
+ meta: { name: "sync", description: "Pull --rebase + push every mounted store; resume conflicts" },
226
+ args: {
227
+ continue: { type: "boolean", description: "Resume after resolving a rebase conflict" },
228
+ abort: { type: "boolean", description: "Abort the conflicted store's rebase" }
229
+ },
230
+ run({ args }) {
231
+ const options = { projectRoot: process.cwd(), now: (/* @__PURE__ */ new Date()).toISOString() };
232
+ if (args.continue === true) {
233
+ report(runContinueSync(options));
234
+ return;
235
+ }
236
+ if (args.abort === true) {
237
+ report(runAbortSync(options));
238
+ return;
239
+ }
240
+ report(runStartSync(options));
241
+ }
242
+ });
243
+ export {
244
+ sync_default as default
245
+ };