IMMICH_URL/IMMICH_API_KEY lived in the platform-wide .env, which was wrong twice over: bun auto-loads .env into every process started in this directory, so `officer` itself held an immich credential it has no code to use — and connecting a library was a shell task on the server rather than something the owner could do from the app. it is a registry, not a single connection: any number of labelled accounts with one selected, the same shape headscale_servers uses. two keys against the same instance (one per immich user) is the ordinary case, so the label is what has to be unique, not the url. one active account per owner is enforced by a partial unique index rather than by convention. keys are encrypted at rest and write-only across the sidecar boundary — no route returns one, masked or otherwise. every save is validated against the live instance first, so a wrong or under-scoped key is a 400 with the reason instead of a stored row that makes every later screen fail mysteriously. the drizzle snapshot under migrations/ is regenerated; nothing applies it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
119 lines
3.9 KiB
JavaScript
119 lines
3.9 KiB
JavaScript
module.exports = {
|
|
apps: [
|
|
{
|
|
name: 'officer',
|
|
script: 'bun',
|
|
args: 'start',
|
|
watch: false,
|
|
},
|
|
// The Anthropic credential proxy. Despite the old name (`officer-claude`) this process does NOT
|
|
// run agents — it holds the proxy secret and forwards to api.anthropic.com. The process that runs
|
|
// agents is `officer-agent` below.
|
|
{
|
|
name: 'officer-anthropic-proxy',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/claude/index.ts',
|
|
watch: false,
|
|
},
|
|
// The process that actually runs `claude`. It used to be spawned on demand by the main server,
|
|
// which made every agent session a grandchild of `officer` and killed it on every restart. As a PM2
|
|
// peer it survives them. It resolves the owner from the database and the proxy secret from the
|
|
// proxy's state file, so it needs nothing from `officer` in order to start.
|
|
{
|
|
name: 'officer-agent',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/claude/user-instance.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-opencode',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/opencode/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-email',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/email/index.ts',
|
|
watch: false,
|
|
},
|
|
// The only sidecar run by `node` rather than `bun`, and the only one that is not TypeScript: node-pty
|
|
// is a native addon. It also does not use sidecar/connect.ts, and carries its own copy of the
|
|
// reconnect loop.
|
|
{
|
|
name: 'officer-pty',
|
|
script: 'node',
|
|
args: 'src/servers/sidecar/pty/index.mjs',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-vnc',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/vnc/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-music',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/music/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-vault',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/vault/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-slskd',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/slskd/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-headscale',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/headscale/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-transmission',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/transmission/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-invoiceshelf',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/invoiceshelf/index.ts',
|
|
watch: false,
|
|
},
|
|
// The photo library. Wraps a self-hosted Immich. The instance and its key are set by the owner from
|
|
// /photos/settings and stored encrypted in `photos_config` — read here, never from the environment,
|
|
// because Bun auto-loads `.env` into every process in this directory and `officer` would hold it too.
|
|
{
|
|
name: 'officer-photos',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/photos/index.ts',
|
|
watch: false,
|
|
},
|
|
// The bitcoin wallet. Holds seed material (sealed under an owner passphrase) and node credentials, so
|
|
// it is the one sidecar whose restart has a security-relevant side effect: every wallet relocks.
|
|
// The one place anything leaves this machine to tell the owner something: push (APNs + FCM) and the
|
|
// Discord webhook, behind one interface. A sidecar rather than platform code because the producers
|
|
// are spread across sidecars, and a platform-owned notifier would make every one of them call back in.
|
|
{
|
|
name: 'officer-notify',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/notify/index.ts',
|
|
watch: false,
|
|
},
|
|
{
|
|
name: 'officer-wallet',
|
|
script: 'bun',
|
|
args: 'run src/servers/sidecar/wallet/index.ts',
|
|
watch: false,
|
|
},
|
|
],
|
|
};
|