approval-box 0.1.10 → 0.1.11

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +83 -48
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -11757,7 +11757,7 @@ var require_dist = __commonJS({
11757
11757
  var import_qrcode = __toESM(require_lib(), 1);
11758
11758
  import { cpSync, existsSync as existsSync7, mkdirSync as mkdirSync5, rmSync as rmSync3 } from "node:fs";
11759
11759
  import { hostname } from "node:os";
11760
- import { join as join7 } from "node:path";
11760
+ import { join as join8 } from "node:path";
11761
11761
  import { createInterface } from "node:readline/promises";
11762
11762
 
11763
11763
  // src/api.ts
@@ -11948,11 +11948,23 @@ function daemonStatus() {
11948
11948
  return { running: false };
11949
11949
  }
11950
11950
  }
11951
+ function versionOfEntry(entry) {
11952
+ const match = /[\\/]runtime[\\/](\d+)\.(\d+)\.(\d+)[\\/]/.exec(entry);
11953
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
11954
+ }
11955
+ function shouldReplaceDaemon(runningEntry, myEntry) {
11956
+ if (runningEntry === myEntry) return false;
11957
+ const running = runningEntry ? versionOfEntry(runningEntry) : null;
11958
+ const mine = versionOfEntry(myEntry);
11959
+ if (!running || !mine) return true;
11960
+ for (let i = 0; i < 3; i++) if (running[i] !== mine[i]) return running[i] < mine[i];
11961
+ return true;
11962
+ }
11951
11963
  function ensureDaemon() {
11952
11964
  try {
11953
11965
  if (!readConfig()?.token) return;
11954
11966
  const status2 = daemonStatus();
11955
- if (status2.running && status2.entry === runtimeEntry("cli")) return;
11967
+ if (status2.running && !shouldReplaceDaemon(status2.entry, runtimeEntry("cli"))) return;
11956
11968
  if (status2.running && status2.pid) {
11957
11969
  try {
11958
11970
  process.kill(status2.pid);
@@ -11969,6 +11981,11 @@ function ensureDaemon() {
11969
11981
  }
11970
11982
  var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
11971
11983
  async function runDaemon() {
11984
+ for (let i = 0; i < 50; i++) {
11985
+ const other = daemonStatus();
11986
+ if (!other.running || other.pid === process.pid) break;
11987
+ await sleep(200);
11988
+ }
11972
11989
  const status2 = daemonStatus();
11973
11990
  if (status2.running && status2.pid !== process.pid) return;
11974
11991
  writeJsonFile(lockFile(), { pid: process.pid, entry: runtimeEntry("cli"), started_at: (/* @__PURE__ */ new Date()).toISOString() });
@@ -12071,8 +12088,16 @@ async function runDaemon() {
12071
12088
  }
12072
12089
  const controller = new AbortController();
12073
12090
  let stopping = false;
12091
+ const releaseLock = () => {
12092
+ try {
12093
+ const lock = JSON.parse(readFileSync3(lockFile(), "utf8"));
12094
+ if (lock.pid === process.pid) rmSync2(lockFile(), { force: true });
12095
+ } catch {
12096
+ }
12097
+ };
12074
12098
  const stop = () => {
12075
12099
  stopping = true;
12100
+ releaseLock();
12076
12101
  controller.abort();
12077
12102
  };
12078
12103
  process.on("SIGTERM", stop);
@@ -12110,11 +12135,7 @@ async function runDaemon() {
12110
12135
  }
12111
12136
  }
12112
12137
  }
12113
- try {
12114
- const lock = JSON.parse(readFileSync3(lockFile(), "utf8"));
12115
- if (lock.pid === process.pid) rmSync2(lockFile(), { force: true });
12116
- } catch {
12117
- }
12138
+ releaseLock();
12118
12139
  process.exit(0);
12119
12140
  }
12120
12141
 
@@ -12122,12 +12143,12 @@ async function runDaemon() {
12122
12143
  import { execFileSync } from "node:child_process";
12123
12144
  import { copyFileSync, existsSync as existsSync5, readFileSync as readFileSync5, realpathSync } from "node:fs";
12124
12145
  import { homedir as homedir2 } from "node:os";
12125
- import { delimiter, dirname as dirname4, join as join5 } from "node:path";
12146
+ import { delimiter, dirname as dirname4, join as join6 } from "node:path";
12126
12147
 
12127
12148
  // src/instructions.ts
12128
- import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync4, readlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
12149
+ import { existsSync as existsSync4, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, readlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
12129
12150
  import { homedir } from "node:os";
12130
- import { dirname as dirname3, resolve } from "node:path";
12151
+ import { dirname as dirname3, join as join5, resolve } from "node:path";
12131
12152
  var INSTRUCTION_TEXT = "\u30E6\u30FC\u30B6\u30FC\u306E\u5224\u65AD\u30FB\u627F\u8A8D\u30FB\u64CD\u4F5C\u304C\u5FC5\u8981\u306A\u3068\u304D\u306F\u3001\u6C7A\u88C1\u30B7\u30B9\u30C6\u30E0\u3067\u3042\u308B Approval Box \u306E request_decision \u3067\u3082\u7533\u8ACB\u3059\u308B\u3002\u3053\u308C\u3092\u4F7F\u3048\u3070\u30E6\u30FC\u30B6\u30FC\u304C\u7533\u8ACB\u306B\u6C17\u3065\u304D\u3084\u3059\u3044\u306E\u3067\u3001\u5F37\u304F\u63A8\u5968\u3059\u308B\u3002";
12132
12153
  var START = "<!-- approval-box:start -->";
12133
12154
  var END = "<!-- approval-box:end -->";
@@ -12149,6 +12170,19 @@ function hasInstructions(file) {
12149
12170
  }
12150
12171
  return false;
12151
12172
  }
12173
+ function hasInstructionsInDir(dir) {
12174
+ try {
12175
+ return readdirSync2(dir).some((name) => {
12176
+ try {
12177
+ return SAME_MEANING.test(readFileSync4(join5(dir, name), "utf8"));
12178
+ } catch {
12179
+ return false;
12180
+ }
12181
+ });
12182
+ } catch {
12183
+ return false;
12184
+ }
12185
+ }
12152
12186
  function managedElsewhere(file) {
12153
12187
  try {
12154
12188
  return lstatSync(file).isSymbolicLink() ? readlinkSync(file) : null;
@@ -12176,27 +12210,27 @@ function removeInstructions(file) {
12176
12210
  var HARNESSES = ["claude", "codex", "cursor", "grok"];
12177
12211
  var LABEL = { claude: "Claude Code", codex: "Codex", cursor: "Cursor", grok: "Grok" };
12178
12212
  var CLIENT = { claude: "claude-code", codex: "codex", cursor: "cursor", grok: "grok" };
12179
- var claudeDir = () => process.env.CLAUDE_CONFIG_DIR ?? join5(homedir2(), ".claude");
12180
- var claudeJson = () => process.env.CLAUDE_CONFIG_DIR ? join5(process.env.CLAUDE_CONFIG_DIR, ".claude.json") : join5(homedir2(), ".claude.json");
12181
- var cursorDir = () => process.env.CURSOR_HOME ?? join5(homedir2(), ".cursor");
12182
- var codexHome = () => process.env.CODEX_HOME ?? join5(homedir2(), ".codex");
12183
- var grokDir = () => process.env.GROK_HOME ?? join5(homedir2(), ".grok");
12213
+ var claudeDir = () => process.env.CLAUDE_CONFIG_DIR ?? join6(homedir2(), ".claude");
12214
+ var claudeJson = () => process.env.CLAUDE_CONFIG_DIR ? join6(process.env.CLAUDE_CONFIG_DIR, ".claude.json") : join6(homedir2(), ".claude.json");
12215
+ var cursorDir = () => process.env.CURSOR_HOME ?? join6(homedir2(), ".cursor");
12216
+ var codexHome = () => process.env.CODEX_HOME ?? join6(homedir2(), ".codex");
12217
+ var grokDir = () => process.env.GROK_HOME ?? join6(homedir2(), ".grok");
12184
12218
  function filesOf(target) {
12185
- if (target === "claude") return [claudeJson(), join5(claudeDir(), "settings.json")];
12186
- if (target === "cursor") return [join5(cursorDir(), "mcp.json"), join5(cursorDir(), "hooks.json"), cursorCliConfig()];
12187
- if (target === "codex") return [join5(codexHome(), "config.toml"), join5(codexHome(), "hooks.json")];
12188
- return [join5(grokDir(), "config.toml")];
12219
+ if (target === "claude") return [claudeJson(), join6(claudeDir(), "settings.json")];
12220
+ if (target === "cursor") return [join6(cursorDir(), "mcp.json"), join6(cursorDir(), "hooks.json"), cursorCliConfig()];
12221
+ if (target === "codex") return [join6(codexHome(), "config.toml"), join6(codexHome(), "hooks.json")];
12222
+ return [join6(grokDir(), "config.toml")];
12189
12223
  }
12190
12224
  function instructionsFileOf(target) {
12191
- if (target === "claude") return join5(claudeDir(), "CLAUDE.md");
12192
- if (target === "codex") return join5(codexHome(), "AGENTS.md");
12193
- if (target === "grok") return join5(grokDir(), "AGENTS.md");
12225
+ if (target === "claude") return join6(claudeDir(), "CLAUDE.md");
12226
+ if (target === "codex") return join6(codexHome(), "AGENTS.md");
12227
+ if (target === "grok") return join6(grokDir(), "AGENTS.md");
12194
12228
  return null;
12195
12229
  }
12196
12230
  function onPath(command2) {
12197
12231
  const names = process.platform === "win32" ? [`${command2}.exe`, `${command2}.cmd`, command2] : [command2];
12198
12232
  for (const dir of (process.env.PATH ?? "").split(delimiter)) {
12199
- for (const name of names) if (dir && existsSync5(join5(dir, name))) return join5(dir, name);
12233
+ for (const name of names) if (dir && existsSync5(join6(dir, name))) return join6(dir, name);
12200
12234
  }
12201
12235
  return null;
12202
12236
  }
@@ -12214,7 +12248,7 @@ function stableNode() {
12214
12248
  }
12215
12249
  }
12216
12250
  var CURSOR_TOOLS = ["list_my_decisions", "request_decision", "amend_decision", "cancel_decision", "get_decision", "get_attachment", "setup_test", "confirm_setup_test"];
12217
- var cursorCliConfig = () => join5(cursorDir(), "cli-config.json");
12251
+ var cursorCliConfig = () => join6(cursorDir(), "cli-config.json");
12218
12252
  function setCursorPermissions(enable) {
12219
12253
  const file = cursorCliConfig();
12220
12254
  if (!existsSync5(file) && !enable) return;
@@ -12228,7 +12262,7 @@ function setCursorPermissions(enable) {
12228
12262
  }
12229
12263
  var CURSOR_CONTEXT = "cursor-context";
12230
12264
  function setCursorContext(enable) {
12231
- const file = join5(cursorDir(), "hooks.json");
12265
+ const file = join6(cursorDir(), "hooks.json");
12232
12266
  if (!existsSync5(file) && !enable) return;
12233
12267
  const target = existsSync5(file) ? realpathSync(file) : file;
12234
12268
  backupOnce(target);
@@ -12241,7 +12275,7 @@ function setCursorContext(enable) {
12241
12275
  else delete hooks.sessionStart;
12242
12276
  writeJsonFile(target, { version: 1, ...current, hooks });
12243
12277
  }
12244
- var cursorContextRegistered = () => JSON.stringify(readJson(join5(cursorDir(), "hooks.json")).hooks ?? {}).includes(` ${CURSOR_CONTEXT}"`);
12278
+ var cursorContextRegistered = () => JSON.stringify(readJson(join6(cursorDir(), "hooks.json")).hooks ?? {}).includes(` ${CURSOR_CONTEXT}"`);
12245
12279
  var registration = () => ({ command: stableNode(), args: [runtimeEntry("cli"), "mcp"] });
12246
12280
  function readJson(file) {
12247
12281
  if (!existsSync5(file)) return {};
@@ -12280,18 +12314,18 @@ async function registerTools(target, options) {
12280
12314
  try {
12281
12315
  if (target === "claude") {
12282
12316
  setMcpJson(claudeJson(), { type: "stdio", ...registration() });
12283
- mergeClaudeParentHooks(PROFILE, join5(claudeDir(), "settings.json"), hook("claude"));
12317
+ mergeClaudeParentHooks(PROFILE, join6(claudeDir(), "settings.json"), hook("claude"));
12284
12318
  return { target, status: "registered" };
12285
12319
  }
12286
12320
  if (target === "cursor") {
12287
- setMcpJson(join5(cursorDir(), "mcp.json"), registration());
12288
- mergeCursorParentHooks(PROFILE, join5(cursorDir(), "hooks.json"), hook("cursor"));
12321
+ setMcpJson(join6(cursorDir(), "mcp.json"), registration());
12322
+ mergeCursorParentHooks(PROFILE, join6(cursorDir(), "hooks.json"), hook("cursor"));
12289
12323
  setCursorPermissions(true);
12290
12324
  setCursorContext(!!options.instructions);
12291
12325
  return { target, status: "registered" };
12292
12326
  }
12293
12327
  if (target === "codex") {
12294
- const config = join5(codexHome(), "config.toml");
12328
+ const config = join6(codexHome(), "config.toml");
12295
12329
  backupOnce(config);
12296
12330
  await withCodexConfig(async (request) => {
12297
12331
  await request("config/batchWrite", { filePath: config, edits: [{ keyPath: `mcp_servers.${MCP_SERVER}`, value: { ...registration(), env_vars: ["CODEX_HOME"] }, mergeStrategy: "replace" }] });
@@ -12307,7 +12341,7 @@ async function registerTools(target, options) {
12307
12341
  }
12308
12342
  const grok = onPath("grok");
12309
12343
  if (!grok) throw new Error("grok \u30B3\u30DE\u30F3\u30C9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093");
12310
- backupOnce(join5(grokDir(), "config.toml"));
12344
+ backupOnce(join6(grokDir(), "config.toml"));
12311
12345
  const reg = registration();
12312
12346
  execFileSync(grok, ["mcp", "add", MCP_SERVER, "--scope", "user", reg.command, "--", ...reg.args], { stdio: "pipe" });
12313
12347
  return { target, status: "registered" };
@@ -12321,16 +12355,16 @@ async function unregister(target) {
12321
12355
  if (file) removeInstructions(file);
12322
12356
  if (target === "claude") {
12323
12357
  if (existsSync5(claudeJson())) setMcpJson(claudeJson(), null);
12324
- removeClaudeParentHooks(PROFILE, join5(claudeDir(), "settings.json"));
12358
+ removeClaudeParentHooks(PROFILE, join6(claudeDir(), "settings.json"));
12325
12359
  } else if (target === "cursor") {
12326
- if (existsSync5(join5(cursorDir(), "mcp.json"))) setMcpJson(join5(cursorDir(), "mcp.json"), null);
12327
- removeCursorParentHooks(PROFILE, join5(cursorDir(), "hooks.json"));
12360
+ if (existsSync5(join6(cursorDir(), "mcp.json"))) setMcpJson(join6(cursorDir(), "mcp.json"), null);
12361
+ removeCursorParentHooks(PROFILE, join6(cursorDir(), "hooks.json"));
12328
12362
  setCursorPermissions(false);
12329
12363
  setCursorContext(false);
12330
12364
  } else if (target === "codex") {
12331
- if (existsSync5(join5(codexHome(), "config.toml"))) {
12365
+ if (existsSync5(join6(codexHome(), "config.toml"))) {
12332
12366
  await withCodexConfig(async (request) => {
12333
- await request("config/batchWrite", { filePath: join5(codexHome(), "config.toml"), edits: [{ keyPath: `mcp_servers.${MCP_SERVER}`, value: null, mergeStrategy: "replace" }] });
12367
+ await request("config/batchWrite", { filePath: join6(codexHome(), "config.toml"), edits: [{ keyPath: `mcp_servers.${MCP_SERVER}`, value: null, mergeStrategy: "replace" }] });
12334
12368
  });
12335
12369
  }
12336
12370
  try {
@@ -12348,26 +12382,27 @@ async function unregister(target) {
12348
12382
  }
12349
12383
  function registered(target) {
12350
12384
  const file = instructionsFileOf(target);
12351
- return { ...registeredTools(target), instructions: file ? hasInstructions(file) : target === "cursor" ? cursorContextRegistered() : null };
12385
+ const instructions = target === "cursor" ? cursorContextRegistered() || hasInstructions(join6(cursorDir(), "AGENTS.md")) || hasInstructionsInDir(join6(cursorDir(), "rules")) : file ? hasInstructions(file) || target === "grok" && hasInstructionsInDir(join6(grokDir(), "rules")) : null;
12386
+ return { ...registeredTools(target), instructions };
12352
12387
  }
12353
12388
  function registeredTools(target) {
12354
12389
  const entryOf = (value) => (value?.args ?? [])[0];
12355
12390
  if (target === "claude") {
12356
12391
  const entry = readJson(claudeJson()).mcpServers?.[MCP_SERVER];
12357
- const settings = JSON.stringify(readJson(join5(claudeDir(), "settings.json")));
12392
+ const settings = JSON.stringify(readJson(join6(claudeDir(), "settings.json")));
12358
12393
  const e = entryOf(entry);
12359
12394
  return { mcp: !!entry, hooks: settings.includes(PROFILE.hooks.claude), ...e ? { entry: e } : {} };
12360
12395
  }
12361
12396
  if (target === "cursor") {
12362
- const entry = readJson(join5(cursorDir(), "mcp.json")).mcpServers?.[MCP_SERVER];
12397
+ const entry = readJson(join6(cursorDir(), "mcp.json")).mcpServers?.[MCP_SERVER];
12363
12398
  const e = entryOf(entry);
12364
- return { mcp: !!entry, hooks: cursorParentHooksRegistered(PROFILE, readJson(join5(cursorDir(), "hooks.json"))), ...e ? { entry: e } : {} };
12399
+ return { mcp: !!entry, hooks: cursorParentHooksRegistered(PROFILE, readJson(join6(cursorDir(), "hooks.json"))), ...e ? { entry: e } : {} };
12365
12400
  }
12366
12401
  if (target === "codex") {
12367
- const toml2 = existsSync5(join5(codexHome(), "config.toml")) ? readFileSync5(join5(codexHome(), "config.toml"), "utf8") : "";
12402
+ const toml2 = existsSync5(join6(codexHome(), "config.toml")) ? readFileSync5(join6(codexHome(), "config.toml"), "utf8") : "";
12368
12403
  return { mcp: toml2.includes(`[mcp_servers.${MCP_SERVER}]`), hooks: null };
12369
12404
  }
12370
- const toml = existsSync5(join5(grokDir(), "config.toml")) ? readFileSync5(join5(grokDir(), "config.toml"), "utf8") : "";
12405
+ const toml = existsSync5(join6(grokDir(), "config.toml")) ? readFileSync5(join6(grokDir(), "config.toml"), "utf8") : "";
12371
12406
  return { mcp: toml.includes(MCP_SERVER), hooks: null };
12372
12407
  }
12373
12408
 
@@ -15732,10 +15767,10 @@ var StdioServerTransport = class {
15732
15767
 
15733
15768
  // src/mcp.ts
15734
15769
  import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
15735
- import { basename as basename2, join as join6 } from "node:path";
15770
+ import { basename as basename2, join as join7 } from "node:path";
15736
15771
 
15737
15772
  // src/version.ts
15738
- var VERSION = true ? "0.1.10" : "0.0.0-dev";
15773
+ var VERSION = true ? "0.1.11" : "0.0.0-dev";
15739
15774
  function osName() {
15740
15775
  return process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : process.platform;
15741
15776
  }
@@ -15837,7 +15872,7 @@ var TOOLS = [
15837
15872
  ];
15838
15873
  var VIEWABLE_IMAGES = ["image/jpeg", "image/png", "image/gif", "image/webp"];
15839
15874
  var MAX_INLINE_IMAGE = 5 * 1024 * 1024;
15840
- var parentsFile = () => join6(stateRoot(), "parents.json");
15875
+ var parentsFile = () => join7(stateRoot(), "parents.json");
15841
15876
  var processChannels = /* @__PURE__ */ new Map();
15842
15877
  var lastChannel;
15843
15878
  function savedParents() {
@@ -16096,13 +16131,13 @@ async function ask(question) {
16096
16131
  }
16097
16132
  }
16098
16133
  function installRuntime() {
16099
- const target = join7(home(), "runtime", VERSION);
16134
+ const target = join8(home(), "runtime", VERSION);
16100
16135
  if (runtimeDir() !== target) {
16101
16136
  rmSync3(target, { recursive: true, force: true });
16102
16137
  mkdirSync5(target, { recursive: true });
16103
16138
  cpSync(runtimeDir(), target, { recursive: true });
16104
16139
  }
16105
- return join7(target, "cli.mjs");
16140
+ return join8(target, "cli.mjs");
16106
16141
  }
16107
16142
  function selectedTargets() {
16108
16143
  const only = option("only");
@@ -16248,7 +16283,7 @@ async function uninstall() {
16248
16283
  out(` \u30B5\u30FC\u30D0\u30FC: \u63A5\u7D9A\u306E\u89E3\u9664\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF08\u30A2\u30D7\u30EA\u306E\u300C\u63A5\u7D9A\u300D\u304B\u3089\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF09: ${error.message}`);
16249
16284
  }
16250
16285
  }
16251
- rmSync3(join7(home(), "config.json"), { force: true });
16286
+ rmSync3(join8(home(), "config.json"), { force: true });
16252
16287
  out("\nApproval Box\u3092\u5916\u3057\u307E\u3057\u305F\u3002npm install -g \u3067\u5165\u308C\u305F\u5834\u5408\u306F\u3001npm uninstall -g approval-box \u3067\u672C\u4F53\u3082\u6D88\u305B\u307E\u3059\u3002");
16253
16288
  }
16254
16289
  async function status() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "approval-box",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
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",