ryugi-artifacts 1.39.2 → 1.39.3

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.cjs CHANGED
@@ -24,8 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/cli/main.ts
27
- var import_node_child_process4 = require("node:child_process");
28
- var import_node_util = require("node:util");
27
+ var import_node_child_process5 = require("node:child_process");
28
+ var import_node_util2 = require("node:util");
29
29
 
30
30
  // src/cli/paths.ts
31
31
  var import_node_fs = __toESM(require("node:fs"), 1);
@@ -985,7 +985,7 @@ async function monitor(options, emit) {
985
985
  }
986
986
 
987
987
  // src/cli/start.ts
988
- var import_node_child_process3 = require("node:child_process");
988
+ var import_node_child_process4 = require("node:child_process");
989
989
  var import_node_crypto3 = __toESM(require("node:crypto"), 1);
990
990
  var import_node_fs11 = __toESM(require("node:fs"), 1);
991
991
  var import_node_path10 = __toESM(require("node:path"), 1);
@@ -1035,6 +1035,54 @@ function artifactPath(root, type, slug) {
1035
1035
  return `/${type}/${artifactId(dir)}`;
1036
1036
  }
1037
1037
 
1038
+ // src/server/browser-focus.ts
1039
+ var import_node_child_process3 = require("node:child_process");
1040
+ var import_node_util = require("node:util");
1041
+ var execute = (0, import_node_util.promisify)(import_node_child_process3.execFile);
1042
+ var MAC_FOCUS_SCRIPT = String.raw`
1043
+ function run(urls) {
1044
+ function key(url) {
1045
+ return String(url).split(/[?#]/)[0].replace(/^(https?:\/\/)127\.0\.0\.1:/, '$1localhost:').replace(/\/$/, '');
1046
+ }
1047
+ var targets = urls.map(key);
1048
+ var ids = ['company.thebrowser.dia', 'com.google.Chrome', 'com.apple.Safari'];
1049
+ var unknown = false;
1050
+ for (var a = 0; a < ids.length; a++) {
1051
+ var app;
1052
+ try { app = Application(ids[a]); if (!app.running()) continue; } catch (e) { continue; }
1053
+ try {
1054
+ var windows = app.windows();
1055
+ for (var w = 0; w < windows.length; w++) {
1056
+ var tabs = windows[w].tabs();
1057
+ for (var t = 0; t < tabs.length; t++) {
1058
+ if (targets.indexOf(key(tabs[t].url())) === -1) continue;
1059
+ try {
1060
+ if (ids[a] === 'company.thebrowser.dia') app.focus(tabs[t]);
1061
+ else {
1062
+ if (ids[a] === 'com.apple.Safari') windows[w].currentTab = tabs[t];
1063
+ else windows[w].activeTabIndex = t + 1;
1064
+ windows[w].index = 1;
1065
+ }
1066
+ app.activate();
1067
+ } catch (e) { console.log('Could not focus the existing browser tab: ' + e.message); }
1068
+ return 'found';
1069
+ }
1070
+ }
1071
+ } catch (e) { unknown = true; }
1072
+ }
1073
+ return unknown ? 'unknown' : 'missing';
1074
+ }`;
1075
+ async function openBrowser(url, aliases = []) {
1076
+ if (process.platform === "darwin") {
1077
+ const { stdout, stderr } = await execute("osascript", ["-l", "JavaScript", "-e", MAC_FOCUS_SCRIPT, url, ...aliases], { timeout: 5e3 });
1078
+ if (stderr.trim()) console.error(stderr.trim());
1079
+ if (stdout.trim() === "found") return;
1080
+ if (stdout.trim() !== "missing") throw new Error("Could not inspect existing browser tabs; open the artifact link manually.");
1081
+ }
1082
+ const launcher = browserLauncher(process.platform, url);
1083
+ if (launcher) await execute(launcher.bin, launcher.args);
1084
+ }
1085
+
1038
1086
  // src/cli/start.ts
1039
1087
  var windowsLike = () => process.platform === "win32";
