ai-garcon 0.1.0 → 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.
- package/README.md +130 -0
- package/bin/check-package.js +13 -0
- package/bin/garcon.js +3 -2
- package/bin/resolve.js +7 -8
- package/bin/update.js +42 -0
- package/dist/darwin-arm64/garcon +0 -0
- package/dist/darwin-x64/garcon +0 -0
- package/dist/linux-arm64/garcon +0 -0
- package/dist/linux-x64/garcon +0 -0
- package/package.json +15 -10
- package/bin/postinstall.js +0 -12
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# ai-garcon
|
|
2
|
+
|
|
3
|
+
Observability for coding agents. One tiny local proxy sits in front of Claude Code, Codex,
|
|
4
|
+
OpenClaw, Hermes or any compatible client, records what every call cost in tokens, and shows
|
|
5
|
+
it in one dashboard, across accounts, tools and, with sync on, every machine you work from.
|
|
6
|
+
Requests and replies are forwarded unchanged; prompts, replies and keys are never stored.
|
|
7
|
+
|
|
8
|
+
Documentation: https://asieke.github.io/garcon/ · Source: https://github.com/asieke/garcon
|
|
9
|
+
|
|
10
|
+
## Install and set up this machine
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm install -g ai-garcon@latest
|
|
14
|
+
garcon setup
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
macOS and Linux, x64 and arm64; Node 18+ is needed to run the npm command.
|
|
18
|
+
`setup` starts Garcon at login and verifies http://127.0.0.1:4141. Open the printed
|
|
19
|
+
Settings link, choose your harness and account label, and copy its configuration.
|
|
20
|
+
Restart the harness, send one short request, and check Logs. Existing usage and sync
|
|
21
|
+
settings are preserved when setup is rerun. Sync is optional.
|
|
22
|
+
|
|
23
|
+
To try it without a global install: `npx ai-garcon@latest` runs in the foreground.
|
|
24
|
+
For containers or Linux without a systemd user session, run `garcon` in one terminal
|
|
25
|
+
and `garcon setup --no-service` in another. A custom foreground address works with
|
|
26
|
+
`garcon -listen 127.0.0.1:4242` and `garcon setup --no-service --url http://127.0.0.1:4242`.
|
|
27
|
+
|
|
28
|
+
If installation fails with EACCES, use a Node version manager or a user-owned npm
|
|
29
|
+
prefix ([npm's instructions](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally/)).
|
|
30
|
+
Run setup as your normal user. If `garcon` is not found, ensure `$(npm prefix -g)/bin`
|
|
31
|
+
is on PATH and restart your shell. `type -a garcon` finds competing source/npm installs.
|
|
32
|
+
|
|
33
|
+
## Update
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
garcon update
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This updates the owning global npm installation, refreshes an installed service,
|
|
40
|
+
and waits for its new version to answer. Without a service, it tells you how to start
|
|
41
|
+
one or restart your foreground process. Usage, settings and device identity are kept.
|
|
42
|
+
Updating briefly restarts the proxy; finish active agent requests first.
|
|
43
|
+
For an older Garcon without `update`, use:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm install -g ai-garcon@latest
|
|
47
|
+
garcon service restart
|
|
48
|
+
garcon doctor --wait 10s
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The service uses its own executable at `~/.local/share/garcon/bin/garcon`, so changing
|
|
52
|
+
Node versions or clearing an npx cache cannot remove it. After changing Node versions,
|
|
53
|
+
reinstall the npm command in the new environment and run `garcon setup`.
|
|
54
|
+
|
|
55
|
+
## Check or remove an installation
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
garcon doctor # reachability, versions, first request, sync progress/errors
|
|
59
|
+
garcon service status
|
|
60
|
+
garcon service uninstall # stop autostart; keep usage and settings
|
|
61
|
+
npm uninstall -g ai-garcon
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Restore each harness's original base URL/provider before removing the proxy, so your
|
|
65
|
+
tools can keep connecting. Linux service logs: `journalctl --user -u garcon`.
|
|
66
|
+
macOS logs: `~/Library/Logs/garcon.log`.
|
|
67
|
+
|
|
68
|
+
## Point an agent at it
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
# Claude Code
|
|
72
|
+
ANTHROPIC_BASE_URL=http://127.0.0.1:4141/claude/me@example.com \
|
|
73
|
+
_CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL=1 claude
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Codex, OpenClaw, Hermes and anything OpenAI- or Anthropic-compatible: Settings → Connect a
|
|
77
|
+
harness generates the exact configuration, or see the
|
|
78
|
+
[docs](https://asieke.github.io/garcon/connect.html). Make one short call and the row appears
|
|
79
|
+
in Logs.
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
## Sync across devices
|
|
83
|
+
|
|
84
|
+
Optional: local recording works without Supabase. First, run `garcon setup` on each
|
|
85
|
+
machine. Give each machine a distinct device name in Settings → Sync. Use the same
|
|
86
|
+
project on every machine; do not copy `sync.json` or another machine's data directory,
|
|
87
|
+
because that would duplicate its identity.
|
|
88
|
+
|
|
89
|
+
**First machine, browser path (no Supabase CLI required):**
|
|
90
|
+
|
|
91
|
+
1. Create or choose a Supabase project in your own account.
|
|
92
|
+
2. Run `garcon connect-supabase --print-sql` and paste the output into that project's SQL Editor.
|
|
93
|
+
3. In Garcon Settings → Sync, enter a device name, project URL and secret (`sb_secret_`) key
|
|
94
|
+
from Project Settings → API Keys. Enable sync and Save. Garcon verifies table access
|
|
95
|
+
before saving. Keep this project key in your password manager for the next machine.
|
|
96
|
+
|
|
97
|
+
**First machine, automated CLI path:** install the [Supabase CLI](https://supabase.com/docs/guides/cli),
|
|
98
|
+
run `supabase login`, then explicitly choose project creation or reuse:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
garcon connect-supabase --create-project --name "work laptop"
|
|
102
|
+
# Or apply the schema to an existing project:
|
|
103
|
+
garcon connect-supabase --project-ref <ref> --name "work laptop"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Creation checks CLI capabilities first; `--org-id` and `--region` choose where to create
|
|
107
|
+
it. Review your organization's project limits and plan in Supabase. If a later step fails,
|
|
108
|
+
reuse the printed project ref instead of creating another project.
|
|
109
|
+
|
|
110
|
+
**Subsequent machines:** open Settings → Sync, paste the same URL and key, choose a new
|
|
111
|
+
device name, enable and Save. No CLI, new project, or SQL needed. For a headless machine,
|
|
112
|
+
read the key from a password manager or protected file rather than putting it in shell history:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
garcon connect-supabase --name "home desktop" \
|
|
116
|
+
--project-url https://<ref>.supabase.co --key-stdin < /path/to/protected-key-file
|
|
117
|
+
# Or with the Supabase CLI already logged in:
|
|
118
|
+
garcon connect-supabase --name "home desktop" --project-ref <ref> --skip-schema
|
|
119
|
+
garcon doctor
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Save verifies table access; syncing happens in the background. Within about a minute,
|
|
123
|
+
Settings → Sync should show the other devices. `garcon doctor` reports pending uploads
|
|
124
|
+
and the latest sync errors. First enable uploads existing local history.
|
|
125
|
+
|
|
126
|
+
Only device, time, harness, account, provider, model, status, latency and token counts
|
|
127
|
+
are synced. Prompts and replies are not recorded. The project secret key can access other
|
|
128
|
+
project data too: use a dedicated project and share the key only with your own trusted
|
|
129
|
+
machines. It is stored in `~/.config/garcon/config.json` with mode 0600. Turning sync off
|
|
130
|
+
stops push/pull while retaining local usage. See the [sync guide](https://asieke.github.io/garcon/sync.html).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
for (const target of ['linux-x64', 'linux-arm64', 'darwin-x64', 'darwin-arm64']) {
|
|
5
|
+
const binary = path.join(__dirname, '..', 'dist', target, 'garcon');
|
|
6
|
+
try {
|
|
7
|
+
const stat = fs.statSync(binary);
|
|
8
|
+
if (!stat.isFile() || stat.size < 1024 || !(stat.mode & 0o111)) throw new Error('invalid executable');
|
|
9
|
+
} catch {
|
|
10
|
+
console.error(`Missing or invalid ${target} binary. Build all targets with scripts/release.sh VERSION --dry-run before packing or publishing.`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
package/bin/garcon.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
const { spawnSync } = require('node:child_process');
|
|
4
|
-
const {
|
|
4
|
+
const { target, binaryPath } = require('./resolve.js');
|
|
5
|
+
if (process.argv[2] === 'update') process.exit(require('./update.js').update(process.argv.slice(3)));
|
|
5
6
|
const bin = binaryPath();
|
|
6
7
|
if (!bin) {
|
|
7
|
-
console.error(`ai-garcon:
|
|
8
|
+
console.error(`ai-garcon: binary missing for ${target}. Supported: linux/darwin on x64/arm64. Reinstall with npm install -g ai-garcon@latest.`);
|
|
8
9
|
console.error('Build from source instead: https://github.com/asieke/garcon');
|
|
9
10
|
process.exit(1);
|
|
10
11
|
}
|
package/bin/resolve.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
//
|
|
1
|
+
// The package ships one static binary per platform under dist/<os>-<arch>/garcon.
|
|
2
2
|
'use strict';
|
|
3
|
-
const
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const target = `${process.platform}-${process.arch}`;
|
|
4
6
|
function binaryPath() {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} catch {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
7
|
+
const p = path.join(__dirname, '..', 'dist', target, 'garcon');
|
|
8
|
+
return fs.existsSync(p) ? p : null;
|
|
10
9
|
}
|
|
11
|
-
module.exports = {
|
|
10
|
+
module.exports = { target, binaryPath };
|
package/bin/update.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const { spawnSync } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
// Only update the global installation that owns this shim, never an unrelated prefix.
|
|
8
|
+
function globalPrefix(packageDir) {
|
|
9
|
+
const suffix = path.join('lib', 'node_modules', 'ai-garcon');
|
|
10
|
+
return packageDir.endsWith(path.sep + suffix) ? packageDir.slice(0, -suffix.length - 1) || '/' : null;
|
|
11
|
+
}
|
|
12
|
+
function update(args, { packageDir = path.resolve(__dirname, '..'), spawn = spawnSync,
|
|
13
|
+
exists = fs.existsSync, home = os.homedir(), platform = process.platform } = {}) {
|
|
14
|
+
if (args.length) {
|
|
15
|
+
console.log('Usage: garcon update\nUpdates this global npm installation, refreshes an installed service, and checks its version.');
|
|
16
|
+
return args.length === 1 && ['--help', '-h'].includes(args[0]) ? 0 : 2;
|
|
17
|
+
}
|
|
18
|
+
const prefix = globalPrefix(packageDir);
|
|
19
|
+
if (!prefix) {
|
|
20
|
+
console.error('For npx: run npx ai-garcon@latest setup. For a local dependency: npm install ai-garcon@latest, then npx garcon setup.');
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
function run(bin, argv) {
|
|
24
|
+
const r = spawn(bin, argv, { stdio: 'inherit' });
|
|
25
|
+
if (r.error) { console.error(r.error.message); return 1; }
|
|
26
|
+
return r.status ?? 1;
|
|
27
|
+
}
|
|
28
|
+
console.log(`Updating ai-garcon in ${prefix}…`);
|
|
29
|
+
const status = run('npm', ['install', '--global', '--prefix', prefix, 'ai-garcon@latest']);
|
|
30
|
+
if (status) {
|
|
31
|
+
console.error('Update failed. For EACCES, use a user-owned npm prefix: https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally/');
|
|
32
|
+
return status;
|
|
33
|
+
}
|
|
34
|
+
const shim = path.join(packageDir, 'bin/garcon.js');
|
|
35
|
+
if (!exists(shim)) { console.error('Package shim missing after update; reinstall ai-garcon.'); return 1; }
|
|
36
|
+
const unit = platform === 'darwin' ? path.join(home, 'Library/LaunchAgents/dev.garcon.plist') : path.join(home, '.config/systemd/user/garcon.service');
|
|
37
|
+
if (!exists(unit)) { console.log('Updated. Run garcon setup to start the service, or restart your foreground Garcon.'); return 0; }
|
|
38
|
+
const restart = run(process.execPath, [shim, 'service', 'restart']);
|
|
39
|
+
if (restart) return restart;
|
|
40
|
+
return run(process.execPath, [shim, 'doctor', '--wait', '10s']);
|
|
41
|
+
}
|
|
42
|
+
module.exports = { update, globalPrefix };
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-garcon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Observability for coding agents: a local pass-through proxy that records what Claude Code, Codex and other agents spend in tokens, with a dashboard and optional cross-device sync.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -20,18 +20,23 @@
|
|
|
20
20
|
"garcon": "bin/garcon.js"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
|
-
"bin"
|
|
23
|
+
"bin",
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"os": [
|
|
28
|
+
"linux",
|
|
29
|
+
"darwin"
|
|
30
|
+
],
|
|
31
|
+
"cpu": [
|
|
32
|
+
"x64",
|
|
33
|
+
"arm64"
|
|
24
34
|
],
|
|
25
|
-
"scripts": {
|
|
26
|
-
"postinstall": "node bin/postinstall.js"
|
|
27
|
-
},
|
|
28
35
|
"engines": {
|
|
29
36
|
"node": ">=18"
|
|
30
37
|
},
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"ai-garcon-darwin-x64": "0.1.0",
|
|
35
|
-
"ai-garcon-darwin-arm64": "0.1.0"
|
|
38
|
+
"scripts": {
|
|
39
|
+
"test": "node --test test/*.test.js",
|
|
40
|
+
"prepack": "node bin/check-package.js"
|
|
36
41
|
}
|
|
37
42
|
}
|
package/bin/postinstall.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// After an install or upgrade, restart a running garcon service so it picks up the new
|
|
2
|
-
// binary. `garcon service restart` is a no-op when no service is installed, and any
|
|
3
|
-
// failure here must never fail the npm install itself.
|
|
4
|
-
'use strict';
|
|
5
|
-
const { spawnSync } = require('node:child_process');
|
|
6
|
-
const { binaryPath } = require('./resolve.js');
|
|
7
|
-
const bin = binaryPath();
|
|
8
|
-
if (bin) {
|
|
9
|
-
try {
|
|
10
|
-
spawnSync(bin, ['service', 'restart'], { stdio: 'inherit' });
|
|
11
|
-
} catch {}
|
|
12
|
-
}
|