@alan-ai-hq/agent-manager 0.1.88 → 0.1.89

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 +328 -173
  2. package/package.json +2 -3
package/dist/index.cjs CHANGED
@@ -15180,7 +15180,7 @@ function resolveCommand(args, env) {
15180
15180
 
15181
15181
  // src/daemon.ts
15182
15182
  var import_node_crypto19 = require("crypto");
15183
- var import_node_os12 = require("os");
15183
+ var import_node_os13 = require("os");
15184
15184
 
15185
15185
  // src/sleep-inhibitor.ts
15186
15186
  var import_node_child_process2 = require("child_process");
@@ -15447,7 +15447,7 @@ function describeError(error61) {
15447
15447
  }
15448
15448
 
15449
15449
  // src/version.ts
15450
- var AGENT_VERSION = "0.1.88";
15450
+ var AGENT_VERSION = "0.1.89";
15451
15451
 
15452
15452
  // src/daemon-worktree.ts
15453
15453
  var import_node_child_process3 = require("child_process");
@@ -19549,9 +19549,9 @@ var asciiTabOrNewline = /[\t\n\r]/g;
19549
19549
  function stripTabAndNewline(value2) {
19550
19550
  return value2.replace(asciiTabOrNewline, "");
19551
19551
  }
19552
- function urlHostnameOk(url3, hostname4) {
19553
- hostname4.lastIndex = 0;
19554
- return hostname4.test(url3.hostname);
19552
+ function urlHostnameOk(url3, hostname5) {
19553
+ hostname5.lastIndex = 0;
19554
+ return hostname5.test(url3.hostname);
19555
19555
  }
19556
19556
  function urlProtocolOk(url3, protocol4) {
19557
19557
  protocol4.lastIndex = 0;
@@ -50894,7 +50894,7 @@ function scheduleRuntimeModelScan(getBaseMetadata, options) {
50894
50894
  var import_node_crypto18 = require("crypto");
50895
50895
  var import_node_fs22 = require("fs");
50896
50896
  var import_node_http = __toESM(require("http"), 1);
50897
- var import_node_os11 = require("os");
50897
+ var import_node_os12 = require("os");
50898
50898
  var import_node_path24 = require("path");
50899
50899
 
50900
50900
  // ../../node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.node.js
@@ -51480,8 +51480,8 @@ var Transport = class extends Emitter {
51480
51480
  return schema + "://" + this._hostname() + this._port() + this.opts.path + this._query(query);
51481
51481
  }
51482
51482
  _hostname() {
51483
- const hostname4 = this.opts.hostname;
51484
- return hostname4.indexOf(":") === -1 ? hostname4 : "[" + hostname4 + "]";
51483
+ const hostname5 = this.opts.hostname;
51484
+ return hostname5.indexOf(":") === -1 ? hostname5 : "[" + hostname5 + "]";
51485
51485
  }
51486
51486
  _port() {
51487
51487
  if (this.opts.port && (this.opts.secure && Number(this.opts.port) !== 443 || !this.opts.secure && Number(this.opts.port) !== 80)) {
@@ -70429,8 +70429,8 @@ function applyPostAuth(clientId, clientSecret, params) {
70429
70429
  function applyPublicAuth(clientId, params) {
70430
70430
  params.set("client_id", clientId);
70431
70431
  }
70432
- function isLoopbackHost(hostname4) {
70433
- return hostname4 === "localhost" || hostname4 === "127.0.0.1" || hostname4 === "[::1]" || hostname4 === "::1";
70432
+ function isLoopbackHost(hostname5) {
70433
+ return hostname5 === "localhost" || hostname5 === "127.0.0.1" || hostname5 === "[::1]" || hostname5 === "::1";
70434
70434
  }
70435
70435
  function assertSecureTokenEndpoint(tokenEndpoint) {
70436
70436
  const url3 = new URL(String(tokenEndpoint));
@@ -75335,7 +75335,8 @@ function createLocalDaemonHttpHandler(deps) {
75335
75335
  queueFullShutdown,
75336
75336
  wsUrl,
75337
75337
  inspectLocalSkill,
75338
- readLocalSkillFile
75338
+ readLocalSkillFile,
75339
+ adoptRuntimeSetupGrant
75339
75340
  } = deps;
75340
75341
  const localApiPort = getLocalApiPort2();
75341
75342
  const heartbeatSeq = getHeartbeatSeq();
@@ -75393,6 +75394,15 @@ function createLocalDaemonHttpHandler(deps) {
75393
75394
  res.writeHead(401, { "content-type": "application/json" }).end(JSON.stringify({ error: "Unauthorized" }));
75394
75395
  return;
75395
75396
  }
75397
+ if (req.method === "POST" && req.url === "/credentials/setup") {
75398
+ void readJsonRequest(req).then((value2) => parseRuntimeSetupGrantInput(value2)).then(adoptRuntimeSetupGrant).then((result) => {
75399
+ res.writeHead(200, { "cache-control": "no-store", "content-type": "application/json" }).end(JSON.stringify(result));
75400
+ }).catch((error61) => {
75401
+ pushLog(`runtime-credential-setup-failed ${error61.message}`);
75402
+ res.writeHead(409, { "cache-control": "no-store", "content-type": "application/json" }).end(JSON.stringify({ error: error61.message }));
75403
+ });
75404
+ return;
75405
+ }
75396
75406
  if (req.method === "GET" && req.url?.startsWith("/skills/preview/file?")) {
75397
75407
  const url3 = new URL(req.url, "http://127.0.0.1");
75398
75408
  const input2 = localSkillRequestInput(url3, true);
@@ -75574,6 +75584,31 @@ function createLocalDaemonHttpHandler(deps) {
75574
75584
  res.writeHead(404, { "content-type": "application/json" }).end(JSON.stringify({ error: "Not found" }));
75575
75585
  };
75576
75586
  }
75587
+ async function readJsonRequest(req) {
75588
+ const chunks = [];
75589
+ let size = 0;
75590
+ for await (const chunk of req) {
75591
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
75592
+ size += buffer.length;
75593
+ if (size > 16384) throw new Error("credential setup request is too large");
75594
+ chunks.push(buffer);
75595
+ }
75596
+ try {
75597
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
75598
+ } catch {
75599
+ throw new Error("credential setup request must be valid JSON");
75600
+ }
75601
+ }
75602
+ function parseRuntimeSetupGrantInput(value2) {
75603
+ if (!value2 || typeof value2 !== "object") {
75604
+ throw new Error("credential setup request must be an object");
75605
+ }
75606
+ const input2 = value2;
75607
+ if (typeof input2.apiUrl !== "string" || typeof input2.wsUrl !== "string" || input2.endpointProfile !== "production" && input2.endpointProfile !== "local" && input2.endpointProfile !== "staging" && input2.endpointProfile !== "custom" || typeof input2.setupToken !== "string" || input2.setupToken.length === 0 || typeof input2.displayName !== "string" || input2.displayName.length === 0 || typeof input2.installationId !== "string" || input2.installationId.length === 0 || input2.teamId !== void 0 && typeof input2.teamId !== "string") {
75608
+ throw new Error("credential setup request is incomplete");
75609
+ }
75610
+ return input2;
75611
+ }
75577
75612
  function localSkillRequestInput(url3, requirePath) {
75578
75613
  const localKey = url3.searchParams.get("localKey") ?? "";
75579
75614
  const expectedContentHash = url3.searchParams.get("expectedContentHash") ?? "";
@@ -76463,6 +76498,123 @@ var RuntimeRunJournal = class {
76463
76498
  }
76464
76499
  };
76465
76500
 
76501
+ // src/runtime-registration.ts
76502
+ var import_node_os11 = require("os");
76503
+ var RuntimeSetupGrantExpiredError = class extends Error {
76504
+ constructor() {
76505
+ super("Runtime setup grant expired");
76506
+ this.name = "RuntimeSetupGrantExpiredError";
76507
+ }
76508
+ };
76509
+ async function createRuntimeSetupGrant(input2) {
76510
+ const response = await fetch(`${input2.apiUrl}/public/runtimes/setup-tokens`, {
76511
+ method: "POST",
76512
+ headers: {
76513
+ authorization: `Bearer ${input2.accessToken}`,
76514
+ "content-type": "application/json"
76515
+ },
76516
+ body: JSON.stringify({
76517
+ scope: input2.scope,
76518
+ ...input2.scope === "team" ? { teamId: input2.teamId } : {},
76519
+ ttlMinutes: 5
76520
+ }),
76521
+ signal: AbortSignal.timeout(1e4)
76522
+ });
76523
+ const body = await response.json();
76524
+ if (!response.ok || typeof body.setupToken !== "string") {
76525
+ const detail = typeof body.error === "string" ? `: ${body.error}` : "";
76526
+ throw new Error(`runtime setup grant creation failed with HTTP ${response.status}${detail}`);
76527
+ }
76528
+ return body.setupToken;
76529
+ }
76530
+ async function exchangeRuntimeSetupGrant(input2) {
76531
+ const registrationAttemptId = getOrCreateSetupAttemptId(input2.setupToken);
76532
+ const registrationInit = {
76533
+ method: "POST",
76534
+ headers: { "content-type": "application/json" },
76535
+ body: JSON.stringify({
76536
+ ...input2.teamId ? { teamId: input2.teamId } : {},
76537
+ setupToken: input2.setupToken,
76538
+ registrationAttemptId,
76539
+ displayName: input2.displayName,
76540
+ hostname: (0, import_node_os11.hostname)(),
76541
+ runtimeKind: "machine",
76542
+ managementKind: "user_managed",
76543
+ hostKind: "daemon",
76544
+ lifecycle: "durable",
76545
+ capabilities: discoverCapabilities(),
76546
+ metadata: {
76547
+ ...await collectRuntimeMetadataWithProviderLimits(),
76548
+ installationId: input2.installationId
76549
+ }
76550
+ })
76551
+ };
76552
+ let response;
76553
+ let transportError;
76554
+ for (let attempt = 1; attempt <= 3; attempt += 1) {
76555
+ try {
76556
+ response = await fetch(
76557
+ `${input2.apiUrl}/public/runtimes/register-with-setup-token`,
76558
+ registrationInit
76559
+ );
76560
+ transportError = void 0;
76561
+ } catch (error61) {
76562
+ transportError = error61;
76563
+ }
76564
+ const retriable = response && (response.status === 408 || response.status === 429 || response.status >= 500);
76565
+ if (response && (!retriable || response.ok) || attempt === 3) break;
76566
+ await new Promise((resolve15) => setTimeout(resolve15, attempt * 100));
76567
+ }
76568
+ if (!response) {
76569
+ const detail = transportError instanceof Error ? transportError.message : String(transportError);
76570
+ throw new Error(`runtime registration failed: unable to reach Alan (${detail})`);
76571
+ }
76572
+ if (!response.ok) {
76573
+ const responseBody = await response.text();
76574
+ let errorCode2;
76575
+ try {
76576
+ const parsed = JSON.parse(responseBody);
76577
+ if (typeof parsed.error === "string") errorCode2 = parsed.error;
76578
+ } catch {
76579
+ }
76580
+ if (response.status === 401 && errorCode2 === "setup_token_expired") {
76581
+ clearPendingSetupIntent();
76582
+ throw new RuntimeSetupGrantExpiredError();
76583
+ }
76584
+ throw new Error(`runtime registration failed: ${response.status} ${responseBody}`);
76585
+ }
76586
+ const body = await response.json();
76587
+ if (typeof body.runtime?.id !== "string" || typeof body.runtime.credentialGeneration !== "number" || typeof body.runtimeToken !== "string" || !body.runtimeToken.startsWith("alan_runtime_") || typeof body.runtimeRenewalToken !== "string" || !body.runtimeRenewalToken.startsWith("alan_runtime_renew_")) {
76588
+ throw new Error("runtime registration returned an invalid credential bundle");
76589
+ }
76590
+ return {
76591
+ runtimeId: body.runtime.id,
76592
+ displayName: typeof body.runtime.displayName === "string" ? body.runtime.displayName : input2.displayName,
76593
+ credentialGeneration: body.runtime.credentialGeneration,
76594
+ runtimeToken: body.runtimeToken,
76595
+ runtimeRenewalToken: body.runtimeRenewalToken
76596
+ };
76597
+ }
76598
+ async function handoffRuntimeSetupGrant(input2) {
76599
+ const response = await fetch(`http://127.0.0.1:${input2.port}/credentials/setup`, {
76600
+ method: "POST",
76601
+ headers: {
76602
+ authorization: `Bearer ${input2.localApiToken}`,
76603
+ "content-type": "application/json"
76604
+ },
76605
+ body: JSON.stringify(input2.setup),
76606
+ signal: AbortSignal.timeout(input2.timeoutMs ?? 2e4)
76607
+ });
76608
+ const body = await response.json();
76609
+ if (!response.ok) {
76610
+ throw new Error(body.error ?? `daemon credential setup failed with HTTP ${response.status}`);
76611
+ }
76612
+ if (typeof body.runtimeId !== "string" || typeof body.credentialGeneration !== "number") {
76613
+ throw new Error("daemon credential setup returned an invalid activation receipt");
76614
+ }
76615
+ return { runtimeId: body.runtimeId, credentialGeneration: body.credentialGeneration };
76616
+ }
76617
+
76466
76618
  // src/skills/local-skill-source.ts
76467
76619
  var import_node_buffer2 = require("buffer");
76468
76620
  var import_node_crypto14 = require("crypto");
@@ -78923,7 +79075,7 @@ async function startDaemon(args) {
78923
79075
  getRuntimeToken: () => runtimeToken
78924
79076
  });
78925
79077
  const runtimeSkillManager = await RuntimeSkillManager.open({
78926
- homeDirectory: (0, import_node_os11.homedir)(),
79078
+ homeDirectory: (0, import_node_os12.homedir)(),
78927
79079
  endpointProfile,
78928
79080
  profileStorageIdentity: configPath,
78929
79081
  controlClient: skillControl
@@ -78931,7 +79083,7 @@ async function startDaemon(args) {
78931
79083
  const runtimeSkillCoordinator = new RuntimeSkillCoordinator(
78932
79084
  runtimeSkillManager,
78933
79085
  skillControl,
78934
- (input2) => resolveSkillScanInput((0, import_node_os11.homedir)(), input2)
79086
+ (input2) => resolveSkillScanInput((0, import_node_os12.homedir)(), input2)
78935
79087
  );
78936
79088
  const runSkillSync = async (reason) => {
78937
79089
  const operation = reason === "startup" ? runtimeSkillCoordinator.runStartup() : reason === "interval" ? runtimeSkillCoordinator.runIncremental() : reason === "refresh" ? runtimeSkillCoordinator.runAudit() : runtimeSkillCoordinator.run();
@@ -79250,27 +79402,7 @@ async function startDaemon(args) {
79250
79402
  const renewRuntimeLease = () => {
79251
79403
  if (runtimeRenewalInFlight) return runtimeRenewalInFlight;
79252
79404
  const attempt = (async () => {
79253
- const adoptRewrittenCredentials = () => {
79254
- const current2 = readConfig();
79255
- if (current2.runtimeId !== runtimeId) return false;
79256
- const nextToken = current2.runtimeToken;
79257
- const nextRenewal = current2.runtimeRenewalToken;
79258
- if (typeof nextToken !== "string" || !nextToken.startsWith("alan_runtime_") || typeof nextRenewal !== "string" || !nextRenewal.startsWith("alan_runtime_renew_")) {
79259
- return false;
79260
- }
79261
- if (nextToken === runtimeToken && nextRenewal === runtimeRenewalToken) {
79262
- return false;
79263
- }
79264
- runtimeToken = nextToken;
79265
- runtimeRenewalToken = nextRenewal;
79266
- socket.auth = { token: nextToken };
79267
- clearConnectErrors();
79268
- pushLog("runtime-credentials-reloaded-from-config");
79269
- socket.connect();
79270
- return true;
79271
- };
79272
79405
  if (!stored.apiUrl || !runtimeRenewalToken) {
79273
- if (adoptRewrittenCredentials()) return true;
79274
79406
  return false;
79275
79407
  }
79276
79408
  let response = null;
@@ -79302,9 +79434,6 @@ async function startDaemon(args) {
79302
79434
  return false;
79303
79435
  }
79304
79436
  if (!response.ok) {
79305
- if (response.status === 401 && adoptRewrittenCredentials()) {
79306
- return true;
79307
- }
79308
79437
  const code = response.status === 401 ? "runtime_renewal_rejected" : response.status === 403 ? "runtime_disabled" : response.status === 410 ? "runtime_deleted" : response.status >= 500 ? "backend_unreachable" : "runtime_renewal_failed";
79309
79438
  rememberConnectErrorCode(code);
79310
79439
  lastConnectError = `Runtime renewal failed: ${response.status} ${await response.text()}`;
@@ -79320,7 +79449,6 @@ async function startDaemon(args) {
79320
79449
  }
79321
79450
  const current = readConfig();
79322
79451
  if (current.runtimeId !== runtimeId || current.runtimeRenewalToken !== runtimeRenewalToken) {
79323
- if (adoptRewrittenCredentials()) return true;
79324
79452
  rememberConnectErrorCode("runtime_renewal_superseded");
79325
79453
  lastConnectError = "Runtime credentials changed while renewal was in progress";
79326
79454
  pushLog("runtime-renewal-superseded");
@@ -79348,6 +79476,64 @@ async function startDaemon(args) {
79348
79476
  });
79349
79477
  return attempt;
79350
79478
  };
79479
+ let runtimeSetupInFlight = null;
79480
+ const adoptRuntimeSetupGrant = (input2) => {
79481
+ if (runtimeSetupInFlight) return runtimeSetupInFlight;
79482
+ const attempt = (async () => {
79483
+ const current = readConfig();
79484
+ if (current.runtimeId !== runtimeId || current.installationId !== installationId || input2.installationId !== installationId) {
79485
+ throw new Error("credential setup does not belong to this daemon installation");
79486
+ }
79487
+ if (input2.apiUrl !== stored.apiUrl || input2.wsUrl !== wsUrl) {
79488
+ throw new Error("credential setup cannot change a running daemon's endpoints");
79489
+ }
79490
+ const bundle = await exchangeRuntimeSetupGrant(input2);
79491
+ if (bundle.runtimeId !== runtimeId) {
79492
+ throw new Error("credential setup resolved to a different runtime");
79493
+ }
79494
+ writeConfig({
79495
+ ...current,
79496
+ runtimeToken: bundle.runtimeToken,
79497
+ runtimeRenewalToken: bundle.runtimeRenewalToken,
79498
+ displayName: bundle.displayName
79499
+ });
79500
+ clearPendingSetupIntent();
79501
+ runtimeToken = bundle.runtimeToken;
79502
+ runtimeRenewalToken = bundle.runtimeRenewalToken;
79503
+ socket.auth = { token: bundle.runtimeToken };
79504
+ clearConnectErrors();
79505
+ const ready = new Promise((resolveReady, rejectReady) => {
79506
+ const timeout = setTimeout(() => {
79507
+ socket.off("runtime.ready", onReady);
79508
+ rejectReady(
79509
+ new Error("backend did not acknowledge the replacement credential generation")
79510
+ );
79511
+ }, 15e3);
79512
+ const onReady = (payload) => {
79513
+ if (payload?.credentialGeneration !== bundle.credentialGeneration) return;
79514
+ clearTimeout(timeout);
79515
+ socket.off("runtime.ready", onReady);
79516
+ resolveReady();
79517
+ };
79518
+ socket.on("runtime.ready", onReady);
79519
+ });
79520
+ pushLog(`runtime-credential-setup-redial generation=${bundle.credentialGeneration}`);
79521
+ if (socket.connected) socket.disconnect();
79522
+ socket.connect();
79523
+ await ready;
79524
+ pushLog(`runtime-credential-setup-ready generation=${bundle.credentialGeneration}`);
79525
+ return {
79526
+ runtimeId: bundle.runtimeId,
79527
+ credentialGeneration: bundle.credentialGeneration
79528
+ };
79529
+ })();
79530
+ runtimeSetupInFlight = attempt;
79531
+ void attempt.finally(() => {
79532
+ if (runtimeSetupInFlight === attempt) runtimeSetupInFlight = null;
79533
+ }).catch(() => {
79534
+ });
79535
+ return attempt;
79536
+ };
79351
79537
  const relocationInFlight = /* @__PURE__ */ new Set();
79352
79538
  const persistWorkspaceRelocations = () => {
79353
79539
  const current = readConfig();
@@ -79773,7 +79959,8 @@ async function startDaemon(args) {
79773
79959
  queueFullShutdown: () => queueFullShutdown(),
79774
79960
  wsUrl,
79775
79961
  inspectLocalSkill: (input2) => runtimeSkillManager.inspectLocalPackage(input2),
79776
- readLocalSkillFile: (input2) => runtimeSkillManager.readLocalPackageFile(input2)
79962
+ readLocalSkillFile: (input2) => runtimeSkillManager.readLocalPackageFile(input2),
79963
+ adoptRuntimeSetupGrant
79777
79964
  })
79778
79965
  );
79779
79966
  const occupiedProbe = await probeLocalDaemonEndpoint(localApiPort, localApiToken);
@@ -79967,7 +80154,7 @@ async function setupDaemon(args) {
79967
80154
  const teamId = argValue(args, "--team") ?? process.env.ALAN_TEAM_ID;
79968
80155
  const setupToken = argValue(args, "--setup-token") ?? process.env.ALAN_RUNTIME_SETUP_TOKEN;
79969
80156
  const token = argValue(args, "--token") ?? process.env.ALAN_SETUP_TOKEN;
79970
- const displayName = argValue(args, "--name") ?? (0, import_node_os12.hostname)();
80157
+ const displayName = argValue(args, "--name") ?? (0, import_node_os13.hostname)();
79971
80158
  const scope = argValue(args, "--scope") ?? process.env.ALAN_RUNTIME_SCOPE ?? (setupToken ? "team" : "user");
79972
80159
  const installationId = argValue(args, "--installation-id") ?? previousConfig.installationId ?? (0, import_node_crypto19.randomUUID)();
79973
80160
  if (scope !== "team" && scope !== "user") {
@@ -79978,69 +80165,65 @@ async function setupDaemon(args) {
79978
80165
  "setup requires --setup-token <token> or --token <Alan access token>.\nFor normal setup, copy the setup token from Alan and run: alan-agent setup --setup-token <token>\nFor browser authorization, run: alan-agent login"
79979
80166
  );
79980
80167
  }
79981
- const registrationAttemptId = setupToken ? getOrCreateSetupAttemptId(setupToken) : (0, import_node_crypto19.randomUUID)();
79982
- const registrationUrl = `${apiUrl}/public/runtimes${setupToken ? "/register-with-setup-token" : ""}`;
79983
- const registrationInit = {
79984
- method: "POST",
79985
- headers: {
79986
- "content-type": "application/json",
79987
- ...setupToken ? {} : { authorization: `Bearer ${token}` }
79988
- },
79989
- body: JSON.stringify({
79990
- ...teamId ? { teamId } : {},
79991
- ...setupToken ? { setupToken, registrationAttemptId } : {},
79992
- displayName,
79993
- hostname: (0, import_node_os12.hostname)(),
79994
- runtimeKind: "machine",
79995
- managementKind: "user_managed",
79996
- hostKind: "daemon",
79997
- lifecycle: "durable",
79998
- capabilities: discoverCapabilities(),
79999
- metadata: {
80000
- ...await collectRuntimeMetadataWithProviderLimits(),
80001
- installationId
80002
- }
80003
- })
80168
+ const registrationGrant = setupToken ?? await createRuntimeSetupGrant({
80169
+ apiUrl,
80170
+ accessToken: token,
80171
+ scope,
80172
+ teamId
80173
+ });
80174
+ const setup = {
80175
+ apiUrl,
80176
+ wsUrl,
80177
+ endpointProfile,
80178
+ setupToken: registrationGrant,
80179
+ teamId,
80180
+ displayName,
80181
+ installationId
80004
80182
  };
80005
- let response;
80006
- let transportError;
80007
- for (let attempt = 1; attempt <= 3; attempt += 1) {
80008
- try {
80009
- response = await fetch(registrationUrl, registrationInit);
80010
- transportError = void 0;
80011
- } catch (error61) {
80012
- transportError = error61;
80183
+ let liveConfig = previousConfig;
80184
+ const localApiPort = getLocalApiPort(args, liveConfig);
80185
+ let live = liveConfig.localApiToken ? await probeLocalDaemon(localApiPort, liveConfig.localApiToken) : null;
80186
+ if (!live && liveConfig.localServiceId && liveConfig.localServiceSecret) {
80187
+ live = await adoptConfiguredLocalDaemon(args);
80188
+ liveConfig = readConfigForRegistration();
80189
+ }
80190
+ if (live) {
80191
+ if (!liveConfig.localApiToken) {
80192
+ throw new Error("running daemon could not be authenticated for credential setup");
80013
80193
  }
80014
- const retriableStatus = response && (response.status === 408 || response.status === 429 || response.status >= 500);
80015
- if (response && (!retriableStatus || response.ok) || attempt === 3) break;
80016
- await new Promise((resolve15) => setTimeout(resolve15, attempt * 100));
80194
+ const body2 = await handoffRuntimeSetupGrant({
80195
+ port: localApiPort,
80196
+ localApiToken: liveConfig.localApiToken,
80197
+ setup
80198
+ });
80199
+ console.info("[alan-agent] Runtime credentials adopted by running daemon", {
80200
+ runtimeId: body2.runtimeId,
80201
+ credentialGeneration: body2.credentialGeneration,
80202
+ configPath: getConfigPath()
80203
+ });
80204
+ return;
80017
80205
  }
80018
- if (!response) {
80019
- const detail = transportError instanceof Error ? transportError.message : String(transportError);
80020
- throw new Error(`runtime registration failed: unable to reach Alan (${detail})`);
80206
+ if (readLocalDaemonOwnerLease(getConfigPath())) {
80207
+ throw new Error(
80208
+ "the daemon still owns this runtime configuration, but its authenticated local API is unreachable; recover or stop the daemon before running setup again"
80209
+ );
80021
80210
  }
80022
- if (!response.ok) {
80023
- const responseBody = await response.text();
80024
- let errorCode2;
80025
- try {
80026
- const parsed = JSON.parse(responseBody);
80027
- if (typeof parsed.error === "string") errorCode2 = parsed.error;
80028
- } catch {
80029
- }
80030
- if (setupToken && response.status === 401 && errorCode2 === "setup_token_expired") {
80031
- clearPendingSetupIntent();
80211
+ let body;
80212
+ try {
80213
+ body = await exchangeRuntimeSetupGrant(setup);
80214
+ } catch (error61) {
80215
+ if (setupToken && error61 instanceof RuntimeSetupGrantExpiredError) {
80032
80216
  console.info("[alan-agent] Setup link expired; continuing with browser authorization");
80033
80217
  await loginWithDeviceCode(args);
80034
80218
  return;
80035
80219
  }
80036
- throw new Error(`runtime registration failed: ${response.status} ${responseBody}`);
80220
+ throw error61;
80037
80221
  }
80038
- const body = await response.json();
80039
80222
  writeConfig({
80040
80223
  apiUrl,
80041
80224
  wsUrl,
80042
80225
  endpointProfile,
80043
- runtimeId: body.runtime.id,
80226
+ runtimeId: body.runtimeId,
80044
80227
  runtimeToken: body.runtimeToken,
80045
80228
  runtimeRenewalToken: body.runtimeRenewalToken,
80046
80229
  localApiPort: getLocalApiPort(args, {}),
@@ -80049,12 +80232,12 @@ async function setupDaemon(args) {
80049
80232
  localServiceSecret: previousConfig.localServiceSecret ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
80050
80233
  eventSpoolKey: previousConfig.eventSpoolKey ?? (0, import_node_crypto19.randomBytes)(32).toString("base64url"),
80051
80234
  daemonEpoch: previousConfig.daemonEpoch,
80052
- displayName: body.runtime.displayName ?? displayName,
80235
+ displayName: body.displayName,
80053
80236
  installationId
80054
80237
  });
80055
- if (setupToken) clearPendingSetupIntent();
80238
+ clearPendingSetupIntent();
80056
80239
  console.info("[alan-agent] Runtime registered", {
80057
- runtimeId: body.runtime.id,
80240
+ runtimeId: body.runtimeId,
80058
80241
  configPath: getConfigPath()
80059
80242
  });
80060
80243
  }
@@ -80074,7 +80257,7 @@ async function loginWithDeviceCode(args) {
80074
80257
  }
80075
80258
  const previousConfig = readConfigForRegistration();
80076
80259
  const { apiUrl, wsUrl, endpointProfile } = resolveEndpoints(args);
80077
- const displayName = argValue(args, "--name") ?? (0, import_node_os12.hostname)();
80260
+ const displayName = argValue(args, "--name") ?? (0, import_node_os13.hostname)();
80078
80261
  const maxPolls = Number.parseInt(argValue(args, "--max-polls") ?? "300", 10);
80079
80262
  const resumed = readPendingDeviceAuthorization(apiUrl);
80080
80263
  const installationId = resumed?.installationId ?? previousConfig.installationId ?? (0, import_node_crypto19.randomUUID)();
@@ -80086,7 +80269,7 @@ async function loginWithDeviceCode(args) {
80086
80269
  headers: { "content-type": "application/json" },
80087
80270
  body: JSON.stringify({
80088
80271
  displayName,
80089
- hostname: (0, import_node_os12.hostname)(),
80272
+ hostname: (0, import_node_os13.hostname)(),
80090
80273
  capabilities: discoverCapabilities(),
80091
80274
  metadata: {
80092
80275
  ...await collectRuntimeMetadataWithProviderLimits(),
@@ -80516,7 +80699,7 @@ async function printDoctor(args = []) {
80516
80699
  // src/mcp-config-adapters.ts
80517
80700
  var import_node_crypto20 = require("crypto");
80518
80701
  var import_node_fs23 = require("fs");
80519
- var import_node_os13 = require("os");
80702
+ var import_node_os14 = require("os");
80520
80703
  var import_node_path25 = require("path");
80521
80704
  var log = {
80522
80705
  info: (...args) => console.info("[mcp-config-adapters]", ...args),
@@ -80526,7 +80709,7 @@ var log = {
80526
80709
  };
80527
80710
  var homeDirectoryOverride;
80528
80711
  function homeDirectory() {
80529
- return homeDirectoryOverride ?? (0, import_node_os13.homedir)();
80712
+ return homeDirectoryOverride ?? (0, import_node_os14.homedir)();
80530
80713
  }
80531
80714
  var MalformedToolConfigError = class extends Error {
80532
80715
  };
@@ -81271,7 +81454,7 @@ var McpSyncService = class {
81271
81454
 
81272
81455
  // src/native-hook-config.ts
81273
81456
  var import_node_fs24 = require("fs");
81274
- var import_node_os14 = require("os");
81457
+ var import_node_os15 = require("os");
81275
81458
  var import_node_path26 = require("path");
81276
81459
  var ALAN_HOOK_MARKER = "# alan-native-session-hook";
81277
81460
  var ALAN_KIMI_HOOKS_START = "# alan-native-session-hooks:start";
@@ -81365,7 +81548,7 @@ function nativeHookCommand(input2) {
81365
81548
  if (environment.length === 0) {
81366
81549
  return { type: "command", command: input2.nodeExecutable, args, timeout: 5 };
81367
81550
  }
81368
- if ((input2.platform ?? (0, import_node_os14.platform)()) === "win32") {
81551
+ if ((input2.platform ?? (0, import_node_os15.platform)()) === "win32") {
81369
81552
  const environmentPrefix2 = environment.map(([key, value2]) => `$env:${key}=${powershellQuote(value2)}`).join("; ");
81370
81553
  const command2 = [input2.nodeExecutable, ...args].map(powershellQuote).join(" ");
81371
81554
  return {
@@ -81410,11 +81593,11 @@ function resolveRuntime(input2 = {}) {
81410
81593
  }
81411
81594
  return {
81412
81595
  configPath,
81413
- homeDir: input2.homeDir ?? (0, import_node_os14.homedir)(),
81596
+ homeDir: input2.homeDir ?? (0, import_node_os15.homedir)(),
81414
81597
  nodeExecutable: input2.nodeExecutable ?? process.execPath,
81415
81598
  cliEntry,
81416
81599
  environment: input2.environment,
81417
- platform: input2.platform ?? (0, import_node_os14.platform)()
81600
+ platform: input2.platform ?? (0, import_node_os15.platform)()
81418
81601
  };
81419
81602
  }
81420
81603
  function readSettings(path2, providerLabel) {
@@ -81505,7 +81688,7 @@ function reconcileClaudeNativeHooks(input2 = {}) {
81505
81688
  })
81506
81689
  });
81507
81690
  }
81508
- function removeClaudeNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
81691
+ function removeClaudeNativeHooks(homeDir = (0, import_node_os15.homedir)()) {
81509
81692
  return removeNestedCommandHooks((0, import_node_path26.join)(homeDir, ".claude", "settings.json"), "Claude");
81510
81693
  }
81511
81694
  function reconcileCodexNativeHooks(input2 = {}) {
@@ -81522,7 +81705,7 @@ function reconcileCodexNativeHooks(input2 = {}) {
81522
81705
  })
81523
81706
  });
81524
81707
  }
81525
- function removeCodexNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
81708
+ function removeCodexNativeHooks(homeDir = (0, import_node_os15.homedir)()) {
81526
81709
  return removeNestedCommandHooks((0, import_node_path26.join)(homeDir, ".codex", "hooks.json"), "Codex");
81527
81710
  }
81528
81711
  function reconcileCopilotNativeHooks(input2 = {}) {
@@ -81546,7 +81729,7 @@ function reconcileCopilotNativeHooks(input2 = {}) {
81546
81729
  );
81547
81730
  return writeSettings(path2, { version: 1, hooks });
81548
81731
  }
81549
- function removeCopilotNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
81732
+ function removeCopilotNativeHooks(homeDir = (0, import_node_os15.homedir)()) {
81550
81733
  const path2 = (0, import_node_path26.join)(homeDir, ".copilot", "hooks", "alan-native-session.json");
81551
81734
  if (!(0, import_node_fs24.existsSync)(path2)) return false;
81552
81735
  if (!(0, import_node_fs24.readFileSync)(path2, "utf8").includes(ALAN_HOOK_MARKER)) return false;
@@ -81571,7 +81754,7 @@ function reconcileCursorNativeHooks(input2 = {}) {
81571
81754
  }
81572
81755
  return writeSettings(path2, { ...settings, version: settings.version ?? 1, hooks });
81573
81756
  }
81574
- function removeCursorNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
81757
+ function removeCursorNativeHooks(homeDir = (0, import_node_os15.homedir)()) {
81575
81758
  const path2 = (0, import_node_path26.join)(homeDir, ".cursor", "hooks.json");
81576
81759
  if (!(0, import_node_fs24.existsSync)(path2)) return false;
81577
81760
  const settings = readSettings(path2, "Cursor");
@@ -81609,7 +81792,7 @@ function reconcileKimiNativeHooks(input2 = {}) {
81609
81792
  `;
81610
81793
  return writeTextFile(path2, content);
81611
81794
  }
81612
- function removeKimiNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
81795
+ function removeKimiNativeHooks(homeDir = (0, import_node_os15.homedir)()) {
81613
81796
  const path2 = (0, import_node_path26.join)(homeDir, ".kimi-code", "config.toml");
81614
81797
  if (!(0, import_node_fs24.existsSync)(path2)) return false;
81615
81798
  const current = (0, import_node_fs24.readFileSync)(path2, "utf8");
@@ -81635,7 +81818,7 @@ function reconcileGrokNativeHooks(input2 = {}) {
81635
81818
  })
81636
81819
  });
81637
81820
  }
81638
- function removeGrokNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
81821
+ function removeGrokNativeHooks(homeDir = (0, import_node_os15.homedir)()) {
81639
81822
  const path2 = (0, import_node_path26.join)(homeDir, ".grok", "hooks", "alan-native-session.json");
81640
81823
  if (!(0, import_node_fs24.existsSync)(path2)) return false;
81641
81824
  if (!(0, import_node_fs24.readFileSync)(path2, "utf8").includes(ALAN_HOOK_MARKER)) return false;
@@ -81739,7 +81922,7 @@ function reconcileOpencodeNativePlugin(input2 = {}) {
81739
81922
  (0, import_node_fs24.renameSync)(temporary, path2);
81740
81923
  return true;
81741
81924
  }
81742
- function removeOpencodeNativePlugin(homeDir = (0, import_node_os14.homedir)()) {
81925
+ function removeOpencodeNativePlugin(homeDir = (0, import_node_os15.homedir)()) {
81743
81926
  const path2 = (0, import_node_path26.join)(homeDir, ".config", "opencode", "plugins", "alan-native-session.js");
81744
81927
  if (!(0, import_node_fs24.existsSync)(path2)) return false;
81745
81928
  if (!(0, import_node_fs24.readFileSync)(path2, "utf8").includes(ALAN_OPENCODE_PLUGIN_MARKER)) return false;
@@ -81754,7 +81937,7 @@ function configFileContainsMarker(path2, marker) {
81754
81937
  return false;
81755
81938
  }
81756
81939
  }
81757
- function inspectNativeHooksConfigured(providerKind, homeDir = (0, import_node_os14.homedir)(), expectedConfigPath) {
81940
+ function inspectNativeHooksConfigured(providerKind, homeDir = (0, import_node_os15.homedir)(), expectedConfigPath) {
81758
81941
  const matchesActiveProfile = (path2, marker) => {
81759
81942
  if (!configFileContainsMarker(path2, marker)) return false;
81760
81943
  if (!expectedConfigPath) return true;
@@ -94335,7 +94518,7 @@ async function runMcpStdioProxy(env = process.env, local = new StdioServerTransp
94335
94518
  // src/native-hook-command.ts
94336
94519
  var import_node_crypto21 = require("crypto");
94337
94520
  var import_node_fs26 = require("fs");
94338
- var import_node_os15 = require("os");
94521
+ var import_node_os16 = require("os");
94339
94522
  var import_node_path28 = require("path");
94340
94523
 
94341
94524
  // src/native-project-config.ts
@@ -94615,7 +94798,7 @@ function resolveCodexSessionIdFromTranscriptPath(transcriptPath) {
94615
94798
  );
94616
94799
  return match?.[1];
94617
94800
  }
94618
- function resolveKimiTranscriptPath(externalSessionId, kimiHomeDir = process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path28.join)((0, import_node_os15.homedir)(), ".kimi-code")) {
94801
+ function resolveKimiTranscriptPath(externalSessionId, kimiHomeDir = process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path28.join)((0, import_node_os16.homedir)(), ".kimi-code")) {
94619
94802
  if ((0, import_node_path28.basename)(externalSessionId) !== externalSessionId) return void 0;
94620
94803
  const sessionsDir = (0, import_node_path28.join)(kimiHomeDir, "sessions");
94621
94804
  if (!(0, import_node_fs26.existsSync)(sessionsDir)) return void 0;
@@ -94840,7 +95023,7 @@ function collectNativeIntegrationStatus(args = []) {
94840
95023
  const config2 = readConfig();
94841
95024
  const configPath = getConfigPath();
94842
95025
  const env = getDaemonCliEnvironment();
94843
- const homeDir = (0, import_node_os15.homedir)();
95026
+ const homeDir = (0, import_node_os16.homedir)();
94844
95027
  return NATIVE_SESSION_PROVIDER_CAPABILITIES.map((capability) => ({
94845
95028
  provider: capability.providerKind,
94846
95029
  command: capability.command,
@@ -94869,7 +95052,7 @@ function decodeResumeFallbackContext(encoded) {
94869
95052
  }
94870
95053
 
94871
95054
  // src/sandbox.ts
94872
- var import_node_os16 = require("os");
95055
+ var import_node_os17 = require("os");
94873
95056
 
94874
95057
  // src/execution-activity-tracker.ts
94875
95058
  var ExecutionActivityTracker = class {
@@ -95484,10 +95667,6 @@ var agentProbeAckSchema = external_exports.object({
95484
95667
  // src/sandbox-outbox.ts
95485
95668
  var import_node_crypto23 = require("crypto");
95486
95669
  var import_node_fs27 = require("fs");
95487
- var SANDBOX_EVENT_OUTBOX_ENV = "ALAN_EVENT_OUTBOX_ENABLED";
95488
- function isSandboxEventOutboxEnabled(env = process.env) {
95489
- return env[SANDBOX_EVENT_OUTBOX_ENV] === "true";
95490
- }
95491
95670
  function deriveSandboxOutboxKey(sessionToken) {
95492
95671
  if (!sessionToken) {
95493
95672
  throw new Error("sandbox event outbox requires ALAN_SESSION_TOKEN for key derivation");
@@ -95507,6 +95686,7 @@ function createSandboxEventOutbox(input2) {
95507
95686
  `sandbox_outbox_spool_reset ${error61 instanceof Error ? error61.message : String(error61)}`
95508
95687
  );
95509
95688
  (0, import_node_fs27.rmSync)(path2, { force: true });
95689
+ (0, import_node_fs27.rmSync)(eventJournalDir(path2), { recursive: true, force: true });
95510
95690
  return new EncryptedEventOutbox(path2, key, input2.pushLog, input2.options);
95511
95691
  }
95512
95692
  }
@@ -95526,7 +95706,12 @@ var SandboxOutboxSocket = class {
95526
95706
  seq = this.seqCounter;
95527
95707
  this.seqByEventId.set(payload.eventId, seq);
95528
95708
  }
95529
- const wirePayload = { ...payload.event, eventId: payload.eventId, seq };
95709
+ const wirePayload = {
95710
+ ...payload.event,
95711
+ eventId: payload.eventId,
95712
+ seq,
95713
+ deliveryRunId: payload.runId
95714
+ };
95530
95715
  this.socket.emit("agent_event", wirePayload, (result) => {
95531
95716
  if (result?.ok) this.seqByEventId.delete(payload.eventId);
95532
95717
  acknowledge({ ok: Boolean(result?.ok), retryable: result?.retryable });
@@ -95540,54 +95725,38 @@ var SandboxEventDispatcher = class {
95540
95725
  currentRunId;
95541
95726
  constructor(input2) {
95542
95727
  this.conversationId = input2.conversationId;
95543
- if (!input2.enabled) return;
95544
- try {
95545
- this.outbox = createSandboxEventOutbox({
95546
- conversationId: input2.conversationId,
95547
- sessionToken: input2.sessionToken,
95548
- pushLog: input2.pushLog,
95549
- options: input2.options,
95550
- spoolPath: input2.spoolPath
95551
- });
95552
- this.outboxSocket = new SandboxOutboxSocket(input2.socket);
95553
- } catch (error61) {
95554
- input2.onInitError?.(error61);
95555
- this.outbox = void 0;
95556
- this.outboxSocket = void 0;
95557
- }
95558
- }
95559
- /** True when events are being durably queued rather than fired-and-forgotten. */
95560
- get active() {
95561
- return this.outbox !== void 0 && this.outboxSocket !== void 0;
95728
+ this.outbox = createSandboxEventOutbox({
95729
+ conversationId: input2.conversationId,
95730
+ sessionToken: input2.sessionToken,
95731
+ pushLog: input2.pushLog,
95732
+ options: input2.options,
95733
+ spoolPath: input2.spoolPath
95734
+ });
95735
+ this.outboxSocket = new SandboxOutboxSocket(input2.socket);
95562
95736
  }
95563
95737
  /** Set the run id used for fair replay and per-run heartbeat pruning. */
95564
95738
  setRunId(runId) {
95565
95739
  this.currentRunId = runId;
95566
95740
  }
95567
95741
  /**
95568
- * Durably deliver one event (enqueue-before-send, remove-on-ack). When the
95569
- * outbox is inactive, defers to `fireAndForget` so behaviour is unchanged.
95742
+ * Durably deliver one event (enqueue-before-send, remove-on-ack).
95570
95743
  */
95571
- emit(event, fireAndForget) {
95572
- if (!this.outbox || !this.outboxSocket) {
95573
- fireAndForget(event);
95574
- return;
95575
- }
95744
+ emit(event) {
95576
95745
  if (isBackgroundHeartbeat(event) && !this.outboxSocket.connected) return;
95577
95746
  this.outbox.enqueue(this.conversationId, this.currentRunId ?? this.conversationId, event);
95578
95747
  this.outbox.flush(this.outboxSocket);
95579
95748
  }
95580
95749
  /** Replay un-acked events in order — called on (re)connect before new events. */
95581
95750
  flush() {
95582
- if (this.outbox && this.outboxSocket) this.outbox.flush(this.outboxSocket);
95751
+ this.outbox.flush(this.outboxSocket);
95583
95752
  }
95584
95753
  /** Reset in-flight state on disconnect so the next flush replays from the head. */
95585
95754
  disconnect() {
95586
- this.outbox?.disconnect();
95755
+ this.outbox.disconnect();
95587
95756
  }
95588
95757
  /** Diagnostics: number of events still awaiting a server ack. */
95589
95758
  pendingCount() {
95590
- return this.outbox?.pendingCount() ?? 0;
95759
+ return this.outbox.pendingCount();
95591
95760
  }
95592
95761
  };
95593
95762
 
@@ -95631,20 +95800,13 @@ var WSClient = class {
95631
95800
  upgrade: false,
95632
95801
  extraHeaders: { "ngrok-skip-browser-warning": "1" }
95633
95802
  });
95634
- const outboxEnabled = isSandboxEventOutboxEnabled();
95635
95803
  this.eventDispatcher = new SandboxEventDispatcher({
95636
95804
  conversationId: sessionId,
95637
95805
  sessionToken: token,
95638
- enabled: outboxEnabled,
95639
95806
  socket: this.socket,
95640
- pushLog: (message) => this.lifecycle?.info("sandbox_agent_event_outbox", { detail: message }),
95641
- onInitError: (error61) => this.lifecycle?.warn("sandbox_agent_event_outbox_init_failed", {
95642
- error: error61 instanceof Error ? error61 : new Error(String(error61))
95643
- })
95807
+ pushLog: (message) => this.lifecycle?.info("sandbox_agent_event_outbox", { detail: message })
95644
95808
  });
95645
- if (this.eventDispatcher.active) {
95646
- this.lifecycle?.info("sandbox_agent_event_outbox_enabled", { conversationId: sessionId });
95647
- }
95809
+ this.lifecycle?.info("sandbox_agent_event_outbox_enabled", { conversationId: sessionId });
95648
95810
  this.setupListeners(callbacks);
95649
95811
  }
95650
95812
  socket;
@@ -95659,11 +95821,7 @@ var WSClient = class {
95659
95821
  intentionalClose = false;
95660
95822
  agentVersion;
95661
95823
  getRunState;
95662
- /**
95663
- * Durable at-least-once delivery for stream events. Active only when
95664
- * `ALAN_EVENT_OUTBOX_ENABLED === "true"`; otherwise events are fired-and-
95665
- * forgotten exactly as before (see {@link SandboxEventDispatcher}).
95666
- */
95824
+ /** Durable at-least-once delivery for stream events (see {@link SandboxEventDispatcher}). */
95667
95825
  eventDispatcher;
95668
95826
  /**
95669
95827
  * Bounded record of `messageId`s whose handoff to `onUserMessage` already
@@ -95686,8 +95844,7 @@ var WSClient = class {
95686
95844
  }
95687
95845
  /**
95688
95846
  * Record the run id for events emitted from here on, so the durable outbox can
95689
- * bucket per-run caps and terminal-event condensation correctly. No-op when the
95690
- * outbox is disabled.
95847
+ * bucket per-run caps and terminal-event condensation correctly.
95691
95848
  */
95692
95849
  setCurrentRunId(runId) {
95693
95850
  this.eventDispatcher.setRunId(runId);
@@ -95728,9 +95885,7 @@ var WSClient = class {
95728
95885
  }
95729
95886
  }
95730
95887
  emitEvent(event) {
95731
- this.eventDispatcher.emit(event, (payload) => {
95732
- this.socket.emit("agent_event", payload);
95733
- });
95888
+ this.eventDispatcher.emit(event);
95734
95889
  }
95735
95890
  waitForConnection(timeoutMs = 15e3) {
95736
95891
  return new Promise((resolve15, reject) => {
@@ -96172,7 +96327,7 @@ async function runSandbox(config2) {
96172
96327
  }
96173
96328
  const presenter = new WebPresenter(wsClient, config2.sessionId, config2.projectPath);
96174
96329
  presenter.setSuppressSessionLifecycle(true);
96175
- const runtimeSkillManager = await RuntimeSkillManager.open({ homeDirectory: (0, import_node_os16.homedir)() });
96330
+ const runtimeSkillManager = await RuntimeSkillManager.open({ homeDirectory: (0, import_node_os17.homedir)() });
96176
96331
  let lastProviderSessionId = config2.providerSessionId;
96177
96332
  let resumeFallbackContext = config2.resumeFallbackContext;
96178
96333
  let activeBackendKind = config2.backendKind || "claude_cli";
@@ -96472,7 +96627,7 @@ async function runSandbox(config2) {
96472
96627
  // src/service-manager.ts
96473
96628
  var import_node_child_process9 = require("child_process");
96474
96629
  var import_node_fs28 = require("fs");
96475
- var import_node_os17 = require("os");
96630
+ var import_node_os18 = require("os");
96476
96631
  var import_node_path29 = require("path");
96477
96632
  var SERVICE_LABEL = "ai.tryalan.agent";
96478
96633
  var SYSTEMD_UNIT = "alan-agent.service";
@@ -96789,7 +96944,7 @@ WantedBy=default.target
96789
96944
  };
96790
96945
  }
96791
96946
  function resolveCurrentPlatform() {
96792
- const currentPlatform = (0, import_node_os17.platform)();
96947
+ const currentPlatform = (0, import_node_os18.platform)();
96793
96948
  if (currentPlatform !== "darwin" && currentPlatform !== "linux" && currentPlatform !== "win32") {
96794
96949
  throw new Error(`Daemon service installation is not supported on ${currentPlatform}`);
96795
96950
  }
@@ -96802,7 +96957,7 @@ function currentServicePlan(args, runtime) {
96802
96957
  if (!cliEntry) throw new Error("Cannot determine the alan-agent executable path");
96803
96958
  return buildDaemonServicePlan({
96804
96959
  platform: currentPlatform,
96805
- homeDir: (0, import_node_os17.homedir)(),
96960
+ homeDir: (0, import_node_os18.homedir)(),
96806
96961
  nodeExecutable: runtime?.executable ?? process.execPath,
96807
96962
  cliEntry: (0, import_node_path29.resolve)(cliEntry),
96808
96963
  profile,
@@ -96883,7 +97038,7 @@ function shouldStartOnInstall(hostState) {
96883
97038
  function resolveUsername(options) {
96884
97039
  if (options?.username) return options.username;
96885
97040
  try {
96886
- return (0, import_node_os17.userInfo)().username;
97041
+ return (0, import_node_os18.userInfo)().username;
96887
97042
  } catch {
96888
97043
  return process.env.USER || process.env.USERNAME || "unknown";
96889
97044
  }
@@ -96921,7 +97076,7 @@ function createHostContext(options = {}) {
96921
97076
  const removeManifest = options.removeManifest ?? ((path2) => (0, import_node_fs28.rmSync)(path2, { force: true }));
96922
97077
  const ensureLogDir = options.ensureLogDir ?? (() => {
96923
97078
  if (plan.platform === "darwin") {
96924
- (0, import_node_fs28.mkdirSync)((0, import_node_path29.join)((0, import_node_os17.homedir)(), ".alan", "agent", "logs"), { recursive: true, mode: 448 });
97079
+ (0, import_node_fs28.mkdirSync)((0, import_node_path29.join)((0, import_node_os18.homedir)(), ".alan", "agent", "logs"), { recursive: true, mode: 448 });
96925
97080
  }
96926
97081
  });
96927
97082
  return {
@@ -97037,11 +97192,11 @@ ${result.output}
97037
97192
 
97038
97193
  // src/skills/skill-cli.ts
97039
97194
  var import_promises6 = require("fs/promises");
97040
- var import_node_os18 = require("os");
97195
+ var import_node_os19 = require("os");
97041
97196
  var import_node_path30 = require("path");
97042
97197
  async function runSkillsCommand(args) {
97043
97198
  const [subcommand, ...options] = args;
97044
- const homeDirectory2 = option(options, "--home") ?? (0, import_node_os18.homedir)();
97199
+ const homeDirectory2 = option(options, "--home") ?? (0, import_node_os19.homedir)();
97045
97200
  const manager = await RuntimeSkillManager.open({ homeDirectory: homeDirectory2 });
97046
97201
  if (subcommand === "scan") {
97047
97202
  const inputPath = option(options, "--input");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alan-ai-hq/agent-manager",
3
- "version": "0.1.88",
3
+ "version": "0.1.89",
4
4
  "type": "module",
5
5
  "description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
6
6
  "bin": {
@@ -40,7 +40,6 @@
40
40
  "test:coverage": "vitest run --coverage",
41
41
  "test:watch": "vitest",
42
42
  "type-check": "tsc --noEmit",
43
- "publish:npm": "node ../../scripts/publish-agent-manager.mjs",
44
- "publish:npm:legacy": "node ../../scripts/publish-agent-manager.mjs --legacy-only"
43
+ "publish:npm": "node ../../scripts/publish-agent-manager.mjs"
45
44
  }
46
45
  }