agenter-app 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -19,6 +19,8 @@ agenter install # adds hooks to ~/.claude/settings.json (a backup is made) + D
19
19
 
20
20
  Then **reload each VS Code window** (or start new Claude sessions). Hooks are read when a session starts.
21
21
 
22
+ Skipped `agenter install`? Running `agenter` notices the hooks are missing and offers to set them up.
23
+
22
24
  Install it globally (`-g`), not with `npx`: the hooks point at the installed files, so they need to stay put.
23
25
  If you move Node (a new Node version manager install, say), run `agenter install` again; it replaces the old hooks.
24
26
 
package/cli.js CHANGED
@@ -1,10 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  // The `agenter` command (npm i -g agenter-app). Each subcommand runs one of the existing scripts.
3
3
  'use strict';
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
4
6
  const path = require('node:path');
7
+ const readline = require('node:readline/promises');
5
8
  const { spawnSync } = require('node:child_process');
6
9
  const { version } = require('./package.json');
7
10
 
11
+ const CLAUDE_SETTINGS = path.join(os.homedir(), '.claude', 'settings.json');
12
+ // The same path install.js puts in the hook commands.
13
+ const HOOK_SCRIPT = path.join(__dirname, 'hook.js').replace(/\\/g, '/');
14
+ const PROMPT_FILE = path.join(os.homedir(), '.agenter', 'cli.json');
15
+
8
16
  const [cmd = 'open', ...rest] = process.argv.slice(2);
9
17
  const isWindows = process.platform === 'win32';
10
18
 
