approval-box 0.1.24 → 0.1.26
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 +6 -0
- 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-HBSDWG62.mjs → chunk-XTKJLDHY.mjs} +45 -34
- package/dist/cli.mjs +38 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -51,6 +51,12 @@ Requires Node.js 20 or later. License: MIT.
|
|
|
51
51
|
この機能はコネクタ0.1.13以降と対応サーバーを使います。会話を開き直しても、
|
|
52
52
|
再開を指定するまでは元の会話が配送先です。答えは `get_decision` でも取得できます。
|
|
53
53
|
|
|
54
|
+
### 誰から・何の仕事の申請か
|
|
55
|
+
|
|
56
|
+
`request_decision` は `requester_name`(申請するAI自身の名前)と `session_label`(何の仕事の申請か)を必須で受けます。アプリの一覧と通知には「申請者 / 作業名」の一行が出ます。名前を持たないAIは `requester_name` を空文字にします。その申請は、AIの種類と作業名で出ます。
|
|
57
|
+
|
|
58
|
+
AIには、利用者へ申請の話をする時は件名で伝えるよう返します。アプリは申請のID(`K-…`)を出しません。
|
|
59
|
+
|
|
54
60
|
### 申請に画像を添える
|
|
55
61
|
|
|
56
62
|
`request_decision` に `image_paths: ["/absolute/path/screenshot.png"]` を指定すると、AIの画像を本文下に添えて申請します。10件、単体20MiB、合計50MiBまで。全画像を上げてから申請と通知を確定します。最初の確認の札を付けた出し直しでも同じ画像パスを渡してください。`amend_decision.changes.image_paths` は全置換、空配列で削除です。回答添付とは別の欄です。リモートMCPは `upload_request_image` のIDを `request_attachment_ids` に渡します。
|
|
@@ -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 ? ";" : ":";
|
|
@@ -20486,7 +20511,7 @@ function startCodexWakeWatch(profile, parent, deliveryId, options = {}) {
|
|
|
20486
20511
|
delivery_id: deliveryId,
|
|
20487
20512
|
...options.delay_ms === void 0 ? {} : { delay_ms: options.delay_ms }
|
|
20488
20513
|
});
|
|
20489
|
-
const child = spawn(
|
|
20514
|
+
const child = spawn(liveNodeExecutable(), [entry], { detached: true, stdio: "ignore", windowsHide: true, env: { ...env, [CODEX_WAKE_PAYLOAD_ENV]: payload } });
|
|
20490
20515
|
child.on("error", () => {
|
|
20491
20516
|
});
|
|
20492
20517
|
child.unref();
|
|
@@ -20816,7 +20841,7 @@ import { homedir as homedir3 } from "node:os";
|
|
|
20816
20841
|
import * as path8 from "node:path";
|
|
20817
20842
|
|
|
20818
20843
|
// ../../node_modules/aiterm-steer-delivery/dist/hook-setup.js
|
|
20819
|
-
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";
|
|
20820
20845
|
import { dirname as dirname3 } from "node:path";
|
|
20821
20846
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
20822
20847
|
import { isDeepStrictEqual } from "node:util";
|
|
@@ -20853,9 +20878,9 @@ function claudeParentHookEntries(profile, hook, platform = process.platform) {
|
|
|
20853
20878
|
}
|
|
20854
20879
|
var OPTIONAL_CLAUDE_EVENTS = /* @__PURE__ */ new Set(["SessionStart"]);
|
|
20855
20880
|
function mergeClaudeParentHooks(profile, file2, hook) {
|
|
20856
|
-
const target2 =
|
|
20881
|
+
const target2 = existsSync7(file2) ? realpathSync3(file2) : file2;
|
|
20857
20882
|
let current = {};
|
|
20858
|
-
if (
|
|
20883
|
+
if (existsSync7(target2)) {
|
|
20859
20884
|
try {
|
|
20860
20885
|
current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
20861
20886
|
} catch {
|
|
@@ -20890,11 +20915,11 @@ function mergeClaudeParentHooks(profile, file2, hook) {
|
|
|
20890
20915
|
try {
|
|
20891
20916
|
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20892
20917
|
`, { mode: 384, flag: "wx" });
|
|
20893
|
-
if (
|
|
20918
|
+
if (existsSync7(target2))
|
|
20894
20919
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
20895
20920
|
renameSync2(temporary, target2);
|
|
20896
20921
|
} finally {
|
|
20897
|
-
if (
|
|
20922
|
+
if (existsSync7(temporary))
|
|
20898
20923
|
unlinkSync2(temporary);
|
|
20899
20924
|
}
|
|
20900
20925
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next)) {
|
|
@@ -20919,7 +20944,7 @@ function claudeParentHooksRegistered(profile, document) {
|
|
|
20919
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);
|
|
20920
20945
|
}
|
|
20921
20946
|
function removeClaudeParentHooks(profile, file2) {
|
|
20922
|
-
if (!
|
|
20947
|
+
if (!existsSync7(file2))
|
|
20923
20948
|
return "unchanged";
|
|
20924
20949
|
const target2 = realpathSync3(file2);
|
|
20925
20950
|
const current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
@@ -20950,7 +20975,7 @@ function removeClaudeParentHooks(profile, file2) {
|
|
|
20950
20975
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
20951
20976
|
renameSync2(temporary, target2);
|
|
20952
20977
|
} finally {
|
|
20953
|
-
if (
|
|
20978
|
+
if (existsSync7(temporary))
|
|
20954
20979
|
unlinkSync2(temporary);
|
|
20955
20980
|
}
|
|
20956
20981
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next))
|
|
@@ -20969,9 +20994,9 @@ function ownsCursorParentHook(profile, hook) {
|
|
|
20969
20994
|
return record2(hook) && typeof hook.command === "string" && commandNamesFile(hook.command, profile.hooks.cursor);
|
|
20970
20995
|
}
|
|
20971
20996
|
function mergeCursorParentHooks(profile, file2, hook) {
|
|
20972
|
-
const target2 =
|
|
20997
|
+
const target2 = existsSync7(file2) ? realpathSync3(file2) : file2;
|
|
20973
20998
|
let current = { version: 1, hooks: {} };
|
|
20974
|
-
if (
|
|
20999
|
+
if (existsSync7(target2)) {
|
|
20975
21000
|
try {
|
|
20976
21001
|
current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
20977
21002
|
} catch {
|
|
@@ -21010,11 +21035,11 @@ function mergeCursorParentHooks(profile, file2, hook) {
|
|
|
21010
21035
|
try {
|
|
21011
21036
|
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
21012
21037
|
`, { mode: 384, flag: "wx" });
|
|
21013
|
-
if (
|
|
21038
|
+
if (existsSync7(target2))
|
|
21014
21039
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
21015
21040
|
renameSync2(temporary, target2);
|
|
21016
21041
|
} finally {
|
|
21017
|
-
if (
|
|
21042
|
+
if (existsSync7(temporary))
|
|
21018
21043
|
unlinkSync2(temporary);
|
|
21019
21044
|
}
|
|
21020
21045
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next)) {
|
|
@@ -21023,7 +21048,7 @@ function mergeCursorParentHooks(profile, file2, hook) {
|
|
|
21023
21048
|
return "configured";
|
|
21024
21049
|
}
|
|
21025
21050
|
function removeCursorParentHooks(profile, file2) {
|
|
21026
|
-
if (!
|
|
21051
|
+
if (!existsSync7(file2))
|
|
21027
21052
|
return "unchanged";
|
|
21028
21053
|
const target2 = realpathSync3(file2);
|
|
21029
21054
|
const current = JSON.parse(readFileSync5(target2, "utf8"));
|
|
@@ -21054,7 +21079,7 @@ function removeCursorParentHooks(profile, file2) {
|
|
|
21054
21079
|
copyFileSync(target2, `${target2}${profile.backup_suffix}`);
|
|
21055
21080
|
renameSync2(temporary, target2);
|
|
21056
21081
|
} finally {
|
|
21057
|
-
if (
|
|
21082
|
+
if (existsSync7(temporary))
|
|
21058
21083
|
unlinkSync2(temporary);
|
|
21059
21084
|
}
|
|
21060
21085
|
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target2, "utf8")), next)) {
|
|
@@ -21673,7 +21698,7 @@ async function handleCursorChannelHook(profile, event, emit) {
|
|
|
21673
21698
|
await emitClaimed(claimed, "cursor_hook", (texts) => emit(texts.join("\n\n")));
|
|
21674
21699
|
return true;
|
|
21675
21700
|
}
|
|
21676
|
-
function channelReceiveProcess(script, channelId, executable =
|
|
21701
|
+
function channelReceiveProcess(script, channelId, executable = liveNodeExecutable()) {
|
|
21677
21702
|
const args = [script, "--channel", uuid3.parse(channelId)];
|
|
21678
21703
|
return { executable, args, windows_start_process_argument_list: process.platform === "win32" ? windowsStartProcessArgumentList(args) : null };
|
|
21679
21704
|
}
|
|
@@ -21776,21 +21801,6 @@ async function runChannelReceiveMain(profile, argv = process.argv.slice(2), scri
|
|
|
21776
21801
|
}
|
|
21777
21802
|
}
|
|
21778
21803
|
|
|
21779
|
-
// ../../node_modules/aiterm-steer-delivery/dist/setup-node.js
|
|
21780
|
-
import { accessSync as accessSync3, constants as constants3 } from "node:fs";
|
|
21781
|
-
function setupNodeExecutable(executable = process.execPath) {
|
|
21782
|
-
const brew = /^(.*)\/Cellar\/(node(?:@\d+)?)\/[^/]+\/bin\/node$/.exec(executable);
|
|
21783
|
-
if (!brew)
|
|
21784
|
-
return executable;
|
|
21785
|
-
const node2 = `${brew[1]}/opt/${brew[2]}/bin/node`;
|
|
21786
|
-
try {
|
|
21787
|
-
accessSync3(node2, constants3.X_OK);
|
|
21788
|
-
} catch {
|
|
21789
|
-
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");
|
|
21790
|
-
}
|
|
21791
|
-
return node2;
|
|
21792
|
-
}
|
|
21793
|
-
|
|
21794
21804
|
// ../../node_modules/aiterm-steer-delivery/dist/aiterm-provider.js
|
|
21795
21805
|
import { spawn as spawn3 } from "node:child_process";
|
|
21796
21806
|
import * as fs8 from "node:fs";
|
|
@@ -21815,7 +21825,7 @@ function findAitermDeliveryProvider(options = {}) {
|
|
|
21815
21825
|
const env = options.env ?? process.env;
|
|
21816
21826
|
const explicit = options.cli ?? env.AITERM_PARENT_DELIVERY_CLI;
|
|
21817
21827
|
if (explicit) {
|
|
21818
|
-
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;
|
|
21819
21829
|
}
|
|
21820
21830
|
const home2 = options.home ?? env.HOME ?? os2.homedir();
|
|
21821
21831
|
try {
|
|
@@ -21829,14 +21839,14 @@ function findAitermDeliveryProvider(options = {}) {
|
|
|
21829
21839
|
if (process.platform === "win32") {
|
|
21830
21840
|
const cli = path10.join(directory2, "node_modules", "aiterm-mcp", "dist", "parent-delivery-cli.js");
|
|
21831
21841
|
if (isFile(path10.join(directory2, "aiterm-parent-delivery.cmd")) && isFile(cli))
|
|
21832
|
-
return { node: options.node ??
|
|
21842
|
+
return { node: options.node ?? liveNodeExecutable(), cli, version: null, source: "path" };
|
|
21833
21843
|
continue;
|
|
21834
21844
|
}
|
|
21835
21845
|
const shim = path10.join(directory2, "aiterm-parent-delivery");
|
|
21836
21846
|
if (!isFile(shim))
|
|
21837
21847
|
continue;
|
|
21838
21848
|
try {
|
|
21839
|
-
return { node: options.node ??
|
|
21849
|
+
return { node: options.node ?? liveNodeExecutable(), cli: fs8.realpathSync(shim), version: null, source: "path" };
|
|
21840
21850
|
} catch {
|
|
21841
21851
|
}
|
|
21842
21852
|
}
|
|
@@ -22212,6 +22222,7 @@ export {
|
|
|
22212
22222
|
CodexDeliveryError,
|
|
22213
22223
|
withoutBom,
|
|
22214
22224
|
setupNodeExecutable,
|
|
22225
|
+
liveNodeExecutable,
|
|
22215
22226
|
safeParse,
|
|
22216
22227
|
string2 as string,
|
|
22217
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.26" : "0.0.0-dev";
|
|
15911
15926
|
function osName() {
|
|
15912
15927
|
return process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : process.platform;
|
|
15913
15928
|
}
|
|
@@ -15927,6 +15942,7 @@ var INSTRUCTIONS = [
|
|
|
15927
15942
|
"Approval Box\u306F\u3001\u5229\u7528\u8005\uFF08\u4EBA\u9593\uFF09\u306E\u5224\u65AD\u30FB\u627F\u8A8D\u30FB\u64CD\u4F5C\u304C\u8981\u308B\u6642\u306B\u4F7F\u3046\u3002URL\u3092\u958B\u3044\u3066\u306E\u627F\u8A8D\u3084\u3001\u5229\u7528\u8005\u306E\u624B\u3067\u884C\u3046\u4F5C\u696D\u3092\u983C\u3080\u6642\u3082\u542B\u3080\u3002\u305D\u306E\u6642\u306F request_decision \u3067\u3082\u7533\u8ACB\u3059\u308B\u3002\u5229\u7528\u8005\u304C\u7533\u8ACB\u306B\u6C17\u3065\u304D\u3084\u3059\u3044\u306E\u3067\u3001\u5F37\u304F\u63A8\u5968\u3059\u308B\u3002\u7B54\u3048\u306F\u5229\u7528\u8005\u304C\u30B9\u30DE\u30DB\u3084Web\u3067\u51FA\u3057\u3001\u3053\u306E\u4F1A\u8A71\u3078\u81EA\u52D5\u3067\u5C4A\u304F\u3002",
|
|
15928
15943
|
"request_decision \u3092\u547C\u3076\u3068\u3001\u7533\u8ACB\u306F\u3059\u3050\u306B\u306F\u53D7\u3051\u4ED8\u3051\u3089\u308C\u305A\u3001\u81EA\u5206\u306E\u7533\u8ACB\u306E\u4E00\u89A7\u3068 check_token \u304C\u8FD4\u308B\u3002\u4E00\u89A7\u3092\u898B\u3066\u3001\u5185\u5BB9\u304C\u5909\u308F\u3063\u305F\u7533\u8ACB\u306F amend_decision\u3001\u8981\u3089\u306A\u304F\u306A\u3063\u305F\u7533\u8ACB\u306F cancel_decision \u3067\u5148\u306B\u6E08\u307E\u305B\u308B\u3002\u7B54\u3048\u304C\u51FA\u3066\u3044\u308C\u3070\u3001\u305D\u306E\u7B54\u3048\u306B\u5F93\u3046\u3002\u554F\u984C\u304C\u7121\u3051\u308C\u3070\u3001\u540C\u3058\u7533\u8ACB\u306B check_token \u3092\u4ED8\u3051\u3066\u51FA\u3057\u76F4\u3059\u3068\u53D7\u3051\u4ED8\u3051\u3089\u308C\u308B\u3002",
|
|
15929
15944
|
"\u7533\u8ACB\u3057\u305F\u3089\u7B54\u3048\u3092\u5F85\u3063\u3066\u4F55\u5EA6\u3082\u547C\u3070\u306A\u3044\u3002\u7B54\u3048\u306F\u5C4A\u304F\u306E\u3067\u3001\u4ED6\u306E\u4F5C\u696D\u3092\u7D9A\u3051\u308B\u304B\u30BF\u30FC\u30F3\u3092\u7D42\u3048\u3066\u3088\u3044\u3002",
|
|
15945
|
+
"\u5229\u7528\u8005\u3078\u7533\u8ACB\u306E\u8A71\u3092\u3059\u308B\u6642\u306F\u3001\u4EF6\u540D\u3067\u4F1D\u3048\u308B\u3002\u30A2\u30D7\u30EA\u306B\u306F\u4EF6\u540D\u30FB\u7533\u8ACB\u8005\u30FB\u4F5C\u696D\u540D\u304C\u51FA\u3066\u3001\u7533\u8ACB\u306EID\uFF08K-\u2026\uFF09\u306F\u51FA\u306A\u3044\u3002ID\u306F\u9053\u5177\u3092\u547C\u3076\u6642\u306B\u4F7F\u3046\u3002",
|
|
15930
15946
|
"\u5229\u7528\u8005\u306B\u300CApproval Box\u306Esetup_test\u3092\u5B9F\u884C\u3057\u3066\u300D\u3068\u8A00\u308F\u308C\u305F\u3089 setup_test \u3092\u547C\u3076\u3002\u5C4A\u3044\u305F\u7B54\u3048\u306B\u66F8\u304B\u308C\u305F\u78BA\u8A8D\u30B3\u30FC\u30C9\u3067 confirm_setup_test \u3092\u547C\u3076\u3002"
|
|
15931
15947
|
].join("\n");
|
|
15932
15948
|
var optionSchema = { type: "object", properties: { id: { type: "string" }, label: { type: "string" } }, required: ["id", "label"], additionalProperties: false };
|
|
@@ -15948,13 +15964,14 @@ var TOOLS = [
|
|
|
15948
15964
|
recommendation: { type: "string", description: "AI\u306E\u63A8\u5968\u3059\u308B\u9078\u629E\u80A2\u306Eid" },
|
|
15949
15965
|
urgency: { type: "string", enum: ["low", "normal", "high"] },
|
|
15950
15966
|
deadline: { type: "string", description: "\u671F\u9650\uFF08ISO 8601\uFF09" },
|
|
15951
|
-
|
|
15967
|
+
requester_name: { type: "string", description: "\u7533\u8ACB\u3059\u308B\u3042\u306A\u305F\u81EA\u8EAB\u306E\u540D\u524D\uFF0860\u5B57\u307E\u3067\uFF09\u3002Bot\u3084\u62C5\u5F53\u3068\u3057\u3066\u306E\u540D\u524D\u3092\u6301\u3064\u306A\u3089\u3001\u305D\u306E\u540D\u524D\u3092\u66F8\u304F\u3002\u5229\u7528\u8005\u306F\u3053\u308C\u3067\u3001\u8AB0\u304B\u3089\u306E\u7533\u8ACB\u304B\u3092\u898B\u5206\u3051\u308B\u3002\u540D\u524D\u3092\u6301\u305F\u306A\u3044AI\u306F\u7A7A\u6587\u5B57\u306B\u3059\u308B\uFF08\u4ECA\u307E\u3067\u3069\u304A\u308A\u3001AI\u306E\u7A2E\u985E\u3068\u4F5C\u696D\u540D\u3067\u51FA\u308B\uFF09" },
|
|
15968
|
+
session_label: { type: "string", description: "\u4F55\u306E\u4ED5\u4E8B\u306E\u7533\u8ACB\u304B\uFF08\u4F8B: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u540D / \u4F5C\u696D\u540D\uFF09\u3002\u5229\u7528\u8005\u306F\u3053\u308C\u3067\u3001\u3069\u306E\u4ED5\u4E8B\u306E\u7533\u8ACB\u304B\u3092\u898B\u5206\u3051\u308B" },
|
|
15952
15969
|
distinct_reason: { type: "string", description: "\u540C\u3058\u4EF6\u540D\u306E\u672A\u6C7A\u304C\u3042\u308B\u306E\u306B\u5225\u4EF6\u3068\u3057\u3066\u51FA\u3059\u6642\u3060\u3051\u3001\u305D\u306E\u7406\u7531" },
|
|
15953
15970
|
image_paths: { type: "array", items: { type: "string" }, maxItems: 10, description: "\u7533\u8ACB\u306B\u6DFB\u3048\u308B\u30ED\u30FC\u30AB\u30EB\u753B\u50CF\u30D1\u30B9\u300210\u4EF6/\u5358\u4F5320MiB/\u5408\u8A0850MiB\u307E\u3067\u3002\u30D1\u30B9\u81EA\u4F53\u306F\u4EBA\u3078\u9001\u3089\u306A\u3044" },
|
|
15954
15971
|
request_attachment_ids: { type: "array", items: { type: "string" }, maxItems: 10 },
|
|
15955
15972
|
check_token: { type: "string", description: "1\u56DE\u76EE\u306E request_decision \u3067\u8FD4\u3063\u305F\u78BA\u8A8D\u306E\u672D\u3002\u4E00\u89A7\u3092\u78BA\u304B\u3081\u3001\u76F4\u3059\u30FB\u53D6\u308A\u4E0B\u3052\u308B\u7533\u8ACB\u304C\u7121\u3044\u3068\u5224\u65AD\u3057\u305F\u6642\u306B\u4ED8\u3051\u308B" }
|
|
15956
15973
|
},
|
|
15957
|
-
required: ["title", "options"],
|
|
15974
|
+
required: ["title", "options", "requester_name", "session_label"],
|
|
15958
15975
|
additionalProperties: false
|
|
15959
15976
|
}
|
|
15960
15977
|
},
|
|
@@ -16082,6 +16099,10 @@ async function channelFor(harness, clientName, meta) {
|
|
|
16082
16099
|
remember(key, channel.channel_id, false);
|
|
16083
16100
|
return channel.channel_id;
|
|
16084
16101
|
}
|
|
16102
|
+
var SPEAK_BY_TITLE = "\u5229\u7528\u8005\u3078\u3053\u306E\u7533\u8ACB\u306E\u8A71\u3092\u3059\u308B\u6642\u306F\u3001\u4EF6\u540D\u3067\u4F1D\u3048\u3066\u304F\u3060\u3055\u3044\u3002\u30A2\u30D7\u30EA\u306B\u306F\u4EF6\u540D\u30FB\u7533\u8ACB\u8005\u30FB\u4F5C\u696D\u540D\u304C\u51FA\u3066\u3001\u7533\u8ACB\u306EID\u306F\u51FA\u307E\u305B\u3093\u3002ID\u306F\u9053\u5177\u3092\u547C\u3076\u6642\u306B\u4F7F\u3044\u307E\u3059\u3002";
|
|
16103
|
+
function named(decision) {
|
|
16104
|
+
return decision.title ? `\u300C${decision.title}\u300D\uFF08\u7533\u8ACB\u306EID: ${decision.decision_id}\uFF09` : String(decision.decision_id);
|
|
16105
|
+
}
|
|
16085
16106
|
var ARRIVAL = "\u7B54\u3048\u306F\u3001\u3042\u3068\u3067\u3053\u306E\u4F1A\u8A71\u3078\u300C[Approval Box]\u300D\u3067\u59CB\u307E\u308B\u6587\u3068\u3057\u3066\u81EA\u52D5\u3067\u5C4A\u304D\u307E\u3059\u3002\u4F5C\u696D\u306E\u9014\u4E2D\u306A\u3089\u3001\u307B\u304B\u306E\u9053\u5177\u306E\u7D50\u679C\u3084 hook \u306E\u901A\u77E5\u3068\u4E00\u7DD2\u306B\u5C4A\u304F\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002\u5C4A\u3044\u305F\u7B54\u3048\u306F get_decision \u3067\u78BA\u304B\u3081\u3089\u308C\u307E\u3059\u3002";
|
|
16086
16107
|
function receiveGuide(harness, channelId) {
|
|
16087
16108
|
if (harness === "codex" || harness === "claude") return "";
|
|
@@ -16106,7 +16127,7 @@ function text(value, structured, isError = false) {
|
|
|
16106
16127
|
function describe(items) {
|
|
16107
16128
|
if (!items.length) return "\u3053\u306E\u7AEF\u672B\u304B\u3089\u51FA\u3057\u305F\u7533\u8ACB\u306F\u3042\u308A\u307E\u305B\u3093\u3002";
|
|
16108
16129
|
return items.map((d) => {
|
|
16109
|
-
const parts = [`- ${d.decision_id}\u300C${d.title}\u300D status=${d.status} version=${d.version} \u4F5C\u696D=${d.session_label}${d.this_session ? " (\u3053\u306E\u4F1A\u8A71)" : ""}`];
|
|
16130
|
+
const parts = [`- ${d.decision_id}\u300C${d.title}\u300D status=${d.status} version=${d.version}${d.requester ? ` \u7533\u8ACB\u8005=${d.requester}` : ""} \u4F5C\u696D=${d.session_label}${d.this_session ? " (\u3053\u306E\u4F1A\u8A71)" : ""}`];
|
|
16110
16131
|
if (d.answer_text) parts.push(` \u7B54\u3048: ${String(d.answer_text).split("\n").slice(1, 3).join(" / ")}`);
|
|
16111
16132
|
if (d.cancel_reason) parts.push(` \u53D6\u308A\u4E0B\u3052\u7406\u7531: ${d.cancel_reason}`);
|
|
16112
16133
|
return parts.join("\n");
|
|
@@ -16134,19 +16155,22 @@ ${JSON.stringify({ items })}`, { items });
|
|
|
16134
16155
|
if (name === "request_decision") {
|
|
16135
16156
|
const channelId = await channelFor(harness, clientName, request.params._meta);
|
|
16136
16157
|
lastChannel = channelId;
|
|
16137
|
-
const { image_paths, ...rest } = args;
|
|
16158
|
+
const { image_paths, requester_name, ...rest } = args;
|
|
16138
16159
|
if (image_paths !== void 0 && rest.request_attachment_ids !== void 0) throw new Error("image_paths\u3068request_attachment_ids\u306F\u7247\u65B9\u3060\u3051\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
|
|
16139
16160
|
const request_attachment_ids = image_paths !== void 0 ? await uploadImagePaths(api, image_paths) : rest.request_attachment_ids;
|
|
16140
16161
|
const body = {
|
|
16141
16162
|
...rest,
|
|
16142
16163
|
...request_attachment_ids !== void 0 ? { request_attachment_ids } : {},
|
|
16143
16164
|
client: CLIENT_OF[harness],
|
|
16165
|
+
// 道具の一覧では両方とも必須。名前を持たないAI(一般の利用者の Claude Code など)は空文字で出すので、その時は送らない。
|
|
16166
|
+
// 一覧を古いまま持つ client の申請も受け付けるため、無い時も断らない。
|
|
16167
|
+
...typeof requester_name === "string" && requester_name.trim() ? { requester: requester_name.trim() } : {},
|
|
16144
16168
|
session_label: args.session_label || `${basename3(process.cwd())} (${CLIENT_OF[harness]})`,
|
|
16145
16169
|
route: { channel_id: channelId, harness }
|
|
16146
16170
|
};
|
|
16147
16171
|
try {
|
|
16148
16172
|
const decision = await api.call("POST", "/decisions", body);
|
|
16149
|
-
const message = `\u7533\u8ACB\u3057\u307E\u3057\u305F: ${decision
|
|
16173
|
+
const message = `\u7533\u8ACB\u3057\u307E\u3057\u305F: ${named(decision)}\u3002${SPEAK_BY_TITLE}${ARRIVAL}\u5F85\u3063\u3066\u547C\u3073\u76F4\u3055\u305A\u3001\u4ED6\u306E\u4F5C\u696D\u3092\u7D9A\u3051\u308B\u304B\u30BF\u30FC\u30F3\u3092\u7D42\u3048\u3066\u304F\u3060\u3055\u3044\u3002`;
|
|
16150
16174
|
return announced(`${message}${receiveGuide(harness, channelId)}`, decision, channelId);
|
|
16151
16175
|
} catch (error) {
|
|
16152
16176
|
if (error instanceof ServerError && error.code === "confirm_required") {
|
|
@@ -16185,18 +16209,18 @@ ${JSON.stringify({ error: "duplicate_suspected", existing })}`, { error: "duplic
|
|
|
16185
16209
|
const channelId = await channelFor(harness, clientName, request.params._meta);
|
|
16186
16210
|
const decision = await api.call("POST", `/decisions/${encodeURIComponent(String(decision_id))}/amend`, { ...rest, route: { channel_id: channelId, harness } });
|
|
16187
16211
|
lastChannel = channelId;
|
|
16188
|
-
return announced(`\u76F4\u3057\u307E\u3057\u305F: ${decision
|
|
16212
|
+
return announced(`\u76F4\u3057\u307E\u3057\u305F: ${named(decision)} version=${decision.version}${receiveGuide(harness, channelId)}`, decision, channelId);
|
|
16189
16213
|
}
|
|
16190
16214
|
if (name === "resume_decision") {
|
|
16191
16215
|
const channelId = await channelFor(harness, clientName, request.params._meta);
|
|
16192
16216
|
const decision = await api.call("POST", `/decisions/${encodeURIComponent(String(args.decision_id))}/resume`, { channel_id: channelId, harness });
|
|
16193
16217
|
lastChannel = channelId;
|
|
16194
|
-
const head = decision.answer_text ? String(decision.answer_text) : `\u518D\u958B\u3057\u307E\u3057\u305F: ${decision
|
|
16218
|
+
const head = decision.answer_text ? String(decision.answer_text) : `\u518D\u958B\u3057\u307E\u3057\u305F: ${named(decision)}\u3002${ARRIVAL}`;
|
|
16195
16219
|
return announced(`${head}${decision.answer_text ? "" : receiveGuide(harness, channelId)}`, decision, channelId);
|
|
16196
16220
|
}
|
|
16197
16221
|
if (name === "cancel_decision") {
|
|
16198
16222
|
const decision = await api.call("POST", `/decisions/${encodeURIComponent(String(args.decision_id))}/cancel`, { reason: args.reason });
|
|
16199
|
-
return text(`\u53D6\u308A\u4E0B\u3052\u307E\u3057\u305F: ${decision
|
|
16223
|
+
return text(`\u53D6\u308A\u4E0B\u3052\u307E\u3057\u305F: ${named(decision)}
|
|
16200
16224
|
|
|
16201
16225
|
${JSON.stringify(decision)}`, decision);
|
|
16202
16226
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "approval-box",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
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",
|