@fenglimg/fabric-cli 0.1.4 → 1.1.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.
Files changed (31) hide show
  1. package/dist/{bootstrap-HUDJ2E3Q.js → bootstrap-PMIA4W6G.js} +16 -12
  2. package/dist/chunk-6ICJICVU.js +10 -0
  3. package/dist/{chunk-T3WQUWW4.js → chunk-6UUPKSDE.js} +78 -36
  4. package/dist/chunk-AEOYCVBG.js +0 -0
  5. package/dist/{chunk-U376IPKT.js → chunk-F2BXHPM5.js} +11 -7
  6. package/dist/chunk-JWUO6TIS.js +220 -0
  7. package/dist/{chunk-CZ7U6ULM.js → chunk-L43IGJ6X.js} +17 -7
  8. package/dist/{chunk-N7TTCGJA.js → chunk-VMYPJPKV.js} +1 -0
  9. package/dist/chunk-WWNXR34K.js +49 -0
  10. package/dist/{config-YKDWIRCT.js → config-PXEEXWLM.js} +14 -11
  11. package/dist/doctor-QTSG2RWF.js +125 -0
  12. package/dist/{hooks-VXXO4VZP.js → hooks-5S5IRVQE.js} +15 -12
  13. package/dist/human-lint-YSFOZHZ7.js +13 -0
  14. package/dist/index.js +16 -11
  15. package/dist/init-R73E5YTG.js +1164 -0
  16. package/dist/{ledger-append-EGIKSMU5.js → ledger-append-XZ5SX4O5.js} +2 -1
  17. package/dist/{pre-commit-CXPH7BZH.js → pre-commit-BLSUMT3P.js} +14 -9
  18. package/dist/{scan-UASZQLQP.js → scan-JBGFRB7P.js} +3 -2
  19. package/dist/serve-4J2CQY25.js +112 -0
  20. package/dist/{sync-meta-YTG5V3Y6.js → sync-meta-THZSEM7Y.js} +6 -2
  21. package/package.json +12 -8
  22. package/templates/agents-md/AGENTS.md.template +20 -29
  23. package/templates/agents-md/variants/cocos.md +20 -0
  24. package/templates/agents-md/variants/next.md +20 -0
  25. package/templates/agents-md/variants/vite.md +20 -0
  26. package/templates/claude-hooks/agents-md-init-reminder.cjs +18 -0
  27. package/templates/claude-skills/agents-md-init/SKILL.md +86 -0
  28. package/dist/chunk-BWZHNZG6.js +0 -236
  29. package/dist/chunk-P4KVFB2T.js +0 -22
  30. package/dist/human-lint-II6TBGP4.js +0 -9
  31. package/dist/init-IBS7KO7A.js +0 -149
@@ -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
+ };
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveClients
4
- } from "./chunk-N7TTCGJA.js";
4
+ } from "./chunk-VMYPJPKV.js";
5
+ import {
6
+ t
7
+ } from "./chunk-6ICJICVU.js";
5
8
 
6
9
  // src/commands/config.ts
7
10
  import { existsSync } from "fs";
@@ -37,7 +40,7 @@ function parseClientFilter(value) {
37
40
  const alias = rawClient.trim().toLowerCase();
38
41
  const clientKind = CLIENT_ALIASES[alias];
39
42
  if (clientKind === void 0) {
40
- throw new Error(`Unknown client "${rawClient}". Use a comma-separated list such as cursor,codex,gemini.`);
43
+ throw new Error(t("cli.config.errors.unknown-client", { client: rawClient }));
41
44
  }
42
45
  clients.add(clientKind);
43
46
  }
@@ -50,7 +53,7 @@ async function loadFabricConfig(workspaceRoot) {
50
53
  }
51
54
  const parsed = JSON.parse(await readFile(configPath, "utf8"));
52
55
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
53
- throw new Error(`Expected object in ${configPath}`);
56
+ throw new Error(t("cli.config.errors.expected-object", { path: configPath }));
54
57
  }