@@ -20,11 +28,59 @@ const shortcuts = (args = []) => {
20
28
  return spawnSync('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ps1, ...args], { stdio: 'inherit' }).status ?? 1;
21
29
  };
22
30
 
31
+ const install = (args = []) => {
32
+ const status = node('install.js', args);
33
+ return status === 0 ? shortcuts() : status;
34
+ };
35
+
36
+ // 'ok' when this copy's hooks are installed, 'other' when only an older copy's are, else 'missing'.
37
+ const hookState = () => {
38
+ let commands = [];
39
+ try {
40
+ const { hooks = {} } = JSON.parse(fs.readFileSync(CLAUDE_SETTINGS, 'utf8'));
41
+ commands = Object.values(hooks).flat().flatMap((g) => g?.hooks || []).map((h) => h?.command).filter((c) => typeof c === 'string');
42
+ } catch {}
43
+ if (commands.some((c) => c.includes(HOOK_SCRIPT))) return 'ok';
44
+ return commands.some((c) => /agenter[^"]*\/hook\.js"$/i.test(c)) ? 'other' : 'missing';
45
+ };
46
+
47
+ // Setup is never run without asking. A "no" is remembered until Agenter moves to a new path.
48
+ async function offerSetup() {
49
+ const state = hookState();
50
+ if (state === 'ok') return;
51
+ try {
52
+ if (JSON.parse(fs.readFileSync(PROMPT_FILE, 'utf8')).declinedSetup === HOOK_SCRIPT) return;
53
+ } catch {}
54
+
55
+ const [why, ask] =
56
+ state === 'other'
57
+ ? ['Your Claude hooks point at another copy of Agenter (an older install, or Node moved).', 'Point them at this one?']
58
+ : ["Agenter's hooks aren't set up yet, so your Claude sessions won't show up.", 'Set them up now?'];
59
+ if (!process.stdin.isTTY) {
60
+ console.log(`${why}\nRun: agenter install`);
61
+ return;
62
+ }
63
+
64
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
65
+ rl.on('SIGINT', () => process.exit(130));
66
+ const answer = (await rl.question(`${why}\n${ask} (Y/n) `)).trim().toLowerCase();
67
+ rl.close();
68
+
69
+ if (['', 'y', 'yes'].includes(answer)) {
70
+ install();
71
+ return;
72
+ }
73
+ fs.mkdirSync(path.dirname(PROMPT_FILE), { recursive: true });
74
+ fs.writeFileSync(PROMPT_FILE, JSON.stringify({ declinedSetup: HOOK_SCRIPT }, null, 2));
75
+ console.log("OK. Run 'agenter install' whenever you want them.");
76
+ }
77
+
23
78
  const help = `Agenter ${version}: one inbox for every Claude Code and Codex session.
24
79
 
25
80
  Usage: agenter [command]
26
81
 
27
- (none), open Open the dashboard (starts the server if needed)
82
+ (none), open Open the dashboard (starts the server if needed); offers setup
83
+ if the hooks aren't installed yet
28
84
  install Add Agenter's hooks to ~/.claude/settings.json (backed up first)
29
85
  and, on Windows, Desktop and Start Menu shortcuts
30
86
  uninstall Remove the hooks and shortcuts
@@ -34,38 +90,40 @@ Usage: agenter [command]
34
90
 
35
91
  After installing, reload your VS Code windows so Claude sessions pick up the hooks.`;
36
92
 
37
- let status = 0;
38
- switch (cmd) {
39
- case 'open':
40
- status = node('open.js', rest);
41
- break;
42
- case 'install':
43
- status = node('install.js', rest);
44
- if (status === 0) status = shortcuts();
45
- break;
46
- case 'uninstall':
47
- status = node('install.js', ['--uninstall']);
48
- shortcuts(['-Remove']);
49
- break;
50
- case 'start':
51
- status = node('server.js', rest);
52
- break;
53
- case 'shortcuts':
54
- status = shortcuts(rest.includes('--startup') ? ['-Startup'] : []);
55
- break;
56
- case 'version':
57
- case '--version':
58
- case '-v':
59
- console.log(version);
60
- break;
61
- case 'help':
62
- case '--help':
63
- case '-h':
64
- console.log(help);
65
- break;
66
- default:
67
- console.error(`Unknown command: ${cmd}\n`);
68
- console.log(help);
69
- status = 1;
70
- }
71
- process.exit(status);
93
+ (async () => {
94
+ let status = 0;
95
+ switch (cmd) {
96
+ case 'open':
97
+ await offerSetup();
98
+ status = node('open.js', rest);
99
+ break;
100
+ case 'install':
101
+ status = install(rest);
102
+ break;
103
+ case 'uninstall':
104
+ status = node('install.js', ['--uninstall']);
105
+ shortcuts(['-Remove']);
106
+ break;
107
+ case 'start':
108
+ status = node('server.js', rest);
109
+ break;
110
+ case 'shortcuts':
111
+ status = shortcuts(rest.includes('--startup') ? ['-Startup'] : []);
112
+ break;
113
+ case 'version':
114
+ case '--version':
115
+ case '-v':
116
+ console.log(version);
117
+ break;
118
+ case 'help':
119
+ case '--help':
120
+ case '-h':
121
+ console.log(help);
122
+ break;
123
+ default:
124
+ console.error(`Unknown command: ${cmd}\n`);
125
+ console.log(help);
126
+ status = 1;
127
+ }
128
+ process.exit(status);
129
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenter-app",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "One local dashboard to watch, approve and steer every Claude Code and Codex session on your machine.",
5
5
  "keywords": [
6
6
  "claude",
@@ -13,13 +13,13 @@
13
13
  ],
14
14
  "author": "Ahmad Pandaog Aquino (https://ahmad-new-portfolio.vercel.app/)",
15
15
  "license": "MIT",
16
- "homepage": "https://github.com/zxcoding123/agenter_app#readme",
16
+ "homepage": "https://agenterlandingpage.vercel.app/",
17
17
  "repository": {
18
18
  "type": "git",
19
19
  "url": "git+https://github.com/zxcoding123/agenter_app.git"
20
20
  },
21
21
  "bugs": {
22
- "url": "https://github.com/zxcoding123/agenter_app/issues"
22
+ "url": "https://agenterlandingpage.vercel.app/"
23
23
  },
24
24
  "bin": {
25
25
  "agenter": "cli.js"
Binary file
Binary file
package/public/index.html CHANGED
@@ -4,7 +4,9 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title>Agenter</title>
7
- <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%23b7d4a6'/%3E%3Cpath d='M16 7l8 9-8 9-8-9z' fill='%23161813'/%3E%3C/svg%3E">
7
+ <link rel="icon" href="/favicon.ico" sizes="any">
8
+ <link rel="icon" type="image/png" sizes="256x256" href="/icon.png">
9
+ <link rel="apple-touch-icon" href="/icon.png">
8
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
12
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&display=swap">
@@ -20,7 +20,7 @@ foreach ($t in $targets) {
20
20
  $lnk.TargetPath = "$env:SystemRoot\System32\wscript.exe"
21
21
  $lnk.Arguments = "`"$root\Agenter.vbs`""
22
22
  $lnk.WorkingDirectory = $root
23
- $lnk.IconLocation = "$env:SystemRoot\System32\shell32.dll,94"
23
+ $lnk.IconLocation = "$root\public\agenter.ico,0"
24
24
  $lnk.Description = 'Watch and answer all your Claude Code sessions'
25
25
  $lnk.Save()
26
26
  "Created $t"
package/server.js CHANGED
@@ -1230,6 +1230,8 @@ const STATIC = {
1230
1230
  '/': ['index.html', 'text/html; charset=utf-8'],
1231
1231
  '/app.js': ['app.js', 'text/javascript; charset=utf-8'],
1232
1232
  '/style.css': ['style.css', 'text/css; charset=utf-8'],
1233
+ '/icon.png': ['icon.png', 'image/png'],
1234
+ '/favicon.ico': ['agenter.ico', 'image/x-icon'],
1233
1235
  };
1234
1236
 
1235
1237
  const ALLOWED_HOSTS = new Set([`127.0.0.1:${PORT}`, `localhost:${PORT}`]);