@themoltnet/pi-extension 0.2.0 → 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.
Files changed (43) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +233 -9
  3. package/dist/index.js +9846 -345
  4. package/package.json +12 -6
  5. package/dist/commands/index.d.ts +0 -5
  6. package/dist/commands/index.d.ts.map +0 -1
  7. package/dist/commands/index.js +0 -4
  8. package/dist/commands/index.js.map +0 -1
  9. package/dist/commands/moltnet-reflect.d.ts +0 -3
  10. package/dist/commands/moltnet-reflect.d.ts.map +0 -1
  11. package/dist/commands/moltnet-reflect.js +0 -32
  12. package/dist/commands/moltnet-reflect.js.map +0 -1
  13. package/dist/commands/resolve-issue.d.ts +0 -3
  14. package/dist/commands/resolve-issue.d.ts.map +0 -1
  15. package/dist/commands/resolve-issue.js +0 -82
  16. package/dist/commands/resolve-issue.js.map +0 -1
  17. package/dist/commands/sandbox.d.ts +0 -3
  18. package/dist/commands/sandbox.d.ts.map +0 -1
  19. package/dist/commands/sandbox.js +0 -20
  20. package/dist/commands/sandbox.js.map +0 -1
  21. package/dist/commands/types.d.ts +0 -33
  22. package/dist/commands/types.d.ts.map +0 -1
  23. package/dist/commands/types.js +0 -2
  24. package/dist/commands/types.js.map +0 -1
  25. package/dist/index.d.ts.map +0 -1
  26. package/dist/index.js.map +0 -1
  27. package/dist/moltnet-tools.d.ts +0 -16
  28. package/dist/moltnet-tools.d.ts.map +0 -1
  29. package/dist/moltnet-tools.js +0 -169
  30. package/dist/moltnet-tools.js.map +0 -1
  31. package/dist/snapshot.d.ts +0 -41
  32. package/dist/snapshot.d.ts.map +0 -1
  33. package/dist/snapshot.js +0 -254
  34. package/dist/snapshot.js.map +0 -1
  35. package/dist/tool-operations.d.ts +0 -13
  36. package/dist/tool-operations.d.ts.map +0 -1
  37. package/dist/tool-operations.js +0 -142
  38. package/dist/tool-operations.js.map +0 -1
  39. package/dist/tsconfig.tsbuildinfo +0 -1
  40. package/dist/vm-manager.d.ts +0 -54
  41. package/dist/vm-manager.d.ts.map +0 -1
  42. package/dist/vm-manager.js +0 -250
  43. package/dist/vm-manager.js.map +0 -1
