agent-switchboard 0.4.12 → 0.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/paths.d.ts +5 -7
- package/dist/config/paths.js +15 -29
- package/dist/config/paths.js.map +1 -1
- package/dist/config/schemas.d.ts +90 -0
- package/dist/config/schemas.js +1 -0
- package/dist/config/schemas.js.map +1 -1
- package/dist/hooks/codex-distribute.d.ts +26 -0
- package/dist/hooks/codex-distribute.js +370 -0
- package/dist/hooks/codex-distribute.js.map +1 -0
- package/dist/hooks/distribution.d.ts +3 -3
- package/dist/hooks/distribution.js +94 -25
- package/dist/hooks/distribution.js.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/library/sources.js +158 -33
- package/dist/library/sources.js.map +1 -1
- package/dist/marketplace/reader.js +2 -2
- package/dist/marketplace/reader.js.map +1 -1
- package/dist/mcp/distribution.js +11 -2
- package/dist/mcp/distribution.js.map +1 -1
- package/dist/targets/builtin/claude-code.js +1 -1
- package/dist/targets/builtin/claude-code.js.map +1 -1
- package/dist/targets/builtin/codex.js +3 -0
- package/dist/targets/builtin/codex.js.map +1 -1
- package/dist/targets/types.d.ts +30 -10
- package/dist/targets/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex hook distribution: writes hooks.json and copies bundle files.
|
|
3
|
+
*
|
|
4
|
+
* Codex reads hooks from ~/.codex/hooks.json (global) and
|
|
5
|
+
* <project>/.codex/hooks.json (project scope). Unlike Claude Code which
|
|
6
|
+
* embeds hooks inside settings.json, Codex uses a dedicated file.
|
|
7
|
+
*
|
|
8
|
+
* Codex only supports: command handlers, 5 event types, no ${HOOK_DIR}
|
|
9
|
+
* runtime expansion. ASB must filter unsupported entries and rewrite
|
|
10
|
+
* bundle paths to absolute paths before writing.
|
|
11
|
+
*/
|
|
12
|
+
import type { ConfigScope } from '../config/scope.js';
|
|
13
|
+
import type { DistributionResult } from '../library/distribute.js';
|
|
14
|
+
import type { BundleDistributionResult } from '../library/distribute-bundle.js';
|
|
15
|
+
import type { HookEntry } from './library.js';
|
|
16
|
+
type CodexPlatform = 'codex';
|
|
17
|
+
export interface CodexHookDistributeOptions {
|
|
18
|
+
scope?: ConfigScope;
|
|
19
|
+
selected: readonly HookEntry[];
|
|
20
|
+
dryRun?: boolean;
|
|
21
|
+
projectMode?: 'managed' | 'exclusive' | 'none';
|
|
22
|
+
}
|
|
23
|
+
export declare function distributeCodexHooks(options: CodexHookDistributeOptions): {
|
|
24
|
+
results: Array<DistributionResult<CodexPlatform> | BundleDistributionResult<CodexPlatform>>;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex hook distribution: writes hooks.json and copies bundle files.
|
|
3
|
+
*
|
|
4
|
+
* Codex reads hooks from ~/.codex/hooks.json (global) and
|
|
5
|
+
* <project>/.codex/hooks.json (project scope). Unlike Claude Code which
|
|
6
|
+
* embeds hooks inside settings.json, Codex uses a dedicated file.
|
|
7
|
+
*
|
|
8
|
+
* Codex only supports: command handlers, 5 event types, no ${HOOK_DIR}
|
|
9
|
+
* runtime expansion. ASB must filter unsupported entries and rewrite
|
|
10
|
+
* bundle paths to absolute paths before writing.
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { ensureTrustEntry } from '../agents/codex.js';
|
|
16
|
+
import { getCodexConfigPath, getCodexDir, getCodexHooksJsonPath, getProjectCodexDir, getProjectCodexHooksJsonPath, } from '../config/paths.js';
|
|
17
|
+
import { distributeBundle } from '../library/distribute-bundle.js';
|
|
18
|
+
import { ensureParentDir, rmDirRecursive } from '../library/fs.js';
|
|
19
|
+
import { listHookBundleFiles } from './library.js';
|
|
20
|
+
import { HOOK_DIR_PLACEHOLDER } from './schema.js';
|
|
21
|
+
const CODEX_SUPPORTED_EVENTS = new Set([
|
|
22
|
+
'PreToolUse',
|
|
23
|
+
'PostToolUse',
|
|
24
|
+
'SessionStart',
|
|
25
|
+
'UserPromptSubmit',
|
|
26
|
+
'Stop',
|
|
27
|
+
]);
|
|
28
|
+
const CODEX_SUPPORTED_HANDLER_TYPES = new Set(['command']);
|
|
29
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: intentional literal placeholder
|
|
30
|
+
const CLAUDE_PLUGIN_ROOT_HOOKS_PREFIX = '${CLAUDE_PLUGIN_ROOT}/hooks';
|
|
31
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: intentional literal placeholder
|
|
32
|
+
const CLAUDE_PLUGIN_ROOT_HOOKS_PREFIX_WINDOWS = '${CLAUDE_PLUGIN_ROOT}\\hooks';
|
|
33
|
+
const ASB_MANAGED_KEY = '_asb_managed_hooks';
|
|
34
|
+
const ASB_HOOKS_SUBDIR = 'asb';
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Path helpers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
function resolveHooksJsonPath(scope) {
|
|
39
|
+
const projectRoot = scope?.project?.trim();
|
|
40
|
+
if (projectRoot && projectRoot.length > 0) {
|
|
41
|
+
return getProjectCodexHooksJsonPath(projectRoot);
|
|
42
|
+
}
|
|
43
|
+
return getCodexHooksJsonPath();
|
|
44
|
+
}
|
|
45
|
+
function resolveHooksBundleParentDir(scope) {
|
|
46
|
+
const projectRoot = scope?.project?.trim();
|
|
47
|
+
if (projectRoot && projectRoot.length > 0) {
|
|
48
|
+
return path.join(getProjectCodexDir(projectRoot), 'hooks', ASB_HOOKS_SUBDIR);
|
|
49
|
+
}
|
|
50
|
+
return path.join(getCodexDir(), 'hooks', ASB_HOOKS_SUBDIR);
|
|
51
|
+
}
|
|
52
|
+
function resolveHookBundleTargetDir(entry, scope) {
|
|
53
|
+
return path.join(resolveHooksBundleParentDir(scope), entry.id);
|
|
54
|
+
}
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Portable path helpers
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
function preferHomeVar(command) {
|
|
59
|
+
const home = os.homedir();
|
|
60
|
+
if (!command.includes(home))
|
|
61
|
+
return command;
|
|
62
|
+
return command.replaceAll(home, '$HOME');
|
|
63
|
+
}
|
|
64
|
+
function filterForCodex(entries) {
|
|
65
|
+
const result = [];
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
const filteredHooks = {};
|
|
68
|
+
for (const [event, groups] of Object.entries(entry.hooks)) {
|
|
69
|
+
if (!CODEX_SUPPORTED_EVENTS.has(event))
|
|
70
|
+
continue;
|
|
71
|
+
const filteredGroups = [];
|
|
72
|
+
for (const group of groups) {
|
|
73
|
+
const filteredHandlers = (group.hooks ?? []).filter((h) => CODEX_SUPPORTED_HANDLER_TYPES.has(h.type ?? ''));
|
|
74
|
+
if (filteredHandlers.length > 0) {
|
|
75
|
+
filteredGroups.push({ ...group, hooks: filteredHandlers });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (filteredGroups.length > 0) {
|
|
79
|
+
filteredHooks[event] = filteredGroups;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (Object.keys(filteredHooks).length > 0) {
|
|
83
|
+
result.push({ entry, hooks: filteredHooks });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// hooks.json I/O
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
function readHooksJson(filePath) {
|
|
92
|
+
try {
|
|
93
|
+
if (fs.existsSync(filePath)) {
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
data: JSON.parse(fs.readFileSync(filePath, 'utf-8')),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
102
|
+
}
|
|
103
|
+
return { ok: true, data: {} };
|
|
104
|
+
}
|
|
105
|
+
function writeHooksJson(filePath, data) {
|
|
106
|
+
ensureParentDir(filePath);
|
|
107
|
+
fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf-8');
|
|
108
|
+
}
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Config merge
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
function rewriteHookDir(hooks, distributedDir) {
|
|
113
|
+
const result = {};
|
|
114
|
+
for (const [event, groups] of Object.entries(hooks)) {
|
|
115
|
+
result[event] = groups.map((group) => ({
|
|
116
|
+
...group,
|
|
117
|
+
hooks: (group.hooks ?? []).map((handler) => {
|
|
118
|
+
if (typeof handler.command !== 'string')
|
|
119
|
+
return handler;
|
|
120
|
+
return {
|
|
121
|
+
...handler,
|
|
122
|
+
command: preferHomeVar(handler.command
|
|
123
|
+
.replaceAll(HOOK_DIR_PLACEHOLDER, distributedDir)
|
|
124
|
+
.replaceAll(CLAUDE_PLUGIN_ROOT_HOOKS_PREFIX, distributedDir)
|
|
125
|
+
.replaceAll(CLAUDE_PLUGIN_ROOT_HOOKS_PREFIX_WINDOWS, distributedDir)),
|
|
126
|
+
};
|
|
127
|
+
}),
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
function mergeHooksIntoFile(fileData, filteredEntries, scope) {
|
|
133
|
+
const existingHooks = (fileData.hooks ?? {});
|
|
134
|
+
// Remove previously ASB-managed matcher groups
|
|
135
|
+
const cleanedHooks = {};
|
|
136
|
+
for (const [event, groups] of Object.entries(existingHooks)) {
|
|
137
|
+
const kept = groups.filter((g) => g._asb_source !== true);
|
|
138
|
+
if (kept.length > 0)
|
|
139
|
+
cleanedHooks[event] = kept;
|
|
140
|
+
}
|
|
141
|
+
// Merge filtered entries
|
|
142
|
+
for (const { entry, hooks } of filteredEntries) {
|
|
143
|
+
const resolvedHooks = entry.isBundle
|
|
144
|
+
? rewriteHookDir(hooks, resolveHookBundleTargetDir(entry, scope))
|
|
145
|
+
: hooks;
|
|
146
|
+
for (const [event, groups] of Object.entries(resolvedHooks)) {
|
|
147
|
+
if (!cleanedHooks[event])
|
|
148
|
+
cleanedHooks[event] = [];
|
|
149
|
+
for (const group of groups) {
|
|
150
|
+
cleanedHooks[event].push({ ...group, _asb_source: true });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
fileData.hooks = cleanedHooks;
|
|
155
|
+
fileData[ASB_MANAGED_KEY] = filteredEntries.map((f) => f.entry.id);
|
|
156
|
+
}
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
// Orphan cleanup for bundles
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
function cleanOrphanBundleDirs(activeIds, scope, dryRun) {
|
|
161
|
+
const parentDir = resolveHooksBundleParentDir(scope);
|
|
162
|
+
const results = [];
|
|
163
|
+
if (!fs.existsSync(parentDir))
|
|
164
|
+
return results;
|
|
165
|
+
try {
|
|
166
|
+
const entries = fs.readdirSync(parentDir, { withFileTypes: true });
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
if (!entry.isDirectory())
|
|
169
|
+
continue;
|
|
170
|
+
if (activeIds.has(entry.name))
|
|
171
|
+
continue;
|
|
172
|
+
const dirPath = path.join(parentDir, entry.name);
|
|
173
|
+
try {
|
|
174
|
+
if (!dryRun)
|
|
175
|
+
rmDirRecursive(dirPath);
|
|
176
|
+
results.push({
|
|
177
|
+
platform: 'codex',
|
|
178
|
+
targetDir: dirPath,
|
|
179
|
+
status: 'deleted',
|
|
180
|
+
reason: 'orphan',
|
|
181
|
+
entryId: entry.name,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
186
|
+
results.push({
|
|
187
|
+
platform: 'codex',
|
|
188
|
+
targetDir: dirPath,
|
|
189
|
+
status: 'error',
|
|
190
|
+
error: `Failed to delete orphan: ${msg}`,
|
|
191
|
+
entryId: entry.name,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Ignore directory read errors
|
|
198
|
+
}
|
|
199
|
+
return results;
|
|
200
|
+
}
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Codex prerequisites: feature flag + project trust
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
function ensureCodexHooksFeature(results) {
|
|
205
|
+
const configPath = getCodexConfigPath();
|
|
206
|
+
if (!fs.existsSync(configPath))
|
|
207
|
+
return;
|
|
208
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
209
|
+
if (content.includes('codex_hooks') && content.includes('true'))
|
|
210
|
+
return;
|
|
211
|
+
// Feature not explicitly enabled - add warning result
|
|
212
|
+
results.push({
|
|
213
|
+
platform: 'codex',
|
|
214
|
+
filePath: configPath,
|
|
215
|
+
status: 'written',
|
|
216
|
+
reason: 'codex_hooks feature flag may not be enabled in config.toml',
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function ensureProjectTrust(projectRoot, results) {
|
|
220
|
+
const globalPath = getCodexConfigPath();
|
|
221
|
+
const globalContent = fs.existsSync(globalPath) ? fs.readFileSync(globalPath, 'utf-8') : '';
|
|
222
|
+
const trustResult = ensureTrustEntry(globalContent, projectRoot);
|
|
223
|
+
if (trustResult.warning) {
|
|
224
|
+
results.push({
|
|
225
|
+
platform: 'codex',
|
|
226
|
+
filePath: globalPath,
|
|
227
|
+
status: 'skipped',
|
|
228
|
+
reason: trustResult.warning,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (trustResult.changed) {
|
|
232
|
+
ensureParentDir(globalPath);
|
|
233
|
+
fs.writeFileSync(globalPath, trustResult.content, 'utf-8');
|
|
234
|
+
results.push({
|
|
235
|
+
platform: 'codex',
|
|
236
|
+
filePath: globalPath,
|
|
237
|
+
status: 'written',
|
|
238
|
+
reason: 'added project trust entry',
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
export function distributeCodexHooks(options) {
|
|
243
|
+
const { scope, selected, dryRun = false, projectMode } = options;
|
|
244
|
+
if (scope?.project && projectMode === 'none') {
|
|
245
|
+
return { results: [] };
|
|
246
|
+
}
|
|
247
|
+
const results = [];
|
|
248
|
+
// Ensure Codex hooks feature flag is enabled
|
|
249
|
+
if (!dryRun) {
|
|
250
|
+
ensureCodexHooksFeature(results);
|
|
251
|
+
}
|
|
252
|
+
// Ensure project trust for project-scoped distribution
|
|
253
|
+
if (!dryRun && scope?.project) {
|
|
254
|
+
ensureProjectTrust(scope.project, results);
|
|
255
|
+
}
|
|
256
|
+
// Filter entries for Codex compatibility
|
|
257
|
+
const filteredEntries = filterForCodex(selected);
|
|
258
|
+
// Pre-validate hooks.json before making any filesystem changes
|
|
259
|
+
const hooksJsonPath = resolveHooksJsonPath(scope);
|
|
260
|
+
const fileResult = readHooksJson(hooksJsonPath);
|
|
261
|
+
if (!fileResult.ok) {
|
|
262
|
+
results.push({
|
|
263
|
+
platform: 'codex',
|
|
264
|
+
filePath: hooksJsonPath,
|
|
265
|
+
status: 'error',
|
|
266
|
+
error: `Cannot read hooks.json, aborting merge: ${fileResult.error}`,
|
|
267
|
+
});
|
|
268
|
+
return { results };
|
|
269
|
+
}
|
|
270
|
+
const fileData = fileResult.data;
|
|
271
|
+
// Validate hooks field shape: must be a Record<string, array> or absent
|
|
272
|
+
if (fileData.hooks !== undefined) {
|
|
273
|
+
if (typeof fileData.hooks !== 'object' ||
|
|
274
|
+
fileData.hooks === null ||
|
|
275
|
+
Array.isArray(fileData.hooks)) {
|
|
276
|
+
results.push({
|
|
277
|
+
platform: 'codex',
|
|
278
|
+
filePath: hooksJsonPath,
|
|
279
|
+
status: 'error',
|
|
280
|
+
error: 'hooks.json has invalid shape: "hooks" must be an object',
|
|
281
|
+
});
|
|
282
|
+
return { results };
|
|
283
|
+
}
|
|
284
|
+
for (const [event, groups] of Object.entries(fileData.hooks)) {
|
|
285
|
+
if (!Array.isArray(groups)) {
|
|
286
|
+
results.push({
|
|
287
|
+
platform: 'codex',
|
|
288
|
+
filePath: hooksJsonPath,
|
|
289
|
+
status: 'error',
|
|
290
|
+
error: `hooks.json has invalid shape: "hooks.${event}" must be an array`,
|
|
291
|
+
});
|
|
292
|
+
return { results };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Phase 1: Copy bundle files (only after validation passes)
|
|
297
|
+
const bundleEntries = filteredEntries.filter((f) => f.entry.isBundle).map((f) => f.entry);
|
|
298
|
+
if (bundleEntries.length > 0) {
|
|
299
|
+
const bundleOutcome = distributeBundle({
|
|
300
|
+
section: 'hooks',
|
|
301
|
+
selected: bundleEntries,
|
|
302
|
+
platforms: ['codex'],
|
|
303
|
+
resolveTargetDir: (_p, entry) => resolveHookBundleTargetDir(entry, scope),
|
|
304
|
+
listFiles: listHookBundleFiles,
|
|
305
|
+
getId: (entry) => entry.id,
|
|
306
|
+
scope,
|
|
307
|
+
dryRun,
|
|
308
|
+
});
|
|
309
|
+
results.push(...bundleOutcome.results);
|
|
310
|
+
}
|
|
311
|
+
// Clean up orphan bundle directories
|
|
312
|
+
const activeBundleIds = new Set(bundleEntries.map((e) => e.id));
|
|
313
|
+
results.push(...cleanOrphanBundleDirs(activeBundleIds, scope, dryRun));
|
|
314
|
+
// Phase 2: Merge hook configs into hooks.json
|
|
315
|
+
const previouslyManaged = (fileData[ASB_MANAGED_KEY] ?? []);
|
|
316
|
+
// Check for existing ASB groups
|
|
317
|
+
const existingHooks = (fileData.hooks ?? {});
|
|
318
|
+
const hasAsbGroups = Object.values(existingHooks).some((groups) => groups.some((g) => g._asb_source === true));
|
|
319
|
+
if (filteredEntries.length === 0 && previouslyManaged.length === 0 && !hasAsbGroups) {
|
|
320
|
+
return { results };
|
|
321
|
+
}
|
|
322
|
+
const before = JSON.stringify(fileData);
|
|
323
|
+
mergeHooksIntoFile(fileData, filteredEntries, scope);
|
|
324
|
+
// Clean up empty state: if no hooks remain, remove the file entirely
|
|
325
|
+
const mergedHooks = fileData.hooks;
|
|
326
|
+
const totalGroups = Object.values(mergedHooks).reduce((sum, groups) => sum + groups.length, 0);
|
|
327
|
+
const hasNoHooks = totalGroups === 0;
|
|
328
|
+
if (hasNoHooks && filteredEntries.length === 0) {
|
|
329
|
+
// Remove ASB tracking keys
|
|
330
|
+
delete fileData[ASB_MANAGED_KEY];
|
|
331
|
+
// If file has only hooks (now empty) and ASB keys, consider deleting
|
|
332
|
+
const remainingKeys = Object.keys(fileData).filter((k) => k !== 'hooks');
|
|
333
|
+
if (remainingKeys.length === 0 && fs.existsSync(hooksJsonPath) && !dryRun) {
|
|
334
|
+
fs.unlinkSync(hooksJsonPath);
|
|
335
|
+
results.push({
|
|
336
|
+
platform: 'codex',
|
|
337
|
+
filePath: hooksJsonPath,
|
|
338
|
+
status: 'deleted',
|
|
339
|
+
reason: 'no hooks remain',
|
|
340
|
+
});
|
|
341
|
+
return { results };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const after = JSON.stringify(fileData);
|
|
345
|
+
if (before === after) {
|
|
346
|
+
results.push({
|
|
347
|
+
platform: 'codex',
|
|
348
|
+
filePath: hooksJsonPath,
|
|
349
|
+
status: 'skipped',
|
|
350
|
+
reason: 'up-to-date',
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
else if (dryRun) {
|
|
354
|
+
const reason = filteredEntries.length === 0 ? 'hooks cleared' : `${filteredEntries.length} hook(s) merged`;
|
|
355
|
+
results.push({ platform: 'codex', filePath: hooksJsonPath, status: 'written', reason });
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
try {
|
|
359
|
+
writeHooksJson(hooksJsonPath, fileData);
|
|
360
|
+
const reason = filteredEntries.length === 0 ? 'hooks cleared' : `${filteredEntries.length} hook(s) merged`;
|
|
361
|
+
results.push({ platform: 'codex', filePath: hooksJsonPath, status: 'written', reason });
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
365
|
+
results.push({ platform: 'codex', filePath: hooksJsonPath, status: 'error', error: msg });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return { results };
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=codex-distribute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-distribute.js","sourceRoot":"","sources":["../../src/hooks/codex-distribute.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
import type { ConfigScope } from '../config/scope.js';
|
|
15
15
|
import type { DistributionResult } from '../library/distribute.js';
|
|
16
16
|
import type { BundleDistributionResult } from '../library/distribute-bundle.js';
|
|
17
|
-
export type HookPlatform = 'claude-code';
|
|
17
|
+
export type HookPlatform = 'claude-code' | 'codex';
|
|
18
18
|
export interface HookDistributionOutcome {
|
|
19
19
|
results: Array<DistributionResult<HookPlatform> | BundleDistributionResult<HookPlatform>>;
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
|
-
* Distribute hooks to Claude Code:
|
|
22
|
+
* Distribute hooks to active targets (Claude Code, Codex, etc.):
|
|
23
23
|
* 1. Copy bundle files for bundle-type hooks
|
|
24
|
-
* 2. Merge all active hook configs into
|
|
24
|
+
* 2. Merge all active hook configs into each target's config
|
|
25
25
|
* 3. Clean up orphan bundle directories
|
|
26
26
|
*/
|
|
27
27
|
export declare function distributeHooks(scope?: ConfigScope, activeAppIds?: string[], assumeInstalled?: ReadonlySet<string>, options?: {
|
|
@@ -19,6 +19,7 @@ import { distributeBundle } from '../library/distribute-bundle.js';
|
|
|
19
19
|
import { ensureParentDir, rmDirRecursive } from '../library/fs.js';
|
|
20
20
|
import { loadLibraryStateSectionForApplication } from '../library/state.js';
|
|
21
21
|
import { getTargetById } from '../targets/registry.js';
|
|
22
|
+
import { distributeCodexHooks } from './codex-distribute.js';
|
|
22
23
|
import { listHookBundleFiles, loadHookLibrary } from './library.js';
|
|
23
24
|
import { HOOK_DIR_PLACEHOLDER } from './schema.js';
|
|
24
25
|
const ASB_MANAGED_KEY = '_asb_managed_hooks';
|
|
@@ -191,10 +192,20 @@ function cleanOrphanBundleDirs(activeIds, scope, dryRun) {
|
|
|
191
192
|
// ---------------------------------------------------------------------------
|
|
192
193
|
// Main distribution entry point
|
|
193
194
|
// ---------------------------------------------------------------------------
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Target reachability check
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
function isTargetReachable(platformId, _activeAppIds, assumeInstalled) {
|
|
199
|
+
const target = getTargetById(platformId);
|
|
200
|
+
if (target?.isInstalled?.() === false && !assumeInstalled?.has(platformId)) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
194
205
|
/**
|
|
195
|
-
* Distribute hooks to Claude Code:
|
|
206
|
+
* Distribute hooks to active targets (Claude Code, Codex, etc.):
|
|
196
207
|
* 1. Copy bundle files for bundle-type hooks
|
|
197
|
-
* 2. Merge all active hook configs into
|
|
208
|
+
* 2. Merge all active hook configs into each target's config
|
|
198
209
|
* 3. Clean up orphan bundle directories
|
|
199
210
|
*/
|
|
200
211
|
export function distributeHooks(scope, activeAppIds, assumeInstalled, options) {
|
|
@@ -202,49 +213,80 @@ export function distributeHooks(scope, activeAppIds, assumeInstalled, options) {
|
|
|
202
213
|
return { results: [] };
|
|
203
214
|
}
|
|
204
215
|
const results = [];
|
|
205
|
-
const
|
|
206
|
-
//
|
|
207
|
-
const
|
|
208
|
-
|
|
216
|
+
const dryRun = options?.dryRun === true;
|
|
217
|
+
// Check if any hook-capable target is reachable before loading library
|
|
218
|
+
const claudeReachable = isTargetReachable('claude-code', activeAppIds, assumeInstalled);
|
|
219
|
+
const codexReachable = isTargetReachable('codex', activeAppIds, assumeInstalled);
|
|
220
|
+
if (!claudeReachable && !codexReachable) {
|
|
209
221
|
return { results };
|
|
210
222
|
}
|
|
211
|
-
//
|
|
212
|
-
// use empty selection so that cleanup/unmerge of previously injected hooks can run.
|
|
213
|
-
const isActive = !activeAppIds || activeAppIds.includes(platform);
|
|
223
|
+
// Load all hook entries once (shared across targets)
|
|
214
224
|
const allEntries = loadHookLibrary(scope);
|
|
215
225
|
const byId = new Map(allEntries.map((e) => [e.id, e]));
|
|
216
|
-
|
|
226
|
+
// --- Claude Code distribution ---
|
|
227
|
+
const claudeResults = distributeClaude({
|
|
228
|
+
scope,
|
|
229
|
+
activeAppIds,
|
|
230
|
+
assumeInstalled,
|
|
231
|
+
allEntries,
|
|
232
|
+
byId,
|
|
233
|
+
dryRun,
|
|
234
|
+
projectMode: options?.projectMode,
|
|
235
|
+
});
|
|
236
|
+
results.push(...claudeResults);
|
|
237
|
+
// --- Codex distribution ---
|
|
238
|
+
const codexResults = distributeCodex({
|
|
239
|
+
scope,
|
|
240
|
+
activeAppIds,
|
|
241
|
+
assumeInstalled,
|
|
242
|
+
allEntries,
|
|
243
|
+
byId,
|
|
244
|
+
dryRun,
|
|
245
|
+
projectMode: options?.projectMode,
|
|
246
|
+
});
|
|
247
|
+
results.push(...codexResults);
|
|
248
|
+
return { results };
|
|
249
|
+
}
|
|
250
|
+
function distributeClaude(ctx) {
|
|
251
|
+
const platform = 'claude-code';
|
|
252
|
+
const results = [];
|
|
253
|
+
// Skip if claude-code is not installed (unless assumed installed)
|
|
254
|
+
const target = getTargetById(platform);
|
|
255
|
+
if (target?.isInstalled?.() === false && !ctx.assumeInstalled?.has(platform)) {
|
|
256
|
+
return results;
|
|
257
|
+
}
|
|
258
|
+
// When activeAppIds is set and doesn't include claude-code, treat as inactive
|
|
259
|
+
const isActive = !ctx.activeAppIds || ctx.activeAppIds.includes(platform);
|
|
260
|
+
const state = loadLibraryStateSectionForApplication('hooks', 'claude-code', ctx.scope);
|
|
217
261
|
const selected = [];
|
|
218
262
|
if (isActive) {
|
|
219
263
|
for (const id of state.enabled) {
|
|
220
|
-
const e = byId.get(id);
|
|
264
|
+
const e = ctx.byId.get(id);
|
|
221
265
|
if (e)
|
|
222
266
|
selected.push(e);
|
|
223
267
|
}
|
|
224
268
|
}
|
|
225
269
|
// Phase 1: Copy bundle files for bundle-type hooks
|
|
226
|
-
const dryRun = options?.dryRun === true;
|
|
227
270
|
const bundleEntries = selected.filter((e) => e.isBundle);
|
|
228
271
|
if (bundleEntries.length > 0) {
|
|
229
272
|
const bundleOutcome = distributeBundle({
|
|
230
273
|
section: 'hooks',
|
|
231
274
|
selected: bundleEntries,
|
|
232
275
|
platforms: [platform],
|
|
233
|
-
resolveTargetDir: (_p, entry) => resolveHookBundleTargetDir(_p, entry, scope),
|
|
276
|
+
resolveTargetDir: (_p, entry) => resolveHookBundleTargetDir(_p, entry, ctx.scope),
|
|
234
277
|
listFiles: listHookBundleFiles,
|
|
235
278
|
getId: (entry) => entry.id,
|
|
236
|
-
scope,
|
|
237
|
-
dryRun,
|
|
279
|
+
scope: ctx.scope,
|
|
280
|
+
dryRun: ctx.dryRun,
|
|
238
281
|
});
|
|
239
282
|
results.push(...bundleOutcome.results);
|
|
240
283
|
}
|
|
241
284
|
// Clean up orphan bundle directories
|
|
242
285
|
const activeBundleIds = new Set(bundleEntries.map((e) => e.id));
|
|
243
|
-
results.push(...cleanOrphanBundleDirs(activeBundleIds, scope, dryRun));
|
|
286
|
+
results.push(...cleanOrphanBundleDirs(activeBundleIds, ctx.scope, ctx.dryRun));
|
|
244
287
|
// Phase 2: Merge hook configs into settings.json
|
|
245
|
-
const settingsPath = resolveSettingsPath(scope);
|
|
288
|
+
const settingsPath = resolveSettingsPath(ctx.scope);
|
|
246
289
|
const settingsResult = readSettingsJson(settingsPath);
|
|
247
|
-
// Abort hooks config merge if settings file is unreadable (prevents data loss)
|
|
248
290
|
if (!settingsResult.ok) {
|
|
249
291
|
results.push({
|
|
250
292
|
platform,
|
|
@@ -252,23 +294,22 @@ export function distributeHooks(scope, activeAppIds, assumeInstalled, options) {
|
|
|
252
294
|
status: 'error',
|
|
253
295
|
error: `Cannot read settings.json, aborting hooks merge: ${settingsResult.error}`,
|
|
254
296
|
});
|
|
255
|
-
return
|
|
297
|
+
return results;
|
|
256
298
|
}
|
|
257
299
|
const settings = settingsResult.data;
|
|
258
300
|
const previouslyManaged = (settings[ASB_MANAGED_KEY] ?? []);
|
|
259
|
-
// Also check for legacy ASB hooks (missing _asb_source marker)
|
|
260
301
|
const existingHooks = (settings.hooks ?? {});
|
|
261
|
-
const hasLegacyAsb = Object.values(existingHooks).some((groups) => groups.some((g) => isLegacyAsbGroup(g, scope)));
|
|
302
|
+
const hasLegacyAsb = Object.values(existingHooks).some((groups) => groups.some((g) => isLegacyAsbGroup(g, ctx.scope)));
|
|
262
303
|
if (selected.length === 0 && previouslyManaged.length === 0 && !hasLegacyAsb) {
|
|
263
|
-
return
|
|
304
|
+
return results;
|
|
264
305
|
}
|
|
265
306
|
const before = JSON.stringify(settings);
|
|
266
|
-
mergeHooksIntoSettings(settings, selected, scope);
|
|
307
|
+
mergeHooksIntoSettings(settings, selected, ctx.scope);
|
|
267
308
|
const after = JSON.stringify(settings);
|
|
268
309
|
if (before === after) {
|
|
269
310
|
results.push({ platform, filePath: settingsPath, status: 'skipped', reason: 'up-to-date' });
|
|
270
311
|
}
|
|
271
|
-
else if (dryRun) {
|
|
312
|
+
else if (ctx.dryRun) {
|
|
272
313
|
const reason = selected.length === 0 ? 'hooks cleared' : `${selected.length} hook(s) merged`;
|
|
273
314
|
results.push({ platform, filePath: settingsPath, status: 'written', reason });
|
|
274
315
|
}
|
|
@@ -283,6 +324,34 @@ export function distributeHooks(scope, activeAppIds, assumeInstalled, options) {
|
|
|
283
324
|
results.push({ platform, filePath: settingsPath, status: 'error', error: msg });
|
|
284
325
|
}
|
|
285
326
|
}
|
|
286
|
-
return
|
|
327
|
+
return results;
|
|
328
|
+
}
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
// Codex distribution (delegates to codex-distribute module)
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
function distributeCodex(ctx) {
|
|
333
|
+
const platform = 'codex';
|
|
334
|
+
// Skip if codex is not installed (unless assumed installed)
|
|
335
|
+
const target = getTargetById(platform);
|
|
336
|
+
if (target?.isInstalled?.() === false && !ctx.assumeInstalled?.has(platform)) {
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
const isActive = !ctx.activeAppIds || ctx.activeAppIds.includes(platform);
|
|
340
|
+
const state = loadLibraryStateSectionForApplication('hooks', 'codex', ctx.scope);
|
|
341
|
+
const selected = [];
|
|
342
|
+
if (isActive) {
|
|
343
|
+
for (const id of state.enabled) {
|
|
344
|
+
const e = ctx.byId.get(id);
|
|
345
|
+
if (e)
|
|
346
|
+
selected.push(e);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const outcome = distributeCodexHooks({
|
|
350
|
+
scope: ctx.scope,
|
|
351
|
+
selected,
|
|
352
|
+
dryRun: ctx.dryRun,
|
|
353
|
+
projectMode: ctx.projectMode,
|
|
354
|
+
});
|
|
355
|
+
return outcome.results;
|
|
287
356
|
}
|
|
288
357
|
//# sourceMappingURL=distribution.js.map
|