@slayzone/cli 0.36.0-beta.12 → 0.36.0-beta.15
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/slay.js +455 -491
- package/package.json +1 -1
package/dist/slay.js
CHANGED
|
@@ -28443,9 +28443,6 @@ var {
|
|
|
28443
28443
|
// ../../shared/platform/src/hub-discovery.ts
|
|
28444
28444
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
28445
28445
|
|
|
28446
|
-
// ../../shared/platform/src/paths.ts
|
|
28447
|
-
var import_node_path = require("node:path");
|
|
28448
|
-
|
|
28449
28446
|
// ../../shared/platform/src/dirs.ts
|
|
28450
28447
|
var import_path = __toESM(require("path"), 1);
|
|
28451
28448
|
var import_os = __toESM(require("os"), 1);
|
|
@@ -28495,8 +28492,13 @@ function parseHubAddress(addr) {
|
|
|
28495
28492
|
|
|
28496
28493
|
// ../../shared/platform/src/paths.ts
|
|
28497
28494
|
function getStorageDir() {
|
|
28498
|
-
return
|
|
28495
|
+
return getSlayzoneHomeDir();
|
|
28499
28496
|
}
|
|
28497
|
+
var SIDECAR_FIXED_PORT = {
|
|
28498
|
+
prod: 51100,
|
|
28499
|
+
dev: 51101,
|
|
28500
|
+
test: 51102
|
|
28501
|
+
};
|
|
28500
28502
|
var HUB_PORT_BLOCK = { start: 51100, end: 51199 };
|
|
28501
28503
|
|
|
28502
28504
|
// ../../shared/platform/src/hub-discovery.ts
|
|
@@ -28605,9 +28607,7 @@ async function findHub(nameOrPort, opts = {}) {
|
|
|
28605
28607
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
28606
28608
|
var import_path3 = __toESM(require("path"), 1);
|
|
28607
28609
|
|
|
28608
|
-
// src/
|
|
28609
|
-
var import_node_sqlite = require("node:sqlite");
|
|
28610
|
-
var import_node_http2 = __toESM(require("node:http"), 1);
|
|
28610
|
+
// src/cli-state.ts
|
|
28611
28611
|
var import_fs = __toESM(require("fs"), 1);
|
|
28612
28612
|
var import_path2 = __toESM(require("path"), 1);
|
|
28613
28613
|
var import_os2 = __toESM(require("os"), 1);
|
|
@@ -28617,18 +28617,6 @@ var import_child_process = require("child_process");
|
|
|
28617
28617
|
var import_util = require("util");
|
|
28618
28618
|
var execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
|
|
28619
28619
|
|
|
28620
|
-
// ../../shared/platform/src/db.ts
|
|
28621
|
-
var DB_PRAGMAS = [
|
|
28622
|
-
"journal_mode = WAL",
|
|
28623
|
-
"foreign_keys = ON",
|
|
28624
|
-
"synchronous = NORMAL",
|
|
28625
|
-
"cache_size = -8000",
|
|
28626
|
-
"busy_timeout = 5000"
|
|
28627
|
-
];
|
|
28628
|
-
function getDbName(packaged) {
|
|
28629
|
-
return packaged ? "slayzone.sqlite" : "slayzone.dev.sqlite";
|
|
28630
|
-
}
|
|
28631
|
-
|
|
28632
28620
|
// ../../shared/platform/src/slz-file-url.ts
|
|
28633
28621
|
var SLZ_FILE_HOST = "app";
|
|
28634
28622
|
var SLZ_FILE_PREFIX = `slz-file://${SLZ_FILE_HOST}`;
|
|
@@ -28636,182 +28624,34 @@ var SLZ_FILE_PREFIX = `slz-file://${SLZ_FILE_HOST}`;
|
|
|
28636
28624
|
// ../../shared/platform/src/ipc-dedup.ts
|
|
28637
28625
|
var UNCHANGED = Object.freeze({ __ipc_unchanged__: true });
|
|
28638
28626
|
|
|
28639
|
-
// src/
|
|
28640
|
-
function
|
|
28641
|
-
const
|
|
28642
|
-
|
|
28643
|
-
console.error("No --project provided and $SLAYZONE_PROJECT_ID is not set.");
|
|
28644
|
-
process.exit(1);
|
|
28645
|
-
}
|
|
28646
|
-
return val;
|
|
28647
|
-
}
|
|
28648
|
-
|
|
28649
|
-
// src/db.ts
|
|
28650
|
-
function defaultDir() {
|
|
28651
|
-
const dir = getStorageDir();
|
|
28652
|
-
if (import_fs.default.existsSync(dir)) return dir;
|
|
28653
|
-
if (process.platform === "linux") {
|
|
28654
|
-
const configHome = process.env.XDG_CONFIG_HOME || import_path2.default.join(import_os2.default.homedir(), ".config");
|
|
28655
|
-
const legacyDir = import_path2.default.join(configHome, "slayzone");
|
|
28656
|
-
if (import_fs.default.existsSync(legacyDir)) return legacyDir;
|
|
28657
|
-
}
|
|
28658
|
-
return dir;
|
|
28659
|
-
}
|
|
28660
|
-
function getDbPath(dev) {
|
|
28661
|
-
return import_path2.default.join(defaultDir(), getDbName(!dev));
|
|
28662
|
-
}
|
|
28663
|
-
function loopbackHubPort() {
|
|
28664
|
-
const parsed = parseHubAddress(process.env.SLAYZONE_HUB_ADDRESS);
|
|
28665
|
-
if (!parsed?.port) return null;
|
|
28666
|
-
return LOOPBACK_HOSTS.has(parsed.host) ? parsed.port : null;
|
|
28667
|
-
}
|
|
28668
|
-
function hasLocalDatabase() {
|
|
28669
|
-
return import_fs.default.existsSync(getDbPath(process.env.SLAYZONE_DEV === "1"));
|
|
28670
|
-
}
|
|
28671
|
-
function getServerPort() {
|
|
28672
|
-
const envPort = loopbackHubPort();
|
|
28673
|
-
if (envPort) return envPort;
|
|
28674
|
-
try {
|
|
28675
|
-
const db = openDb();
|
|
28676
|
-
const row = db.query(
|
|
28677
|
-
`SELECT value FROM settings WHERE key = 'server_port' LIMIT 1`
|
|
28678
|
-
);
|
|
28679
|
-
db.close();
|
|
28680
|
-
const port = parseInt(row[0]?.value ?? "", 10);
|
|
28681
|
-
return port > 0 && port <= 65535 ? port : null;
|
|
28682
|
-
} catch {
|
|
28683
|
-
return null;
|
|
28684
|
-
}
|
|
28685
|
-
}
|
|
28686
|
-
function getAlternateServerPort() {
|
|
28687
|
-
if (loopbackHubPort()) return null;
|
|
28688
|
-
const dev = process.env.SLAYZONE_DEV === "1";
|
|
28689
|
-
const altPath = getDbPath(!dev);
|
|
28690
|
-
if (!import_fs.default.existsSync(altPath)) return null;
|
|
28691
|
-
try {
|
|
28692
|
-
const altDb = new import_node_sqlite.DatabaseSync(altPath);
|
|
28693
|
-
const row = altDb.prepare(`SELECT value FROM settings WHERE key = 'server_port' LIMIT 1`).get();
|
|
28694
|
-
altDb.close();
|
|
28695
|
-
const port = parseInt(row?.value ?? "", 10);
|
|
28696
|
-
return port > 0 && port <= 65535 ? port : null;
|
|
28697
|
-
} catch {
|
|
28698
|
-
return null;
|
|
28699
|
-
}
|
|
28700
|
-
}
|
|
28701
|
-
function postJson(port, path9, timeoutMs = 3e3) {
|
|
28702
|
-
return new Promise((resolve) => {
|
|
28703
|
-
const req = import_node_http2.default.request({ hostname: "127.0.0.1", port, path: path9, method: "POST" }, (res) => {
|
|
28704
|
-
res.resume();
|
|
28705
|
-
res.on("end", () => {
|
|
28706
|
-
const code = res.statusCode ?? 0;
|
|
28707
|
-
resolve(code >= 200 && code < 300);
|
|
28708
|
-
});
|
|
28709
|
-
});
|
|
28710
|
-
req.on("error", () => resolve(false));
|
|
28711
|
-
req.setTimeout(timeoutMs, () => {
|
|
28712
|
-
req.destroy();
|
|
28713
|
-
resolve(false);
|
|
28714
|
-
});
|
|
28715
|
-
req.end();
|
|
28716
|
-
});
|
|
28717
|
-
}
|
|
28718
|
-
function probePort(port) {
|
|
28719
|
-
return postJson(port, "/api/notify", 1e3);
|
|
28720
|
-
}
|
|
28721
|
-
async function postHubNotify(hub, timeoutMs = 3e3) {
|
|
28722
|
-
try {
|
|
28723
|
-
const headers = hub.token ? { Authorization: `Bearer ${hub.token}` } : {};
|
|
28724
|
-
const res = await fetch(`${hub.baseUrl}/api/notify`, {
|
|
28725
|
-
method: "POST",
|
|
28726
|
-
headers,
|
|
28727
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
28728
|
-
});
|
|
28729
|
-
return res.ok;
|
|
28730
|
-
} catch {
|
|
28731
|
-
return false;
|
|
28732
|
-
}
|
|
28733
|
-
}
|
|
28734
|
-
async function notifyApp() {
|
|
28735
|
-
const hub = resolveHubTarget();
|
|
28736
|
-
if (hub) {
|
|
28737
|
-
const ok = await postHubNotify(hub);
|
|
28738
|
-
if (!ok) {
|
|
28739
|
-
console.error(
|
|
28740
|
-
"Warning: hub notify failed (POST /api/notify) \u2014 hub may be stale or unreachable"
|
|
28741
|
-
);
|
|
28742
|
-
}
|
|
28743
|
-
return;
|
|
28744
|
-
}
|
|
28745
|
-
const port = getServerPort();
|
|
28746
|
-
if (port) {
|
|
28747
|
-
const ok = await postJson(port, "/api/notify");
|
|
28748
|
-
if (!ok) {
|
|
28749
|
-
console.error(
|
|
28750
|
-
"Warning: app notify failed (POST /api/notify) \u2014 app may be stale or unreachable"
|
|
28751
|
-
);
|
|
28752
|
-
}
|
|
28753
|
-
return;
|
|
28754
|
-
}
|
|
28755
|
-
const altPort = getAlternateServerPort();
|
|
28756
|
-
if (altPort && await probePort(altPort)) {
|
|
28757
|
-
const dev = process.env.SLAYZONE_DEV === "1";
|
|
28758
|
-
const hint = dev ? "without --dev" : "with --dev";
|
|
28759
|
-
console.error(
|
|
28760
|
-
`Warning: SlayZone app is running ${hint}. Changes were saved but the app was not notified.`
|
|
28761
|
-
);
|
|
28762
|
-
console.error(` Re-run ${dev ? "without --dev" : "with --dev"} to target the same database.`);
|
|
28763
|
-
}
|
|
28627
|
+
// src/cli-state.ts
|
|
28628
|
+
function getCliStateDir() {
|
|
28629
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_os2.default.homedir();
|
|
28630
|
+
return import_path2.default.join(home, ".slayzone", "cli");
|
|
28764
28631
|
}
|
|
28765
|
-
function
|
|
28766
|
-
const
|
|
28767
|
-
return import_path2.default.join(
|
|
28632
|
+
function getHubTargetPath() {
|
|
28633
|
+
const name = process.env.SLAYZONE_DEV === "1" ? "hub-target.dev.json" : "hub-target.json";
|
|
28634
|
+
return import_path2.default.join(getCliStateDir(), name);
|
|
28768
28635
|
}
|
|
28769
|
-
function
|
|
28770
|
-
|
|
28771
|
-
const dbPath = getDbPath(dev);
|
|
28772
|
-
if (!import_fs.default.existsSync(dbPath)) {
|
|
28773
|
-
console.error(`Database not found: ${dbPath}`);
|
|
28774
|
-
const altPath = getDbPath(!dev);
|
|
28775
|
-
if (import_fs.default.existsSync(altPath)) {
|
|
28776
|
-
const hint = dev ? "without --dev" : "with --dev";
|
|
28777
|
-
console.error(`Found other database at: ${altPath}`);
|
|
28778
|
-
console.error(`Re-run ${hint} to target that database.`);
|
|
28779
|
-
} else {
|
|
28780
|
-
console.error("Make sure SlayZone has been launched at least once.");
|
|
28781
|
-
}
|
|
28782
|
-
process.exit(1);
|
|
28783
|
-
}
|
|
28784
|
-
const db = new import_node_sqlite.DatabaseSync(dbPath);
|
|
28785
|
-
for (const pragma of DB_PRAGMAS) {
|
|
28786
|
-
db.exec(`PRAGMA ${pragma}`);
|
|
28787
|
-
}
|
|
28788
|
-
return {
|
|
28789
|
-
query(sql, params = {}) {
|
|
28790
|
-
return db.prepare(sql).all(params);
|
|
28791
|
-
},
|
|
28792
|
-
run(sql, params = {}) {
|
|
28793
|
-
db.prepare(sql).run(params);
|
|
28794
|
-
},
|
|
28795
|
-
close() {
|
|
28796
|
-
db.close();
|
|
28797
|
-
},
|
|
28798
|
-
raw() {
|
|
28799
|
-
return db;
|
|
28800
|
-
}
|
|
28801
|
-
};
|
|
28636
|
+
function getServiceRuntimeDir(kind) {
|
|
28637
|
+
return import_path2.default.join(getCliStateDir(), `${kind}-runtime`);
|
|
28802
28638
|
}
|
|
28803
|
-
function
|
|
28804
|
-
|
|
28639
|
+
function legacyHubTargetPaths() {
|
|
28640
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? import_os2.default.homedir();
|
|
28641
|
+
const candidates = [
|
|
28642
|
+
import_path2.default.join(getStorageDir(), "cli-hub-target.json"),
|
|
28643
|
+
import_path2.default.join(home, ".slayzone", "cli-hub-target.json")
|
|
28644
|
+
];
|
|
28645
|
+
return candidates.filter((p2, i) => candidates.indexOf(p2) === i && import_fs.default.existsSync(p2));
|
|
28805
28646
|
}
|
|
28806
28647
|
|
|
28807
28648
|
// src/hub-config.ts
|
|
28808
|
-
var HUB_CONFIG_FILENAME = "hub.json";
|
|
28809
28649
|
var hubOverride = null;
|
|
28810
28650
|
function setHubOverride(target) {
|
|
28811
28651
|
hubOverride = target;
|
|
28812
28652
|
}
|
|
28813
28653
|
function getHubConfigPath() {
|
|
28814
|
-
return
|
|
28654
|
+
return getHubTargetPath();
|
|
28815
28655
|
}
|
|
28816
28656
|
function normalizeHubUrl(raw) {
|
|
28817
28657
|
const trimmed = raw.trim();
|
|
@@ -28825,8 +28665,13 @@ function normalizeHubUrl(raw) {
|
|
|
28825
28665
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
28826
28666
|
return `${parsed.origin}${parsed.pathname.replace(/\/+$/, "")}`;
|
|
28827
28667
|
}
|
|
28668
|
+
function hubFilePathForRead() {
|
|
28669
|
+
const current = getHubConfigPath();
|
|
28670
|
+
if (import_fs2.default.existsSync(current)) return current;
|
|
28671
|
+
return legacyHubTargetPaths()[0] ?? current;
|
|
28672
|
+
}
|
|
28828
28673
|
function readHubFile() {
|
|
28829
|
-
const configPath =
|
|
28674
|
+
const configPath = hubFilePathForRead();
|
|
28830
28675
|
let rawText;
|
|
28831
28676
|
try {
|
|
28832
28677
|
rawText = import_fs2.default.readFileSync(configPath, "utf-8");
|
|
@@ -28888,20 +28733,43 @@ function writeHubConfig(url, token) {
|
|
|
28888
28733
|
return configPath;
|
|
28889
28734
|
}
|
|
28890
28735
|
function removeHubConfig() {
|
|
28736
|
+
let removed = false;
|
|
28737
|
+
for (const target of [getHubConfigPath(), ...legacyHubTargetPaths()]) {
|
|
28738
|
+
try {
|
|
28739
|
+
import_fs2.default.unlinkSync(target);
|
|
28740
|
+
removed = true;
|
|
28741
|
+
} catch (e) {
|
|
28742
|
+
if (e.code !== "ENOENT") throw e;
|
|
28743
|
+
}
|
|
28744
|
+
}
|
|
28745
|
+
return removed;
|
|
28746
|
+
}
|
|
28747
|
+
|
|
28748
|
+
// src/local-hub.ts
|
|
28749
|
+
function fixedPortForChannel() {
|
|
28750
|
+
return process.env.SLAYZONE_DEV === "1" ? SIDECAR_FIXED_PORT.dev : SIDECAR_FIXED_PORT.prod;
|
|
28751
|
+
}
|
|
28752
|
+
async function probeFixedPort() {
|
|
28753
|
+
const port = fixedPortForChannel();
|
|
28754
|
+
const hub = await findHub(String(port));
|
|
28755
|
+
return hub ? hub.port : null;
|
|
28756
|
+
}
|
|
28757
|
+
async function isCoLocatedHub() {
|
|
28758
|
+
const configured = resolveHubTarget();
|
|
28759
|
+
if (!configured) return true;
|
|
28891
28760
|
try {
|
|
28892
|
-
|
|
28893
|
-
return
|
|
28894
|
-
} catch
|
|
28895
|
-
|
|
28896
|
-
throw e;
|
|
28761
|
+
const host = new URL(configured.baseUrl).hostname.replace(/^\[|\]$/g, "");
|
|
28762
|
+
return LOOPBACK_HOSTS.has(host);
|
|
28763
|
+
} catch {
|
|
28764
|
+
return false;
|
|
28897
28765
|
}
|
|
28898
28766
|
}
|
|
28899
28767
|
|
|
28900
28768
|
// src/api.ts
|
|
28901
|
-
function resolveTarget() {
|
|
28769
|
+
async function resolveTarget() {
|
|
28902
28770
|
const hub = resolveHubTarget();
|
|
28903
28771
|
if (hub) return { baseUrl: hub.baseUrl, token: hub.token, hub: true };
|
|
28904
|
-
const port =
|
|
28772
|
+
const port = await probeFixedPort();
|
|
28905
28773
|
if (!port) {
|
|
28906
28774
|
console.error("SlayZone server port not found. Is the app running?");
|
|
28907
28775
|
process.exit(1);
|
|
@@ -28923,7 +28791,7 @@ function connectError(target) {
|
|
|
28923
28791
|
process.exit(1);
|
|
28924
28792
|
}
|
|
28925
28793
|
async function request(path9, init) {
|
|
28926
|
-
const target = resolveTarget();
|
|
28794
|
+
const target = await resolveTarget();
|
|
28927
28795
|
let res;
|
|
28928
28796
|
try {
|
|
28929
28797
|
res = await fetch(`${target.baseUrl}${path9}`, withAuth(init, target.token));
|
|
@@ -28961,7 +28829,7 @@ function apiDelete(path9, body) {
|
|
|
28961
28829
|
});
|
|
28962
28830
|
}
|
|
28963
28831
|
async function apiFetch(path9, init) {
|
|
28964
|
-
const target = resolveTarget();
|
|
28832
|
+
const target = await resolveTarget();
|
|
28965
28833
|
try {
|
|
28966
28834
|
return await fetch(`${target.baseUrl}${path9}`, withAuth(init, target.token));
|
|
28967
28835
|
} catch {
|
|
@@ -28969,7 +28837,7 @@ async function apiFetch(path9, init) {
|
|
|
28969
28837
|
}
|
|
28970
28838
|
}
|
|
28971
28839
|
async function apiGetStream(path9, passThroughCodes = []) {
|
|
28972
|
-
const target = resolveTarget();
|
|
28840
|
+
const target = await resolveTarget();
|
|
28973
28841
|
let res;
|
|
28974
28842
|
try {
|
|
28975
28843
|
res = await fetch(`${target.baseUrl}${path9}`, withAuth(void 0, target.token));
|
|
@@ -28992,7 +28860,7 @@ async function apiGetStream(path9, passThroughCodes = []) {
|
|
|
28992
28860
|
return { body: res.body };
|
|
28993
28861
|
}
|
|
28994
28862
|
async function requestStream(method, path9, body) {
|
|
28995
|
-
const target = resolveTarget();
|
|
28863
|
+
const target = await resolveTarget();
|
|
28996
28864
|
let res;
|
|
28997
28865
|
try {
|
|
28998
28866
|
res = await fetch(`${target.baseUrl}${path9}`, {
|
|
@@ -29035,171 +28903,6 @@ function failFromText(body, status) {
|
|
|
29035
28903
|
process.exit(1);
|
|
29036
28904
|
}
|
|
29037
28905
|
|
|
29038
|
-
// ../../domains/terminal/src/shared/types.ts
|
|
29039
|
-
var BuiltinTerminalMode = {
|
|
29040
|
-
ClaudeCode: "claude-code",
|
|
29041
|
-
ClaudeChat: "claude-chat",
|
|
29042
|
-
Codex: "codex",
|
|
29043
|
-
CodexChat: "codex-chat",
|
|
29044
|
-
Gemini: "gemini",
|
|
29045
|
-
Antigravity: "antigravity",
|
|
29046
|
-
CursorAgent: "cursor-agent",
|
|
29047
|
-
OpenCode: "opencode",
|
|
29048
|
-
QwenCode: "qwen-code",
|
|
29049
|
-
Copilot: "copilot"
|
|
29050
|
-
};
|
|
29051
|
-
var DEFAULT_TERMINAL_MODES = [
|
|
29052
|
-
{
|
|
29053
|
-
id: BuiltinTerminalMode.ClaudeCode,
|
|
29054
|
-
label: "Claude",
|
|
29055
|
-
type: "claude-code",
|
|
29056
|
-
initialCommand: "claude --session-id {id} {flags}",
|
|
29057
|
-
resumeCommand: "claude --resume {id} {flags}",
|
|
29058
|
-
headlessCommand: "claude -p {prompt} {flags}",
|
|
29059
|
-
defaultFlags: "--allow-dangerously-skip-permissions",
|
|
29060
|
-
enabled: true,
|
|
29061
|
-
isBuiltin: true,
|
|
29062
|
-
order: 0
|
|
29063
|
-
},
|
|
29064
|
-
{
|
|
29065
|
-
id: BuiltinTerminalMode.ClaudeChat,
|
|
29066
|
-
label: "Claude Chat",
|
|
29067
|
-
type: "claude-code",
|
|
29068
|
-
initialCommand: null,
|
|
29069
|
-
resumeCommand: null,
|
|
29070
|
-
headlessCommand: "claude -p {prompt} {flags}",
|
|
29071
|
-
defaultFlags: "--allow-dangerously-skip-permissions",
|
|
29072
|
-
enabled: true,
|
|
29073
|
-
isBuiltin: true,
|
|
29074
|
-
order: 0.5
|
|
29075
|
-
},
|
|
29076
|
-
{
|
|
29077
|
-
id: BuiltinTerminalMode.Codex,
|
|
29078
|
-
label: "Codex",
|
|
29079
|
-
type: "codex",
|
|
29080
|
-
initialCommand: "codex {flags}",
|
|
29081
|
-
resumeCommand: "codex {flags} resume {id}",
|
|
29082
|
-
headlessCommand: "codex exec {flags} {prompt}",
|
|
29083
|
-
defaultFlags: "--sandbox workspace-write",
|
|
29084
|
-
enabled: true,
|
|
29085
|
-
isBuiltin: true,
|
|
29086
|
-
order: 1
|
|
29087
|
-
},
|
|
29088
|
-
{
|
|
29089
|
-
// Codex Chat — structured (non-PTY) chat backed by `codex app-server`'s
|
|
29090
|
-
// JSON-RPC protocol. Coexists with the PTY `codex` mode above.
|
|
29091
|
-
// `initialCommand`/`resumeCommand` are null: chat is spawned by the
|
|
29092
|
-
// chat-transport-manager, not the PTY manager.
|
|
29093
|
-
id: BuiltinTerminalMode.CodexChat,
|
|
29094
|
-
label: "Codex Chat",
|
|
29095
|
-
type: "codex",
|
|
29096
|
-
initialCommand: null,
|
|
29097
|
-
resumeCommand: null,
|
|
29098
|
-
headlessCommand: "codex exec {flags} {prompt}",
|
|
29099
|
-
defaultFlags: "",
|
|
29100
|
-
enabled: true,
|
|
29101
|
-
isBuiltin: true,
|
|
29102
|
-
order: 1.5
|
|
29103
|
-
},
|
|
29104
|
-
{
|
|
29105
|
-
id: BuiltinTerminalMode.Gemini,
|
|
29106
|
-
label: "Gemini",
|
|
29107
|
-
type: "gemini",
|
|
29108
|
-
initialCommand: "gemini {flags}",
|
|
29109
|
-
resumeCommand: "gemini --resume latest {flags}",
|
|
29110
|
-
headlessCommand: "gemini -p {prompt} {flags}",
|
|
29111
|
-
defaultFlags: "--yolo",
|
|
29112
|
-
enabled: true,
|
|
29113
|
-
isBuiltin: true,
|
|
29114
|
-
order: 2
|
|
29115
|
-
},
|
|
29116
|
-
{
|
|
29117
|
-
// Antigravity CLI — Google's successor to Gemini CLI (Gemini CLI stops
|
|
29118
|
-
// serving free/Pro/Ultra requests 2026-06-18). Binary is `agy`. Commands
|
|
29119
|
-
// confirmed against `agy --help` (v1.0.0):
|
|
29120
|
-
// resume `agy --conversation=<id>` (short `-c` = most-recent)
|
|
29121
|
-
// headless `-p` / `--print` (single non-interactive prompt)
|
|
29122
|
-
// auto-approve `--dangerously-skip-permissions` (skip tool permission prompts)
|
|
29123
|
-
//
|
|
29124
|
-
// `resumeCommand` uses `{id}`: the SessionStart hook captures the CLI
|
|
29125
|
-
// session_id into provider_config.antigravity (see agent-hook.ts
|
|
29126
|
-
// `persistConversationId`), and `{id}` is only ever interpolated when a
|
|
29127
|
-
// captured id exists — pty-manager picks `resumeCommand` solely when
|
|
29128
|
-
// `resuming = !!existingConversationId`. No id → `initialCommand` (fresh
|
|
29129
|
-
// session).
|
|
29130
|
-
id: BuiltinTerminalMode.Antigravity,
|
|
29131
|
-
label: "Antigravity",
|
|
29132
|
-
type: "antigravity",
|
|
29133
|
-
initialCommand: "agy {flags}",
|
|
29134
|
-
resumeCommand: "agy --conversation={id} {flags}",
|
|
29135
|
-
headlessCommand: "agy -p {prompt} {flags}",
|
|
29136
|
-
defaultFlags: "--dangerously-skip-permissions",
|
|
29137
|
-
enabled: true,
|
|
29138
|
-
isBuiltin: true,
|
|
29139
|
-
order: 2.5
|
|
29140
|
-
},
|
|
29141
|
-
{
|
|
29142
|
-
id: BuiltinTerminalMode.CursorAgent,
|
|
29143
|
-
label: "Cursor",
|
|
29144
|
-
type: "cursor-agent",
|
|
29145
|
-
initialCommand: "cursor-agent {flags}",
|
|
29146
|
-
resumeCommand: "cursor-agent --resume {id} {flags}",
|
|
29147
|
-
headlessCommand: "cursor-agent -p {prompt} {flags}",
|
|
29148
|
-
defaultFlags: "--force",
|
|
29149
|
-
enabled: true,
|
|
29150
|
-
isBuiltin: true,
|
|
29151
|
-
order: 3
|
|
29152
|
-
},
|
|
29153
|
-
{
|
|
29154
|
-
id: BuiltinTerminalMode.OpenCode,
|
|
29155
|
-
label: "OpenCode",
|
|
29156
|
-
type: "opencode",
|
|
29157
|
-
initialCommand: "opencode {flags}",
|
|
29158
|
-
resumeCommand: "opencode --session {id} {flags}",
|
|
29159
|
-
headlessCommand: "opencode run {flags} {prompt}",
|
|
29160
|
-
defaultFlags: "",
|
|
29161
|
-
enabled: true,
|
|
29162
|
-
isBuiltin: true,
|
|
29163
|
-
order: 4
|
|
29164
|
-
},
|
|
29165
|
-
{
|
|
29166
|
-
id: BuiltinTerminalMode.QwenCode,
|
|
29167
|
-
label: "Qwen",
|
|
29168
|
-
type: "qwen-code",
|
|
29169
|
-
initialCommand: "qwen --session-id {id} {flags}",
|
|
29170
|
-
resumeCommand: "qwen --resume {id} {flags}",
|
|
29171
|
-
headlessCommand: "qwen -p {prompt} {flags}",
|
|
29172
|
-
defaultFlags: "--yolo",
|
|
29173
|
-
enabled: true,
|
|
29174
|
-
isBuiltin: true,
|
|
29175
|
-
order: 6
|
|
29176
|
-
},
|
|
29177
|
-
{
|
|
29178
|
-
id: BuiltinTerminalMode.Copilot,
|
|
29179
|
-
label: "Copilot",
|
|
29180
|
-
type: "copilot",
|
|
29181
|
-
initialCommand: "copilot --resume={id} {flags}",
|
|
29182
|
-
resumeCommand: "copilot --resume={id} {flags}",
|
|
29183
|
-
headlessCommand: "copilot -p {prompt} {flags}",
|
|
29184
|
-
defaultFlags: "--allow-all-tools",
|
|
29185
|
-
enabled: true,
|
|
29186
|
-
isBuiltin: true,
|
|
29187
|
-
order: 7
|
|
29188
|
-
},
|
|
29189
|
-
{
|
|
29190
|
-
id: "terminal",
|
|
29191
|
-
label: "Terminal",
|
|
29192
|
-
type: "terminal",
|
|
29193
|
-
initialCommand: null,
|
|
29194
|
-
resumeCommand: null,
|
|
29195
|
-
headlessCommand: null,
|
|
29196
|
-
defaultFlags: null,
|
|
29197
|
-
enabled: true,
|
|
29198
|
-
isBuiltin: true,
|
|
29199
|
-
order: 8
|
|
29200
|
-
}
|
|
29201
|
-
];
|
|
29202
|
-
|
|
29203
28906
|
// src/commands/tasks/cli-author.ts
|
|
29204
28907
|
function cliAuthor() {
|
|
29205
28908
|
const agentId = process.env.SLAYZONE_AGENT_ID;
|
|
@@ -29412,6 +29115,88 @@ async function listAction(opts) {
|
|
|
29412
29115
|
printTasks(data, blockedIds);
|
|
29413
29116
|
}
|
|
29414
29117
|
|
|
29118
|
+
// src/db.ts
|
|
29119
|
+
var import_node_http2 = __toESM(require("node:http"), 1);
|
|
29120
|
+
|
|
29121
|
+
// src/db-helpers.mts
|
|
29122
|
+
function resolveProjectArg(opt) {
|
|
29123
|
+
const val = opt ?? process.env.SLAYZONE_PROJECT_ID;
|
|
29124
|
+
if (!val) {
|
|
29125
|
+
console.error("No --project provided and $SLAYZONE_PROJECT_ID is not set.");
|
|
29126
|
+
process.exit(1);
|
|
29127
|
+
}
|
|
29128
|
+
return val;
|
|
29129
|
+
}
|
|
29130
|
+
|
|
29131
|
+
// src/db.ts
|
|
29132
|
+
function postJson(port, path9, timeoutMs = 3e3) {
|
|
29133
|
+
return new Promise((resolve) => {
|
|
29134
|
+
const req = import_node_http2.default.request({ hostname: "127.0.0.1", port, path: path9, method: "POST" }, (res) => {
|
|
29135
|
+
res.resume();
|
|
29136
|
+
res.on("end", () => {
|
|
29137
|
+
const code = res.statusCode ?? 0;
|
|
29138
|
+
resolve(code >= 200 && code < 300);
|
|
29139
|
+
});
|
|
29140
|
+
});
|
|
29141
|
+
req.on("error", () => resolve(false));
|
|
29142
|
+
req.setTimeout(timeoutMs, () => {
|
|
29143
|
+
req.destroy();
|
|
29144
|
+
resolve(false);
|
|
29145
|
+
});
|
|
29146
|
+
req.end();
|
|
29147
|
+
});
|
|
29148
|
+
}
|
|
29149
|
+
async function probeAlternateChannel() {
|
|
29150
|
+
const dev = process.env.SLAYZONE_DEV === "1";
|
|
29151
|
+
const altPort = dev ? SIDECAR_FIXED_PORT.prod : SIDECAR_FIXED_PORT.dev;
|
|
29152
|
+
const hub = await findHub(String(altPort));
|
|
29153
|
+
return hub ? hub.port : null;
|
|
29154
|
+
}
|
|
29155
|
+
async function postHubNotify(hub, timeoutMs = 3e3) {
|
|
29156
|
+
try {
|
|
29157
|
+
const headers = hub.token ? { Authorization: `Bearer ${hub.token}` } : {};
|
|
29158
|
+
const res = await fetch(`${hub.baseUrl}/api/notify`, {
|
|
29159
|
+
method: "POST",
|
|
29160
|
+
headers,
|
|
29161
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
29162
|
+
});
|
|
29163
|
+
return res.ok;
|
|
29164
|
+
} catch {
|
|
29165
|
+
return false;
|
|
29166
|
+
}
|
|
29167
|
+
}
|
|
29168
|
+
async function notifyApp() {
|
|
29169
|
+
const hub = resolveHubTarget();
|
|
29170
|
+
if (hub) {
|
|
29171
|
+
const ok = await postHubNotify(hub);
|
|
29172
|
+
if (!ok) {
|
|
29173
|
+
console.error(
|
|
29174
|
+
"Warning: hub notify failed (POST /api/notify) \u2014 hub may be stale or unreachable"
|
|
29175
|
+
);
|
|
29176
|
+
}
|
|
29177
|
+
return;
|
|
29178
|
+
}
|
|
29179
|
+
const port = await probeFixedPort();
|
|
29180
|
+
if (port) {
|
|
29181
|
+
const ok = await postJson(port, "/api/notify");
|
|
29182
|
+
if (!ok) {
|
|
29183
|
+
console.error(
|
|
29184
|
+
"Warning: app notify failed (POST /api/notify) \u2014 app may be stale or unreachable"
|
|
29185
|
+
);
|
|
29186
|
+
}
|
|
29187
|
+
return;
|
|
29188
|
+
}
|
|
29189
|
+
const altPort = await probeAlternateChannel();
|
|
29190
|
+
if (altPort) {
|
|
29191
|
+
const dev = process.env.SLAYZONE_DEV === "1";
|
|
29192
|
+
const hint = dev ? "without --dev" : "with --dev";
|
|
29193
|
+
console.error(
|
|
29194
|
+
`Warning: SlayZone app is running ${hint}. Changes were saved but the app was not notified.`
|
|
29195
|
+
);
|
|
29196
|
+
console.error(` Re-run ${dev ? "without --dev" : "with --dev"} to target the same database.`);
|
|
29197
|
+
}
|
|
29198
|
+
}
|
|
29199
|
+
|
|
29415
29200
|
// src/commands/tasks/create.ts
|
|
29416
29201
|
async function createAction(title, opts) {
|
|
29417
29202
|
const projectRef = resolveProjectArg(opts.project);
|
|
@@ -30094,27 +29879,6 @@ function getEffectiveRenderMode(title, override) {
|
|
|
30094
29879
|
}
|
|
30095
29880
|
|
|
30096
29881
|
// src/commands/tasks/artifacts.ts
|
|
30097
|
-
function resolveArtifact(db, prefix) {
|
|
30098
|
-
const rows = db.query(
|
|
30099
|
-
`SELECT * FROM task_artifacts WHERE id LIKE :prefix || '%' LIMIT 2`,
|
|
30100
|
-
{ ":prefix": prefix }
|
|
30101
|
-
);
|
|
30102
|
-
if (rows.length === 0) {
|
|
30103
|
-
console.error(`Artifact not found: "${prefix}"`);
|
|
30104
|
-
process.exit(1);
|
|
30105
|
-
}
|
|
30106
|
-
if (rows.length > 1) {
|
|
30107
|
-
console.error(
|
|
30108
|
-
`Ambiguous artifact id "${prefix}". Matches: ${rows.map((r) => r.id.slice(0, 8)).join(", ")}`
|
|
30109
|
-
);
|
|
30110
|
-
process.exit(1);
|
|
30111
|
-
}
|
|
30112
|
-
return rows[0];
|
|
30113
|
-
}
|
|
30114
|
-
function artifactFilePath(artifactsDir, taskId, artifactId, title) {
|
|
30115
|
-
const ext = getExtensionFromTitle(title) || ".txt";
|
|
30116
|
-
return import_path6.default.join(artifactsDir, taskId, `${artifactId}${ext}`);
|
|
30117
|
-
}
|
|
30118
29882
|
function printArtifacts(artifacts, folders) {
|
|
30119
29883
|
if (artifacts.length === 0) {
|
|
30120
29884
|
console.log("No artifacts.");
|
|
@@ -30403,11 +30167,18 @@ function artifactsSubcommand() {
|
|
|
30403
30167
|
console.log(`Deleted: ${artifact.id.slice(0, 8)} ${artifact.title}`);
|
|
30404
30168
|
});
|
|
30405
30169
|
cmd.command("path <artifactId>").description("Print artifact file path").action(async (artifactId) => {
|
|
30406
|
-
const
|
|
30407
|
-
|
|
30408
|
-
|
|
30409
|
-
const
|
|
30410
|
-
|
|
30170
|
+
const { data } = await apiGet(
|
|
30171
|
+
`/api/artifacts/${encodeURIComponent(artifactId)}`
|
|
30172
|
+
);
|
|
30173
|
+
const local = await isCoLocatedHub();
|
|
30174
|
+
if (!local) {
|
|
30175
|
+
console.error(
|
|
30176
|
+
`Refusing to print a path for a hub on another machine \u2014 ${data.filePath} exists there, not here.
|
|
30177
|
+
Use \`slay tasks artifacts read ${artifactId}\` to get the content, or \`download\` to write it locally.`
|
|
30178
|
+
);
|
|
30179
|
+
process.exit(1);
|
|
30180
|
+
}
|
|
30181
|
+
process.stdout.write(data.filePath);
|
|
30411
30182
|
});
|
|
30412
30183
|
cmd.command("mkdir <name>").description("Create a folder").option("--task <id>", "Task ID (or $SLAYZONE_TASK_ID)").option("--parent <id>", "Parent folder ID").option("--json", "Output as JSON").action(async (name, opts) => {
|
|
30413
30184
|
const taskRef = await resolveId(opts.task);
|
|
@@ -30739,7 +30510,7 @@ function tasksCommand() {
|
|
|
30739
30510
|
|
|
30740
30511
|
// src/commands/projects.ts
|
|
30741
30512
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
30742
|
-
var
|
|
30513
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
30743
30514
|
|
|
30744
30515
|
// ../../shared/workflow/src/types.ts
|
|
30745
30516
|
var WORKFLOW_CATEGORIES = [
|
|
@@ -30861,7 +30632,7 @@ function normalizeProjectPath(input) {
|
|
|
30861
30632
|
if (!input) return null;
|
|
30862
30633
|
const trimmed = input.trim();
|
|
30863
30634
|
if (!trimmed) return null;
|
|
30864
|
-
return
|
|
30635
|
+
return import_node_path.default.resolve(trimmed);
|
|
30865
30636
|
}
|
|
30866
30637
|
function ensureProjectPath(projectPath) {
|
|
30867
30638
|
if (!projectPath) return false;
|
|
@@ -31085,6 +30856,7 @@ complete -c slay -n '__fish_use_subcommand' -a 'automations' -d 'Manage automati
|
|
|
31085
30856
|
complete -c slay -n '__fish_use_subcommand' -a 'processes' -d 'Manage processes'
|
|
31086
30857
|
complete -c slay -n '__fish_use_subcommand' -a 'hub' -d 'Run, list and target SlayZone hubs'
|
|
31087
30858
|
complete -c slay -n '__fish_use_subcommand' -a 'runner' -d 'Run and manage SlayZone runners'
|
|
30859
|
+
complete -c slay -n '__fish_use_subcommand' -a 'update' -d 'Update globally npm-installed @slayzone packages'
|
|
31088
30860
|
complete -c slay -n '__fish_use_subcommand' -a 'completions' -d 'Print shell completions'
|
|
31089
30861
|
complete -c slay -n '__fish_seen_subcommand_from tasks' -a 'list create view done update archive delete open search subtasks subtask-add tag'
|
|
31090
30862
|
complete -c slay -n '__fish_seen_subcommand_from processes' -a 'list logs kill follow'
|
|
@@ -31109,6 +30881,7 @@ _slay() {
|
|
|
31109
30881
|
'processes:Manage processes'
|
|
31110
30882
|
'hub:Run, list and target SlayZone hubs'
|
|
31111
30883
|
'runner:Run and manage SlayZone runners'
|
|
30884
|
+
'update:Update globally npm-installed @slayzone packages'
|
|
31112
30885
|
'completions:Print shell completions'
|
|
31113
30886
|
)
|
|
31114
30887
|
local -a task_commands
|
|
@@ -31210,6 +30983,9 @@ _slay() {
|
|
|
31210
30983
|
runner)
|
|
31211
30984
|
_describe 'runner commands' runner_commands
|
|
31212
30985
|
;;
|
|
30986
|
+
update)
|
|
30987
|
+
_arguments '--check[Report available updates without installing]'
|
|
30988
|
+
;;
|
|
31213
30989
|
completions)
|
|
31214
30990
|
_arguments ':shell:(fish zsh bash)'
|
|
31215
30991
|
;;
|
|
@@ -31227,7 +31003,7 @@ _slay_completions() {
|
|
|
31227
31003
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
31228
31004
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
31229
31005
|
if [ $COMP_CWORD -eq 1 ]; then
|
|
31230
|
-
COMPREPLY=( $(compgen -W "tasks projects tags templates automations processes hub runner completions" -- "$cur") )
|
|
31006
|
+
COMPREPLY=( $(compgen -W "tasks projects tags templates automations processes hub runner update completions" -- "$cur") )
|
|
31231
31007
|
elif [ $COMP_CWORD -eq 2 ]; then
|
|
31232
31008
|
case "$prev" in
|
|
31233
31009
|
tasks)
|
|
@@ -31254,6 +31030,9 @@ _slay_completions() {
|
|
|
31254
31030
|
runner)
|
|
31255
31031
|
COMPREPLY=( $(compgen -W "ls mint create start stop rm restart logs" -- "$cur") )
|
|
31256
31032
|
;;
|
|
31033
|
+
update)
|
|
31034
|
+
COMPREPLY=( $(compgen -W "--check" -- "$cur") )
|
|
31035
|
+
;;
|
|
31257
31036
|
completions)
|
|
31258
31037
|
COMPREPLY=( $(compgen -W "fish zsh bash" -- "$cur") )
|
|
31259
31038
|
;;
|
|
@@ -31287,7 +31066,7 @@ function completionsCommand() {
|
|
|
31287
31066
|
|
|
31288
31067
|
// src/commands/init.ts
|
|
31289
31068
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
31290
|
-
var
|
|
31069
|
+
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
31291
31070
|
|
|
31292
31071
|
// ../../domains/ai-config/src/shared/provider-registry.ts
|
|
31293
31072
|
var PROVIDER_PATHS = {
|
|
@@ -34691,7 +34470,7 @@ function writeInstructionsToDisk(projectPath, providers) {
|
|
|
34691
34470
|
}
|
|
34692
34471
|
const written = [];
|
|
34693
34472
|
for (const filename of filenames) {
|
|
34694
|
-
const filePath =
|
|
34473
|
+
const filePath = import_node_path2.default.join(projectPath, filename);
|
|
34695
34474
|
const existing = import_node_fs2.default.existsSync(filePath) ? import_node_fs2.default.readFileSync(filePath, "utf-8") : "";
|
|
34696
34475
|
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
34697
34476
|
import_node_fs2.default.appendFileSync(filePath, prefix + INSTRUCTIONS, "utf-8");
|
|
@@ -34704,8 +34483,8 @@ function writeSkillsToDisk(projectPath, providers, skills) {
|
|
|
34704
34483
|
const mapping = PROVIDER_PATHS[provider];
|
|
34705
34484
|
if (!mapping?.skillsDir) continue;
|
|
34706
34485
|
for (const skill of skills) {
|
|
34707
|
-
const filePath =
|
|
34708
|
-
import_node_fs2.default.mkdirSync(
|
|
34486
|
+
const filePath = import_node_path2.default.join(projectPath, mapping.skillsDir, skill.slug, "SKILL.md");
|
|
34487
|
+
import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(filePath), { recursive: true });
|
|
34709
34488
|
import_node_fs2.default.writeFileSync(filePath, skill.content, "utf-8");
|
|
34710
34489
|
}
|
|
34711
34490
|
}
|
|
@@ -35546,94 +35325,119 @@ function panelsCommand() {
|
|
|
35546
35325
|
// src/commands/hub.ts
|
|
35547
35326
|
var import_node_child_process3 = require("node:child_process");
|
|
35548
35327
|
var import_node_fs7 = require("node:fs");
|
|
35549
|
-
var
|
|
35328
|
+
var import_node_path6 = require("node:path");
|
|
35550
35329
|
|
|
35551
35330
|
// ../../shared/platform/src/slayzone-config.ts
|
|
35552
35331
|
var import_node_fs4 = require("node:fs");
|
|
35553
|
-
var
|
|
35332
|
+
var import_node_path3 = require("node:path");
|
|
35554
35333
|
|
|
35555
35334
|
// ../../shared/platform/src/runner-identity.ts
|
|
35556
35335
|
var DEFAULT_LOCAL_RUNNER_NAME = "local-runner";
|
|
35557
35336
|
|
|
35558
35337
|
// ../../shared/platform/src/slayzone-config.ts
|
|
35559
|
-
function
|
|
35560
|
-
return (0,
|
|
35338
|
+
function getHubConfigFilePath() {
|
|
35339
|
+
return (0, import_node_path3.join)(getSlayzoneHomeDir(), "hub.config.json");
|
|
35340
|
+
}
|
|
35341
|
+
function getRunnerConfigFilePath() {
|
|
35342
|
+
return (0, import_node_path3.join)(getSlayzoneHomeDir(), "runner.config.json");
|
|
35561
35343
|
}
|
|
35562
|
-
function
|
|
35344
|
+
function legacyConfigFilePathFor(newFilePath) {
|
|
35345
|
+
return (0, import_node_path3.join)((0, import_node_path3.dirname)(newFilePath), "config.json");
|
|
35346
|
+
}
|
|
35347
|
+
function coerceHubConfig(raw) {
|
|
35563
35348
|
const cfg = {};
|
|
35564
|
-
if (typeof raw.runnerTransportSecret === "string" && raw.runnerTransportSecret.length > 0)
|
|
35565
|
-
cfg.runnerTransportSecret = raw.runnerTransportSecret;
|
|
35566
35349
|
if (typeof raw.address === "string" && raw.address.length > 0) cfg.address = raw.address;
|
|
35567
35350
|
if (typeof raw.publicAddress === "string" && raw.publicAddress.length > 0)
|
|
35568
35351
|
cfg.publicAddress = raw.publicAddress;
|
|
35569
|
-
if (typeof raw.hubName === "string" && raw.hubName.trim().length > 0)
|
|
35570
|
-
cfg.hubName = raw.hubName.trim();
|
|
35571
35352
|
if (raw.mode === "local" || raw.mode === "remote") cfg.mode = raw.mode;
|
|
35353
|
+
if (typeof raw.hubName === "string" && raw.hubName.trim().length > 0) cfg.hubName = raw.hubName.trim();
|
|
35572
35354
|
if (typeof raw.port === "number" && Number.isInteger(raw.port)) cfg.port = raw.port;
|
|
35573
35355
|
if (typeof raw.publicUrl === "string" && raw.publicUrl.length > 0) cfg.publicUrl = raw.publicUrl;
|
|
35356
|
+
return cfg;
|
|
35357
|
+
}
|
|
35358
|
+
function coerceRunnerConfig(raw) {
|
|
35359
|
+
const cfg = {};
|
|
35574
35360
|
if (typeof raw.joinToken === "string" && raw.joinToken.length > 0) cfg.joinToken = raw.joinToken;
|
|
35575
|
-
if (typeof raw.runnerName === "string" && raw.runnerName.length > 0)
|
|
35576
|
-
cfg.runnerName = raw.runnerName;
|
|
35361
|
+
if (typeof raw.runnerName === "string" && raw.runnerName.length > 0) cfg.runnerName = raw.runnerName;
|
|
35577
35362
|
if (typeof raw.hubUrl === "string" && raw.hubUrl.length > 0) cfg.hubUrl = raw.hubUrl;
|
|
35578
35363
|
if (Array.isArray(raw.allowedRoots)) {
|
|
35579
|
-
const roots = raw.allowedRoots.filter(
|
|
35580
|
-
(r) => typeof r === "string" && r.length > 0
|
|
35581
|
-
);
|
|
35364
|
+
const roots = raw.allowedRoots.filter((r) => typeof r === "string" && r.length > 0);
|
|
35582
35365
|
if (roots.length > 0) cfg.allowedRoots = roots;
|
|
35583
35366
|
}
|
|
35584
35367
|
if (typeof raw.pinnedCertSha256 === "string" && raw.pinnedCertSha256.length > 0)
|
|
35585
35368
|
cfg.pinnedCertSha256 = raw.pinnedCertSha256;
|
|
35586
35369
|
return cfg;
|
|
35587
35370
|
}
|
|
35588
|
-
function
|
|
35371
|
+
function readJsonObject(path9) {
|
|
35589
35372
|
let raw;
|
|
35590
35373
|
try {
|
|
35591
|
-
raw = (0, import_node_fs4.readFileSync)(
|
|
35374
|
+
raw = (0, import_node_fs4.readFileSync)(path9, "utf8");
|
|
35592
35375
|
} catch (err) {
|
|
35593
|
-
if (err.code === "ENOENT") return
|
|
35376
|
+
if (err.code === "ENOENT") return null;
|
|
35594
35377
|
process.stderr.write(
|
|
35595
|
-
`[slayzone-config] cannot read ${
|
|
35378
|
+
`[slayzone-config] cannot read ${path9}: ${err instanceof Error ? err.message : String(err)} \u2014 using empty config
|
|
35596
35379
|
`
|
|
35597
35380
|
);
|
|
35598
|
-
return
|
|
35381
|
+
return null;
|
|
35599
35382
|
}
|
|
35600
35383
|
let parsed;
|
|
35601
35384
|
try {
|
|
35602
35385
|
parsed = JSON.parse(raw);
|
|
35603
35386
|
} catch (err) {
|
|
35604
35387
|
process.stderr.write(
|
|
35605
|
-
`[slayzone-config] ${
|
|
35388
|
+
`[slayzone-config] ${path9} is not valid JSON: ${err instanceof Error ? err.message : String(err)} \u2014 using empty config
|
|
35606
35389
|
`
|
|
35607
35390
|
);
|
|
35608
|
-
return
|
|
35391
|
+
return null;
|
|
35609
35392
|
}
|
|
35610
35393
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
35611
|
-
process.stderr.write(`[slayzone-config] ${
|
|
35394
|
+
process.stderr.write(`[slayzone-config] ${path9} is not a JSON object \u2014 using empty config
|
|
35612
35395
|
`);
|
|
35613
|
-
return
|
|
35396
|
+
return null;
|
|
35614
35397
|
}
|
|
35615
|
-
return
|
|
35398
|
+
return parsed;
|
|
35616
35399
|
}
|
|
35617
|
-
function
|
|
35618
|
-
const dir = (0,
|
|
35400
|
+
function writeJsonAtomic(path9, data) {
|
|
35401
|
+
const dir = (0, import_node_path3.dirname)(path9);
|
|
35619
35402
|
(0, import_node_fs4.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
35620
|
-
const tmpPath = `${
|
|
35621
|
-
(0, import_node_fs4.writeFileSync)(tmpPath, `${JSON.stringify(
|
|
35403
|
+
const tmpPath = `${path9}.tmp-${process.pid}-${Date.now()}`;
|
|
35404
|
+
(0, import_node_fs4.writeFileSync)(tmpPath, `${JSON.stringify(data, null, 2)}
|
|
35622
35405
|
`, { mode: 384 });
|
|
35623
35406
|
try {
|
|
35624
|
-
(0, import_node_fs4.renameSync)(tmpPath,
|
|
35407
|
+
(0, import_node_fs4.renameSync)(tmpPath, path9);
|
|
35625
35408
|
} catch (err) {
|
|
35626
35409
|
(0, import_node_fs4.rmSync)(tmpPath, { force: true });
|
|
35627
35410
|
throw err;
|
|
35628
35411
|
}
|
|
35629
35412
|
}
|
|
35630
|
-
function
|
|
35631
|
-
|
|
35632
|
-
|
|
35413
|
+
function saveHubConfigFile(cfg, path9 = getHubConfigFilePath()) {
|
|
35414
|
+
writeJsonAtomic(path9, cfg);
|
|
35415
|
+
}
|
|
35416
|
+
function updateHubConfigFile(patch, path9 = getHubConfigFilePath()) {
|
|
35417
|
+
const current = readJsonObject(path9);
|
|
35418
|
+
const merged = current ? coerceHubConfig(current) : {};
|
|
35419
|
+
for (const [k, v2] of Object.entries(patch)) {
|
|
35420
|
+
if (v2 !== void 0) merged[k] = v2;
|
|
35421
|
+
}
|
|
35422
|
+
saveHubConfigFile(merged, path9);
|
|
35423
|
+
return merged;
|
|
35424
|
+
}
|
|
35425
|
+
function loadRunnerConfigFile(path9 = getRunnerConfigFilePath()) {
|
|
35426
|
+
const raw = readJsonObject(path9);
|
|
35427
|
+
if (raw) return coerceRunnerConfig(raw);
|
|
35428
|
+
const legacy = readJsonObject(legacyConfigFilePathFor(path9));
|
|
35429
|
+
return legacy ? coerceRunnerConfig(legacy) : {};
|
|
35430
|
+
}
|
|
35431
|
+
function saveRunnerConfigFile(cfg, path9 = getRunnerConfigFilePath()) {
|
|
35432
|
+
writeJsonAtomic(path9, cfg);
|
|
35433
|
+
}
|
|
35434
|
+
function updateRunnerConfigFile(patch, path9 = getRunnerConfigFilePath()) {
|
|
35435
|
+
const current = readJsonObject(path9);
|
|
35436
|
+
const merged = current ? coerceRunnerConfig(current) : {};
|
|
35633
35437
|
for (const [k, v2] of Object.entries(patch)) {
|
|
35634
35438
|
if (v2 !== void 0) merged[k] = v2;
|
|
35635
35439
|
}
|
|
35636
|
-
|
|
35440
|
+
saveRunnerConfigFile(merged, path9);
|
|
35637
35441
|
return merged;
|
|
35638
35442
|
}
|
|
35639
35443
|
|
|
@@ -35641,7 +35445,7 @@ function updateSlayzoneConfig(patch, configPath = getSlayzoneConfigPath()) {
|
|
|
35641
35445
|
var import_node_child_process = require("node:child_process");
|
|
35642
35446
|
var import_node_fs5 = require("node:fs");
|
|
35643
35447
|
var import_node_os = require("node:os");
|
|
35644
|
-
var
|
|
35448
|
+
var import_node_path4 = require("node:path");
|
|
35645
35449
|
var KINDS = {
|
|
35646
35450
|
hub: {
|
|
35647
35451
|
labelPrefix: "com.slayzone.hub.",
|
|
@@ -35677,8 +35481,8 @@ function assertValidServiceName(kind, name) {
|
|
|
35677
35481
|
}
|
|
35678
35482
|
function defaultUnitDir(backend) {
|
|
35679
35483
|
const home = process.env.HOME ?? (0, import_node_os.homedir)();
|
|
35680
|
-
if (backend === "launchd") return (0,
|
|
35681
|
-
if (backend === "systemd") return (0,
|
|
35484
|
+
if (backend === "launchd") return (0, import_node_path4.join)(home, "Library", "LaunchAgents");
|
|
35485
|
+
if (backend === "systemd") return (0, import_node_path4.join)(home, ".config", "systemd", "user");
|
|
35682
35486
|
throw new Error("[slayzone] no unit directory: this platform has no user service backend");
|
|
35683
35487
|
}
|
|
35684
35488
|
function detectBackend() {
|
|
@@ -35699,7 +35503,7 @@ function detectBackend() {
|
|
|
35699
35503
|
}
|
|
35700
35504
|
function unitPath(kind, name, backend, unitDir = defaultUnitDir(backend)) {
|
|
35701
35505
|
assertValidServiceName(kind, name);
|
|
35702
|
-
return backend === "launchd" ? (0,
|
|
35506
|
+
return backend === "launchd" ? (0, import_node_path4.join)(unitDir, `${KINDS[kind].labelPrefix}${name}.plist`) : (0, import_node_path4.join)(unitDir, `${KINDS[kind].systemdPrefix}${name}.service`);
|
|
35703
35507
|
}
|
|
35704
35508
|
function nameFromUnitFile(kind, file, backend) {
|
|
35705
35509
|
if (backend === "launchd") {
|
|
@@ -35754,9 +35558,9 @@ ${envEntries}
|
|
|
35754
35558
|
<false/>
|
|
35755
35559
|
</dict>
|
|
35756
35560
|
<key>StandardOutPath</key>
|
|
35757
|
-
<string>${xmlEscape((0,
|
|
35561
|
+
<string>${xmlEscape((0, import_node_path4.join)(spec.logDir, kind.outLog))}</string>
|
|
35758
35562
|
<key>StandardErrorPath</key>
|
|
35759
|
-
<string>${xmlEscape((0,
|
|
35563
|
+
<string>${xmlEscape((0, import_node_path4.join)(spec.logDir, kind.errLog))}</string>
|
|
35760
35564
|
<key>ProcessType</key>
|
|
35761
35565
|
<string>Background</string>
|
|
35762
35566
|
</dict>
|
|
@@ -35811,7 +35615,7 @@ function listRegisteredUnits(kind, backend, unitDir = defaultUnitDir(backend)) {
|
|
|
35811
35615
|
const out = [];
|
|
35812
35616
|
for (const file of files) {
|
|
35813
35617
|
const name = nameFromUnitFile(kind, file, backend);
|
|
35814
|
-
if (name) out.push({ name, unitPath: (0,
|
|
35618
|
+
if (name) out.push({ name, unitPath: (0, import_node_path4.join)(unitDir, file) });
|
|
35815
35619
|
}
|
|
35816
35620
|
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
35817
35621
|
}
|
|
@@ -35843,8 +35647,8 @@ function launchdLabel(kind, name) {
|
|
|
35843
35647
|
var import_node_child_process2 = require("node:child_process");
|
|
35844
35648
|
var import_node_fs6 = require("node:fs");
|
|
35845
35649
|
var import_node_module = require("node:module");
|
|
35846
|
-
var
|
|
35847
|
-
var CLI_VERSION = true ? "0.36.0-beta.
|
|
35650
|
+
var import_node_path5 = require("node:path");
|
|
35651
|
+
var CLI_VERSION = true ? "0.36.0-beta.15" : "";
|
|
35848
35652
|
function fail(message) {
|
|
35849
35653
|
console.error(message);
|
|
35850
35654
|
process.exit(1);
|
|
@@ -35877,18 +35681,18 @@ function readServicePkg(kind, pkgJsonPath) {
|
|
|
35877
35681
|
}
|
|
35878
35682
|
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.[PACKAGES[kind].bin];
|
|
35879
35683
|
if (!binRel) return null;
|
|
35880
|
-
const binPath = (0,
|
|
35684
|
+
const binPath = (0, import_node_path5.join)((0, import_node_path5.dirname)(pkgJsonPath), binRel);
|
|
35881
35685
|
if (!(0, import_node_fs6.existsSync)(binPath)) return null;
|
|
35882
35686
|
return { binPath, version: pkg.version ?? "unknown" };
|
|
35883
35687
|
}
|
|
35884
35688
|
function interpreterFor(binPath, version) {
|
|
35885
|
-
let dir = (0,
|
|
35689
|
+
let dir = (0, import_node_path5.dirname)(binPath);
|
|
35886
35690
|
for (let i = 0; i < 6; i++) {
|
|
35887
|
-
const pathTxt = (0,
|
|
35691
|
+
const pathTxt = (0, import_node_path5.join)(dir, "node_modules", "electron", "path.txt");
|
|
35888
35692
|
if ((0, import_node_fs6.existsSync)(pathTxt)) {
|
|
35889
35693
|
try {
|
|
35890
35694
|
const rel = (0, import_node_fs6.readFileSync)(pathTxt, "utf8").trim();
|
|
35891
|
-
const electron = (0,
|
|
35695
|
+
const electron = (0, import_node_path5.join)(dir, "node_modules", "electron", "dist", rel);
|
|
35892
35696
|
if ((0, import_node_fs6.existsSync)(electron)) {
|
|
35893
35697
|
return {
|
|
35894
35698
|
command: electron,
|
|
@@ -35901,7 +35705,7 @@ function interpreterFor(binPath, version) {
|
|
|
35901
35705
|
} catch {
|
|
35902
35706
|
}
|
|
35903
35707
|
}
|
|
35904
|
-
const parent = (0,
|
|
35708
|
+
const parent = (0, import_node_path5.dirname)(dir);
|
|
35905
35709
|
if (parent === dir) break;
|
|
35906
35710
|
dir = parent;
|
|
35907
35711
|
}
|
|
@@ -35916,7 +35720,7 @@ function resolveServiceBin(kind) {
|
|
|
35916
35720
|
// this package's CJS bundle.
|
|
35917
35721
|
() => {
|
|
35918
35722
|
try {
|
|
35919
|
-
return (0, import_node_module.createRequire)(process.argv[1] ?? (0,
|
|
35723
|
+
return (0, import_node_module.createRequire)(process.argv[1] ?? (0, import_node_path5.join)(process.cwd(), "x")).resolve(
|
|
35920
35724
|
`${pkg}/package.json`
|
|
35921
35725
|
);
|
|
35922
35726
|
} catch {
|
|
@@ -35927,7 +35731,7 @@ function resolveServiceBin(kind) {
|
|
|
35927
35731
|
() => {
|
|
35928
35732
|
const self2 = process.argv[1];
|
|
35929
35733
|
if (!self2) return null;
|
|
35930
|
-
const sibling = (0,
|
|
35734
|
+
const sibling = (0, import_node_path5.join)((0, import_node_path5.dirname)(self2), "..", "..", devDir, "package.json");
|
|
35931
35735
|
return (0, import_node_fs6.existsSync)(sibling) ? sibling : null;
|
|
35932
35736
|
}
|
|
35933
35737
|
];
|
|
@@ -35937,8 +35741,8 @@ function resolveServiceBin(kind) {
|
|
|
35937
35741
|
const found2 = readServicePkg(kind, path9);
|
|
35938
35742
|
if (found2) return interpreterFor(found2.binPath, found2.version);
|
|
35939
35743
|
}
|
|
35940
|
-
const prefix = (
|
|
35941
|
-
const installed = (0,
|
|
35744
|
+
const prefix = getServiceRuntimeDir(kind);
|
|
35745
|
+
const installed = (0, import_node_path5.join)(prefix, "node_modules", pkg, "package.json");
|
|
35942
35746
|
const wanted = CLI_VERSION ? `${pkg}@${CLI_VERSION}` : `${pkg}@beta`;
|
|
35943
35747
|
if (!(0, import_node_fs6.existsSync)(installed) || CLI_VERSION && readServicePkg(kind, installed)?.version !== CLI_VERSION) {
|
|
35944
35748
|
console.log(`Installing ${wanted}\u2026`);
|
|
@@ -35970,13 +35774,13 @@ function ensureLogDir(kind, root) {
|
|
|
35970
35774
|
(0, import_node_fs6.mkdirSync)(dir, { recursive: true });
|
|
35971
35775
|
return dir;
|
|
35972
35776
|
}
|
|
35973
|
-
function logDirFor(
|
|
35974
|
-
return
|
|
35777
|
+
function logDirFor(_kind, root) {
|
|
35778
|
+
return (0, import_node_path5.join)(root, "logs");
|
|
35975
35779
|
}
|
|
35976
35780
|
function serviceLogPaths(kind, root) {
|
|
35977
35781
|
const dir = logDirFor(kind, root);
|
|
35978
35782
|
const names = serviceLogNames(kind);
|
|
35979
|
-
return { out: (0,
|
|
35783
|
+
return { out: (0, import_node_path5.join)(dir, names.out), err: (0, import_node_path5.join)(dir, names.err) };
|
|
35980
35784
|
}
|
|
35981
35785
|
function failWithLog(kind, name, logPath, what) {
|
|
35982
35786
|
let detail = "";
|
|
@@ -36006,7 +35810,7 @@ function readServiceLogTail(kind, root, lines) {
|
|
|
36006
35810
|
const chunks = [];
|
|
36007
35811
|
for (const f of files) {
|
|
36008
35812
|
try {
|
|
36009
|
-
chunks.push((0, import_node_fs6.readFileSync)((0,
|
|
35813
|
+
chunks.push((0, import_node_fs6.readFileSync)((0, import_node_path5.join)(dir, f), "utf8"));
|
|
36010
35814
|
} catch {
|
|
36011
35815
|
}
|
|
36012
35816
|
}
|
|
@@ -36023,7 +35827,7 @@ function followServiceLog(args) {
|
|
|
36023
35827
|
}
|
|
36024
35828
|
const dir = logDirFor(kind, root);
|
|
36025
35829
|
if (!(0, import_node_fs6.existsSync)(dir)) fail(`No log directory at ${shortenPath(dir)}.`);
|
|
36026
|
-
const candidates = (0, import_node_fs6.readdirSync)(dir).filter((f) => f.endsWith(".log")).map((f) => ({ f, path: (0,
|
|
35830
|
+
const candidates = (0, import_node_fs6.readdirSync)(dir).filter((f) => f.endsWith(".log")).map((f) => ({ f, path: (0, import_node_path5.join)(dir, f), mtime: (0, import_node_fs6.statSync)((0, import_node_path5.join)(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
36027
35831
|
if (candidates.length === 0) fail(`No log files in ${shortenPath(dir)}.`);
|
|
36028
35832
|
const target = candidates[0].path;
|
|
36029
35833
|
const targs = follow ? ["-f", "-n", String(lines), target] : ["-n", String(lines), target];
|
|
@@ -36192,20 +35996,11 @@ ${hint}` : ""}`);
|
|
|
36192
35996
|
|
|
36193
35997
|
// src/commands/hub.ts
|
|
36194
35998
|
var HUB_PACKAGE = servicePackage("hub");
|
|
36195
|
-
function outOfBlockPorts() {
|
|
36196
|
-
if (!hasLocalDatabase()) return [];
|
|
36197
|
-
try {
|
|
36198
|
-
const port = getServerPort();
|
|
36199
|
-
return port ? [port] : [];
|
|
36200
|
-
} catch {
|
|
36201
|
-
return [];
|
|
36202
|
-
}
|
|
36203
|
-
}
|
|
36204
35999
|
function discoverAllHubs() {
|
|
36205
|
-
return discoverHubs(
|
|
36000
|
+
return discoverHubs();
|
|
36206
36001
|
}
|
|
36207
36002
|
function findAnyHub(nameOrPort) {
|
|
36208
|
-
return findHub(nameOrPort
|
|
36003
|
+
return findHub(nameOrPort);
|
|
36209
36004
|
}
|
|
36210
36005
|
function formatUptime(ms) {
|
|
36211
36006
|
const s = Math.floor(ms / 1e3);
|
|
@@ -36277,8 +36072,8 @@ async function launchHub(args) {
|
|
|
36277
36072
|
const bin = resolveServiceBin("hub");
|
|
36278
36073
|
const logDir = ensureLogDir("hub", root);
|
|
36279
36074
|
const logs = serviceLogPaths("hub", root);
|
|
36280
|
-
const
|
|
36281
|
-
const findIt = () =>
|
|
36075
|
+
const probePort = address !== void 0 ? parseHubAddress(address)?.port : port;
|
|
36076
|
+
const findIt = () => probePort === void 0 ? findAnyHub(name) : findHub(String(probePort));
|
|
36282
36077
|
if (backend === "none") {
|
|
36283
36078
|
const out = (0, import_node_fs7.openSync)(logs.out, "a");
|
|
36284
36079
|
const child = (0, import_node_child_process3.spawn)(bin.command, bin.args, {
|
|
@@ -36511,7 +36306,7 @@ function hubCommand() {
|
|
|
36511
36306
|
"Externally-reachable address of this hub \u2014 makes it a REMOTE hub (auth + TLS + wss join tokens)"
|
|
36512
36307
|
).option("--bind <host[:port]>", "Address to bind (default: loopback, or 0.0.0.0 when remote)").action(
|
|
36513
36308
|
async (name, opts) => {
|
|
36514
|
-
const root = (0,
|
|
36309
|
+
const root = (0, import_node_path6.resolve)(opts.root ?? process.cwd());
|
|
36515
36310
|
const port = opts.port === void 0 ? void 0 : Number(opts.port);
|
|
36516
36311
|
if (port !== void 0 && (!Number.isInteger(port) || port < 1 || port > 65535)) {
|
|
36517
36312
|
fail(`Invalid --port ${opts.port} \u2014 expected an integer 1-65535.`);
|
|
@@ -36556,13 +36351,13 @@ Start it with \`slay hub start ${name}\`, or remove it with \`slay hub rm ${name
|
|
|
36556
36351
|
);
|
|
36557
36352
|
}
|
|
36558
36353
|
if (publicAddress !== void 0) {
|
|
36559
|
-
|
|
36354
|
+
updateHubConfigFile(
|
|
36560
36355
|
{
|
|
36561
36356
|
mode: "remote",
|
|
36562
36357
|
publicAddress,
|
|
36563
36358
|
...address !== void 0 ? { address } : {}
|
|
36564
36359
|
},
|
|
36565
|
-
(0,
|
|
36360
|
+
(0, import_node_path6.join)(root, "hub.config.json")
|
|
36566
36361
|
);
|
|
36567
36362
|
console.log("Mode: remote (client auth + TLS enforced)");
|
|
36568
36363
|
console.log(`Bind: ${address ?? "(hub block default)"}`);
|
|
@@ -36792,7 +36587,7 @@ machines dial, recreate it with \`--public-address <host:port>\`.`
|
|
|
36792
36587
|
// src/commands/runner.ts
|
|
36793
36588
|
var import_node_child_process4 = require("node:child_process");
|
|
36794
36589
|
var import_node_fs8 = require("node:fs");
|
|
36795
|
-
var
|
|
36590
|
+
var import_node_path7 = require("node:path");
|
|
36796
36591
|
|
|
36797
36592
|
// ../../shared/platform/src/join-token.ts
|
|
36798
36593
|
var JOIN_TOKEN_PREFIX = "szjt1";
|
|
@@ -36819,7 +36614,7 @@ var RUNNER_PACKAGE = servicePackage("runner");
|
|
|
36819
36614
|
var ENROLL_TIMEOUT_MS = 3e4;
|
|
36820
36615
|
var CONNECTED_RE = /"mode":"(enroll|hello)"/;
|
|
36821
36616
|
function configPathFor(root) {
|
|
36822
|
-
return (0,
|
|
36617
|
+
return (0, import_node_path7.join)(root, "runner.config.json");
|
|
36823
36618
|
}
|
|
36824
36619
|
function warnIfLoopbackHub(hubUrl) {
|
|
36825
36620
|
if (!isLoopbackRunnerUrl(hubUrl)) return;
|
|
@@ -36833,7 +36628,8 @@ never connect. For a hub other machines can reach, recreate it with
|
|
|
36833
36628
|
}
|
|
36834
36629
|
function isEnrolled(root) {
|
|
36835
36630
|
try {
|
|
36836
|
-
|
|
36631
|
+
const parsed = JSON.parse((0, import_node_fs8.readFileSync)((0, import_node_path7.join)(root, "runner.state.json"), "utf8"));
|
|
36632
|
+
return typeof parsed === "object" && parsed !== null && Object.keys(parsed).length > 0;
|
|
36837
36633
|
} catch {
|
|
36838
36634
|
return false;
|
|
36839
36635
|
}
|
|
@@ -37014,14 +36810,22 @@ Run \`slay runner mint\` there, or put the hub in remote mode (\`slay hub create
|
|
|
37014
36810
|
cmd.command("ls").description("List the runners installed on this machine").option("--json", "Output as JSON").action((opts) => {
|
|
37015
36811
|
const backend = detectBackend();
|
|
37016
36812
|
if (backend === "none") {
|
|
37017
|
-
|
|
36813
|
+
if (opts.json) {
|
|
36814
|
+
console.log("[]");
|
|
36815
|
+
return;
|
|
36816
|
+
}
|
|
36817
|
+
console.log(
|
|
36818
|
+
"No runners installed \u2014 this platform has no user service manager, so runners cannot be registered here."
|
|
36819
|
+
);
|
|
36820
|
+
console.log(`Run one in the foreground instead:
|
|
36821
|
+
npx ${RUNNER_PACKAGE}`);
|
|
37018
36822
|
return;
|
|
37019
36823
|
}
|
|
37020
36824
|
const units = listRegisteredUnits("runner", backend);
|
|
37021
36825
|
const rows = units.map((u) => {
|
|
37022
36826
|
const root = readUnitRoot("runner", u.name, backend);
|
|
37023
36827
|
const status = supervisorStatus("runner", backend, u.name);
|
|
37024
|
-
const hubUrl = root ?
|
|
36828
|
+
const hubUrl = root ? loadRunnerConfigFile(configPathFor(root)).hubUrl ?? null : null;
|
|
37025
36829
|
return {
|
|
37026
36830
|
name: u.name,
|
|
37027
36831
|
unitPath: u.unitPath,
|
|
@@ -37073,7 +36877,7 @@ Runner "${r.name}" is stopped. Start it: slay runner start ${r.name}`);
|
|
|
37073
36877
|
"Filesystem root the runner may operate under (repeatable; default: the runner root)",
|
|
37074
36878
|
(value, previous = []) => [...previous, value]
|
|
37075
36879
|
).action(async (name, opts) => {
|
|
37076
|
-
const root = (0,
|
|
36880
|
+
const root = (0, import_node_path7.resolve)(opts.root ?? process.cwd());
|
|
37077
36881
|
const backend = resolveBackend();
|
|
37078
36882
|
const decoded = decodeJoinToken(opts.token);
|
|
37079
36883
|
if (!decoded) {
|
|
@@ -37096,15 +36900,15 @@ Mint one on the hub:
|
|
|
37096
36900
|
Start it with \`slay runner start ${name}\`, or remove it with \`slay runner rm ${name}\`.`
|
|
37097
36901
|
);
|
|
37098
36902
|
}
|
|
37099
|
-
const occupant =
|
|
36903
|
+
const occupant = loadRunnerConfigFile(configPathFor(root)).runnerName;
|
|
37100
36904
|
if (occupant !== void 0) {
|
|
37101
36905
|
fail(
|
|
37102
36906
|
`A runner is already installed in ${shortenPath(root)} \u2014 "${occupant}".
|
|
37103
36907
|
` + (occupant === name ? `Start it with \`slay runner start ${name}\`, or remove it with \`slay runner rm ${name}\`.` : `Give this runner its own directory with \`--root <dir>\`, or remove "${occupant}" first with \`slay runner rm ${occupant}\`.`)
|
|
37104
36908
|
);
|
|
37105
36909
|
}
|
|
37106
|
-
const allowedRoots = opts.allow && opts.allow.length > 0 ? opts.allow.map((d) => (0,
|
|
37107
|
-
|
|
36910
|
+
const allowedRoots = opts.allow && opts.allow.length > 0 ? opts.allow.map((d) => (0, import_node_path7.resolve)(d)) : [root];
|
|
36911
|
+
updateRunnerConfigFile(
|
|
37108
36912
|
{
|
|
37109
36913
|
joinToken: opts.token,
|
|
37110
36914
|
hubUrl: decoded.hubUrl,
|
|
@@ -37208,30 +37012,189 @@ Start it with \`slay runner start ${name}\`, or remove it with \`slay runner rm
|
|
|
37208
37012
|
return cmd;
|
|
37209
37013
|
}
|
|
37210
37014
|
|
|
37015
|
+
// src/commands/update.ts
|
|
37016
|
+
var import_node_child_process5 = require("node:child_process");
|
|
37017
|
+
var import_node_fs9 = require("node:fs");
|
|
37018
|
+
var import_node_os2 = require("node:os");
|
|
37019
|
+
var import_node_path8 = require("node:path");
|
|
37020
|
+
var PACKAGE_NAMES = ["@slayzone/cli", "@slayzone/runner", "@slayzone/hub"];
|
|
37021
|
+
var KIND_FOR_PACKAGE = {
|
|
37022
|
+
"@slayzone/hub": "hub",
|
|
37023
|
+
"@slayzone/runner": "runner"
|
|
37024
|
+
};
|
|
37025
|
+
function runCapture(bin, args) {
|
|
37026
|
+
try {
|
|
37027
|
+
return (0, import_node_child_process5.execFileSync)(bin, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
37028
|
+
} catch {
|
|
37029
|
+
return null;
|
|
37030
|
+
}
|
|
37031
|
+
}
|
|
37032
|
+
function bunGlobalRoot() {
|
|
37033
|
+
const base = process.env.BUN_INSTALL || (0, import_node_path8.join)((0, import_node_os2.homedir)(), ".bun");
|
|
37034
|
+
const dir = (0, import_node_path8.join)(base, "install", "global", "node_modules");
|
|
37035
|
+
return (0, import_node_fs9.existsSync)(dir) ? dir : null;
|
|
37036
|
+
}
|
|
37037
|
+
var MANAGERS = [
|
|
37038
|
+
{
|
|
37039
|
+
id: "npm",
|
|
37040
|
+
bin: "npm",
|
|
37041
|
+
globalRoot: () => runCapture("npm", ["root", "-g"]),
|
|
37042
|
+
installArgs: (names, target) => ["install", "-g", ...names.map((n) => `${n}@${target}`)]
|
|
37043
|
+
},
|
|
37044
|
+
{
|
|
37045
|
+
id: "pnpm",
|
|
37046
|
+
bin: "pnpm",
|
|
37047
|
+
globalRoot: () => runCapture("pnpm", ["root", "-g"]),
|
|
37048
|
+
// pnpm prompts interactively (or silently skips, off a TTY) before running a
|
|
37049
|
+
// global package's install scripts — `--allow-build=<name>` pre-approves it,
|
|
37050
|
+
// needed for hub/runner's native rebuild (better-sqlite3/node-pty). Verified
|
|
37051
|
+
// via `pnpm add --help` (10.30.3); harmless to pass for cli, which has none.
|
|
37052
|
+
installArgs: (names, target) => [
|
|
37053
|
+
"add",
|
|
37054
|
+
"-g",
|
|
37055
|
+
...names.filter((n) => KIND_FOR_PACKAGE[n]).map((n) => `--allow-build=${n}`),
|
|
37056
|
+
...names.map((n) => `${n}@${target}`)
|
|
37057
|
+
]
|
|
37058
|
+
},
|
|
37059
|
+
{
|
|
37060
|
+
id: "bun",
|
|
37061
|
+
bin: "bun",
|
|
37062
|
+
globalRoot: bunGlobalRoot,
|
|
37063
|
+
// Same problem as pnpm's build gate, bun's own flavor: postinstall scripts
|
|
37064
|
+
// don't run for a package unless it's trusted. `--trust` opts the packages
|
|
37065
|
+
// in this install into that list. Verified via `bun add --help` (1.3.6).
|
|
37066
|
+
installArgs: (names, target) => [
|
|
37067
|
+
"add",
|
|
37068
|
+
"-g",
|
|
37069
|
+
...names.some((n) => KIND_FOR_PACKAGE[n]) ? ["--trust"] : [],
|
|
37070
|
+
...names.map((n) => `${n}@${target}`)
|
|
37071
|
+
]
|
|
37072
|
+
}
|
|
37073
|
+
];
|
|
37074
|
+
function readInstalledVersion(globalRoot, pkg) {
|
|
37075
|
+
const pkgJsonPath = (0, import_node_path8.join)(globalRoot, ...pkg.split("/"), "package.json");
|
|
37076
|
+
if (!(0, import_node_fs9.existsSync)(pkgJsonPath)) return null;
|
|
37077
|
+
try {
|
|
37078
|
+
const parsed = JSON.parse((0, import_node_fs9.readFileSync)(pkgJsonPath, "utf8"));
|
|
37079
|
+
return typeof parsed.version === "string" ? parsed.version : null;
|
|
37080
|
+
} catch {
|
|
37081
|
+
return null;
|
|
37082
|
+
}
|
|
37083
|
+
}
|
|
37084
|
+
function fetchDistTags() {
|
|
37085
|
+
for (const bin of ["npm", "pnpm"]) {
|
|
37086
|
+
const out = runCapture(bin, ["view", "@slayzone/cli", "dist-tags", "--json"]);
|
|
37087
|
+
if (!out) continue;
|
|
37088
|
+
try {
|
|
37089
|
+
return JSON.parse(out);
|
|
37090
|
+
} catch {
|
|
37091
|
+
}
|
|
37092
|
+
}
|
|
37093
|
+
return null;
|
|
37094
|
+
}
|
|
37095
|
+
function printRestartHints(updatedPackages) {
|
|
37096
|
+
const backend = resolveBackend();
|
|
37097
|
+
if (backend === "none") return;
|
|
37098
|
+
const hints = [];
|
|
37099
|
+
for (const pkg of updatedPackages) {
|
|
37100
|
+
const kind = KIND_FOR_PACKAGE[pkg];
|
|
37101
|
+
if (!kind) continue;
|
|
37102
|
+
for (const unit of listRegisteredUnits(kind, backend)) {
|
|
37103
|
+
hints.push(` slay ${kind} restart ${unit.name} --upgrade`);
|
|
37104
|
+
}
|
|
37105
|
+
}
|
|
37106
|
+
if (hints.length === 0) return;
|
|
37107
|
+
console.log("\nRestart to apply:");
|
|
37108
|
+
for (const hint of hints) console.log(hint);
|
|
37109
|
+
}
|
|
37110
|
+
function updateCommand() {
|
|
37111
|
+
const cmd = new Command("update").description("Update globally installed @slayzone packages (cli, hub, runner) \u2014 npm, pnpm, or bun").option("--check", "Report available updates without installing anything").action((opts) => {
|
|
37112
|
+
const roots = /* @__PURE__ */ new Map();
|
|
37113
|
+
for (const mgr of MANAGERS) {
|
|
37114
|
+
const root = mgr.globalRoot();
|
|
37115
|
+
if (root) roots.set(mgr.id, root);
|
|
37116
|
+
}
|
|
37117
|
+
if (roots.size === 0) {
|
|
37118
|
+
fail("Could not resolve a global install root for npm, pnpm, or bun. Is at least one on PATH?");
|
|
37119
|
+
}
|
|
37120
|
+
const found = [];
|
|
37121
|
+
for (const [manager, root] of roots) {
|
|
37122
|
+
for (const name of PACKAGE_NAMES) {
|
|
37123
|
+
const installedVersion = readInstalledVersion(root, name);
|
|
37124
|
+
if (installedVersion) found.push({ manager, name, installedVersion });
|
|
37125
|
+
}
|
|
37126
|
+
}
|
|
37127
|
+
if (found.length === 0) {
|
|
37128
|
+
console.log("No @slayzone packages found in any global npm, pnpm, or bun install.");
|
|
37129
|
+
return;
|
|
37130
|
+
}
|
|
37131
|
+
const distTags = fetchDistTags();
|
|
37132
|
+
if (!distTags) {
|
|
37133
|
+
fail(
|
|
37134
|
+
"Could not reach the npm registry to check for updates (`npm view @slayzone/cli dist-tags` and `pnpm view` both failed)."
|
|
37135
|
+
);
|
|
37136
|
+
}
|
|
37137
|
+
const onPrerelease = found.some((p2) => p2.installedVersion.includes("-"));
|
|
37138
|
+
const target = (onPrerelease ? distTags.beta : void 0) ?? distTags.latest ?? distTags.beta;
|
|
37139
|
+
if (!target) fail("The registry returned no usable dist-tag for @slayzone/cli.");
|
|
37140
|
+
const managerW = Math.max("MANAGER".length, ...found.map((p2) => p2.manager.length));
|
|
37141
|
+
const nameW = Math.max("PACKAGE".length, ...found.map((p2) => p2.name.length));
|
|
37142
|
+
const versionW = Math.max("INSTALLED".length, ...found.map((p2) => p2.installedVersion.length));
|
|
37143
|
+
console.log(
|
|
37144
|
+
`${"MANAGER".padEnd(managerW)} ${"PACKAGE".padEnd(nameW)} ${"INSTALLED".padEnd(versionW)} STATUS`
|
|
37145
|
+
);
|
|
37146
|
+
for (const p2 of found) {
|
|
37147
|
+
const status = p2.installedVersion === target ? "up to date" : `-> ${target}`;
|
|
37148
|
+
console.log(
|
|
37149
|
+
`${p2.manager.padEnd(managerW)} ${p2.name.padEnd(nameW)} ${p2.installedVersion.padEnd(versionW)} ${status}`
|
|
37150
|
+
);
|
|
37151
|
+
}
|
|
37152
|
+
const outdated = found.filter((p2) => p2.installedVersion !== target);
|
|
37153
|
+
if (outdated.length === 0) {
|
|
37154
|
+
console.log("\nEverything is up to date.");
|
|
37155
|
+
return;
|
|
37156
|
+
}
|
|
37157
|
+
if (opts.check) {
|
|
37158
|
+
console.log("\n--check: nothing installed. Run `slay update` to apply.");
|
|
37159
|
+
return;
|
|
37160
|
+
}
|
|
37161
|
+
const byManager = /* @__PURE__ */ new Map();
|
|
37162
|
+
for (const p2 of outdated) {
|
|
37163
|
+
const list = byManager.get(p2.manager) ?? [];
|
|
37164
|
+
list.push(p2.name);
|
|
37165
|
+
byManager.set(p2.manager, list);
|
|
37166
|
+
}
|
|
37167
|
+
for (const [managerId, names] of byManager) {
|
|
37168
|
+
const mgr = MANAGERS.find((m) => m.id === managerId);
|
|
37169
|
+
if (!mgr) continue;
|
|
37170
|
+
const args = mgr.installArgs(names, target);
|
|
37171
|
+
console.log(`
|
|
37172
|
+
[${managerId}] Installing: ${names.map((n) => `${n}@${target}`).join(" ")}`);
|
|
37173
|
+
try {
|
|
37174
|
+
(0, import_node_child_process5.execFileSync)(mgr.bin, args, { stdio: "inherit" });
|
|
37175
|
+
} catch {
|
|
37176
|
+
fail(
|
|
37177
|
+
`${mgr.bin} install failed. Install the packages yourself and retry:
|
|
37178
|
+
` + names.map((n) => ` ${mgr.bin} ${mgr.id === "npm" ? "install" : "add"} -g ${n}@${target}`).join("\n")
|
|
37179
|
+
);
|
|
37180
|
+
}
|
|
37181
|
+
}
|
|
37182
|
+
printRestartHints(outdated.map((p2) => p2.name));
|
|
37183
|
+
});
|
|
37184
|
+
return cmd;
|
|
37185
|
+
}
|
|
37186
|
+
|
|
37211
37187
|
// src/index.ts
|
|
37212
|
-
|
|
37213
|
-
process.on("warning", (warning) => {
|
|
37214
|
-
if (warning.name === "ExperimentalWarning" && /SQLite/i.test(warning.message)) return;
|
|
37215
|
-
console.warn(`${warning.name}: ${warning.message}`);
|
|
37216
|
-
});
|
|
37217
|
-
var program2 = new Command().name("slay").description("SlayZone CLI").version("0.36.0-beta.12").option("--dev", "Use development database (slayzone.dev.sqlite)").option("--hub <name|port>", "Target a specific hub on this machine (see `slay hub ls`)").showSuggestionAfterError(true).showHelpAfterError(true).hook("preAction", async (thisCommand) => {
|
|
37188
|
+
var program2 = new Command().name("slay").description("SlayZone CLI").version("0.36.0-beta.15").option("--dev", "Use development database (slayzone.dev.sqlite)").option("--hub <name|port>", "Target a specific hub on this machine (see `slay hub ls`)").showSuggestionAfterError(true).showHelpAfterError(true).hook("preAction", async (thisCommand) => {
|
|
37218
37189
|
const root = thisCommand.parent ?? thisCommand;
|
|
37219
37190
|
const opts = root.opts();
|
|
37220
37191
|
if (opts.dev) process.env.SLAYZONE_DEV = "1";
|
|
37221
37192
|
if (opts.hub !== void 0) await applyHubOverride(opts.hub);
|
|
37222
37193
|
});
|
|
37223
37194
|
async function applyHubOverride(nameOrPort) {
|
|
37224
|
-
|
|
37225
|
-
if (hasLocalDatabase()) {
|
|
37226
|
-
try {
|
|
37227
|
-
const appPort = getServerPort();
|
|
37228
|
-
if (appPort) extraPorts = [appPort];
|
|
37229
|
-
} catch {
|
|
37230
|
-
}
|
|
37231
|
-
}
|
|
37232
|
-
const hub = await findHub(nameOrPort, { extraPorts });
|
|
37195
|
+
const hub = await findHub(nameOrPort);
|
|
37233
37196
|
if (!hub) {
|
|
37234
|
-
const running = await discoverHubs(
|
|
37197
|
+
const running = await discoverHubs();
|
|
37235
37198
|
console.error(`No hub named or listening on "${nameOrPort}".`);
|
|
37236
37199
|
console.error(
|
|
37237
37200
|
running.length > 0 ? `Running hubs: ${running.map((h) => `${h.name} (${h.port})`).join(", ")}` : "No hubs are running on this machine."
|
|
@@ -37255,6 +37218,7 @@ program2.addCommand(initCommand());
|
|
|
37255
37218
|
program2.addCommand(ptyCommand());
|
|
37256
37219
|
program2.addCommand(hubCommand());
|
|
37257
37220
|
program2.addCommand(runnerCommand());
|
|
37221
|
+
program2.addCommand(updateCommand());
|
|
37258
37222
|
program2.parseAsync(process.argv).catch((err) => {
|
|
37259
37223
|
console.error(err instanceof Error ? err.message : String(err));
|
|
37260
37224
|
process.exit(1);
|