@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
|
@@ -8,11 +8,15 @@ import {
|
|
|
8
8
|
} from "@fenglimg/fabric-shared";
|
|
9
9
|
var locale = detectNodeLocale();
|
|
10
10
|
var t = createTranslator(locale);
|
|
11
|
-
function
|
|
11
|
+
function getProjectTranslator(projectRoot = process.cwd()) {
|
|
12
12
|
return createTranslator(resolveFabricLocale(projectRoot));
|
|
13
13
|
}
|
|
14
|
+
function getDoctorTranslator(projectRoot) {
|
|
15
|
+
return getProjectTranslator(projectRoot);
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
export {
|
|
16
19
|
t,
|
|
20
|
+
getProjectTranslator,
|
|
17
21
|
getDoctorTranslator
|
|
18
22
|
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
storeGitRemote
|
|
4
|
+
} from "./chunk-5ZUMLCD5.js";
|
|
5
|
+
import {
|
|
6
|
+
loadGlobalConfig,
|
|
7
|
+
loadProjectConfig,
|
|
8
|
+
resolveGlobalRoot
|
|
9
|
+
} from "./chunk-XCBVSGCS.js";
|
|
10
|
+
|
|
11
|
+
// src/lib/unknown-flags.ts
|
|
12
|
+
function warnUnknownFlags(known) {
|
|
13
|
+
const knownSet = /* @__PURE__ */ new Set([...known, "help", "version"]);
|
|
14
|
+
const unknown = [];
|
|
15
|
+
for (const tok of process.argv.slice(2)) {
|
|
16
|
+
if (!tok.startsWith("--")) continue;
|
|
17
|
+
const name = tok.slice(2).split("=")[0].replace(/^no-/, "");
|
|
18
|
+
if (name.length === 0) continue;
|
|
19
|
+
if (!knownSet.has(name)) unknown.push(tok.split("=")[0]);
|
|
20
|
+
}
|
|
21
|
+
if (unknown.length > 0) {
|
|
22
|
+
process.stderr.write(`[fabric] ignored unknown flag(s): ${unknown.join(", ")}
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/store/info-ops.ts
|
|
28
|
+
function whoami(globalRoot = resolveGlobalRoot()) {
|
|
29
|
+
const config = loadGlobalConfig(globalRoot);
|
|
30
|
+
if (config === null) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
uid: config.uid,
|
|
35
|
+
stores: config.stores.map((s) => ({
|
|
36
|
+
alias: s.alias,
|
|
37
|
+
store_uuid: s.store_uuid,
|
|
38
|
+
// F4: parity with `fabric store list` — local-only reflects the store
|
|
39
|
+
// repo's TRUE git remote (what sync actually pushes to), not the registry
|
|
40
|
+
// metadata. A store with a physical `origin` but no registry `remote`
|
|
41
|
+
// (e.g. the personal store) was misreported as local-only by whoami while
|
|
42
|
+
// `store list` honestly showed its remote. Both now read the same source.
|
|
43
|
+
local_only: storeGitRemote(s.store_uuid, globalRoot) === void 0
|
|
44
|
+
}))
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function projectStatus(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
48
|
+
const global = loadGlobalConfig(globalRoot);
|
|
49
|
+
const project = loadProjectConfig(projectRoot);
|
|
50
|
+
return {
|
|
51
|
+
uid: global?.uid ?? null,
|
|
52
|
+
mounted: (global?.stores ?? []).map((s) => s.alias),
|
|
53
|
+
project_id: project?.project_id ?? null,
|
|
54
|
+
is_fabric_project: project !== null,
|
|
55
|
+
required: (project?.required_stores ?? []).map((r) => r.id),
|
|
56
|
+
active_write_store: project?.active_write_store ?? null
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
warnUnknownFlags,
|
|
62
|
+
whoami,
|
|
63
|
+
projectStatus
|
|
64
|
+
};
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadGlobalConfig,
|
|
4
|
+
loadProjectConfig,
|
|
5
|
+
resolveGlobalRoot,
|
|
6
|
+
saveGlobalConfig,
|
|
7
|
+
saveProjectConfig
|
|
8
|
+
} from "./chunk-XCBVSGCS.js";
|
|
9
|
+
|
|
10
|
+
// src/store/store-ops.ts
|
|
11
|
+
import { execFileSync } from "child_process";
|
|
12
|
+
import { randomUUID } from "crypto";
|
|
13
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, rmSync, symlinkSync } from "fs";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
import {
|
|
16
|
+
addMountedStore,
|
|
17
|
+
bindRequiredStore,
|
|
18
|
+
detachMountedStore,
|
|
19
|
+
explainStore,
|
|
20
|
+
initStore,
|
|
21
|
+
STORES_ROOT_DIR,
|
|
22
|
+
storeRelativePath
|
|
23
|
+
} from "@fenglimg/fabric-shared";
|
|
24
|
+
var NO_GLOBAL_CONFIG = "no global Fabric config found \u2014 run `fabric install --global <url>` first";
|
|
25
|
+
function requireConfig(globalRoot) {
|
|
26
|
+
const config = loadGlobalConfig(globalRoot);
|
|
27
|
+
if (config === null) {
|
|
28
|
+
throw new Error(NO_GLOBAL_CONFIG);
|
|
29
|
+
}
|
|
30
|
+
return config;
|
|
31
|
+
}
|
|
32
|
+
function storeList(globalRoot = resolveGlobalRoot()) {
|
|
33
|
+
return requireConfig(globalRoot).stores;
|
|
34
|
+
}
|
|
35
|
+
var STORE_BY_ALIAS_DIR = "by-alias";
|
|
36
|
+
function syncStoreAliasLinks(globalRoot = resolveGlobalRoot()) {
|
|
37
|
+
const result = { created: [], removed: [], errors: [] };
|
|
38
|
+
const config = loadGlobalConfig(globalRoot);
|
|
39
|
+
if (config === null) {
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
const byAliasDir = join(globalRoot, STORES_ROOT_DIR, STORE_BY_ALIAS_DIR);
|
|
43
|
+
const desired = new Map(config.stores.map((s) => [s.alias, s.store_uuid]));
|
|
44
|
+
try {
|
|
45
|
+
mkdirSync(byAliasDir, { recursive: true });
|
|
46
|
+
} catch {
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
let existing = [];
|
|
50
|
+
try {
|
|
51
|
+
existing = readdirSync(byAliasDir);
|
|
52
|
+
} catch {
|
|
53
|
+
existing = [];
|
|
54
|
+
}
|
|
55
|
+
for (const name of existing) {
|
|
56
|
+
if (desired.has(name)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
rmSync(join(byAliasDir, name), { force: true, recursive: false });
|
|
61
|
+
result.removed.push(name);
|
|
62
|
+
} catch {
|
|
63
|
+
result.errors.push(name);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const [alias, uuid] of desired) {
|
|
67
|
+
const link = join(byAliasDir, alias);
|
|
68
|
+
const target = join("..", uuid);
|
|
69
|
+
try {
|
|
70
|
+
let current = null;
|
|
71
|
+
try {
|
|
72
|
+
if (lstatSync(link).isSymbolicLink()) {
|
|
73
|
+
current = readlinkSync(link);
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
current = null;
|
|
77
|
+
}
|
|
78
|
+
if (current === target) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
rmSync(link, { force: true });
|
|
82
|
+
symlinkSync(target, link);
|
|
83
|
+
result.created.push(alias);
|
|
84
|
+
} catch {
|
|
85
|
+
result.errors.push(alias);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
function detectAliasLinkDrift(globalRoot = resolveGlobalRoot()) {
|
|
91
|
+
const config = loadGlobalConfig(globalRoot);
|
|
92
|
+
if (config === null) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const byAliasDir = join(globalRoot, STORES_ROOT_DIR, STORE_BY_ALIAS_DIR);
|
|
96
|
+
if (!existsSync(byAliasDir)) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
const drifted = [];
|
|
100
|
+
for (const store of config.stores) {
|
|
101
|
+
const link = join(byAliasDir, store.alias);
|
|
102
|
+
const target = join("..", store.store_uuid);
|
|
103
|
+
try {
|
|
104
|
+
if (!lstatSync(link).isSymbolicLink() || readlinkSync(link) !== target) {
|
|
105
|
+
drifted.push(store.alias);
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
drifted.push(store.alias);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return drifted;
|
|
112
|
+
}
|
|
113
|
+
function storeAdd(store, globalRoot = resolveGlobalRoot()) {
|
|
114
|
+
const next = addMountedStore(requireConfig(globalRoot), store);
|
|
115
|
+
saveGlobalConfig(next, globalRoot);
|
|
116
|
+
syncStoreAliasLinks(globalRoot);
|
|
117
|
+
return next;
|
|
118
|
+
}
|
|
119
|
+
function storeCreate(alias, now, options = {}) {
|
|
120
|
+
const globalRoot = options.globalRoot ?? resolveGlobalRoot();
|
|
121
|
+
const config = requireConfig(globalRoot);
|
|
122
|
+
const uuid = options.uuid ?? randomUUID();
|
|
123
|
+
const storeDir = join(globalRoot, storeRelativePath(uuid));
|
|
124
|
+
initStore(
|
|
125
|
+
storeDir,
|
|
126
|
+
{ store_uuid: uuid, created_at: now, canonical_alias: alias },
|
|
127
|
+
{ git: options.git }
|
|
128
|
+
);
|
|
129
|
+
if (options.remote !== void 0 && options.git !== false) {
|
|
130
|
+
gitRemoteAdd(storeDir, options.remote);
|
|
131
|
+
}
|
|
132
|
+
const mounted = options.remote === void 0 ? { store_uuid: uuid, alias } : { store_uuid: uuid, alias, remote: options.remote };
|
|
133
|
+
const next = addMountedStore(config, mounted);
|
|
134
|
+
saveGlobalConfig(next, globalRoot);
|
|
135
|
+
syncStoreAliasLinks(globalRoot);
|
|
136
|
+
return { config: next, store_uuid: uuid, storeDir };
|
|
137
|
+
}
|
|
138
|
+
function gitRemoteAdd(storeDir, remote) {
|
|
139
|
+
try {
|
|
140
|
+
execFileSync("git", ["remote", "add", "origin", remote], {
|
|
141
|
+
cwd: storeDir,
|
|
142
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
143
|
+
});
|
|
144
|
+
} catch {
|
|
145
|
+
try {
|
|
146
|
+
execFileSync("git", ["remote", "set-url", "origin", remote], {
|
|
147
|
+
cwd: storeDir,
|
|
148
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
149
|
+
});
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function storeGitRemote(uuid, globalRoot = resolveGlobalRoot()) {
|
|
155
|
+
const storeDir = join(globalRoot, storeRelativePath(uuid));
|
|
156
|
+
if (!existsSync(storeDir)) {
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const out = execFileSync("git", ["remote", "get-url", "origin"], {
|
|
161
|
+
cwd: storeDir,
|
|
162
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
163
|
+
encoding: "utf8"
|
|
164
|
+
});
|
|
165
|
+
const trimmed = out.trim();
|
|
166
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
167
|
+
} catch {
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function assertStoreMountable(uuid, globalRoot = resolveGlobalRoot()) {
|
|
172
|
+
const storeDir = join(globalRoot, storeRelativePath(uuid));
|
|
173
|
+
if (!existsSync(join(storeDir, "store.json"))) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`cannot mount store ${uuid}: no store tree at ${storeDir} \u2014 clone it first (\`fabric install --global --url <remote>\`) or create it locally, then re-run \`fabric store add\`. Refusing to register a phantom store.`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function storeRemove(alias, globalRoot = resolveGlobalRoot()) {
|
|
180
|
+
const result = detachMountedStore(requireConfig(globalRoot), alias);
|
|
181
|
+
saveGlobalConfig(result.config, globalRoot);
|
|
182
|
+
syncStoreAliasLinks(globalRoot);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
function storeExplain(alias, globalRoot = resolveGlobalRoot()) {
|
|
186
|
+
return explainStore(requireConfig(globalRoot), alias);
|
|
187
|
+
}
|
|
188
|
+
var NO_PROJECT_CONFIG = "no project Fabric config \u2014 run `fabric install` in this repo first";
|
|
189
|
+
function requireProjectConfig(projectRoot) {
|
|
190
|
+
const config = loadProjectConfig(projectRoot);
|
|
191
|
+
if (config === null) {
|
|
192
|
+
throw new Error(NO_PROJECT_CONFIG);
|
|
193
|
+
}
|
|
194
|
+
return config;
|
|
195
|
+
}
|
|
196
|
+
function storeBind(projectRoot, entry) {
|
|
197
|
+
const config = requireProjectConfig(projectRoot);
|
|
198
|
+
const next = {
|
|
199
|
+
...config,
|
|
200
|
+
required_stores: bindRequiredStore(config.required_stores ?? [], entry)
|
|
201
|
+
};
|
|
202
|
+
saveProjectConfig(next, projectRoot);
|
|
203
|
+
return next;
|
|
204
|
+
}
|
|
205
|
+
function storeSwitchWrite(projectRoot, alias) {
|
|
206
|
+
const config = requireProjectConfig(projectRoot);
|
|
207
|
+
const next = { ...config, active_write_store: alias };
|
|
208
|
+
saveProjectConfig(next, projectRoot);
|
|
209
|
+
return next;
|
|
210
|
+
}
|
|
211
|
+
function missingRequiredStores(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
212
|
+
const project = loadProjectConfig(projectRoot);
|
|
213
|
+
if (project === null || project.required_stores === void 0) {
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
const global = loadGlobalConfig(globalRoot);
|
|
217
|
+
const mounted = new Set(
|
|
218
|
+
(global?.stores ?? []).flatMap((s) => [s.alias, s.store_uuid])
|
|
219
|
+
);
|
|
220
|
+
return project.required_stores.filter((r) => !mounted.has(r.id));
|
|
221
|
+
}
|
|
222
|
+
function unboundAvailableStores(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
223
|
+
const global = loadGlobalConfig(globalRoot);
|
|
224
|
+
if (global === null) {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
const project = loadProjectConfig(projectRoot);
|
|
228
|
+
const declared = new Set((project?.required_stores ?? []).map((r) => r.id));
|
|
229
|
+
return global.stores.filter(
|
|
230
|
+
(s) => s.personal !== true && !declared.has(s.alias) && !declared.has(s.store_uuid)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export {
|
|
235
|
+
storeList,
|
|
236
|
+
syncStoreAliasLinks,
|
|
237
|
+
detectAliasLinkDrift,
|
|
238
|
+
storeAdd,
|
|
239
|
+
storeCreate,
|
|
240
|
+
storeGitRemote,
|
|
241
|
+
assertStoreMountable,
|
|
242
|
+
storeRemove,
|
|
243
|
+
storeExplain,
|
|
244
|
+
storeBind,
|
|
245
|
+
storeSwitchWrite,
|
|
246
|
+
missingRequiredStores,
|
|
247
|
+
unboundAvailableStores
|
|
248
|
+
};
|
|
@@ -4,7 +4,14 @@
|
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import stringWidth from "string-width";
|
|
6
6
|
function isColorEnabled() {
|
|
7
|
-
|
|
7
|
+
if (process.env.NO_COLOR) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
const force = process.env.FORCE_COLOR;
|
|
11
|
+
if (force !== void 0) {
|
|
12
|
+
return force !== "0" && force.toLowerCase() !== "false";
|
|
13
|
+
}
|
|
14
|
+
return Boolean(process.stdout.isTTY) && Boolean(process.stderr.isTTY);
|
|
8
15
|
}
|
|
9
16
|
function colorize(painter) {
|
|
10
17
|
return (value) => isColorEnabled() ? painter(value) : value;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/store/scope-explain.ts
|
|
4
|
+
import {
|
|
5
|
+
SCOPE_COORDINATE_PATTERN,
|
|
6
|
+
buildStoreResolveInput,
|
|
7
|
+
createStoreResolver,
|
|
8
|
+
resolveGlobalRoot
|
|
9
|
+
} from "@fenglimg/fabric-shared";
|
|
10
|
+
import { GenericConfigError } from "@fenglimg/fabric-shared/errors";
|
|
11
|
+
function buildResolveInput(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
12
|
+
return buildStoreResolveInput(projectRoot, globalRoot);
|
|
13
|
+
}
|
|
14
|
+
function scopeExplain(projectRoot, scope, globalRoot = resolveGlobalRoot()) {
|
|
15
|
+
if (!SCOPE_COORDINATE_PATTERN.test(scope)) {
|
|
16
|
+
throw new GenericConfigError(`invalid scope coordinate '${scope}'`, {
|
|
17
|
+
actionHint: "use ':'-joined lowercase [a-z0-9_-] segments, e.g. `team`, `personal`, `project:fabric-v2`, `org:acme:team:platform`",
|
|
18
|
+
details: { scope }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const input = buildResolveInput(projectRoot, globalRoot);
|
|
22
|
+
if (input === null) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const resolver = createStoreResolver();
|
|
26
|
+
return {
|
|
27
|
+
scope,
|
|
28
|
+
readSet: resolver.resolveReadSet(input),
|
|
29
|
+
writeTarget: resolver.resolveWriteTarget(input, scope).target
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
buildResolveInput,
|
|
35
|
+
scopeExplain
|
|
36
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
resolveClients
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XC5RUHLK.js";
|
|
5
5
|
import {
|
|
6
6
|
t
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2CY4BMTH.js";
|
|
8
8
|
|
|
9
9
|
// src/commands/config.ts
|
|
10
10
|
import { existsSync, statSync } from "fs";
|
|
@@ -178,8 +178,8 @@ var configCmd = defineCommand({
|
|
|
178
178
|
"onboard-reset": onboardResetCmd
|
|
179
179
|
},
|
|
180
180
|
async run({ args }) {
|
|
181
|
-
const
|
|
182
|
-
if (
|
|
181
|
+
const argvAfterConfig = process.argv.slice(3);
|
|
182
|
+
if (argvAfterConfig.includes("dismiss-slot") || argvAfterConfig.includes("onboard-reset")) {
|
|
183
183
|
return;
|
|
184
184
|
}
|
|
185
185
|
const workspaceRoot = resolve(args.target ?? process.cwd());
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
buildResolveInput
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
loadProjectConfig
|
|
7
|
-
} from "./chunk-LFIKMVY7.js";
|
|
4
|
+
} from "./chunk-EOT63RDH.js";
|
|
8
5
|
import {
|
|
6
|
+
loadProjectConfig,
|
|
9
7
|
resolveGlobalRoot
|
|
10
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-XCBVSGCS.js";
|
|
11
9
|
|
|
12
10
|
// src/store/bindings-io.ts
|
|
13
11
|
import { writeBindingsSnapshot } from "@fenglimg/fabric-shared";
|
|
@@ -307,7 +307,7 @@ function serializeTomlInlineTable(values) {
|
|
|
307
307
|
const entries = Object.entries(values).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key} = ${escapeTomlString(value)}`);
|
|
308
308
|
return `{ ${entries.join(", ")} }`;
|
|
309
309
|
}
|
|
310
|
-
function serializeCodexServerBlock(serverName, serverEntry) {
|
|
310
|
+
function serializeCodexServerBlock(serverName, serverEntry, preservedUserLines = []) {
|
|
311
311
|
const lines = [
|
|
312
312
|
`[mcp_servers.${serverName}]`,
|
|
313
313
|
`command = ${escapeTomlString(serverEntry.command)}`,
|
|
@@ -316,9 +316,26 @@ function serializeCodexServerBlock(serverName, serverEntry) {
|
|
|
316
316
|
if (serverEntry.env !== void 0 && Object.keys(serverEntry.env).length > 0) {
|
|
317
317
|
lines.push(`env = ${serializeTomlInlineTable(serverEntry.env)}`);
|
|
318
318
|
}
|
|
319
|
+
lines.push(...preservedUserLines);
|
|
319
320
|
return `${lines.join("\n")}
|
|
320
321
|
`;
|
|
321
322
|
}
|
|
323
|
+
var CODEX_MANAGED_BLOCK_KEYS = /* @__PURE__ */ new Set(["command", "args", "env"]);
|
|
324
|
+
function extractCodexBlockUserLines(blockText) {
|
|
325
|
+
const out = [];
|
|
326
|
+
const lines = blockText.split("\n");
|
|
327
|
+
for (const line of lines) {
|
|
328
|
+
const trimmed = line.trim();
|
|
329
|
+
if (trimmed.length === 0) continue;
|
|
330
|
+
if (/^\[/.test(trimmed)) continue;
|
|
331
|
+
const keyMatch = /^([A-Za-z0-9_-]+)\s*=/.exec(trimmed);
|
|
332
|
+
if (keyMatch !== null && CODEX_MANAGED_BLOCK_KEYS.has(keyMatch[1])) {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
out.push(trimmed);
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
322
339
|
function trimTrailingBlankLines(value) {
|
|
323
340
|
return value.replace(/\s+$/u, "");
|
|
324
341
|
}
|
|
@@ -341,13 +358,16 @@ function removeCodexServerBlock(rawConfig, serverName) {
|
|
|
341
358
|
return { text, changed };
|
|
342
359
|
}
|
|
343
360
|
function upsertCodexServerBlock(rawConfig, serverName, serverEntry) {
|
|
344
|
-
const block = serializeCodexServerBlock(serverName, serverEntry);
|
|
345
361
|
const normalized = rawConfig.replace(/\r\n/g, "\n");
|
|
346
|
-
const
|
|
362
|
+
const escaped = serverName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
363
|
+
const legacyPattern = new RegExp(String.raw`\n?\[mcp\.servers\.${escaped}\]\n[\s\S]*?(?=\n\[[^\n]+\]\n|$)`, "g");
|
|
347
364
|
const currentPattern = new RegExp(
|
|
348
|
-
String.raw`\n?\[mcp_servers\.${
|
|
365
|
+
String.raw`\n?\[mcp_servers\.${escaped}\]\n[\s\S]*?(?=\n\[[^\n]+\]\n|$)`,
|
|
349
366
|
"g"
|
|
350
367
|
);
|
|
368
|
+
const existingMatch = normalized.match(currentPattern);
|
|
369
|
+
const preservedUserLines = existingMatch !== null && existingMatch.length > 0 ? extractCodexBlockUserLines(existingMatch[0]) : [];
|
|
370
|
+
const block = serializeCodexServerBlock(serverName, serverEntry, preservedUserLines);
|
|
351
371
|
const withoutLegacy = normalized.replace(legacyPattern, "");
|
|
352
372
|
const withoutExisting = withoutLegacy.replace(currentPattern, "");
|
|
353
373
|
const trimmed = trimTrailingBlankLines(withoutExisting);
|
|
@@ -528,10 +548,11 @@ function detectClientSupports(workspaceRoot, fabricConfig = {}) {
|
|
|
528
548
|
},
|
|
529
549
|
installedCapabilities: {
|
|
530
550
|
hook: existsSync4(join4(workspaceRoot, ".codex", "hooks.json")),
|
|
531
|
-
//
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
|
|
551
|
+
// F6: the v2 skills (fabric-archive/review/import/…) DO install to
|
|
552
|
+
// `.codex/skills/` now, so probe that directory instead of the stale
|
|
553
|
+
// hardcoded `false` (which made `fabric install` always re-report Codex
|
|
554
|
+
// skills as uninstalled even right after installing them).
|
|
555
|
+
skill: existsSync4(join4(workspaceRoot, ".codex", "skills"))
|
|
535
556
|
}
|
|
536
557
|
}
|
|
537
558
|
];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/store/global-config-io.ts
|
|
4
|
+
import {
|
|
5
|
+
resolveGlobalRoot,
|
|
6
|
+
globalConfigPath,
|
|
7
|
+
loadGlobalConfig,
|
|
8
|
+
saveGlobalConfig
|
|
9
|
+
} from "@fenglimg/fabric-shared";
|
|
10
|
+
|
|
11
|
+
// src/store/project-config-io.ts
|
|
12
|
+
import {
|
|
13
|
+
projectConfigPath,
|
|
14
|
+
loadProjectConfig,
|
|
15
|
+
saveProjectConfig
|
|
16
|
+
} from "@fenglimg/fabric-shared";
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
resolveGlobalRoot,
|
|
20
|
+
globalConfigPath,
|
|
21
|
+
loadGlobalConfig,
|
|
22
|
+
saveGlobalConfig,
|
|
23
|
+
loadProjectConfig,
|
|
24
|
+
saveProjectConfig
|
|
25
|
+
};
|