@miller-tech/uap 1.119.4 → 1.121.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/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +14 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/guided-setup.d.ts +5 -0
- package/dist/cli/guided-setup.d.ts.map +1 -1
- package/dist/cli/guided-setup.js +61 -4
- package/dist/cli/guided-setup.js.map +1 -1
- package/dist/cli/proxy-lifecycle.d.ts +125 -0
- package/dist/cli/proxy-lifecycle.d.ts.map +1 -0
- package/dist/cli/proxy-lifecycle.js +286 -0
- package/dist/cli/proxy-lifecycle.js.map +1 -0
- package/dist/cli/proxy.d.ts +35 -0
- package/dist/cli/proxy.d.ts.map +1 -0
- package/dist/cli/proxy.js +395 -0
- package/dist/cli/proxy.js.map +1 -0
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +14 -0
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/wizard-config.d.ts +28 -0
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +60 -0
- package/dist/cli/wizard-config.js.map +1 -1
- package/package.json +1 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference-counted, session-scoped proxy lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Goal (per product spec): the UAP Anthropic proxy should start when an agent
|
|
5
|
+
* session is triggered (via the SessionStart hook) and exit WITH the agent —
|
|
6
|
+
* but only when it is safe to do so:
|
|
7
|
+
*
|
|
8
|
+
* - If a proxy is already running, ADOPT it (reuse) — never start a second.
|
|
9
|
+
* - A proxy we adopted (already up), OR a systemd-managed unit, is NEVER
|
|
10
|
+
* stopped by us on session end (systemd units are persistent infra).
|
|
11
|
+
* - A proxy WE spawned as a plain process is reference-counted across
|
|
12
|
+
* sessions: it is stopped on release only when the LAST client (agent
|
|
13
|
+
* session) leaves. If any other client is still using it, it keeps running.
|
|
14
|
+
*
|
|
15
|
+
* This module holds the pure decision logic + a tiny file-backed registry so it
|
|
16
|
+
* is unit-testable without spawning a real proxy or touching systemd. The real
|
|
17
|
+
* side effects (spawn / systemctl / HTTP health probe) are injected as `deps`.
|
|
18
|
+
*
|
|
19
|
+
* Liveness note: a client's `pid` MUST be the long-lived AGENT process (the one
|
|
20
|
+
* that spawns SessionStart and SessionEnd), NOT the ephemeral hook/CLI process
|
|
21
|
+
* — otherwise the dead-pid pruning below evicts every live session moments
|
|
22
|
+
* after it registers. The hook passes `$PPID` (the agent) via `--client-pid`.
|
|
23
|
+
*/
|
|
24
|
+
/** Default port the proxy listens on (matches run-anthropic-proxy-continuity.sh). */
|
|
25
|
+
export declare const DEFAULT_PROXY_PORT: number;
|
|
26
|
+
/**
|
|
27
|
+
* Runtime root for the client registry + owner marker. Prefer XDG_RUNTIME_DIR
|
|
28
|
+
* (tmpfs at /run/user/<uid>, mode 0700, cleared on logout) and fall back to
|
|
29
|
+
* ~/.cache. Overridable via UAP_PROXY_RUNTIME_DIR for tests.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runtimeDir(): string;
|
|
32
|
+
/** How the proxy we own was launched — only 'process' is ever auto-stopped. */
|
|
33
|
+
export type OwnerKind = 'process' | 'systemd';
|
|
34
|
+
export interface OwnerRecord {
|
|
35
|
+
kind: OwnerKind;
|
|
36
|
+
/** pid of the launched proxy process (kind==='process'). */
|
|
37
|
+
pid?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Opaque process-identity token captured at launch (e.g. /proc start-time).
|
|
40
|
+
* Checked before signaling to defend against PID reuse.
|
|
41
|
+
*/
|
|
42
|
+
startToken?: string;
|
|
43
|
+
/** systemd unit name (kind==='systemd'). */
|
|
44
|
+
unit?: string;
|
|
45
|
+
port: number;
|
|
46
|
+
startedAt: string;
|
|
47
|
+
}
|
|
48
|
+
export interface ClientRecord {
|
|
49
|
+
clientId: string;
|
|
50
|
+
/** pid of the long-lived AGENT process, used to prune dead clients. */
|
|
51
|
+
pid: number;
|
|
52
|
+
harness?: string;
|
|
53
|
+
registeredAt: string;
|
|
54
|
+
}
|
|
55
|
+
/** Is a pid still alive? `kill(pid, 0)` throws ESRCH when it isn't. */
|
|
56
|
+
export declare function isPidAlive(pid: number): boolean;
|
|
57
|
+
/** Derive the agent pid encoded in a `ppid-<n>` fallback client id, if present. */
|
|
58
|
+
export declare function pidFromClientId(clientId: string): number | null;
|
|
59
|
+
/** Register (or refresh) a client in the registry. Idempotent per clientId. */
|
|
60
|
+
export declare function registerClient(rt: string, rec: ClientRecord): void;
|
|
61
|
+
/** Remove a client from the registry (no-op if absent). */
|
|
62
|
+
export declare function deregisterClient(rt: string, clientId: string): void;
|
|
63
|
+
/** List live clients, pruning any whose AGENT process has died (self-healing). */
|
|
64
|
+
export declare function listClients(rt: string, opts?: {
|
|
65
|
+
prune?: boolean;
|
|
66
|
+
}): ClientRecord[];
|
|
67
|
+
export declare function readOwner(rt: string): OwnerRecord | null;
|
|
68
|
+
export declare function writeOwner(rt: string, rec: OwnerRecord): void;
|
|
69
|
+
export declare function clearOwner(rt: string): void;
|
|
70
|
+
export declare function acquireStartLock(rt: string, timeoutMs?: number): Promise<boolean>;
|
|
71
|
+
export declare function releaseStartLock(rt: string): void;
|
|
72
|
+
/** Outcome of a start attempt. `owner` is set ONLY for a process WE spawned and
|
|
73
|
+
* confirmed serving — systemd/adopted starts return owner:null (never stopped). */
|
|
74
|
+
export interface StartResult {
|
|
75
|
+
healthy: boolean;
|
|
76
|
+
owner: OwnerRecord | null;
|
|
77
|
+
}
|
|
78
|
+
export interface LifecycleDeps {
|
|
79
|
+
/** Resolve true when the proxy answers a health probe on `port`. */
|
|
80
|
+
probeHealth: (port: number) => Promise<boolean>;
|
|
81
|
+
/** Start the proxy; wait for health; return {healthy, owner}. Owner==null
|
|
82
|
+
* means "do not claim stoppable ownership" (systemd / failed / adopted). */
|
|
83
|
+
startProxy: (port: number) => Promise<StartResult>;
|
|
84
|
+
/** Stop a proxy WE own (kill pid after identity check). */
|
|
85
|
+
stopProxy: (owner: OwnerRecord) => Promise<void>;
|
|
86
|
+
/** ISO timestamp (injectable for deterministic tests). */
|
|
87
|
+
now: () => string;
|
|
88
|
+
}
|
|
89
|
+
export type EnsureAction = 'reused' | 'started' | 'start-failed';
|
|
90
|
+
export interface EnsureResult {
|
|
91
|
+
action: EnsureAction;
|
|
92
|
+
port: number;
|
|
93
|
+
owner: OwnerRecord | null;
|
|
94
|
+
clients: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Ensure a proxy is available for this client.
|
|
98
|
+
* - already healthy -> ADOPT (reuse); register client; claim no ownership.
|
|
99
|
+
* - not healthy -> take the start lock, re-probe, then start. Claim ownership
|
|
100
|
+
* ONLY if the adapter returns a stoppable owner (a process we spawned).
|
|
101
|
+
* Fail-open: a failed start returns 'start-failed' and never throws.
|
|
102
|
+
*/
|
|
103
|
+
export declare function ensureProxy(rt: string, client: ClientRecord, port: number, deps: LifecycleDeps): Promise<EnsureResult>;
|
|
104
|
+
export type ReleaseAction = 'stopped' | 'left-other-clients' | 'left-adopted' | 'not-running';
|
|
105
|
+
export interface ReleaseResult {
|
|
106
|
+
action: ReleaseAction;
|
|
107
|
+
remainingClients: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Release this client. Stop the proxy ONLY when:
|
|
111
|
+
* - we own it (a process WE spawned — owner marker present), AND
|
|
112
|
+
* - no other client remains after removing this one.
|
|
113
|
+
* Otherwise leave it running:
|
|
114
|
+
* - 'left-other-clients' — another agent session is still using it.
|
|
115
|
+
* - 'left-adopted' — we never owned it (pre-existing / systemd / external).
|
|
116
|
+
*/
|
|
117
|
+
export declare function releaseProxy(rt: string, clientId: string, deps: LifecycleDeps): Promise<ReleaseResult>;
|
|
118
|
+
/**
|
|
119
|
+
* Derive a stable client id shared across a session's SessionStart + Stop
|
|
120
|
+
* hooks. Order MATCHES the hook derivation (session-start.sh) so a manual CLI
|
|
121
|
+
* call and the hook agree: explicit flag, then harness session ids, then the
|
|
122
|
+
* parent pid (the agent) — spelled `ppid-<n>` to match the hook.
|
|
123
|
+
*/
|
|
124
|
+
export declare function resolveClientId(explicit?: string): string;
|
|
125
|
+
//# sourceMappingURL=proxy-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-lifecycle.d.ts","sourceRoot":"","sources":["../../src/cli/proxy-lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference-counted, session-scoped proxy lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Goal (per product spec): the UAP Anthropic proxy should start when an agent
|
|
5
|
+
* session is triggered (via the SessionStart hook) and exit WITH the agent —
|
|
6
|
+
* but only when it is safe to do so:
|
|
7
|
+
*
|
|
8
|
+
* - If a proxy is already running, ADOPT it (reuse) — never start a second.
|
|
9
|
+
* - A proxy we adopted (already up), OR a systemd-managed unit, is NEVER
|
|
10
|
+
* stopped by us on session end (systemd units are persistent infra).
|
|
11
|
+
* - A proxy WE spawned as a plain process is reference-counted across
|
|
12
|
+
* sessions: it is stopped on release only when the LAST client (agent
|
|
13
|
+
* session) leaves. If any other client is still using it, it keeps running.
|
|
14
|
+
*
|
|
15
|
+
* This module holds the pure decision logic + a tiny file-backed registry so it
|
|
16
|
+
* is unit-testable without spawning a real proxy or touching systemd. The real
|
|
17
|
+
* side effects (spawn / systemctl / HTTP health probe) are injected as `deps`.
|
|
18
|
+
*
|
|
19
|
+
* Liveness note: a client's `pid` MUST be the long-lived AGENT process (the one
|
|
20
|
+
* that spawns SessionStart and SessionEnd), NOT the ephemeral hook/CLI process
|
|
21
|
+
* — otherwise the dead-pid pruning below evicts every live session moments
|
|
22
|
+
* after it registers. The hook passes `$PPID` (the agent) via `--client-pid`.
|
|
23
|
+
*/
|
|
24
|
+
import { mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, existsSync, } from 'fs';
|
|
25
|
+
import { join } from 'path';
|
|
26
|
+
import os from 'os';
|
|
27
|
+
/** Default port the proxy listens on (matches run-anthropic-proxy-continuity.sh). */
|
|
28
|
+
export const DEFAULT_PROXY_PORT = Number(process.env.PROXY_PORT ?? 4000);
|
|
29
|
+
const DIR_MODE = 0o700;
|
|
30
|
+
const FILE_MODE = 0o600;
|
|
31
|
+
/**
|
|
32
|
+
* Runtime root for the client registry + owner marker. Prefer XDG_RUNTIME_DIR
|
|
33
|
+
* (tmpfs at /run/user/<uid>, mode 0700, cleared on logout) and fall back to
|
|
34
|
+
* ~/.cache. Overridable via UAP_PROXY_RUNTIME_DIR for tests.
|
|
35
|
+
*/
|
|
36
|
+
export function runtimeDir() {
|
|
37
|
+
const override = process.env.UAP_PROXY_RUNTIME_DIR;
|
|
38
|
+
if (override)
|
|
39
|
+
return override;
|
|
40
|
+
const base = process.env.XDG_RUNTIME_DIR || join(os.homedir(), '.cache');
|
|
41
|
+
return join(base, 'uap-proxy');
|
|
42
|
+
}
|
|
43
|
+
function clientsDir(rt) {
|
|
44
|
+
return join(rt, 'clients');
|
|
45
|
+
}
|
|
46
|
+
function ownerPath(rt) {
|
|
47
|
+
return join(rt, 'owner.json');
|
|
48
|
+
}
|
|
49
|
+
function lockPath(rt) {
|
|
50
|
+
return join(rt, 'start.lock');
|
|
51
|
+
}
|
|
52
|
+
/** Is a pid still alive? `kill(pid, 0)` throws ESRCH when it isn't. */
|
|
53
|
+
export function isPidAlive(pid) {
|
|
54
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
55
|
+
return false;
|
|
56
|
+
try {
|
|
57
|
+
process.kill(pid, 0);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
// EPERM means the process exists but we can't signal it — still alive.
|
|
62
|
+
return e.code === 'EPERM';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function safeFilename(clientId) {
|
|
66
|
+
// Registry files are named by client id; keep them filesystem-safe and
|
|
67
|
+
// incapable of escaping the clients dir (no path separators survive).
|
|
68
|
+
return clientId.replace(/[^A-Za-z0-9._-]/g, '_').slice(0, 200) || 'anon';
|
|
69
|
+
}
|
|
70
|
+
/** Derive the agent pid encoded in a `ppid-<n>` fallback client id, if present. */
|
|
71
|
+
export function pidFromClientId(clientId) {
|
|
72
|
+
const m = /^ppid-(\d+)$/.exec(clientId);
|
|
73
|
+
if (!m)
|
|
74
|
+
return null;
|
|
75
|
+
const n = Number(m[1]);
|
|
76
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
77
|
+
}
|
|
78
|
+
/** Atomic write (tmp + rename) with restrictive mode so a torn read is impossible. */
|
|
79
|
+
function atomicWrite(path, data) {
|
|
80
|
+
const tmp = `${path}.tmp.${process.pid}.${Math.floor(process.hrtime()[1] % 1e6)}`;
|
|
81
|
+
writeFileSync(tmp, data, { mode: FILE_MODE });
|
|
82
|
+
renameSync(tmp, path);
|
|
83
|
+
}
|
|
84
|
+
/** Register (or refresh) a client in the registry. Idempotent per clientId. */
|
|
85
|
+
export function registerClient(rt, rec) {
|
|
86
|
+
const dir = clientsDir(rt);
|
|
87
|
+
mkdirSync(dir, { recursive: true, mode: DIR_MODE });
|
|
88
|
+
atomicWrite(join(dir, safeFilename(rec.clientId)), JSON.stringify(rec));
|
|
89
|
+
}
|
|
90
|
+
/** Remove a client from the registry (no-op if absent). */
|
|
91
|
+
export function deregisterClient(rt, clientId) {
|
|
92
|
+
try {
|
|
93
|
+
rmSync(join(clientsDir(rt), safeFilename(clientId)), { force: true });
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* best-effort */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** List live clients, pruning any whose AGENT process has died (self-healing). */
|
|
100
|
+
export function listClients(rt, opts = {}) {
|
|
101
|
+
const dir = clientsDir(rt);
|
|
102
|
+
if (!existsSync(dir))
|
|
103
|
+
return [];
|
|
104
|
+
const out = [];
|
|
105
|
+
let entries = [];
|
|
106
|
+
try {
|
|
107
|
+
entries = readdirSync(dir);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
for (const name of entries) {
|
|
113
|
+
if (name.endsWith('.tmp') || name.includes('.tmp.'))
|
|
114
|
+
continue; // in-flight write
|
|
115
|
+
const full = join(dir, name);
|
|
116
|
+
let rec = null;
|
|
117
|
+
try {
|
|
118
|
+
rec = JSON.parse(readFileSync(full, 'utf8'));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
rec = null;
|
|
122
|
+
}
|
|
123
|
+
if (!rec || typeof rec.clientId !== 'string') {
|
|
124
|
+
if (opts.prune !== false)
|
|
125
|
+
rmSync(full, { force: true });
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
// A client whose AGENT process is gone ended without a clean release
|
|
129
|
+
// (crash). Drop it so it never pins the proxy alive forever. pid<=0 means
|
|
130
|
+
// "liveness unknown" — keep it (rely on clean release) rather than evict.
|
|
131
|
+
if (typeof rec.pid === 'number' && rec.pid > 0 && !isPidAlive(rec.pid)) {
|
|
132
|
+
if (opts.prune !== false)
|
|
133
|
+
rmSync(full, { force: true });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
out.push(rec);
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
export function readOwner(rt) {
|
|
141
|
+
const p = ownerPath(rt);
|
|
142
|
+
if (!existsSync(p))
|
|
143
|
+
return null;
|
|
144
|
+
try {
|
|
145
|
+
const rec = JSON.parse(readFileSync(p, 'utf8'));
|
|
146
|
+
if (rec && (rec.kind === 'process' || rec.kind === 'systemd'))
|
|
147
|
+
return rec;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
/* fall through */
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
export function writeOwner(rt, rec) {
|
|
155
|
+
mkdirSync(rt, { recursive: true, mode: DIR_MODE });
|
|
156
|
+
atomicWrite(ownerPath(rt), JSON.stringify(rec));
|
|
157
|
+
}
|
|
158
|
+
export function clearOwner(rt) {
|
|
159
|
+
try {
|
|
160
|
+
rmSync(ownerPath(rt), { force: true });
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
/* best-effort */
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Start lock — serialize the probe->start->writeOwner critical section so two
|
|
168
|
+
// simultaneous SessionStarts don't both spawn a proxy onto the same port.
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
const LOCK_STALE_MS = 30_000;
|
|
171
|
+
export async function acquireStartLock(rt, timeoutMs = 5000) {
|
|
172
|
+
mkdirSync(rt, { recursive: true, mode: DIR_MODE });
|
|
173
|
+
const p = lockPath(rt);
|
|
174
|
+
const deadline = Date.now() + timeoutMs;
|
|
175
|
+
for (;;) {
|
|
176
|
+
try {
|
|
177
|
+
mkdirSync(p); // atomic: succeeds only if it did not exist
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Held. Steal it if it is stale (a crashed holder).
|
|
182
|
+
try {
|
|
183
|
+
const st = statSync(p);
|
|
184
|
+
if (Date.now() - st.mtimeMs > LOCK_STALE_MS) {
|
|
185
|
+
rmSync(p, { recursive: true, force: true });
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
continue; // vanished between attempts — retry
|
|
191
|
+
}
|
|
192
|
+
if (Date.now() >= deadline)
|
|
193
|
+
return false; // give up; caller proceeds (fail-open)
|
|
194
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export function releaseStartLock(rt) {
|
|
199
|
+
try {
|
|
200
|
+
rmSync(lockPath(rt), { recursive: true, force: true });
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
/* best-effort */
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Ensure a proxy is available for this client.
|
|
208
|
+
* - already healthy -> ADOPT (reuse); register client; claim no ownership.
|
|
209
|
+
* - not healthy -> take the start lock, re-probe, then start. Claim ownership
|
|
210
|
+
* ONLY if the adapter returns a stoppable owner (a process we spawned).
|
|
211
|
+
* Fail-open: a failed start returns 'start-failed' and never throws.
|
|
212
|
+
*/
|
|
213
|
+
export async function ensureProxy(rt, client, port, deps) {
|
|
214
|
+
listClients(rt); // prune dead clients first
|
|
215
|
+
registerClient(rt, client);
|
|
216
|
+
if (await deps.probeHealth(port)) {
|
|
217
|
+
return { action: 'reused', port, owner: readOwner(rt), clients: listClients(rt).length };
|
|
218
|
+
}
|
|
219
|
+
const locked = await acquireStartLock(rt);
|
|
220
|
+
try {
|
|
221
|
+
// Another session may have started it while we waited for the lock.
|
|
222
|
+
if (await deps.probeHealth(port)) {
|
|
223
|
+
return { action: 'reused', port, owner: readOwner(rt), clients: listClients(rt).length };
|
|
224
|
+
}
|
|
225
|
+
const res = await deps.startProxy(port);
|
|
226
|
+
if (!res.healthy) {
|
|
227
|
+
return { action: 'start-failed', port, owner: null, clients: listClients(rt).length };
|
|
228
|
+
}
|
|
229
|
+
// Own ONLY a process we spawned + confirmed. systemd/adopted -> owner null.
|
|
230
|
+
if (res.owner)
|
|
231
|
+
writeOwner(rt, res.owner);
|
|
232
|
+
return { action: 'started', port, owner: res.owner, clients: listClients(rt).length };
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
if (locked)
|
|
236
|
+
releaseStartLock(rt);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Release this client. Stop the proxy ONLY when:
|
|
241
|
+
* - we own it (a process WE spawned — owner marker present), AND
|
|
242
|
+
* - no other client remains after removing this one.
|
|
243
|
+
* Otherwise leave it running:
|
|
244
|
+
* - 'left-other-clients' — another agent session is still using it.
|
|
245
|
+
* - 'left-adopted' — we never owned it (pre-existing / systemd / external).
|
|
246
|
+
*/
|
|
247
|
+
export async function releaseProxy(rt, clientId, deps) {
|
|
248
|
+
deregisterClient(rt, clientId);
|
|
249
|
+
const remaining = listClients(rt); // prunes dead clients too
|
|
250
|
+
const owner = readOwner(rt);
|
|
251
|
+
if (!owner) {
|
|
252
|
+
return { action: 'left-adopted', remainingClients: remaining.length };
|
|
253
|
+
}
|
|
254
|
+
if (remaining.length > 0) {
|
|
255
|
+
return { action: 'left-other-clients', remainingClients: remaining.length };
|
|
256
|
+
}
|
|
257
|
+
// We own it and we are the last client — shut it down with the agent.
|
|
258
|
+
try {
|
|
259
|
+
await deps.stopProxy(owner);
|
|
260
|
+
}
|
|
261
|
+
finally {
|
|
262
|
+
clearOwner(rt);
|
|
263
|
+
}
|
|
264
|
+
return { action: 'stopped', remainingClients: 0 };
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Derive a stable client id shared across a session's SessionStart + Stop
|
|
268
|
+
* hooks. Order MATCHES the hook derivation (session-start.sh) so a manual CLI
|
|
269
|
+
* call and the hook agree: explicit flag, then harness session ids, then the
|
|
270
|
+
* parent pid (the agent) — spelled `ppid-<n>` to match the hook.
|
|
271
|
+
*/
|
|
272
|
+
export function resolveClientId(explicit) {
|
|
273
|
+
const candidates = [
|
|
274
|
+
explicit,
|
|
275
|
+
process.env.CLAUDE_SESSION_ID,
|
|
276
|
+
process.env.FACTORY_SESSION_ID,
|
|
277
|
+
process.env.CURSOR_SESSION_ID,
|
|
278
|
+
process.env.UAP_SESSION_ID,
|
|
279
|
+
];
|
|
280
|
+
for (const c of candidates) {
|
|
281
|
+
if (c && c.trim())
|
|
282
|
+
return c.trim();
|
|
283
|
+
}
|
|
284
|
+
return `ppid-${process.ppid}`;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=proxy-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-lifecycle.js","sourceRoot":"","sources":["../../src/cli/proxy-lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `uap proxy` — reference-counted, session-scoped lifecycle for the UAP
|
|
3
|
+
* Anthropic proxy.
|
|
4
|
+
*
|
|
5
|
+
* uap proxy ensure [--client <id>] [--client-pid <n>] [--port <n>] [--quiet]
|
|
6
|
+
* Start the proxy if none is running, or ADOPT an already-running one.
|
|
7
|
+
* Registers this session as a client. Wired into the SessionStart hook.
|
|
8
|
+
* uap proxy release [--client <id>] [--quiet]
|
|
9
|
+
* Deregister this session; stop the proxy ONLY if WE spawned it (as a
|
|
10
|
+
* plain process) AND no other client remains. systemd/adopted proxies are
|
|
11
|
+
* never stopped. Wired into the Stop / SessionEnd hook.
|
|
12
|
+
* uap proxy status [--port <n>] [--json]
|
|
13
|
+
* uap proxy start | stop | restart manual controls
|
|
14
|
+
* uap proxy enable | disable toggle .uap.json proxy.autostart
|
|
15
|
+
*
|
|
16
|
+
* Everything is fail-open: hook-driven calls never throw and never block the
|
|
17
|
+
* session — a proxy that won't start just means the agent runs without it.
|
|
18
|
+
*
|
|
19
|
+
* Env overrides (test/advanced):
|
|
20
|
+
* PROXY_PORT default port (4000)
|
|
21
|
+
* UAP_PROXY_RUNTIME_DIR registry root (default $XDG_RUNTIME_DIR/uap-proxy)
|
|
22
|
+
* UAP_PROXY_RUN_SCRIPT proxy launch script (default: bundled continuity script)
|
|
23
|
+
* UAP_PROXY_NO_SYSTEMD=1 force the detached-process path (skip systemd)
|
|
24
|
+
* UAP_PROXY_HEALTH_WAIT_MS how long to wait for /health after launch (15000)
|
|
25
|
+
*/
|
|
26
|
+
export interface ProxyOptions {
|
|
27
|
+
client?: string;
|
|
28
|
+
clientPid?: string | number;
|
|
29
|
+
ifEnabled?: boolean;
|
|
30
|
+
port?: string | number;
|
|
31
|
+
quiet?: boolean;
|
|
32
|
+
json?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function proxyCommand(sub: string | undefined, options?: ProxyOptions): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/cli/proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AA0PH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CA8If"}
|