approval-box 0.1.4 → 0.1.6

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 CHANGED
@@ -14,8 +14,8 @@ npx -y approval-box@latest setup
14
14
 
15
15
  1. `setup` finds the agents on this machine and registers Approval Box (MCP server and hooks). It shows the files it will change and keeps a backup (`*.approval-box-backup`) before writing.
16
16
  PCにあるAIを見つけて登録します。書き換えるファイルを先に見せ、控えを残してから書き換えます。
17
- It also offers to add one short paragraph to each agent's global instructions (`~/.claude/CLAUDE.md`, `$CODEX_HOME/AGENTS.md`, `~/.grok/AGENTS.md`) so the agent also files decisions, approvals and actions with `request_decision`. Cursor reads these from Settings → Rules → User Rules, so setup shows the text to paste. Skip with `--no-instructions`.
18
- AIが毎回読む全体の指示に「判断・承認・操作が要る時は request_decision でも申請する」という一節を足すかを聞きます。Cursor は Settings → Rules → User Rules に貼る一文を案内します。足さない時は `--no-instructions`。
17
+ It also offers to add one short paragraph to each agent's global instructions (`~/.claude/CLAUDE.md`, `$CODEX_HOME/AGENTS.md`, `~/.grok/AGENTS.md`) so the agent also files decisions, approvals and actions with `request_decision`. Cursor does not read a global file, so setup passes the same text through a `sessionStart` hook in `~/.cursor/hooks.json`. Skip with `--no-instructions`.
18
+ AIが毎回読む全体の指示に「判断・承認・操作が要る時は request_decision でも申請する」という一節を足すかを聞きます。Cursor はファイルから読まないので、会話の始まりのhook(`~/.cursor/hooks.json` の sessionStart)で渡します。足さない時は `--no-instructions`。
19
19
  2. Scan the QR code or enter the code in “Add device” in the app or web.
20
20
  画面のQRコードかコードを、アプリかWeb版の「端末を追加」で読み取ります。
21
21
  3. Tell your agent: `Approval Boxのsetup_testを実行して` (or “run Approval Box setup_test”). Answer the test request; when the answer reaches the agent, you are ready.
@@ -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-EZ7CZDGK.mjs";
5
+ } from "./chunks/chunk-LEWADASG.mjs";
6
6
 
7
7
  // src/hooks/claude.ts
8
8
  await runClaudeHookMain(PROFILE);
@@ -2,7 +2,7 @@ import { createRequire as __kbCreateRequire } from 'node:module'; const require
2
2
  import {
3
3
  PROFILE,
4
4
  runCodexHookMain
5
- } from "./chunks/chunk-EZ7CZDGK.mjs";
5
+ } from "./chunks/chunk-LEWADASG.mjs";
6
6
 
7
7
  // src/hooks/codex.ts
8
8
  await runCodexHookMain(PROFILE, process.argv[2]);
@@ -2,7 +2,7 @@ import { createRequire as __kbCreateRequire } from 'node:module'; const require
2
2
  import {
3
3
  PROFILE,
4
4
  runCursorHookMain
5
- } from "./chunks/chunk-EZ7CZDGK.mjs";
5
+ } from "./chunks/chunk-LEWADASG.mjs";
6
6
 
7
7
  // src/hooks/cursor.ts
8
8
  await runCursorHookMain(PROFILE);
@@ -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-EZ7CZDGK.mjs";
5
+ } from "./chunks/chunk-LEWADASG.mjs";
6
6
 
7
7
  // src/hooks/receive.ts
8
8
  await runChannelReceiveMain(PROFILE);
