@alan-ai-hq/agent-manager 0.1.90 → 0.1.91

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.
Files changed (2) hide show
  1. package/dist/index.cjs +806 -796
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -15451,7 +15451,7 @@ function describeError(error61) {
15451
15451
  }
15452
15452
 
15453
15453
  // src/version.ts
15454
- var AGENT_VERSION = "0.1.90";
15454
+ var AGENT_VERSION = "0.1.91";
15455
15455
 
15456
15456
  // src/daemon-worktree.ts
15457
15457
  var import_node_child_process3 = require("child_process");
@@ -42795,6 +42795,7 @@ function buildCodexEffortArgs(selectedEffortLevel, options) {
42795
42795
  return ["-c", `model_reasoning_effort=${level}`];
42796
42796
  }
42797
42797
  var CODEX_STARTUP_TIMEOUT_MS = 3e5;
42798
+ var ALAN_MCP_STARTUP_TIMEOUT_SEC = 30;
42798
42799
  function buildCodexManagedMcpArgs(registration) {
42799
42800
  const serverName = managedMcpServerName(registration);
42800
42801
  return [
@@ -42802,7 +42803,11 @@ function buildCodexManagedMcpArgs(registration) {
42802
42803
  "-c",
42803
42804
  `mcp_servers.${serverName}.url=${JSON.stringify(registration.url)}`,
42804
42805
  "-c",
42805
- `mcp_servers.${serverName}.env_http_headers.x-alan-run-reference=${JSON.stringify(ALAN_RUN_REFERENCE_ENV)}`
42806
+ `mcp_servers.${serverName}.env_http_headers.x-alan-run-reference=${JSON.stringify(ALAN_RUN_REFERENCE_ENV)}`,
42807
+ "-c",
42808
+ `mcp_servers.${serverName}.required=true`,
42809
+ "-c",
42810
+ `mcp_servers.${serverName}.startup_timeout_sec=${ALAN_MCP_STARTUP_TIMEOUT_SEC}`
42806
42811
  ];
42807
42812
  }
42808
42813
  function createCodexRuntimeBackend(command = "codex", defaultArgs = []) {
@@ -82145,164 +82150,785 @@ function runMcpIntegrationCommand(args, options = {}) {
82145
82150
  throw new Error(`Unknown integrations action: ${action}`);
82146
82151
  }
82147
82152
 
82148
- // src/lifecycle-logger.ts
82149
- var AgentLifecycleLogger = class _AgentLifecycleLogger {
82150
- context;
82151
- constructor(context = {}) {
82152
- this.context = normalizeContext(context);
82153
- }
82154
- setContext(context) {
82155
- this.context = normalizeContext({ ...this.context, ...context });
82156
- }
82157
- child(context) {
82158
- return new _AgentLifecycleLogger({ ...this.context, ...context });
82159
- }
82160
- debug(event, fields = {}) {
82161
- this.log("debug", event, fields);
82162
- }
82163
- info(event, fields = {}) {
82164
- this.log("info", event, fields);
82165
- }
82166
- warn(event, fields = {}) {
82167
- this.log("warn", event, fields);
82168
- }
82169
- error(event, fields = {}) {
82170
- this.log("error", event, fields);
82171
- }
82172
- log(level, event, fields) {
82173
- const record2 = omitUndefined({
82174
- ts: (/* @__PURE__ */ new Date()).toISOString(),
82175
- level,
82176
- component: "agent-manager",
82177
- event,
82178
- ...this.context,
82179
- ...normalizeFields(fields)
82180
- });
82181
- console[level](JSON.stringify(record2));
82182
- }
82183
- };
82184
- function lifecycleContextFromEnv(env) {
82185
- return normalizeContext({
82186
- taskId: env.ALAN_TASK_ID,
82187
- conversationId: env.ALAN_SESSION_ID,
82188
- runId: env.ALAN_RUN_ID,
82189
- sandboxId: env.ALAN_SANDBOX_ID,
82190
- provider: env.ALAN_SANDBOX_PROVIDER,
82191
- backendKind: env.ALAN_BACKEND_KIND,
82192
- agentVersion: AGENT_VERSION
82193
- });
82194
- }
82195
- function normalizeContext(context) {
82196
- return omitUndefined({
82197
- ...context,
82198
- agentVersion: context.agentVersion ?? AGENT_VERSION
82199
- });
82153
+ // src/service-manager.ts
82154
+ var import_node_child_process9 = require("child_process");
82155
+ var import_node_fs25 = require("fs");
82156
+ var import_node_os16 = require("os");
82157
+ var import_node_path27 = require("path");
82158
+ var SERVICE_LABEL = "ai.tryalan.agent";
82159
+ var SYSTEMD_UNIT = "alan-agent.service";
82160
+ var WINDOWS_TASK = "Alan Agent";
82161
+ function xml(value2) {
82162
+ return value2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
82200
82163
  }
82201
- function normalizeFields(fields) {
82202
- const normalized = {};
82203
- for (const [key, value2] of Object.entries(fields)) {
82204
- if (value2 instanceof Error) {
82205
- normalized[key] = {
82206
- name: value2.name,
82207
- message: value2.message,
82208
- stack: value2.stack
82209
- };
82210
- } else {
82211
- normalized[key] = value2;
82212
- }
82213
- }
82214
- return normalized;
82164
+ function systemdArg(value2) {
82165
+ return `"${value2.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
82215
82166
  }
82216
- function omitUndefined(record2) {
82217
- return Object.fromEntries(Object.entries(record2).filter(([, value2]) => value2 !== void 0));
82167
+ function powershellLiteral(value2) {
82168
+ return `'${value2.replaceAll("'", "''")}'`;
82218
82169
  }
82219
-
82220
- // ../../node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
82221
- var __create3 = Object.create;
82222
- var __defProp3 = Object.defineProperty;
82223
- var __getOwnPropDesc3 = Object.getOwnPropertyDescriptor;
82224
- var __getOwnPropNames3 = Object.getOwnPropertyNames;
82225
- var __getProtoOf3 = Object.getPrototypeOf;
82226
- var __hasOwnProp3 = Object.prototype.hasOwnProperty;
82227
- var __commonJSMin2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
82228
- var __exportAll2 = (all, symbols) => {
82229
- let target = {};
82230
- for (var name in all) {
82231
- __defProp3(target, name, {
82232
- get: all[name],
82233
- enumerable: true
82234
- });
82170
+ function serviceNames(profile) {
82171
+ if (profile === "production") {
82172
+ return { launchd: SERVICE_LABEL, systemd: SYSTEMD_UNIT, windows: WINDOWS_TASK };
82235
82173
  }
82236
- if (symbols) {
82237
- __defProp3(target, Symbol.toStringTag, { value: "Module" });
82174
+ const suffix = profile === "custom" ? "prod" : profile;
82175
+ const title = `${suffix[0]?.toUpperCase()}${suffix.slice(1)}`;
82176
+ return {
82177
+ launchd: `${SERVICE_LABEL}.${suffix}`,
82178
+ systemd: `alan-agent-${suffix}.service`,
82179
+ windows: `${WINDOWS_TASK} ${title}`
82180
+ };
82181
+ }
82182
+ function buildDaemonServicePlan(input2) {
82183
+ const daemonArgs = [input2.nodeExecutable, input2.cliEntry, "daemon", "--profile", input2.profile];
82184
+ const names = serviceNames(input2.profile);
82185
+ if (input2.platform === "darwin") {
82186
+ const userId = input2.userId ?? process.getuid?.();
82187
+ if (userId === void 0) throw new Error("Cannot determine the current macOS user ID");
82188
+ const domain2 = `gui/${userId}`;
82189
+ const serviceTarget = `${domain2}/${names.launchd}`;
82190
+ const manifestPath = (0, import_node_path27.join)(input2.homeDir, "Library", "LaunchAgents", `${names.launchd}.plist`);
82191
+ const logDir = (0, import_node_path27.join)(resolveAgentConfigDirectory(input2.profile, input2.homeDir), "logs");
82192
+ const programArguments = daemonArgs.map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
82193
+ const environmentEntries = Object.entries(input2.environment ?? {}).map(([key, value2]) => ` <key>${xml(key)}</key>
82194
+ <string>${xml(value2)}</string>`).join("\n");
82195
+ const environmentBlock = environmentEntries ? ` <key>EnvironmentVariables</key>
82196
+ <dict>
82197
+ ${environmentEntries}
82198
+ </dict>
82199
+ ` : "";
82200
+ const manifest = `<?xml version="1.0" encoding="UTF-8"?>
82201
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
82202
+ <plist version="1.0">
82203
+ <dict>
82204
+ <key>Label</key>
82205
+ <string>${names.launchd}</string>
82206
+ <key>ProgramArguments</key>
82207
+ <array>
82208
+ ${programArguments}
82209
+ </array>
82210
+ ${environmentBlock} <key>RunAtLoad</key>
82211
+ <true/>
82212
+ <key>KeepAlive</key>
82213
+ <dict>
82214
+ <key>SuccessfulExit</key>
82215
+ <false/>
82216
+ </dict>
82217
+ <key>ThrottleInterval</key>
82218
+ <integer>5</integer>
82219
+ <key>StandardOutPath</key>
82220
+ <string>${xml((0, import_node_path27.join)(logDir, "daemon.log"))}</string>
82221
+ <key>StandardErrorPath</key>
82222
+ <string>${xml((0, import_node_path27.join)(logDir, "daemon-error.log"))}</string>
82223
+ </dict>
82224
+ </plist>
82225
+ `;
82226
+ return {
82227
+ platform: "darwin",
82228
+ manifestPath,
82229
+ manifest,
82230
+ logDirectory: logDir,
82231
+ loadDefinitionCommands: [
82232
+ {
82233
+ command: "launchctl",
82234
+ args: ["bootstrap", domain2, manifestPath],
82235
+ tolerateFailure: true
82236
+ }
82237
+ ],
82238
+ reloadDefinitionCommands: [
82239
+ {
82240
+ command: "launchctl",
82241
+ args: ["bootout", domain2, manifestPath],
82242
+ tolerateFailure: true
82243
+ },
82244
+ {
82245
+ command: "launchctl",
82246
+ args: ["bootstrap", domain2, manifestPath],
82247
+ tolerateFailure: false
82248
+ }
82249
+ ],
82250
+ enableCommands: [
82251
+ {
82252
+ command: "launchctl",
82253
+ args: ["enable", serviceTarget],
82254
+ tolerateFailure: true
82255
+ }
82256
+ ],
82257
+ startCommands: [
82258
+ {
82259
+ command: "launchctl",
82260
+ args: ["kickstart", serviceTarget],
82261
+ tolerateFailure: false
82262
+ }
82263
+ ],
82264
+ stopCommands: [
82265
+ {
82266
+ command: "launchctl",
82267
+ args: ["kill", "SIGTERM", serviceTarget],
82268
+ tolerateFailure: true
82269
+ }
82270
+ ],
82271
+ replaceCommands: [
82272
+ {
82273
+ command: "launchctl",
82274
+ args: ["bootout", domain2, manifestPath],
82275
+ tolerateFailure: true
82276
+ },
82277
+ {
82278
+ command: "launchctl",
82279
+ args: ["bootstrap", domain2, manifestPath],
82280
+ tolerateFailure: false
82281
+ },
82282
+ {
82283
+ command: "launchctl",
82284
+ args: ["kickstart", "-k", serviceTarget],
82285
+ tolerateFailure: false
82286
+ }
82287
+ ],
82288
+ uninstallCommands: [
82289
+ {
82290
+ command: "launchctl",
82291
+ args: ["bootout", domain2, manifestPath],
82292
+ tolerateFailure: true
82293
+ }
82294
+ ],
82295
+ statusCommand: {
82296
+ command: "launchctl",
82297
+ args: ["print", serviceTarget],
82298
+ tolerateFailure: true
82299
+ },
82300
+ isActiveCommand: {
82301
+ command: "launchctl",
82302
+ args: ["print", serviceTarget],
82303
+ tolerateFailure: true
82304
+ },
82305
+ lingerStatusCommand: null
82306
+ };
82238
82307
  }
82239
- return target;
82240
- };
82241
- var __copyProps3 = (to, from, except, desc) => {
82242
- if (from && typeof from === "object" || typeof from === "function") {
82243
- for (var keys = __getOwnPropNames3(from), i = 0, n = keys.length, key; i < n; i++) {
82244
- key = keys[i];
82245
- if (!__hasOwnProp3.call(to, key) && key !== except) {
82246
- __defProp3(to, key, {
82247
- get: ((k) => from[k]).bind(null, key),
82248
- enumerable: !(desc = __getOwnPropDesc3(from, key)) || desc.enumerable
82249
- });
82308
+ if (input2.platform === "linux") {
82309
+ const manifestPath = (0, import_node_path27.join)(input2.homeDir, ".config", "systemd", "user", names.systemd);
82310
+ const environmentLines = Object.entries(input2.environment ?? {}).map(([key, value2]) => `Environment=${systemdArg(`${key}=${value2}`)}`).join("\n");
82311
+ const manifest = `[Unit]
82312
+ Description=Alan local agent daemon
82313
+ After=network-online.target
82314
+ Wants=network-online.target
82315
+ StartLimitIntervalSec=300
82316
+ StartLimitBurst=3
82317
+
82318
+ [Service]
82319
+ Type=simple
82320
+ ${environmentLines ? `${environmentLines}
82321
+ ` : ""}ExecStart=${daemonArgs.map(systemdArg).join(" ")}
82322
+ Restart=on-failure
82323
+ RestartSec=5
82324
+
82325
+ [Install]
82326
+ WantedBy=default.target
82327
+ `;
82328
+ return {
82329
+ platform: "linux",
82330
+ manifestPath,
82331
+ manifest,
82332
+ logDirectory: null,
82333
+ loadDefinitionCommands: [
82334
+ {
82335
+ command: "systemctl",
82336
+ args: ["--user", "daemon-reload"],
82337
+ tolerateFailure: false
82338
+ }
82339
+ ],
82340
+ reloadDefinitionCommands: [
82341
+ {
82342
+ command: "systemctl",
82343
+ args: ["--user", "daemon-reload"],
82344
+ tolerateFailure: false
82345
+ }
82346
+ ],
82347
+ enableCommands: [
82348
+ {
82349
+ command: "systemctl",
82350
+ args: ["--user", "enable", names.systemd],
82351
+ tolerateFailure: false
82352
+ }
82353
+ ],
82354
+ startCommands: [
82355
+ {
82356
+ command: "systemctl",
82357
+ args: ["--user", "start", names.systemd],
82358
+ tolerateFailure: false
82359
+ }
82360
+ ],
82361
+ stopCommands: [
82362
+ {
82363
+ command: "systemctl",
82364
+ args: ["--user", "stop", names.systemd],
82365
+ tolerateFailure: true
82366
+ }
82367
+ ],
82368
+ replaceCommands: [
82369
+ {
82370
+ command: "systemctl",
82371
+ args: ["--user", "daemon-reload"],
82372
+ tolerateFailure: false
82373
+ },
82374
+ {
82375
+ command: "systemctl",
82376
+ args: ["--user", "restart", names.systemd],
82377
+ tolerateFailure: false
82378
+ }
82379
+ ],
82380
+ uninstallCommands: [
82381
+ {
82382
+ command: "systemctl",
82383
+ args: ["--user", "disable", "--now", names.systemd],
82384
+ tolerateFailure: true
82385
+ },
82386
+ {
82387
+ command: "systemctl",
82388
+ args: ["--user", "daemon-reload"],
82389
+ tolerateFailure: false
82390
+ }
82391
+ ],
82392
+ statusCommand: {
82393
+ command: "systemctl",
82394
+ args: ["--user", "status", names.systemd, "--no-pager"],
82395
+ tolerateFailure: true
82396
+ },
82397
+ isActiveCommand: {
82398
+ command: "systemctl",
82399
+ args: ["--user", "is-active", names.systemd],
82400
+ tolerateFailure: true
82401
+ },
82402
+ lingerStatusCommand: {
82403
+ command: "loginctl",
82404
+ args: ["show-user", "$(id -un)", "-p", "Linger"],
82405
+ tolerateFailure: true
82250
82406
  }
82251
- }
82407
+ };
82252
82408
  }
82253
- return to;
82254
- };
82255
- var __toESM3 = (mod, isNodeMode, target) => (target = mod != null ? __create3(__getProtoOf3(mod)) : {}, __copyProps3(isNodeMode || !mod || !mod.__esModule ? __defProp3(target, "default", {
82256
- value: mod,
82257
- enumerable: true
82258
- }) : target, mod));
82259
-
82260
- // ../../node_modules/@modelcontextprotocol/server/dist/dialects-DoSzNhcb.mjs
82261
- var DRAFT_2020_12_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft/2020-12/schema", "http://json-schema.org/draft/2020-12/schema"]);
82262
- var DRAFT_2019_09_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft/2019-09/schema", "http://json-schema.org/draft/2019-09/schema"]);
82263
- var DRAFT_07_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft-07/schema", "http://json-schema.org/draft-07/schema"]);
82264
- var DRAFT_06_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft-06/schema", "http://json-schema.org/draft-06/schema"]);
82265
- function declares2019Dialect2($schema) {
82266
- return typeof $schema === "string" && DRAFT_2019_09_URIS2.has($schema.replace(/#$/, ""));
82267
- }
82268
- function declaredDialect2(schema, remedy) {
82269
- if (!("$schema" in schema) || typeof schema.$schema !== "string") return "2020-12";
82270
- const declared = schema.$schema.replace(/#$/, "");
82271
- if (DRAFT_2020_12_URIS2.has(declared)) return "2020-12";
82272
- if (DRAFT_2019_09_URIS2.has(declared)) return "2019-09";
82273
- if (DRAFT_07_URIS2.has(declared) || DRAFT_06_URIS2.has(declared)) return "draft-7";
82274
- throw new Error(`JSON Schema declares an unsupported dialect ("$schema": "${schema.$schema.slice(0, 200)}"). The default validator supports JSON Schema 2020-12, 2019-09, draft-07, and draft-06; ${remedy}`);
82409
+ const environmentPrefix = Object.entries(input2.environment ?? {}).map(([key, value2]) => `$env:${key} = ${powershellLiteral(value2)}`).join("; ");
82410
+ const directArgument = [input2.cliEntry, "daemon", "--profile", input2.profile].map((part) => part.includes(" ") ? `"${part}"` : part).join(" ");
82411
+ const executable = powershellLiteral(environmentPrefix ? "powershell.exe" : input2.nodeExecutable);
82412
+ const argument = powershellLiteral(
82413
+ environmentPrefix ? `-NoProfile -NonInteractive -WindowStyle Hidden -Command "${environmentPrefix}; & ${powershellLiteral(input2.nodeExecutable)} ${powershellLiteral(input2.cliEntry)} daemon --profile ${input2.profile}"` : directArgument
82414
+ );
82415
+ const registerScript = [
82416
+ "$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name",
82417
+ `$action = New-ScheduledTaskAction -Execute ${executable} -Argument ${argument}`,
82418
+ "$trigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser",
82419
+ "$principal = New-ScheduledTaskPrincipal -UserId $currentUser -LogonType Interactive -RunLevel Limited",
82420
+ "$settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit ([TimeSpan]::Zero)",
82421
+ `Register-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null`
82422
+ ].join("; ");
82423
+ return {
82424
+ platform: "win32",
82425
+ manifestPath: null,
82426
+ manifest: null,
82427
+ logDirectory: null,
82428
+ loadDefinitionCommands: [
82429
+ {
82430
+ command: "powershell.exe",
82431
+ args: ["-NoProfile", "-NonInteractive", "-Command", registerScript],
82432
+ tolerateFailure: false
82433
+ }
82434
+ ],
82435
+ reloadDefinitionCommands: [
82436
+ {
82437
+ command: "powershell.exe",
82438
+ args: ["-NoProfile", "-NonInteractive", "-Command", registerScript],
82439
+ tolerateFailure: false
82440
+ }
82441
+ ],
82442
+ enableCommands: [],
82443
+ startCommands: [
82444
+ {
82445
+ command: "powershell.exe",
82446
+ args: [
82447
+ "-NoProfile",
82448
+ "-NonInteractive",
82449
+ "-Command",
82450
+ `Start-ScheduledTask -TaskName ${powershellLiteral(names.windows)}`
82451
+ ],
82452
+ tolerateFailure: false
82453
+ }
82454
+ ],
82455
+ stopCommands: [
82456
+ {
82457
+ command: "powershell.exe",
82458
+ args: [
82459
+ "-NoProfile",
82460
+ "-NonInteractive",
82461
+ "-Command",
82462
+ `Stop-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -ErrorAction SilentlyContinue`
82463
+ ],
82464
+ tolerateFailure: true
82465
+ }
82466
+ ],
82467
+ replaceCommands: [
82468
+ {
82469
+ command: "powershell.exe",
82470
+ args: [
82471
+ "-NoProfile",
82472
+ "-NonInteractive",
82473
+ "-Command",
82474
+ `${registerScript}; Start-ScheduledTask -TaskName ${powershellLiteral(names.windows)}`
82475
+ ],
82476
+ tolerateFailure: false
82477
+ }
82478
+ ],
82479
+ uninstallCommands: [
82480
+ {
82481
+ command: "powershell.exe",
82482
+ args: [
82483
+ "-NoProfile",
82484
+ "-NonInteractive",
82485
+ "-Command",
82486
+ `Unregister-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -Confirm:$false -ErrorAction SilentlyContinue`
82487
+ ],
82488
+ tolerateFailure: true
82489
+ }
82490
+ ],
82491
+ statusCommand: {
82492
+ command: "powershell.exe",
82493
+ args: [
82494
+ "-NoProfile",
82495
+ "-NonInteractive",
82496
+ "-Command",
82497
+ `Get-ScheduledTask -TaskName ${powershellLiteral(names.windows)} | Format-List TaskName,State`
82498
+ ],
82499
+ tolerateFailure: true
82500
+ },
82501
+ isActiveCommand: {
82502
+ command: "powershell.exe",
82503
+ args: [
82504
+ "-NoProfile",
82505
+ "-NonInteractive",
82506
+ "-Command",
82507
+ `(Get-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -ErrorAction SilentlyContinue).State`
82508
+ ],
82509
+ tolerateFailure: true
82510
+ },
82511
+ lingerStatusCommand: null
82512
+ };
82275
82513
  }
82276
-
82277
- // ../../node_modules/@modelcontextprotocol/server/dist/src-CX2iR2pK.mjs
82278
- var BRANDS2 = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
82279
- function stampErrorBrands2(instance, ctor) {
82280
- const brands = /* @__PURE__ */ new Set();
82281
- let current = ctor;
82282
- while (typeof current === "function") {
82283
- const brand = current.mcpBrand;
82284
- if (Object.prototype.hasOwnProperty.call(current, "mcpBrand") && typeof brand === "string") brands.add(brand);
82285
- current = Object.getPrototypeOf(current);
82514
+ function resolveCurrentPlatform() {
82515
+ const currentPlatform = (0, import_node_os16.platform)();
82516
+ if (currentPlatform !== "darwin" && currentPlatform !== "linux" && currentPlatform !== "win32") {
82517
+ throw new Error(`Daemon service installation is not supported on ${currentPlatform}`);
82286
82518
  }
82287
- if (brands.size === 0) return;
82288
- Object.defineProperty(instance, BRANDS2, {
82289
- value: brands,
82290
- enumerable: false,
82291
- configurable: true
82519
+ return currentPlatform;
82520
+ }
82521
+ function currentServicePlan(args, runtime) {
82522
+ const currentPlatform = resolveCurrentPlatform();
82523
+ const profile = resolveEndpointProfileFromArgs(args);
82524
+ const cliEntry = runtime?.cliEntry ?? process.argv[1];
82525
+ if (!cliEntry) throw new Error("Cannot determine the alan-agent executable path");
82526
+ return buildDaemonServicePlan({
82527
+ platform: currentPlatform,
82528
+ homeDir: (0, import_node_os16.homedir)(),
82529
+ nodeExecutable: runtime?.executable ?? process.execPath,
82530
+ cliEntry: (0, import_node_path27.resolve)(cliEntry),
82531
+ profile,
82532
+ environment: runtime?.environment
82292
82533
  });
82293
82534
  }
82294
- function brandedHasInstance2(cls, value2) {
82535
+ function writeManifestAtomic(path2, contents) {
82536
+ (0, import_node_fs25.mkdirSync)((0, import_node_path27.dirname)(path2), { recursive: true, mode: 448 });
82537
+ const pendingPath = `${path2}.pending-${process.pid}`;
82295
82538
  try {
82296
- if (typeof value2 === "object" && value2 !== null && Object.prototype.hasOwnProperty.call(cls, "mcpBrand") && typeof cls.mcpBrand === "string" && Object.prototype.hasOwnProperty.call(value2, BRANDS2)) {
82297
- const carried = value2[BRANDS2];
82298
- if (carried && typeof carried.has === "function" && carried.has(cls.mcpBrand)) return true;
82299
- }
82300
- } catch {
82539
+ (0, import_node_fs25.writeFileSync)(pendingPath, contents, { mode: 384 });
82540
+ (0, import_node_fs25.chmodSync)(pendingPath, 384);
82541
+ (0, import_node_fs25.renameSync)(pendingPath, path2);
82542
+ } finally {
82543
+ (0, import_node_fs25.rmSync)(pendingPath, { force: true });
82301
82544
  }
82302
- return Function.prototype[Symbol.hasInstance].call(cls, value2);
82303
82545
  }
82304
- var OAuthError3 = class OAuthError4 extends Error {
82305
- static {
82546
+ function defaultReadManifest(path2) {
82547
+ if (!(0, import_node_fs25.existsSync)(path2)) return null;
82548
+ return (0, import_node_fs25.readFileSync)(path2, "utf8");
82549
+ }
82550
+ function runServiceCommand(command) {
82551
+ const result = (0, import_node_child_process9.spawnSync)(command.command, command.args, { encoding: "utf8", shell: false });
82552
+ const status = result.status ?? 1;
82553
+ const output2 = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
82554
+ if (status !== 0 && !command.tolerateFailure) {
82555
+ throw new Error(
82556
+ `Service command failed (${command.command} ${command.args.join(" ")}): ${output2 || `exit ${status}`}`
82557
+ );
82558
+ }
82559
+ return { status, output: output2 };
82560
+ }
82561
+ function defaultSleep(ms) {
82562
+ return new Promise((resolveSleep) => {
82563
+ setTimeout(resolveSleep, ms);
82564
+ });
82565
+ }
82566
+ function parseServiceHostState(servicePlatform, result) {
82567
+ const output2 = result.output;
82568
+ if (servicePlatform === "linux") {
82569
+ const trimmed = output2.trim().toLowerCase();
82570
+ if (trimmed === "inactive" || trimmed === "failed" || trimmed === "dead" || /\binactive\b/i.test(output2) || /\bfailed\b/i.test(output2)) {
82571
+ return "stopped";
82572
+ }
82573
+ }
82574
+ if (result.status !== 0) return "unknown";
82575
+ if (servicePlatform === "darwin") {
82576
+ if (/\bstate\s*=\s*running\b/i.test(output2)) return "running";
82577
+ if (/\bstate\s*=\s*(not running|waiting|stopped)\b/i.test(output2)) return "stopped";
82578
+ if (/\bpid\s*=\s*[1-9]\d*\b/i.test(output2)) return "running";
82579
+ if (/could not find service/i.test(output2)) return "stopped";
82580
+ return "unknown";
82581
+ }
82582
+ if (servicePlatform === "linux") {
82583
+ const trimmed = output2.trim().toLowerCase();
82584
+ if (trimmed === "active" || /\bactive\s*\(running\)/i.test(output2)) return "running";
82585
+ if (trimmed === "activating" || trimmed === "reloading") return "starting";
82586
+ return "unknown";
82587
+ }
82588
+ const stateMatch = output2.match(/\b(?:State|state)\s*[:=]\s*(\w+)/);
82589
+ const state = (stateMatch?.[1] ?? output2.trim()).toLowerCase();
82590
+ if (state === "running") return "running";
82591
+ if (state === "ready" || state === "disabled" || state === "queued") return "stopped";
82592
+ return "unknown";
82593
+ }
82594
+ function resolveEnsureDefinitionOutcome(input2) {
82595
+ if (!input2.definitionChanged) {
82596
+ return { changed: false, updatePending: false };
82597
+ }
82598
+ if (input2.hostState === "running" || input2.hostState === "starting") {
82599
+ return { changed: true, updatePending: true };
82600
+ }
82601
+ return { changed: true, updatePending: false };
82602
+ }
82603
+ function shouldStartOnInstall(hostState) {
82604
+ return hostState === "stopped";
82605
+ }
82606
+ function resolveUsername(options) {
82607
+ if (options?.username) return options.username;
82608
+ try {
82609
+ return (0, import_node_os16.userInfo)().username;
82610
+ } catch {
82611
+ return process.env.USER || process.env.USERNAME || "unknown";
82612
+ }
82613
+ }
82614
+ function buildLingerStatusCommand(username) {
82615
+ return {
82616
+ command: "loginctl",
82617
+ args: ["show-user", username, "-p", "Linger"],
82618
+ tolerateFailure: true
82619
+ };
82620
+ }
82621
+ function assertSystemdUserLingerEnabled(options = {}) {
82622
+ const username = resolveUsername(options);
82623
+ const run = options.runCommand ?? runServiceCommand;
82624
+ const result = run(buildLingerStatusCommand(username));
82625
+ if (result.status !== 0) {
82626
+ throw new Error(
82627
+ `Cannot verify systemd user linger for ${username} (loginctl failed). For durable headless VM boot run: sudo loginctl enable-linger ${username}`
82628
+ );
82629
+ }
82630
+ if (!/Linger=yes/i.test(result.output)) {
82631
+ throw new Error(
82632
+ `systemd user linger is disabled for ${username}. For durable headless VM boot run: sudo loginctl enable-linger ${username}`
82633
+ );
82634
+ }
82635
+ }
82636
+ function createHostContext(options = {}) {
82637
+ const args = options.args ?? [];
82638
+ const plan = currentServicePlan(args, options.runtime);
82639
+ const run = options.runCommand ?? runServiceCommand;
82640
+ const sleep4 = options.sleep ?? defaultSleep;
82641
+ const nowMs = options.nowMs ?? Date.now;
82642
+ const readManifest = options.readManifest ?? defaultReadManifest;
82643
+ const writeManifest = options.writeManifest ?? writeManifestAtomic;
82644
+ const removeManifest = options.removeManifest ?? ((path2) => (0, import_node_fs25.rmSync)(path2, { force: true }));
82645
+ const ensureLogDir = options.ensureLogDir ?? (() => {
82646
+ if (plan.logDirectory) (0, import_node_fs25.mkdirSync)(plan.logDirectory, { recursive: true, mode: 448 });
82647
+ });
82648
+ return {
82649
+ args,
82650
+ plan,
82651
+ run,
82652
+ sleep: sleep4,
82653
+ nowMs,
82654
+ readManifest,
82655
+ writeManifest,
82656
+ removeManifest,
82657
+ ensureLogDir,
82658
+ profile: resolveEndpointProfileFromArgs(args)
82659
+ };
82660
+ }
82661
+ function inspectDaemonService(options = {}) {
82662
+ const { plan, run, nowMs } = createHostContext(options);
82663
+ const result = run(plan.isActiveCommand);
82664
+ const state = parseServiceHostState(plan.platform, result);
82665
+ return {
82666
+ state,
82667
+ platform: plan.platform,
82668
+ detail: result.output || void 0,
82669
+ observedAtMs: nowMs()
82670
+ };
82671
+ }
82672
+ function ensureDaemonServiceDefinition(options = {}) {
82673
+ const ctx = createHostContext(options);
82674
+ const { plan, run, readManifest, writeManifest, ensureLogDir } = ctx;
82675
+ let definitionChanged = false;
82676
+ if (plan.manifestPath && plan.manifest) {
82677
+ ensureLogDir();
82678
+ const existing = readManifest(plan.manifestPath);
82679
+ definitionChanged = existing !== plan.manifest;
82680
+ if (definitionChanged) {
82681
+ writeManifest(plan.manifestPath, plan.manifest);
82682
+ }
82683
+ } else if (plan.platform === "win32") {
82684
+ definitionChanged = true;
82685
+ }
82686
+ const inspection = inspectDaemonService(options);
82687
+ const outcome = resolveEnsureDefinitionOutcome({
82688
+ definitionChanged,
82689
+ hostState: inspection.state
82690
+ });
82691
+ if (outcome.updatePending) {
82692
+ return outcome;
82693
+ }
82694
+ if (inspection.state === "running" || inspection.state === "starting") {
82695
+ return outcome;
82696
+ }
82697
+ const definitionCommands = inspection.state === "stopped" ? plan.reloadDefinitionCommands : plan.loadDefinitionCommands;
82698
+ for (const command of definitionCommands) run(command);
82699
+ return outcome;
82700
+ }
82701
+ function enableDaemonService(options = {}) {
82702
+ const { plan, run } = createHostContext(options);
82703
+ for (const command of plan.enableCommands) run(command);
82704
+ }
82705
+ function startDaemonService(options = {}) {
82706
+ const { plan, run } = createHostContext(options);
82707
+ for (const command of plan.startCommands) run(command);
82708
+ }
82709
+ function uninstallDaemonService(args = [], options = {}) {
82710
+ const ctx = createHostContext({ ...options, args: options.args ?? args });
82711
+ for (const command of ctx.plan.uninstallCommands) ctx.run(command);
82712
+ if (ctx.plan.manifestPath) ctx.removeManifest(ctx.plan.manifestPath);
82713
+ console.info("[alan-agent] Per-user daemon service removed");
82714
+ }
82715
+ function installDaemonService(args = [], runtime, options = {}) {
82716
+ const profile = resolveEndpointProfileFromArgs(args);
82717
+ const configPath = resolveAgentConfigPath({ profile });
82718
+ if (!configExistsAtPath(configPath)) {
82719
+ throw new Error(`No ${profile} runtime is configured. Run alan-agent setup or login first.`);
82720
+ }
82721
+ const headless = options.headless ?? args.includes("--headless");
82722
+ const merged = { ...options, args, runtime, headless };
82723
+ const ctx = createHostContext(merged);
82724
+ if (headless) {
82725
+ if (ctx.plan.platform !== "linux") {
82726
+ throw new Error("--headless is only supported on Linux systemd user services");
82727
+ }
82728
+ assertSystemdUserLingerEnabled(merged);
82729
+ }
82730
+ const ensured = ensureDaemonServiceDefinition(merged);
82731
+ enableDaemonService(merged);
82732
+ const inspection = inspectDaemonService(merged);
82733
+ if (ensured.updatePending) {
82734
+ console.info("[alan-agent] Daemon service definition update pending; leaving running service", {
82735
+ profile,
82736
+ state: inspection.state
82737
+ });
82738
+ return;
82739
+ }
82740
+ if (!shouldStartOnInstall(inspection.state)) {
82741
+ console.info("[alan-agent] Per-user daemon service already present", {
82742
+ profile,
82743
+ state: inspection.state
82744
+ });
82745
+ return;
82746
+ }
82747
+ startDaemonService(merged);
82748
+ console.info("[alan-agent] Per-user daemon service installed", { profile });
82749
+ }
82750
+ function printDaemonServiceStatus(args = []) {
82751
+ const plan = currentServicePlan(args);
82752
+ const result = runServiceCommand({ ...plan.statusCommand, tolerateFailure: true });
82753
+ if (result.status !== 0) {
82754
+ process.stdout.write(`unknown
82755
+ ${result.output}
82756
+ `);
82757
+ return;
82758
+ }
82759
+ process.stdout.write(`${result.output}
82760
+ `);
82761
+ }
82762
+
82763
+ // src/install-command.ts
82764
+ async function runInstallCommand(commandArgs) {
82765
+ bindConfigPath(commandArgs);
82766
+ const configured = readConfig();
82767
+ const configurationMode = resolveInstallConfigurationMode(commandArgs, configured);
82768
+ if (configurationMode === "setup") await setupDaemon(commandArgs);
82769
+ if (configurationMode === "login") await loginWithDeviceCode(commandArgs);
82770
+ installDaemonService(commandArgs);
82771
+ runMcpIntegrationCommand(["reconcile", ...commandArgs]);
82772
+ }
82773
+
82774
+ // src/lifecycle-logger.ts
82775
+ var AgentLifecycleLogger = class _AgentLifecycleLogger {
82776
+ context;
82777
+ constructor(context = {}) {
82778
+ this.context = normalizeContext(context);
82779
+ }
82780
+ setContext(context) {
82781
+ this.context = normalizeContext({ ...this.context, ...context });
82782
+ }
82783
+ child(context) {
82784
+ return new _AgentLifecycleLogger({ ...this.context, ...context });
82785
+ }
82786
+ debug(event, fields = {}) {
82787
+ this.log("debug", event, fields);
82788
+ }
82789
+ info(event, fields = {}) {
82790
+ this.log("info", event, fields);
82791
+ }
82792
+ warn(event, fields = {}) {
82793
+ this.log("warn", event, fields);
82794
+ }
82795
+ error(event, fields = {}) {
82796
+ this.log("error", event, fields);
82797
+ }
82798
+ log(level, event, fields) {
82799
+ const record2 = omitUndefined({
82800
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
82801
+ level,
82802
+ component: "agent-manager",
82803
+ event,
82804
+ ...this.context,
82805
+ ...normalizeFields(fields)
82806
+ });
82807
+ console[level](JSON.stringify(record2));
82808
+ }
82809
+ };
82810
+ function lifecycleContextFromEnv(env) {
82811
+ return normalizeContext({
82812
+ taskId: env.ALAN_TASK_ID,
82813
+ conversationId: env.ALAN_SESSION_ID,
82814
+ runId: env.ALAN_RUN_ID,
82815
+ sandboxId: env.ALAN_SANDBOX_ID,
82816
+ provider: env.ALAN_SANDBOX_PROVIDER,
82817
+ backendKind: env.ALAN_BACKEND_KIND,
82818
+ agentVersion: AGENT_VERSION
82819
+ });
82820
+ }
82821
+ function normalizeContext(context) {
82822
+ return omitUndefined({
82823
+ ...context,
82824
+ agentVersion: context.agentVersion ?? AGENT_VERSION
82825
+ });
82826
+ }
82827
+ function normalizeFields(fields) {
82828
+ const normalized = {};
82829
+ for (const [key, value2] of Object.entries(fields)) {
82830
+ if (value2 instanceof Error) {
82831
+ normalized[key] = {
82832
+ name: value2.name,
82833
+ message: value2.message,
82834
+ stack: value2.stack
82835
+ };
82836
+ } else {
82837
+ normalized[key] = value2;
82838
+ }
82839
+ }
82840
+ return normalized;
82841
+ }
82842
+ function omitUndefined(record2) {
82843
+ return Object.fromEntries(Object.entries(record2).filter(([, value2]) => value2 !== void 0));
82844
+ }
82845
+
82846
+ // ../../node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
82847
+ var __create3 = Object.create;
82848
+ var __defProp3 = Object.defineProperty;
82849
+ var __getOwnPropDesc3 = Object.getOwnPropertyDescriptor;
82850
+ var __getOwnPropNames3 = Object.getOwnPropertyNames;
82851
+ var __getProtoOf3 = Object.getPrototypeOf;
82852
+ var __hasOwnProp3 = Object.prototype.hasOwnProperty;
82853
+ var __commonJSMin2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
82854
+ var __exportAll2 = (all, symbols) => {
82855
+ let target = {};
82856
+ for (var name in all) {
82857
+ __defProp3(target, name, {
82858
+ get: all[name],
82859
+ enumerable: true
82860
+ });
82861
+ }
82862
+ if (symbols) {
82863
+ __defProp3(target, Symbol.toStringTag, { value: "Module" });
82864
+ }
82865
+ return target;
82866
+ };
82867
+ var __copyProps3 = (to, from, except, desc) => {
82868
+ if (from && typeof from === "object" || typeof from === "function") {
82869
+ for (var keys = __getOwnPropNames3(from), i = 0, n = keys.length, key; i < n; i++) {
82870
+ key = keys[i];
82871
+ if (!__hasOwnProp3.call(to, key) && key !== except) {
82872
+ __defProp3(to, key, {
82873
+ get: ((k) => from[k]).bind(null, key),
82874
+ enumerable: !(desc = __getOwnPropDesc3(from, key)) || desc.enumerable
82875
+ });
82876
+ }
82877
+ }
82878
+ }
82879
+ return to;
82880
+ };
82881
+ var __toESM3 = (mod, isNodeMode, target) => (target = mod != null ? __create3(__getProtoOf3(mod)) : {}, __copyProps3(isNodeMode || !mod || !mod.__esModule ? __defProp3(target, "default", {
82882
+ value: mod,
82883
+ enumerable: true
82884
+ }) : target, mod));
82885
+
82886
+ // ../../node_modules/@modelcontextprotocol/server/dist/dialects-DoSzNhcb.mjs
82887
+ var DRAFT_2020_12_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft/2020-12/schema", "http://json-schema.org/draft/2020-12/schema"]);
82888
+ var DRAFT_2019_09_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft/2019-09/schema", "http://json-schema.org/draft/2019-09/schema"]);
82889
+ var DRAFT_07_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft-07/schema", "http://json-schema.org/draft-07/schema"]);
82890
+ var DRAFT_06_URIS2 = /* @__PURE__ */ new Set(["https://json-schema.org/draft-06/schema", "http://json-schema.org/draft-06/schema"]);
82891
+ function declares2019Dialect2($schema) {
82892
+ return typeof $schema === "string" && DRAFT_2019_09_URIS2.has($schema.replace(/#$/, ""));
82893
+ }
82894
+ function declaredDialect2(schema, remedy) {
82895
+ if (!("$schema" in schema) || typeof schema.$schema !== "string") return "2020-12";
82896
+ const declared = schema.$schema.replace(/#$/, "");
82897
+ if (DRAFT_2020_12_URIS2.has(declared)) return "2020-12";
82898
+ if (DRAFT_2019_09_URIS2.has(declared)) return "2019-09";
82899
+ if (DRAFT_07_URIS2.has(declared) || DRAFT_06_URIS2.has(declared)) return "draft-7";
82900
+ throw new Error(`JSON Schema declares an unsupported dialect ("$schema": "${schema.$schema.slice(0, 200)}"). The default validator supports JSON Schema 2020-12, 2019-09, draft-07, and draft-06; ${remedy}`);
82901
+ }
82902
+
82903
+ // ../../node_modules/@modelcontextprotocol/server/dist/src-CX2iR2pK.mjs
82904
+ var BRANDS2 = /* @__PURE__ */ Symbol.for("mcp.sdk.errorBrands");
82905
+ function stampErrorBrands2(instance, ctor) {
82906
+ const brands = /* @__PURE__ */ new Set();
82907
+ let current = ctor;
82908
+ while (typeof current === "function") {
82909
+ const brand = current.mcpBrand;
82910
+ if (Object.prototype.hasOwnProperty.call(current, "mcpBrand") && typeof brand === "string") brands.add(brand);
82911
+ current = Object.getPrototypeOf(current);
82912
+ }
82913
+ if (brands.size === 0) return;
82914
+ Object.defineProperty(instance, BRANDS2, {
82915
+ value: brands,
82916
+ enumerable: false,
82917
+ configurable: true
82918
+ });
82919
+ }
82920
+ function brandedHasInstance2(cls, value2) {
82921
+ try {
82922
+ if (typeof value2 === "object" && value2 !== null && Object.prototype.hasOwnProperty.call(cls, "mcpBrand") && typeof cls.mcpBrand === "string" && Object.prototype.hasOwnProperty.call(value2, BRANDS2)) {
82923
+ const carried = value2[BRANDS2];
82924
+ if (carried && typeof carried.has === "function" && carried.has(cls.mcpBrand)) return true;
82925
+ }
82926
+ } catch {
82927
+ }
82928
+ return Function.prototype[Symbol.hasInstance].call(cls, value2);
82929
+ }
82930
+ var OAuthError3 = class OAuthError4 extends Error {
82931
+ static {
82306
82932
  Object.defineProperty(this, "mcpBrand", { value: "mcp.OAuthError" });
82307
82933
  }
82308
82934
  static [Symbol.hasInstance](value2) {
@@ -94584,27 +95210,27 @@ async function runMcpStdioProxy(env = process.env, local = new StdioServerTransp
94584
95210
 
94585
95211
  // src/native-hook-command.ts
94586
95212
  var import_node_crypto21 = require("crypto");
94587
- var import_node_fs26 = require("fs");
94588
- var import_node_os16 = require("os");
94589
- var import_node_path28 = require("path");
95213
+ var import_node_fs27 = require("fs");
95214
+ var import_node_os17 = require("os");
95215
+ var import_node_path29 = require("path");
94590
95216
 
94591
95217
  // src/native-project-config.ts
94592
- var import_node_fs25 = require("fs");
94593
- var import_node_path27 = require("path");
95218
+ var import_node_fs26 = require("fs");
95219
+ var import_node_path28 = require("path");
94594
95220
  var MAX_ALAN_PROJECT_CONFIG_BYTES = 64 * 1024;
94595
95221
  var ORGANIZATION_SLUG_PATTERN = /^[a-z0-9-]+$/;
94596
95222
  var TEAM_IDENTIFIER_PATTERN = /^[A-Z0-9]{2,4}$/i;
94597
95223
  function readAlanProjectPin(cwd) {
94598
95224
  let fd;
94599
95225
  try {
94600
- fd = (0, import_node_fs25.openSync)(
94601
- (0, import_node_path27.join)(cwd, "alan.json"),
94602
- import_node_fs25.constants.O_RDONLY | import_node_fs25.constants.O_NONBLOCK | (import_node_fs25.constants.O_NOFOLLOW ?? 0)
95226
+ fd = (0, import_node_fs26.openSync)(
95227
+ (0, import_node_path28.join)(cwd, "alan.json"),
95228
+ import_node_fs26.constants.O_RDONLY | import_node_fs26.constants.O_NONBLOCK | (import_node_fs26.constants.O_NOFOLLOW ?? 0)
94603
95229
  );
94604
- const stat2 = (0, import_node_fs25.fstatSync)(fd);
95230
+ const stat2 = (0, import_node_fs26.fstatSync)(fd);
94605
95231
  if (!stat2.isFile() || stat2.size > MAX_ALAN_PROJECT_CONFIG_BYTES) return void 0;
94606
95232
  const buffer = Buffer.allocUnsafe(MAX_ALAN_PROJECT_CONFIG_BYTES + 1);
94607
- const bytesRead = (0, import_node_fs25.readSync)(fd, buffer, 0, buffer.byteLength, 0);
95233
+ const bytesRead = (0, import_node_fs26.readSync)(fd, buffer, 0, buffer.byteLength, 0);
94608
95234
  if (bytesRead > MAX_ALAN_PROJECT_CONFIG_BYTES) return void 0;
94609
95235
  const parsed = JSON.parse(buffer.subarray(0, bytesRead).toString("utf8"));
94610
95236
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
@@ -94620,7 +95246,7 @@ function readAlanProjectPin(cwd) {
94620
95246
  } finally {
94621
95247
  if (fd !== void 0) {
94622
95248
  try {
94623
- (0, import_node_fs25.closeSync)(fd);
95249
+ (0, import_node_fs26.closeSync)(fd);
94624
95250
  } catch {
94625
95251
  }
94626
95252
  }
@@ -94859,19 +95485,19 @@ function nonNegativeIntegerField(payload, ...names) {
94859
95485
  return void 0;
94860
95486
  }
94861
95487
  function resolveCodexSessionIdFromTranscriptPath(transcriptPath) {
94862
- const fileName = (0, import_node_path28.basename)(transcriptPath);
95488
+ const fileName = (0, import_node_path29.basename)(transcriptPath);
94863
95489
  const match = /^rollout-.*-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i.exec(
94864
95490
  fileName
94865
95491
  );
94866
95492
  return match?.[1];
94867
95493
  }
94868
- function resolveKimiTranscriptPath(externalSessionId, kimiHomeDir = process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path28.join)((0, import_node_os16.homedir)(), ".kimi-code")) {
94869
- if ((0, import_node_path28.basename)(externalSessionId) !== externalSessionId) return void 0;
94870
- const sessionsDir = (0, import_node_path28.join)(kimiHomeDir, "sessions");
94871
- if (!(0, import_node_fs26.existsSync)(sessionsDir)) return void 0;
94872
- for (const workspace of (0, import_node_fs26.readdirSync)(sessionsDir, { withFileTypes: true })) {
95494
+ function resolveKimiTranscriptPath(externalSessionId, kimiHomeDir = process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path29.join)((0, import_node_os17.homedir)(), ".kimi-code")) {
95495
+ if ((0, import_node_path29.basename)(externalSessionId) !== externalSessionId) return void 0;
95496
+ const sessionsDir = (0, import_node_path29.join)(kimiHomeDir, "sessions");
95497
+ if (!(0, import_node_fs27.existsSync)(sessionsDir)) return void 0;
95498
+ for (const workspace of (0, import_node_fs27.readdirSync)(sessionsDir, { withFileTypes: true })) {
94873
95499
  if (!workspace.isDirectory()) continue;
94874
- const transcriptPath = (0, import_node_path28.join)(
95500
+ const transcriptPath = (0, import_node_path29.join)(
94875
95501
  sessionsDir,
94876
95502
  workspace.name,
94877
95503
  externalSessionId,
@@ -94879,7 +95505,7 @@ function resolveKimiTranscriptPath(externalSessionId, kimiHomeDir = process.env.
94879
95505
  "main",
94880
95506
  "wire.jsonl"
94881
95507
  );
94882
- if ((0, import_node_fs26.existsSync)(transcriptPath)) return transcriptPath;
95508
+ if ((0, import_node_fs27.existsSync)(transcriptPath)) return transcriptPath;
94883
95509
  }
94884
95510
  return void 0;
94885
95511
  }
@@ -94914,7 +95540,7 @@ function parseNativeHookEnvelope(input2) {
94914
95540
  const rawHookEvent = input2.hookEvent ?? stringField4(payload, "hook_event_name", "hookEvent", "hookEventName", "type") ?? "notification";
94915
95541
  const eventType = normalizeHookEvent(rawHookEvent);
94916
95542
  const cwd = stringField4(payload, "cwd", "working_directory", "workingDirectory") ?? firstStringArrayField(payload, "workspace_roots", "workspaceRoots");
94917
- const resolvedCwd = cwd ? (0, import_node_path28.resolve)(cwd) : void 0;
95543
+ const resolvedCwd = cwd ? (0, import_node_path29.resolve)(cwd) : void 0;
94918
95544
  const transcriptPath = eventType === "subagent_start" || eventType === "subagent_end" ? stringField4(
94919
95545
  payload,
94920
95546
  "agent_transcript_path",
@@ -94960,7 +95586,7 @@ function parseNativeHookEnvelope(input2) {
94960
95586
  ...(eventType === "subagent_start" || eventType === "subagent_end") && parentSessionId ? { parentExternalSessionId: parentSessionId } : {},
94961
95587
  ...resolvedCwd ? { cwd: resolvedCwd } : {},
94962
95588
  ...projectPin,
94963
- ...transcriptPath ? { transcriptPath: (0, import_node_path28.resolve)(transcriptPath) } : {},
95589
+ ...transcriptPath ? { transcriptPath: (0, import_node_path29.resolve)(transcriptPath) } : {},
94964
95590
  ...cursor ? { sourceCursor: cursor } : {},
94965
95591
  providerPayload
94966
95592
  };
@@ -95007,7 +95633,7 @@ function readBoundedHookPayload(fd = 0, maxBytes = MAX_NATIVE_HOOK_STDIN_BYTES)
95007
95633
  let totalBytes = 0;
95008
95634
  while (true) {
95009
95635
  const chunk = Buffer.allocUnsafe(Math.min(64 * 1024, maxBytes + 1 - totalBytes));
95010
- const bytesRead = (0, import_node_fs26.readSync)(fd, chunk, 0, chunk.byteLength, null);
95636
+ const bytesRead = (0, import_node_fs27.readSync)(fd, chunk, 0, chunk.byteLength, null);
95011
95637
  if (bytesRead === 0) break;
95012
95638
  totalBytes += bytesRead;
95013
95639
  if (totalBytes > maxBytes) throw new Error(`hook input exceeds ${maxBytes} bytes`);
@@ -95090,7 +95716,7 @@ function collectNativeIntegrationStatus(args = []) {
95090
95716
  const config2 = readConfig();
95091
95717
  const configPath = getConfigPath();
95092
95718
  const env = getDaemonCliEnvironment();
95093
- const homeDir = (0, import_node_os16.homedir)();
95719
+ const homeDir = (0, import_node_os17.homedir)();
95094
95720
  return NATIVE_SESSION_PROVIDER_CAPABILITIES.map((capability) => ({
95095
95721
  provider: capability.providerKind,
95096
95722
  command: capability.command,
@@ -95119,7 +95745,7 @@ function decodeResumeFallbackContext(encoded) {
95119
95745
  }
95120
95746
 
95121
95747
  // src/sandbox.ts
95122
- var import_node_os17 = require("os");
95748
+ var import_node_os18 = require("os");
95123
95749
 
95124
95750
  // src/execution-activity-tracker.ts
95125
95751
  var ExecutionActivityTracker = class {
@@ -95733,7 +96359,7 @@ var agentProbeAckSchema = external_exports.object({
95733
96359
 
95734
96360
  // src/sandbox-outbox.ts
95735
96361
  var import_node_crypto23 = require("crypto");
95736
- var import_node_fs27 = require("fs");
96362
+ var import_node_fs28 = require("fs");
95737
96363
  function deriveSandboxOutboxKey(sessionToken) {
95738
96364
  if (!sessionToken) {
95739
96365
  throw new Error("sandbox event outbox requires ALAN_SESSION_TOKEN for key derivation");
@@ -95754,24 +96380,24 @@ function assertValidOutboxKey(key, path2) {
95754
96380
  }
95755
96381
  function loadOrCreateSandboxOutboxKey(input2) {
95756
96382
  const keyPath = sandboxOutboxKeyPath(input2.spoolPath);
95757
- if ((0, import_node_fs27.existsSync)(keyPath)) {
95758
- (0, import_node_fs27.chmodSync)(keyPath, 384);
95759
- return assertValidOutboxKey((0, import_node_fs27.readFileSync)(keyPath, "utf8").trim(), keyPath);
96383
+ if ((0, import_node_fs28.existsSync)(keyPath)) {
96384
+ (0, import_node_fs28.chmodSync)(keyPath, 384);
96385
+ return assertValidOutboxKey((0, import_node_fs28.readFileSync)(keyPath, "utf8").trim(), keyPath);
95760
96386
  }
95761
96387
  const initialKey = deriveSandboxOutboxKey(input2.sessionToken);
95762
96388
  try {
95763
- (0, import_node_fs27.writeFileSync)(keyPath, initialKey, { encoding: "utf8", flag: "wx", mode: 384 });
96389
+ (0, import_node_fs28.writeFileSync)(keyPath, initialKey, { encoding: "utf8", flag: "wx", mode: 384 });
95764
96390
  return initialKey;
95765
96391
  } catch (error61) {
95766
96392
  if (error61.code !== "EEXIST") throw error61;
95767
- (0, import_node_fs27.chmodSync)(keyPath, 384);
95768
- return assertValidOutboxKey((0, import_node_fs27.readFileSync)(keyPath, "utf8").trim(), keyPath);
96393
+ (0, import_node_fs28.chmodSync)(keyPath, 384);
96394
+ return assertValidOutboxKey((0, import_node_fs28.readFileSync)(keyPath, "utf8").trim(), keyPath);
95769
96395
  }
95770
96396
  }
95771
96397
  function quarantineUnusableOutbox(path2) {
95772
96398
  const suffix = `corrupt-${Date.now()}-${process.pid}`;
95773
96399
  for (const candidate of [path2, eventJournalDir(path2)]) {
95774
- if ((0, import_node_fs27.existsSync)(candidate)) (0, import_node_fs27.renameSync)(candidate, `${candidate}.${suffix}`);
96400
+ if ((0, import_node_fs28.existsSync)(candidate)) (0, import_node_fs28.renameSync)(candidate, `${candidate}.${suffix}`);
95775
96401
  }
95776
96402
  }
95777
96403
  function createSandboxEventOutbox(input2) {
@@ -96431,7 +97057,7 @@ async function runSandbox(config2) {
96431
97057
  }
96432
97058
  const presenter = new WebPresenter(wsClient, config2.sessionId, config2.projectPath);
96433
97059
  presenter.setSuppressSessionLifecycle(true);
96434
- const runtimeSkillManager = await RuntimeSkillManager.open({ homeDirectory: (0, import_node_os17.homedir)() });
97060
+ const runtimeSkillManager = await RuntimeSkillManager.open({ homeDirectory: (0, import_node_os18.homedir)() });
96435
97061
  let lastProviderSessionId = config2.providerSessionId;
96436
97062
  let resumeFallbackContext = config2.resumeFallbackContext;
96437
97063
  let activeBackendKind = config2.backendKind || "claude_cli";
@@ -96728,616 +97354,6 @@ async function runSandbox(config2) {
96728
97354
  wsClient.close();
96729
97355
  }
96730
97356
 
96731
- // src/service-manager.ts
96732
- var import_node_child_process9 = require("child_process");
96733
- var import_node_fs28 = require("fs");
96734
- var import_node_os18 = require("os");
96735
- var import_node_path29 = require("path");
96736
- var SERVICE_LABEL = "ai.tryalan.agent";
96737
- var SYSTEMD_UNIT = "alan-agent.service";
96738
- var WINDOWS_TASK = "Alan Agent";
96739
- function xml(value2) {
96740
- return value2.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
96741
- }
96742
- function systemdArg(value2) {
96743
- return `"${value2.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
96744
- }
96745
- function powershellLiteral(value2) {
96746
- return `'${value2.replaceAll("'", "''")}'`;
96747
- }
96748
- function serviceNames(profile) {
96749
- if (profile === "production") {
96750
- return { launchd: SERVICE_LABEL, systemd: SYSTEMD_UNIT, windows: WINDOWS_TASK };
96751
- }
96752
- const suffix = profile === "custom" ? "prod" : profile;
96753
- const title = `${suffix[0]?.toUpperCase()}${suffix.slice(1)}`;
96754
- return {
96755
- launchd: `${SERVICE_LABEL}.${suffix}`,
96756
- systemd: `alan-agent-${suffix}.service`,
96757
- windows: `${WINDOWS_TASK} ${title}`
96758
- };
96759
- }
96760
- function buildDaemonServicePlan(input2) {
96761
- const daemonArgs = [input2.nodeExecutable, input2.cliEntry, "daemon", "--profile", input2.profile];
96762
- const names = serviceNames(input2.profile);
96763
- if (input2.platform === "darwin") {
96764
- const userId = input2.userId ?? process.getuid?.();
96765
- if (userId === void 0) throw new Error("Cannot determine the current macOS user ID");
96766
- const domain2 = `gui/${userId}`;
96767
- const serviceTarget = `${domain2}/${names.launchd}`;
96768
- const manifestPath = (0, import_node_path29.join)(input2.homeDir, "Library", "LaunchAgents", `${names.launchd}.plist`);
96769
- const logDir = (0, import_node_path29.join)(resolveAgentConfigDirectory(input2.profile, input2.homeDir), "logs");
96770
- const programArguments = daemonArgs.map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
96771
- const environmentEntries = Object.entries(input2.environment ?? {}).map(([key, value2]) => ` <key>${xml(key)}</key>
96772
- <string>${xml(value2)}</string>`).join("\n");
96773
- const environmentBlock = environmentEntries ? ` <key>EnvironmentVariables</key>
96774
- <dict>
96775
- ${environmentEntries}
96776
- </dict>
96777
- ` : "";
96778
- const manifest = `<?xml version="1.0" encoding="UTF-8"?>
96779
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
96780
- <plist version="1.0">
96781
- <dict>
96782
- <key>Label</key>
96783
- <string>${names.launchd}</string>
96784
- <key>ProgramArguments</key>
96785
- <array>
96786
- ${programArguments}
96787
- </array>
96788
- ${environmentBlock} <key>RunAtLoad</key>
96789
- <true/>
96790
- <key>KeepAlive</key>
96791
- <dict>
96792
- <key>SuccessfulExit</key>
96793
- <false/>
96794
- </dict>
96795
- <key>ThrottleInterval</key>
96796
- <integer>5</integer>
96797
- <key>StandardOutPath</key>
96798
- <string>${xml((0, import_node_path29.join)(logDir, "daemon.log"))}</string>
96799
- <key>StandardErrorPath</key>
96800
- <string>${xml((0, import_node_path29.join)(logDir, "daemon-error.log"))}</string>
96801
- </dict>
96802
- </plist>
96803
- `;
96804
- return {
96805
- platform: "darwin",
96806
- manifestPath,
96807
- manifest,
96808
- logDirectory: logDir,
96809
- loadDefinitionCommands: [
96810
- {
96811
- command: "launchctl",
96812
- args: ["bootstrap", domain2, manifestPath],
96813
- tolerateFailure: true
96814
- }
96815
- ],
96816
- reloadDefinitionCommands: [
96817
- {
96818
- command: "launchctl",
96819
- args: ["bootout", domain2, manifestPath],
96820
- tolerateFailure: true
96821
- },
96822
- {
96823
- command: "launchctl",
96824
- args: ["bootstrap", domain2, manifestPath],
96825
- tolerateFailure: false
96826
- }
96827
- ],
96828
- enableCommands: [
96829
- {
96830
- command: "launchctl",
96831
- args: ["enable", serviceTarget],
96832
- tolerateFailure: true
96833
- }
96834
- ],
96835
- startCommands: [
96836
- {
96837
- command: "launchctl",
96838
- args: ["kickstart", serviceTarget],
96839
- tolerateFailure: false
96840
- }
96841
- ],
96842
- stopCommands: [
96843
- {
96844
- command: "launchctl",
96845
- args: ["kill", "SIGTERM", serviceTarget],
96846
- tolerateFailure: true
96847
- }
96848
- ],
96849
- replaceCommands: [
96850
- {
96851
- command: "launchctl",
96852
- args: ["bootout", domain2, manifestPath],
96853
- tolerateFailure: true
96854
- },
96855
- {
96856
- command: "launchctl",
96857
- args: ["bootstrap", domain2, manifestPath],
96858
- tolerateFailure: false
96859
- },
96860
- {
96861
- command: "launchctl",
96862
- args: ["kickstart", "-k", serviceTarget],
96863
- tolerateFailure: false
96864
- }
96865
- ],
96866
- uninstallCommands: [
96867
- {
96868
- command: "launchctl",
96869
- args: ["bootout", domain2, manifestPath],
96870
- tolerateFailure: true
96871
- }
96872
- ],
96873
- statusCommand: {
96874
- command: "launchctl",
96875
- args: ["print", serviceTarget],
96876
- tolerateFailure: true
96877
- },
96878
- isActiveCommand: {
96879
- command: "launchctl",
96880
- args: ["print", serviceTarget],
96881
- tolerateFailure: true
96882
- },
96883
- lingerStatusCommand: null
96884
- };
96885
- }
96886
- if (input2.platform === "linux") {
96887
- const manifestPath = (0, import_node_path29.join)(input2.homeDir, ".config", "systemd", "user", names.systemd);
96888
- const environmentLines = Object.entries(input2.environment ?? {}).map(([key, value2]) => `Environment=${systemdArg(`${key}=${value2}`)}`).join("\n");
96889
- const manifest = `[Unit]
96890
- Description=Alan local agent daemon
96891
- After=network-online.target
96892
- Wants=network-online.target
96893
- StartLimitIntervalSec=300
96894
- StartLimitBurst=3
96895
-
96896
- [Service]
96897
- Type=simple
96898
- ${environmentLines ? `${environmentLines}
96899
- ` : ""}ExecStart=${daemonArgs.map(systemdArg).join(" ")}
96900
- Restart=on-failure
96901
- RestartSec=5
96902
-
96903
- [Install]
96904
- WantedBy=default.target
96905
- `;
96906
- return {
96907
- platform: "linux",
96908
- manifestPath,
96909
- manifest,
96910
- logDirectory: null,
96911
- loadDefinitionCommands: [
96912
- {
96913
- command: "systemctl",
96914
- args: ["--user", "daemon-reload"],
96915
- tolerateFailure: false
96916
- }
96917
- ],
96918
- reloadDefinitionCommands: [
96919
- {
96920
- command: "systemctl",
96921
- args: ["--user", "daemon-reload"],
96922
- tolerateFailure: false
96923
- }
96924
- ],
96925
- enableCommands: [
96926
- {
96927
- command: "systemctl",
96928
- args: ["--user", "enable", names.systemd],
96929
- tolerateFailure: false
96930
- }
96931
- ],
96932
- startCommands: [
96933
- {
96934
- command: "systemctl",
96935
- args: ["--user", "start", names.systemd],
96936
- tolerateFailure: false
96937
- }
96938
- ],
96939
- stopCommands: [
96940
- {
96941
- command: "systemctl",
96942
- args: ["--user", "stop", names.systemd],
96943
- tolerateFailure: true
96944
- }
96945
- ],
96946
- replaceCommands: [
96947
- {
96948
- command: "systemctl",
96949
- args: ["--user", "daemon-reload"],
96950
- tolerateFailure: false
96951
- },
96952
- {
96953
- command: "systemctl",
96954
- args: ["--user", "restart", names.systemd],
96955
- tolerateFailure: false
96956
- }
96957
- ],
96958
- uninstallCommands: [
96959
- {
96960
- command: "systemctl",
96961
- args: ["--user", "disable", "--now", names.systemd],
96962
- tolerateFailure: true
96963
- },
96964
- {
96965
- command: "systemctl",
96966
- args: ["--user", "daemon-reload"],
96967
- tolerateFailure: false
96968
- }
96969
- ],
96970
- statusCommand: {
96971
- command: "systemctl",
96972
- args: ["--user", "status", names.systemd, "--no-pager"],
96973
- tolerateFailure: true
96974
- },
96975
- isActiveCommand: {
96976
- command: "systemctl",
96977
- args: ["--user", "is-active", names.systemd],
96978
- tolerateFailure: true
96979
- },
96980
- lingerStatusCommand: {
96981
- command: "loginctl",
96982
- args: ["show-user", "$(id -un)", "-p", "Linger"],
96983
- tolerateFailure: true
96984
- }
96985
- };
96986
- }
96987
- const environmentPrefix = Object.entries(input2.environment ?? {}).map(([key, value2]) => `$env:${key} = ${powershellLiteral(value2)}`).join("; ");
96988
- const directArgument = [input2.cliEntry, "daemon", "--profile", input2.profile].map((part) => part.includes(" ") ? `"${part}"` : part).join(" ");
96989
- const executable = powershellLiteral(environmentPrefix ? "powershell.exe" : input2.nodeExecutable);
96990
- const argument = powershellLiteral(
96991
- environmentPrefix ? `-NoProfile -NonInteractive -WindowStyle Hidden -Command "${environmentPrefix}; & ${powershellLiteral(input2.nodeExecutable)} ${powershellLiteral(input2.cliEntry)} daemon --profile ${input2.profile}"` : directArgument
96992
- );
96993
- const registerScript = [
96994
- "$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name",
96995
- `$action = New-ScheduledTaskAction -Execute ${executable} -Argument ${argument}`,
96996
- "$trigger = New-ScheduledTaskTrigger -AtLogOn -User $currentUser",
96997
- "$principal = New-ScheduledTaskPrincipal -UserId $currentUser -LogonType Interactive -RunLevel Limited",
96998
- "$settings = New-ScheduledTaskSettingsSet -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1) -ExecutionTimeLimit ([TimeSpan]::Zero)",
96999
- `Register-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force | Out-Null`
97000
- ].join("; ");
97001
- return {
97002
- platform: "win32",
97003
- manifestPath: null,
97004
- manifest: null,
97005
- logDirectory: null,
97006
- loadDefinitionCommands: [
97007
- {
97008
- command: "powershell.exe",
97009
- args: ["-NoProfile", "-NonInteractive", "-Command", registerScript],
97010
- tolerateFailure: false
97011
- }
97012
- ],
97013
- reloadDefinitionCommands: [
97014
- {
97015
- command: "powershell.exe",
97016
- args: ["-NoProfile", "-NonInteractive", "-Command", registerScript],
97017
- tolerateFailure: false
97018
- }
97019
- ],
97020
- enableCommands: [],
97021
- startCommands: [
97022
- {
97023
- command: "powershell.exe",
97024
- args: [
97025
- "-NoProfile",
97026
- "-NonInteractive",
97027
- "-Command",
97028
- `Start-ScheduledTask -TaskName ${powershellLiteral(names.windows)}`
97029
- ],
97030
- tolerateFailure: false
97031
- }
97032
- ],
97033
- stopCommands: [
97034
- {
97035
- command: "powershell.exe",
97036
- args: [
97037
- "-NoProfile",
97038
- "-NonInteractive",
97039
- "-Command",
97040
- `Stop-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -ErrorAction SilentlyContinue`
97041
- ],
97042
- tolerateFailure: true
97043
- }
97044
- ],
97045
- replaceCommands: [
97046
- {
97047
- command: "powershell.exe",
97048
- args: [
97049
- "-NoProfile",
97050
- "-NonInteractive",
97051
- "-Command",
97052
- `${registerScript}; Start-ScheduledTask -TaskName ${powershellLiteral(names.windows)}`
97053
- ],
97054
- tolerateFailure: false
97055
- }
97056
- ],
97057
- uninstallCommands: [
97058
- {
97059
- command: "powershell.exe",
97060
- args: [
97061
- "-NoProfile",
97062
- "-NonInteractive",
97063
- "-Command",
97064
- `Unregister-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -Confirm:$false -ErrorAction SilentlyContinue`
97065
- ],
97066
- tolerateFailure: true
97067
- }
97068
- ],
97069
- statusCommand: {
97070
- command: "powershell.exe",
97071
- args: [
97072
- "-NoProfile",
97073
- "-NonInteractive",
97074
- "-Command",
97075
- `Get-ScheduledTask -TaskName ${powershellLiteral(names.windows)} | Format-List TaskName,State`
97076
- ],
97077
- tolerateFailure: true
97078
- },
97079
- isActiveCommand: {
97080
- command: "powershell.exe",
97081
- args: [
97082
- "-NoProfile",
97083
- "-NonInteractive",
97084
- "-Command",
97085
- `(Get-ScheduledTask -TaskName ${powershellLiteral(names.windows)} -ErrorAction SilentlyContinue).State`
97086
- ],
97087
- tolerateFailure: true
97088
- },
97089
- lingerStatusCommand: null
97090
- };
97091
- }
97092
- function resolveCurrentPlatform() {
97093
- const currentPlatform = (0, import_node_os18.platform)();
97094
- if (currentPlatform !== "darwin" && currentPlatform !== "linux" && currentPlatform !== "win32") {
97095
- throw new Error(`Daemon service installation is not supported on ${currentPlatform}`);
97096
- }
97097
- return currentPlatform;
97098
- }
97099
- function currentServicePlan(args, runtime) {
97100
- const currentPlatform = resolveCurrentPlatform();
97101
- const profile = resolveEndpointProfileFromArgs(args);
97102
- const cliEntry = runtime?.cliEntry ?? process.argv[1];
97103
- if (!cliEntry) throw new Error("Cannot determine the alan-agent executable path");
97104
- return buildDaemonServicePlan({
97105
- platform: currentPlatform,
97106
- homeDir: (0, import_node_os18.homedir)(),
97107
- nodeExecutable: runtime?.executable ?? process.execPath,
97108
- cliEntry: (0, import_node_path29.resolve)(cliEntry),
97109
- profile,
97110
- environment: runtime?.environment
97111
- });
97112
- }
97113
- function writeManifestAtomic(path2, contents) {
97114
- (0, import_node_fs28.mkdirSync)((0, import_node_path29.dirname)(path2), { recursive: true, mode: 448 });
97115
- const pendingPath = `${path2}.pending-${process.pid}`;
97116
- try {
97117
- (0, import_node_fs28.writeFileSync)(pendingPath, contents, { mode: 384 });
97118
- (0, import_node_fs28.chmodSync)(pendingPath, 384);
97119
- (0, import_node_fs28.renameSync)(pendingPath, path2);
97120
- } finally {
97121
- (0, import_node_fs28.rmSync)(pendingPath, { force: true });
97122
- }
97123
- }
97124
- function defaultReadManifest(path2) {
97125
- if (!(0, import_node_fs28.existsSync)(path2)) return null;
97126
- return (0, import_node_fs28.readFileSync)(path2, "utf8");
97127
- }
97128
- function runServiceCommand(command) {
97129
- const result = (0, import_node_child_process9.spawnSync)(command.command, command.args, { encoding: "utf8", shell: false });
97130
- const status = result.status ?? 1;
97131
- const output2 = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
97132
- if (status !== 0 && !command.tolerateFailure) {
97133
- throw new Error(
97134
- `Service command failed (${command.command} ${command.args.join(" ")}): ${output2 || `exit ${status}`}`
97135
- );
97136
- }
97137
- return { status, output: output2 };
97138
- }
97139
- function defaultSleep(ms) {
97140
- return new Promise((resolveSleep) => {
97141
- setTimeout(resolveSleep, ms);
97142
- });
97143
- }
97144
- function parseServiceHostState(servicePlatform, result) {
97145
- const output2 = result.output;
97146
- if (servicePlatform === "linux") {
97147
- const trimmed = output2.trim().toLowerCase();
97148
- if (trimmed === "inactive" || trimmed === "failed" || trimmed === "dead" || /\binactive\b/i.test(output2) || /\bfailed\b/i.test(output2)) {
97149
- return "stopped";
97150
- }
97151
- }
97152
- if (result.status !== 0) return "unknown";
97153
- if (servicePlatform === "darwin") {
97154
- if (/\bstate\s*=\s*running\b/i.test(output2)) return "running";
97155
- if (/\bstate\s*=\s*(not running|waiting|stopped)\b/i.test(output2)) return "stopped";
97156
- if (/\bpid\s*=\s*[1-9]\d*\b/i.test(output2)) return "running";
97157
- if (/could not find service/i.test(output2)) return "stopped";
97158
- return "unknown";
97159
- }
97160
- if (servicePlatform === "linux") {
97161
- const trimmed = output2.trim().toLowerCase();
97162
- if (trimmed === "active" || /\bactive\s*\(running\)/i.test(output2)) return "running";
97163
- if (trimmed === "activating" || trimmed === "reloading") return "starting";
97164
- return "unknown";
97165
- }
97166
- const stateMatch = output2.match(/\b(?:State|state)\s*[:=]\s*(\w+)/);
97167
- const state = (stateMatch?.[1] ?? output2.trim()).toLowerCase();
97168
- if (state === "running") return "running";
97169
- if (state === "ready" || state === "disabled" || state === "queued") return "stopped";
97170
- return "unknown";
97171
- }
97172
- function resolveEnsureDefinitionOutcome(input2) {
97173
- if (!input2.definitionChanged) {
97174
- return { changed: false, updatePending: false };
97175
- }
97176
- if (input2.hostState === "running" || input2.hostState === "starting") {
97177
- return { changed: true, updatePending: true };
97178
- }
97179
- return { changed: true, updatePending: false };
97180
- }
97181
- function shouldStartOnInstall(hostState) {
97182
- return hostState === "stopped";
97183
- }
97184
- function resolveUsername(options) {
97185
- if (options?.username) return options.username;
97186
- try {
97187
- return (0, import_node_os18.userInfo)().username;
97188
- } catch {
97189
- return process.env.USER || process.env.USERNAME || "unknown";
97190
- }
97191
- }
97192
- function buildLingerStatusCommand(username) {
97193
- return {
97194
- command: "loginctl",
97195
- args: ["show-user", username, "-p", "Linger"],
97196
- tolerateFailure: true
97197
- };
97198
- }
97199
- function assertSystemdUserLingerEnabled(options = {}) {
97200
- const username = resolveUsername(options);
97201
- const run = options.runCommand ?? runServiceCommand;
97202
- const result = run(buildLingerStatusCommand(username));
97203
- if (result.status !== 0) {
97204
- throw new Error(
97205
- `Cannot verify systemd user linger for ${username} (loginctl failed). For durable headless VM boot run: sudo loginctl enable-linger ${username}`
97206
- );
97207
- }
97208
- if (!/Linger=yes/i.test(result.output)) {
97209
- throw new Error(
97210
- `systemd user linger is disabled for ${username}. For durable headless VM boot run: sudo loginctl enable-linger ${username}`
97211
- );
97212
- }
97213
- }
97214
- function createHostContext(options = {}) {
97215
- const args = options.args ?? [];
97216
- const plan = currentServicePlan(args, options.runtime);
97217
- const run = options.runCommand ?? runServiceCommand;
97218
- const sleep4 = options.sleep ?? defaultSleep;
97219
- const nowMs = options.nowMs ?? Date.now;
97220
- const readManifest = options.readManifest ?? defaultReadManifest;
97221
- const writeManifest = options.writeManifest ?? writeManifestAtomic;
97222
- const removeManifest = options.removeManifest ?? ((path2) => (0, import_node_fs28.rmSync)(path2, { force: true }));
97223
- const ensureLogDir = options.ensureLogDir ?? (() => {
97224
- if (plan.logDirectory) (0, import_node_fs28.mkdirSync)(plan.logDirectory, { recursive: true, mode: 448 });
97225
- });
97226
- return {
97227
- args,
97228
- plan,
97229
- run,
97230
- sleep: sleep4,
97231
- nowMs,
97232
- readManifest,
97233
- writeManifest,
97234
- removeManifest,
97235
- ensureLogDir,
97236
- profile: resolveEndpointProfileFromArgs(args)
97237
- };
97238
- }
97239
- function inspectDaemonService(options = {}) {
97240
- const { plan, run, nowMs } = createHostContext(options);
97241
- const result = run(plan.isActiveCommand);
97242
- const state = parseServiceHostState(plan.platform, result);
97243
- return {
97244
- state,
97245
- platform: plan.platform,
97246
- detail: result.output || void 0,
97247
- observedAtMs: nowMs()
97248
- };
97249
- }
97250
- function ensureDaemonServiceDefinition(options = {}) {
97251
- const ctx = createHostContext(options);
97252
- const { plan, run, readManifest, writeManifest, ensureLogDir } = ctx;
97253
- let definitionChanged = false;
97254
- if (plan.manifestPath && plan.manifest) {
97255
- ensureLogDir();
97256
- const existing = readManifest(plan.manifestPath);
97257
- definitionChanged = existing !== plan.manifest;
97258
- if (definitionChanged) {
97259
- writeManifest(plan.manifestPath, plan.manifest);
97260
- }
97261
- } else if (plan.platform === "win32") {
97262
- definitionChanged = true;
97263
- }
97264
- const inspection = inspectDaemonService(options);
97265
- const outcome = resolveEnsureDefinitionOutcome({
97266
- definitionChanged,
97267
- hostState: inspection.state
97268
- });
97269
- if (outcome.updatePending) {
97270
- return outcome;
97271
- }
97272
- if (inspection.state === "running" || inspection.state === "starting") {
97273
- return outcome;
97274
- }
97275
- const definitionCommands = inspection.state === "stopped" ? plan.reloadDefinitionCommands : plan.loadDefinitionCommands;
97276
- for (const command of definitionCommands) run(command);
97277
- return outcome;
97278
- }
97279
- function enableDaemonService(options = {}) {
97280
- const { plan, run } = createHostContext(options);
97281
- for (const command of plan.enableCommands) run(command);
97282
- }
97283
- function startDaemonService(options = {}) {
97284
- const { plan, run } = createHostContext(options);
97285
- for (const command of plan.startCommands) run(command);
97286
- }
97287
- function uninstallDaemonService(args = [], options = {}) {
97288
- const ctx = createHostContext({ ...options, args: options.args ?? args });
97289
- for (const command of ctx.plan.uninstallCommands) ctx.run(command);
97290
- if (ctx.plan.manifestPath) ctx.removeManifest(ctx.plan.manifestPath);
97291
- console.info("[alan-agent] Per-user daemon service removed");
97292
- }
97293
- function installDaemonService(args = [], runtime, options = {}) {
97294
- const profile = resolveEndpointProfileFromArgs(args);
97295
- const configPath = resolveAgentConfigPath({ profile });
97296
- if (!configExistsAtPath(configPath)) {
97297
- throw new Error(`No ${profile} runtime is configured. Run alan-agent setup or login first.`);
97298
- }
97299
- const headless = options.headless ?? args.includes("--headless");
97300
- const merged = { ...options, args, runtime, headless };
97301
- const ctx = createHostContext(merged);
97302
- if (headless) {
97303
- if (ctx.plan.platform !== "linux") {
97304
- throw new Error("--headless is only supported on Linux systemd user services");
97305
- }
97306
- assertSystemdUserLingerEnabled(merged);
97307
- }
97308
- const ensured = ensureDaemonServiceDefinition(merged);
97309
- enableDaemonService(merged);
97310
- const inspection = inspectDaemonService(merged);
97311
- if (ensured.updatePending) {
97312
- console.info("[alan-agent] Daemon service definition update pending; leaving running service", {
97313
- profile,
97314
- state: inspection.state
97315
- });
97316
- return;
97317
- }
97318
- if (!shouldStartOnInstall(inspection.state)) {
97319
- console.info("[alan-agent] Per-user daemon service already present", {
97320
- profile,
97321
- state: inspection.state
97322
- });
97323
- return;
97324
- }
97325
- startDaemonService(merged);
97326
- console.info("[alan-agent] Per-user daemon service installed", { profile });
97327
- }
97328
- function printDaemonServiceStatus(args = []) {
97329
- const plan = currentServicePlan(args);
97330
- const result = runServiceCommand({ ...plan.statusCommand, tolerateFailure: true });
97331
- if (result.status !== 0) {
97332
- process.stdout.write(`unknown
97333
- ${result.output}
97334
- `);
97335
- return;
97336
- }
97337
- process.stdout.write(`${result.output}
97338
- `);
97339
- }
97340
-
97341
97357
  // src/skills/skill-cli.ts
97342
97358
  var import_promises6 = require("fs/promises");
97343
97359
  var import_node_os19 = require("os");
@@ -97536,13 +97552,7 @@ async function main() {
97536
97552
  return;
97537
97553
  }
97538
97554
  if (command === "install") {
97539
- bindConfigPath(commandArgs);
97540
- const configured = readConfig();
97541
- const configurationMode = resolveInstallConfigurationMode(commandArgs, configured);
97542
- const setup = configurationMode === "setup" ? await setupDaemon(commandArgs) : null;
97543
- if (configurationMode === "login") await loginWithDeviceCode(commandArgs);
97544
- if (!setup?.daemonAlreadyRunning) installDaemonService(commandArgs);
97545
- runMcpIntegrationCommand(["reconcile", ...commandArgs]);
97555
+ await runInstallCommand(commandArgs);
97546
97556
  return;
97547
97557
  }
97548
97558
  if (command === "login") {