@dev.sail.money/sailor 1.1.0-62 → 1.1.0-63
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/package.json
CHANGED
|
@@ -966,8 +966,8 @@ var require_command = __commonJS({
|
|
|
966
966
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports2) {
|
|
967
967
|
var EventEmitter = require("node:events").EventEmitter;
|
|
968
968
|
var childProcess = require("node:child_process");
|
|
969
|
-
var
|
|
970
|
-
var
|
|
969
|
+
var path9 = require("node:path");
|
|
970
|
+
var fs10 = require("node:fs");
|
|
971
971
|
var process2 = require("node:process");
|
|
972
972
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
973
973
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1899,11 +1899,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1899
1899
|
let launchWithNode = false;
|
|
1900
1900
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1901
1901
|
function findFile(baseDir, baseName) {
|
|
1902
|
-
const localBin =
|
|
1903
|
-
if (
|
|
1904
|
-
if (sourceExt.includes(
|
|
1902
|
+
const localBin = path9.resolve(baseDir, baseName);
|
|
1903
|
+
if (fs10.existsSync(localBin)) return localBin;
|
|
1904
|
+
if (sourceExt.includes(path9.extname(baseName))) return void 0;
|
|
1905
1905
|
const foundExt = sourceExt.find(
|
|
1906
|
-
(ext) =>
|
|
1906
|
+
(ext) => fs10.existsSync(`${localBin}${ext}`)
|
|
1907
1907
|
);
|
|
1908
1908
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1909
1909
|
return void 0;
|
|
@@ -1915,21 +1915,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1915
1915
|
if (this._scriptPath) {
|
|
1916
1916
|
let resolvedScriptPath;
|
|
1917
1917
|
try {
|
|
1918
|
-
resolvedScriptPath =
|
|
1918
|
+
resolvedScriptPath = fs10.realpathSync(this._scriptPath);
|
|
1919
1919
|
} catch (err) {
|
|
1920
1920
|
resolvedScriptPath = this._scriptPath;
|
|
1921
1921
|
}
|
|
1922
|
-
executableDir =
|
|
1923
|
-
|
|
1922
|
+
executableDir = path9.resolve(
|
|
1923
|
+
path9.dirname(resolvedScriptPath),
|
|
1924
1924
|
executableDir
|
|
1925
1925
|
);
|
|
1926
1926
|
}
|
|
1927
1927
|
if (executableDir) {
|
|
1928
1928
|
let localFile = findFile(executableDir, executableFile);
|
|
1929
1929
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1930
|
-
const legacyName =
|
|
1930
|
+
const legacyName = path9.basename(
|
|
1931
1931
|
this._scriptPath,
|
|
1932
|
-
|
|
1932
|
+
path9.extname(this._scriptPath)
|
|
1933
1933
|
);
|
|
1934
1934
|
if (legacyName !== this._name) {
|
|
1935
1935
|
localFile = findFile(
|
|
@@ -1940,7 +1940,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1940
1940
|
}
|
|
1941
1941
|
executableFile = localFile || executableFile;
|
|
1942
1942
|
}
|
|
1943
|
-
launchWithNode = sourceExt.includes(
|
|
1943
|
+
launchWithNode = sourceExt.includes(path9.extname(executableFile));
|
|
1944
1944
|
let proc;
|
|
1945
1945
|
if (process2.platform !== "win32") {
|
|
1946
1946
|
if (launchWithNode) {
|
|
@@ -2780,7 +2780,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2780
2780
|
* @return {Command}
|
|
2781
2781
|
*/
|
|
2782
2782
|
nameFromFilename(filename) {
|
|
2783
|
-
this._name =
|
|
2783
|
+
this._name = path9.basename(filename, path9.extname(filename));
|
|
2784
2784
|
return this;
|
|
2785
2785
|
}
|
|
2786
2786
|
/**
|
|
@@ -2794,9 +2794,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2794
2794
|
* @param {string} [path]
|
|
2795
2795
|
* @return {(string|null|Command)}
|
|
2796
2796
|
*/
|
|
2797
|
-
executableDir(
|
|
2798
|
-
if (
|
|
2799
|
-
this._executableDir =
|
|
2797
|
+
executableDir(path10) {
|
|
2798
|
+
if (path10 === void 0) return this._executableDir;
|
|
2799
|
+
this._executableDir = path10;
|
|
2800
2800
|
return this;
|
|
2801
2801
|
}
|
|
2802
2802
|
/**
|
|
@@ -30772,9 +30772,9 @@ var init_defineKzg = __esm({
|
|
|
30772
30772
|
});
|
|
30773
30773
|
|
|
30774
30774
|
// ../../node_modules/.pnpm/viem@2.51.3_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@5.0.10_zod@4.4.3/node_modules/viem/_esm/utils/kzg/setupKzg.js
|
|
30775
|
-
function setupKzg(parameters,
|
|
30775
|
+
function setupKzg(parameters, path9) {
|
|
30776
30776
|
try {
|
|
30777
|
-
parameters.loadTrustedSetup(
|
|
30777
|
+
parameters.loadTrustedSetup(path9);
|
|
30778
30778
|
} catch (e) {
|
|
30779
30779
|
const error = e;
|
|
30780
30780
|
if (!error.message.includes("trusted setup is already loaded"))
|
|
@@ -35190,8 +35190,8 @@ var require_websocket_server2 = __commonJS({
|
|
|
35190
35190
|
});
|
|
35191
35191
|
|
|
35192
35192
|
// src/index.ts
|
|
35193
|
-
var
|
|
35194
|
-
var
|
|
35193
|
+
var import_node_fs19 = require("node:fs");
|
|
35194
|
+
var import_node_path15 = require("node:path");
|
|
35195
35195
|
|
|
35196
35196
|
// ../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
|
|
35197
35197
|
var import_index = __toESM(require_commander(), 1);
|
|
@@ -37123,14 +37123,14 @@ var HDKey = class _HDKey {
|
|
|
37123
37123
|
}
|
|
37124
37124
|
this.pubHash = hash160(this.pubKey);
|
|
37125
37125
|
}
|
|
37126
|
-
derive(
|
|
37127
|
-
if (!/^[mM]'?/.test(
|
|
37126
|
+
derive(path9) {
|
|
37127
|
+
if (!/^[mM]'?/.test(path9)) {
|
|
37128
37128
|
throw new Error('Path must start with "m" or "M"');
|
|
37129
37129
|
}
|
|
37130
|
-
if (/^[mM]'?$/.test(
|
|
37130
|
+
if (/^[mM]'?$/.test(path9)) {
|
|
37131
37131
|
return this;
|
|
37132
37132
|
}
|
|
37133
|
-
const parts =
|
|
37133
|
+
const parts = path9.replace(/^[mM]'?\//, "").split("/");
|
|
37134
37134
|
let child = this;
|
|
37135
37135
|
for (const c of parts) {
|
|
37136
37136
|
const m = /^(\d+)('?)$/.exec(c);
|
|
@@ -37462,8 +37462,8 @@ function privateKeyToAccount(privateKey, options = {}) {
|
|
|
37462
37462
|
}
|
|
37463
37463
|
|
|
37464
37464
|
// ../../node_modules/.pnpm/viem@2.51.3_bufferutil@4.1.0_typescript@5.9.3_utf-8-validate@5.0.10_zod@4.4.3/node_modules/viem/_esm/accounts/hdKeyToAccount.js
|
|
37465
|
-
function hdKeyToAccount(hdKey_, { accountIndex = 0, addressIndex = 0, changeIndex = 0, path:
|
|
37466
|
-
const hdKey = hdKey_.derive(
|
|
37465
|
+
function hdKeyToAccount(hdKey_, { accountIndex = 0, addressIndex = 0, changeIndex = 0, path: path9, ...options } = {}) {
|
|
37466
|
+
const hdKey = hdKey_.derive(path9 || `m/44'/60'/${accountIndex}'/${changeIndex}/${addressIndex}`);
|
|
37467
37467
|
const account2 = privateKeyToAccount(toHex(hdKey.privateKey), options);
|
|
37468
37468
|
return {
|
|
37469
37469
|
...account2,
|
|
@@ -37564,8 +37564,8 @@ var LocalKeyring = class _LocalKeyring {
|
|
|
37564
37564
|
return _LocalKeyring.fromPrivateKey(`0x${pkBytes.toString("hex")}`);
|
|
37565
37565
|
}
|
|
37566
37566
|
/** Loads a keyring from an encrypted JSON keystore file on disk. */
|
|
37567
|
-
static async fromKeystoreFile(
|
|
37568
|
-
const keystore = JSON.parse((0, import_node_fs.readFileSync)(
|
|
37567
|
+
static async fromKeystoreFile(path9, password) {
|
|
37568
|
+
const keystore = JSON.parse((0, import_node_fs.readFileSync)(path9, "utf-8"));
|
|
37569
37569
|
return _LocalKeyring.fromKeystore(keystore, password);
|
|
37570
37570
|
}
|
|
37571
37571
|
/** Signs a raw 32-byte hash. Returns a 65-byte ECDSA signature. */
|
|
@@ -39141,9 +39141,9 @@ var SigningServer = class {
|
|
|
39141
39141
|
);
|
|
39142
39142
|
}
|
|
39143
39143
|
removeRuntimeState() {
|
|
39144
|
-
const
|
|
39144
|
+
const path9 = (0, import_node_path4.join)(this.runtimeDir, SERVER_STATE_FILE);
|
|
39145
39145
|
try {
|
|
39146
|
-
if ((0, import_node_fs5.existsSync)(
|
|
39146
|
+
if ((0, import_node_fs5.existsSync)(path9)) (0, import_node_fs5.unlinkSync)(path9);
|
|
39147
39147
|
} catch {
|
|
39148
39148
|
}
|
|
39149
39149
|
}
|
|
@@ -40557,8 +40557,8 @@ function scaffoldFoundryWorkspace(root) {
|
|
|
40557
40557
|
writeIfMissing((0, import_node_path6.join)(root, "mandates", "BoundedCallPermission.sol"), EXAMPLE_MANDATE_SOL);
|
|
40558
40558
|
writeIfMissing((0, import_node_path6.join)(root, "mandates", "README.md"), MANDATES_README);
|
|
40559
40559
|
}
|
|
40560
|
-
function writeIfMissing(
|
|
40561
|
-
if (!(0, import_node_fs7.existsSync)(
|
|
40560
|
+
function writeIfMissing(path9, content) {
|
|
40561
|
+
if (!(0, import_node_fs7.existsSync)(path9)) (0, import_node_fs7.writeFileSync)(path9, content, "utf8");
|
|
40562
40562
|
}
|
|
40563
40563
|
|
|
40564
40564
|
// src/commands/init.ts
|
|
@@ -44044,8 +44044,423 @@ async function scan(options) {
|
|
|
44044
44044
|
);
|
|
44045
44045
|
}
|
|
44046
44046
|
|
|
44047
|
-
// src/commands/
|
|
44047
|
+
// src/commands/service.ts
|
|
44048
44048
|
var import_node_child_process2 = require("node:child_process");
|
|
44049
|
+
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
44050
|
+
var import_node_os = __toESM(require("node:os"), 1);
|
|
44051
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
44052
|
+
function sanitizeName(raw) {
|
|
44053
|
+
const s = raw.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
44054
|
+
return s || "agent";
|
|
44055
|
+
}
|
|
44056
|
+
function launchdLabel(projectName) {
|
|
44057
|
+
return `money.sail.${projectName}`;
|
|
44058
|
+
}
|
|
44059
|
+
function systemdUnitName(projectName) {
|
|
44060
|
+
return `sail-${projectName}.service`;
|
|
44061
|
+
}
|
|
44062
|
+
function windowsTaskName(projectName) {
|
|
44063
|
+
return `Sail-${projectName}`;
|
|
44064
|
+
}
|
|
44065
|
+
function runArgs(cfg) {
|
|
44066
|
+
const args = ["run"];
|
|
44067
|
+
if (cfg.chain != null) args.push("--chain", String(cfg.chain));
|
|
44068
|
+
return args;
|
|
44069
|
+
}
|
|
44070
|
+
function xmlEscape(s) {
|
|
44071
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
44072
|
+
}
|
|
44073
|
+
function buildLaunchdPlist(cfg) {
|
|
44074
|
+
const label = launchdLabel(cfg.projectName);
|
|
44075
|
+
const args = [cfg.nodePath, cfg.cliEntry, ...runArgs(cfg)];
|
|
44076
|
+
const argXml = args.map((a) => ` <string>${xmlEscape(a)}</string>`).join("\n");
|
|
44077
|
+
const intervalEnv = cfg.interval != null ? ` <key>EnvironmentVariables</key>
|
|
44078
|
+
<dict>
|
|
44079
|
+
<key>SAILOR_INTERVAL</key>
|
|
44080
|
+
<string>${cfg.interval}</string>
|
|
44081
|
+
</dict>
|
|
44082
|
+
` : "";
|
|
44083
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
44084
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
44085
|
+
<plist version="1.0">
|
|
44086
|
+
<dict>
|
|
44087
|
+
<key>Label</key>
|
|
44088
|
+
<string>${label}</string>
|
|
44089
|
+
<key>ProgramArguments</key>
|
|
44090
|
+
<array>
|
|
44091
|
+
${argXml}
|
|
44092
|
+
</array>
|
|
44093
|
+
<key>WorkingDirectory</key>
|
|
44094
|
+
<string>${xmlEscape(cfg.projectDir)}</string>
|
|
44095
|
+
${intervalEnv} <key>RunAtLoad</key>
|
|
44096
|
+
<true/>
|
|
44097
|
+
<key>KeepAlive</key>
|
|
44098
|
+
<dict>
|
|
44099
|
+
<key>SuccessfulExit</key>
|
|
44100
|
+
<false/>
|
|
44101
|
+
</dict>
|
|
44102
|
+
<key>ThrottleInterval</key>
|
|
44103
|
+
<integer>${cfg.restartSec ?? 30}</integer>
|
|
44104
|
+
<key>StandardOutPath</key>
|
|
44105
|
+
<string>${xmlEscape(cfg.logPath)}</string>
|
|
44106
|
+
<key>StandardErrorPath</key>
|
|
44107
|
+
<string>${xmlEscape(cfg.logPath)}</string>
|
|
44108
|
+
</dict>
|
|
44109
|
+
</plist>
|
|
44110
|
+
`;
|
|
44111
|
+
}
|
|
44112
|
+
function buildSystemdUnit(cfg) {
|
|
44113
|
+
const exec = [cfg.nodePath, cfg.cliEntry, ...runArgs(cfg)].map((a) => /\s/.test(a) ? `"${a}"` : a).join(" ");
|
|
44114
|
+
const intervalEnv = cfg.interval != null ? `Environment=SAILOR_INTERVAL=${cfg.interval}
|
|
44115
|
+
` : "";
|
|
44116
|
+
return `[Unit]
|
|
44117
|
+
Description=Sail agent \u2014 ${cfg.projectName}
|
|
44118
|
+
After=network-online.target
|
|
44119
|
+
Wants=network-online.target
|
|
44120
|
+
|
|
44121
|
+
[Service]
|
|
44122
|
+
Type=simple
|
|
44123
|
+
WorkingDirectory=${cfg.projectDir}
|
|
44124
|
+
${intervalEnv}ExecStart=${exec}
|
|
44125
|
+
Restart=on-failure
|
|
44126
|
+
RestartSec=${cfg.restartSec ?? 30}
|
|
44127
|
+
StandardOutput=append:${cfg.logPath}
|
|
44128
|
+
StandardError=append:${cfg.logPath}
|
|
44129
|
+
|
|
44130
|
+
[Install]
|
|
44131
|
+
WantedBy=default.target
|
|
44132
|
+
`;
|
|
44133
|
+
}
|
|
44134
|
+
function buildWindowsTaskXml(cfg) {
|
|
44135
|
+
const runTail = runArgs(cfg).join(" ");
|
|
44136
|
+
const intervalSet = cfg.interval != null ? `set SAILOR_INTERVAL=${cfg.interval}&& ` : "";
|
|
44137
|
+
const inner = `${intervalSet}"${cfg.nodePath}" "${cfg.cliEntry}" ${runTail} >> "${cfg.logPath}" 2>&1`;
|
|
44138
|
+
const args = `/c "${inner}"`;
|
|
44139
|
+
return `<?xml version="1.0" encoding="UTF-16"?>
|
|
44140
|
+
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
44141
|
+
<RegistrationInfo>
|
|
44142
|
+
<Description>Sail agent \u2014 ${xmlEscape(cfg.projectName)}</Description>
|
|
44143
|
+
</RegistrationInfo>
|
|
44144
|
+
<Triggers>
|
|
44145
|
+
<LogonTrigger>
|
|
44146
|
+
<Enabled>true</Enabled>
|
|
44147
|
+
</LogonTrigger>
|
|
44148
|
+
</Triggers>
|
|
44149
|
+
<Settings>
|
|
44150
|
+
<RestartOnFailure>
|
|
44151
|
+
<Interval>PT${cfg.restartSec ?? 30}S</Interval>
|
|
44152
|
+
<Count>999</Count>
|
|
44153
|
+
</RestartOnFailure>
|
|
44154
|
+
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
|
44155
|
+
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
|
44156
|
+
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
|
44157
|
+
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
|
44158
|
+
</Settings>
|
|
44159
|
+
<Actions>
|
|
44160
|
+
<Exec>
|
|
44161
|
+
<Command>cmd.exe</Command>
|
|
44162
|
+
<Arguments>${xmlEscape(args)}</Arguments>
|
|
44163
|
+
<WorkingDirectory>${xmlEscape(cfg.projectDir)}</WorkingDirectory>
|
|
44164
|
+
</Exec>
|
|
44165
|
+
</Actions>
|
|
44166
|
+
</Task>
|
|
44167
|
+
`;
|
|
44168
|
+
}
|
|
44169
|
+
function isTccProtected(projectDir, home = import_node_os.default.homedir()) {
|
|
44170
|
+
const rel = import_node_path12.default.relative(home, import_node_path12.default.resolve(projectDir));
|
|
44171
|
+
if (rel.startsWith("..") || import_node_path12.default.isAbsolute(rel)) return false;
|
|
44172
|
+
const top = rel.split(import_node_path12.default.sep)[0];
|
|
44173
|
+
return ["Desktop", "Documents", "Downloads"].includes(top ?? "");
|
|
44174
|
+
}
|
|
44175
|
+
function resolveCliEntry() {
|
|
44176
|
+
try {
|
|
44177
|
+
return import_node_fs16.default.realpathSync(process.argv[1]);
|
|
44178
|
+
} catch {
|
|
44179
|
+
return import_node_path12.default.resolve(process.argv[1]);
|
|
44180
|
+
}
|
|
44181
|
+
}
|
|
44182
|
+
function resolveProjectDir(explicit) {
|
|
44183
|
+
const dir = import_node_path12.default.resolve(explicit ?? process.cwd());
|
|
44184
|
+
if (!import_node_fs16.default.existsSync(import_node_path12.default.join(dir, ".sail"))) {
|
|
44185
|
+
throw new Error(
|
|
44186
|
+
`No .sail/ found in ${dir}.
|
|
44187
|
+
Run this from your Sailor project root, or pass --project <path>. (The installer does not search parent directories \u2014 that would risk targeting the wrong project.)`
|
|
44188
|
+
);
|
|
44189
|
+
}
|
|
44190
|
+
return dir;
|
|
44191
|
+
}
|
|
44192
|
+
function passphraseReadiness(projectDir) {
|
|
44193
|
+
const account2 = (() => {
|
|
44194
|
+
try {
|
|
44195
|
+
return JSON.parse(
|
|
44196
|
+
import_node_fs16.default.readFileSync(import_node_path12.default.join(projectDir, ".sail", "account.json"), "utf-8")
|
|
44197
|
+
);
|
|
44198
|
+
} catch {
|
|
44199
|
+
return null;
|
|
44200
|
+
}
|
|
44201
|
+
})();
|
|
44202
|
+
const prevCwd = process.cwd();
|
|
44203
|
+
let keystorePresent = false;
|
|
44204
|
+
try {
|
|
44205
|
+
process.chdir(projectDir);
|
|
44206
|
+
keystorePresent = keyExists("manager", account2?.safe);
|
|
44207
|
+
} catch {
|
|
44208
|
+
keystorePresent = false;
|
|
44209
|
+
} finally {
|
|
44210
|
+
process.chdir(prevCwd);
|
|
44211
|
+
}
|
|
44212
|
+
const env = parseEnvFile(import_node_path12.default.join(projectDir, ".sail", ".env.local"));
|
|
44213
|
+
const passphraseInEnvFile = Boolean(env.SAIL_PASSPHRASE);
|
|
44214
|
+
return { keystorePresent, passphraseInEnvFile, ready: keystorePresent && passphraseInEnvFile };
|
|
44215
|
+
}
|
|
44216
|
+
function buildConfig(opts) {
|
|
44217
|
+
const projectDir = resolveProjectDir(opts.project);
|
|
44218
|
+
return {
|
|
44219
|
+
projectName: sanitizeName(import_node_path12.default.basename(projectDir)),
|
|
44220
|
+
projectDir,
|
|
44221
|
+
nodePath: process.execPath,
|
|
44222
|
+
cliEntry: resolveCliEntry(),
|
|
44223
|
+
logPath: import_node_path12.default.join(projectDir, ".sail", "agent.log"),
|
|
44224
|
+
interval: opts.interval != null ? Number(opts.interval) : void 0,
|
|
44225
|
+
chain: opts.chain != null ? Number(opts.chain) : void 0,
|
|
44226
|
+
restartSec: 30
|
|
44227
|
+
};
|
|
44228
|
+
}
|
|
44229
|
+
function plistPath(projectName) {
|
|
44230
|
+
return import_node_path12.default.join(import_node_os.default.homedir(), "Library", "LaunchAgents", `${launchdLabel(projectName)}.plist`);
|
|
44231
|
+
}
|
|
44232
|
+
function systemdPath(projectName) {
|
|
44233
|
+
return import_node_path12.default.join(import_node_os.default.homedir(), ".config", "systemd", "user", systemdUnitName(projectName));
|
|
44234
|
+
}
|
|
44235
|
+
async function serviceInstall(opts = {}) {
|
|
44236
|
+
const cfg = buildConfig(opts);
|
|
44237
|
+
const platform = process.platform;
|
|
44238
|
+
if (platform === "darwin" && isTccProtected(cfg.projectDir)) {
|
|
44239
|
+
const msg = `Project is under a macOS TCC-protected folder (Desktop/Documents/Downloads):
|
|
44240
|
+
${cfg.projectDir}
|
|
44241
|
+
launchd services cannot read those folders, so the agent would silently fail to read .sail/.
|
|
44242
|
+
Move the project somewhere like ~/sail/<name>, or re-run with --force to install anyway.`;
|
|
44243
|
+
if (!opts.force) throw new Error(msg);
|
|
44244
|
+
console.warn(`\u26A0 ${msg}
|
|
44245
|
+
Proceeding because --force was given.`);
|
|
44246
|
+
}
|
|
44247
|
+
const pp = passphraseReadiness(cfg.projectDir);
|
|
44248
|
+
if (!pp.ready) {
|
|
44249
|
+
const why = !pp.keystorePresent ? "no agent keystore found" : "SAIL_PASSPHRASE is not in .sail/.env.local";
|
|
44250
|
+
const msg = `Passphrase not resolvable for an unattended service (${why}).
|
|
44251
|
+
A service does not inherit your shell env, so SAIL_PASSPHRASE must live in .sail/.env.local (0600).
|
|
44252
|
+
Run "sailor keys generate" (and save the passphrase) or set it in .sail/.env.local, then retry. Verify with "sailor doctor".`;
|
|
44253
|
+
if (!opts.force) throw new Error(msg);
|
|
44254
|
+
console.warn(`\u26A0 ${msg}
|
|
44255
|
+
Proceeding because --force was given.`);
|
|
44256
|
+
}
|
|
44257
|
+
import_node_fs16.default.mkdirSync(import_node_path12.default.dirname(cfg.logPath), { recursive: true });
|
|
44258
|
+
if (platform === "darwin") {
|
|
44259
|
+
const plist = buildLaunchdPlist(cfg);
|
|
44260
|
+
const dest = plistPath(cfg.projectName);
|
|
44261
|
+
import_node_fs16.default.mkdirSync(import_node_path12.default.dirname(dest), { recursive: true });
|
|
44262
|
+
import_node_fs16.default.writeFileSync(dest, plist);
|
|
44263
|
+
const uid2 = process.getuid?.() ?? 0;
|
|
44264
|
+
try {
|
|
44265
|
+
try {
|
|
44266
|
+
(0, import_node_child_process2.execFileSync)("launchctl", ["bootout", `gui/${uid2}/${launchdLabel(cfg.projectName)}`], {
|
|
44267
|
+
stdio: "ignore"
|
|
44268
|
+
});
|
|
44269
|
+
} catch {
|
|
44270
|
+
}
|
|
44271
|
+
(0, import_node_child_process2.execFileSync)("launchctl", ["bootstrap", `gui/${uid2}`, dest], { stdio: "inherit" });
|
|
44272
|
+
} catch (err) {
|
|
44273
|
+
throw new Error(`launchctl bootstrap failed: ${err.message}`);
|
|
44274
|
+
}
|
|
44275
|
+
emit(opts.json, () => okInstall(cfg, dest), { status: "ok", platform, unit: dest, ...cfg });
|
|
44276
|
+
return;
|
|
44277
|
+
}
|
|
44278
|
+
if (platform === "linux") {
|
|
44279
|
+
const unit = buildSystemdUnit(cfg);
|
|
44280
|
+
const dest = systemdPath(cfg.projectName);
|
|
44281
|
+
import_node_fs16.default.mkdirSync(import_node_path12.default.dirname(dest), { recursive: true });
|
|
44282
|
+
import_node_fs16.default.writeFileSync(dest, unit);
|
|
44283
|
+
try {
|
|
44284
|
+
(0, import_node_child_process2.execFileSync)("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
|
|
44285
|
+
(0, import_node_child_process2.execFileSync)("systemctl", ["--user", "enable", "--now", systemdUnitName(cfg.projectName)], {
|
|
44286
|
+
stdio: "inherit"
|
|
44287
|
+
});
|
|
44288
|
+
} catch (err) {
|
|
44289
|
+
throw new Error(`systemctl --user enable failed: ${err.message}`);
|
|
44290
|
+
}
|
|
44291
|
+
emit(opts.json, () => okInstall(cfg, dest), { status: "ok", platform, unit: dest, ...cfg });
|
|
44292
|
+
return;
|
|
44293
|
+
}
|
|
44294
|
+
if (platform === "win32") {
|
|
44295
|
+
const xml = buildWindowsTaskXml(cfg);
|
|
44296
|
+
const dest = import_node_path12.default.join(import_node_os.default.tmpdir(), `${windowsTaskName(cfg.projectName)}.xml`);
|
|
44297
|
+
import_node_fs16.default.writeFileSync(dest, xml, "utf-8");
|
|
44298
|
+
try {
|
|
44299
|
+
(0, import_node_child_process2.execFileSync)(
|
|
44300
|
+
"schtasks",
|
|
44301
|
+
["/Create", "/TN", windowsTaskName(cfg.projectName), "/XML", dest, "/F"],
|
|
44302
|
+
{ stdio: "inherit" }
|
|
44303
|
+
);
|
|
44304
|
+
} catch (err) {
|
|
44305
|
+
throw new Error(`schtasks /Create failed: ${err.message}`);
|
|
44306
|
+
} finally {
|
|
44307
|
+
try {
|
|
44308
|
+
import_node_fs16.default.rmSync(dest, { force: true });
|
|
44309
|
+
} catch {
|
|
44310
|
+
}
|
|
44311
|
+
}
|
|
44312
|
+
emit(opts.json, () => okInstall(cfg, windowsTaskName(cfg.projectName)), {
|
|
44313
|
+
status: "ok",
|
|
44314
|
+
platform,
|
|
44315
|
+
unit: windowsTaskName(cfg.projectName),
|
|
44316
|
+
...cfg
|
|
44317
|
+
});
|
|
44318
|
+
return;
|
|
44319
|
+
}
|
|
44320
|
+
throw new Error(`Unsupported platform for service install: ${platform}`);
|
|
44321
|
+
}
|
|
44322
|
+
function okInstall(cfg, unit) {
|
|
44323
|
+
console.log(`\u2713 Installed Sail agent service for "${cfg.projectName}"`);
|
|
44324
|
+
console.log(` unit: ${unit}`);
|
|
44325
|
+
console.log(` runs: ${cfg.nodePath} ${cfg.cliEntry} ${runArgs(cfg).join(" ")}`);
|
|
44326
|
+
console.log(` workdir: ${cfg.projectDir}`);
|
|
44327
|
+
console.log(` logs: ${cfg.logPath} (sailor service logs -f)`);
|
|
44328
|
+
console.log(" The loop runs unattended and restarts on crash.");
|
|
44329
|
+
console.log(
|
|
44330
|
+
" This is one execution host; you can also wake the agent on demand with `sailor trigger github`."
|
|
44331
|
+
);
|
|
44332
|
+
}
|
|
44333
|
+
async function serviceStatus(opts = {}) {
|
|
44334
|
+
const projectName = sanitizeName(import_node_path12.default.basename(resolveProjectDir(opts.project)));
|
|
44335
|
+
const platform = process.platform;
|
|
44336
|
+
let installed = false;
|
|
44337
|
+
let running = false;
|
|
44338
|
+
let detail = "";
|
|
44339
|
+
try {
|
|
44340
|
+
if (platform === "darwin") {
|
|
44341
|
+
installed = import_node_fs16.default.existsSync(plistPath(projectName));
|
|
44342
|
+
const uid2 = process.getuid?.() ?? 0;
|
|
44343
|
+
try {
|
|
44344
|
+
detail = (0, import_node_child_process2.execFileSync)("launchctl", ["print", `gui/${uid2}/${launchdLabel(projectName)}`], {
|
|
44345
|
+
encoding: "utf-8",
|
|
44346
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
44347
|
+
});
|
|
44348
|
+
installed = true;
|
|
44349
|
+
running = /state = running/.test(detail);
|
|
44350
|
+
} catch {
|
|
44351
|
+
}
|
|
44352
|
+
} else if (platform === "linux") {
|
|
44353
|
+
installed = import_node_fs16.default.existsSync(systemdPath(projectName));
|
|
44354
|
+
try {
|
|
44355
|
+
detail = (0, import_node_child_process2.execFileSync)("systemctl", ["--user", "is-active", systemdUnitName(projectName)], {
|
|
44356
|
+
encoding: "utf-8",
|
|
44357
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
44358
|
+
}).trim();
|
|
44359
|
+
} catch (err) {
|
|
44360
|
+
detail = (err.stdout?.toString() ?? "").trim() || err.message;
|
|
44361
|
+
}
|
|
44362
|
+
running = detail === "active";
|
|
44363
|
+
} else if (platform === "win32") {
|
|
44364
|
+
try {
|
|
44365
|
+
detail = (0, import_node_child_process2.execFileSync)("schtasks", ["/Query", "/TN", windowsTaskName(projectName)], {
|
|
44366
|
+
encoding: "utf-8",
|
|
44367
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
44368
|
+
});
|
|
44369
|
+
installed = true;
|
|
44370
|
+
running = /Running/.test(detail);
|
|
44371
|
+
} catch (err) {
|
|
44372
|
+
detail = err.message;
|
|
44373
|
+
}
|
|
44374
|
+
}
|
|
44375
|
+
} catch (err) {
|
|
44376
|
+
detail = err.message;
|
|
44377
|
+
}
|
|
44378
|
+
const state = !installed ? "not installed" : running ? "running" : "installed \xB7 idle";
|
|
44379
|
+
emit(
|
|
44380
|
+
opts.json,
|
|
44381
|
+
() => {
|
|
44382
|
+
console.log(`Service "${projectName}": ${state}`);
|
|
44383
|
+
if (detail) console.log(detail.split("\n").slice(0, 8).join("\n"));
|
|
44384
|
+
},
|
|
44385
|
+
{ status: "ok", project: projectName, installed, running }
|
|
44386
|
+
);
|
|
44387
|
+
}
|
|
44388
|
+
async function serviceStop(opts = {}) {
|
|
44389
|
+
const projectName = sanitizeName(import_node_path12.default.basename(resolveProjectDir(opts.project)));
|
|
44390
|
+
const platform = process.platform;
|
|
44391
|
+
if (platform === "darwin") {
|
|
44392
|
+
const uid2 = process.getuid?.() ?? 0;
|
|
44393
|
+
(0, import_node_child_process2.execFileSync)("launchctl", ["bootout", `gui/${uid2}/${launchdLabel(projectName)}`], {
|
|
44394
|
+
stdio: "inherit"
|
|
44395
|
+
});
|
|
44396
|
+
} else if (platform === "linux") {
|
|
44397
|
+
(0, import_node_child_process2.execFileSync)("systemctl", ["--user", "stop", systemdUnitName(projectName)], { stdio: "inherit" });
|
|
44398
|
+
} else if (platform === "win32") {
|
|
44399
|
+
(0, import_node_child_process2.execFileSync)("schtasks", ["/End", "/TN", windowsTaskName(projectName)], { stdio: "inherit" });
|
|
44400
|
+
}
|
|
44401
|
+
emit(opts.json, () => console.log(`\u2713 Stopped service "${projectName}" (not removed).`), {
|
|
44402
|
+
status: "ok",
|
|
44403
|
+
project: projectName,
|
|
44404
|
+
stopped: true
|
|
44405
|
+
});
|
|
44406
|
+
}
|
|
44407
|
+
async function serviceUninstall(opts = {}) {
|
|
44408
|
+
const projectName = sanitizeName(import_node_path12.default.basename(resolveProjectDir(opts.project)));
|
|
44409
|
+
const platform = process.platform;
|
|
44410
|
+
if (platform === "darwin") {
|
|
44411
|
+
const uid2 = process.getuid?.() ?? 0;
|
|
44412
|
+
try {
|
|
44413
|
+
(0, import_node_child_process2.execFileSync)("launchctl", ["bootout", `gui/${uid2}/${launchdLabel(projectName)}`], {
|
|
44414
|
+
stdio: "ignore"
|
|
44415
|
+
});
|
|
44416
|
+
} catch {
|
|
44417
|
+
}
|
|
44418
|
+
import_node_fs16.default.rmSync(plistPath(projectName), { force: true });
|
|
44419
|
+
} else if (platform === "linux") {
|
|
44420
|
+
try {
|
|
44421
|
+
(0, import_node_child_process2.execFileSync)("systemctl", ["--user", "disable", "--now", systemdUnitName(projectName)], {
|
|
44422
|
+
stdio: "ignore"
|
|
44423
|
+
});
|
|
44424
|
+
} catch {
|
|
44425
|
+
}
|
|
44426
|
+
import_node_fs16.default.rmSync(systemdPath(projectName), { force: true });
|
|
44427
|
+
try {
|
|
44428
|
+
(0, import_node_child_process2.execFileSync)("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" });
|
|
44429
|
+
} catch {
|
|
44430
|
+
}
|
|
44431
|
+
} else if (platform === "win32") {
|
|
44432
|
+
(0, import_node_child_process2.execFileSync)("schtasks", ["/Delete", "/TN", windowsTaskName(projectName), "/F"], {
|
|
44433
|
+
stdio: "inherit"
|
|
44434
|
+
});
|
|
44435
|
+
}
|
|
44436
|
+
emit(opts.json, () => console.log(`\u2713 Uninstalled service "${projectName}".`), {
|
|
44437
|
+
status: "ok",
|
|
44438
|
+
project: projectName,
|
|
44439
|
+
uninstalled: true
|
|
44440
|
+
});
|
|
44441
|
+
}
|
|
44442
|
+
async function serviceLogs(opts = {}) {
|
|
44443
|
+
const projectDir = resolveProjectDir(opts.project);
|
|
44444
|
+
const logPath = import_node_path12.default.join(projectDir, ".sail", "agent.log");
|
|
44445
|
+
if (!import_node_fs16.default.existsSync(logPath)) {
|
|
44446
|
+
console.log(`No log yet at ${logPath}. The service writes here once it runs.`);
|
|
44447
|
+
return;
|
|
44448
|
+
}
|
|
44449
|
+
if (opts.follow) {
|
|
44450
|
+
if (process.platform === "win32") {
|
|
44451
|
+
console.log(import_node_fs16.default.readFileSync(logPath, "utf-8"));
|
|
44452
|
+
console.log("(follow mode is not supported on Windows here \u2014 re-run to refresh)");
|
|
44453
|
+
return;
|
|
44454
|
+
}
|
|
44455
|
+
(0, import_node_child_process2.execFileSync)("tail", ["-f", logPath], { stdio: "inherit" });
|
|
44456
|
+
return;
|
|
44457
|
+
}
|
|
44458
|
+
const lines = import_node_fs16.default.readFileSync(logPath, "utf-8").split("\n");
|
|
44459
|
+
console.log(lines.slice(-200).join("\n"));
|
|
44460
|
+
}
|
|
44461
|
+
|
|
44462
|
+
// src/commands/trigger.ts
|
|
44463
|
+
var import_node_child_process3 = require("node:child_process");
|
|
44049
44464
|
var GH_API = "https://api.github.com";
|
|
44050
44465
|
function parseRepoFromRemoteUrl(url) {
|
|
44051
44466
|
const trimmed = url.trim().replace(/\.git$/, "");
|
|
@@ -44061,7 +44476,7 @@ function resolveRepo(explicit) {
|
|
|
44061
44476
|
}
|
|
44062
44477
|
let url;
|
|
44063
44478
|
try {
|
|
44064
|
-
url = (0,
|
|
44479
|
+
url = (0, import_node_child_process3.execFileSync)("git", ["remote", "get-url", "origin"], {
|
|
44065
44480
|
encoding: "utf-8",
|
|
44066
44481
|
stdio: ["ignore", "pipe", "ignore"]
|
|
44067
44482
|
}).trim();
|
|
@@ -44194,14 +44609,14 @@ async function sessionResume() {
|
|
|
44194
44609
|
}
|
|
44195
44610
|
|
|
44196
44611
|
// src/commands/station.ts
|
|
44197
|
-
var
|
|
44198
|
-
var
|
|
44199
|
-
var RUNTIME_SERVER_FILE2 = (0,
|
|
44612
|
+
var import_node_fs17 = require("node:fs");
|
|
44613
|
+
var import_node_path13 = require("node:path");
|
|
44614
|
+
var RUNTIME_SERVER_FILE2 = (0, import_node_path13.join)(".sail", "runtime", "server.json");
|
|
44200
44615
|
function readState(projectRoot) {
|
|
44201
|
-
const file = (0,
|
|
44202
|
-
if (!(0,
|
|
44616
|
+
const file = (0, import_node_path13.join)(projectRoot, RUNTIME_SERVER_FILE2);
|
|
44617
|
+
if (!(0, import_node_fs17.existsSync)(file)) return null;
|
|
44203
44618
|
try {
|
|
44204
|
-
return JSON.parse((0,
|
|
44619
|
+
return JSON.parse((0, import_node_fs17.readFileSync)(file, "utf8"));
|
|
44205
44620
|
} catch {
|
|
44206
44621
|
return null;
|
|
44207
44622
|
}
|
|
@@ -44273,9 +44688,9 @@ async function stationStop(options) {
|
|
|
44273
44688
|
}
|
|
44274
44689
|
const daemon = await discoverDaemon(projectRoot);
|
|
44275
44690
|
if (!daemon) {
|
|
44276
|
-
const file = (0,
|
|
44691
|
+
const file = (0, import_node_path13.join)(projectRoot, RUNTIME_SERVER_FILE2);
|
|
44277
44692
|
try {
|
|
44278
|
-
if ((0,
|
|
44693
|
+
if ((0, import_node_fs17.existsSync)(file)) (0, import_node_fs17.rmSync)(file);
|
|
44279
44694
|
} catch {
|
|
44280
44695
|
}
|
|
44281
44696
|
emit(options.json, () => console.log("Station process not found; cleared stale state."), {
|
|
@@ -44291,9 +44706,9 @@ async function stationStop(options) {
|
|
|
44291
44706
|
pid: state.pid
|
|
44292
44707
|
});
|
|
44293
44708
|
} catch {
|
|
44294
|
-
const file = (0,
|
|
44709
|
+
const file = (0, import_node_path13.join)(projectRoot, RUNTIME_SERVER_FILE2);
|
|
44295
44710
|
try {
|
|
44296
|
-
if ((0,
|
|
44711
|
+
if ((0, import_node_fs17.existsSync)(file)) (0, import_node_fs17.rmSync)(file);
|
|
44297
44712
|
} catch {
|
|
44298
44713
|
}
|
|
44299
44714
|
emit(options.json, () => console.log("Station process not found; cleared stale state."), {
|
|
@@ -44347,16 +44762,16 @@ async function status() {
|
|
|
44347
44762
|
}
|
|
44348
44763
|
|
|
44349
44764
|
// src/commands/ui.ts
|
|
44350
|
-
var
|
|
44351
|
-
var
|
|
44765
|
+
var import_node_child_process4 = require("node:child_process");
|
|
44766
|
+
var import_node_fs18 = __toESM(require("node:fs"), 1);
|
|
44352
44767
|
var import_node_net2 = __toESM(require("node:net"), 1);
|
|
44353
|
-
var
|
|
44354
|
-
var UI_STATE_FILE =
|
|
44768
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
44769
|
+
var UI_STATE_FILE = import_node_path14.default.join(".sail", "runtime", "ui.json");
|
|
44355
44770
|
function readState2(projectRoot) {
|
|
44356
|
-
const file =
|
|
44357
|
-
if (!
|
|
44771
|
+
const file = import_node_path14.default.join(projectRoot, UI_STATE_FILE);
|
|
44772
|
+
if (!import_node_fs18.default.existsSync(file)) return null;
|
|
44358
44773
|
try {
|
|
44359
|
-
return JSON.parse(
|
|
44774
|
+
return JSON.parse(import_node_fs18.default.readFileSync(file, "utf-8"));
|
|
44360
44775
|
} catch {
|
|
44361
44776
|
return null;
|
|
44362
44777
|
}
|
|
@@ -44397,15 +44812,15 @@ function waitForPort(port, timeoutMs) {
|
|
|
44397
44812
|
}
|
|
44398
44813
|
async function uiCommand() {
|
|
44399
44814
|
const distDir = cliDistDir();
|
|
44400
|
-
const uiDistDir =
|
|
44401
|
-
const serverBundle =
|
|
44815
|
+
const uiDistDir = import_node_path14.default.join(packageRoot(), "packages", "ui", "dist");
|
|
44816
|
+
const serverBundle = import_node_path14.default.resolve(distDir, "server.cjs");
|
|
44402
44817
|
const projectRoot = process.cwd();
|
|
44403
|
-
const sailDir2 =
|
|
44818
|
+
const sailDir2 = import_node_path14.default.join(projectRoot, ".sail");
|
|
44404
44819
|
const port = await findFreePort(projectPort(projectRoot));
|
|
44405
|
-
if (!
|
|
44820
|
+
if (!import_node_fs18.default.existsSync(serverBundle)) {
|
|
44406
44821
|
throw new Error(`Server bundle not found at ${serverBundle}. Re-run the sailor build.`);
|
|
44407
44822
|
}
|
|
44408
|
-
if (!
|
|
44823
|
+
if (!import_node_fs18.default.existsSync(import_node_path14.default.join(uiDistDir, "index.html"))) {
|
|
44409
44824
|
throw new Error(`UI dist not found at ${uiDistDir}. Re-run the sailor build.`);
|
|
44410
44825
|
}
|
|
44411
44826
|
const existing = readState2(projectRoot);
|
|
@@ -44413,17 +44828,17 @@ async function uiCommand() {
|
|
|
44413
44828
|
console.log(`Sailor UI is already running (pid ${existing.pid}) at http://localhost:${existing.port}`);
|
|
44414
44829
|
return;
|
|
44415
44830
|
}
|
|
44416
|
-
const runtimeDir =
|
|
44417
|
-
|
|
44418
|
-
const logFile =
|
|
44419
|
-
const logFd =
|
|
44420
|
-
const child = (0,
|
|
44831
|
+
const runtimeDir = import_node_path14.default.join(projectRoot, ".sail", "runtime");
|
|
44832
|
+
import_node_fs18.default.mkdirSync(runtimeDir, { recursive: true });
|
|
44833
|
+
const logFile = import_node_path14.default.join(runtimeDir, "ui.log");
|
|
44834
|
+
const logFd = import_node_fs18.default.openSync(logFile, "a");
|
|
44835
|
+
const child = (0, import_node_child_process4.spawn)(process.execPath, [serverBundle], {
|
|
44421
44836
|
detached: true,
|
|
44422
44837
|
stdio: ["ignore", logFd, logFd],
|
|
44423
44838
|
env: { ...process.env, SAIL_DIR: sailDir2, SERVE_DIST: "1", PORT: String(port), SAILOR_UI_DIST: uiDistDir }
|
|
44424
44839
|
});
|
|
44425
44840
|
child.unref();
|
|
44426
|
-
|
|
44841
|
+
import_node_fs18.default.closeSync(logFd);
|
|
44427
44842
|
const READY_TIMEOUT_MS = 1e4;
|
|
44428
44843
|
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
44429
44844
|
let ready = false;
|
|
@@ -44437,18 +44852,18 @@ async function uiCommand() {
|
|
|
44437
44852
|
if (!ready) {
|
|
44438
44853
|
let tail = "";
|
|
44439
44854
|
try {
|
|
44440
|
-
tail =
|
|
44855
|
+
tail = import_node_fs18.default.readFileSync(logFile, "utf-8").split("\n").filter(Boolean).slice(-15).join("\n");
|
|
44441
44856
|
} catch {
|
|
44442
44857
|
}
|
|
44443
44858
|
throw new Error(
|
|
44444
44859
|
`Sailor UI failed to start within ${READY_TIMEOUT_MS / 1e3}s on port ${port}.` + (tail ? `
|
|
44445
44860
|
|
|
44446
44861
|
Server output:
|
|
44447
|
-
${tail}` : ` See ${
|
|
44862
|
+
${tail}` : ` See ${import_node_path14.default.relative(projectRoot, logFile)}.`)
|
|
44448
44863
|
);
|
|
44449
44864
|
}
|
|
44450
|
-
|
|
44451
|
-
|
|
44865
|
+
import_node_fs18.default.writeFileSync(
|
|
44866
|
+
import_node_path14.default.join(projectRoot, UI_STATE_FILE),
|
|
44452
44867
|
JSON.stringify({ pid: child.pid, port, startedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)
|
|
44453
44868
|
);
|
|
44454
44869
|
console.log(`Sailor UI started at http://localhost:${port} (pid ${child.pid})`);
|
|
@@ -44459,7 +44874,7 @@ function uiStatus() {
|
|
|
44459
44874
|
if (state && isAlive(state.pid)) {
|
|
44460
44875
|
console.log(`\u25CF running http://localhost:${state.port} (pid ${state.pid})`);
|
|
44461
44876
|
} else {
|
|
44462
|
-
if (state)
|
|
44877
|
+
if (state) import_node_fs18.default.rmSync(import_node_path14.default.join(process.cwd(), UI_STATE_FILE), { force: true });
|
|
44463
44878
|
console.log("\u25CB Sailor UI is not running");
|
|
44464
44879
|
}
|
|
44465
44880
|
}
|
|
@@ -44471,19 +44886,19 @@ function uiStop() {
|
|
|
44471
44886
|
return;
|
|
44472
44887
|
}
|
|
44473
44888
|
if (!isAlive(state.pid)) {
|
|
44474
|
-
|
|
44889
|
+
import_node_fs18.default.rmSync(import_node_path14.default.join(projectRoot, UI_STATE_FILE), { force: true });
|
|
44475
44890
|
console.log("Sailor UI is not running (stale state file removed).");
|
|
44476
44891
|
return;
|
|
44477
44892
|
}
|
|
44478
44893
|
process.kill(state.pid, "SIGTERM");
|
|
44479
|
-
|
|
44894
|
+
import_node_fs18.default.rmSync(import_node_path14.default.join(projectRoot, UI_STATE_FILE), { force: true });
|
|
44480
44895
|
console.log(`Stopped Sailor UI (pid ${state.pid}).`);
|
|
44481
44896
|
}
|
|
44482
44897
|
|
|
44483
44898
|
// src/index.ts
|
|
44484
44899
|
function cliVersion() {
|
|
44485
44900
|
try {
|
|
44486
|
-
const pkg = JSON.parse((0,
|
|
44901
|
+
const pkg = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path15.join)(packageRoot(), "package.json"), "utf-8"));
|
|
44487
44902
|
return pkg.version ?? "0.0.0";
|
|
44488
44903
|
} catch {
|
|
44489
44904
|
return "0.0.0";
|
|
@@ -44597,6 +45012,14 @@ program2.command("capabilities").description(
|
|
|
44597
45012
|
"Feasibility map (read-only): chains, kernel model, mandate templates, strategy primitives"
|
|
44598
45013
|
).option("--json", "Emit machine-readable JSON").action(actionWith(capabilities));
|
|
44599
45014
|
program2.command("chains").description("List supported chains and their SailKernel deployment addresses").option("--verify", "Verify each kernel is deployed via eth_getCode (one RPC call per chain)").option("--json", "Emit machine-readable JSON").action(actionWith(chainsCommand));
|
|
45015
|
+
var service = program2.command("service").description(
|
|
45016
|
+
"Run the agent unattended as a local OS service (launchd/systemd/Task Scheduler).\nOne execution host among several \u2014 it runs the loop directly, and composes with\nthe external-trigger seam (`sailor trigger github`) and the cloud cron job."
|
|
45017
|
+
);
|
|
45018
|
+
service.command("install").description("Install + start the agent as a local service that restarts on crash").option("--interval <s>", "Loop interval in seconds (sets SAILOR_INTERVAL in the unit)").option("--project <path>", "Project root (must contain .sail/; default: current directory)").option("--chain <id>", "Chain ID to run on").option("--force", "Proceed despite a TCC-protected path or unresolved passphrase (with warning)").option("--json", "Emit machine-readable JSON").action(actionWith(serviceInstall));
|
|
45019
|
+
service.command("status").description("Show whether the agent service is installed and running").option("--project <path>", "Project root (default: current directory)").option("--json", "Emit machine-readable JSON").action(actionWith(serviceStatus));
|
|
45020
|
+
service.command("stop").description("Stop the service without removing it").option("--project <path>", "Project root (default: current directory)").option("--json", "Emit machine-readable JSON").action(actionWith(serviceStop));
|
|
45021
|
+
service.command("uninstall").description("Stop and remove the service unit entirely").option("--project <path>", "Project root (default: current directory)").option("--json", "Emit machine-readable JSON").action(actionWith(serviceUninstall));
|
|
45022
|
+
service.command("logs").description("Show the agent log (.sail/agent.log); -f to follow").option("--project <path>", "Project root (default: current directory)").option("-f, --follow", "Follow the log (tail -f)").action(actionWith(serviceLogs));
|
|
44600
45023
|
program2.parse(process.argv);
|
|
44601
45024
|
/*! Bundled license information:
|
|
44602
45025
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Do not edit manually — run `pnpm build` to regenerate.
|
|
6
6
|
*
|
|
7
7
|
* Spec version : 1.2.0
|
|
8
|
-
* Generated at : 2026-06-15T17:
|
|
8
|
+
* Generated at : 2026-06-15T17:59:04.614Z
|
|
9
9
|
*/
|
|
10
10
|
export declare const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
|
|
11
11
|
export declare const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Do not edit manually — run `pnpm build` to regenerate.
|
|
6
6
|
*
|
|
7
7
|
* Spec version : 1.2.0
|
|
8
|
-
* Generated at : 2026-06-15T17:
|
|
8
|
+
* Generated at : 2026-06-15T17:59:04.614Z
|
|
9
9
|
*/
|
|
10
10
|
export const SAIL_INTELLIGENCE_BASE_URL = "https://api.sail.money";
|
|
11
11
|
export const SAIL_INTELLIGENCE_DOCS_URL = "https://api.sail.money/docs";
|