@fenglimg/fabric-cli 0.1.3 → 1.0.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/dist/{bootstrap-BBFPEJQP.js → bootstrap-PMIA4W6G.js} +16 -12
- package/dist/{chunk-ZW4M4WZB.js → chunk-5BSTO745.js} +9 -6
- package/dist/chunk-6ICJICVU.js +10 -0
- package/dist/chunk-AEOYCVBG.js +0 -0
- package/dist/{chunk-SC4A43WR.js → chunk-DKQ3HOTK.js} +59 -89
- package/dist/{chunk-PJ4J4377.js → chunk-F2BXHPM5.js} +11 -7
- package/dist/{chunk-YHIKLBTB.js → chunk-L43IGJ6X.js} +17 -7
- package/dist/chunk-P4KVFB2T.js +0 -0
- package/dist/{chunk-3FZPYATY.js → chunk-VMYPJPKV.js} +11 -4
- package/dist/chunk-WWNXR34K.js +49 -0
- package/dist/{config-TNY6BCQ2.js → config-PXEEXWLM.js} +14 -11
- package/dist/{hooks-QWVCECWF.js → hooks-5S5IRVQE.js} +36 -11
- package/dist/human-lint-YSFOZHZ7.js +13 -0
- package/dist/index.js +15 -11
- package/dist/init-G6Q3OOMC.js +601 -0
- package/dist/{ledger-append-KYPMIAM4.js → ledger-append-XZ5SX4O5.js} +2 -1
- package/dist/{pre-commit-ICTZBF6F.js → pre-commit-IEIXHKOD.js} +13 -7
- package/dist/{scan-COKVYPOH.js → scan-6CURGC3D.js} +3 -1
- package/dist/serve-4J2CQY25.js +112 -0
- package/dist/{sync-meta-YIB7IBHK.js → sync-meta-L6M4AEUT.js} +2 -1
- package/package.json +12 -8
- package/templates/agents-md/AGENTS.md.template +17 -11
- package/templates/agents-md/variants/cocos.md +37 -0
- package/templates/agents-md/variants/next.md +37 -0
- package/templates/agents-md/variants/vite.md +37 -0
- package/templates/claude-hooks/agents-md-init-reminder.cjs +18 -0
- package/templates/claude-skills/agents-md-init/SKILL.md +86 -0
- package/dist/human-lint-SV4D5LQ7.js +0 -9
- package/dist/init-VR43EQRO.js +0 -149
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
resolveClients
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VMYPJPKV.js";
|
|
5
5
|
import {
|
|
6
6
|
readFabricConfig
|
|
7
7
|
} from "./chunk-AEOYCVBG.js";
|
|
8
|
+
import {
|
|
9
|
+
t
|
|
10
|
+
} from "./chunk-6ICJICVU.js";
|
|
8
11
|
|
|
9
12
|
// src/commands/bootstrap.ts
|
|
10
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -50,18 +53,18 @@ var CLIENT_TARGET_MAP = {
|
|
|
50
53
|
var bootstrapCommand = defineCommand({
|
|
51
54
|
meta: {
|
|
52
55
|
name: "bootstrap",
|
|
53
|
-
description: "
|
|
56
|
+
description: t("cli.bootstrap.description")
|
|
54
57
|
},
|
|
55
58
|
subCommands: {
|
|
56
59
|
install: defineCommand({
|
|
57
60
|
meta: {
|
|
58
61
|
name: "install",
|
|
59
|
-
description: "
|
|
62
|
+
description: t("cli.bootstrap.install.description")
|
|
60
63
|
},
|
|
61
64
|
args: {
|
|
62
65
|
clients: {
|
|
63
66
|
type: "string",
|
|
64
|
-
description: "
|
|
67
|
+
description: t("cli.bootstrap.install.args.clients.description")
|
|
65
68
|
}
|
|
66
69
|
},
|
|
67
70
|
async run({ args }) {
|
|
@@ -72,7 +75,8 @@ var bootstrapCommand = defineCommand({
|
|
|
72
75
|
const clients = selectedClients ?? detectedClients;
|
|
73
76
|
if (clients.size === 0) {
|
|
74
77
|
process.stderr.write(
|
|
75
|
-
"
|
|
78
|
+
`${t("cli.bootstrap.install.no-targets")}
|
|
79
|
+
`
|
|
76
80
|
);
|
|
77
81
|
return;
|
|
78
82
|
}
|
|
@@ -93,7 +97,7 @@ function parseClientFilter(value) {
|
|
|
93
97
|
const alias = rawClient.trim().toLowerCase();
|
|
94
98
|
const client = CLIENT_ALIASES[alias];
|
|
95
99
|
if (client === void 0) {
|
|
96
|
-
throw new Error(
|
|
100
|
+
throw new Error(t("cli.bootstrap.errors.unknown-client", { client: rawClient }));
|
|
97
101
|
}
|
|
98
102
|
clients.add(client);
|
|
99
103
|
}
|
|
@@ -138,26 +142,26 @@ function installBootstrap(client, workspaceRoot) {
|
|
|
138
142
|
return;
|
|
139
143
|
}
|
|
140
144
|
writeFileSync(targetPath, ensureTrailingNewline(template), "utf8");
|
|
141
|
-
process.stderr.write(
|
|
145
|
+
process.stderr.write(`${t("cli.bootstrap.install.installed", { path: targetPath })}
|
|
142
146
|
`);
|
|
143
147
|
}
|
|
144
148
|
function writeCodexBootstrap(targetPath, template) {
|
|
145
149
|
const nextContent = ensureTrailingNewline(template);
|
|
146
150
|
if (!existsSync(targetPath)) {
|
|
147
151
|
writeFileSync(targetPath, nextContent, "utf8");
|
|
148
|
-
process.stderr.write(
|
|
152
|
+
process.stderr.write(`${t("cli.bootstrap.install.installed", { path: targetPath })}
|
|
149
153
|
`);
|
|
150
154
|
return;
|
|
151
155
|
}
|
|
152
156
|
const existing = readFileSync(targetPath, "utf8");
|
|
153
157
|
if (existing.includes("# Fabric Bootstrap")) {
|
|
154
|
-
process.stderr.write(
|
|
158
|
+
process.stderr.write(`${t("cli.bootstrap.install.skipped-header", { path: targetPath })}
|
|
155
159
|
`);
|
|
156
160
|
return;
|
|
157
161
|
}
|
|
158
162
|
const separator = existing.startsWith("\n") || existing.length === 0 ? "" : "\n";
|
|
159
163
|
writeFileSync(targetPath, `${nextContent}${separator}${existing}`, "utf8");
|
|
160
|
-
process.stderr.write(
|
|
164
|
+
process.stderr.write(`${t("cli.bootstrap.install.prepended", { path: targetPath })}
|
|
161
165
|
`);
|
|
162
166
|
}
|
|
163
167
|
function ensureTrailingNewline(content) {
|
|
@@ -175,7 +179,7 @@ function findTemplatePath(relativePath) {
|
|
|
175
179
|
return candidate;
|
|
176
180
|
}
|
|
177
181
|
}
|
|
178
|
-
throw new Error(
|
|
182
|
+
throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
|
|
179
183
|
}
|
|
180
184
|
function templateCandidatesFrom(start, relativePath) {
|
|
181
185
|
const candidates = [];
|
|
@@ -188,7 +192,7 @@ function templateCandidatesFrom(start, relativePath) {
|
|
|
188
192
|
}
|
|
189
193
|
current = parent;
|
|
190
194
|
}
|
|
191
|
-
return candidates;
|
|
195
|
+
return candidates.reverse();
|
|
192
196
|
}
|
|
193
197
|
export {
|
|
194
198
|
bootstrapCommand,
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
resolveIgnores
|
|
4
4
|
} from "./chunk-P4KVFB2T.js";
|
|
5
|
+
import {
|
|
6
|
+
t
|
|
7
|
+
} from "./chunk-6ICJICVU.js";
|
|
5
8
|
|
|
6
9
|
// src/commands/sync-meta.ts
|
|
7
10
|
import { createHash } from "crypto";
|
|
@@ -11,17 +14,17 @@ import { defineCommand } from "citty";
|
|
|
11
14
|
var syncMetaCommand = defineCommand({
|
|
12
15
|
meta: {
|
|
13
16
|
name: "sync-meta",
|
|
14
|
-
description: "
|
|
17
|
+
description: t("cli.sync-meta.description")
|
|
15
18
|
},
|
|
16
19
|
args: {
|
|
17
20
|
target: {
|
|
18
21
|
type: "string",
|
|
19
|
-
description: "
|
|
22
|
+
description: t("cli.sync-meta.args.target.description"),
|
|
20
23
|
default: process.cwd()
|
|
21
24
|
},
|
|
22
25
|
"check-only": {
|
|
23
26
|
type: "boolean",
|
|
24
|
-
description: "
|
|
27
|
+
description: t("cli.sync-meta.args.check-only.description"),
|
|
25
28
|
default: false
|
|
26
29
|
}
|
|
27
30
|
},
|
|
@@ -32,7 +35,7 @@ var syncMetaCommand = defineCommand({
|
|
|
32
35
|
const existingMeta = readExistingMeta(metaPath);
|
|
33
36
|
if (args["check-only"]) {
|
|
34
37
|
if (!existingMeta || stableStringify(existingMeta) !== stableStringify(computedMeta)) {
|
|
35
|
-
writeStderr("
|
|
38
|
+
writeStderr(t("cli.sync-meta.drift-detected"));
|
|
36
39
|
process.exitCode = 1;
|
|
37
40
|
}
|
|
38
41
|
return;
|
|
@@ -43,7 +46,7 @@ var syncMetaCommand = defineCommand({
|
|
|
43
46
|
mkdirSync(join(target, ".fabric"), { recursive: true });
|
|
44
47
|
writeFileSync(metaPath, `${JSON.stringify(computedMeta, null, 2)}
|
|
45
48
|
`, "utf8");
|
|
46
|
-
writeStderr(
|
|
49
|
+
writeStderr(t("cli.sync-meta.updated", { label: t("cli.shared.updated"), path: metaPath }));
|
|
47
50
|
}
|
|
48
51
|
});
|
|
49
52
|
var sync_meta_default = syncMetaCommand;
|
|
@@ -77,7 +80,7 @@ function normalizeTarget(targetInput) {
|
|
|
77
80
|
}
|
|
78
81
|
function assertExistingDirectory(target) {
|
|
79
82
|
if (!existsSync(target) || !statSync(target).isDirectory()) {
|
|
80
|
-
throw new Error(
|
|
83
|
+
throw new Error(t("cli.shared.target-invalid", { target }));
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
function readExistingMeta(metaPath) {
|
package/dist/chunk-AEOYCVBG.js
CHANGED
|
File without changes
|
|
@@ -7,80 +7,31 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
resolveIgnores
|
|
9
9
|
} from "./chunk-P4KVFB2T.js";
|
|
10
|
+
import {
|
|
11
|
+
displayWidth,
|
|
12
|
+
padEnd,
|
|
13
|
+
paint,
|
|
14
|
+
symbol
|
|
15
|
+
} from "./chunk-WWNXR34K.js";
|
|
16
|
+
import {
|
|
17
|
+
t
|
|
18
|
+
} from "./chunk-6ICJICVU.js";
|
|
10
19
|
|
|
11
20
|
// src/commands/scan.ts
|
|
12
|
-
import { existsSync
|
|
13
|
-
import { isAbsolute, join
|
|
21
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
22
|
+
import { isAbsolute, join, relative, resolve, sep } from "path";
|
|
14
23
|
import { defineCommand } from "citty";
|
|
15
24
|
|
|
16
25
|
// src/scanner/detector.ts
|
|
17
|
-
import {
|
|
18
|
-
import { join } from "path";
|
|
19
|
-
function detectFramework(root) {
|
|
20
|
-
const evidence = [];
|
|
21
|
-
if (existsSync(join(root, "project.config.json"))) {
|
|
22
|
-
return {
|
|
23
|
-
kind: "cocos-creator",
|
|
24
|
-
evidence: ["project.config.json"]
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
const packageJsonPath = join(root, "package.json");
|
|
28
|
-
if (existsSync(packageJsonPath)) {
|
|
29
|
-
const packageJson = readPackageJson(packageJsonPath);
|
|
30
|
-
const deps = collectDependencyNames(packageJson);
|
|
31
|
-
for (const [dependencyName, kind] of [
|
|
32
|
-
["next", "next"],
|
|
33
|
-
["vite", "vite"],
|
|
34
|
-
["react", "react"],
|
|
35
|
-
["vue", "vue"]
|
|
36
|
-
]) {
|
|
37
|
-
if (deps.has(dependencyName)) {
|
|
38
|
-
evidence.push(`package.json dependency: ${dependencyName}`);
|
|
39
|
-
return { kind, evidence };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
evidence.push("package.json");
|
|
43
|
-
}
|
|
44
|
-
if (existsSync(join(root, "Cargo.toml"))) {
|
|
45
|
-
return {
|
|
46
|
-
kind: "rust",
|
|
47
|
-
evidence: ["Cargo.toml"]
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
if (existsSync(join(root, "pyproject.toml"))) {
|
|
51
|
-
return {
|
|
52
|
-
kind: "python",
|
|
53
|
-
evidence: ["pyproject.toml"]
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
kind: "unknown",
|
|
58
|
-
evidence
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function readPackageJson(packageJsonPath) {
|
|
62
|
-
try {
|
|
63
|
-
return JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
64
|
-
} catch {
|
|
65
|
-
return {};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function collectDependencyNames(packageJson) {
|
|
69
|
-
return /* @__PURE__ */ new Set([
|
|
70
|
-
...Object.keys(packageJson.dependencies ?? {}),
|
|
71
|
-
...Object.keys(packageJson.devDependencies ?? {}),
|
|
72
|
-
...Object.keys(packageJson.peerDependencies ?? {}),
|
|
73
|
-
...Object.keys(packageJson.optionalDependencies ?? {})
|
|
74
|
-
]);
|
|
75
|
-
}
|
|
26
|
+
import { detectFramework } from "@fenglimg/fabric-shared";
|
|
76
27
|
|
|
77
28
|
// src/commands/scan.ts
|
|
78
29
|
function createScanReport(targetInput = process.cwd(), fabricConfig) {
|
|
79
30
|
const target = normalizeTarget(targetInput);
|
|
80
31
|
const framework = detectFramework(target);
|
|
81
32
|
const readmeQuality = getReadmeQuality(target);
|
|
82
|
-
const hasContributing =
|
|
83
|
-
const hasExistingFabric =
|
|
33
|
+
const hasContributing = existsSync(join(target, "CONTRIBUTING.md"));
|
|
34
|
+
const hasExistingFabric = existsSync(join(target, "AGENTS.md")) || existsSync(join(target, ".fabric"));
|
|
84
35
|
const walkResult = walkFiles(target, resolveIgnores(fabricConfig));
|
|
85
36
|
return {
|
|
86
37
|
target,
|
|
@@ -101,21 +52,21 @@ function createScanReport(targetInput = process.cwd(), fabricConfig) {
|
|
|
101
52
|
var scanCommand = defineCommand({
|
|
102
53
|
meta: {
|
|
103
54
|
name: "scan",
|
|
104
|
-
description: "
|
|
55
|
+
description: t("cli.scan.description")
|
|
105
56
|
},
|
|
106
57
|
args: {
|
|
107
58
|
target: {
|
|
108
59
|
type: "string",
|
|
109
|
-
description: "
|
|
60
|
+
description: t("cli.scan.args.target.description")
|
|
110
61
|
},
|
|
111
62
|
debug: {
|
|
112
63
|
type: "boolean",
|
|
113
|
-
description: "
|
|
64
|
+
description: t("cli.scan.args.debug.description"),
|
|
114
65
|
default: false
|
|
115
66
|
},
|
|
116
67
|
json: {
|
|
117
68
|
type: "boolean",
|
|
118
|
-
description: "
|
|
69
|
+
description: t("cli.scan.args.json.description"),
|
|
119
70
|
default: false
|
|
120
71
|
}
|
|
121
72
|
},
|
|
@@ -141,16 +92,16 @@ function normalizeTarget(targetInput) {
|
|
|
141
92
|
return isAbsolute(targetInput) ? targetInput : resolve(process.cwd(), targetInput);
|
|
142
93
|
}
|
|
143
94
|
function getReadmeQuality(target) {
|
|
144
|
-
const readmePath =
|
|
145
|
-
if (!
|
|
95
|
+
const readmePath = join(target, "README.md");
|
|
96
|
+
if (!existsSync(readmePath)) {
|
|
146
97
|
return "stub";
|
|
147
98
|
}
|
|
148
|
-
const wordCount =
|
|
99
|
+
const wordCount = readFileSync(readmePath, "utf8").trim().split(/\s+/).filter(Boolean).length;
|
|
149
100
|
return wordCount >= 200 ? "ok" : "stub";
|
|
150
101
|
}
|
|
151
102
|
function walkFiles(root, ignorePatterns) {
|
|
152
|
-
if (!
|
|
153
|
-
throw new Error(
|
|
103
|
+
if (!existsSync(root) || !statSync(root).isDirectory()) {
|
|
104
|
+
throw new Error(t("cli.shared.target-invalid", { target: root }));
|
|
154
105
|
}
|
|
155
106
|
let fileCount = 0;
|
|
156
107
|
let ignoredCount = 0;
|
|
@@ -161,7 +112,7 @@ function walkFiles(root, ignorePatterns) {
|
|
|
161
112
|
continue;
|
|
162
113
|
}
|
|
163
114
|
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
164
|
-
const absolutePath =
|
|
115
|
+
const absolutePath = join(current, entry.name);
|
|
165
116
|
const relativePath = toPosixPath(relative(root, absolutePath));
|
|
166
117
|
if (shouldIgnore(relativePath, entry.isDirectory(), ignorePatterns)) {
|
|
167
118
|
ignoredCount += 1;
|
|
@@ -196,40 +147,59 @@ function toPosixPath(path) {
|
|
|
196
147
|
function buildRecommendations(input) {
|
|
197
148
|
const recommendations = [];
|
|
198
149
|
if (!input.hasExistingFabric) {
|
|
199
|
-
recommendations.push("
|
|
150
|
+
recommendations.push(t("cli.scan.recommendation.init"));
|
|
200
151
|
}
|
|
201
152
|
if (input.readmeQuality === "stub") {
|
|
202
|
-
recommendations.push("
|
|
153
|
+
recommendations.push(t("cli.scan.recommendation.readme"));
|
|
203
154
|
}
|
|
204
155
|
if (!input.hasContributing) {
|
|
205
|
-
recommendations.push("
|
|
156
|
+
recommendations.push(t("cli.scan.recommendation.contributing"));
|
|
206
157
|
}
|
|
207
158
|
if (input.framework.kind === "unknown") {
|
|
208
|
-
recommendations.push("
|
|
159
|
+
recommendations.push(t("cli.scan.recommendation.unknown-framework"));
|
|
209
160
|
} else {
|
|
210
|
-
recommendations.push(
|
|
161
|
+
recommendations.push(t("cli.scan.recommendation.framework-dirs", { framework: input.framework.kind }));
|
|
211
162
|
}
|
|
212
163
|
return recommendations;
|
|
213
164
|
}
|
|
214
165
|
function printPrettyReport(report, debug) {
|
|
215
|
-
console.log("
|
|
216
|
-
|
|
217
|
-
|
|
166
|
+
console.log(paint.ai(t("cli.scan.report.title")));
|
|
167
|
+
const rows = [
|
|
168
|
+
[t("cli.scan.report.target"), paint.human(report.target)],
|
|
169
|
+
[t("cli.scan.report.framework"), paint.ai(report.framework.kind)],
|
|
170
|
+
[
|
|
171
|
+
t("cli.scan.report.readme-quality"),
|
|
172
|
+
report.readmeQuality === "ok" ? paint.success(t("cli.scan.readme-quality.ok")) : paint.warn(t("cli.scan.readme-quality.stub"))
|
|
173
|
+
],
|
|
174
|
+
[
|
|
175
|
+
t("cli.scan.report.contributing"),
|
|
176
|
+
report.hasContributing ? paint.success(t("cli.shared.present")) : paint.warn(t("cli.shared.absent"))
|
|
177
|
+
],
|
|
178
|
+
[t("cli.scan.report.files-counted"), String(report.fileCount)],
|
|
179
|
+
[t("cli.scan.report.ignored-entries"), report.ignoredCount > 0 ? paint.muted(String(report.ignoredCount)) : "0"],
|
|
180
|
+
[
|
|
181
|
+
t("cli.scan.report.existing-fabric"),
|
|
182
|
+
report.hasExistingFabric ? paint.warn(t("cli.shared.yes")) : paint.success(t("cli.shared.no"))
|
|
183
|
+
]
|
|
184
|
+
];
|
|
218
185
|
if (debug) {
|
|
219
|
-
|
|
186
|
+
rows.splice(2, 0, [
|
|
187
|
+
t("cli.scan.report.evidence"),
|
|
188
|
+
report.framework.evidence.length > 0 ? paint.muted(report.framework.evidence.join(", ")) : paint.muted(t("cli.shared.none"))
|
|
189
|
+
]);
|
|
190
|
+
}
|
|
191
|
+
const labelWidth = Math.max(...rows.map(([key]) => displayWidth(key)));
|
|
192
|
+
for (const [key, value] of rows) {
|
|
193
|
+
console.log(`${paint.muted(padEnd(key, labelWidth))} ${value}`);
|
|
220
194
|
}
|
|
221
|
-
console.log(
|
|
222
|
-
console.log(`CONTRIBUTING.md: ${report.hasContributing ? "present" : "missing"}`);
|
|
223
|
-
console.log(`Files counted: ${report.fileCount}`);
|
|
224
|
-
console.log(`Ignored entries: ${report.ignoredCount}`);
|
|
225
|
-
console.log(`Existing Fabric files: ${report.hasExistingFabric ? "yes" : "no"}`);
|
|
226
|
-
console.log("Recommendations:");
|
|
195
|
+
console.log(paint.muted(t("cli.scan.report.recommendations")));
|
|
227
196
|
for (const recommendation of report.recommendations) {
|
|
228
|
-
console.log(
|
|
197
|
+
console.log(`${symbol.warn} ${paint.drift(recommendation)}`);
|
|
229
198
|
}
|
|
230
199
|
}
|
|
231
200
|
|
|
232
201
|
export {
|
|
202
|
+
detectFramework,
|
|
233
203
|
createScanReport,
|
|
234
204
|
scanCommand,
|
|
235
205
|
scan_default
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
t
|
|
4
|
+
} from "./chunk-6ICJICVU.js";
|
|
2
5
|
|
|
3
6
|
// src/commands/ledger-append.ts
|
|
4
7
|
import { execSync } from "child_process";
|
|
@@ -10,17 +13,17 @@ var INITIAL_PARENT_SHA = "root";
|
|
|
10
13
|
var ledgerAppendCommand = defineCommand({
|
|
11
14
|
meta: {
|
|
12
15
|
name: "ledger-append",
|
|
13
|
-
description: "
|
|
16
|
+
description: t("cli.ledger-append.description")
|
|
14
17
|
},
|
|
15
18
|
args: {
|
|
16
19
|
target: {
|
|
17
20
|
type: "string",
|
|
18
|
-
description: "
|
|
21
|
+
description: t("cli.ledger-append.args.target.description"),
|
|
19
22
|
default: process.cwd()
|
|
20
23
|
},
|
|
21
24
|
staged: {
|
|
22
25
|
type: "boolean",
|
|
23
|
-
description: "
|
|
26
|
+
description: t("cli.ledger-append.args.staged.description"),
|
|
24
27
|
default: false
|
|
25
28
|
}
|
|
26
29
|
},
|
|
@@ -28,7 +31,7 @@ var ledgerAppendCommand = defineCommand({
|
|
|
28
31
|
const target = normalizeTarget(args.target);
|
|
29
32
|
assertExistingDirectory(target);
|
|
30
33
|
if (!args.staged) {
|
|
31
|
-
writeStderr("requires
|
|
34
|
+
writeStderr(t("cli.ledger-append.requires-staged"));
|
|
32
35
|
process.exitCode = 1;
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
@@ -40,6 +43,7 @@ var ledgerAppendCommand = defineCommand({
|
|
|
40
43
|
const diffStat = readDiffStat(target).trim();
|
|
41
44
|
const entry = {
|
|
42
45
|
ts: Date.now(),
|
|
46
|
+
source: "human",
|
|
43
47
|
parent_sha: readParentSha(target),
|
|
44
48
|
intent,
|
|
45
49
|
affected_paths: stagedFiles,
|
|
@@ -59,7 +63,7 @@ function normalizeTarget(targetInput) {
|
|
|
59
63
|
}
|
|
60
64
|
function assertExistingDirectory(target) {
|
|
61
65
|
if (!existsSync(target) || !statSync(target).isDirectory()) {
|
|
62
|
-
throw new Error(
|
|
66
|
+
throw new Error(t("cli.shared.target-invalid", { target }));
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
function getStagedFiles(target) {
|
|
@@ -83,8 +87,8 @@ function deriveIntent(stagedFiles) {
|
|
|
83
87
|
}
|
|
84
88
|
const uniqueNames = Array.from(new Set(stagedFiles.map((file) => basename(file))));
|
|
85
89
|
const head = uniqueNames.slice(0, 2).join(", ");
|
|
86
|
-
const suffix = uniqueNames.length > 2 ?
|
|
87
|
-
return
|
|
90
|
+
const suffix = uniqueNames.length > 2 ? t("cli.ledger-append.intent.auto-more", { count: String(uniqueNames.length - 2) }) : "";
|
|
91
|
+
return t("cli.ledger-append.intent.auto", { head, suffix });
|
|
88
92
|
}
|
|
89
93
|
function hasMatchingTailEntry(target, entry) {
|
|
90
94
|
const ledgerPath = join(target, LEDGER_FILE);
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
padEnd
|
|
4
|
+
} from "./chunk-WWNXR34K.js";
|
|
5
|
+
import {
|
|
6
|
+
t
|
|
7
|
+
} from "./chunk-6ICJICVU.js";
|
|
2
8
|
|
|
3
9
|
// src/commands/human-lint.ts
|
|
4
10
|
import { createHash } from "crypto";
|
|
@@ -6,15 +12,16 @@ import { existsSync } from "fs";
|
|
|
6
12
|
import { readFile } from "fs/promises";
|
|
7
13
|
import { isAbsolute, join, resolve } from "path";
|
|
8
14
|
import { defineCommand } from "citty";
|
|
15
|
+
import { humanLockEntrySchema } from "@fenglimg/fabric-shared";
|
|
9
16
|
var humanLintCommand = defineCommand({
|
|
10
17
|
meta: {
|
|
11
18
|
name: "human-lint",
|
|
12
|
-
description: "
|
|
19
|
+
description: t("cli.human-lint.description")
|
|
13
20
|
},
|
|
14
21
|
args: {
|
|
15
22
|
target: {
|
|
16
23
|
type: "string",
|
|
17
|
-
description: "
|
|
24
|
+
description: t("cli.human-lint.args.target.description"),
|
|
18
25
|
default: process.cwd()
|
|
19
26
|
}
|
|
20
27
|
},
|
|
@@ -60,11 +67,13 @@ var humanLintCommand = defineCommand({
|
|
|
60
67
|
if (violations.length === 0) {
|
|
61
68
|
return;
|
|
62
69
|
}
|
|
63
|
-
writeStderr("
|
|
64
|
-
writeStderr(
|
|
70
|
+
writeStderr(t("cli.human-lint.drift-detected"));
|
|
71
|
+
writeStderr(
|
|
72
|
+
`${padEnd(t("cli.human-lint.table.location"), 32)} ${padEnd(t("cli.human-lint.table.expected"), 18)} ${t("cli.human-lint.table.got")}`
|
|
73
|
+
);
|
|
65
74
|
for (const violation of violations) {
|
|
66
75
|
writeStderr(
|
|
67
|
-
`${violation.location
|
|
76
|
+
`${padEnd(violation.location, 32)} ${padEnd(violation.expected, 18)} ${violation.actual}`
|
|
68
77
|
);
|
|
69
78
|
}
|
|
70
79
|
process.exitCode = 1;
|
|
@@ -81,7 +90,7 @@ function hashLockedContent(content, entry) {
|
|
|
81
90
|
}
|
|
82
91
|
function shortenHash(value) {
|
|
83
92
|
if (value === "missing") {
|
|
84
|
-
return
|
|
93
|
+
return t("cli.shared.missing");
|
|
85
94
|
}
|
|
86
95
|
return value.slice(0, 15);
|
|
87
96
|
}
|
|
@@ -92,5 +101,6 @@ function writeStderr(message) {
|
|
|
92
101
|
|
|
93
102
|
export {
|
|
94
103
|
humanLintCommand,
|
|
95
|
-
human_lint_default
|
|
104
|
+
human_lint_default,
|
|
105
|
+
humanLockEntrySchema
|
|
96
106
|
};
|
package/dist/chunk-P4KVFB2T.js
CHANGED
|
File without changes
|
|
@@ -89,9 +89,15 @@ var ClaudeCodeCLIWriter = class extends JsonClientConfigWriter {
|
|
|
89
89
|
constructor(configuredPath) {
|
|
90
90
|
super(configuredPath);
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
// Writes to project-level .claude/settings.json so MCP is scoped to the project.
|
|
93
|
+
// Detection in resolver still checks ~/ to confirm Claude Code is installed.
|
|
94
|
+
defaultPath(workspaceRoot) {
|
|
95
|
+
const globalClaudeDir = join(homedir(), ".claude");
|
|
96
|
+
const projectClaudeDir = join(workspaceRoot, ".claude");
|
|
97
|
+
if (!existsSync(globalClaudeDir) && !existsSync(projectClaudeDir)) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return join(projectClaudeDir, "settings.json");
|
|
95
101
|
}
|
|
96
102
|
};
|
|
97
103
|
var CursorWriter = class extends JsonClientConfigWriter {
|
|
@@ -234,6 +240,7 @@ var CodexTOMLConfigWriter = class {
|
|
|
234
240
|
};
|
|
235
241
|
|
|
236
242
|
// src/config/resolver.ts
|
|
243
|
+
import { clientPathsSchema, fabricConfigSchema } from "@fenglimg/fabric-shared";
|
|
237
244
|
function hasExplicitPath(clientPaths, key) {
|
|
238
245
|
return typeof clientPaths?.[key] === "string" && clientPaths[key].trim().length > 0;
|
|
239
246
|
}
|
|
@@ -247,7 +254,7 @@ function resolveClients(workspaceRoot, fabricConfig = {}) {
|
|
|
247
254
|
const writers = [];
|
|
248
255
|
addIfDetected(
|
|
249
256
|
writers,
|
|
250
|
-
existsSync4(join4(homedir4(), ".claude")),
|
|
257
|
+
existsSync4(join4(homedir4(), ".claude")) || existsSync4(join4(workspaceRoot, ".claude")),
|
|
251
258
|
(configuredPath) => new ClaudeCodeCLIWriter(configuredPath),
|
|
252
259
|
hasExplicitPath(clientPaths, "claudeCodeCLI") ? clientPaths.claudeCodeCLI : void 0
|
|
253
260
|
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/colors.ts
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import stringWidth from "string-width";
|
|
6
|
+
function isColorEnabled() {
|
|
7
|
+
return !process.env.NO_COLOR && Boolean(process.stdout.isTTY) && Boolean(process.stderr.isTTY);
|
|
8
|
+
}
|
|
9
|
+
function colorize(painter) {
|
|
10
|
+
return (value) => isColorEnabled() ? painter(value) : value;
|
|
11
|
+
}
|
|
12
|
+
var paint = {
|
|
13
|
+
success: colorize(pc.green),
|
|
14
|
+
warn: colorize(pc.yellow),
|
|
15
|
+
error: colorize(pc.red),
|
|
16
|
+
drift: colorize(pc.magenta),
|
|
17
|
+
ai: colorize(pc.blue),
|
|
18
|
+
human: colorize(pc.cyan),
|
|
19
|
+
muted: colorize(pc.dim)
|
|
20
|
+
};
|
|
21
|
+
var symbol = {
|
|
22
|
+
get ok() {
|
|
23
|
+
return isColorEnabled() ? paint.success("\u2713") : "[ok]";
|
|
24
|
+
},
|
|
25
|
+
get warn() {
|
|
26
|
+
return isColorEnabled() ? paint.warn("!") : "[warn]";
|
|
27
|
+
},
|
|
28
|
+
get error() {
|
|
29
|
+
return isColorEnabled() ? paint.error("x") : "[error]";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function displayWidth(value) {
|
|
33
|
+
return stringWidth(value);
|
|
34
|
+
}
|
|
35
|
+
function padEnd(value, width, char = " ") {
|
|
36
|
+
const fill = char.length > 0 ? char : " ";
|
|
37
|
+
let result = value;
|
|
38
|
+
while (displayWidth(result) < width) {
|
|
39
|
+
result += fill;
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
paint,
|
|
46
|
+
symbol,
|
|
47
|
+
displayWidth,
|
|
48
|
+
padEnd
|
|
49
|
+
};
|