@alan-ai-hq/agent-manager 0.1.95 → 0.1.96
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/index.cjs +219 -521
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -3404,7 +3404,7 @@ var require_websocket = __commonJS({
|
|
|
3404
3404
|
var http2 = require("http");
|
|
3405
3405
|
var net = require("net");
|
|
3406
3406
|
var tls = require("tls");
|
|
3407
|
-
var { randomBytes: randomBytes13, createHash:
|
|
3407
|
+
var { randomBytes: randomBytes13, createHash: createHash18 } = require("crypto");
|
|
3408
3408
|
var { Duplex, Readable: Readable2 } = require("stream");
|
|
3409
3409
|
var { URL: URL2 } = require("url");
|
|
3410
3410
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -4061,7 +4061,7 @@ var require_websocket = __commonJS({
|
|
|
4061
4061
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
4062
4062
|
return;
|
|
4063
4063
|
}
|
|
4064
|
-
const digest =
|
|
4064
|
+
const digest = createHash18("sha1").update(key + GUID).digest("base64");
|
|
4065
4065
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
4066
4066
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
4067
4067
|
return;
|
|
@@ -4428,7 +4428,7 @@ var require_websocket_server = __commonJS({
|
|
|
4428
4428
|
var EventEmitter = require("events");
|
|
4429
4429
|
var http2 = require("http");
|
|
4430
4430
|
var { Duplex } = require("stream");
|
|
4431
|
-
var { createHash:
|
|
4431
|
+
var { createHash: createHash18 } = require("crypto");
|
|
4432
4432
|
var extension = require_extension();
|
|
4433
4433
|
var PerMessageDeflate = require_permessage_deflate();
|
|
4434
4434
|
var subprotocol = require_subprotocol();
|
|
@@ -4725,7 +4725,7 @@ var require_websocket_server = __commonJS({
|
|
|
4725
4725
|
);
|
|
4726
4726
|
}
|
|
4727
4727
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
4728
|
-
const digest =
|
|
4728
|
+
const digest = createHash18("sha1").update(key + GUID).digest("base64");
|
|
4729
4729
|
const headers = [
|
|
4730
4730
|
"HTTP/1.1 101 Switching Protocols",
|
|
4731
4731
|
"Upgrade: websocket",
|
|
@@ -15451,7 +15451,7 @@ function describeError(error61) {
|
|
|
15451
15451
|
}
|
|
15452
15452
|
|
|
15453
15453
|
// src/version.ts
|
|
15454
|
-
var AGENT_VERSION = "0.1.
|
|
15454
|
+
var AGENT_VERSION = "0.1.96";
|
|
15455
15455
|
|
|
15456
15456
|
// src/daemon-worktree.ts
|
|
15457
15457
|
var import_node_child_process3 = require("child_process");
|
|
@@ -49610,16 +49610,6 @@ async function probeLocalDaemon(port, token, timeoutMs = 750) {
|
|
|
49610
49610
|
const probe = await probeLocalDaemonEndpoint(port, token, timeoutMs);
|
|
49611
49611
|
return probe.state === "running" ? probe.status : null;
|
|
49612
49612
|
}
|
|
49613
|
-
function requestLocalDaemonShutdown(port, token) {
|
|
49614
|
-
return fetch(`http://127.0.0.1:${port}/shutdown?force=1`, {
|
|
49615
|
-
method: "POST",
|
|
49616
|
-
headers: {
|
|
49617
|
-
authorization: `Bearer ${token}`,
|
|
49618
|
-
"x-alan-shutdown-reason": "runtime_shutdown"
|
|
49619
|
-
},
|
|
49620
|
-
signal: AbortSignal.timeout(5e3)
|
|
49621
|
-
});
|
|
49622
|
-
}
|
|
49623
49613
|
async function adoptLocalDaemonControl(input2) {
|
|
49624
49614
|
const timeoutMs = input2.timeoutMs ?? 750;
|
|
49625
49615
|
try {
|
|
@@ -76697,13 +76687,13 @@ var RuntimeRunJournal = class {
|
|
|
76697
76687
|
* Keep the exact interruption outcome until a durable authenticated control
|
|
76698
76688
|
* channel can prove both identity and ownership.
|
|
76699
76689
|
*/
|
|
76700
|
-
assessRecovery(runId,
|
|
76690
|
+
assessRecovery(runId, isProcessAlive) {
|
|
76701
76691
|
const entry = this.entries.get(runId);
|
|
76702
76692
|
if (!entry) return void 0;
|
|
76703
76693
|
if (entry.providerPid === void 0) {
|
|
76704
76694
|
return { reattachable: false, reason: "provider_not_recorded" };
|
|
76705
76695
|
}
|
|
76706
|
-
if (!
|
|
76696
|
+
if (!isProcessAlive(entry.providerPid)) {
|
|
76707
76697
|
return {
|
|
76708
76698
|
reattachable: false,
|
|
76709
76699
|
reason: "provider_not_running",
|
|
@@ -80450,17 +80440,6 @@ async function runLocalDaemonRecoveryLadder(input2) {
|
|
|
80450
80440
|
error: "The local daemon exhausted its reconnect and safe-restart recovery budget."
|
|
80451
80441
|
};
|
|
80452
80442
|
}
|
|
80453
|
-
function writeRegisteredRuntimeConfig(args, previousConfig, registered) {
|
|
80454
|
-
writeConfig({
|
|
80455
|
-
...registered,
|
|
80456
|
-
localApiPort: getLocalApiPort(args, {}),
|
|
80457
|
-
localApiToken: previousConfig.localApiToken ?? (0, import_node_crypto19.randomBytes)(24).toString("hex"),
|
|
80458
|
-
localServiceId: previousConfig.localServiceId ?? (0, import_node_crypto19.randomUUID)(),
|
|
80459
|
-
localServiceSecret: previousConfig.localServiceSecret ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
|
|
80460
|
-
eventSpoolKey: previousConfig.eventSpoolKey ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
|
|
80461
|
-
daemonEpoch: previousConfig.daemonEpoch
|
|
80462
|
-
});
|
|
80463
|
-
}
|
|
80464
80443
|
async function setupDaemon(args) {
|
|
80465
80444
|
bindConfigPath(args);
|
|
80466
80445
|
const previousConfig = readConfigForRegistration();
|
|
@@ -80521,7 +80500,7 @@ async function setupDaemon(args) {
|
|
|
80521
80500
|
credentialGeneration: body2.credentialGeneration,
|
|
80522
80501
|
configPath: getConfigPath()
|
|
80523
80502
|
});
|
|
80524
|
-
return
|
|
80503
|
+
return { daemonAlreadyRunning: true };
|
|
80525
80504
|
}
|
|
80526
80505
|
if (readLocalDaemonOwnerLease(getConfigPath())) {
|
|
80527
80506
|
throw new Error(
|
|
@@ -80535,17 +80514,23 @@ async function setupDaemon(args) {
|
|
|
80535
80514
|
if (setupToken && error61 instanceof RuntimeSetupGrantExpiredError) {
|
|
80536
80515
|
console.info("[alan-agent] Setup link expired; continuing with browser authorization");
|
|
80537
80516
|
await loginWithDeviceCode(args);
|
|
80538
|
-
return false;
|
|
80517
|
+
return { daemonAlreadyRunning: false };
|
|
80539
80518
|
}
|
|
80540
80519
|
throw error61;
|
|
80541
80520
|
}
|
|
80542
|
-
|
|
80521
|
+
writeConfig({
|
|
80543
80522
|
apiUrl,
|
|
80544
80523
|
wsUrl,
|
|
80545
80524
|
endpointProfile,
|
|
80546
80525
|
runtimeId: body.runtimeId,
|
|
80547
80526
|
runtimeToken: body.runtimeToken,
|
|
80548
80527
|
runtimeRenewalToken: body.runtimeRenewalToken,
|
|
80528
|
+
localApiPort: getLocalApiPort(args, {}),
|
|
80529
|
+
localApiToken: previousConfig.localApiToken ?? (0, import_node_crypto19.randomBytes)(24).toString("hex"),
|
|
80530
|
+
localServiceId: previousConfig.localServiceId ?? (0, import_node_crypto19.randomUUID)(),
|
|
80531
|
+
localServiceSecret: previousConfig.localServiceSecret ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
|
|
80532
|
+
eventSpoolKey: previousConfig.eventSpoolKey ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
|
|
80533
|
+
daemonEpoch: previousConfig.daemonEpoch,
|
|
80549
80534
|
displayName: body.displayName,
|
|
80550
80535
|
installationId
|
|
80551
80536
|
});
|
|
@@ -80554,7 +80539,7 @@ async function setupDaemon(args) {
|
|
|
80554
80539
|
runtimeId: body.runtimeId,
|
|
80555
80540
|
configPath: getConfigPath()
|
|
80556
80541
|
});
|
|
80557
|
-
return false;
|
|
80542
|
+
return { daemonAlreadyRunning: false };
|
|
80558
80543
|
}
|
|
80559
80544
|
async function loginWithDeviceCode(args) {
|
|
80560
80545
|
bindConfigPath(args);
|
|
@@ -80643,13 +80628,19 @@ async function loginWithDeviceCode(args) {
|
|
|
80643
80628
|
if (ownedPending?.operationId !== operation.id) {
|
|
80644
80629
|
throw new Error("browser authorization sidecar ownership was lost before finalization");
|
|
80645
80630
|
}
|
|
80646
|
-
|
|
80631
|
+
writeConfig({
|
|
80647
80632
|
apiUrl,
|
|
80648
80633
|
wsUrl,
|
|
80649
80634
|
endpointProfile,
|
|
80650
80635
|
runtimeId: body.runtime.id,
|
|
80651
80636
|
runtimeToken: body.runtimeToken,
|
|
80652
80637
|
runtimeRenewalToken: body.runtimeRenewalToken,
|
|
80638
|
+
localApiPort: getLocalApiPort(args, {}),
|
|
80639
|
+
localApiToken: previousConfig.localApiToken ?? (0, import_node_crypto19.randomBytes)(24).toString("hex"),
|
|
80640
|
+
localServiceId: previousConfig.localServiceId ?? (0, import_node_crypto19.randomUUID)(),
|
|
80641
|
+
localServiceSecret: previousConfig.localServiceSecret ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
|
|
80642
|
+
eventSpoolKey: previousConfig.eventSpoolKey ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
|
|
80643
|
+
daemonEpoch: previousConfig.daemonEpoch,
|
|
80653
80644
|
displayName: body.runtime.displayName ?? displayName,
|
|
80654
80645
|
installationId
|
|
80655
80646
|
});
|
|
@@ -80688,7 +80679,14 @@ async function stopDaemon(args) {
|
|
|
80688
80679
|
console.info("[alan-agent] No daemon listening", { port: localApiPort });
|
|
80689
80680
|
return;
|
|
80690
80681
|
}
|
|
80691
|
-
const response = await
|
|
80682
|
+
const response = await fetch(`http://127.0.0.1:${localApiPort}/shutdown?force=1`, {
|
|
80683
|
+
method: "POST",
|
|
80684
|
+
headers: {
|
|
80685
|
+
authorization: `Bearer ${localApiToken}`,
|
|
80686
|
+
"x-alan-shutdown-reason": "runtime_shutdown"
|
|
80687
|
+
},
|
|
80688
|
+
signal: AbortSignal.timeout(5e3)
|
|
80689
|
+
});
|
|
80692
80690
|
if (!response.ok) {
|
|
80693
80691
|
throw new Error(`Failed to stop daemon: HTTP ${response.status}`);
|
|
80694
80692
|
}
|
|
@@ -80833,7 +80831,14 @@ async function drainAndStopLocalDaemonBeforeCredentialCleanup(args, stored) {
|
|
|
80833
80831
|
`Logout could not safely drain the local daemon (HTTP ${prepare.status}). Stop or update the local service before removing credentials.`
|
|
80834
80832
|
);
|
|
80835
80833
|
}
|
|
80836
|
-
const shutdown = await
|
|
80834
|
+
const shutdown = await fetch(`http://127.0.0.1:${localApiPort}/shutdown?force=1`, {
|
|
80835
|
+
method: "POST",
|
|
80836
|
+
headers: {
|
|
80837
|
+
authorization: `Bearer ${localApiToken}`,
|
|
80838
|
+
"x-alan-shutdown-reason": "runtime_shutdown"
|
|
80839
|
+
},
|
|
80840
|
+
signal: AbortSignal.timeout(5e3)
|
|
80841
|
+
});
|
|
80837
80842
|
if (!shutdown.ok) {
|
|
80838
80843
|
throw new Error(`Logout could not stop the local daemon (HTTP ${shutdown.status}).`);
|
|
80839
80844
|
}
|
|
@@ -80994,9 +80999,6 @@ async function printDoctor(args = []) {
|
|
|
80994
80999
|
);
|
|
80995
81000
|
}
|
|
80996
81001
|
|
|
80997
|
-
// src/install-command.ts
|
|
80998
|
-
var import_promises6 = require("timers/promises");
|
|
80999
|
-
|
|
81000
81002
|
// src/mcp-config-adapters.ts
|
|
81001
81003
|
var import_node_crypto20 = require("crypto");
|
|
81002
81004
|
var import_node_fs23 = require("fs");
|
|
@@ -82381,14 +82383,12 @@ function runMcpIntegrationCommand(args, options = {}) {
|
|
|
82381
82383
|
|
|
82382
82384
|
// src/service-manager.ts
|
|
82383
82385
|
var import_node_child_process9 = require("child_process");
|
|
82384
|
-
var import_node_crypto21 = require("crypto");
|
|
82385
82386
|
var import_node_fs25 = require("fs");
|
|
82386
82387
|
var import_node_os16 = require("os");
|
|
82387
82388
|
var import_node_path27 = require("path");
|
|
82388
82389
|
var SERVICE_LABEL = "ai.tryalan.agent";
|
|
82389
82390
|
var SYSTEMD_UNIT = "alan-agent.service";
|
|
82390
82391
|
var WINDOWS_TASK = "Alan Agent";
|
|
82391
|
-
var STOP_POLL_INTERVAL_MS = 200;
|
|
82392
82392
|
function xml(value2) {
|
|
82393
82393
|
return value2.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
82394
82394
|
}
|
|
@@ -82398,18 +82398,6 @@ function systemdArg(value2) {
|
|
|
82398
82398
|
function powershellLiteral(value2) {
|
|
82399
82399
|
return `'${value2.replaceAll("'", "''")}'`;
|
|
82400
82400
|
}
|
|
82401
|
-
function powershellCommand(script, tolerateFailure = false) {
|
|
82402
|
-
return {
|
|
82403
|
-
command: "powershell.exe",
|
|
82404
|
-
args: ["-NoProfile", "-NonInteractive", "-Command", script],
|
|
82405
|
-
tolerateFailure
|
|
82406
|
-
};
|
|
82407
|
-
}
|
|
82408
|
-
function windowsCommandLineArgument(value2) {
|
|
82409
|
-
if (value2 && !/[\s"]/u.test(value2)) return value2;
|
|
82410
|
-
const escaped = value2.replace(/(\\*)"/gu, (_match, slashes) => `${slashes}${slashes}\\"`).replace(/\\+$/u, (slashes) => `${slashes}${slashes}`);
|
|
82411
|
-
return `"${escaped}"`;
|
|
82412
|
-
}
|
|
82413
82401
|
function serviceNames(profile) {
|
|
82414
82402
|
if (profile === "production") {
|
|
82415
82403
|
return { launchd: SERVICE_LABEL, systemd: SYSTEMD_UNIT, windows: WINDOWS_TASK };
|
|
@@ -82431,7 +82419,7 @@ function buildDaemonServicePlan(input2) {
|
|
|
82431
82419
|
const domain2 = `gui/${userId}`;
|
|
82432
82420
|
const serviceTarget = `${domain2}/${names.launchd}`;
|
|
82433
82421
|
const manifestPath = (0, import_node_path27.join)(input2.homeDir, "Library", "LaunchAgents", `${names.launchd}.plist`);
|
|
82434
|
-
const
|
|
82422
|
+
const logDir = (0, import_node_path27.join)(resolveAgentConfigDirectory(input2.profile, input2.homeDir), "logs");
|
|
82435
82423
|
const programArguments = daemonArgs.map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
|
|
82436
82424
|
const environmentEntries = Object.entries(input2.environment ?? {}).map(([key, value2]) => ` <key>${xml(key)}</key>
|
|
82437
82425
|
<string>${xml(value2)}</string>`).join("\n");
|
|
@@ -82460,9 +82448,9 @@ ${environmentBlock} <key>RunAtLoad</key>
|
|
|
82460
82448
|
<key>ThrottleInterval</key>
|
|
82461
82449
|
<integer>5</integer>
|
|
82462
82450
|
<key>StandardOutPath</key>
|
|
82463
|
-
<string>${xml((0, import_node_path27.join)(
|
|
82451
|
+
<string>${xml((0, import_node_path27.join)(logDir, "daemon.log"))}</string>
|
|
82464
82452
|
<key>StandardErrorPath</key>
|
|
82465
|
-
<string>${xml((0, import_node_path27.join)(
|
|
82453
|
+
<string>${xml((0, import_node_path27.join)(logDir, "daemon-error.log"))}</string>
|
|
82466
82454
|
</dict>
|
|
82467
82455
|
</plist>
|
|
82468
82456
|
`;
|
|
@@ -82470,7 +82458,7 @@ ${environmentBlock} <key>RunAtLoad</key>
|
|
|
82470
82458
|
platform: "darwin",
|
|
82471
82459
|
manifestPath,
|
|
82472
82460
|
manifest,
|
|
82473
|
-
logDirectory:
|
|
82461
|
+
logDirectory: logDir,
|
|
82474
82462
|
loadDefinitionCommands: [
|
|
82475
82463
|
{
|
|
82476
82464
|
command: "launchctl",
|
|
@@ -82511,6 +82499,23 @@ ${environmentBlock} <key>RunAtLoad</key>
|
|
|
82511
82499
|
tolerateFailure: true
|
|
82512
82500
|
}
|
|
82513
82501
|
],
|
|
82502
|
+
replaceCommands: [
|
|
82503
|
+
{
|
|
82504
|
+
command: "launchctl",
|
|
82505
|
+
args: ["bootout", domain2, manifestPath],
|
|
82506
|
+
tolerateFailure: true
|
|
82507
|
+
},
|
|
82508
|
+
{
|
|
82509
|
+
command: "launchctl",
|
|
82510
|
+
args: ["bootstrap", domain2, manifestPath],
|
|
82511
|
+
tolerateFailure: false
|
|
82512
|
+
},
|
|
82513
|
+
{
|
|
82514
|
+
command: "launchctl",
|
|
82515
|
+
args: ["kickstart", "-k", serviceTarget],
|
|
82516
|
+
tolerateFailure: false
|
|
82517
|
+
}
|
|
82518
|
+
],
|
|
82514
82519
|
uninstallCommands: [
|
|
82515
82520
|
{
|
|
82516
82521
|
command: "launchctl",
|
|
@@ -82527,7 +82532,8 @@ ${environmentBlock} <key>RunAtLoad</key>
|
|
|
82527
82532
|
command: "launchctl",
|
|
82528
82533
|
args: ["print", serviceTarget],
|
|
82529
82534
|
tolerateFailure: true
|
|
82530
|
-
}
|
|
82535
|
+
},
|
|
82536
|
+
lingerStatusCommand: null
|
|
82531
82537
|
};
|
|
82532
82538
|
}
|
|
82533
82539
|
if (input2.platform === "linux") {
|
|
@@ -82590,6 +82596,18 @@ WantedBy=default.target
|
|
|
82590
82596
|
tolerateFailure: true
|
|
82591
82597
|
}
|
|
82592
82598
|
],
|
|
82599
|
+
replaceCommands: [
|
|
82600
|
+
{
|
|
82601
|
+
command: "systemctl",
|
|
82602
|
+
args: ["--user", "daemon-reload"],
|
|
82603
|
+
tolerateFailure: false
|
|
82604
|
+
},
|
|
82605
|
+
{
|
|
82606
|
+
command: "systemctl",
|
|
82607
|
+
args: ["--user", "restart", names.systemd],
|
|
82608
|
+
tolerateFailure: false
|
|
82609
|
+
}
|
|
82610
|
+
],
|
|
82593
82611
|
uninstallCommands: [
|
|
82594
82612
|
{
|
|
82595
82613
|
command: "systemctl",
|
|
@@ -82611,179 +82629,117 @@ WantedBy=default.target
|
|
|
82611
82629
|
command: "systemctl",
|
|
82612
82630
|
args: ["--user", "is-active", names.systemd],
|
|
82613
82631
|
tolerateFailure: true
|
|
82632
|
+
},
|
|
82633
|
+
lingerStatusCommand: {
|
|
82634
|
+
command: "loginctl",
|
|
82635
|
+
args: ["show-user", "$(id -un)", "-p", "Linger"],
|
|
82636
|
+
tolerateFailure: true
|
|
82614
82637
|
}
|
|
82615
82638
|
};
|
|
82616
82639
|
}
|
|
82617
|
-
const
|
|
82618
|
-
const
|
|
82619
|
-
const
|
|
82620
|
-
const
|
|
82621
|
-
|
|
82622
|
-
const daemonArguments = [input2.cliEntry, "daemon", "--profile", input2.profile].map(windowsCommandLineArgument).join(" ");
|
|
82623
|
-
const environmentStatements = Object.entries(input2.environment ?? {}).map(
|
|
82624
|
-
([key, value2]) => `$startInfo.EnvironmentVariables[${powershellLiteral(key)}] = ${powershellLiteral(value2)}`
|
|
82640
|
+
const environmentPrefix = Object.entries(input2.environment ?? {}).map(([key, value2]) => `$env:${key} = ${powershellLiteral(value2)}`).join("; ");
|
|
82641
|
+
const directArgument = [input2.cliEntry, "daemon", "--profile", input2.profile].map((part) => part.includes(" ") ? `"${part}"` : part).join(" ");
|
|
82642
|
+
const executable = powershellLiteral(environmentPrefix ? "powershell.exe" : input2.nodeExecutable);
|
|
82643
|
+
const argument = powershellLiteral(
|
|
82644
|
+
environmentPrefix ? `-NoProfile -NonInteractive -WindowStyle Hidden -Command "${environmentPrefix}; & ${powershellLiteral(input2.nodeExecutable)} ${powershellLiteral(input2.cliEntry)} daemon --profile ${input2.profile}"` : directArgument
|
|
82625
82645
|
);
|
|
82626
|
-
const launcherScript = [
|
|
82627
|
-
"$ErrorActionPreference = 'Stop'",
|
|
82628
|
-
"$startInfo = [System.Diagnostics.ProcessStartInfo]::new()",
|
|
82629
|
-
`$startInfo.FileName = ${powershellLiteral(input2.nodeExecutable)}`,
|
|
82630
|
-
`$startInfo.Arguments = ${powershellLiteral(daemonArguments)}`,
|
|
82631
|
-
`$startInfo.WorkingDirectory = ${powershellLiteral((0, import_node_path27.dirname)(input2.cliEntry))}`,
|
|
82632
|
-
"$startInfo.UseShellExecute = $false",
|
|
82633
|
-
"$startInfo.CreateNoWindow = $true",
|
|
82634
|
-
"$startInfo.RedirectStandardOutput = $true",
|
|
82635
|
-
"$startInfo.RedirectStandardError = $true",
|
|
82636
|
-
...environmentStatements,
|
|
82637
|
-
`$stdout = [System.IO.File]::Open(${powershellLiteral((0, import_node_path27.join)(logDir, "daemon-launcher.log"))}, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite)`,
|
|
82638
|
-
`$stderr = [System.IO.File]::Open(${powershellLiteral((0, import_node_path27.join)(logDir, "daemon-launcher-error.log"))}, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite)`,
|
|
82639
|
-
"$process = [System.Diagnostics.Process]::new()",
|
|
82640
|
-
"$process.StartInfo = $startInfo",
|
|
82641
|
-
"try { if (-not $process.Start()) { throw 'Alan daemon process did not start' }; $stdoutCopy = $process.StandardOutput.BaseStream.CopyToAsync($stdout); $stderrCopy = $process.StandardError.BaseStream.CopyToAsync($stderr); $process.WaitForExit(); [System.Threading.Tasks.Task]::WaitAll([System.Threading.Tasks.Task[]]@($stdoutCopy, $stderrCopy)); $exitCode = $process.ExitCode } finally { $stdout.Dispose(); $stderr.Dispose(); $process.Dispose() }",
|
|
82642
|
-
"exit $exitCode"
|
|
82643
|
-
].join("; ");
|
|
82644
|
-
const executable = powershellLiteral("powershell.exe");
|
|
82645
|
-
const launcherArguments = `-NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand ${Buffer.from(launcherScript, "utf16le").toString("base64")}`;
|
|
82646
|
-
const settingsScript = "New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit ([TimeSpan]::Zero) -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries";
|
|
82647
|
-
const ownerMarker = `Alan daemon owner v1 ${(0, import_node_crypto21.createHash)("sha256").update(
|
|
82648
|
-
JSON.stringify({
|
|
82649
|
-
executable: input2.nodeExecutable,
|
|
82650
|
-
cliEntry: input2.cliEntry,
|
|
82651
|
-
profile: input2.profile,
|
|
82652
|
-
taskBaseName: names.windows
|
|
82653
|
-
})
|
|
82654
|
-
).digest("hex")}`;
|
|
82655
|
-
const definitionMarker = `${ownerMarker}; definition v3 ${(0, import_node_crypto21.createHash)("sha256").update(
|
|
82656
|
-
JSON.stringify({
|
|
82657
|
-
executable: "powershell.exe",
|
|
82658
|
-
launcherArguments,
|
|
82659
|
-
workingDirectory: (0, import_node_path27.dirname)(input2.cliEntry),
|
|
82660
|
-
settingsScript,
|
|
82661
|
-
taskBaseName: names.windows
|
|
82662
|
-
})
|
|
82663
|
-
).digest("hex")}`;
|
|
82664
|
-
const windowsDefinitionContext = [
|
|
82665
|
-
`$expectedLauncherArguments = ${powershellLiteral(launcherArguments)}`,
|
|
82666
|
-
`$expectedWorkingDirectory = ${powershellLiteral((0, import_node_path27.dirname)(input2.cliEntry))}`,
|
|
82667
|
-
`$expectedOwnerMarker = ${powershellLiteral(`${ownerMarker};`)}`,
|
|
82668
|
-
`$expectedDefinitionMarker = ${powershellLiteral(definitionMarker)}`,
|
|
82669
|
-
`$expectedLegacyExecutable = ${powershellLiteral(legacyExecutable)}`,
|
|
82670
|
-
`$expectedLegacyArguments = ${powershellLiteral(legacyArguments)}`
|
|
82671
|
-
].join("; ");
|
|
82672
|
-
const taskContext = [
|
|
82673
|
-
"$currentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()",
|
|
82674
|
-
"$currentUser = $currentIdentity.Name",
|
|
82675
|
-
"$currentSid = $currentIdentity.User.Value",
|
|
82676
|
-
`$taskName = ${powershellLiteral(names.windows)} + ' ' + $currentSid`
|
|
82677
|
-
].join("; ");
|
|
82678
|
-
const resolveTaskSid = "function Resolve-TaskSid([string]$value) { try { return ([System.Security.Principal.NTAccount]$value).Translate([System.Security.Principal.SecurityIdentifier]).Value } catch { try { return [System.Security.Principal.SecurityIdentifier]::new($value).Value } catch { return '' } } }";
|
|
82679
|
-
const currentLookup = "$task = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq $taskName })[0]";
|
|
82680
|
-
const checkCurrentOwnership = [
|
|
82681
|
-
currentLookup,
|
|
82682
|
-
"$currentOwned = $false",
|
|
82683
|
-
"if ($null -ne $task) { try {",
|
|
82684
|
-
"$taskAction = @($task.Actions)[0]",
|
|
82685
|
-
"$currentOwned = @($task.Actions).Count -eq 1 -and (Resolve-TaskSid ([string]$task.Principal.UserId)) -eq $currentSid -and (([string]$task.Description).StartsWith($expectedOwnerMarker, [System.StringComparison]::Ordinal) -or (([string]$taskAction.Execute) -ieq 'powershell.exe' -and ([string]$taskAction.Arguments) -ceq $expectedLauncherArguments -and ([string]$taskAction.WorkingDirectory) -ieq $expectedWorkingDirectory))",
|
|
82686
|
-
"} catch { $currentOwned = $false } }"
|
|
82687
|
-
].join("; ");
|
|
82688
|
-
const legacyLookup = `$legacyTask = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq ${powershellLiteral(names.windows)} })[0]`;
|
|
82689
|
-
const checkLegacyOwnership = [
|
|
82690
|
-
legacyLookup,
|
|
82691
|
-
"$legacyOwned = $false",
|
|
82692
|
-
"$legacyState = 'Missing'",
|
|
82693
|
-
"if ($null -ne $legacyTask) { try {",
|
|
82694
|
-
"$legacyState = [string]$legacyTask.State",
|
|
82695
|
-
"$legacySid = Resolve-TaskSid ([string]$legacyTask.Principal.UserId)",
|
|
82696
|
-
"$legacyAction = @($legacyTask.Actions)[0]",
|
|
82697
|
-
"if ($null -ne $legacyAction) {",
|
|
82698
|
-
"$legacyOwned = $legacySid -eq $currentSid -and @($legacyTask.Actions).Count -eq 1 -and ((([string]$legacyAction.Execute) -ieq $expectedLegacyExecutable -and ([string]$legacyAction.Arguments) -ieq $expectedLegacyArguments -and ([string]$legacyAction.WorkingDirectory) -eq '') -or (([string]$legacyAction.Execute) -ieq 'powershell.exe' -and ([string]$legacyAction.Arguments) -ceq $expectedLauncherArguments -and ([string]$legacyAction.WorkingDirectory) -ieq $expectedWorkingDirectory))",
|
|
82699
|
-
"}",
|
|
82700
|
-
"} catch { $legacyOwned = $false } }"
|
|
82701
|
-
].join("; ");
|
|
82702
|
-
const assertOwnedTasks = [
|
|
82703
|
-
checkCurrentOwnership,
|
|
82704
|
-
checkLegacyOwnership,
|
|
82705
|
-
`if ($null -ne $task -and -not $currentOwned) { throw ${powershellLiteral(`${names.windows} task is not owned by this Alan installation`)} }`,
|
|
82706
|
-
`if ($null -ne $legacyTask -and -not $legacyOwned) { throw ${powershellLiteral(`Legacy ${names.windows} task is not owned by this Alan installation`)} }`,
|
|
82707
|
-
"if ($null -ne $task -and @('Ready', 'Disabled', 'Queued') -notcontains ([string]$task.State)) { throw 'Alan daemon task became active or has unknown state' }",
|
|
82708
|
-
"if ($null -ne $legacyTask -and @('Ready', 'Disabled', 'Queued') -notcontains ([string]$legacyTask.State)) { throw 'Legacy Alan daemon task became active or has unknown state' }"
|
|
82709
|
-
].join("; ");
|
|
82710
|
-
const cleanupLegacyTask = [
|
|
82711
|
-
checkLegacyOwnership,
|
|
82712
|
-
`if ($null -ne $legacyTask -and -not $legacyOwned) { throw ${powershellLiteral(`Legacy ${names.windows} task is not owned by this Alan installation`)} }`,
|
|
82713
|
-
"if ($null -ne $legacyTask -and @('Ready', 'Disabled', 'Queued') -notcontains ([string]$legacyTask.State)) { throw 'Legacy Alan daemon task became active or has unknown state' }",
|
|
82714
|
-
`if ($null -ne $legacyTask) { Unregister-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -TaskPath '\\' -Confirm:$false -ErrorAction Stop }`,
|
|
82715
|
-
`$legacyRemaining = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq ${powershellLiteral(names.windows)} })[0]`,
|
|
82716
|
-
"if ($null -ne $legacyRemaining) { throw 'Legacy Alan daemon task still exists after migration' }"
|
|
82717
|
-
].join("; ");
|
|
82718
82646
|
const registerScript = [
|
|
82719
|
-
|
|
82720
|
-
|
|
82721
|
-
windowsDefinitionContext,
|
|
82722
|
-
`$action = New-ScheduledTaskAction -Execute ${executable} -Argument $expectedLauncherArguments -WorkingDirectory $expectedWorkingDirectory`,
|
|
82647
|
+
"$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name",
|
|
82648
|
+
`$action = New-ScheduledTaskAction -Execute ${executable} -Argument ${argument}`,
|
|
82723
82649
|
"$trigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser",
|
|
82724
82650
|
"$principal = New-ScheduledTaskPrincipal -UserId $currentUser -LogonType Interactive -RunLevel Limited",
|
|
82725
|
-
|
|
82726
|
-
|
|
82727
|
-
"Register-ScheduledTask -TaskName $taskName -Description $expectedDefinitionMarker -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force -ErrorAction Stop | Out-Null",
|
|
82728
|
-
cleanupLegacyTask,
|
|
82729
|
-
"$registeredTask = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq $taskName })[0]",
|
|
82730
|
-
"if ($null -eq $registeredTask -or $registeredTask.Description -cne $expectedDefinitionMarker) { throw 'Alan daemon task definition was not applied' }"
|
|
82731
|
-
].join("; ");
|
|
82732
|
-
const uninstallScript = [
|
|
82733
|
-
taskContext,
|
|
82734
|
-
resolveTaskSid,
|
|
82735
|
-
windowsDefinitionContext,
|
|
82736
|
-
assertOwnedTasks,
|
|
82737
|
-
"if ($null -ne $legacyTask) { Unregister-ScheduledTask -TaskName $legacyTask.TaskName -TaskPath $legacyTask.TaskPath -Confirm:$false -ErrorAction Stop }",
|
|
82738
|
-
"$task = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq $taskName })[0]",
|
|
82739
|
-
"if ($null -ne $task) { Unregister-ScheduledTask -TaskName $taskName -TaskPath '\\' -Confirm:$false -ErrorAction Stop }",
|
|
82740
|
-
"$remaining = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and ($_.TaskName -eq $taskName -or $_.TaskName -eq $legacyTask.TaskName) })",
|
|
82741
|
-
"if ($remaining.Count -gt 0) { throw 'Alan daemon task still exists after unregister' }"
|
|
82651
|
+
"$settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit ([TimeSpan]::Zero)",
|
|
82652
|
+
`Register-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null`
|
|
82742
82653
|
].join("; ");
|
|
82743
|
-
const statusScript = [
|
|
82744
|
-
taskContext,
|
|
82745
|
-
resolveTaskSid,
|
|
82746
|
-
windowsDefinitionContext,
|
|
82747
|
-
checkCurrentOwnership,
|
|
82748
|
-
checkLegacyOwnership,
|
|
82749
|
-
"$definitionMatches = $false",
|
|
82750
|
-
"if ($null -eq $task) { Write-Output 'State: Missing' } else {",
|
|
82751
|
-
"$taskTrigger = @($task.Triggers)[0]",
|
|
82752
|
-
"$definitionMatches = @($task.Actions).Count -eq 1 -and @($task.Triggers).Count -eq 1 -and $task.Description -ceq $expectedDefinitionMarker -and (Resolve-TaskSid ([string]$task.Principal.UserId)) -eq $currentSid -and [string]$task.Principal.LogonType -eq 'Interactive' -and [string]$task.Principal.RunLevel -eq 'Limited' -and [string]$taskAction.Execute -ieq 'powershell.exe' -and [string]$taskAction.Arguments -ceq $expectedLauncherArguments -and [string]$taskAction.WorkingDirectory -ieq $expectedWorkingDirectory -and $taskTrigger.CimClass.CimClassName -eq 'MSFT_TaskLogonTrigger' -and (Resolve-TaskSid ([string]$taskTrigger.UserId)) -eq $currentSid -and -not $task.Settings.DisallowStartIfOnBatteries -and -not $task.Settings.StopIfGoingOnBatteries -and $task.Settings.RestartCount -eq 3 -and [string]$task.Settings.RestartInterval -eq 'PT1M' -and [string]$task.Settings.ExecutionTimeLimit -eq 'PT0S'",
|
|
82753
|
-
"Write-Output ('TaskName: ' + $task.TaskName); Write-Output ('State: ' + $task.State); Write-Output ('Definition: ' + $task.Description)",
|
|
82754
|
-
"}",
|
|
82755
|
-
"Write-Output ('DefinitionMatch: ' + $definitionMatches)",
|
|
82756
|
-
"Write-Output ('CurrentOwned: ' + $currentOwned)",
|
|
82757
|
-
"$legacyPresent = $null -ne $legacyTask",
|
|
82758
|
-
"Write-Output ('LegacyTask: ' + $legacyPresent)",
|
|
82759
|
-
"Write-Output ('LegacyOwned: ' + $legacyOwned)",
|
|
82760
|
-
"Write-Output ('LegacyState: ' + $legacyState)"
|
|
82761
|
-
].join("; ");
|
|
82762
|
-
const activeScript = [
|
|
82763
|
-
taskContext,
|
|
82764
|
-
"$task = @(Get-ScheduledTask -ErrorAction Stop | Where-Object { $_.TaskPath -eq '\\' -and $_.TaskName -eq $taskName })[0]",
|
|
82765
|
-
"if ($null -eq $task) { Write-Output 'Missing' } else { Write-Output $task.State }"
|
|
82766
|
-
].join("; ");
|
|
82767
|
-
const registerCommand = powershellCommand(registerScript);
|
|
82768
82654
|
return {
|
|
82769
82655
|
platform: "win32",
|
|
82770
82656
|
manifestPath: null,
|
|
82771
82657
|
manifest: null,
|
|
82772
|
-
logDirectory:
|
|
82773
|
-
loadDefinitionCommands: [
|
|
82774
|
-
|
|
82658
|
+
logDirectory: null,
|
|
82659
|
+
loadDefinitionCommands: [
|
|
82660
|
+
{
|
|
82661
|
+
command: "powershell.exe",
|
|
82662
|
+
args: ["-NoProfile", "-NonInteractive", "-Command", registerScript],
|
|
82663
|
+
tolerateFailure: false
|
|
82664
|
+
}
|
|
82665
|
+
],
|
|
82666
|
+
reloadDefinitionCommands: [
|
|
82667
|
+
{
|
|
82668
|
+
command: "powershell.exe",
|
|
82669
|
+
args: ["-NoProfile", "-NonInteractive", "-Command", registerScript],
|
|
82670
|
+
tolerateFailure: false
|
|
82671
|
+
}
|
|
82672
|
+
],
|
|
82775
82673
|
enableCommands: [],
|
|
82776
|
-
startCommands: [
|
|
82674
|
+
startCommands: [
|
|
82675
|
+
{
|
|
82676
|
+
command: "powershell.exe",
|
|
82677
|
+
args: [
|
|
82678
|
+
"-NoProfile",
|
|
82679
|
+
"-NonInteractive",
|
|
82680
|
+
"-Command",
|
|
82681
|
+
`Start-ScheduledTask -TaskName ${powershellLiteral(names.windows)}`
|
|
82682
|
+
],
|
|
82683
|
+
tolerateFailure: false
|
|
82684
|
+
}
|
|
82685
|
+
],
|
|
82777
82686
|
stopCommands: [
|
|
82778
|
-
|
|
82779
|
-
|
|
82780
|
-
|
|
82781
|
-
|
|
82687
|
+
{
|
|
82688
|
+
command: "powershell.exe",
|
|
82689
|
+
args: [
|
|
82690
|
+
"-NoProfile",
|
|
82691
|
+
"-NonInteractive",
|
|
82692
|
+
"-Command",
|
|
82693
|
+
`Stop-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -ErrorAction SilentlyContinue`
|
|
82694
|
+
],
|
|
82695
|
+
tolerateFailure: true
|
|
82696
|
+
}
|
|
82697
|
+
],
|
|
82698
|
+
replaceCommands: [
|
|
82699
|
+
{
|
|
82700
|
+
command: "powershell.exe",
|
|
82701
|
+
args: [
|
|
82702
|
+
"-NoProfile",
|
|
82703
|
+
"-NonInteractive",
|
|
82704
|
+
"-Command",
|
|
82705
|
+
`${registerScript}; Start-ScheduledTask -TaskName ${powershellLiteral(names.windows)}`
|
|
82706
|
+
],
|
|
82707
|
+
tolerateFailure: false
|
|
82708
|
+
}
|
|
82782
82709
|
],
|
|
82783
|
-
uninstallCommands: [
|
|
82784
|
-
|
|
82785
|
-
|
|
82786
|
-
|
|
82710
|
+
uninstallCommands: [
|
|
82711
|
+
{
|
|
82712
|
+
command: "powershell.exe",
|
|
82713
|
+
args: [
|
|
82714
|
+
"-NoProfile",
|
|
82715
|
+
"-NonInteractive",
|
|
82716
|
+
"-Command",
|
|
82717
|
+
`Unregister-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -Confirm:$false -ErrorAction SilentlyContinue`
|
|
82718
|
+
],
|
|
82719
|
+
tolerateFailure: true
|
|
82720
|
+
}
|
|
82721
|
+
],
|
|
82722
|
+
statusCommand: {
|
|
82723
|
+
command: "powershell.exe",
|
|
82724
|
+
args: [
|
|
82725
|
+
"-NoProfile",
|
|
82726
|
+
"-NonInteractive",
|
|
82727
|
+
"-Command",
|
|
82728
|
+
`Get-ScheduledTask -TaskName ${powershellLiteral(names.windows)} | Format-List TaskName,State`
|
|
82729
|
+
],
|
|
82730
|
+
tolerateFailure: true
|
|
82731
|
+
},
|
|
82732
|
+
isActiveCommand: {
|
|
82733
|
+
command: "powershell.exe",
|
|
82734
|
+
args: [
|
|
82735
|
+
"-NoProfile",
|
|
82736
|
+
"-NonInteractive",
|
|
82737
|
+
"-Command",
|
|
82738
|
+
`(Get-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -ErrorAction SilentlyContinue).State`
|
|
82739
|
+
],
|
|
82740
|
+
tolerateFailure: true
|
|
82741
|
+
},
|
|
82742
|
+
lingerStatusCommand: null
|
|
82787
82743
|
};
|
|
82788
82744
|
}
|
|
82789
82745
|
function resolveCurrentPlatform() {
|
|
@@ -82793,14 +82749,14 @@ function resolveCurrentPlatform() {
|
|
|
82793
82749
|
}
|
|
82794
82750
|
return currentPlatform;
|
|
82795
82751
|
}
|
|
82796
|
-
function currentServicePlan(args, runtime
|
|
82797
|
-
const currentPlatform =
|
|
82752
|
+
function currentServicePlan(args, runtime) {
|
|
82753
|
+
const currentPlatform = resolveCurrentPlatform();
|
|
82798
82754
|
const profile = resolveEndpointProfileFromArgs(args);
|
|
82799
82755
|
const cliEntry = runtime?.cliEntry ?? process.argv[1];
|
|
82800
82756
|
if (!cliEntry) throw new Error("Cannot determine the alan-agent executable path");
|
|
82801
82757
|
return buildDaemonServicePlan({
|
|
82802
82758
|
platform: currentPlatform,
|
|
82803
|
-
homeDir:
|
|
82759
|
+
homeDir: (0, import_node_os16.homedir)(),
|
|
82804
82760
|
nodeExecutable: runtime?.executable ?? process.execPath,
|
|
82805
82761
|
cliEntry: (0, import_node_path27.resolve)(cliEntry),
|
|
82806
82762
|
profile,
|
|
@@ -82823,13 +82779,9 @@ function defaultReadManifest(path2) {
|
|
|
82823
82779
|
return (0, import_node_fs25.readFileSync)(path2, "utf8");
|
|
82824
82780
|
}
|
|
82825
82781
|
function runServiceCommand(command) {
|
|
82826
|
-
const result = (0, import_node_child_process9.spawnSync)(command.command, command.args, {
|
|
82827
|
-
encoding: "utf8",
|
|
82828
|
-
shell: false,
|
|
82829
|
-
...(0, import_node_os16.platform)() === "win32" ? { timeout: 15e3, windowsHide: true } : {}
|
|
82830
|
-
});
|
|
82782
|
+
const result = (0, import_node_child_process9.spawnSync)(command.command, command.args, { encoding: "utf8", shell: false });
|
|
82831
82783
|
const status = result.status ?? 1;
|
|
82832
|
-
const output2 = `${result.stdout ?? ""}${result.stderr ?? ""}
|
|
82784
|
+
const output2 = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
82833
82785
|
if (status !== 0 && !command.tolerateFailure) {
|
|
82834
82786
|
throw new Error(
|
|
82835
82787
|
`Service command failed (${command.command} ${command.args.join(" ")}): ${output2 || `exit ${status}`}`
|
|
@@ -82842,23 +82794,6 @@ function defaultSleep(ms) {
|
|
|
82842
82794
|
setTimeout(resolveSleep, ms);
|
|
82843
82795
|
});
|
|
82844
82796
|
}
|
|
82845
|
-
function isProcessAlive(pid) {
|
|
82846
|
-
if (pid <= 0) return false;
|
|
82847
|
-
try {
|
|
82848
|
-
process.kill(pid, 0);
|
|
82849
|
-
return true;
|
|
82850
|
-
} catch (error61) {
|
|
82851
|
-
return error61.code === "EPERM";
|
|
82852
|
-
}
|
|
82853
|
-
}
|
|
82854
|
-
async function requestWindowsDaemonShutdown(owner) {
|
|
82855
|
-
try {
|
|
82856
|
-
const response = await requestLocalDaemonShutdown(owner.localApiPort, owner.localApiToken);
|
|
82857
|
-
return response.ok ? "accepted" : "rejected";
|
|
82858
|
-
} catch {
|
|
82859
|
-
return "unreachable";
|
|
82860
|
-
}
|
|
82861
|
-
}
|
|
82862
82797
|
function parseServiceHostState(servicePlatform, result) {
|
|
82863
82798
|
const output2 = result.output;
|
|
82864
82799
|
if (servicePlatform === "linux") {
|
|
@@ -82884,62 +82819,9 @@ function parseServiceHostState(servicePlatform, result) {
|
|
|
82884
82819
|
const stateMatch = output2.match(/\b(?:State|state)\s*[:=]\s*(\w+)/);
|
|
82885
82820
|
const state = (stateMatch?.[1] ?? output2.trim()).toLowerCase();
|
|
82886
82821
|
if (state === "running") return "running";
|
|
82887
|
-
if (state === "queued") return "
|
|
82888
|
-
if (state === "ready" || state === "disabled") return "stopped";
|
|
82822
|
+
if (state === "ready" || state === "disabled" || state === "queued") return "stopped";
|
|
82889
82823
|
return "unknown";
|
|
82890
82824
|
}
|
|
82891
|
-
function parseWindowsTaskInspection(result) {
|
|
82892
|
-
if (result.status !== 0) {
|
|
82893
|
-
throw new Error("Cannot inspect Windows daemon task definition");
|
|
82894
|
-
}
|
|
82895
|
-
const value2 = (name) => {
|
|
82896
|
-
const match = result.output.match(new RegExp(`^${name}:\\s*(.*)$`, "imu"));
|
|
82897
|
-
if (!match) throw new Error(`Incomplete Windows daemon task inspection: missing ${name}`);
|
|
82898
|
-
return match[1]?.trim() ?? "";
|
|
82899
|
-
};
|
|
82900
|
-
const boolean4 = (name) => {
|
|
82901
|
-
const parsed = value2(name).toLowerCase();
|
|
82902
|
-
if (parsed === "true") return true;
|
|
82903
|
-
if (parsed === "false") return false;
|
|
82904
|
-
throw new Error(`Incomplete Windows daemon task inspection: invalid ${name}`);
|
|
82905
|
-
};
|
|
82906
|
-
const currentPresent = /^TaskName:\s*.+$/imu.test(result.output);
|
|
82907
|
-
const currentStateValue = value2("State");
|
|
82908
|
-
const currentOwned = boolean4("CurrentOwned");
|
|
82909
|
-
const definitionMatches = boolean4("DefinitionMatch");
|
|
82910
|
-
const legacyPresent = boolean4("LegacyTask");
|
|
82911
|
-
const legacyOwned = boolean4("LegacyOwned");
|
|
82912
|
-
const legacyStateValue = value2("LegacyState");
|
|
82913
|
-
if (currentPresent !== (currentStateValue.toLowerCase() !== "missing")) {
|
|
82914
|
-
throw new Error("Incomplete Windows daemon task inspection: inconsistent current task state");
|
|
82915
|
-
}
|
|
82916
|
-
if (!currentPresent && (currentOwned || definitionMatches)) {
|
|
82917
|
-
throw new Error(
|
|
82918
|
-
"Incomplete Windows daemon task inspection: absent current task is marked owned"
|
|
82919
|
-
);
|
|
82920
|
-
}
|
|
82921
|
-
if (legacyPresent !== (legacyStateValue.toLowerCase() !== "missing") || !legacyPresent && legacyOwned) {
|
|
82922
|
-
throw new Error("Incomplete Windows daemon task inspection: inconsistent legacy task state");
|
|
82923
|
-
}
|
|
82924
|
-
return {
|
|
82925
|
-
currentPresent,
|
|
82926
|
-
currentOwned,
|
|
82927
|
-
currentState: currentPresent ? parseServiceHostState("win32", { status: 0, output: currentStateValue }) : "stopped",
|
|
82928
|
-
definitionMatches,
|
|
82929
|
-
definitionMarker: result.output.match(/^Definition:\s*(.+)$/imu)?.[1]?.trim(),
|
|
82930
|
-
legacyPresent,
|
|
82931
|
-
legacyOwned,
|
|
82932
|
-
legacyState: legacyPresent ? parseServiceHostState("win32", { status: 0, output: legacyStateValue }) : "stopped"
|
|
82933
|
-
};
|
|
82934
|
-
}
|
|
82935
|
-
function assertWindowsTaskOwnership(tasks) {
|
|
82936
|
-
if (tasks.currentPresent && !tasks.currentOwned) {
|
|
82937
|
-
throw new Error("Windows daemon task is not owned by this Alan installation");
|
|
82938
|
-
}
|
|
82939
|
-
if (tasks.legacyPresent && !tasks.legacyOwned) {
|
|
82940
|
-
throw new Error("Legacy Windows daemon task is not owned by this Alan installation");
|
|
82941
|
-
}
|
|
82942
|
-
}
|
|
82943
82825
|
function resolveEnsureDefinitionOutcome(input2) {
|
|
82944
82826
|
if (!input2.definitionChanged) {
|
|
82945
82827
|
return { changed: false, updatePending: false };
|
|
@@ -82949,6 +82831,9 @@ function resolveEnsureDefinitionOutcome(input2) {
|
|
|
82949
82831
|
}
|
|
82950
82832
|
return { changed: true, updatePending: false };
|
|
82951
82833
|
}
|
|
82834
|
+
function shouldStartOnInstall(hostState) {
|
|
82835
|
+
return hostState === "stopped";
|
|
82836
|
+
}
|
|
82952
82837
|
function resolveUsername(options) {
|
|
82953
82838
|
if (options?.username) return options.username;
|
|
82954
82839
|
try {
|
|
@@ -82957,14 +82842,17 @@ function resolveUsername(options) {
|
|
|
82957
82842
|
return process.env.USER || process.env.USERNAME || "unknown";
|
|
82958
82843
|
}
|
|
82959
82844
|
}
|
|
82960
|
-
function
|
|
82961
|
-
|
|
82962
|
-
const run = options.runCommand ?? runServiceCommand;
|
|
82963
|
-
const result = run({
|
|
82845
|
+
function buildLingerStatusCommand(username) {
|
|
82846
|
+
return {
|
|
82964
82847
|
command: "loginctl",
|
|
82965
82848
|
args: ["show-user", username, "-p", "Linger"],
|
|
82966
82849
|
tolerateFailure: true
|
|
82967
|
-
}
|
|
82850
|
+
};
|
|
82851
|
+
}
|
|
82852
|
+
function assertSystemdUserLingerEnabled(options = {}) {
|
|
82853
|
+
const username = resolveUsername(options);
|
|
82854
|
+
const run = options.runCommand ?? runServiceCommand;
|
|
82855
|
+
const result = run(buildLingerStatusCommand(username));
|
|
82968
82856
|
if (result.status !== 0) {
|
|
82969
82857
|
throw new Error(
|
|
82970
82858
|
`Cannot verify systemd user linger for ${username} (loginctl failed). For durable headless VM boot run: sudo loginctl enable-linger ${username}`
|
|
@@ -82978,9 +82866,9 @@ function assertSystemdUserLingerEnabled(options = {}) {
|
|
|
82978
82866
|
}
|
|
82979
82867
|
function createHostContext(options = {}) {
|
|
82980
82868
|
const args = options.args ?? [];
|
|
82981
|
-
const plan = currentServicePlan(args, options.runtime
|
|
82869
|
+
const plan = currentServicePlan(args, options.runtime);
|
|
82982
82870
|
const run = options.runCommand ?? runServiceCommand;
|
|
82983
|
-
const
|
|
82871
|
+
const sleep4 = options.sleep ?? defaultSleep;
|
|
82984
82872
|
const nowMs = options.nowMs ?? Date.now;
|
|
82985
82873
|
const readManifest = options.readManifest ?? defaultReadManifest;
|
|
82986
82874
|
const writeManifest = options.writeManifest ?? writeManifestAtomic;
|
|
@@ -82992,20 +82880,13 @@ function createHostContext(options = {}) {
|
|
|
82992
82880
|
args,
|
|
82993
82881
|
plan,
|
|
82994
82882
|
run,
|
|
82995
|
-
sleep:
|
|
82883
|
+
sleep: sleep4,
|
|
82996
82884
|
nowMs,
|
|
82997
82885
|
readManifest,
|
|
82998
82886
|
writeManifest,
|
|
82999
82887
|
removeManifest,
|
|
83000
82888
|
ensureLogDir,
|
|
83001
|
-
|
|
83002
|
-
readOwner: options.readOwner ?? readLocalDaemonOwnerLease,
|
|
83003
|
-
isProcessAlive: options.isProcessAlive ?? isProcessAlive,
|
|
83004
|
-
probeEndpoint: options.probeEndpoint ?? probeLocalDaemonEndpoint,
|
|
83005
|
-
requestWindowsShutdown: options.requestWindowsShutdown ?? requestWindowsDaemonShutdown,
|
|
83006
|
-
inspectJournal: options.inspectJournal ?? inspectLocalDaemonRunJournal,
|
|
83007
|
-
acquireMaintenance: options.acquireMaintenance ?? acquireLocalDaemonMaintenanceLease,
|
|
83008
|
-
releaseMaintenance: options.releaseMaintenance ?? releaseLocalDaemonMaintenanceLease
|
|
82889
|
+
profile: resolveEndpointProfileFromArgs(args)
|
|
83009
82890
|
};
|
|
83010
82891
|
}
|
|
83011
82892
|
function inspectDaemonService(options = {}) {
|
|
@@ -83021,9 +82902,8 @@ function inspectDaemonService(options = {}) {
|
|
|
83021
82902
|
}
|
|
83022
82903
|
function ensureDaemonServiceDefinition(options = {}) {
|
|
83023
82904
|
const ctx = createHostContext(options);
|
|
83024
|
-
const { plan, run,
|
|
82905
|
+
const { plan, run, readManifest, writeManifest, ensureLogDir } = ctx;
|
|
83025
82906
|
let definitionChanged = false;
|
|
83026
|
-
let inspection;
|
|
83027
82907
|
if (plan.manifestPath && plan.manifest) {
|
|
83028
82908
|
ensureLogDir();
|
|
83029
82909
|
const existing = readManifest(plan.manifestPath);
|
|
@@ -83032,38 +82912,20 @@ function ensureDaemonServiceDefinition(options = {}) {
|
|
|
83032
82912
|
writeManifest(plan.manifestPath, plan.manifest);
|
|
83033
82913
|
}
|
|
83034
82914
|
} else if (plan.platform === "win32") {
|
|
83035
|
-
|
|
83036
|
-
const result = run(plan.statusCommand);
|
|
83037
|
-
const tasks = parseWindowsTaskInspection(result);
|
|
83038
|
-
assertWindowsTaskOwnership(tasks);
|
|
83039
|
-
if (tasks.currentPresent && tasks.currentState === "unknown" || tasks.legacyPresent && tasks.legacyState === "unknown") {
|
|
83040
|
-
throw new Error("Cannot safely update a Windows daemon task with unknown state");
|
|
83041
|
-
}
|
|
83042
|
-
definitionChanged = tasks.definitionMarker !== plan.definitionMarker || !tasks.definitionMatches || tasks.legacyPresent;
|
|
83043
|
-
const running = tasks.currentState === "running" || tasks.legacyState === "running";
|
|
83044
|
-
inspection = {
|
|
83045
|
-
state: running ? "running" : tasks.currentState,
|
|
83046
|
-
platform: plan.platform,
|
|
83047
|
-
detail: result.output || void 0,
|
|
83048
|
-
observedAtMs: nowMs()
|
|
83049
|
-
};
|
|
82915
|
+
definitionChanged = true;
|
|
83050
82916
|
}
|
|
83051
|
-
inspection
|
|
83052
|
-
const definitionHostState = plan.platform === "win32" && inspection.state === "starting" ? "stopped" : inspection.state;
|
|
82917
|
+
const inspection = inspectDaemonService(options);
|
|
83053
82918
|
const outcome = resolveEnsureDefinitionOutcome({
|
|
83054
82919
|
definitionChanged,
|
|
83055
|
-
hostState:
|
|
82920
|
+
hostState: inspection.state
|
|
83056
82921
|
});
|
|
83057
82922
|
if (outcome.updatePending) {
|
|
83058
82923
|
return outcome;
|
|
83059
82924
|
}
|
|
83060
|
-
if (
|
|
82925
|
+
if (inspection.state === "running" || inspection.state === "starting") {
|
|
83061
82926
|
return outcome;
|
|
83062
82927
|
}
|
|
83063
|
-
|
|
83064
|
-
return outcome;
|
|
83065
|
-
}
|
|
83066
|
-
const definitionCommands = definitionHostState === "stopped" ? plan.reloadDefinitionCommands : plan.loadDefinitionCommands;
|
|
82928
|
+
const definitionCommands = inspection.state === "stopped" ? plan.reloadDefinitionCommands : plan.loadDefinitionCommands;
|
|
83067
82929
|
for (const command of definitionCommands) run(command);
|
|
83068
82930
|
return outcome;
|
|
83069
82931
|
}
|
|
@@ -83075,140 +82937,10 @@ function startDaemonService(options = {}) {
|
|
|
83075
82937
|
const { plan, run } = createHostContext(options);
|
|
83076
82938
|
for (const command of plan.startCommands) run(command);
|
|
83077
82939
|
}
|
|
83078
|
-
|
|
83079
|
-
const {
|
|
83080
|
-
plan,
|
|
83081
|
-
run,
|
|
83082
|
-
sleep: sleep5,
|
|
83083
|
-
nowMs,
|
|
83084
|
-
configPath,
|
|
83085
|
-
readOwner,
|
|
83086
|
-
isProcessAlive: processIsAlive,
|
|
83087
|
-
probeEndpoint,
|
|
83088
|
-
requestWindowsShutdown: requestShutdown
|
|
83089
|
-
} = createHostContext(options);
|
|
83090
|
-
let owner;
|
|
83091
|
-
try {
|
|
83092
|
-
owner = readOwner(configPath);
|
|
83093
|
-
} catch {
|
|
83094
|
-
return "identity_changed";
|
|
83095
|
-
}
|
|
83096
|
-
const ownerMatches = (candidate) => candidate.pid === identity.pid && candidate.daemonSessionId === identity.daemonSessionId && candidate.localApiPort === identity.port && (identity.serviceId === void 0 || candidate.localServiceId === identity.serviceId) && (identity.startedAtMs === void 0 || candidate.startedAtMs === identity.startedAtMs);
|
|
83097
|
-
if (!owner || !ownerMatches(owner)) {
|
|
83098
|
-
return "identity_changed";
|
|
83099
|
-
}
|
|
83100
|
-
if (plan.platform === "win32") {
|
|
83101
|
-
const shutdown = await requestShutdown(owner);
|
|
83102
|
-
if (shutdown === "rejected") return "identity_changed";
|
|
83103
|
-
if (shutdown === "unreachable") {
|
|
83104
|
-
for (const command of plan.stopCommands) run(command);
|
|
83105
|
-
}
|
|
83106
|
-
const deadline2 = nowMs() + timeoutMs;
|
|
83107
|
-
while (nowMs() < deadline2) {
|
|
83108
|
-
let currentOwner;
|
|
83109
|
-
try {
|
|
83110
|
-
currentOwner = readOwner(configPath);
|
|
83111
|
-
} catch {
|
|
83112
|
-
return "identity_changed";
|
|
83113
|
-
}
|
|
83114
|
-
if (currentOwner && !ownerMatches(currentOwner)) {
|
|
83115
|
-
return "identity_changed";
|
|
83116
|
-
}
|
|
83117
|
-
if (!processIsAlive(identity.pid)) {
|
|
83118
|
-
const endpoint = await probeEndpoint(identity.port, owner.localApiToken, 250);
|
|
83119
|
-
if (endpoint.state === "absent") return "exited";
|
|
83120
|
-
if (endpoint.state === "listening_unauthorized" || endpoint.status.daemonSessionId !== identity.daemonSessionId) {
|
|
83121
|
-
return "identity_changed";
|
|
83122
|
-
}
|
|
83123
|
-
}
|
|
83124
|
-
await sleep5(STOP_POLL_INTERVAL_MS);
|
|
83125
|
-
}
|
|
83126
|
-
return "timeout";
|
|
83127
|
-
}
|
|
83128
|
-
for (const command of plan.stopCommands) run(command);
|
|
83129
|
-
const deadline = nowMs() + timeoutMs;
|
|
83130
|
-
while (nowMs() < deadline) {
|
|
83131
|
-
const result = run(plan.isActiveCommand);
|
|
83132
|
-
const state = parseServiceHostState(plan.platform, result);
|
|
83133
|
-
if (state === "stopped") return "exited";
|
|
83134
|
-
if (state === "unknown") {
|
|
83135
|
-
} else if (identity.pid > 0) {
|
|
83136
|
-
try {
|
|
83137
|
-
process.kill(identity.pid, 0);
|
|
83138
|
-
} catch {
|
|
83139
|
-
return "exited";
|
|
83140
|
-
}
|
|
83141
|
-
}
|
|
83142
|
-
await sleep5(STOP_POLL_INTERVAL_MS);
|
|
83143
|
-
}
|
|
83144
|
-
return "timeout";
|
|
83145
|
-
}
|
|
83146
|
-
async function uninstallDaemonService(args = [], options = {}) {
|
|
82940
|
+
function uninstallDaemonService(args = [], options = {}) {
|
|
83147
82941
|
const ctx = createHostContext({ ...options, args: options.args ?? args });
|
|
83148
|
-
|
|
83149
|
-
|
|
83150
|
-
let tasks;
|
|
83151
|
-
try {
|
|
83152
|
-
tasks = parseWindowsTaskInspection(ownership);
|
|
83153
|
-
} catch (error61) {
|
|
83154
|
-
throw new Error(
|
|
83155
|
-
`Cannot inspect Windows daemon task ownership before uninstall: ${error61 instanceof Error ? error61.message : String(error61)}`
|
|
83156
|
-
);
|
|
83157
|
-
}
|
|
83158
|
-
assertWindowsTaskOwnership(tasks);
|
|
83159
|
-
if (!tasks.currentPresent && !tasks.legacyPresent) {
|
|
83160
|
-
console.info("[alan-agent] Per-user daemon service removed");
|
|
83161
|
-
return;
|
|
83162
|
-
}
|
|
83163
|
-
const acquired = ctx.acquireMaintenance(ctx.configPath, "watchdog", 3e4);
|
|
83164
|
-
if (!acquired.acquired) {
|
|
83165
|
-
throw new Error("Cannot uninstall the Windows daemon service while maintenance is active");
|
|
83166
|
-
}
|
|
83167
|
-
try {
|
|
83168
|
-
const journal = ctx.inspectJournal(ctx.configPath);
|
|
83169
|
-
if (!journal.safeToRestart) {
|
|
83170
|
-
throw new Error(
|
|
83171
|
-
`Windows daemon service uninstall is deferred while ${journal.activeRunCount} active run${journal.activeRunCount === 1 ? "" : "s"} finish`
|
|
83172
|
-
);
|
|
83173
|
-
}
|
|
83174
|
-
let owner;
|
|
83175
|
-
try {
|
|
83176
|
-
owner = ctx.readOwner(ctx.configPath);
|
|
83177
|
-
} catch (error61) {
|
|
83178
|
-
throw new Error(
|
|
83179
|
-
`Cannot verify Windows daemon ownership before uninstall: ${error61 instanceof Error ? error61.message : String(error61)}`
|
|
83180
|
-
);
|
|
83181
|
-
}
|
|
83182
|
-
if (owner) {
|
|
83183
|
-
const stopped = await stopDaemonServiceAndWait(
|
|
83184
|
-
{
|
|
83185
|
-
pid: owner.pid,
|
|
83186
|
-
serviceId: owner.localServiceId,
|
|
83187
|
-
daemonSessionId: owner.daemonSessionId,
|
|
83188
|
-
port: owner.localApiPort,
|
|
83189
|
-
startedAtMs: owner.startedAtMs
|
|
83190
|
-
},
|
|
83191
|
-
1e4,
|
|
83192
|
-
{ ...options, args: ctx.args }
|
|
83193
|
-
);
|
|
83194
|
-
if (stopped !== "exited") {
|
|
83195
|
-
throw new Error(
|
|
83196
|
-
stopped === "identity_changed" ? "Windows daemon ownership changed before uninstall" : "Timed out waiting for the Windows daemon to stop before uninstall"
|
|
83197
|
-
);
|
|
83198
|
-
}
|
|
83199
|
-
} else {
|
|
83200
|
-
if (tasks.currentState !== "stopped" || tasks.legacyState !== "stopped") {
|
|
83201
|
-
throw new Error("Cannot uninstall a running Windows daemon without verified ownership");
|
|
83202
|
-
}
|
|
83203
|
-
}
|
|
83204
|
-
for (const command of ctx.plan.uninstallCommands) ctx.run(command);
|
|
83205
|
-
} finally {
|
|
83206
|
-
ctx.releaseMaintenance(ctx.configPath, acquired.lease.id);
|
|
83207
|
-
}
|
|
83208
|
-
} else {
|
|
83209
|
-
for (const command of ctx.plan.uninstallCommands) ctx.run(command);
|
|
83210
|
-
if (ctx.plan.manifestPath) ctx.removeManifest(ctx.plan.manifestPath);
|
|
83211
|
-
}
|
|
82942
|
+
for (const command of ctx.plan.uninstallCommands) ctx.run(command);
|
|
82943
|
+
if (ctx.plan.manifestPath) ctx.removeManifest(ctx.plan.manifestPath);
|
|
83212
82944
|
console.info("[alan-agent] Per-user daemon service removed");
|
|
83213
82945
|
}
|
|
83214
82946
|
function installDaemonService(args = [], runtime, options = {}) {
|
|
@@ -83236,7 +82968,7 @@ function installDaemonService(args = [], runtime, options = {}) {
|
|
|
83236
82968
|
});
|
|
83237
82969
|
return;
|
|
83238
82970
|
}
|
|
83239
|
-
if (inspection.state
|
|
82971
|
+
if (!shouldStartOnInstall(inspection.state)) {
|
|
83240
82972
|
console.info("[alan-agent] Per-user daemon service already present", {
|
|
83241
82973
|
profile,
|
|
83242
82974
|
state: inspection.state
|
|
@@ -83260,48 +82992,14 @@ ${result.output}
|
|
|
83260
82992
|
}
|
|
83261
82993
|
|
|
83262
82994
|
// src/install-command.ts
|
|
83263
|
-
|
|
83264
|
-
async function runInstallCommand(commandArgs, currentPlatform = process.platform) {
|
|
83265
|
-
if (currentPlatform === "win32" && commandArgs.includes("--headless")) {
|
|
83266
|
-
throw new Error("--headless is only supported on Linux systemd user services");
|
|
83267
|
-
}
|
|
82995
|
+
async function runInstallCommand(commandArgs) {
|
|
83268
82996
|
bindConfigPath(commandArgs);
|
|
83269
82997
|
const configured = readConfig();
|
|
83270
82998
|
const configurationMode = resolveInstallConfigurationMode(commandArgs, configured);
|
|
83271
|
-
|
|
83272
|
-
const deadline = isWindowsSetup ? Date.now() + WINDOWS_SETUP_READY_TIMEOUT_MS : 0;
|
|
83273
|
-
const runtimeIdentityChanged = configurationMode === "setup" ? await setupDaemon(commandArgs) : false;
|
|
82999
|
+
if (configurationMode === "setup") await setupDaemon(commandArgs);
|
|
83274
83000
|
if (configurationMode === "login") await loginWithDeviceCode(commandArgs);
|
|
83275
|
-
if (!isWindowsSetup) {
|
|
83276
|
-
installDaemonService(commandArgs);
|
|
83277
|
-
runMcpIntegrationCommand(["reconcile", ...commandArgs]);
|
|
83278
|
-
return;
|
|
83279
|
-
}
|
|
83280
|
-
const { runtimeId, localApiPort, localApiToken } = readConfig();
|
|
83281
|
-
if (!runtimeId || !localApiPort || !localApiToken) {
|
|
83282
|
-
throw new Error("Windows runtime setup completed without a local readiness endpoint");
|
|
83283
|
-
}
|
|
83284
|
-
if (runtimeIdentityChanged) {
|
|
83285
|
-
while (Date.now() < deadline) {
|
|
83286
|
-
const status = await probeLocalDaemon(localApiPort, localApiToken, 250);
|
|
83287
|
-
if (status?.runtimeId === runtimeId && status.connected) break;
|
|
83288
|
-
if (!status) {
|
|
83289
|
-
const service = inspectDaemonService({ args: commandArgs });
|
|
83290
|
-
if (service.state !== "running" && service.state !== "starting") break;
|
|
83291
|
-
}
|
|
83292
|
-
await (0, import_promises6.setTimeout)(100);
|
|
83293
|
-
}
|
|
83294
|
-
}
|
|
83295
83001
|
installDaemonService(commandArgs);
|
|
83296
|
-
|
|
83297
|
-
const status = await probeLocalDaemon(localApiPort, localApiToken, 250);
|
|
83298
|
-
if (status?.runtimeId === runtimeId && status.connected) {
|
|
83299
|
-
runMcpIntegrationCommand(["reconcile", ...commandArgs]);
|
|
83300
|
-
return;
|
|
83301
|
-
}
|
|
83302
|
-
await (0, import_promises6.setTimeout)(100);
|
|
83303
|
-
}
|
|
83304
|
-
throw new Error("Windows runtime did not become ready within 9 seconds");
|
|
83002
|
+
runMcpIntegrationCommand(["reconcile", ...commandArgs]);
|
|
83305
83003
|
}
|
|
83306
83004
|
|
|
83307
83005
|
// src/lifecycle-logger.ts
|
|
@@ -86678,7 +86376,7 @@ var REQUEST_STATE_ONLY_LEG_PACING_MS2 = 250;
|
|
|
86678
86376
|
function inputRequiredRoundsExceededMessage2(method, maxRounds) {
|
|
86679
86377
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
86680
86378
|
}
|
|
86681
|
-
function
|
|
86379
|
+
function sleep3(ms, signal) {
|
|
86682
86380
|
return new Promise((resolve15, reject) => {
|
|
86683
86381
|
if (signal?.aborted) {
|
|
86684
86382
|
reject(signal.reason instanceof SdkError2 ? signal.reason : new SdkError2(SdkErrorCode2.RequestTimeout, String(signal.reason)));
|
|
@@ -94945,7 +94643,7 @@ var LegacyInputRequiredShim = class {
|
|
|
94945
94643
|
} finally {
|
|
94946
94644
|
roundAbort.dispose();
|
|
94947
94645
|
}
|
|
94948
|
-
} else await
|
|
94646
|
+
} else await sleep3(REQUEST_STATE_ONLY_LEG_PACING_MS2, outerSignal);
|
|
94949
94647
|
let ctxNext = {
|
|
94950
94648
|
...ctx,
|
|
94951
94649
|
mcpReq: {
|
|
@@ -95742,7 +95440,7 @@ async function runMcpStdioProxy(env = process.env, local = new StdioServerTransp
|
|
|
95742
95440
|
}
|
|
95743
95441
|
|
|
95744
95442
|
// src/native-hook-command.ts
|
|
95745
|
-
var
|
|
95443
|
+
var import_node_crypto21 = require("crypto");
|
|
95746
95444
|
var import_node_fs27 = require("fs");
|
|
95747
95445
|
var import_node_os17 = require("os");
|
|
95748
95446
|
var import_node_path29 = require("path");
|
|
@@ -96111,7 +95809,7 @@ function parseNativeHookEnvelope(input2) {
|
|
|
96111
95809
|
const projectPin = eventType === "session_start" && resolvedCwd ? readAlanProjectPin(resolvedCwd) : void 0;
|
|
96112
95810
|
return {
|
|
96113
95811
|
schemaVersion: 1,
|
|
96114
|
-
eventId: (0,
|
|
95812
|
+
eventId: (0, import_node_crypto21.randomUUID)(),
|
|
96115
95813
|
provider: capability.provider,
|
|
96116
95814
|
eventType,
|
|
96117
95815
|
observedAt: (input2.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -96607,7 +96305,7 @@ function delay2(ms) {
|
|
|
96607
96305
|
}
|
|
96608
96306
|
|
|
96609
96307
|
// src/web-presenter.ts
|
|
96610
|
-
var
|
|
96308
|
+
var import_node_crypto22 = require("crypto");
|
|
96611
96309
|
var WebPresenter = class {
|
|
96612
96310
|
constructor(wsClient, conversationId, cwd) {
|
|
96613
96311
|
this.conversationId = conversationId;
|
|
@@ -96793,7 +96491,7 @@ var WebPresenter = class {
|
|
|
96793
96491
|
this.applicationProblem = createAlanProblem({
|
|
96794
96492
|
domain: "application",
|
|
96795
96493
|
code: input2.code,
|
|
96796
|
-
id: (0,
|
|
96494
|
+
id: (0, import_node_crypto22.randomUUID)(),
|
|
96797
96495
|
title: APPLICATION_PROBLEM_TITLES[input2.code],
|
|
96798
96496
|
detail: input2.message,
|
|
96799
96497
|
// The schema's slot for the technical cause, so the problem carries it
|
|
@@ -96863,7 +96561,7 @@ var WebPresenter = class {
|
|
|
96863
96561
|
};
|
|
96864
96562
|
|
|
96865
96563
|
// src/ws-client.ts
|
|
96866
|
-
var
|
|
96564
|
+
var import_node_crypto24 = require("crypto");
|
|
96867
96565
|
|
|
96868
96566
|
// ../shared/dist/agent-liveness.js
|
|
96869
96567
|
var AGENT_LIVENESS_PROTOCOL_VERSION = 1;
|
|
@@ -96891,13 +96589,13 @@ var agentProbeAckSchema = external_exports.object({
|
|
|
96891
96589
|
});
|
|
96892
96590
|
|
|
96893
96591
|
// src/sandbox-outbox.ts
|
|
96894
|
-
var
|
|
96592
|
+
var import_node_crypto23 = require("crypto");
|
|
96895
96593
|
var import_node_fs28 = require("fs");
|
|
96896
96594
|
function deriveSandboxOutboxKey(sessionToken) {
|
|
96897
96595
|
if (!sessionToken) {
|
|
96898
96596
|
throw new Error("sandbox event outbox requires ALAN_SESSION_TOKEN for key derivation");
|
|
96899
96597
|
}
|
|
96900
|
-
return (0,
|
|
96598
|
+
return (0, import_node_crypto23.createHash)("sha256").update(sessionToken, "utf8").digest("base64url");
|
|
96901
96599
|
}
|
|
96902
96600
|
function sandboxOutboxSpoolPath(conversationId) {
|
|
96903
96601
|
return `/tmp/alan-agent-outbox-${conversationId}.enc`;
|
|
@@ -97074,7 +96772,7 @@ var WSClient = class {
|
|
|
97074
96772
|
}
|
|
97075
96773
|
socket;
|
|
97076
96774
|
/** Stable id for this agent process; fences stale heartbeats server-side. */
|
|
97077
|
-
agentSessionId = (0,
|
|
96775
|
+
agentSessionId = (0, import_node_crypto24.randomUUID)();
|
|
97078
96776
|
/** Monotonic heartbeat sequence — advances on every hello + heartbeat. */
|
|
97079
96777
|
heartbeatSeq = 0;
|
|
97080
96778
|
heartbeatTimer = null;
|
|
@@ -97906,7 +97604,7 @@ async function runSandbox(config2) {
|
|
|
97906
97604
|
}
|
|
97907
97605
|
|
|
97908
97606
|
// src/skills/skill-cli.ts
|
|
97909
|
-
var
|
|
97607
|
+
var import_promises6 = require("fs/promises");
|
|
97910
97608
|
var import_node_os19 = require("os");
|
|
97911
97609
|
var import_node_path30 = require("path");
|
|
97912
97610
|
async function runSkillsCommand(args) {
|
|
@@ -97953,7 +97651,7 @@ async function defaultScanInput(homeDirectory2) {
|
|
|
97953
97651
|
}
|
|
97954
97652
|
async function readProtectedJson(path2) {
|
|
97955
97653
|
const absolutePath = (0, import_node_path30.resolve)(path2);
|
|
97956
|
-
const stat2 = await (0,
|
|
97654
|
+
const stat2 = await (0, import_promises6.lstat)(absolutePath);
|
|
97957
97655
|
if (!stat2.isFile()) throw new Error(`Skill input is not a regular file: ${absolutePath}`);
|
|
97958
97656
|
if (process.platform !== "win32" && (stat2.mode & 63) !== 0) {
|
|
97959
97657
|
throw new Error(`Skill input must not be accessible by group or other users: ${absolutePath}`);
|
|
@@ -97962,7 +97660,7 @@ async function readProtectedJson(path2) {
|
|
|
97962
97660
|
throw new Error(`Skill input must be owned by the current user: ${absolutePath}`);
|
|
97963
97661
|
}
|
|
97964
97662
|
if (stat2.size > 2 * 1024 * 1024) throw new Error("Skill input exceeds 2 MiB");
|
|
97965
|
-
return JSON.parse(await (0,
|
|
97663
|
+
return JSON.parse(await (0, import_promises6.readFile)(absolutePath, "utf8"));
|
|
97966
97664
|
}
|
|
97967
97665
|
function option(args, name) {
|
|
97968
97666
|
const index = args.indexOf(name);
|
|
@@ -98120,7 +97818,7 @@ async function main() {
|
|
|
98120
97818
|
return;
|
|
98121
97819
|
}
|
|
98122
97820
|
if (command === "service" && commandArgs[0] === "uninstall") {
|
|
98123
|
-
|
|
97821
|
+
uninstallDaemonService(commandArgs.slice(1));
|
|
98124
97822
|
return;
|
|
98125
97823
|
}
|
|
98126
97824
|
if (command === "service" && commandArgs[0] === "status") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alan-ai-hq/agent-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.96",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
|
|
6
6
|
"bin": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"tsx": "^4.19.0",
|
|
28
28
|
"typescript": "~5.9.3",
|
|
29
29
|
"@alan-ai/agent-core": "0.1.0",
|
|
30
|
-
"@alan-ai/
|
|
31
|
-
"@alan-ai/
|
|
30
|
+
"@alan-ai/sandbox-runtime-spec": "0.1.0",
|
|
31
|
+
"@alan-ai/shared": "0.1.0"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsup",
|