orionfold-relay 0.15.4 → 0.16.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.
package/dist/cli.js CHANGED
@@ -27,11 +27,11 @@ var __copyProps = (to, from, except, desc16) => {
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
29
  // src/lib/utils/app-root.ts
30
- import { existsSync as existsSync2, readFileSync } from "fs";
31
- import { join as join2, dirname as dirname2 } from "path";
30
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
31
+ import { join as join3, dirname as dirname2 } from "path";
32
32
  function getAppRoot(metaDirname, depth) {
33
33
  if (metaDirname) {
34
- const candidate = join2(metaDirname, ...Array(depth).fill(".."));
34
+ const candidate = join3(metaDirname, ...Array(depth).fill(".."));
35
35
  if (isPackageRoot(candidate)) return candidate;
36
36
  let dir = metaDirname;
37
37
  while (true) {
@@ -44,10 +44,10 @@ function getAppRoot(metaDirname, depth) {
44
44
  return process.cwd();
45
45
  }
46
46
  function isPackageRoot(dir) {
47
- const pkgPath = join2(dir, "package.json");
48
- if (!existsSync2(pkgPath)) return false;
47
+ const pkgPath = join3(dir, "package.json");
48
+ if (!existsSync3(pkgPath)) return false;
49
49
  try {
50
- const pkg2 = JSON.parse(readFileSync(pkgPath, "utf-8"));
50
+ const pkg2 = JSON.parse(readFileSync2(pkgPath, "utf-8"));
51
51
  return pkg2.name === PKG_NAME;
52
52
  } catch {
53
53
  return false;
@@ -63,17 +63,17 @@ var init_app_root = __esm({
63
63
 
64
64
  // src/lib/config/env.ts
65
65
  import { homedir } from "os";
66
- import { join as join3, resolve } from "path";
66
+ import { join as join4, resolve } from "path";
67
67
  function dataDir() {
68
- return process.env.RELAY_DATA_DIR || join3(homedir(), DEFAULT_DATA_DIR_NAME);
68
+ return process.env.RELAY_DATA_DIR || join4(homedir(), DEFAULT_DATA_DIR_NAME);
69
69
  }
70
70
  function dbPath() {
71
- return join3(dataDir(), DB_FILENAME);
71
+ return join4(dataDir(), DB_FILENAME);
72
72
  }
73
73
  function isPrivateDataDir() {
74
74
  const override = process.env.RELAY_DATA_DIR;
75
75
  if (!override) return false;
76
- return resolve(override) !== resolve(join3(homedir(), DEFAULT_DATA_DIR_NAME));
76
+ return resolve(override) !== resolve(join4(homedir(), DEFAULT_DATA_DIR_NAME));
77
77
  }
78
78
  function launchCwd() {
79
79
  return process.env.RELAY_LAUNCH_CWD || process.cwd();
@@ -125,7 +125,7 @@ __export(ainative_paths_exports, {
125
125
  getAinativeSnapshotsDir: () => getAinativeSnapshotsDir,
126
126
  getAinativeUploadsDir: () => getAinativeUploadsDir
127
127
  });
128
- import { join as join4 } from "path";
128
+ import { join as join5 } from "path";
129
129
  function getAinativeDataDir() {
130
130
  return dataDir();
131
131
  }
@@ -133,55 +133,55 @@ function getAinativeDbPath() {
133
133
  return dbPath();
134
134
  }
135
135
  function getAinativeUploadsDir() {
136
- return join4(getAinativeDataDir(), "uploads");
136
+ return join5(getAinativeDataDir(), "uploads");
137
137
  }
138
138
  function getAinativeBlueprintsDir() {
139
- return join4(getAinativeDataDir(), "blueprints");
139
+ return join5(getAinativeDataDir(), "blueprints");
140
140
  }
141
141
  function getAinativeScreenshotsDir() {
142
- return join4(getAinativeDataDir(), "screenshots");
142
+ return join5(getAinativeDataDir(), "screenshots");
143
143
  }
144
144
  function getAinativeSnapshotsDir() {
145
- return join4(getAinativeDataDir(), "snapshots");
145
+ return join5(getAinativeDataDir(), "snapshots");
146
146
  }
147
147
  function getAinativeOutputsDir() {
148
- return join4(getAinativeDataDir(), "outputs");
148
+ return join5(getAinativeDataDir(), "outputs");
149
149
  }
150
150
  function getAinativeSessionsDir() {
151
- return join4(getAinativeDataDir(), "sessions");
151
+ return join5(getAinativeDataDir(), "sessions");
152
152
  }
153
153
  function getAinativeLogsDir() {
154
- return join4(getAinativeDataDir(), "logs");
154
+ return join5(getAinativeDataDir(), "logs");
155
155
  }
156
156
  function getAinativeDocumentsDir() {
157
- return join4(getAinativeDataDir(), "documents");
157
+ return join5(getAinativeDataDir(), "documents");
158
158
  }
159
159
  function getAinativeCodexDir() {
160
- return join4(getAinativeDataDir(), "codex");
160
+ return join5(getAinativeDataDir(), "codex");
161
161
  }
162
162
  function getAinativeCodexConfigPath() {
163
- return join4(getAinativeCodexDir(), "config.toml");
163
+ return join5(getAinativeCodexDir(), "config.toml");
164
164
  }
165
165
  function getAinativeCodexAuthPath() {
166
- return join4(getAinativeCodexDir(), "auth.json");
166
+ return join5(getAinativeCodexDir(), "auth.json");
167
167
  }
168
168
  function getAinativeProfilesDir() {
169
- return join4(getAinativeDataDir(), "profiles");
169
+ return join5(getAinativeDataDir(), "profiles");
170
170
  }
171
171
  function getAinativePluginsDir() {
172
- return join4(getAinativeDataDir(), "plugins");
172
+ return join5(getAinativeDataDir(), "plugins");
173
173
  }
174
174
  function getAinativeAppsDir() {
175
- return join4(getAinativeDataDir(), "apps");
175
+ return join5(getAinativeDataDir(), "apps");
176
176
  }
177
177
  function getAinativePluginsLockPath() {
178
- return join4(getAinativeDataDir(), "plugins.lock");
178
+ return join5(getAinativeDataDir(), "plugins.lock");
179
179
  }
180
180
  function getAinativeSchedulesDir() {
181
- return join4(getAinativeDataDir(), "schedules");
181
+ return join5(getAinativeDataDir(), "schedules");
182
182
  }
183
183
  function getAinativePluginExamplesDir() {
184
- return join4(
184
+ return join5(
185
185
  getAppRoot(import.meta.dirname, 3),
186
186
  "src",
187
187
  "lib",
@@ -1155,12 +1155,12 @@ var init_bootstrap = __esm({
1155
1155
  });
1156
1156
 
1157
1157
  // src/lib/instance/detect.ts
1158
- import { existsSync as existsSync4 } from "fs";
1159
- import { join as join6 } from "path";
1158
+ import { existsSync as existsSync5 } from "fs";
1159
+ import { join as join7 } from "path";
1160
1160
  function isDevMode(cwd = process.cwd()) {
1161
1161
  if (isInstanceModeEnv()) return false;
1162
1162
  if (isDevModeEnv()) return true;
1163
- if (existsSync4(join6(cwd, ".git", "relay-dev-mode"))) return true;
1163
+ if (existsSync5(join7(cwd, ".git", "relay-dev-mode"))) return true;
1164
1164
  return false;
1165
1165
  }
1166
1166
  function isPrivateInstance() {
@@ -1221,25 +1221,25 @@ var init_types = __esm({
1221
1221
  });
1222
1222
 
1223
1223
  // src/lib/environment/parsers/utils.ts
1224
- import { createHash } from "crypto";
1225
- import { readFileSync as readFileSync3, statSync } from "fs";
1224
+ import { createHash as createHash2 } from "crypto";
1225
+ import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
1226
1226
  function computeHash(content) {
1227
1227
  const truncated = content.slice(0, MAX_HASH_BYTES);
1228
- return createHash("sha256").update(truncated).digest("hex");
1228
+ return createHash2("sha256").update(truncated).digest("hex");
1229
1229
  }
1230
1230
  function safePreview(content) {
1231
1231
  return content.slice(0, MAX_PREVIEW_CHARS).trim();
1232
1232
  }
1233
1233
  function safeStat(path19) {
1234
1234
  try {
1235
- return statSync(path19);
1235
+ return statSync2(path19);
1236
1236
  } catch {
1237
1237
  return null;
1238
1238
  }
1239
1239
  }
1240
1240
  function safeReadFile(path19) {
1241
1241
  try {
1242
- return readFileSync3(path19, "utf-8");
1242
+ return readFileSync4(path19, "utf-8");
1243
1243
  } catch {
1244
1244
  return null;
1245
1245
  }
@@ -1344,7 +1344,7 @@ __export(wrap_exports, {
1344
1344
  import fs from "fs";
1345
1345
  import path from "path";
1346
1346
  import { execFileSync } from "child_process";
1347
- import { fileURLToPath } from "url";
1347
+ import { fileURLToPath as fileURLToPath2 } from "url";
1348
1348
  function logToFile(line) {
1349
1349
  try {
1350
1350
  const logsDir = getAinativeLogsDir();
@@ -1357,9 +1357,9 @@ function logToFile(line) {
1357
1357
  } catch {
1358
1358
  }
1359
1359
  }
1360
- function profilePath(relative) {
1361
- const moduleDir = path.dirname(fileURLToPath(import.meta.url));
1362
- return path.join(moduleDir, "profiles", relative);
1360
+ function profilePath(relative2) {
1361
+ const moduleDir = path.dirname(fileURLToPath2(import.meta.url));
1362
+ return path.join(moduleDir, "profiles", relative2);
1363
1363
  }
1364
1364
  function readSeatbeltProfile(cap, pluginId) {
1365
1365
  const p = profilePath(`seatbelt-${cap}.sb`);
@@ -3114,7 +3114,7 @@ __export(db_exports, {
3114
3114
  });
3115
3115
  import Database2 from "better-sqlite3";
3116
3116
  import { drizzle } from "drizzle-orm/better-sqlite3";
3117
- import { mkdirSync } from "fs";
3117
+ import { mkdirSync as mkdirSync2 } from "fs";
3118
3118
  var dataDir2, dbPath2, sqlite, db;
3119
3119
  var init_db = __esm({
3120
3120
  "src/lib/db/index.ts"() {
@@ -3123,7 +3123,7 @@ var init_db = __esm({
3123
3123
  init_env();
3124
3124
  init_bootstrap();
3125
3125
  dataDir2 = dataDir();
3126
- mkdirSync(dataDir2, { recursive: true });
3126
+ mkdirSync2(dataDir2, { recursive: true });
3127
3127
  dbPath2 = dbPath();
3128
3128
  sqlite = new Database2(dbPath2);
3129
3129
  sqlite.pragma("journal_mode = WAL");
@@ -3913,7 +3913,7 @@ __export(load_exports, {
3913
3913
  loadLicense: () => loadLicense
3914
3914
  });
3915
3915
  import fs4 from "fs";
3916
- import { fileURLToPath as fileURLToPath2 } from "url";
3916
+ import { fileURLToPath as fileURLToPath3 } from "url";
3917
3917
  function assertEnvelope(value, origin) {
3918
3918
  if (!value || typeof value !== "object") {
3919
3919
  throw new LicenseLoadError(`License at ${origin} is not a JSON object.`);
@@ -3957,7 +3957,7 @@ async function loadLicense(urlOrPath) {
3957
3957
  }
3958
3958
  return parse2(await res.text(), urlOrPath);
3959
3959
  }
3960
- const filePath = urlOrPath.startsWith("file://") ? fileURLToPath2(urlOrPath) : urlOrPath;
3960
+ const filePath = urlOrPath.startsWith("file://") ? fileURLToPath3(urlOrPath) : urlOrPath;
3961
3961
  let text2;
3962
3962
  try {
3963
3963
  text2 = fs4.readFileSync(filePath, "utf-8");
@@ -4227,7 +4227,7 @@ var init_query_builder = __esm({
4227
4227
  });
4228
4228
 
4229
4229
  // src/lib/data/row-hash.ts
4230
- import { createHash as createHash2 } from "crypto";
4230
+ import { createHash as createHash3 } from "crypto";
4231
4231
  function canonicalizeRowForHash(data, columnNames) {
4232
4232
  const canonical = {};
4233
4233
  for (const name of columnNames) {
@@ -4237,7 +4237,7 @@ function canonicalizeRowForHash(data, columnNames) {
4237
4237
  return JSON.stringify(canonical);
4238
4238
  }
4239
4239
  function hashRowData(data, columnNames) {
4240
- return createHash2("sha256").update(canonicalizeRowForHash(data, columnNames)).digest("hex");
4240
+ return createHash3("sha256").update(canonicalizeRowForHash(data, columnNames)).digest("hex");
4241
4241
  }
4242
4242
  var init_row_hash = __esm({
4243
4243
  "src/lib/data/row-hash.ts"() {
@@ -5763,24 +5763,24 @@ __export(crypto_exports, {
5763
5763
  getOrCreateKeyfile: () => getOrCreateKeyfile
5764
5764
  });
5765
5765
  import { randomBytes, createCipheriv, createDecipheriv } from "crypto";
5766
- import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, chmodSync } from "fs";
5767
- import { join as join7 } from "path";
5766
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, chmodSync } from "fs";
5767
+ import { join as join8 } from "path";
5768
5768
  function getKeyfilePath() {
5769
- return join7(dataDir(), ".keyfile");
5769
+ return join8(dataDir(), ".keyfile");
5770
5770
  }
5771
5771
  function getOrCreateKeyfile() {
5772
5772
  const keyfilePath = getKeyfilePath();
5773
- if (existsSync5(keyfilePath)) {
5774
- const key2 = readFileSync4(keyfilePath);
5773
+ if (existsSync6(keyfilePath)) {
5774
+ const key2 = readFileSync5(keyfilePath);
5775
5775
  if (key2.length !== KEY_LENGTH) {
5776
5776
  throw new Error(`Invalid keyfile: expected ${KEY_LENGTH} bytes, got ${key2.length}`);
5777
5777
  }
5778
5778
  return key2;
5779
5779
  }
5780
- const dir = join7(keyfilePath, "..");
5781
- mkdirSync2(dir, { recursive: true });
5780
+ const dir = join8(keyfilePath, "..");
5781
+ mkdirSync3(dir, { recursive: true });
5782
5782
  const key = randomBytes(KEY_LENGTH);
5783
- writeFileSync(keyfilePath, key, { mode: 384 });
5783
+ writeFileSync2(keyfilePath, key, { mode: 384 });
5784
5784
  chmodSync(keyfilePath, 384);
5785
5785
  return key;
5786
5786
  }
@@ -6737,18 +6737,18 @@ __export(workspace_context_exports, {
6737
6737
  getLaunchCwd: () => getLaunchCwd,
6738
6738
  getWorkspaceContext: () => getWorkspaceContext
6739
6739
  });
6740
- import { basename, dirname as dirname3 } from "path";
6740
+ import { basename as basename2, dirname as dirname3 } from "path";
6741
6741
  import { homedir as homedir4 } from "os";
6742
6742
  import { execFileSync as execFileSync2 } from "child_process";
6743
- import { statSync as statSync2 } from "fs";
6744
- import { join as join8 } from "path";
6743
+ import { statSync as statSync3 } from "fs";
6744
+ import { join as join9 } from "path";
6745
6745
  function getLaunchCwd() {
6746
6746
  return launchCwd();
6747
6747
  }
6748
6748
  function getWorkspaceContext() {
6749
6749
  const cwd = getLaunchCwd();
6750
6750
  const home = homedir4();
6751
- const folderName = basename(cwd);
6751
+ const folderName = basename2(cwd);
6752
6752
  const parent = dirname3(cwd);
6753
6753
  const parentPath = parent.startsWith(home) ? "~" + parent.slice(home.length) : parent;
6754
6754
  let gitBranch = null;
@@ -6762,8 +6762,8 @@ function getWorkspaceContext() {
6762
6762
  }
6763
6763
  let isWorktree = false;
6764
6764
  try {
6765
- const gitPath = join8(cwd, ".git");
6766
- const stat2 = statSync2(gitPath);
6765
+ const gitPath = join9(cwd, ".git");
6766
+ const stat2 = statSync3(gitPath);
6767
6767
  isWorktree = stat2.isFile();
6768
6768
  } catch {
6769
6769
  }
@@ -7045,12 +7045,12 @@ var init_browser_mcp = __esm({
7045
7045
 
7046
7046
  // src/lib/screenshots/persist.ts
7047
7047
  import { randomUUID as randomUUID3 } from "crypto";
7048
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, unlinkSync } from "fs";
7049
- import { join as join9 } from "path";
7048
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, unlinkSync } from "fs";
7049
+ import { join as join10 } from "path";
7050
7050
  async function persistScreenshot(base64Data, opts2) {
7051
7051
  const screenshotsDir = getAinativeScreenshotsDir();
7052
7052
  const id = randomUUID3();
7053
- const originalPath = join9(screenshotsDir, `${id}.png`);
7053
+ const originalPath = join10(screenshotsDir, `${id}.png`);
7054
7054
  let thumbnailPath = null;
7055
7055
  try {
7056
7056
  if (base64Data.length > MAX_BASE64_BYTES) {
@@ -7064,9 +7064,9 @@ async function persistScreenshot(base64Data, opts2) {
7064
7064
  const dimensions = imageSize(new Uint8Array(buffer));
7065
7065
  const width = dimensions.width ?? 0;
7066
7066
  const height = dimensions.height ?? 0;
7067
- mkdirSync3(screenshotsDir, { recursive: true });
7068
- writeFileSync2(originalPath, buffer);
7069
- thumbnailPath = join9(screenshotsDir, `${id}_thumb.png`);
7067
+ mkdirSync4(screenshotsDir, { recursive: true });
7068
+ writeFileSync3(originalPath, buffer);
7069
+ thumbnailPath = join10(screenshotsDir, `${id}_thumb.png`);
7070
7070
  try {
7071
7071
  const sharp = (await import("sharp")).default;
7072
7072
  await sharp(buffer).resize(THUMBNAIL_WIDTH, void 0, { withoutEnlargement: true }).png({ quality: 80 }).toFile(thumbnailPath);
@@ -7131,7 +7131,7 @@ var init_persist = __esm({
7131
7131
  });
7132
7132
 
7133
7133
  // src/lib/usage/pricing-registry.ts
7134
- import { createHash as createHash3 } from "crypto";
7134
+ import { createHash as createHash4 } from "crypto";
7135
7135
  function buildDefaultProviders() {
7136
7136
  const nowIso = "2026-03-17T00:00:00.000Z";
7137
7137
  return {
@@ -11297,7 +11297,7 @@ var init_schedule_tools = __esm({
11297
11297
  import { z as z13 } from "zod";
11298
11298
  import { eq as eq25, and as and14, desc as desc10 } from "drizzle-orm";
11299
11299
  import { access, stat, copyFile, mkdir } from "fs/promises";
11300
- import { basename as basename2, extname, join as join10 } from "path";
11300
+ import { basename as basename3, extname, join as join11 } from "path";
11301
11301
  import crypto4 from "crypto";
11302
11302
  function resolveMimeType(filename) {
11303
11303
  return MIME_TYPES[extname(filename).toLowerCase()] ?? "application/octet-stream";
@@ -11389,14 +11389,14 @@ function documentTools(ctx) {
11389
11389
  await access(args.file_path);
11390
11390
  const stats = await stat(args.file_path);
11391
11391
  if (!stats.isFile()) return err(`Not a file: ${args.file_path}`);
11392
- const originalName = basename2(args.file_path);
11392
+ const originalName = basename3(args.file_path);
11393
11393
  const mimeType = resolveMimeType(originalName);
11394
11394
  const id = crypto4.randomUUID();
11395
11395
  const ext = extname(originalName);
11396
11396
  const filename = `${id}${ext}`;
11397
11397
  const uploadsDir = getAinativeUploadsDir();
11398
11398
  await mkdir(uploadsDir, { recursive: true });
11399
- const storagePath = join10(uploadsDir, filename);
11399
+ const storagePath = join11(uploadsDir, filename);
11400
11400
  await copyFile(args.file_path, storagePath);
11401
11401
  const effectiveProjectId = args.projectId ?? ctx.projectId ?? null;
11402
11402
  const now = /* @__PURE__ */ new Date();
@@ -12863,8 +12863,8 @@ var list_fused_profiles_exports = {};
12863
12863
  __export(list_fused_profiles_exports, {
12864
12864
  listFusedProfiles: () => listFusedProfiles
12865
12865
  });
12866
- import { readdirSync, readFileSync as readFileSync5, statSync as statSync3, existsSync as existsSync6 } from "fs";
12867
- import { join as join11 } from "path";
12866
+ import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync4, existsSync as existsSync7 } from "fs";
12867
+ import { join as join12 } from "path";
12868
12868
  import { homedir as homedir5 } from "os";
12869
12869
  function parseFrontmatter2(content) {
12870
12870
  const match = content.match(/^---\n([\s\S]*?)\n---/);
@@ -12880,15 +12880,15 @@ function parseFrontmatter2(content) {
12880
12880
  return result;
12881
12881
  }
12882
12882
  function loadFilesystemSkills(skillsDir, origin, projectRootDir) {
12883
- if (!existsSync6(skillsDir)) return [];
12883
+ if (!existsSync7(skillsDir)) return [];
12884
12884
  const profiles = [];
12885
- for (const entry of readdirSync(skillsDir)) {
12886
- const skillPath = join11(skillsDir, entry);
12885
+ for (const entry of readdirSync2(skillsDir)) {
12886
+ const skillPath = join12(skillsDir, entry);
12887
12887
  try {
12888
- if (!statSync3(skillPath).isDirectory()) continue;
12889
- const skillMdPath = join11(skillPath, "SKILL.md");
12890
- if (!existsSync6(skillMdPath)) continue;
12891
- const content = readFileSync5(skillMdPath, "utf8");
12888
+ if (!statSync4(skillPath).isDirectory()) continue;
12889
+ const skillMdPath = join12(skillPath, "SKILL.md");
12890
+ if (!existsSync7(skillMdPath)) continue;
12891
+ const content = readFileSync6(skillMdPath, "utf8");
12892
12892
  const fm = parseFrontmatter2(content);
12893
12893
  if (!fm || !fm.name) {
12894
12894
  console.warn(
@@ -12921,14 +12921,14 @@ function loadFilesystemSkills(skillsDir, origin, projectRootDir) {
12921
12921
  }
12922
12922
  return profiles;
12923
12923
  }
12924
- async function listFusedProfiles(projectDir, userSkillsDir = join11(homedir5(), ".claude", "skills")) {
12924
+ async function listFusedProfiles(projectDir, userSkillsDir = join12(homedir5(), ".claude", "skills")) {
12925
12925
  const registry2 = listProfiles();
12926
12926
  const registryIds = new Set(registry2.map((p) => p.id));
12927
12927
  const userSkills = loadFilesystemSkills(userSkillsDir, "filesystem-user", void 0).filter(
12928
12928
  (p) => !registryIds.has(p.id)
12929
12929
  );
12930
12930
  const projectSkills = projectDir ? loadFilesystemSkills(
12931
- join11(projectDir, ".claude", "skills"),
12931
+ join12(projectDir, ".claude", "skills"),
12932
12932
  "filesystem-project",
12933
12933
  projectDir
12934
12934
  ).filter((p) => !registryIds.has(p.id) && !userSkills.some((u) => u.id === p.id)) : [];
@@ -15604,21 +15604,21 @@ var init_active_skills = __esm({
15604
15604
  });
15605
15605
 
15606
15606
  // src/lib/environment/parsers/skill.ts
15607
- import { readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
15608
- import { join as join12, basename as basename3 } from "path";
15607
+ import { readdirSync as readdirSync3, readFileSync as readFileSync7 } from "fs";
15608
+ import { join as join13, basename as basename4 } from "path";
15609
15609
  function parseSkillDir(dirPath, tool, scope, baseDir) {
15610
15610
  const stat2 = safeStat(dirPath);
15611
15611
  if (!stat2?.isDirectory()) return null;
15612
- const name = basename3(dirPath);
15612
+ const name = basename4(dirPath);
15613
15613
  if (name.startsWith(".")) return null;
15614
15614
  let mainFile = "";
15615
15615
  let content = "";
15616
15616
  try {
15617
- const files = readdirSync2(dirPath);
15617
+ const files = readdirSync3(dirPath);
15618
15618
  const skillFile = files.find((f) => f === "SKILL.md") || files.find((f) => f.endsWith(".md")) || files[0];
15619
15619
  if (skillFile) {
15620
- mainFile = join12(dirPath, skillFile);
15621
- content = readFileSync6(mainFile, "utf-8");
15620
+ mainFile = join13(dirPath, skillFile);
15621
+ content = readFileSync7(mainFile, "utf-8");
15622
15622
  }
15623
15623
  } catch {
15624
15624
  return null;
@@ -15664,8 +15664,8 @@ var init_skill = __esm({
15664
15664
  });
15665
15665
 
15666
15666
  // src/lib/environment/parsers/settings.ts
15667
- import { readdirSync as readdirSync3 } from "fs";
15668
- import { join as join13, basename as basename4 } from "path";
15667
+ import { readdirSync as readdirSync4 } from "fs";
15668
+ import { join as join14, basename as basename5 } from "path";
15669
15669
  function parseClaudeSettings(filePath, scope, baseDir) {
15670
15670
  const content = safeReadFile(filePath);
15671
15671
  if (!content) return [];
@@ -15679,7 +15679,7 @@ function parseClaudeSettings(filePath, scope, baseDir) {
15679
15679
  tool: "claude-code",
15680
15680
  category: "permission",
15681
15681
  scope,
15682
- name: `${basename4(filePath, ".json")}-allow`,
15682
+ name: `${basename5(filePath, ".json")}-allow`,
15683
15683
  relPath: filePath.replace(baseDir, "").replace(/^\//, ""),
15684
15684
  absPath: filePath,
15685
15685
  contentHash: computeHash(JSON.stringify(config.permissions.allow)),
@@ -15694,7 +15694,7 @@ function parseClaudeSettings(filePath, scope, baseDir) {
15694
15694
  tool: "claude-code",
15695
15695
  category: "permission",
15696
15696
  scope,
15697
- name: `${basename4(filePath, ".json")}-deny`,
15697
+ name: `${basename5(filePath, ".json")}-deny`,
15698
15698
  relPath: filePath.replace(baseDir, "").replace(/^\//, ""),
15699
15699
  absPath: filePath,
15700
15700
  contentHash: computeHash(JSON.stringify(config.permissions.deny)),
@@ -15768,8 +15768,8 @@ function parseOutputStyles(dirPath, tool, baseDir) {
15768
15768
  if (!stat2?.isDirectory()) return [];
15769
15769
  const artifacts = [];
15770
15770
  try {
15771
- for (const entry of readdirSync3(dirPath)) {
15772
- const fullPath = join13(dirPath, entry);
15771
+ for (const entry of readdirSync4(dirPath)) {
15772
+ const fullPath = join14(dirPath, entry);
15773
15773
  const content = safeReadFile(fullPath);
15774
15774
  if (!content) continue;
15775
15775
  const fStat = safeStat(fullPath);
@@ -15778,7 +15778,7 @@ function parseOutputStyles(dirPath, tool, baseDir) {
15778
15778
  tool,
15779
15779
  category: "output-style",
15780
15780
  scope: "user",
15781
- name: basename4(entry, ".md"),
15781
+ name: basename5(entry, ".md"),
15782
15782
  relPath: fullPath.replace(baseDir, "").replace(/^\//, ""),
15783
15783
  absPath: fullPath,
15784
15784
  contentHash: computeHash(content),
@@ -15846,18 +15846,18 @@ var init_instructions = __esm({
15846
15846
  });
15847
15847
 
15848
15848
  // src/lib/environment/scanners/claude-code.ts
15849
- import { readdirSync as readdirSync4, existsSync as existsSync7 } from "fs";
15850
- import { join as join14 } from "path";
15849
+ import { readdirSync as readdirSync5, existsSync as existsSync8 } from "fs";
15850
+ import { join as join15 } from "path";
15851
15851
  function scanUserLevel(userHome) {
15852
- const claudeDir = join14(userHome, ".claude");
15852
+ const claudeDir = join15(userHome, ".claude");
15853
15853
  const artifacts = [];
15854
15854
  const errors = [];
15855
- if (!existsSync7(claudeDir)) return { artifacts, errors };
15856
- const skillsDir = join14(claudeDir, "skills");
15857
- if (existsSync7(skillsDir)) {
15855
+ if (!existsSync8(claudeDir)) return { artifacts, errors };
15856
+ const skillsDir = join15(claudeDir, "skills");
15857
+ if (existsSync8(skillsDir)) {
15858
15858
  try {
15859
- for (const entry of readdirSync4(skillsDir)) {
15860
- const skillPath = join14(skillsDir, entry);
15859
+ for (const entry of readdirSync5(skillsDir)) {
15860
+ const skillPath = join15(skillsDir, entry);
15861
15861
  const artifact = parseSkillDir(skillPath, "claude-code", "user", userHome);
15862
15862
  if (artifact) artifacts.push(artifact);
15863
15863
  }
@@ -15865,32 +15865,32 @@ function scanUserLevel(userHome) {
15865
15865
  errors.push({ path: skillsDir, error: String(e) });
15866
15866
  }
15867
15867
  }
15868
- const mcpPath = join14(claudeDir, ".mcp.json");
15869
- if (existsSync7(mcpPath)) {
15868
+ const mcpPath = join15(claudeDir, ".mcp.json");
15869
+ if (existsSync8(mcpPath)) {
15870
15870
  artifacts.push(...parseClaudeMcpConfig(mcpPath, "user", userHome));
15871
15871
  }
15872
- const pluginsFile = join14(claudeDir, "plugins", "installed_plugins.json");
15873
- if (existsSync7(pluginsFile)) {
15872
+ const pluginsFile = join15(claudeDir, "plugins", "installed_plugins.json");
15873
+ if (existsSync8(pluginsFile)) {
15874
15874
  artifacts.push(...parseClaudePlugins(pluginsFile, userHome));
15875
15875
  }
15876
15876
  for (const settingsFile of ["settings.json", "settings.local.json"]) {
15877
- const settingsPath = join14(claudeDir, settingsFile);
15878
- if (existsSync7(settingsPath)) {
15877
+ const settingsPath = join15(claudeDir, settingsFile);
15878
+ if (existsSync8(settingsPath)) {
15879
15879
  artifacts.push(...parseClaudeSettings(settingsPath, "user", userHome));
15880
15880
  }
15881
15881
  }
15882
- const outputStylesDir = join14(claudeDir, "output-styles");
15883
- if (existsSync7(outputStylesDir)) {
15882
+ const outputStylesDir = join15(claudeDir, "output-styles");
15883
+ if (existsSync8(outputStylesDir)) {
15884
15884
  artifacts.push(...parseOutputStyles(outputStylesDir, "claude-code", userHome));
15885
15885
  }
15886
- const projectsDir = join14(claudeDir, "projects");
15887
- if (existsSync7(projectsDir)) {
15886
+ const projectsDir = join15(claudeDir, "projects");
15887
+ if (existsSync8(projectsDir)) {
15888
15888
  try {
15889
- for (const projEntry of readdirSync4(projectsDir)) {
15890
- const memoryDir = join14(projectsDir, projEntry, "memory");
15891
- if (!existsSync7(memoryDir)) continue;
15892
- const memoryIndex = join14(memoryDir, "MEMORY.md");
15893
- if (existsSync7(memoryIndex)) {
15889
+ for (const projEntry of readdirSync5(projectsDir)) {
15890
+ const memoryDir = join15(projectsDir, projEntry, "memory");
15891
+ if (!existsSync8(memoryDir)) continue;
15892
+ const memoryIndex = join15(memoryDir, "MEMORY.md");
15893
+ if (existsSync8(memoryIndex)) {
15894
15894
  const artifact = parseInstructionFile(
15895
15895
  memoryIndex,
15896
15896
  "user",
@@ -15911,16 +15911,16 @@ function scanUserLevel(userHome) {
15911
15911
  return { artifacts, errors };
15912
15912
  }
15913
15913
  function scanProjectLevel(projectDir) {
15914
- const claudeDir = join14(projectDir, ".claude");
15914
+ const claudeDir = join15(projectDir, ".claude");
15915
15915
  const artifacts = [];
15916
15916
  const errors = [];
15917
15917
  artifacts.push(...scanInstructionFiles(projectDir, "project", projectDir));
15918
- if (!existsSync7(claudeDir)) return { artifacts, errors };
15919
- const skillsDir = join14(claudeDir, "skills");
15920
- if (existsSync7(skillsDir)) {
15918
+ if (!existsSync8(claudeDir)) return { artifacts, errors };
15919
+ const skillsDir = join15(claudeDir, "skills");
15920
+ if (existsSync8(skillsDir)) {
15921
15921
  try {
15922
- for (const entry of readdirSync4(skillsDir)) {
15923
- const skillPath = join14(skillsDir, entry);
15922
+ for (const entry of readdirSync5(skillsDir)) {
15923
+ const skillPath = join15(skillsDir, entry);
15924
15924
  const artifact = parseSkillDir(skillPath, "claude-code", "project", projectDir);
15925
15925
  if (artifact) artifacts.push(artifact);
15926
15926
  }
@@ -15928,21 +15928,21 @@ function scanProjectLevel(projectDir) {
15928
15928
  errors.push({ path: skillsDir, error: String(e) });
15929
15929
  }
15930
15930
  }
15931
- const mcpPath = join14(claudeDir, ".mcp.json");
15932
- if (existsSync7(mcpPath)) {
15931
+ const mcpPath = join15(claudeDir, ".mcp.json");
15932
+ if (existsSync8(mcpPath)) {
15933
15933
  artifacts.push(...parseClaudeMcpConfig(mcpPath, "project", projectDir));
15934
15934
  }
15935
15935
  for (const settingsFile of ["settings.json", "settings.local.json"]) {
15936
- const settingsPath = join14(claudeDir, settingsFile);
15937
- if (existsSync7(settingsPath)) {
15936
+ const settingsPath = join15(claudeDir, settingsFile);
15937
+ if (existsSync8(settingsPath)) {
15938
15938
  artifacts.push(...parseClaudeSettings(settingsPath, "project", projectDir));
15939
15939
  }
15940
15940
  }
15941
- const hooksDir = join14(claudeDir, "hooks");
15942
- if (existsSync7(hooksDir)) {
15941
+ const hooksDir = join15(claudeDir, "hooks");
15942
+ if (existsSync8(hooksDir)) {
15943
15943
  try {
15944
- for (const entry of readdirSync4(hooksDir)) {
15945
- const hookPath = join14(hooksDir, entry);
15944
+ for (const entry of readdirSync5(hooksDir)) {
15945
+ const hookPath = join15(hooksDir, entry);
15946
15946
  const content = safeReadFile(hookPath);
15947
15947
  if (!content) continue;
15948
15948
  const stat2 = safeStat(hookPath);
@@ -15987,18 +15987,18 @@ var init_claude_code = __esm({
15987
15987
  });
15988
15988
 
15989
15989
  // src/lib/environment/scanners/codex.ts
15990
- import { readdirSync as readdirSync5, existsSync as existsSync8 } from "fs";
15991
- import { join as join15 } from "path";
15990
+ import { readdirSync as readdirSync6, existsSync as existsSync9 } from "fs";
15991
+ import { join as join16 } from "path";
15992
15992
  function scanUserLevel2(userHome) {
15993
- const codexDir = join15(userHome, ".codex");
15993
+ const codexDir = join16(userHome, ".codex");
15994
15994
  const artifacts = [];
15995
15995
  const errors = [];
15996
- if (!existsSync8(codexDir)) return { artifacts, errors };
15997
- const skillsDir = join15(codexDir, "skills");
15998
- if (existsSync8(skillsDir)) {
15996
+ if (!existsSync9(codexDir)) return { artifacts, errors };
15997
+ const skillsDir = join16(codexDir, "skills");
15998
+ if (existsSync9(skillsDir)) {
15999
15999
  try {
16000
- for (const entry of readdirSync5(skillsDir)) {
16001
- const skillPath = join15(skillsDir, entry);
16000
+ for (const entry of readdirSync6(skillsDir)) {
16001
+ const skillPath = join16(skillsDir, entry);
16002
16002
  const artifact = parseSkillDir(skillPath, "codex", "user", userHome);
16003
16003
  if (artifact) artifacts.push(artifact);
16004
16004
  }
@@ -16006,16 +16006,16 @@ function scanUserLevel2(userHome) {
16006
16006
  errors.push({ path: skillsDir, error: String(e) });
16007
16007
  }
16008
16008
  }
16009
- const configPath = join15(codexDir, "config.toml");
16010
- if (existsSync8(configPath)) {
16009
+ const configPath = join16(codexDir, "config.toml");
16010
+ if (existsSync9(configPath)) {
16011
16011
  artifacts.push(...parseCodexSettings(configPath, userHome));
16012
16012
  artifacts.push(...parseCodexMcpConfig(configPath, userHome));
16013
16013
  }
16014
- const rulesDir = join15(codexDir, "rules");
16015
- if (existsSync8(rulesDir)) {
16014
+ const rulesDir = join16(codexDir, "rules");
16015
+ if (existsSync9(rulesDir)) {
16016
16016
  try {
16017
- for (const entry of readdirSync5(rulesDir)) {
16018
- const rulePath = join15(rulesDir, entry);
16017
+ for (const entry of readdirSync6(rulesDir)) {
16018
+ const rulePath = join16(rulesDir, entry);
16019
16019
  const content = safeReadFile(rulePath);
16020
16020
  if (!content) continue;
16021
16021
  const stat2 = safeStat(rulePath);
@@ -16038,11 +16038,11 @@ function scanUserLevel2(userHome) {
16038
16038
  errors.push({ path: rulesDir, error: String(e) });
16039
16039
  }
16040
16040
  }
16041
- const memoriesDir = join15(codexDir, "memories");
16042
- if (existsSync8(memoriesDir)) {
16041
+ const memoriesDir = join16(codexDir, "memories");
16042
+ if (existsSync9(memoriesDir)) {
16043
16043
  try {
16044
- for (const entry of readdirSync5(memoriesDir)) {
16045
- const memPath = join15(memoriesDir, entry);
16044
+ for (const entry of readdirSync6(memoriesDir)) {
16045
+ const memPath = join16(memoriesDir, entry);
16046
16046
  const content = safeReadFile(memPath);
16047
16047
  if (!content) continue;
16048
16048
  const stat2 = safeStat(memPath);
@@ -16070,8 +16070,8 @@ function scanUserLevel2(userHome) {
16070
16070
  function scanProjectLevel2(projectDir) {
16071
16071
  const artifacts = [];
16072
16072
  const errors = [];
16073
- const codexMd = join15(projectDir, "codex.md");
16074
- if (existsSync8(codexMd)) {
16073
+ const codexMd = join16(projectDir, "codex.md");
16074
+ if (existsSync9(codexMd)) {
16075
16075
  const artifact = parseInstructionFile(codexMd, "project", projectDir, "codex");
16076
16076
  if (artifact) artifacts.push(artifact);
16077
16077
  }
@@ -16097,13 +16097,13 @@ var init_codex = __esm({
16097
16097
  });
16098
16098
 
16099
16099
  // src/lib/environment/scanner.ts
16100
- import { existsSync as existsSync9 } from "fs";
16101
- import { join as join16 } from "path";
16100
+ import { existsSync as existsSync10 } from "fs";
16101
+ import { join as join17 } from "path";
16102
16102
  import { homedir as homedir6 } from "os";
16103
16103
  function detectPersonas(userHome, projectDir) {
16104
16104
  const personas = [];
16105
- const hasClaudeCode = existsSync9(join16(userHome, ".claude")) || existsSync9(join16(projectDir, ".claude"));
16106
- const hasCodex = existsSync9(join16(userHome, ".codex"));
16105
+ const hasClaudeCode = existsSync10(join17(userHome, ".claude")) || existsSync10(join17(projectDir, ".claude"));
16106
+ const hasCodex = existsSync10(join17(userHome, ".codex"));
16107
16107
  if (hasClaudeCode) personas.push("claude-code");
16108
16108
  if (hasCodex) personas.push("codex");
16109
16109
  return personas;
@@ -16254,8 +16254,8 @@ __export(list_skills_exports, {
16254
16254
  listSkills: () => listSkills,
16255
16255
  listSkillsEnriched: () => listSkillsEnriched
16256
16256
  });
16257
- import { readFileSync as readFileSync7, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
16258
- import { join as join17 } from "path";
16257
+ import { readFileSync as readFileSync8, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
16258
+ import { join as join18 } from "path";
16259
16259
  function listSkills(options = {}) {
16260
16260
  const projectDir = options.projectDir ?? getLaunchCwd();
16261
16261
  const scan = scanEnvironment({ projectDir });
@@ -16279,7 +16279,7 @@ function getSkill(id, options = {}) {
16279
16279
  const filePath = resolveSkillFile(hit.absPath);
16280
16280
  if (!filePath) return null;
16281
16281
  try {
16282
- const content = readFileSync7(filePath, "utf8");
16282
+ const content = readFileSync8(filePath, "utf8");
16283
16283
  return { ...hit, content };
16284
16284
  } catch {
16285
16285
  return null;
@@ -16287,7 +16287,7 @@ function getSkill(id, options = {}) {
16287
16287
  }
16288
16288
  function resolveSkillFile(dirPath) {
16289
16289
  try {
16290
- const stat2 = statSync4(dirPath);
16290
+ const stat2 = statSync5(dirPath);
16291
16291
  if (!stat2.isDirectory()) {
16292
16292
  return dirPath;
16293
16293
  }
@@ -16295,15 +16295,15 @@ function resolveSkillFile(dirPath) {
16295
16295
  return null;
16296
16296
  }
16297
16297
  for (const name of ["SKILL.md", "skill.md"]) {
16298
- const candidate = join17(dirPath, name);
16298
+ const candidate = join18(dirPath, name);
16299
16299
  try {
16300
- if (statSync4(candidate).isFile()) return candidate;
16300
+ if (statSync5(candidate).isFile()) return candidate;
16301
16301
  } catch {
16302
16302
  }
16303
16303
  }
16304
16304
  try {
16305
- const fallback = readdirSync6(dirPath).find((f) => f.toLowerCase().endsWith(".md"));
16306
- if (fallback) return join17(dirPath, fallback);
16305
+ const fallback = readdirSync7(dirPath).find((f) => f.toLowerCase().endsWith(".md"));
16306
+ if (fallback) return join18(dirPath, fallback);
16307
16307
  } catch {
16308
16308
  }
16309
16309
  return null;
@@ -18704,7 +18704,7 @@ __export(openai_auth_exports, {
18704
18704
  updateOpenAIAuthStatus: () => updateOpenAIAuthStatus,
18705
18705
  updateOpenAIOAuthStatus: () => updateOpenAIOAuthStatus
18706
18706
  });
18707
- import { existsSync as existsSync11 } from "fs";
18707
+ import { existsSync as existsSync12 } from "fs";
18708
18708
  function parseJson(raw) {
18709
18709
  if (!raw) return null;
18710
18710
  try {
@@ -18738,7 +18738,7 @@ async function getOpenAIAuthSettings() {
18738
18738
  } else {
18739
18739
  apiKeySource = "unknown";
18740
18740
  }
18741
- const oauthConnected = storedOauthConnected === "true" || storedOauthConnected == null && existsSync11(getAinativeCodexAuthPath());
18741
+ const oauthConnected = storedOauthConnected === "true" || storedOauthConnected == null && existsSync12(getAinativeCodexAuthPath());
18742
18742
  return {
18743
18743
  method,
18744
18744
  hasKey: hasDbKey || hasEnvKey,
@@ -18828,13 +18828,13 @@ __export(mcp_sync_exports, {
18828
18828
  preparePluginMcpCodexSync: () => preparePluginMcpCodexSync,
18829
18829
  syncPluginMcpToCodex: () => syncPluginMcpToCodex
18830
18830
  });
18831
- import { writeFileSync as writeFileSync4 } from "fs";
18832
- import { join as join19 } from "path";
18831
+ import { writeFileSync as writeFileSync5 } from "fs";
18832
+ import { join as join20 } from "path";
18833
18833
  import { homedir as homedir7 } from "os";
18834
18834
  function prepareMcpToClaude(artifact, scope, projectDir) {
18835
18835
  const metadata = artifact.metadata ? JSON.parse(artifact.metadata) : {};
18836
18836
  const serverName = artifact.name;
18837
- const targetPath = scope === "user" ? join19(homedir7(), ".claude", ".mcp.json") : join19(projectDir || getLaunchCwd(), ".claude", ".mcp.json");
18837
+ const targetPath = scope === "user" ? join20(homedir7(), ".claude", ".mcp.json") : join20(projectDir || getLaunchCwd(), ".claude", ".mcp.json");
18838
18838
  const existing = safeReadFile(targetPath);
18839
18839
  let config;
18840
18840
  try {
@@ -18859,7 +18859,7 @@ function prepareMcpToClaude(artifact, scope, projectDir) {
18859
18859
  function prepareMcpToCodex(artifact) {
18860
18860
  const metadata = artifact.metadata ? JSON.parse(artifact.metadata) : {};
18861
18861
  const serverName = artifact.name;
18862
- const targetPath = join19(homedir7(), ".codex", "config.toml");
18862
+ const targetPath = join20(homedir7(), ".codex", "config.toml");
18863
18863
  const existing = safeReadFile(targetPath) || "";
18864
18864
  const lines = [];
18865
18865
  lines.push(`[mcp_servers.${serverName}]`);
@@ -18894,7 +18894,7 @@ function prepareMcpSync(artifact, targetTool, scope, projectDir) {
18894
18894
  return prepareMcpToCodex(artifact);
18895
18895
  }
18896
18896
  function preparePluginMcpCodexSync(registrations, targetPath) {
18897
- const resolvedPath = targetPath ?? join19(homedir7(), ".codex", "config.toml");
18897
+ const resolvedPath = targetPath ?? join20(homedir7(), ".codex", "config.toml");
18898
18898
  const existing = safeReadFile(resolvedPath) || "";
18899
18899
  const pluginKeys = new Set(
18900
18900
  registrations.map((r) => `${r.pluginId}-${r.serverName}`)
@@ -18959,7 +18959,7 @@ async function syncPluginMcpToCodex() {
18959
18959
  const { listPluginMcpRegistrations: listPluginMcpRegistrations2 } = await Promise.resolve().then(() => (init_mcp_loader(), mcp_loader_exports));
18960
18960
  const registrations = await listPluginMcpRegistrations2();
18961
18961
  const op = preparePluginMcpCodexSync(registrations);
18962
- writeFileSync4(op.targetPath, op.content, "utf8");
18962
+ writeFileSync5(op.targetPath, op.content, "utf8");
18963
18963
  }
18964
18964
  var init_mcp_sync = __esm({
18965
18965
  "src/lib/environment/sync/mcp-sync.ts"() {
@@ -25235,8 +25235,8 @@ import { execFileSync as execFileSync3 } from "child_process";
25235
25235
  import yaml12 from "js-yaml";
25236
25236
  import semver from "semver";
25237
25237
  function relayCoreVersion() {
25238
- if (semver.valid("0.15.4")) {
25239
- return "0.15.4";
25238
+ if (semver.valid("0.16.0")) {
25239
+ return "0.16.0";
25240
25240
  }
25241
25241
  try {
25242
25242
  const root = getAppRoot(import.meta.dirname, 3);
@@ -25606,14 +25606,14 @@ var init_cli = __esm({
25606
25606
 
25607
25607
  // bin/cli.ts
25608
25608
  import { program } from "commander";
25609
- import { basename as basename5, dirname as dirname5, join as join20 } from "path";
25609
+ import { basename as basename6, dirname as dirname5, join as join21 } from "path";
25610
25610
  import { homedir as homedir8 } from "os";
25611
- import { fileURLToPath as fileURLToPath3 } from "url";
25611
+ import { fileURLToPath as fileURLToPath4 } from "url";
25612
25612
  import {
25613
- mkdirSync as mkdirSync5,
25614
- existsSync as existsSync12,
25615
- readFileSync as readFileSync8,
25616
- writeFileSync as writeFileSync5,
25613
+ mkdirSync as mkdirSync6,
25614
+ existsSync as existsSync13,
25615
+ readFileSync as readFileSync9,
25616
+ writeFileSync as writeFileSync6,
25617
25617
  cpSync as cpSync2,
25618
25618
  unlinkSync as unlinkSync2
25619
25619
  } from "fs";
@@ -25685,19 +25685,249 @@ function isNonLoopbackHost(host) {
25685
25685
  return true;
25686
25686
  }
25687
25687
 
25688
+ // src/lib/desktop/prebuilt-download.ts
25689
+ import { createHash } from "crypto";
25690
+ import {
25691
+ copyFileSync,
25692
+ createWriteStream,
25693
+ createReadStream,
25694
+ existsSync as existsSync2,
25695
+ mkdirSync,
25696
+ readdirSync,
25697
+ readFileSync,
25698
+ rmSync,
25699
+ statSync,
25700
+ symlinkSync,
25701
+ writeFileSync
25702
+ } from "fs";
25703
+ import { basename, join as join2, relative } from "path";
25704
+ import { Readable } from "stream";
25705
+ import { pipeline } from "stream/promises";
25706
+ import { fileURLToPath } from "url";
25707
+ import * as tar from "tar";
25708
+ var PrebuiltDownloadError = class extends Error {
25709
+ constructor(message, options) {
25710
+ super(message, options);
25711
+ this.name = "PrebuiltDownloadError";
25712
+ }
25713
+ };
25714
+ var RELEASE_DOWNLOAD_BASE = "https://github.com/orionfold/relay/releases/download";
25715
+ function artifactFileName(version) {
25716
+ return `relay-next-build-${version}.tgz`;
25717
+ }
25718
+ function buildArtifactUrl(version, override) {
25719
+ if (override && override.trim()) {
25720
+ return override.trim();
25721
+ }
25722
+ return `${RELEASE_DOWNLOAD_BASE}/v${version}/${artifactFileName(version)}`;
25723
+ }
25724
+ function artifactCachePaths(buildsDir, version) {
25725
+ const tgz = join2(buildsDir, artifactFileName(version));
25726
+ return { tgz, sha: `${tgz}.sha256` };
25727
+ }
25728
+ function parseSha256File(text2) {
25729
+ const match = text2.match(/\b[0-9a-f]{64}\b/i);
25730
+ if (!match) {
25731
+ throw new PrebuiltDownloadError(
25732
+ `Checksum file did not contain a sha256 digest: "${text2.slice(0, 80)}"`
25733
+ );
25734
+ }
25735
+ return match[0].toLowerCase();
25736
+ }
25737
+ async function sha256OfFile(filePath) {
25738
+ const hash = createHash("sha256");
25739
+ await pipeline(createReadStream(filePath), hash);
25740
+ return hash.digest("hex");
25741
+ }
25742
+ async function downloadToFile(url, destPath) {
25743
+ let parsed;
25744
+ try {
25745
+ parsed = new URL(url);
25746
+ } catch (cause) {
25747
+ throw new PrebuiltDownloadError(`Invalid artifact URL: ${url}`, { cause });
25748
+ }
25749
+ if (parsed.protocol === "file:") {
25750
+ const sourcePath = fileURLToPath(parsed);
25751
+ if (!existsSync2(sourcePath)) {
25752
+ throw new PrebuiltDownloadError(`Artifact not found at ${sourcePath}`);
25753
+ }
25754
+ copyFileSync(sourcePath, destPath);
25755
+ return;
25756
+ }
25757
+ let response;
25758
+ try {
25759
+ response = await fetch(url, { redirect: "follow" });
25760
+ } catch (cause) {
25761
+ throw new PrebuiltDownloadError(
25762
+ `Network error downloading ${url}: ${cause instanceof Error ? cause.message : String(cause)}`,
25763
+ { cause }
25764
+ );
25765
+ }
25766
+ if (!response.ok || !response.body) {
25767
+ throw new PrebuiltDownloadError(
25768
+ `Download of ${url} failed with HTTP ${response.status} ${response.statusText}`
25769
+ );
25770
+ }
25771
+ try {
25772
+ await pipeline(
25773
+ Readable.fromWeb(response.body),
25774
+ createWriteStream(destPath)
25775
+ );
25776
+ } catch (cause) {
25777
+ rmSync(destPath, { force: true });
25778
+ throw new PrebuiltDownloadError(
25779
+ `Failed writing artifact to ${destPath}: ${cause instanceof Error ? cause.message : String(cause)}`,
25780
+ { cause }
25781
+ );
25782
+ }
25783
+ }
25784
+ async function extractPrebuilt(tgzPath, destDir) {
25785
+ try {
25786
+ await tar.extract({ file: tgzPath, cwd: destDir, strict: true });
25787
+ } catch (cause) {
25788
+ throw new PrebuiltDownloadError(
25789
+ `Failed extracting ${basename(tgzPath)}: ${cause instanceof Error ? cause.message : String(cause)}`,
25790
+ { cause }
25791
+ );
25792
+ }
25793
+ if (!existsSync2(join2(destDir, ".next", "BUILD_ID"))) {
25794
+ throw new PrebuiltDownloadError(
25795
+ `Artifact ${basename(tgzPath)} extracted but contains no .next/BUILD_ID \u2014 not a valid prebuilt bundle.`
25796
+ );
25797
+ }
25798
+ relinkExternalPackages(destDir);
25799
+ }
25800
+ function relinkExternalPackages(destDir) {
25801
+ const manifestPath = join2(destDir, ".next", "relay-external-packages.json");
25802
+ if (!existsSync2(manifestPath)) {
25803
+ return;
25804
+ }
25805
+ let links;
25806
+ try {
25807
+ links = JSON.parse(readFileSync(manifestPath, "utf-8")).links ?? {};
25808
+ } catch (cause) {
25809
+ throw new PrebuiltDownloadError(
25810
+ `Artifact manifest ${manifestPath} is not valid JSON.`,
25811
+ { cause }
25812
+ );
25813
+ }
25814
+ const linksDir = join2(destDir, ".next", "node_modules");
25815
+ mkdirSync(linksDir, { recursive: true });
25816
+ for (const [hashedName, packagePath] of Object.entries(links)) {
25817
+ const target = join2(destDir, "node_modules", packagePath);
25818
+ if (!existsSync2(target)) {
25819
+ throw new PrebuiltDownloadError(
25820
+ `Prebuilt server expects package "${packagePath}" (as ${hashedName}) but it is not installed at ${target}. The npm install may be incomplete \u2014 reinstall and retry.`
25821
+ );
25822
+ }
25823
+ const linkPath = join2(linksDir, hashedName);
25824
+ rmSync(linkPath, { recursive: true, force: true });
25825
+ try {
25826
+ if (process.platform === "win32") {
25827
+ symlinkSync(target, linkPath, "junction");
25828
+ } else {
25829
+ symlinkSync(relative(linksDir, target), linkPath);
25830
+ }
25831
+ } catch (cause) {
25832
+ throw new PrebuiltDownloadError(
25833
+ `Could not link ${hashedName} \u2192 ${target}: ${cause instanceof Error ? cause.message : String(cause)}`,
25834
+ { cause }
25835
+ );
25836
+ }
25837
+ }
25838
+ }
25839
+ function pruneBuildCache(buildsDir, currentVersion, keep = 2) {
25840
+ let entries;
25841
+ try {
25842
+ entries = readdirSync(buildsDir).filter(
25843
+ (name) => /^relay-next-build-.+\.tgz$/.test(name)
25844
+ );
25845
+ } catch {
25846
+ return;
25847
+ }
25848
+ const current = artifactFileName(currentVersion);
25849
+ const others = entries.filter((name) => name !== current).map((name) => {
25850
+ const filePath = join2(buildsDir, name);
25851
+ let mtime = 0;
25852
+ try {
25853
+ mtime = statSync(filePath).mtimeMs;
25854
+ } catch {
25855
+ }
25856
+ return { name, filePath, mtime };
25857
+ }).sort((a, b) => b.mtime - a.mtime);
25858
+ const keepOthers = entries.includes(current) ? keep - 1 : keep;
25859
+ for (const stale of others.slice(Math.max(keepOthers, 0))) {
25860
+ rmSync(stale.filePath, { force: true });
25861
+ rmSync(`${stale.filePath}.sha256`, { force: true });
25862
+ }
25863
+ }
25864
+ async function ensurePrebuilt({
25865
+ version,
25866
+ effectiveCwd,
25867
+ buildsDir,
25868
+ artifactUrlOverride,
25869
+ log
25870
+ }) {
25871
+ if (existsSync2(join2(effectiveCwd, ".next", "BUILD_ID"))) {
25872
+ return "already-present";
25873
+ }
25874
+ mkdirSync(buildsDir, { recursive: true });
25875
+ const cache = artifactCachePaths(buildsDir, version);
25876
+ if (existsSync2(cache.tgz) && existsSync2(cache.sha)) {
25877
+ log(`Using cached production build for ${version} (${cache.tgz}).`);
25878
+ await verifyChecksum(cache.tgz, readFileSync(cache.sha, "utf-8"));
25879
+ await extractPrebuilt(cache.tgz, effectiveCwd);
25880
+ return "from-cache";
25881
+ }
25882
+ const url = buildArtifactUrl(version, artifactUrlOverride);
25883
+ log(`Downloading production build for ${version} (~40 MB) from ${url} ...`);
25884
+ try {
25885
+ await downloadToFile(url, cache.tgz);
25886
+ const shaText = await fetchChecksumText(`${url}.sha256`, buildsDir);
25887
+ writeFileSync(cache.sha, shaText, "utf-8");
25888
+ await verifyChecksum(cache.tgz, shaText);
25889
+ await extractPrebuilt(cache.tgz, effectiveCwd);
25890
+ } catch (error) {
25891
+ rmSync(cache.tgz, { force: true });
25892
+ rmSync(cache.sha, { force: true });
25893
+ throw error;
25894
+ }
25895
+ log(`Production build ready (cached at ${cache.tgz}).`);
25896
+ pruneBuildCache(buildsDir, version);
25897
+ return "downloaded";
25898
+ }
25899
+ async function fetchChecksumText(shaUrl, buildsDir) {
25900
+ const tempPath = join2(buildsDir, `.sha-download-${process.pid}`);
25901
+ try {
25902
+ await downloadToFile(shaUrl, tempPath);
25903
+ return readFileSync(tempPath, "utf-8");
25904
+ } finally {
25905
+ rmSync(tempPath, { force: true });
25906
+ }
25907
+ }
25908
+ async function verifyChecksum(tgzPath, shaFileText) {
25909
+ const expected = parseSha256File(shaFileText);
25910
+ const actual = await sha256OfFile(tgzPath);
25911
+ if (actual !== expected) {
25912
+ throw new PrebuiltDownloadError(
25913
+ `Checksum mismatch for ${basename(tgzPath)}: expected ${expected}, got ${actual}. The download may be corrupt or tampered with.`
25914
+ );
25915
+ }
25916
+ }
25917
+
25688
25918
  // bin/cli.ts
25689
25919
  init_ainative_paths();
25690
25920
  init_bootstrap();
25691
25921
 
25692
25922
  // src/lib/utils/migrate-to-ainative.ts
25693
- import { existsSync as existsSync3, renameSync, cpSync, rmSync, readFileSync as readFileSync2 } from "fs";
25694
- import { join as join5 } from "path";
25923
+ import { existsSync as existsSync4, renameSync, cpSync, rmSync as rmSync2, readFileSync as readFileSync3 } from "fs";
25924
+ import { join as join6 } from "path";
25695
25925
  import { homedir as homedir2 } from "os";
25696
25926
  import Database from "better-sqlite3";
25697
25927
  function hasSqliteHeader(path19) {
25698
25928
  const SQLITE_MAGIC = "SQLite format 3\0";
25699
25929
  try {
25700
- const header = readFileSync2(path19, { encoding: null });
25930
+ const header = readFileSync3(path19, { encoding: null });
25701
25931
  return header.length >= 16 && header.subarray(0, 16).toString("binary") === SQLITE_MAGIC;
25702
25932
  } catch {
25703
25933
  return false;
@@ -25705,7 +25935,7 @@ function hasSqliteHeader(path19) {
25705
25935
  }
25706
25936
  async function migrateLegacyData(options = {}) {
25707
25937
  const home = options.home ?? homedir2();
25708
- const gitDir = options.gitDir ?? join5(process.cwd(), ".git");
25938
+ const gitDir = options.gitDir ?? join6(process.cwd(), ".git");
25709
25939
  const log = options.logger ?? ((m) => console.log(`[migrate] ${m}`));
25710
25940
  const report = {
25711
25941
  dirMigrated: false,
@@ -25715,9 +25945,9 @@ async function migrateLegacyData(options = {}) {
25715
25945
  keychainMigrated: false,
25716
25946
  errors: []
25717
25947
  };
25718
- const oldDir = join5(home, ".stagent");
25719
- const newDir = join5(home, ".ainative");
25720
- if (existsSync3(oldDir) && !existsSync3(newDir)) {
25948
+ const oldDir = join6(home, ".stagent");
25949
+ const newDir = join6(home, ".ainative");
25950
+ if (existsSync4(oldDir) && !existsSync4(newDir)) {
25721
25951
  try {
25722
25952
  renameSync(oldDir, newDir);
25723
25953
  report.dirMigrated = true;
@@ -25727,7 +25957,7 @@ async function migrateLegacyData(options = {}) {
25727
25957
  if (e.code === "EXDEV") {
25728
25958
  try {
25729
25959
  cpSync(oldDir, newDir, { recursive: true });
25730
- rmSync(oldDir, { recursive: true, force: true });
25960
+ rmSync2(oldDir, { recursive: true, force: true });
25731
25961
  report.dirMigrated = true;
25732
25962
  log(`copied ${oldDir} -> ${newDir} (cross-device fallback)`);
25733
25963
  } catch (copyErr) {
@@ -25740,11 +25970,11 @@ async function migrateLegacyData(options = {}) {
25740
25970
  }
25741
25971
  }
25742
25972
  }
25743
- if (existsSync3(newDir)) {
25973
+ if (existsSync4(newDir)) {
25744
25974
  for (const suffix of ["", "-shm", "-wal"]) {
25745
- const oldName = join5(newDir, `stagent.db${suffix}`);
25746
- const newName = join5(newDir, `ainative.db${suffix}`);
25747
- if (existsSync3(oldName) && !existsSync3(newName)) {
25975
+ const oldName = join6(newDir, `stagent.db${suffix}`);
25976
+ const newName = join6(newDir, `ainative.db${suffix}`);
25977
+ if (existsSync4(oldName) && !existsSync4(newName)) {
25748
25978
  try {
25749
25979
  renameSync(oldName, newName);
25750
25980
  report.dbFilesRenamed++;
@@ -25754,11 +25984,11 @@ async function migrateLegacyData(options = {}) {
25754
25984
  }
25755
25985
  }
25756
25986
  }
25757
- const dbPath4 = join5(newDir, "ainative.db");
25758
- if (existsSync3(dbPath4) && !hasSqliteHeader(dbPath4)) {
25987
+ const dbPath4 = join6(newDir, "ainative.db");
25988
+ if (existsSync4(dbPath4) && !hasSqliteHeader(dbPath4)) {
25759
25989
  log(`skipping SQL migration \u2014 ${dbPath4} exists but lacks SQLite header`);
25760
25990
  }
25761
- if (existsSync3(dbPath4) && hasSqliteHeader(dbPath4)) {
25991
+ if (existsSync4(dbPath4) && hasSqliteHeader(dbPath4)) {
25762
25992
  try {
25763
25993
  const db3 = new Database(dbPath4);
25764
25994
  try {
@@ -25789,10 +26019,10 @@ async function migrateLegacyData(options = {}) {
25789
26019
  report.errors.push(`SQL migration failed: ${String(err2)}`);
25790
26020
  }
25791
26021
  }
25792
- if (existsSync3(gitDir)) {
25793
- const oldSentinel = join5(gitDir, "stagent-dev-mode");
25794
- const newSentinel = join5(gitDir, "ainative-dev-mode");
25795
- if (existsSync3(oldSentinel) && !existsSync3(newSentinel)) {
26022
+ if (existsSync4(gitDir)) {
26023
+ const oldSentinel = join6(gitDir, "stagent-dev-mode");
26024
+ const newSentinel = join6(gitDir, "ainative-dev-mode");
26025
+ if (existsSync4(oldSentinel) && !existsSync4(newSentinel)) {
25796
26026
  try {
25797
26027
  renameSync(oldSentinel, newSentinel);
25798
26028
  report.sentinelRenamed = true;
@@ -25819,16 +26049,16 @@ async function migrateLegacyData(options = {}) {
25819
26049
 
25820
26050
  // bin/cli.ts
25821
26051
  init_detect();
25822
- var __dirname = dirname5(fileURLToPath3(import.meta.url));
25823
- var appDir = join20(__dirname, "..");
26052
+ var __dirname = dirname5(fileURLToPath4(import.meta.url));
26053
+ var appDir = join21(__dirname, "..");
25824
26054
  var launchCwd2 = process.cwd();
25825
- var _envLocalPath = join20(launchCwd2, ".env.local");
25826
- var _firstRunNeedsEnv = !existsSync12(_envLocalPath) && !process.env.RELAY_DATA_DIR && !isDevMode(launchCwd2);
26055
+ var _envLocalPath = join21(launchCwd2, ".env.local");
26056
+ var _firstRunNeedsEnv = !existsSync13(_envLocalPath) && !process.env.RELAY_DATA_DIR && !isDevMode(launchCwd2);
25827
26057
  if (_firstRunNeedsEnv) {
25828
- const folderName = basename5(launchCwd2);
25829
- const autoDataDir = join20(homedir8(), `.${folderName}`);
26058
+ const folderName = basename6(launchCwd2);
26059
+ const autoDataDir = join21(homedir8(), `.${folderName}`);
25830
26060
  try {
25831
- writeFileSync5(
26061
+ writeFileSync6(
25832
26062
  _envLocalPath,
25833
26063
  `# Auto-created by orionfold-relay on first run.
25834
26064
  # Points this folder's install at an isolated data directory.
@@ -25850,8 +26080,8 @@ Continuing with the default data directory (~/.relay). This folder will not get
25850
26080
  }
25851
26081
  }
25852
26082
  }
25853
- if (existsSync12(_envLocalPath)) {
25854
- for (const line of readFileSync8(_envLocalPath, "utf-8").split("\n")) {
26083
+ if (existsSync13(_envLocalPath)) {
26084
+ for (const line of readFileSync9(_envLocalPath, "utf-8").split("\n")) {
25855
26085
  const trimmed = line.trim();
25856
26086
  if (!trimmed || trimmed.startsWith("#")) continue;
25857
26087
  const eqIdx = trimmed.indexOf("=");
@@ -25863,7 +26093,7 @@ if (existsSync12(_envLocalPath)) {
25863
26093
  }
25864
26094
  }
25865
26095
  }
25866
- var pkg = JSON.parse(readFileSync8(join20(appDir, "package.json"), "utf-8"));
26096
+ var pkg = JSON.parse(readFileSync9(join21(appDir, "package.json"), "utf-8"));
25867
26097
  function getHelpText() {
25868
26098
  const dir = getAinativeDataDir();
25869
26099
  const db3 = getAinativeDbPath();
@@ -25871,8 +26101,8 @@ function getHelpText() {
25871
26101
  Data:
25872
26102
  Directory ${dir}
25873
26103
  Database ${db3}
25874
- Sessions ${join20(dir, "sessions")}
25875
- Logs ${join20(dir, "logs")}
26104
+ Sessions ${join21(dir, "sessions")}
26105
+ Logs ${join21(dir, "logs")}
25876
26106
 
25877
26107
  Environment variables:
25878
26108
  RELAY_DATA_DIR Custom data directory for the web app
@@ -25938,15 +26168,15 @@ var requestedPort = Number.parseInt(opts.port, 10);
25938
26168
  if (Number.isNaN(requestedPort) || requestedPort <= 0) {
25939
26169
  program.error(`Invalid port: ${opts.port}`);
25940
26170
  }
25941
- for (const dir of [DATA_DIR, join20(DATA_DIR, "logs"), join20(DATA_DIR, "sessions")]) {
25942
- mkdirSync5(dir, { recursive: true });
26171
+ for (const dir of [DATA_DIR, join21(DATA_DIR, "logs"), join21(DATA_DIR, "sessions")]) {
26172
+ mkdirSync6(dir, { recursive: true });
25943
26173
  }
25944
26174
  if (opts.reset) {
25945
- if (existsSync12(dbPath3)) {
26175
+ if (existsSync13(dbPath3)) {
25946
26176
  unlinkSync2(dbPath3);
25947
26177
  for (const suffix of ["-wal", "-shm"]) {
25948
26178
  const filePath = dbPath3 + suffix;
25949
- if (existsSync12(filePath)) unlinkSync2(filePath);
26179
+ if (existsSync13(filePath)) unlinkSync2(filePath);
25950
26180
  }
25951
26181
  console.log("Database reset.");
25952
26182
  } else {
@@ -25956,7 +26186,7 @@ if (opts.reset) {
25956
26186
  var sqlite2 = new Database3(dbPath3);
25957
26187
  sqlite2.pragma("journal_mode = WAL");
25958
26188
  sqlite2.pragma("foreign_keys = ON");
25959
- var migrationsDir = join20(appDir, "src", "lib", "db", "migrations");
26189
+ var migrationsDir = join21(appDir, "src", "lib", "db", "migrations");
25960
26190
  var db2 = drizzle2(sqlite2);
25961
26191
  var needsLegacyRecovery = hasLegacyTables(sqlite2) && !hasMigrationHistory(sqlite2);
25962
26192
  if (needsLegacyRecovery) {
@@ -25987,17 +26217,17 @@ async function main() {
25987
26217
  findAvailablePort
25988
26218
  });
25989
26219
  let effectiveCwd = appDir;
25990
- const localNm = join20(appDir, "node_modules");
25991
- if (!existsSync12(join20(localNm, "next", "package.json"))) {
26220
+ const localNm = join21(appDir, "node_modules");
26221
+ if (!existsSync13(join21(localNm, "next", "package.json"))) {
25992
26222
  let searchDir = dirname5(appDir);
25993
26223
  while (searchDir !== dirname5(searchDir)) {
25994
- const candidate = join20(searchDir, "node_modules", "next", "package.json");
25995
- if (existsSync12(candidate)) {
26224
+ const candidate = join21(searchDir, "node_modules", "next", "package.json");
26225
+ if (existsSync13(candidate)) {
25996
26226
  const hoistedRoot = searchDir;
25997
26227
  for (const name of ["src", "public"]) {
25998
- const dest = join20(hoistedRoot, name);
25999
- const src = join20(appDir, name);
26000
- if (!existsSync12(dest) && existsSync12(src)) {
26228
+ const dest = join21(hoistedRoot, name);
26229
+ const src = join21(appDir, name);
26230
+ if (!existsSync13(dest) && existsSync13(src)) {
26001
26231
  cpSync2(src, dest, { recursive: true });
26002
26232
  }
26003
26233
  }
@@ -26009,10 +26239,10 @@ async function main() {
26009
26239
  "components.json",
26010
26240
  "drizzle.config.ts"
26011
26241
  ]) {
26012
- const dest = join20(hoistedRoot, name);
26013
- const src = join20(appDir, name);
26014
- if (!existsSync12(dest) && existsSync12(src)) {
26015
- writeFileSync5(dest, readFileSync8(src));
26242
+ const dest = join21(hoistedRoot, name);
26243
+ const src = join21(appDir, name);
26244
+ if (!existsSync13(dest) && existsSync13(src)) {
26245
+ writeFileSync6(dest, readFileSync9(src));
26016
26246
  }
26017
26247
  }
26018
26248
  effectiveCwd = hoistedRoot;
@@ -26021,8 +26251,25 @@ async function main() {
26021
26251
  searchDir = dirname5(searchDir);
26022
26252
  }
26023
26253
  }
26254
+ if (!existsSync13(join21(effectiveCwd, ".next", "BUILD_ID")) && !isDevMode(launchCwd2)) {
26255
+ try {
26256
+ await ensurePrebuilt({
26257
+ version: pkg.version,
26258
+ effectiveCwd,
26259
+ buildsDir: join21(DATA_DIR, "builds"),
26260
+ artifactUrlOverride: process.env.RELAY_BUILD_ARTIFACT_URL,
26261
+ log: (message) => console.log(message)
26262
+ });
26263
+ } catch (e) {
26264
+ const reason = e instanceof Error ? e.message : String(e);
26265
+ console.warn(
26266
+ `\u26A0 Could not set up the production build (${reason}).
26267
+ Falling back to development mode for this run \u2014 Relay still works, but slower and with dev-mode console noise. Check your network (the build downloads once per version from GitHub Releases) and re-run, or set RELAY_BUILD_ARTIFACT_URL to a mirror.`
26268
+ );
26269
+ }
26270
+ }
26024
26271
  const nextEntrypoint = resolveNextEntrypoint(effectiveCwd);
26025
- const isPrebuilt = existsSync12(join20(effectiveCwd, ".next", "BUILD_ID"));
26272
+ const isPrebuilt = existsSync13(join21(effectiveCwd, ".next", "BUILD_ID"));
26026
26273
  const bindHost = opts.hostname || "127.0.0.1";
26027
26274
  if (isNonLoopbackHost(bindHost)) {
26028
26275
  console.warn(
@@ -26049,7 +26296,13 @@ async function main() {
26049
26296
  RELAY_DATA_DIR: DATA_DIR,
26050
26297
  RELAY_LAUNCH_CWD: launchCwd2,
26051
26298
  PORT: String(actualPort),
26052
- ...opts.safeMode ? { RELAY_SAFE_MODE: "true" } : {}
26299
+ ...opts.safeMode ? { RELAY_SAFE_MODE: "true" } : {},
26300
+ // In dev mode, Next blocks cross-origin /_next/* dev-asset requests from
26301
+ // the LAN client's IP, breaking the app over the network (issue #13).
26302
+ // When the operator has opted into non-loopback binding, tell next.config
26303
+ // to allow any dev origin. Mirrors the same trust decision as the warning
26304
+ // above; harmless for the prebuilt `next start` path (no dev-origin gate).
26305
+ ...isNonLoopbackHost(bindHost) ? { RELAY_ALLOW_LAN_ORIGINS: "true" } : {}
26053
26306
  }
26054
26307
  });
26055
26308
  if (opts.open !== false) {