ryugi-artifacts 1.11.0 → 1.12.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.cjs +181 -28
- package/dist/server.cjs +297 -75
- package/dist/viewer/index.js +12 -12
- package/dist/viewer/index2.css +29 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -295,11 +295,151 @@ function commentText(value) {
|
|
|
295
295
|
return null;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
+
// src/cli/config.ts
|
|
299
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
300
|
+
var import_node_path6 = __toESM(require("node:path"), 1);
|
|
301
|
+
|
|
302
|
+
// src/server/config.ts
|
|
303
|
+
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
304
|
+
var import_node_path3 = __toESM(require("node:path"), 1);
|
|
305
|
+
|
|
306
|
+
// src/shared/cloud.ts
|
|
307
|
+
var isVisibility = (value) => value === "private" || value === "public";
|
|
308
|
+
|
|
309
|
+
// src/server/state.ts
|
|
310
|
+
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
|
311
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
312
|
+
|
|
313
|
+
// src/shared/validate.ts
|
|
314
|
+
var BOARD_NUMBERS = ["x", "y", "w", "h"];
|
|
315
|
+
var BOARD_REQUIRED = ["file", "page", ...BOARD_NUMBERS];
|
|
316
|
+
|
|
317
|
+
// src/server/state.ts
|
|
318
|
+
function writeJsonAtomic(file, value) {
|
|
319
|
+
import_node_fs4.default.mkdirSync(import_node_path2.default.dirname(file), { recursive: true });
|
|
320
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
321
|
+
import_node_fs4.default.writeFileSync(tmp, `${JSON.stringify(value, null, 2)}
|
|
322
|
+
`, { mode: 384 });
|
|
323
|
+
import_node_fs4.default.renameSync(tmp, file);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// src/server/config.ts
|
|
327
|
+
var defaults = () => ({ version: 1, artifacts: {} });
|
|
328
|
+
function isCloudRecord(value) {
|
|
329
|
+
if (typeof value !== "object" || value === null) return false;
|
|
330
|
+
const { id, url, publishedAt, visibility } = value;
|
|
331
|
+
return typeof id === "string" && typeof url === "string" && (typeof publishedAt === "string" || publishedAt === null) && isVisibility(visibility);
|
|
332
|
+
}
|
|
333
|
+
function normalize(raw) {
|
|
334
|
+
const config2 = defaults();
|
|
335
|
+
if (typeof raw !== "object" || raw === null) return config2;
|
|
336
|
+
const { autoPublish } = raw;
|
|
337
|
+
if (typeof autoPublish === "boolean") config2.autoPublish = autoPublish;
|
|
338
|
+
const artifacts = raw.artifacts;
|
|
339
|
+
if (typeof artifacts !== "object" || artifacts === null) return config2;
|
|
340
|
+
for (const [key, value] of Object.entries(artifacts)) {
|
|
341
|
+
if (typeof value !== "object" || value === null) continue;
|
|
342
|
+
const { visibility, cloud, autoPublish: autoPublish2 } = value;
|
|
343
|
+
if (visibility !== void 0 && !isVisibility(visibility)) continue;
|
|
344
|
+
const entry = {};
|
|
345
|
+
if (visibility) entry.visibility = visibility;
|
|
346
|
+
if (isCloudRecord(cloud)) entry.cloud = { id: cloud.id, url: cloud.url, publishedAt: cloud.publishedAt, visibility: cloud.visibility };
|
|
347
|
+
if (autoPublish2 === false) entry.autoPublish = false;
|
|
348
|
+
config2.artifacts[key] = entry;
|
|
349
|
+
}
|
|
350
|
+
return config2;
|
|
351
|
+
}
|
|
352
|
+
function readConfig(file) {
|
|
353
|
+
let text2;
|
|
354
|
+
try {
|
|
355
|
+
text2 = import_node_fs5.default.readFileSync(file, "utf8");
|
|
356
|
+
} catch {
|
|
357
|
+
return { config: defaults() };
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
return { config: normalize(JSON.parse(text2)) };
|
|
361
|
+
} catch (err) {
|
|
362
|
+
return { config: defaults(), warning: `config.json is not valid JSON: ${err.message}` };
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function ensureGitignore(dir) {
|
|
366
|
+
const file = import_node_path3.default.join(dir, ".gitignore");
|
|
367
|
+
let current = "";
|
|
368
|
+
try {
|
|
369
|
+
current = import_node_fs5.default.readFileSync(file, "utf8");
|
|
370
|
+
} catch {
|
|
371
|
+
import_node_fs5.default.writeFileSync(file, "config.json\n");
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (current.split(/\r?\n/).some((line) => line.trim() === "config.json")) return;
|
|
375
|
+
import_node_fs5.default.writeFileSync(file, `${current}${current === "" || current.endsWith("\n") ? "" : "\n"}config.json
|
|
376
|
+
`);
|
|
377
|
+
}
|
|
378
|
+
function ensureConfig(file) {
|
|
379
|
+
import_node_fs5.default.mkdirSync(import_node_path3.default.dirname(file), { recursive: true });
|
|
380
|
+
ensureGitignore(import_node_path3.default.dirname(file));
|
|
381
|
+
if (!import_node_fs5.default.existsSync(file)) writeJsonAtomic(file, defaults());
|
|
382
|
+
}
|
|
383
|
+
function setProjectAutoPublish(file, value) {
|
|
384
|
+
const { config: config2, warning } = readConfig(file);
|
|
385
|
+
if (warning) throw new Error(warning);
|
|
386
|
+
if (value === null) delete config2.autoPublish;
|
|
387
|
+
else config2.autoPublish = value;
|
|
388
|
+
import_node_fs5.default.mkdirSync(import_node_path3.default.dirname(file), { recursive: true });
|
|
389
|
+
writeJsonAtomic(file, config2);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/server/credentials.ts
|
|
393
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
394
|
+
function credentialsFile(env, platform, home) {
|
|
395
|
+
if (platform === "win32" && env.APPDATA) return import_node_path4.default.join(env.APPDATA, "ryugi", "credentials.json");
|
|
396
|
+
return import_node_path4.default.join(env.XDG_CONFIG_HOME || import_node_path4.default.join(home, ".config"), "ryugi", "credentials.json");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// src/server/settings.ts
|
|
400
|
+
var import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
401
|
+
var import_node_path5 = __toESM(require("node:path"), 1);
|
|
402
|
+
var settingsFileFor = (credentialsFile2) => import_node_path5.default.join(import_node_path5.default.dirname(credentialsFile2), "config.json");
|
|
403
|
+
function readSettings(file) {
|
|
404
|
+
try {
|
|
405
|
+
const raw = JSON.parse(import_node_fs6.default.readFileSync(file, "utf8"));
|
|
406
|
+
return typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
|
|
407
|
+
} catch {
|
|
408
|
+
return {};
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function readGlobalAutoPublish(file) {
|
|
412
|
+
const value = readSettings(file).autoPublish;
|
|
413
|
+
return typeof value === "boolean" ? value : void 0;
|
|
414
|
+
}
|
|
415
|
+
function writeGlobalAutoPublish(file, value) {
|
|
416
|
+
import_node_fs6.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true, mode: 448 });
|
|
417
|
+
writeJsonAtomic(file, { ...readSettings(file), autoPublish: value });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/cli/config.ts
|
|
421
|
+
var VALUES = { on: true, off: false, inherit: null };
|
|
422
|
+
function config(options, emit) {
|
|
423
|
+
const globalFile = settingsFileFor(credentialsFile(process.env, process.platform, import_node_os.default.homedir()));
|
|
424
|
+
const projectFile = import_node_path6.default.join(import_node_path6.default.dirname(projectPaths(options.projectDir).root), "config.json");
|
|
425
|
+
if (options.autoPublish !== void 0) {
|
|
426
|
+
const value = VALUES[options.autoPublish];
|
|
427
|
+
if (value === void 0) throw new CliError("--auto-publish takes on, off, or (with --project) inherit");
|
|
428
|
+
if (options.project) {
|
|
429
|
+
ensureConfig(projectFile);
|
|
430
|
+
setProjectAutoPublish(projectFile, value);
|
|
431
|
+
} else if (value === null) throw new CliError("inherit only applies with --project");
|
|
432
|
+
else writeGlobalAutoPublish(globalFile, value);
|
|
433
|
+
}
|
|
434
|
+
emit({ type: "auto-publish", global: readGlobalAutoPublish(globalFile) ?? null, project: readConfig(projectFile).config.autoPublish ?? null });
|
|
435
|
+
return 0;
|
|
436
|
+
}
|
|
437
|
+
|
|
298
438
|
// src/cli/start.ts
|
|
299
439
|
var import_node_child_process2 = require("node:child_process");
|
|
300
440
|
var import_node_crypto = __toESM(require("node:crypto"), 1);
|
|
301
|
-
var
|
|
302
|
-
var
|
|
441
|
+
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
442
|
+
var import_node_path7 = __toESM(require("node:path"), 1);
|
|
303
443
|
var import_node_readline = __toESM(require("node:readline"), 1);
|
|
304
444
|
var windowsLike = () => process.platform === "win32";
|
|
305
445
|
function withLink(info, artifact, reused) {
|
|
@@ -314,13 +454,13 @@ function withLink(info, artifact, reused) {
|
|
|
314
454
|
async function acquireLock(lock) {
|
|
315
455
|
for (let attempt = 0; attempt < 150; attempt++) {
|
|
316
456
|
try {
|
|
317
|
-
|
|
457
|
+
import_node_fs7.default.mkdirSync(lock);
|
|
318
458
|
return true;
|
|
319
459
|
} catch {
|
|
320
460
|
}
|
|
321
461
|
try {
|
|
322
|
-
if (Date.now() -
|
|
323
|
-
|
|
462
|
+
if (Date.now() - import_node_fs7.default.statSync(lock).mtimeMs > 6e4) {
|
|
463
|
+
import_node_fs7.default.rmdirSync(lock);
|
|
324
464
|
continue;
|
|
325
465
|
}
|
|
326
466
|
} catch {
|
|
@@ -350,13 +490,13 @@ function registerOwner(paths) {
|
|
|
350
490
|
const owner = ownerPid();
|
|
351
491
|
if (owner) owners.add(owner);
|
|
352
492
|
const tmp = `${paths.owners}.${process.pid}`;
|
|
353
|
-
|
|
493
|
+
import_node_fs7.default.writeFileSync(tmp, [...owners].sort((a, b) => a - b).map((pid) => `${pid}
|
|
354
494
|
`).join(""));
|
|
355
|
-
|
|
495
|
+
import_node_fs7.default.renameSync(tmp, paths.owners);
|
|
356
496
|
}
|
|
357
497
|
function recordAgent(paths) {
|
|
358
498
|
const markers = Object.fromEntries(AGENT_MARKERS.flatMap((key) => process.env[key] ? [[key, process.env[key]]] : []));
|
|
359
|
-
if (Object.keys(markers).length)
|
|
499
|
+
if (Object.keys(markers).length) import_node_fs7.default.writeFileSync(paths.agent, `${JSON.stringify(markers)}
|
|
360
500
|
`);
|
|
361
501
|
}
|
|
362
502
|
async function replace(pid, paths) {
|
|
@@ -388,9 +528,9 @@ async function start(options, emit) {
|
|
|
388
528
|
const foreground = options.foreground || !options.background && (!!process.env.CODEX_CI || windowsLike());
|
|
389
529
|
process.umask(63);
|
|
390
530
|
const paths = projectPaths(options.projectDir);
|
|
391
|
-
|
|
392
|
-
if (!
|
|
393
|
-
const server =
|
|
531
|
+
import_node_fs7.default.mkdirSync(paths.state, { recursive: true });
|
|
532
|
+
if (!import_node_fs7.default.existsSync(import_node_path7.default.join(paths.state, ".gitignore"))) import_node_fs7.default.writeFileSync(import_node_path7.default.join(paths.state, ".gitignore"), "*\n");
|
|
533
|
+
const server = import_node_path7.default.join(__dirname, "server.cjs");
|
|
394
534
|
const version = process.env.RYUGI_ARTIFACTS_VERSION ?? "";
|
|
395
535
|
if (!await acquireLock(paths.lock)) throw new CliError("Another start for this project is still starting; retry in a moment");
|
|
396
536
|
let locked = true;
|
|
@@ -398,7 +538,7 @@ async function start(options, emit) {
|
|
|
398
538
|
if (!locked) return;
|
|
399
539
|
locked = false;
|
|
400
540
|
try {
|
|
401
|
-
|
|
541
|
+
import_node_fs7.default.rmdirSync(paths.lock);
|
|
402
542
|
} catch {
|
|
403
543
|
}
|
|
404
544
|
};
|
|
@@ -416,17 +556,17 @@ async function start(options, emit) {
|
|
|
416
556
|
}
|
|
417
557
|
registerOwner(paths);
|
|
418
558
|
recordAgent(paths);
|
|
419
|
-
|
|
559
|
+
import_node_fs7.default.rmSync(paths.info, { force: true });
|
|
420
560
|
const id = import_node_crypto.default.randomBytes(24).toString("hex");
|
|
421
|
-
|
|
561
|
+
import_node_fs7.default.writeFileSync(paths.serverId, `${id}
|
|
422
562
|
`);
|
|
423
|
-
|
|
563
|
+
import_node_fs7.default.writeFileSync(paths.version, `${version}
|
|
424
564
|
`);
|
|
425
565
|
const env = serverEnv(paths, options);
|
|
426
566
|
const args = [server, `--artifacts-server-id=${id}`];
|
|
427
567
|
if (foreground) {
|
|
428
568
|
const child2 = (0, import_node_child_process2.spawn)(process.execPath, args, { env, stdio: ["ignore", "pipe", "inherit"] });
|
|
429
|
-
|
|
569
|
+
import_node_fs7.default.writeFileSync(paths.pid, `${child2.pid}
|
|
430
570
|
`);
|
|
431
571
|
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => child2.kill("SIGTERM"));
|
|
432
572
|
import_node_readline.default.createInterface({ input: child2.stdout }).on("line", (line) => {
|
|
@@ -441,15 +581,15 @@ async function start(options, emit) {
|
|
|
441
581
|
emit(value.type === "server-started" ? withLink(value, options.artifact, false) : value);
|
|
442
582
|
});
|
|
443
583
|
const exited = new Promise((resolve) => child2.on("close", (code) => resolve(code ?? 1)));
|
|
444
|
-
for (let waited = 0; waited < 5e3 && !
|
|
584
|
+
for (let waited = 0; waited < 5e3 && !import_node_fs7.default.existsSync(paths.info); waited += 100) await sleep(100);
|
|
445
585
|
unlock();
|
|
446
586
|
return await exited;
|
|
447
587
|
}
|
|
448
|
-
const log =
|
|
588
|
+
const log = import_node_fs7.default.openSync(paths.log, "w");
|
|
449
589
|
const child = (0, import_node_child_process2.spawn)(process.execPath, args, { env, detached: true, stdio: ["ignore", log, log] });
|
|
450
|
-
|
|
590
|
+
import_node_fs7.default.closeSync(log);
|
|
451
591
|
child.unref();
|
|
452
|
-
|
|
592
|
+
import_node_fs7.default.writeFileSync(paths.pid, `${child.pid}
|
|
453
593
|
`);
|
|
454
594
|
for (let waited = 0; waited < 5e3; waited += 100) {
|
|
455
595
|
const lines = (readText(paths.log) ?? "").split("\n");
|
|
@@ -509,13 +649,13 @@ async function publish(options, emit) {
|
|
|
509
649
|
}
|
|
510
650
|
|
|
511
651
|
// src/cli/stop.ts
|
|
512
|
-
var
|
|
652
|
+
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
|
513
653
|
async function stop(projectDir, emit) {
|
|
514
654
|
const paths = projectPaths(projectDir);
|
|
515
655
|
const markStopped = (reason) => {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
656
|
+
import_node_fs8.default.rmSync(paths.info, { force: true });
|
|
657
|
+
import_node_fs8.default.mkdirSync(paths.state, { recursive: true });
|
|
658
|
+
import_node_fs8.default.writeFileSync(paths.stopped, `${JSON.stringify({ reason, timestamp: Math.floor(Date.now() / 1e3) })}
|
|
519
659
|
`);
|
|
520
660
|
};
|
|
521
661
|
const pid = Number(readText(paths.pid));
|
|
@@ -525,8 +665,8 @@ async function stop(projectDir, emit) {
|
|
|
525
665
|
}
|
|
526
666
|
const id = readText(paths.serverId) ?? "";
|
|
527
667
|
if (!Number.isInteger(pid) || pid <= 0 || !/^[A-Za-z0-9_-]{32,64}$/.test(id) || !hasServerId(pid, id)) {
|
|
528
|
-
|
|
529
|
-
|
|
668
|
+
import_node_fs8.default.rmSync(paths.pid, { force: true });
|
|
669
|
+
import_node_fs8.default.rmSync(paths.serverId, { force: true });
|
|
530
670
|
markStopped("stale_pid");
|
|
531
671
|
emit({ status: "stale_pid" });
|
|
532
672
|
return 0;
|
|
@@ -546,7 +686,7 @@ async function stop(projectDir, emit) {
|
|
|
546
686
|
emit({ status: "failed", error: "process still running" });
|
|
547
687
|
return 1;
|
|
548
688
|
}
|
|
549
|
-
for (const file of [paths.pid, paths.serverId, paths.log, paths.owners])
|
|
689
|
+
for (const file of [paths.pid, paths.serverId, paths.log, paths.owners]) import_node_fs8.default.rmSync(file, { force: true });
|
|
550
690
|
markStopped("stop");
|
|
551
691
|
emit({ status: "stopped" });
|
|
552
692
|
return 0;
|
|
@@ -571,6 +711,10 @@ Commands:
|
|
|
571
711
|
reply --artifact document/<id> --thread <threadId> [--text <text>]
|
|
572
712
|
resolve --artifact document/<id> --thread <threadId>
|
|
573
713
|
Without --text, add and reply read the message from stdin.
|
|
714
|
+
config Auto-publish changed artifacts as private cloud copies when the agent's turn ends:
|
|
715
|
+
--auto-publish on|off for every project
|
|
716
|
+
--auto-publish on|off|inherit --project override for this project only
|
|
717
|
+
Without --auto-publish, prints the current values.
|
|
574
718
|
|
|
575
719
|
Options:
|
|
576
720
|
--project-dir <path> Project directory (default: current directory)
|
|
@@ -596,6 +740,7 @@ function text(value) {
|
|
|
596
740
|
if (value.type === "login-required" || value.type === "login") return `${value.message}
|
|
597
741
|
${value.url}`;
|
|
598
742
|
if (value.type === "published") return `${value.url} (${value.visibility})`;
|
|
743
|
+
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`}.`;
|
|
599
744
|
const commented = commentText(value);
|
|
600
745
|
if (commented !== null) return commented;
|
|
601
746
|
if (typeof value.status === "string") return value.status === "stopped" ? "Stopped." : value.status.replace(/_/g, " ");
|
|
@@ -706,8 +851,16 @@ async function main(argv) {
|
|
|
706
851
|
text: values.text
|
|
707
852
|
}, emit);
|
|
708
853
|
}
|
|
854
|
+
if (command === "config") {
|
|
855
|
+
const { values } = parse(rest, { "auto-publish": { type: "string" }, project: { type: "boolean" } });
|
|
856
|
+
return config({
|
|
857
|
+
projectDir: values["project-dir"] ?? process.cwd(),
|
|
858
|
+
autoPublish: values["auto-publish"],
|
|
859
|
+
project: !!values.project
|
|
860
|
+
}, emit);
|
|
861
|
+
}
|
|
709
862
|
if (command === "--version" || command === "-v") {
|
|
710
|
-
console.log("1.
|
|
863
|
+
console.log("1.12.0");
|
|
711
864
|
return 0;
|
|
712
865
|
}
|
|
713
866
|
if (command === "--help" || command === "-h") {
|