agentapprove 0.1.7 → 0.1.9
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 +1 -1
- package/dist/cli.js +258 -42
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ agentapprove --no-e2e # Skip end-to-end encryption setup
|
|
|
95
95
|
- Node.js 18+
|
|
96
96
|
- macOS, Linux, or Windows (with Git Bash / Git for Windows)
|
|
97
97
|
- System tools: `curl`, `jq`, `openssl` (included with Git Bash on Windows)
|
|
98
|
-
- Agent Approve iOS app and active subscription ($
|
|
98
|
+
- Agent Approve iOS app and active subscription ($14.99/month, 7-day free trial)
|
|
99
99
|
|
|
100
100
|
## Links
|
|
101
101
|
|
package/dist/cli.js
CHANGED
|
@@ -5,21 +5,35 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
8
13
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
9
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
23
|
for (let key of __getOwnPropNames(mod))
|
|
12
24
|
if (!__hasOwnProp.call(to, key))
|
|
13
25
|
__defProp(to, key, {
|
|
14
|
-
get: (
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
15
27
|
enumerable: true
|
|
16
28
|
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
17
31
|
return to;
|
|
18
32
|
};
|
|
19
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
20
34
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
21
35
|
|
|
22
|
-
// node_modules/sisteransi/src/index.js
|
|
36
|
+
// ../../node_modules/.bun/sisteransi@1.0.5/node_modules/sisteransi/src/index.js
|
|
23
37
|
var require_src = __commonJS((exports, module) => {
|
|
24
38
|
var ESC = "\x1B";
|
|
25
39
|
var CSI = `${ESC}[`;
|
|
@@ -77,7 +91,7 @@ var require_src = __commonJS((exports, module) => {
|
|
|
77
91
|
module.exports = { cursor, scroll, erase, beep };
|
|
78
92
|
});
|
|
79
93
|
|
|
80
|
-
// node_modules/picocolors/picocolors.js
|
|
94
|
+
// ../../node_modules/.bun/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
81
95
|
var require_picocolors = __commonJS((exports, module) => {
|
|
82
96
|
var p = process || {};
|
|
83
97
|
var argv = p.argv || [];
|
|
@@ -147,7 +161,7 @@ var require_picocolors = __commonJS((exports, module) => {
|
|
|
147
161
|
module.exports.createColors = createColors;
|
|
148
162
|
});
|
|
149
163
|
|
|
150
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
|
|
164
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
|
|
151
165
|
var require_QRMode = __commonJS((exports, module) => {
|
|
152
166
|
module.exports = {
|
|
153
167
|
MODE_NUMBER: 1 << 0,
|
|
@@ -157,7 +171,7 @@ var require_QRMode = __commonJS((exports, module) => {
|
|
|
157
171
|
};
|
|
158
172
|
});
|
|
159
173
|
|
|
160
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QR8bitByte.js
|
|
174
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QR8bitByte.js
|
|
161
175
|
var require_QR8bitByte = __commonJS((exports, module) => {
|
|
162
176
|
var QRMode = require_QRMode();
|
|
163
177
|
function QR8bitByte(data) {
|
|
@@ -177,7 +191,7 @@ var require_QR8bitByte = __commonJS((exports, module) => {
|
|
|
177
191
|
module.exports = QR8bitByte;
|
|
178
192
|
});
|
|
179
193
|
|
|
180
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRMath.js
|
|
194
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMath.js
|
|
181
195
|
var require_QRMath = __commonJS((exports, module) => {
|
|
182
196
|
var QRMath = {
|
|
183
197
|
glog: function(n) {
|
|
@@ -213,7 +227,7 @@ var require_QRMath = __commonJS((exports, module) => {
|
|
|
213
227
|
module.exports = QRMath;
|
|
214
228
|
});
|
|
215
229
|
|
|
216
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRPolynomial.js
|
|
230
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRPolynomial.js
|
|
217
231
|
var require_QRPolynomial = __commonJS((exports, module) => {
|
|
218
232
|
var QRMath = require_QRMath();
|
|
219
233
|
function QRPolynomial(num, shift) {
|
|
@@ -263,7 +277,7 @@ var require_QRPolynomial = __commonJS((exports, module) => {
|
|
|
263
277
|
module.exports = QRPolynomial;
|
|
264
278
|
});
|
|
265
279
|
|
|
266
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRMaskPattern.js
|
|
280
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRMaskPattern.js
|
|
267
281
|
var require_QRMaskPattern = __commonJS((exports, module) => {
|
|
268
282
|
module.exports = {
|
|
269
283
|
PATTERN000: 0,
|
|
@@ -277,7 +291,7 @@ var require_QRMaskPattern = __commonJS((exports, module) => {
|
|
|
277
291
|
};
|
|
278
292
|
});
|
|
279
293
|
|
|
280
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRUtil.js
|
|
294
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRUtil.js
|
|
281
295
|
var require_QRUtil = __commonJS((exports, module) => {
|
|
282
296
|
var QRMode = require_QRMode();
|
|
283
297
|
var QRPolynomial = require_QRPolynomial();
|
|
@@ -503,7 +517,7 @@ var require_QRUtil = __commonJS((exports, module) => {
|
|
|
503
517
|
module.exports = QRUtil;
|
|
504
518
|
});
|
|
505
519
|
|
|
506
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js
|
|
520
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js
|
|
507
521
|
var require_QRErrorCorrectLevel = __commonJS((exports, module) => {
|
|
508
522
|
module.exports = {
|
|
509
523
|
L: 1,
|
|
@@ -513,7 +527,7 @@ var require_QRErrorCorrectLevel = __commonJS((exports, module) => {
|
|
|
513
527
|
};
|
|
514
528
|
});
|
|
515
529
|
|
|
516
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRRSBlock.js
|
|
530
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRRSBlock.js
|
|
517
531
|
var require_QRRSBlock = __commonJS((exports, module) => {
|
|
518
532
|
var QRErrorCorrectLevel = require_QRErrorCorrectLevel();
|
|
519
533
|
function QRRSBlock(totalCount, dataCount) {
|
|
@@ -716,7 +730,7 @@ var require_QRRSBlock = __commonJS((exports, module) => {
|
|
|
716
730
|
module.exports = QRRSBlock;
|
|
717
731
|
});
|
|
718
732
|
|
|
719
|
-
// node_modules/qrcode-terminal/vendor/QRCode/QRBitBuffer.js
|
|
733
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/QRBitBuffer.js
|
|
720
734
|
var require_QRBitBuffer = __commonJS((exports, module) => {
|
|
721
735
|
function QRBitBuffer() {
|
|
722
736
|
this.buffer = [];
|
|
@@ -749,7 +763,7 @@ var require_QRBitBuffer = __commonJS((exports, module) => {
|
|
|
749
763
|
module.exports = QRBitBuffer;
|
|
750
764
|
});
|
|
751
765
|
|
|
752
|
-
// node_modules/qrcode-terminal/vendor/QRCode/index.js
|
|
766
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/vendor/QRCode/index.js
|
|
753
767
|
var require_QRCode = __commonJS((exports, module) => {
|
|
754
768
|
var QR8bitByte = require_QR8bitByte();
|
|
755
769
|
var QRUtil = require_QRUtil();
|
|
@@ -1070,7 +1084,7 @@ var require_QRCode = __commonJS((exports, module) => {
|
|
|
1070
1084
|
module.exports = QRCode;
|
|
1071
1085
|
});
|
|
1072
1086
|
|
|
1073
|
-
// node_modules/qrcode-terminal/lib/main.js
|
|
1087
|
+
// ../../node_modules/.bun/qrcode-terminal@0.12.0/node_modules/qrcode-terminal/lib/main.js
|
|
1074
1088
|
var require_main = __commonJS((exports, module) => {
|
|
1075
1089
|
var QRCode = require_QRCode();
|
|
1076
1090
|
var QRErrorCorrectLevel = require_QRErrorCorrectLevel();
|
|
@@ -1164,7 +1178,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
1164
1178
|
};
|
|
1165
1179
|
});
|
|
1166
1180
|
|
|
1167
|
-
// node_modules/@clack/core/dist/index.mjs
|
|
1181
|
+
// ../../node_modules/.bun/@clack+core@0.3.5/node_modules/@clack/core/dist/index.mjs
|
|
1168
1182
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
1169
1183
|
import { stdin as $, stdout as k } from "node:process";
|
|
1170
1184
|
import * as f from "node:readline";
|
|
@@ -1578,7 +1592,7 @@ function OD({ input: e = $, output: u = k, overwrite: F = true, hideCursor: t =
|
|
|
1578
1592
|
};
|
|
1579
1593
|
}
|
|
1580
1594
|
|
|
1581
|
-
// node_modules/@clack/prompts/dist/index.mjs
|
|
1595
|
+
// ../../node_modules/.bun/@clack+prompts@0.8.2/node_modules/@clack/prompts/dist/index.mjs
|
|
1582
1596
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
1583
1597
|
var import_sisteransi2 = __toESM(require_src(), 1);
|
|
1584
1598
|
import h from "node:process";
|
|
@@ -1822,7 +1836,7 @@ var ve = async (s, n) => {
|
|
|
1822
1836
|
return t;
|
|
1823
1837
|
};
|
|
1824
1838
|
|
|
1825
|
-
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
1839
|
+
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
1826
1840
|
var ANSI_BACKGROUND_OFFSET = 10;
|
|
1827
1841
|
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
1828
1842
|
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
@@ -1999,7 +2013,7 @@ function assembleStyles() {
|
|
|
1999
2013
|
var ansiStyles = assembleStyles();
|
|
2000
2014
|
var ansi_styles_default = ansiStyles;
|
|
2001
2015
|
|
|
2002
|
-
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
2016
|
+
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
2003
2017
|
import process2 from "node:process";
|
|
2004
2018
|
import os from "node:os";
|
|
2005
2019
|
import tty from "node:tty";
|
|
@@ -2131,7 +2145,7 @@ var supportsColor = {
|
|
|
2131
2145
|
};
|
|
2132
2146
|
var supports_color_default = supportsColor;
|
|
2133
2147
|
|
|
2134
|
-
// node_modules/chalk/source/utilities.js
|
|
2148
|
+
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js
|
|
2135
2149
|
function stringReplaceAll(string, substring, replacer) {
|
|
2136
2150
|
let index = string.indexOf(substring);
|
|
2137
2151
|
if (index === -1) {
|
|
@@ -2164,7 +2178,7 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
|
2164
2178
|
return returnValue;
|
|
2165
2179
|
}
|
|
2166
2180
|
|
|
2167
|
-
// node_modules/chalk/source/index.js
|
|
2181
|
+
// ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/index.js
|
|
2168
2182
|
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
2169
2183
|
var GENERATOR = Symbol("GENERATOR");
|
|
2170
2184
|
var STYLER = Symbol("STYLER");
|
|
@@ -2318,7 +2332,7 @@ import { homedir, hostname, platform } from "os";
|
|
|
2318
2332
|
import { join, dirname, basename } from "path";
|
|
2319
2333
|
import { execSync, spawnSync } from "child_process";
|
|
2320
2334
|
import { randomBytes, createHash } from "crypto";
|
|
2321
|
-
var VERSION = "0.1.
|
|
2335
|
+
var VERSION = "0.1.9";
|
|
2322
2336
|
function getApiUrl() {
|
|
2323
2337
|
return process.env.AGENTAPPROVE_API || "https://api.agentapprove.com";
|
|
2324
2338
|
}
|
|
@@ -2366,6 +2380,9 @@ function getCommand() {
|
|
|
2366
2380
|
}
|
|
2367
2381
|
return filtered[0] || "install";
|
|
2368
2382
|
}
|
|
2383
|
+
var OPENCODE_PLUGIN_VERSION = "0.1.6";
|
|
2384
|
+
var OPENCLAW_PLUGIN_VERSION = "0.2.3";
|
|
2385
|
+
var OPENCLAW_PLUGIN_SPEC = `@agentapprove/openclaw@${OPENCLAW_PLUGIN_VERSION}`;
|
|
2369
2386
|
var AGENTS = {
|
|
2370
2387
|
"claude-code": {
|
|
2371
2388
|
name: "Claude Code",
|
|
@@ -2421,7 +2438,7 @@ var AGENTS = {
|
|
|
2421
2438
|
]
|
|
2422
2439
|
},
|
|
2423
2440
|
"vscode-agent": {
|
|
2424
|
-
name: "VS Code
|
|
2441
|
+
name: "VS Code GitHub Copilot",
|
|
2425
2442
|
configPath: join(homedir(), ".agentapprove", "hooks", "vscode-hooks.json"),
|
|
2426
2443
|
hooksKey: "hooks",
|
|
2427
2444
|
hooks: [
|
|
@@ -2436,7 +2453,7 @@ var AGENTS = {
|
|
|
2436
2453
|
]
|
|
2437
2454
|
},
|
|
2438
2455
|
"copilot-cli": {
|
|
2439
|
-
name: "Copilot CLI",
|
|
2456
|
+
name: "GitHub Copilot CLI",
|
|
2440
2457
|
configPath: join(homedir(), ".agentapprove", "copilot-cli-hooks.json"),
|
|
2441
2458
|
hooksKey: "hooks",
|
|
2442
2459
|
hooks: [
|
|
@@ -2456,6 +2473,18 @@ var AGENTS = {
|
|
|
2456
2473
|
{ name: "agentapprove", file: "@agentapprove/openclaw", description: "Tool approval + event monitoring", isApprovalHook: true, isPlugin: true }
|
|
2457
2474
|
]
|
|
2458
2475
|
},
|
|
2476
|
+
codex: {
|
|
2477
|
+
name: "OpenAI Codex",
|
|
2478
|
+
configPath: join(homedir(), ".codex", "hooks.json"),
|
|
2479
|
+
hooksKey: "hooks",
|
|
2480
|
+
hooks: [
|
|
2481
|
+
{ name: "SessionStart", file: "codex-session-start.sh", description: "Session started", hasMatcher: true },
|
|
2482
|
+
{ name: "PreToolUse", file: "codex-pre-tool.sh", description: "Tool approval", hasMatcher: true, isApprovalHook: true, timeout: 300 },
|
|
2483
|
+
{ name: "PostToolUse", file: "codex-post-tool.sh", description: "Tool completion logging", hasMatcher: true },
|
|
2484
|
+
{ name: "UserPromptSubmit", file: "codex-user-prompt.sh", description: "User prompt submitted", hasMatcher: false },
|
|
2485
|
+
{ name: "Stop", file: "codex-stop.sh", description: "Agent stopped (iOS input)", hasMatcher: false, timeout: 600 }
|
|
2486
|
+
]
|
|
2487
|
+
},
|
|
2459
2488
|
opencode: {
|
|
2460
2489
|
name: "OpenCode",
|
|
2461
2490
|
configPath: getOpenCodeConfigPath(),
|
|
@@ -2580,6 +2609,15 @@ function readJsoncConfig(configPath) {
|
|
|
2580
2609
|
return {};
|
|
2581
2610
|
}
|
|
2582
2611
|
}
|
|
2612
|
+
function getGithubHookEnv(agentId) {
|
|
2613
|
+
if (agentId === "vscode-agent") {
|
|
2614
|
+
return { AGENTAPPROVE_GITHUB_VARIANT: "vscode" };
|
|
2615
|
+
}
|
|
2616
|
+
if (agentId === "copilot-cli") {
|
|
2617
|
+
return { AGENTAPPROVE_GITHUB_VARIANT: "github" };
|
|
2618
|
+
}
|
|
2619
|
+
return;
|
|
2620
|
+
}
|
|
2583
2621
|
function addToVSCodeHookLocations() {
|
|
2584
2622
|
const hookLocation = "~/.agentapprove/hooks";
|
|
2585
2623
|
const modified = [];
|
|
@@ -2636,6 +2674,10 @@ function detectInstalledAgents() {
|
|
|
2636
2674
|
if (existsSync(join(homedir(), ".openclaw"))) {
|
|
2637
2675
|
installed.push(id);
|
|
2638
2676
|
}
|
|
2677
|
+
} else if (id === "codex") {
|
|
2678
|
+
if (existsSync(join(homedir(), ".codex"))) {
|
|
2679
|
+
installed.push(id);
|
|
2680
|
+
}
|
|
2639
2681
|
} else if (id === "opencode") {
|
|
2640
2682
|
if (existsSync(getOpenCodeConfigDir())) {
|
|
2641
2683
|
installed.push(id);
|
|
@@ -2800,6 +2842,87 @@ function writeJsonConfig(configPath, config) {
|
|
|
2800
2842
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + `
|
|
2801
2843
|
`);
|
|
2802
2844
|
}
|
|
2845
|
+
function ensureCodexFeatureFlag(configPath = join(homedir(), ".codex", "config.toml")) {
|
|
2846
|
+
const dir = dirname(configPath);
|
|
2847
|
+
if (!existsSync(dir)) {
|
|
2848
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
2849
|
+
}
|
|
2850
|
+
const sectionHeader = "[features]";
|
|
2851
|
+
const desiredLine = "codex_hooks = true";
|
|
2852
|
+
if (!existsSync(configPath)) {
|
|
2853
|
+
writeFileSync(configPath, `${sectionHeader}
|
|
2854
|
+
${desiredLine}
|
|
2855
|
+
`, { mode: 384 });
|
|
2856
|
+
return { updated: true, backupPath: null };
|
|
2857
|
+
}
|
|
2858
|
+
const original = readFileSync(configPath, "utf-8");
|
|
2859
|
+
const lines = original.split(/\r?\n/);
|
|
2860
|
+
const updatedLines = [];
|
|
2861
|
+
let inFeatures = false;
|
|
2862
|
+
let foundFeatures = false;
|
|
2863
|
+
let foundKey = false;
|
|
2864
|
+
let changed = false;
|
|
2865
|
+
for (const line of lines) {
|
|
2866
|
+
const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*$/);
|
|
2867
|
+
if (sectionMatch) {
|
|
2868
|
+
if (inFeatures && !foundKey) {
|
|
2869
|
+
updatedLines.push(desiredLine);
|
|
2870
|
+
foundKey = true;
|
|
2871
|
+
changed = true;
|
|
2872
|
+
}
|
|
2873
|
+
inFeatures = sectionMatch[1] === "features";
|
|
2874
|
+
foundFeatures ||= inFeatures;
|
|
2875
|
+
updatedLines.push(line);
|
|
2876
|
+
continue;
|
|
2877
|
+
}
|
|
2878
|
+
if (inFeatures && /^\s*codex_hooks\s*=/.test(line)) {
|
|
2879
|
+
if (line.trim() !== desiredLine) {
|
|
2880
|
+
updatedLines.push(desiredLine);
|
|
2881
|
+
changed = true;
|
|
2882
|
+
} else {
|
|
2883
|
+
updatedLines.push(line);
|
|
2884
|
+
}
|
|
2885
|
+
foundKey = true;
|
|
2886
|
+
continue;
|
|
2887
|
+
}
|
|
2888
|
+
updatedLines.push(line);
|
|
2889
|
+
}
|
|
2890
|
+
if (inFeatures && !foundKey) {
|
|
2891
|
+
updatedLines.push(desiredLine);
|
|
2892
|
+
changed = true;
|
|
2893
|
+
}
|
|
2894
|
+
if (!foundFeatures) {
|
|
2895
|
+
const hasContent = updatedLines.some((line) => line.trim() !== "");
|
|
2896
|
+
if (hasContent) {
|
|
2897
|
+
updatedLines.push("");
|
|
2898
|
+
}
|
|
2899
|
+
updatedLines.push(sectionHeader, desiredLine);
|
|
2900
|
+
changed = true;
|
|
2901
|
+
}
|
|
2902
|
+
if (!changed) {
|
|
2903
|
+
return { updated: false, backupPath: null };
|
|
2904
|
+
}
|
|
2905
|
+
const backupPath = backupConfig(configPath);
|
|
2906
|
+
writeFileSync(configPath, `${updatedLines.join(`
|
|
2907
|
+
`).replace(/\n*$/, `
|
|
2908
|
+
`)}`, { mode: 384 });
|
|
2909
|
+
return { updated: true, backupPath };
|
|
2910
|
+
}
|
|
2911
|
+
function disableCodexFeatureFlag(configPath = join(homedir(), ".codex", "config.toml")) {
|
|
2912
|
+
if (!existsSync(configPath)) {
|
|
2913
|
+
return { updated: false, backupPath: null };
|
|
2914
|
+
}
|
|
2915
|
+
const original = readFileSync(configPath, "utf-8");
|
|
2916
|
+
const updated = original.split(/\r?\n/).filter((line) => !/^\s*codex_hooks\s*=/.test(line)).join(`
|
|
2917
|
+
`).replace(/\n*$/, `
|
|
2918
|
+
`);
|
|
2919
|
+
if (updated === original) {
|
|
2920
|
+
return { updated: false, backupPath: null };
|
|
2921
|
+
}
|
|
2922
|
+
const backupPath = backupConfig(configPath);
|
|
2923
|
+
writeFileSync(configPath, updated, { mode: 384 });
|
|
2924
|
+
return { updated: true, backupPath };
|
|
2925
|
+
}
|
|
2803
2926
|
async function createPairingSession(configuredAgents, e2eKeyId) {
|
|
2804
2927
|
try {
|
|
2805
2928
|
const machineHostname = hostname();
|
|
@@ -3133,7 +3256,38 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
|
|
|
3133
3256
|
hookArray.push(hookEntry);
|
|
3134
3257
|
}
|
|
3135
3258
|
installedHooks.push(hook.name);
|
|
3259
|
+
} else if (agentId === "codex") {
|
|
3260
|
+
if (!hooksConfig[hook.name]) {
|
|
3261
|
+
hooksConfig[hook.name] = [];
|
|
3262
|
+
}
|
|
3263
|
+
const hookArray = hooksConfig[hook.name];
|
|
3264
|
+
const hasMatcher = hook.hasMatcher ?? true;
|
|
3265
|
+
const hookTimeout = hook.timeout;
|
|
3266
|
+
const existingIdx = hookArray.findIndex((h2) => h2.hooks?.some((hookScript) => {
|
|
3267
|
+
if (typeof hookScript === "string")
|
|
3268
|
+
return hookScript.includes("agentapprove");
|
|
3269
|
+
if (typeof hookScript === "object" && hookScript.command)
|
|
3270
|
+
return hookScript.command.includes("agentapprove");
|
|
3271
|
+
return false;
|
|
3272
|
+
}));
|
|
3273
|
+
const hookObject = {
|
|
3274
|
+
type: "command",
|
|
3275
|
+
command: hookCommand
|
|
3276
|
+
};
|
|
3277
|
+
if (hookTimeout) {
|
|
3278
|
+
hookObject.timeout = hookTimeout;
|
|
3279
|
+
}
|
|
3280
|
+
const hookEntry = hasMatcher ? { matcher: "*", hooks: [hookObject] } : { hooks: [hookObject] };
|
|
3281
|
+
if (existingIdx >= 0) {
|
|
3282
|
+
hookArray[existingIdx] = hookEntry;
|
|
3283
|
+
} else {
|
|
3284
|
+
hookArray.push(hookEntry);
|
|
3285
|
+
}
|
|
3286
|
+
installedHooks.push(hook.name);
|
|
3136
3287
|
} else if (agentId === "cursor") {
|
|
3288
|
+
if (typeof config["version"] !== "number") {
|
|
3289
|
+
config["version"] = 1;
|
|
3290
|
+
}
|
|
3137
3291
|
const existing = hooksConfig[hook.name];
|
|
3138
3292
|
const needsStopTimeout = hook.name === "stop" || hook.name === "subagentStop";
|
|
3139
3293
|
const isApproval = hook.isApprovalHook;
|
|
@@ -3214,6 +3368,10 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
|
|
|
3214
3368
|
type: "command",
|
|
3215
3369
|
command: hookCommand
|
|
3216
3370
|
};
|
|
3371
|
+
const hookEnv = getGithubHookEnv(agentId);
|
|
3372
|
+
if (hookEnv) {
|
|
3373
|
+
hookEntry.env = hookEnv;
|
|
3374
|
+
}
|
|
3217
3375
|
if (hook.isApprovalHook) {
|
|
3218
3376
|
hookEntry.timeout = 300;
|
|
3219
3377
|
}
|
|
@@ -3224,7 +3382,9 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
|
|
|
3224
3382
|
hooksConfig[hook.name] = cleanedArray;
|
|
3225
3383
|
installedHooks.push(hook.name);
|
|
3226
3384
|
} else if (agentId === "copilot-cli") {
|
|
3227
|
-
config["version"]
|
|
3385
|
+
if (typeof config["version"] !== "number") {
|
|
3386
|
+
config["version"] = 1;
|
|
3387
|
+
}
|
|
3228
3388
|
if (!hooksConfig[hook.name]) {
|
|
3229
3389
|
hooksConfig[hook.name] = [];
|
|
3230
3390
|
}
|
|
@@ -3237,6 +3397,10 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
|
|
|
3237
3397
|
type: "command",
|
|
3238
3398
|
bash: isWindows() ? toGitBashPath(hookPath) : hookPath
|
|
3239
3399
|
};
|
|
3400
|
+
const hookEnv = getGithubHookEnv(agentId);
|
|
3401
|
+
if (hookEnv) {
|
|
3402
|
+
hookEntry.env = hookEnv;
|
|
3403
|
+
}
|
|
3240
3404
|
if (hook.isApprovalHook) {
|
|
3241
3405
|
hookEntry.timeoutSec = 300;
|
|
3242
3406
|
}
|
|
@@ -3249,7 +3413,7 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
|
|
|
3249
3413
|
const approvalHooks = agent.hooks.filter((h2) => h2.isApprovalHook);
|
|
3250
3414
|
for (const hook of approvalHooks) {
|
|
3251
3415
|
if (hooksConfig[hook.name]) {
|
|
3252
|
-
if (agentId === "claude-code" || agentId === "gemini-cli") {
|
|
3416
|
+
if (agentId === "claude-code" || agentId === "gemini-cli" || agentId === "codex") {
|
|
3253
3417
|
const hookArray = hooksConfig[hook.name];
|
|
3254
3418
|
if (Array.isArray(hookArray)) {
|
|
3255
3419
|
const cleaned = hookArray.filter((h2) => {
|
|
@@ -3321,6 +3485,9 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
|
|
|
3321
3485
|
}
|
|
3322
3486
|
}
|
|
3323
3487
|
writeJsonConfig(agent.configPath, config);
|
|
3488
|
+
if (agentId === "codex") {
|
|
3489
|
+
ensureCodexFeatureFlag();
|
|
3490
|
+
}
|
|
3324
3491
|
return { success: true, backupPath, hooks: installedHooks };
|
|
3325
3492
|
}
|
|
3326
3493
|
function getManualInstructions(agentId, hooksDir) {
|
|
@@ -3334,13 +3501,39 @@ function getManualInstructions(agentId, hooksDir) {
|
|
|
3334
3501
|
const hookTimeout = hook.timeout;
|
|
3335
3502
|
const hookPath = join(hooksDir, hook.file);
|
|
3336
3503
|
const hookCmd = buildHookCommand(hookPath, agentId);
|
|
3337
|
-
const
|
|
3504
|
+
const hookObject = {
|
|
3505
|
+
type: "command",
|
|
3506
|
+
command: hookCmd
|
|
3507
|
+
};
|
|
3338
3508
|
if (hookTimeout) {
|
|
3339
|
-
|
|
3509
|
+
hookObject.timeout = hookTimeout;
|
|
3340
3510
|
}
|
|
3511
|
+
const entry = hasMatcher ? { matcher: "*", hooks: [hookObject] } : { hooks: [hookObject] };
|
|
3341
3512
|
hooksObj[hook.name] = [entry];
|
|
3342
3513
|
}
|
|
3343
3514
|
return JSON.stringify({ hooks: hooksObj }, null, 2);
|
|
3515
|
+
} else if (agentId === "codex") {
|
|
3516
|
+
const hooksObj = {};
|
|
3517
|
+
for (const hook of agent.hooks) {
|
|
3518
|
+
const hasMatcher = hook.hasMatcher ?? true;
|
|
3519
|
+
const hookTimeout = hook.timeout;
|
|
3520
|
+
const hookPath = join(hooksDir, hook.file);
|
|
3521
|
+
const hookCmd = buildHookCommand(hookPath, agentId);
|
|
3522
|
+
const hookObject = {
|
|
3523
|
+
type: "command",
|
|
3524
|
+
command: hookCmd
|
|
3525
|
+
};
|
|
3526
|
+
if (hookTimeout) {
|
|
3527
|
+
hookObject.timeout = hookTimeout;
|
|
3528
|
+
}
|
|
3529
|
+
const entry = hasMatcher ? { matcher: "*", hooks: [hookObject] } : { hooks: [hookObject] };
|
|
3530
|
+
hooksObj[hook.name] = [entry];
|
|
3531
|
+
}
|
|
3532
|
+
return `${JSON.stringify({ hooks: hooksObj }, null, 2)}
|
|
3533
|
+
|
|
3534
|
+
Also ensure ~/.codex/config.toml contains:
|
|
3535
|
+
[features]
|
|
3536
|
+
codex_hooks = true`;
|
|
3344
3537
|
} else if (agentId === "cursor") {
|
|
3345
3538
|
const hooksObj = {};
|
|
3346
3539
|
for (const hook of agent.hooks) {
|
|
@@ -3357,7 +3550,7 @@ function getManualInstructions(agentId, hooksDir) {
|
|
|
3357
3550
|
}
|
|
3358
3551
|
hooksObj[hook.name] = [entry];
|
|
3359
3552
|
}
|
|
3360
|
-
return JSON.stringify({ hooks: hooksObj }, null, 2);
|
|
3553
|
+
return JSON.stringify({ version: 1, hooks: hooksObj }, null, 2);
|
|
3361
3554
|
} else if (agentId === "gemini-cli") {
|
|
3362
3555
|
const hooksObj = {};
|
|
3363
3556
|
for (const hook of agent.hooks) {
|
|
@@ -3378,6 +3571,9 @@ function getManualInstructions(agentId, hooksDir) {
|
|
|
3378
3571
|
type: "command",
|
|
3379
3572
|
command: hookCmd
|
|
3380
3573
|
};
|
|
3574
|
+
const hookEnv = getGithubHookEnv(agentId);
|
|
3575
|
+
if (hookEnv)
|
|
3576
|
+
entry.env = hookEnv;
|
|
3381
3577
|
if (isApproval)
|
|
3382
3578
|
entry.timeout = 300;
|
|
3383
3579
|
if (hookTimeout)
|
|
@@ -3394,6 +3590,9 @@ function getManualInstructions(agentId, hooksDir) {
|
|
|
3394
3590
|
type: "command",
|
|
3395
3591
|
bash: isWindows() ? toGitBashPath(hookPath) : hookPath
|
|
3396
3592
|
};
|
|
3593
|
+
const hookEnv = getGithubHookEnv(agentId);
|
|
3594
|
+
if (hookEnv)
|
|
3595
|
+
entry.env = hookEnv;
|
|
3397
3596
|
if (isApproval)
|
|
3398
3597
|
entry.timeoutSec = 300;
|
|
3399
3598
|
hooksObj[hook.name] = [entry];
|
|
@@ -3421,7 +3620,7 @@ function getManualInstructions(agentId, hooksDir) {
|
|
|
3421
3620
|
return [
|
|
3422
3621
|
"Install the Agent Approve plugin for OpenClaw:",
|
|
3423
3622
|
"",
|
|
3424
|
-
|
|
3623
|
+
` openclaw plugins install ${OPENCLAW_PLUGIN_SPEC}`,
|
|
3425
3624
|
"",
|
|
3426
3625
|
"Then add to your OpenClaw config (~/.openclaw/openclaw.json):",
|
|
3427
3626
|
"",
|
|
@@ -3442,7 +3641,7 @@ function getManualInstructions(agentId, hooksDir) {
|
|
|
3442
3641
|
"",
|
|
3443
3642
|
"Then add the dependency to your OpenCode package.json (same directory):",
|
|
3444
3643
|
"",
|
|
3445
|
-
|
|
3644
|
+
` { "dependencies": { "@agentapprove/opencode": "${OPENCODE_PLUGIN_VERSION}" } }`,
|
|
3446
3645
|
"",
|
|
3447
3646
|
"OpenCode will auto-install the plugin on next start."
|
|
3448
3647
|
].join(`
|
|
@@ -3488,6 +3687,11 @@ var HOOK_FILES = [
|
|
|
3488
3687
|
"gemini-session-start.sh",
|
|
3489
3688
|
"gemini-session-end.sh",
|
|
3490
3689
|
"gemini-stop.sh",
|
|
3690
|
+
"codex-session-start.sh",
|
|
3691
|
+
"codex-pre-tool.sh",
|
|
3692
|
+
"codex-post-tool.sh",
|
|
3693
|
+
"codex-user-prompt.sh",
|
|
3694
|
+
"codex-stop.sh",
|
|
3491
3695
|
"github-session-start.sh",
|
|
3492
3696
|
"github-session-end.sh",
|
|
3493
3697
|
"github-user-prompt.sh",
|
|
@@ -3531,7 +3735,7 @@ async function copyHookScripts(hooksDir, token) {
|
|
|
3531
3735
|
}
|
|
3532
3736
|
function installOpenClawPluginViaCli() {
|
|
3533
3737
|
try {
|
|
3534
|
-
execSync(
|
|
3738
|
+
execSync(`openclaw plugins install ${OPENCLAW_PLUGIN_SPEC}`, { stdio: "pipe" });
|
|
3535
3739
|
return { success: true };
|
|
3536
3740
|
} catch (err) {
|
|
3537
3741
|
const message = err instanceof Error ? err.message : "unknown error";
|
|
@@ -3770,7 +3974,7 @@ E2E Key: ${keyId}`;
|
|
|
3770
3974
|
Privacy: ${existingConfig.privacy || "unknown"}${e2eLine}`, "Existing configuration found");
|
|
3771
3975
|
} else {
|
|
3772
3976
|
me(`Approve AI agent actions from your iPhone or Apple Watch.
|
|
3773
|
-
Installs hooks for Claude Code, Cursor, Gemini CLI, VS Code, and Copilot CLI.`, "About");
|
|
3977
|
+
Installs hooks for Claude Code, Cursor, Gemini CLI, VS Code GitHub Copilot, and GitHub Copilot CLI.`, "About");
|
|
3774
3978
|
}
|
|
3775
3979
|
const installedAgents = detectInstalledAgents();
|
|
3776
3980
|
const agentOptions = Object.entries(AGENTS).map(([id, agent]) => ({
|
|
@@ -4069,6 +4273,9 @@ AGENTAPPROVE_E2E_MODE=${installMode}
|
|
|
4069
4273
|
for (const agentId of selectedAgents) {
|
|
4070
4274
|
const agent = AGENTS[agentId];
|
|
4071
4275
|
filesToModify.push(agent.configPath);
|
|
4276
|
+
if (agentId === "codex") {
|
|
4277
|
+
filesToModify.push(join(homedir(), ".codex", "config.toml"));
|
|
4278
|
+
}
|
|
4072
4279
|
if (agentId === "opencode") {
|
|
4073
4280
|
filesToModify.push(join(getOpenCodeConfigDir(), "package.json"));
|
|
4074
4281
|
}
|
|
@@ -4116,16 +4323,19 @@ Backups will be created with timestamp`, "Files to be modified");
|
|
|
4116
4323
|
}
|
|
4117
4324
|
}
|
|
4118
4325
|
}
|
|
4326
|
+
if (agentId === "codex") {
|
|
4327
|
+
v2.info(source_default.dim(" Updated ~/.codex/config.toml to enable codex_hooks"));
|
|
4328
|
+
}
|
|
4119
4329
|
if (agentId === "copilot-cli") {
|
|
4120
|
-
v2.info(source_default.dim(` To use with Copilot CLI, copy to your repo:
|
|
4330
|
+
v2.info(source_default.dim(` To use with GitHub Copilot CLI, copy to your repo:
|
|
4121
4331
|
` + ` cp ${agent.configPath} .github/hooks/agentapprove.json`));
|
|
4122
4332
|
}
|
|
4123
4333
|
} else {
|
|
4124
4334
|
spinner.stop(`${agent.name} configuration failed`);
|
|
4125
4335
|
if (agentId === "openclaw") {
|
|
4126
|
-
v2.warn(`Could not install
|
|
4336
|
+
v2.warn(`Could not install ${OPENCLAW_PLUGIN_SPEC} via OpenClaw CLI.
|
|
4127
4337
|
` + ` Error: ${result.error || "unknown"}
|
|
4128
|
-
` + ` Install manually: openclaw plugins install
|
|
4338
|
+
` + ` Install manually: openclaw plugins install ${OPENCLAW_PLUGIN_SPEC}
|
|
4129
4339
|
` + ` Then re-run: npx agentapprove`);
|
|
4130
4340
|
}
|
|
4131
4341
|
}
|
|
@@ -4263,9 +4473,7 @@ async function uninstallCommand() {
|
|
|
4263
4473
|
if (!existsSync(agent.configPath))
|
|
4264
4474
|
continue;
|
|
4265
4475
|
const config = readJsonConfig(agent.configPath);
|
|
4266
|
-
const hooksConfig = config[agent.hooksKey];
|
|
4267
|
-
if (!hooksConfig && agentId !== "opencode")
|
|
4268
|
-
continue;
|
|
4476
|
+
const hooksConfig = config[agent.hooksKey] ?? {};
|
|
4269
4477
|
let modified = false;
|
|
4270
4478
|
if (agentId === "opencode") {
|
|
4271
4479
|
const pluginArray = config.plugin;
|
|
@@ -4330,6 +4538,12 @@ async function uninstallCommand() {
|
|
|
4330
4538
|
writeJsonConfig(agent.configPath, config);
|
|
4331
4539
|
console.log(` ${source_default.green("✓")} Removed hooks from ${agent.name}`);
|
|
4332
4540
|
}
|
|
4541
|
+
if (agentId === "codex" && modified && Object.keys(hooksConfig).length === 0) {
|
|
4542
|
+
const codexFlag = disableCodexFeatureFlag();
|
|
4543
|
+
if (codexFlag.updated) {
|
|
4544
|
+
console.log(` ${source_default.green("✓")} Disabled codex_hooks in ~/.codex/config.toml`);
|
|
4545
|
+
}
|
|
4546
|
+
}
|
|
4333
4547
|
}
|
|
4334
4548
|
const envPath = join(getAgentApproveDir(), "env");
|
|
4335
4549
|
if (existsSync(envPath)) {
|
|
@@ -4388,7 +4602,7 @@ async function initRepoCommand() {
|
|
|
4388
4602
|
const cliHooksPath = join(getAgentApproveDir(), "copilot-cli-hooks.json");
|
|
4389
4603
|
if (!existsSync(cliHooksPath)) {
|
|
4390
4604
|
console.log(source_default.yellow(`
|
|
4391
|
-
Copilot CLI hooks not found. Run the installer first with Copilot CLI selected.`));
|
|
4605
|
+
GitHub Copilot CLI hooks not found. Run the installer first with GitHub Copilot CLI selected.`));
|
|
4392
4606
|
console.log(source_default.dim(` npx agentapprove install
|
|
4393
4607
|
`));
|
|
4394
4608
|
process.exit(1);
|
|
@@ -4411,7 +4625,7 @@ async function initRepoCommand() {
|
|
|
4411
4625
|
const targetDir = join(repoRoot, ".github", "hooks");
|
|
4412
4626
|
const targetFile = join(targetDir, "agentapprove.json");
|
|
4413
4627
|
console.log(source_default.cyan(`
|
|
4414
|
-
Installing Copilot CLI hooks to ${targetFile}
|
|
4628
|
+
Installing GitHub Copilot CLI hooks to ${targetFile}
|
|
4415
4629
|
`));
|
|
4416
4630
|
if (existsSync(targetFile)) {
|
|
4417
4631
|
console.log(source_default.yellow(" agentapprove.json already exists in .github/hooks/"));
|
|
@@ -4428,7 +4642,7 @@ async function initRepoCommand() {
|
|
|
4428
4642
|
mkdirSync(targetDir, { recursive: true });
|
|
4429
4643
|
}
|
|
4430
4644
|
copyFileSync(cliHooksPath, targetFile);
|
|
4431
|
-
console.log(source_default.green(` ✓ Copied Copilot CLI hooks to .github/hooks/agentapprove.json`));
|
|
4645
|
+
console.log(source_default.green(` ✓ Copied GitHub Copilot CLI hooks to .github/hooks/agentapprove.json`));
|
|
4432
4646
|
console.log(source_default.dim(` Commit this file so Copilot coding agent uses your hooks.
|
|
4433
4647
|
`));
|
|
4434
4648
|
}
|
|
@@ -4444,7 +4658,7 @@ ${source_default.yellow("Commands:")}
|
|
|
4444
4658
|
${source_default.green("install")} Run the installation wizard (default)
|
|
4445
4659
|
${source_default.green("pair")} Link a new iOS device with existing E2E keys
|
|
4446
4660
|
${source_default.green("refresh")} Generate a new token (when expired)
|
|
4447
|
-
${source_default.green("init-repo")} Add Copilot CLI hooks to current repo (.github/hooks/)
|
|
4661
|
+
${source_default.green("init-repo")} Add GitHub Copilot CLI hooks to current repo (.github/hooks/)
|
|
4448
4662
|
${source_default.green("status")} Show current configuration and installed hooks
|
|
4449
4663
|
${source_default.green("disable")} Temporarily disable hooks
|
|
4450
4664
|
${source_default.green("enable")} Re-enable hooks after disabling
|
|
@@ -4520,6 +4734,7 @@ Session: ${session.sessionCode}`, "Scan with Agent Approve iOS app");
|
|
|
4520
4734
|
failBehavior,
|
|
4521
4735
|
configSetAt
|
|
4522
4736
|
});
|
|
4737
|
+
await storeTokenInKeychain(token);
|
|
4523
4738
|
pushConfigToCloud({
|
|
4524
4739
|
apiUrl,
|
|
4525
4740
|
token,
|
|
@@ -4692,6 +4907,7 @@ ${noteLabel}`, "Scan with Agent Approve iOS app");
|
|
|
4692
4907
|
failBehavior: existingConfig?.failBehavior || "ask",
|
|
4693
4908
|
configSetAt
|
|
4694
4909
|
});
|
|
4910
|
+
await storeTokenInKeychain(result.token);
|
|
4695
4911
|
const hooksDir = join(getAgentApproveDir(), "hooks");
|
|
4696
4912
|
if (existsSync(hooksDir)) {
|
|
4697
4913
|
const updateSpinner = _2();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentapprove",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Approve AI agent actions from your iPhone or Apple Watch",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"dev": "bun --watch src/cli.ts",
|
|
11
11
|
"build": "bun build src/cli.ts --outdir dist --target node",
|
|
12
|
+
"pack:check": "bun run build && node ../../scripts/check-publish-packlist.mjs",
|
|
12
13
|
"start": "bun src/cli.ts",
|
|
13
14
|
"test": "bun test",
|
|
14
|
-
"prepublishOnly": "bun run
|
|
15
|
+
"prepublishOnly": "bun run pack:check"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist/**/*"
|
|
@@ -43,13 +44,14 @@
|
|
|
43
44
|
"node": ">=18"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@clack/prompts": "
|
|
47
|
-
"chalk": "
|
|
48
|
-
"qrcode-terminal": "
|
|
47
|
+
"@clack/prompts": "0.8.2",
|
|
48
|
+
"chalk": "5.6.2",
|
|
49
|
+
"qrcode-terminal": "0.12.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
|
-
"@
|
|
52
|
-
"@types/
|
|
53
|
-
"
|
|
52
|
+
"@socketsecurity/bun-security-scanner": "1.1.2",
|
|
53
|
+
"@types/node": "22.19.3",
|
|
54
|
+
"@types/qrcode-terminal": "0.12.2",
|
|
55
|
+
"typescript": "5.9.3"
|
|
54
56
|
}
|
|
55
57
|
}
|