scenri 0.18.0 → 0.18.1

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,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.1](https://github.com/tonygorb/Scenri/compare/v0.18.0...v0.18.1) (2026-09-26)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **codex:** call the image tool once and copy the file its result names ([4244a20](https://github.com/tonygorb/Scenri/commit/4244a200d1b2637dab386c18741549910dbb7c0e))
9
+ * **codex:** leave the machine's own MCP servers out of every exec ([c59e31c](https://github.com/tonygorb/Scenri/commit/c59e31cdccd9b8a3feb3d5e31f9839dfa77cc85f))
10
+ * **codex:** run every exec on gpt-6-sol and never print the picture ([0aade5e](https://github.com/tonygorb/Scenri/commit/0aade5e40cd8ab35079be07e5834f4978a27e34a))
11
+ * keep host actions on the computer running Scenri, and cut Codex cost ([6f3f262](https://github.com/tonygorb/Scenri/commit/6f3f2622f71eb81b57cecf7e016c2c64d5b94fa0))
12
+ * keep host actions on the computer running Scenri, and cut Codex cost ([#255](https://github.com/tonygorb/Scenri/issues/255)) ([6f3f262](https://github.com/tonygorb/Scenri/commit/6f3f2622f71eb81b57cecf7e016c2c64d5b94fa0))
13
+ * **security:** forbid framing and type sniffing on every answer ([9bccee7](https://github.com/tonygorb/Scenri/commit/9bccee7617902303c0ebf965ba5e5a43881e9543))
14
+ * **security:** keep backups and desktop logs to their owner ([bf5a54b](https://github.com/tonygorb/Scenri/commit/bf5a54b312e76acdd1590520d74c269dd1b277cd))
15
+ * **security:** keep host actions, paths and secrets on this computer ([349e82f](https://github.com/tonygorb/Scenri/commit/349e82f38b38da96cdcc8f99acba49d3383e106c))
16
+ * **security:** look up store names when the crawl is handed the real fetch ([ab62872](https://github.com/tonygorb/Scenri/commit/ab62872e549591df73a1d3aeaee67d3e925e93f4))
17
+ * **security:** never tell a phone where the desktop icon lives ([328df67](https://github.com/tonygorb/Scenri/commit/328df676234643e3ef6d6aaeebdd860330c4e511))
18
+ * **security:** only the computer running Scenri can change a spend cap ([e248269](https://github.com/tonygorb/Scenri/commit/e24826920040ae4a238fc884da72b34654ab3350))
19
+ * **security:** only the computer running Scenri can install an update or restart into one ([f9bdf02](https://github.com/tonygorb/Scenri/commit/f9bdf02243f122ac6f794cb3c79b16a96f594565))
20
+ * **security:** only the computer running Scenri can shut it down ([e22085f](https://github.com/tonygorb/Scenri/commit/e22085f5b15347d8614376054dfa5807017b9b02))
21
+ * **security:** only the studio can make Codex status spend a turn ([ba3be74](https://github.com/tonygorb/Scenri/commit/ba3be7402602f58f3d7b6797db5e5edb62030758))
22
+ * **security:** read an IPv6 address whole before deciding it is public ([305ce11](https://github.com/tonygorb/Scenri/commit/305ce116ba889c3fb7fa3344d9965c47a4f48dd6))
23
+ * **security:** take provider keys only from the computer running Scenri ([883545d](https://github.com/tonygorb/Scenri/commit/883545dbfc25e1dc97c2ab3e85daa6df343409c5))
24
+ * **server:** bound the library download to its last byte, not its headers ([707c3ae](https://github.com/tonygorb/Scenri/commit/707c3aecaacba0c8c0071e1d742a9af0894ba265))
25
+ * **studio:** a phone is not offered Shut down, Update or a cap to change ([82b4bb1](https://github.com/tonygorb/Scenri/commit/82b4bb1040d22504c357726a7de209691bcee3bf))
26
+
3
27
  ## [0.18.0](https://github.com/tonygorb/Scenri/compare/v0.17.2...v0.18.0) (2026-09-25)
4
28
 
5
29
 
@@ -2,7 +2,7 @@ import { homedir } from 'os';
2
2
  import { join } from 'path';
3
3
  import Database from 'better-sqlite3';
4
4
  import { randomUUID, createHash } from 'crypto';
5
- import { mkdirSync, existsSync, chmodSync, rmSync, readFileSync, writeFileSync, readdirSync } from 'fs';
5
+ import { mkdirSync, existsSync, chmodSync, rmSync, readFileSync, statSync, writeFileSync, renameSync, readdirSync } from 'fs';
6
6
 
7
7
  // ../core/src/index.ts
8
8
 
@@ -492,12 +492,21 @@ var SchemaTooNewError = class extends Error {
492
492
  };
493
493
  function backupBeforeMigration(db, homeDir, fromVersion) {
494
494
  const dir = join(homeDir, "backups");
495
- mkdirSync(dir, { recursive: true });
495
+ mkdirSync(dir, { recursive: true, mode: 448 });
496
+ try {
497
+ chmodSync(dir, 448);
498
+ } catch {
499
+ }
496
500
  const d = /* @__PURE__ */ new Date();
497
501
  const p = (n) => String(n).padStart(2, "0");
498
502
  const stamp = `${d.getFullYear()}${p(d.getMonth() + 1)}${p(d.getDate())}-${p(d.getHours())}${p(d.getMinutes())}${p(d.getSeconds())}`;
499
503
  db.pragma("wal_checkpoint(TRUNCATE)");
500
- db.prepare("VACUUM INTO ?").run(join(dir, `scenri-v${fromVersion}-${stamp}.db`));
504
+ const snapshot = join(dir, `scenri-v${fromVersion}-${stamp}.db`);
505
+ db.prepare("VACUUM INTO ?").run(snapshot);
506
+ try {
507
+ chmodSync(snapshot, 384);
508
+ } catch {
509
+ }
501
510
  const old = readdirSync(dir).filter((f) => /^scenri-v\d+-\d{8}-\d{6}\.db$/.test(f)).sort((a, b) => a.slice(-18).localeCompare(b.slice(-18)));
502
511
  for (const f of old.slice(0, Math.max(0, old.length - 3))) rmSync(join(dir, f));
503
512
  }
@@ -583,7 +592,15 @@ function createImageStore(homeDir) {
583
592
  const clean = /^[a-z0-9]{2,5}$/i.test(ext) ? ext.toLowerCase() : "png";
584
593
  const hash = createHash("sha256").update(buf).digest("hex").slice(0, 32);
585
594
  const file = fileFor(hash, clean);
586
- if (!existsSync(file)) writeFileSync(file, buf);
595
+ if (!existsSync(file) || statSync(file).size !== buf.length) {
596
+ const tmp = `${file}.${process.pid}.tmp`;
597
+ try {
598
+ writeFileSync(tmp, buf);
599
+ renameSync(tmp, file);
600
+ } finally {
601
+ rmSync(tmp, { force: true });
602
+ }
603
+ }
587
604
  return hash;
588
605
  },
589
606
  pathFor(hash) {
@@ -2257,5 +2274,5 @@ function createCore(homeDir = defaultHome()) {
2257
2274
  }
2258
2275
 
2259
2276
  export { ASPECT_TOLERANCE, BUDGET_EXHAUSTED, EDIT_REFERENCE_ROLE_DIRECTIVE, REFERENCE_ROLE_DIRECTIVE, SCHEMA_VERSION, STEM_MIN, SchemaTooNewError, SpendCapError, TRIGRAM_MIN, budgetSize, createCatalogStore, createCore, createStore, defaultHome, fold, ftsMatch, matchesQuery, nameMatches, ratioLabel, searchTerms, shortTermSql, termMatches, uniqueProjectSlug, uniqueSetSlug, uniqueSlug };
2260
- //# sourceMappingURL=chunk-HI7CG4TK.js.map
2261
- //# sourceMappingURL=chunk-HI7CG4TK.js.map
2277
+ //# sourceMappingURL=chunk-VQPHG2GQ.js.map
2278
+ //# sourceMappingURL=chunk-VQPHG2GQ.js.map
@@ -5,7 +5,7 @@ import { defaultHome, newestStaged, listStaged, compareSemver, entryOf } from '.
5
5
  import { removeDesktop, failureDetail, installDesktop, POWERSHELL_ARGS } from './chunk-3BGDI4HI.js';
6
6
  import { launcherDir, logsDir, powershellPath } from './chunk-2IGINCPU.js';
7
7
  import { execFile, spawn } from 'child_process';
8
- import { closeSync, existsSync, readFileSync, writeFileSync, mkdirSync, openSync, rmSync, statSync, renameSync, appendFileSync } from 'fs';
8
+ import { closeSync, existsSync, readFileSync, writeFileSync, mkdirSync, openSync, rmSync, chmodSync, statSync, renameSync, appendFileSync } from 'fs';
9
9
  import { homedir } from 'os';
10
10
  import { join, dirname, delimiter, win32 } from 'path';
11
11
  import { createServer } from 'http';
@@ -144,17 +144,28 @@ function rotate(path, maxBytes) {
144
144
  }
145
145
  function appendLog(path, line, opts = {}) {
146
146
  try {
147
- mkdirSync(dirname(path), { recursive: true });
147
+ mkdirSync(dirname(path), { recursive: true, mode: 448 });
148
+ ownerOnly(dirname(path), 448);
148
149
  rotate(path, opts.maxBytes ?? DEFAULT_MAX);
149
150
  appendFileSync(path, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
150
- `);
151
+ `, { mode: 384 });
152
+ ownerOnly(path, 384);
151
153
  } catch {
152
154
  }
153
155
  }
154
156
  function openLogFd(path, opts = {}) {
155
- mkdirSync(dirname(path), { recursive: true });
157
+ mkdirSync(dirname(path), { recursive: true, mode: 448 });
158
+ ownerOnly(dirname(path), 448);
156
159
  rotate(path, opts.maxBytes ?? 5 * DEFAULT_MAX);
157
- return openSync(path, "a");
160
+ const fd = openSync(path, "a", 384);
161
+ ownerOnly(path, 384);
162
+ return fd;
163
+ }
164
+ function ownerOnly(path, mode) {
165
+ try {
166
+ chmodSync(path, mode);
167
+ } catch {
168
+ }
158
169
  }
159
170
  var LOCK_FRESH_MS = 6e4;
160
171
  var READY_TIMEOUT_MS = 18e4;
@@ -463,7 +474,7 @@ async function addOrRepair(ownEntry, say, over) {
463
474
  }
464
475
  async function rememberDecline(home) {
465
476
  try {
466
- const { createCore } = await import('./src-VQCTLFGX.js');
477
+ const { createCore } = await import('./src-CHSXV3ZA.js');
467
478
  const core = createCore(home);
468
479
  try {
469
480
  core.store.setSetting("desktop.prompt", "declined");
@@ -530,5 +541,5 @@ function tail(path, bytes = 4096) {
530
541
  }
531
542
 
532
543
  export { addToDesktop, assetsDirFor, installDeps, runDesktopCommand, runExecFile, runOpenCommand };
533
- //# sourceMappingURL=cli-Y5X5XXFA.js.map
534
- //# sourceMappingURL=cli-Y5X5XXFA.js.map
544
+ //# sourceMappingURL=cli-HHU7DUWE.js.map
545
+ //# sourceMappingURL=cli-HHU7DUWE.js.map
package/dist/index.js CHANGED
@@ -86,12 +86,12 @@ try {
86
86
  break;
87
87
  }
88
88
  case "desktop": {
89
- const { runDesktopCommand } = await import('./cli-Y5X5XXFA.js');
89
+ const { runDesktopCommand } = await import('./cli-HHU7DUWE.js');
90
90
  process.exit(await runDesktopCommand(command, fileURLToPath(import.meta.url)));
91
91
  break;
92
92
  }
93
93
  case "open": {
94
- const { runOpenCommand } = await import('./cli-Y5X5XXFA.js');
94
+ const { runOpenCommand } = await import('./cli-HHU7DUWE.js');
95
95
  process.exit(await runOpenCommand(fileURLToPath(import.meta.url)));
96
96
  break;
97
97
  }