@fenglimg/fabric-cli 2.1.0-rc.2 → 2.2.0-rc.3
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/dist/{chunk-PWLW3B57.js → chunk-2CY4BMTH.js} +5 -1
- package/dist/chunk-5LQIHYFC.js +64 -0
- package/dist/chunk-5ZUMLCD5.js +248 -0
- package/dist/{chunk-WWNXR34K.js → chunk-BO4XIZWZ.js} +8 -1
- package/dist/chunk-EOT63RDH.js +36 -0
- package/dist/{chunk-BATF4PEJ.js → chunk-F6ITRM7T.js} +4 -4
- package/dist/{chunk-WU6GAPKH.js → chunk-H3FE6VIK.js} +3 -5
- package/dist/{chunk-MF3OTILQ.js → chunk-XC5RUHLK.js} +29 -8
- package/dist/chunk-XCBVSGCS.js +25 -0
- package/dist/{chunk-F46ORPOA.js → chunk-XHHCRDIR.js} +149 -7
- package/dist/{config-XJIPZNUP.js → config-VJMXCLXW.js} +3 -3
- package/dist/{doctor-QVNPHLJK.js → doctor-J4O3X54I.js} +154 -30
- package/dist/index.js +57 -16
- package/dist/{install-2HDO5FTQ.js → install-BULNDUIM.js} +241 -108
- package/dist/{metrics-ACEQFPDU.js → metrics-RER6NLFC.js} +22 -9
- package/dist/{onboard-coverage-MFCAEBDO.js → onboard-coverage-JWQWDZW7.js} +1 -1
- package/dist/{plan-context-hint-FC6P3WFE.js → plan-context-hint-CHVZGOZ5.js} +21 -8
- package/dist/{scope-explain-2F2R5URO.js → scope-explain-BWRWBCCP.js} +19 -5
- package/dist/{status-GLQWLWH6.js → status-PANEGKU2.js} +17 -6
- package/dist/store-66NK2FTQ.js +443 -0
- package/dist/sync-EA5HZMXM.js +395 -0
- package/dist/{uninstall-TAXSUSKH.js → uninstall-F75MPKQC.js} +61 -4
- package/dist/whoami-66YKY5DZ.js +47 -0
- package/package.json +3 -3
- package/templates/hooks/cite-policy-evict.cjs +412 -160
- package/templates/hooks/configs/claude-code.json +17 -2
- package/templates/hooks/configs/codex-hooks.json +14 -2
- package/templates/hooks/configs/cursor-hooks.json +14 -2
- package/templates/hooks/fabric-hint.cjs +247 -19
- package/templates/hooks/knowledge-hint-broad.cjs +176 -10
- package/templates/hooks/knowledge-hint-narrow.cjs +64 -5
- package/templates/hooks/lib/injection-log.cjs +91 -0
- package/templates/hooks/lib/state-store.cjs +30 -11
- package/templates/hooks/post-tooluse-mutation.cjs +285 -0
- package/templates/hooks/session-end-marker.cjs +140 -0
- package/templates/skills/fabric-archive/SKILL.md +7 -1
- package/templates/skills/fabric-audit/SKILL.md +53 -0
- package/templates/skills/fabric-connect/SKILL.md +48 -0
- package/templates/skills/fabric-review/SKILL.md +2 -0
- package/templates/skills/fabric-review/ref/cite-contract.md +56 -0
- package/templates/skills/fabric-store/SKILL.md +44 -0
- package/dist/chunk-HFQVXY6P.js +0 -86
- package/dist/chunk-L4Q55UC4.js +0 -52
- package/dist/chunk-LFIKMVY7.js +0 -27
- package/dist/chunk-RYAFBNES.js +0 -33
- package/dist/chunk-T5RPGCCM.js +0 -40
- package/dist/store-XTSE5TY6.js +0 -105
- package/dist/sync-BJCWDPNC.js +0 -245
- package/dist/whoami-B6AEMSEV.js +0 -31
package/dist/chunk-HFQVXY6P.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadProjectConfig,
|
|
4
|
-
saveProjectConfig
|
|
5
|
-
} from "./chunk-LFIKMVY7.js";
|
|
6
|
-
import {
|
|
7
|
-
loadGlobalConfig,
|
|
8
|
-
resolveGlobalRoot,
|
|
9
|
-
saveGlobalConfig
|
|
10
|
-
} from "./chunk-RYAFBNES.js";
|
|
11
|
-
|
|
12
|
-
// src/store/store-ops.ts
|
|
13
|
-
import {
|
|
14
|
-
addMountedStore,
|
|
15
|
-
bindRequiredStore,
|
|
16
|
-
detachMountedStore,
|
|
17
|
-
explainStore
|
|
18
|
-
} from "@fenglimg/fabric-shared";
|
|
19
|
-
var NO_GLOBAL_CONFIG = "no global Fabric config found \u2014 run `fabric install --global <url>` first";
|
|
20
|
-
function requireConfig(globalRoot) {
|
|
21
|
-
const config = loadGlobalConfig(globalRoot);
|
|
22
|
-
if (config === null) {
|
|
23
|
-
throw new Error(NO_GLOBAL_CONFIG);
|
|
24
|
-
}
|
|
25
|
-
return config;
|
|
26
|
-
}
|
|
27
|
-
function storeList(globalRoot = resolveGlobalRoot()) {
|
|
28
|
-
return requireConfig(globalRoot).stores;
|
|
29
|
-
}
|
|
30
|
-
function storeAdd(store, globalRoot = resolveGlobalRoot()) {
|
|
31
|
-
const next = addMountedStore(requireConfig(globalRoot), store);
|
|
32
|
-
saveGlobalConfig(next, globalRoot);
|
|
33
|
-
return next;
|
|
34
|
-
}
|
|
35
|
-
function storeRemove(alias, globalRoot = resolveGlobalRoot()) {
|
|
36
|
-
const result = detachMountedStore(requireConfig(globalRoot), alias);
|
|
37
|
-
saveGlobalConfig(result.config, globalRoot);
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
function storeExplain(alias, globalRoot = resolveGlobalRoot()) {
|
|
41
|
-
return explainStore(requireConfig(globalRoot), alias);
|
|
42
|
-
}
|
|
43
|
-
var NO_PROJECT_CONFIG = "no project Fabric config \u2014 run `fabric install` in this repo first";
|
|
44
|
-
function requireProjectConfig(projectRoot) {
|
|
45
|
-
const config = loadProjectConfig(projectRoot);
|
|
46
|
-
if (config === null) {
|
|
47
|
-
throw new Error(NO_PROJECT_CONFIG);
|
|
48
|
-
}
|
|
49
|
-
return config;
|
|
50
|
-
}
|
|
51
|
-
function storeBind(projectRoot, entry) {
|
|
52
|
-
const config = requireProjectConfig(projectRoot);
|
|
53
|
-
const next = {
|
|
54
|
-
...config,
|
|
55
|
-
required_stores: bindRequiredStore(config.required_stores ?? [], entry)
|
|
56
|
-
};
|
|
57
|
-
saveProjectConfig(next, projectRoot);
|
|
58
|
-
return next;
|
|
59
|
-
}
|
|
60
|
-
function storeSwitchWrite(projectRoot, alias) {
|
|
61
|
-
const config = requireProjectConfig(projectRoot);
|
|
62
|
-
const next = { ...config, active_write_store: alias };
|
|
63
|
-
saveProjectConfig(next, projectRoot);
|
|
64
|
-
return next;
|
|
65
|
-
}
|
|
66
|
-
function missingRequiredStores(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
67
|
-
const project = loadProjectConfig(projectRoot);
|
|
68
|
-
if (project === null || project.required_stores === void 0) {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
const global = loadGlobalConfig(globalRoot);
|
|
72
|
-
const mounted = new Set(
|
|
73
|
-
(global?.stores ?? []).flatMap((s) => [s.alias, s.store_uuid])
|
|
74
|
-
);
|
|
75
|
-
return project.required_stores.filter((r) => !mounted.has(r.id));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export {
|
|
79
|
-
storeList,
|
|
80
|
-
storeAdd,
|
|
81
|
-
storeRemove,
|
|
82
|
-
storeExplain,
|
|
83
|
-
storeBind,
|
|
84
|
-
storeSwitchWrite,
|
|
85
|
-
missingRequiredStores
|
|
86
|
-
};
|
package/dist/chunk-L4Q55UC4.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadProjectConfig
|
|
4
|
-
} from "./chunk-LFIKMVY7.js";
|
|
5
|
-
import {
|
|
6
|
-
loadGlobalConfig,
|
|
7
|
-
resolveGlobalRoot
|
|
8
|
-
} from "./chunk-RYAFBNES.js";
|
|
9
|
-
|
|
10
|
-
// src/store/scope-explain.ts
|
|
11
|
-
import {
|
|
12
|
-
createStoreResolver
|
|
13
|
-
} from "@fenglimg/fabric-shared";
|
|
14
|
-
function buildResolveInput(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
15
|
-
const global = loadGlobalConfig(globalRoot);
|
|
16
|
-
if (global === null) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
const project = loadProjectConfig(projectRoot);
|
|
20
|
-
return {
|
|
21
|
-
uid: global.uid,
|
|
22
|
-
mountedStores: global.stores.map((s) => ({
|
|
23
|
-
store_uuid: s.store_uuid,
|
|
24
|
-
alias: s.alias,
|
|
25
|
-
...s.remote === void 0 ? {} : { remote: s.remote },
|
|
26
|
-
writable: s.writable ?? true,
|
|
27
|
-
personal: s.personal ?? false
|
|
28
|
-
})),
|
|
29
|
-
requiredStores: (project?.required_stores ?? []).map((r) => ({
|
|
30
|
-
id: r.id,
|
|
31
|
-
...r.suggested_remote === void 0 ? {} : { suggested_remote: r.suggested_remote }
|
|
32
|
-
})),
|
|
33
|
-
...project?.active_write_store === void 0 ? {} : { activeWriteAlias: project.active_write_store }
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function scopeExplain(projectRoot, scope, globalRoot = resolveGlobalRoot()) {
|
|
37
|
-
const input = buildResolveInput(projectRoot, globalRoot);
|
|
38
|
-
if (input === null) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
const resolver = createStoreResolver();
|
|
42
|
-
return {
|
|
43
|
-
scope,
|
|
44
|
-
readSet: resolver.resolveReadSet(input),
|
|
45
|
-
writeTarget: resolver.resolveWriteTarget(input, scope).target
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export {
|
|
50
|
-
buildResolveInput,
|
|
51
|
-
scopeExplain
|
|
52
|
-
};
|
package/dist/chunk-LFIKMVY7.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/store/project-config-io.ts
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
import { fabricConfigSchema } from "@fenglimg/fabric-shared";
|
|
7
|
-
function projectConfigPath(projectRoot) {
|
|
8
|
-
return join(projectRoot, ".fabric", "fabric-config.json");
|
|
9
|
-
}
|
|
10
|
-
function loadProjectConfig(projectRoot) {
|
|
11
|
-
const path = projectConfigPath(projectRoot);
|
|
12
|
-
if (!existsSync(path)) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
return fabricConfigSchema.parse(JSON.parse(readFileSync(path, "utf8")));
|
|
16
|
-
}
|
|
17
|
-
function saveProjectConfig(config, projectRoot) {
|
|
18
|
-
const validated = fabricConfigSchema.parse(config);
|
|
19
|
-
mkdirSync(join(projectRoot, ".fabric"), { recursive: true });
|
|
20
|
-
writeFileSync(projectConfigPath(projectRoot), `${JSON.stringify(validated, null, 2)}
|
|
21
|
-
`, "utf8");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
loadProjectConfig,
|
|
26
|
-
saveProjectConfig
|
|
27
|
-
};
|
package/dist/chunk-RYAFBNES.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/store/global-config-io.ts
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
5
|
-
import { homedir } from "os";
|
|
6
|
-
import { join } from "path";
|
|
7
|
-
import { globalConfigSchema } from "@fenglimg/fabric-shared";
|
|
8
|
-
function resolveGlobalRoot() {
|
|
9
|
-
return join(process.env.FABRIC_HOME ?? homedir(), ".fabric");
|
|
10
|
-
}
|
|
11
|
-
function globalConfigPath(globalRoot = resolveGlobalRoot()) {
|
|
12
|
-
return join(globalRoot, "fabric-global.json");
|
|
13
|
-
}
|
|
14
|
-
function loadGlobalConfig(globalRoot = resolveGlobalRoot()) {
|
|
15
|
-
const path = globalConfigPath(globalRoot);
|
|
16
|
-
if (!existsSync(path)) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
return globalConfigSchema.parse(JSON.parse(readFileSync(path, "utf8")));
|
|
20
|
-
}
|
|
21
|
-
function saveGlobalConfig(config, globalRoot = resolveGlobalRoot()) {
|
|
22
|
-
const validated = globalConfigSchema.parse(config);
|
|
23
|
-
mkdirSync(globalRoot, { recursive: true });
|
|
24
|
-
writeFileSync(globalConfigPath(globalRoot), `${JSON.stringify(validated, null, 2)}
|
|
25
|
-
`, "utf8");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export {
|
|
29
|
-
resolveGlobalRoot,
|
|
30
|
-
globalConfigPath,
|
|
31
|
-
loadGlobalConfig,
|
|
32
|
-
saveGlobalConfig
|
|
33
|
-
};
|
package/dist/chunk-T5RPGCCM.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadProjectConfig
|
|
4
|
-
} from "./chunk-LFIKMVY7.js";
|
|
5
|
-
import {
|
|
6
|
-
loadGlobalConfig,
|
|
7
|
-
resolveGlobalRoot
|
|
8
|
-
} from "./chunk-RYAFBNES.js";
|
|
9
|
-
|
|
10
|
-
// src/store/info-ops.ts
|
|
11
|
-
function whoami(globalRoot = resolveGlobalRoot()) {
|
|
12
|
-
const config = loadGlobalConfig(globalRoot);
|
|
13
|
-
if (config === null) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
return {
|
|
17
|
-
uid: config.uid,
|
|
18
|
-
stores: config.stores.map((s) => ({
|
|
19
|
-
alias: s.alias,
|
|
20
|
-
store_uuid: s.store_uuid,
|
|
21
|
-
local_only: s.remote === void 0
|
|
22
|
-
}))
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function projectStatus(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
26
|
-
const global = loadGlobalConfig(globalRoot);
|
|
27
|
-
const project = loadProjectConfig(projectRoot);
|
|
28
|
-
return {
|
|
29
|
-
uid: global?.uid ?? null,
|
|
30
|
-
mounted: (global?.stores ?? []).map((s) => s.alias),
|
|
31
|
-
project_id: project?.project_id ?? null,
|
|
32
|
-
required: (project?.required_stores ?? []).map((r) => r.id),
|
|
33
|
-
active_write_store: project?.active_write_store ?? null
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export {
|
|
38
|
-
whoami,
|
|
39
|
-
projectStatus
|
|
40
|
-
};
|
package/dist/store-XTSE5TY6.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
storeAdd,
|
|
4
|
-
storeBind,
|
|
5
|
-
storeExplain,
|
|
6
|
-
storeList,
|
|
7
|
-
storeRemove,
|
|
8
|
-
storeSwitchWrite
|
|
9
|
-
} from "./chunk-HFQVXY6P.js";
|
|
10
|
-
import {
|
|
11
|
-
regenerateBindingsSnapshot
|
|
12
|
-
} from "./chunk-WU6GAPKH.js";
|
|
13
|
-
import "./chunk-L4Q55UC4.js";
|
|
14
|
-
import "./chunk-LFIKMVY7.js";
|
|
15
|
-
import "./chunk-RYAFBNES.js";
|
|
16
|
-
|
|
17
|
-
// src/commands/store.ts
|
|
18
|
-
import { defineCommand } from "citty";
|
|
19
|
-
var listCommand = defineCommand({
|
|
20
|
-
meta: { name: "list", description: "List mounted knowledge stores" },
|
|
21
|
-
run() {
|
|
22
|
-
const stores = storeList();
|
|
23
|
-
if (stores.length === 0) {
|
|
24
|
-
console.log("(no stores mounted)");
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
for (const store of stores) {
|
|
28
|
-
console.log(`${store.alias} ${store.store_uuid} ${store.remote ?? "(local-only)"}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
var addCommand = defineCommand({
|
|
33
|
-
meta: { name: "add", description: "Mount a knowledge store into the global registry" },
|
|
34
|
-
args: {
|
|
35
|
-
uuid: { type: "string", required: true, description: "Intrinsic store UUID" },
|
|
36
|
-
alias: { type: "string", required: true, description: "Local alias for this store" },
|
|
37
|
-
remote: { type: "string", description: "Git remote locator (omit for local-only)" }
|
|
38
|
-
},
|
|
39
|
-
run({ args }) {
|
|
40
|
-
const store = args.remote === void 0 ? { store_uuid: args.uuid, alias: args.alias } : { store_uuid: args.uuid, alias: args.alias, remote: args.remote };
|
|
41
|
-
const next = storeAdd(store);
|
|
42
|
-
console.log(`mounted '${args.alias}' (${next.stores.length} store(s) total)`);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
var removeCommand = defineCommand({
|
|
46
|
-
meta: { name: "remove", description: "Detach a store from the registry (does NOT delete it)" },
|
|
47
|
-
args: {
|
|
48
|
-
alias: { type: "positional", required: true, description: "Alias to detach" }
|
|
49
|
-
},
|
|
50
|
-
run({ args }) {
|
|
51
|
-
const { detached } = storeRemove(args.alias);
|
|
52
|
-
console.log(
|
|
53
|
-
detached === null ? `no store aliased '${args.alias}'` : `detached '${args.alias}' \u2014 on-disk store tree left intact (detach \u2260 delete)`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
var explainCommand = defineCommand({
|
|
58
|
-
meta: { name: "explain", description: "Explain how a store alias resolves" },
|
|
59
|
-
args: {
|
|
60
|
-
alias: { type: "positional", required: true, description: "Alias to explain" }
|
|
61
|
-
},
|
|
62
|
-
run({ args }) {
|
|
63
|
-
const explanation = storeExplain(args.alias);
|
|
64
|
-
console.log(
|
|
65
|
-
explanation === null ? `no store aliased '${args.alias}'` : JSON.stringify(explanation, null, 2)
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
var bindCommand = defineCommand({
|
|
70
|
-
meta: { name: "bind", description: "Declare a required store on this project's config" },
|
|
71
|
-
args: {
|
|
72
|
-
id: { type: "positional", required: true, description: "Store alias/UUID to require" },
|
|
73
|
-
remote: { type: "string", description: "Suggested remote for clone onboarding" }
|
|
74
|
-
},
|
|
75
|
-
run({ args }) {
|
|
76
|
-
const entry = args.remote === void 0 ? { id: args.id } : { id: args.id, suggested_remote: args.remote };
|
|
77
|
-
const next = storeBind(process.cwd(), entry);
|
|
78
|
-
console.log(`bound required store '${args.id}' (${next.required_stores?.length ?? 0} required)`);
|
|
79
|
-
regenerateBindingsSnapshot(process.cwd(), { now: (/* @__PURE__ */ new Date()).toISOString() });
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
var switchWriteCommand = defineCommand({
|
|
83
|
-
meta: { name: "switch-write", description: "Set the active write store for non-personal scopes" },
|
|
84
|
-
args: {
|
|
85
|
-
alias: { type: "positional", required: true, description: "Alias of the store to write to" }
|
|
86
|
-
},
|
|
87
|
-
run({ args }) {
|
|
88
|
-
storeSwitchWrite(process.cwd(), args.alias);
|
|
89
|
-
console.log(`active write store set to '${args.alias}' for this project`);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
var store_default = defineCommand({
|
|
93
|
-
meta: { name: "store", description: "Manage mounted Fabric knowledge stores" },
|
|
94
|
-
subCommands: {
|
|
95
|
-
list: listCommand,
|
|
96
|
-
add: addCommand,
|
|
97
|
-
remove: removeCommand,
|
|
98
|
-
explain: explainCommand,
|
|
99
|
-
bind: bindCommand,
|
|
100
|
-
"switch-write": switchWriteCommand
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
export {
|
|
104
|
-
store_default as default
|
|
105
|
-
};
|
package/dist/sync-BJCWDPNC.js
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
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
|
-
};
|
package/dist/whoami-B6AEMSEV.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
whoami
|
|
4
|
-
} from "./chunk-T5RPGCCM.js";
|
|
5
|
-
import "./chunk-LFIKMVY7.js";
|
|
6
|
-
import "./chunk-RYAFBNES.js";
|
|
7
|
-
|
|
8
|
-
// src/commands/whoami.ts
|
|
9
|
-
import { defineCommand } from "citty";
|
|
10
|
-
var whoami_default = defineCommand({
|
|
11
|
-
meta: { name: "whoami", description: "Show this machine's Fabric uid and mounted stores" },
|
|
12
|
-
run() {
|
|
13
|
-
const info = whoami();
|
|
14
|
-
if (info === null) {
|
|
15
|
-
console.log("no global Fabric config \u2014 run `fabric install --global <url>` first");
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
console.log(`uid: ${info.uid}`);
|
|
19
|
-
if (info.stores.length === 0) {
|
|
20
|
-
console.log("stores: (none mounted)");
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
console.log("stores:");
|
|
24
|
-
for (const store of info.stores) {
|
|
25
|
-
console.log(` ${store.alias} ${store.store_uuid}${store.local_only ? " (local-only)" : ""}`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
export {
|
|
30
|
-
whoami_default as default
|
|
31
|
-
};
|