ryugi-artifacts 1.30.0 → 1.31.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/dist/cli.cjs CHANGED
@@ -27,85 +27,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  var import_node_child_process3 = require("node:child_process");
28
28
  var import_node_util = require("node:util");
29
29
 
30
- // src/cli/comment.ts
31
- var import_node_fs3 = __toESM(require("node:fs"), 1);
32
-
33
- // src/server/agent.ts
34
- var NAMES = {
35
- claude: "Claude Code",
36
- "claude-code": "Claude Code",
37
- cowork: "Claude Cowork",
38
- codex: "Codex",
39
- cursor: "Cursor",
40
- "cursor-cli": "Cursor",
41
- gemini: "Gemini CLI",
42
- "gemini-cli": "Gemini CLI",
43
- "github-copilot": "GitHub Copilot",
44
- "github-copilot-cli": "GitHub Copilot",
45
- kilo: "Kilo Code",
46
- opencode: "OpenCode",
47
- "qwen-code": "Qwen Code",
48
- antigravity: "Antigravity",
49
- augment: "Augment",
50
- "augment-cli": "Augment",
51
- goose: "Goose",
52
- amp: "Amp",
53
- cline: "Cline",
54
- roo: "Roo Code",
55
- devin: "Devin",
56
- replit: "Replit",
57
- v0: "v0"
58
- };
59
- var AGENT_DISPLAY_NAMES = [...new Set(Object.values(NAMES))];
60
- var MARKERS = [
61
- ["cowork", (env) => !!env.CLAUDE_CODE_IS_COWORK],
62
- ["kilo", (env) => !!env.KILO],
63
- ["codex", (env) => !!(env.CODEX_THREAD_ID || env.CODEX_SANDBOX || env.CODEX_CI)],
64
- ["cursor", (env) => !!(env.CURSOR_AGENT || env.CURSOR_TRACE_ID)],
65
- ["gemini", (env) => !!env.GEMINI_CLI],
66
- ["github-copilot", (env) => !!env.COPILOT_CLI],
67
- ["opencode", (env) => env.OPENCODE === "1" || !!env.OPENCODE_CLIENT],
68
- ["qwen-code", (env) => !!env.QWEN_CODE],
69
- ["antigravity", (env) => !!env.ANTIGRAVITY_AGENT],
70
- ["augment", (env) => !!env.AUGMENT_AGENT],
71
- ["cline", (env) => !!env.CLINE_ACTIVE],
72
- ["roo", (env) => !!env.ROO_ACTIVE],
73
- ["claude", (env) => !!(env.CLAUDECODE || env.CLAUDE_CODE)]
74
- ];
75
- var AGENT_MARKERS = [
76
- "AI_AGENT",
77
- "AGENT",
78
- "CLAUDE_CODE_IS_COWORK",
79
- "KILO",
80
- "CODEX_THREAD_ID",
81
- "CODEX_SANDBOX",
82
- "CODEX_CI",
83
- "CURSOR_AGENT",
84
- "CURSOR_TRACE_ID",
85
- "GEMINI_CLI",
86
- "COPILOT_CLI",
87
- "OPENCODE",
88
- "OPENCODE_CLIENT",
89
- "QWEN_CODE",
90
- "ANTIGRAVITY_AGENT",
91
- "AUGMENT_AGENT",
92
- "CLINE_ACTIVE",
93
- "ROO_ACTIVE",
94
- "CLAUDECODE",
95
- "CLAUDE_CODE"
96
- ];
97
- var declaredName = (value) => value?.trim().split(/[@_]/)[0]?.toLowerCase() || void 0;
98
- function detectAgent(env) {
99
- if (env.CLAUDE_CODE_IS_COWORK) return NAMES.cowork;
100
- const declared = declaredName(env.AI_AGENT);
101
- if (declared) return NAMES[declared] ?? declared;
102
- const marked = MARKERS.find(([, test]) => test(env))?.[0];
103
- if (marked) return NAMES[marked];
104
- const agent = declaredName(env.AGENT);
105
- if (agent && !/^(1|true|yes)$/.test(agent)) return NAMES[agent] ?? agent;
106
- return void 0;
107
- }
108
-
109
30
  // src/cli/paths.ts
110
31
  var import_node_fs = __toESM(require("node:fs"), 1);
111
32
  var import_node_path = __toESM(require("node:path"), 1);
@@ -230,6 +151,114 @@ function serverClient(projectDir) {
230
151
  };
231
152
  }
232
153
 