@@ -21949,6 +21949,7 @@ export {
21949
21949
  waitProcessCommandLine,
21950
21950
  mergeClaudeParentHooks,
21951
21951
  removeClaudeParentHooks,
21952
+ cursorParentHookCommand,
21952
21953
  mergeCursorParentHooks,
21953
21954
  removeCursorParentHooks,
21954
21955
  openChannel,
package/dist/cli.mjs CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  codexParentFromRequest,
21
21
  configureCodexSteer,
22
22
  cursorHookRoot,
23
+ cursorParentHookCommand,
23
24
  cursorParentHooksRegistered,
24
25
  custom,
25
26
  discriminatedUnion,
@@ -51,7 +52,7 @@ import {
51
52
  verifyCursorParent,
52
53
  waitProcessCommandLine,
53
54
  withCodexReceiver
54
- } from "./chunks/chunk-EZ7CZDGK.mjs";
55
+ } from "./chunks/chunk-LEWADASG.mjs";
55
56
 
56
57
  // ../../node_modules/qrcode/lib/can-promise.js
57
58
  var require_can_promise = __commonJS({
@@ -12048,7 +12049,7 @@ async function runDaemon() {
12048
12049
 
12049
12050
  // src/harness.ts
12050
12051
  import { execFileSync } from "node:child_process";
12051
- import { copyFileSync, existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
12052
+ import { copyFileSync, existsSync as existsSync4, readFileSync as readFileSync4, realpathSync } from "node:fs";
12052
12053
  import { homedir } from "node:os";
12053
12054
  import { delimiter, dirname as dirname4, join as join4 } from "node:path";
12054
12055
 
@@ -12136,6 +12137,22 @@ function setCursorPermissions(enable) {
12136
12137
  if (enable) allow.push(...ours);
12137
12138
  writeJsonFile(file, { ...current, permissions: { ...permissions, allow, deny: permissions.deny ?? [] } });
12138
12139
  }
12140
+ var CURSOR_CONTEXT = "cursor-context";
12141
+ function setCursorContext(enable) {
12142
+ const file = join4(cursorDir(), "hooks.json");
12143
+ if (!existsSync4(file) && !enable) return;
12144
+ const target = existsSync4(file) ? realpathSync(file) : file;
12145
+ backupOnce(target);
12146
+ const current = existsSync4(target) ? readJson(target) : { version: 1 };
12147
+ const hooks = { ...current.hooks ?? {} };
12148
+ const ours = (entry) => typeof entry?.command === "string" && entry.command.includes(MCP_SERVER) && entry.command.endsWith(` ${CURSOR_CONTEXT}`);
12149
+ const rest = (hooks.sessionStart ?? []).filter((entry) => !ours(entry));
12150
+ if (enable) rest.push({ command: `${cursorParentHookCommand({ command: stableNode(), script: runtimeEntry("cli") })} ${CURSOR_CONTEXT}`, timeout: 10 });
12151
+ if (rest.length) hooks.sessionStart = rest;
12152
+ else delete hooks.sessionStart;
12153
+ writeJsonFile(target, { version: 1, ...current, hooks });
12154
+ }
12155
+ var cursorContextRegistered = () => JSON.stringify(readJson(join4(cursorDir(), "hooks.json")).hooks ?? {}).includes(` ${CURSOR_CONTEXT}"`);
12139
12156
  var registration = () => ({ command: stableNode(), args: [runtimeEntry("cli"), "mcp"] });
12140
12157
  function readJson(file) {
12141
12158
  if (!existsSync4(file)) return {};
@@ -12176,6 +12193,7 @@ async function register(target, options = {}) {
12176
12193
  setMcpJson(join4(cursorDir(), "mcp.json"), registration());
12177
12194
  mergeCursorParentHooks(PROFILE, join4(cursorDir(), "hooks.json"), hook("cursor"));
12178
12195
  setCursorPermissions(true);
12196
+ setCursorContext(!!options.instructions);
12179
12197
  return { target, status: "registered" };
12180
12198
  }
12181
12199
  if (target === "codex") {
@@ -12214,6 +12232,7 @@ async function unregister(target) {
12214
12232
  if (existsSync4(join4(cursorDir(), "mcp.json"))) setMcpJson(join4(cursorDir(), "mcp.json"), null);
12215
12233
  removeCursorParentHooks(PROFILE, join4(cursorDir(), "hooks.json"));
12216
12234
  setCursorPermissions(false);
12235
+ setCursorContext(false);
12217
12236
  } else if (target === "codex") {
12218
12237
  if (existsSync4(join4(codexHome(), "config.toml"))) {
12219
12238
  await withCodexConfig(async (request) => {
@@ -12235,7 +12254,7 @@ async function unregister(target) {
12235
12254
  }
12236
12255
  function registered(target) {
12237
12256
  const file = instructionsFileOf(target);
12238
- return { ...registeredTools(target), instructions: file ? hasInstructions(file) : null };
12257
+ return { ...registeredTools(target), instructions: file ? hasInstructions(file) : target === "cursor" ? cursorContextRegistered() : null };
12239
12258
  }
12240
12259
  function registeredTools(target) {
12241
12260
  const entryOf = (value) => (value?.args ?? [])[0];
@@ -15622,7 +15641,7 @@ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "node:f
15622
15641
  import { basename as basename2, join as join5 } from "node:path";
15623
15642
 
15624
15643
  // src/version.ts
15625
- var VERSION = true ? "0.1.4" : "0.0.0-dev";
15644
+ var VERSION = true ? "0.1.6" : "0.0.0-dev";
15626
15645
  function osName() {
15627
15646
  return process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : process.platform;
15628
15647
  }
@@ -16032,7 +16051,7 @@ async function setup() {
16032
16051
  out(` \u300C${INSTRUCTION_TEXT}\u300D`);
16033
16052
  for (const target of targets) {
16034
16053
  const file = instructionsFileOf(target);
16035
- out(` ${LABEL[target]}: ${file ?? "\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u306F\u8AAD\u307E\u306A\u3044\u305F\u3081\u3001\u767B\u9332\u5F8C\u306B\u8CBC\u308B\u5834\u6240\u3092\u6848\u5185\u3057\u307E\u3059"}`);
16054
+ out(` ${LABEL[target]}: ${file ?? "\u4F1A\u8A71\u306E\u59CB\u307E\u308A\u306Ehook\uFF08hooks.json \u306E sessionStart\uFF09\u3067\u6E21\u3057\u307E\u3059"}`);
16036
16055
  }
16037
16056
  const instructions = !flag("no-instructions") && (flag("yes") || !/^n(o)?$/i.test(await ask("\u8DB3\u3057\u307E\u3059\u304B\uFF1F [Y/n] ")));
16038
16057
  const cli = installRuntime();
@@ -16067,11 +16086,6 @@ async function registerTargets() {
16067
16086
  out(` ${LABEL[target]}: ${result.status === "registered" ? "\u767B\u9332\u3057\u307E\u3057\u305F" : `\u5931\u6557 \u2014 ${result.detail}`}${extra}`);
16068
16087
  if (result.status === "failed") failed = true;
16069
16088
  }
16070
- if (flag("instructions") && targets.includes("cursor")) {
16071
- out(`
16072
- Cursor \u306F\u5168\u4F53\u306E\u6307\u793A\u3092\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u8AAD\u307F\u307E\u305B\u3093\u3002Cursor \u306E Settings \u2192 Rules \u2192 User Rules \u306B\u3001\u6B21\u306E\u4E00\u6587\u3092\u8CBC\u3063\u3066\u304F\u3060\u3055\u3044\u3002
16073
- ${INSTRUCTION_TEXT}`);
16074
- }
16075
16089
  ensureDaemon();
16076
16090
  out("\n\u767B\u9332\u3057\u305FAI\u306F\u3001\u958B\u3044\u3066\u3044\u308B\u4F1A\u8A71\u3092\u9589\u3058\u3066\u958B\u304D\u76F4\u3059\u3068Approval Box\u3092\u4F7F\u3048\u307E\u3059\u3002");
16077
16091
  if (failed) process.exit(1);
@@ -16127,6 +16141,7 @@ async function status() {
16127
16141
  }
16128
16142
  async function doctor() {
16129
16143
  const problems = [];
16144
+ const hints = [];
16130
16145
  const config = readConfig();
16131
16146
  if (!config?.token) problems.push("Approval Box\u306B\u3064\u306A\u304C\u3063\u3066\u3044\u307E\u305B\u3093 \u2192 npx approval-box setup");
16132
16147
  else {
@@ -16143,7 +16158,9 @@ async function doctor() {
16143
16158
  if (!r.mcp) problems.push(`${LABEL[target]}: MCP\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093 \u2192 npx approval-box setup --only ${target}`);
16144
16159
  if (r.hooks === false) problems.push(`${LABEL[target]}: hook\u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u305B\u3093 \u2192 npx approval-box setup --only ${target}`);
16145
16160
  if (r.entry && !existsSync6(r.entry)) problems.push(`${LABEL[target]}: \u767B\u9332\u5148\u306E\u30D5\u30A1\u30A4\u30EB\u304C\u3042\u308A\u307E\u305B\u3093\uFF08${r.entry}\uFF09\u3002node \u3084Approval Box\u3092\u5165\u308C\u76F4\u3057\u305F\u6642\u306B\u8D77\u304D\u307E\u3059 \u2192 npx approval-box setup`);
16161
+ if (r.mcp && r.instructions === false) hints.push(`${LABEL[target]}: \u5168\u4F53\u306E\u6307\u793A\u306BApproval Box\u306E\u4E00\u7BC0\u304C\u3042\u308A\u307E\u305B\u3093\u3002AI\u304C\u7533\u8ACB\u3092\u51FA\u3055\u306A\u3044\u6642\u306F \u2192 npx approval-box setup --only ${target}`);
16146
16162
  }
16163
+ for (const hint of hints) out(`\u30FB${hint}`);
16147
16164
  if (!problems.length) out("\u554F\u984C\u306F\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u5C4A\u304B\u306A\u3044\u6642\u306F\u3001AI\u306B\u300CApproval Box\u306Esetup_test\u3092\u5B9F\u884C\u3057\u3066\u300D\u3068\u8A00\u3063\u3066\u3001\u3069\u3053\u3067\u6B62\u307E\u308B\u304B\u3092\u78BA\u304B\u3081\u3066\u304F\u3060\u3055\u3044\u3002");
16148
16165
  else for (const problem of problems) out(`\u2717 ${problem}`);
16149
16166
  if (problems.length) process.exitCode = 1;
@@ -16165,6 +16182,13 @@ function help() {
16165
16182
  npx approval-box doctor \u5C4A\u304B\u306A\u3044\u6642\u306E\u539F\u56E0\u3092\u8ABF\u3079\u308B
16166
16183
  npx approval-box uninstall \u767B\u9332\u3092\u5168\u90E8\u5916\u3057\u3001\u3053\u306E\u7AEF\u672B\u306E\u63A5\u7D9A\u3092\u89E3\u9664\u3059\u308B`);
16167
16184
  }
16185
+ async function cursorContext() {
16186
+ for await (const _ of process.stdin) {
16187
+ }
16188
+ out(JSON.stringify({ additional_context: `## Approval Box
16189
+
16190
+ ${INSTRUCTION_TEXT}` }));
16191
+ }
16168
16192
  var commands = {
16169
16193
  setup,
16170
16194
  test,
@@ -16173,6 +16197,7 @@ var commands = {
16173
16197
  uninstall,
16174
16198
  help,
16175
16199
  register: registerTargets,
16200
+ "cursor-context": cursorContext,
16176
16201
  mcp: runMcp,
16177
16202
  daemon: runDaemon,
16178
16203
  version: () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "approval-box",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",