@fenglimg/fabric-cli 1.3.1 → 1.5.0
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/README.md +15 -11
- package/dist/approve-YT4DEABS.js +138 -0
- package/dist/{bootstrap-3PUKUYTY.js → bootstrap-VGL3AR26.js} +3 -3
- package/dist/{chunk-VOQKQ6W2.js → chunk-BEKSXO5N.js} +10 -2
- package/dist/{chunk-XFSQM3LJ.js → chunk-BVTMVW5M.js} +1 -1
- package/dist/{chunk-AZRKMFRY.js → chunk-QSAEGVKE.js} +2 -2
- package/dist/{chunk-TKTWHAKV.js → chunk-T2WJF5I3.js} +9 -9
- package/dist/{config-GINBGANU.js → config-EC5L2QNI.js} +2 -2
- package/dist/index.js +7 -6
- package/dist/{init-T3LGMGAO.js → init-YR7EVBYQ.js} +1088 -281
- package/dist/{scan-43R3IBLR.js → scan-QH76LC7Z.js} +1 -1
- package/dist/scanner/tree-sitter-probe.d.ts +24 -0
- package/dist/scanner/tree-sitter-probe.js +107 -0
- package/dist/{update-AN3FYF2O.js → update-M5M5PYKE.js} +7 -7
- package/package.json +7 -3
- package/templates/codex-hooks/fabric-session-start.cjs +19 -0
- package/templates/codex-hooks/fabric-stop-reminder.cjs +18 -0
- package/templates/codex-skills/fabric-init/SKILL.md +27 -0
package/README.md
CHANGED
|
@@ -13,14 +13,18 @@
|
|
|
13
13
|
|
|
14
14
|
`fabric bootstrap install` refreshes the internal bootstrap guide at `.fabric/bootstrap/README.md`. It does not generate root `AGENTS.md`, `CLAUDE.md`, or `GEMINI.md`.
|
|
15
15
|
|
|
16
|
-
## Common Commands
|
|
17
|
-
|
|
18
|
-
- `fabric init`
|
|
19
|
-
- `fabric serve`
|
|
20
|
-
- `fabric doctor --audit`
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- `fabric
|
|
16
|
+
## Common Commands
|
|
17
|
+
|
|
18
|
+
- `fabric init`
|
|
19
|
+
- `fabric serve`
|
|
20
|
+
- `fabric doctor --audit`
|
|
21
|
+
- `fabric approve --interactive`
|
|
22
|
+
- `fabric approve --all`
|
|
23
|
+
|
|
24
|
+
## Advanced Commands
|
|
25
|
+
|
|
26
|
+
- `fabric bootstrap install`
|
|
27
|
+
- `fabric config install`
|
|
28
|
+
- `fabric hooks install`
|
|
29
|
+
|
|
30
|
+
`fabric approve` updates drifted entries in `.fabric/human-lock.json` after review. Use `--interactive` for per-entry confirmation and `--all` only when drift has already been reviewed elsewhere.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
padEnd
|
|
4
|
+
} from "./chunk-WWNXR34K.js";
|
|
5
|
+
import {
|
|
6
|
+
t
|
|
7
|
+
} from "./chunk-6ICJICVU.js";
|
|
8
|
+
|
|
9
|
+
// src/commands/approve.ts
|
|
10
|
+
import { createInterface } from "readline/promises";
|
|
11
|
+
import { stdin as input, stdout as output } from "process";
|
|
12
|
+
import { isAbsolute, resolve } from "path";
|
|
13
|
+
import { approveHumanLock, readHumanLock } from "@fenglimg/fabric-server";
|
|
14
|
+
import { defineCommand, renderUsage } from "citty";
|
|
15
|
+
var approveCommand = defineCommand({
|
|
16
|
+
meta: {
|
|
17
|
+
name: "approve",
|
|
18
|
+
description: t("cli.approve.description")
|
|
19
|
+
},
|
|
20
|
+
args: {
|
|
21
|
+
all: {
|
|
22
|
+
type: "boolean",
|
|
23
|
+
description: t("cli.approve.args.all.description"),
|
|
24
|
+
default: false
|
|
25
|
+
},
|
|
26
|
+
interactive: {
|
|
27
|
+
type: "boolean",
|
|
28
|
+
description: t("cli.approve.args.interactive.description"),
|
|
29
|
+
default: false
|
|
30
|
+
},
|
|
31
|
+
target: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: t("cli.approve.args.target.description"),
|
|
34
|
+
default: process.cwd()
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
async run({ args }) {
|
|
38
|
+
const target = normalizeTarget(args.target);
|
|
39
|
+
if (args.all === args.interactive) {
|
|
40
|
+
writeStdout(await renderUsage(approveCommand));
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (args.all) {
|
|
45
|
+
await runApproveAll(target);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await runApproveInteractive(target);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
var approve_default = approveCommand;
|
|
52
|
+
async function runApproveAll(projectRoot) {
|
|
53
|
+
const driftEntries = await readDriftEntries(projectRoot);
|
|
54
|
+
if (driftEntries.length === 0) {
|
|
55
|
+
writeStdout(t("cli.approve.no-drift"));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let approvedCount = 0;
|
|
59
|
+
for (const entry of driftEntries) {
|
|
60
|
+
await approveEntry(projectRoot, entry);
|
|
61
|
+
approvedCount += 1;
|
|
62
|
+
}
|
|
63
|
+
writeStdout(t("cli.approve.summary", { approved: String(approvedCount), skipped: "0", total: String(driftEntries.length) }));
|
|
64
|
+
}
|
|
65
|
+
async function runApproveInteractive(projectRoot) {
|
|
66
|
+
const driftEntries = await readDriftEntries(projectRoot);
|
|
67
|
+
if (driftEntries.length === 0) {
|
|
68
|
+
writeStdout(t("cli.approve.no-drift"));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const rl = createInterface({ input, output });
|
|
72
|
+
let approvedCount = 0;
|
|
73
|
+
let skippedCount = 0;
|
|
74
|
+
try {
|
|
75
|
+
for (const entry of driftEntries) {
|
|
76
|
+
writeStdout(formatEntry(entry));
|
|
77
|
+
const answer = (await rl.question(t("cli.approve.prompt"))).trim().toLowerCase();
|
|
78
|
+
if (answer === "y" || answer === "yes") {
|
|
79
|
+
await approveEntry(projectRoot, entry);
|
|
80
|
+
approvedCount += 1;
|
|
81
|
+
writeStdout(t("cli.approve.approved-one", { location: formatLocation(entry) }));
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
skippedCount += 1;
|
|
85
|
+
writeStdout(t("cli.approve.skipped-one", { location: formatLocation(entry) }));
|
|
86
|
+
}
|
|
87
|
+
} finally {
|
|
88
|
+
rl.close();
|
|
89
|
+
}
|
|
90
|
+
writeStdout(
|
|
91
|
+
t("cli.approve.summary", {
|
|
92
|
+
approved: String(approvedCount),
|
|
93
|
+
skipped: String(skippedCount),
|
|
94
|
+
total: String(driftEntries.length)
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
async function readDriftEntries(projectRoot) {
|
|
99
|
+
const entries = await readHumanLock(projectRoot);
|
|
100
|
+
return entries.filter((entry) => entry.drift);
|
|
101
|
+
}
|
|
102
|
+
async function approveEntry(projectRoot, entry) {
|
|
103
|
+
await approveHumanLock(projectRoot, {
|
|
104
|
+
file: entry.file,
|
|
105
|
+
start_line: entry.start_line,
|
|
106
|
+
end_line: entry.end_line,
|
|
107
|
+
new_hash: entry.current_hash
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function normalizeTarget(targetInput) {
|
|
111
|
+
return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
|
|
112
|
+
}
|
|
113
|
+
function formatEntry(entry) {
|
|
114
|
+
return [
|
|
115
|
+
formatLocation(entry),
|
|
116
|
+
`${padEnd(t("cli.approve.table.expected"), 10)} ${shortenHash(entry.hash)}`,
|
|
117
|
+
`${padEnd(t("cli.approve.table.current"), 10)} ${shortenHash(entry.current_hash)}`
|
|
118
|
+
].join("\n");
|
|
119
|
+
}
|
|
120
|
+
function formatLocation(entry) {
|
|
121
|
+
return `${entry.file}:${entry.start_line}-${entry.end_line}`;
|
|
122
|
+
}
|
|
123
|
+
function shortenHash(value) {
|
|
124
|
+
if (value === "missing") {
|
|
125
|
+
return t("cli.shared.missing");
|
|
126
|
+
}
|
|
127
|
+
return value.slice(0, 15);
|
|
128
|
+
}
|
|
129
|
+
function writeStdout(message) {
|
|
130
|
+
process.stdout.write(`${message}
|
|
131
|
+
`);
|
|
132
|
+
}
|
|
133
|
+
export {
|
|
134
|
+
approveCommand,
|
|
135
|
+
approve_default as default,
|
|
136
|
+
runApproveAll,
|
|
137
|
+
runApproveInteractive
|
|
138
|
+
};
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
bootstrapCommand,
|
|
4
4
|
bootstrap_default,
|
|
5
5
|
installBootstrap
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-VOQKQ6W2.js";
|
|
6
|
+
} from "./chunk-T2WJF5I3.js";
|
|
7
|
+
import "./chunk-QSAEGVKE.js";
|
|
9
8
|
import "./chunk-AEOYCVBG.js";
|
|
10
9
|
import "./chunk-WWNXR34K.js";
|
|
10
|
+
import "./chunk-BEKSXO5N.js";
|
|
11
11
|
import "./chunk-6ICJICVU.js";
|
|
12
12
|
export {
|
|
13
13
|
bootstrapCommand,
|
|
@@ -345,6 +345,10 @@ function detectClientSupports(workspaceRoot, fabricConfig = {}) {
|
|
|
345
345
|
mcp: true,
|
|
346
346
|
hook: true,
|
|
347
347
|
skill: true
|
|
348
|
+
},
|
|
349
|
+
installedCapabilities: {
|
|
350
|
+
hook: true,
|
|
351
|
+
skill: true
|
|
348
352
|
}
|
|
349
353
|
},
|
|
350
354
|
{
|
|
@@ -421,8 +425,12 @@ function detectClientSupports(workspaceRoot, fabricConfig = {}) {
|
|
|
421
425
|
capabilities: {
|
|
422
426
|
bootstrap: true,
|
|
423
427
|
mcp: true,
|
|
424
|
-
hook:
|
|
425
|
-
skill:
|
|
428
|
+
hook: true,
|
|
429
|
+
skill: true
|
|
430
|
+
},
|
|
431
|
+
installedCapabilities: {
|
|
432
|
+
hook: existsSync4(join4(workspaceRoot, ".codex", "hooks.json")),
|
|
433
|
+
skill: existsSync4(join4(workspaceRoot, ".agents", "skills", "fabric-init", "SKILL.md"))
|
|
426
434
|
}
|
|
427
435
|
}
|
|
428
436
|
];
|
|
@@ -40,7 +40,7 @@ function resolveIgnores(fabricConfig) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// src/commands/scan.ts
|
|
43
|
-
function createScanReport(targetInput = process.cwd(), fabricConfig) {
|
|
43
|
+
async function createScanReport(targetInput = process.cwd(), fabricConfig) {
|
|
44
44
|
const target = normalizeTarget(targetInput);
|
|
45
45
|
const framework = detectFramework(target);
|
|
46
46
|
const readmeQuality = getReadmeQuality(target);
|
|
@@ -93,7 +93,7 @@ var scanCommand = defineCommand({
|
|
|
93
93
|
for (const step of resolution.chain) {
|
|
94
94
|
logger(step);
|
|
95
95
|
}
|
|
96
|
-
const report = createScanReport(resolution.target, fabricConfig);
|
|
96
|
+
const report = await createScanReport(resolution.target, fabricConfig);
|
|
97
97
|
if (args.json) {
|
|
98
98
|
console.log(JSON.stringify(report, null, 2));
|
|
99
99
|
return;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createScanReport
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
resolveClients
|
|
7
|
-
} from "./chunk-VOQKQ6W2.js";
|
|
4
|
+
} from "./chunk-QSAEGVKE.js";
|
|
8
5
|
import {
|
|
9
6
|
readFabricConfig
|
|
10
7
|
} from "./chunk-AEOYCVBG.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveClients
|
|
10
|
+
} from "./chunk-BEKSXO5N.js";
|
|
11
11
|
import {
|
|
12
12
|
t
|
|
13
13
|
} from "./chunk-6ICJICVU.js";
|
|
@@ -26,22 +26,22 @@ var AGENTS_TEMPLATE_BY_FRAMEWORK = {
|
|
|
26
26
|
next: "templates/agents-md/variants/next.md"
|
|
27
27
|
};
|
|
28
28
|
var FABRIC_GUIDE_PATH = ".fabric/bootstrap/README.md";
|
|
29
|
-
function buildFabricBootstrapGuide(target) {
|
|
29
|
+
async function buildFabricBootstrapGuide(target) {
|
|
30
30
|
const workspaceRoot = normalizeTarget(target);
|
|
31
|
-
const scanReport = createScanReport(workspaceRoot);
|
|
31
|
+
const scanReport = await createScanReport(workspaceRoot);
|
|
32
32
|
const template = readFileSync(findBootstrapTemplatePath(scanReport.framework.kind), "utf8");
|
|
33
33
|
const packageName = readPackageName(workspaceRoot) ?? parse(workspaceRoot).base;
|
|
34
34
|
return ensureTrailingNewline(
|
|
35
35
|
template.replaceAll("{ projectName }", packageName).replaceAll("{ frameworkKind }", scanReport.framework.kind)
|
|
36
36
|
);
|
|
37
37
|
}
|
|
38
|
-
function ensureFabricBootstrapGuide(workspaceRoot, force) {
|
|
38
|
+
async function ensureFabricBootstrapGuide(workspaceRoot, force) {
|
|
39
39
|
const guidePath = resolve(workspaceRoot, FABRIC_GUIDE_PATH);
|
|
40
40
|
if (existsSync(guidePath) && !force) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
mkdirSync(dirname(guidePath), { recursive: true });
|
|
44
|
-
writeFileSync(guidePath, buildFabricBootstrapGuide(workspaceRoot), "utf8");
|
|
44
|
+
writeFileSync(guidePath, await buildFabricBootstrapGuide(workspaceRoot), "utf8");
|
|
45
45
|
}
|
|
46
46
|
function findBootstrapTemplatePath(frameworkKind) {
|
|
47
47
|
const relativePath = AGENTS_TEMPLATE_BY_FRAMEWORK[frameworkKind] ?? "templates/agents-md/AGENTS.md.template";
|
|
@@ -170,7 +170,7 @@ async function installBootstrap(target, options = {}) {
|
|
|
170
170
|
const installed = [];
|
|
171
171
|
const skipped = [];
|
|
172
172
|
const details = [];
|
|
173
|
-
ensureFabricBootstrapGuide(workspaceRoot, options.force);
|
|
173
|
+
await ensureFabricBootstrapGuide(workspaceRoot, options.force);
|
|
174
174
|
for (const bootstrapTarget of targets) {
|
|
175
175
|
details.push({
|
|
176
176
|
client: bootstrapTarget.client,
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
config_default,
|
|
5
5
|
installMcpClients,
|
|
6
6
|
parseClientFilter
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-BVTMVW5M.js";
|
|
8
|
+
import "./chunk-BEKSXO5N.js";
|
|
9
9
|
import "./chunk-YDZJRLHL.js";
|
|
10
10
|
import "./chunk-6ICJICVU.js";
|
|
11
11
|
export {
|
package/dist/index.js
CHANGED
|
@@ -8,17 +8,18 @@ import { defineCommand, runMain } from "citty";
|
|
|
8
8
|
|
|
9
9
|
// src/commands/index.ts
|
|
10
10
|
var allCommands = {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
approve: () => import("./approve-YT4DEABS.js").then((module) => module.default),
|
|
12
|
+
init: () => import("./init-YR7EVBYQ.js").then((module) => module.default),
|
|
13
|
+
update: () => import("./update-M5M5PYKE.js").then((module) => module.default),
|
|
14
|
+
scan: () => import("./scan-QH76LC7Z.js").then((module) => module.default),
|
|
14
15
|
serve: () => import("./serve-4J2CQY25.js").then((module) => module.default),
|
|
15
16
|
doctor: () => import("./doctor-QTSG2RWF.js").then((module) => module.default),
|
|
16
17
|
"sync-meta": () => import("./sync-meta-LKVSO6TS.js").then((module) => module.default),
|
|
17
18
|
"human-lint": () => import("./human-lint-YSFOZHZ7.js").then((module) => module.default),
|
|
18
19
|
"ledger-append": () => import("./ledger-append-DULKJ6Q2.js").then((module) => module.default),
|
|
19
20
|
"pre-commit": () => import("./pre-commit-IK6SJOPT.js").then((module) => module.default),
|
|
20
|
-
bootstrap: () => import("./bootstrap-
|
|
21
|
-
config: () => import("./config-
|
|
21
|
+
bootstrap: () => import("./bootstrap-VGL3AR26.js").then((module) => module.default),
|
|
22
|
+
config: () => import("./config-EC5L2QNI.js").then((module) => module.configCmd),
|
|
22
23
|
hooks: () => import("./hooks-ZSWVH2JD.js").then((module) => ({
|
|
23
24
|
...module.default,
|
|
24
25
|
meta: {
|
|
@@ -32,7 +33,7 @@ var allCommands = {
|
|
|
32
33
|
var main = defineCommand({
|
|
33
34
|
meta: {
|
|
34
35
|
name: "fabric",
|
|
35
|
-
version: "1.
|
|
36
|
+
version: "1.5.0",
|
|
36
37
|
description: 'Initialize and manage Fabric projects. Use "fabric init" for one-shot setup.'
|
|
37
38
|
},
|
|
38
39
|
subCommands: allCommands
|