154
+ // src/cli/check.ts
155
+ async function check(options, emit) {
156
+ if (!options.artifact || !ARTIFACT_PATTERN.test(options.artifact)) throw new CliError(ARTIFACT_ERROR);
157
+ const server = serverClient(options.projectDir);
158
+ const { status, json } = await server.call("POST", `/api/agent/${options.artifact}/check`);
159
+ if (status === 404 && typeof json.error !== "string") {
160
+ throw new CliError(`The running artifacts server is older than this CLI. Run \`${invocation()} start --project-dir ${server.project}\` to replace it, then run this again.`);
161
+ }
162
+ if (status < 200 || status >= 300) throw new CliError(json.error || `HTTP ${status}`);
163
+ emit({ type: "checked", artifact: options.artifact, ...json });
164
+ return 0;
165
+ }
166
+ function checkText(value) {
167
+ if (value.type !== "checked") return null;
168
+ const warnings = value.warnings ?? [];
169
+ const pending = value.pending ?? [];
170
+ const dynamic = value.dynamic ?? {};
171
+ const unrun = Object.entries(dynamic).filter(([, block]) => block.ran === false).map(([file]) => file);
172
+ const lines = [
173
+ ...warnings.map((warning) => `warning: ${warning}`),
174
+ ...pending.length ? [`pending: ${pending.join(", ")}`] : [],
175
+ ...value.merging ? ["still merging the last edit; check again"] : [],
176
+ ...value.ran === false ? ["not run in a browser yet"] : [],
177
+ ...unrun.length ? [`not run in a browser yet: ${unrun.join(", ")}`] : []
178
+ ];
179
+ return lines.length ? `${value.artifact}
180
+ ${lines.join("\n")}` : `${value.artifact}: no warnings`;
181
+ }
182
+
183
+ // src/cli/comment.ts
184
+ var import_node_fs3 = __toESM(require("node:fs"), 1);
185
+
186
+ // src/server/agent.ts
187
+ var NAMES = {
188
+ claude: "Claude Code",
189
+ "claude-code": "Claude Code",
190
+ cowork: "Claude Cowork",
191
+ codex: "Codex",
192
+ cursor: "Cursor",
193
+ "cursor-cli": "Cursor",
194
+ gemini: "Gemini CLI",
195
+ "gemini-cli": "Gemini CLI",
196
+ "github-copilot": "GitHub Copilot",
197
+ "github-copilot-cli": "GitHub Copilot",
198
+ kilo: "Kilo Code",
199
+ opencode: "OpenCode",
200
+ "qwen-code": "Qwen Code",
201
+ antigravity: "Antigravity",
202
+ augment: "Augment",
203
+ "augment-cli": "Augment",
204
+ goose: "Goose",
205
+ amp: "Amp",
206
+ cline: "Cline",
207
+ roo: "Roo Code",
208
+ devin: "Devin",
209
+ replit: "Replit",
210
+ v0: "v0"
211
+ };
212
+ var AGENT_DISPLAY_NAMES = [...new Set(Object.values(NAMES))];
213
+ var MARKERS = [
214
+ ["cowork", (env) => !!env.CLAUDE_CODE_IS_COWORK],
215
+ ["kilo", (env) => !!env.KILO],
216
+ ["codex", (env) => !!(env.CODEX_THREAD_ID || env.CODEX_SANDBOX || env.CODEX_CI)],
217
+ ["cursor", (env) => !!(env.CURSOR_AGENT || env.CURSOR_TRACE_ID)],
218
+ ["gemini", (env) => !!env.GEMINI_CLI],
219
+ ["github-copilot", (env) => !!env.COPILOT_CLI],
220
+ ["opencode", (env) => env.OPENCODE === "1" || !!env.OPENCODE_CLIENT],
221
+ ["qwen-code", (env) => !!env.QWEN_CODE],
222
+ ["antigravity", (env) => !!env.ANTIGRAVITY_AGENT],
223
+ ["augment", (env) => !!env.AUGMENT_AGENT],
224
+ ["cline", (env) => !!env.CLINE_ACTIVE],
225
+ ["roo", (env) => !!env.ROO_ACTIVE],
226
+ ["claude", (env) => !!(env.CLAUDECODE || env.CLAUDE_CODE)]
227
+ ];
228
+ var AGENT_MARKERS = [
229
+ "AI_AGENT",
230
+ "AGENT",
231
+ "CLAUDE_CODE_IS_COWORK",
232
+ "KILO",
233
+ "CODEX_THREAD_ID",
234
+ "CODEX_SANDBOX",
235
+ "CODEX_CI",
236
+ "CURSOR_AGENT",
237
+ "CURSOR_TRACE_ID",
238
+ "GEMINI_CLI",
239
+ "COPILOT_CLI",
240
+ "OPENCODE",
241
+ "OPENCODE_CLIENT",
242
+ "QWEN_CODE",
243
+ "ANTIGRAVITY_AGENT",
244
+ "AUGMENT_AGENT",
245
+ "CLINE_ACTIVE",
246
+ "ROO_ACTIVE",
247
+ "CLAUDECODE",
248
+ "CLAUDE_CODE"
249
+ ];
250
+ var declaredName = (value) => value?.trim().split(/[@_]/)[0]?.toLowerCase() || void 0;
251
+ function detectAgent(env) {
252
+ if (env.CLAUDE_CODE_IS_COWORK) return NAMES.cowork;
253
+ const declared = declaredName(env.AI_AGENT);
254
+ if (declared) return NAMES[declared] ?? declared;
255
+ const marked = MARKERS.find(([, test]) => test(env))?.[0];
256
+ if (marked) return NAMES[marked];
257
+ const agent = declaredName(env.AGENT);
258
+ if (agent && !/^(1|true|yes)$/.test(agent)) return NAMES[agent] ?? agent;
259
+ return void 0;
260
+ }
261
+
233
262
  // src/cli/comment.ts
