approval-box 0.1.12 → 0.1.14
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 +11 -0
- package/dist/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/approval-box-claude-hook.mjs +1 -1
- package/dist/approval-box-codex-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-S4DEUZZH.mjs → chunk-GH2JG56Y.mjs} +313 -237
- package/dist/cli.mjs +46 -10
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -35,3 +35,14 @@ npx approval-box uninstall # remove everything and unlink this device / 全部
|
|
|
35
35
|
Self-hosted server: `npx -y approval-box@latest setup --server https://your-server`.
|
|
36
36
|
|
|
37
37
|
Requires Node.js 20 or later. License: MIT.
|
|
38
|
+
|
|
39
|
+
### 会話を開き直した時
|
|
40
|
+
|
|
41
|
+
`list_my_decisions` で、自分が引き継ぐ申請を確かめ、対象ごとに
|
|
42
|
+
`resume_decision({decision_id: "K-…"})` を呼びます。未決・保留なら今の会話へ
|
|
43
|
+
配送先を移し、回答済みなら答えを直接返します。同じ端末にある他の作業の申請は、
|
|
44
|
+
引き継ぐ対象に含めないでください。`amend_decision` も、修正が成功した時に配送先を
|
|
45
|
+
呼び出した会話へ更新します。Cursor・Grokでは、返る案内に従って背景の受信を起動します。
|
|
46
|
+
|
|
47
|
+
この機能はコネクタ0.1.13以降と対応サーバーを使います。会話を開き直しても、
|
|
48
|
+
再開を指定するまでは元の会話が配送先です。答えは `get_decision` でも取得できます。
|
|
@@ -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-
|
|
5
|
+
} from "./chunks/chunk-GH2JG56Y.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
|
runChannelReceiveMain
|
|
5
|
-
} from "./chunks/chunk-
|
|
5
|
+
} from "./chunks/chunk-GH2JG56Y.mjs";
|
|
6
6
|
|
|
7
7
|
// src/hooks/receive.ts
|
|
8
8
|
await runChannelReceiveMain(PROFILE);
|
|
@@ -43,7 +43,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
43
43
|
import { homedir } from "node:os";
|
|
44
44
|
import { join } from "node:path";
|
|
45
45
|
var MCP_SERVER = "approval-box";
|
|
46
|
-
var DISPATCH_TOOLS = ["request_decision", "setup_test"];
|
|
46
|
+
var DISPATCH_TOOLS = ["request_decision", "setup_test", "amend_decision", "resume_decision"];
|
|
47
47
|
var home = () => process.env.APPROVAL_BOX_HOME ?? join(homedir(), ".approval-box");
|
|
48
48
|
var stateRoot = () => join(home(), "state");
|
|
49
49
|
var HOOK_FILES = {
|
|
@@ -19822,7 +19822,7 @@ function writeHookJson(file2, value) {
|
|
|
19822
19822
|
fs.unlinkSync(temporary);
|
|
19823
19823
|
}
|
|
19824
19824
|
}
|
|
19825
|
-
function waitForFileState(dir, inspect, timeoutMs) {
|
|
19825
|
+
function waitForFileState(dir, inspect, timeoutMs, signal) {
|
|
19826
19826
|
return new Promise((resolve2, reject) => {
|
|
19827
19827
|
let finished = false;
|
|
19828
19828
|
let timer;
|
|
@@ -19837,11 +19837,13 @@ function waitForFileState(dir, inspect, timeoutMs) {
|
|
|
19837
19837
|
clearInterval(timer);
|
|
19838
19838
|
if (timeout)
|
|
19839
19839
|
clearTimeout(timeout);
|
|
19840
|
+
signal?.removeEventListener("abort", abort);
|
|
19840
19841
|
if (error62)
|
|
19841
19842
|
reject(error62);
|
|
19842
19843
|
else
|
|
19843
19844
|
resolve2(value);
|
|
19844
19845
|
};
|
|
19846
|
+
const abort = () => finish(new Error("WAIT_FOR_FILE_ABORTED"));
|
|
19845
19847
|
const check2 = () => {
|
|
19846
19848
|
if (finished)
|
|
19847
19849
|
return;
|
|
@@ -19857,12 +19859,17 @@ function waitForFileState(dir, inspect, timeoutMs) {
|
|
|
19857
19859
|
timer = setInterval(check2, 5e3);
|
|
19858
19860
|
if (timeoutMs !== void 0)
|
|
19859
19861
|
timeout = setTimeout(() => finish(new Error("WAIT_FOR_FILE_TIMEOUT")), timeoutMs);
|
|
19862
|
+
if (signal?.aborted)
|
|
19863
|
+
abort();
|
|
19864
|
+
else
|
|
19865
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
19860
19866
|
check2();
|
|
19861
19867
|
});
|
|
19862
19868
|
}
|
|
19863
19869
|
|
|
19864
19870
|
// ../../node_modules/aiterm-steer-delivery/dist/windows.js
|
|
19865
19871
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
19872
|
+
import { realpathSync } from "node:fs";
|
|
19866
19873
|
import * as path3 from "node:path";
|
|
19867
19874
|
var WINDOWS_POWERSHELL_7_COMMAND = "pwsh.exe";
|
|
19868
19875
|
var WINDOWS_POWERSHELL_7_INSTALL = "winget install --id Microsoft.PowerShell --source winget";
|
|
@@ -19899,9 +19906,15 @@ function resolveWindowsPowerShell7(probe = defaultProbe) {
|
|
|
19899
19906
|
}
|
|
19900
19907
|
if (version2.status !== 0 || identity?.edition !== "Core" || !Number.isInteger(identity.major) || Number(identity.major) < 7)
|
|
19901
19908
|
fail();
|
|
19909
|
+
let canonical;
|
|
19910
|
+
try {
|
|
19911
|
+
canonical = realpathSync.native(executable);
|
|
19912
|
+
} catch {
|
|
19913
|
+
return fail();
|
|
19914
|
+
}
|
|
19902
19915
|
if (probe === defaultProbe)
|
|
19903
|
-
resolvedDefault =
|
|
19904
|
-
return
|
|
19916
|
+
resolvedDefault = canonical;
|
|
19917
|
+
return canonical;
|
|
19905
19918
|
}
|
|
19906
19919
|
var quotePowerShell = (value) => `'${value.replace(/'/g, "''")}'`;
|
|
19907
19920
|
function windowsPowerShellSync(script, onFailure, timeout = 15e3) {
|
|
@@ -20170,6 +20183,18 @@ function parsePosixProcessTable(text) {
|
|
|
20170
20183
|
};
|
|
20171
20184
|
});
|
|
20172
20185
|
}
|
|
20186
|
+
var HOOK_SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "dash", "zsh", "ksh", "ash", "busybox", "pwsh", "powershell", "cmd"]);
|
|
20187
|
+
function executableName(row) {
|
|
20188
|
+
const source = row.executable || (row.command.startsWith('"') ? row.command.slice(1).split('"')[0] : row.command.split(/\s+/u)[0]);
|
|
20189
|
+
return (source.split(/[\\/]/u).pop() ?? "").replace(/^-/u, "").replace(/\.exe$/iu, "").toLowerCase();
|
|
20190
|
+
}
|
|
20191
|
+
function hookOwnerProcess(rows, pid) {
|
|
20192
|
+
const byPid = new Map(rows.map((row) => [row.pid, row]));
|
|
20193
|
+
let current = byPid.get(pid);
|
|
20194
|
+
for (let depth = 0; current && depth < 4 && HOOK_SHELLS.has(executableName(current)); depth += 1)
|
|
20195
|
+
current = byPid.get(current.parent_pid);
|
|
20196
|
+
return current;
|
|
20197
|
+
}
|
|
20173
20198
|
function readRuntimeProcesses() {
|
|
20174
20199
|
if (!isWin2) {
|
|
20175
20200
|
const result2 = spawnSync3("/bin/ps", ["-axww", "-o", "pid=,ppid=,pgid=,stat=,lstart=,time=,command="], {
|
|
@@ -20595,8 +20620,8 @@ function assertOpen(parent) {
|
|
|
20595
20620
|
}
|
|
20596
20621
|
function prepareClaudeHookRequest(input2, root) {
|
|
20597
20622
|
const event = external_exports.object({ session_id: external_exports.uuid(), tool_use_id: requestId, agent_id: external_exports.string().optional() }).parse(input2);
|
|
20598
|
-
const
|
|
20599
|
-
if (!
|
|
20623
|
+
const owner = hookOwnerProcess(readRuntimeProcesses(), process.ppid);
|
|
20624
|
+
if (!owner)
|
|
20600
20625
|
throw new ClaudeDeliveryError("CLAUDE_PARENT_PROCESS_UNAVAILABLE", "hook\u3092\u8D77\u52D5\u3057\u305F\u89AAprocess\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093");
|
|
20601
20626
|
const dir = path8.join(root, event.tool_use_id);
|
|
20602
20627
|
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
@@ -20604,8 +20629,8 @@ function prepareClaudeHookRequest(input2, root) {
|
|
|
20604
20629
|
request_id: event.tool_use_id,
|
|
20605
20630
|
session_id: event.session_id,
|
|
20606
20631
|
agent_id: event.agent_id ?? null,
|
|
20607
|
-
parent_pid:
|
|
20608
|
-
parent_started_identity:
|
|
20632
|
+
parent_pid: owner.pid,
|
|
20633
|
+
parent_started_identity: owner.started_identity
|
|
20609
20634
|
});
|
|
20610
20635
|
}
|
|
20611
20636
|
function claudeParentFromRequest(profile, clientName, metadata, root) {
|
|
@@ -20695,6 +20720,250 @@ async function runClaudeResultHook(profile, input2, emit, root) {
|
|
|
20695
20720
|
import * as fs6 from "node:fs";
|
|
20696
20721
|
import { homedir as homedir3 } from "node:os";
|
|
20697
20722
|
import * as path9 from "node:path";
|
|
20723
|
+
|
|
20724
|
+
// ../../node_modules/aiterm-steer-delivery/dist/hook-setup.js
|
|
20725
|
+
import { copyFileSync, existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, readFileSync as readFileSync5, realpathSync as realpathSync4, renameSync as renameSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
20726
|
+
import { dirname as dirname3 } from "node:path";
|
|
20727
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
20728
|
+
import { isDeepStrictEqual } from "node:util";
|
|
20729
|
+
var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20730
|
+
function endsWithFile(value, file2) {
|
|
20731
|
+
return value === file2 || value.endsWith(`/${file2}`) || value.endsWith(`\\${file2}`);
|
|
20732
|
+
}
|
|
20733
|
+
function shellQuote(value, platform = process.platform) {
|
|
20734
|
+
if (platform === "win32")
|
|
20735
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
20736
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
20737
|
+
}
|
|
20738
|
+
function claudeParentHookCommand(hook, platform = process.platform) {
|
|
20739
|
+
const words = `${shellQuote(hook.command, platform)} ${shellQuote(hook.script, platform)}`;
|
|
20740
|
+
if (platform === "win32")
|
|
20741
|
+
return { command: `& ${words}; exit (Get-Variable LASTEXITCODE -ValueOnly)`, shell: "powershell" };
|
|
20742
|
+
return { command: `exec ${words}` };
|
|
20743
|
+
}
|
|
20744
|
+
function claudeParentHookEntries(profile, hook, platform = process.platform) {
|
|
20745
|
+
const command2 = { type: "command", ...claudeParentHookCommand(hook, platform) };
|
|
20746
|
+
const matcher = `^mcp__${profile.mcp_server}__(${profile.dispatch_tools.join("|")})$`;
|
|
20747
|
+
return {
|
|
20748
|
+
PreToolUse: [{ matcher, hooks: [{ ...command2, timeout: 15 }] }],
|
|
20749
|
+
PostToolUse: [{ matcher, hooks: [{ ...command2, asyncRewake: true, timeout: 86400 }] }],
|
|
20750
|
+
// 長く続く受信(channel)では、turnが終わるたびに待機を張り直す。
|
|
20751
|
+
...profile.channels ? { Stop: [{ hooks: [{ ...command2, asyncRewake: true, timeout: 86400 }] }] } : {},
|
|
20752
|
+
SessionEnd: [{ hooks: [{ ...command2, timeout: 15 }] }]
|
|
20753
|
+
};
|
|
20754
|
+
}
|
|
20755
|
+
function mergeClaudeParentHooks(profile, file2, hook) {
|
|
20756
|
+
const target = existsSync6(file2) ? realpathSync4(file2) : file2;
|
|
20757
|
+
let current = {};
|
|
20758
|
+
if (existsSync6(target)) {
|
|
20759
|
+
try {
|
|
20760
|
+
current = JSON.parse(readFileSync5(target, "utf8"));
|
|
20761
|
+
} catch {
|
|
20762
|
+
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9AJSON\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20763
|
+
}
|
|
20764
|
+
}
|
|
20765
|
+
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
20766
|
+
throw new SetupError("config_invalid", "Claude\u306Ehooks\u8A2D\u5B9A\u306Fobject\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
20767
|
+
}
|
|
20768
|
+
if (current.disableAllHooks === true)
|
|
20769
|
+
throw new SetupError("claude_parent_hooks_disabled", "Claude\u306Ehook\u304C\u7121\u52B9\u3067\u3059\u3002disableAllHooks\u3092false\u306B\u5909\u66F4\u3057\u3066\u304B\u3089setup\u3057\u3066\u304F\u3060\u3055\u3044");
|
|
20770
|
+
const hooks = { ...current.hooks };
|
|
20771
|
+
for (const [event, additions] of Object.entries(claudeParentHookEntries(profile, hook))) {
|
|
20772
|
+
const previous = hooks[event] ?? [];
|
|
20773
|
+
if (!Array.isArray(previous) || previous.some((group) => !record2(group) || !Array.isArray(group.hooks))) {
|
|
20774
|
+
throw new SetupError("config_invalid", `Claude\u306E${event} hook\u5F62\u5F0F\u3092\u8AAD\u3081\u307E\u305B\u3093`);
|
|
20775
|
+
}
|
|
20776
|
+
const owned = previous.flatMap((group) => group.hooks.filter((entry) => isClaudeParentHook(profile, entry)));
|
|
20777
|
+
if (owned.length === additions.flatMap((group) => group.hooks).length && additions.every((addition) => previous.some((group) => isDeepStrictEqual(group, addition))))
|
|
20778
|
+
continue;
|
|
20779
|
+
const retained = previous.map((group) => ({
|
|
20780
|
+
...group,
|
|
20781
|
+
hooks: group.hooks.filter((entry) => !isClaudeParentHook(profile, entry))
|
|
20782
|
+
})).filter((group) => group.hooks.length > 0);
|
|
20783
|
+
hooks[event] = [...retained, ...additions];
|
|
20784
|
+
}
|
|
20785
|
+
const next = { ...current, hooks };
|
|
20786
|
+
if (isDeepStrictEqual(current, next))
|
|
20787
|
+
return "unchanged";
|
|
20788
|
+
mkdirSync5(dirname3(target), { recursive: true });
|
|
20789
|
+
const temporary = `${target}.${profile.id}-${randomUUID2()}`;
|
|
20790
|
+
try {
|
|
20791
|
+
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20792
|
+
`, { mode: 384, flag: "wx" });
|
|
20793
|
+
if (existsSync6(target))
|
|
20794
|
+
copyFileSync(target, `${target}${profile.backup_suffix}`);
|
|
20795
|
+
renameSync2(temporary, target);
|
|
20796
|
+
} finally {
|
|
20797
|
+
if (existsSync6(temporary))
|
|
20798
|
+
unlinkSync3(temporary);
|
|
20799
|
+
}
|
|
20800
|
+
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target, "utf8")), next)) {
|
|
20801
|
+
throw new SetupError("config_readback_failed", "Claude\u306Ehook\u767B\u9332\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
20802
|
+
}
|
|
20803
|
+
return "configured";
|
|
20804
|
+
}
|
|
20805
|
+
function isClaudeParentHook(profile, hook) {
|
|
20806
|
+
if (!record2(hook) || hook.type !== "command")
|
|
20807
|
+
return false;
|
|
20808
|
+
if (Array.isArray(hook.args))
|
|
20809
|
+
return typeof hook.args[0] === "string" && endsWithFile(hook.args[0], profile.hooks.claude);
|
|
20810
|
+
return typeof hook.command === "string" && commandNamesFile(hook.command, profile.hooks.claude);
|
|
20811
|
+
}
|
|
20812
|
+
function ownedClaudeParentHooks(profile, document, event) {
|
|
20813
|
+
const hooks = record2(document) && record2(document.hooks) ? document.hooks[event] : void 0;
|
|
20814
|
+
if (!Array.isArray(hooks))
|
|
20815
|
+
return [];
|
|
20816
|
+
return hooks.flatMap((group) => record2(group) && Array.isArray(group.hooks) ? group.hooks : []).filter((entry) => isClaudeParentHook(profile, entry));
|
|
20817
|
+
}
|
|
20818
|
+
function claudeParentHooksRegistered(profile, document) {
|
|
20819
|
+
return Object.keys(claudeParentHookEntries(profile, { command: "", script: profile.hooks.claude })).every((event) => ownedClaudeParentHooks(profile, document, event).length > 0);
|
|
20820
|
+
}
|
|
20821
|
+
function removeClaudeParentHooks(profile, file2) {
|
|
20822
|
+
if (!existsSync6(file2))
|
|
20823
|
+
return "unchanged";
|
|
20824
|
+
const target = realpathSync4(file2);
|
|
20825
|
+
const current = JSON.parse(readFileSync5(target, "utf8"));
|
|
20826
|
+
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
20827
|
+
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20828
|
+
}
|
|
20829
|
+
if (current.hooks === void 0)
|
|
20830
|
+
return "unchanged";
|
|
20831
|
+
const hooks = { ...current.hooks };
|
|
20832
|
+
for (const event of ["PreToolUse", "PostToolUse", "Stop", "SessionEnd"]) {
|
|
20833
|
+
if (hooks[event] === void 0)
|
|
20834
|
+
continue;
|
|
20835
|
+
if (!Array.isArray(hooks[event]))
|
|
20836
|
+
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20837
|
+
hooks[event] = hooks[event].map((group) => {
|
|
20838
|
+
if (!record2(group) || !Array.isArray(group.hooks))
|
|
20839
|
+
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20840
|
+
return { ...group, hooks: group.hooks.filter((entry) => !isClaudeParentHook(profile, entry)) };
|
|
20841
|
+
}).filter((group) => group.hooks.length > 0);
|
|
20842
|
+
}
|
|
20843
|
+
const next = { ...current, hooks };
|
|
20844
|
+
if (isDeepStrictEqual(current, next))
|
|
20845
|
+
return "unchanged";
|
|
20846
|
+
const temporary = `${target}.${profile.id}-${randomUUID2()}`;
|
|
20847
|
+
try {
|
|
20848
|
+
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20849
|
+
`, { mode: 384, flag: "wx" });
|
|
20850
|
+
copyFileSync(target, `${target}${profile.backup_suffix}`);
|
|
20851
|
+
renameSync2(temporary, target);
|
|
20852
|
+
} finally {
|
|
20853
|
+
if (existsSync6(temporary))
|
|
20854
|
+
unlinkSync3(temporary);
|
|
20855
|
+
}
|
|
20856
|
+
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target, "utf8")), next))
|
|
20857
|
+
throw new SetupError("config_readback_failed", "Claude hook\u89E3\u9664\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
20858
|
+
return "removed";
|
|
20859
|
+
}
|
|
20860
|
+
function cursorParentHookCommand(hook) {
|
|
20861
|
+
const command2 = `${shellQuote(hook.command)} ${shellQuote(hook.script)}`;
|
|
20862
|
+
return process.platform === "win32" ? `& ${command2}` : command2;
|
|
20863
|
+
}
|
|
20864
|
+
function commandNamesFile(command2, file2) {
|
|
20865
|
+
const escaped = file2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20866
|
+
return new RegExp(`(?:^|[\\\\/'"\\s])${escaped}(?:['"\\s]|$)`, "u").test(command2);
|
|
20867
|
+
}
|
|
20868
|
+
function ownsCursorParentHook(profile, hook) {
|
|
20869
|
+
return record2(hook) && typeof hook.command === "string" && commandNamesFile(hook.command, profile.hooks.cursor);
|
|
20870
|
+
}
|
|
20871
|
+
function mergeCursorParentHooks(profile, file2, hook) {
|
|
20872
|
+
const target = existsSync6(file2) ? realpathSync4(file2) : file2;
|
|
20873
|
+
let current = { version: 1, hooks: {} };
|
|
20874
|
+
if (existsSync6(target)) {
|
|
20875
|
+
try {
|
|
20876
|
+
current = JSON.parse(readFileSync5(target, "utf8"));
|
|
20877
|
+
} catch {
|
|
20878
|
+
throw new SetupError("config_invalid", "Cursor\u306Ehook\u8A2D\u5B9AJSON\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20879
|
+
}
|
|
20880
|
+
} else {
|
|
20881
|
+
try {
|
|
20882
|
+
if (lstatSync(file2).isSymbolicLink())
|
|
20883
|
+
throw new SetupError("config_invalid", "Cursor\u306Ehooks\u8A2D\u5B9Asymlink\u306E\u53C2\u7167\u5148\u304C\u3042\u308A\u307E\u305B\u3093");
|
|
20884
|
+
} catch (error62) {
|
|
20885
|
+
if (error62.code !== "ENOENT")
|
|
20886
|
+
throw error62;
|
|
20887
|
+
}
|
|
20888
|
+
}
|
|
20889
|
+
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
20890
|
+
throw new SetupError("config_invalid", "Cursor\u306Ehooks\u8A2D\u5B9A\u306Fobject\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
20891
|
+
}
|
|
20892
|
+
const hooks = { ...current.hooks };
|
|
20893
|
+
const entry = { command: cursorParentHookCommand(hook), timeout: 15 };
|
|
20894
|
+
for (const event of ["afterMCPExecution", "postToolUse"]) {
|
|
20895
|
+
const previous = hooks[event] ?? [];
|
|
20896
|
+
if (!Array.isArray(previous))
|
|
20897
|
+
throw new SetupError("config_invalid", `Cursor\u306E${event} hook\u5F62\u5F0F\u3092\u8AAD\u3081\u307E\u305B\u3093`);
|
|
20898
|
+
const retained = previous.filter((hook2) => !ownsCursorParentHook(profile, hook2));
|
|
20899
|
+
const owned = previous.filter((hook2) => ownsCursorParentHook(profile, hook2));
|
|
20900
|
+
if (owned.length === 1 && isDeepStrictEqual(owned[0], entry) && retained.length + 1 === previous.length)
|
|
20901
|
+
continue;
|
|
20902
|
+
const index = previous.findIndex((hook2) => ownsCursorParentHook(profile, hook2));
|
|
20903
|
+
hooks[event] = index < 0 ? [...retained, entry] : previous.map((hook2, i) => i === index ? entry : hook2).filter((hook2, i) => i === index || !ownsCursorParentHook(profile, hook2));
|
|
20904
|
+
}
|
|
20905
|
+
const next = { ...current, version: current.version ?? 1, hooks };
|
|
20906
|
+
if (isDeepStrictEqual(current, next))
|
|
20907
|
+
return "unchanged";
|
|
20908
|
+
mkdirSync5(dirname3(target), { recursive: true });
|
|
20909
|
+
const temporary = `${target}.${profile.id}-${randomUUID2()}`;
|
|
20910
|
+
try {
|
|
20911
|
+
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20912
|
+
`, { mode: 384, flag: "wx" });
|
|
20913
|
+
if (existsSync6(target))
|
|
20914
|
+
copyFileSync(target, `${target}${profile.backup_suffix}`);
|
|
20915
|
+
renameSync2(temporary, target);
|
|
20916
|
+
} finally {
|
|
20917
|
+
if (existsSync6(temporary))
|
|
20918
|
+
unlinkSync3(temporary);
|
|
20919
|
+
}
|
|
20920
|
+
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target, "utf8")), next)) {
|
|
20921
|
+
throw new SetupError("config_readback_failed", "Cursor\u306Ehook\u767B\u9332\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
20922
|
+
}
|
|
20923
|
+
return "configured";
|
|
20924
|
+
}
|
|
20925
|
+
function removeCursorParentHooks(profile, file2) {
|
|
20926
|
+
if (!existsSync6(file2))
|
|
20927
|
+
return "unchanged";
|
|
20928
|
+
const target = realpathSync4(file2);
|
|
20929
|
+
const current = JSON.parse(readFileSync5(target, "utf8"));
|
|
20930
|
+
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
20931
|
+
throw new SetupError("config_invalid", "Cursor\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20932
|
+
}
|
|
20933
|
+
if (current.hooks === void 0)
|
|
20934
|
+
return "unchanged";
|
|
20935
|
+
const hooks = { ...current.hooks };
|
|
20936
|
+
for (const event of ["afterMCPExecution", "postToolUse"]) {
|
|
20937
|
+
if (hooks[event] === void 0)
|
|
20938
|
+
continue;
|
|
20939
|
+
if (!Array.isArray(hooks[event]))
|
|
20940
|
+
throw new SetupError("config_invalid", "Cursor\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
20941
|
+
const retained = hooks[event].filter((hook) => !ownsCursorParentHook(profile, hook));
|
|
20942
|
+
if (retained.length)
|
|
20943
|
+
hooks[event] = retained;
|
|
20944
|
+
else
|
|
20945
|
+
delete hooks[event];
|
|
20946
|
+
}
|
|
20947
|
+
const next = { ...current, hooks };
|
|
20948
|
+
if (isDeepStrictEqual(current, next))
|
|
20949
|
+
return "unchanged";
|
|
20950
|
+
const temporary = `${target}.${profile.id}-${randomUUID2()}`;
|
|
20951
|
+
try {
|
|
20952
|
+
writeFileSync3(temporary, `${JSON.stringify(next, null, 2)}
|
|
20953
|
+
`, { mode: 384, flag: "wx" });
|
|
20954
|
+
copyFileSync(target, `${target}${profile.backup_suffix}`);
|
|
20955
|
+
renameSync2(temporary, target);
|
|
20956
|
+
} finally {
|
|
20957
|
+
if (existsSync6(temporary))
|
|
20958
|
+
unlinkSync3(temporary);
|
|
20959
|
+
}
|
|
20960
|
+
if (!isDeepStrictEqual(JSON.parse(readFileSync5(target, "utf8")), next)) {
|
|
20961
|
+
throw new SetupError("config_readback_failed", "Cursor hook\u89E3\u9664\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
20962
|
+
}
|
|
20963
|
+
return "removed";
|
|
20964
|
+
}
|
|
20965
|
+
|
|
20966
|
+
// ../../node_modules/aiterm-steer-delivery/dist/cursor-receiver.js
|
|
20698
20967
|
var cursorParentSchema = external_exports.object({
|
|
20699
20968
|
kind: external_exports.literal("cursor"),
|
|
20700
20969
|
hook_root: external_exports.string()
|
|
@@ -20720,7 +20989,7 @@ function cursorParentHooksRegistered(profile, document) {
|
|
|
20720
20989
|
if (entry === null || typeof entry !== "object")
|
|
20721
20990
|
return false;
|
|
20722
20991
|
const command2 = entry.command;
|
|
20723
|
-
return typeof command2 === "string" && command2
|
|
20992
|
+
return typeof command2 === "string" && commandNamesFile(command2, profile.hooks.cursor);
|
|
20724
20993
|
});
|
|
20725
20994
|
};
|
|
20726
20995
|
return owns("postToolUse") && owns("afterMCPExecution");
|
|
@@ -20888,7 +21157,7 @@ function waitProcessCommandLine(wait, platform = process.platform) {
|
|
|
20888
21157
|
// ../../node_modules/aiterm-steer-delivery/dist/channel.js
|
|
20889
21158
|
import * as fs7 from "node:fs";
|
|
20890
21159
|
import * as path10 from "node:path";
|
|
20891
|
-
import { randomUUID as
|
|
21160
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
20892
21161
|
import { setTimeout as delay } from "node:timers/promises";
|
|
20893
21162
|
var uuid3 = external_exports.uuid();
|
|
20894
21163
|
var channelSchema = external_exports.object({
|
|
@@ -20914,7 +21183,7 @@ function mkdirs(...dirs) {
|
|
|
20914
21183
|
fs7.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
20915
21184
|
}
|
|
20916
21185
|
function openChannel(profile, parent) {
|
|
20917
|
-
const channel_id =
|
|
21186
|
+
const channel_id = randomUUID3();
|
|
20918
21187
|
const dir = channelDir(profile, channel_id);
|
|
20919
21188
|
const created_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
20920
21189
|
let channel;
|
|
@@ -20980,7 +21249,7 @@ async function sendToChannel(profile, channelId, deliveryId, text, runtime) {
|
|
|
20980
21249
|
}
|
|
20981
21250
|
const name = `${Date.now().toString().padStart(15, "0")}-${(sendSequence++).toString().padStart(9, "0")}-${deliveryId}.json`;
|
|
20982
21251
|
const item = { delivery_id: deliveryId, text, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
20983
|
-
const temporary = path10.join(dir, `.${deliveryId}.${
|
|
21252
|
+
const temporary = path10.join(dir, `.${deliveryId}.${randomUUID3()}.tmp`);
|
|
20984
21253
|
fs7.writeFileSync(temporary, JSON.stringify(item) + "\n", { flag: "wx", mode: 384 });
|
|
20985
21254
|
try {
|
|
20986
21255
|
fs7.linkSync(temporary, path10.join(dir, "inbox", name));
|
|
@@ -21019,6 +21288,25 @@ function channelDeliveryState(profile, channelId, deliveryId) {
|
|
|
21019
21288
|
}
|
|
21020
21289
|
return fs7.readdirSync(path10.join(dir, "inbox")).some((name) => name.endsWith(`-${deliveryId}.json`)) ? "queued" : null;
|
|
21021
21290
|
}
|
|
21291
|
+
function withdrawFromChannel(profile, channelId, deliveryId) {
|
|
21292
|
+
uuid3.parse(deliveryId);
|
|
21293
|
+
const dir = channelDir(profile, channelId);
|
|
21294
|
+
const inbox = path10.join(dir, "inbox");
|
|
21295
|
+
const name = fs7.existsSync(inbox) ? fs7.readdirSync(inbox).find((entry) => entry.endsWith(`-${deliveryId}.json`)) : void 0;
|
|
21296
|
+
if (!name)
|
|
21297
|
+
return false;
|
|
21298
|
+
const claim3 = path10.join(dir, "claims", `${deliveryId}.json`);
|
|
21299
|
+
try {
|
|
21300
|
+
fs7.linkSync(path10.join(inbox, name), claim3);
|
|
21301
|
+
fs7.unlinkSync(path10.join(inbox, name));
|
|
21302
|
+
} catch (error62) {
|
|
21303
|
+
if (["ENOENT", "EEXIST"].includes(error62.code ?? ""))
|
|
21304
|
+
return false;
|
|
21305
|
+
throw error62;
|
|
21306
|
+
}
|
|
21307
|
+
writeJson0600(claim3, { delivery_id: deliveryId, state: "withdrawn", at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
21308
|
+
return true;
|
|
21309
|
+
}
|
|
21022
21310
|
function claimPending(profile, channelId, by, limit = Infinity) {
|
|
21023
21311
|
const dir = channelDir(profile, channelId);
|
|
21024
21312
|
const inbox = path10.join(dir, "inbox");
|
|
@@ -21111,7 +21399,7 @@ function acquireWaiter(index) {
|
|
|
21111
21399
|
if (typeof owner.pid === "number" && typeof owner.started_identity === "string" && processIdentity2(owner.pid) === owner.started_identity)
|
|
21112
21400
|
return null;
|
|
21113
21401
|
try {
|
|
21114
|
-
fs7.renameSync(file2, path10.join(index, `waiter.${
|
|
21402
|
+
fs7.renameSync(file2, path10.join(index, `waiter.${randomUUID3()}.stale`));
|
|
21115
21403
|
} catch {
|
|
21116
21404
|
}
|
|
21117
21405
|
for (const name of fs7.readdirSync(index).filter((entry) => entry.endsWith(".stale")))
|
|
@@ -21313,6 +21601,8 @@ async function runCodexHookMain(profile, directory2 = process.argv[2]) {
|
|
|
21313
21601
|
async function runClaudeHookMain(profile, root = claudeHookRoot(profile)) {
|
|
21314
21602
|
try {
|
|
21315
21603
|
const event = JSON.parse(await readStdin());
|
|
21604
|
+
if (event !== null && typeof event === "object" && typeof event.hookEventName === "string")
|
|
21605
|
+
return;
|
|
21316
21606
|
const write = (text) => new Promise((resolve2, reject) => {
|
|
21317
21607
|
process.stderr.write(text, (error62) => error62 ? reject(error62) : resolve2());
|
|
21318
21608
|
});
|
|
@@ -21383,7 +21673,7 @@ function setupNodeExecutable(executable = process.execPath) {
|
|
|
21383
21673
|
// ../../node_modules/aiterm-steer-delivery/dist/codex-setup.js
|
|
21384
21674
|
import * as fs8 from "node:fs";
|
|
21385
21675
|
import * as path11 from "node:path";
|
|
21386
|
-
import { isDeepStrictEqual } from "node:util";
|
|
21676
|
+
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
21387
21677
|
function codexHookCommand(node2, hook, directory2, platform = process.platform, powershell = () => resolveWindowsPowerShell7()) {
|
|
21388
21678
|
if (platform === "win32") {
|
|
21389
21679
|
const script = `& ${[node2, hook, directory2].map(quotePowerShell).join(" ")}; exit $LASTEXITCODE`;
|
|
@@ -21453,7 +21743,7 @@ function planCodexParentHooks(file2, command2, previousCommand) {
|
|
|
21453
21743
|
delete hooks[event];
|
|
21454
21744
|
}
|
|
21455
21745
|
const next = { ...current, hooks };
|
|
21456
|
-
return { target, current, next, changed: !
|
|
21746
|
+
return { target, current, next, changed: !isDeepStrictEqual2(current, next), moves, owned: ownedAt };
|
|
21457
21747
|
}
|
|
21458
21748
|
function writeCodexHookPlan(profile, plan) {
|
|
21459
21749
|
if (!plan.changed)
|
|
@@ -21461,7 +21751,7 @@ function writeCodexHookPlan(profile, plan) {
|
|
|
21461
21751
|
if (fs8.existsSync(plan.target))
|
|
21462
21752
|
fs8.copyFileSync(plan.target, `${plan.target}${profile.backup_suffix}`);
|
|
21463
21753
|
writeHookJson(plan.target, plan.next);
|
|
21464
|
-
if (!
|
|
21754
|
+
if (!isDeepStrictEqual2(JSON.parse(fs8.readFileSync(plan.target, "utf8")), plan.next))
|
|
21465
21755
|
throw new SetupError("codex_hook_readback_failed", "Codex hook\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
21466
21756
|
return true;
|
|
21467
21757
|
}
|
|
@@ -21657,222 +21947,6 @@ async function configureCodexSteer(profile, action = "status", overrides) {
|
|
|
21657
21947
|
return needsRestart(config2) ? { status: "restart_required", reason_code: "codex_restart_required" } : { status: "ready" };
|
|
21658
21948
|
}
|
|
21659
21949
|
|
|
21660
|
-
// ../../node_modules/aiterm-steer-delivery/dist/hook-setup.js
|
|
21661
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync9, lstatSync as lstatSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync8, realpathSync as realpathSync4, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
21662
|
-
import { dirname as dirname4 } from "node:path";
|
|
21663
|
-
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
21664
|
-
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
21665
|
-
var record2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21666
|
-
function endsWithFile(value, file2) {
|
|
21667
|
-
return value === file2 || value.endsWith(`/${file2}`) || value.endsWith(`\\${file2}`);
|
|
21668
|
-
}
|
|
21669
|
-
function claudeParentHookEntries(profile, hook) {
|
|
21670
|
-
const command2 = { type: "command", command: hook.command, args: [hook.script] };
|
|
21671
|
-
const matcher = `^mcp__${profile.mcp_server}__(${profile.dispatch_tools.join("|")})$`;
|
|
21672
|
-
return {
|
|
21673
|
-
PreToolUse: [{ matcher, hooks: [{ ...command2, timeout: 15 }] }],
|
|
21674
|
-
PostToolUse: [{ matcher, hooks: [{ ...command2, asyncRewake: true, timeout: 86400 }] }],
|
|
21675
|
-
// 長く続く受信(channel)では、turnが終わるたびに待機を張り直す。
|
|
21676
|
-
...profile.channels ? { Stop: [{ hooks: [{ ...command2, asyncRewake: true, timeout: 86400 }] }] } : {},
|
|
21677
|
-
SessionEnd: [{ hooks: [{ ...command2, timeout: 15 }] }]
|
|
21678
|
-
};
|
|
21679
|
-
}
|
|
21680
|
-
function mergeClaudeParentHooks(profile, file2, hook) {
|
|
21681
|
-
const target = existsSync9(file2) ? realpathSync4(file2) : file2;
|
|
21682
|
-
let current = {};
|
|
21683
|
-
if (existsSync9(target)) {
|
|
21684
|
-
try {
|
|
21685
|
-
current = JSON.parse(readFileSync8(target, "utf8"));
|
|
21686
|
-
} catch {
|
|
21687
|
-
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9AJSON\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21688
|
-
}
|
|
21689
|
-
}
|
|
21690
|
-
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
21691
|
-
throw new SetupError("config_invalid", "Claude\u306Ehooks\u8A2D\u5B9A\u306Fobject\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
21692
|
-
}
|
|
21693
|
-
if (current.disableAllHooks === true)
|
|
21694
|
-
throw new SetupError("claude_parent_hooks_disabled", "Claude\u306Ehook\u304C\u7121\u52B9\u3067\u3059\u3002disableAllHooks\u3092false\u306B\u5909\u66F4\u3057\u3066\u304B\u3089setup\u3057\u3066\u304F\u3060\u3055\u3044");
|
|
21695
|
-
const hooks = { ...current.hooks };
|
|
21696
|
-
for (const [event, additions] of Object.entries(claudeParentHookEntries(profile, hook))) {
|
|
21697
|
-
const previous = hooks[event] ?? [];
|
|
21698
|
-
if (!Array.isArray(previous) || previous.some((group) => !record2(group) || !Array.isArray(group.hooks))) {
|
|
21699
|
-
throw new SetupError("config_invalid", `Claude\u306E${event} hook\u5F62\u5F0F\u3092\u8AAD\u3081\u307E\u305B\u3093`);
|
|
21700
|
-
}
|
|
21701
|
-
const retained = previous.map((group) => ({
|
|
21702
|
-
...group,
|
|
21703
|
-
hooks: group.hooks.filter((entry) => !isClaudeParentHook(profile, entry))
|
|
21704
|
-
})).filter((group) => group.hooks.length > 0);
|
|
21705
|
-
hooks[event] = [...retained, ...additions];
|
|
21706
|
-
}
|
|
21707
|
-
const next = { ...current, hooks };
|
|
21708
|
-
if (isDeepStrictEqual2(current, next))
|
|
21709
|
-
return "unchanged";
|
|
21710
|
-
mkdirSync7(dirname4(target), { recursive: true });
|
|
21711
|
-
const temporary = `${target}.${profile.id}-${randomUUID3()}`;
|
|
21712
|
-
try {
|
|
21713
|
-
writeFileSync5(temporary, `${JSON.stringify(next, null, 2)}
|
|
21714
|
-
`, { mode: 384, flag: "wx" });
|
|
21715
|
-
if (existsSync9(target))
|
|
21716
|
-
copyFileSync2(target, `${target}${profile.backup_suffix}`);
|
|
21717
|
-
renameSync3(temporary, target);
|
|
21718
|
-
} finally {
|
|
21719
|
-
if (existsSync9(temporary))
|
|
21720
|
-
unlinkSync4(temporary);
|
|
21721
|
-
}
|
|
21722
|
-
if (!isDeepStrictEqual2(JSON.parse(readFileSync8(target, "utf8")), next)) {
|
|
21723
|
-
throw new SetupError("config_readback_failed", "Claude\u306Ehook\u767B\u9332\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
21724
|
-
}
|
|
21725
|
-
return "configured";
|
|
21726
|
-
}
|
|
21727
|
-
function isClaudeParentHook(profile, hook) {
|
|
21728
|
-
return record2(hook) && hook.type === "command" && Array.isArray(hook.args) && typeof hook.args[0] === "string" && endsWithFile(hook.args[0], profile.hooks.claude);
|
|
21729
|
-
}
|
|
21730
|
-
function removeClaudeParentHooks(profile, file2) {
|
|
21731
|
-
if (!existsSync9(file2))
|
|
21732
|
-
return "unchanged";
|
|
21733
|
-
const target = realpathSync4(file2);
|
|
21734
|
-
const current = JSON.parse(readFileSync8(target, "utf8"));
|
|
21735
|
-
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
21736
|
-
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21737
|
-
}
|
|
21738
|
-
if (current.hooks === void 0)
|
|
21739
|
-
return "unchanged";
|
|
21740
|
-
const hooks = { ...current.hooks };
|
|
21741
|
-
for (const event of ["PreToolUse", "PostToolUse", "Stop", "SessionEnd"]) {
|
|
21742
|
-
if (hooks[event] === void 0)
|
|
21743
|
-
continue;
|
|
21744
|
-
if (!Array.isArray(hooks[event]))
|
|
21745
|
-
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21746
|
-
hooks[event] = hooks[event].map((group) => {
|
|
21747
|
-
if (!record2(group) || !Array.isArray(group.hooks))
|
|
21748
|
-
throw new SetupError("config_invalid", "Claude\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21749
|
-
return { ...group, hooks: group.hooks.filter((entry) => !isClaudeParentHook(profile, entry)) };
|
|
21750
|
-
}).filter((group) => group.hooks.length > 0);
|
|
21751
|
-
}
|
|
21752
|
-
const next = { ...current, hooks };
|
|
21753
|
-
if (isDeepStrictEqual2(current, next))
|
|
21754
|
-
return "unchanged";
|
|
21755
|
-
const temporary = `${target}.${profile.id}-${randomUUID3()}`;
|
|
21756
|
-
try {
|
|
21757
|
-
writeFileSync5(temporary, `${JSON.stringify(next, null, 2)}
|
|
21758
|
-
`, { mode: 384, flag: "wx" });
|
|
21759
|
-
copyFileSync2(target, `${target}${profile.backup_suffix}`);
|
|
21760
|
-
renameSync3(temporary, target);
|
|
21761
|
-
} finally {
|
|
21762
|
-
if (existsSync9(temporary))
|
|
21763
|
-
unlinkSync4(temporary);
|
|
21764
|
-
}
|
|
21765
|
-
if (!isDeepStrictEqual2(JSON.parse(readFileSync8(target, "utf8")), next))
|
|
21766
|
-
throw new SetupError("config_readback_failed", "Claude hook\u89E3\u9664\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
21767
|
-
return "removed";
|
|
21768
|
-
}
|
|
21769
|
-
function shellQuote(value) {
|
|
21770
|
-
if (process.platform === "win32")
|
|
21771
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
21772
|
-
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
21773
|
-
}
|
|
21774
|
-
function cursorParentHookCommand(hook) {
|
|
21775
|
-
const command2 = `${shellQuote(hook.command)} ${shellQuote(hook.script)}`;
|
|
21776
|
-
return process.platform === "win32" ? `& ${command2}` : command2;
|
|
21777
|
-
}
|
|
21778
|
-
function ownsCursorParentHook(profile, hook) {
|
|
21779
|
-
return record2(hook) && typeof hook.command === "string" && hook.command.includes(profile.hooks.cursor);
|
|
21780
|
-
}
|
|
21781
|
-
function mergeCursorParentHooks(profile, file2, hook) {
|
|
21782
|
-
const target = existsSync9(file2) ? realpathSync4(file2) : file2;
|
|
21783
|
-
let current = { version: 1, hooks: {} };
|
|
21784
|
-
if (existsSync9(target)) {
|
|
21785
|
-
try {
|
|
21786
|
-
current = JSON.parse(readFileSync8(target, "utf8"));
|
|
21787
|
-
} catch {
|
|
21788
|
-
throw new SetupError("config_invalid", "Cursor\u306Ehook\u8A2D\u5B9AJSON\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21789
|
-
}
|
|
21790
|
-
} else {
|
|
21791
|
-
try {
|
|
21792
|
-
if (lstatSync2(file2).isSymbolicLink())
|
|
21793
|
-
throw new SetupError("config_invalid", "Cursor\u306Ehooks\u8A2D\u5B9Asymlink\u306E\u53C2\u7167\u5148\u304C\u3042\u308A\u307E\u305B\u3093");
|
|
21794
|
-
} catch (error62) {
|
|
21795
|
-
if (error62.code !== "ENOENT")
|
|
21796
|
-
throw error62;
|
|
21797
|
-
}
|
|
21798
|
-
}
|
|
21799
|
-
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
21800
|
-
throw new SetupError("config_invalid", "Cursor\u306Ehooks\u8A2D\u5B9A\u306Fobject\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
21801
|
-
}
|
|
21802
|
-
const hooks = { ...current.hooks };
|
|
21803
|
-
const entry = { command: cursorParentHookCommand(hook), timeout: 15 };
|
|
21804
|
-
for (const event of ["afterMCPExecution", "postToolUse"]) {
|
|
21805
|
-
const previous = hooks[event] ?? [];
|
|
21806
|
-
if (!Array.isArray(previous))
|
|
21807
|
-
throw new SetupError("config_invalid", `Cursor\u306E${event} hook\u5F62\u5F0F\u3092\u8AAD\u3081\u307E\u305B\u3093`);
|
|
21808
|
-
const retained = previous.filter((hook2) => !ownsCursorParentHook(profile, hook2));
|
|
21809
|
-
const owned = previous.filter((hook2) => ownsCursorParentHook(profile, hook2));
|
|
21810
|
-
if (owned.length === 1 && isDeepStrictEqual2(owned[0], entry) && retained.length + 1 === previous.length)
|
|
21811
|
-
continue;
|
|
21812
|
-
const index = previous.findIndex((hook2) => ownsCursorParentHook(profile, hook2));
|
|
21813
|
-
hooks[event] = index < 0 ? [...retained, entry] : previous.map((hook2, i) => i === index ? entry : hook2).filter((hook2, i) => i === index || !ownsCursorParentHook(profile, hook2));
|
|
21814
|
-
}
|
|
21815
|
-
const next = { ...current, version: current.version ?? 1, hooks };
|
|
21816
|
-
if (isDeepStrictEqual2(current, next))
|
|
21817
|
-
return "unchanged";
|
|
21818
|
-
mkdirSync7(dirname4(target), { recursive: true });
|
|
21819
|
-
const temporary = `${target}.${profile.id}-${randomUUID3()}`;
|
|
21820
|
-
try {
|
|
21821
|
-
writeFileSync5(temporary, `${JSON.stringify(next, null, 2)}
|
|
21822
|
-
`, { mode: 384, flag: "wx" });
|
|
21823
|
-
if (existsSync9(target))
|
|
21824
|
-
copyFileSync2(target, `${target}${profile.backup_suffix}`);
|
|
21825
|
-
renameSync3(temporary, target);
|
|
21826
|
-
} finally {
|
|
21827
|
-
if (existsSync9(temporary))
|
|
21828
|
-
unlinkSync4(temporary);
|
|
21829
|
-
}
|
|
21830
|
-
if (!isDeepStrictEqual2(JSON.parse(readFileSync8(target, "utf8")), next)) {
|
|
21831
|
-
throw new SetupError("config_readback_failed", "Cursor\u306Ehook\u767B\u9332\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
21832
|
-
}
|
|
21833
|
-
return "configured";
|
|
21834
|
-
}
|
|
21835
|
-
function removeCursorParentHooks(profile, file2) {
|
|
21836
|
-
if (!existsSync9(file2))
|
|
21837
|
-
return "unchanged";
|
|
21838
|
-
const target = realpathSync4(file2);
|
|
21839
|
-
const current = JSON.parse(readFileSync8(target, "utf8"));
|
|
21840
|
-
if (!record2(current) || current.hooks !== void 0 && !record2(current.hooks)) {
|
|
21841
|
-
throw new SetupError("config_invalid", "Cursor\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21842
|
-
}
|
|
21843
|
-
if (current.hooks === void 0)
|
|
21844
|
-
return "unchanged";
|
|
21845
|
-
const hooks = { ...current.hooks };
|
|
21846
|
-
for (const event of ["afterMCPExecution", "postToolUse"]) {
|
|
21847
|
-
if (hooks[event] === void 0)
|
|
21848
|
-
continue;
|
|
21849
|
-
if (!Array.isArray(hooks[event]))
|
|
21850
|
-
throw new SetupError("config_invalid", "Cursor\u306Ehook\u8A2D\u5B9A\u3092\u8AAD\u3081\u307E\u305B\u3093");
|
|
21851
|
-
const retained = hooks[event].filter((hook) => !ownsCursorParentHook(profile, hook));
|
|
21852
|
-
if (retained.length)
|
|
21853
|
-
hooks[event] = retained;
|
|
21854
|
-
else
|
|
21855
|
-
delete hooks[event];
|
|
21856
|
-
}
|
|
21857
|
-
const next = { ...current, hooks };
|
|
21858
|
-
if (isDeepStrictEqual2(current, next))
|
|
21859
|
-
return "unchanged";
|
|
21860
|
-
const temporary = `${target}.${profile.id}-${randomUUID3()}`;
|
|
21861
|
-
try {
|
|
21862
|
-
writeFileSync5(temporary, `${JSON.stringify(next, null, 2)}
|
|
21863
|
-
`, { mode: 384, flag: "wx" });
|
|
21864
|
-
copyFileSync2(target, `${target}${profile.backup_suffix}`);
|
|
21865
|
-
renameSync3(temporary, target);
|
|
21866
|
-
} finally {
|
|
21867
|
-
if (existsSync9(temporary))
|
|
21868
|
-
unlinkSync4(temporary);
|
|
21869
|
-
}
|
|
21870
|
-
if (!isDeepStrictEqual2(JSON.parse(readFileSync8(target, "utf8")), next)) {
|
|
21871
|
-
throw new SetupError("config_readback_failed", "Cursor hook\u89E3\u9664\u306E\u8AAD\u623B\u3057\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093");
|
|
21872
|
-
}
|
|
21873
|
-
return "removed";
|
|
21874
|
-
}
|
|
21875
|
-
|
|
21876
21950
|
export {
|
|
21877
21951
|
__require,
|
|
21878
21952
|
__commonJS,
|
|
@@ -21910,21 +21984,23 @@ export {
|
|
|
21910
21984
|
verifyCodexParent,
|
|
21911
21985
|
configureCodexSteer,
|
|
21912
21986
|
claudeParentFromRequest,
|
|
21913
|
-
isCursorMcpClient,
|
|
21914
|
-
cursorParentHooksRegistered,
|
|
21915
|
-
verifyCursorParent,
|
|
21916
|
-
handleCursorHook,
|
|
21917
|
-
waitProcessCommandLine,
|
|
21918
21987
|
mergeClaudeParentHooks,
|
|
21988
|
+
claudeParentHooksRegistered,
|
|
21919
21989
|
removeClaudeParentHooks,
|
|
21920
21990
|
cursorParentHookCommand,
|
|
21921
21991
|
mergeCursorParentHooks,
|
|
21922
21992
|
removeCursorParentHooks,
|
|
21993
|
+
isCursorMcpClient,
|
|
21994
|
+
cursorParentHooksRegistered,
|
|
21995
|
+
verifyCursorParent,
|
|
21996
|
+
handleCursorHook,
|
|
21997
|
+
waitProcessCommandLine,
|
|
21923
21998
|
openChannel,
|
|
21924
21999
|
readChannel,
|
|
21925
22000
|
channelClosed,
|
|
21926
22001
|
sendToChannel,
|
|
21927
22002
|
channelDeliveryState,
|
|
22003
|
+
withdrawFromChannel,
|
|
21928
22004
|
channelMarker,
|
|
21929
22005
|
handleCursorChannelHook,
|
|
21930
22006
|
channelReceiveProcess,
|
package/dist/cli.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
channelReceiveProcess,
|
|
18
18
|
claudeHookRoot,
|
|
19
19
|
claudeParentFromRequest,
|
|
20
|
+
claudeParentHooksRegistered,
|
|
20
21
|
codexParentFromRequest,
|
|
21
22
|
configureCodexSteer,
|
|
22
23
|
cursorHookRoot,
|
|
@@ -51,8 +52,9 @@ import {
|
|
|
51
52
|
verifyCodexParent,
|
|
52
53
|
verifyCursorParent,
|
|
53
54
|
waitProcessCommandLine,
|
|
54
|
-
withCodexReceiver
|
|
55
|
-
|
|
55
|
+
withCodexReceiver,
|
|
56
|
+
withdrawFromChannel
|
|
57
|
+
} from "./chunks/chunk-GH2JG56Y.mjs";
|
|
56
58
|
|
|
57
59
|
// ../../node_modules/qrcode/lib/can-promise.js
|
|
58
60
|
var require_can_promise = __commonJS({
|
|
@@ -12074,7 +12076,24 @@ async function runDaemon() {
|
|
|
12074
12076
|
again = false;
|
|
12075
12077
|
try {
|
|
12076
12078
|
const { items } = await api.call("GET", "/deliveries");
|
|
12077
|
-
|
|
12079
|
+
const waiting = new Map(items.map((item) => [item.decision_id, item]));
|
|
12080
|
+
for (const [id, entry] of Object.entries(journal)) {
|
|
12081
|
+
if (entry.state !== "queued") continue;
|
|
12082
|
+
const item = waiting.get(id);
|
|
12083
|
+
if (item && item.delivery_id === entry.delivery_id && item.route.channel_id === entry.channel_id) continue;
|
|
12084
|
+
const withdrawn = withdrawFromChannel(PROFILE, entry.channel_id, entry.delivery_id);
|
|
12085
|
+
if (withdrawn || !item) {
|
|
12086
|
+
delete journal[id];
|
|
12087
|
+
save();
|
|
12088
|
+
log(`\u914D\u9001 ${id} \u2192 ${withdrawn ? "withdrawn" : "resolved"}`);
|
|
12089
|
+
} else {
|
|
12090
|
+
Object.assign(entry, safeState(entry) === "emitted" ? { state: "report", result: "delivered" } : { state: "report", result: "unknown", detail: "\u914D\u9001\u5148\u306E\u5909\u66F4\u524D\u306B\u53D7\u3051\u53E3\u304C\u672C\u6587\u3092\u53D6\u5F97\u3057\u307E\u3057\u305F\u3002\u518D\u9001\u3057\u307E\u305B\u3093" });
|
|
12091
|
+
save();
|
|
12092
|
+
await report(id);
|
|
12093
|
+
waiting.delete(id);
|
|
12094
|
+
}
|
|
12095
|
+
}
|
|
12096
|
+
for (const item of waiting.values()) await deliver(item);
|
|
12078
12097
|
} catch (error) {
|
|
12079
12098
|
log(`\u914D\u9001\u5F85\u3061\u306E\u53D6\u5F97\u306B\u5931\u6557: ${error.message}`);
|
|
12080
12099
|
}
|
|
@@ -12247,7 +12266,7 @@ function stableNode() {
|
|
|
12247
12266
|
return process.execPath;
|
|
12248
12267
|
}
|
|
12249
12268
|
}
|
|
12250
|
-
var CURSOR_TOOLS = ["list_my_decisions", "request_decision", "amend_decision", "cancel_decision", "get_decision", "get_attachment", "setup_test", "confirm_setup_test"];
|
|
12269
|
+
var CURSOR_TOOLS = ["list_my_decisions", "request_decision", "amend_decision", "resume_decision", "cancel_decision", "get_decision", "get_attachment", "setup_test", "confirm_setup_test"];
|
|
12251
12270
|
var cursorCliConfig = () => join6(cursorDir(), "cli-config.json");
|
|
12252
12271
|
function setCursorPermissions(enable) {
|
|
12253
12272
|
const file = cursorCliConfig();
|
|
@@ -12389,9 +12408,9 @@ function registeredTools(target) {
|
|
|
12389
12408
|
const entryOf = (value) => (value?.args ?? [])[0];
|
|
12390
12409
|
if (target === "claude") {
|
|
12391
12410
|
const entry = readJson(claudeJson()).mcpServers?.[MCP_SERVER];
|
|
12392
|
-
const settings =
|
|
12411
|
+
const settings = readJson(join6(claudeDir(), "settings.json"));
|
|
12393
12412
|
const e = entryOf(entry);
|
|
12394
|
-
return { mcp: !!entry, hooks:
|
|
12413
|
+
return { mcp: !!entry, hooks: claudeParentHooksRegistered(PROFILE, settings), ...e ? { entry: e } : {} };
|
|
12395
12414
|
}
|
|
12396
12415
|
if (target === "cursor") {
|
|
12397
12416
|
const entry = readJson(join6(cursorDir(), "mcp.json")).mcpServers?.[MCP_SERVER];
|
|
@@ -15770,7 +15789,7 @@ import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:f
|
|
|
15770
15789
|
import { basename as basename2, join as join7 } from "node:path";
|
|
15771
15790
|
|
|
15772
15791
|
// src/version.ts
|
|
15773
|
-
var VERSION = true ? "0.1.
|
|
15792
|
+
var VERSION = true ? "0.1.14" : "0.0.0-dev";
|
|
15774
15793
|
function osName() {
|
|
15775
15794
|
return process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : process.platform;
|
|
15776
15795
|
}
|
|
@@ -15786,6 +15805,7 @@ function harnessOf(clientName) {
|
|
|
15786
15805
|
return "other";
|
|
15787
15806
|
}
|
|
15788
15807
|
var INSTRUCTIONS = [
|
|
15808
|
+
"\u4F1A\u8A71\u304C\u66FF\u308F\u3063\u305F\u3089 list_my_decisions \u3067\u81EA\u5206\u304C\u5F15\u304D\u7D99\u3050\u7533\u8ACB\u3092\u78BA\u304B\u3081\u3001\u7533\u8ACB\u3054\u3068\u306B resume_decision \u3092\u547C\u3076\u3002\u672A\u6C7A\u30FB\u4FDD\u7559\u306E\u7B54\u3048\u306F\u65B0\u3057\u3044\u4F1A\u8A71\u3078\u5C4A\u304D\u3001\u56DE\u7B54\u6E08\u307F\u306A\u3089\u305D\u306E\u5834\u3067\u7B54\u3048\u304C\u8FD4\u308B\u3002",
|
|
15789
15809
|
"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",
|
|
15790
15810
|
"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",
|
|
15791
15811
|
"\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",
|
|
@@ -15844,6 +15864,11 @@ var TOOLS = [
|
|
|
15844
15864
|
additionalProperties: false
|
|
15845
15865
|
}
|
|
15846
15866
|
},
|
|
15867
|
+
{
|
|
15868
|
+
name: "resume_decision",
|
|
15869
|
+
description: "\u524D\u306E\u4F1A\u8A71\u304B\u3089\u5F15\u304D\u7D99\u3044\u3060\u81EA\u5206\u306E\u7533\u8ACB\u3092\u3001\u3053\u306E\u4F1A\u8A71\u3067\u518D\u958B\u3059\u308B\u3002\u672A\u6C7A\u30FB\u4FDD\u7559\u306A\u3089\u7B54\u3048\u306E\u914D\u9001\u5148\u3092\u3053\u306E\u4F1A\u8A71\u3078\u5909\u66F4\u3057\u3001\u56DE\u7B54\u6E08\u307F\u306A\u3089\u7B54\u3048\u3092\u76F4\u63A5\u8FD4\u3059\u3002list_my_decisions\u3067\u5BFE\u8C61\u3092\u78BA\u304B\u3081\u3001\u5F15\u304D\u7D99\u3050\u7533\u8ACB\u3054\u3068\u306B\u547C\u3076\u3002",
|
|
15870
|
+
inputSchema: { type: "object", properties: { decision_id: { type: "string" } }, required: ["decision_id"], additionalProperties: false }
|
|
15871
|
+
},
|
|
15847
15872
|
{
|
|
15848
15873
|
name: "cancel_decision",
|
|
15849
15874
|
description: "\u672A\u6C7A\u30FB\u4FDD\u7559\u306E\u81EA\u5206\u306E\u7533\u8ACB\u3092\u53D6\u308A\u4E0B\u3052\u308B\u3002reason \u306B\u7406\u7531\u3092\u66F8\u304F\u3002",
|
|
@@ -16028,10 +16053,21 @@ ${JSON.stringify({ error: "duplicate_suspected", existing })}`, { error: "duplic
|
|
|
16028
16053
|
}
|
|
16029
16054
|
if (name === "amend_decision") {
|
|
16030
16055
|
const { decision_id, ...rest } = args;
|
|
16031
|
-
const
|
|
16032
|
-
|
|
16056
|
+
const channelId = await channelFor(harness, clientName, request.params._meta);
|
|
16057
|
+
const decision = await api.call("POST", `/decisions/${encodeURIComponent(String(decision_id))}/amend`, { ...rest, route: { channel_id: channelId, harness } });
|
|
16058
|
+
lastChannel = channelId;
|
|
16059
|
+
return text(`\u76F4\u3057\u307E\u3057\u305F: ${decision.decision_id} version=${decision.version}${receiveGuide(harness, channelId)}
|
|
16033
16060
|
|
|
16034
|
-
${JSON.stringify(decision)}`, decision);
|
|
16061
|
+
${JSON.stringify(decision)}`, { ...decision, steer_channel: { channel_id: channelId } });
|
|
16062
|
+
}
|
|
16063
|
+
if (name === "resume_decision") {
|
|
16064
|
+
const channelId = await channelFor(harness, clientName, request.params._meta);
|
|
16065
|
+
const decision = await api.call("POST", `/decisions/${encodeURIComponent(String(args.decision_id))}/resume`, { channel_id: channelId, harness });
|
|
16066
|
+
lastChannel = channelId;
|
|
16067
|
+
const head = decision.answer_text ? String(decision.answer_text) : `\u518D\u958B\u3057\u307E\u3057\u305F: ${decision.decision_id}\u3002\u7B54\u3048\u306F\u3053\u306E\u4F1A\u8A71\u3078\u5C4A\u304D\u307E\u3059\u3002`;
|
|
16068
|
+
return text(`${head}${decision.answer_text ? "" : receiveGuide(harness, channelId)}
|
|
16069
|
+
|
|
16070
|
+
${JSON.stringify(decision)}`, { ...decision, steer_channel: { channel_id: channelId } });
|
|
16035
16071
|
}
|
|
16036
16072
|
if (name === "cancel_decision") {
|
|
16037
16073
|
const decision = await api.call("POST", `/decisions/${encodeURIComponent(String(args.decision_id))}/cancel`, { reason: args.reason });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "approval-box",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
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",
|
|
@@ -28,14 +28,13 @@
|
|
|
28
28
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
29
29
|
"test": "node --test 'test/**/*.test.ts'"
|
|
30
30
|
},
|
|
31
|
-
"dependencies": {},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
34
33
|
"@types/node": "^25.9.1",
|
|
35
|
-
"
|
|
34
|
+
"@types/qrcode": "^1.5.5",
|
|
35
|
+
"aiterm-steer-delivery": "^0.2.0",
|
|
36
36
|
"esbuild": "^0.28.2",
|
|
37
37
|
"qrcode": "^1.5.4",
|
|
38
|
-
"@types/qrcode": "^1.5.5",
|
|
39
38
|
"typescript": "^6.0.3",
|
|
40
39
|
"zod": "^4.4.3"
|
|
41
40
|
},
|