approval-box 0.1.23 → 0.1.25
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/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/approval-box-claude-hook.mjs +1 -1
- package/dist/approval-box-cursor-hook.mjs +1 -1
- package/dist/approval-box-receive.mjs +1 -1
- package/dist/chunks/{chunk-SN7I52NL.mjs → chunk-XTKJLDHY.mjs} +195 -46
- package/dist/cli.mjs +21 -6
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { createRequire as __kbCreateRequire } from 'node:module'; const require
|
|
|
2
2
|
import {
|
|
3
3
|
PROFILE,
|
|
4
4
|
runChannelReceiveMain
|
|
5
|
-
} from "./chunks/chunk-
|
|
5
|
+
} from "./chunks/chunk-XTKJLDHY.mjs";
|
|
6
6
|
|
|
7
7
|
// src/hooks/receive.ts
|
|
8
8
|
await runChannelReceiveMain(PROFILE);
|
|
@@ -19783,6 +19783,31 @@ var SetupError = class extends Error {
|
|
|
19783
19783
|
}
|
|
19784
19784
|
};
|
|
19785
19785
|
|
|
19786
|
+
// ../../node_modules/aiterm-steer-delivery/dist/setup-node.js
|
|
19787
|
+
import { accessSync, constants, existsSync } from "node:fs";
|
|
19788
|
+
var BREW_NODE = /^(.*)\/Cellar\/(node(?:@\d+)?)\/[^/]+\/bin\/node$/;
|
|
19789
|
+
function setupNodeExecutable(executable = process.execPath) {
|
|
19790
|
+
const brew = BREW_NODE.exec(executable);
|
|
19791
|
+
if (!brew)
|
|
19792
|
+
return executable;
|
|
19793
|
+
const node2 = `${brew[1]}/opt/${brew[2]}/bin/node`;
|
|
19794
|
+
try {
|
|
19795
|
+
accessSync(node2, constants.X_OK);
|
|
19796
|
+
} catch {
|
|
19797
|
+
throw new SetupError("node_runtime_unavailable", "Homebrew\u306ENode\u8D77\u52D5\u5148\u3092\u5B9F\u884C\u3067\u304D\u307E\u305B\u3093\u3002Node\u306E\u5C0E\u5165\u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044");
|
|
19798
|
+
}
|
|
19799
|
+
return node2;
|
|
19800
|
+
}
|
|
19801
|
+
function liveNodeExecutable(executable = process.execPath, exists = existsSync) {
|
|
19802
|
+
const brew = BREW_NODE.exec(executable);
|
|
19803
|
+
if (brew) {
|
|
19804
|
+
const opt = `${brew[1]}/opt/${brew[2]}/bin/node`;
|
|
19805
|
+
if (exists(opt))
|
|
19806
|
+
return opt;
|
|
19807
|
+
}
|
|
19808
|
+
return exists(executable) ? executable : "node";
|
|
19809
|
+
}
|
|
19810
|
+
|
|
19786
19811
|
// ../../node_modules/aiterm-steer-delivery/dist/files.js
|
|
19787
19812
|
import * as fs from "node:fs";
|
|
19788
19813
|
import * as path2 from "node:path";
|
|
@@ -20025,7 +20050,7 @@ function resolveCodexExecutable() {
|
|
|
20025
20050
|
}
|
|
20026
20051
|
return null;
|
|
20027
20052
|
}
|
|
20028
|
-
function codexSpawnEnv(env = process.env, node2 =
|
|
20053
|
+
function codexSpawnEnv(env = process.env, node2 = liveNodeExecutable(), platform = process.platform) {
|
|
20029
20054
|
const windows = platform === "win32";
|
|
20030
20055
|
const key = Object.keys(env).find((name) => windows ? name.toLowerCase() === "path" : name === "PATH") ?? "PATH";
|
|
20031
20056
|
const delimiter2 = windows ? ";" : ":";
|
|
@@ -20200,6 +20225,136 @@ function hookOwnerProcess(rows, pid) {
|
|
|
20200
20225
|
current = byPid.get(current.parent_pid);
|
|
20201
20226
|
return current;
|
|
20202
20227
|
}
|
|
20228
|
+
function processExists(pid) {
|
|
20229
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
20230
|
+
return false;
|
|
20231
|
+
try {
|
|
20232
|
+
process.kill(pid, 0);
|
|
20233
|
+
return true;
|
|
20234
|
+
} catch (error62) {
|
|
20235
|
+
return error62.code === "EPERM";
|
|
20236
|
+
}
|
|
20237
|
+
}
|
|
20238
|
+
function windowsJson(script, failure2) {
|
|
20239
|
+
const source = ["$ErrorActionPreference='Stop'", "[Console]::OutputEncoding=[Text.UTF8Encoding]::new($false)", script].join("\n");
|
|
20240
|
+
const result = spawnSync3(resolveWindowsPowerShell7(), ["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(source, "utf16le").toString("base64")], {
|
|
20241
|
+
encoding: "utf8",
|
|
20242
|
+
timeout: 15e3,
|
|
20243
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
20244
|
+
windowsHide: true
|
|
20245
|
+
});
|
|
20246
|
+
if (result.error || result.status !== 0)
|
|
20247
|
+
throw new ProcessTableError(failure2);
|
|
20248
|
+
try {
|
|
20249
|
+
return JSON.parse(result.stdout);
|
|
20250
|
+
} catch {
|
|
20251
|
+
throw new ProcessTableError(failure2);
|
|
20252
|
+
}
|
|
20253
|
+
}
|
|
20254
|
+
function assertPids(pids) {
|
|
20255
|
+
const wanted = [...new Set(pids)];
|
|
20256
|
+
if (wanted.some((pid) => !Number.isSafeInteger(pid) || pid < 0))
|
|
20257
|
+
throw new ProcessTableError("process\u7167\u4F1A\u306Epid\u304C\u4E0D\u6B63\u3067\u3059");
|
|
20258
|
+
return wanted;
|
|
20259
|
+
}
|
|
20260
|
+
var WINDOWS_STARTED = [
|
|
20261
|
+
"function Started($p) {",
|
|
20262
|
+
" try { return $p.StartTime.ToUniversalTime().ToString('o') }",
|
|
20263
|
+
" catch [InvalidOperationException] { return '' }",
|
|
20264
|
+
` catch { $w = Get-CimInstance Win32_Process -Filter "ProcessId=$($p.Id)" -Property CreationDate; if ($null -eq $w) { return '' }`,
|
|
20265
|
+
" if ($null -eq $w.CreationDate) { return $null }; return $w.CreationDate.ToUniversalTime().ToString('o') }",
|
|
20266
|
+
"}"
|
|
20267
|
+
].join("\n");
|
|
20268
|
+
function readProcessIdentities(pids) {
|
|
20269
|
+
const wanted = assertPids(pids).filter(processExists);
|
|
20270
|
+
if (wanted.length === 0)
|
|
20271
|
+
return [];
|
|
20272
|
+
if (!isWin2) {
|
|
20273
|
+
const result = spawnSync3("/bin/ps", ["-o", "pid=,lstart=", "-p", wanted.join(",")], {
|
|
20274
|
+
encoding: "utf8",
|
|
20275
|
+
env: { ...process.env, LC_ALL: "C" },
|
|
20276
|
+
timeout: 1e4
|
|
20277
|
+
});
|
|
20278
|
+
if (result.error || result.status !== 0 && !(result.status === 1 && !result.stdout.trim())) {
|
|
20279
|
+
throw new ProcessTableError("OS\u306Eprocess\u4E00\u89A7\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093");
|
|
20280
|
+
}
|
|
20281
|
+
return result.stdout.split("\n").filter((line) => line.trim()).map((line) => {
|
|
20282
|
+
const match = /^\s*(\d+)\s+(\S+\s+\S+\s+\d+\s+\S+\s+\d+)\s*$/.exec(line);
|
|
20283
|
+
if (!match)
|
|
20284
|
+
throw new ProcessTableError("process\u4E00\u89A7\u306E\u5F62\u5F0F\u3092\u8A8D\u8B58\u3067\u304D\u307E\u305B\u3093");
|
|
20285
|
+
return { pid: Number(match[1]), started_identity: match[2].trim() };
|
|
20286
|
+
});
|
|
20287
|
+
}
|
|
20288
|
+
const rows = windowsJson([
|
|
20289
|
+
WINDOWS_STARTED,
|
|
20290
|
+
"$rows=@()",
|
|
20291
|
+
`foreach ($id in @(${wanted.join(",")})) {`,
|
|
20292
|
+
" try { $p=[Diagnostics.Process]::GetProcessById($id) } catch [ArgumentException] { continue }",
|
|
20293
|
+
" $started=Started $p",
|
|
20294
|
+
" if ($started -eq '') { continue }",
|
|
20295
|
+
" $rows += [ordered]@{ pid=[int]$id; started_identity=$started }",
|
|
20296
|
+
"}",
|
|
20297
|
+
"ConvertTo-Json -Compress -InputObject $rows"
|
|
20298
|
+
].join("\n"), "Windows\u306Eprocess\u306E\u958B\u59CB\u6642\u523B\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093");
|
|
20299
|
+
if (!Array.isArray(rows))
|
|
20300
|
+
throw new ProcessTableError("Windows process\u306E\u8AAD\u307F\u304C\u914D\u5217\u3067\u306F\u3042\u308A\u307E\u305B\u3093");
|
|
20301
|
+
return rows.map((row) => {
|
|
20302
|
+
if (!row || !Number.isSafeInteger(row.pid))
|
|
20303
|
+
throw new ProcessTableError("Windows process\u306E\u8AAD\u307F\u306Efield\u304C\u4E0D\u6B63\u3067\u3059");
|
|
20304
|
+
if (row.started_identity === null)
|
|
20305
|
+
return { pid: row.pid, started_identity: null };
|
|
20306
|
+
if (typeof row.started_identity !== "string" || !Number.isFinite(Date.parse(row.started_identity)))
|
|
20307
|
+
throw new ProcessTableError("Windows process\u306E\u8AAD\u307F\u306Efield\u304C\u4E0D\u6B63\u3067\u3059");
|
|
20308
|
+
return { pid: row.pid, started_identity: new Date(row.started_identity).toISOString() };
|
|
20309
|
+
});
|
|
20310
|
+
}
|
|
20311
|
+
function processIsRunning(pid, startedIdentity) {
|
|
20312
|
+
return processExists(pid) && readProcessIdentities([pid])[0]?.started_identity === startedIdentity;
|
|
20313
|
+
}
|
|
20314
|
+
function readProcessLineage(pid, depth = 8) {
|
|
20315
|
+
if (!isWin2)
|
|
20316
|
+
return readRuntimeProcesses();
|
|
20317
|
+
if (!Number.isSafeInteger(pid) || pid <= 0 || !Number.isSafeInteger(depth) || depth <= 0)
|
|
20318
|
+
throw new ProcessTableError("process\u7167\u4F1A\u306Epid\u304C\u4E0D\u6B63\u3067\u3059");
|
|
20319
|
+
let rows;
|
|
20320
|
+
try {
|
|
20321
|
+
rows = windowsJson([
|
|
20322
|
+
"$rows=@(); $child=$null",
|
|
20323
|
+
`$id=${pid}`,
|
|
20324
|
+
`for ($i=0; $i -lt ${depth} -and $id -gt 0; $i++) {`,
|
|
20325
|
+
" try { $p=Get-Process -Id $id; $started=$p.StartTime.ToUniversalTime() } catch { break }",
|
|
20326
|
+
// Windowsの親PIDは親の終了後も残り、別のprocessへ使い回される。子より後に始まったprocessは親でない。
|
|
20327
|
+
" if ($null -ne $child -and $started -gt $child) { break }",
|
|
20328
|
+
" $parent=0; try { if ($null -ne $p.Parent) { $parent=[int]$p.Parent.Id } } catch { }",
|
|
20329
|
+
" $exe=''; try { $exe=[string]$p.Path } catch { }",
|
|
20330
|
+
" if (-not $exe) { $exe=[string]$p.ProcessName }",
|
|
20331
|
+
" $cpu=0.0; try { $cpu=[double]$p.TotalProcessorTime.TotalSeconds } catch { }",
|
|
20332
|
+
" $rows += [ordered]@{ pid=[int]$p.Id; parent_pid=$parent; executable=$exe; started_identity=$started.ToString('o'); cpu_seconds=$cpu }",
|
|
20333
|
+
" $child=$started; $id=$parent",
|
|
20334
|
+
"}",
|
|
20335
|
+
"ConvertTo-Json -Compress -InputObject $rows"
|
|
20336
|
+
].join("\n"), "Windows\u306Eprocess\u306E\u5148\u7956\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093");
|
|
20337
|
+
} catch {
|
|
20338
|
+
return readRuntimeProcesses();
|
|
20339
|
+
}
|
|
20340
|
+
if (!Array.isArray(rows) || rows[0]?.pid !== pid)
|
|
20341
|
+
return readRuntimeProcesses();
|
|
20342
|
+
return rows.map((row) => {
|
|
20343
|
+
if (!row || !Number.isSafeInteger(row.pid) || !Number.isSafeInteger(row.parent_pid) || typeof row.executable !== "string" || !Number.isFinite(row.cpu_seconds) || typeof row.started_identity !== "string" || !Number.isFinite(Date.parse(row.started_identity)))
|
|
20344
|
+
throw new ProcessTableError("Windows process\u306E\u8AAD\u307F\u306Efield\u304C\u4E0D\u6B63\u3067\u3059");
|
|
20345
|
+
return {
|
|
20346
|
+
pid: row.pid,
|
|
20347
|
+
parent_pid: row.parent_pid,
|
|
20348
|
+
process_group_id: null,
|
|
20349
|
+
stopped: null,
|
|
20350
|
+
executable: row.executable,
|
|
20351
|
+
started_identity: new Date(row.started_identity).toISOString(),
|
|
20352
|
+
command: row.executable,
|
|
20353
|
+
cpu_seconds: row.cpu_seconds,
|
|
20354
|
+
argv_digest: createHash2("sha256").update(row.executable).digest("hex")
|
|
20355
|
+
};
|
|
20356
|
+
});
|
|
20357
|
+
}
|
|
20203
20358
|
function readRuntimeProcesses() {
|
|
20204
20359
|
if (!isWin2) {
|
|
20205
20360
|
const result2 = spawnSync3("/bin/ps", ["-axww", "-o", "pid=,ppid=,pgid=,stat=,lstart=,time=,command="], {
|
|
@@ -20356,7 +20511,7 @@ function startCodexWakeWatch(profile, parent, deliveryId, options = {}) {
|
|
|
20356
20511
|
delivery_id: deliveryId,
|
|
20357
20512
|
...options.delay_ms === void 0 ? {} : { delay_ms: options.delay_ms }
|
|
20358
20513
|
});
|
|
20359
|
-
const child = spawn(
|
|
20514
|
+
const child = spawn(liveNodeExecutable(), [entry], { detached: true, stdio: "ignore", windowsHide: true, env: { ...env, [CODEX_WAKE_PAYLOAD_ENV]: payload } });
|
|
20360
20515
|
child.on("error", () => {
|
|
20361
20516
|
});
|
|
20362
20517
|
child.unref();
|
|
@@ -20506,7 +20661,7 @@ var claudeParentSchema = external_exports.object({
|
|
|
20506
20661
|
hook_root: external_exports.string()
|
|
20507
20662
|
}).strict();
|
|
20508
20663
|
function processIdentity(pid) {
|
|
20509
|
-
return
|
|
20664
|
+
return readProcessIdentities([pid])[0]?.started_identity ?? void 0;
|
|
20510
20665
|
}
|
|
20511
20666
|
function directory(parent) {
|
|
20512
20667
|
return path7.join(parent.hook_root, parent.request_id);
|
|
@@ -20530,8 +20685,7 @@ function assertOpen(parent) {
|
|
|
20530
20685
|
}
|
|
20531
20686
|
function prepareClaudeHookRequest(input2, root) {
|
|
20532
20687
|
const event = external_exports.object({ session_id: external_exports.uuid(), tool_use_id: requestId, agent_id: external_exports.string().optional() }).parse(input2);
|
|
20533
|
-
const
|
|
20534
|
-
const owner = hookOwnerProcess(rows, process.ppid);
|
|
20688
|
+
const owner = hookOwnerProcess(readProcessLineage(process.ppid), process.ppid);
|
|
20535
20689
|
if (!owner)
|
|
20536
20690
|
throw new ClaudeDeliveryError("CLAUDE_PARENT_PROCESS_UNAVAILABLE", "hook\u3092\u8D77\u52D5\u3057\u305F\u89AAprocess\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093");
|
|
20537
20691
|
const dir = path7.join(root, event.tool_use_id);
|
|
@@ -20544,13 +20698,14 @@ function prepareClaudeHookRequest(input2, root) {
|
|
|
20544
20698
|
parent_started_identity: owner.started_identity
|
|
20545
20699
|
});
|
|
20546
20700
|
try {
|
|
20547
|
-
sweepClaudeHookRequests(root,
|
|
20701
|
+
sweepClaudeHookRequests(root, processIsRunning);
|
|
20548
20702
|
} catch {
|
|
20549
20703
|
}
|
|
20550
20704
|
}
|
|
20551
20705
|
var STALE_REQUEST_MS = 24 * 60 * 60 * 1e3;
|
|
20552
20706
|
var REQUEST_FILES = /* @__PURE__ */ new Set(["request.json", "delivery.json", "answer.json", "hook.json", "sending.json", "emitted.json", "failed.json", "closed.json"]);
|
|
20553
20707
|
function sweepClaudeHookRequests(root, rows, now = Date.now()) {
|
|
20708
|
+
const running = typeof rows === "function" ? rows : (pid, startedIdentity) => rows.find((row) => row.pid === pid)?.started_identity === startedIdentity;
|
|
20554
20709
|
let entries;
|
|
20555
20710
|
try {
|
|
20556
20711
|
entries = fs5.readdirSync(root, { withFileTypes: true });
|
|
@@ -20576,7 +20731,7 @@ function sweepClaudeHookRequests(root, rows, now = Date.now()) {
|
|
|
20576
20731
|
invocation = invocationSchema.parse(JSON.parse(fs5.readFileSync(path7.join(dir, "request.json"), "utf8")));
|
|
20577
20732
|
} catch {
|
|
20578
20733
|
}
|
|
20579
|
-
if (invocation &&
|
|
20734
|
+
if (invocation && running(invocation.parent_pid, invocation.parent_started_identity))
|
|
20580
20735
|
continue;
|
|
20581
20736
|
}
|
|
20582
20737
|
fs5.rmSync(dir, { recursive: true, force: true });
|
|
@@ -20635,7 +20790,7 @@ function closeClaudeParentSession(input2, root) {
|
|
|
20635
20790
|
throw failure2;
|
|
20636
20791
|
}
|
|
20637
20792
|
function assertParentAlive(invocation) {
|
|
20638
|
-
if (
|
|
20793
|
+
if (!processIsRunning(invocation.parent_pid, invocation.parent_started_identity)) {
|
|
20639
20794
|
throw new ClaudeDeliveryError("CLAUDE_PARENT_PROCESS_CLOSED", "\u4F9D\u983C\u5143\u306EClaude process\u306F\u7D42\u4E86\u3057\u307E\u3057\u305F\u3002\u56DE\u7B54\u306F\u4FDD\u5B58\u3057\u305F\u307E\u307E\u3067\u3059");
|
|
20640
20795
|
}
|
|
20641
20796
|
}
|
|
@@ -20686,7 +20841,7 @@ import { homedir as homedir3 } from "node:os";
|
|
|
20686
20841
|
import * as path8 from "node:path";
|
|
20687
20842
|
|
|
20688
20843
|
// ../../node_modules/aiterm-steer-delivery/dist/hook-setup.js
|
|
20689
|
-
import { copyFileSync, existsSync as
|
|
20844
|
+
import { copyFileSync, existsSync as existsSync7, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync5, realpathSync as realpathSync3, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
20690
20845
|
import { dirname as dirname3 } from "node:path";
|
|
20691
20846
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
20692
20847
|
import { isDeepStrictEqual } from "node:util";
|
|
@@ -20723,9 +20878,9 @@ function claudeParentHookEntries(profile, hook, platform = process.platform) {
|
|
|
20723
20878
|
}
|
|
20724
20879
|
var OPTIONAL_CLAUDE_EVENTS = /* @__PURE__ */ new Set(["SessionStart"]);
|
|
20725
20880
|
function mergeClaudeParentHooks(profile, file2, hook) {
|
|
20726
|
-
const target2 =
|
|
20881
|
+
const target2 = existsSync7(file2) ? realpathSync3(file2) : file2;
|
|
20727
20882
|
let current = {};
|
|
20728
|
-
if (
|
|
20883
|
+
if (existsSync7(target2)) {
|
|
20729
20884
|
try {
|
|
20730
20885
|
current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
20731
20886
|
} catch {
|
|
@@ -20760,11 +20915,11 @@ function mergeClaudeParentHooks(profile, file2, hook) {
|
|
|
20760
20915
|
try {
|
|
20761
20916
|
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20762
20917
|
`, { mode: 384, flag: "wx" });
|
|
20763
|
-
if (
|
|
20918
|
+
if (existsSync7(target2))
|
|
20764
20919
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
20765
20920
|
renameSync2(temporary, target2);
|
|
20766
20921
|
} finally {
|
|
20767
|
-
if (
|
|
20922
|
+
if (existsSync7(temporary))
|
|
20768
20923
|
unlinkSync2(temporary);
|
|
20769
20924
|
}
|
|
20770
20925
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next)) {
|
|
@@ -20789,7 +20944,7 @@ function claudeParentHooksRegistered(profile, document) {
|
|
|
20789
20944
|
return Object.keys(claudeParentHookEntries(profile, { command: "", script: profile.hooks.claude })).filter((event) => !OPTIONAL_CLAUDE_EVENTS.has(event)).every((event) => ownedClaudeParentHooks(profile, document, event).length > 0);
|
|
20790
20945
|
}
|
|
20791
20946
|
function removeClaudeParentHooks(profile, file2) {
|
|
20792
|
-
if (!
|
|
20947
|
+
if (!existsSync7(file2))
|
|
20793
20948
|
return "unchanged";
|
|
20794
20949
|
const target2 = realpathSync3(file2);
|
|
20795
20950
|
const current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
@@ -20820,7 +20975,7 @@ function removeClaudeParentHooks(profile, file2) {
|
|
|
20820
20975
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
20821
20976
|
renameSync2(temporary, target2);
|
|
20822
20977
|
} finally {
|
|
20823
|
-
if (
|
|
20978
|
+
if (existsSync7(temporary))
|
|
20824
20979
|
unlinkSync2(temporary);
|
|
20825
20980
|
}
|
|
20826
20981
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next))
|
|
@@ -20839,9 +20994,9 @@ function ownsCursorParentHook(profile, hook) {
|
|
|
20839
20994
|
return record2(hook) && typeof hook.command === "string" && commandNamesFile(hook.command, profile.hooks.cursor);
|
|
20840
20995
|
}
|
|
20841
20996
|
function mergeCursorParentHooks(profile, file2, hook) {
|
|
20842
|
-
const target2 =
|
|
20997
|
+
const target2 = existsSync7(file2) ? realpathSync3(file2) : file2;
|
|
20843
20998
|
let current = { version: 1, hooks: {} };
|
|
20844
|
-
if (
|
|
20999
|
+
if (existsSync7(target2)) {
|
|
20845
21000
|
try {
|
|
20846
21001
|
current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
20847
21002
|
} catch {
|
|
@@ -20880,11 +21035,11 @@ function mergeCursorParentHooks(profile, file2, hook) {
|
|
|
20880
21035
|
try {
|
|
20881
21036
|
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20882
21037
|
`, { mode: 384, flag: "wx" });
|
|
20883
|
-
if (
|
|
21038
|
+
if (existsSync7(target2))
|
|
20884
21039
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
20885
21040
|
renameSync2(temporary, target2);
|
|
20886
21041
|
} finally {
|
|
20887
|
-
if (
|
|
21042
|
+
if (existsSync7(temporary))
|
|
20888
21043
|
unlinkSync2(temporary);
|
|
20889
21044
|
}
|
|
20890
21045
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next)) {
|
|
@@ -20893,7 +21048,7 @@ function mergeCursorParentHooks(profile, file2, hook) {
|
|
|
20893
21048
|
return "configured";
|
|
20894
21049
|
}
|
|
20895
21050
|
function removeCursorParentHooks(profile, file2) {
|
|
20896
|
-
if (!
|
|
21051
|
+
if (!existsSync7(file2))
|
|
20897
21052
|
return "unchanged";
|
|
20898
21053
|
const target2 = realpathSync3(file2);
|
|
20899
21054
|
const current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
@@ -20924,7 +21079,7 @@ function removeCursorParentHooks(profile, file2) {
|
|
|
20924
21079
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
20925
21080
|
renameSync2(temporary, target2);
|
|
20926
21081
|
} finally {
|
|
20927
|
-
if (
|
|
21082
|
+
if (existsSync7(temporary))
|
|
20928
21083
|
unlinkSync2(temporary);
|
|
20929
21084
|
}
|
|
20930
21085
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next)) {
|
|
@@ -21146,7 +21301,7 @@ function channelDir(profile, channelId) {
|
|
|
21146
21301
|
return path9.join(channelRoot(profile), uuid3.parse(channelId));
|
|
21147
21302
|
}
|
|
21148
21303
|
function processIdentity2(pid) {
|
|
21149
|
-
return
|
|
21304
|
+
return readProcessIdentities([pid])[0]?.started_identity ?? void 0;
|
|
21150
21305
|
}
|
|
21151
21306
|
function mkdirs(...dirs) {
|
|
21152
21307
|
for (const dir of dirs)
|
|
@@ -21255,7 +21410,7 @@ function channelDeliveryState(profile, channelId, deliveryId) {
|
|
|
21255
21410
|
return "unknown";
|
|
21256
21411
|
if (value.state === "withdrawn")
|
|
21257
21412
|
return "withdrawn";
|
|
21258
|
-
if (typeof value.pid === "number" && typeof value.started_identity === "string" &&
|
|
21413
|
+
if (typeof value.pid === "number" && typeof value.started_identity === "string" && !processIsRunning(value.pid, value.started_identity))
|
|
21259
21414
|
return "unknown";
|
|
21260
21415
|
return "sending";
|
|
21261
21416
|
}
|
|
@@ -21380,7 +21535,7 @@ function acquireWaiter(index) {
|
|
|
21380
21535
|
owner = JSON.parse(fs7.readFileSync(file2, "utf8"));
|
|
21381
21536
|
} catch {
|
|
21382
21537
|
}
|
|
21383
|
-
if (typeof owner.pid === "number" && typeof owner.started_identity === "string" &&
|
|
21538
|
+
if (typeof owner.pid === "number" && typeof owner.started_identity === "string" && processIsRunning(owner.pid, owner.started_identity))
|
|
21384
21539
|
return null;
|
|
21385
21540
|
try {
|
|
21386
21541
|
fs7.renameSync(file2, path9.join(index, `waiter.${randomUUID3()}.stale`));
|
|
@@ -21401,9 +21556,10 @@ function releaseWaiter(index, identity) {
|
|
|
21401
21556
|
}
|
|
21402
21557
|
}
|
|
21403
21558
|
function currentHookOwner() {
|
|
21404
|
-
const owner = hookOwnerProcess(
|
|
21559
|
+
const owner = hookOwnerProcess(readProcessLineage(process.ppid), process.ppid);
|
|
21405
21560
|
return owner ? { pid: owner.pid, started_identity: owner.started_identity } : null;
|
|
21406
21561
|
}
|
|
21562
|
+
var WAITER_OWNER_IDENTITY_RECHECK_MS = 6e4;
|
|
21407
21563
|
async function runClaudeChannelWaiter(profile, input2, emit, options = {}) {
|
|
21408
21564
|
const event = external_exports.object({ session_id: external_exports.uuid() }).loose().parse(input2);
|
|
21409
21565
|
if (!openClaudeChannels(profile, event.session_id).length)
|
|
@@ -21414,15 +21570,22 @@ async function runClaudeChannelWaiter(profile, input2, emit, options = {}) {
|
|
|
21414
21570
|
if (!identity)
|
|
21415
21571
|
return 0;
|
|
21416
21572
|
const deadline = Date.now() + (options.wait_ms ?? 8634e4);
|
|
21573
|
+
const runtime = options.runtime ?? { exists: processExists, identity: processIdentity2 };
|
|
21574
|
+
const recheckMs = options.identity_recheck_ms ?? WAITER_OWNER_IDENTITY_RECHECK_MS;
|
|
21417
21575
|
let lastParentCheck = 0;
|
|
21576
|
+
let lastIdentityCheck = null;
|
|
21418
21577
|
try {
|
|
21419
21578
|
for (; ; ) {
|
|
21420
21579
|
const channels = openClaudeChannels(profile, event.session_id);
|
|
21421
21580
|
if (!channels.length)
|
|
21422
21581
|
return 0;
|
|
21423
|
-
if (Date.now() - lastParentCheck >= 5e3) {
|
|
21582
|
+
if (Date.now() - lastParentCheck >= (options.owner_check_ms ?? 5e3)) {
|
|
21424
21583
|
lastParentCheck = Date.now();
|
|
21425
|
-
const
|
|
21584
|
+
const verify = lastIdentityCheck === null || lastParentCheck - lastIdentityCheck >= recheckMs;
|
|
21585
|
+
if (verify)
|
|
21586
|
+
lastIdentityCheck = lastParentCheck;
|
|
21587
|
+
const running = (pid, identity2) => runtime.exists(pid) && (!verify || runtime.identity(pid) === identity2);
|
|
21588
|
+
const alive = owner ? running(owner.pid, owner.started_identity) : channels.some((channel) => running(channel.claude.parent_pid, channel.claude.parent_started_identity));
|
|
21426
21589
|
if (!alive)
|
|
21427
21590
|
return 0;
|
|
21428
21591
|
}
|
|
@@ -21535,7 +21698,7 @@ async function handleCursorChannelHook(profile, event, emit) {
|
|
|
21535
21698
|
await emitClaimed(claimed, "cursor_hook", (texts) => emit(texts.join("\n\n")));
|
|
21536
21699
|
return true;
|
|
21537
21700
|
}
|
|
21538
|
-
function channelReceiveProcess(script, channelId, executable =
|
|
21701
|
+
function channelReceiveProcess(script, channelId, executable = liveNodeExecutable()) {
|
|
21539
21702
|
const args = [script, "--channel", uuid3.parse(channelId)];
|
|
21540
21703
|
return { executable, args, windows_start_process_argument_list: process.platform === "win32" ? windowsStartProcessArgumentList(args) : null };
|
|
21541
21704
|
}
|
|
@@ -21638,21 +21801,6 @@ async function runChannelReceiveMain(profile, argv = process.argv.slice(2), scri
|
|
|
21638
21801
|
}
|
|
21639
21802
|
}
|
|
21640
21803
|
|
|
21641
|
-
// ../../node_modules/aiterm-steer-delivery/dist/setup-node.js
|
|
21642
|
-
import { accessSync as accessSync3, constants as constants3 } from "node:fs";
|
|
21643
|
-
function setupNodeExecutable(executable = process.execPath) {
|
|
21644
|
-
const brew = /^(.*)\/Cellar\/(node(?:@\d+)?)\/[^/]+\/bin\/node$/.exec(executable);
|
|
21645
|
-
if (!brew)
|
|
21646
|
-
return executable;
|
|
21647
|
-
const node2 = `${brew[1]}/opt/${brew[2]}/bin/node`;
|
|
21648
|
-
try {
|
|
21649
|
-
accessSync3(node2, constants3.X_OK);
|
|
21650
|
-
} catch {
|
|
21651
|
-
throw new SetupError("node_runtime_unavailable", "Homebrew\u306ENode\u8D77\u52D5\u5148\u3092\u5B9F\u884C\u3067\u304D\u307E\u305B\u3093\u3002Node\u306E\u5C0E\u5165\u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044");
|
|
21652
|
-
}
|
|
21653
|
-
return node2;
|
|
21654
|
-
}
|
|
21655
|
-
|
|
21656
21804
|
// ../../node_modules/aiterm-steer-delivery/dist/aiterm-provider.js
|
|
21657
21805
|
import { spawn as spawn3 } from "node:child_process";
|
|
21658
21806
|
import * as fs8 from "node:fs";
|
|
@@ -21677,7 +21825,7 @@ function findAitermDeliveryProvider(options = {}) {
|
|
|
21677
21825
|
const env = options.env ?? process.env;
|
|
21678
21826
|
const explicit = options.cli ?? env.AITERM_PARENT_DELIVERY_CLI;
|
|
21679
21827
|
if (explicit) {
|
|
21680
|
-
return path10.isAbsolute(explicit) && isFile(explicit) ? { node: options.node ??
|
|
21828
|
+
return path10.isAbsolute(explicit) && isFile(explicit) ? { node: options.node ?? liveNodeExecutable(), cli: explicit, version: null, source: "explicit" } : null;
|
|
21681
21829
|
}
|
|
21682
21830
|
const home2 = options.home ?? env.HOME ?? os2.homedir();
|
|
21683
21831
|
try {
|
|
@@ -21691,14 +21839,14 @@ function findAitermDeliveryProvider(options = {}) {
|
|
|
21691
21839
|
if (process.platform === "win32") {
|
|
21692
21840
|
const cli = path10.join(directory2, "node_modules", "aiterm-mcp", "dist", "parent-delivery-cli.js");
|
|
21693
21841
|
if (isFile(path10.join(directory2, "aiterm-parent-delivery.cmd")) && isFile(cli))
|
|
21694
|
-
return { node: options.node ??
|
|
21842
|
+
return { node: options.node ?? liveNodeExecutable(), cli, version: null, source: "path" };
|
|
21695
21843
|
continue;
|
|
21696
21844
|
}
|
|
21697
21845
|
const shim = path10.join(directory2, "aiterm-parent-delivery");
|
|
21698
21846
|
if (!isFile(shim))
|
|
21699
21847
|
continue;
|
|
21700
21848
|
try {
|
|
21701
|
-
return { node: options.node ??
|
|
21849
|
+
return { node: options.node ?? liveNodeExecutable(), cli: fs8.realpathSync(shim), version: null, source: "path" };
|
|
21702
21850
|
} catch {
|
|
21703
21851
|
}
|
|
21704
21852
|
}
|
|
@@ -22074,6 +22222,7 @@ export {
|
|
|
22074
22222
|
CodexDeliveryError,
|
|
22075
22223
|
withoutBom,
|
|
22076
22224
|
setupNodeExecutable,
|
|
22225
|
+
liveNodeExecutable,
|
|
22077
22226
|
safeParse,
|
|
22078
22227
|
string2 as string,
|
|
22079
22228
|
number2 as number,
|
package/dist/cli.mjs
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
isCursorMcpClient,
|
|
33
33
|
iso_exports,
|
|
34
34
|
literal,
|
|
35
|
+
liveNodeExecutable,
|
|
35
36
|
looseObject,
|
|
36
37
|
mergeClaudeParentHooks,
|
|
37
38
|
mergeCursorParentHooks,
|
|
@@ -56,7 +57,7 @@ import {
|
|
|
56
57
|
waitProcessCommandLine,
|
|
57
58
|
withCodexReceiver,
|
|
58
59
|
withdrawFromChannel
|
|
59
|
-
} from "./chunks/chunk-
|
|
60
|
+
} from "./chunks/chunk-XTKJLDHY.mjs";
|
|
60
61
|
|
|
61
62
|
// ../../node_modules/qrcode/lib/can-promise.js
|
|
62
63
|
var require_can_promise = __commonJS({
|
|
@@ -11883,7 +11884,7 @@ function writeConfig(config) {
|
|
|
11883
11884
|
|
|
11884
11885
|
// src/daemon-launch.ts
|
|
11885
11886
|
import { spawn, spawnSync } from "node:child_process";
|
|
11886
|
-
import { closeSync, openSync } from "node:fs";
|
|
11887
|
+
import { appendFileSync, closeSync, openSync } from "node:fs";
|
|
11887
11888
|
import { join as join2, resolve } from "node:path";
|
|
11888
11889
|
function windowsDaemonLaunchScript(executable, entry, cwd, environment) {
|
|
11889
11890
|
const env = Object.fromEntries(["APPROVAL_BOX_HOME", "HOME", "USERPROFILE", "APPDATA", "LOCALAPPDATA", "PATH", "CODEX_HOME", "GROK_HOME", "CODEX_BIN"].flatMap((key) => environment[key] === void 0 ? [] : [[key, environment[key]]]));
|
|
@@ -11900,9 +11901,20 @@ function launchDaemon(executable, entry, cwd) {
|
|
|
11900
11901
|
if (result.error || result.status !== 0 || !/^\s*\d+\s*$/.test(result.stdout ?? "")) throw new Error(`Windows\u306E\u5E38\u99D0\u8D77\u52D5\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF08${result.error?.message ?? `exit ${result.status}`}\uFF09`);
|
|
11901
11902
|
return;
|
|
11902
11903
|
}
|
|
11903
|
-
const
|
|
11904
|
+
const file = join2(cwd, "daemon.log");
|
|
11905
|
+
const log = openSync(file, "a", 384);
|
|
11904
11906
|
try {
|
|
11905
|
-
spawn(executable, [entry, "daemon"], { cwd, detached: true, stdio: ["ignore", "ignore", log], windowsHide: true })
|
|
11907
|
+
const child = spawn(executable, [entry, "daemon"], { cwd, detached: true, stdio: ["ignore", "ignore", log], windowsHide: true });
|
|
11908
|
+
child.on("error", (error) => {
|
|
11909
|
+
const line = `approval-box: \u914D\u9001\u30C7\u30FC\u30E2\u30F3\u3092\u8D77\u52D5\u3067\u304D\u307E\u305B\u3093\uFF08DAEMON_LAUNCH_FAILED\uFF09: ${executable}: ${error.message}
|
|
11910
|
+
`;
|
|
11911
|
+
try {
|
|
11912
|
+
appendFileSync(file, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}`, { mode: 384 });
|
|
11913
|
+
} catch {
|
|
11914
|
+
}
|
|
11915
|
+
process.stderr.write(line);
|
|
11916
|
+
});
|
|
11917
|
+
child.unref();
|
|
11906
11918
|
} finally {
|
|
11907
11919
|
closeSync(log);
|
|
11908
11920
|
}
|
|
@@ -12030,6 +12042,9 @@ function shouldReplaceDaemon(runningEntry, myEntry) {
|
|
|
12030
12042
|
for (let i = 0; i < 3; i++) if (running[i] !== mine[i]) return running[i] < mine[i];
|
|
12031
12043
|
return true;
|
|
12032
12044
|
}
|
|
12045
|
+
function daemonNode(executable = process.execPath, exists = existsSync3) {
|
|
12046
|
+
return liveNodeExecutable(executable, exists);
|
|
12047
|
+
}
|
|
12033
12048
|
function ensureDaemon() {
|
|
12034
12049
|
try {
|
|
12035
12050
|
if (!readConfig()?.token) return;
|
|
@@ -12042,7 +12057,7 @@ function ensureDaemon() {
|
|
|
12042
12057
|
}
|
|
12043
12058
|
}
|
|
12044
12059
|
mkdirSync3(stateRoot(), { recursive: true, mode: 448 });
|
|
12045
|
-
launchDaemon(
|
|
12060
|
+
launchDaemon(daemonNode(), runtimeEntry("cli"), stateRoot());
|
|
12046
12061
|
} catch (error) {
|
|
12047
12062
|
process.stderr.write(`approval-box: \u914D\u9001\u30C7\u30FC\u30E2\u30F3\u3092\u8D77\u52D5\u3067\u304D\u307E\u305B\u3093: ${error.message}
|
|
12048
12063
|
`);
|
|
@@ -15907,7 +15922,7 @@ function claudeChannelIsCurrent(profile, channelId, parent) {
|
|
|
15907
15922
|
}
|
|
15908
15923
|
|
|
15909
15924
|
// src/version.ts
|
|
15910
|
-
var VERSION = true ? "0.1.
|
|
15925
|
+
var VERSION = true ? "0.1.25" : "0.0.0-dev";
|
|
15911
15926
|
function osName() {
|
|
15912
15927
|
return process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : process.platform;
|
|
15913
15928
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "approval-box",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "Approval Box connector: lets Claude Code, Codex, Cursor and Grok ask you for a decision, and steers your answer back into the same session.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://approval-box.kitepon.dev",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
33
33
|
"@types/node": "^25.9.1",
|
|
34
34
|
"@types/qrcode": "^1.5.5",
|
|
35
|
-
"aiterm-steer-delivery": "0.4.
|
|
35
|
+
"aiterm-steer-delivery": "0.4.6",
|
|
36
36
|
"esbuild": "^0.28.2",
|
|
37
37
|
"qrcode": "^1.5.4",
|
|
38
38
|
"typescript": "^6.0.3",
|