scenri 0.3.4 → 0.3.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.5](https://github.com/tonygorb/Scenri/compare/v0.3.4...v0.3.5) (2026-08-20)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * keep untrusted text out of the Windows shell lines ([f564c35](https://github.com/tonygorb/Scenri/commit/f564c358dc018f2e7e52e00eae004122690dc2be))
9
+ * make the Codex engine and updates work on Windows ([f94f420](https://github.com/tonygorb/Scenri/commit/f94f42069049b65920dfc95491a074cfd3617b8f))
10
+ * make the Codex engine and updates work on Windows ([f21cb9d](https://github.com/tonygorb/Scenri/commit/f21cb9d513f291bfc64585f9f3a3f67ea5738bde))
11
+
12
+
13
+ ### Performance Improvements
14
+
15
+ * cut the e2e wall clock roughly in half ([2cacbce](https://github.com/tonygorb/Scenri/commit/2cacbced34b6c58541c0b7942cd107aaa234f477))
16
+
3
17
  ## [0.3.4](https://github.com/tonygorb/Scenri/compare/v0.3.3...v0.3.4) (2026-08-20)
4
18
 
5
19
 
@@ -1,6 +1,6 @@
1
1
  import { stagingDir, versionsDir, isValidVersionDir, pruneStaged, entryOf } from './chunk-4MAFHYAD.js';
2
2
  import { spawnSync, spawn } from 'child_process';
3
- import { rmSync, mkdirSync, readFileSync, renameSync } from 'fs';
3
+ import { existsSync, rmSync, mkdirSync, readFileSync, renameSync } from 'fs';
4
4
  import { join, dirname } from 'path';
5
5
 
6
6
  // src/update/check.ts
@@ -97,6 +97,7 @@ function createUpdateChecker(deps) {
97
97
  }
98
98
  function findNpm(opts = {}) {
99
99
  const env = opts.env ?? process.env;
100
+ const platform = opts.platform ?? process.platform;
100
101
  const canRun = opts.canRun ?? ((argv) => {
101
102
  try {
102
103
  return spawnSync(argv[0], [...argv.slice(1), "--version"], { stdio: "ignore", timeout: 1e4 }).status === 0;
@@ -104,9 +105,26 @@ function findNpm(opts = {}) {
104
105
  return false;
105
106
  }
106
107
  });
107
- if (canRun(["npm"])) return ["npm"];
108
- const ep = env.npm_execpath;
108
+ if (platform !== "win32" && canRun(["npm"])) return ["npm"];
109
+ const ep = env.npm_execpath?.replace(/npx-cli\.js$/, "npm-cli.js");
109
110
  if (ep && /npm-cli\.js$/.test(ep) && canRun([process.execPath, ep])) return [process.execPath, ep];
111
+ if (platform === "win32") {
112
+ const cli = windowsNpmCli();
113
+ if (cli && canRun([process.execPath, cli])) return [process.execPath, cli];
114
+ }
115
+ return null;
116
+ }
117
+ function windowsNpmCli() {
118
+ try {
119
+ const out = spawnSync("where", ["npm"], { encoding: "utf8", timeout: 1e4 });
120
+ if (out.status !== 0 || !out.stdout) return null;
121
+ for (const line of out.stdout.split(/\r?\n/)) {
122
+ if (!/npm(\.cmd)?$/i.test(line.trim())) continue;
123
+ const cli = join(dirname(line.trim()), "node_modules", "npm", "bin", "npm-cli.js");
124
+ if (existsSync(cli)) return cli;
125
+ }
126
+ } catch {
127
+ }
110
128
  return null;
111
129
  }
112
130
  function run(argv) {
@@ -202,5 +220,5 @@ async function stageVersion(deps) {
202
220
  }
203
221
 
204
222
  export { classify, createUpdateChecker, fetchDistTagLatest, findNpm, stageVersion };
205
- //# sourceMappingURL=chunk-GA7P7K2M.js.map
206
- //# sourceMappingURL=chunk-GA7P7K2M.js.map
223
+ //# sourceMappingURL=chunk-3W2RHBZC.js.map
224
+ //# sourceMappingURL=chunk-3W2RHBZC.js.map
@@ -1,4 +1,4 @@
1
- import { stageVersion, fetchDistTagLatest, findNpm } from './chunk-GA7P7K2M.js';
1
+ import { stageVersion, fetchDistTagLatest, findNpm } from './chunk-3W2RHBZC.js';
2
2
  import { readMeta } from './chunk-Y3ZPBPLP.js';
3
3
  import { defaultHome, newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
4
4
 
@@ -43,7 +43,8 @@ async function runUpdateCommand(opts) {
43
43
  }
44
44
  if (!findNpm()) {
45
45
  console.error(" npm is not reachable from here, so nothing can be downloaded.");
46
- console.error(" Install Node.js with npm, or run: npx scenri@latest");
46
+ console.error(" Run the newest version directly with: npx scenri@latest");
47
+ console.error(" (or install Node.js with npm and try again)");
47
48
  return 1;
48
49
  }
49
50
  console.log(` downloading ${meta.name} ${latest}\u2026`);
@@ -62,5 +63,5 @@ async function runUpdateCommand(opts) {
62
63
  }
63
64
 
64
65
  export { runUpdateCommand };
65
- //# sourceMappingURL=cli-GQLRYYGU.js.map
66
- //# sourceMappingURL=cli-GQLRYYGU.js.map
66
+ //# sourceMappingURL=cli-HF5KPURA.js.map
67
+ //# sourceMappingURL=cli-HF5KPURA.js.map
package/dist/index.js CHANGED
@@ -64,7 +64,7 @@ try {
64
64
  await (await import('./serve.js')).serve();
65
65
  break;
66
66
  case "update": {
67
- const { runUpdateCommand } = await import('./cli-GQLRYYGU.js');
67
+ const { runUpdateCommand } = await import('./cli-HF5KPURA.js');
68
68
  process.exit(await runUpdateCommand(command));
69
69
  break;
70
70
  }
package/dist/serve.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { portBusyLines } from './chunk-WGIZJXNE.js';
2
- import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-GA7P7K2M.js';
2
+ import { createUpdateChecker, classify, stageVersion, findNpm } from './chunk-3W2RHBZC.js';
3
3
  import { readMeta, repoSlug } from './chunk-Y3ZPBPLP.js';
4
4
  import { newestStaged, compareSemver } from './chunk-4MAFHYAD.js';
5
5
  import { networkInterfaces, homedir, tmpdir } from 'os';
@@ -1857,11 +1857,17 @@ function execArgs(dir, promptText, effort = "low") {
1857
1857
  function createRunner(opts = {}) {
1858
1858
  const spawnImpl = opts.spawnImpl ?? spawn;
1859
1859
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
1860
+ const platform = opts.platform ?? process.platform;
1861
+ const winArg = (a) => `"${a.replace(/[\r\n]+/g, " ").replace(/"/g, "'").replace(/%/g, " percent ")}"`;
1862
+ const spawnCodex = (args) => platform === "win32" ? spawnImpl(["codex", ...args].map(winArg).join(" "), [], {
1863
+ stdio: ["ignore", "pipe", "pipe"],
1864
+ shell: true
1865
+ }) : spawnImpl("codex", args, { stdio: ["ignore", "pipe", "pipe"] });
1860
1866
  function run2(args, signal) {
1861
1867
  return new Promise((resolve, reject) => {
1862
1868
  let child;
1863
1869
  try {
1864
- child = spawnImpl("codex", args, { stdio: ["ignore", "pipe", "pipe"] });
1870
+ child = spawnCodex(args);
1865
1871
  } catch (err) {
1866
1872
  reject(new Error(`Failed to spawn codex: ${err.message}`));
1867
1873
  return;
@@ -1930,7 +1936,7 @@ function createRunner(opts = {}) {
1930
1936
  };
1931
1937
  let child;
1932
1938
  try {
1933
- child = spawnImpl("codex", args, { stdio: ["ignore", "pipe", "pipe"] });
1939
+ child = spawnCodex(args);
1934
1940
  } catch {
1935
1941
  done(false);
1936
1942
  return;
@@ -2108,6 +2114,7 @@ function stateFrom(avail) {
2108
2114
  }
2109
2115
  function createCodexSetup(opts = {}) {
2110
2116
  const spawnImpl = opts.spawnImpl ?? spawn;
2117
+ const platform = opts.platform ?? process.platform;
2111
2118
  const runner = createRunner(opts);
2112
2119
  const installTimeoutMs = opts.installTimeoutMs ?? DEFAULT_INSTALL_TIMEOUT_MS;
2113
2120
  function run2(cmd, args, timeoutMs) {
@@ -2126,7 +2133,7 @@ function createCodexSetup(opts = {}) {
2126
2133
  done({ code: null, stderr, spawnError: `${cmd} timed out after ${timeoutMs}ms` });
2127
2134
  }, timeoutMs);
2128
2135
  try {
2129
- child = spawnImpl(cmd, args, { stdio: ["ignore", "pipe", "pipe"], shell: process.platform === "win32" });
2136
+ child = spawnImpl(cmd, args, { stdio: ["ignore", "pipe", "pipe"], shell: platform === "win32" });
2130
2137
  } catch (err) {
2131
2138
  done({ code: null, stderr, spawnError: err.message });
2132
2139
  return;
@@ -2159,7 +2166,7 @@ function createCodexSetup(opts = {}) {
2159
2166
  }
2160
2167
  return { ok: true };
2161
2168
  }
2162
- if (process.platform !== "win32" && /EACCES|permission denied/i.test(res.stderr)) {
2169
+ if (platform !== "win32" && /EACCES|permission denied/i.test(res.stderr)) {
2163
2170
  return {
2164
2171
  ok: false,
2165
2172
  fallbackCommand: INSTALL_COMMAND_SUDO,
@@ -6538,6 +6545,16 @@ function registerImageRoutes(app, deps) {
6538
6545
 
6539
6546
  // src/release/notes.data.ts
6540
6547
  var RELEASES = [
6548
+ {
6549
+ version: "0.3.5",
6550
+ date: "2026-08-21",
6551
+ sections: [
6552
+ {
6553
+ heading: "Fixes",
6554
+ body: "Setting up the Codex engine on Windows no longer reports a successful install as missing, and updates can now find npm there. When npm truly is unreachable, the update command points to the one-line recovery instead of a dead end."
6555
+ }
6556
+ ]
6557
+ },
6541
6558
  {
6542
6559
  version: "0.3.4",
6543
6560
  date: "2026-08-21",
@@ -6895,7 +6912,7 @@ function registerSystemRoutes(app, deps) {
6895
6912
  }
6896
6913
  core.close();
6897
6914
  for (const name of ["scenri.db", "scenri.db-wal", "scenri.db-shm", "images", "backups"]) {
6898
- rmSync(join(core.home, name), { recursive: true, force: true });
6915
+ rmSync(join(core.home, name), { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
6899
6916
  }
6900
6917
  return { ok: true, scope };
6901
6918
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scenri",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "author": "Tony Gorb <hello@scenri.co>",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",