agentapprove 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +121 -20
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -48,6 +48,7 @@ agentapprove --no-e2e # Skip end-to-end encryption setup
48
48
  - **Gemini CLI** - Google's CLI
49
49
  - **VS Code Agent** - VS Code agent hooks
50
50
  - **GitHub Copilot CLI** - GitHub's coding agent
51
+ - **OpenCode** - Open-source AI coding agent
51
52
  - **OpenClaw** - Open-source AI agent platform
52
53
  - **OpenAI Codex** - coming soon
53
54
  - And more
@@ -58,7 +59,7 @@ agentapprove --no-e2e # Skip end-to-end encryption setup
58
59
  - **Push notifications** - Never miss an approval request. Avoid wasted idle time with your agents
59
60
  - **Apple Watch** - One-tap approvals from your wrist. Review context and respond without reaching for your phone
60
61
  - **Voice commands** - Send follow-up commands to your agents using the microphone when they finish a task
61
- - **Agent observability** - Full visibility into what all your agents are doing, especially autonomous agents like OpenClaw or long-running loops
62
+ - **Agent observability** - Full visibility into what all your agents are doing, especially autonomous agents like OpenClaw or long-running loops (Ralph loops)
62
63
  - **Centralized policies** - Set auto-approve and deny rules across all your agents from a single policy
63
64
  - **End-to-end encryption** - You own the keys. Approval requests are encrypted on your machine and decrypted only on your device
64
65
  - **Privacy tiers** - Choose minimal, summary, or full data logging. Control retention from 1 to 365 days
package/dist/cli.js CHANGED
@@ -2322,6 +2322,15 @@ var VERSION = "0.1.1";
2322
2322
  function getApiUrl() {
2323
2323
  return process.env.AGENTAPPROVE_API || "https://api.agentapprove.com";
2324
2324
  }
2325
+ function getXdgConfigHome() {
2326
+ return process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
2327
+ }
2328
+ function getOpenCodeConfigDir() {
2329
+ return join(getXdgConfigHome(), "opencode");
2330
+ }
2331
+ function getOpenCodeConfigPath() {
2332
+ return join(getOpenCodeConfigDir(), "opencode.json");
2333
+ }
2325
2334
  var API_URL = getApiUrl();
2326
2335
  var API_VERSION = process.env.AGENTAPPROVE_API_VERSION || "v001";
2327
2336
  function hasFlag2(flag) {
@@ -2446,6 +2455,14 @@ var AGENTS = {
2446
2455
  hooks: [
2447
2456
  { name: "agentapprove", file: "@agentapprove/openclaw", description: "Tool approval + event monitoring", isApprovalHook: true, isPlugin: true }
2448
2457
  ]
2458
+ },
2459
+ opencode: {
2460
+ name: "OpenCode",
2461
+ configPath: getOpenCodeConfigPath(),
2462
+ hooksKey: "plugin",
2463
+ hooks: [
2464
+ { name: "agentapprove", file: "@agentapprove/opencode", description: "Tool approval + event monitoring", isApprovalHook: true, isPlugin: true }
2465
+ ]
2449
2466
  }
2450
2467
  };
