@fenglimg/fabric-cli 0.1.2 → 0.1.4

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveClients
4
- } from "./chunk-3FZPYATY.js";
4
+ } from "./chunk-N7TTCGJA.js";
5
5
  import {
6
6
  readFabricConfig
7
7
  } from "./chunk-AEOYCVBG.js";
@@ -50,18 +50,18 @@ var CLIENT_TARGET_MAP = {
50
50
  var bootstrapCommand = defineCommand({
51
51
  meta: {
52
52
  name: "bootstrap",
53
- description: "Install Fabric bootstrap prompt templates for supported AI clients."
53
+ description: "\u4E3A\u652F\u6301\u7684 AI \u5BA2\u6237\u7AEF\u5B89\u88C5 Fabric \u5F15\u5BFC\u63D0\u793A\u6A21\u677F\u3002"
54
54
  },
55
55
  subCommands: {
56
56
  install: defineCommand({
57
57
  meta: {
58
58
  name: "install",
59
- description: "Copy Fabric bootstrap templates into client-native locations."
59
+ description: "\u5C06 Fabric \u5F15\u5BFC\u6A21\u677F\u590D\u5236\u5230\u5404\u5BA2\u6237\u7AEF\u7684\u539F\u751F\u4F4D\u7F6E\u3002"
60
60
  },
61
61
  args: {
62
62
  clients: {
63
63
  type: "string",
64
- description: "Optional comma-separated client filter, e.g. claude,cursor,codex."
64
+ description: "\u53EF\u9009\u7684\u9017\u53F7\u5206\u9694\u5BA2\u6237\u7AEF\u8FC7\u6EE4\u5668\uFF0C\u4F8B\u5982 claude,cursor,codex\u3002"
65
65
  }
66
66
  },
67
67
  async run({ args }) {
@@ -101,21 +101,21 @@ function createScanReport(targetInput = process.cwd(), fabricConfig) {
101
101
  var scanCommand = defineCommand({
102
102
  meta: {
103
103
  name: "scan",
104
- description: "Scan a project for Fabric bootstrap candidates."
104
+ description: "\u626B\u63CF\u9879\u76EE\u4EE5\u68C0\u6D4B Fabric \u5F15\u5BFC\u5019\u9009\u6A21\u5757\u3002"
105
105
  },
106
106
  args: {
107
107
  target: {
108
108
  type: "string",
109
- description: "Absolute target path to scan. Defaults to CLI target, EXTERNAL_FIXTURE_PATH, fabric.config.json, or cwd."
109
+ description: "\u626B\u63CF\u7684\u76EE\u6807\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 CLI \u53C2\u6570\u3001EXTERNAL_FIXTURE_PATH\u3001fabric.config.json \u6216\u5F53\u524D\u76EE\u5F55\u3002"
110
110
  },
111
111
  debug: {
112
112
  type: "boolean",
113
- description: "Print detector evidence in pretty output.",
113
+ description: "\u4EE5\u683C\u5F0F\u5316\u8F93\u51FA\u6253\u5370\u68C0\u6D4B\u8BC1\u636E\u3002",
114
114
  default: false
115
115
  },
116
116
  json: {
117
117
  type: "boolean",
118
- description: "Print the diagnostic report as JSON.",
118
+ description: "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u8BCA\u65AD\u62A5\u544A\u3002",
119
119
  default: false
120
120
  }
121
121
  },
@@ -9,12 +9,12 @@ import { defineCommand } from "citty";
9
9
  var humanLintCommand = defineCommand({
10
10
  meta: {
11
11
  name: "human-lint",
12
- description: "Validate locked human sections."
12
+ description: "\u9A8C\u8BC1\u9501\u5B9A\u7684\u4EBA\u5DE5\u7F16\u8F91\u533A\u5757\u3002"
13
13
  },
14
14
  args: {
15
15
  target: {
16
16
  type: "string",
17
- description: "Target project path. Defaults to the current working directory.",
17
+ description: "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
18
18
  default: process.cwd()
19
19
  }
20
20
  },
@@ -89,9 +89,15 @@ var ClaudeCodeCLIWriter = class extends JsonClientConfigWriter {
89
89
  constructor(configuredPath) {
90
90
  super(configuredPath);
91
91
  }
92
- defaultPath() {
93
- const claudeDir = join(homedir(), ".claude");
94
- return existsSync(claudeDir) ? join(claudeDir, "settings.json") : null;
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 {
@@ -247,7 +253,7 @@ function resolveClients(workspaceRoot, fabricConfig = {}) {
247
253
  const writers = [];
248
254
  addIfDetected(
249
255
  writers,
250
- existsSync4(join4(homedir4(), ".claude")),
256
+ existsSync4(join4(homedir4(), ".claude")) || existsSync4(join4(workspaceRoot, ".claude")),
251
257
  (configuredPath) => new ClaudeCodeCLIWriter(configuredPath),
252
258
  hasExplicitPath(clientPaths, "claudeCodeCLI") ? clientPaths.claudeCodeCLI : void 0
253
259
  );
@@ -11,17 +11,17 @@ import { defineCommand } from "citty";
11
11
  var syncMetaCommand = defineCommand({
12
12
  meta: {
13
13
  name: "sync-meta",
14
- description: "Sync Fabric metadata from AGENTS.md files."
14
+ description: "\u4ECE AGENTS.md \u6587\u4EF6\u540C\u6B65 Fabric \u5143\u6570\u636E\u3002"
15
15
  },
16
16
  args: {
17
17
  target: {
18
18
  type: "string",
19
- description: "Target project path. Defaults to the current working directory.",
19
+ description: "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
20
20
  default: process.cwd()
21
21
  },
22
22
  "check-only": {
23
23
  type: "boolean",
24
- description: "Exit with code 1 if .fabric/agents.meta.json is stale.",
24
+ description: "\u5982\u679C .fabric/agents.meta.json \u5DF2\u8FC7\u671F\u5219\u4EE5\u4EE3\u7801 1 \u9000\u51FA\u3002",
25
25
  default: false
26
26
  }
27
27
  },
@@ -10,17 +10,17 @@ var INITIAL_PARENT_SHA = "root";
10
10
  var ledgerAppendCommand = defineCommand({
11
11
  meta: {
12
12
  name: "ledger-append",
13
- description: "Append a Fabric intent ledger entry."
13
+ description: "\u5411 Fabric \u610F\u56FE\u65E5\u5FD7\u6DFB\u52A0\u4E00\u6761\u8BB0\u5F55\u3002"
14
14
  },
15
15
  args: {
16
16
  target: {
17
17
  type: "string",
18
- description: "Target project path. Defaults to the current working directory.",
18
+ description: "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
19
19
  default: process.cwd()
20
20
  },
21
21
  staged: {
22
22
  type: "boolean",
23
- description: "Derive the entry from staged changes for pre-commit.",
23
+ description: "\u4ECE\u6682\u5B58\u53D8\u66F4\u4E2D\u63A8\u5BFC\u8BB0\u5F55\uFF08\u7528\u4E8E pre-commit \u9636\u6BB5\uFF09\u3002",
24
24
  default: false
25
25
  }
26
26
  },
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveClients
4
- } from "./chunk-3FZPYATY.js";
4
+ } from "./chunk-N7TTCGJA.js";
5
5
 
6
6
  // src/commands/config.ts
7
7
  import { existsSync } from "fs";
@@ -65,22 +65,22 @@ function writeStderr(message) {
65
65
  var configCmd = defineCommand({
66
66
  meta: {
67
67
  name: "config",
68
- description: "Manage Fabric MCP client configuration."
68
+ description: "\u7BA1\u7406 Fabric MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u3002"
69
69
  },
70
70
  subCommands: {
71
71
  install: defineCommand({
72
72
  meta: {
73
73
  name: "install",
74
- description: "Install Fabric MCP server entries into detected client configs."
74
+ description: "\u5C06 Fabric MCP \u670D\u52A1\u5668\u6761\u76EE\u5B89\u88C5\u5230\u68C0\u6D4B\u5230\u7684\u5BA2\u6237\u7AEF\u914D\u7F6E\u4E2D\u3002"
75
75
  },
76
76
  args: {
77
77
  clients: {
78
78
  type: "string",
79
- description: "Optional comma-separated client filter, e.g. cursor,codex,gemini."
79
+ description: "\u53EF\u9009\u7684\u9017\u53F7\u5206\u9694\u5BA2\u6237\u7AEF\u8FC7\u6EE4\u5668\uFF0C\u4F8B\u5982 cursor,codex,gemini\u3002"
80
80
  },
81
81
  "dry-run": {
82
82
  type: "boolean",
83
- description: "Print detected writes without changing files.",
83
+ description: "\u9884\u89C8\u68C0\u6D4B\u5230\u7684\u5199\u5165\u64CD\u4F5C\uFF0C\u4E0D\u4FEE\u6539\u6587\u4EF6\u3002",
84
84
  default: false
85
85
  }
86
86
  },
@@ -93,7 +93,7 @@ var configCmd = defineCommand({
93
93
  (writer) => selectedClients === null ? true : selectedClients.has(writer.clientKind)
94
94
  );
95
95
  if (writers.length === 0) {
96
- writeStderr("No Fabric MCP client configs detected. Create a client directory or set fabric.config.json clientPaths.");
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");
97
97
  return;
98
98
  }
99
99
  for (const writer of writers) {
@@ -8,18 +8,18 @@ import { defineCommand } from "citty";
8
8
  var hooksCommand = defineCommand({
9
9
  meta: {
10
10
  name: "hooks",
11
- description: "Manage Fabric git hook templates."
11
+ description: "\u7BA1\u7406 Fabric Git \u94A9\u5B50\u6A21\u677F\u3002"
12
12
  },
13
13
  subCommands: {
14
14
  install: defineCommand({
15
15
  meta: {
16
16
  name: "install",
17
- description: "Install the Fabric Husky pre-commit hook template."
17
+ description: "\u5B89\u88C5 Fabric Husky pre-commit \u94A9\u5B50\u6A21\u677F\u3002"
18
18
  },
19
19
  args: {
20
20
  target: {
21
21
  type: "string",
22
- description: "Target project path. Defaults to the current working directory.",
22
+ description: "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
23
23
  default: process.cwd()
24
24
  }
25
25
  },
@@ -33,7 +33,23 @@ var hooksCommand = defineCommand({
33
33
  throw new Error(`package.json is required to install hooks: ${packageJsonPath}`);
34
34
  }
35
35
  mkdirSync(huskyDir, { recursive: true });
36
- writeFileSync(hookPath, readFileSync(findTemplatePath("templates/husky/pre-commit"), "utf8"), "utf8");
36
+ const templateContent = readFileSync(findTemplatePath("templates/husky/pre-commit"), "utf8");
37
+ let hookAction;
38
+ if (existsSync(hookPath)) {
39
+ const existing = readFileSync(hookPath, "utf8");
40
+ if (existing.includes("FAB_BIN=")) {
41
+ hookAction = "skipped";
42
+ } else {
43
+ const fabricBlock = templateContent.replace(/^#!\/bin\/sh\n/, "");
44
+ const separator = existing.endsWith("\n") ? "\n" : "\n\n";
45
+ writeFileSync(hookPath, `${existing}${separator}# --- Fabric ---
46
+ ${fabricBlock}`, "utf8");
47
+ hookAction = "appended";
48
+ }
49
+ } else {
50
+ writeFileSync(hookPath, templateContent, "utf8");
51
+ hookAction = "created";
52
+ }
37
53
  chmodSync(hookPath, 493);
38
54
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
39
55
  const scripts = packageJson.scripts && typeof packageJson.scripts === "object" && !Array.isArray(packageJson.scripts) ? packageJson.scripts : {};
@@ -44,7 +60,13 @@ var hooksCommand = defineCommand({
44
60
  writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}
45
61
  `, "utf8");
46
62
  }
47
- writeStderr(`Installed ${hookPath}`);
63
+ if (hookAction === "skipped") {
64
+ writeStderr(`Fabric hook already present in ${hookPath}, skipped.`);
65
+ } else if (hookAction === "appended") {
66
+ writeStderr(`Appended Fabric hook to existing ${hookPath}`);
67
+ } else {
68
+ writeStderr(`Created ${hookPath}`);
69
+ }
48
70
  if (hadPrepare) {
49
71
  writeStderr(`Left existing prepare script unchanged in ${packageJsonPath}`);
50
72
  } else {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  humanLintCommand,
4
4
  human_lint_default
5
- } from "./chunk-YHIKLBTB.js";
5
+ } from "./chunk-CZ7U6ULM.js";
6
6
  export {
7
7
  human_lint_default as default,
8
8
  humanLintCommand
package/dist/index.js CHANGED
@@ -8,23 +8,23 @@ import { defineCommand, runMain } from "citty";
8
8
 
9
9
  // src/commands/index.ts
10
10
  var allCommands = {
11
- bootstrap: () => import("./bootstrap-BBFPEJQP.js").then((module) => module.default),
12
- init: () => import("./init-VR43EQRO.js").then((module) => module.default),
13
- scan: () => import("./scan-COKVYPOH.js").then((module) => module.default),
14
- "sync-meta": () => import("./sync-meta-YIB7IBHK.js").then((module) => module.default),
15
- "human-lint": () => import("./human-lint-SV4D5LQ7.js").then((module) => module.default),
16
- "ledger-append": () => import("./ledger-append-KYPMIAM4.js").then((module) => module.default),
17
- hooks: () => import("./hooks-QWVCECWF.js").then((module) => module.default),
18
- config: () => import("./config-TNY6BCQ2.js").then((module) => module.configCmd),
19
- "pre-commit": () => import("./pre-commit-ICTZBF6F.js").then((module) => module.default)
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)
20
20
  };
21
21
 
22
22
  // src/index.ts
23
23
  var main = defineCommand({
24
24
  meta: {
25
25
  name: "fab",
26
- version: "0.0.0",
27
- description: "Fabric CLI"
26
+ version: "0.1.4",
27
+ description: "Fabric CLI - AI \u667A\u80FD\u4F53\u534F\u4F5C\u6846\u67B6"
28
28
  },
29
29
  subCommands: allCommands
30
30
  });
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createScanReport
4
- } from "./chunk-SC4A43WR.js";
4
+ } from "./chunk-BWZHNZG6.js";
5
5
  import {
6
6
  createDebugLogger,
7
7
  resolveDevMode
@@ -17,16 +17,16 @@ import { defineCommand } from "citty";
17
17
  var initCommand = defineCommand({
18
18
  meta: {
19
19
  name: "init",
20
- description: "Initialize Fabric in a target project."
20
+ description: "\u5728\u76EE\u6807\u9879\u76EE\u4E2D\u521D\u59CB\u5316 Fabric\u3002"
21
21
  },
22
22
  args: {
23
23
  target: {
24
24
  type: "string",
25
- description: "Target project path. Defaults to CLI target, EXTERNAL_FIXTURE_PATH, fabric.config.json, or cwd."
25
+ description: "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 CLI \u53C2\u6570\u3001EXTERNAL_FIXTURE_PATH\u3001fabric.config.json \u6216\u5F53\u524D\u76EE\u5F55\u3002"
26
26
  },
27
27
  debug: {
28
28
  type: "boolean",
29
- description: "Print target resolution details to stderr.",
29
+ description: "\u5C06\u76EE\u6807\u89E3\u6790\u8BE6\u60C5\u8F93\u51FA\u5230 stderr\u3002",
30
30
  default: false
31
31
  }
32
32
  },
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ledgerAppendCommand,
4
4
  ledger_append_default
5
- } from "./chunk-PJ4J4377.js";
5
+ } from "./chunk-U376IPKT.js";
6
6
  export {
7
7
  ledger_append_default as default,
8
8
  ledgerAppendCommand
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-AEOYCVBG.js";
5
5
  import {
6
6
  sync_meta_default
7
- } from "./chunk-ZW4M4WZB.js";
7
+ } from "./chunk-T3WQUWW4.js";
8
8
  import "./chunk-P4KVFB2T.js";
9
9
  import {
10
10
  human_lint_default
11
- } from "./chunk-YHIKLBTB.js";
11
+ } from "./chunk-CZ7U6ULM.js";
12
12
  import {
13
13
  ledger_append_default
14
- } from "./chunk-PJ4J4377.js";
14
+ } from "./chunk-U376IPKT.js";
15
15
 
16
16
  // src/commands/pre-commit.ts
17
17
  import { defineCommand } from "citty";
@@ -28,12 +28,12 @@ async function runOrFail(name, cmd, args) {
28
28
  var pre_commit_default = defineCommand({
29
29
  meta: {
30
30
  name: "pre-commit",
31
- description: "Composite pre-commit hook \u2014 runs sync-meta --check-only, human-lint, ledger-append --staged in a single Node process for <300ms budget."
31
+ description: "\u590D\u5408 pre-commit \u94A9\u5B50 \u2014\u2014 \u5728\u5355\u4E00 Node \u8FDB\u7A0B\u4E2D\u4F9D\u6B21\u6267\u884C sync-meta --check-only\u3001human-lint\u3001ledger-append --staged\uFF0C300ms \u5185\u5B8C\u6210\u3002"
32
32
  },
33
33
  args: {
34
34
  target: {
35
35
  type: "string",
36
- description: "Project root (default: cwd or EXTERNAL_FIXTURE_PATH)"
36
+ description: "\u9879\u76EE\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4E3A\u5F53\u524D\u76EE\u5F55\u6216 EXTERNAL_FIXTURE_PATH\uFF09\u3002"
37
37
  }
38
38
  },
39
39
  async run({ args }) {
@@ -3,7 +3,7 @@ import {
3
3
  createScanReport,
4
4
  scanCommand,
5
5
  scan_default
6
- } from "./chunk-SC4A43WR.js";
6
+ } from "./chunk-BWZHNZG6.js";
7
7
  import "./chunk-AEOYCVBG.js";
8
8
  import "./chunk-P4KVFB2T.js";
9
9
  export {
@@ -3,7 +3,7 @@ import {
3
3
  computeAgentsMeta,
4
4
  syncMetaCommand,
5
5
  sync_meta_default
6
- } from "./chunk-ZW4M4WZB.js";
6
+ } from "./chunk-T3WQUWW4.js";
7
7
  import "./chunk-P4KVFB2T.js";
8
8
  export {
9
9
  computeAgentsMeta,
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@fenglimg/fabric-cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "bin": {
6
- "fab": "./dist/index.js"
6
+ "fab": "dist/index.js"
7
7
  },
8
8
  "main": "./dist/index.js",
9
9
  "types": "./dist/index.d.ts",
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "templates"
12
13
  ],
13
14
  "scripts": {
14
15
  "build": "tsup",
@@ -0,0 +1,29 @@
1
+ # { projectName } — L0 AGENTS.md
2
+
3
+ // TODO: describe project purpose.
4
+
5
+ <!-- TODO: tech stack: detected framework is { frameworkKind }. Verify this manually before replacing TODOs. -->
6
+
7
+ <!-- fab:index -->
8
+ <!-- /fab:index -->
9
+
10
+ ## Human Documentation References
11
+
12
+ // TODO: reference README.md sections that are source-of-truth for humans.
13
+ // TODO: reference CONTRIBUTING.md if this project has one.
14
+
15
+ ## L0 AI Constraints
16
+
17
+ // TODO: list hard constraints, e.g., ban any, require TypeScript strict.
18
+ // TODO: list commands AI may run for validation.
19
+ // TODO: list files or directories AI must not modify without permission.
20
+
21
+ ## @HUMAN
22
+
23
+ // TODO: human-owned decisions live here. AI must not rewrite locked sentences.
24
+ // TODO: placeholder locked sentence 1.
25
+ // TODO: placeholder locked sentence 2.
26
+
27
+ ## L1 Candidate Notes
28
+
29
+ // TODO: identify domain folders that may need scoped AGENTS.md files.
@@ -0,0 +1,8 @@
1
+ # Fabric Bootstrap
2
+ - 本项目使用 Fabric Protocol 管理规则。
3
+ - **任何文件修改前**,必须调 MCP tool `fab_get_rules(path=<被改文件>)` 获取规则。
4
+ - 新建 L1/L2 节点时,必须调 `fab_update_registry`,**严禁**直接编辑 `.fabric/agents.meta.json`。
5
+ - 涉及 @HUMAN 段(`.fabric/human-lock.json` 中列出)时,必须停下来请示人类。
6
+ - 每次完整任务结束,调 `fab_append_intent` 写一条意图记录。
7
+
8
+ @AGENTS.md
@@ -0,0 +1,8 @@
1
+ # Fabric Bootstrap
2
+ - 本项目使用 Fabric Protocol 管理规则。
3
+ - **任何文件修改前**,必须调 MCP tool `fab_get_rules(path=<被改文件>)` 获取规则。
4
+ - 新建 L1/L2 节点时,必须调 `fab_update_registry`,**严禁**直接编辑 `.fabric/agents.meta.json`。
5
+ - 涉及 @HUMAN 段(`.fabric/human-lock.json` 中列出)时,必须停下来请示人类。
6
+ - 每次完整任务结束,调 `fab_append_intent` 写一条意图记录。
7
+
8
+ @AGENTS.md
@@ -0,0 +1,6 @@
1
+ # Fabric Bootstrap
2
+ - 本项目使用 Fabric Protocol 管理规则。
3
+ - **任何文件修改前**,必须调 MCP tool `fab_get_rules(path=<被改文件>)` 获取规则。
4
+ - 新建 L1/L2 节点时,必须调 `fab_update_registry`,**严禁**直接编辑 `.fabric/agents.meta.json`。
5
+ - 涉及 @HUMAN 段(`.fabric/human-lock.json` 中列出)时,必须停下来请示人类。
6
+ - 每次完整任务结束,调 `fab_append_intent` 写一条意图记录。
@@ -0,0 +1,11 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: Fabric Protocol bootstrap rules
4
+ ---
5
+
6
+ # Fabric Bootstrap
7
+ - 本项目使用 Fabric Protocol 管理规则。
8
+ - **任何文件修改前**,必须调 MCP tool `fab_get_rules(path=<被改文件>)` 获取规则。
9
+ - 新建 L1/L2 节点时,必须调 `fab_update_registry`,**严禁**直接编辑 `.fabric/agents.meta.json`。
10
+ - 涉及 @HUMAN 段(`.fabric/human-lock.json` 中列出)时,必须停下来请示人类。
11
+ - 每次完整任务结束,调 `fab_append_intent` 写一条意图记录。
@@ -0,0 +1,6 @@
1
+ # Fabric Bootstrap
2
+ - 本项目使用 Fabric Protocol 管理规则。
3
+ - **任何文件修改前**,必须调 MCP tool `fab_get_rules(path=<被改文件>)` 获取规则。
4
+ - 新建 L1/L2 节点时,必须调 `fab_update_registry`,**严禁**直接编辑 `.fabric/agents.meta.json`。
5
+ - 涉及 @HUMAN 段(`.fabric/human-lock.json` 中列出)时,必须停下来请示人类。
6
+ - 每次完整任务结束,调 `fab_append_intent` 写一条意图记录。
@@ -0,0 +1,6 @@
1
+ # Fabric Bootstrap
2
+ - 本项目使用 Fabric Protocol 管理规则。
3
+ - **任何文件修改前**,必须调 MCP tool `fab_get_rules(path=<被改文件>)` 获取规则。
4
+ - 新建 L1/L2 节点时,必须调 `fab_update_registry`,**严禁**直接编辑 `.fabric/agents.meta.json`。
5
+ - 涉及 @HUMAN 段(`.fabric/human-lock.json` 中列出)时,必须停下来请示人类。
6
+ - 每次完整任务结束,调 `fab_append_intent` 写一条意图记录。
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://fabric.local/schemas/human-lock.json",
3
+ "locked": [],
4
+ "examples": [
5
+ {
6
+ "file": "AGENTS.md",
7
+ "start_line": 18,
8
+ "end_line": 22,
9
+ "hash": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+ # Fabric pre-commit hook — sub-300ms budget via single Node process
3
+ # Runs: sync-meta --check-only → human-lint → ledger-append --staged → meta-guard
4
+ # Uses local binary (no npx spawn) to avoid 3× Node startup cost.
5
+
6
+ FAB_BIN="./node_modules/.bin/fab"
7
+
8
+ if [ ! -x "$FAB_BIN" ]; then
9
+ echo "fabric: $FAB_BIN not found. Run 'pnpm install' at repo root." >&2
10
+ exit 1
11
+ fi
12
+
13
+ # Single Node invocation covering all three checks + meta guard.
14
+ # The `pre-commit` meta-command chains sync-meta/human-lint/ledger-append
15
+ # inside one process for minimal startup overhead.
16
+ "$FAB_BIN" pre-commit || exit $?
17
+
18
+ # Guard: block manual edits to .fabric/agents.meta.json
19
+ if git diff --cached --name-only | grep -q '^\.fabric/agents\.meta\.json$'; then
20
+ if [ "$FAB_ALLOW_META_EDIT" != '1' ]; then
21
+ echo '.fabric/agents.meta.json cannot be manually edited; use fab_update_registry or set FAB_ALLOW_META_EDIT=1' >&2
22
+ exit 1
23
+ fi
24
+ fi