@codeyam-editor/codeyam-editor 0.1.3 → 0.1.4
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/npm/cloud.js +289 -34
- package/npm/container.js +11 -0
- package/npm/disk-pressure.js +89 -0
- package/npm/editor-dev.js +11 -0
- package/npm/editor.js +12 -0
- package/npm/fleet-build-data.js +81 -0
- package/npm/fleet-cleanup.js +27 -0
- package/npm/fleet-job-badge.js +45 -1
- package/npm/fleet-plans.js +96 -0
- package/npm/fleet-reconcile.js +58 -1
- package/npm/launch-config.js +109 -4
- package/npm/scenario-check.js +81 -1
- package/npm/scenario-handlers.js +16 -0
- package/npm/utils.js +138 -7
- package/package.json +5 -5
- package/ui/dist/assets/EditorShell-tMMdarZD.js +187 -0
- package/ui/dist/assets/ScenarioDataPanel-xWYGZOpo.js +5 -0
- package/ui/dist/assets/{ScenarioDataPanelFullPage-Bnghtj8a.js → ScenarioDataPanelFullPage-5G6KuZgw.js} +1 -1
- package/ui/dist/assets/ScenarioRenderer-CSdhX1Ak.js +1 -0
- package/ui/dist/assets/index-BGqairFV.css +1 -0
- package/ui/dist/assets/{index-KDFAgt2e.js → index-BuK0lizt.js} +9 -9
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/EditorShell-CGsBSA6u.js +0 -186
- package/ui/dist/assets/ScenarioDataPanel-nuLXJzLf.js +0 -5
- package/ui/dist/assets/ScenarioRenderer-B_Za9jL8.js +0 -1
- package/ui/dist/assets/index-Bih6HJ_u.css +0 -1
package/npm/utils.js
CHANGED
|
@@ -620,6 +620,114 @@ function tryKillPid(pid) {
|
|
|
620
620
|
}
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
/**
|
|
624
|
+
* True when the launcher is attached to an interactive terminal — i.e. a human
|
|
625
|
+
* could have typed Ctrl+C. Headless / agent-driven launchers (cloud containers,
|
|
626
|
+
* `npm run editor` under a supervisor) have no tty here. Used to decide whether a
|
|
627
|
+
* received SIGINT is a deliberate "stop the editor" (forward it) or a stray
|
|
628
|
+
* group / spurious signal that must NOT reap the now-detached server.
|
|
629
|
+
*/
|
|
630
|
+
function isInteractiveLauncher(stream = process.stdout) {
|
|
631
|
+
return Boolean(stream && stream.isTTY);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Spawn options for the editor server child. The server is spawned `detached:
|
|
636
|
+
* true` so it leads its OWN session + process group (setsid), decoupling its
|
|
637
|
+
* lifetime from the launcher's controlling terminal and process group — a stray
|
|
638
|
+
* tty Ctrl+C or a group-wide `kill(-pgid, SIGINT)` can no longer reach it. stdio
|
|
639
|
+
* is detached from the terminal for the same reason (an inherited tty can still
|
|
640
|
+
* deliver tty signals to a detached child): stdout/stderr go to `logFd` when one
|
|
641
|
+
* is supplied, else are ignored — the Rust server writes its own
|
|
642
|
+
* `.codeyam/logs/editor-server.log` regardless.
|
|
643
|
+
*/
|
|
644
|
+
function buildServerSpawnOptions({ cwd, env, logFd = null }) {
|
|
645
|
+
return {
|
|
646
|
+
stdio: logFd === null ? "ignore" : ["ignore", logFd, logFd],
|
|
647
|
+
cwd,
|
|
648
|
+
detached: true,
|
|
649
|
+
env,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Open (creating dirs as needed) the launcher-managed server stdout/stderr log
|
|
655
|
+
* in append mode and return its fd, or null if it can't be opened. Kept separate
|
|
656
|
+
* from the Rust server's own structured `editor-server.log` so the two streams
|
|
657
|
+
* never interleave. Best-effort: a failure here just means the detached server's
|
|
658
|
+
* stdio is ignored, never that the launch itself fails.
|
|
659
|
+
*/
|
|
660
|
+
function openServerOutputLog(cwd) {
|
|
661
|
+
try {
|
|
662
|
+
const dir = path.join(cwd, ".codeyam", "logs");
|
|
663
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
664
|
+
return fs.openSync(path.join(dir, "editor-server.out.log"), "a");
|
|
665
|
+
} catch {
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Format one launcher-teardown-signal record for
|
|
672
|
+
* `.codeyam/logs/launcher-signals.log`. Pure: every input is passed in, so the
|
|
673
|
+
* formatting is unit-testable without a real signal or `ps`. Captures the
|
|
674
|
+
* launcher's own pid/ppid/pgid, whether it was interactive (a tty Ctrl+C) vs
|
|
675
|
+
* headless (a stray/spurious signal), the decision taken (forwarded teardown vs
|
|
676
|
+
* kept the server alive), and a best-effort `ps` group snapshot so the SENDER of
|
|
677
|
+
* a spurious `kill()` can be identified on the next repro.
|
|
678
|
+
*/
|
|
679
|
+
function formatLauncherSignalRecord({ signal, pid, ppid, pgid, interactive, forwarded, ps, timestamp }) {
|
|
680
|
+
const lines = [
|
|
681
|
+
`[${timestamp}] launcher-signal signal=${signal} pid=${pid} ppid=${ppid} pgid=${pgid} ` +
|
|
682
|
+
`interactive=${interactive} action=${forwarded ? "forwarded-teardown" : "ignored-kept-server-alive"}`,
|
|
683
|
+
];
|
|
684
|
+
if (ps && ps.trim() !== "") {
|
|
685
|
+
lines.push(ps.trimEnd());
|
|
686
|
+
}
|
|
687
|
+
return lines.join("\n") + "\n";
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Append a launcher-teardown-signal forensic record. Called from each launcher's
|
|
692
|
+
* SIGINT handler BEFORE it decides whether to forward, so a server reaped by a
|
|
693
|
+
* stray group SIGINT (or a spurious `kill()` to a headless launcher) always
|
|
694
|
+
* leaves a trail naming the launcher's process group. Best-effort: never throws,
|
|
695
|
+
* so a logging failure can never block the teardown decision.
|
|
696
|
+
*/
|
|
697
|
+
function logLauncherTeardownSignal(signal, projectDir, { interactive, forwarded }) {
|
|
698
|
+
try {
|
|
699
|
+
const pid = process.pid;
|
|
700
|
+
const ppid = typeof process.ppid === "number" ? process.ppid : -1;
|
|
701
|
+
let pgid = -1;
|
|
702
|
+
let ps = "";
|
|
703
|
+
if (process.platform !== "win32") {
|
|
704
|
+
const pgidOut = spawnSync("ps", ["-o", "pgid=", "-p", String(pid)], { encoding: "utf8" });
|
|
705
|
+
if (!pgidOut.error) {
|
|
706
|
+
pgid = parseInt(pgidOut.stdout.trim(), 10);
|
|
707
|
+
}
|
|
708
|
+
if (Number.isInteger(pgid) && pgid > 0) {
|
|
709
|
+
const grp = spawnSync("ps", ["-o", "pid,ppid,pgid,tpgid,comm", "-g", String(pgid)], { encoding: "utf8" });
|
|
710
|
+
if (!grp.error) ps = grp.stdout;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
const dir = path.join(projectDir, ".codeyam", "logs");
|
|
714
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
715
|
+
const record = formatLauncherSignalRecord({
|
|
716
|
+
signal,
|
|
717
|
+
pid,
|
|
718
|
+
ppid,
|
|
719
|
+
pgid,
|
|
720
|
+
interactive: Boolean(interactive),
|
|
721
|
+
forwarded: Boolean(forwarded),
|
|
722
|
+
ps,
|
|
723
|
+
timestamp: new Date().toISOString(),
|
|
724
|
+
});
|
|
725
|
+
fs.appendFileSync(path.join(dir, "launcher-signals.log"), record);
|
|
726
|
+
} catch {
|
|
727
|
+
/* best-effort forensics — never block teardown on a logging failure */
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
623
731
|
/**
|
|
624
732
|
* Send the platform-correct termination signal to a spawned child process.
|
|
625
733
|
* Used by editor.js / editor-dev.js / container.js when the user hits Ctrl+C —
|
|
@@ -726,12 +834,29 @@ async function ensureServer(port = 14199) {
|
|
|
726
834
|
const binary = ensureBinary();
|
|
727
835
|
// UI bundle is embedded in the Rust binary; CODEYAM_EDITOR_UI_DIR is
|
|
728
836
|
// now an explicit dev-override only.
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
837
|
+
//
|
|
838
|
+
// The server is spawned into its OWN session/process group (detached: true)
|
|
839
|
+
// with stdio detached from the launcher's controlling terminal, so a stray
|
|
840
|
+
// tty Ctrl+C or a group-wide SIGINT can no longer reap it — its lifetime is
|
|
841
|
+
// governed only by the launcher's deliberate teardown forward and the
|
|
842
|
+
// pidfile / API-shutdown paths. stdout/stderr are appended to
|
|
843
|
+
// `.codeyam/logs/editor-server.out.log` (the Rust server also writes its own
|
|
844
|
+
// editor-server.log). `unref()` keeps the detached child from pinning the
|
|
845
|
+
// launcher's event loop alive on its own.
|
|
846
|
+
const logFd = openServerOutputLog(process.cwd());
|
|
847
|
+
const child = spawn(
|
|
848
|
+
binary,
|
|
849
|
+
["start", "--no-open", "--port", String(port)],
|
|
850
|
+
buildServerSpawnOptions({ cwd: process.cwd(), env: process.env, logFd }),
|
|
851
|
+
);
|
|
852
|
+
if (logFd !== null) {
|
|
853
|
+
try {
|
|
854
|
+
fs.closeSync(logFd);
|
|
855
|
+
} catch {
|
|
856
|
+
/* child holds its own dup of the fd; the launcher's copy is no longer needed */
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
child.unref();
|
|
735
860
|
|
|
736
861
|
const { outcome, exitedBeforeBind } = await awaitServerReadyOrChildExit(child, port);
|
|
737
862
|
|
|
@@ -740,7 +865,8 @@ async function ensureServer(port = 14199) {
|
|
|
740
865
|
const detail = signal != null ? `signal ${signal}` : `code ${code}`;
|
|
741
866
|
console.error(
|
|
742
867
|
`codeyam-editor server exited (${detail}) before binding port ${port}. ` +
|
|
743
|
-
"Likely a preflight bail; see
|
|
868
|
+
"Likely a preflight bail; see .codeyam/logs/editor-server.out.log " +
|
|
869
|
+
"and .codeyam/logs/editor-server.log.",
|
|
744
870
|
);
|
|
745
871
|
// Always propagate as a real failure — even on code 0 the caller
|
|
746
872
|
// needs to know the server isn't running.
|
|
@@ -814,6 +940,11 @@ module.exports = {
|
|
|
814
940
|
restartServer,
|
|
815
941
|
ensureServer,
|
|
816
942
|
awaitServerReadyOrChildExit,
|
|
943
|
+
isInteractiveLauncher,
|
|
944
|
+
buildServerSpawnOptions,
|
|
945
|
+
openServerOutputLog,
|
|
946
|
+
formatLauncherSignalRecord,
|
|
947
|
+
logLauncherTeardownSignal,
|
|
817
948
|
killChildProcess,
|
|
818
949
|
deepMergeJson,
|
|
819
950
|
stripUnderscoreTopLevelKeys,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeyam-editor/codeyam-editor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Language-agnostic managed execution sandbox for scenario-driven development",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codeyam-editor": "./npm/cli.js"
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"playwright": "^1.58.2"
|
|
10
10
|
},
|
|
11
11
|
"optionalDependencies": {
|
|
12
|
-
"@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.
|
|
13
|
-
"@codeyam-editor/codeyam-editor-darwin-x64": "0.1.
|
|
14
|
-
"@codeyam-editor/codeyam-editor-linux-x64": "0.1.
|
|
15
|
-
"@codeyam-editor/codeyam-editor-win32-x64": "0.1.
|
|
12
|
+
"@codeyam-editor/codeyam-editor-darwin-arm64": "0.1.4",
|
|
13
|
+
"@codeyam-editor/codeyam-editor-darwin-x64": "0.1.4",
|
|
14
|
+
"@codeyam-editor/codeyam-editor-linux-x64": "0.1.4",
|
|
15
|
+
"@codeyam-editor/codeyam-editor-win32-x64": "0.1.4"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"codeyam",
|