@windyroad/voice-tone 0.9.7 → 0.9.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/hooks/hooks.json
CHANGED
|
@@ -145,6 +145,17 @@
|
|
|
145
145
|
}
|
|
146
146
|
]
|
|
147
147
|
}
|
|
148
|
+
],
|
|
149
|
+
"SubagentStart": [
|
|
150
|
+
{
|
|
151
|
+
"matcher": "^wr-voice-tone:agent$",
|
|
152
|
+
"hooks": [
|
|
153
|
+
{
|
|
154
|
+
"type": "command",
|
|
155
|
+
"command": "node \"${PLUGIN_ROOT}/hooks-codex/codex-agent-completion.mjs\""
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
148
159
|
]
|
|
149
160
|
}
|
|
150
161
|
}
|
|
@@ -37,6 +37,10 @@ function registrationPath(sessionId, target) {
|
|
|
37
37
|
return join(transportDir(), `registration-${transportId(sessionId, target)}.json`);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function registeredPath(value) { return registrationPath(value.parentSession, value.source === "subagent-start" ? "native:" + value.target : value.target); }
|
|
41
|
+
function nativePath(sessionId) { return join(stateDir(sessionId), "native-review-" + role); }
|
|
42
|
+
function nativeEnabled(input) { return role !== "wr-voice-tone:external-comms" && existsSync(nativePath(input.session_id)); }
|
|
43
|
+
|
|
40
44
|
function receiptPath(sessionId, target, suffix = "") {
|
|
41
45
|
return join(transportDir(), `receipt-${transportId(sessionId, target)}.json${suffix}`);
|
|
42
46
|
}
|
|
@@ -136,7 +140,30 @@ function clear(input, target) {
|
|
|
136
140
|
for (const suffix of ["", ".claim", ".done"]) rmSync(receiptPath(input.session_id, target, suffix), { force: true });
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
function rememberNative(input) {
|
|
144
|
+
if (role === "wr-voice-tone:external-comms" || input.agent_type !== role || typeof input.agent_id !== "string" || !/^[A-Za-z0-9-]+$/.test(input.agent_id)) return;
|
|
145
|
+
const bound = checkout(input.cwd);
|
|
146
|
+
const hash = bound && policyHash(bound.root);
|
|
147
|
+
if (!bound || !hash) return diagnostic("invalid-native-binding", input);
|
|
148
|
+
const target = input.agent_id;
|
|
149
|
+
if (existsSync(receiptPath(input.session_id, target, ".done")) || existsSync(statePath(input, target, ".done"))) return;
|
|
150
|
+
const registered = { source: "subagent-start", parentSession: input.session_id, role, target, ...bound, policyHash: hash, createdAt: Date.now() };
|
|
151
|
+
mkdirSync(transportDir(), { recursive: true, mode: 0o700 });
|
|
152
|
+
try { writeFileSync(registeredPath(registered), JSON.stringify(registered), { flag: "wx", mode: 0o600 }); }
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (error?.code !== "EEXIST") throw error;
|
|
155
|
+
const previous = JSON.parse(readFileSync(registeredPath(registered), "utf8"));
|
|
156
|
+
for (const key of ["source", "parentSession", "role", "target", "root", "physical", "policyHash"]) {
|
|
157
|
+
if (previous[key] !== registered[key]) return diagnostic("native-registration-conflict", input);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
mkdirSync(stateDir(input.session_id), { recursive: true });
|
|
161
|
+
try { writeFileSync(nativePath(input.session_id), "", { flag: "wx", mode: 0o600 }); }
|
|
162
|
+
catch (error) { if (error?.code !== "EEXIST") throw error; }
|
|
163
|
+
}
|
|
164
|
+
|
|
139
165
|
function remember(input) {
|
|
166
|
+
if (nativeEnabled(input)) return;
|
|
140
167
|
reapTransport();
|
|
141
168
|
const target = normalizeTarget(targetFromSpawn(input));
|
|
142
169
|
if (!target) return;
|
|
@@ -226,7 +253,7 @@ function writeMarker(input, registered, target, output, completedAt, claimed) {
|
|
|
226
253
|
}
|
|
227
254
|
renameSync(claimed.path, claimed.done);
|
|
228
255
|
rmSync(statePath({ session_id: registered.parentSession }, target), { force: true });
|
|
229
|
-
rmSync(
|
|
256
|
+
rmSync(registeredPath(registered), { force: true });
|
|
230
257
|
const assessedAt = new Date(completedAt);
|
|
231
258
|
for (const candidate of [
|
|
232
259
|
join(process.env.TMPDIR || "/tmp", `voice-tone-reviewed-${registered.parentSession}`),
|
|
@@ -246,6 +273,7 @@ function writeMarker(input, registered, target, output, completedAt, claimed) {
|
|
|
246
273
|
}
|
|
247
274
|
|
|
248
275
|
function complete(input, target, output) {
|
|
276
|
+
if (nativeEnabled(input)) return;
|
|
249
277
|
target = completionTarget(target, stateDir(input.session_id), "codex-review-", role + ":");
|
|
250
278
|
if (!target || typeof output !== "string" || !output) return;
|
|
251
279
|
const path = statePath(input, target);
|
|
@@ -298,8 +326,11 @@ function persistPending(input, target, output) {
|
|
|
298
326
|
target = normalizeTarget(target);
|
|
299
327
|
if (!target || typeof output !== "string" || !output) return;
|
|
300
328
|
const registrationsForCheckout = registrations(input, target);
|
|
301
|
-
const
|
|
302
|
-
const
|
|
329
|
+
const native = registrationsForCheckout.filter(({ registered }) => registered.source === "subagent-start");
|
|
330
|
+
const nativeExact = native.filter(({ registered }) => registered.parentSession === input.session_id && registered.target === input.agent_id);
|
|
331
|
+
const legacy = registrationsForCheckout.filter(({ registered }) => registered.source !== "subagent-start");
|
|
332
|
+
const exact = legacy.filter(({ registered }) => registered.target === target);
|
|
333
|
+
const candidates = nativeEnabled(input) || nativeExact.length ? nativeExact : exact.length ? exact : legacy.filter(({ registered }) => registered.parentSession === input.session_id);
|
|
303
334
|
if (candidates.length !== 1) {
|
|
304
335
|
diagnostic(candidates.length ? "ambiguous-parent-registration" : "missing-parent-registration", input);
|
|
305
336
|
return;
|
|
@@ -335,6 +366,7 @@ function consumePending(input) {
|
|
|
335
366
|
continue;
|
|
336
367
|
}
|
|
337
368
|
if (pending.parentSession !== input.session_id || pending.role !== role) continue;
|
|
369
|
+
if (nativeEnabled(input) && pending.source !== "subagent-start") continue;
|
|
338
370
|
if (!validRegistration(pending, input, pending.target, age)) continue;
|
|
339
371
|
const claimPath = path + ".claim";
|
|
340
372
|
const donePath = path + ".done";
|
|
@@ -369,6 +401,7 @@ if (!/^[0-9]+$/.test(ttlSeconds) || !Number.isSafeInteger(ttl) || ttl <= 0) {
|
|
|
369
401
|
}
|
|
370
402
|
|
|
371
403
|
try {
|
|
404
|
+
if (input.hook_event_name === "SubagentStart") rememberNative(input);
|
|
372
405
|
if (SPAWN_TOOLS.has(input.tool_name)) remember(input);
|
|
373
406
|
if (CLOSE_TOOLS.has(input.tool_name)) close(input);
|
|
374
407
|
if (WAIT_TOOLS.has(input.tool_name)) wait(input);
|
|
@@ -378,7 +411,7 @@ try {
|
|
|
378
411
|
else {
|
|
379
412
|
const target = input.task_name || input.agent_name || input.agent_id;
|
|
380
413
|
const local = statePath(input, normalizeTarget(target));
|
|
381
|
-
if (existsSync(local)) complete(input, target, input.last_assistant_message);
|
|
414
|
+
if (!nativeEnabled(input) && existsSync(local)) complete(input, target, input.last_assistant_message);
|
|
382
415
|
else persistPending(input, target, input.last_assistant_message);
|
|
383
416
|
}
|
|
384
417
|
}
|
|
@@ -37,6 +37,10 @@ function registrationPath(sessionId, target) {
|
|
|
37
37
|
return join(transportDir(), `registration-${transportId(sessionId, target)}.json`);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
function registeredPath(value) { return registrationPath(value.parentSession, value.source === "subagent-start" ? "native:" + value.target : value.target); }
|
|
41
|
+
function nativePath(sessionId) { return join(stateDir(sessionId), "native-review-" + role); }
|
|
42
|
+
function nativeEnabled(input) { return role !== "wr-voice-tone:external-comms" && existsSync(nativePath(input.session_id)); }
|
|
43
|
+
|
|
40
44
|
function receiptPath(sessionId, target, suffix = "") {
|
|
41
45
|
return join(transportDir(), `receipt-${transportId(sessionId, target)}.json${suffix}`);
|
|
42
46
|
}
|
|
@@ -136,7 +140,30 @@ function clear(input, target) {
|
|
|
136
140
|
for (const suffix of ["", ".claim", ".done"]) rmSync(receiptPath(input.session_id, target, suffix), { force: true });
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
function rememberNative(input) {
|
|
144
|
+
if (role === "wr-voice-tone:external-comms" || input.agent_type !== role || typeof input.agent_id !== "string" || !/^[A-Za-z0-9-]+$/.test(input.agent_id)) return;
|
|
145
|
+
const bound = checkout(input.cwd);
|
|
146
|
+
const hash = bound && policyHash(bound.root);
|
|
147
|
+
if (!bound || !hash) return diagnostic("invalid-native-binding", input);
|
|
148
|
+
const target = input.agent_id;
|
|
149
|
+
if (existsSync(receiptPath(input.session_id, target, ".done")) || existsSync(statePath(input, target, ".done"))) return;
|
|
150
|
+
const registered = { source: "subagent-start", parentSession: input.session_id, role, target, ...bound, policyHash: hash, createdAt: Date.now() };
|
|
151
|
+
mkdirSync(transportDir(), { recursive: true, mode: 0o700 });
|
|
152
|
+
try { writeFileSync(registeredPath(registered), JSON.stringify(registered), { flag: "wx", mode: 0o600 }); }
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (error?.code !== "EEXIST") throw error;
|
|
155
|
+
const previous = JSON.parse(readFileSync(registeredPath(registered), "utf8"));
|
|
156
|
+
for (const key of ["source", "parentSession", "role", "target", "root", "physical", "policyHash"]) {
|
|
157
|
+
if (previous[key] !== registered[key]) return diagnostic("native-registration-conflict", input);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
mkdirSync(stateDir(input.session_id), { recursive: true });
|
|
161
|
+
try { writeFileSync(nativePath(input.session_id), "", { flag: "wx", mode: 0o600 }); }
|
|
162
|
+
catch (error) { if (error?.code !== "EEXIST") throw error; }
|
|
163
|
+
}
|
|
164
|
+
|
|
139
165
|
function remember(input) {
|
|
166
|
+
if (nativeEnabled(input)) return;
|
|
140
167
|
reapTransport();
|
|
141
168
|
const target = normalizeTarget(targetFromSpawn(input));
|
|
142
169
|
if (!target) return;
|
|
@@ -226,7 +253,7 @@ function writeMarker(input, registered, target, output, completedAt, claimed) {
|
|
|
226
253
|
}
|
|
227
254
|
renameSync(claimed.path, claimed.done);
|
|
228
255
|
rmSync(statePath({ session_id: registered.parentSession }, target), { force: true });
|
|
229
|
-
rmSync(
|
|
256
|
+
rmSync(registeredPath(registered), { force: true });
|
|
230
257
|
const assessedAt = new Date(completedAt);
|
|
231
258
|
for (const candidate of [
|
|
232
259
|
join(process.env.TMPDIR || "/tmp", `voice-tone-reviewed-${registered.parentSession}`),
|
|
@@ -246,6 +273,7 @@ function writeMarker(input, registered, target, output, completedAt, claimed) {
|
|
|
246
273
|
}
|
|
247
274
|
|
|
248
275
|
function complete(input, target, output) {
|
|
276
|
+
if (nativeEnabled(input)) return;
|
|
249
277
|
target = completionTarget(target, stateDir(input.session_id), "codex-review-", role + ":");
|
|
250
278
|
if (!target || typeof output !== "string" || !output) return;
|
|
251
279
|
const path = statePath(input, target);
|
|
@@ -298,8 +326,11 @@ function persistPending(input, target, output) {
|
|
|
298
326
|
target = normalizeTarget(target);
|
|
299
327
|
if (!target || typeof output !== "string" || !output) return;
|
|
300
328
|
const registrationsForCheckout = registrations(input, target);
|
|
301
|
-
const
|
|
302
|
-
const
|
|
329
|
+
const native = registrationsForCheckout.filter(({ registered }) => registered.source === "subagent-start");
|
|
330
|
+
const nativeExact = native.filter(({ registered }) => registered.parentSession === input.session_id && registered.target === input.agent_id);
|
|
331
|
+
const legacy = registrationsForCheckout.filter(({ registered }) => registered.source !== "subagent-start");
|
|
332
|
+
const exact = legacy.filter(({ registered }) => registered.target === target);
|
|
333
|
+
const candidates = nativeEnabled(input) || nativeExact.length ? nativeExact : exact.length ? exact : legacy.filter(({ registered }) => registered.parentSession === input.session_id);
|
|
303
334
|
if (candidates.length !== 1) {
|
|
304
335
|
diagnostic(candidates.length ? "ambiguous-parent-registration" : "missing-parent-registration", input);
|
|
305
336
|
return;
|
|
@@ -335,6 +366,7 @@ function consumePending(input) {
|
|
|
335
366
|
continue;
|
|
336
367
|
}
|
|
337
368
|
if (pending.parentSession !== input.session_id || pending.role !== role) continue;
|
|
369
|
+
if (nativeEnabled(input) && pending.source !== "subagent-start") continue;
|
|
338
370
|
if (!validRegistration(pending, input, pending.target, age)) continue;
|
|
339
371
|
const claimPath = path + ".claim";
|
|
340
372
|
const donePath = path + ".done";
|
|
@@ -369,6 +401,7 @@ if (!/^[0-9]+$/.test(ttlSeconds) || !Number.isSafeInteger(ttl) || ttl <= 0) {
|
|
|
369
401
|
}
|
|
370
402
|
|
|
371
403
|
try {
|
|
404
|
+
if (input.hook_event_name === "SubagentStart") rememberNative(input);
|
|
372
405
|
if (SPAWN_TOOLS.has(input.tool_name)) remember(input);
|
|
373
406
|
if (CLOSE_TOOLS.has(input.tool_name)) close(input);
|
|
374
407
|
if (WAIT_TOOLS.has(input.tool_name)) wait(input);
|
|
@@ -378,7 +411,7 @@ try {
|
|
|
378
411
|
else {
|
|
379
412
|
const target = input.task_name || input.agent_name || input.agent_id;
|
|
380
413
|
const local = statePath(input, normalizeTarget(target));
|
|
381
|
-
if (existsSync(local)) complete(input, target, input.last_assistant_message);
|
|
414
|
+
if (!nativeEnabled(input) && existsSync(local)) complete(input, target, input.last_assistant_message);
|
|
382
415
|
else persistPending(input, target, input.last_assistant_message);
|
|
383
416
|
}
|
|
384
417
|
}
|
package/hooks-codex/hooks.json
CHANGED
|
@@ -145,6 +145,17 @@
|
|
|
145
145
|
}
|
|
146
146
|
]
|
|
147
147
|
}
|
|
148
|
+
],
|
|
149
|
+
"SubagentStart": [
|
|
150
|
+
{
|
|
151
|
+
"matcher": "^wr-voice-tone:agent$",
|
|
152
|
+
"hooks": [
|
|
153
|
+
{
|
|
154
|
+
"type": "command",
|
|
155
|
+
"command": "node \"${PLUGIN_ROOT}/hooks-codex/codex-agent-completion.mjs\""
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
148
159
|
]
|
|
149
160
|
}
|
|
150
161
|
}
|