55
58
  return parsed;
56
59
  }
@@ -65,22 +68,22 @@ function writeStderr(message) {
65
68
  var configCmd = defineCommand({
66
69
  meta: {
67
70
  name: "config",
68
- description: "\u7BA1\u7406 Fabric MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u3002"
71
+ description: t("cli.config.description")
69
72
  },
70
73
  subCommands: {
71
74
  install: defineCommand({
72
75
  meta: {
73
76
  name: "install",
74
- description: "\u5C06 Fabric MCP \u670D\u52A1\u5668\u6761\u76EE\u5B89\u88C5\u5230\u68C0\u6D4B\u5230\u7684\u5BA2\u6237\u7AEF\u914D\u7F6E\u4E2D\u3002"
77
+ description: t("cli.config.install.description")
75
78
  },
76
79
  args: {
77
80
  clients: {
78
81
  type: "string",
79
- description: "\u53EF\u9009\u7684\u9017\u53F7\u5206\u9694\u5BA2\u6237\u7AEF\u8FC7\u6EE4\u5668\uFF0C\u4F8B\u5982 cursor,codex,gemini\u3002"
82
+ description: t("cli.config.install.args.clients.description")
80
83
  },
81
84
  "dry-run": {
82
85
  type: "boolean",
83
- description: "\u9884\u89C8\u68C0\u6D4B\u5230\u7684\u5199\u5165\u64CD\u4F5C\uFF0C\u4E0D\u4FEE\u6539\u6587\u4EF6\u3002",
86
+ description: t("cli.config.install.args.dry-run.description"),
84
87
  default: false
85
88
  }
86
89
  },
@@ -93,21 +96,21 @@ var configCmd = defineCommand({
93
96
  (writer) => selectedClients === null ? true : selectedClients.has(writer.clientKind)
94
97
  );
95
98
  if (writers.length === 0) {
96
- writeStderr("\u672A\u68C0\u6D4B\u5230 Fabric MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u3002\u8BF7\u521B\u5EFA\u5BA2\u6237\u7AEF\u76EE\u5F55\u6216\u5728 fabric.config.json \u4E2D\u8BBE\u7F6E clientPaths\u3002");
99
+ writeStderr(t("cli.config.install.no-configs"));
97
100
  return;
98
101
  }
99
102
  for (const writer of writers) {
100
103
  const configPath = await writer.detect(workspaceRoot);
101
104
  if (configPath === null) {
102
- writeStderr(`Skipping ${writer.clientKind}: no config path detected.`);
105
+ writeStderr(t("cli.config.install.no-config-path", { client: writer.clientKind }));
103
106
  continue;
104
107
  }
105
108
  if (args["dry-run"]) {
106
- writeStderr(`[dry-run] ${writer.clientKind}: would write ${configPath}`);
109
+ writeStderr(t("cli.config.install.dry-run", { client: writer.clientKind, path: configPath }));
107
110
  continue;
108
111
  }
109
112
  await writer.write(serverPath, workspaceRoot);
110
- writeStderr(`${writer.clientKind}: wrote ${configPath}`);
113
+ writeStderr(t("cli.config.install.wrote", { client: writer.clientKind, path: configPath }));
111
114
  }
112
115
  }
113
116
  })
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveDevMode
4
+ } from "./chunk-AEOYCVBG.js";
5
+ import {
6
+ padEnd,
7
+ paint,
8
+ symbol
9
+ } from "./chunk-WWNXR34K.js";
10
+ import {
11
+ t
12
+ } from "./chunk-6ICJICVU.js";
13
+
14
+ // src/commands/doctor.ts
15
+ import { defineCommand } from "citty";
16
+ import { runDoctorAuditReport, runDoctorReport } from "@fenglimg/fabric-server";
17
+ var DEFAULT_AUDIT_WINDOW_MINUTES = 5;
18
+ var doctorCommand = defineCommand({
19
+ meta: {
20
+ name: "doctor",
21
+ description: t("cli.doctor.description")
22
+ },
23
+ args: {
24
+ target: {
25
+ type: "string",
26
+ description: t("cli.doctor.args.target.description")
27
+ },
28
+ audit: {
29
+ type: "boolean",
30
+ description: t("cli.doctor.args.audit.description"),
31
+ default: false
32
+ },
33
+ "window-minutes": {
34
+ type: "string",
35
+ description: t("cli.doctor.args.window-minutes.description"),
36
+ default: String(DEFAULT_AUDIT_WINDOW_MINUTES)
37
+ }
38
+ },
39
+ async run({ args }) {
40
+ const workspaceRoot = process.cwd();
41
+ const resolution = resolveDevMode(args.target, workspaceRoot);
42
+ const report = await runDoctorReport(resolution.target);
43
+ writeStdout(`${renderStatus(report.status)} ${paint.ai("fab doctor")} ${paint.human(resolution.target)}`);
44
+ for (const check of report.checks) {
45
+ writeStdout(`${renderStatus(check.status)} ${check.name}: ${check.message}`);
46
+ }
47
+ if (!args.audit) {
48
+ return;
49
+ }
50
+ const auditReport = await runDoctorAuditReport(resolution.target, {
51
+ force: true,
52
+ windowMs: parseWindowMinutes(args["window-minutes"])
53
+ });
54
+ if (auditReport.mode === "off") {
55
+ writeStderr(t("cli.doctor.audit.preview-only"));
56
+ }
57
+ if (auditReport.checkedPathCount === 0) {
58
+ writeStderr(t("cli.doctor.audit.none"));
59
+ return;
60
+ }
61
+ if (auditReport.violationCount === 0) {
62
+ writeStderr(
63
+ `${symbol.ok} ${t("cli.doctor.audit.clean", {
64
+ count: String(auditReport.checkedPathCount),
65
+ window: formatDuration(auditReport.windowMs)
66
+ })}`
67
+ );
68
+ return;
69
+ }
70
+ const writer = auditReport.mode === "strict" ? console.error : console.warn;
71
+ writer(
72
+ t("cli.doctor.audit.violations", {
73
+ count: String(auditReport.violationCount),
74
+ window: formatDuration(auditReport.windowMs)
75
+ })
76
+ );
77
+ writeStderr(
78
+ `${padEnd(t("cli.doctor.audit.table.path"), 32)} ${padEnd(t("cli.doctor.audit.table.edit"), 22)} ${padEnd(t("cli.doctor.audit.table.rules"), 22)} ${t("cli.doctor.audit.table.intent")}`
79
+ );
80
+ for (const violation of auditReport.violations) {
81
+ writeStderr(
82
+ `${padEnd(violation.path, 32)} ${padEnd(new Date(violation.editTs).toISOString(), 22)} ${padEnd(formatRulesTs(violation.lastGetRulesTs), 22)} ${violation.intent}`
83
+ );
84
+ }
85
+ if (auditReport.mode === "strict") {
86
+ process.exitCode = 1;
87
+ }
88
+ }
89
+ });
90
+ var doctor_default = doctorCommand;
91
+ function renderStatus(status) {
92
+ if (status === "ok") {
93
+ return symbol.ok;
94
+ }
95
+ if (status === "warn") {
96
+ return symbol.warn;
97
+ }
98
+ return symbol.error;
99
+ }
100
+ function parseWindowMinutes(value) {
101
+ const minutes = Number.parseInt(value ?? String(DEFAULT_AUDIT_WINDOW_MINUTES), 10);
102
+ if (!Number.isInteger(minutes) || minutes < 1) {
103
+ throw new Error(t("cli.doctor.errors.invalid-window", { value: value ?? "<unset>" }));
104
+ }
105
+ return minutes * 60 * 1e3;
106
+ }
107
+ function formatDuration(durationMs) {
108
+ const minutes = Math.max(Math.floor(durationMs / (60 * 1e3)), 1);
109
+ return `${minutes}m`;
110
+ }
111
+ function formatRulesTs(value) {
112
+ return value === null ? t("cli.shared.none") : new Date(value).toISOString();
113
+ }
114
+ function writeStdout(message) {
115
+ process.stdout.write(`${message}
116
+ `);
117
+ }
118
+ function writeStderr(message) {
119
+ process.stderr.write(`${message}
120
+ `);
121
+ }
122
+ export {
123
+ doctor_default as default,
124
+ doctorCommand
125
+ };
@@ -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/hooks.ts
4
7
  import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
@@ -8,18 +11,18 @@ import { defineCommand } from "citty";
8
11
  var hooksCommand = defineCommand({
9
12
  meta: {
10
13
  name: "hooks",
11
- description: "\u7BA1\u7406 Fabric Git \u94A9\u5B50\u6A21\u677F\u3002"
14
+ description: t("cli.hooks.description")
12
15
  },
13
16
  subCommands: {
14
17
  install: defineCommand({
15
18
  meta: {
16
19
  name: "install",
17
- description: "\u5B89\u88C5 Fabric Husky pre-commit \u94A9\u5B50\u6A21\u677F\u3002"
20
+ description: t("cli.hooks.install.description")
18
21
  },
19
22
  args: {
20
23
  target: {
21
24
  type: "string",
22
- description: "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
25
+ description: t("cli.hooks.install.args.target.description"),
23
26
  default: process.cwd()
24
27
  }
25
28
  },
@@ -30,7 +33,7 @@ var hooksCommand = defineCommand({
30
33
  const hookPath = join(huskyDir, "pre-commit");
31
34
  const packageJsonPath = join(target, "package.json");
32
35
  if (!existsSync(packageJsonPath)) {
33
- throw new Error(`package.json is required to install hooks: ${packageJsonPath}`);
36
+ throw new Error(t("cli.hooks.errors.package-json-required", { path: packageJsonPath }));
34
37
  }
35
38
  mkdirSync(huskyDir, { recursive: true });
36
39
  const templateContent = readFileSync(findTemplatePath("templates/husky/pre-commit"), "utf8");
@@ -61,16 +64,16 @@ ${fabricBlock}`, "utf8");
61
64
  `, "utf8");
62
65
  }
63
66
  if (hookAction === "skipped") {
64
- writeStderr(`Fabric hook already present in ${hookPath}, skipped.`);
67
+ writeStderr(t("cli.hooks.install.hook-skipped", { path: hookPath }));
65
68
  } else if (hookAction === "appended") {
66
- writeStderr(`Appended Fabric hook to existing ${hookPath}`);
69
+ writeStderr(t("cli.hooks.install.hook-appended", { path: hookPath }));
67
70
  } else {
68
- writeStderr(`Created ${hookPath}`);
71
+ writeStderr(t("cli.hooks.install.hook-created", { path: hookPath }));
69
72
  }
70
73
  if (hadPrepare) {
71
- writeStderr(`Left existing prepare script unchanged in ${packageJsonPath}`);
74
+ writeStderr(t("cli.hooks.install.prepare-left", { path: packageJsonPath }));
72
75
  } else {
73
- writeStderr(`Added prepare script to ${packageJsonPath}`);
76
+ writeStderr(t("cli.hooks.install.prepare-added", { path: packageJsonPath }));
74
77
  }
75
78
  }
76
79
  })
@@ -82,7 +85,7 @@ function normalizeTarget(targetInput) {
82
85
  }
83
86
  function assertExistingDirectory(target) {
84
87
  if (!existsSync(target) || !statSync(target).isDirectory()) {
85
- throw new Error(`Target must be an existing directory: ${target}`);
88
+ throw new Error(t("cli.shared.target-invalid", { target }));
86
89
  }
87
90
  }
88
91
  function findTemplatePath(relativePath) {
@@ -96,7 +99,7 @@ function findTemplatePath(relativePath) {
96
99
  return candidate;
97
100
  }
98
101
  }
99
- throw new Error(`Template not found: ${relativePath}`);
102
+ throw new Error(t("cli.shared.template-not-found", { path: relativePath }));
100
103
  }
101
104
  function templateCandidatesFrom(start, relativePath) {
102
105
  const candidates = [];
@@ -109,7 +112,7 @@ function templateCandidatesFrom(start, relativePath) {
109
112
  }
110
113
  current = parent;
111
114
  }
112
- return candidates;
115
+ return candidates.reverse();
113
116
  }
114
117
  function writeStderr(message) {
115
118
  process.stderr.write(`${message}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ humanLintCommand,
4
+ humanLockEntrySchema,
5
+ human_lint_default
6
+ } from "./chunk-L43IGJ6X.js";
7
+ import "./chunk-WWNXR34K.js";
8
+ import "./chunk-6ICJICVU.js";
9
+ export {
10
+ human_lint_default as default,
11
+ humanLintCommand,
12
+ humanLockEntrySchema
13
+ };
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ t
4
+ } from "./chunk-6ICJICVU.js";
2
5
 
3
6
  // src/index.ts
4
7
  import { realpathSync } from "fs";
@@ -8,23 +11,25 @@ import { defineCommand, runMain } from "citty";
8
11
 
9
12
  // src/commands/index.ts
10
13
  var allCommands = {
11
- bootstrap: () => import("./bootstrap-HUDJ2E3Q.js").then((module) => module.default),
12
- init: () => import("./init-IBS7KO7A.js").then((module) => module.default),
13
- scan: () => import("./scan-UASZQLQP.js").then((module) => module.default),
14
- "sync-meta": () => import("./sync-meta-YTG5V3Y6.js").then((module) => module.default),
15
- "human-lint": () => import("./human-lint-II6TBGP4.js").then((module) => module.default),
16
- "ledger-append": () => import("./ledger-append-EGIKSMU5.js").then((module) => module.default),
17
- hooks: () => import("./hooks-VXXO4VZP.js").then((module) => module.default),
18
- config: () => import("./config-YKDWIRCT.js").then((module) => module.configCmd),
19
- "pre-commit": () => import("./pre-commit-CXPH7BZH.js").then((module) => module.default)
14
+ bootstrap: () => import("./bootstrap-PMIA4W6G.js").then((module) => module.default),
15
+ doctor: () => import("./doctor-QTSG2RWF.js").then((module) => module.default),
16
+ init: () => import("./init-R73E5YTG.js").then((module) => module.default),
17
+ scan: () => import("./scan-JBGFRB7P.js").then((module) => module.default),
18
+ serve: () => import("./serve-4J2CQY25.js").then((module) => module.default),
19
+ "sync-meta": () => import("./sync-meta-THZSEM7Y.js").then((module) => module.default),
20
+ "human-lint": () => import("./human-lint-YSFOZHZ7.js").then((module) => module.default),
21
+ "ledger-append": () => import("./ledger-append-XZ5SX4O5.js").then((module) => module.default),
22
+ hooks: () => import("./hooks-5S5IRVQE.js").then((module) => module.default),
23
+ config: () => import("./config-PXEEXWLM.js").then((module) => module.configCmd),
24
+ "pre-commit": () => import("./pre-commit-BLSUMT3P.js").then((module) => module.default)
20
25
  };
21
26
 
22
27
  // src/index.ts
23
28
  var main = defineCommand({
24
29
  meta: {
25
30
  name: "fab",
26
- version: "0.1.4",
27
- description: "Fabric CLI - AI \u667A\u80FD\u4F53\u534F\u4F5C\u6846\u67B6"
31
+ version: "1.1.0",
32
+ description: t("cli.main.description")
28
33
  },
29
34
  subCommands: allCommands
30
35
  });