agentvigil 1.0.0
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/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/commands/autostart.d.ts +3 -0
- package/dist/commands/autostart.d.ts.map +1 -0
- package/dist/commands/autostart.js +57 -0
- package/dist/commands/autostart.js.map +1 -0
- package/dist/commands/daemon.d.ts +31 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +131 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +158 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +89 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/uninstall.d.ts +7 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +13 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/crypto/encryption.d.ts +11 -0
- package/dist/crypto/encryption.d.ts.map +1 -0
- package/dist/crypto/encryption.js +57 -0
- package/dist/crypto/encryption.js.map +1 -0
- package/dist/hooks/hook-handler.d.ts +18 -0
- package/dist/hooks/hook-handler.d.ts.map +1 -0
- package/dist/hooks/hook-handler.js +256 -0
- package/dist/hooks/hook-handler.js.map +1 -0
- package/dist/hooks/hook-manager.d.ts +22 -0
- package/dist/hooks/hook-manager.d.ts.map +1 -0
- package/dist/hooks/hook-manager.js +133 -0
- package/dist/hooks/hook-manager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/fcm-client.d.ts +15 -0
- package/dist/notifications/fcm-client.d.ts.map +1 -0
- package/dist/notifications/fcm-client.js +72 -0
- package/dist/notifications/fcm-client.js.map +1 -0
- package/dist/notifications/ntfy-client.d.ts +6 -0
- package/dist/notifications/ntfy-client.d.ts.map +1 -0
- package/dist/notifications/ntfy-client.js +51 -0
- package/dist/notifications/ntfy-client.js.map +1 -0
- package/dist/relay/relay-handler.d.ts +51 -0
- package/dist/relay/relay-handler.d.ts.map +1 -0
- package/dist/relay/relay-handler.js +325 -0
- package/dist/relay/relay-handler.js.map +1 -0
- package/dist/sessions/keystroke-injector.d.ts +4 -0
- package/dist/sessions/keystroke-injector.d.ts.map +1 -0
- package/dist/sessions/keystroke-injector.js +216 -0
- package/dist/sessions/keystroke-injector.js.map +1 -0
- package/dist/sessions/process-detector.d.ts +27 -0
- package/dist/sessions/process-detector.d.ts.map +1 -0
- package/dist/sessions/process-detector.js +180 -0
- package/dist/sessions/process-detector.js.map +1 -0
- package/dist/sessions/session-manager.d.ts +37 -0
- package/dist/sessions/session-manager.d.ts.map +1 -0
- package/dist/sessions/session-manager.js +90 -0
- package/dist/sessions/session-manager.js.map +1 -0
- package/dist/sessions/session-poller.d.ts +18 -0
- package/dist/sessions/session-poller.d.ts.map +1 -0
- package/dist/sessions/session-poller.js +73 -0
- package/dist/sessions/session-poller.js.map +1 -0
- package/dist/sessions/session-watcher.d.ts +20 -0
- package/dist/sessions/session-watcher.d.ts.map +1 -0
- package/dist/sessions/session-watcher.js +71 -0
- package/dist/sessions/session-watcher.js.map +1 -0
- package/dist/sessions/tmux-bridge.d.ts +11 -0
- package/dist/sessions/tmux-bridge.d.ts.map +1 -0
- package/dist/sessions/tmux-bridge.js +67 -0
- package/dist/sessions/tmux-bridge.js.map +1 -0
- package/dist/tunnel/tunnel-manager.d.ts +8 -0
- package/dist/tunnel/tunnel-manager.d.ts.map +1 -0
- package/dist/tunnel/tunnel-manager.js +57 -0
- package/dist/tunnel/tunnel-manager.js.map +1 -0
- package/dist/tunnel/websocket-server.d.ts +48 -0
- package/dist/tunnel/websocket-server.d.ts.map +1 -0
- package/dist/tunnel/websocket-server.js +173 -0
- package/dist/tunnel/websocket-server.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config.d.ts +23 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +54 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +11 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/qr.d.ts +19 -0
- package/dist/utils/qr.d.ts.map +1 -0
- package/dist/utils/qr.js +17 -0
- package/dist/utils/qr.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AgentVigil Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# AgentVigil
|
|
2
|
+
|
|
3
|
+
Never babysit a stuck AI coding session again.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
AgentVigil watches your AI coding agents (Claude Code, Codex, Amp) for permission prompts, idle states, and completions, then pushes an encrypted notification to your phone the moment one needs your attention. Approve or deny right from the lock screen — no need to keep checking your terminal.
|
|
8
|
+
|
|
9
|
+
<!-- screenshot here -->
|
|
10
|
+
|
|
11
|
+
## How it works
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Claude Code → hooks → AgentVigil companion → Cloudflare Tunnel → AgentVigil app (Android / iOS)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The companion runs quietly on your Mac, picks up hook events the instant they fire, encrypts them end-to-end, and relays them through a Cloudflare Tunnel to your phone. Replies (approve/deny) make the same trip in reverse.
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- macOS (Apple Silicon or Intel)
|
|
22
|
+
- Node.js >= 18
|
|
23
|
+
- [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) (`brew install cloudflared`)
|
|
24
|
+
- AgentVigil app — [Android (Google Play)](https://play.google.com/store/apps/details?id=com.stacktree.agentvigil) · iOS (coming soon)
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx agentvigil setup
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx agentvigil start
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| Command | Description |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `agentvigil setup` | First-time setup: register hooks and pair with mobile app |
|
|
41
|
+
| `agentvigil start` | Start the AgentVigil daemon |
|
|
42
|
+
| `agentvigil status` | Show all active agent sessions |
|
|
43
|
+
| `agentvigil logs` | Tail the AgentVigil log file |
|
|
44
|
+
| `agentvigil unpair` | Revoke mobile app pairing |
|
|
45
|
+
| `agentvigil uninstall` | Remove AgentVigil hooks from Claude Code and Codex |
|
|
46
|
+
| `agentvigil install-autostart` | Start AgentVigil automatically on login |
|
|
47
|
+
| `agentvigil uninstall-autostart` | Remove autostart |
|
|
48
|
+
|
|
49
|
+
## Supported Agents
|
|
50
|
+
|
|
51
|
+
| Agent | Session Detection | Push Notifications | Approve/Deny |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| Claude Code | ✅ | ✅ | ✅ |
|
|
54
|
+
| Codex CLI | ✅ | ✅ (coming soon) | ✅ (coming soon) |
|
|
55
|
+
| Amp | ✅ | 🔜 | 🔜 |
|
|
56
|
+
|
|
57
|
+
## Security
|
|
58
|
+
|
|
59
|
+
- **End-to-end encrypted** — every message between your Mac and phone is encrypted with TweetNaCl (XSalsa20-Poly1305).
|
|
60
|
+
- **Zero server storage** — there is no AgentVigil backend. Nothing about your sessions is ever stored on a server.
|
|
61
|
+
- **Cloudflare Tunnel, no open ports** — your Mac is never directly reachable from the internet.
|
|
62
|
+
- **Session content stays local** — prompts, code, and terminal output never leave your Mac except as encrypted relay traffic to your own paired phone.
|
|
63
|
+
|
|
64
|
+
Audit this code — it's all here.
|
|
65
|
+
|
|
66
|
+
## Why open source?
|
|
67
|
+
|
|
68
|
+
AgentVigil runs as a daemon with access to your AI coding sessions and your terminal. That's a lot of trust to ask for, so the code that earns it should be inspectable by anyone. Open source lets you (or anyone) verify exactly what data is read, what gets encrypted, and where it goes before you let it run on your machine.
|
|
69
|
+
|
|
70
|
+
## Contributing
|
|
71
|
+
|
|
72
|
+
Issues and PRs welcome.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autostart.d.ts","sourceRoot":"","sources":["../../src/commands/autostart.ts"],"names":[],"mappings":"AA6CA,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAYzD;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3D"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import { logger } from '../utils/logger.js';
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
// dist/commands/autostart.js → go up one level to reach dist/
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const distDir = path.dirname(path.dirname(__filename));
|
|
12
|
+
const entryPoint = path.join(distDir, 'index.js');
|
|
13
|
+
const LABEL = 'com.agentvigil.daemon';
|
|
14
|
+
const PLIST_PATH = path.join(os.homedir(), 'Library', 'LaunchAgents', `${LABEL}.plist`);
|
|
15
|
+
const LOG_PATH = path.join(os.homedir(), '.agentvigil', 'agentvigil.log');
|
|
16
|
+
function buildPlist() {
|
|
17
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
18
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
19
|
+
<plist version="1.0">
|
|
20
|
+
<dict>
|
|
21
|
+
<key>Label</key>
|
|
22
|
+
<string>${LABEL}</string>
|
|
23
|
+
<key>ProgramArguments</key>
|
|
24
|
+
<array>
|
|
25
|
+
<string>${process.execPath}</string>
|
|
26
|
+
<string>${entryPoint}</string>
|
|
27
|
+
<string>start</string>
|
|
28
|
+
</array>
|
|
29
|
+
<key>RunAtLoad</key>
|
|
30
|
+
<true/>
|
|
31
|
+
<key>KeepAlive</key>
|
|
32
|
+
<true/>
|
|
33
|
+
<key>StandardOutPath</key>
|
|
34
|
+
<string>${LOG_PATH}</string>
|
|
35
|
+
<key>StandardErrorPath</key>
|
|
36
|
+
<string>${LOG_PATH}</string>
|
|
37
|
+
</dict>
|
|
38
|
+
</plist>
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
export async function runInstallAutostart() {
|
|
42
|
+
await fs.mkdir(path.dirname(PLIST_PATH), { recursive: true });
|
|
43
|
+
await fs.mkdir(path.dirname(LOG_PATH), { recursive: true });
|
|
44
|
+
await fs.writeFile(PLIST_PATH, buildPlist(), 'utf8');
|
|
45
|
+
// Reload in case it's already registered from a previous install.
|
|
46
|
+
await execFileAsync('launchctl', ['unload', PLIST_PATH]).catch(() => { });
|
|
47
|
+
await execFileAsync('launchctl', ['load', '-w', PLIST_PATH]);
|
|
48
|
+
logger.success('AgentVigil will now start automatically on login.');
|
|
49
|
+
logger.info(`Launch agent: ${PLIST_PATH}`);
|
|
50
|
+
logger.info(`Logs: ${LOG_PATH}`);
|
|
51
|
+
}
|
|
52
|
+
export async function runUninstallAutostart() {
|
|
53
|
+
await execFileAsync('launchctl', ['unload', PLIST_PATH]).catch(() => { });
|
|
54
|
+
await fs.rm(PLIST_PATH, { force: true });
|
|
55
|
+
logger.success('AgentVigil autostart removed.');
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=autostart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autostart.js","sourceRoot":"","sources":["../../src/commands/autostart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,8DAA8D;AAC9D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,OAAO,GAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;AAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAElD,MAAM,KAAK,GAAQ,uBAAuB,CAAC;AAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC;AACxF,MAAM,QAAQ,GAAK,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAE5E,SAAS,UAAU;IACjB,OAAO;;;;;YAKG,KAAK;;;cAGH,OAAO,CAAC,QAAQ;cAChB,UAAU;;;;;;;;YAQZ,QAAQ;;YAER,QAAQ;;;CAGnB,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC;IAErD,kEAAkE;IAClE,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACzE,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAE7D,MAAM,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;IACpE,MAAM,CAAC,IAAI,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC,SAAS,QAAQ,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,aAAa,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACzE,MAAM,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,MAAM,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared daemon runtime — used by both `setup` (post-pairing) and `start`.
|
|
3
|
+
*
|
|
4
|
+
* Caller is responsible for having already:
|
|
5
|
+
* - created and started the AgentVigilWsServer
|
|
6
|
+
* - set the shared secret on the WS server
|
|
7
|
+
* - (optionally) started a cloudflared tunnel
|
|
8
|
+
*/
|
|
9
|
+
import { type Session, type SessionState } from '../sessions/session-manager.js';
|
|
10
|
+
import type { AgentVigilWsServer } from '../tunnel/websocket-server.js';
|
|
11
|
+
import type { TunnelManager } from '../tunnel/tunnel-manager.js';
|
|
12
|
+
import type { AgentEvent, AgentEventType } from '../types.js';
|
|
13
|
+
export declare const TMUX_POLL_INTERVAL_MS = 5000;
|
|
14
|
+
export declare const SESSION_CLEANUP_INTERVAL_MS: number;
|
|
15
|
+
export declare const EVENT_TYPE_FOR_STATE: Record<SessionState, AgentEventType>;
|
|
16
|
+
/** Returns the first non-loopback IPv4 address of this machine. */
|
|
17
|
+
export declare function getLocalIPv4(): string | undefined;
|
|
18
|
+
export declare function toAgentEvent(session: Session): AgentEvent;
|
|
19
|
+
export declare function syncTmuxPanes(): Promise<void>;
|
|
20
|
+
export interface DaemonOptions {
|
|
21
|
+
wsServer: AgentVigilWsServer;
|
|
22
|
+
tunnelManager?: TunnelManager;
|
|
23
|
+
ntfyTopic: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Starts the relay, session watching, and tmux polling loops.
|
|
27
|
+
* Resolves when SIGINT/SIGTERM is received.
|
|
28
|
+
* The caller should NOT stop wsServer or tunnelManager before calling this.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runDaemon({ wsServer, tunnelManager, ntfyTopic }: DaemonOptions): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,YAAY,EAClB,MAAM,gCAAgC,CAAC;AAIxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9D,eAAO,MAAM,qBAAqB,OAAQ,CAAC;AAC3C,eAAO,MAAM,2BAA2B,QAAgB,CAAC;AAEzD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,YAAY,EAAE,cAAc,CAMrE,CAAC;AAEF,mEAAmE;AACnE,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAOjD;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAazD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqEpG"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared daemon runtime — used by both `setup` (post-pairing) and `start`.
|
|
3
|
+
*
|
|
4
|
+
* Caller is responsible for having already:
|
|
5
|
+
* - created and started the AgentVigilWsServer
|
|
6
|
+
* - set the shared secret on the WS server
|
|
7
|
+
* - (optionally) started a cloudflared tunnel
|
|
8
|
+
*/
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import { logger } from '../utils/logger.js';
|
|
11
|
+
import { RelayHandler } from '../relay/relay-handler.js';
|
|
12
|
+
import { cleanup, getActiveSessions, getAllSessions, updateSession, } from '../sessions/session-manager.js';
|
|
13
|
+
import { startSessionPolling } from '../sessions/session-poller.js';
|
|
14
|
+
import { watchSessions } from '../sessions/session-watcher.js';
|
|
15
|
+
import { enumerateTmuxSessions, findTmuxPaneForSession } from '../sessions/tmux-bridge.js';
|
|
16
|
+
export const TMUX_POLL_INTERVAL_MS = 5_000;
|
|
17
|
+
export const SESSION_CLEANUP_INTERVAL_MS = 5 * 60 * 1000;
|
|
18
|
+
export const EVENT_TYPE_FOR_STATE = {
|
|
19
|
+
working: 'session_started',
|
|
20
|
+
blocked: 'permission_prompt',
|
|
21
|
+
done: 'task_complete',
|
|
22
|
+
error: 'session_error',
|
|
23
|
+
idle: 'idle_waiting',
|
|
24
|
+
};
|
|
25
|
+
/** Returns the first non-loopback IPv4 address of this machine. */
|
|
26
|
+
export function getLocalIPv4() {
|
|
27
|
+
for (const addrs of Object.values(os.networkInterfaces())) {
|
|
28
|
+
for (const addr of addrs ?? []) {
|
|
29
|
+
if (addr.family === 'IPv4' && !addr.internal)
|
|
30
|
+
return addr.address;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
export function toAgentEvent(session) {
|
|
36
|
+
return {
|
|
37
|
+
type: EVENT_TYPE_FOR_STATE[session.state],
|
|
38
|
+
session_id: session.session_id,
|
|
39
|
+
project_name: session.project_name,
|
|
40
|
+
cwd: session.cwd,
|
|
41
|
+
agent: session.agent,
|
|
42
|
+
message: session.last_message ?? session.state,
|
|
43
|
+
timestamp: session.last_activity.toISOString(),
|
|
44
|
+
pid: session.pid,
|
|
45
|
+
permission_command: session.permission_command,
|
|
46
|
+
tool_name: session.tool_name,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export async function syncTmuxPanes() {
|
|
50
|
+
try {
|
|
51
|
+
const panes = await enumerateTmuxSessions();
|
|
52
|
+
if (panes.length === 0)
|
|
53
|
+
return;
|
|
54
|
+
for (const session of getAllSessions()) {
|
|
55
|
+
const pane = findTmuxPaneForSession(session.cwd, panes);
|
|
56
|
+
if (pane && pane.pane_id !== session.tmux_pane_id) {
|
|
57
|
+
updateSession(session.session_id, { tmux_pane_id: pane.pane_id, pid: pane.pid });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
logger.warn('Failed to sync tmux panes', err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Starts the relay, session watching, and tmux polling loops.
|
|
67
|
+
* Resolves when SIGINT/SIGTERM is received.
|
|
68
|
+
* The caller should NOT stop wsServer or tunnelManager before calling this.
|
|
69
|
+
*/
|
|
70
|
+
export async function runDaemon({ wsServer, tunnelManager, ntfyTopic }) {
|
|
71
|
+
const relay = new RelayHandler(wsServer, ntfyTopic);
|
|
72
|
+
// ── Process-based session detection ─────────────────────────────────────
|
|
73
|
+
// Polls every 10 s via pgrep + lsof. First poll is awaited so the store
|
|
74
|
+
// is fully populated before we advertise readiness.
|
|
75
|
+
const poller = await startSessionPolling((session) => {
|
|
76
|
+
// New session detected by the poller — push to phone immediately.
|
|
77
|
+
if (wsServer.isPhoneConnected) {
|
|
78
|
+
wsServer.sendEvent(toAgentEvent(session));
|
|
79
|
+
}
|
|
80
|
+
}, (sessionId) => {
|
|
81
|
+
// Session process died — remove from phone fleet immediately.
|
|
82
|
+
if (wsServer.isPhoneConnected) {
|
|
83
|
+
wsServer.sendEvent({
|
|
84
|
+
type: 'session_ended',
|
|
85
|
+
session_id: sessionId,
|
|
86
|
+
project_name: '',
|
|
87
|
+
cwd: '',
|
|
88
|
+
agent: 'claude-code',
|
|
89
|
+
message: 'Session terminated',
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
logger.info(`Session poll ready: ${getActiveSessions().length} active session(s)`);
|
|
95
|
+
// First poll complete — push fresh state if phone already connected.
|
|
96
|
+
if (wsServer.isPhoneConnected) {
|
|
97
|
+
wsServer.sendFullSync();
|
|
98
|
+
logger.info('Sent post-startup full sync to already-connected phone');
|
|
99
|
+
}
|
|
100
|
+
// ── JSONL watcher: live last_message updates for existing sessions ───────
|
|
101
|
+
// ignoreInitial=true — poller owns session creation; this is supplementary.
|
|
102
|
+
// Also the only signal that a `blocked` session resumed after the user
|
|
103
|
+
// approved/denied its permission prompt directly in the Mac terminal (no
|
|
104
|
+
// hook fires for that) — see RelayHandler.handleTranscriptActivity.
|
|
105
|
+
const watcher = watchSessions((update) => {
|
|
106
|
+
void relay.handleTranscriptActivity(update);
|
|
107
|
+
});
|
|
108
|
+
const tmuxTimer = setInterval(() => { void syncTmuxPanes(); }, TMUX_POLL_INTERVAL_MS);
|
|
109
|
+
const cleanTimer = setInterval(() => cleanup(), SESSION_CLEANUP_INTERVAL_MS);
|
|
110
|
+
void syncTmuxPanes();
|
|
111
|
+
logger.success('✅ AgentVigil is running — watching for Claude Code sessions');
|
|
112
|
+
await new Promise((resolve) => {
|
|
113
|
+
let shuttingDown = false;
|
|
114
|
+
const shutdown = async () => {
|
|
115
|
+
if (shuttingDown)
|
|
116
|
+
return;
|
|
117
|
+
shuttingDown = true;
|
|
118
|
+
logger.info('Shutting down AgentVigil...');
|
|
119
|
+
clearInterval(tmuxTimer);
|
|
120
|
+
clearInterval(cleanTimer);
|
|
121
|
+
poller.stop();
|
|
122
|
+
await watcher.close();
|
|
123
|
+
tunnelManager?.stop();
|
|
124
|
+
wsServer.stop();
|
|
125
|
+
resolve();
|
|
126
|
+
};
|
|
127
|
+
process.on('SIGINT', () => void shutdown());
|
|
128
|
+
process.on('SIGTERM', () => void shutdown());
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAID,wBAAsB,QAAQ,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+JxE"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
import { isCloudflaredInstalled, getConfig, saveConfig } from '../utils/config.js';
|
|
4
|
+
import { buildHookCommand, registerHooks } from '../hooks/hook-manager.js';
|
|
5
|
+
import { deriveSharedSecret, encrypt, loadOrCreateKeyPair } from '../crypto/encryption.js';
|
|
6
|
+
import { buildQrPayload, generateQrCode } from '../utils/qr.js';
|
|
7
|
+
import { AgentVigilWsServer } from '../tunnel/websocket-server.js';
|
|
8
|
+
import { TunnelManager } from '../tunnel/tunnel-manager.js';
|
|
9
|
+
import { RelayHandler } from '../relay/relay-handler.js';
|
|
10
|
+
import { getAllSessions } from '../sessions/session-manager.js';
|
|
11
|
+
import { SERVICE_ACCOUNT_PATH, printFcmSetupInstructions } from '../notifications/fcm-client.js';
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import { getLocalIPv4, runDaemon, toAgentEvent, } from './daemon.js';
|
|
14
|
+
const MIN_NODE_MAJOR_VERSION = 18;
|
|
15
|
+
export async function runSetup(options = {}) {
|
|
16
|
+
logger.banner('AgentVigil Setup');
|
|
17
|
+
logger.info('This will:');
|
|
18
|
+
logger.info(' 1. Register hooks with Claude Code and Codex');
|
|
19
|
+
logger.info(' 2. Generate encryption keys');
|
|
20
|
+
logger.info(' 3. Start a secure tunnel');
|
|
21
|
+
logger.info(' 4. Show a QR code to pair with your phone');
|
|
22
|
+
logger.info('');
|
|
23
|
+
if (!isNodeVersionSupported(process.version)) {
|
|
24
|
+
logger.error(`Node.js >= ${MIN_NODE_MAJOR_VERSION} is required (found ${process.version}) — please upgrade and re-run setup.`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const hasCloudflared = await isCloudflaredInstalled();
|
|
28
|
+
if (!hasCloudflared) {
|
|
29
|
+
logger.error('cloudflared is required but not installed.');
|
|
30
|
+
logger.info('');
|
|
31
|
+
logger.info('Install it with:');
|
|
32
|
+
logger.info(' brew install cloudflared');
|
|
33
|
+
logger.info('');
|
|
34
|
+
logger.info('Then run setup again:');
|
|
35
|
+
logger.info(' npx agentvigil setup');
|
|
36
|
+
logger.info('');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (options.dryRun) {
|
|
40
|
+
printDryRunPlan();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
await registerHooks();
|
|
44
|
+
logger.info(`Hook command: ${buildHookCommand('permission_prompt')}`);
|
|
45
|
+
logger.info('Verify with: cat ~/.claude/settings.json | grep -A2 agentvigil');
|
|
46
|
+
const keyPair = await loadOrCreateKeyPair();
|
|
47
|
+
const config = await getConfig();
|
|
48
|
+
// ── Relay handler — wired up after pairing via closure reference ────────
|
|
49
|
+
let relay;
|
|
50
|
+
let wsServer;
|
|
51
|
+
let resolvePairing;
|
|
52
|
+
const paired = new Promise((resolve) => {
|
|
53
|
+
resolvePairing = resolve;
|
|
54
|
+
});
|
|
55
|
+
const handlePairRequest = (request, socket) => {
|
|
56
|
+
const sharedSecret = deriveSharedSecret(keyPair.secretKey, request.pub_key);
|
|
57
|
+
wsServer.setSharedSecret(sharedSecret);
|
|
58
|
+
const device = {
|
|
59
|
+
name: request.device_name,
|
|
60
|
+
device_id: uuidv4(),
|
|
61
|
+
public_key: request.pub_key,
|
|
62
|
+
shared_secret: sharedSecret,
|
|
63
|
+
paired_at: new Date().toISOString(),
|
|
64
|
+
};
|
|
65
|
+
// Encrypted confirmation — phone needs this to know pairing succeeded.
|
|
66
|
+
const confirmation = encrypt(JSON.stringify({ type: 'paired', device_id: config.device_id }), sharedSecret);
|
|
67
|
+
socket.send(JSON.stringify({ payload: confirmation }));
|
|
68
|
+
resolvePairing(device);
|
|
69
|
+
};
|
|
70
|
+
// Create the WS server with relay callbacks wired via closure so that
|
|
71
|
+
// commands and hook events work immediately after pairing, without
|
|
72
|
+
// needing to restart the server.
|
|
73
|
+
wsServer = new AgentVigilWsServer(config.ws_port, {
|
|
74
|
+
getSessions: () => getAllSessions().map(toAgentEvent),
|
|
75
|
+
onPairRequest: handlePairRequest,
|
|
76
|
+
onCommand: (command) => { void relay?.handlePhoneCommand(command); },
|
|
77
|
+
onHookEvent: (event) => { void relay?.handleAgentEvent(event); },
|
|
78
|
+
localToken: keyPair.secretKey,
|
|
79
|
+
});
|
|
80
|
+
wsServer.start();
|
|
81
|
+
// ── Tunnel ──────────────────────────────────────────────────────────────
|
|
82
|
+
const tunnelManager = new TunnelManager();
|
|
83
|
+
let tunnelUrl;
|
|
84
|
+
try {
|
|
85
|
+
tunnelUrl = await tunnelManager.start(config.ws_port);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
logger.warn('Could not start cloudflared tunnel — pairing will only work on the local network', err);
|
|
89
|
+
}
|
|
90
|
+
if (tunnelUrl) {
|
|
91
|
+
config.tunnel_url = tunnelUrl;
|
|
92
|
+
await saveConfig(config);
|
|
93
|
+
}
|
|
94
|
+
// Use the Mac's real LAN IP when there is no internet tunnel, so the phone
|
|
95
|
+
// (on the same Wi-Fi) can actually reach the WebSocket server.
|
|
96
|
+
const localIp = getLocalIPv4();
|
|
97
|
+
const lanUrl = localIp
|
|
98
|
+
? `ws://${localIp}:${config.ws_port}`
|
|
99
|
+
: `ws://localhost:${config.ws_port}`;
|
|
100
|
+
const qrUrl = tunnelUrl ?? lanUrl;
|
|
101
|
+
if (!tunnelUrl && localIp) {
|
|
102
|
+
logger.info(`No tunnel — using LAN address ${lanUrl} (phone and Mac must share the same Wi-Fi).`);
|
|
103
|
+
}
|
|
104
|
+
const qrPayload = buildQrPayload({
|
|
105
|
+
tunnelUrl: qrUrl,
|
|
106
|
+
ntfyTopic: config.ntfy_topic,
|
|
107
|
+
deviceId: config.device_id,
|
|
108
|
+
publicKey: keyPair.publicKey,
|
|
109
|
+
});
|
|
110
|
+
logger.info('Scan this QR code with the AgentVigil mobile app:');
|
|
111
|
+
generateQrCode(qrPayload);
|
|
112
|
+
logger.info('Waiting for the app to pair...');
|
|
113
|
+
// ── Wait for pairing ────────────────────────────────────────────────────
|
|
114
|
+
const device = await paired;
|
|
115
|
+
config.paired_devices = [
|
|
116
|
+
...config.paired_devices.filter((d) => d.public_key !== device.public_key),
|
|
117
|
+
device,
|
|
118
|
+
];
|
|
119
|
+
await saveConfig(config);
|
|
120
|
+
logger.success(`✅ Paired with AgentVigil (${device.name})`);
|
|
121
|
+
if (!fs.existsSync(SERVICE_ACCOUNT_PATH)) {
|
|
122
|
+
printFcmSetupInstructions();
|
|
123
|
+
}
|
|
124
|
+
logger.info('');
|
|
125
|
+
logger.success('Setup complete!');
|
|
126
|
+
logger.info('');
|
|
127
|
+
logger.info('Next steps:');
|
|
128
|
+
logger.info(' 1. Scan the QR code above with AgentVigil on your phone');
|
|
129
|
+
logger.info(' 2. Download AgentVigil: https://agentvigil.app');
|
|
130
|
+
logger.info(' 3. Start the daemon: npx agentvigil start');
|
|
131
|
+
logger.info('');
|
|
132
|
+
logger.info('To start automatically on login:');
|
|
133
|
+
logger.info(' npx agentvigil install-autostart');
|
|
134
|
+
logger.info('');
|
|
135
|
+
logger.info('Staying alive as daemon — watching for Claude Code sessions (Ctrl-C to quit).');
|
|
136
|
+
// ── Activate relay and run as daemon ────────────────────────────────────
|
|
137
|
+
// Assigning `relay` here makes the WS server's onCommand / onHookEvent
|
|
138
|
+
// callbacks live; sessions are now forwarded in real time.
|
|
139
|
+
relay = new RelayHandler(wsServer, config.ntfy_topic);
|
|
140
|
+
await runDaemon({
|
|
141
|
+
wsServer,
|
|
142
|
+
tunnelManager: tunnelUrl ? tunnelManager : undefined,
|
|
143
|
+
ntfyTopic: config.ntfy_topic,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function isNodeVersionSupported(version) {
|
|
147
|
+
const major = Number(version.replace(/^v/, '').split('.')[0]);
|
|
148
|
+
return Number.isFinite(major) && major >= MIN_NODE_MAJOR_VERSION;
|
|
149
|
+
}
|
|
150
|
+
function printDryRunPlan() {
|
|
151
|
+
logger.info('Dry run — no changes will be made. `setup` would:');
|
|
152
|
+
logger.info(' 1. Register Claude Code hooks in ~/.claude/settings.json (merged, never overwritten)');
|
|
153
|
+
logger.info(' 2. Generate an X25519 keypair and save it to ~/.agentvigil/keys.json');
|
|
154
|
+
logger.info(' 3. Start a local WebSocket server and display a pairing QR code');
|
|
155
|
+
logger.info(' 4. Start a cloudflared tunnel so the phone can pair from anywhere');
|
|
156
|
+
logger.info(' 5. After pairing, run as daemon (no need to run `start` separately)');
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAgBA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA0F9C"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
import { ensureCloudflared, getConfig, saveConfig } from '../utils/config.js';
|
|
4
|
+
import { deriveSharedSecret, encrypt, loadOrCreateKeyPair } from '../crypto/encryption.js';
|
|
5
|
+
import { AgentVigilWsServer } from '../tunnel/websocket-server.js';
|
|
6
|
+
import { TunnelManager } from '../tunnel/tunnel-manager.js';
|
|
7
|
+
import { RelayHandler } from '../relay/relay-handler.js';
|
|
8
|
+
import { getActiveSessions } from '../sessions/session-manager.js';
|
|
9
|
+
import { getLocalIPv4, runDaemon, toAgentEvent, } from './daemon.js';
|
|
10
|
+
export async function runStart() {
|
|
11
|
+
logger.banner('AgentVigil');
|
|
12
|
+
const config = await getConfig();
|
|
13
|
+
if (config.paired_devices.length === 0) {
|
|
14
|
+
logger.warn('No paired devices found — run `npx agentvigil setup` first.');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const keyPair = await loadOrCreateKeyPair();
|
|
18
|
+
const hasCloudflared = await ensureCloudflared();
|
|
19
|
+
let wsServer;
|
|
20
|
+
let relay;
|
|
21
|
+
const handlePairRequest = (request, socket) => {
|
|
22
|
+
const sharedSecret = deriveSharedSecret(keyPair.secretKey, request.pub_key);
|
|
23
|
+
wsServer.setSharedSecret(sharedSecret);
|
|
24
|
+
const device = {
|
|
25
|
+
name: request.device_name,
|
|
26
|
+
device_id: uuidv4(),
|
|
27
|
+
public_key: request.pub_key,
|
|
28
|
+
shared_secret: sharedSecret,
|
|
29
|
+
paired_at: new Date().toISOString(),
|
|
30
|
+
};
|
|
31
|
+
const confirmation = encrypt(JSON.stringify({ type: 'paired', device_id: config.device_id }), sharedSecret);
|
|
32
|
+
socket.send(JSON.stringify({ payload: confirmation }));
|
|
33
|
+
config.paired_devices = [
|
|
34
|
+
...config.paired_devices.filter((d) => d.public_key !== device.public_key),
|
|
35
|
+
device,
|
|
36
|
+
];
|
|
37
|
+
void saveConfig(config);
|
|
38
|
+
logger.success(`Paired with a new device: ${device.name}`);
|
|
39
|
+
};
|
|
40
|
+
wsServer = new AgentVigilWsServer(config.ws_port, {
|
|
41
|
+
getSessions: () => {
|
|
42
|
+
// Deduplicate by cwd — poller and hook may both have created entries for
|
|
43
|
+
// the same project. Prefer blocked state so the permission card shows.
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
const deduped = getActiveSessions()
|
|
46
|
+
.sort((a, b) => (a.state === 'blocked' ? -1 : b.state === 'blocked' ? 1 : 0))
|
|
47
|
+
.filter(s => {
|
|
48
|
+
if (seen.has(s.cwd))
|
|
49
|
+
return false;
|
|
50
|
+
seen.add(s.cwd);
|
|
51
|
+
return true;
|
|
52
|
+
});
|
|
53
|
+
logger.info(`Full sync: sending ${deduped.length} active session(s) to phone`);
|
|
54
|
+
return deduped.map(toAgentEvent);
|
|
55
|
+
},
|
|
56
|
+
onPairRequest: handlePairRequest,
|
|
57
|
+
onCommand: (command) => { void relay.handlePhoneCommand(command); },
|
|
58
|
+
onHookEvent: (event) => { void relay.handleAgentEvent(event); },
|
|
59
|
+
localToken: keyPair.secretKey,
|
|
60
|
+
});
|
|
61
|
+
relay = new RelayHandler(wsServer, config.ntfy_topic);
|
|
62
|
+
// Resume the most recently paired device without requiring a re-scan.
|
|
63
|
+
wsServer.setSharedSecret(config.paired_devices.at(-1)?.shared_secret);
|
|
64
|
+
wsServer.start();
|
|
65
|
+
// ── Tunnel ──────────────────────────────────────────────────────────────
|
|
66
|
+
let tunnelManager;
|
|
67
|
+
if (hasCloudflared) {
|
|
68
|
+
tunnelManager = new TunnelManager();
|
|
69
|
+
try {
|
|
70
|
+
const tunnelUrl = await tunnelManager.start(config.ws_port);
|
|
71
|
+
config.tunnel_url = tunnelUrl;
|
|
72
|
+
await saveConfig(config);
|
|
73
|
+
logger.info(`Tunnel: ${tunnelUrl}`);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
logger.warn('Could not start cloudflared tunnel — continuing with ntfy notifications only', err);
|
|
77
|
+
tunnelManager = undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const localIp = getLocalIPv4();
|
|
82
|
+
const lanUrl = localIp ? `ws://${localIp}:${config.ws_port}` : undefined;
|
|
83
|
+
logger.warn('cloudflared is not installed — continuing with ntfy notifications only.');
|
|
84
|
+
if (lanUrl)
|
|
85
|
+
logger.info(`LAN address (same Wi-Fi only): ${lanUrl}`);
|
|
86
|
+
}
|
|
87
|
+
await runDaemon({ wsServer, tunnelManager, ntfyTopic: config.ntfy_topic });
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes all AgentVigil hook entries from ~/.claude/settings.json.
|
|
3
|
+
* Only removes commands registered by AgentVigil — all other hooks
|
|
4
|
+
* (including other tools' hooks) are left completely untouched.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runUninstall(): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=uninstall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAIlD"}
|