@inthedark/wb 0.0.5 → 0.0.6

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.
@@ -8,6 +8,7 @@ import { fileURLToPath } from "node:url";
8
8
 
9
9
  const MAX_OUTPUT_BYTES = 1024 * 1024;
10
10
  const PACKAGED_WB = path.join(path.dirname(fileURLToPath(import.meta.url)), "wb");
11
+ const DANGEROUS_ACCESS = "DANGEROUSLY_ACCESS_ENV_VARS";
11
12
 
12
13
  export default class StoreCommandRunner {
13
14
  constructor({ maxOutputBytes = MAX_OUTPUT_BYTES, packagedWb = PACKAGED_WB } = {}) {
@@ -19,9 +20,16 @@ export default class StoreCommandRunner {
19
20
  async run(argv, { signal } = {}) {
20
21
  signal?.throwIfAborted();
21
22
  // `wb` means this package's own bootstrap so lookups work without PATH setup.
22
- const [executable, ...args] = argv[0] === "wb" ? [process.execPath, this.packagedWb, ...argv.slice(1)] : argv;
23
+ const packaged = argv[0] === "wb";
24
+ const [executable, ...args] = packaged ? [process.execPath, this.packagedWb, ...argv.slice(1)] : argv;
23
25
  return await new Promise((resolve, reject) => {
24
- const child = spawn(executable, args, { shell: false, signal, stdio: ["ignore", "pipe", "ignore"], windowsHide: true });
26
+ const child = spawn(executable, args, {
27
+ env: packaged ? { ...process.env, [DANGEROUS_ACCESS]: "1" } : process.env,
28
+ shell: false,
29
+ signal,
30
+ stdio: ["ignore", "pipe", "ignore"],
31
+ windowsHide: true,
32
+ });
25
33
  const chunks = [];
26
34
  let length = 0;
27
35
  let overflow = false;
@@ -19,6 +19,7 @@ export default class WorkbenchBootstrap {
19
19
  home = os.homedir(),
20
20
  packageRoot = path.dirname(fileURLToPath(import.meta.url)),
21
21
  environment = process.env,
22
+ platform = process.platform,
22
23
  prompt = new WorkbenchInstallPrompt(),
23
24
  commands = new WorkbenchBootstrapCommand({ environment }),
24
25
  toolchain = new WorkbenchToolchain({ home, environment, commands }),
@@ -28,6 +29,7 @@ export default class WorkbenchBootstrap {
28
29
  this.home = home;
29
30
  this.packageRoot = packageRoot;
30
31
  this.environment = environment;
32
+ this.platform = platform;
31
33
  this.prompt = prompt;
32
34
  this.commands = commands;
33
35
  this.toolchain = toolchain;
@@ -94,47 +96,6 @@ export default class WorkbenchBootstrap {
94
96
  }
95
97
  }
96
98
 
97
- async discardIncomplete(record) {
98
- const root = path.resolve(record.root);
99
- if (root !== record.root || !["wb", "workbench"].includes(path.basename(root).toLowerCase())) {
100
- throw new Error(`Cannot verify failed install destination ${record.root}; it was preserved.`);
101
- }
102
- let stat;
103
- try { stat = await fs.lstat(root); }
104
- catch (error) {
105
- if (error.code !== "ENOENT") throw error;
106
- await fs.unlink(this.registry);
107
- return;
108
- }
109
- if (!stat.isDirectory() || stat.isSymbolicLink()) {
110
- throw new Error(`Failed install destination ${root} is not an ordinary directory; it was preserved.`);
111
- }
112
- if (await fs.realpath(root) !== root) {
113
- throw new Error(`Failed install destination ${root} resolves elsewhere; it was preserved.`);
114
- }
115
- if ((await fs.readdir(root)).length) {
116
- if (!await this.checkoutExists(root)) {
117
- throw new Error(`Failed install destination ${root} is not a complete Workbench checkout; it was preserved.`);
118
- }
119
- const git = await fs.lstat(path.join(root, ".git")).catch(error => {
120
- if (error.code === "ENOENT") return null;
121
- throw error;
122
- });
123
- if (!git?.isDirectory() || git.isSymbolicLink()) {
124
- throw new Error(`Failed install destination ${root} is not a regular Git clone; it was preserved.`);
125
- }
126
- let changes = "";
127
- await this.commands.run("git", ["status", "--porcelain=v1", "--untracked-files=all"], {
128
- cwd: root,
129
- output: { write: bytes => { changes += bytes.toString(); } },
130
- errorOutput: { write() {} },
131
- });
132
- if (changes.trim()) throw new Error(`Failed install destination ${root} has changes; it was preserved.`);
133
- }
134
- await fs.rm(root, { recursive: true });
135
- await fs.unlink(this.registry);
136
- }
137
-
138
99
  async run(args) {
139
100
  const managed = this.environment.WORKBENCH_THREAD_ID || this.environment.CODEX_THREAD_ID;
140
101
  const view = args[0] === "view" && (args.length === 1 || args.length === 2 && ["daemon", "app"].includes(args[1]));
@@ -159,7 +120,7 @@ export default class WorkbenchBootstrap {
159
120
  await this.requireTool("bash");
160
121
  const warning = installed?.phase === "ready"
161
122
  ? `\nNote: Previous installation at ${installed.root} no longer exists and will be recreated.`
162
- : installed ? `\nNote: Incomplete install attempt at ${installed.root} will be removed.` : "";
123
+ : installed ? `\nResuming incomplete install at ${installed.root}.` : "";
163
124
  const choice = await this.prompt.choose(
164
125
  `Workbench is not installed. This command will provision a private Vite+ toolchain if needed, clone the repository, run build commands, and register wb through your package manager. Continue?${warning}`,
165
126
  ["Let's go!", "Cancel"],
@@ -194,33 +155,25 @@ export default class WorkbenchBootstrap {
194
155
  if (latest?.root !== installed?.root || latest?.phase !== installed?.phase) {
195
156
  throw new Error("The selected Workbench installation changed while setup was open. Run wb again.");
196
157
  }
197
- if (latest && latest.phase !== "ready") await this.discardIncomplete(latest);
198
- await this.requireEmptyDestination(root);
158
+ const resume = latest?.root === root && await this.checkoutExists(root);
159
+ if (!resume) await this.requireEmptyDestination(root);
160
+ // Recording before provisioning keeps the chosen location as the next default if anything fails.
161
+ await this.writeInstallation({ version: 1, root, phase: resume ? "setup" : "cloning" });
199
162
  await this.registration.prepare();
200
163
  await this.toolchain.ensure();
201
- let record = { version: 1, root, phase: "cloning" };
202
- await this.writeInstallation(record);
203
164
  await this.prompt.withHeader(async () => {
204
- this.write(`Installing Workbench at ${root}\n`);
205
- try {
165
+ this.write(`${resume ? "Resuming" : "Installing"} Workbench at ${root}\n`);
166
+ if (!resume) {
206
167
  // Install sandboxes substitute a local snapshot; ordinary installs clone the public repository.
207
168
  const repository = this.environment.WORKBENCH_INSTALL_REPOSITORY || "https://github.com/ErisInTheDark/workbench.git";
208
169
  await this.commands.run("git", ["clone", "--progress", "--branch", "main", "--single-branch", repository, root]);
209
170
  if (!await this.checkoutExists(root)) throw new Error("Clone did not produce a Workbench checkout.");
210
- record = { ...record, phase: "setup" };
211
- await this.writeInstallation(record);
212
- await this.commands.run(process.execPath, [path.join(root, "scripts", "install.mjs"), "--prepare"], { cwd: root });
213
- await this.registration.register(root);
214
- } catch (error) {
215
- try { await this.discardIncomplete(record); }
216
- catch (cleanupError) {
217
- throw new Error(`${error.message} Incomplete checkout was preserved at ${root}: ${cleanupError.message}`, { cause: error });
218
- }
219
- throw error;
171
+ await this.writeInstallation({ version: 1, root, phase: "setup" });
220
172
  }
173
+ await this.commands.run(process.execPath, [path.join(root, "scripts", "install.mjs"), "--prepare"], { cwd: root });
174
+ await this.registration.register(root);
221
175
  });
222
- record = { ...record, phase: "ready" };
223
- await this.writeInstallation(record);
176
+ await this.writeInstallation({ version: 1, root, phase: "ready" });
224
177
  } finally {
225
178
  // Closing the connection also releases the OS lock after normal completion;
226
179
  // process death releases it without a stale PID or lock-file recovery path.
package/index.mjs CHANGED
@@ -17,10 +17,6 @@ function warnDefault(message) {
17
17
  process.emitWarning(message, "WorkbenchStoreWarning");
18
18
  }
19
19
 
20
- function isManagedAgentProcess() {
21
- return Boolean(process.env.WORKBENCH_THREAD_ID?.trim() || process.env.CODEX_THREAD_ID?.trim());
22
- }
23
-
24
20
  function stripTerminalLineEnding(value) {
25
21
  return value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
26
22
  }
@@ -58,10 +54,6 @@ async function resolveReferences(parsed, definitions, { runner, signal, warn })
58
54
  }
59
55
  }
60
56
  if (!lookups.size) return parsed;
61
- if (isManagedAgentProcess()) {
62
- warn("Store lookups are disabled in Workbench-managed agent processes. Store references were left unchanged.");
63
- return parsed;
64
- }
65
57
  const results = new Map(await Promise.all(Array.from(lookups, async ([id, lookup]) => {
66
58
  const result = await runner.run(lookup.argv, { signal });
67
59
  if (!result.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inthedark/wb",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",