anon-pi 0.1.1 → 0.3.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/Dockerfile.pi +35 -7
- package/README.md +65 -23
- package/dist/anon-pi.d.ts +157 -44
- package/dist/anon-pi.d.ts.map +1 -1
- package/dist/anon-pi.js +311 -104
- package/dist/anon-pi.js.map +1 -1
- package/dist/cli.js +92 -18
- package/dist/cli.js.map +1 -1
- package/examples/Dockerfile.pi-webveil +100 -0
- package/package.json +3 -2
- package/src/anon-pi.ts +391 -135
- package/src/cli.ts +129 -19
package/dist/anon-pi.js
CHANGED
|
@@ -17,46 +17,66 @@
|
|
|
17
17
|
// trust.json that trusts /work). anon-pi does not synthesize pi's trust.json.
|
|
18
18
|
// - Session identity = the ABSOLUTE workdir path (hashed). Same folder resumes
|
|
19
19
|
// the same session config+state; reseed is manual (delete the session dir).
|
|
20
|
-
import {
|
|
20
|
+
import { existsSync } from 'node:fs';
|
|
21
21
|
import { homedir } from 'node:os';
|
|
22
|
-
import { isAbsolute, join, resolve } from 'node:path';
|
|
22
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
23
24
|
/** The container path the workdir is mounted at (pi's cwd). */
|
|
24
25
|
export const CONTAINER_WORKDIR = '/work';
|
|
25
26
|
/**
|
|
26
|
-
* The
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* The container path pi uses as its config+state home. anon-pi mounts a
|
|
28
|
+
* PERSISTENT host dir here (Model B), so everything pi writes, sessions,
|
|
29
|
+
* history, settings (your model choice), `pi install`ed extensions, downloaded
|
|
30
|
+
* bin/fd, survives across launches. Statefulness is the default; --ephemeral
|
|
31
|
+
* mounts a throwaway dir here instead.
|
|
31
32
|
*/
|
|
32
|
-
export const
|
|
33
|
-
/** The pi env var that overrides its config dir (see pi config.ts getAgentDir). */
|
|
34
|
-
export const PI_AGENT_DIR_ENV = 'PI_CODING_AGENT_DIR';
|
|
35
|
-
const DEFAULT_PROXY = 'socks5h://127.0.0.1:9050';
|
|
36
|
-
/** A user-facing error whose message is meant to be printed verbatim (no stack). */
|
|
37
|
-
export class AnonPiError extends Error {
|
|
38
|
-
}
|
|
33
|
+
export const CONTAINER_AGENT_DIR = '/root/.pi/agent';
|
|
39
34
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* mounted at a literal `~` directory or a cwd-relative path.
|
|
35
|
+
* Where the image STAGES its first-launch defaults (extensions + trust.json).
|
|
36
|
+
* NOT the agent dir, so it never conflicts with the persistent mount. The
|
|
37
|
+
* entrypoint promotes these into the mounted agent dir only when the home is
|
|
38
|
+
* FRESH (Model C seed-if-fresh).
|
|
45
39
|
*/
|
|
46
|
-
export
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
40
|
+
export const CONTAINER_STAGE_DIR = '/opt/anon-pi-seed/agent';
|
|
41
|
+
/**
|
|
42
|
+
* Where anon-pi mounts the canonical models.json (from `import`) read-only, so
|
|
43
|
+
* the first-launch seed can copy it into the fresh home alongside the image's
|
|
44
|
+
* staged defaults. Read-only: the container never writes back to the host seed.
|
|
45
|
+
*/
|
|
46
|
+
export const CONTAINER_MODELS_SEED = '/anon-pi-seed/models.json';
|
|
47
|
+
/** Marker file written into the agent dir after seeding; holds the seed version. */
|
|
48
|
+
export const SEED_MARKER = '.anon-pi-seed';
|
|
49
|
+
/** The single file the host-side seed carries: pi's model/provider registry. */
|
|
50
|
+
export const MODELS_FILE = 'models.json';
|
|
51
|
+
/**
|
|
52
|
+
* containerRunCmd builds the container command: on a FRESH home (no seed
|
|
53
|
+
* marker), promote the image's staged defaults + the mounted models.json into
|
|
54
|
+
* the persistent agent dir and stamp the marker; then exec pi. On a seeded home
|
|
55
|
+
* it does nothing but exec pi, so pi's persisted state (incl. anything you
|
|
56
|
+
* `pi install`ed or models pi added) is used as-is and NEVER clobbered.
|
|
57
|
+
*
|
|
58
|
+
* seedVersion is written into the marker so a future image can re-seed changed
|
|
59
|
+
* defaults on a version bump; v1 only seeds when the marker is absent.
|
|
60
|
+
*/
|
|
61
|
+
export function containerRunCmd(seedVersion) {
|
|
62
|
+
const agent = CONTAINER_AGENT_DIR;
|
|
63
|
+
const marker = `${agent}/${SEED_MARKER}`;
|
|
64
|
+
return (`mkdir -p "${agent}" && ` +
|
|
65
|
+
`if [ ! -f "${marker}" ]; then ` +
|
|
66
|
+
// image-staged defaults (extensions, trust.json), if the image provides them
|
|
67
|
+
`{ [ -d "${CONTAINER_STAGE_DIR}" ] && cp -a "${CONTAINER_STAGE_DIR}/." "${agent}/" || true; } && ` +
|
|
68
|
+
// the host-imported models.json, if mounted
|
|
69
|
+
`{ [ -f "${CONTAINER_MODELS_SEED}" ] && cp "${CONTAINER_MODELS_SEED}" "${agent}/${MODELS_FILE}" || true; } && ` +
|
|
70
|
+
`printf '%s\\n' "${seedVersion}" > "${marker}"; ` +
|
|
71
|
+
`fi && ` +
|
|
72
|
+
`exec pi`);
|
|
73
|
+
}
|
|
74
|
+
/** The seed version anon-pi stamps when it seeds a fresh home (bump to re-seed). */
|
|
75
|
+
export const SEED_VERSION = '1';
|
|
76
|
+
/** A user-facing error whose message is meant to be printed verbatim (no stack). */
|
|
77
|
+
export class AnonPiError extends Error {
|
|
58
78
|
}
|
|
59
|
-
/** Resolve the anon-pi home dir (holds the
|
|
79
|
+
/** Resolve the anon-pi home dir (holds the seed). */
|
|
60
80
|
export function resolveAnonPiHome(env) {
|
|
61
81
|
if (env.anonPiHome)
|
|
62
82
|
return resolve(env.anonPiHome);
|
|
@@ -65,99 +85,258 @@ export function resolveAnonPiHome(env) {
|
|
|
65
85
|
: join(env.home, '.config');
|
|
66
86
|
return join(base, 'anon-pi');
|
|
67
87
|
}
|
|
68
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* The CANONICAL host seed dir holding models.json (written by `anon-pi import`).
|
|
90
|
+
* Mounted read-only so the first-launch seed can copy models.json into a fresh
|
|
91
|
+
* persistent home. Workdir-independent (import does not need a workdir).
|
|
92
|
+
*/
|
|
69
93
|
export function resolveConfigSeed(env) {
|
|
70
94
|
if (env.configSeed)
|
|
71
95
|
return resolve(env.configSeed);
|
|
72
96
|
return join(resolveAnonPiHome(env), 'agent');
|
|
73
97
|
}
|
|
74
98
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
99
|
+
* Encode an absolute path into a directory name using pi's OWN convention (see
|
|
100
|
+
* pi coding-agent session-manager: `--${cwd without leading slash, / \ : -> -}--`),
|
|
101
|
+
* so an anon-pi state dir is readable and matches pi's mental model (no opaque
|
|
102
|
+
* hash). e.g. /home/u/dev/x -> --home-u-dev-x--
|
|
78
103
|
*/
|
|
79
|
-
export function
|
|
80
|
-
return
|
|
104
|
+
export function pathSlug(absPath) {
|
|
105
|
+
return `--${absPath.replace(/^[/\\]/, '').replace(/[/\\:]/g, '-')}--`;
|
|
81
106
|
}
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
|
|
107
|
+
/**
|
|
108
|
+
* The persistent per-workdir state dir on the host (mounted at the container's
|
|
109
|
+
* ~/.pi/agent). Keyed by the workdir via pi's path-slug convention:
|
|
110
|
+
* <anonPiHome>/state/<slug>/agent
|
|
111
|
+
*/
|
|
112
|
+
export function stateAgentDir(env, absWorkdir) {
|
|
113
|
+
return join(resolveAnonPiHome(env), 'state', pathSlug(absWorkdir), 'agent');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Normalise a proxy-less host:port key from an ANON_PI_LLM value or a provider
|
|
117
|
+
* baseUrl, so `192.168.1.150:8080` matches `http://192.168.1.150:8080/v1`.
|
|
118
|
+
* Returns `host` (no port) or `host:port`, lowercased, scheme/path stripped.
|
|
119
|
+
*/
|
|
120
|
+
export function hostPortKey(value) {
|
|
121
|
+
let v = value.trim();
|
|
122
|
+
const scheme = v.indexOf('://');
|
|
123
|
+
if (scheme >= 0)
|
|
124
|
+
v = v.slice(scheme + 3);
|
|
125
|
+
v = v.split('/')[0]; // drop path (/v1, ...)
|
|
126
|
+
v = v.replace(/^[^@]*@/, ''); // drop any user:pass@
|
|
127
|
+
return v.toLowerCase();
|
|
128
|
+
}
|
|
129
|
+
/** apiKey values that are NOT real secrets (safe to carry into the seed). */
|
|
130
|
+
const BENIGN_API_KEYS = new Set(['', 'none', 'ollama', 'no-key', 'local']);
|
|
131
|
+
/**
|
|
132
|
+
* PURE: given a parsed host models.json and the ANON_PI_LLM value, select the
|
|
133
|
+
* provider whose baseUrl points at that host:port and return a barebones
|
|
134
|
+
* models.json carrying ONLY that provider (verbatim, with its models). Throws
|
|
135
|
+
* AnonPiError if nothing matches. Carries no other provider (so etherplay /
|
|
136
|
+
* google / paid API keys never enter the seed).
|
|
137
|
+
*/
|
|
138
|
+
export function pickProviderForLlm(hostModels, llmDirect) {
|
|
139
|
+
const providers = hostModels.providers ?? {};
|
|
140
|
+
const want = hostPortKey(llmDirect);
|
|
141
|
+
const matches = [];
|
|
142
|
+
for (const [name, p] of Object.entries(providers)) {
|
|
143
|
+
if (!p || typeof p !== 'object' || !p.baseUrl)
|
|
144
|
+
continue;
|
|
145
|
+
if (hostPortKey(p.baseUrl) === want)
|
|
146
|
+
matches.push(name);
|
|
147
|
+
}
|
|
148
|
+
if (matches.length === 0) {
|
|
149
|
+
const known = Object.entries(providers)
|
|
150
|
+
.filter(([, p]) => p && p.baseUrl)
|
|
151
|
+
.map(([n, p]) => ` ${n}: ${p.baseUrl}`)
|
|
152
|
+
.join('\n');
|
|
153
|
+
throw new AnonPiError(`anon-pi import: no provider in your host models.json points at ANON_PI_LLM (${want}).\n` +
|
|
154
|
+
(known
|
|
155
|
+
? `Providers found:\n${known}\n`
|
|
156
|
+
: 'No providers with a baseUrl were found.\n') +
|
|
157
|
+
'Set ANON_PI_LLM to the host:port of a provider above, or add that provider to pi first.');
|
|
158
|
+
}
|
|
159
|
+
const name = matches[0];
|
|
160
|
+
const provider = providers[name];
|
|
161
|
+
const key = (provider.apiKey ?? '').trim().toLowerCase();
|
|
162
|
+
const apiKeyLooksReal = !BENIGN_API_KEYS.has(key);
|
|
163
|
+
return {
|
|
164
|
+
name,
|
|
165
|
+
models: { providers: { [name]: provider } },
|
|
166
|
+
apiKeyLooksReal,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The default host models.json path `import` reads FROM. Overridable via
|
|
171
|
+
* ANON_PI_SOURCE_MODELS; defaults to the real pi config (~/.pi/agent/models.json
|
|
172
|
+
* under the container-less host HOME, or PI_CODING_AGENT_DIR if the user set it).
|
|
173
|
+
*/
|
|
174
|
+
export function resolveSourceModelsPath(env) {
|
|
175
|
+
if (env.sourceModels && env.sourceModels.trim() !== '') {
|
|
176
|
+
return resolve(env.sourceModels);
|
|
177
|
+
}
|
|
178
|
+
const agentDir = env.piAgentDir && env.piAgentDir.trim() !== ''
|
|
179
|
+
? env.piAgentDir
|
|
180
|
+
: join(env.home, '.pi', 'agent');
|
|
181
|
+
return join(agentDir, MODELS_FILE);
|
|
85
182
|
}
|
|
86
183
|
/**
|
|
87
184
|
* Build the run plan from the environment + the (optional) workdir arg. PURE: it
|
|
88
|
-
* resolves paths and composes the netcage argv,
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
185
|
+
* resolves paths and composes the netcage argv, performing NO filesystem writes
|
|
186
|
+
* or spawns. It THROWS AnonPiError for the required inputs (image, llm, proxy).
|
|
187
|
+
*
|
|
188
|
+
* Statefulness (Model B): a persistent per-workdir host dir is mounted at the
|
|
189
|
+
* container's ~/.pi/agent, so pi's sessions/history/settings/extensions persist.
|
|
190
|
+
* First-launch seed (Model C): when that home is FRESH, the container run
|
|
191
|
+
* command promotes the image's staged defaults + the imported models.json into
|
|
192
|
+
* it and stamps a marker; thereafter pi OWNS the home and nothing is clobbered.
|
|
193
|
+
*
|
|
194
|
+
* `modelsSeedExists` reports whether the canonical import models.json exists (so
|
|
195
|
+
* it is mounted for the seed); `stateExists` reports whether this workdir's
|
|
196
|
+
* state home already exists (so `fresh` is known).
|
|
197
|
+
*
|
|
198
|
+
* --ephemeral mounts NO writable state: pi writes to the container's own
|
|
199
|
+
* filesystem, which netcage runs with `--rm`, so it is destroyed when the
|
|
200
|
+
* container exits. Nothing writable ever touches a host path; there is no
|
|
201
|
+
* cleanup and no leftover-on-crash. (The read-only models.json seed is still
|
|
202
|
+
* mounted; it is a single file anon-pi never writes to.)
|
|
93
203
|
*/
|
|
94
|
-
export function buildRunPlan(env, workdirArg,
|
|
204
|
+
export function buildRunPlan(env, workdirArg, modelsSeedExists, stateExists) {
|
|
95
205
|
if (!env.image || env.image.trim() === '') {
|
|
206
|
+
// dockerfilePath is injected (cli.ts resolves the shipped Dockerfile.pi via
|
|
207
|
+
// import.meta.url; tests pass a fixed path). Every command is emitted
|
|
208
|
+
// flush-left so it copy-pastes cleanly: an indented heredoc would bake
|
|
209
|
+
// leading spaces into the Dockerfile and break the EOF terminator, so we
|
|
210
|
+
// point at the shipped file instead of printing a heredoc.
|
|
211
|
+
const df = env.dockerfilePath ?? 'Dockerfile.pi';
|
|
212
|
+
const wv = env.webveilDockerfilePath ?? 'examples/Dockerfile.pi-webveil';
|
|
96
213
|
throw new AnonPiError('anon-pi: set ANON_PI_IMAGE to a container image that has `pi` on its PATH.\n' +
|
|
97
214
|
'\n' +
|
|
98
|
-
'No
|
|
99
|
-
'
|
|
215
|
+
'No image yet? A ready Dockerfile.pi ships with anon-pi (it installs the\n' +
|
|
216
|
+
'official @earendil-works/pi-coding-agent). Build it and point at it:\n' +
|
|
217
|
+
'\n' +
|
|
218
|
+
`podman build -t localhost/anon-pi-pi:latest -f "${df}" "$(dirname "${df}")"\n` +
|
|
219
|
+
'export ANON_PI_IMAGE=localhost/anon-pi-pi:latest\n' +
|
|
100
220
|
'\n' +
|
|
101
|
-
|
|
102
|
-
'
|
|
103
|
-
' RUN apt-get update && apt-get install -y --no-install-recommends \\\n' +
|
|
104
|
-
' bash ca-certificates git ripgrep && rm -rf /var/lib/apt/lists/*\n' +
|
|
105
|
-
' RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent\n' +
|
|
106
|
-
' WORKDIR /work\n' +
|
|
107
|
-
' EOF\n' +
|
|
108
|
-
' podman build -t localhost/anon-pi-pi:latest -f Dockerfile.pi .\n' +
|
|
109
|
-
' export ANON_PI_IMAGE=localhost/anon-pi-pi:latest\n' +
|
|
221
|
+
'Or the fuller example with the pi-webveil extension + a local SearXNG\n' +
|
|
222
|
+
'(anonymized web search):\n' +
|
|
110
223
|
'\n' +
|
|
111
|
-
|
|
112
|
-
'
|
|
224
|
+
`podman build -t localhost/anon-pi-webveil:latest -f "${wv}" "$(dirname "${wv}")"\n` +
|
|
225
|
+
'export ANON_PI_IMAGE=localhost/anon-pi-webveil:latest\n' +
|
|
226
|
+
'\n' +
|
|
227
|
+
'See the README (Providing a pi image) for details and a community-image note.');
|
|
113
228
|
}
|
|
114
229
|
if (!env.llmDirect || env.llmDirect.trim() === '') {
|
|
115
230
|
throw new AnonPiError('anon-pi: set ANON_PI_LLM to the RFC1918/link-local IP[:port] of the local model pi should reach directly (e.g. ANON_PI_LLM=192.168.1.150:8080). All other egress stays forced through the proxy.');
|
|
116
231
|
}
|
|
232
|
+
if (!env.proxy || env.proxy.trim() === '') {
|
|
233
|
+
// No default: this is an anonymity tool, so the proxy is REQUIRED and never
|
|
234
|
+
// guessed (mirrors netcage, which fails closed without --proxy). A silent
|
|
235
|
+
// default would anonymize through the wrong endpoint, or fail deep in the
|
|
236
|
+
// jail with a confusing DNS error, if the guessed proxy is not actually up.
|
|
237
|
+
throw new AnonPiError('anon-pi: set ANON_PI_PROXY to your socks5h proxy. anon-pi has no default:\n' +
|
|
238
|
+
'the proxy is what makes the session anonymous, so it is never guessed.\n' +
|
|
239
|
+
'\n' +
|
|
240
|
+
'Pick the one you run (copy-paste), then re-run anon-pi:\n' +
|
|
241
|
+
'\n' +
|
|
242
|
+
'# Tor (system tor / Tor Browser bundle default port)\n' +
|
|
243
|
+
'export ANON_PI_PROXY=socks5h://127.0.0.1:9050\n' +
|
|
244
|
+
'\n' +
|
|
245
|
+
'# wireproxy -> a WireGuard VPN (Mullvad, Proton, ...); use YOUR configured\n' +
|
|
246
|
+
'# [Socks5] BindAddress port (1080 in wireproxy examples):\n' +
|
|
247
|
+
'export ANON_PI_PROXY=socks5h://127.0.0.1:1080\n' +
|
|
248
|
+
'\n' +
|
|
249
|
+
'# an SSH dynamic-forward (ssh -D 1080 host) or any other socks5h endpoint\n' +
|
|
250
|
+
'export ANON_PI_PROXY=socks5h://127.0.0.1:1080\n' +
|
|
251
|
+
'\n' +
|
|
252
|
+
'Only socks5h:// is accepted (plain socks5:// resolves DNS locally and leaks).');
|
|
253
|
+
}
|
|
117
254
|
const home = env.home;
|
|
118
255
|
if (!home || home.trim() === '') {
|
|
119
256
|
throw new AnonPiError('anon-pi: could not resolve HOME.');
|
|
120
257
|
}
|
|
121
258
|
const raw = workdirArg && workdirArg.trim() !== '' ? workdirArg : process.cwd();
|
|
122
259
|
const workdir = isAbsolute(raw) ? raw : resolve(raw);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
260
|
+
// Persistent per-workdir state home, unless --ephemeral (no writable mount).
|
|
261
|
+
const ephemeral = env.ephemeral === true;
|
|
262
|
+
const stateDir = ephemeral ? '' : stateAgentDir(env, workdir);
|
|
263
|
+
// Ephemeral home is always fresh (the container's throwaway layer); a
|
|
264
|
+
// persistent home is fresh iff its dir is absent.
|
|
265
|
+
const fresh = ephemeral ? true : !stateExists(stateDir);
|
|
266
|
+
// The canonical imported models.json is mounted (read-only) for the seed only
|
|
267
|
+
// when it exists; pi can also start with no models and you add them in-session.
|
|
268
|
+
const modelsSeed = join(resolveConfigSeed(env), MODELS_FILE);
|
|
269
|
+
const haveModelsSeed = modelsSeedExists(modelsSeed);
|
|
270
|
+
const proxy = env.proxy.trim();
|
|
271
|
+
// netcage's --allow-direct wants a bare IP[:port]/CIDR (no scheme/path), but a
|
|
272
|
+
// user naturally sets ANON_PI_LLM to a URL (http://192.168.1.150:8080). Strip
|
|
273
|
+
// it to host:port with the same helper `import` uses to match providers, so a
|
|
274
|
+
// URL, an ip:port, or a bare ip all work.
|
|
275
|
+
const directTarget = hostPortKey(env.llmDirect);
|
|
276
|
+
const seedVersion = env.seedVersion ?? SEED_VERSION;
|
|
136
277
|
const netcageArgs = [
|
|
137
278
|
'run',
|
|
138
279
|
'--proxy',
|
|
139
280
|
proxy,
|
|
140
281
|
'--allow-direct',
|
|
141
|
-
|
|
282
|
+
directTarget,
|
|
142
283
|
'-it',
|
|
143
284
|
'-v',
|
|
144
285
|
workdir, // netcage defaults a target-less -v to /work and cwd to /work
|
|
145
|
-
'-v',
|
|
146
|
-
`${sessionDir}:${agentMount}`,
|
|
147
|
-
'-e',
|
|
148
|
-
`${PI_AGENT_DIR_ENV}=${agentMount}`,
|
|
149
|
-
env.image,
|
|
150
|
-
'pi',
|
|
151
286
|
];
|
|
287
|
+
// Persistent mode ONLY: mount the per-workdir state home at ~/.pi/agent
|
|
288
|
+
// (Model B). --ephemeral mounts nothing writable: pi writes to the container's
|
|
289
|
+
// own --rm layer, gone on exit, no host state.
|
|
290
|
+
if (!ephemeral) {
|
|
291
|
+
netcageArgs.push('-v', `${stateDir}:${CONTAINER_AGENT_DIR}`);
|
|
292
|
+
}
|
|
293
|
+
// Mount the imported models.json read-only for the first-launch seed, if any.
|
|
294
|
+
if (haveModelsSeed) {
|
|
295
|
+
netcageArgs.push('-v', `${modelsSeed}:${CONTAINER_MODELS_SEED}:ro`);
|
|
296
|
+
}
|
|
297
|
+
netcageArgs.push(env.image, 'sh', '-c', containerRunCmd(seedVersion));
|
|
152
298
|
return {
|
|
153
299
|
workdir,
|
|
154
|
-
|
|
155
|
-
configSeed,
|
|
156
|
-
|
|
157
|
-
needsSeed,
|
|
300
|
+
stateDir,
|
|
301
|
+
configSeed: haveModelsSeed ? modelsSeed : '',
|
|
302
|
+
fresh,
|
|
158
303
|
netcageArgs,
|
|
159
304
|
};
|
|
160
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Absolute path to the Dockerfile.pi that ships with anon-pi, resolved from this
|
|
308
|
+
* module's location (package root, one level up from dist/anon-pi.js), or
|
|
309
|
+
* undefined if it cannot be found. Used only to make the missing-image error's
|
|
310
|
+
* build command concrete.
|
|
311
|
+
*/
|
|
312
|
+
export function shippedDockerfilePath() {
|
|
313
|
+
return shippedFile('Dockerfile.pi');
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Absolute path to the fuller pi-webveil + SearXNG example that ships with
|
|
317
|
+
* anon-pi (examples/Dockerfile.pi-webveil), or undefined if not found.
|
|
318
|
+
*/
|
|
319
|
+
export function shippedWebveilDockerfilePath() {
|
|
320
|
+
return shippedFile(join('examples', 'Dockerfile.pi-webveil'));
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Resolve a file shipped in the package root, from this module's location
|
|
324
|
+
* (package root is one level up from dist/anon-pi.js). Returns undefined if it
|
|
325
|
+
* cannot be found or import.meta.url is unavailable.
|
|
326
|
+
*/
|
|
327
|
+
function shippedFile(rel) {
|
|
328
|
+
try {
|
|
329
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
330
|
+
for (const p of [join(here, '..', rel), join(here, rel)]) {
|
|
331
|
+
if (existsSync(p))
|
|
332
|
+
return p;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// import.meta.url unavailable (e.g. some test bundlers): fall through.
|
|
337
|
+
}
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
161
340
|
/** Read the AnonPiEnv from a process env map (kept separate so tests inject one). */
|
|
162
341
|
export function envFromProcess(penv) {
|
|
163
342
|
return {
|
|
@@ -168,40 +347,68 @@ export function envFromProcess(penv) {
|
|
|
168
347
|
image: penv.ANON_PI_IMAGE,
|
|
169
348
|
llmDirect: penv.ANON_PI_LLM,
|
|
170
349
|
xdgConfigHome: penv.XDG_CONFIG_HOME,
|
|
171
|
-
|
|
350
|
+
dockerfilePath: shippedDockerfilePath(),
|
|
351
|
+
webveilDockerfilePath: shippedWebveilDockerfilePath(),
|
|
352
|
+
sourceModels: penv.ANON_PI_SOURCE_MODELS,
|
|
353
|
+
piAgentDir: penv.PI_CODING_AGENT_DIR,
|
|
354
|
+
ephemeral: isTruthy(penv.ANON_PI_EPHEMERAL),
|
|
172
355
|
};
|
|
173
356
|
}
|
|
357
|
+
/** Whether an env-var string is set to a truthy value (1/true/yes, any case). */
|
|
358
|
+
function isTruthy(v) {
|
|
359
|
+
if (!v)
|
|
360
|
+
return false;
|
|
361
|
+
const s = v.trim().toLowerCase();
|
|
362
|
+
return s === '1' || s === 'true' || s === 'yes' || s === 'on';
|
|
363
|
+
}
|
|
174
364
|
/** The --help text (kept here so it is covered by the same module). */
|
|
175
365
|
export const HELP = `anon-pi - launch pi inside a netcage (anonymized egress + one direct local model)
|
|
176
366
|
|
|
177
367
|
USAGE
|
|
178
|
-
anon-pi [WORKDIR]
|
|
368
|
+
anon-pi [WORKDIR] launch pi jailed, working in WORKDIR (default: cwd)
|
|
369
|
+
anon-pi import seed models.json from your local model
|
|
179
370
|
|
|
180
|
-
WORKDIR the host folder pi works in (mounted at
|
|
181
|
-
|
|
371
|
+
WORKDIR the host folder pi works in (mounted at ${CONTAINER_WORKDIR}; pi's cwd). Files pi
|
|
372
|
+
writes there land on the host.
|
|
182
373
|
|
|
183
374
|
WHAT IT DOES
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
375
|
+
Runs pi inside netcage with all web/DNS egress forced through the socks5h
|
|
376
|
+
proxy (fail-closed) and ONE direct hole to your local model (ANON_PI_LLM).
|
|
377
|
+
|
|
378
|
+
STATEFUL by default: a persistent per-workdir home
|
|
379
|
+
(<ANON_PI_HOME>/state/<workdir>/agent) is mounted at the container's
|
|
380
|
+
~/.pi/agent, so your conversations, history, settings (model choice), and any
|
|
381
|
+
extensions you \`pi install\` persist across launches. Re-running in the same
|
|
382
|
+
folder resumes it. On a FRESH home, the image's staged defaults (extensions,
|
|
383
|
+
trust) and your imported models.json are seeded in once; after that pi owns the
|
|
384
|
+
home and nothing is overwritten. Requires \`netcage\`.
|
|
385
|
+
|
|
386
|
+
--ephemeral (or ANON_PI_EPHEMERAL=1): mount NO writable state; pi writes to the
|
|
387
|
+
container's own --rm layer, gone on exit. Nothing writable touches the host,
|
|
388
|
+
no cleanup, no leftover-on-crash.
|
|
389
|
+
|
|
390
|
+
import
|
|
391
|
+
Reads your host ~/.pi/agent/models.json, picks the provider whose baseUrl
|
|
392
|
+
serves ANON_PI_LLM, and writes JUST that provider to the canonical seed
|
|
393
|
+
(<ANON_PI_CONFIG>/models.json). No other provider's API keys, no sessions, no
|
|
394
|
+
identity. It SEEDS a fresh home; models you later add inside pi persist and are
|
|
395
|
+
never clobbered. Re-run with --force to overwrite the canonical seed.
|
|
189
396
|
|
|
190
397
|
ENVIRONMENT
|
|
191
|
-
ANON_PI_IMAGE (required) image with \`pi\` on PATH. No image yet?
|
|
192
|
-
anon-pi without it prints a ready-to-build
|
|
193
|
-
recipe; see the README (Providing a pi image).
|
|
398
|
+
ANON_PI_IMAGE (required for run) image with \`pi\` on PATH. No image yet?
|
|
399
|
+
Running anon-pi without it prints a ready-to-build
|
|
400
|
+
Dockerfile.pi recipe; see the README (Providing a pi image).
|
|
194
401
|
ANON_PI_LLM (required) RFC1918/link-local IP[:port] of the local model
|
|
195
|
-
ANON_PI_PROXY socks5h URL (
|
|
402
|
+
ANON_PI_PROXY (required) socks5h URL of your proxy (Tor/wireproxy/ssh -D).
|
|
403
|
+
No default: the proxy is what anonymizes, so it is never guessed.
|
|
404
|
+
ANON_PI_EPHEMERAL set to 1 for a throwaway (non-persistent) session
|
|
196
405
|
ANON_PI_HOME anon-pi home (default $XDG_CONFIG_HOME/anon-pi or ~/.config/anon-pi)
|
|
197
|
-
ANON_PI_CONFIG canonical seed dir (default <ANON_PI_HOME>/agent)
|
|
198
|
-
|
|
199
|
-
${DEFAULT_CONTAINER_AGENT_DIR}; set to your image's ~/.pi/agent, e.g. /root/.pi/agent)
|
|
406
|
+
ANON_PI_CONFIG canonical seed dir holding models.json (default <ANON_PI_HOME>/agent)
|
|
407
|
+
ANON_PI_SOURCE_MODELS (import) host models.json to read (default ~/.pi/agent/models.json)
|
|
200
408
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
rm -rf
|
|
204
|
-
and the next run re-seeds it from the canonical config.
|
|
409
|
+
RESET A SESSION
|
|
410
|
+
Delete its state home to start fresh (re-seeds next launch):
|
|
411
|
+
rm -rf <ANON_PI_HOME>/state/<workdir-slug>/agent
|
|
205
412
|
|
|
206
413
|
PLATFORM
|
|
207
414
|
Linux only (via netcage's netns/nft jail). On macOS/Windows it works only
|
package/dist/anon-pi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anon-pi.js","sourceRoot":"","sources":["../src/anon-pi.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,sCAAsC;AACtC,8EAA8E;AAC9E,iFAAiF;AACjF,yEAAyE;AACzE,+EAA+E;AAC/E,kCAAkC;AAClC,gFAAgF;AAChF,sEAAsE;AACtE,6EAA6E;AAC7E,kFAAkF;AAClF,2EAA2E;AAC3E,kFAAkF;AAClF,yEAAyE;AACzE,kFAAkF;AAClF,iFAAiF;AACjF,gFAAgF;AAEhF,OAAO,EAAC,UAAU,EAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"anon-pi.js","sourceRoot":"","sources":["../src/anon-pi.ts"],"names":[],"mappings":"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"}
|