ccc-notifier 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -122
- package/dist/{budget-EHWPEYXY.js → budget-V7CCMJHF.js} +1 -1
- package/dist/{chunk-J6Y3RMMC.js → chunk-27SJELD2.js} +107 -22
- package/dist/{chunk-2VPBBIDW.js → chunk-4JSRGJCZ.js} +61 -22
- package/dist/chunk-6HTETN26.js +226 -0
- package/dist/{chunk-5LHZOZZO.js → chunk-CH34OJ7Q.js} +241 -110
- package/dist/chunk-D4D76RGQ.js +547 -0
- package/dist/chunk-HLJAJS2W.js +55 -0
- package/dist/chunk-OOAC5ULQ.js +1101 -0
- package/dist/chunk-OYD6H3ZZ.js +124 -0
- package/dist/{chunk-TUZVISLD.js → chunk-T6Z2ZAN4.js} +1 -1
- package/dist/cli.js +388 -77
- package/dist/{dashboard-GYKABTTN.js → dashboard-NORNHUPT.js} +3 -4
- package/dist/{history-6OUJLXJT.js → history-DL4SG3PG.js} +3 -5
- package/dist/{mute-GBDNN5PB.js → mute-UIR5P5N5.js} +2 -2
- package/dist/{setup-W3CSTHJC.js → setup-3SRNQ5PG.js} +4 -3
- package/dist/subagent-store-US4TJJQR.js +31 -0
- package/dist/sweep-RUPPGAWJ.js +795 -0
- package/dist/{track-QT2U3E2R.js → track-H4AIT575.js} +53 -31
- package/package.json +1 -1
- package/dist/chunk-26CISNOE.js +0 -324
- package/dist/chunk-CKVK3UCA.js +0 -357
- package/dist/chunk-LHKBGA5K.js +0 -462
- package/dist/chunk-ZHIZZ6V5.js +0 -92
- package/dist/sweep-IBSV4LRD.js +0 -604
|
@@ -8,14 +8,19 @@ import {
|
|
|
8
8
|
detectCodex
|
|
9
9
|
} from "./chunk-HTYUYKFW.js";
|
|
10
10
|
import {
|
|
11
|
+
loadPriceTable
|
|
12
|
+
} from "./chunk-6HTETN26.js";
|
|
13
|
+
import {
|
|
14
|
+
configFilePath,
|
|
11
15
|
paths,
|
|
12
16
|
readConfig
|
|
13
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-OOAC5ULQ.js";
|
|
14
18
|
|
|
15
19
|
// src/setup.ts
|
|
16
20
|
import {
|
|
17
21
|
copyFileSync as copyFileSync2,
|
|
18
22
|
existsSync as existsSync2,
|
|
23
|
+
lstatSync,
|
|
19
24
|
mkdirSync as mkdirSync2,
|
|
20
25
|
readFileSync as readFileSync2,
|
|
21
26
|
rmSync,
|
|
@@ -35,123 +40,201 @@ import {
|
|
|
35
40
|
writeFileSync
|
|
36
41
|
} from "fs";
|
|
37
42
|
import { dirname, join } from "path";
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
var CODEX_HOOK_EVENTS = ["Stop", "UserPromptSubmit", "SubagentStart", "SubagentStop"];
|
|
44
|
+
var CODEX_HOOK_TIMEOUT_SECONDS = 20;
|
|
45
|
+
function isPlainObject(value) {
|
|
46
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
47
|
}
|
|
41
48
|
function codexHooksFile() {
|
|
42
49
|
return join(codexHome(), "hooks.json");
|
|
43
50
|
}
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
function normalizeExecutablePath(value) {
|
|
52
|
+
return process.platform === "win32" ? value.replace(/\\/g, "/") : value;
|
|
53
|
+
}
|
|
54
|
+
function codexHookCommand(nodePath, cliPath, event = "Stop") {
|
|
55
|
+
const node = normalizeExecutablePath(nodePath);
|
|
56
|
+
const cli = normalizeExecutablePath(cliPath);
|
|
57
|
+
return `"${node}" "${cli}" __ccc-notifier-codex-hook ${event}`;
|
|
58
|
+
}
|
|
59
|
+
function tokenize(command) {
|
|
60
|
+
const result = [];
|
|
61
|
+
const re = /\s*(?:"([^"]*)"|'([^']*)'|(\S+))/gy;
|
|
62
|
+
let offset = 0;
|
|
63
|
+
while (offset < command.length) {
|
|
64
|
+
re.lastIndex = offset;
|
|
65
|
+
const match = re.exec(command);
|
|
66
|
+
if (!match) return null;
|
|
67
|
+
result.push(match[1] ?? match[2] ?? match[3]);
|
|
68
|
+
offset = re.lastIndex;
|
|
50
69
|
}
|
|
51
|
-
return
|
|
70
|
+
return result;
|
|
52
71
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
72
|
+
function parseLegacyOwnedCommand(command) {
|
|
73
|
+
const tokens = tokenize(command);
|
|
74
|
+
if (tokens === null || tokens.length !== 4 || !isCccNotifierExecutablePair(tokens[0], tokens[1]) || tokens[2] !== "track" || tokens[3] !== "--codex") return null;
|
|
75
|
+
return {
|
|
76
|
+
nodePath: normalizeExecutablePath(tokens[0]),
|
|
77
|
+
cliPath: normalizeExecutablePath(tokens[1]),
|
|
78
|
+
event: "Stop"
|
|
79
|
+
};
|
|
55
80
|
}
|
|
56
|
-
function
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
81
|
+
function isCccNotifierExecutablePair(nodePath, cliPath) {
|
|
82
|
+
const node = normalizeExecutablePath(nodePath);
|
|
83
|
+
const cli = normalizeExecutablePath(cliPath);
|
|
84
|
+
const nodeAbsolute = node.startsWith("/") || /^[a-z]:\//i.test(node);
|
|
85
|
+
const cliAbsolute = cli.startsWith("/") || /^[a-z]:\//i.test(cli);
|
|
86
|
+
return nodeAbsolute && cliAbsolute && /(^|\/)node(?:\.exe)?$/i.test(node) && /\/(?:ccc-notifier\/dist|ccc-notifier-dist)\/cli\.js$/i.test(cli);
|
|
87
|
+
}
|
|
88
|
+
function parseOwnedCodexHookCommand(command) {
|
|
89
|
+
if (typeof command !== "string") return null;
|
|
90
|
+
const tokens = tokenize(command);
|
|
91
|
+
if (tokens === null || tokens.length !== 4 || tokens[2] !== "__ccc-notifier-codex-hook") return null;
|
|
92
|
+
if (!CODEX_HOOK_EVENTS.includes(tokens[3])) return null;
|
|
93
|
+
if (!isCccNotifierExecutablePair(tokens[0], tokens[1])) return null;
|
|
94
|
+
return {
|
|
95
|
+
nodePath: normalizeExecutablePath(tokens[0]),
|
|
96
|
+
cliPath: normalizeExecutablePath(tokens[1]),
|
|
97
|
+
event: tokens[3]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function parseConfiguredOwnedCodexHookCommand(command, event) {
|
|
101
|
+
const parsed = parseOwnedCodexHookCommand(command) ?? (typeof command === "string" ? parseLegacyOwnedCommand(command) : null);
|
|
102
|
+
return parsed !== null && (event === void 0 || parsed.event === event) ? parsed : null;
|
|
103
|
+
}
|
|
104
|
+
function isOwnedHandler(value, event) {
|
|
105
|
+
if (!isPlainObject(value) || value.type !== "command") return false;
|
|
106
|
+
return parseConfiguredOwnedCodexHookCommand(value.command, event) !== null;
|
|
107
|
+
}
|
|
108
|
+
function canonicalHandler(command) {
|
|
109
|
+
return { type: "command", command, timeout: CODEX_HOOK_TIMEOUT_SECONDS };
|
|
63
110
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
111
|
+
function manualSnippet(nodePath, cliPath) {
|
|
112
|
+
const hooks = Object.fromEntries(
|
|
113
|
+
CODEX_HOOK_EVENTS.map((event) => [
|
|
114
|
+
event,
|
|
115
|
+
[{ hooks: [canonicalHandler(codexHookCommand(nodePath, cliPath, event))] }]
|
|
116
|
+
])
|
|
117
|
+
);
|
|
118
|
+
return JSON.stringify({ hooks }, null, 2);
|
|
66
119
|
}
|
|
67
|
-
function
|
|
120
|
+
function backup(path) {
|
|
68
121
|
const backupPath = `${path}.bak-${Date.now()}`;
|
|
69
122
|
copyFileSync(path, backupPath);
|
|
70
123
|
return backupPath;
|
|
71
124
|
}
|
|
72
|
-
function
|
|
73
|
-
writeFileSync(path, JSON.stringify(
|
|
125
|
+
function write(path, value) {
|
|
126
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
127
|
+
`, "utf8");
|
|
128
|
+
}
|
|
129
|
+
function validateShape(root) {
|
|
130
|
+
if (root.hooks !== void 0 && !isPlainObject(root.hooks)) return null;
|
|
131
|
+
const hooks = root.hooks ?? {};
|
|
132
|
+
for (const event of CODEX_HOOK_EVENTS) {
|
|
133
|
+
if (hooks[event] !== void 0 && !Array.isArray(hooks[event])) return null;
|
|
134
|
+
const groups = hooks[event] ?? [];
|
|
135
|
+
for (const group of groups) {
|
|
136
|
+
if (!isPlainObject(group) || !Array.isArray(group.hooks)) return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return hooks;
|
|
74
140
|
}
|
|
75
141
|
function registerCodexHook(nodePath, cliPath) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
142
|
+
const path = codexHooksFile();
|
|
143
|
+
if (!existsSync(path)) {
|
|
144
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
145
|
+
const hooks2 = {};
|
|
146
|
+
for (const event of CODEX_HOOK_EVENTS) {
|
|
147
|
+
hooks2[event] = [{ hooks: [canonicalHandler(codexHookCommand(nodePath, cliPath, event))] }];
|
|
148
|
+
}
|
|
149
|
+
write(path, { hooks: hooks2 });
|
|
81
150
|
return { status: "written", backupPath: null };
|
|
82
151
|
}
|
|
83
|
-
const raw = readFileSync(
|
|
152
|
+
const raw = readFileSync(path, "utf8");
|
|
84
153
|
let parsed;
|
|
85
154
|
try {
|
|
86
155
|
parsed = JSON.parse(raw);
|
|
87
156
|
} catch {
|
|
88
|
-
return { status: "manual", backupPath: null, manualSnippet:
|
|
157
|
+
return { status: "manual", backupPath: null, manualSnippet: manualSnippet(nodePath, cliPath) };
|
|
89
158
|
}
|
|
90
159
|
if (!isPlainObject(parsed)) {
|
|
91
|
-
return { status: "manual", backupPath: null, manualSnippet:
|
|
160
|
+
return { status: "manual", backupPath: null, manualSnippet: manualSnippet(nodePath, cliPath) };
|
|
92
161
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return { status: "manual", backupPath: null, manualSnippet: buildManualSnippet(command) };
|
|
97
|
-
}
|
|
98
|
-
const hooks = hooksVal ?? {};
|
|
99
|
-
const stopVal = hooks.Stop;
|
|
100
|
-
if (stopVal !== void 0 && !Array.isArray(stopVal)) {
|
|
101
|
-
return { status: "manual", backupPath: null, manualSnippet: buildManualSnippet(command) };
|
|
162
|
+
const hooks = validateShape(parsed);
|
|
163
|
+
if (hooks === null) {
|
|
164
|
+
return { status: "manual", backupPath: null, manualSnippet: manualSnippet(nodePath, cliPath) };
|
|
102
165
|
}
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
166
|
+
let changed = false;
|
|
167
|
+
for (const event of CODEX_HOOK_EVENTS) {
|
|
168
|
+
const groups = hooks[event] ?? [];
|
|
169
|
+
const wanted = canonicalHandler(codexHookCommand(nodePath, cliPath, event));
|
|
170
|
+
let found = false;
|
|
171
|
+
const groupsToRemove = /* @__PURE__ */ new Set();
|
|
172
|
+
for (const group of groups) {
|
|
173
|
+
const handlers = group.hooks;
|
|
174
|
+
for (let i = 0; i < handlers.length; i++) {
|
|
175
|
+
if (!isOwnedHandler(handlers[i], event)) continue;
|
|
176
|
+
if (!found) {
|
|
177
|
+
found = true;
|
|
178
|
+
const current = handlers[i];
|
|
179
|
+
const needsUpdate = !isPlainObject(current) || current.type !== wanted.type || current.command !== wanted.command || current.timeout !== wanted.timeout;
|
|
180
|
+
if (needsUpdate) {
|
|
181
|
+
handlers[i] = isPlainObject(current) ? { ...current, ...wanted } : wanted;
|
|
182
|
+
changed = true;
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
handlers.splice(i--, 1);
|
|
186
|
+
changed = true;
|
|
187
|
+
if (handlers.length === 0) groupsToRemove.add(group);
|
|
188
|
+
}
|
|
116
189
|
}
|
|
117
190
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
191
|
+
if (!found) {
|
|
192
|
+
groups.push({ hooks: [wanted] });
|
|
193
|
+
changed = true;
|
|
194
|
+
}
|
|
195
|
+
const retainedGroups = groups.filter((group) => !groupsToRemove.has(group));
|
|
196
|
+
if (retainedGroups.length !== groups.length) changed = true;
|
|
197
|
+
hooks[event] = retainedGroups;
|
|
122
198
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
writeHooks(hooksFile, obj);
|
|
199
|
+
if (!changed) return { status: "unchanged", backupPath: null };
|
|
200
|
+
const backupPath = backup(path);
|
|
201
|
+
parsed.hooks = hooks;
|
|
202
|
+
write(path, parsed);
|
|
128
203
|
return { status: "written", backupPath };
|
|
129
204
|
}
|
|
130
205
|
function removeCodexHook() {
|
|
131
|
-
const
|
|
132
|
-
if (!existsSync(
|
|
133
|
-
const raw = readFileSync(hooksFile, "utf8");
|
|
206
|
+
const path = codexHooksFile();
|
|
207
|
+
if (!existsSync(path)) return { status: "unchanged", backupPath: null };
|
|
134
208
|
let parsed;
|
|
135
209
|
try {
|
|
136
|
-
parsed = JSON.parse(
|
|
210
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
137
211
|
} catch {
|
|
138
212
|
return { status: "unchanged", backupPath: null };
|
|
139
213
|
}
|
|
140
214
|
if (!isPlainObject(parsed)) return { status: "unchanged", backupPath: null };
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
215
|
+
const hooks = validateShape(parsed);
|
|
216
|
+
if (hooks === null) return { status: "unchanged", backupPath: null };
|
|
217
|
+
let changed = false;
|
|
218
|
+
for (const event of CODEX_HOOK_EVENTS) {
|
|
219
|
+
const original = hooks[event] ?? [];
|
|
220
|
+
const groups = [];
|
|
221
|
+
for (const group of original) {
|
|
222
|
+
const handlers = group.hooks;
|
|
223
|
+
const filtered = handlers.filter((handler) => !isOwnedHandler(handler, event));
|
|
224
|
+
const removedOwned = filtered.length !== handlers.length;
|
|
225
|
+
if (removedOwned) changed = true;
|
|
226
|
+
if (!removedOwned) groups.push(group);
|
|
227
|
+
else if (filtered.length > 0) groups.push({ ...group, hooks: filtered });
|
|
228
|
+
}
|
|
229
|
+
if (groups.length === 0) {
|
|
230
|
+
if (event in hooks) delete hooks[event];
|
|
231
|
+
} else {
|
|
232
|
+
hooks[event] = groups;
|
|
233
|
+
}
|
|
153
234
|
}
|
|
154
|
-
|
|
235
|
+
if (!changed) return { status: "unchanged", backupPath: null };
|
|
236
|
+
const backupPath = backup(path);
|
|
237
|
+
write(path, parsed);
|
|
155
238
|
return { status: "written", backupPath };
|
|
156
239
|
}
|
|
157
240
|
|
|
@@ -186,7 +269,7 @@ function buildHookCommand() {
|
|
|
186
269
|
function matchesMarker(command) {
|
|
187
270
|
return command.includes(HOOK_MARKER);
|
|
188
271
|
}
|
|
189
|
-
function
|
|
272
|
+
function isOurStopEntry(entry) {
|
|
190
273
|
if (!isPlainObject2(entry)) return false;
|
|
191
274
|
const hooks = entry.hooks;
|
|
192
275
|
if (!Array.isArray(hooks)) return false;
|
|
@@ -223,8 +306,8 @@ function makeTestRecord() {
|
|
|
223
306
|
sidechainTokens: null,
|
|
224
307
|
apiCalls: 1,
|
|
225
308
|
costUSD: 0.01,
|
|
226
|
-
costJPY: 1.
|
|
227
|
-
fxRate:
|
|
309
|
+
costJPY: 1.6,
|
|
310
|
+
fxRate: 160,
|
|
228
311
|
fxSource: "fixed",
|
|
229
312
|
prompt: "\u30BB\u30C3\u30C8\u30A2\u30C3\u30D7\u5B8C\u4E86\u30C6\u30B9\u30C8"
|
|
230
313
|
};
|
|
@@ -246,10 +329,13 @@ function parseInitFlags(argv) {
|
|
|
246
329
|
for (let i = 0; i < argv.length; i++) {
|
|
247
330
|
const a = argv[i];
|
|
248
331
|
if (a === "--yes" || a === "-y") flags.yes = true;
|
|
249
|
-
else if (a === "--os-only")
|
|
250
|
-
|
|
251
|
-
else if (a === "--
|
|
252
|
-
|
|
332
|
+
else if (a === "--os-only") {
|
|
333
|
+
flags.osOnly = true;
|
|
334
|
+
} else if (a === "--slack-only") {
|
|
335
|
+
flags.slackOnly = true;
|
|
336
|
+
} else if (a === "--no-notify") {
|
|
337
|
+
flags.noNotify = true;
|
|
338
|
+
} else if (a === "--codex") flags.codex = true;
|
|
253
339
|
else if (a === "--no-codex") flags.noCodex = true;
|
|
254
340
|
else if (a === "--slack-webhook" || a.startsWith("--slack-webhook=")) {
|
|
255
341
|
flags.slackWebhook = takeValue(argv, i, "--slack-webhook");
|
|
@@ -267,6 +353,38 @@ function parseInitFlags(argv) {
|
|
|
267
353
|
}
|
|
268
354
|
return flags;
|
|
269
355
|
}
|
|
356
|
+
function configPathEntryExists(path) {
|
|
357
|
+
try {
|
|
358
|
+
lstatSync(path);
|
|
359
|
+
return true;
|
|
360
|
+
} catch (err) {
|
|
361
|
+
if (isPlainObject2(err) && err.code === "ENOENT") return false;
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function isExactCodexMigrationInvocation(argv, flags) {
|
|
366
|
+
return flags.yes && flags.codex && argv.every((arg) => arg === "--yes" || arg === "-y" || arg === "--codex");
|
|
367
|
+
}
|
|
368
|
+
function printCodexHookResult(codexResult) {
|
|
369
|
+
if (codexResult.status === "written") {
|
|
370
|
+
console.log(`Codex \u306B Stop/UserPromptSubmit/SubagentStart/SubagentStop hook \u3092\u767B\u9332\u3057\u307E\u3057\u305F: ${codexHooksFile()}`);
|
|
371
|
+
if (codexResult.backupPath) {
|
|
372
|
+
console.log(` \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7: ${codexResult.backupPath}`);
|
|
373
|
+
}
|
|
374
|
+
console.log(
|
|
375
|
+
"\u6B21\u56DE codex \u8D77\u52D5\u6642\u306B\u300EHooks need review\u300F\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002\u300ETrust all and continue\u300F\u3092\u9078\u3076\u3068\u6709\u52B9\u306B\u306A\u308A\u307E\u3059(\u627F\u8A8D\u307E\u3067\u306F\u52D5\u304D\u307E\u305B\u3093)"
|
|
376
|
+
);
|
|
377
|
+
} else if (codexResult.status === "unchanged") {
|
|
378
|
+
console.log("Codex \u306E Stop/UserPromptSubmit/SubagentStart/SubagentStop hook \u306F\u767B\u9332\u6E08\u307F\u3067\u3059");
|
|
379
|
+
} else {
|
|
380
|
+
console.error(`Codex \u306E hooks.json \u3092\u81EA\u52D5\u7DE8\u96C6\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F: ${codexHooksFile()}`);
|
|
381
|
+
console.error("\u5B89\u5168\u306E\u305F\u3081 hooks.json \u306E\u81EA\u52D5\u7DE8\u96C6\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002");
|
|
382
|
+
console.error("\u4EE5\u4E0B\u306E JSON \u306E4\u30A4\u30D9\u30F3\u30C8\u3092 hooks.json \u3078\u624B\u52D5\u3067\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044:");
|
|
383
|
+
console.error("");
|
|
384
|
+
console.error(codexResult.manualSnippet ?? "");
|
|
385
|
+
console.error("");
|
|
386
|
+
}
|
|
387
|
+
}
|
|
270
388
|
function parseUninstallFlags(argv) {
|
|
271
389
|
const flags = { yes: false, purge: false };
|
|
272
390
|
for (const a of argv) {
|
|
@@ -300,7 +418,7 @@ function mergeSettings(sPath, command) {
|
|
|
300
418
|
const hooks = obj.hooks;
|
|
301
419
|
if (!Array.isArray(hooks.Stop)) hooks.Stop = [];
|
|
302
420
|
const stop = hooks.Stop;
|
|
303
|
-
const idx = stop.findIndex(
|
|
421
|
+
const idx = stop.findIndex(isOurStopEntry);
|
|
304
422
|
if (idx >= 0) {
|
|
305
423
|
const entry = stop[idx];
|
|
306
424
|
const entryHooks = entry.hooks;
|
|
@@ -322,6 +440,33 @@ async function runInit(argv) {
|
|
|
322
440
|
console.error("--codex \u3068 --no-codex \u306F\u540C\u6642\u306B\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093");
|
|
323
441
|
return 1;
|
|
324
442
|
}
|
|
443
|
+
const exactMigrationInvocation = isExactCodexMigrationInvocation(argv, flags);
|
|
444
|
+
const configEntryState = exactMigrationInvocation ? configPathEntryExists(configFilePath()) : false;
|
|
445
|
+
if (configEntryState === null) {
|
|
446
|
+
console.error(`config.json \u306E\u5B58\u5728\u3092\u5B89\u5168\u306B\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F: ${configFilePath()}`);
|
|
447
|
+
console.error("\u5B89\u5168\u306E\u305F\u3081 Codex hook \u3092\u542B\u3080\u3059\u3079\u3066\u306E\u5909\u66F4\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002");
|
|
448
|
+
return 1;
|
|
449
|
+
}
|
|
450
|
+
const codexOnlyMigration = exactMigrationInvocation && configEntryState;
|
|
451
|
+
if (codexOnlyMigration) {
|
|
452
|
+
const codexResult2 = registerCodexHook(process.execPath, resolveCliPath());
|
|
453
|
+
printCodexHookResult(codexResult2);
|
|
454
|
+
if (codexResult2.status === "manual") {
|
|
455
|
+
console.error(
|
|
456
|
+
"Codex hook \u9650\u5B9A\u79FB\u884C\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002config.json\u3001Claude settings\u3001\u901A\u77E5\u8A2D\u5B9A\u306F\u5909\u66F4\u3057\u3066\u3044\u307E\u305B\u3093\u3002"
|
|
457
|
+
);
|
|
458
|
+
return 1;
|
|
459
|
+
}
|
|
460
|
+
console.log(
|
|
461
|
+
"Codex hook \u306E\u307F\u3092\u78BA\u8A8D\u30FB\u66F4\u65B0\u3057\u307E\u3057\u305F\u3002config.json\u3001Claude settings\u3001\u901A\u77E5\u8A2D\u5B9A\u306F\u5909\u66F4\u305B\u305A\u3001\u30C6\u30B9\u30C8\u901A\u77E5\u3082\u9001\u4FE1\u3057\u3066\u3044\u307E\u305B\u3093\u3002"
|
|
462
|
+
);
|
|
463
|
+
if (codexResult2.status === "written") {
|
|
464
|
+
console.log(
|
|
465
|
+
"Codex \u3092\u518D\u8D77\u52D5\u3057\u3001/hooks \u3067 Stop / UserPromptSubmit / SubagentStart / SubagentStop \u3092\u4FE1\u983C\u6E08\u307F\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return 0;
|
|
469
|
+
}
|
|
325
470
|
let installCodex = false;
|
|
326
471
|
const cfg = readConfig();
|
|
327
472
|
const initialChannel = !cfg.notify.os && !cfg.notify.slack ? "none" : cfg.notify.slack ? cfg.notify.os ? "both" : "slack" : "os";
|
|
@@ -493,6 +638,7 @@ async function runInit(argv) {
|
|
|
493
638
|
if (installCodex) {
|
|
494
639
|
codexResult = registerCodexHook(process.execPath, resolveCliPath());
|
|
495
640
|
}
|
|
641
|
+
await loadPriceTable(cccn.cacheDir, { offline: false });
|
|
496
642
|
const notifyDisabled = !cfg.notify.os && !cfg.notify.slack;
|
|
497
643
|
if (notifyDisabled) {
|
|
498
644
|
console.log("\u30C6\u30B9\u30C8\u901A\u77E5: \u901A\u77E5\u306A\u3057\u30E2\u30FC\u30C9\u306E\u305F\u3081\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F");
|
|
@@ -517,24 +663,7 @@ async function runInit(argv) {
|
|
|
517
663
|
console.log("Claude Code \u3067\u4F55\u304B\u5B9F\u884C\u3059\u308B\u3068\u901A\u77E5\u304C\u5C4A\u304D\u307E\u3059\u3002\u78BA\u8A8D: npx ccc-notifier doctor");
|
|
518
664
|
}
|
|
519
665
|
if (codexResult) {
|
|
520
|
-
|
|
521
|
-
console.log(`Codex \u306B\u3082 Stop hook \u3092\u767B\u9332\u3057\u307E\u3057\u305F: ${codexHooksFile()}`);
|
|
522
|
-
if (codexResult.backupPath) {
|
|
523
|
-
console.log(` \u30D0\u30C3\u30AF\u30A2\u30C3\u30D7: ${codexResult.backupPath}`);
|
|
524
|
-
}
|
|
525
|
-
console.log(
|
|
526
|
-
"\u6B21\u56DE codex \u8D77\u52D5\u6642\u306B\u300EHooks need review\u300F\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002\u300ETrust all and continue\u300F\u3092\u9078\u3076\u3068\u6709\u52B9\u306B\u306A\u308A\u307E\u3059(\u627F\u8A8D\u307E\u3067\u306F\u52D5\u304D\u307E\u305B\u3093)"
|
|
527
|
-
);
|
|
528
|
-
} else if (codexResult.status === "unchanged") {
|
|
529
|
-
console.log("Codex \u306E Stop hook \u306F\u767B\u9332\u6E08\u307F\u3067\u3059");
|
|
530
|
-
} else {
|
|
531
|
-
console.error(`Codex \u306E hooks.json \u3092\u81EA\u52D5\u7DE8\u96C6\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F: ${codexHooksFile()}`);
|
|
532
|
-
console.error("\u5B89\u5168\u306E\u305F\u3081 hooks.json \u306E\u81EA\u52D5\u7DE8\u96C6\u3092\u4E2D\u6B62\u3057\u307E\u3057\u305F\u3002");
|
|
533
|
-
console.error("\u4EE5\u4E0B\u306E JSON \u3092 hooks.json \u306E hooks.Stop \u914D\u5217\u306B\u624B\u52D5\u3067\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044:");
|
|
534
|
-
console.error("");
|
|
535
|
-
console.error(codexResult.manualSnippet ?? "");
|
|
536
|
-
console.error("");
|
|
537
|
-
}
|
|
666
|
+
printCodexHookResult(codexResult);
|
|
538
667
|
}
|
|
539
668
|
return 0;
|
|
540
669
|
}
|
|
@@ -558,12 +687,12 @@ async function runUninstall(argv) {
|
|
|
558
687
|
const obj = parsed;
|
|
559
688
|
const hooks = isPlainObject2(obj.hooks) ? obj.hooks : null;
|
|
560
689
|
const stop = hooks && Array.isArray(hooks.Stop) ? hooks.Stop : null;
|
|
561
|
-
const hasMarker = stop ? stop.some(
|
|
690
|
+
const hasMarker = stop ? stop.some(isOurStopEntry) : false;
|
|
562
691
|
if (!hasMarker || !hooks || !stop) {
|
|
563
692
|
console.log("\u767B\u9332\u306A\u3057: \u672C\u30C4\u30FC\u30EB\u306E Stop \u30D5\u30C3\u30AF\u306F\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002");
|
|
564
693
|
} else {
|
|
565
694
|
const backupPath = backupSettings(sPath);
|
|
566
|
-
const filtered = stop.filter((e) => !
|
|
695
|
+
const filtered = stop.filter((e) => !isOurStopEntry(e));
|
|
567
696
|
if (filtered.length === 0) {
|
|
568
697
|
delete hooks.Stop;
|
|
569
698
|
} else {
|
|
@@ -577,7 +706,7 @@ async function runUninstall(argv) {
|
|
|
577
706
|
}
|
|
578
707
|
const codexRemoval = removeCodexHook();
|
|
579
708
|
if (codexRemoval.status === "written") {
|
|
580
|
-
console.log("Codex \u306E Stop hook \u3092\u524A\u9664\u3057\u307E\u3057\u305F");
|
|
709
|
+
console.log("Codex \u306E Stop/UserPromptSubmit/SubagentStart/SubagentStop hook \u3092\u524A\u9664\u3057\u307E\u3057\u305F");
|
|
581
710
|
}
|
|
582
711
|
if (flags.purge) {
|
|
583
712
|
const home = paths().home;
|
|
@@ -602,7 +731,9 @@ async function runUninstall(argv) {
|
|
|
602
731
|
}
|
|
603
732
|
|
|
604
733
|
export {
|
|
605
|
-
|
|
734
|
+
CODEX_HOOK_EVENTS,
|
|
735
|
+
CODEX_HOOK_TIMEOUT_SECONDS,
|
|
736
|
+
parseConfiguredOwnedCodexHookCommand,
|
|
606
737
|
matchesMarker,
|
|
607
738
|
runInit,
|
|
608
739
|
runUninstall
|