2451
2468
  function findGitBash() {
@@ -2619,6 +2636,10 @@ function detectInstalledAgents() {
2619
2636
  if (existsSync(join(homedir(), ".openclaw"))) {
2620
2637
  installed.push(id);
2621
2638
  }
2639
+ } else if (id === "opencode") {
2640
+ if (existsSync(getOpenCodeConfigDir())) {
2641
+ installed.push(id);
2642
+ }
2622
2643
  } else {
2623
2644
  const configDir = dirname(agent.configPath);
2624
2645
  if (existsSync(configDir)) {
@@ -3055,6 +3076,39 @@ async function installHooksForAgent(agentId, hooksDir, mode = "approval") {
3055
3076
  installedHooks.push("agentapprove");
3056
3077
  return { success: true, backupPath, hooks: installedHooks };
3057
3078
  }
3079
+ if (agentId === "opencode") {
3080
+ if (!config.plugin) {
3081
+ config.plugin = [];
3082
+ }
3083
+ const pluginArray = config.plugin;
3084
+ if (!pluginArray.includes("@agentapprove/opencode")) {
3085
+ pluginArray.push("@agentapprove/opencode");
3086
+ }
3087
+ writeJsonConfig(agent.configPath, config);
3088
+ const opencodePkgDir = join(getOpenCodeConfigDir(), ".opencode");
3089
+ const opencodePkgPath = join(opencodePkgDir, "package.json");
3090
+ try {
3091
+ if (!existsSync(opencodePkgDir)) {
3092
+ mkdirSync(opencodePkgDir, { recursive: true });
3093
+ }
3094
+ let pkgJson = {};
3095
+ if (existsSync(opencodePkgPath)) {
3096
+ pkgJson = JSON.parse(readFileSync(opencodePkgPath, "utf-8"));
3097
+ }
3098
+ if (!pkgJson.dependencies) {
3099
+ pkgJson.dependencies = {};
3100
+ }
3101
+ pkgJson.dependencies["@agentapprove/opencode"] = "latest";
3102
+ writeFileSync(opencodePkgPath, JSON.stringify(pkgJson, null, 2) + `
3103
+ `);
3104
+ } catch (err) {
3105
+ if (err instanceof Error) {
3106
+ console.warn(`Warning: Could not update .opencode/package.json: ${err.message}`);
3107
+ }
3108
+ }
3109
+ installedHooks.push("agentapprove");
3110
+ return { success: true, backupPath, hooks: installedHooks };
3111
+ }
3058
3112
  const hooksToInstall = mode === "observe" ? agent.hooks.filter((h2) => !h2.isApprovalHook) : agent.hooks;
3059
3113
  for (const hook of hooksToInstall) {
3060
3114
  const hookPath = join(hooksDir, hook.file);
@@ -3364,6 +3418,23 @@ function getManualInstructions(agentId, hooksDir) {
3364
3418
  "",
3365
3419
  "Restart the OpenClaw gateway to activate."
3366
3420
  ].join(`
3421
+ `);
3422
+ } else if (agentId === "opencode") {
3423
+ const configJson = JSON.stringify({
3424
+ plugin: ["@agentapprove/opencode"]
3425
+ }, null, 2);
3426
+ const opencodeConfigPath = process.env.XDG_CONFIG_HOME ? `${process.env.XDG_CONFIG_HOME}/opencode/opencode.json` : "~/.config/opencode/opencode.json";
3427
+ return [
3428
+ `Add the Agent Approve plugin to your OpenCode config (${opencodeConfigPath}):`,
3429
+ "",
3430
+ configJson,
3431
+ "",
3432
+ "Then add the dependency to .opencode/package.json:",
3433
+ "",
3434
+ ' { "dependencies": { "@agentapprove/opencode": "latest" } }',
3435
+ "",
3436
+ "OpenCode will auto-install the plugin on next start."
3437
+ ].join(`
3367
3438
  `);
3368
3439
  }
3369
3440
  return "";
@@ -4168,32 +4239,62 @@ async function uninstallCommand() {
4168
4239
  if (!hooksConfig)
4169
4240
  continue;
4170
4241
  let modified = false;
4171
- for (const hook of agent.hooks) {
4172
- const hookEntry = hooksConfig[hook.name];
4173
- if (!hookEntry)
4174
- continue;
4175
- if (Array.isArray(hookEntry)) {
4176
- const filtered = hookEntry.filter((e2) => {
4177
- const str = JSON.stringify(e2);
4178
- return !str.includes("agentapprove");
4179
- });
4180
- if (filtered.length !== hookEntry.length) {
4181
- if (filtered.length === 0) {
4182
- delete hooksConfig[hook.name];
4183
- } else {
4184
- hooksConfig[hook.name] = filtered;
4242
+ if (agentId === "opencode") {
4243
+ const pluginArray = config.plugin;
4244
+ if (Array.isArray(pluginArray)) {
4245
+ const filtered = pluginArray.filter((p) => !p.includes("agentapprove"));
4246
+ if (filtered.length !== pluginArray.length) {
4247
+ config.plugin = filtered;
4248
+ modified = true;
4249
+ }
4250
+ }
4251
+ const opencodePkgDir = join(getOpenCodeConfigDir(), ".opencode");
4252
+ const opencodePkgPath = join(opencodePkgDir, "package.json");
4253
+ try {
4254
+ if (existsSync(opencodePkgPath)) {
4255
+ const pkgJson = JSON.parse(readFileSync(opencodePkgPath, "utf-8"));
4256
+ const deps = pkgJson.dependencies;
4257
+ if (deps && deps["@agentapprove/opencode"]) {
4258
+ delete deps["@agentapprove/opencode"];
4259
+ writeFileSync(opencodePkgPath, JSON.stringify(pkgJson, null, 2) + `
4260
+ `);
4185
4261
  }
4262
+ }
4263
+ } catch {}
4264
+ } else if (agentId === "openclaw") {
4265
+ const entries = hooksConfig.entries;
4266
+ if (entries && entries.agentapprove) {
4267
+ delete entries.agentapprove;
4268
+ modified = true;
4269
+ }
4270
+ } else {
4271
+ for (const hook of agent.hooks) {
4272
+ const hookEntry = hooksConfig[hook.name];
4273
+ if (!hookEntry)
4274
+ continue;
4275
+ if (Array.isArray(hookEntry)) {
4276
+ const filtered = hookEntry.filter((e2) => {
4277
+ const str = JSON.stringify(e2);
4278
+ return !str.includes("agentapprove");
4279
+ });
4280
+ if (filtered.length !== hookEntry.length) {
4281
+ if (filtered.length === 0) {
4282
+ delete hooksConfig[hook.name];
4283
+ } else {
4284
+ hooksConfig[hook.name] = filtered;
4285
+ }
4286
+ modified = true;
4287
+ }
4288
+ } else if (typeof hookEntry === "string" && hookEntry.includes("agentapprove")) {
4289
+ delete hooksConfig[hook.name];
4186
4290
  modified = true;
4187
4291
  }
4188
- } else if (typeof hookEntry === "string" && hookEntry.includes("agentapprove")) {
4189
- delete hooksConfig[hook.name];
4292
+ }
4293
+ if (hooksConfig["Prompt"]) {
4294
+ delete hooksConfig["Prompt"];
4190
4295
  modified = true;
4191
4296
  }
4192
4297
  }
4193
- if (hooksConfig["Prompt"]) {
4194
- delete hooksConfig["Prompt"];
4195
- modified = true;
4196
- }
4197
4298
  if (modified) {
4198
4299
  writeJsonConfig(agent.configPath, config);
4199
4300
  console.log(` ${source_default.green("✓")} Removed hooks from ${agent.name}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentapprove",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Approve AI agent actions from your iPhone or Apple Watch",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,6 +22,7 @@
22
22
  "cursor",
23
23
  "gemini",
24
24
  "openclaw",
25
+ "opencode",
25
26
  "ai",
26
27
  "agent",
27
28
  "approval",