lee-spec-kit 0.8.7 → 0.8.8

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.en.md CHANGED
@@ -75,8 +75,8 @@ The overall approach is influenced by [spec-kit](https://github.com/github/spec-
75
75
  - `docs`
76
76
  - `detect`
77
77
  - `github`
78
- - `integrations codex-hooks`
79
- - `integrations codex`
78
+ - `integrations codex-hooks`: install/remove hooks in the workspace and configured project roots
79
+ - `integrations codex`: install/remove the optional global `[features].hooks` setting
80
80
  - `commit-audit --json`
81
81
  - `workflow-audit --json`
82
82
 
package/README.md CHANGED
@@ -75,8 +75,8 @@ npx lee-spec-kit feature user-auth
75
75
  - `docs`: 내장 agent policy 문서 조회
76
76
  - `detect`: 현재 워크스페이스가 lee-spec-kit 프로젝트인지 감지
77
77
  - `github`: issue/pr 본문 생성 및 검증
78
- - `integrations codex-hooks`: 현재 workspace용 Codex hooks 스캐폴드 생성/제거
79
- - `integrations codex`: 전역 Codex hooks flag 설치/제거
78
+ - `integrations codex-hooks`: 현재 workspace와 configured project root용 Codex hooks 생성/제거
79
+ - `integrations codex`: 선택적 전역 `[features].hooks` 설정 설치/제거
80
80
  - `commit-audit --json`: hooks용 commit-time docs path validator
81
81
  - `workflow-audit --json`: hooks용 docs sync validator
82
82
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- export { LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN, LEE_SPEC_KIT_CODEX_BOOTSTRAP_END, getCodexConfigPath, getCodexHome, hasLeeSpecKitCodexBootstrap, removeLeeSpecKitCodexBootstrap, upsertLeeSpecKitCodexBootstrap } from './chunk-LYFRLOFQ.js';
2
+ export { LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN, LEE_SPEC_KIT_CODEX_BOOTSTRAP_END, getCodexConfigPath, getCodexHome, hasLeeSpecKitCodexBootstrap, removeLeeSpecKitCodexBootstrap, upsertLeeSpecKitCodexBootstrap } from './chunk-3AFCPGGS.js';
3
3
  import './chunk-7V7RMGEU.js';
4
- //# sourceMappingURL=bootstrap-G37N6RGB.js.map
5
- //# sourceMappingURL=bootstrap-G37N6RGB.js.map
4
+ //# sourceMappingURL=bootstrap-Q77MTW3Q.js.map
5
+ //# sourceMappingURL=bootstrap-Q77MTW3Q.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"bootstrap-G37N6RGB.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"bootstrap-Q77MTW3Q.js"}
@@ -5,7 +5,7 @@ import path from 'path';
5
5
 
6
6
  var LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN = "# lee-spec-kit:codex-bootstrap:begin";
7
7
  var LEE_SPEC_KIT_CODEX_BOOTSTRAP_END = "# lee-spec-kit:codex-bootstrap:end";
8
- var REQUIRED_HOOKS_FLAG_LINE = "codex_hooks = true";
8
+ var REQUIRED_HOOKS_FLAG_LINE = "hooks = true";
9
9
  function renderManagedSegment() {
10
10
  return [
11
11
  LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN,
@@ -13,11 +13,6 @@ function renderManagedSegment() {
13
13
  LEE_SPEC_KIT_CODEX_BOOTSTRAP_END
14
14
  ].join("\n");
15
15
  }
16
- function renderManagedBlock() {
17
- return `${renderManagedSegment()}
18
-
19
- `;
20
- }
21
16
  function sanitizeTomlScanContent(content) {
22
17
  let result = "";
23
18
  let index = 0;
@@ -102,33 +97,22 @@ function stripManagedBlock(content) {
102
97
  const replaceEnd = endIndex + LEE_SPEC_KIT_CODEX_BOOTSTRAP_END.length;
103
98
  return `${content.slice(0, beginIndex)}${content.slice(replaceEnd)}`;
104
99
  }
105
- function findFirstTableHeaderIndex(content) {
100
+ function findFeaturesTableHeaderEnd(content) {
106
101
  const sanitized = sanitizeTomlScanContent(content);
107
- const match = sanitized.match(/^\s*\[[^\]]+\](?:\s*#.*)?$/m);
108
- return match?.index ?? -1;
102
+ const match = /^\s*\[features\](?:\s*#.*)?(?:\r?\n|$)/m.exec(sanitized);
103
+ return match?.index === void 0 ? -1 : match.index + match[0].length;
109
104
  }
110
- function insertManagedBlockAtTopLevel(content, block) {
111
- const normalizedBlock = block.trimEnd();
112
- const firstTableIndex = findFirstTableHeaderIndex(content);
113
- if (firstTableIndex === -1) {
114
- let next2 = content;
115
- if (next2.length > 0 && !next2.endsWith("\n")) next2 += "\n";
116
- if (next2.trim().length > 0 && !next2.endsWith("\n\n")) next2 += "\n";
117
- next2 += `${normalizedBlock}
118
- `;
119
- return next2;
120
- }
121
- const before = content.slice(0, firstTableIndex).trimEnd();
122
- const after = content.slice(firstTableIndex).replace(/^\n+/, "");
123
- let next = "";
124
- if (before.length > 0) {
125
- next += before;
126
- if (!next.endsWith("\n\n")) next += next.endsWith("\n") ? "\n" : "\n\n";
105
+ function insertManagedFeaturesBlock(content) {
106
+ const segment = renderManagedSegment();
107
+ const featuresHeaderEnd = findFeaturesTableHeaderEnd(content);
108
+ if (featuresHeaderEnd !== -1) {
109
+ return `${content.slice(0, featuresHeaderEnd)}${segment}
110
+ ${content.slice(featuresHeaderEnd)}`;
127
111
  }
128
- next += `${normalizedBlock}
129
-
130
- ${after}`;
131
- return next;
112
+ const prefix = content.trimEnd();
113
+ return `${prefix}${prefix ? "\n\n" : ""}[features]
114
+ ${segment}
115
+ `;
132
116
  }
133
117
  function getCodexHome() {
134
118
  const explicit = String(process.env.CODEX_HOME || "").trim();
@@ -139,7 +123,7 @@ function getCodexConfigPath() {
139
123
  return path.join(getCodexHome(), "config.toml");
140
124
  }
141
125
  function contentIncludesRequiredBootstrap(content) {
142
- return hasEnabledTopLevelCodexHooksKey(content) || hasEnabledFeaturesTableCodexHooksKey(content) || hasEnabledFeaturesInlineTableCodexHooksKey(content);
126
+ return hasEnabledTopLevelFeaturesHooksKey(content) || hasEnabledFeaturesTableHooksKey(content) || hasEnabledFeaturesInlineTableHooksKey(content) || hasEnabledTopLevelCodexHooksKey(content) || hasEnabledFeaturesTableCodexHooksKey(content) || hasEnabledFeaturesInlineTableCodexHooksKey(content);
143
127
  }
144
128
  function hasConflictingTopLevelKey(content, key) {
145
129
  const sanitized = sanitizeTomlScanContent(content);
@@ -148,7 +132,10 @@ function hasConflictingTopLevelKey(content, key) {
148
132
  return keyPattern.test(sanitized);
149
133
  }
150
134
  function hasEnabledTopLevelCodexHooksKey(content) {
151
- return /^\s*codex_hooks\s*=\s*true\b/m.test(
135
+ return /^\s*codex_hooks\s*=\s*true\b/m.test(sanitizeTomlScanContent(content));
136
+ }
137
+ function hasEnabledTopLevelFeaturesHooksKey(content) {
138
+ return /^\s*features\.hooks\s*=\s*true\b/m.test(
152
139
  sanitizeTomlScanContent(content)
153
140
  );
154
141
  }
@@ -164,7 +151,9 @@ function hasConflictingFeaturesTableKey(content, key) {
164
151
  continue;
165
152
  }
166
153
  if (!inFeaturesTable) continue;
167
- if (new RegExp(`^${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*=`).test(line)) {
154
+ if (new RegExp(`^${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*=`).test(
155
+ line
156
+ )) {
168
157
  return true;
169
158
  }
170
159
  }
@@ -188,6 +177,23 @@ function hasEnabledFeaturesTableCodexHooksKey(content) {
188
177
  }
189
178
  return false;
190
179
  }
180
+ function hasEnabledFeaturesTableHooksKey(content) {
181
+ const lines = sanitizeTomlScanContent(content).split("\n");
182
+ let inFeaturesTable = false;
183
+ for (const rawLine of lines) {
184
+ const line = rawLine.trim();
185
+ if (!line || line.startsWith("#")) continue;
186
+ const tableMatch = line.match(/^\[([^\]]+)\](?:\s*#.*)?$/);
187
+ if (tableMatch) {
188
+ inFeaturesTable = tableMatch[1]?.trim() === "features";
189
+ continue;
190
+ }
191
+ if (inFeaturesTable && /^hooks\s*=\s*true\b/.test(line)) {
192
+ return true;
193
+ }
194
+ }
195
+ return false;
196
+ }
191
197
  function hasConflictingFeaturesInlineTableKey(content, key) {
192
198
  const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
193
199
  const lines = sanitizeTomlScanContent(content).split("\n");
@@ -213,44 +219,46 @@ function hasEnabledFeaturesInlineTableCodexHooksKey(content) {
213
219
  }
214
220
  return false;
215
221
  }
222
+ function hasEnabledFeaturesInlineTableHooksKey(content) {
223
+ const lines = sanitizeTomlScanContent(content).split("\n");
224
+ return lines.some((rawLine) => {
225
+ const line = rawLine.trim();
226
+ return !!line && !line.startsWith("#") && /^features\s*=\s*\{/.test(line) && /\bhooks\s*=\s*true\b/.test(line);
227
+ });
228
+ }
216
229
  async function hasLeeSpecKitCodexBootstrap(filePath = getCodexConfigPath()) {
217
230
  if (!await fs.pathExists(filePath)) return false;
218
231
  const content = await fs.readFile(filePath, "utf-8");
219
232
  return content.includes(LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN) && content.includes(LEE_SPEC_KIT_CODEX_BOOTSTRAP_END) || contentIncludesRequiredBootstrap(content);
220
233
  }
221
234
  async function upsertLeeSpecKitCodexBootstrap(filePath = getCodexConfigPath()) {
222
- const block = renderManagedBlock();
223
- const segment = renderManagedSegment();
224
235
  await fs.ensureDir(path.dirname(filePath));
225
236
  const exists = await fs.pathExists(filePath);
226
237
  if (!exists) {
227
- await fs.writeFile(filePath, block, "utf-8");
238
+ await fs.writeFile(filePath, insertManagedFeaturesBlock(""), "utf-8");
228
239
  return { changed: true, action: "created", filePath };
229
240
  }
230
241
  const current = await fs.readFile(filePath, "utf-8");
231
242
  const externalContent = stripManagedBlock(current);
232
- const beginIndex = current.indexOf(LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN);
233
- const endIndex = current.indexOf(LEE_SPEC_KIT_CODEX_BOOTSTRAP_END);
234
- if (hasConflictingTopLevelKey(externalContent, "codex_hooks") || hasConflictingTopLevelKey(externalContent, "features.codex_hooks") || hasConflictingFeaturesTableKey(externalContent, "codex_hooks") || hasConflictingFeaturesInlineTableKey(externalContent, "codex_hooks")) {
235
- throw new Error(
236
- `Codex config already defines codex_hooks outside lee-spec-kit managed block: ${filePath}`
237
- );
238
- }
239
- if (beginIndex !== -1 && endIndex !== -1 && beginIndex <= endIndex) {
240
- const replaceEnd = endIndex + LEE_SPEC_KIT_CODEX_BOOTSTRAP_END.length;
241
- const next2 = `${current.slice(0, beginIndex)}${segment}${current.slice(replaceEnd)}`;
242
- if (next2 === current) {
243
+ if (contentIncludesRequiredBootstrap(externalContent)) {
244
+ if (externalContent === current) {
243
245
  return { changed: false, action: "noop", filePath };
244
246
  }
245
- await fs.writeFile(filePath, next2, "utf-8");
247
+ await fs.writeFile(filePath, externalContent.trimEnd() + "\n", "utf-8");
246
248
  return { changed: true, action: "updated", filePath };
247
249
  }
248
- if (contentIncludesRequiredBootstrap(current)) {
249
- return { changed: false, action: "noop", filePath };
250
+ if (hasConflictingTopLevelKey(externalContent, "features.hooks") || hasConflictingFeaturesTableKey(externalContent, "hooks") || hasConflictingFeaturesInlineTableKey(externalContent, "hooks") || hasConflictingTopLevelKey(externalContent, "codex_hooks") || hasConflictingTopLevelKey(externalContent, "features.codex_hooks") || hasConflictingFeaturesTableKey(externalContent, "codex_hooks") || hasConflictingFeaturesInlineTableKey(externalContent, "codex_hooks")) {
251
+ throw new Error(
252
+ `Codex config already defines hooks outside lee-spec-kit managed block: ${filePath}`
253
+ );
250
254
  }
251
- const next = insertManagedBlockAtTopLevel(current, block);
255
+ const next = insertManagedFeaturesBlock(externalContent);
252
256
  await fs.writeFile(filePath, next, "utf-8");
253
- return { changed: true, action: "appended", filePath };
257
+ return {
258
+ changed: true,
259
+ action: externalContent === current ? "appended" : "updated",
260
+ filePath
261
+ };
254
262
  }
255
263
  async function removeLeeSpecKitCodexBootstrap(filePath = getCodexConfigPath()) {
256
264
  if (!await fs.pathExists(filePath)) {
@@ -271,5 +279,5 @@ async function removeLeeSpecKitCodexBootstrap(filePath = getCodexConfigPath()) {
271
279
  }
272
280
 
273
281
  export { LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN, LEE_SPEC_KIT_CODEX_BOOTSTRAP_END, getCodexConfigPath, getCodexHome, hasLeeSpecKitCodexBootstrap, removeLeeSpecKitCodexBootstrap, upsertLeeSpecKitCodexBootstrap };
274
- //# sourceMappingURL=chunk-LYFRLOFQ.js.map
275
- //# sourceMappingURL=chunk-LYFRLOFQ.js.map
282
+ //# sourceMappingURL=chunk-3AFCPGGS.js.map
283
+ //# sourceMappingURL=chunk-3AFCPGGS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/integrations/codex/bootstrap.ts"],"names":[],"mappings":"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","file":"chunk-3AFCPGGS.js","sourcesContent":["import fs from 'fs-extra';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport const LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN =\n '# lee-spec-kit:codex-bootstrap:begin';\nexport const LEE_SPEC_KIT_CODEX_BOOTSTRAP_END =\n '# lee-spec-kit:codex-bootstrap:end';\n\nconst REQUIRED_HOOKS_FLAG_LINE = 'hooks = true';\n\nfunction renderManagedSegment(): string {\n return [\n LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN,\n REQUIRED_HOOKS_FLAG_LINE,\n LEE_SPEC_KIT_CODEX_BOOTSTRAP_END,\n ].join('\\n');\n}\n\nfunction sanitizeTomlScanContent(content: string): string {\n let result = '';\n let index = 0;\n let state: 'normal' | 'basic' | 'literal' | 'multibasic' | 'multiliteral' =\n 'normal';\n\n while (index < content.length) {\n const nextThree = content.slice(index, index + 3);\n const char = content[index] || '';\n\n if (state === 'normal') {\n if (nextThree === '\"\"\"') {\n result += ' ';\n index += 3;\n state = 'multibasic';\n continue;\n }\n if (nextThree === \"'''\") {\n result += ' ';\n index += 3;\n state = 'multiliteral';\n continue;\n }\n if (char === '\"') {\n result += ' ';\n index += 1;\n state = 'basic';\n continue;\n }\n if (char === \"'\") {\n result += ' ';\n index += 1;\n state = 'literal';\n continue;\n }\n result += char;\n index += 1;\n continue;\n }\n\n if (state === 'basic') {\n if (char === '\\\\') {\n result += ' ';\n index += 2;\n continue;\n }\n result += char === '\\n' ? '\\n' : ' ';\n index += 1;\n if (char === '\"') state = 'normal';\n continue;\n }\n\n if (state === 'literal') {\n result += char === '\\n' ? '\\n' : ' ';\n index += 1;\n if (char === \"'\") state = 'normal';\n continue;\n }\n\n if (state === 'multibasic') {\n if (nextThree === '\"\"\"') {\n result += ' ';\n index += 3;\n state = 'normal';\n continue;\n }\n result += char === '\\n' ? '\\n' : ' ';\n index += 1;\n continue;\n }\n\n if (nextThree === \"'''\") {\n result += ' ';\n index += 3;\n state = 'normal';\n continue;\n }\n result += char === '\\n' ? '\\n' : ' ';\n index += 1;\n }\n\n return result;\n}\n\nfunction stripManagedBlock(content: string): string {\n const beginIndex = content.indexOf(LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN);\n const endIndex = content.indexOf(LEE_SPEC_KIT_CODEX_BOOTSTRAP_END);\n if (beginIndex === -1 || endIndex === -1 || beginIndex > endIndex) {\n return content;\n }\n const replaceEnd = endIndex + LEE_SPEC_KIT_CODEX_BOOTSTRAP_END.length;\n return `${content.slice(0, beginIndex)}${content.slice(replaceEnd)}`;\n}\n\nfunction findFeaturesTableHeaderEnd(content: string): number {\n const sanitized = sanitizeTomlScanContent(content);\n const match = /^\\s*\\[features\\](?:\\s*#.*)?(?:\\r?\\n|$)/m.exec(sanitized);\n return match?.index === undefined ? -1 : match.index + match[0].length;\n}\n\nfunction insertManagedFeaturesBlock(content: string): string {\n const segment = renderManagedSegment();\n const featuresHeaderEnd = findFeaturesTableHeaderEnd(content);\n if (featuresHeaderEnd !== -1) {\n return `${content.slice(0, featuresHeaderEnd)}${segment}\\n${content.slice(featuresHeaderEnd)}`;\n }\n\n const prefix = content.trimEnd();\n return `${prefix}${prefix ? '\\n\\n' : ''}[features]\\n${segment}\\n`;\n}\n\nexport function getCodexHome(): string {\n const explicit = String(process.env.CODEX_HOME || '').trim();\n if (explicit) return explicit;\n return path.join(os.homedir(), '.codex');\n}\n\nexport function getCodexConfigPath(): string {\n return path.join(getCodexHome(), 'config.toml');\n}\n\nfunction contentIncludesRequiredBootstrap(content: string): boolean {\n return (\n hasEnabledTopLevelFeaturesHooksKey(content) ||\n hasEnabledFeaturesTableHooksKey(content) ||\n hasEnabledFeaturesInlineTableHooksKey(content) ||\n hasEnabledTopLevelCodexHooksKey(content) ||\n hasEnabledFeaturesTableCodexHooksKey(content) ||\n hasEnabledFeaturesInlineTableCodexHooksKey(content)\n );\n}\n\nfunction hasConflictingTopLevelKey(content: string, key: string): boolean {\n const sanitized = sanitizeTomlScanContent(content);\n const escaped = key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const keyPattern = new RegExp(`^\\\\s*${escaped}\\\\s*=`, 'm');\n return keyPattern.test(sanitized);\n}\n\nfunction hasEnabledTopLevelCodexHooksKey(content: string): boolean {\n return /^\\s*codex_hooks\\s*=\\s*true\\b/m.test(sanitizeTomlScanContent(content));\n}\n\nfunction hasEnabledTopLevelFeaturesHooksKey(content: string): boolean {\n return /^\\s*features\\.hooks\\s*=\\s*true\\b/m.test(\n sanitizeTomlScanContent(content)\n );\n}\n\nfunction hasConflictingFeaturesTableKey(content: string, key: string): boolean {\n const lines = sanitizeTomlScanContent(content).split('\\n');\n let inFeaturesTable = false;\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith('#')) continue;\n\n const tableMatch = line.match(/^\\[([^\\]]+)\\](?:\\s*#.*)?$/);\n if (tableMatch) {\n inFeaturesTable = tableMatch[1]?.trim() === 'features';\n continue;\n }\n\n if (!inFeaturesTable) continue;\n if (\n new RegExp(`^${key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*=`).test(\n line\n )\n ) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction hasEnabledFeaturesTableCodexHooksKey(content: string): boolean {\n const lines = sanitizeTomlScanContent(content).split('\\n');\n let inFeaturesTable = false;\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith('#')) continue;\n\n const tableMatch = line.match(/^\\[([^\\]]+)\\](?:\\s*#.*)?$/);\n if (tableMatch) {\n inFeaturesTable = tableMatch[1]?.trim() === 'features';\n continue;\n }\n\n if (!inFeaturesTable) continue;\n if (/^codex_hooks\\s*=\\s*true\\b/.test(line)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction hasEnabledFeaturesTableHooksKey(content: string): boolean {\n const lines = sanitizeTomlScanContent(content).split('\\n');\n let inFeaturesTable = false;\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith('#')) continue;\n\n const tableMatch = line.match(/^\\[([^\\]]+)\\](?:\\s*#.*)?$/);\n if (tableMatch) {\n inFeaturesTable = tableMatch[1]?.trim() === 'features';\n continue;\n }\n\n if (inFeaturesTable && /^hooks\\s*=\\s*true\\b/.test(line)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction hasConflictingFeaturesInlineTableKey(\n content: string,\n key: string\n): boolean {\n const escapedKey = key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const lines = sanitizeTomlScanContent(content).split('\\n');\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith('#')) continue;\n if (!/^features\\s*=\\s*\\{/.test(line)) continue;\n if (new RegExp(`\\\\b${escapedKey}\\\\s*=`).test(line)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction hasEnabledFeaturesInlineTableCodexHooksKey(content: string): boolean {\n const lines = sanitizeTomlScanContent(content).split('\\n');\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith('#')) continue;\n if (!/^features\\s*=\\s*\\{/.test(line)) continue;\n if (/\\bcodex_hooks\\s*=\\s*true\\b/.test(line)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction hasEnabledFeaturesInlineTableHooksKey(content: string): boolean {\n const lines = sanitizeTomlScanContent(content).split('\\n');\n return lines.some((rawLine) => {\n const line = rawLine.trim();\n return (\n !!line &&\n !line.startsWith('#') &&\n /^features\\s*=\\s*\\{/.test(line) &&\n /\\bhooks\\s*=\\s*true\\b/.test(line)\n );\n });\n}\n\nexport async function hasLeeSpecKitCodexBootstrap(\n filePath = getCodexConfigPath()\n): Promise<boolean> {\n if (!(await fs.pathExists(filePath))) return false;\n const content = await fs.readFile(filePath, 'utf-8');\n return (\n (content.includes(LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN) &&\n content.includes(LEE_SPEC_KIT_CODEX_BOOTSTRAP_END)) ||\n contentIncludesRequiredBootstrap(content)\n );\n}\n\nexport async function upsertLeeSpecKitCodexBootstrap(\n filePath = getCodexConfigPath()\n): Promise<{\n changed: boolean;\n action: 'created' | 'appended' | 'updated' | 'noop';\n filePath: string;\n}> {\n await fs.ensureDir(path.dirname(filePath));\n\n const exists = await fs.pathExists(filePath);\n if (!exists) {\n await fs.writeFile(filePath, insertManagedFeaturesBlock(''), 'utf-8');\n return { changed: true, action: 'created', filePath };\n }\n\n const current = await fs.readFile(filePath, 'utf-8');\n const externalContent = stripManagedBlock(current);\n\n if (contentIncludesRequiredBootstrap(externalContent)) {\n if (externalContent === current) {\n return { changed: false, action: 'noop', filePath };\n }\n await fs.writeFile(filePath, externalContent.trimEnd() + '\\n', 'utf-8');\n return { changed: true, action: 'updated', filePath };\n }\n\n if (\n hasConflictingTopLevelKey(externalContent, 'features.hooks') ||\n hasConflictingFeaturesTableKey(externalContent, 'hooks') ||\n hasConflictingFeaturesInlineTableKey(externalContent, 'hooks') ||\n hasConflictingTopLevelKey(externalContent, 'codex_hooks') ||\n hasConflictingTopLevelKey(externalContent, 'features.codex_hooks') ||\n hasConflictingFeaturesTableKey(externalContent, 'codex_hooks') ||\n hasConflictingFeaturesInlineTableKey(externalContent, 'codex_hooks')\n ) {\n throw new Error(\n `Codex config already defines hooks outside lee-spec-kit managed block: ${filePath}`\n );\n }\n\n const next = insertManagedFeaturesBlock(externalContent);\n\n await fs.writeFile(filePath, next, 'utf-8');\n return {\n changed: true,\n action: externalContent === current ? 'appended' : 'updated',\n filePath,\n };\n}\n\nexport async function removeLeeSpecKitCodexBootstrap(\n filePath = getCodexConfigPath()\n): Promise<{ changed: boolean; filePath: string }> {\n if (!(await fs.pathExists(filePath))) {\n return { changed: false, filePath };\n }\n\n const current = await fs.readFile(filePath, 'utf-8');\n const beginIndex = current.indexOf(LEE_SPEC_KIT_CODEX_BOOTSTRAP_BEGIN);\n const endIndex = current.indexOf(LEE_SPEC_KIT_CODEX_BOOTSTRAP_END);\n if (beginIndex === -1 || endIndex === -1 || beginIndex > endIndex) {\n return { changed: false, filePath };\n }\n\n const replaceEnd = endIndex + LEE_SPEC_KIT_CODEX_BOOTSTRAP_END.length;\n let next = `${current.slice(0, beginIndex)}${current.slice(replaceEnd)}`;\n next = next.replace(/\\n{3,}/g, '\\n\\n').trimEnd();\n if (next.length > 0) next += '\\n';\n await fs.writeFile(filePath, next, 'utf-8');\n return { changed: true, filePath };\n}\n"]}
@@ -12,12 +12,14 @@ var MANAGED_HOOK_FILENAMES = [
12
12
  "pre_tool_use_policy.mjs",
13
13
  "stop_workflow_audit.mjs"
14
14
  ];
15
- function getHookScriptContent(fileName) {
15
+ function getHookScriptContent(fileName, repoRoot, workflowRoot) {
16
16
  switch (fileName) {
17
17
  case "_lee_spec_kit_hook_utils.mjs":
18
18
  return `#!/usr/bin/env node
19
19
  import fs from 'node:fs';
20
+ import path from 'node:path';
20
21
  import { spawnSync } from 'node:child_process';
22
+ import { fileURLToPath } from 'node:url';
21
23
 
22
24
  export function readHookInput() {
23
25
  try {
@@ -38,6 +40,18 @@ export function readHookInput() {
38
40
  }
39
41
 
40
42
  const CLI_ENTRYPOINT = ${JSON.stringify(getInstalledCliEntrypoint())};
43
+ const HOOK_REPO_ROOT = path.resolve(
44
+ path.dirname(fileURLToPath(import.meta.url)),
45
+ '..',
46
+ '..'
47
+ );
48
+ const WORKFLOW_ROOT_RELATIVE = ${JSON.stringify(
49
+ path.relative(path.resolve(repoRoot), path.resolve(workflowRoot))
50
+ )};
51
+
52
+ export function getWorkflowCwd() {
53
+ return path.resolve(HOOK_REPO_ROOT, WORKFLOW_ROOT_RELATIVE);
54
+ }
41
55
 
42
56
  export function runLeeSpecKit(args, cwd = process.cwd()) {
43
57
  return spawnSync(process.execPath, [CLI_ENTRYPOINT, ...args], {
@@ -115,7 +129,7 @@ export function printBlock(reason) {
115
129
  `;
116
130
  case "session_start_lee_spec_kit.mjs":
117
131
  return `#!/usr/bin/env node
118
- import { printAdditionalContext, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
132
+ import { getWorkflowCwd, printAdditionalContext, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
119
133
 
120
134
  // Equivalent CLI probe: npx lee-spec-kit detect --json
121
135
  const inputResult = readHookInput();
@@ -123,7 +137,7 @@ if (!inputResult.ok) {
123
137
  process.exit(0);
124
138
  }
125
139
  const input = inputResult.value;
126
- const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : process.cwd();
140
+ const cwd = getWorkflowCwd();
127
141
  const detectedResult = runLeeSpecKitJson(['detect', '--json'], cwd);
128
142
  const detected = detectedResult.ok ? detectedResult.data : null;
129
143
 
@@ -167,14 +181,14 @@ if (detected?.status === 'ok' && detected?.isLeeSpecKitProject === true) {
167
181
  `;
168
182
  case "user_prompt_submit_lee_spec_kit.mjs":
169
183
  return `#!/usr/bin/env node
170
- import { printAdditionalContext, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
184
+ import { getWorkflowCwd, printAdditionalContext, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
171
185
 
172
186
  const inputResult = readHookInput();
173
187
  if (!inputResult.ok) {
174
188
  process.exit(0);
175
189
  }
176
190
  const input = inputResult.value;
177
- const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : process.cwd();
191
+ const cwd = getWorkflowCwd();
178
192
  const detectedResult = runLeeSpecKitJson(['detect', '--json'], cwd);
179
193
  const detected = detectedResult.ok ? detectedResult.data : null;
180
194
 
@@ -213,7 +227,7 @@ if (detected?.status === 'ok' && detected?.isLeeSpecKitProject === true) {
213
227
  `;
214
228
  case "pre_tool_use_policy.mjs":
215
229
  return `#!/usr/bin/env node
216
- import { printBlock, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
230
+ import { getWorkflowCwd, printBlock, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
217
231
  import fs from 'node:fs';
218
232
  import path from 'node:path';
219
233
 
@@ -232,6 +246,7 @@ if (!inputResult.ok) {
232
246
  }
233
247
  const input = inputResult.value;
234
248
  const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : process.cwd();
249
+ const workflowCwd = getWorkflowCwd();
235
250
  const command = String(input?.tool_input?.command || '').trim();
236
251
 
237
252
  function tokenizeShellCommand(value) {
@@ -873,7 +888,7 @@ if (hasUnsupportedGitTarget || hasGitTargetEnvOverride) {
873
888
  process.exit(0);
874
889
  }
875
890
 
876
- const detectedResult = runLeeSpecKitJson(['detect', '--json'], cwd);
891
+ const detectedResult = runLeeSpecKitJson(['detect', '--json'], workflowCwd);
877
892
  if (!detectedResult.ok) {
878
893
  printBlock('lee-spec-kit detection failed inside the Codex hook. Fix the local CLI or hook setup before continuing.');
879
894
  process.exit(0);
@@ -921,7 +936,7 @@ if (stageBoundAction || isPotentialMergeCleanupCommand || hasUnsupportedShellWra
921
936
  const stageArgs = commandFeatureRef
922
937
  ? ['workflow-stage', commandFeatureRef, '--json']
923
938
  : ['workflow-stage', '--json'];
924
- const stageResult = runLeeSpecKitJson(stageArgs, cwd);
939
+ const stageResult = runLeeSpecKitJson(stageArgs, workflowCwd);
925
940
  if (!stageResult.ok) {
926
941
  printBlock('lee-spec-kit workflow-stage failed inside the Codex hook. Resolve the workflow stage before running this stage-bound command.');
927
942
  process.exit(0);
@@ -972,7 +987,7 @@ if (isGitCommit) {
972
987
  if (commitMessage) {
973
988
  commitAuditArgs.push('--message', commitMessage);
974
989
  }
975
- const commitAuditResult = runLeeSpecKitJson(commitAuditArgs, cwd);
990
+ const commitAuditResult = runLeeSpecKitJson(commitAuditArgs, workflowCwd);
976
991
  if (!commitAuditResult.ok) {
977
992
  printBlock('lee-spec-kit commit-audit failed inside the Codex hook. Resolve the docs guardrail failure before committing.');
978
993
  process.exit(0);
@@ -992,7 +1007,7 @@ if (isGitCommit) {
992
1007
  }
993
1008
  }
994
1009
 
995
- const auditResult = runLeeSpecKitJson(['workflow-audit', '--json'], cwd);
1010
+ const auditResult = runLeeSpecKitJson(['workflow-audit', '--json'], workflowCwd);
996
1011
  if (!auditResult.ok) {
997
1012
  printBlock('lee-spec-kit workflow-audit failed inside the Codex hook. Resolve the docs sync guardrail failure before continuing.');
998
1013
  process.exit(0);
@@ -1008,7 +1023,7 @@ if (!(audit?.status === 'ok' || audit?.status === 'skipped')) {
1008
1023
  `;
1009
1024
  case "stop_workflow_audit.mjs":
1010
1025
  return `#!/usr/bin/env node
1011
- import { printBlock, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
1026
+ import { getWorkflowCwd, printBlock, readHookInput, runLeeSpecKitJson } from './_lee_spec_kit_hook_utils.mjs';
1012
1027
 
1013
1028
  // Equivalent CLI probe: npx lee-spec-kit workflow-audit --json
1014
1029
  const inputResult = readHookInput();
@@ -1022,7 +1037,7 @@ if (input?.stop_hook_active === true) {
1022
1037
  process.exit(0);
1023
1038
  }
1024
1039
 
1025
- const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : process.cwd();
1040
+ const cwd = getWorkflowCwd();
1026
1041
  const detectedResult = runLeeSpecKitJson(['detect', '--json'], cwd);
1027
1042
  if (!detectedResult.ok) {
1028
1043
  printBlock('lee-spec-kit detection failed inside the stop hook. Resolve the local CLI or hook setup before stopping.');
@@ -1065,7 +1080,9 @@ function escapeRegExp(value) {
1065
1080
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1066
1081
  }
1067
1082
  function getPortableHookCommandSuffix(fileName) {
1068
- const relativeHookPath = normalizePathSlashes(getManagedHookRelativePath(fileName));
1083
+ const relativeHookPath = normalizePathSlashes(
1084
+ getManagedHookRelativePath(fileName)
1085
+ );
1069
1086
  const loaderSource = [
1070
1087
  "(async () => {",
1071
1088
  " const fs = require('node:fs');",
@@ -1095,7 +1112,9 @@ function getPortableHookCommandSuffix(fileName) {
1095
1112
  function isManagedCommand(command) {
1096
1113
  const normalized = normalizePathSlashes(command).trim();
1097
1114
  return MANAGED_HOOK_FILENAMES.some((fileName) => {
1098
- const currentCommand = normalizePathSlashes(toPortableHookCommand(fileName)).trim();
1115
+ const currentCommand = normalizePathSlashes(
1116
+ toPortableHookCommand(fileName)
1117
+ ).trim();
1099
1118
  const portableSuffix = normalizePathSlashes(
1100
1119
  getPortableHookCommandSuffix(fileName)
1101
1120
  ).trim();
@@ -1118,7 +1137,7 @@ function getManagedHooksConfig() {
1118
1137
  return {
1119
1138
  SessionStart: [
1120
1139
  {
1121
- matcher: "startup|resume",
1140
+ matcher: "startup|resume|clear|compact",
1122
1141
  hooks: [
1123
1142
  {
1124
1143
  type: "command",
@@ -1203,7 +1222,12 @@ function removeManagedGroups(current) {
1203
1222
  const nextHooks = {
1204
1223
  ...current.hooks && typeof current.hooks === "object" ? current.hooks : {}
1205
1224
  };
1206
- for (const eventName of ["SessionStart", "UserPromptSubmit", "PreToolUse", "Stop"]) {
1225
+ for (const eventName of [
1226
+ "SessionStart",
1227
+ "UserPromptSubmit",
1228
+ "PreToolUse",
1229
+ "Stop"
1230
+ ]) {
1207
1231
  const pruned = pruneManagedGroups(
1208
1232
  Array.isArray(nextHooks[eventName]) ? nextHooks[eventName] : void 0
1209
1233
  );
@@ -1230,16 +1254,20 @@ function getRepoHooksDir(repoRoot = process.cwd()) {
1230
1254
  function getRepoHooksConfigPath(repoRoot = process.cwd()) {
1231
1255
  return path.join(getRepoCodexDir(repoRoot), "hooks.json");
1232
1256
  }
1233
- async function upsertLeeSpecKitCodexHooks(repoRoot = process.cwd()) {
1257
+ async function upsertLeeSpecKitCodexHooks(repoRoot = process.cwd(), workflowRoot = repoRoot) {
1234
1258
  const hooksDir = getRepoHooksDir(repoRoot);
1235
1259
  const hooksJsonPath = getRepoHooksConfigPath(repoRoot);
1236
1260
  await fs.ensureDir(hooksDir);
1237
1261
  for (const fileName of MANAGED_HOOK_FILENAMES) {
1238
1262
  const targetPath = path.join(hooksDir, fileName);
1239
- await fs.writeFile(targetPath, getHookScriptContent(fileName), {
1240
- encoding: "utf-8",
1241
- mode: 493
1242
- });
1263
+ await fs.writeFile(
1264
+ targetPath,
1265
+ getHookScriptContent(fileName, repoRoot, workflowRoot),
1266
+ {
1267
+ encoding: "utf-8",
1268
+ mode: 493
1269
+ }
1270
+ );
1243
1271
  }
1244
1272
  const managedHooks = getManagedHooksConfig();
1245
1273
  const exists = await fs.pathExists(hooksJsonPath);
@@ -1286,5 +1314,5 @@ async function removeLeeSpecKitCodexHooks(repoRoot = process.cwd()) {
1286
1314
  }
1287
1315
 
1288
1316
  export { getRepoCodexDir, getRepoHooksConfigPath, getRepoHooksDir, removeLeeSpecKitCodexHooks, resolveCodexHooksRepoRoot, upsertLeeSpecKitCodexHooks };
1289
- //# sourceMappingURL=hooks-UUAAVDS3.js.map
1290
- //# sourceMappingURL=hooks-UUAAVDS3.js.map
1317
+ //# sourceMappingURL=hooks-373Z6JG2.js.map
1318
+ //# sourceMappingURL=hooks-373Z6JG2.js.map