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 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 { pkg, binaryPath } = require('./resolve.js');
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: no prebuilt binary for ${process.platform}-${process.arch} (package ${pkg}).`);
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
- // Locate the prebuilt binary for this platform, installed as an optional dependency.
1
+ // The package ships one static binary per platform under dist/<os>-<arch>/garcon.
2
2
  'use strict';
3
- const pkg = `ai-garcon-${process.platform}-${process.arch}`;
3
+ const path = require('node:path');
4
+ const fs = require('node:fs');
5
+ const target = `${process.platform}-${process.arch}`;
4
6
  function binaryPath() {
5
- try {
6
- return require.resolve(`${pkg}/bin/garcon`);
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 = { pkg, binaryPath };
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.0",
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
- "optionalDependencies": {
32
- "ai-garcon-linux-x64": "0.1.0",
33
- "ai-garcon-linux-arm64": "0.1.0",
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
  }
@@ -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
- }