approval-box 0.1.29 → 0.1.31

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.
@@ -2,7 +2,7 @@ import { createRequire as __kbCreateRequire } from 'node:module'; const require
2
2
  import {
3
3
  PROFILE,
4
4
  runClaudeHookMain
5
- } from "./chunks/chunk-GFEMLSCW.mjs";
5
+ } from "./chunks/chunk-ACEZENFU.mjs";
6
6
 
7
7
  // src/hooks/claude.ts
8
8
  await runClaudeHookMain(PROFILE);
@@ -5,7 +5,7 @@ import {
5
5
  handleCursorChannelHook,
6
6
  handleCursorHook,
7
7
  withoutBom
8
- } from "./chunks/chunk-GFEMLSCW.mjs";
8
+ } from "./chunks/chunk-ACEZENFU.mjs";
9
9
 
10
10
  // src/cursor-binding.ts
11
11
  async function bindCursorResult(profile, raw) {
@@ -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-GFEMLSCW.mjs";
5
+ } from "./chunks/chunk-ACEZENFU.mjs";
6
6
 
7
7
  // src/hooks/receive.ts
8
8
  await runChannelReceiveMain(PROFILE);
@@ -22268,8 +22268,10 @@ export {
22268
22268
  PROFILE,
22269
22269
  claudeHookRoot,
22270
22270
  cursorHookRoot,
22271
+ channelRoot,
22271
22272
  CodexDeliveryError,
22272
22273
  withoutBom,
22274
+ processIsRunning,
22273
22275
  setupNodeExecutable,
22274
22276
  liveNodeExecutable,
22275
22277
  safeParse,
package/dist/cli.mjs CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  channelDeliveryState,
17
17
  channelMarker,
18
18
  channelReceiveProcess,
19
+ channelRoot,
19
20
  claudeHookRoot,
20
21
  claudeParentFromRequest,
21
22
  claudeParentHooksRegistered,
@@ -41,6 +42,7 @@ import {
41
42
  openChannel,
42
43
  optional,
43
44
  preprocess,
45
+ processIsRunning,
44
46
  readChannel,
45
47
  record,
46
48
  removeClaudeParentHooks,
@@ -57,7 +59,7 @@ import {
57
59
  waitProcessCommandLine,
58
60
  withCodexReceiver,
59
61
  withdrawFromChannel
60
- } from "./chunks/chunk-GFEMLSCW.mjs";
62
+ } from "./chunks/chunk-ACEZENFU.mjs";
61
63
 
62
64
  // ../../node_modules/qrcode/lib/can-promise.js
63
65
  var require_can_promise = __commonJS({
@@ -11927,7 +11929,7 @@ function requireConfig() {
11927
11929
  if (!config?.token) throw new Error("Approval Box\u306B\u3064\u306A\u304C\u3063\u3066\u3044\u307E\u305B\u3093\u3002npx approval-box setup \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
11928
11930
  return config;
11929
11931
  }
11930
- function writeJsonFile(file, value) {
11932
+ function writeJsonFile(file, value, options = {}) {
11931
11933
  mkdirSync(dirname(file), { recursive: true, mode: 448 });
11932
11934
  const temp = `${file}.${process.pid}.tmp`;
11933
11935
  try {
@@ -11935,10 +11937,12 @@ function writeJsonFile(file, value) {
11935
11937
  `, { mode: 384 });
11936
11938
  renameSync(temp, file);
11937
11939
  } catch (error) {
11938
- try {
11939
- rmSync(temp, { force: true });
11940
- } catch {
11941
- process.stderr.write("approval-box: \u4FDD\u5B58\u306B\u5931\u6557\u3057\u305F\u4E00\u6642\u30D5\u30A1\u30A4\u30EB\u3092\u56DE\u53CE\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\n");
11940
+ if (options.discardTemporaryOnError) {
11941
+ try {
11942
+ rmSync(temp, { force: true });
11943
+ } catch {
11944
+ process.stderr.write("approval-box: \u4FDD\u5B58\u306B\u5931\u6557\u3057\u305F\u4E00\u6642\u30D5\u30A1\u30A4\u30EB\u3092\u56DE\u53CE\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\n");
11945
+ }
11942
11946
  }
11943
11947
  throw error;
11944
11948
  }
@@ -12094,6 +12098,7 @@ function runtimeEntry(kind) {
12094
12098
  var lockFile = () => join5(stateRoot(), "daemon.json");
12095
12099
  var journalFile = () => join5(stateRoot(), "deliveries.json");
12096
12100
  var IDLE_EXIT_MS = 30 * 6e4;
12101
+ var ORPHAN_GRACE_MS = 5 * 6e4;
12097
12102
  function alive(pid) {
12098
12103
  try {
12099
12104
  process.kill(pid, 0);
@@ -12126,6 +12131,31 @@ function shouldReplaceDaemon(runningEntry, myEntry) {
12126
12131
  function daemonNode(executable = process.execPath, exists = existsSync3) {
12127
12132
  return liveNodeExecutable(executable, exists);
12128
12133
  }
12134
+ function receiverOf(channelId, profile = PROFILE, running = processIsRunning) {
12135
+ let claude;
12136
+ try {
12137
+ if (channelClosed(profile, channelId)) return "closed";
12138
+ claude = readChannel(profile, channelId).claude;
12139
+ } catch {
12140
+ return "present";
12141
+ }
12142
+ if (!claude || running(claude.parent_pid, claude.parent_started_identity)) return "present";
12143
+ try {
12144
+ const waiter = JSON.parse(readFileSync3(join5(channelRoot(profile), "claude-sessions", claude.session_id, "waiter.json"), "utf8"));
12145
+ if (typeof waiter.pid === "number" && typeof waiter.started_identity === "string" && running(waiter.pid, waiter.started_identity)) return "present";
12146
+ } catch {
12147
+ }
12148
+ return "gone";
12149
+ }
12150
+ function abandoned(entry, receiver, now = Date.now()) {
12151
+ if (receiver === "present") {
12152
+ delete entry.orphaned_at;
12153
+ return false;
12154
+ }
12155
+ if (receiver === "closed") return true;
12156
+ entry.orphaned_at ??= new Date(now).toISOString();
12157
+ return now - Date.parse(entry.orphaned_at) >= ORPHAN_GRACE_MS;
12158
+ }
12129
12159
  function ensureDaemon() {
12130
12160
  try {
12131
12161
  if (!readConfig()?.token) return;
@@ -12221,8 +12251,14 @@ async function runDaemon() {
12221
12251
  if (current === "emitted") Object.assign(entry, { state: "report", result: "delivered" });
12222
12252
  else if (current === "unknown") Object.assign(entry, { state: "report", result: "unknown", detail: "\u53D7\u3051\u53E3\u306E\u51FA\u529B\u3092\u78BA\u304B\u3081\u3089\u308C\u307E\u305B\u3093\u3067\u3057\u305F" });
12223
12253
  else if (current === null || current === "withdrawn") Object.assign(entry, { state: "report", result: "failed", detail: "\u914D\u9001\u306E\u8A18\u9332\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093" });
12224
- else if (current === "queued" && channelClosed(PROFILE, entry.channel_id)) Object.assign(entry, { state: "report", result: "failed", detail: "\u7533\u8ACB\u3092\u51FA\u3057\u305FAI\u306E\u4F1A\u8A71\u304C\u7D42\u308F\u3063\u3066\u3044\u307E\u3059" });
12225
- else continue;
12254
+ else if (current === "queued") {
12255
+ const before = entry.orphaned_at;
12256
+ const giveUp = abandoned(entry, receiverOf(entry.channel_id));
12257
+ if (entry.orphaned_at !== before) save();
12258
+ if (!giveUp) continue;
12259
+ if (!withdrawFromChannel(PROFILE, entry.channel_id, entry.delivery_id)) continue;
12260
+ Object.assign(entry, { state: "report", result: "failed", detail: "\u7533\u8ACB\u3092\u51FA\u3057\u305FAI\u306E\u4F1A\u8A71\u304C\u7D42\u308F\u3063\u3066\u3044\u307E\u3059" });
12261
+ } else continue;
12226
12262
  save();
12227
12263
  log(`\u914D\u9001 ${id} \u2192 ${entry.result}`);
12228
12264
  await report(id);
@@ -12441,7 +12477,7 @@ function setCursorPermissions(enable) {
12441
12477
  const ours = new Set(CURSOR_TOOLS.map((tool) => `Mcp(${MCP_SERVER}:${tool})`));
12442
12478
  const allow = (permissions.allow ?? []).filter((rule) => !ours.has(rule));
12443
12479
  if (enable) allow.push(...ours);
12444
- writeJsonFile(file, { ...current, permissions: { ...permissions, allow, deny: permissions.deny ?? [] } });
12480
+ writeJsonFile(file, { ...current, permissions: { ...permissions, allow, deny: permissions.deny ?? [] } }, { discardTemporaryOnError: true });
12445
12481
  }
12446
12482
  var CURSOR_CONTEXT = "cursor-context";
12447
12483
  function setCursorContext(enable) {
@@ -12456,7 +12492,7 @@ function setCursorContext(enable) {
12456
12492
  if (enable) rest.push({ command: `${cursorParentHookCommand({ command: stableNode(), script: runtimeEntry("cli") })} ${CURSOR_CONTEXT}`, timeout: 10 });
12457
12493
  if (rest.length) hooks.sessionStart = rest;
12458
12494
  else delete hooks.sessionStart;
12459
- writeJsonFile(target, { version: 1, ...current, hooks });
12495
+ writeJsonFile(target, { version: 1, ...current, hooks }, { discardTemporaryOnError: true });
12460
12496
  }
12461
12497
  var cursorContextRegistered = () => JSON.stringify(readJson(join7(cursorDir(), "hooks.json")).hooks ?? {}).includes(` ${CURSOR_CONTEXT}"`);
12462
12498
  var registration = () => ({ command: stableNode(), args: [runtimeEntry("cli"), "mcp"] });
@@ -12474,7 +12510,7 @@ function setMcpJson(file, value) {
12474
12510
  const servers = { ...current.mcpServers ?? {} };
12475
12511
  if (value) servers[MCP_SERVER] = value;
12476
12512
  else delete servers[MCP_SERVER];
12477
- writeJsonFile(file, { ...current, mcpServers: servers });
12513
+ writeJsonFile(file, { ...current, mcpServers: servers }, { discardTemporaryOnError: true });
12478
12514
  }
12479
12515
  async function withCodexConfig(fn) {
12480
12516
  return withCodexReceiver(PROFILE, { thread_id: "00000000-0000-4000-8000-000000000000", codex_home: codexHome() }, fn);
@@ -16026,7 +16062,7 @@ function claudeChannelIsCurrent(profile, channelId, parent) {
16026
16062
  }
16027
16063
 
16028
16064
  // src/version.ts
16029
- var VERSION = true ? "0.1.29" : "0.0.0-dev";
16065
+ var VERSION = true ? "0.1.31" : "0.0.0-dev";
16030
16066
  function osName() {
16031
16067
  return process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : process.platform;
16032
16068
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "approval-box",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
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",