1040
1088
  function withLink(info, artifact, reused) {
@@ -1048,9 +1096,8 @@ function withLink(info, artifact, reused) {
1048
1096
  return out;
1049
1097
  }
1050
1098
  var RESERVE_TIMEOUT_MS = 5e3;
1051
- var inClaudeCode = () => !!(process.env.CLAUDECODE || process.env.CLAUDE_CODE);
1052
1099
  async function withCloudLink(out, artifact) {
1053
- if (!artifact || !inClaudeCode() || typeof out.url !== "string") return out;
1100
+ if (!artifact || typeof out.url !== "string") return out;
1054
1101
  const server = new URL(out.url);
1055
1102
  if (server.hostname === "localhost") server.hostname = "127.0.0.1";
1056
1103
  try {
@@ -1164,7 +1211,14 @@ async function start(options, emit) {
1164
1211
  if (!version || readText(paths.version) === version) {
1165
1212
  registerOwner(paths);
1166
1213
  recordAgent(paths);
1167
- emit(await withCloudLink(withLink(JSON.parse(info), options.artifact, true), options.artifact));
1214
+ const out = await withCloudLink(withLink(JSON.parse(info), options.artifact, true), options.artifact);
1215
+ emit(out);
1216
+ if (process.platform === "darwin" && options.open && options.artifact && !process.env.ARTIFACTS_OPEN_CMD) {
1217
+ const local = out.link;
1218
+ await openBrowser(typeof out.cloudLink === "string" ? out.cloudLink : local, [local]).catch((error) => {
1219
+ console.error(error.message);
1220
+ });
1221
+ }
1168
1222
  return 0;
1169
1223
  }
1170
1224
  await replace(running, paths);
@@ -1180,7 +1234,7 @@ async function start(options, emit) {
1180
1234
  const env = serverEnv(paths, options);
1181
1235
  const args = [server, `--artifacts-server-id=${id}`];
1182
1236
  if (foreground) {
1183
- const child2 = (0, import_node_child_process3.spawn)(process.execPath, args, { env, stdio: ["ignore", "pipe", "inherit"] });
1237
+ const child2 = (0, import_node_child_process4.spawn)(process.execPath, args, { env, stdio: ["ignore", "pipe", "inherit"] });
1184
1238
  import_node_fs11.default.writeFileSync(paths.pid, `${child2.pid}
1185
1239
  `);
1186
1240
  for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => child2.kill("SIGTERM"));
@@ -1202,7 +1256,7 @@ async function start(options, emit) {
1202
1256
  return await exited;
1203
1257
  }
1204
1258
  const log = import_node_fs11.default.openSync(paths.log, "w");
1205
- const child = (0, import_node_child_process3.spawn)(process.execPath, args, { env, detached: true, stdio: ["ignore", log, log] });
1259
+ const child = (0, import_node_child_process4.spawn)(process.execPath, args, { env, detached: true, stdio: ["ignore", log, log] });
1206
1260
  import_node_fs11.default.closeSync(log);
1207
1261
  child.unref();
1208
1262
  import_node_fs11.default.writeFileSync(paths.pid, `${child.pid}
@@ -1322,7 +1376,7 @@ Options:
1322
1376
  var common = { "project-dir": { type: "string" }, json: { type: "boolean" } };
1323
1377
  function parse(args, options, positionals = 0) {
1324
1378
  try {
1325
- const parsed = (0, import_node_util.parseArgs)({ args, options: { ...common, ...options }, allowPositionals: positionals > 0, strict: true });
1379
+ const parsed = (0, import_node_util2.parseArgs)({ args, options: { ...common, ...options }, allowPositionals: positionals > 0, strict: true });
1326
1380
  if (parsed.positionals.length > positionals) throw new CliError(`Unknown argument: ${parsed.positionals[positionals]}`);
1327
1381
  return parsed;
1328
1382
  } catch (err) {
@@ -1333,7 +1387,7 @@ function parse(args, options, positionals = 0) {
1333
1387
  }
1334
1388
  function text(value) {
1335
1389
  if (typeof value.error === "string") return `Error: ${value.error}`;
1336
- if (value.type === "server-started") return `${value.link ?? value.url}${value.reused ? " (already running)" : ""}`;
1390
+ if (value.type === "server-started") return `${value.cloudLink ?? value.link ?? value.url}${value.reused ? " (already running)" : ""}`;
1337
1391
  if (value.type === "login-required" || value.type === "login") return `${value.message}
1338
1392
  ${value.url}`;
1339
1393
  if (value.type === "published") return `${value.url} (${value.visibility})`;
@@ -1347,10 +1401,10 @@ ${value.url}`;
1347
1401
  if (typeof value.status === "string") return value.status === "stopped" ? "Stopped." : value.status.replace(/_/g, " ");
1348
1402
  return JSON.stringify(value);
1349
1403
  }
1350
- function openBrowser(url) {
1404
+ function openBrowser2(url) {
1351
1405
  const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
1352
1406
  const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
1353
- (0, import_node_child_process4.execFile)(command, args, () => {
1407
+ (0, import_node_child_process5.execFile)(command, args, () => {
1354
1408
  });
1355
1409
  }
1356
1410
  async function browse(argv) {
@@ -1370,7 +1424,7 @@ async function browse(argv) {
1370
1424
  if (value.type !== "server-started") return;
1371
1425
  console.log(value.url);
1372
1426
  if (!value.reused) console.log("Press Ctrl+C to stop the server.");
1373
- if (!values["no-open"]) openBrowser(value.url);
1427
+ if (!values["no-open"]) openBrowser2(value.url);
1374
1428
  });
1375
1429
  }
1376
1430
  async function main(argv) {
@@ -1478,7 +1532,7 @@ async function main(argv) {
1478
1532
  return await monitor({ json: !!values.json }, emit);
1479
1533
  }
1480
1534
  if (command === "--version" || command === "-v") {
1481
- console.log("1.39.2");
1535
+ console.log("1.39.3");
1482
1536
  return 0;
1483
1537
  }
1484
1538
  if (command === "--help" || command === "-h") {
package/dist/server.cjs CHANGED
@@ -5170,7 +5170,7 @@ var require_websocket_server = __commonJS({
5170
5170
  });
5171
5171
 
5172
5172
  // src/server/main.ts
5173
- var import_node_child_process2 = require("node:child_process");
5173
+ var import_node_child_process3 = require("node:child_process");
5174
5174
  var import_node_fs27 = __toESM(require("node:fs"), 1);
5175
5175
  var import_node_os2 = __toESM(require("node:os"), 1);
5176
5176
  var import_node_path23 = __toESM(require("node:path"), 1);
@@ -90504,6 +90504,7 @@ function createCloudRoutes(options) {
90504
90504
  },
90505
90505
  match: (pathname) => ROUTE.exec(pathname),
90506
90506
  autoPublish,
90507
+ reserve: (ref) => serialized(`${ref.type}/${ref.id}`, () => reserve(ref)),
90507
90508
  publication,
90508
90509
  changed(key2) {
90509
90510
  changedDuringPublish.add(key2);
@@ -91770,12 +91771,11 @@ async function startArtifactsServer(options) {
91770
91771
  contentToken,
91771
91772
  url,
91772
91773
  linkFor,
91773
- cloudLinkFor: (type, id2) => {
91774
- if (!options.cloud || !options.configFile || !readCredentials(options.cloud.credentialsFile, options.cloud.origin)) return null;
91775
- const url2 = readConfig(options.configFile).config.artifacts[`${type}/${id2}`]?.cloud?.url;
91774
+ cloudLinkFor: async (type, id2) => {
91775
+ if (!cloud || !options.cloud || !readCredentials(options.cloud.credentialsFile, options.cloud.origin)) return null;
91776
+ const { url: url2 } = await cloud.reserve({ type, id: id2 });
91776
91777
  return url2 ? ownLink(url2, hostIdFor(options.cloud.credentialsFile)) : null;
91777
91778
  },
91778
- clientCount: () => clients.size,
91779
91779
  onArtifactChange: (listener) => {
91780
91780
  changeListeners.push(listener);
91781
91781
  for (const change of initialChanges) listener(change.ref, change.payload, change.files);
@@ -91798,6 +91798,10 @@ async function startArtifactsServer(options) {
91798
91798
  };
91799
91799
  }
91800
91800
 
91801
+ // src/server/browser-focus.ts
91802
+ var import_node_child_process2 = require("node:child_process");
91803
+ var import_node_util = require("node:util");
91804
+
91801
91805
  // src/server/lifecycle.ts
91802
91806
  var import_node_fs25 = __toESM(require("node:fs"), 1);
91803
91807
  var DEFAULT_IDLE_TIMEOUT_MS = 4 * 60 * 60 * 1e3;
@@ -91859,6 +91863,52 @@ function processAlive(pid) {
91859
91863
  }
91860
91864
  }
91861
91865
 
91866
+ // src/server/browser-focus.ts
91867
+ var execute = (0, import_node_util.promisify)(import_node_child_process2.execFile);
91868
+ var MAC_FOCUS_SCRIPT = String.raw`
91869
+ function run(urls) {
91870
+ function key(url) {
91871
+ return String(url).split(/[?#]/)[0].replace(/^(https?:\/\/)127\.0\.0\.1:/, '$1localhost:').replace(/\/$/, '');
91872
+ }
91873
+ var targets = urls.map(key);
91874
+ var ids = ['company.thebrowser.dia', 'com.google.Chrome', 'com.apple.Safari'];
91875
+ var unknown = false;
91876
+ for (var a = 0; a < ids.length; a++) {
91877
+ var app;
91878
+ try { app = Application(ids[a]); if (!app.running()) continue; } catch (e) { continue; }
91879
+ try {
91880
+ var windows = app.windows();
91881
+ for (var w = 0; w < windows.length; w++) {
91882
+ var tabs = windows[w].tabs();
91883
+ for (var t = 0; t < tabs.length; t++) {
91884
+ if (targets.indexOf(key(tabs[t].url())) === -1) continue;
91885
+ try {
91886
+ if (ids[a] === 'company.thebrowser.dia') app.focus(tabs[t]);
91887
+ else {
91888
+ if (ids[a] === 'com.apple.Safari') windows[w].currentTab = tabs[t];
91889
+ else windows[w].activeTabIndex = t + 1;
91890
+ windows[w].index = 1;
91891
+ }
91892
+ app.activate();
91893
+ } catch (e) { console.log('Could not focus the existing browser tab: ' + e.message); }
91894
+ return 'found';
91895
+ }
91896
+ }
91897
+ } catch (e) { unknown = true; }
91898
+ }
91899
+ return unknown ? 'unknown' : 'missing';
91900
+ }`;
91901
+ async function openBrowser(url, aliases2 = []) {
91902
+ if (process.platform === "darwin") {
91903
+ const { stdout, stderr } = await execute("osascript", ["-l", "JavaScript", "-e", MAC_FOCUS_SCRIPT, url, ...aliases2], { timeout: 5e3 });
91904
+ if (stderr.trim()) console.error(stderr.trim());
91905
+ if (stdout.trim() === "found") return;
91906
+ if (stdout.trim() !== "missing") throw new Error("Could not inspect existing browser tabs; open the artifact link manually.");
91907
+ }
91908
+ const launcher = browserLauncher(process.platform, url);
91909
+ if (launcher) await execute(launcher.bin, launcher.args);
91910
+ }
91911
+
91862
91912
  // src/server/ready.ts
91863
91913
  var pageOfGroup = (canvas, ids) => ids.map((id2) => canvas.boards[id2]?.page).find((page) => Boolean(page));
91864
91914
  function openReady(payload) {
@@ -91948,7 +91998,7 @@ function touchEntry(dir, entry) {
91948
91998
  }
91949
91999
 
91950
92000
  // package.json
91951
- var version = "1.39.2";
92001
+ var version = "1.39.3";
91952
92002
 
91953
92003
  // src/server/main.ts
91954
92004
  async function main() {
@@ -91970,20 +92020,19 @@ async function main() {
91970
92020
  lastActivity = Date.now();
91971
92021
  });
91972
92022
  let browserOpened = false;
91973
- server.onArtifactChange((ref, payload) => {
92023
+ server.onArtifactChange(async (ref, payload) => {
91974
92024
  if (browserOpened || !config.open || !isLoopback(config.host)) return;
91975
92025
  if (config.openArtifact && `${ref.type}/${ref.id}` !== config.openArtifact) return;
91976
92026
  if ("canvas" in payload ? !openReady(payload) : payload.warnings.length > 0) return;
91977
92027
  browserOpened = true;
91978
- if (server.clientCount() > 0) return;
91979
- const link = server.cloudLinkFor(ref.type, ref.id) ?? server.linkFor(ref.type, ref.id);
92028
+ const link = await server.cloudLinkFor(ref.type, ref.id) ?? server.linkFor(ref.type, ref.id);
91980
92029
  if (config.openCmd) {
91981
- (0, import_node_child_process2.exec)(`${config.openCmd} ${JSON.stringify(link)}`, () => {
92030
+ (0, import_node_child_process3.exec)(`${config.openCmd} ${JSON.stringify(link)}`, () => {
91982
92031
  });
91983
92032
  return;
91984
92033
  }
91985
- const launcher = browserLauncher(process.platform, link);
91986
- if (launcher) (0, import_node_child_process2.execFile)(launcher.bin, launcher.args, () => {
92034
+ await openBrowser(link, [server.linkFor(ref.type, ref.id)]).catch((error) => {
92035
+ console.error(JSON.stringify({ type: "browser-open-error", error: error.message }));
91987
92036
  });
91988
92037
  });
91989
92038
  const registry2 = registryDir();
@@ -4592,7 +4592,7 @@ function zi(e, t) {
4592
4592
  }
4593
4593
  //#endregion
4594
4594
  //#region src/viewer/lib/version.ts
4595
- var Bi = "1.39.2", Vi = 100, Hi = 2e3, Ui = 50, Wi = (e, t = Vi) => typeof e == "string" && e.length > 0 && e.length <= t, Gi = (e) => typeof e == "number" && Number.isFinite(e), Ki = (e) => Gi(e) && e >= 0 && e <= 1;
4595
+ var Bi = "1.39.3", Vi = 100, Hi = 2e3, Ui = 50, Wi = (e, t = Vi) => typeof e == "string" && e.length > 0 && e.length <= t, Gi = (e) => typeof e == "number" && Number.isFinite(e), Ki = (e) => Gi(e) && e >= 0 && e <= 1;
4596
4596
  function qi(e) {
4597
4597
  if (!Array.isArray(e) || e.length === 0 || e.length > Ui) return null;
4598
4598
  let t = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ryugi-artifacts",
3
- "version": "1.39.2",
3
+ "version": "1.39.3",
4
4
  "type": "module",
5
5
  "description": "Server and viewer for the Ryugi artifacts app",
6
6
  "license": "AGPL-3.0-only",