package/dist/snapshot.js DELETED
@@ -1,254 +0,0 @@
1
- /**
2
- * Snapshot builder with auto-build and caching.
3
- *
4
- * Builds a Gondolin VM snapshot in two layers:
5
- * 1. Base (always): Alpine essentials, git, gh CLI, MoltNet CLI, agent user
6
- * 2. User setup commands (optional): arbitrary shell commands on top of the base
7
- *
8
- * Consumers provide raw shell commands — no abstraction over package managers
9
- * or runtimes. The base provides curl, git, tar, jq; everything else is up to
10
- * the setup commands.
11
- *
12
- * Caches in a platform-appropriate directory:
13
- * - macOS: ~/Library/Caches/moltnet/gondolin/
14
- * - Linux: ~/.cache/moltnet/gondolin/
15
- *
16
- * The cache key is a hash of the full config. When any input changes,
17
- * a new snapshot is built automatically.
18
- */
19
- import { execFileSync } from 'node:child_process';
20
- import { createHash } from 'node:crypto';
21
- import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from 'node:fs';
22
- import path from 'node:path';
23
- import { createHttpHooks, ensureImageSelector, loadGuestAssets, VM, } from '@earendil-works/gondolin';
24
- // ---------------------------------------------------------------------------
25
- // Base constants (always installed)
26
- // ---------------------------------------------------------------------------
27
- /** Alpine packages required by every snapshot. */
28
- const BASE_ALPINE_PACKAGES = [
29
- 'ca-certificates',
30
- 'curl',
31
- 'file',
32
- 'git',
33
- 'jq',
34
- 'ripgrep',
35
- 'tar',
36
- 'xz',
37
- ];
38
- /** gh CLI version installed in every snapshot. */
39
- const GH_VERSION = '2.74.0';
40
- /** MoltNet CLI version — downloaded as a binary, no Node needed. */
41
- const MOLTNET_CLI_VERSION = '1.28.0';
42
- /** Resolve guest architecture from host (Gondolin VMs match host arch). */
43
- function getGuestArch() {
44
- const hostArch = process.arch; // 'arm64' | 'x64' | ...
45
- if (hostArch === 'arm64')
46
- return { gh: 'linux_arm64', npm: 'linux-arm64' };
47
- return { gh: 'linux_amd64', npm: 'linux-amd64' };
48
- }
49
- /** Hosts reachable during snapshot build. */
50
- const SETUP_ALLOWED_HOSTS = [
51
- 'dl-cdn.alpinelinux.org',
52
- '*.alpinelinux.org',
53
- 'registry.npmjs.org',
54
- '*.npmjs.org',
55
- 'nodejs.org',
56
- '*.nodejs.org',
57
- 'unofficial-builds.nodejs.org',
58
- 'github.com',
59
- '*.github.com',
60
- '*.githubusercontent.com',
61
- 'objects.githubusercontent.com',
62
- ];
63
- // ---------------------------------------------------------------------------
64
- // Default config (base only — no extra setup)
65
- // ---------------------------------------------------------------------------
66
- const DEFAULT_CONFIG = {};
67
- // ---------------------------------------------------------------------------
68
- // Cache management
69
- // ---------------------------------------------------------------------------
70
- function getCacheDir() {
71
- if (process.platform === 'darwin') {
72
- return path.join(process.env.HOME ?? '/tmp', 'Library', 'Caches', 'moltnet', 'gondolin');
73
- }
74
- const xdgCache = process.env.XDG_CACHE_HOME;
75
- const base = xdgCache ?? path.join(process.env.HOME ?? '/tmp', '.cache');
76
- return path.join(base, 'moltnet', 'gondolin');
77
- }
78
- function computeConfigHash(config) {
79
- const h = createHash('sha256');
80
- // Include base constants so hash changes if we bump gh/cli versions
81
- h.update(JSON.stringify({
82
- baseAlpine: BASE_ALPINE_PACKAGES,
83
- ghVersion: GH_VERSION,
84
- cliVersion: MOLTNET_CLI_VERSION,
85
- config,
86
- }));
87
- return h.digest('hex').slice(0, 12);
88
- }
89
- function getSnapshotPath(config) {
90
- const hash = computeConfigHash(config);
91
- const dir = path.join(getCacheDir(), `v2-${hash}`);
92
- return path.join(dir, 'snapshot.qcow2');
93
- }
94
- /**
95
- * Ensure a cached snapshot exists, building one if needed.
96
- * Returns the absolute path to the qcow2 checkpoint file.
97
- */
98
- export async function ensureSnapshot(options = {}) {
99
- const config = options.config ?? DEFAULT_CONFIG;
100
- const log = options.onProgress ?? (() => { });
101
- const maxCached = options.maxCached ?? 1;
102
- const snapshotPath = getSnapshotPath(config);
103
- const snapshotDir = path.dirname(snapshotPath);
104
- if (existsSync(snapshotPath)) {
105
- log(`snapshot cache hit: ${snapshotPath}`);
106
- return snapshotPath;
107
- }
108
- log('snapshot cache miss — building (this takes 1-3 minutes)...');
109
- mkdirSync(snapshotDir, { recursive: true });
110
- const overlayPath = path.join(snapshotDir, 'build.overlay.qcow2');
111
- // Clean up any stale build artifacts
112
- if (existsSync(overlayPath))
113
- rmSync(overlayPath);
114
- if (existsSync(snapshotPath))
115
- rmSync(snapshotPath);
116
- // Resolve alpine-base image
117
- log('resolving alpine-base image...');
118
- const resolvedImage = await ensureImageSelector('alpine-base');
119
- const assets = loadGuestAssets(resolvedImage.assetDir);
120
- // Create qcow2 overlay backed by rootfs
121
- const overlaySize = config.overlaySize ?? '3G';
122
- log(`creating qcow2 overlay (${overlaySize})...`);
123
- execFileSync('qemu-img', [
124
- 'create',
125
- '-f',
126
- 'qcow2',
127
- '-F',
128
- 'raw',
129
- '-b',
130
- assets.rootfsPath,
131
- overlayPath,
132
- overlaySize,
133
- ], { stdio: 'pipe' });
134
- const allAllowedHosts = [
135
- ...SETUP_ALLOWED_HOSTS,
136
- ...(config.allowedHosts ?? []),
137
- ];
138
- const { httpHooks } = createHttpHooks({ allowedHosts: allAllowedHosts });
139
- log('booting VM for setup...');
140
- const vm = await VM.create({
141
- httpHooks,
142
- env: {
143
- PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/go/bin',
144
- HOME: '/root',
145
- GOROOT: '/usr/lib/go',
146
- GOPATH: '/root/go',
147
- },
148
- sandbox: {
149
- rootDiskPath: overlayPath,
150
- rootDiskFormat: 'qcow2',
151
- rootDiskReadOnly: false,
152
- rootDiskDeleteOnClose: false,
153
- },
154
- });
155
- try {
156
- await buildSnapshot(vm, config, log);
157
- log('creating checkpoint...');
158
- await vm.checkpoint(snapshotPath);
159
- log(`snapshot saved: ${snapshotPath}`);
160
- }
161
- finally {
162
- try {
163
- await vm.close();
164
- }
165
- catch {
166
- // may already be closed by checkpoint
167
- }
168
- if (existsSync(overlayPath))
169
- rmSync(overlayPath, { force: true });
170
- }
171
- // Prune old snapshots
172
- pruneOldSnapshots(maxCached, snapshotDir);
173
- return snapshotPath;
174
- }
175
- // ---------------------------------------------------------------------------
176
- // Build phases
177
- // ---------------------------------------------------------------------------
178
- /** Helper: run a command in the VM, throw on failure. */
179
- async function run(vm, log, label, cmd) {
180
- log(label);
181
- const r = await vm.exec(cmd);
182
- if (r.exitCode !== 0) {
183
- const output = [r.stderr, r.stdout]
184
- .filter(Boolean)
185
- .join('\n')
186
- .slice(0, 800);
187
- throw new Error(`snapshot build "${label}" failed (exit ${r.exitCode}):\n${output}`);
188
- }
189
- }
190
- async function buildSnapshot(vm, config, log) {
191
- // ── Base layer (always) ─────────────────────────────────────────────
192
- // Resize filesystem to fill overlay
193
- await run(vm, log, 'resizing rootfs...', 'apk add --no-cache e2fsprogs-extra >/dev/null 2>&1 && resize2fs /dev/vda 2>/dev/null');
194
- // Install base Alpine packages
195
- await run(vm, log, `installing base packages: ${BASE_ALPINE_PACKAGES.join(' ')}`, `apk add --no-cache ${BASE_ALPINE_PACKAGES.join(' ')}`);
196
- // Install gh CLI from GitHub releases
197
- const arch = getGuestArch();
198
- await run(vm, log, `installing gh ${GH_VERSION} (${arch.gh})...`, `sh -eu -c '
199
- curl -fsSL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_${arch.gh}.tar.gz" -o /tmp/gh.tar.gz
200
- tar -xzf /tmp/gh.tar.gz -C /tmp
201
- mv /tmp/gh_${GH_VERSION}_${arch.gh}/bin/gh /usr/local/bin/gh
202
- chmod +x /usr/local/bin/gh
203
- rm -rf /tmp/gh.tar.gz /tmp/gh_${GH_VERSION}_${arch.gh}
204
- gh --version
205
- '`);
206
- // Install MoltNet CLI binary directly from npm registry (no Node required)
207
- await run(vm, log, `installing moltnet CLI ${MOLTNET_CLI_VERSION} (${arch.npm})...`, `sh -eu -c '
208
- curl -fsSL "https://registry.npmjs.org/@themoltnet/cli-${arch.npm}/-/cli-${arch.npm}-${MOLTNET_CLI_VERSION}.tgz" -o /tmp/moltnet.tgz
209
- tar -xzf /tmp/moltnet.tgz -C /tmp
210
- mv /tmp/package/bin/moltnet /usr/local/bin/moltnet
211
- chmod +x /usr/local/bin/moltnet
212
- rm -rf /tmp/moltnet.tgz /tmp/package
213
- '`);
214
- // Create agent user and workspace
215
- await run(vm, log, 'creating agent user...', `sh -eu -c '
216
- addgroup -g 501 agent 2>/dev/null || true
217
- adduser -D -u 501 -G agent -h /home/agent -s /bin/sh agent 2>/dev/null || true
218
- mkdir -p /home/agent/.moltnet /home/agent/.cache /workspace
219
- chown -R agent:agent /home/agent /workspace
220
- chmod 644 /etc/gondolin/mitm/ca.crt 2>/dev/null || true
221
- '`);
222
- // Configure DNS (VM gateway DNS may not forward correctly)
223
- await run(vm, log, 'configuring DNS resolvers...', `sh -c 'echo "nameserver 8.8.8.8
224
- nameserver 1.1.1.1" > /etc/resolv.conf'`);
225
- // ── User setup commands (optional) ─────────────────────────────────
226
- if (config.setupCommands?.length) {
227
- for (let i = 0; i < config.setupCommands.length; i++) {
228
- await run(vm, log, `setup [${i + 1}/${config.setupCommands.length}]...`, config.setupCommands[i]);
229
- }
230
- }
231
- }
232
- // ---------------------------------------------------------------------------
233
- // Pruning
234
- // ---------------------------------------------------------------------------
235
- function pruneOldSnapshots(maxCached, currentDir) {
236
- const cacheRoot = getCacheDir();
237
- if (!existsSync(cacheRoot))
238
- return;
239
- const entries = readdirSync(cacheRoot, { withFileTypes: true })
240
- .filter((e) => e.isDirectory() && e.name.startsWith('v'))
241
- .map((e) => {
242
- const fullPath = path.join(cacheRoot, e.name);
243
- const stat = statSync(fullPath);
244
- return { path: fullPath, mtime: stat.mtimeMs };
245
- })
246
- .sort((a, b) => b.mtime - a.mtime);
247
- // Keep maxCached + the current one
248
- for (const entry of entries.slice(maxCached + 1)) {
249
- if (entry.path !== currentDir) {
250
- rmSync(entry.path, { recursive: true, force: true });
251
- }
252
- }
253
- }
254
- //# sourceMappingURL=snapshot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- import type { VM } from '@earendil-works/gondolin';
2
- import type { BashOperations, EditOperations, ReadOperations, WriteOperations } from '@mariozechner/pi-coding-agent';
3
- export type { BashOperations, EditOperations, ReadOperations, WriteOperations };
4
- /**
5
- * Map a host-side absolute path to a guest-side /workspace path.
6
- * Throws if the path escapes the workspace.
7
- */
8
- export declare function toGuestPath(localCwd: string, localPath: string): string;
9
- export declare function createGondolinReadOps(vm: VM, localCwd: string): ReadOperations;
10
- export declare function createGondolinWriteOps(vm: VM, localCwd: string): WriteOperations;
11
- export declare function createGondolinEditOps(vm: VM, localCwd: string): EditOperations;
12
- export declare function createGondolinBashOps(vm: VM, localCwd: string): BashOperations;
13
- //# sourceMappingURL=tool-operations.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-operations.d.ts","sourceRoot":"","sources":["../src/tool-operations.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,eAAe,EAChB,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC;AAQhF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQvE;AAED,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,GACf,cAAc,CAkChB;AAED,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,GACf,eAAe,CAsBjB;AAED,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,GACf,cAAc,CAIhB;AAED,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,GACf,cAAc,CAiDhB"}
@@ -1,142 +0,0 @@
1
- /**
2
- * Gondolin tool operations: redirect pi's built-in tool operations
3
- * (read, write, edit, bash) to execute inside the VM.
4
- *
5
- * Follows the same pattern as upstream pi-gondolin.ts — pi's tool factories
6
- * accept an `operations` object that provides the underlying I/O.
7
- */
8
- import path from 'node:path';
9
- const GUEST_WORKSPACE = '/workspace';
10
- function shQuote(s) {
11
- return "'" + s.replace(/'/g, "'\\''") + "'";
12
- }
13
- /**
14
- * Map a host-side absolute path to a guest-side /workspace path.
15
- * Throws if the path escapes the workspace.
16
- */
17
- export function toGuestPath(localCwd, localPath) {
18
- const rel = path.relative(localCwd, localPath);
19
- if (rel === '')
20
- return GUEST_WORKSPACE;
21
- if (rel.startsWith('..') || path.isAbsolute(rel)) {
22
- throw new Error(`path escapes workspace: ${localPath}`);
23
- }
24
- const posixRel = rel.split(path.sep).join(path.posix.sep);
25
- return path.posix.join(GUEST_WORKSPACE, posixRel);
26
- }
27
- export function createGondolinReadOps(vm, localCwd) {
28
- return {
29
- readFile: async (p) => {
30
- const r = await vm.exec(['/bin/cat', toGuestPath(localCwd, p)]);
31
- if (!r.ok)
32
- throw new Error(`cat failed (${r.exitCode}): ${r.stderr}`);
33
- return r.stdoutBuffer;
34
- },
35
- access: async (p) => {
36
- const r = await vm.exec([
37
- '/bin/sh',
38
- '-lc',
39
- `test -r ${shQuote(toGuestPath(localCwd, p))}`,
40
- ]);
41
- if (!r.ok)
42
- throw new Error(`not readable: ${p}`);
43
- },
44
- detectImageMimeType: async (p) => {
45
- try {
46
- const r = await vm.exec([
47
- '/bin/sh',
48
- '-lc',
49
- `file --mime-type -b ${shQuote(toGuestPath(localCwd, p))}`,
50
- ]);
51
- if (!r.ok)
52
- return null;
53
- const m = r.stdout.trim();
54
- return ['image/jpeg', 'image/png', 'image/gif', 'image/webp'].includes(m)
55
- ? m
56
- : null;
57
- }
58
- catch {
59
- return null;
60
- }
61
- },
62
- };
63
- }
64
- export function createGondolinWriteOps(vm, localCwd) {
65
- return {
66
- writeFile: async (p, content) => {
67
- const guestPath = toGuestPath(localCwd, p);
68
- const dir = path.posix.dirname(guestPath);
69
- const b64 = Buffer.from(content, 'utf8').toString('base64');
70
- const r = await vm.exec([
71
- '/bin/sh',
72
- '-lc',
73
- [
74
- 'set -eu',
75
- `mkdir -p ${shQuote(dir)}`,
76
- `echo ${shQuote(b64)} | base64 -d > ${shQuote(guestPath)}`,
77
- ].join('\n'),
78
- ]);
79
- if (!r.ok)
80
- throw new Error(`write failed (${r.exitCode}): ${r.stderr}`);
81
- },
82
- mkdir: async (dir) => {
83
- const r = await vm.exec(['/bin/mkdir', '-p', toGuestPath(localCwd, dir)]);
84
- if (!r.ok)
85
- throw new Error(`mkdir failed (${r.exitCode}): ${r.stderr}`);
86
- },
87
- };
88
- }
89
- export function createGondolinEditOps(vm, localCwd) {
90
- const r = createGondolinReadOps(vm, localCwd);
91
- const w = createGondolinWriteOps(vm, localCwd);
92
- return { readFile: r.readFile, access: r.access, writeFile: w.writeFile };
93
- }
94
- export function createGondolinBashOps(vm, localCwd) {
95
- return {
96
- exec: async (command, cwd, { onData, signal, timeout, env }) => {
97
- const guestCwd = toGuestPath(localCwd, cwd);
98
- const ac = new AbortController();
99
- const onAbort = () => ac.abort();
100
- signal?.addEventListener('abort', onAbort, { once: true });
101
- let timedOut = false;
102
- const timer = timeout && timeout > 0
103
- ? setTimeout(() => {
104
- timedOut = true;
105
- ac.abort();
106
- }, timeout * 1000)
107
- : undefined;
108
- try {
109
- // Do not forward host env to guest — the VM has its own env set at
110
- // resume time. Forwarding leaks host-specific paths (GOROOT, PATH, etc).
111
- void env;
112
- const proc = vm.exec(['/bin/sh', '-lc', command], {
113
- cwd: guestCwd,
114
- signal: ac.signal,
115
- stdout: 'pipe',
116
- stderr: 'pipe',
117
- });
118
- for await (const chunk of proc.output()) {
119
- const buf = typeof chunk.data === 'string'
120
- ? Buffer.from(chunk.data, 'utf8')
121
- : chunk.data;
122
- onData(buf);
123
- }
124
- const r = await proc;
125
- return { exitCode: r.exitCode };
126
- }
127
- catch (err) {
128
- if (signal?.aborted)
129
- throw new Error('aborted');
130
- if (timedOut)
131
- throw new Error(`timeout:${timeout}`);
132
- throw err;
133
- }
134
- finally {
135
- if (timer)
136
- clearTimeout(timer);
137
- signal?.removeEventListener('abort', onAbort);
138
- }
139
- },
140
- };
141
- }
142
- //# sourceMappingURL=tool-operations.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-operations.js","sourceRoot":"","sources":["../src/tool-operations.ts"],"names":[],"mappings":"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"}