@fenglimg/fabric-cli 2.2.0-rc.1 → 2.2.0-rc.10
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 +8 -5
- package/dist/chunk-27HK6H5Y.js +69 -0
- package/dist/{chunk-AOE6AYI7.js → chunk-2KBCTMID.js} +31 -8
- package/dist/chunk-3D7B2UAZ.js +149 -0
- package/dist/{chunk-XC5RUHLK.js → chunk-3IOLS5EK.js} +23 -38
- package/dist/{plan-context-hint-FC6P3WFE.js → chunk-722JU5BP.js} +52 -12
- package/dist/{chunk-2R55HNVD.js → chunk-7ZDXBOOU.js} +234 -206
- package/dist/{doctor-YONYXDX6.js → chunk-E7HJUU34.js} +215 -52
- package/dist/chunk-EOT63RDH.js +36 -0
- package/dist/chunk-FNHDQTPC.js +16 -0
- package/dist/{chunk-2CY4BMTH.js → chunk-HORSMSZL.js} +9 -5
- package/dist/{chunk-BO4XIZWZ.js → chunk-NLNH64A3.js} +5 -18
- package/dist/{chunk-WU6GAPKH.js → chunk-PTGQAZEW.js} +12 -4
- package/dist/chunk-QFIVFZRH.js +13 -0
- package/dist/chunk-QPAW6IYT.js +387 -0
- package/dist/{chunk-COI5VDFU.js → chunk-WA3DYGSY.js} +1 -2
- package/dist/{config-XYRBZJDU.js → config-A3LTECAY.js} +4 -3
- package/dist/context-UJCGYOT6.js +117 -0
- package/dist/doctor-MDTZWKBK.js +24 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +133 -22
- package/dist/info-7FKBTMVO.js +139 -0
- package/dist/install-v2-RINEA24K.js +3279 -0
- package/dist/{metrics-RER6NLFC.js → metrics-HMFH4YHK.js} +1 -1
- package/dist/{onboard-coverage-JWQWDZW7.js → onboard-coverage-XSG77LL3.js} +48 -27
- package/dist/plan-context-hint-5TNGH3R4.js +12 -0
- package/dist/{scope-explain-CDIZESP5.js → scope-explain-HLJZ2M33.js} +17 -6
- package/dist/status-4R3TM4FJ.js +37 -0
- package/dist/store-HOCORVL3.js +563 -0
- package/dist/{sync-UJ4BBCZJ.js → sync-DT5UJMMR.js} +197 -30
- package/dist/{uninstall-C3QXKOO6.js → uninstall-IFN2KYBK.js} +97 -140
- package/dist/whoami-ITGEFWH4.js +49 -0
- package/package.json +7 -5
- package/templates/hooks/cite-policy-evict.cjs +412 -160
- package/templates/hooks/configs/README.md +14 -27
- package/templates/hooks/configs/claude-code.json +17 -2
- package/templates/hooks/configs/codex-hooks.json +15 -3
- package/templates/hooks/fabric-hint.cjs +477 -176
- package/templates/hooks/knowledge-hint-broad.cjs +577 -274
- package/templates/hooks/knowledge-hint-narrow.cjs +113 -73
- package/templates/hooks/lib/banner-i18n.cjs +31 -0
- package/templates/hooks/lib/bindings-snapshot-reader.cjs +118 -7
- package/templates/hooks/lib/cite-line-parser.cjs +12 -20
- package/templates/hooks/lib/client-adapter.cjs +66 -7
- package/templates/hooks/lib/nudge-policy.cjs +117 -0
- package/templates/hooks/lib/state-store.cjs +60 -0
- package/templates/hooks/post-tooluse-mutation.cjs +386 -0
- package/templates/hooks/session-end-marker.cjs +140 -0
- package/templates/skills/fabric/SKILL.md +100 -0
- package/templates/skills/fabric-archive/SKILL.md +35 -24
- package/templates/skills/fabric-archive/ref/dry-run-scope.md +1 -1
- package/templates/skills/fabric-archive/ref/i18n-policy.md +2 -3
- package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +2 -3
- package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +1 -1
- package/templates/skills/fabric-archive/ref/phase-3-6-related-edges.md +18 -0
- package/templates/skills/fabric-archive/ref/phase-3-7-semantic-scope.md +47 -0
- package/templates/skills/fabric-audit/SKILL.md +13 -3
- package/templates/skills/fabric-connect/SKILL.md +3 -3
- package/templates/skills/fabric-import/SKILL.md +7 -7
- package/templates/skills/fabric-import/ref/i18n-policy.md +2 -3
- package/templates/skills/fabric-import/ref/state-recovery.md +1 -2
- package/templates/skills/fabric-review/SKILL.md +14 -5
- package/templates/skills/fabric-review/ref/cite-contract.md +1 -1
- package/templates/skills/fabric-review/ref/i18n-policy.md +2 -3
- package/templates/skills/fabric-review/ref/output-contract.md +1 -1
- package/templates/skills/fabric-review/ref/per-mode-flows.md +2 -2
- package/templates/skills/fabric-review/ref/worked-examples.md +1 -1
- package/templates/skills/fabric-store/SKILL.md +1 -1
- package/templates/skills/fabric-sync/SKILL.md +1 -1
- package/templates/skills/lib/shared-policy.md +2 -2
- package/dist/chunk-4R2CYEA4.js +0 -116
- 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/install-74ANPCCP.js +0 -2737
- package/dist/status-GLQWLWH6.js +0 -23
- package/dist/store-XB3ADT65.js +0 -144
- package/dist/whoami-2MLO4Y37.js +0 -36
- package/templates/hooks/configs/cursor-hooks.json +0 -18
- package/templates/hooks/lib/cite-contract-reminder.cjs +0 -179
- package/templates/hooks/lib/summary-fallback.cjs +0 -210
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
deepMerge
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3IOLS5EK.js";
|
|
5
5
|
|
|
6
6
|
// src/install/write-bootstrap-snapshot.ts
|
|
7
7
|
import { existsSync, readFileSync } from "fs";
|
|
8
8
|
import { mkdir } from "fs/promises";
|
|
9
9
|
import { dirname, join } from "path";
|
|
10
10
|
import { atomicWriteText } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
11
|
-
import {
|
|
11
|
+
import { resolveBootstrapCanonical } from "@fenglimg/fabric-shared/templates/bootstrap-canonical";
|
|
12
12
|
var FABRIC_AGENTS_RELPATH = join(".fabric", "AGENTS.md");
|
|
13
13
|
var PROJECT_RULES_RELPATH = join(".fabric", "project-rules.md");
|
|
14
14
|
function fabricAgentsSnapshotPath(targetRoot) {
|
|
@@ -25,32 +25,38 @@ function readProjectRulesIfPresent(targetRoot) {
|
|
|
25
25
|
async function writeFabricAgentsSnapshot(targetRoot) {
|
|
26
26
|
const step = "bootstrap-snapshot";
|
|
27
27
|
const target = fabricAgentsSnapshotPath(targetRoot);
|
|
28
|
+
const canonical = resolveBootstrapCanonical();
|
|
28
29
|
if (existsSync(target)) {
|
|
29
30
|
try {
|
|
30
31
|
const existing = readFileSync(target, "utf8");
|
|
31
|
-
if (existing ===
|
|
32
|
+
if (existing === canonical) {
|
|
32
33
|
return { step, path: target, status: "skipped", message: "up-to-date" };
|
|
33
34
|
}
|
|
34
35
|
} catch {
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
await mkdir(dirname(target), { recursive: true });
|
|
38
|
-
await atomicWriteText(target,
|
|
39
|
+
await atomicWriteText(target, canonical);
|
|
39
40
|
return { step, path: target, status: "written" };
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// src/install/skills-and-hooks.ts
|
|
43
|
-
import { chmodSync, existsSync as existsSync2, readdirSync, readFileSync as readFileSync2
|
|
44
|
+
import { chmodSync, existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
44
45
|
import { mkdir as mkdir2, readFile, rm } from "fs/promises";
|
|
45
46
|
import { dirname as dirname2, join as join2, parse, resolve } from "path";
|
|
46
47
|
import { fileURLToPath } from "url";
|
|
48
|
+
import { resolveGlobalLocale } from "@fenglimg/fabric-shared";
|
|
47
49
|
import { atomicWriteJson, atomicWriteText as atomicWriteText2 } from "@fenglimg/fabric-shared/node/atomic-write";
|
|
48
50
|
import {
|
|
49
51
|
BOOTSTRAP_MARKER_BEGIN,
|
|
50
52
|
BOOTSTRAP_MARKER_END,
|
|
51
|
-
BOOTSTRAP_REGEX
|
|
52
|
-
LEGACY_KB_REGEX
|
|
53
|
+
BOOTSTRAP_REGEX
|
|
53
54
|
} from "@fenglimg/fabric-shared/templates/bootstrap-canonical";
|
|
55
|
+
var SKILL_ROUTER_TEMPLATE_REL = "skills/fabric/SKILL.md";
|
|
56
|
+
var ROUTER_INTENT_MARKER_BEGIN = "<!-- fabric:router-intent:begin -->";
|
|
57
|
+
var ROUTER_INTENT_MARKER_END = "<!-- fabric:router-intent:end -->";
|
|
58
|
+
var ROUTER_INTENT_GENERATED_NOTE = "<!-- \u672C\u5757\u7531 `fabric install` \u4ECE 7 \u4E2A leaf skill \u7684 description Triggers \u5B50\u53E5\u751F\u6210\u3002\u4E25\u7981\u624B\u7F16;\u6539 leaf description \u540E\u91CD\u8DD1 `fabric install`\u3002 -->";
|
|
59
|
+
var ROUTER_INTENT_REGEX = /<!-- fabric:router-intent:begin -->[\s\S]*?<!-- fabric:router-intent:end -->/u;
|
|
54
60
|
var SKILL_TEMPLATE_REL = "skills/fabric-archive/SKILL.md";
|
|
55
61
|
var SKILL_REVIEW_TEMPLATE_REL = "skills/fabric-review/SKILL.md";
|
|
56
62
|
var SKILL_IMPORT_TEMPLATE_REL = "skills/fabric-import/SKILL.md";
|
|
@@ -62,11 +68,18 @@ var HOOK_SCRIPT_TEMPLATE_REL = "hooks/fabric-hint.cjs";
|
|
|
62
68
|
var HOOK_BROAD_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-broad.cjs";
|
|
63
69
|
var HOOK_NARROW_SCRIPT_TEMPLATE_REL = "hooks/knowledge-hint-narrow.cjs";
|
|
64
70
|
var HOOK_CITE_EVICT_SCRIPT_TEMPLATE_REL = "hooks/cite-policy-evict.cjs";
|
|
71
|
+
var HOOK_SESSION_END_SCRIPT_TEMPLATE_REL = "hooks/session-end-marker.cjs";
|
|
72
|
+
var HOOK_POST_TOOLUSE_SCRIPT_TEMPLATE_REL = "hooks/post-tooluse-mutation.cjs";
|
|
65
73
|
var HOOK_LIB_TEMPLATE_DIR_REL = "hooks/lib";
|
|
66
74
|
var CLAUDE_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/claude-code.json";
|
|
67
75
|
var CODEX_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/codex-hooks.json";
|
|
68
|
-
var CURSOR_HOOK_CONFIG_TEMPLATE_REL = "hooks/configs/cursor-hooks.json";
|
|
69
76
|
var SKILL_DESTINATIONS = {
|
|
77
|
+
// B2 skill-router: the fabric/ router skill — single-file (no ref/), installed
|
|
78
|
+
// alongside the 7 leaf skills as the human-facing dispatch entry point.
|
|
79
|
+
fabricRouter: [
|
|
80
|
+
".claude/skills/fabric/SKILL.md",
|
|
81
|
+
".codex/skills/fabric/SKILL.md"
|
|
82
|
+
],
|
|
70
83
|
fabricArchive: [
|
|
71
84
|
".claude/skills/fabric-archive/SKILL.md",
|
|
72
85
|
".codex/skills/fabric-archive/SKILL.md"
|
|
@@ -103,6 +116,59 @@ var SKILL_DESTINATIONS = {
|
|
|
103
116
|
".codex/skills/fabric-connect/SKILL.md"
|
|
104
117
|
]
|
|
105
118
|
};
|
|
119
|
+
var FABRIC_SKILL_INSTALL_SPECS = {
|
|
120
|
+
fabricRouter: {
|
|
121
|
+
slug: "fabric",
|
|
122
|
+
templateRel: SKILL_ROUTER_TEMPLATE_REL,
|
|
123
|
+
destinations: SKILL_DESTINATIONS.fabricRouter,
|
|
124
|
+
step: "skill-router"
|
|
125
|
+
},
|
|
126
|
+
fabricArchive: {
|
|
127
|
+
slug: "fabric-archive",
|
|
128
|
+
templateRel: SKILL_TEMPLATE_REL,
|
|
129
|
+
destinations: SKILL_DESTINATIONS.fabricArchive,
|
|
130
|
+
step: "skill",
|
|
131
|
+
includeRefFiles: true
|
|
132
|
+
},
|
|
133
|
+
fabricReview: {
|
|
134
|
+
slug: "fabric-review",
|
|
135
|
+
templateRel: SKILL_REVIEW_TEMPLATE_REL,
|
|
136
|
+
destinations: SKILL_DESTINATIONS.fabricReview,
|
|
137
|
+
step: "skill-review",
|
|
138
|
+
includeRefFiles: true
|
|
139
|
+
},
|
|
140
|
+
fabricImport: {
|
|
141
|
+
slug: "fabric-import",
|
|
142
|
+
templateRel: SKILL_IMPORT_TEMPLATE_REL,
|
|
143
|
+
destinations: SKILL_DESTINATIONS.fabricImport,
|
|
144
|
+
step: "skill-import",
|
|
145
|
+
includeRefFiles: true
|
|
146
|
+
},
|
|
147
|
+
fabricSync: {
|
|
148
|
+
slug: "fabric-sync",
|
|
149
|
+
templateRel: SKILL_SYNC_TEMPLATE_REL,
|
|
150
|
+
destinations: SKILL_DESTINATIONS.fabricSync,
|
|
151
|
+
step: "skill-sync"
|
|
152
|
+
},
|
|
153
|
+
fabricStore: {
|
|
154
|
+
slug: "fabric-store",
|
|
155
|
+
templateRel: SKILL_STORE_TEMPLATE_REL,
|
|
156
|
+
destinations: SKILL_DESTINATIONS.fabricStore,
|
|
157
|
+
step: "skill-store"
|
|
158
|
+
},
|
|
159
|
+
fabricAudit: {
|
|
160
|
+
slug: "fabric-audit",
|
|
161
|
+
templateRel: SKILL_AUDIT_TEMPLATE_REL,
|
|
162
|
+
destinations: SKILL_DESTINATIONS.fabricAudit,
|
|
163
|
+
step: "skill-audit"
|
|
164
|
+
},
|
|
165
|
+
fabricConnect: {
|
|
166
|
+
slug: "fabric-connect",
|
|
167
|
+
templateRel: SKILL_CONNECT_TEMPLATE_REL,
|
|
168
|
+
destinations: SKILL_DESTINATIONS.fabricConnect,
|
|
169
|
+
step: "skill-connect"
|
|
170
|
+
}
|
|
171
|
+
};
|
|
106
172
|
var DEPRECATED_SKILL_DIRS = [
|
|
107
173
|
".claude/skills/fabric-init",
|
|
108
174
|
".codex/skills/fabric-init"
|
|
@@ -110,51 +176,64 @@ var DEPRECATED_SKILL_DIRS = [
|
|
|
110
176
|
var HOOK_SCRIPT_DESTINATIONS = {
|
|
111
177
|
fabricHint: [
|
|
112
178
|
".claude/hooks/fabric-hint.cjs",
|
|
113
|
-
".codex/hooks/fabric-hint.cjs"
|
|
114
|
-
".cursor/hooks/fabric-hint.cjs"
|
|
179
|
+
".codex/hooks/fabric-hint.cjs"
|
|
115
180
|
],
|
|
116
181
|
knowledgeHintBroad: [
|
|
117
182
|
".claude/hooks/knowledge-hint-broad.cjs",
|
|
118
|
-
".codex/hooks/knowledge-hint-broad.cjs"
|
|
119
|
-
".cursor/hooks/knowledge-hint-broad.cjs"
|
|
183
|
+
".codex/hooks/knowledge-hint-broad.cjs"
|
|
120
184
|
],
|
|
121
185
|
knowledgeHintNarrow: [
|
|
122
186
|
".claude/hooks/knowledge-hint-narrow.cjs",
|
|
123
|
-
".codex/hooks/knowledge-hint-narrow.cjs"
|
|
124
|
-
".cursor/hooks/knowledge-hint-narrow.cjs"
|
|
187
|
+
".codex/hooks/knowledge-hint-narrow.cjs"
|
|
125
188
|
],
|
|
126
189
|
// v2.0.0-rc.34 TASK-06: Claude Code — UserPromptSubmit cite-policy long-
|
|
127
190
|
// session evict sidecar.
|
|
128
|
-
// v2.0.0-rc.37 NEW-21: extended to Codex
|
|
129
|
-
//
|
|
191
|
+
// v2.0.0-rc.37 NEW-21: extended to Codex SessionStart slot.
|
|
192
|
+
// Codex doesn't have an equivalent per-prompt event, so cite-policy-
|
|
130
193
|
// evict.cjs runs in "SessionStart mode" (one-shot stderr emit per session
|
|
131
194
|
// boot, no turn-counter). Cadence is lower than Claude Code's per-prompt
|
|
132
|
-
// window but strictly better than 0 (rc.32 baseline measured Codex
|
|
195
|
+
// window but strictly better than 0 (rc.32 baseline measured Codex
|
|
133
196
|
// at 3.1% cite coverage when no cite-reminder surface existed).
|
|
134
197
|
citePolicyEvict: [
|
|
135
198
|
".claude/hooks/cite-policy-evict.cjs",
|
|
136
|
-
".codex/hooks/cite-policy-evict.cjs"
|
|
137
|
-
|
|
199
|
+
".codex/hooks/cite-policy-evict.cjs"
|
|
200
|
+
],
|
|
201
|
+
// lifecycle-refactor W2-T2: SessionEnd marker hook — both clients.
|
|
202
|
+
sessionEndMarker: [
|
|
203
|
+
".claude/hooks/session-end-marker.cjs",
|
|
204
|
+
".codex/hooks/session-end-marker.cjs"
|
|
205
|
+
],
|
|
206
|
+
// lifecycle-refactor W2-T3: PostToolUse mutation marker hook — both.
|
|
207
|
+
postTooluseMutation: [
|
|
208
|
+
".claude/hooks/post-tooluse-mutation.cjs",
|
|
209
|
+
".codex/hooks/post-tooluse-mutation.cjs"
|
|
138
210
|
]
|
|
139
211
|
};
|
|
140
212
|
var HOOK_LIB_DESTINATIONS = [
|
|
141
213
|
".claude/hooks/lib",
|
|
142
|
-
".codex/hooks/lib"
|
|
143
|
-
".cursor/hooks/lib"
|
|
214
|
+
".codex/hooks/lib"
|
|
144
215
|
];
|
|
145
216
|
var HOOK_CONFIG_TARGETS = {
|
|
146
217
|
claudeCode: ".claude/settings.json",
|
|
147
|
-
codex: ".codex/hooks.json"
|
|
148
|
-
cursor: ".cursor/hooks.json"
|
|
218
|
+
codex: ".codex/hooks.json"
|
|
149
219
|
};
|
|
150
220
|
var HOOK_CONFIG_ARRAY_PATHS = {
|
|
151
221
|
// F2: "hooks.UserPromptSubmit" MUST be listed — the Claude Code template
|
|
152
222
|
// ships a UserPromptSubmit cite-policy hook, so without this path deepMerge
|
|
153
223
|
// array-REPLACEs (instead of append-with-dedupe) on re-install, silently
|
|
154
224
|
// clobbering any user-defined UserPromptSubmit hook.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
225
|
+
// lifecycle-refactor W2-T2/T3: PostToolUse + SessionEnd arrays added so
|
|
226
|
+
// deepMerge append-with-dedupes them on re-install (omitting them would
|
|
227
|
+
// array-REPLACE, clobbering any user-defined entries in those slots).
|
|
228
|
+
claudeCode: [
|
|
229
|
+
"hooks.Stop",
|
|
230
|
+
"hooks.SessionStart",
|
|
231
|
+
"hooks.PreToolUse",
|
|
232
|
+
"hooks.UserPromptSubmit",
|
|
233
|
+
"hooks.PostToolUse",
|
|
234
|
+
"hooks.SessionEnd"
|
|
235
|
+
],
|
|
236
|
+
codex: ["events.Stop", "events.SessionStart", "events.PreToolUse", "events.PostToolUse", "events.SessionEnd"]
|
|
158
237
|
};
|
|
159
238
|
var FABRIC_HOOK_COMMAND_PATHS = {
|
|
160
239
|
claudeCode: {
|
|
@@ -163,38 +242,20 @@ var FABRIC_HOOK_COMMAND_PATHS = {
|
|
|
163
242
|
knowledgeHintNarrow: "${CLAUDE_PROJECT_DIR}/.claude/hooks/knowledge-hint-narrow.cjs",
|
|
164
243
|
// F3: the UserPromptSubmit cite-policy-evict hook must be a known fabric
|
|
165
244
|
// command so uninstall prunes it (matches the literal in claude-code.json).
|
|
166
|
-
citePolicyEvict: "${CLAUDE_PROJECT_DIR}/.claude/hooks/cite-policy-evict.cjs"
|
|
245
|
+
citePolicyEvict: "${CLAUDE_PROJECT_DIR}/.claude/hooks/cite-policy-evict.cjs",
|
|
246
|
+
// lifecycle-refactor W2-T2/T3: SessionEnd + PostToolUse marker hooks.
|
|
247
|
+
sessionEndMarker: "${CLAUDE_PROJECT_DIR}/.claude/hooks/session-end-marker.cjs",
|
|
248
|
+
postTooluseMutation: "${CLAUDE_PROJECT_DIR}/.claude/hooks/post-tooluse-mutation.cjs"
|
|
167
249
|
},
|
|
168
250
|
codex: {
|
|
169
251
|
fabricHint: '"$(git rev-parse --show-toplevel)/.codex/hooks/fabric-hint.cjs"',
|
|
170
252
|
knowledgeHintBroad: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-broad.cjs"',
|
|
171
253
|
knowledgeHintNarrow: '"$(git rev-parse --show-toplevel)/.codex/hooks/knowledge-hint-narrow.cjs"',
|
|
172
|
-
citePolicyEvict: '"$(git rev-parse --show-toplevel)/.codex/hooks/cite-policy-evict.cjs"'
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
fabricHint: ".cursor/hooks/fabric-hint.cjs",
|
|
176
|
-
knowledgeHintBroad: ".cursor/hooks/knowledge-hint-broad.cjs",
|
|
177
|
-
knowledgeHintNarrow: ".cursor/hooks/knowledge-hint-narrow.cjs",
|
|
178
|
-
citePolicyEvict: ".cursor/hooks/cite-policy-evict.cjs"
|
|
254
|
+
citePolicyEvict: '"$(git rev-parse --show-toplevel)/.codex/hooks/cite-policy-evict.cjs"',
|
|
255
|
+
sessionEndMarker: '"$(git rev-parse --show-toplevel)/.codex/hooks/session-end-marker.cjs"',
|
|
256
|
+
postTooluseMutation: '"$(git rev-parse --show-toplevel)/.codex/hooks/post-tooluse-mutation.cjs"'
|
|
179
257
|
}
|
|
180
258
|
};
|
|
181
|
-
function readFabricLanguagePreference(projectRoot) {
|
|
182
|
-
const configPath = join2(projectRoot, ".fabric", "fabric-config.json");
|
|
183
|
-
if (!existsSync2(configPath)) {
|
|
184
|
-
return "match-existing";
|
|
185
|
-
}
|
|
186
|
-
try {
|
|
187
|
-
const raw = readFileSync2(configPath, "utf8");
|
|
188
|
-
const parsed = JSON.parse(raw);
|
|
189
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
190
|
-
return "match-existing";
|
|
191
|
-
}
|
|
192
|
-
const value = parsed["fabric_language"];
|
|
193
|
-
return typeof value === "string" && value.length > 0 ? value : "match-existing";
|
|
194
|
-
} catch {
|
|
195
|
-
return "match-existing";
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
259
|
var SKILL_TOKEN_ERROR_TOKENS = 1e4;
|
|
199
260
|
var STALE_INSTALL_RATIO = 1.5;
|
|
200
261
|
function estimateSkillTokens(text) {
|
|
@@ -223,107 +284,98 @@ function inspectStaleInstall(target, source) {
|
|
|
223
284
|
}
|
|
224
285
|
return null;
|
|
225
286
|
}
|
|
226
|
-
async function
|
|
227
|
-
const source = await readTemplate(
|
|
228
|
-
validateSkillCanonicalSize(source,
|
|
229
|
-
const targets =
|
|
287
|
+
async function installFabricSkill(projectRoot, spec) {
|
|
288
|
+
const source = await readTemplate(spec.templateRel);
|
|
289
|
+
validateSkillCanonicalSize(source, spec.slug);
|
|
290
|
+
const targets = spec.destinations.map((rel) => join2(projectRoot, rel));
|
|
230
291
|
const results = [];
|
|
231
292
|
for (const target of targets) {
|
|
232
293
|
const staleMsg = inspectStaleInstall(target, source);
|
|
233
|
-
const result = await copyTextIdempotent(
|
|
294
|
+
const result = await copyTextIdempotent(spec.step, source, target);
|
|
234
295
|
if (staleMsg && result.status === "written") {
|
|
235
296
|
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
236
297
|
}
|
|
237
298
|
results.push(result);
|
|
238
299
|
}
|
|
239
|
-
|
|
300
|
+
if (spec.includeRefFiles) {
|
|
301
|
+
results.push(...await installSkillRefFiles(projectRoot, spec.slug));
|
|
302
|
+
}
|
|
240
303
|
return results;
|
|
241
304
|
}
|
|
305
|
+
async function installFabricArchiveSkill(projectRoot, _options = {}) {
|
|
306
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricArchive);
|
|
307
|
+
}
|
|
242
308
|
async function installFabricReviewSkill(projectRoot, _options = {}) {
|
|
243
|
-
|
|
244
|
-
validateSkillCanonicalSize(source, "fabric-review");
|
|
245
|
-
const targets = SKILL_DESTINATIONS.fabricReview.map((rel) => join2(projectRoot, rel));
|
|
246
|
-
const results = [];
|
|
247
|
-
for (const target of targets) {
|
|
248
|
-
const staleMsg = inspectStaleInstall(target, source);
|
|
249
|
-
const result = await copyTextIdempotent("skill-review", source, target);
|
|
250
|
-
if (staleMsg && result.status === "written") {
|
|
251
|
-
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
252
|
-
}
|
|
253
|
-
results.push(result);
|
|
254
|
-
}
|
|
255
|
-
results.push(...await installSkillRefFiles(projectRoot, "fabric-review"));
|
|
256
|
-
return results;
|
|
309
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricReview);
|
|
257
310
|
}
|
|
258
311
|
async function installFabricImportSkill(projectRoot, _options = {}) {
|
|
259
|
-
|
|
260
|
-
validateSkillCanonicalSize(source, "fabric-import");
|
|
261
|
-
const targets = SKILL_DESTINATIONS.fabricImport.map((rel) => join2(projectRoot, rel));
|
|
262
|
-
const results = [];
|
|
263
|
-
for (const target of targets) {
|
|
264
|
-
const staleMsg = inspectStaleInstall(target, source);
|
|
265
|
-
const result = await copyTextIdempotent("skill-import", source, target);
|
|
266
|
-
if (staleMsg && result.status === "written") {
|
|
267
|
-
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
268
|
-
}
|
|
269
|
-
results.push(result);
|
|
270
|
-
}
|
|
271
|
-
results.push(...await installSkillRefFiles(projectRoot, "fabric-import"));
|
|
272
|
-
return results;
|
|
312
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricImport);
|
|
273
313
|
}
|
|
274
314
|
async function installFabricSyncSkill(projectRoot, _options = {}) {
|
|
275
|
-
|
|
276
|
-
validateSkillCanonicalSize(source, "fabric-sync");
|
|
277
|
-
const targets = SKILL_DESTINATIONS.fabricSync.map((rel) => join2(projectRoot, rel));
|
|
278
|
-
const results = [];
|
|
279
|
-
for (const target of targets) {
|
|
280
|
-
const staleMsg = inspectStaleInstall(target, source);
|
|
281
|
-
const result = await copyTextIdempotent("skill-sync", source, target);
|
|
282
|
-
if (staleMsg && result.status === "written") {
|
|
283
|
-
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
284
|
-
}
|
|
285
|
-
results.push(result);
|
|
286
|
-
}
|
|
287
|
-
return results;
|
|
315
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricSync);
|
|
288
316
|
}
|
|
289
317
|
async function installFabricStoreSkill(projectRoot, _options = {}) {
|
|
290
|
-
|
|
291
|
-
validateSkillCanonicalSize(source, "fabric-store");
|
|
292
|
-
const targets = SKILL_DESTINATIONS.fabricStore.map((rel) => join2(projectRoot, rel));
|
|
293
|
-
const results = [];
|
|
294
|
-
for (const target of targets) {
|
|
295
|
-
const staleMsg = inspectStaleInstall(target, source);
|
|
296
|
-
const result = await copyTextIdempotent("skill-store", source, target);
|
|
297
|
-
if (staleMsg && result.status === "written") {
|
|
298
|
-
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
299
|
-
}
|
|
300
|
-
results.push(result);
|
|
301
|
-
}
|
|
302
|
-
return results;
|
|
318
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricStore);
|
|
303
319
|
}
|
|
304
320
|
async function installFabricAuditSkill(projectRoot, _options = {}) {
|
|
305
|
-
|
|
306
|
-
validateSkillCanonicalSize(source, "fabric-audit");
|
|
307
|
-
const targets = SKILL_DESTINATIONS.fabricAudit.map((rel) => join2(projectRoot, rel));
|
|
308
|
-
const results = [];
|
|
309
|
-
for (const target of targets) {
|
|
310
|
-
const staleMsg = inspectStaleInstall(target, source);
|
|
311
|
-
const result = await copyTextIdempotent("skill-audit", source, target);
|
|
312
|
-
if (staleMsg && result.status === "written") {
|
|
313
|
-
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
314
|
-
}
|
|
315
|
-
results.push(result);
|
|
316
|
-
}
|
|
317
|
-
return results;
|
|
321
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricAudit);
|
|
318
322
|
}
|
|
319
323
|
async function installFabricConnectSkill(projectRoot, _options = {}) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
324
|
+
return installFabricSkill(projectRoot, FABRIC_SKILL_INSTALL_SPECS.fabricConnect);
|
|
325
|
+
}
|
|
326
|
+
function extractSkillMdDescription(skillMd) {
|
|
327
|
+
const fm = skillMd.match(/^---\n([\s\S]*?)\n---/u);
|
|
328
|
+
if (!fm) return "";
|
|
329
|
+
const desc = fm[1].match(/^description:\s*(.+?)\s*$/mu);
|
|
330
|
+
if (!desc) return "";
|
|
331
|
+
return desc[1].replace(/^["'](.+)["']$/u, "$1").trim();
|
|
332
|
+
}
|
|
333
|
+
function extractTriggersClause(description) {
|
|
334
|
+
const m = description.match(/Triggers?\s+([\s\S]+)$/u);
|
|
335
|
+
if (!m) return "";
|
|
336
|
+
return m[1].trim().replace(/[.。]\s*$/u, "").replace(/\|/gu, "\\|");
|
|
337
|
+
}
|
|
338
|
+
function renderRouterIntentBlock(leaves) {
|
|
339
|
+
const rows = leaves.map((l) => `| ${l.triggers} | \`${l.slug}\` |`).join("\n");
|
|
340
|
+
const enumVals = leaves.map((l) => l.slug.replace(/^fabric-/u, "")).join(" | ");
|
|
341
|
+
return [
|
|
342
|
+
ROUTER_INTENT_MARKER_BEGIN,
|
|
343
|
+
ROUTER_INTENT_GENERATED_NOTE,
|
|
344
|
+
"",
|
|
345
|
+
"| \u7528\u6237\u610F\u56FE(leaf description Triggers) | \u4E0B\u6E38 skill |",
|
|
346
|
+
"| --- | --- |",
|
|
347
|
+
rows,
|
|
348
|
+
"",
|
|
349
|
+
`\`S_CLASSIFY\` \u7684 \`task_type\` \u679A\u4E3E:\`${enumVals}\``,
|
|
350
|
+
ROUTER_INTENT_MARKER_END
|
|
351
|
+
].join("\n");
|
|
352
|
+
}
|
|
353
|
+
async function buildRouterSkillSource() {
|
|
354
|
+
const template = await readTemplate(SKILL_ROUTER_TEMPLATE_REL);
|
|
355
|
+
if (!ROUTER_INTENT_REGEX.test(template)) {
|
|
356
|
+
throw new Error(
|
|
357
|
+
`fabric/SKILL.md is missing the ${ROUTER_INTENT_MARKER_BEGIN} \u2026 ${ROUTER_INTENT_MARKER_END} marker pair \u2014 cannot regenerate the Intent Map. This is a Fabric release bug (router template was hand-edited away from the managed-block contract).`
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
const leafSpecs = Object.values(FABRIC_SKILL_INSTALL_SPECS).filter(
|
|
361
|
+
(spec) => spec.slug !== "fabric"
|
|
362
|
+
);
|
|
363
|
+
const leaves = [];
|
|
364
|
+
for (const spec of leafSpecs) {
|
|
365
|
+
const leafMd = await readTemplate(spec.templateRel);
|
|
366
|
+
leaves.push({ slug: spec.slug, triggers: extractTriggersClause(extractSkillMdDescription(leafMd)) });
|
|
367
|
+
}
|
|
368
|
+
return template.replace(ROUTER_INTENT_REGEX, renderRouterIntentBlock(leaves));
|
|
369
|
+
}
|
|
370
|
+
async function installFabricRouterSkill(projectRoot, _options = {}) {
|
|
371
|
+
const source = await buildRouterSkillSource();
|
|
372
|
+
validateSkillCanonicalSize(source, "fabric");
|
|
373
|
+
const spec = FABRIC_SKILL_INSTALL_SPECS.fabricRouter;
|
|
374
|
+
const targets = spec.destinations.map((rel) => join2(projectRoot, rel));
|
|
323
375
|
const results = [];
|
|
324
376
|
for (const target of targets) {
|
|
325
377
|
const staleMsg = inspectStaleInstall(target, source);
|
|
326
|
-
const result = await copyTextIdempotent(
|
|
378
|
+
const result = await copyTextIdempotent(spec.step, source, target);
|
|
327
379
|
if (staleMsg && result.status === "written") {
|
|
328
380
|
result.message = result.message ? `${staleMsg}; ${result.message}` : staleMsg;
|
|
329
381
|
}
|
|
@@ -517,6 +569,38 @@ async function installCitePolicyEvictHook(projectRoot, _options = {}) {
|
|
|
517
569
|
}
|
|
518
570
|
return results;
|
|
519
571
|
}
|
|
572
|
+
async function installSessionEndMarkerHook(projectRoot, _options = {}) {
|
|
573
|
+
const source = await readTemplate(HOOK_SESSION_END_SCRIPT_TEMPLATE_REL);
|
|
574
|
+
const targets = HOOK_SCRIPT_DESTINATIONS.sessionEndMarker.map((rel) => join2(projectRoot, rel));
|
|
575
|
+
const results = [];
|
|
576
|
+
for (const target of targets) {
|
|
577
|
+
const result = await copyTextIdempotent("hook-session-end-script", source, target);
|
|
578
|
+
if (result.status === "written" && process.platform !== "win32") {
|
|
579
|
+
try {
|
|
580
|
+
chmodSync(target, 493);
|
|
581
|
+
} catch {
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
results.push(result);
|
|
585
|
+
}
|
|
586
|
+
return results;
|
|
587
|
+
}
|
|
588
|
+
async function installPostTooluseMutationHook(projectRoot, _options = {}) {
|
|
589
|
+
const source = await readTemplate(HOOK_POST_TOOLUSE_SCRIPT_TEMPLATE_REL);
|
|
590
|
+
const targets = HOOK_SCRIPT_DESTINATIONS.postTooluseMutation.map((rel) => join2(projectRoot, rel));
|
|
591
|
+
const results = [];
|
|
592
|
+
for (const target of targets) {
|
|
593
|
+
const result = await copyTextIdempotent("hook-post-tooluse-script", source, target);
|
|
594
|
+
if (result.status === "written" && process.platform !== "win32") {
|
|
595
|
+
try {
|
|
596
|
+
chmodSync(target, 493);
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
results.push(result);
|
|
601
|
+
}
|
|
602
|
+
return results;
|
|
603
|
+
}
|
|
520
604
|
async function installHookLibs(projectRoot, _options = {}) {
|
|
521
605
|
const libTemplateDir = findTemplatePath(HOOK_LIB_TEMPLATE_DIR_REL);
|
|
522
606
|
let libFiles;
|
|
@@ -584,16 +668,6 @@ async function mergeCodexHookConfig(projectRoot, _options = {}) {
|
|
|
584
668
|
[...HOOK_CONFIG_ARRAY_PATHS.codex]
|
|
585
669
|
);
|
|
586
670
|
}
|
|
587
|
-
async function mergeCursorHookConfig(projectRoot, _options = {}) {
|
|
588
|
-
const fragment = await readJsonTemplate(CURSOR_HOOK_CONFIG_TEMPLATE_REL);
|
|
589
|
-
const targetPath = join2(projectRoot, HOOK_CONFIG_TARGETS.cursor);
|
|
590
|
-
return mergeJsonIdempotent(
|
|
591
|
-
"cursor-hook-config",
|
|
592
|
-
targetPath,
|
|
593
|
-
fragment,
|
|
594
|
-
[...HOOK_CONFIG_ARRAY_PATHS.cursor]
|
|
595
|
-
);
|
|
596
|
-
}
|
|
597
671
|
function buildManagedBlockBody(targetRoot) {
|
|
598
672
|
const snapshotPath = fabricAgentsSnapshotPath(targetRoot);
|
|
599
673
|
const snapshot = readFileSync2(snapshotPath, "utf8");
|
|
@@ -610,13 +684,6 @@ function wrapInBootstrapMarkers(body) {
|
|
|
610
684
|
${body}
|
|
611
685
|
${BOOTSTRAP_MARKER_END}`;
|
|
612
686
|
}
|
|
613
|
-
function stripLegacyKnowledgeBaseSection(existing) {
|
|
614
|
-
const match = existing.match(LEGACY_KB_REGEX);
|
|
615
|
-
if (match === null) return existing;
|
|
616
|
-
const before = existing.slice(0, match.index ?? 0);
|
|
617
|
-
const after = existing.slice((match.index ?? 0) + match[0].length);
|
|
618
|
-
return `${before}${after.replace(/^\r?\n/, "")}`;
|
|
619
|
-
}
|
|
620
687
|
var CLAUDE_BOOTSTRAP_HEADER = "# Project Knowledge";
|
|
621
688
|
var CLAUDE_AGENTS_IMPORT_LINE = "@.fabric/AGENTS.md";
|
|
622
689
|
var CLAUDE_PROJECT_RULES_IMPORT_LINE = "@.fabric/project-rules.md";
|
|
@@ -639,7 +706,7 @@ async function writeClaudeBootstrapThinShell(targetRoot, _options = {}) {
|
|
|
639
706
|
};
|
|
640
707
|
}
|
|
641
708
|
}
|
|
642
|
-
let next =
|
|
709
|
+
let next = existing;
|
|
643
710
|
if (!projectRulesPresent) {
|
|
644
711
|
next = removeImportLine(next, CLAUDE_PROJECT_RULES_IMPORT_LINE);
|
|
645
712
|
}
|
|
@@ -714,23 +781,22 @@ async function writeCodexBootstrapManagedBlock(targetRoot, _options = {}) {
|
|
|
714
781
|
}
|
|
715
782
|
const body = buildManagedBlockBody(targetRoot);
|
|
716
783
|
const managedBlock = wrapInBootstrapMarkers(body);
|
|
717
|
-
const stripped = stripLegacyKnowledgeBaseSection(existing);
|
|
718
784
|
let next;
|
|
719
|
-
const match =
|
|
785
|
+
const match = existing.match(BOOTSTRAP_REGEX);
|
|
720
786
|
if (match !== null) {
|
|
721
|
-
const before =
|
|
722
|
-
const after =
|
|
787
|
+
const before = existing.slice(0, match.index ?? 0);
|
|
788
|
+
const after = existing.slice((match.index ?? 0) + match[0].length);
|
|
723
789
|
const cleaned = `${before}${after.replace(/^\r?\n/, "")}`;
|
|
724
790
|
const trailingNewline = cleaned.length === 0 || cleaned.endsWith("\n") ? "" : "\n";
|
|
725
791
|
next = `${cleaned}${trailingNewline}${cleaned.length === 0 ? "" : "\n"}${managedBlock}
|
|
726
792
|
`;
|
|
727
793
|
} else {
|
|
728
|
-
if (
|
|
794
|
+
if (existing.length === 0) {
|
|
729
795
|
next = `${managedBlock}
|
|
730
796
|
`;
|
|
731
797
|
} else {
|
|
732
|
-
const trailingNewline =
|
|
733
|
-
next = `${
|
|
798
|
+
const trailingNewline = existing.endsWith("\n") ? "" : "\n";
|
|
799
|
+
next = `${existing}${trailingNewline}
|
|
734
800
|
${managedBlock}
|
|
735
801
|
`;
|
|
736
802
|
}
|
|
@@ -751,55 +817,6 @@ ${managedBlock}
|
|
|
751
817
|
};
|
|
752
818
|
}
|
|
753
819
|
}
|
|
754
|
-
var CURSOR_RULE_FRONT_MATTER = "---\nalwaysApply: true\ndescription: Fabric Protocol bootstrap rules\n---\n\n";
|
|
755
|
-
var CURSOR_LEGACY_FLAT_FILE_REL = join2(".cursor", "rules");
|
|
756
|
-
var CURSOR_BOOTSTRAP_MDC_REL = join2(".cursor", "rules", "fabric-bootstrap.mdc");
|
|
757
|
-
async function writeCursorBootstrapManagedBlock(targetRoot, _options = {}) {
|
|
758
|
-
const step = "bootstrap-cursor";
|
|
759
|
-
const target = join2(targetRoot, CURSOR_BOOTSTRAP_MDC_REL);
|
|
760
|
-
const legacyFlatFile = join2(targetRoot, CURSOR_LEGACY_FLAT_FILE_REL);
|
|
761
|
-
try {
|
|
762
|
-
if (existsSync2(legacyFlatFile)) {
|
|
763
|
-
const stat = statSync(legacyFlatFile);
|
|
764
|
-
if (stat.isFile()) {
|
|
765
|
-
await rm(legacyFlatFile, { force: true });
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
} catch {
|
|
769
|
-
}
|
|
770
|
-
const body = buildManagedBlockBody(targetRoot);
|
|
771
|
-
const managedBlock = wrapInBootstrapMarkers(body);
|
|
772
|
-
const expected = `${CURSOR_RULE_FRONT_MATTER}${managedBlock}
|
|
773
|
-
`;
|
|
774
|
-
let existing = "";
|
|
775
|
-
if (existsSync2(target)) {
|
|
776
|
-
try {
|
|
777
|
-
existing = await readFile(target, "utf8");
|
|
778
|
-
} catch (error) {
|
|
779
|
-
return {
|
|
780
|
-
step,
|
|
781
|
-
path: target,
|
|
782
|
-
status: "error",
|
|
783
|
-
message: error instanceof Error ? error.message : String(error)
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
if (existing === expected) {
|
|
788
|
-
return { step, path: target, status: "skipped", message: "up-to-date" };
|
|
789
|
-
}
|
|
790
|
-
try {
|
|
791
|
-
await mkdir2(dirname2(target), { recursive: true });
|
|
792
|
-
await atomicWriteText2(target, expected);
|
|
793
|
-
return { step, path: target, status: "written" };
|
|
794
|
-
} catch (error) {
|
|
795
|
-
return {
|
|
796
|
-
step,
|
|
797
|
-
path: target,
|
|
798
|
-
status: "error",
|
|
799
|
-
message: error instanceof Error ? error.message : String(error)
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
820
|
async function copyTextIdempotent(step, source, target) {
|
|
804
821
|
if (existsSync2(target)) {
|
|
805
822
|
try {
|
|
@@ -818,6 +835,17 @@ var FABRIC_HOOK_SCRIPT_BASENAMES = /* @__PURE__ */ new Set([
|
|
|
818
835
|
"fabric-hint.cjs",
|
|
819
836
|
"knowledge-hint-broad.cjs",
|
|
820
837
|
"knowledge-hint-narrow.cjs",
|
|
838
|
+
// dual-sink W5-1: the strip set must enumerate the COMPLETE fabric-owned hook
|
|
839
|
+
// surface — same set as FABRIC_HOOK_COMMAND_PATHS. Otherwise a matcher change
|
|
840
|
+
// in the template (e.g. adding `apply_patch` to the Codex PreToolUse/PostToolUse
|
|
841
|
+
// matchers) silently fails to propagate on upgrade: stripStaleHookEntries
|
|
842
|
+
// leaves the un-listed entry in place, and the subsequent append-with-dedupe
|
|
843
|
+
// matches it by `command` and SKIPS the new-matcher fragment, preserving the
|
|
844
|
+
// stale matcher. Listing these three makes the canonical template entry the
|
|
845
|
+
// sole survivor on every re-install, so matcher edits actually sync.
|
|
846
|
+
"cite-policy-evict.cjs",
|
|
847
|
+
"post-tooluse-mutation.cjs",
|
|
848
|
+
"session-end-marker.cjs",
|
|
821
849
|
// rc.5 TASK-010 rename — old hook scripts that pre-upgrade workspaces
|
|
822
850
|
// may still have registered. Sweeping them prevents the double-fire
|
|
823
851
|
// documented in audit §2.6.
|
|
@@ -956,7 +984,6 @@ export {
|
|
|
956
984
|
HOOK_CONFIG_TARGETS,
|
|
957
985
|
HOOK_CONFIG_ARRAY_PATHS,
|
|
958
986
|
FABRIC_HOOK_COMMAND_PATHS,
|
|
959
|
-
readFabricLanguagePreference,
|
|
960
987
|
installFabricArchiveSkill,
|
|
961
988
|
installFabricReviewSkill,
|
|
962
989
|
installFabricImportSkill,
|
|
@@ -964,17 +991,18 @@ export {
|
|
|
964
991
|
installFabricStoreSkill,
|
|
965
992
|
installFabricAuditSkill,
|
|
966
993
|
installFabricConnectSkill,
|
|
994
|
+
installFabricRouterSkill,
|
|
967
995
|
cleanupDeprecatedSkills,
|
|
968
996
|
installSharedSkillLib,
|
|
969
997
|
installArchiveHintHook,
|
|
970
998
|
installKnowledgeHintBroadHook,
|
|
971
999
|
installKnowledgeHintNarrowHook,
|
|
972
1000
|
installCitePolicyEvictHook,
|
|
1001
|
+
installSessionEndMarkerHook,
|
|
1002
|
+
installPostTooluseMutationHook,
|
|
973
1003
|
installHookLibs,
|
|
974
1004
|
mergeClaudeCodeHookConfig,
|
|
975
1005
|
mergeCodexHookConfig,
|
|
976
|
-
mergeCursorHookConfig,
|
|
977
1006
|
writeClaudeBootstrapThinShell,
|
|
978
|
-
writeCodexBootstrapManagedBlock
|
|
979
|
-
writeCursorBootstrapManagedBlock
|
|
1007
|
+
writeCodexBootstrapManagedBlock
|
|
980
1008
|
};
|