create-snipara 2.1.0 → 2.2.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.
@@ -0,0 +1,19 @@
1
+ interface ManagedNativeConfiguration {
2
+ command: string;
3
+ args: string[];
4
+ env?: Record<string, string>;
5
+ }
6
+ /** Preserve source-bound context and unrelated connections; add only local capabilities. */
7
+ declare function mergeManagedMcpServers<T>(existing: Record<string, T>, native: T, hosted: T, sourceBound?: boolean): Record<string, T>;
8
+ interface ManagedCodexOptions {
9
+ file: string;
10
+ python: string;
11
+ server: ManagedNativeConfiguration;
12
+ env: Record<string, string | undefined>;
13
+ validateExisting: (server: ManagedNativeConfiguration) => boolean;
14
+ initialContent?: string;
15
+ }
16
+ declare function managedCodexSnippet(server: ManagedNativeConfiguration): string;
17
+ declare function mergeManagedCodexConfig(options: ManagedCodexOptions): "created" | "appended" | "unchanged";
18
+
19
+ export { type ManagedCodexOptions, type ManagedNativeConfiguration, managedCodexSnippet, mergeManagedCodexConfig, mergeManagedMcpServers };
@@ -0,0 +1,86 @@
1
+ // src/managed-config.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { execFileSync } from "child_process";
5
+ import { TextDecoder } from "util";
6
+ function mergeManagedMcpServers(existing, native, hosted, sourceBound = false) {
7
+ return { ...existing, ...sourceBound || existing["snipara-repository"] ? {} : { snipara: hosted }, "snipara-local": native };
8
+ }
9
+ var PARSE = "import json,sys\ntry:\n import tomllib\nexcept ImportError:\n import tomli as tomllib\nvalue=tomllib.loads(sys.stdin.read())\nservers=value.get('mcp_servers',{})\nif not isinstance(servers,dict): raise ValueError('invalid MCP table')\nprint(json.dumps(servers.get('snipara-local'),ensure_ascii=True))";
10
+ function parse(content, options) {
11
+ try {
12
+ return JSON.parse(execFileSync(options.python, ["-I", "-B", "-c", PARSE], {
13
+ input: content,
14
+ env: options.env,
15
+ encoding: "utf8",
16
+ timeout: 5e3,
17
+ maxBuffer: 1e6,
18
+ stdio: ["pipe", "pipe", "pipe"]
19
+ }));
20
+ } catch {
21
+ throw new Error("Existing Codex configuration is malformed or its parser is unavailable; file preserved");
22
+ }
23
+ }
24
+ function object(value) {
25
+ return value !== null && typeof value === "object" && !Array.isArray(value);
26
+ }
27
+ function managedCodexSnippet(server) {
28
+ const env = server.env && Object.keys(server.env).length ? `
29
+ env = { ${Object.entries(server.env).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }` : "";
30
+ return `[mcp_servers.snipara-local]
31
+ command = ${JSON.stringify(server.command)}
32
+ args = ${JSON.stringify(server.args)}${env}
33
+ `;
34
+ }
35
+ function mergeManagedCodexConfig(options) {
36
+ const directory = path.dirname(options.file);
37
+ if (!fs.existsSync(directory)) fs.mkdirSync(directory, { mode: 448 });
38
+ const parent = fs.lstatSync(directory);
39
+ if (!parent.isDirectory() || parent.isSymbolicLink() || parent.uid !== process.getuid?.() || parent.mode & 18)
40
+ throw new Error("Codex configuration directory is not safely owned; preserved");
41
+ let previous = null;
42
+ try {
43
+ const fd2 = fs.openSync(options.file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
44
+ try {
45
+ const info = fs.fstatSync(fd2);
46
+ if (!info.isFile() || info.uid !== process.getuid?.() || info.nlink !== 1 || info.size > 1e6 || info.mode & 18)
47
+ throw new Error("Existing Codex configuration is not safely owned; preserved");
48
+ previous = fs.readFileSync(fd2);
49
+ if (previous.length > 1e6) throw new Error("Existing Codex configuration exceeds its bound; preserved");
50
+ } finally {
51
+ fs.closeSync(fd2);
52
+ }
53
+ } catch (error) {
54
+ if (error.code !== "ENOENT") throw error;
55
+ }
56
+ const content = previous ? new TextDecoder("utf8", { fatal: true }).decode(previous) : options.initialContent ?? "";
57
+ const selected = parse(content, options);
58
+ if (selected !== null) {
59
+ if (!object(selected) || Object.keys(selected).some((key) => !["command", "args", "env"].includes(key)) || typeof selected.command !== "string" || !Array.isArray(selected.args) || !selected.args.every((value) => typeof value === "string") || selected.env !== void 0 && (!object(selected.env) || !Object.values(selected.env).every((value) => typeof value === "string")) || !options.validateExisting(selected))
60
+ throw new Error("Existing managed Codex connection conflicts with setup; file preserved and activation incomplete");
61
+ return "unchanged";
62
+ }
63
+ const result = content + (content ? content.endsWith("\n") ? "\n" : "\n\n" : "") + managedCodexSnippet(options.server);
64
+ parse(result, options);
65
+ if (previous && !fs.readFileSync(options.file).equals(previous))
66
+ throw new Error("Codex configuration changed during setup; file preserved");
67
+ if (!previous) {
68
+ fs.writeFileSync(options.file, result, { flag: "wx", mode: 384 });
69
+ return "created";
70
+ }
71
+ const fd = fs.openSync(options.file, fs.constants.O_WRONLY | fs.constants.O_APPEND | fs.constants.O_NOFOLLOW);
72
+ try {
73
+ const current = fs.fstatSync(fd), named = fs.lstatSync(options.file);
74
+ if (current.ino !== named.ino || current.dev !== named.dev || current.size !== previous.length || !current.isFile())
75
+ throw new Error("Codex configuration changed during setup; file preserved");
76
+ fs.writeFileSync(fd, result.slice(content.length), "utf8");
77
+ } finally {
78
+ fs.closeSync(fd);
79
+ }
80
+ return "appended";
81
+ }
82
+ export {
83
+ managedCodexSnippet,
84
+ mergeManagedCodexConfig,
85
+ mergeManagedMcpServers
86
+ };
@@ -0,0 +1,38 @@
1
+ import { ManagedToolchainManifest } from '@snipara/project-intelligence-contracts';
2
+
3
+ declare const MANAGED_VERSIONS: Readonly<{
4
+ companion: string;
5
+ orchestrator: string;
6
+ sandbox: string;
7
+ }>;
8
+ declare function assertManagedRuntimeVersions(nodeVersion: string, pythonVersion: string): void;
9
+ type Execution = {
10
+ command: string;
11
+ args: string[];
12
+ cwd: string;
13
+ env: Record<string, string | undefined>;
14
+ timeoutMs: number;
15
+ };
16
+ type ManagedInstallerRunner = (input: Execution) => Promise<{
17
+ stdout: string;
18
+ }>;
19
+ interface ManagedInstallerOptions {
20
+ home?: string;
21
+ runner?: ManagedInstallerRunner;
22
+ python?: string;
23
+ npm?: string;
24
+ repair?: boolean;
25
+ }
26
+ declare function readManagedManifest(file: string, options?: ManagedInstallerOptions): ManagedToolchainManifest;
27
+ /** A retained bootstrap executes only Companion; its old peer commands are never selected. */
28
+ declare function verifyRetainedCompanionBootstrap(command: string, active: ManagedToolchainManifest, options?: ManagedInstallerOptions): boolean;
29
+ declare function managedToolchainStatus(options?: ManagedInstallerOptions): {
30
+ status: "absent" | "ready";
31
+ manifest: ManagedToolchainManifest | null;
32
+ manifestPath: string | null;
33
+ };
34
+ declare const runManagedInstaller: ManagedInstallerRunner;
35
+ declare function prepareManagedToolchain(options?: ManagedInstallerOptions): Promise<ManagedToolchainManifest>;
36
+ declare function rollbackManagedToolchain(options?: ManagedInstallerOptions): Promise<ManagedToolchainManifest>;
37
+
38
+ export { MANAGED_VERSIONS, type ManagedInstallerOptions, type ManagedInstallerRunner, assertManagedRuntimeVersions, managedToolchainStatus, prepareManagedToolchain, readManagedManifest, rollbackManagedToolchain, runManagedInstaller, verifyRetainedCompanionBootstrap };
@@ -0,0 +1,505 @@
1
+ // src/managed-toolchain.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { homedir } from "os";
5
+ import { createHash as createHash5, randomUUID as randomUUID2 } from "crypto";
6
+ import { spawn } from "child_process";
7
+
8
+ // ../project-intelligence-contracts/src/worker-profile.ts
9
+ import { createHash } from "crypto";
10
+
11
+ // ../project-intelligence-contracts/src/producer-loop.ts
12
+ import { createHash as createHash2 } from "crypto";
13
+
14
+ // ../project-intelligence-contracts/src/decision-request.ts
15
+ import { createHash as createHash3 } from "crypto";
16
+
17
+ // ../project-intelligence-contracts/src/why-capture-confidence-v1.json
18
+ var why_capture_confidence_v1_default = {
19
+ version: "why-capture-confidence-v1",
20
+ base: 0.72,
21
+ decisionRationaleBonus: 0.1,
22
+ nonManualSourceBonus: 0.04,
23
+ maximum: 0.9,
24
+ decimalPlaces: 2,
25
+ validatedExecutionOutcomes: ["completed"],
26
+ vectors: [
27
+ {
28
+ candidateType: "CONTEXT",
29
+ hasDecision: false,
30
+ hasRationale: false,
31
+ sourceKind: "manual",
32
+ executionOutcome: "completed",
33
+ expected: 0.72
34
+ },
35
+ {
36
+ candidateType: "DECISION",
37
+ hasDecision: true,
38
+ hasRationale: true,
39
+ sourceKind: "manual",
40
+ executionOutcome: "completed",
41
+ expected: 0.82
42
+ },
43
+ {
44
+ candidateType: "DECISION",
45
+ hasDecision: true,
46
+ hasRationale: true,
47
+ sourceKind: "phase_commit",
48
+ executionOutcome: "completed",
49
+ expected: 0.86
50
+ },
51
+ {
52
+ candidateType: "DECISION",
53
+ hasDecision: true,
54
+ hasRationale: true,
55
+ sourceKind: "phase_commit",
56
+ executionOutcome: "partial",
57
+ expected: 0.76
58
+ },
59
+ {
60
+ candidateType: "DECISION",
61
+ hasDecision: true,
62
+ hasRationale: true,
63
+ sourceKind: "phase_commit",
64
+ executionOutcome: "blocked",
65
+ expected: 0.76
66
+ },
67
+ {
68
+ candidateType: "DECISION",
69
+ hasDecision: true,
70
+ hasRationale: true,
71
+ sourceKind: "phase_commit",
72
+ executionOutcome: "abandoned",
73
+ expected: 0.76
74
+ },
75
+ {
76
+ candidateType: "DECISION",
77
+ hasDecision: true,
78
+ hasRationale: false,
79
+ sourceKind: "final_commit",
80
+ executionOutcome: "completed",
81
+ expected: 0.76
82
+ }
83
+ ]
84
+ };
85
+
86
+ // ../project-intelligence-contracts/src/why-capture-confidence.ts
87
+ var WHY_CAPTURE_CONFIDENCE_VERSION = why_capture_confidence_v1_default.version;
88
+ var WHY_CAPTURE_CONFIDENCE_TEST_VECTORS = why_capture_confidence_v1_default.vectors;
89
+
90
+ // ../project-intelligence-contracts/src/judgment-integrity.ts
91
+ import { randomUUID } from "crypto";
92
+
93
+ // ../project-intelligence-contracts/src/agent-memory-pilot.ts
94
+ import { createHash as createHash4 } from "crypto";
95
+
96
+ // ../project-intelligence-contracts/src/managed-toolchain.ts
97
+ var MANAGED_TOOLCHAIN_VERSION = "snipara.toolchain.v1";
98
+ var MANAGED_TOOLCHAIN_COMPONENTS = ["companion", "orchestrator", "sandbox"];
99
+ var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
100
+ var bounded = (value, max) => typeof value === "string" && value.length > 0 && value.length <= max && !Array.from(value).some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) === 127);
101
+ function canonicalAbsolute(value) {
102
+ return bounded(value, 4096) && value.startsWith("/") && value !== "/" && !value.endsWith("/") && !value.split("/").some((part, index) => index > 0 && ["", ".", ".."].includes(part));
103
+ }
104
+ function parseManagedToolchainManifest(value) {
105
+ if (!object(value) || value.schemaVersion !== MANAGED_TOOLCHAIN_VERSION || !bounded(value.bundleId, 128) || !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(value.bundleId) || !canonicalAbsolute(value.root) || !object(value.components) || !object(value.contracts) || value.contracts.taskReference !== 1 || value.contracts.validation !== 1 || !Array.isArray(value.capabilities) || value.capabilities.length > 32 || !value.capabilities.every((item) => bounded(item, 64) && /^[a-z][a-z0-9_-]*$/.test(item)) || new Set(value.capabilities).size !== value.capabilities.length) {
106
+ throw new Error("Unsupported or invalid managed toolchain manifest");
107
+ }
108
+ const root = value.root;
109
+ const components = {};
110
+ for (const name of MANAGED_TOOLCHAIN_COMPONENTS) {
111
+ const component = value.components[name];
112
+ if (!object(component) || !bounded(component.version, 64) || !/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/.test(component.version) || !canonicalAbsolute(component.command) || !component.command.startsWith(root + "/") || typeof component.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(component.sha256)) {
113
+ throw new Error("Invalid managed component identity");
114
+ }
115
+ components[name] = { version: component.version, command: component.command, sha256: component.sha256 };
116
+ }
117
+ return {
118
+ schemaVersion: MANAGED_TOOLCHAIN_VERSION,
119
+ bundleId: value.bundleId,
120
+ root,
121
+ components,
122
+ contracts: { taskReference: 1, validation: 1 },
123
+ capabilities: [...value.capabilities]
124
+ };
125
+ }
126
+
127
+ // src/managed-versions.json
128
+ var managed_versions_default = {
129
+ companion: "4.2.0",
130
+ orchestrator: "1.16.0",
131
+ sandbox: "3.0.0"
132
+ };
133
+
134
+ // src/managed-toolchain.ts
135
+ var MANAGED_VERSIONS = Object.freeze(managed_versions_default);
136
+ function assertManagedRuntimeVersions(nodeVersion, pythonVersion) {
137
+ const node = /^v?(\d+)\.\d+\.\d+(?:[-+].*)?$/.exec(nodeVersion);
138
+ const python = /^Python (\d+)\.(\d+)\.\d+(?:[a-z0-9.+-]*)?$/i.exec(pythonVersion.trim());
139
+ if (!node || Number(node[1]) < 18 || !python || Number(python[1]) !== 3 || Number(python[2]) < 10)
140
+ throw new Error("Local work requires existing Node.js 18+ and Python 3.10+. Update your system runtimes and retry; no operating-system runtime was installed");
141
+ }
142
+ var ManagedInstallerCleanupError = class extends Error {
143
+ };
144
+ var sha = (bytes2) => createHash5("sha256").update(bytes2).digest("hex");
145
+ var uid = () => {
146
+ if (!process.getuid || process.platform === "win32") throw new Error("Managed local work requires macOS or Linux");
147
+ return process.getuid();
148
+ };
149
+ function exists(file) {
150
+ try {
151
+ fs.lstatSync(file);
152
+ return true;
153
+ } catch (error) {
154
+ if (error.code === "ENOENT") return false;
155
+ throw error;
156
+ }
157
+ }
158
+ function owned(file, directory, privateMode = false) {
159
+ const info = fs.lstatSync(file);
160
+ if (info.uid !== uid() || info.isSymbolicLink() || (directory ? !info.isDirectory() : !info.isFile()) || !directory && info.nlink !== 1 || (info.mode & 18) !== 0 || privateMode && (info.mode & 63) !== 0)
161
+ throw new Error("Managed installation path is not owned and protected");
162
+ return info;
163
+ }
164
+ function privateDirectory(directory) {
165
+ if (!exists(directory)) {
166
+ privateDirectory(path.dirname(directory));
167
+ fs.mkdirSync(directory, { mode: 448 });
168
+ }
169
+ owned(directory, true);
170
+ }
171
+ function location(options) {
172
+ const home = fs.realpathSync(options.home ?? homedir());
173
+ owned(home, true);
174
+ return path.join(home, ".local/share/snipara/toolchains");
175
+ }
176
+ function bytes(file, limit = 65536) {
177
+ owned(file, false);
178
+ const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
179
+ try {
180
+ const info = fs.fstatSync(fd);
181
+ if (!info.isFile() || info.uid !== uid() || info.size > limit || info.mode & 18)
182
+ throw new Error("Managed installation artifact is invalid");
183
+ const value = fs.readFileSync(fd);
184
+ if (value.length > limit) throw new Error("Managed installation artifact exceeds its bound");
185
+ return value;
186
+ } finally {
187
+ fs.closeSync(fd);
188
+ }
189
+ }
190
+ function writePrivate(file, value) {
191
+ fs.writeFileSync(file, JSON.stringify(value, null, 2) + "\n", { mode: 384, flag: "wx" });
192
+ }
193
+ function protectedCommand(root, command) {
194
+ const real = fs.realpathSync(command);
195
+ if (!real.startsWith(root + path.sep)) throw new Error("Managed command escapes its bundle");
196
+ for (let current = path.dirname(real); current !== root; current = path.dirname(current)) owned(current, true);
197
+ const info = owned(real, false);
198
+ if (!(info.mode & 73)) throw new Error("Managed command is not executable");
199
+ return real;
200
+ }
201
+ function readManagedManifest(file, options = {}) {
202
+ const base = location(options);
203
+ owned(base, true, true);
204
+ const link = fs.lstatSync(file);
205
+ let target = file;
206
+ if (link.isSymbolicLink()) {
207
+ if (link.uid !== uid()) throw new Error("Managed pointer has a foreign owner");
208
+ target = path.resolve(path.dirname(file), fs.readlinkSync(file));
209
+ }
210
+ if (path.basename(target) !== "toolchain.json" || path.dirname(path.dirname(target)) !== base)
211
+ throw new Error("Managed manifest is outside the private installation");
212
+ const root = path.dirname(target);
213
+ owned(root, true, true);
214
+ if (fs.realpathSync(root) !== root) throw new Error("Managed bundle cannot use linked directories");
215
+ owned(target, false, true);
216
+ const manifest = parseManagedToolchainManifest(JSON.parse(bytes(target).toString("utf8")));
217
+ if (manifest.root !== root || manifest.bundleId !== path.basename(root) || !manifest.capabilities.includes("validation") || !manifest.capabilities.includes("coordination"))
218
+ throw new Error("Managed bundle identity or required capabilities differ");
219
+ for (const component of Object.values(manifest.components)) {
220
+ if (protectedCommand(root, component.command) !== component.command || sha(bytes(component.command, 8e6)) !== component.sha256)
221
+ throw new Error("Managed command identity changed; prepare a replacement bundle");
222
+ }
223
+ return manifest;
224
+ }
225
+ function verifyRetainedCompanionBootstrap(command, active, options = {}) {
226
+ try {
227
+ const current = readManagedManifest(path.join(active.root, "toolchain.json"), options);
228
+ const base = location(options);
229
+ if (!path.isAbsolute(command) || !command.startsWith(base + path.sep)) return false;
230
+ const bundleId = command.slice(base.length + 1).split(path.sep)[0], root = path.join(base, bundleId);
231
+ owned(root, true, true);
232
+ if (fs.realpathSync(root) !== root || protectedCommand(root, command) !== command) return false;
233
+ const manifestFile = path.join(root, "toolchain.json");
234
+ owned(manifestFile, false, true);
235
+ const body = bytes(manifestFile), observedHash = sha(bytes(command, 8e6));
236
+ let previous;
237
+ try {
238
+ previous = parseManagedToolchainManifest(JSON.parse(body.toString("utf8")));
239
+ } catch {
240
+ return command === path.join(root, path.relative(current.root, current.components.companion.command)) && observedHash === current.components.companion.sha256;
241
+ }
242
+ return previous.root === root && previous.bundleId === bundleId && previous.components.companion.command === command && previous.components.companion.sha256 === observedHash;
243
+ } catch {
244
+ return false;
245
+ }
246
+ }
247
+ function managedToolchainStatus(options = {}) {
248
+ const active = path.join(location(options), "active.json");
249
+ if (!exists(active)) return { status: "absent", manifest: null, manifestPath: null };
250
+ return { status: "ready", manifest: readManagedManifest(active, options), manifestPath: fs.realpathSync(active) };
251
+ }
252
+ function program(name) {
253
+ for (const directory of (process.env.PATH ?? "").split(path.delimiter)) {
254
+ if (!directory || !path.isAbsolute(directory)) continue;
255
+ const candidate = path.join(directory, name);
256
+ try {
257
+ fs.accessSync(candidate, fs.constants.X_OK);
258
+ if (fs.statSync(candidate).isFile()) return fs.realpathSync(candidate);
259
+ } catch {
260
+ }
261
+ }
262
+ throw new Error(`${name} is required; no operating-system runtime will be installed`);
263
+ }
264
+ function cleanEnvironment(root) {
265
+ return {
266
+ PATH: [path.dirname(process.execPath), "/usr/local/bin", "/opt/homebrew/bin", "/usr/bin", "/bin"].join(path.delimiter),
267
+ HOME: path.join(root, "home"),
268
+ TMPDIR: path.join(root, "tmp"),
269
+ LANG: "C.UTF-8",
270
+ LC_ALL: "C.UTF-8",
271
+ PYTHONNOUSERSITE: "1",
272
+ PYTHONDONTWRITEBYTECODE: "1",
273
+ PIP_DISABLE_PIP_VERSION_CHECK: "1",
274
+ PIP_NO_INPUT: "1",
275
+ PIP_CONFIG_FILE: "/dev/null",
276
+ NPM_CONFIG_USERCONFIG: "/dev/null",
277
+ NPM_CONFIG_GLOBALCONFIG: "/dev/null",
278
+ NPM_CONFIG_IGNORE_SCRIPTS: "true",
279
+ NPM_CONFIG_AUDIT: "false",
280
+ NPM_CONFIG_FUND: "false",
281
+ NO_COLOR: "1"
282
+ };
283
+ }
284
+ var runManagedInstaller = async (input) => new Promise((resolve, reject) => {
285
+ const child = spawn(input.command, input.args, {
286
+ cwd: input.cwd,
287
+ env: input.env,
288
+ shell: false,
289
+ stdio: ["ignore", "pipe", "pipe"],
290
+ detached: process.platform !== "win32"
291
+ });
292
+ let output = "", size = 0, stopped = false, stopReason = null;
293
+ let reapTimer;
294
+ const kill = () => {
295
+ try {
296
+ if (child.pid) process.kill(-child.pid, "SIGKILL");
297
+ } catch {
298
+ child.kill("SIGKILL");
299
+ }
300
+ };
301
+ const interrupted = () => stop("Managed preparation interrupted; the prior selection was preserved");
302
+ const exiting = () => kill();
303
+ const cleanup = () => {
304
+ clearTimeout(timer);
305
+ if (reapTimer) clearTimeout(reapTimer);
306
+ process.removeListener("SIGINT", interrupted);
307
+ process.removeListener("SIGTERM", interrupted);
308
+ process.removeListener("exit", exiting);
309
+ };
310
+ const stop = (message) => {
311
+ if (stopped || stopReason) return;
312
+ stopReason = message;
313
+ kill();
314
+ reapTimer = setTimeout(() => {
315
+ if (!stopped) {
316
+ stopped = true;
317
+ cleanup();
318
+ reject(new ManagedInstallerCleanupError("Managed installer cleanup could not be observed within its deadline; installation lock retained"));
319
+ }
320
+ }, 2e3);
321
+ };
322
+ const timer = setTimeout(() => stop("Managed preparation exceeded its bounded deadline"), input.timeoutMs);
323
+ process.on("SIGINT", interrupted);
324
+ process.on("SIGTERM", interrupted);
325
+ process.on("exit", exiting);
326
+ child.stdout.on("data", (value) => {
327
+ size += value.length;
328
+ if (size > 1e6) stop("Managed preparation output exceeded its bound");
329
+ else output += value.toString("utf8");
330
+ });
331
+ child.stderr.on("data", (value) => {
332
+ size += value.length;
333
+ if (size > 1e6) stop("Managed preparation output exceeded its bound");
334
+ });
335
+ child.on("error", () => {
336
+ cleanup();
337
+ if (!stopped) {
338
+ stopped = true;
339
+ reject(new Error("Managed preparation executable was unavailable"));
340
+ }
341
+ });
342
+ child.on("close", (code) => {
343
+ cleanup();
344
+ if (stopped) return;
345
+ stopped = true;
346
+ if (stopReason) reject(new Error(stopReason));
347
+ else if (code !== 0) reject(new Error("Managed preparation step failed; the previous active bundle was preserved"));
348
+ else resolve({ stdout: output });
349
+ });
350
+ });
351
+ function switchPointer(base, name, target) {
352
+ const current = path.join(base, name);
353
+ if (exists(current)) {
354
+ const stat = fs.lstatSync(current);
355
+ if (!stat.isSymbolicLink() || stat.uid !== uid()) throw new Error("Managed active pointer must be an owned symlink");
356
+ }
357
+ const temporary = path.join(base, `.pointer-${randomUUID2()}`);
358
+ fs.symlinkSync(target, temporary);
359
+ try {
360
+ fs.renameSync(temporary, current);
361
+ } finally {
362
+ if (exists(temporary)) fs.unlinkSync(temporary);
363
+ }
364
+ }
365
+ async function locked(options, action) {
366
+ const base = location(options);
367
+ privateDirectory(base);
368
+ owned(base, true, true);
369
+ const lock = path.join(base, ".install.lock");
370
+ const fd = fs.openSync(lock, "wx", 384);
371
+ let release = true;
372
+ try {
373
+ fs.writeFileSync(fd, JSON.stringify({ pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() }));
374
+ return await action(base);
375
+ } catch (error) {
376
+ if (error instanceof ManagedInstallerCleanupError) release = false;
377
+ throw error;
378
+ } finally {
379
+ fs.closeSync(fd);
380
+ if (release) fs.unlinkSync(lock);
381
+ }
382
+ }
383
+ async function prepareManagedToolchain(options = {}) {
384
+ if (Number(process.versions.node.split(".")[0]) < 18)
385
+ throw new Error("Local work requires Node.js 18+; update your system runtime and retry");
386
+ return locked(options, async (base) => {
387
+ const active = path.join(base, "active.json");
388
+ let prior = null;
389
+ let recovery = null;
390
+ const preserveInvalidSelection = () => {
391
+ const pointer = fs.lstatSync(active);
392
+ if (!pointer.isSymbolicLink() || pointer.uid !== uid()) throw new Error("Repair refuses a foreign or non-symlink active pointer");
393
+ const target = path.resolve(base, fs.readlinkSync(active));
394
+ if (path.basename(target) !== "toolchain.json" || path.dirname(path.dirname(target)) !== base)
395
+ throw new Error("Repair refuses an active pointer outside the owned installation");
396
+ const root2 = path.dirname(target);
397
+ owned(root2, true, true);
398
+ if (fs.realpathSync(root2) !== root2) throw new Error("Repair refuses a linked bundle directory");
399
+ let previousHash = null;
400
+ if (exists(target)) {
401
+ owned(target, false, true);
402
+ previousHash = sha(bytes(target));
403
+ }
404
+ return { priorManifestPath: target, priorManifestSha256: previousHash, priorSelection: "invalid_owned_bundle" };
405
+ };
406
+ if (exists(active)) {
407
+ try {
408
+ prior = readManagedManifest(active, options);
409
+ } catch (error) {
410
+ if (!options.repair) throw error;
411
+ recovery = preserveInvalidSelection();
412
+ prior = null;
413
+ }
414
+ }
415
+ const runner = options.runner ?? runManagedInstaller;
416
+ async function handshake(manifest) {
417
+ for (const [name, component] of Object.entries(manifest.components)) {
418
+ const command = name === "companion" ? process.execPath : component.command;
419
+ const args = name === "companion" ? [component.command, "--version"] : ["--version"];
420
+ const observed = await runner({ command, args, cwd: manifest.root, env: cleanEnvironment(manifest.root), timeoutMs: 15e3 });
421
+ if (!new RegExp(`^(?:snipara-${name}[ ,]+)?${component.version.replaceAll(".", "\\.")}$`, "i").test(observed.stdout.trim()))
422
+ throw new Error("Managed component version handshake did not match the pinned bundle");
423
+ }
424
+ }
425
+ const selectedPrior = prior;
426
+ if (selectedPrior && Object.entries(MANAGED_VERSIONS).every(([name, version]) => selectedPrior.components[name].version === version)) {
427
+ try {
428
+ await handshake(selectedPrior);
429
+ readManagedManifest(active, options);
430
+ return selectedPrior;
431
+ } catch (error) {
432
+ if (!options.repair) throw error;
433
+ recovery = preserveInvalidSelection();
434
+ prior = null;
435
+ }
436
+ }
437
+ const bundleId = `bundle-${MANAGED_VERSIONS.companion}-${MANAGED_VERSIONS.orchestrator}-${MANAGED_VERSIONS.sandbox}-${randomUUID2()}`;
438
+ const root = path.join(base, bundleId);
439
+ fs.mkdirSync(root, { mode: 448 });
440
+ for (const directory of ["home", "tmp"]) fs.mkdirSync(path.join(root, directory), { mode: 448 });
441
+ const env = cleanEnvironment(root);
442
+ const run = (command, args, timeoutMs = 3e5) => runner({ command, args, cwd: root, env, timeoutMs });
443
+ try {
444
+ if (recovery) writePrivate(path.join(root, "recovery.json"), { schemaVersion: "snipara.toolchain_recovery.v1", ...recovery, originalBundlePreserved: true });
445
+ const python = options.python ?? program("python3"), npm = options.npm ?? program("npm");
446
+ if (![python, npm].every((value) => path.isAbsolute(value))) throw new Error("Managed package managers need absolute executable paths");
447
+ const runtime = await run(python, ["--version"], 1e4);
448
+ assertManagedRuntimeVersions(process.versions.node, runtime.stdout);
449
+ const venv = path.join(root, "python"), prefix = path.join(root, "node");
450
+ await run(python, ["-I", "-m", "venv", venv], 6e4);
451
+ await run(path.join(venv, "bin/python"), ["-I", "-m", "pip", "install", "--no-input", "--disable-pip-version-check", "snipara-sandbox[validation,mcp]==" + MANAGED_VERSIONS.sandbox, "snipara-orchestrator==" + MANAGED_VERSIONS.orchestrator]);
452
+ await run(npm, ["install", "--prefix", prefix, "--ignore-scripts", "--no-audit", "--no-fund", "--save-exact", "snipara-companion@" + MANAGED_VERSIONS.companion]);
453
+ const manifest = {
454
+ schemaVersion: "snipara.toolchain.v1",
455
+ bundleId,
456
+ root,
457
+ components: {
458
+ companion: { version: MANAGED_VERSIONS.companion, command: fs.realpathSync(path.join(prefix, "node_modules/.bin/snipara-companion")), sha256: "" },
459
+ orchestrator: { version: MANAGED_VERSIONS.orchestrator, command: path.join(venv, "bin/snipara-orchestrator"), sha256: "" },
460
+ sandbox: { version: MANAGED_VERSIONS.sandbox, command: path.join(venv, "bin/snipara-sandbox"), sha256: "" }
461
+ },
462
+ contracts: { taskReference: 1, validation: 1 },
463
+ capabilities: ["validation", "coordination"]
464
+ };
465
+ for (const component of Object.values(manifest.components)) {
466
+ component.command = protectedCommand(root, component.command);
467
+ component.sha256 = sha(bytes(component.command, 8e6));
468
+ }
469
+ const manifestFile = path.join(root, "toolchain.json");
470
+ writePrivate(manifestFile, parseManagedToolchainManifest(manifest));
471
+ await handshake(manifest);
472
+ readManagedManifest(manifestFile, options);
473
+ writePrivate(path.join(root, "prepared.json"), { schemaVersion: "snipara.toolchain_preparation.v1", status: "prepared", manifestSha256: sha(bytes(manifestFile)), observedAt: (/* @__PURE__ */ new Date()).toISOString(), activationObserved: false });
474
+ if (prior) switchPointer(base, "previous.json", path.join(prior.root, "toolchain.json"));
475
+ switchPointer(base, "active.json", manifestFile);
476
+ return manifest;
477
+ } catch (error) {
478
+ writePrivate(path.join(root, "failed.json"), { schemaVersion: "snipara.toolchain_preparation.v1", status: "failed", observedAt: (/* @__PURE__ */ new Date()).toISOString(), reason: "preparation_or_identity_check_failed", priorActivePreserved: true });
479
+ throw error;
480
+ }
481
+ });
482
+ }
483
+ async function rollbackManagedToolchain(options = {}) {
484
+ return locked(options, async (base) => {
485
+ const previous = readManagedManifest(path.join(base, "previous.json"), options);
486
+ let active = null;
487
+ try {
488
+ active = readManagedManifest(path.join(base, "active.json"), options);
489
+ } catch {
490
+ }
491
+ switchPointer(base, "active.json", path.join(previous.root, "toolchain.json"));
492
+ if (active) switchPointer(base, "previous.json", path.join(active.root, "toolchain.json"));
493
+ return previous;
494
+ });
495
+ }
496
+ export {
497
+ MANAGED_VERSIONS,
498
+ assertManagedRuntimeVersions,
499
+ managedToolchainStatus,
500
+ prepareManagedToolchain,
501
+ readManagedManifest,
502
+ rollbackManagedToolchain,
503
+ runManagedInstaller,
504
+ verifyRetainedCompanionBootstrap
505
+ };
@@ -0,0 +1,12 @@
1
+ interface ObservedSource {
2
+ root: string;
3
+ kind: "repository" | "local-repository" | "folder";
4
+ fingerprint: string;
5
+ repository?: string;
6
+ }
7
+
8
+ declare function detectSourceConnection(workspace: string, options?: {
9
+ python?: string;
10
+ }): ObservedSource | null;
11
+
12
+ export { detectSourceConnection };