234
263
  var COMMENT_ACTIONS = ["list", "add", "reply", "resolve"];
235
264
  var ARTIFACT = /^(document|artboard)\/[a-z0-9][a-z0-9-]*$/;
@@ -655,7 +684,7 @@ async function start(options, emit) {
655
684
  const lines = (readText(paths.log) ?? "").split("\n");
656
685
  const started = lines.find((line) => line.includes('"server-started"'));
657
686
  if (started) {
658
- for (let check = 0; check < 20; check++) {
687
+ for (let check2 = 0; check2 < 20; check2++) {
659
688
  if (!alive(child.pid)) throw new CliError(`Server started but was killed. Retry in a persistent terminal with: ${invocation()} start --project-dir ${paths.project}${options.artifact ? ` --artifact ${options.artifact}` : ""} --host ${options.host} --url-host ${options.urlHost} --foreground`);
660
689
  await sleep(100);
661
690
  }
@@ -782,6 +811,8 @@ running until Ctrl+C.
782
811
  Commands:
783
812
  start Start the project's artifacts server, or reuse the running one
784
813
  stop Stop the project's artifacts server; the artifacts are kept
814
+ check Wait until the server has checked the latest write, then print its warnings (needs a running server):
815
+ --artifact <type>/<id>
785
816
  publish Publish an artifact to the Ryugi cloud (needs a running server):
786
817
  --artifact <type>/<id> [--public | --private] [--unpublish]
787
818
  --list | --delete <cloud-id> | --login | --logout
@@ -822,6 +853,8 @@ function text(value) {
822
853
  ${value.url}`;
823
854
  if (value.type === "published") return `${value.url} (${value.visibility})`;
824
855
  if (value.type === "auto-publish") return `Auto-publish: ${value.global === null ? "not decided" : value.global ? "on" : "off"} for every project${value.project === null ? "" : `, ${value.project ? "on" : "off"} for this project`}.`;
856
+ const checked = checkText(value);
857
+ if (checked !== null) return checked;
825
858
  const commented = commentText(value);
826
859
  if (commented !== null) return commented;
827
860
  if (typeof value.status === "string") return value.status === "stopped" ? "Stopped." : value.status.replace(/_/g, " ");
@@ -890,6 +923,13 @@ async function main(argv) {
890
923
  const { values, positionals } = parse(rest, {}, 1);
891
924
  return await stop(values["project-dir"] ?? positionals[0] ?? process.cwd(), emit);
892
925
  }
926
+ if (command === "check") {
927
+ const { values } = parse(rest, { artifact: { type: "string" } });
928
+ return await check({
929
+ projectDir: values["project-dir"] ?? process.cwd(),
930
+ artifact: values.artifact
931
+ }, emit);
932
+ }
893
933
  if (command === "publish") {
894
934
  const { values } = parse(rest, {
895
935
  artifact: { type: "string" },
@@ -947,7 +987,7 @@ async function main(argv) {
947
987
  }, emit);
948
988
  }
949
989
  if (command === "--version" || command === "-v") {
950
- console.log("1.30.0");
990
+ console.log("1.31.1");
951
991
  return 0;
952
992
  }
953
993
  if (command === "--help" || command === "-h") {
package/dist/server.cjs CHANGED
@@ -5186,6 +5186,7 @@ var BOARD_TYPES = ["html", "image", "video"];
5186
5186
  var isMediaBoard = (board) => board.type === "image" || board.type === "video";
5187
5187
 
5188
5188
  // src/server/artifacts.ts
5189
+ var import_node_crypto = __toESM(require("node:crypto"), 1);
5189
5190
  var import_node_fs = __toESM(require("node:fs"), 1);
5190
5191
  var import_node_path = __toESM(require("node:path"), 1);
5191
5192
 
@@ -5233,9 +5234,9 @@ function artifactKeyOf(relative) {
5233
5234
  return { type, id: id2 };
5234
5235
  }
5235
5236
  function artifactSignature(dir, type) {
5236
- let count = 0;
5237
5237
  let size = 0;
5238
5238
  let latest = 0;
5239
+ const names = [];
5239
5240
  const walk = (current) => {
5240
5241
  let entries2;
5241
5242
  try {
@@ -5249,7 +5250,7 @@ function artifactSignature(dir, type) {
5249
5250
  const full = import_node_path.default.join(current, entry.name);
5250
5251
  try {
5251
5252
  const stat = import_node_fs.default.statSync(full);
5252
- count += 1;
5253
+ names.push(import_node_path.default.relative(dir, full));
5253
5254
  latest = Math.max(latest, stat.mtimeMs);
5254
5255
  if (entry.isDirectory()) walk(full);
5255
5256
  else size += stat.size;
@@ -5259,7 +5260,8 @@ function artifactSignature(dir, type) {
5259
5260
  }
5260
5261
  };
5261
5262
  walk(dir);
5262
- return `${count}:${size}:${latest}`;
5263
+ const hash = import_node_crypto.default.createHash("sha1").update(names.sort().join("\0")).digest("hex").slice(0, 12);
5264
+ return `${names.length}:${size}:${latest}:${hash}`;
5263
5265
  }
5264
5266
 
5265
5267
  // src/server/document.ts
@@ -5422,7 +5424,7 @@ function customAlphabet(alphabet, defaultSize = 21) {
5422
5424
  }
5423
5425
  var nanoid = customAlphabet(urlAlphabet);
5424
5426
 
5425
- // node_modules/.pnpm/@haklex+rich-litexml@0.54.2_typescript@5.9.3/node_modules/@haklex/rich-litexml/dist/src-BcPLrM3G.js
5427
+ // node_modules/.pnpm/@haklex+rich-litexml@0.54.3_typescript@5.9.3/node_modules/@haklex/rich-litexml/dist/src-CwO17cE7.js
5426
5428
  var impl = null;
5427
5429
  function registerParseHTML(fn5) {
5428
5430
  impl = fn5;
@@ -6699,6 +6701,7 @@ var INLINE_TAGS = /* @__PURE__ */ new Set([
6699
6701
  "strong",
6700
6702
  "em",
6701
6703
  "del",
6704
+ "strike",
6702
6705
  "a",
6703
6706
  "mention",
6704
6707
  "tag",
@@ -17569,11 +17572,11 @@ function Document4() {
17569
17572
  }
17570
17573
  setPrototypeOf(Document4, Document2).prototype = Document2.prototype;
17571
17574
 
17572
- // node_modules/.pnpm/@haklex+rich-litexml@0.54.2_typescript@5.9.3/node_modules/@haklex/rich-litexml/dist/node.mjs
17575
+ // node_modules/.pnpm/@haklex+rich-litexml@0.54.3_typescript@5.9.3/node_modules/@haklex/rich-litexml/dist/node.mjs
17573
17576
  registerParseHTML((html) => parseHTML2(html).document);
17574
17577
 
17575
17578
  // node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/index.js
17576
- var import_node_crypto = require("node:crypto");
17579
+ var import_node_crypto2 = require("node:crypto");
17577
17580
 
17578
17581
  // node_modules/.pnpm/nanoid@5.1.16/node_modules/nanoid/url-alphabet/index.js
17579
17582
  var urlAlphabet2 = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
@@ -17587,10 +17590,10 @@ function fillPool(bytes) {
17587
17590
  try {
17588
17591
  if (!pool || pool.length < bytes) {
17589
17592
  pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
17590
- import_node_crypto.webcrypto.getRandomValues(pool);
17593
+ import_node_crypto2.webcrypto.getRandomValues(pool);
17591
17594
  poolOffset = 0;
17592
17595
  } else if (poolOffset + bytes > pool.length) {
17593
- import_node_crypto.webcrypto.getRandomValues(pool);
17596
+ import_node_crypto2.webcrypto.getRandomValues(pool);
17594
17597
  poolOffset = 0;
17595
17598
  }
17596
17599
  } catch (e5) {
@@ -17800,7 +17803,7 @@ function boxDrawingDiagrams(state) {
17800
17803
  }
17801
17804
 
17802
17805
  // src/server/board-comments.ts
17803
- var import_node_crypto2 = __toESM(require("node:crypto"), 1);
17806
+ var import_node_crypto3 = __toESM(require("node:crypto"), 1);
17804
17807
  var import_node_fs8 = __toESM(require("node:fs"), 1);
17805
17808
  var import_node_path7 = __toESM(require("node:path"), 1);
17806
17809
 
@@ -18663,7 +18666,7 @@ function fileHash(dir, relative) {
18663
18666
  const stamp2 = `${stat.size}:${stat.mtimeMs}`;
18664
18667
  const cached = hashCache.get(file);
18665
18668
  if (cached?.stamp === stamp2) return cached.hash;
18666
- const hash = import_node_crypto2.default.createHash("sha1").update(import_node_fs8.default.readFileSync(file)).digest("hex").slice(0, 12);
18669
+ const hash = import_node_crypto3.default.createHash("sha1").update(import_node_fs8.default.readFileSync(file)).digest("hex").slice(0, 12);
18667
18670
  hashCache.set(file, { stamp: stamp2, hash });
18668
18671
  return hash;
18669
18672
  } catch {
@@ -53028,7 +53031,7 @@ decorateMethods(EphemeralStoreWasm.prototype, [
53028
53031
  ]);
53029
53032
  decorateMethods(UndoManager.prototype, ["undo", "redo"]);
53030
53033
 
53031
- // node_modules/.pnpm/@haklex+rich-collab-loro@0.54.2_lexical@0.52.0_typescript@5.9.3__loro-crdt@1.16.4/node_modules/@haklex/rich-collab-loro/dist/index.mjs
53034
+ // node_modules/.pnpm/@haklex+rich-collab-loro@0.54.3_lexical@0.52.0_typescript@5.9.3__loro-crdt@1.16.4/node_modules/@haklex/rich-collab-loro/dist/index.mjs
53032
53035
  function transformOffset(previous, next, offset) {
53033
53036
  const limit = Math.min(previous.length, next.length);
53034
53037
  let prefix = 0;
@@ -84443,7 +84446,7 @@ var UNORDERED_LIST2 = mod28.UNORDERED_LIST;
84443
84446
  var isTableRowDivider2 = mod28.isTableRowDivider;
84444
84447
  var registerMarkdownShortcuts2 = mod28.registerMarkdownShortcuts;
84445
84448
 
84446
- // node_modules/.pnpm/@haklex+rich-headless@0.54.2_lexical@0.52.0_typescript@5.9.3__typescript@5.9.3/node_modules/@haklex/rich-headless/dist/transformers.mjs
84449
+ // node_modules/.pnpm/@haklex+rich-headless@0.54.3_lexical@0.52.0_typescript@5.9.3__typescript@5.9.3/node_modules/@haklex/rich-headless/dist/transformers.mjs
84447
84450
  var NEVER = /a^/;
84448
84451
  var NOOP = () => {
84449
84452
  };
@@ -87115,7 +87118,7 @@ var signal2 = mod43.signal;
87115
87118
  var untracked2 = mod43.untracked;
87116
87119
  var watchedSignal3 = mod43.watchedSignal;
87117
87120
 
87118
- // node_modules/.pnpm/@haklex+rich-headless@0.54.2_lexical@0.52.0_typescript@5.9.3__typescript@5.9.3/node_modules/@haklex/rich-headless/dist/index.mjs
87121
+ // node_modules/.pnpm/@haklex+rich-headless@0.54.3_lexical@0.52.0_typescript@5.9.3__typescript@5.9.3/node_modules/@haklex/rich-headless/dist/index.mjs
87119
87122
  var builtinNodes = [
87120
87123
  HeadingNode2,
87121
87124
  QuoteNode2,
@@ -88956,7 +88959,7 @@ function injectRuntime(html, options = {}) {
88956
88959
  }
88957
88960
 
88958
88961
  // src/server/http.ts
88959
- var import_node_crypto3 = __toESM(require("node:crypto"), 1);
88962
+ var import_node_crypto4 = __toESM(require("node:crypto"), 1);
88960
88963
  var import_node_fs10 = __toESM(require("node:fs"), 1);
88961
88964
  var import_node_path10 = __toESM(require("node:path"), 1);
88962
88965
  var MIME2 = {
@@ -88982,11 +88985,11 @@ var MIME2 = {
88982
88985
  ".webm": "video/webm"
88983
88986
  };
88984
88987
  var mimeOf = (file) => MIME2[import_node_path10.default.extname(file).toLowerCase()] ?? "application/octet-stream";
88985
- var randomToken = () => import_node_crypto3.default.randomBytes(24).toString("base64url");
88988
+ var randomToken = () => import_node_crypto4.default.randomBytes(24).toString("base64url");
88986
88989
  function safeEqual(a5, b6) {
88987
88990
  const ab = Buffer.from(a5);
88988
88991
  const bb = Buffer.from(b6);
88989
- return ab.length === bb.length && import_node_crypto3.default.timingSafeEqual(ab, bb);
88992
+ return ab.length === bb.length && import_node_crypto4.default.timingSafeEqual(ab, bb);
88990
88993
  }
88991
88994
  function parseCookies(header) {
88992
88995
  const cookies = {};
@@ -89499,7 +89502,7 @@ function createRelayClient(options) {
89499
89502
  }
89500
89503
 
89501
89504
  // src/server/ws.ts
89502
- var import_node_crypto4 = __toESM(require("node:crypto"), 1);
89505
+ var import_node_crypto5 = __toESM(require("node:crypto"), 1);
89503
89506
  var WS_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
89504
89507
  var OPCODE_TEXT = 1;
89505
89508
  var OPCODE_CLOSE = 8;
@@ -89507,7 +89510,7 @@ var OPCODE_PING = 9;
89507
89510
  var OPCODE_PONG = 10;
89508
89511
  var MAX_CLIENT_FRAME = 8 * 1024 * 1024;
89509
89512
  function acceptKey(clientKey) {
89510
- return import_node_crypto4.default.createHash("sha1").update(clientKey + WS_MAGIC).digest("base64");
89513
+ return import_node_crypto5.default.createHash("sha1").update(clientKey + WS_MAGIC).digest("base64");
89511
89514
  }
89512
89515
  function encodeFrame(opcode, payload) {
89513
89516
  const len = payload.length;
@@ -89646,7 +89649,7 @@ function hostIdFor(credentialsFile2) {
89646
89649
  }
89647
89650
 
89648
89651
  // src/server/avatars.ts
89649
- var import_node_crypto5 = require("node:crypto");
89652
+ var import_node_crypto6 = require("node:crypto");
89650
89653
  var AVATAR_ROUTE = /^\/api\/avatar\/([a-z]+)\/([^/]+)$/;
89651
89654
  var MAX_BYTES = 512 * 1024;
89652
89655
  var TIMEOUT_MS = 5e3;
@@ -89655,7 +89658,7 @@ var SOURCES = {
89655
89658
  gravatar: { valid: /^[0-9a-f]{64}$/, url: (id2) => `https://gravatar.com/avatar/${id2}?s=64&d=404` }
89656
89659
  };
89657
89660
  var githubAvatar = (login) => `/api/avatar/github/${login}`;
89658
- var gravatarAvatar = (email) => `/api/avatar/gravatar/${(0, import_node_crypto5.createHash)("sha256").update(email.trim().toLowerCase()).digest("hex")}`;
89661
+ var gravatarAvatar = (email) => `/api/avatar/gravatar/${(0, import_node_crypto6.createHash)("sha256").update(email.trim().toLowerCase()).digest("hex")}`;
89659
89662
  function createAvatars(fetchImpl = fetch) {
89660
89663
  const cache = /* @__PURE__ */ new Map();
89661
89664
  const fetchAvatar = async (url) => {
@@ -89687,7 +89690,7 @@ function createAvatars(fetchImpl = fetch) {
89687
89690
  }
89688
89691
 
89689
89692
  // src/server/cloud.ts
89690
- var import_node_crypto6 = __toESM(require("node:crypto"), 1);
89693
+ var import_node_crypto7 = __toESM(require("node:crypto"), 1);
89691
89694
 
89692
89695
  // src/shared/brand.ts
89693
89696
  var RYUGI_MARK_VIEWBOX = "0 0 512 512";
@@ -90002,7 +90005,7 @@ function createCloudRoutes(options) {
90002
90005
  const state = randomToken();
90003
90006
  const verifier = randomToken();
90004
90007
  pendingStates.set(state, { expires: now + LOGIN_STATE_TTL_MS, verifier });
90005
- const challenge = import_node_crypto6.default.createHash("sha256").update(verifier).digest("base64url");
90008
+ const challenge = import_node_crypto7.default.createHash("sha256").update(verifier).digest("base64url");
90006
90009
  return `${origin}/auth/cli?port=${options.port()}&state=${state}&challenge=${challenge}`;
90007
90010
  };
90008
90011
  const cloudFetch = async (method, path22, body) => {
@@ -90074,7 +90077,7 @@ function createCloudRoutes(options) {
90074
90077
  } catch (err) {
90075
90078
  throw new CloudRefused(413, err.message);
90076
90079
  }
90077
- const sha = (data) => import_node_crypto6.default.createHash("sha256").update(data).digest("hex");
90080
+ const sha = (data) => import_node_crypto7.default.createHash("sha256").update(data).digest("hex");
90078
90081
  const hashed = withCloudRuntime(ref.type, packed).map((file) => ({ ...file, hash: sha(file.data) }));
90079
90082
  const content = { title: inspected.title, payload: inspected.payload, files: hashed.map(({ path: path22, hash }) => ({ path: path22, hash })) };
90080
90083
  const fingerprint = sha(JSON.stringify({ title: inspected.title, payload: fingerprintPayload(inspected.payload), files: packed.map((file) => ({ path: file.path, hash: sha(file.data) })) }));
@@ -90448,7 +90451,7 @@ function commentNames({ agentFile, projectDir, cloud }) {
90448
90451
  }
90449
90452
 
90450
90453
  // src/server/viewer-page.ts
90451
- var import_node_crypto7 = require("node:crypto");
90454
+ var import_node_crypto8 = require("node:crypto");
90452
90455
  var escapeHtml2 = (value) => value.replace(/[&<>"']/g, (ch) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[ch]);
90453
90456
  function viewerPage(template, page) {
90454
90457
  const values = {
@@ -90468,12 +90471,12 @@ function viewerPage(template, page) {
90468
90471
  }
90469
90472
  var INLINE_SCRIPT = /<script\b(?![^>]*\bsrc=)[^>]*>([\s\S]*?)<\/script>/gi;
90470
90473
  function allowInlineScripts(csp, html) {
90471
- const hashes = [...html.matchAll(INLINE_SCRIPT)].map(([, body]) => `'sha256-${(0, import_node_crypto7.createHash)("sha256").update(body).digest("base64")}'`);
90474
+ const hashes = [...html.matchAll(INLINE_SCRIPT)].map(([, body]) => `'sha256-${(0, import_node_crypto8.createHash)("sha256").update(body).digest("base64")}'`);
90472
90475
  return hashes.length ? csp.replace(/script-src [^;]*/, (directive) => `${directive} ${hashes.join(" ")}`) : csp;
90473
90476
  }
90474
90477
 
90475
90478
  // src/server/auto-publish.ts
90476
- var import_node_crypto8 = __toESM(require("node:crypto"), 1);
90479
+ var import_node_crypto9 = __toESM(require("node:crypto"), 1);
90477
90480
  var import_node_fs20 = __toESM(require("node:fs"), 1);
90478
90481
  var IDLE_MS = 5 * 60 * 1e3;
90479
90482
  var MAX_WAIT_MS = 15 * 60 * 1e3;
@@ -90508,7 +90511,7 @@ function createAutoPublisher(options) {
90508
90511
  const failures = /* @__PURE__ */ new Map();
90509
90512
  const save = () => writeJsonAtomic(options.stateFile, { dirty: [...dirty], notice, paused });
90510
90513
  const raise = (kind, message, upgradeUrl) => {
90511
- if (notice?.kind !== kind) notice = { id: import_node_crypto8.default.randomUUID(), kind, message, ...upgradeUrl ? { upgradeUrl } : {} };
90514
+ if (notice?.kind !== kind) notice = { id: import_node_crypto9.default.randomUUID(), kind, message, ...upgradeUrl ? { upgradeUrl } : {} };
90512
90515
  };
90513
90516
  let idleTimer = null;
90514
90517
  let maxTimer = null;
@@ -90723,9 +90726,12 @@ var MAX_COMMENT_OP = 64 * 1024;
90723
90726
  var API_AGENT_COMMENTS_ROUTE = /^\/api\/agent\/document\/([^/]+)\/comments$/;
90724
90727
  var API_BOARD_COMMENTS_ROUTE = /^\/api\/artboard\/([^/]+)\/comments$/;
90725
90728
  var API_AGENT_BOARD_COMMENTS_ROUTE = /^\/api\/agent\/artboard\/([^/]+)\/comments$/;
90729
+ var API_AGENT_CHECK_ROUTE = /^\/api\/agent\/([^/]+)\/([^/]+)\/check$/;
90726
90730
  var MAX_DOCUMENT_UPDATE = 8 * 1024 * 1024;
90727
90731
  var MAX_RELAY_FILE = 8 * 1024 * 1024;
90728
90732
  var MAX_RUNTIME_MESSAGE = 2048;
90733
+ var CHECK_WATCH_WAIT_MS = 2e3;
90734
+ var CHECK_MERGE_WAIT_MS = 6e4;
90729
90735
  var MAX_RUNTIME_WARNINGS = 20;
90730
90736
  function readArtifact(dir, ref, runtime = []) {
90731
90737
  if (ref.type === "artboard") return readCanvas(dir);
@@ -91235,6 +91241,17 @@ async function startArtifactsServer(options) {
91235
91241
  });
91236
91242
  return;
91237
91243
  }
91244
+ const agentCheckMatch = API_AGENT_CHECK_ROUTE.exec(pathname);
91245
+ if (agentCheckMatch) {
91246
+ if (req.method !== "POST" || key2 === null || !safeEqual(key2, token)) {
91247
+ send(res, 403, "Forbidden: agent calls need ?key=");
91248
+ return;
91249
+ }
91250
+ void serveAgentCheck(res, agentCheckMatch[1], agentCheckMatch[2]).catch((err) => {
91251
+ if (!res.headersSent) send(res, 500, `Artifacts error: ${err.message}`);
91252
+ });
91253
+ return;
91254
+ }
91238
91255
  const boardCommentsMatch = API_BOARD_COMMENTS_ROUTE.exec(pathname);
91239
91256
  if (boardCommentsMatch) {
91240
91257
  void serveBoardComments(req, res, boardCommentsMatch[1]).catch((err) => {
@@ -91431,6 +91448,31 @@ async function startArtifactsServer(options) {
91431
91448
  }
91432
91449
  }
91433
91450
  }) : null;
91451
+ const serveAgentCheck = async (res, type, id2) => {
91452
+ const ref = artifactKeyOf(`${type}/${id2}`);
91453
+ const dir = ref && resolveArtifactDir(root, ref.type, ref.id);
91454
+ if (!ref || !dir) {
91455
+ sendJson(res, 404, { error: `${type}/${id2} not found in ${root}` });
91456
+ return;
91457
+ }
91458
+ const key2 = `${ref.type}/${ref.id}`;
91459
+ for (let waited = 0; waited < CHECK_WATCH_WAIT_MS && signatures.get(key2) !== artifactSignature(dir, ref.type); waited += 50) {
91460
+ await new Promise((resolve) => setTimeout(resolve, 50));
91461
+ }
91462
+ let merging = false;
91463
+ if (ref.type === "document") {
91464
+ const session = await documents.open(ref.id);
91465
+ const text2 = await import_node_fs23.default.promises.readFile(import_node_path20.default.join(dir, "doc.xml"), "utf8").catch(() => null);
91466
+ if (session && text2 !== null) {
91467
+ session.onFileText(text2);
91468
+ const timeout = new Promise((resolve) => setTimeout(() => resolve("timeout"), CHECK_MERGE_WAIT_MS).unref());
91469
+ merging = await Promise.race([session.settled(), timeout]) === "timeout";
91470
+ }
91471
+ }
91472
+ writeState(ref, dir);
91473
+ const state = JSON.parse(await import_node_fs23.default.promises.readFile(import_node_path20.default.join(stateDir, ref.type, ref.id, "warnings.json"), "utf8"));
91474
+ sendJson(res, 200, merging ? { ...state, merging: true } : state);
91475
+ };
91434
91476
  const watcher = watchTree(
91435
91477
  root,
91436
91478
  (files) => {
@@ -91601,7 +91643,7 @@ function openReady(payload) {
91601
91643
  }
91602
91644
 
91603
91645
  // package.json
91604
- var version = "1.30.0";
91646
+ var version = "1.31.1";
91605
91647
 
91606
91648
  // src/server/main.ts
91607
91649
  async function main() {
@@ -1 +1 @@
1
- import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{n as t,t as n}from"./jsx-runtime-CldxteV5.js";import{a as r}from"./useSandboxFrame-DJc_WnFq.js";import{t as i}from"./index.js";import a from"./CloudDocument-F3ikpU1A.js";import{DocumentView as o,t as s}from"./DocumentPage-DJWzglCT.js";var c=e(t(),1),l=`1.30.0`,u=e=>/^(\d+)\.(\d+)\./.exec(e??``)?.slice(1,3).join(`.`)??null;function d(e,t){let n=u(e);return n!==null&&n===u(t)}var f=(e,t)=>`电脑上的 ryugi 是 ${t??`未知版本`},网页是 ${e},版本对上之前只能评论`,p=n();function m({id:e,state:t,contentBase:n,liveContentBase:u,comments:m}){let{transport:h,presence:g}=s(e,u??n??``),_=g?.online??!1;r(e,{online:g?.online??null});let[v,y]=(0,c.useState)(!1);if((0,c.useEffect)(()=>{_&&y(!0)},[_]),!h||!(v||_))return!t||!n?(0,p.jsx)(i,{children:g===null?`正在连接…`:`还没发布。电脑在线时,这里会实时显示。`}):(0,p.jsx)(a,{id:e,state:t,contentBase:n,comments:m,offline:g!==null&&!_});let b=_&&d(l,g?.version??null),x=_&&!b?f(l,g?.version??null):null;return(0,p.jsx)(o,{id:e,transport:h,live:_,cloud:{online:_,canEdit:b,reason:x}})}export{m as default};
1
+ import{i as e}from"./rolldown-runtime-COiEfhsA.js";import{n as t,t as n}from"./jsx-runtime-CldxteV5.js";import{a as r}from"./useSandboxFrame-DJc_WnFq.js";import{t as i}from"./index.js";import a from"./CloudDocument-F3ikpU1A.js";import{DocumentView as o,t as s}from"./DocumentPage-DJWzglCT.js";var c=e(t(),1),l=`1.31.1`,u=e=>/^(\d+)\.(\d+)\./.exec(e??``)?.slice(1,3).join(`.`)??null;function d(e,t){let n=u(e);return n!==null&&n===u(t)}var f=(e,t)=>`电脑上的 ryugi 是 ${t??`未知版本`},网页是 ${e},版本对上之前只能评论`,p=n();function m({id:e,state:t,contentBase:n,liveContentBase:u,comments:m}){let{transport:h,presence:g}=s(e,u??n??``),_=g?.online??!1;r(e,{online:g?.online??null});let[v,y]=(0,c.useState)(!1);if((0,c.useEffect)(()=>{_&&y(!0)},[_]),!h||!(v||_))return!t||!n?(0,p.jsx)(i,{children:g===null?`正在连接…`:`还没发布。电脑在线时,这里会实时显示。`}):(0,p.jsx)(a,{id:e,state:t,contentBase:n,comments:m,offline:g!==null&&!_});let b=_&&d(l,g?.version??null),x=_&&!b?f(l,g?.version??null):null;return(0,p.jsx)(o,{id:e,transport:h,live:_,cloud:{online:_,canEdit:b,reason:x}})}export{m as default};