@aiden-ade/sandbox-agent 0.1.79 → 0.1.82

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 +1362 -612
  2. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -14973,7 +14973,7 @@ function resolveCommand(args, env) {
14973
14973
 
14974
14974
  // src/daemon.ts
14975
14975
  var import_node_crypto17 = require("crypto");
14976
- var import_node_os11 = require("os");
14976
+ var import_node_os12 = require("os");
14977
14977
 
14978
14978
  // src/sleep-inhibitor.ts
14979
14979
  var import_node_child_process2 = require("child_process");
@@ -15240,7 +15240,7 @@ function describeError(error61) {
15240
15240
  }
15241
15241
 
15242
15242
  // src/version.ts
15243
- var AGENT_VERSION = "0.1.79";
15243
+ var AGENT_VERSION = "0.1.82";
15244
15244
 
15245
15245
  // src/daemon-worktree.ts
15246
15246
  var import_node_child_process3 = require("child_process");
@@ -15296,104 +15296,6 @@ function isInteractiveToolName(name, input2) {
15296
15296
  var ALAN_AGENT_WORKOS_USER_ID_PREFIX = "alan-agent:";
15297
15297
  var ALAN_AGENT_WORKOS_USER_ID_LIKE_PATTERN = `${ALAN_AGENT_WORKOS_USER_ID_PREFIX}%`;
15298
15298
 
15299
- // ../shared/dist/constants/colors.js
15300
- var CATEGORICAL_COLORS = {
15301
- slate: "#7280a0",
15302
- slateMuted: "#8892a4",
15303
- slateCool: "#6b7a96",
15304
- slateDeep: "#64748b",
15305
- slateClosed: "#7a8295",
15306
- slateLight: "#94a3b8",
15307
- slatePale: "#cbd5e1",
15308
- blue: "#5583b5",
15309
- blueMuted: "#6a90b0",
15310
- blueBright: "#3b82f6",
15311
- blueSoft: "#7d9fc2",
15312
- cyan: "#3a92a8",
15313
- cyanBright: "#2f9ab5",
15314
- cyanSoft: "#6dadb8",
15315
- teal: "#4895a5",
15316
- tealDeep: "#2e9e80",
15317
- green: "#3d9170",
15318
- greenBright: "#3a9c6f",
15319
- greenMuted: "#5a9a6a",
15320
- greenSoft: "#6daa94",
15321
- greenLeaf: "#74b080",
15322
- purple: "#7e6db2",
15323
- dubaiPurple: "#6366f1",
15324
- purpleMuted: "#9a6daa",
15325
- purpleSoft: "#9a8cbd",
15326
- violet: "#8b6bbf",
15327
- indigo: "#6b75d6",
15328
- indigoMuted: "#838cc0",
15329
- gold: "#b08a45",
15330
- goldMuted: "#a89248",
15331
- amber: "#c49a30",
15332
- yellow: "#eab308",
15333
- orange: "#c27058",
15334
- orangeDeep: "#c47d3a",
15335
- orangeBright: "#f97316",
15336
- orangeSoft: "#d49872",
15337
- orangePale: "#fdba74",
15338
- red: "#c25858",
15339
- redBright: "#ef4444",
15340
- redSoft: "#c47474",
15341
- pink: "#b25a8a",
15342
- pinkMuted: "#b86078",
15343
- pinkSoft: "#c07a9a",
15344
- rose: "#c44d8a",
15345
- bronze: "#8a8258",
15346
- avatarBlue: "#4a7fc4",
15347
- avatarPurple: "#7b62c4",
15348
- avatarOrange: "#c4703a"
15349
- };
15350
- var CATEGORICAL_COLOR_VALUES = Object.values(CATEGORICAL_COLORS);
15351
- var CATEGORICAL_COLOR_VALUE_SET = new Set(CATEGORICAL_COLOR_VALUES);
15352
-
15353
- // ../shared/dist/constants/labels.js
15354
- var LABEL_COLOR_PRESETS = {
15355
- bug: CATEGORICAL_COLORS.red,
15356
- feature: CATEGORICAL_COLORS.purple,
15357
- improvement: CATEGORICAL_COLORS.blue,
15358
- refactor: CATEGORICAL_COLORS.gold,
15359
- docs: CATEGORICAL_COLORS.green,
15360
- chore: CATEGORICAL_COLORS.slate,
15361
- design: CATEGORICAL_COLORS.pink,
15362
- research: CATEGORICAL_COLORS.cyan
15363
- };
15364
- var LABEL_COLOR_PALETTE = [
15365
- CATEGORICAL_COLORS.orange,
15366
- CATEGORICAL_COLORS.goldMuted,
15367
- CATEGORICAL_COLORS.greenMuted,
15368
- CATEGORICAL_COLORS.teal,
15369
- CATEGORICAL_COLORS.indigo,
15370
- CATEGORICAL_COLORS.purpleMuted,
15371
- CATEGORICAL_COLORS.pinkMuted,
15372
- CATEGORICAL_COLORS.bronze,
15373
- CATEGORICAL_COLORS.blueMuted
15374
- ];
15375
- var LABEL_COLOR_CHOICES = [
15376
- CATEGORICAL_COLORS.slate,
15377
- CATEGORICAL_COLORS.blue,
15378
- CATEGORICAL_COLORS.purple,
15379
- CATEGORICAL_COLORS.green,
15380
- CATEGORICAL_COLORS.red,
15381
- CATEGORICAL_COLORS.orange,
15382
- CATEGORICAL_COLORS.gold,
15383
- CATEGORICAL_COLORS.pink,
15384
- CATEGORICAL_COLORS.cyan,
15385
- CATEGORICAL_COLORS.teal
15386
- ];
15387
- var AVATAR_COLOR_PALETTE = [
15388
- CATEGORICAL_COLORS.avatarBlue,
15389
- CATEGORICAL_COLORS.avatarPurple,
15390
- CATEGORICAL_COLORS.indigo,
15391
- CATEGORICAL_COLORS.rose,
15392
- CATEGORICAL_COLORS.avatarOrange,
15393
- CATEGORICAL_COLORS.greenBright,
15394
- CATEGORICAL_COLORS.cyanBright
15395
- ];
15396
-
15397
15299
  // ../shared/dist/constants/local-workspace.js
15398
15300
  var ALAN_DEFAULT_WORKSPACE_URI = "alan://workspace";
15399
15301
  function isAlanDefaultWorkspace(value2) {
@@ -15412,172 +15314,12 @@ Before create_task:
15412
15314
  4. Use list_team_labels and apply matching labels when creating or updating; do not invent label variants.
15413
15315
  5. Similarity hits are hints only \u2014 synthesize context and use judgment, not fixed thresholds.`;
15414
15316
 
15415
- // ../shared/dist/constants/tasks.js
15416
- var STATUS_OPTIONS = [
15417
- {
15418
- value: "backlog",
15419
- label: "Backlog",
15420
- color: CATEGORICAL_COLORS.slateMuted,
15421
- group: "not_started",
15422
- dotClass: "text-muted-foreground",
15423
- headerBg: "bg-muted/60"
15424
- },
15425
- {
15426
- value: "todo",
15427
- label: "Todo",
15428
- color: CATEGORICAL_COLORS.slateCool,
15429
- group: "not_started",
15430
- dotClass: "text-muted-foreground/70",
15431
- headerBg: "bg-muted/40"
15432
- },
15433
- {
15434
- value: "in_progress",
15435
- label: "In Progress",
15436
- color: CATEGORICAL_COLORS.amber,
15437
- group: "active",
15438
- dotClass: "text-amber-700 dark:text-amber-400",
15439
- headerBg: "bg-amber-400/15"
15440
- },
15441
- {
15442
- value: "in_review",
15443
- label: "In Review",
15444
- color: CATEGORICAL_COLORS.violet,
15445
- group: "active",
15446
- dotClass: "text-violet-500 dark:text-violet-400",
15447
- headerBg: "bg-violet-400/15"
15448
- },
15449
- {
15450
- value: "done",
15451
- label: "Done",
15452
- color: CATEGORICAL_COLORS.tealDeep,
15453
- group: "done",
15454
- dotClass: "text-teal-600 dark:text-teal-400",
15455
- headerBg: "bg-teal-400/15"
15456
- },
15457
- {
15458
- value: "cancelled",
15459
- label: "Cancelled",
15460
- color: CATEGORICAL_COLORS.slateClosed,
15461
- group: "closed",
15462
- dotClass: "text-muted-foreground/60",
15463
- headerBg: "bg-muted/60"
15464
- }
15465
- ];
15466
- var DEFAULT_TEAM_STATUSES = STATUS_OPTIONS.map((o) => ({
15467
- id: o.value,
15468
- label: o.label,
15469
- color: o.color,
15470
- group: o.group
15471
- }));
15472
- var EPIC_STATUS_OPTIONS = [
15473
- {
15474
- value: "backlog",
15475
- label: "Backlog",
15476
- color: CATEGORICAL_COLORS.slateMuted,
15477
- group: "not_started"
15478
- },
15479
- {
15480
- value: "planned",
15481
- label: "Planned",
15482
- color: CATEGORICAL_COLORS.blueSoft,
15483
- group: "not_started"
15484
- },
15485
- {
15486
- value: "in_progress",
15487
- label: "In Progress",
15488
- color: CATEGORICAL_COLORS.amber,
15489
- group: "active"
15490
- },
15491
- {
15492
- value: "completed",
15493
- label: "Completed",
15494
- color: CATEGORICAL_COLORS.tealDeep,
15495
- group: "done"
15496
- },
15497
- {
15498
- value: "canceled",
15499
- label: "Canceled",
15500
- color: CATEGORICAL_COLORS.slateClosed,
15501
- group: "closed"
15502
- }
15503
- ];
15504
- var DEFAULT_EPIC_STATUSES = EPIC_STATUS_OPTIONS.map((o) => ({
15505
- id: o.value,
15506
- label: o.label,
15507
- color: o.color,
15508
- group: o.group
15509
- }));
15510
- var PRIORITY_OPTIONS = [
15511
- {
15512
- value: "p0",
15513
- label: "Urgent",
15514
- detail: "Urgent",
15515
- color: CATEGORICAL_COLORS.redBright,
15516
- iconClass: "text-red-500/70",
15517
- flagClass: "text-red-600 dark:text-red-400"
15518
- },
15519
- {
15520
- value: "p1",
15521
- label: "High",
15522
- detail: "High",
15523
- color: CATEGORICAL_COLORS.orangeBright,
15524
- iconClass: "text-orange-500/70",
15525
- flagClass: "text-orange-600 dark:text-orange-400"
15526
- },
15527
- {
15528
- value: "p2",
15529
- label: "Medium",
15530
- detail: "Medium",
15531
- color: CATEGORICAL_COLORS.yellow,
15532
- iconClass: "text-amber-500/70 dark:text-amber-400/70",
15533
- flagClass: "text-amber-600 dark:text-amber-400"
15534
- },
15535
- {
15536
- value: "p3",
15537
- label: "Low",
15538
- detail: "Low",
15539
- color: CATEGORICAL_COLORS.blueBright,
15540
- iconClass: "text-blue-500/70 dark:text-blue-400/70",
15541
- flagClass: "text-blue-600 dark:text-blue-400"
15542
- },
15543
- {
15544
- value: "none",
15545
- label: "No priority",
15546
- detail: "No priority",
15547
- color: CATEGORICAL_COLORS.slateDeep,
15548
- iconClass: "text-muted-foreground/40",
15549
- flagClass: "text-muted-foreground/50"
15550
- }
15551
- ];
15552
-
15553
- // ../shared/dist/constants/workspace-retention.js
15554
- var RESOURCE_CLASS_GC_TIME_MS = {
15555
- /**
15556
- * Small, stable, expensive-to-refetch descriptors: team lists, member lists,
15557
- * label sets, status metadata. Kilobytes that rarely change.
15558
- */
15559
- metadata: 30 * 6e4,
15560
- /** Everything not explicitly classified. The previous global default. */
15561
- standard: 10 * 6e4,
15562
- /**
15563
- * Large per-entity payloads: transcripts, diffs, file trees, image sets,
15564
- * paginated bulk lists. Megabytes that are cheap to re-fetch on return.
15565
- */
15566
- bulk: 9e4,
15567
- /**
15568
- * Immutable content addressed by a content hash (commit diffs). Retaining it
15569
- * is a pure win while it fits the budget, and the budget controller drops it
15570
- * first under pressure precisely because it can always be re-derived.
15571
- */
15572
- immutable: 60 * 6e4
15573
- };
15574
-
15575
15317
  // ../shared/dist/node/local-workspace.js
15576
15318
  var import_node_fs2 = require("fs");
15577
15319
  var import_node_os2 = require("os");
15578
15320
  var import_node_path2 = require("path");
15579
- function resolveAlanDefaultWorkspacePath(homeDirectory = (0, import_node_os2.homedir)()) {
15580
- return (0, import_node_path2.join)(homeDirectory, ".alan", "workspace");
15321
+ function resolveAlanDefaultWorkspacePath(homeDirectory2 = (0, import_node_os2.homedir)()) {
15322
+ return (0, import_node_path2.join)(homeDirectory2, ".alan", "workspace");
15581
15323
  }
15582
15324
 
15583
15325
  // src/local-workspace-migration.ts
@@ -35665,6 +35407,22 @@ var import_node_os4 = require("os");
35665
35407
  var import_node_path5 = require("path");
35666
35408
  var DEFAULT_AGENT_DIR = (0, import_node_path5.join)((0, import_node_os4.homedir)(), ".alan", "agent");
35667
35409
  var LEGACY_AGENT_DIR = (0, import_node_path5.join)((0, import_node_os4.homedir)(), ".aiden", "agent");
35410
+ function configuredConfigPathFromEnvironment() {
35411
+ const explicit = process.env.ALAN_AGENT_CONFIG_PATH?.trim() || process.env.ALAN_AGENT_CONFIG?.trim();
35412
+ return explicit || void 0;
35413
+ }
35414
+ function resolveIsolatedAgentBaseDir(profile) {
35415
+ switch (profile) {
35416
+ case "local":
35417
+ return (0, import_node_path5.join)((0, import_node_os4.homedir)(), ".alan-dev", "agent");
35418
+ case "staging":
35419
+ return (0, import_node_path5.join)((0, import_node_os4.homedir)(), ".alan-staging", "agent");
35420
+ case "custom":
35421
+ return (0, import_node_path5.join)((0, import_node_os4.homedir)(), ".alan-prod", "agent");
35422
+ default:
35423
+ return null;
35424
+ }
35425
+ }
35668
35426
  var AGENT_CONFIG_KEYS = /* @__PURE__ */ new Map([
35669
35427
  ["apiUrl", "string"],
35670
35428
  ["wsUrl", "string"],
@@ -35742,9 +35500,13 @@ function resolveAgentConfigPath(input2) {
35742
35500
  const profile = normalizeAgentEndpointProfile(
35743
35501
  typeof input2?.profile === "string" ? input2.profile : input2?.profile ?? null
35744
35502
  ) ?? "production";
35745
- const baseDir = input2?.baseDir ?? DEFAULT_AGENT_DIR;
35746
- if (input2?.baseDir === void 0) migrateLegacyAgentConfig({ profile });
35747
- return (0, import_node_path5.join)(baseDir, resolveAgentConfigFileName(profile));
35503
+ if (input2?.baseDir !== void 0) {
35504
+ return (0, import_node_path5.join)(input2.baseDir, resolveAgentConfigFileName(profile));
35505
+ }
35506
+ const isolatedBaseDir = profile === "production" ? null : resolveIsolatedAgentBaseDir(profile);
35507
+ if (isolatedBaseDir) return (0, import_node_path5.join)(isolatedBaseDir, "config.json");
35508
+ migrateLegacyAgentConfig({ profile });
35509
+ return (0, import_node_path5.join)(DEFAULT_AGENT_DIR, resolveAgentConfigFileName(profile));
35748
35510
  }
35749
35511
  function configExistsAtPath(configPath) {
35750
35512
  return (0, import_node_fs5.existsSync)(configPath);
@@ -35760,13 +35522,22 @@ function explicitConfigPathFromArgs(args) {
35760
35522
  const prefix = "--config-path=";
35761
35523
  return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length).trim() || void 0;
35762
35524
  }
35525
+ function hasExplicitProfileArg(args) {
35526
+ return args.some((arg) => arg === "--profile" || arg.startsWith("--profile="));
35527
+ }
35763
35528
  function bindAgentConfigPathFromArgs(args) {
35764
35529
  const argumentPath = explicitConfigPathFromArgs(args);
35765
35530
  if (argumentPath) {
35766
35531
  process.env.ALAN_AGENT_CONFIG_PATH = argumentPath;
35767
35532
  return argumentPath;
35768
35533
  }
35769
- const explicit = process.env.ALAN_AGENT_CONFIG_PATH?.trim();
35534
+ if (hasExplicitProfileArg(args)) {
35535
+ const profile2 = resolveEndpointProfileFromArgs(args);
35536
+ const configPath2 = resolveAgentConfigPath({ profile: profile2 });
35537
+ process.env.ALAN_AGENT_CONFIG_PATH = configPath2;
35538
+ return configPath2;
35539
+ }
35540
+ const explicit = configuredConfigPathFromEnvironment();
35770
35541
  if (explicit) return explicit;
35771
35542
  const profile = resolveEndpointProfileFromArgs(args);
35772
35543
  const configPath = resolveAgentConfigPath({ profile });
@@ -37182,16 +36953,6 @@ function isCodexTransientReconnectNotice(message) {
37182
36953
  return false;
37183
36954
  }
37184
36955
 
37185
- // ../shared/dist/utils/agent-run-status.js
37186
- var ACTIVE_AGENT_RUN_STATUSES = [
37187
- "pending",
37188
- "awaiting_agent",
37189
- "awaiting_sandbox",
37190
- "dispatched",
37191
- "running"
37192
- ];
37193
- var STOPPABLE_AGENT_RUN_STATUSES = [...ACTIVE_AGENT_RUN_STATUSES, "paused"];
37194
-
37195
36956
  // ../shared/dist/agent/types.js
37196
36957
  function resolveEffectiveBackendKind(backendKind) {
37197
36958
  if (backendKind === "codex")
@@ -39162,6 +38923,8 @@ function classifyCliErrorDetailed(stderr, _exitCode, opts) {
39162
38923
  "grok build usage balance"
39163
38924
  ) || has("payment required") && has("status 402"))
39164
38925
  return specForErrorKind("usage_limit");
38926
+ if (has("creditserror", "no payment method")) return specForErrorKind("subscription_required");
38927
+ if (has("datapolicyerror", "requires explicit opt in")) return specForErrorKind("model_mismatch");
39165
38928
  if (has("no chat found", "chat not found", "session not found", "could not resume"))
39166
38929
  return specForErrorKind("resume_failed");
39167
38930
  if (has("rate_limit", "rate limit") || /\b429\b/.test(haystack))
@@ -45744,6 +45507,20 @@ function classifyOpenCodeError(errorRecord, fallbackMessage) {
45744
45507
  recoveryClass: "user_fixable"
45745
45508
  };
45746
45509
  }
45510
+ if (name === "CreditsError") {
45511
+ return {
45512
+ message: extracted || fallbackMessage,
45513
+ errorKind: "subscription_required",
45514
+ recoveryClass: "user_fixable"
45515
+ };
45516
+ }
45517
+ if (name === "DataPolicyError") {
45518
+ return {
45519
+ message: extracted || fallbackMessage,
45520
+ errorKind: "model_mismatch",
45521
+ recoveryClass: "user_fixable"
45522
+ };
45523
+ }
45747
45524
  const message = extracted || fallbackMessage;
45748
45525
  const detailed = classifyCliErrorDetailed(message, 1);
45749
45526
  return { message, errorKind: detailed.errorKind, recoveryClass: detailed.recoveryClass };
@@ -49088,9 +48865,14 @@ function removeAlanOwnedLocalArtifacts() {
49088
48865
 
49089
48866
  // src/provider-model-discovery.ts
49090
48867
  var import_node_fs12 = require("fs");
48868
+ var import_node_os6 = require("os");
48869
+ var import_node_path11 = require("path");
49091
48870
  var MODEL_DISCOVERY_TIMEOUT_MS = 8e3;
49092
48871
  var ANTIGRAVITY_MODEL_DISCOVERY_TIMEOUT_MS = 12e3;
49093
48872
  var OPENCODE_ZEN_MODEL_IDS = OPENCODE_ZEN_MODELS.map((model) => model.id);
48873
+ var OPENCODE_ZEN_STATIC_BILLING = new Map(
48874
+ OPENCODE_ZEN_MODELS.filter((model) => model.billing).map((model) => [model.id, model.billing])
48875
+ );
49094
48876
  var CLAUDE_MODEL_ID_PATTERN = /claude-(?:sonnet|opus|haiku|fable)-[a-z0-9][a-z0-9-]*/g;
49095
48877
  var CLAUDE_MODEL_ALIASES = ["sonnet", "opus", "haiku", "fable"];
49096
48878
  var CLAUDE_MODEL_ALIAS_SET = new Set(CLAUDE_MODEL_ALIASES);
@@ -49162,7 +48944,7 @@ function extractCodexDiscoveredModelIdsFromDebugJson(value2) {
49162
48944
  }
49163
48945
  return [...new Set(ids)];
49164
48946
  }
49165
- var OPENCODE_MODEL_ID_LINE_PATTERN = /^[a-z0-9][\w.-]*\/[\w.-]+$/i;
48947
+ var OPENCODE_MODEL_ID_LINE_PATTERN = /^[a-z0-9][\w.-]*(?:\/[\w.-]+)+$/i;
49166
48948
  function parseOpenCodeVerboseModelOutput(text) {
49167
48949
  const entries = [];
49168
48950
  const lines = text.split(/\r?\n/);
@@ -49350,7 +49132,190 @@ async function probeJsonOrTextModels(executable, env, argSets, options) {
49350
49132
  }
49351
49133
  return [];
49352
49134
  }
49135
+ var OPENCODE_ZEN_MODELS_URL = "https://opencode.ai/zen/v1/models";
49136
+ var ZEN_ENTITLEMENT_TIMEOUT_MS = 5e3;
49137
+ var OPENCODE_ZEN_ID_PREFIX = "opencode/";
49138
+ function readOpenCodeZenCredential(env) {
49139
+ const direct = env.OPENCODE_API_KEY?.trim();
49140
+ if (direct) return direct;
49141
+ return readZenCredentialFromAuthDocument(readOpenCodeAuthDocument(env) ?? void 0);
49142
+ }
49143
+ function readOpenCodeAuthDocument(env) {
49144
+ const injected = env.OPENCODE_AUTH_CONTENT?.trim();
49145
+ if (injected) return injected;
49146
+ const dataHome = env.XDG_DATA_HOME?.trim() || (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".local", "share");
49147
+ try {
49148
+ return (0, import_node_fs12.readFileSync)((0, import_node_path11.join)(dataHome, "opencode", "auth.json"), "utf8");
49149
+ } catch {
49150
+ return null;
49151
+ }
49152
+ }
49153
+ var OPENCODE_PROVIDER_ENV_KEYS = [
49154
+ ["OPENROUTER_API_KEY", "openrouter"],
49155
+ ["ANTHROPIC_API_KEY", "anthropic"],
49156
+ ["OPENAI_API_KEY", "openai"],
49157
+ ["GEMINI_API_KEY", "google"],
49158
+ ["GOOGLE_GENERATIVE_AI_API_KEY", "google"],
49159
+ ["XAI_API_KEY", "xai"],
49160
+ ["GROQ_API_KEY", "groq"],
49161
+ ["MISTRAL_API_KEY", "mistral"],
49162
+ ["DEEPSEEK_API_KEY", "deepseek"]
49163
+ ];
49164
+ function readConfiguredOpenCodeProviders(env) {
49165
+ const configured = /* @__PURE__ */ new Set(["opencode", "opencode-go"]);
49166
+ const document2 = readOpenCodeAuthDocument(env);
49167
+ if (document2) {
49168
+ try {
49169
+ const parsed = JSON.parse(document2);
49170
+ if (parsed && typeof parsed === "object") {
49171
+ for (const providerId of Object.keys(parsed)) configured.add(providerId);
49172
+ }
49173
+ } catch {
49174
+ }
49175
+ }
49176
+ for (const [envKey, namespace] of OPENCODE_PROVIDER_ENV_KEYS) {
49177
+ if (env[envKey]?.trim()) configured.add(namespace);
49178
+ }
49179
+ return configured;
49180
+ }
49181
+ function readZenCredentialFromAuthDocument(content) {
49182
+ const trimmed = content?.trim();
49183
+ if (!trimmed) return null;
49184
+ try {
49185
+ const entry = JSON.parse(trimmed).opencode;
49186
+ if (!entry || typeof entry !== "object") return null;
49187
+ const { key, access: access2 } = entry;
49188
+ for (const candidate of [key, access2]) {
49189
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
49190
+ }
49191
+ return null;
49192
+ } catch {
49193
+ return null;
49194
+ }
49195
+ }
49196
+ async function fetchZenEntitledModelIds(credential) {
49197
+ try {
49198
+ const response = await fetch(OPENCODE_ZEN_MODELS_URL, {
49199
+ headers: credential ? { Authorization: `Bearer ${credential}` } : {},
49200
+ signal: AbortSignal.timeout(ZEN_ENTITLEMENT_TIMEOUT_MS)
49201
+ });
49202
+ if (!response.ok) return null;
49203
+ const data = (await response.json())?.data;
49204
+ if (!Array.isArray(data)) return null;
49205
+ const ids = data.map((entry) => entry?.id).filter((id) => typeof id === "string" && id.length > 0);
49206
+ return ids.length > 0 ? new Set(ids) : null;
49207
+ } catch {
49208
+ return null;
49209
+ }
49210
+ }
49211
+ function applyZenEntitlement(discovery, entitled) {
49212
+ const zenId = (id) => `${OPENCODE_ZEN_ID_PREFIX}${id}`;
49213
+ const kept = discovery.models.filter(
49214
+ (id) => !id.startsWith(OPENCODE_ZEN_ID_PREFIX) || entitled.has(id.slice(OPENCODE_ZEN_ID_PREFIX.length))
49215
+ );
49216
+ const keptSet = new Set(kept);
49217
+ const scannedSet = new Set(discovery.models);
49218
+ const unscannedEntitled = [...entitled].map(zenId);
49219
+ return {
49220
+ ...discovery,
49221
+ models: [...kept, ...unscannedEntitled.filter((id) => !keptSet.has(id))],
49222
+ catalogModels: [
49223
+ ...discovery.catalogModels ?? discovery.models,
49224
+ ...unscannedEntitled.filter((id) => !scannedSet.has(id))
49225
+ ]
49226
+ };
49227
+ }
49228
+ var OPENCODE_CATALOGUE_CACHE_SEGMENTS = ["opencode", "models.json"];
49229
+ var OPENCODE_CACHE_PROVIDER_KEYS = ["opencode", "opencode-go"];
49230
+ function readOpenCodeCatalogueCache(env) {
49231
+ const cacheHome = env.XDG_CACHE_HOME?.trim() || (0, import_node_path11.join)((0, import_node_os6.homedir)(), ".cache");
49232
+ let parsed;
49233
+ try {
49234
+ parsed = JSON.parse(
49235
+ (0, import_node_fs12.readFileSync)((0, import_node_path11.join)(cacheHome, ...OPENCODE_CATALOGUE_CACHE_SEGMENTS), "utf8")
49236
+ );
49237
+ } catch {
49238
+ return null;
49239
+ }
49240
+ if (!parsed || typeof parsed !== "object") return null;
49241
+ const variants = {};
49242
+ const billing = {};
49243
+ const deprecated = /* @__PURE__ */ new Set();
49244
+ for (const providerKey of OPENCODE_CACHE_PROVIDER_KEYS) {
49245
+ const models = parsed[providerKey]?.models;
49246
+ if (!models || typeof models !== "object") continue;
49247
+ for (const [modelId, entry] of Object.entries(models)) {
49248
+ if (!entry || typeof entry !== "object") continue;
49249
+ const id = `${providerKey}/${modelId}`;
49250
+ const record2 = entry;
49251
+ if (record2.status === "deprecated") deprecated.add(id);
49252
+ const options = Array.isArray(record2.reasoning_options) ? record2.reasoning_options : [];
49253
+ const effort = options.find(
49254
+ (option2) => option2?.type === "effort"
49255
+ );
49256
+ const values = Array.isArray(effort?.values) ? effort.values.filter((value2) => typeof value2 === "string") : [];
49257
+ if (values.length > 0) variants[id] = values;
49258
+ const cost = record2.cost;
49259
+ if (typeof cost?.input === "number" && typeof cost?.output === "number") {
49260
+ billing[id] = cost.input === 0 && cost.output === 0 ? "free" : "paid";
49261
+ }
49262
+ }
49263
+ }
49264
+ return Object.keys(variants).length > 0 || Object.keys(billing).length > 0 ? { variants, billing, deprecated } : null;
49265
+ }
49266
+ function hydrateOpenCodeMetadata(discovery, cache2) {
49267
+ const ids = /* @__PURE__ */ new Set([...discovery.models, ...discovery.catalogModels ?? []]);
49268
+ const modelVariants = { ...discovery.modelVariants };
49269
+ const modelBilling = { ...discovery.modelBilling };
49270
+ for (const id of ids) {
49271
+ if (!Object.hasOwn(modelVariants, id) && cache2.variants[id]) {
49272
+ modelVariants[id] = cache2.variants[id];
49273
+ }
49274
+ if (!Object.hasOwn(modelBilling, id) && cache2.billing[id]) {
49275
+ modelBilling[id] = cache2.billing[id];
49276
+ }
49277
+ }
49278
+ return {
49279
+ ...discovery,
49280
+ ...Object.keys(modelVariants).length > 0 ? { modelVariants } : {},
49281
+ ...Object.keys(modelBilling).length > 0 ? { modelBilling } : {}
49282
+ };
49283
+ }
49353
49284
  async function discoverOpenCodeModels(executable, env) {
49285
+ const credential = readOpenCodeZenCredential(env);
49286
+ const [rawScan, entitled] = await Promise.all([
49287
+ scanOpenCodeModels(executable, env),
49288
+ fetchZenEntitledModelIds(credential)
49289
+ ]);
49290
+ const configured = readConfiguredOpenCodeProviders(env);
49291
+ const inConfigured = (id) => {
49292
+ const slash = id.indexOf("/");
49293
+ return slash > 0 && configured.has(id.slice(0, slash));
49294
+ };
49295
+ const scanned = {
49296
+ ...rawScan,
49297
+ models: rawScan.models.filter(inConfigured),
49298
+ ...rawScan.catalogModels ? { catalogModels: rawScan.catalogModels.filter(inConfigured) } : {}
49299
+ };
49300
+ const filtered = entitled ? applyZenEntitlement(scanned, entitled) : scanned;
49301
+ const cache2 = readOpenCodeCatalogueCache(env);
49302
+ const hydrated = cache2 ? hydrateOpenCodeMetadata(filtered, cache2) : filtered;
49303
+ const keyEntitled = credential && entitled ? entitled : null;
49304
+ const withoutDeprecated = cache2 ? hydrated.models.filter(
49305
+ (id) => !cache2.deprecated.has(id) || keyEntitled !== null && id.startsWith(OPENCODE_ZEN_ID_PREFIX) && keyEntitled.has(id.slice(OPENCODE_ZEN_ID_PREFIX.length))
49306
+ ) : hydrated.models;
49307
+ return {
49308
+ ...hydrated,
49309
+ models: credential ? withoutDeprecated : filterZenToFreeModels(withoutDeprecated, hydrated.modelBilling)
49310
+ };
49311
+ }
49312
+ function filterZenToFreeModels(models, billing) {
49313
+ return models.filter((id) => {
49314
+ if (!id.startsWith("opencode/") && !id.startsWith("opencode-go/")) return true;
49315
+ return (billing?.[id] ?? OPENCODE_ZEN_STATIC_BILLING.get(id)) === "free";
49316
+ });
49317
+ }
49318
+ async function scanOpenCodeModels(executable, env) {
49354
49319
  const verbose = await runCliProbeAsync(
49355
49320
  executable,
49356
49321
  withModelProbeEnv(env),
@@ -49613,6 +49578,7 @@ function discoverCapabilities() {
49613
49578
  available,
49614
49579
  ...version2 ? { version: version2 } : {},
49615
49580
  models: modelDiscovery?.models ?? [],
49581
+ ...modelDiscovery?.catalogModels ? { catalogModels: modelDiscovery.catalogModels } : {},
49616
49582
  ...modelDiscovery?.modelVariants ? { modelVariants: modelDiscovery.modelVariants } : {},
49617
49583
  ...modelDiscovery?.modelBilling ? { modelBilling: modelDiscovery.modelBilling } : {},
49618
49584
  lastCheckedAt: now,
@@ -49860,8 +49826,8 @@ function scheduleRuntimeModelScan(getBaseMetadata, options) {
49860
49826
  var import_node_crypto16 = require("crypto");
49861
49827
  var import_node_fs20 = require("fs");
49862
49828
  var import_node_http = __toESM(require("http"), 1);
49863
- var import_node_os10 = require("os");
49864
- var import_node_path22 = require("path");
49829
+ var import_node_os11 = require("os");
49830
+ var import_node_path23 = require("path");
49865
49831
 
49866
49832
  // ../../node_modules/engine.io-client/build/esm-debug/transports/polling-xhr.node.js
49867
49833
  var XMLHttpRequestModule = __toESM(require_XMLHttpRequest(), 1);
@@ -53421,8 +53387,8 @@ Object.assign(lookup, {
53421
53387
  var import_node_child_process7 = require("child_process");
53422
53388
  var import_node_crypto5 = require("crypto");
53423
53389
  var import_node_fs13 = require("fs");
53424
- var import_node_os6 = require("os");
53425
- var import_node_path11 = require("path");
53390
+ var import_node_os7 = require("os");
53391
+ var import_node_path12 = require("path");
53426
53392
  var import_node_url = require("url");
53427
53393
  var BINDING_SWITCH_GIT_METHODS = [
53428
53394
  "git.status",
@@ -53474,8 +53440,8 @@ async function waitForCheckpointTestBarrier() {
53474
53440
  const barrierDir = process.env.NODE_ENV === "test" ? process.env.ALAN_TEST_GIT_CHECKPOINT_BARRIER_DIR : void 0;
53475
53441
  if (!barrierDir) return;
53476
53442
  (0, import_node_fs13.mkdirSync)(barrierDir, { recursive: true });
53477
- const readyPath = (0, import_node_path11.join)(barrierDir, "ready");
53478
- const releasePath = (0, import_node_path11.join)(barrierDir, "release");
53443
+ const readyPath = (0, import_node_path12.join)(barrierDir, "ready");
53444
+ const releasePath = (0, import_node_path12.join)(barrierDir, "release");
53479
53445
  (0, import_node_fs13.writeFileSync)(readyPath, "ready\n");
53480
53446
  const deadline = Date.now() + 5e3;
53481
53447
  while (!(0, import_node_fs13.existsSync)(releasePath)) {
@@ -53492,8 +53458,8 @@ async function waitForCheckpointFinalizeTestBarrier() {
53492
53458
  const barrierDir = process.env.NODE_ENV === "test" ? process.env.ALAN_TEST_GIT_CHECKPOINT_FINALIZE_BARRIER_DIR : void 0;
53493
53459
  if (!barrierDir) return;
53494
53460
  (0, import_node_fs13.mkdirSync)(barrierDir, { recursive: true });
53495
- const readyPath = (0, import_node_path11.join)(barrierDir, "ready");
53496
- const releasePath = (0, import_node_path11.join)(barrierDir, "release");
53461
+ const readyPath = (0, import_node_path12.join)(barrierDir, "ready");
53462
+ const releasePath = (0, import_node_path12.join)(barrierDir, "release");
53497
53463
  (0, import_node_fs13.writeFileSync)(readyPath, "ready\n");
53498
53464
  const deadline = Date.now() + 5e3;
53499
53465
  while (!(0, import_node_fs13.existsSync)(releasePath)) {
@@ -53634,7 +53600,7 @@ function acquireCheckpointRepositoryLocks(repoRoot) {
53634
53600
  "checkpoint_lock_unavailable"
53635
53601
  );
53636
53602
  const locks = {
53637
- headLockPath: (0, import_node_path11.join)(gitDir, "HEAD.lock"),
53603
+ headLockPath: (0, import_node_path12.join)(gitDir, "HEAD.lock"),
53638
53604
  headLockHeld: false,
53639
53605
  indexLockPath: `${indexPath}.lock`,
53640
53606
  indexLockHeld: false,
@@ -53676,8 +53642,8 @@ function assertCheckpointHead(repoRoot, expectedRef, expectedHeadSha) {
53676
53642
  }
53677
53643
  }
53678
53644
  function createCheckpointIndexBaseline(repoRoot, checkpointSha) {
53679
- const tempDir = (0, import_node_fs13.mkdtempSync)((0, import_node_path11.join)((0, import_node_os6.tmpdir)(), "alan-checkpoint-index-"));
53680
- const indexPath = (0, import_node_path11.join)(tempDir, "index");
53645
+ const tempDir = (0, import_node_fs13.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "alan-checkpoint-index-"));
53646
+ const indexPath = (0, import_node_path12.join)(tempDir, "index");
53681
53647
  try {
53682
53648
  runGitWithOptions(
53683
53649
  repoRoot,
@@ -53738,7 +53704,7 @@ function commonRequest(params) {
53738
53704
  return {
53739
53705
  switchId: requiredString2(params, "switchId"),
53740
53706
  repoKey: requiredString2(params, "repoKey"),
53741
- repoPath: (0, import_node_path11.resolve)(requiredString2(params, "repoPath"))
53707
+ repoPath: (0, import_node_path12.resolve)(requiredString2(params, "repoPath"))
53742
53708
  };
53743
53709
  }
53744
53710
  function assertCommitSha(sha, key) {
@@ -53772,8 +53738,8 @@ function canonicalRemoteUrl(repoRoot, value2) {
53772
53738
  }
53773
53739
  const scpStyle = trimmed.match(/^([^/@:\s]+)@([^/:\s]+):(.+)$/);
53774
53740
  const urlValue = scpStyle ? `ssh://${scpStyle[1]}@${scpStyle[2]}/${scpStyle[3]}` : trimmed;
53775
- if ((0, import_node_path11.isAbsolute)(urlValue) || urlValue.startsWith("./") || urlValue.startsWith("../")) {
53776
- const absolute = (0, import_node_path11.isAbsolute)(urlValue) ? urlValue : (0, import_node_path11.resolve)(repoRoot, urlValue);
53741
+ if ((0, import_node_path12.isAbsolute)(urlValue) || urlValue.startsWith("./") || urlValue.startsWith("../")) {
53742
+ const absolute = (0, import_node_path12.isAbsolute)(urlValue) ? urlValue : (0, import_node_path12.resolve)(repoRoot, urlValue);
53777
53743
  return `file://${canonicalPathWithMissingTail(absolute).replace(/\/+$/, "").replace(/\.git$/, "")}`;
53778
53744
  }
53779
53745
  let parsed;
@@ -53839,24 +53805,24 @@ function inspectedRemoteUrl(repoRoot, params) {
53839
53805
  return urls[0];
53840
53806
  }
53841
53807
  function isPathContained2(childPath, parentPath) {
53842
- const rel = (0, import_node_path11.relative)((0, import_node_path11.resolve)(parentPath), (0, import_node_path11.resolve)(childPath));
53843
- return rel === "" || !(0, import_node_path11.isAbsolute)(rel) && rel !== ".." && !rel.startsWith(`..${import_node_path11.sep}`);
53808
+ const rel = (0, import_node_path12.relative)((0, import_node_path12.resolve)(parentPath), (0, import_node_path12.resolve)(childPath));
53809
+ return rel === "" || !(0, import_node_path12.isAbsolute)(rel) && rel !== ".." && !rel.startsWith(`..${import_node_path12.sep}`);
53844
53810
  }
53845
53811
  function canonicalPathWithMissingTail(path2) {
53846
53812
  const missingSegments = [];
53847
- let cursor = (0, import_node_path11.resolve)(path2);
53813
+ let cursor = (0, import_node_path12.resolve)(path2);
53848
53814
  while (!(0, import_node_fs13.existsSync)(cursor)) {
53849
- const parent = (0, import_node_path11.dirname)(cursor);
53815
+ const parent = (0, import_node_path12.dirname)(cursor);
53850
53816
  if (parent === cursor) {
53851
53817
  throw new BindingSwitchGitError(
53852
53818
  "path_canonicalization_failed",
53853
53819
  "The selected path has no existing canonical ancestor"
53854
53820
  );
53855
53821
  }
53856
- missingSegments.unshift((0, import_node_path11.basename)(cursor));
53822
+ missingSegments.unshift((0, import_node_path12.basename)(cursor));
53857
53823
  cursor = parent;
53858
53824
  }
53859
- return (0, import_node_path11.join)(import_node_fs13.realpathSync.native(cursor), ...missingSegments);
53825
+ return (0, import_node_path12.join)(import_node_fs13.realpathSync.native(cursor), ...missingSegments);
53860
53826
  }
53861
53827
  function assertCanonicalPathContained(childPath, parentPath, code, message) {
53862
53828
  if (!isPathContained2(
@@ -53867,7 +53833,7 @@ function assertCanonicalPathContained(childPath, parentPath, code, message) {
53867
53833
  }
53868
53834
  }
53869
53835
  function alanWorktreeRoot(projectRoot) {
53870
- return (0, import_node_path11.join)((0, import_node_path11.dirname)(projectRoot), `${(0, import_node_path11.basename)(projectRoot)}-alan-worktrees`);
53836
+ return (0, import_node_path12.join)((0, import_node_path12.dirname)(projectRoot), `${(0, import_node_path12.basename)(projectRoot)}-alan-worktrees`);
53871
53837
  }
53872
53838
  function resolveRepositoryRoot(requestedPath) {
53873
53839
  if (!(0, import_node_fs13.existsSync)(requestedPath)) {
@@ -53883,7 +53849,7 @@ function resolveRepositoryRoot(requestedPath) {
53883
53849
  "The selected folder is not inside a Git repository"
53884
53850
  );
53885
53851
  }
53886
- return import_node_fs13.realpathSync.native((0, import_node_path11.resolve)(root.stdout.trim()));
53852
+ return import_node_fs13.realpathSync.native((0, import_node_path12.resolve)(root.stdout.trim()));
53887
53853
  }
53888
53854
  function listWorktrees(repoRoot) {
53889
53855
  return runGit(repoRoot, ["worktree", "list", "--porcelain"]).split("\n\n").flatMap((entry) => {
@@ -53902,7 +53868,7 @@ function resolveAuthorizedRepository(params, requireTrustedContext = false) {
53902
53868
  const { repoPath } = commonRequest(params);
53903
53869
  const repoRoot = resolveRepositoryRoot(repoPath);
53904
53870
  const expectedRepoRoot = requireTrustedContext ? requiredString2(params, "expectedRepoRoot") : optionalString(params, "expectedRepoRoot");
53905
- if (expectedRepoRoot && resolveRepositoryRoot((0, import_node_path11.resolve)(expectedRepoRoot)) !== repoRoot) {
53871
+ if (expectedRepoRoot && resolveRepositoryRoot((0, import_node_path12.resolve)(expectedRepoRoot)) !== repoRoot) {
53906
53872
  throw new BindingSwitchGitError(
53907
53873
  "repository_path_changed",
53908
53874
  "The selected path now resolves to a different Git repository"
@@ -53910,7 +53876,7 @@ function resolveAuthorizedRepository(params, requireTrustedContext = false) {
53910
53876
  }
53911
53877
  const projectPath = requireTrustedContext ? requiredString2(params, "projectPath") : optionalString(params, "projectPath");
53912
53878
  if (!projectPath) return repoRoot;
53913
- const projectRoot = resolveRepositoryRoot((0, import_node_path11.resolve)(projectPath));
53879
+ const projectRoot = resolveRepositoryRoot((0, import_node_path12.resolve)(projectPath));
53914
53880
  const registrations = listWorktrees(projectRoot);
53915
53881
  const registered = registrations.find(({ path: path2 }) => path2 === repoRoot);
53916
53882
  if (!registered) {
@@ -53946,8 +53912,8 @@ function updateLengthPrefixed(hash2, value2) {
53946
53912
  hash2.update("\0");
53947
53913
  }
53948
53914
  function proposedTreeSha(repoRoot, headSha) {
53949
- const tempDir = (0, import_node_fs13.mkdtempSync)((0, import_node_path11.join)((0, import_node_os6.tmpdir)(), "alan-switch-index-"));
53950
- const indexPath = (0, import_node_path11.join)(tempDir, "index");
53915
+ const tempDir = (0, import_node_fs13.mkdtempSync)((0, import_node_path12.join)((0, import_node_os7.tmpdir)(), "alan-switch-index-"));
53916
+ const indexPath = (0, import_node_path12.join)(tempDir, "index");
53951
53917
  const options = { env: { GIT_INDEX_FILE: indexPath } };
53952
53918
  try {
53953
53919
  if (headSha) {
@@ -54409,12 +54375,12 @@ async function prepareWorktree(params) {
54409
54375
  "Worktree preparation requires the Project's main checkout"
54410
54376
  );
54411
54377
  }
54412
- const worktreePath = (0, import_node_path11.resolve)(requiredString2(params, "worktreePath"));
54378
+ const worktreePath = (0, import_node_path12.resolve)(requiredString2(params, "worktreePath"));
54413
54379
  const managedRoot = alanWorktreeRoot(projectRoot);
54414
54380
  const pathError = "The destination worktree path is outside the Alan-managed worktree directory";
54415
- const intendedManagedRoot = (0, import_node_path11.join)(
54416
- import_node_fs13.realpathSync.native((0, import_node_path11.dirname)(managedRoot)),
54417
- (0, import_node_path11.basename)(managedRoot)
54381
+ const intendedManagedRoot = (0, import_node_path12.join)(
54382
+ import_node_fs13.realpathSync.native((0, import_node_path12.dirname)(managedRoot)),
54383
+ (0, import_node_path12.basename)(managedRoot)
54418
54384
  );
54419
54385
  if (canonicalPathWithMissingTail(managedRoot) !== intendedManagedRoot) {
54420
54386
  throw new BindingSwitchGitError("worktree_path_not_authorized", pathError);
@@ -54474,7 +54440,7 @@ async function prepareWorktree(params) {
54474
54440
  );
54475
54441
  }
54476
54442
  }
54477
- (0, import_node_fs13.mkdirSync)((0, import_node_path11.dirname)(worktreePath), { recursive: true });
54443
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(worktreePath), { recursive: true });
54478
54444
  if (branchExists) {
54479
54445
  runGit(repoRoot, ["worktree", "add", worktreePath, branch], "worktree_prepare_failed");
54480
54446
  const currentHead = runGit(worktreePath, ["rev-parse", "HEAD"]);
@@ -54553,11 +54519,11 @@ async function executeBindingSwitchGitRpc(method, params) {
54553
54519
 
54554
54520
  // src/daemon-execute.ts
54555
54521
  var import_node_fs15 = require("fs");
54556
- var import_node_path13 = require("path");
54522
+ var import_node_path14 = require("path");
54557
54523
 
54558
54524
  // src/cli-ensure-install.ts
54559
54525
  var import_node_child_process8 = require("child_process");
54560
- var import_node_os7 = require("os");
54526
+ var import_node_os8 = require("os");
54561
54527
  var CLI_RUNTIME_VERSIONS_ENV = "ALAN_CLI_RUNTIME_VERSIONS";
54562
54528
  var INSTALLABLE_PROVIDER_PACKAGES = {
54563
54529
  claude_cli: { npmPackage: "@anthropic-ai/claude-code", command: "claude", label: "Claude Code" },
@@ -54585,7 +54551,7 @@ function versionPolicy(npmPackage) {
54585
54551
  }
54586
54552
  function runNpmInstall(installSpec, env, timeoutMs) {
54587
54553
  return new Promise((resolve15) => {
54588
- const isWin = (0, import_node_os7.platform)() === "win32";
54554
+ const isWin = (0, import_node_os8.platform)() === "win32";
54589
54555
  let child;
54590
54556
  try {
54591
54557
  child = (0, import_node_child_process8.spawn)("npm", ["install", "-g", installSpec], {
@@ -54655,13 +54621,13 @@ function ensureProviderCliInstalled(backendKind, options) {
54655
54621
  }
54656
54622
 
54657
54623
  // src/core-agent.ts
54658
- var import_node_os9 = require("os");
54624
+ var import_node_os10 = require("os");
54659
54625
 
54660
54626
  // src/mcp-registration.ts
54661
54627
  var import_node_crypto6 = require("crypto");
54662
54628
  var import_node_fs14 = require("fs");
54663
- var import_node_os8 = require("os");
54664
- var import_node_path12 = require("path");
54629
+ var import_node_os9 = require("os");
54630
+ var import_node_path13 = require("path");
54665
54631
 
54666
54632
  // ../../node_modules/smol-toml/dist/error.js
54667
54633
  function getLineColFromPtr(string4, ptr) {
@@ -55602,7 +55568,7 @@ var inspectAlanMcpThroughProviderCli = async (backendKind, expectedUrl, home) =>
55602
55568
  return result;
55603
55569
  };
55604
55570
  async function waitForConfigLock(lockPath) {
55605
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(lockPath), { recursive: true });
55571
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(lockPath), { recursive: true });
55606
55572
  const startedAt = Date.now();
55607
55573
  while (true) {
55608
55574
  try {
@@ -55683,8 +55649,8 @@ function atomicWriteManagedConfig(path2, content) {
55683
55649
  (0, import_node_fs14.rmSync)(pendingPath, { force: true });
55684
55650
  }
55685
55651
  }
55686
- async function configureAntigravityApiKeyMode(home = (0, import_node_os8.homedir)()) {
55687
- const path2 = (0, import_node_path12.join)(home, ".gemini", "antigravity-cli", "settings.json");
55652
+ async function configureAntigravityApiKeyMode(home = (0, import_node_os9.homedir)()) {
55653
+ const path2 = (0, import_node_path13.join)(home, ".gemini", "antigravity-cli", "settings.json");
55688
55654
  const releaseLock = await waitForConfigLock(`${path2}.alan-lock`);
55689
55655
  try {
55690
55656
  const existingContent = (0, import_node_fs14.existsSync)(path2) ? (0, import_node_fs14.readFileSync)(path2, "utf8") : "";
@@ -55697,13 +55663,13 @@ async function configureAntigravityApiKeyMode(home = (0, import_node_os8.homedir
55697
55663
  releaseLock();
55698
55664
  }
55699
55665
  }
55700
- async function ensureAlanMcpRegistered(backendKind, registration, home = (0, import_node_os8.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
55666
+ async function ensureAlanMcpRegistered(backendKind, registration, home = (0, import_node_os9.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
55701
55667
  try {
55702
55668
  const mcpServers = buildAlanMcpServers(registration);
55703
55669
  const files = alanMcpConfigFilesForBackend(backendKind, mcpServers, home);
55704
55670
  const paths = [];
55705
55671
  for (const file2 of files) {
55706
- (0, import_node_fs14.mkdirSync)((0, import_node_path12.dirname)(file2.path), { recursive: true });
55672
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(file2.path), { recursive: true });
55707
55673
  const releaseLock = await waitForConfigLock(`${file2.path}.alan-lock`);
55708
55674
  try {
55709
55675
  const current = (0, import_node_fs14.existsSync)(file2.path) ? (0, import_node_fs14.readFileSync)(file2.path, "utf8") : null;
@@ -55768,7 +55734,7 @@ async function ensureAlanMcpRegistered(backendKind, registration, home = (0, imp
55768
55734
  return { ok: false, paths: [], error: err instanceof Error ? err.message : String(err) };
55769
55735
  }
55770
55736
  }
55771
- async function restoreStaticAlanMcp(backendKind, apiUrl, home = (0, import_node_os8.homedir)()) {
55737
+ async function restoreStaticAlanMcp(backendKind, apiUrl, home = (0, import_node_os9.homedir)()) {
55772
55738
  let url3;
55773
55739
  try {
55774
55740
  url3 = new URL("/mcp", apiUrl).toString();
@@ -55784,7 +55750,7 @@ async function restoreStaticAlanMcp(backendKind, apiUrl, home = (0, import_node_
55784
55750
  verification: { method: "file" }
55785
55751
  }));
55786
55752
  }
55787
- async function verifyAlanMcpRegistered(backendKind, home = (0, import_node_os8.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
55753
+ async function verifyAlanMcpRegistered(backendKind, home = (0, import_node_os9.homedir)(), inspectCli = inspectAlanMcpThroughProviderCli) {
55788
55754
  const files = alanMcpConfigFilesForBackend(backendKind, {}, home);
55789
55755
  const missing = files.map((f) => f.path).filter((p) => !(0, import_node_fs14.existsSync)(p));
55790
55756
  const presentEntries = files.map((file2) => ({
@@ -56096,7 +56062,7 @@ var CoreAgent = class _CoreAgent extends BaseMachineAgent {
56096
56062
  if (backendKind === "antigravity_cli" && augmented.GEMINI_API_KEY?.trim()) {
56097
56063
  await configureAntigravityApiKeyMode(augmented.HOME ?? augmented.USERPROFILE);
56098
56064
  }
56099
- if ((0, import_node_os9.platform)() !== "win32") {
56065
+ if ((0, import_node_os10.platform)() !== "win32") {
56100
56066
  const home = augmented.HOME ?? "/home/user";
56101
56067
  const extraPaths = [`${home}/.local/node/bin`, `${home}/.local/bin`];
56102
56068
  const separator = ":";
@@ -60269,9 +60235,9 @@ function buildMcpParamHeaders(declarations, args) {
60269
60235
  for (const decl of declarations) {
60270
60236
  const raw = valueAtPath(args, decl.path);
60271
60237
  if (raw === void 0 || raw === null) continue;
60272
- const stringValue = mcpParamPrimitiveToString(raw);
60273
- if (stringValue === void 0) continue;
60274
- out[`${MCP_PARAM_HEADER_PREFIX}${decl.headerName}`] = encodeMcpParamValue(stringValue);
60238
+ const stringValue2 = mcpParamPrimitiveToString(raw);
60239
+ if (stringValue2 === void 0) continue;
60240
+ out[`${MCP_PARAM_HEADER_PREFIX}${decl.headerName}`] = encodeMcpParamValue(stringValue2);
60275
60241
  }
60276
60242
  return out;
60277
60243
  }
@@ -73145,24 +73111,24 @@ async function handleAgentExecute(ctx, payload) {
73145
73111
  let workspaceReadiness = inspectWorkspaceReadiness(workspaceRequired ? cwd : void 0);
73146
73112
  const expectedRepoUrls = [
73147
73113
  ...(payload.repoLocalPaths ?? []).filter(
73148
- (repo) => explicitWorkspacePath ? (0, import_node_path13.resolve)(repo.localPath) === (0, import_node_path13.resolve)(explicitWorkspacePath) : false
73114
+ (repo) => explicitWorkspacePath ? (0, import_node_path14.resolve)(repo.localPath) === (0, import_node_path14.resolve)(explicitWorkspacePath) : false
73149
73115
  ).map((repo) => repo.repoUrl),
73150
73116
  ...payload.localRepoUrls ?? []
73151
73117
  ];
73152
73118
  if (workspaceReadiness.code === "workspace_missing" && explicitWorkspacePath && !payload.worktreeInfo) {
73153
- const previousPath = (0, import_node_path13.resolve)(explicitWorkspacePath);
73119
+ const previousPath = (0, import_node_path14.resolve)(explicitWorkspacePath);
73154
73120
  const remembered = workspaceRelocations.get(previousPath);
73155
73121
  const rememberedPath = remembered?.canonicalPath;
73156
73122
  const relocated = rememberedPath && workspaceMatchesExpectedRepositories({
73157
73123
  workspacePath: rememberedPath,
73158
73124
  expectedRepoUrls
73159
- }) ? (0, import_node_path13.resolve)(rememberedPath) : discoverRelocatedWorkspace({
73125
+ }) ? (0, import_node_path14.resolve)(rememberedPath) : discoverRelocatedWorkspace({
73160
73126
  missingPath: explicitWorkspacePath,
73161
73127
  approvedWorkspacePaths: payload.approvedWorkspacePaths,
73162
73128
  expectedRepoUrls
73163
73129
  });
73164
73130
  if (relocated) {
73165
- if (!remembered || (0, import_node_path13.resolve)(remembered.canonicalPath) !== relocated) {
73131
+ if (!remembered || (0, import_node_path14.resolve)(remembered.canonicalPath) !== relocated) {
73166
73132
  workspaceRelocations.set(previousPath, {
73167
73133
  conversationId: payload.conversationId,
73168
73134
  runId: payload.runId,
@@ -73946,7 +73912,7 @@ function transcriptGraceExpired(observedAt, now, graceMs) {
73946
73912
  // src/native-hook-inbox.ts
73947
73913
  var import_node_crypto8 = require("crypto");
73948
73914
  var import_node_fs16 = require("fs");
73949
- var import_node_path14 = require("path");
73915
+ var import_node_path15 = require("path");
73950
73916
  var INBOX_FILE_VERSION = 1;
73951
73917
  var DEFAULT_MAX_BYTES = 64 * 1024 * 1024;
73952
73918
  var DEFAULT_MAX_ENTRIES = 1e4;
@@ -73993,8 +73959,8 @@ var EncryptedNativeHookInbox = class {
73993
73959
  };
73994
73960
  const monotonic = process.hrtime.bigint().toString().padStart(20, "0");
73995
73961
  const prefix = `${String(Date.now()).padStart(13, "0")}-${monotonic}-${envelope.eventId}`;
73996
- const temporaryPath = (0, import_node_path14.join)(this.path, `.${prefix}-${(0, import_node_crypto8.randomUUID)()}.tmp`);
73997
- const finalPath = (0, import_node_path14.join)(this.path, `${prefix}.event`);
73962
+ const temporaryPath = (0, import_node_path15.join)(this.path, `.${prefix}-${(0, import_node_crypto8.randomUUID)()}.tmp`);
73963
+ const finalPath = (0, import_node_path15.join)(this.path, `${prefix}.event`);
73998
73964
  (0, import_node_fs16.writeFileSync)(temporaryPath, JSON.stringify(file2), { mode: 384, flag: "wx" });
73999
73965
  (0, import_node_fs16.chmodSync)(temporaryPath, 384);
74000
73966
  (0, import_node_fs16.renameSync)(temporaryPath, finalPath);
@@ -74012,9 +73978,9 @@ var EncryptedNativeHookInbox = class {
74012
73978
  const result = { attempted: 0, acknowledged: 0, deferred: 0 };
74013
73979
  const names = encryptedEntryNames(this.path).filter((name) => name.endsWith(".event")).slice(0, Math.max(0, limit));
74014
73980
  for (const name of names) {
74015
- const sourcePath = (0, import_node_path14.join)(this.path, name);
73981
+ const sourcePath = (0, import_node_path15.join)(this.path, name);
74016
73982
  const claimedName = `${name.slice(0, -".event".length)}.processing-${(0, import_node_crypto8.randomUUID)()}`;
74017
- const claimedPath = (0, import_node_path14.join)(this.path, claimedName);
73983
+ const claimedPath = (0, import_node_path15.join)(this.path, claimedName);
74018
73984
  try {
74019
73985
  (0, import_node_fs16.renameSync)(sourcePath, claimedPath);
74020
73986
  } catch {
@@ -74061,14 +74027,14 @@ var EncryptedNativeHookInbox = class {
74061
74027
  if (name.endsWith(".quarantine")) continue;
74062
74028
  const marker = name.indexOf(".processing-");
74063
74029
  if (marker === -1) continue;
74064
- const claimedPath = (0, import_node_path14.join)(this.path, name);
74065
- const eventPath = (0, import_node_path14.join)(this.path, `${name.slice(0, marker)}.event`);
74030
+ const claimedPath = (0, import_node_path15.join)(this.path, name);
74031
+ const eventPath = (0, import_node_path15.join)(this.path, `${name.slice(0, marker)}.event`);
74066
74032
  if ((0, import_node_fs16.existsSync)(eventPath)) (0, import_node_fs16.rmSync)(claimedPath, { force: true });
74067
74033
  else (0, import_node_fs16.renameSync)(claimedPath, eventPath);
74068
74034
  }
74069
74035
  }
74070
74036
  enforceBounds() {
74071
- const entries = encryptedEntryNames(this.path).filter((name) => name.endsWith(".event")).map((name) => ({ name, bytes: (0, import_node_fs16.statSync)((0, import_node_path14.join)(this.path, name)).size }));
74037
+ const entries = encryptedEntryNames(this.path).filter((name) => name.endsWith(".event")).map((name) => ({ name, bytes: (0, import_node_fs16.statSync)((0, import_node_path15.join)(this.path, name)).size }));
74072
74038
  const totalBytes = entries.reduce((sum, entry) => sum + entry.bytes, 0);
74073
74039
  if (entries.length > this.maxEntries || totalBytes > this.maxBytes) {
74074
74040
  throw new Error(
@@ -74078,13 +74044,13 @@ var EncryptedNativeHookInbox = class {
74078
74044
  }
74079
74045
  };
74080
74046
  function nativeHookInboxPath(configPath) {
74081
- return (0, import_node_path14.join)((0, import_node_path14.dirname)(configPath), "native-hook-inbox");
74047
+ return (0, import_node_path15.join)((0, import_node_path15.dirname)(configPath), "native-hook-inbox");
74082
74048
  }
74083
74049
 
74084
74050
  // src/native-transcript-cursor.ts
74085
74051
  var import_node_crypto9 = require("crypto");
74086
74052
  var import_node_fs17 = require("fs");
74087
- var import_node_path15 = require("path");
74053
+ var import_node_path16 = require("path");
74088
74054
  var CURSOR_FILE_VERSION = 1;
74089
74055
  function nativeTranscriptCursorKey(input2) {
74090
74056
  return (0, import_node_crypto9.createHash)("sha256").update(`${input2.provider}\0${input2.externalSessionId}\0${input2.transcriptPath}`).digest("base64url");
@@ -74115,7 +74081,7 @@ var NativeTranscriptCursorStore = class {
74115
74081
  return parsed.entries;
74116
74082
  }
74117
74083
  persist() {
74118
- (0, import_node_fs17.mkdirSync)((0, import_node_path15.dirname)(this.path), { recursive: true, mode: 448 });
74084
+ (0, import_node_fs17.mkdirSync)((0, import_node_path16.dirname)(this.path), { recursive: true, mode: 448 });
74119
74085
  const pendingPath = `${this.path}.pending-${process.pid}-${(0, import_node_crypto9.randomBytes)(6).toString("hex")}`;
74120
74086
  try {
74121
74087
  (0, import_node_fs17.writeFileSync)(
@@ -74228,7 +74194,7 @@ var NativeTranscriptStreamer = class {
74228
74194
  continue;
74229
74195
  }
74230
74196
  const parsed = parseJsonObject3(raw);
74231
- const events = parsed ? claudeRecordToAgentEvents(parsed) : [];
74197
+ const events = parsed ? providerRecordToAgentEvents(hook.provider, parsed) : [];
74232
74198
  for (let index = 0; index < events.length; index += 1) {
74233
74199
  const deliveredEvent = events[index];
74234
74200
  const sourceCursor = `${start.generation}:${recordEndOffset}:${index}`;
@@ -74288,12 +74254,62 @@ function parseJsonObject3(value2) {
74288
74254
  return null;
74289
74255
  }
74290
74256
  }
74291
- function claudeRecordToAgentEvents(record2) {
74257
+ function providerRecordToAgentEvents(provider, record2) {
74258
+ if (provider === "codex") return codexRecordToAgentEvents(record2);
74259
+ if (provider === "copilot") return copilotRecordToAgentEvents(record2);
74260
+ return claudeCompatibleRecordToAgentEvents(record2);
74261
+ }
74262
+ function copilotRecordToAgentEvents(record2) {
74263
+ if (typeof record2.type !== "string" || !isRecord2(record2.data)) return [];
74264
+ const timestamp = timestampOf(record2) ? Date.parse(timestampOf(record2)) : Date.now();
74265
+ const ts = Number.isFinite(timestamp) ? timestamp : Date.now();
74266
+ const data = record2.data;
74267
+ if (record2.type === "assistant.message") {
74268
+ const events = [];
74269
+ if (typeof data.reasoningText === "string" && data.reasoningText.length > 0) {
74270
+ events.push({ type: "thinking", text: data.reasoningText, ts });
74271
+ }
74272
+ if (typeof data.content === "string" && data.content.length > 0) {
74273
+ events.push({ type: "text", text: data.content, ts });
74274
+ }
74275
+ if (Array.isArray(data.toolRequests)) {
74276
+ for (const request of data.toolRequests) {
74277
+ if (!isRecord2(request)) continue;
74278
+ const id = stringValue(request.id, request.toolCallId, request.tool_call_id);
74279
+ const name = stringValue(request.name, request.toolName, request.tool_name);
74280
+ if (id && name) {
74281
+ events.push({
74282
+ type: "tool_use",
74283
+ id,
74284
+ name,
74285
+ input: request.arguments ?? request.input,
74286
+ ts
74287
+ });
74288
+ }
74289
+ }
74290
+ }
74291
+ return events;
74292
+ }
74293
+ if (record2.type === "tool.execution_complete" || record2.type === "tool.execution_end") {
74294
+ const id = stringValue(data.toolCallId, data.tool_call_id, data.id);
74295
+ if (!id) return [];
74296
+ return [
74297
+ {
74298
+ type: "tool_result",
74299
+ id,
74300
+ content: extractText2(data.result ?? data.output ?? data.content),
74301
+ ts
74302
+ }
74303
+ ];
74304
+ }
74305
+ return [];
74306
+ }
74307
+ function claudeCompatibleRecordToAgentEvents(record2) {
74292
74308
  const timestamp = timestampOf(record2) ? Date.parse(timestampOf(record2)) : Date.now();
74293
74309
  const ts = Number.isFinite(timestamp) ? timestamp : Date.now();
74294
74310
  const message = isRecord2(record2.message) ? record2.message : record2;
74295
74311
  const content = message.content;
74296
- const role = typeof message.role === "string" ? message.role : typeof record2.type === "string" ? record2.type : null;
74312
+ const role = typeof message.role === "string" ? message.role : typeof record2.role === "string" ? record2.role : typeof record2.type === "string" ? record2.type : null;
74297
74313
  if (role === "user") {
74298
74314
  if (!Array.isArray(content)) return [];
74299
74315
  return content.flatMap((block) => {
@@ -74331,6 +74347,47 @@ function claudeRecordToAgentEvents(record2) {
74331
74347
  return [{ type: "text", text: content, ts }];
74332
74348
  return [];
74333
74349
  }
74350
+ function codexRecordToAgentEvents(record2) {
74351
+ if (record2.type !== "response_item" || !isRecord2(record2.payload)) return [];
74352
+ const payload = record2.payload;
74353
+ const timestamp = timestampOf(record2) ? Date.parse(timestampOf(record2)) : Date.now();
74354
+ const ts = Number.isFinite(timestamp) ? timestamp : Date.now();
74355
+ if (payload.type === "message" && payload.role === "assistant") {
74356
+ if (!Array.isArray(payload.content)) return [];
74357
+ return payload.content.flatMap((block) => {
74358
+ if (!isRecord2(block) || block.type !== "output_text" || typeof block.text !== "string") {
74359
+ return [];
74360
+ }
74361
+ return block.text ? [{ type: "text", text: block.text, ts }] : [];
74362
+ });
74363
+ }
74364
+ if (payload.type === "reasoning") {
74365
+ const text = extractText2(payload.summary);
74366
+ return text ? [{ type: "thinking", text, ts }] : [];
74367
+ }
74368
+ if (payload.type === "custom_tool_call") {
74369
+ const id = stringValue(payload.call_id, payload.id);
74370
+ const name = stringValue(payload.name);
74371
+ if (!id || !name) return [];
74372
+ return [{ type: "tool_use", id, name, input: parseEmbeddedJson(payload.input), ts }];
74373
+ }
74374
+ if (payload.type === "custom_tool_call_output") {
74375
+ const id = stringValue(payload.call_id, payload.id);
74376
+ return id ? [{ type: "tool_result", id, content: extractText2(payload.output), ts }] : [];
74377
+ }
74378
+ return [];
74379
+ }
74380
+ function stringValue(...values) {
74381
+ return values.find((value2) => typeof value2 === "string" && value2.length > 0) ?? null;
74382
+ }
74383
+ function parseEmbeddedJson(value2) {
74384
+ if (typeof value2 !== "string") return value2;
74385
+ try {
74386
+ return JSON.parse(value2);
74387
+ } catch {
74388
+ return value2;
74389
+ }
74390
+ }
74334
74391
  function extractText2(value2) {
74335
74392
  if (typeof value2 === "string") return value2;
74336
74393
  if (Array.isArray(value2)) return value2.map(extractText2).filter(Boolean).join("\n");
@@ -74430,7 +74487,7 @@ var ObservableMap = class extends Map {
74430
74487
 
74431
74488
  // src/run-journal.ts
74432
74489
  var import_node_fs19 = require("fs");
74433
- var import_node_path16 = require("path");
74490
+ var import_node_path17 = require("path");
74434
74491
  var JOURNAL_VERSION = 1;
74435
74492
  var INTERRUPTED_ENTRY_TTL_MS = 24 * 60 * 6e4;
74436
74493
  function isEntry(value2) {
@@ -74574,7 +74631,7 @@ var RuntimeRunJournal = class {
74574
74631
  }
74575
74632
  persist() {
74576
74633
  const pendingPath = `${this.path}.pending`;
74577
- (0, import_node_fs19.mkdirSync)((0, import_node_path16.dirname)(this.path), { recursive: true });
74634
+ (0, import_node_fs19.mkdirSync)((0, import_node_path17.dirname)(this.path), { recursive: true });
74578
74635
  try {
74579
74636
  (0, import_node_fs19.writeFileSync)(
74580
74637
  pendingPath,
@@ -74615,13 +74672,13 @@ var RunStartGate = class {
74615
74672
  var import_node_buffer2 = require("buffer");
74616
74673
  var import_node_crypto12 = require("crypto");
74617
74674
  var import_promises2 = require("fs/promises");
74618
- var import_node_path18 = __toESM(require("path"), 1);
74675
+ var import_node_path19 = __toESM(require("path"), 1);
74619
74676
 
74620
74677
  // ../shared/dist/node/skill-package.js
74621
74678
  var import_node_buffer = require("buffer");
74622
74679
  var import_node_crypto11 = require("crypto");
74623
74680
  var import_promises = require("fs/promises");
74624
- var import_node_path17 = require("path");
74681
+ var import_node_path18 = require("path");
74625
74682
  var import_yaml = __toESM(require_dist2(), 1);
74626
74683
 
74627
74684
  // ../shared/dist/skills/domain.js
@@ -75045,7 +75102,7 @@ async function inspectSkillPackage(packageRoot, options = {}) {
75045
75102
  }
75046
75103
  const inspectedFiles = await Promise.all(files.map(readPackageFile));
75047
75104
  inspectedFiles.sort(comparePackageFiles);
75048
- const parsedMetadata = parseSkillMetadata(inspectedFiles.find((file2) => file2.manifest.path === "SKILL.md")?.bytes, options.expectedName === void 0 ? (0, import_node_path17.basename)(root) : options.expectedName);
75105
+ const parsedMetadata = parseSkillMetadata(inspectedFiles.find((file2) => file2.manifest.path === "SKILL.md")?.bytes, options.expectedName === void 0 ? (0, import_node_path18.basename)(root) : options.expectedName);
75049
75106
  const manifestFiles = inspectedFiles.map((file2) => file2.manifest);
75050
75107
  const diagnostics = [
75051
75108
  ...parsedMetadata.conformance,
@@ -75069,7 +75126,7 @@ async function readSkillPackageFile(packageRoot, path2, expectedSha256) {
75069
75126
  if (!normalizedPath || normalizedPath !== path2 || normalizedPath.includes("\\") || components.some((component) => !component || component === "." || component === "..")) {
75070
75127
  throw new SkillPackageError("INVALID_PATH", `Invalid Skill package path: ${path2}`, path2);
75071
75128
  }
75072
- const absolutePath = await (0, import_promises.realpath)((0, import_node_path17.resolve)(root, ...components)).catch(() => null);
75129
+ const absolutePath = await (0, import_promises.realpath)((0, import_node_path18.resolve)(root, ...components)).catch(() => null);
75073
75130
  if (!absolutePath || normalizeRelativePath(root, absolutePath) !== normalizedPath) {
75074
75131
  throw new SkillPackageError("INVALID_PATH", `Skill package file was not found: ${path2}`, path2);
75075
75132
  }
@@ -75090,7 +75147,7 @@ async function readSkillPackageFile(packageRoot, path2, expectedSha256) {
75090
75147
  return { file: read.manifest, bytes: read.bytes };
75091
75148
  }
75092
75149
  async function requirePackageRoot(packageRoot) {
75093
- const root = await (0, import_promises.realpath)((0, import_node_path17.resolve)(packageRoot)).catch(() => null);
75150
+ const root = await (0, import_promises.realpath)((0, import_node_path18.resolve)(packageRoot)).catch(() => null);
75094
75151
  if (!root) {
75095
75152
  throw new SkillPackageError("INVALID_PACKAGE_ROOT", "Skill package directory does not exist");
75096
75153
  }
@@ -75116,7 +75173,7 @@ async function walkPackage(root, ignoredPaths) {
75116
75173
  async function walkDirectory(directory) {
75117
75174
  const entries = await (0, import_promises.readdir)(directory, { withFileTypes: true });
75118
75175
  for (const entry of entries) {
75119
- const absolutePath = (0, import_node_path17.resolve)(directory, entry.name);
75176
+ const absolutePath = (0, import_node_path18.resolve)(directory, entry.name);
75120
75177
  const normalizedPath = normalizeRelativePath(root, absolutePath);
75121
75178
  if (isIgnored(normalizedPath, entry.name, entry.isDirectory(), ignored))
75122
75179
  continue;
@@ -75153,10 +75210,10 @@ function createIgnoreMatcher(path2) {
75153
75210
  const expression = globToRegExp(pattern);
75154
75211
  return (candidate) => expression.test(candidate) || expression.test(`${candidate}/`);
75155
75212
  }
75156
- function isIgnored(normalizedPath, basename6, isDirectory2, configured) {
75157
- if (isDirectory2 && ALWAYS_IGNORED_DIRECTORIES.has(basename6))
75213
+ function isIgnored(normalizedPath, basename7, isDirectory2, configured) {
75214
+ if (isDirectory2 && ALWAYS_IGNORED_DIRECTORIES.has(basename7))
75158
75215
  return true;
75159
- if (!isDirectory2 && ALWAYS_IGNORED_FILES.has(basename6))
75216
+ if (!isDirectory2 && ALWAYS_IGNORED_FILES.has(basename7))
75160
75217
  return true;
75161
75218
  return configured.some((matches) => matches(normalizedPath));
75162
75219
  }
@@ -75183,12 +75240,12 @@ function globToRegExp(pattern) {
75183
75240
  return new RegExp(`${source}(?:/.*)?$`);
75184
75241
  }
75185
75242
  function normalizeRelativePath(root, absolutePath) {
75186
- const nativeRelativePath = (0, import_node_path17.relative)(root, absolutePath);
75187
- if (!nativeRelativePath || nativeRelativePath.startsWith(`..${import_node_path17.sep}`) || nativeRelativePath === "..") {
75243
+ const nativeRelativePath = (0, import_node_path18.relative)(root, absolutePath);
75244
+ if (!nativeRelativePath || nativeRelativePath.startsWith(`..${import_node_path18.sep}`) || nativeRelativePath === "..") {
75188
75245
  throw new SkillPackageError("INVALID_PATH", "Skill package path escapes its root");
75189
75246
  }
75190
- const normalized = nativeRelativePath.split(import_node_path17.sep).join("/").normalize("NFC");
75191
- if (normalized.includes("\0") || normalized.includes("\uFFFD") || import_node_path17.posix.isAbsolute(normalized)) {
75247
+ const normalized = nativeRelativePath.split(import_node_path18.sep).join("/").normalize("NFC");
75248
+ if (normalized.includes("\0") || normalized.includes("\uFFFD") || import_node_path18.posix.isAbsolute(normalized)) {
75192
75249
  throw new SkillPackageError("INVALID_PATH", `Invalid Skill package path: ${normalized}`);
75193
75250
  }
75194
75251
  return normalized;
@@ -75223,7 +75280,7 @@ function requireSafeFile(path2, size, normalizedPaths) {
75223
75280
  }
75224
75281
  }
75225
75282
  function isSecretPath(path2) {
75226
- const name = import_node_path17.posix.basename(path2).toLowerCase();
75283
+ const name = import_node_path18.posix.basename(path2).toLowerCase();
75227
75284
  if (SECRET_BASENAMES.has(name) || name.startsWith(".env."))
75228
75285
  return true;
75229
75286
  return name.endsWith(".private-key.pem") || name.endsWith(".private-key.key");
@@ -75251,12 +75308,12 @@ function classifyFileKind(path2) {
75251
75308
  return "reference";
75252
75309
  if (path2.startsWith("assets/"))
75253
75310
  return "asset";
75254
- if (/^(?:licen[cs]e|copying|notice)(?:\.|$)/i.test(import_node_path17.posix.basename(path2)))
75311
+ if (/^(?:licen[cs]e|copying|notice)(?:\.|$)/i.test(import_node_path18.posix.basename(path2)))
75255
75312
  return "license";
75256
75313
  return "other";
75257
75314
  }
75258
75315
  function classifyPreview(path2, bytes) {
75259
- const extension = import_node_path17.posix.extname(path2).toLowerCase();
75316
+ const extension = import_node_path18.posix.extname(path2).toLowerCase();
75260
75317
  if (IMAGE_EXTENSIONS.has(extension))
75261
75318
  return "image";
75262
75319
  if (bytes.includes(0))
@@ -75360,7 +75417,7 @@ function normalizePackageReference(value2) {
75360
75417
  const withoutSuffix = trimmed.split(/[?#]/, 1)[0];
75361
75418
  if (!withoutSuffix)
75362
75419
  return null;
75363
- const normalized = import_node_path17.posix.normalize(withoutSuffix).replace(/^\.\//, "").normalize("NFC");
75420
+ const normalized = import_node_path18.posix.normalize(withoutSuffix).replace(/^\.\//, "").normalize("NFC");
75364
75421
  if (normalized === ".." || normalized.startsWith("../"))
75365
75422
  return null;
75366
75423
  return normalized;
@@ -75597,9 +75654,9 @@ var LocalSkillSource = class {
75597
75654
  */
75598
75655
  async scanRootAsPackage(resolvedRoot, ignoredPaths, mode) {
75599
75656
  const directory = resolvedRoot.directory;
75600
- if (!await pathExists((0, import_node_path18.join)(directory, "SKILL.md"))) return null;
75657
+ if (!await pathExists((0, import_node_path19.join)(directory, "SKILL.md"))) return null;
75601
75658
  const canonicalRoot = await (0, import_promises2.realpath)(directory).catch(() => directory);
75602
- const name = import_node_path18.default.basename(canonicalRoot);
75659
+ const name = import_node_path19.default.basename(canonicalRoot);
75603
75660
  try {
75604
75661
  const fingerprint = await fingerprintPackage(canonicalRoot);
75605
75662
  const ignoreSignature = JSON.stringify(ignoredPaths);
@@ -75669,7 +75726,7 @@ var LocalSkillSource = class {
75669
75726
  );
75670
75727
  for (const entry of entries) {
75671
75728
  if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
75672
- const candidatePath = (0, import_node_path18.join)(resolvedRoot.directory, entry.name);
75729
+ const candidatePath = (0, import_node_path19.join)(resolvedRoot.directory, entry.name);
75673
75730
  const canonicalPath = await (0, import_promises2.realpath)(candidatePath).catch(() => null);
75674
75731
  if (!canonicalPath) {
75675
75732
  diagnostics.push({
@@ -75735,7 +75792,7 @@ async function fingerprintPackage(root) {
75735
75792
  entries.sort((left, right) => import_node_buffer2.Buffer.compare(import_node_buffer2.Buffer.from(left.name), import_node_buffer2.Buffer.from(right.name)));
75736
75793
  for (const entry of entries) {
75737
75794
  const path2 = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
75738
- const absolutePath = (0, import_node_path18.join)(directory, entry.name);
75795
+ const absolutePath = (0, import_node_path19.join)(directory, entry.name);
75739
75796
  const metadata = await (0, import_promises2.lstat)(absolutePath);
75740
75797
  hash2.update(path2.normalize("NFC")).update("\0").update(
75741
75798
  entry.isDirectory() ? "d" : entry.isFile() ? "f" : entry.isSymbolicLink() ? "l" : "o"
@@ -75760,12 +75817,12 @@ async function canonicalDirectories(directories) {
75760
75817
  return [...new Set(canonical)];
75761
75818
  }
75762
75819
  function isWithinDirectory(parent, candidate) {
75763
- const path2 = (0, import_node_path18.relative)(parent, candidate);
75764
- return path2 !== ".." && !path2.startsWith(`..${import_node_path18.sep}`) && !(0, import_node_path18.isAbsolute)(path2);
75820
+ const path2 = (0, import_node_path19.relative)(parent, candidate);
75821
+ return path2 !== ".." && !path2.startsWith(`..${import_node_path19.sep}`) && !(0, import_node_path19.isAbsolute)(path2);
75765
75822
  }
75766
- async function loadSkillSourceConfig(homeDirectory) {
75767
- const configDirectory = (0, import_node_path18.join)(homeDirectory, ".alan");
75768
- const configPath = (0, import_node_path18.join)(configDirectory, "config.toml");
75823
+ async function loadSkillSourceConfig(homeDirectory2) {
75824
+ const configDirectory = (0, import_node_path19.join)(homeDirectory2, ".alan");
75825
+ const configPath = (0, import_node_path19.join)(configDirectory, "config.toml");
75769
75826
  await (0, import_promises2.mkdir)(configDirectory, { recursive: true, mode: 448 });
75770
75827
  let created = false;
75771
75828
  try {
@@ -75780,18 +75837,18 @@ async function loadSkillSourceConfig(homeDirectory) {
75780
75837
  }
75781
75838
  const content = await (0, import_promises2.readFile)(configPath, "utf8");
75782
75839
  try {
75783
- return { state: "ready", config: parseSkillSourceConfig(content, homeDirectory), created };
75840
+ return { state: "ready", config: parseSkillSourceConfig(content, homeDirectory2), created };
75784
75841
  } catch (error61) {
75785
75842
  return {
75786
75843
  state: "invalid",
75787
- config: parseSkillSourceConfig(DEFAULT_SKILL_CONFIG, homeDirectory),
75844
+ config: parseSkillSourceConfig(DEFAULT_SKILL_CONFIG, homeDirectory2),
75788
75845
  created: false,
75789
75846
  diagnostic: error61 instanceof Error ? error61.message : String(error61)
75790
75847
  };
75791
75848
  }
75792
75849
  }
75793
- async function resolveSkillScanInput(homeDirectory, declared) {
75794
- const loaded = await loadSkillSourceConfig(homeDirectory);
75850
+ async function resolveSkillScanInput(homeDirectory2, declared) {
75851
+ const loaded = await loadSkillSourceConfig(homeDirectory2);
75795
75852
  if (loaded.state === "invalid") {
75796
75853
  throw Object.assign(new Error(`Invalid Skill source configuration: ${loaded.diagnostic}`), {
75797
75854
  code: "SKILL_SOURCE_CONFIG_INVALID"
@@ -75799,7 +75856,7 @@ async function resolveSkillScanInput(homeDirectory, declared) {
75799
75856
  }
75800
75857
  const { config: config2 } = loaded;
75801
75858
  if (!config2.enabled) return { ...declared, roots: [], ignoredPaths: config2.ignoredPaths };
75802
- const draftsPath = (0, import_node_path18.resolve)((0, import_node_path18.join)(homeDirectory, ".alan", "skill-sources"));
75859
+ const draftsPath = (0, import_node_path19.resolve)((0, import_node_path19.join)(homeDirectory2, ".alan", "skill-sources"));
75803
75860
  const enabledProviders = new Set(declared.enabledProviderKinds ?? []);
75804
75861
  const configured = [];
75805
75862
  for (const source of config2.sources) {
@@ -75807,7 +75864,7 @@ async function resolveSkillScanInput(homeDirectory, declared) {
75807
75864
  continue;
75808
75865
  }
75809
75866
  configured.push(
75810
- (0, import_node_path18.resolve)(source.path) === draftsPath ? { kind: "drafts", path: source.path, label: "Alan drafts" } : {
75867
+ (0, import_node_path19.resolve)(source.path) === draftsPath ? { kind: "drafts", path: source.path, label: "Alan drafts" } : {
75811
75868
  kind: "configured",
75812
75869
  declarationId: source.declarationId,
75813
75870
  path: source.path,
@@ -75823,7 +75880,7 @@ async function resolveSkillScanInput(homeDirectory, declared) {
75823
75880
  ignoredPaths: [.../* @__PURE__ */ new Set([...config2.ignoredPaths, ...declared.ignoredPaths ?? []])]
75824
75881
  };
75825
75882
  }
75826
- function parseSkillSourceConfig(content, homeDirectory) {
75883
+ function parseSkillSourceConfig(content, homeDirectory2) {
75827
75884
  const parsed = parse5(content);
75828
75885
  if (!isRecord4(parsed) || parsed.version !== 1 || !isRecord4(parsed.skills)) {
75829
75886
  throw new Error("~/.alan/config.toml must contain version = 1 and a [skills] table");
@@ -75846,7 +75903,7 @@ function parseSkillSourceConfig(content, homeDirectory) {
75846
75903
  `skills.sources entry ${index + 1} must contain string path and label values`
75847
75904
  );
75848
75905
  }
75849
- const sourcePath = resolveSkillSourcePath(value2.path, homeDirectory);
75906
+ const sourcePath = resolveSkillSourcePath(value2.path, homeDirectory2);
75850
75907
  const label = value2.label.trim();
75851
75908
  if (!label) throw new Error(`skills.sources entry ${index + 1} has an empty label`);
75852
75909
  const declarationId = value2.id === void 0 ? stableSourceDeclarationId(sourcePath) : requiredSourceId(value2.id, `skills.sources[${index}].id`);
@@ -75854,7 +75911,7 @@ function parseSkillSourceConfig(content, homeDirectory) {
75854
75911
  value2.providers,
75855
75912
  `skills.sources[${index}].providers`
75856
75913
  );
75857
- const relativeDirectory = import_node_path18.default.relative(homeDirectory, sourcePath);
75914
+ const relativeDirectory = import_node_path19.default.relative(homeDirectory2, sourcePath);
75858
75915
  const inferredProviders = providerKindsForUserDirectory(relativeDirectory);
75859
75916
  const declaredProviders = value2.providers === void 0 ? inferredProviders : [...new Set(explicitProviders.map((provider) => provider.trim()).filter(Boolean))];
75860
75917
  const stale = staleCodexDeclaration(relativeDirectory, label, declaredProviders);
@@ -75884,14 +75941,14 @@ function requiredSourceId(value2, field) {
75884
75941
  }
75885
75942
  return value2;
75886
75943
  }
75887
- function resolveSkillSourcePath(sourcePath, homeDirectory, pathApi = import_node_path18.default) {
75944
+ function resolveSkillSourcePath(sourcePath, homeDirectory2, pathApi = import_node_path19.default) {
75888
75945
  const trimmed = sourcePath.trim();
75889
- if (trimmed === "~") return pathApi.resolve(homeDirectory);
75946
+ if (trimmed === "~") return pathApi.resolve(homeDirectory2);
75890
75947
  if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
75891
75948
  const components = trimmed.slice(2).split(/[\\/]+/).filter(Boolean);
75892
- return pathApi.resolve(pathApi.join(homeDirectory, ...components));
75949
+ return pathApi.resolve(pathApi.join(homeDirectory2, ...components));
75893
75950
  }
75894
- return pathApi.isAbsolute(trimmed) ? pathApi.resolve(trimmed) : pathApi.resolve(homeDirectory, trimmed);
75951
+ return pathApi.isAbsolute(trimmed) ? pathApi.resolve(trimmed) : pathApi.resolve(homeDirectory2, trimmed);
75895
75952
  }
75896
75953
  function optionalBoolean(value2, fallback, field) {
75897
75954
  if (value2 === void 0) return fallback;
@@ -75919,7 +75976,7 @@ function resolveScanRoots(roots, enabledProviderKinds) {
75919
75976
  ).entries()) {
75920
75977
  resolved.push({
75921
75978
  root,
75922
- directory: (0, import_node_path18.join)(root.path, relativeDirectory),
75979
+ directory: (0, import_node_path19.join)(root.path, relativeDirectory),
75923
75980
  order: `1:${root.repositoryId}:${String(index).padStart(2, "0")}`
75924
75981
  });
75925
75982
  }
@@ -75978,7 +76035,7 @@ async function pathExists(candidate) {
75978
76035
  }
75979
76036
  async function hasManagedMarker(directory) {
75980
76037
  try {
75981
- await (0, import_promises2.access)((0, import_node_path18.join)(directory, ".alan-managed.json"));
76038
+ await (0, import_promises2.access)((0, import_node_path19.join)(directory, ".alan-managed.json"));
75982
76039
  return true;
75983
76040
  } catch {
75984
76041
  return false;
@@ -76147,12 +76204,12 @@ var RuntimeSkillCoordinator = class {
76147
76204
  var import_node_buffer5 = require("buffer");
76148
76205
  var import_node_crypto15 = require("crypto");
76149
76206
  var import_promises5 = require("fs/promises");
76150
- var import_node_path21 = require("path");
76207
+ var import_node_path22 = require("path");
76151
76208
 
76152
76209
  // src/skills/managed-skill-store.ts
76153
76210
  var import_node_crypto13 = require("crypto");
76154
76211
  var import_promises3 = require("fs/promises");
76155
- var import_node_path19 = require("path");
76212
+ var import_node_path20 = require("path");
76156
76213
  var EMPTY_STATE = {
76157
76214
  version: 1,
76158
76215
  sources: {},
@@ -76171,7 +76228,7 @@ var ManagedSkillStore = class _ManagedSkillStore {
76171
76228
  static async open(baseDirectory) {
76172
76229
  await (0, import_promises3.mkdir)(baseDirectory, { recursive: true, mode: 448 });
76173
76230
  try {
76174
- const parsed = JSON.parse(await (0, import_promises3.readFile)((0, import_node_path19.join)(baseDirectory, "state.json"), "utf8"));
76231
+ const parsed = JSON.parse(await (0, import_promises3.readFile)((0, import_node_path20.join)(baseDirectory, "state.json"), "utf8"));
76175
76232
  return new _ManagedSkillStore(baseDirectory, parseState(parsed), "verified");
76176
76233
  } catch (error61) {
76177
76234
  if (isMissingPath2(error61)) {
@@ -76270,8 +76327,8 @@ var ManagedSkillStore = class _ManagedSkillStore {
76270
76327
  this.canRemoveManagedFiles = true;
76271
76328
  }
76272
76329
  async persist() {
76273
- const statePath = (0, import_node_path19.join)(this.baseDirectory, "state.json");
76274
- const pendingPath = (0, import_node_path19.join)(
76330
+ const statePath = (0, import_node_path20.join)(this.baseDirectory, "state.json");
76331
+ const pendingPath = (0, import_node_path20.join)(
76275
76332
  this.baseDirectory,
76276
76333
  `.state.json.pending-${process.pid}-${(0, import_node_crypto13.randomBytes)(6).toString("hex")}`
76277
76334
  );
@@ -76356,7 +76413,7 @@ function isMissingPath2(error61) {
76356
76413
  var import_node_buffer3 = require("buffer");
76357
76414
  var import_node_crypto14 = require("crypto");
76358
76415
  var import_promises4 = require("fs/promises");
76359
- var import_node_path20 = require("path");
76416
+ var import_node_path21 = require("path");
76360
76417
  var import_node_stream = require("stream");
76361
76418
  var import_node_zlib = require("zlib");
76362
76419
  var import_tar_stream = __toESM(require_tar_stream(), 1);
@@ -76365,7 +76422,7 @@ async function createSkillBundle(packageRoot) {
76365
76422
  const archive = (0, import_tar_stream.pack)();
76366
76423
  const tarPromise = collectStream(archive);
76367
76424
  for (const file2 of before.files) {
76368
- const bytes2 = await (0, import_promises4.readFile)((0, import_node_path20.join)(packageRoot, ...file2.path.split("/")));
76425
+ const bytes2 = await (0, import_promises4.readFile)((0, import_node_path21.join)(packageRoot, ...file2.path.split("/")));
76369
76426
  await addArchiveEntry(archive, {
76370
76427
  name: file2.path,
76371
76428
  type: "file",
@@ -76480,13 +76537,13 @@ async function extractEntry(header, stream, destination, limits) {
76480
76537
  if (bytes.byteLength !== declaredSize) {
76481
76538
  throw new Error(`Skill archive file size is invalid: ${path2}`);
76482
76539
  }
76483
- const outputPath = (0, import_node_path20.join)(destination, ...path2.split("/"));
76484
- await (0, import_promises4.mkdir)((0, import_node_path20.dirname)(outputPath), { recursive: true, mode: 448 });
76540
+ const outputPath = (0, import_node_path21.join)(destination, ...path2.split("/"));
76541
+ await (0, import_promises4.mkdir)((0, import_node_path21.dirname)(outputPath), { recursive: true, mode: 448 });
76485
76542
  await (0, import_promises4.writeFile)(outputPath, bytes, { mode: (header.mode ?? 420) & 73 ? 493 : 420 });
76486
76543
  }
76487
76544
  function requireSafeArchivePath(value2) {
76488
76545
  const normalized = value2.replaceAll("\\", "/").normalize("NFC");
76489
- if (!normalized || normalized.startsWith("/") || normalized.includes("\0") || import_node_path20.posix.normalize(normalized) !== normalized || normalized === ".." || normalized.startsWith("../")) {
76546
+ if (!normalized || normalized.startsWith("/") || normalized.includes("\0") || import_node_path21.posix.normalize(normalized) !== normalized || normalized === ".." || normalized.startsWith("../")) {
76490
76547
  throw new Error(`Skill archive contains an unsafe path: ${value2}`);
76491
76548
  }
76492
76549
  return normalized;
@@ -76565,14 +76622,14 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76565
76622
  }
76566
76623
  reconcileTail = Promise.resolve();
76567
76624
  static async open(options) {
76568
- const skillsStateDirectory = (0, import_node_path21.join)(options.homeDirectory, ".alan", "skills");
76569
- const managedSkillsDirectory = (0, import_node_path21.join)(options.homeDirectory, ".agents", "skills");
76625
+ const skillsStateDirectory = (0, import_node_path22.join)(options.homeDirectory, ".alan", "skills");
76626
+ const managedSkillsDirectory = (0, import_node_path22.join)(options.homeDirectory, ".agents", "skills");
76570
76627
  const store = await ManagedSkillStore.open(skillsStateDirectory);
76571
76628
  return new _RuntimeSkillManager(
76572
76629
  skillsStateDirectory,
76573
76630
  managedSkillsDirectory,
76574
- (0, import_node_path21.join)(options.homeDirectory, ".claude", "skills"),
76575
- (0, import_node_path21.join)(options.homeDirectory, ".alan", "sync-manifest.json"),
76631
+ (0, import_node_path22.join)(options.homeDirectory, ".claude", "skills"),
76632
+ (0, import_node_path22.join)(options.homeDirectory, ".alan", "sync-manifest.json"),
76576
76633
  store,
76577
76634
  options.downloadBundle ?? downloadBundleWithFetch,
76578
76635
  options.localSource ?? new LocalSkillSource(),
@@ -76731,7 +76788,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76731
76788
  if (!runtimeDirectory) {
76732
76789
  throw new Error("Selected Skill version is not installed on this runtime");
76733
76790
  }
76734
- const packageDirectory = (0, import_node_path21.join)(this.managedSkillsDirectory, runtimeDirectory);
76791
+ const packageDirectory = (0, import_node_path22.join)(this.managedSkillsDirectory, runtimeDirectory);
76735
76792
  const marker = await readMarker(packageDirectory);
76736
76793
  if (!marker || marker.skillId !== invocation.skillId || marker.versionId !== invocation.versionId) {
76737
76794
  throw new Error("Selected Skill projection is missing or no longer owned by Alan");
@@ -76745,11 +76802,11 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76745
76802
  async reconcileUnlocked(manifest) {
76746
76803
  const desired = desiredSkillManifestSchema.parse(manifest);
76747
76804
  await (0, import_promises5.mkdir)(this.managedSkillsDirectory, { recursive: true, mode: 448 });
76748
- await (0, import_promises5.mkdir)((0, import_node_path21.join)(this.skillsStateDirectory, "cache", "sha256"), {
76805
+ await (0, import_promises5.mkdir)((0, import_node_path22.join)(this.skillsStateDirectory, "cache", "sha256"), {
76749
76806
  recursive: true,
76750
76807
  mode: 448
76751
76808
  });
76752
- await (0, import_promises5.mkdir)((0, import_node_path21.join)(this.skillsStateDirectory, "tmp"), { recursive: true, mode: 448 });
76809
+ await (0, import_promises5.mkdir)((0, import_node_path22.join)(this.skillsStateDirectory, "tmp"), { recursive: true, mode: 448 });
76753
76810
  const results = [];
76754
76811
  const nextProjections = {};
76755
76812
  for (const entry of desired.skills) {
@@ -76800,7 +76857,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76800
76857
  };
76801
76858
  }
76802
76859
  async reuseCurrentProjection(entry) {
76803
- const destination = (0, import_node_path21.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76860
+ const destination = (0, import_node_path22.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76804
76861
  const marker = await readMarker(destination);
76805
76862
  if (marker?.skillId !== entry.skillId || marker.versionId !== entry.versionId || marker.contentHash !== entry.contentHash || !await packageMatches(destination, entry.contentHash)) {
76806
76863
  return null;
@@ -76809,19 +76866,19 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76809
76866
  return entry.contentHash;
76810
76867
  }
76811
76868
  async adoptLegacyProjection(entry) {
76812
- const destination = (0, import_node_path21.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76869
+ const destination = (0, import_node_path22.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76813
76870
  if (await pathExists2(destination)) return;
76814
76871
  const manifest = await readLegacyManifest(this.legacyManifestPath);
76815
76872
  const legacy = manifest?.skills[entry.slug];
76816
76873
  if (!legacy) return;
76817
- const source = (0, import_node_path21.join)(this.managedSkillsDirectory, entry.slug);
76874
+ const source = (0, import_node_path22.join)(this.managedSkillsDirectory, entry.slug);
76818
76875
  if (!await legacyFileMatches(source, legacy.hash) || !await packageMatches(source, entry.contentHash)) {
76819
76876
  return;
76820
76877
  }
76821
76878
  await (0, import_promises5.rename)(source, destination);
76822
76879
  try {
76823
76880
  await (0, import_promises5.writeFile)(
76824
- (0, import_node_path21.join)(destination, ".alan-managed.json"),
76881
+ (0, import_node_path22.join)(destination, ".alan-managed.json"),
76825
76882
  `${JSON.stringify(markerFor(entry), null, 2)}
76826
76883
  `,
76827
76884
  { encoding: "utf8", flag: "wx", mode: 384 }
@@ -76830,19 +76887,19 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76830
76887
  await (0, import_promises5.rename)(destination, source).catch(() => void 0);
76831
76888
  throw error61;
76832
76889
  }
76833
- await removeExactLegacySkill((0, import_node_path21.join)(this.compatibilitySkillsDirectory, entry.slug), legacy.hash);
76890
+ await removeExactLegacySkill((0, import_node_path22.join)(this.compatibilitySkillsDirectory, entry.slug), legacy.hash);
76834
76891
  }
76835
76892
  async retireLegacySyncManifest() {
76836
76893
  const manifest = await readLegacyManifest(this.legacyManifestPath);
76837
76894
  if (!manifest) return;
76838
76895
  for (const [command, entry] of Object.entries(manifest.skills)) {
76839
- await removeExactLegacySkill((0, import_node_path21.join)(this.managedSkillsDirectory, command), entry.hash);
76840
- await removeExactLegacySkill((0, import_node_path21.join)(this.compatibilitySkillsDirectory, command), entry.hash);
76896
+ await removeExactLegacySkill((0, import_node_path22.join)(this.managedSkillsDirectory, command), entry.hash);
76897
+ await removeExactLegacySkill((0, import_node_path22.join)(this.compatibilitySkillsDirectory, command), entry.hash);
76841
76898
  }
76842
76899
  await (0, import_promises5.rm)(this.legacyManifestPath, { force: true });
76843
76900
  }
76844
76901
  async ensureCached(entry) {
76845
- const cacheDirectory = (0, import_node_path21.join)(
76902
+ const cacheDirectory = (0, import_node_path22.join)(
76846
76903
  this.skillsStateDirectory,
76847
76904
  "cache",
76848
76905
  "sha256",
@@ -76856,7 +76913,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76856
76913
  `Downloaded Skill bundle length ${bytes.byteLength} does not match ${entry.compressedBytes}`
76857
76914
  );
76858
76915
  }
76859
- const pendingDirectory = (0, import_node_path21.join)(
76916
+ const pendingDirectory = (0, import_node_path22.join)(
76860
76917
  this.skillsStateDirectory,
76861
76918
  "tmp",
76862
76919
  `cache-${process.pid}-${(0, import_node_crypto15.randomBytes)(8).toString("hex")}`
@@ -76877,22 +76934,22 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76877
76934
  return cacheDirectory;
76878
76935
  }
76879
76936
  async project(entry, cacheDirectory) {
76880
- const destination = (0, import_node_path21.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76937
+ const destination = (0, import_node_path22.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76881
76938
  const existing = await readMarker(destination);
76882
76939
  if (existing?.skillId === entry.skillId && existing.versionId === entry.versionId && existing.contentHash === entry.contentHash && await packageMatches(destination, entry.contentHash)) {
76883
76940
  await this.ensureCompatibilityProjection(entry, destination);
76884
76941
  return entry.contentHash;
76885
76942
  }
76886
76943
  const suffix = `${process.pid}-${(0, import_node_crypto15.randomBytes)(8).toString("hex")}`;
76887
- const pending = (0, import_node_path21.join)(this.managedSkillsDirectory, `.pending-${suffix}`);
76888
- const backup = (0, import_node_path21.join)(this.managedSkillsDirectory, `.backup-${suffix}`);
76944
+ const pending = (0, import_node_path22.join)(this.managedSkillsDirectory, `.pending-${suffix}`);
76945
+ const backup = (0, import_node_path22.join)(this.managedSkillsDirectory, `.backup-${suffix}`);
76889
76946
  let movedExisting = false;
76890
76947
  let installedPending = false;
76891
76948
  let completed = false;
76892
76949
  try {
76893
76950
  await (0, import_promises5.cp)(cacheDirectory, pending, { recursive: true, errorOnExist: true, force: false });
76894
76951
  await (0, import_promises5.writeFile)(
76895
- (0, import_node_path21.join)(pending, ".alan-managed.json"),
76952
+ (0, import_node_path22.join)(pending, ".alan-managed.json"),
76896
76953
  `${JSON.stringify(markerFor(entry), null, 2)}
76897
76954
  `,
76898
76955
  { encoding: "utf8", flag: "wx", mode: 384 }
@@ -76933,7 +76990,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76933
76990
  }
76934
76991
  }
76935
76992
  async requireReplaceable(entry) {
76936
- const destination = (0, import_node_path21.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76993
+ const destination = (0, import_node_path22.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76937
76994
  if (!await pathExists2(destination)) return;
76938
76995
  const marker = await readMarker(destination);
76939
76996
  if (!marker) throw unmanagedPathConflict(entry.runtimeDirectory);
@@ -76950,8 +77007,8 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76950
77007
  if (!this.store.inspect().canRemoveManagedFiles) return failures;
76951
77008
  for (const [runtimeDirectory, recorded] of Object.entries(this.store.projections())) {
76952
77009
  if (desired[runtimeDirectory]) continue;
76953
- const destination = (0, import_node_path21.join)(this.managedSkillsDirectory, runtimeDirectory);
76954
- const compatibility = (0, import_node_path21.join)(this.compatibilitySkillsDirectory, runtimeDirectory);
77010
+ const destination = (0, import_node_path22.join)(this.managedSkillsDirectory, runtimeDirectory);
77011
+ const compatibility = (0, import_node_path22.join)(this.compatibilitySkillsDirectory, runtimeDirectory);
76955
77012
  const marker = await readMarker(destination);
76956
77013
  if (!await pathExists2(destination)) continue;
76957
77014
  if (marker && markerMatchesProjection(marker, recorded)) {
@@ -76982,7 +77039,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76982
77039
  }
76983
77040
  async ensureCompatibilityProjection(entry, canonicalDirectory) {
76984
77041
  await (0, import_promises5.mkdir)(this.compatibilitySkillsDirectory, { recursive: true, mode: 448 });
76985
- const destination = (0, import_node_path21.join)(this.compatibilitySkillsDirectory, entry.runtimeDirectory);
77042
+ const destination = (0, import_node_path22.join)(this.compatibilitySkillsDirectory, entry.runtimeDirectory);
76986
77043
  if (await pathExists2(destination)) {
76987
77044
  if (await compatibilityProjectionMatches(destination, canonicalDirectory, entry)) return;
76988
77045
  throw unmanagedCompatibilityConflict(entry.runtimeDirectory);
@@ -76997,7 +77054,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76997
77054
  try {
76998
77055
  await (0, import_promises5.cp)(canonicalDirectory, pending, { recursive: true, errorOnExist: true, force: false });
76999
77056
  await (0, import_promises5.writeFile)(
77000
- (0, import_node_path21.join)(pending, ".alan-compatibility.json"),
77057
+ (0, import_node_path22.join)(pending, ".alan-compatibility.json"),
77001
77058
  `${JSON.stringify({ ...markerFor(entry), canonicalDirectory }, null, 2)}
77002
77059
  `,
77003
77060
  { encoding: "utf8", flag: "wx", mode: 384 }
@@ -77022,14 +77079,14 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
77022
77079
  }
77023
77080
  async withMachineLock(work) {
77024
77081
  await (0, import_promises5.mkdir)(this.skillsStateDirectory, { recursive: true, mode: 448 });
77025
- const lockDirectory = (0, import_node_path21.join)(this.skillsStateDirectory, "manager.lock");
77082
+ const lockDirectory = (0, import_node_path22.join)(this.skillsStateDirectory, "manager.lock");
77026
77083
  const deadline = Date.now() + 3e4;
77027
77084
  while (true) {
77028
77085
  try {
77029
77086
  await (0, import_promises5.mkdir)(lockDirectory, { mode: 448 });
77030
77087
  try {
77031
77088
  await (0, import_promises5.writeFile)(
77032
- (0, import_node_path21.join)(lockDirectory, "owner.json"),
77089
+ (0, import_node_path22.join)(lockDirectory, "owner.json"),
77033
77090
  `${JSON.stringify({ pid: process.pid, acquiredAt: (/* @__PURE__ */ new Date()).toISOString() })}
77034
77091
  `,
77035
77092
  { encoding: "utf8", flag: "wx", mode: 384 }
@@ -77079,7 +77136,7 @@ async function packageMatches(directory, expectedHash) {
77079
77136
  async function readMarker(directory) {
77080
77137
  try {
77081
77138
  const value2 = JSON.parse(
77082
- await (0, import_promises5.readFile)((0, import_node_path21.join)(directory, ".alan-managed.json"), "utf8")
77139
+ await (0, import_promises5.readFile)((0, import_node_path22.join)(directory, ".alan-managed.json"), "utf8")
77083
77140
  );
77084
77141
  if (typeof value2 !== "object" || value2 === null || !("protocolVersion" in value2) || value2.protocolVersion !== SKILLS_PROTOCOL_VERSION || !("skillId" in value2) || typeof value2.skillId !== "string" || !("versionId" in value2) || typeof value2.versionId !== "string" || !("contentHash" in value2) || typeof value2.contentHash !== "string" || !/^sha256:[a-f0-9]{64}$/.test(value2.contentHash)) {
77085
77142
  return null;
@@ -77093,7 +77150,7 @@ async function compatibilityProjectionMatches(destination, canonicalDirectory, e
77093
77150
  const metadata = await (0, import_promises5.lstat)(destination);
77094
77151
  if (metadata.isSymbolicLink()) {
77095
77152
  const target = await (0, import_promises5.readlink)(destination);
77096
- return (0, import_node_path21.resolve)((0, import_node_path21.dirname)(destination), target) === (0, import_node_path21.resolve)(canonicalDirectory);
77153
+ return (0, import_node_path22.resolve)((0, import_node_path22.dirname)(destination), target) === (0, import_node_path22.resolve)(canonicalDirectory);
77097
77154
  }
77098
77155
  if (!metadata.isDirectory()) return false;
77099
77156
  const marker = await readCompatibilityMarker(destination);
@@ -77104,7 +77161,7 @@ async function removeCompatibilityProjection(destination, canonicalDirectory, pr
77104
77161
  const metadata = await (0, import_promises5.lstat)(destination);
77105
77162
  if (metadata.isSymbolicLink()) {
77106
77163
  const target = await (0, import_promises5.readlink)(destination);
77107
- if ((0, import_node_path21.resolve)((0, import_node_path21.dirname)(destination), target) !== (0, import_node_path21.resolve)(canonicalDirectory)) return false;
77164
+ if ((0, import_node_path22.resolve)((0, import_node_path22.dirname)(destination), target) !== (0, import_node_path22.resolve)(canonicalDirectory)) return false;
77108
77165
  await (0, import_promises5.rm)(destination, { force: true });
77109
77166
  return true;
77110
77167
  }
@@ -77116,7 +77173,7 @@ async function removeCompatibilityProjection(destination, canonicalDirectory, pr
77116
77173
  async function readCompatibilityMarker(directory) {
77117
77174
  try {
77118
77175
  const value2 = JSON.parse(
77119
- await (0, import_promises5.readFile)((0, import_node_path21.join)(directory, ".alan-compatibility.json"), "utf8")
77176
+ await (0, import_promises5.readFile)((0, import_node_path22.join)(directory, ".alan-compatibility.json"), "utf8")
77120
77177
  );
77121
77178
  if (value2.protocolVersion !== SKILLS_PROTOCOL_VERSION || typeof value2.skillId !== "string" || typeof value2.versionId !== "string" || !/^sha256:[a-f0-9]{64}$/.test(value2.contentHash) || typeof value2.canonicalDirectory !== "string") {
77122
77179
  return null;
@@ -77156,7 +77213,7 @@ async function legacyFileMatches(directory, expectedHash) {
77156
77213
  try {
77157
77214
  const metadata = await (0, import_promises5.lstat)(directory);
77158
77215
  if (!metadata.isDirectory() || metadata.isSymbolicLink()) return false;
77159
- const content = await (0, import_promises5.readFile)((0, import_node_path21.join)(directory, "SKILL.md"));
77216
+ const content = await (0, import_promises5.readFile)((0, import_node_path22.join)(directory, "SKILL.md"));
77160
77217
  return (0, import_node_crypto15.createHash)("sha256").update(content).digest("hex").slice(0, 16) === expectedHash;
77161
77218
  } catch {
77162
77219
  return false;
@@ -77164,7 +77221,7 @@ async function legacyFileMatches(directory, expectedHash) {
77164
77221
  }
77165
77222
  async function removeExactLegacySkill(directory, expectedHash) {
77166
77223
  if (!await legacyFileMatches(directory, expectedHash)) return;
77167
- await (0, import_promises5.rm)((0, import_node_path21.join)(directory, "SKILL.md"), { force: true });
77224
+ await (0, import_promises5.rm)((0, import_node_path22.join)(directory, "SKILL.md"), { force: true });
77168
77225
  const remaining = await (0, import_promises5.readdir)(directory);
77169
77226
  if (remaining.length === 0) await (0, import_promises5.rm)(directory, { recursive: true, force: true });
77170
77227
  }
@@ -77324,13 +77381,13 @@ async function startDaemon(args) {
77324
77381
  getRuntimeToken: () => runtimeToken
77325
77382
  });
77326
77383
  const runtimeSkillManager = await RuntimeSkillManager.open({
77327
- homeDirectory: (0, import_node_os10.homedir)(),
77384
+ homeDirectory: (0, import_node_os11.homedir)(),
77328
77385
  controlClient: skillControl
77329
77386
  });
77330
77387
  const runtimeSkillCoordinator = new RuntimeSkillCoordinator(
77331
77388
  runtimeSkillManager,
77332
77389
  skillControl,
77333
- (input2) => resolveSkillScanInput((0, import_node_os10.homedir)(), input2)
77390
+ (input2) => resolveSkillScanInput((0, import_node_os11.homedir)(), input2)
77334
77391
  );
77335
77392
  const runSkillSync = (reason) => {
77336
77393
  const operation = reason === "startup" ? runtimeSkillCoordinator.runStartup() : reason === "interval" ? runtimeSkillCoordinator.runIncremental() : reason === "refresh" ? runtimeSkillCoordinator.runAudit() : runtimeSkillCoordinator.run();
@@ -77404,10 +77461,10 @@ async function startDaemon(args) {
77404
77461
  installationId
77405
77462
  });
77406
77463
  const recentLogs = [];
77407
- const daemonLogPath = (0, import_node_path22.join)((0, import_node_path22.dirname)(configPath), "logs", "daemon.log");
77464
+ const daemonLogPath = (0, import_node_path23.join)((0, import_node_path23.dirname)(configPath), "logs", "daemon.log");
77408
77465
  const persistDaemonLog = (line) => {
77409
77466
  try {
77410
- (0, import_node_fs20.mkdirSync)((0, import_node_path22.dirname)(daemonLogPath), { recursive: true });
77467
+ (0, import_node_fs20.mkdirSync)((0, import_node_path23.dirname)(daemonLogPath), { recursive: true });
77411
77468
  try {
77412
77469
  if ((0, import_node_fs20.statSync)(daemonLogPath).size > 5 * 1024 * 1024) {
77413
77470
  (0, import_node_fs20.renameSync)(daemonLogPath, `${daemonLogPath}.1`);
@@ -77539,7 +77596,7 @@ async function startDaemon(args) {
77539
77596
  };
77540
77597
  for (const relocation of stored.workspaceRelocations ?? []) {
77541
77598
  if (relocation?.conversationId && relocation.runId && relocation.previousPath && relocation.canonicalPath) {
77542
- workspaceRelocations.set((0, import_node_path22.resolve)(relocation.previousPath), relocation);
77599
+ workspaceRelocations.set((0, import_node_path23.resolve)(relocation.previousPath), relocation);
77543
77600
  }
77544
77601
  }
77545
77602
  if (stored.localApiPort !== localApiPort || stored.localApiToken !== localApiToken || stored.localServiceId !== localServiceId || stored.localServiceSecret !== localServiceSecret || stored.eventSpoolKey !== eventSpoolKey || stored.daemonEpoch !== daemonEpoch || stored.installationId !== installationId) {
@@ -78247,7 +78304,7 @@ async function setupDaemon(args) {
78247
78304
  const teamId = argValue(args, "--team") ?? process.env.ALAN_TEAM_ID;
78248
78305
  const setupToken = argValue(args, "--setup-token") ?? process.env.ALAN_RUNTIME_SETUP_TOKEN;
78249
78306
  const token = argValue(args, "--token") ?? process.env.ALAN_SETUP_TOKEN;
78250
- const displayName = argValue(args, "--name") ?? (0, import_node_os11.hostname)();
78307
+ const displayName = argValue(args, "--name") ?? (0, import_node_os12.hostname)();
78251
78308
  const scope = argValue(args, "--scope") ?? process.env.ALAN_RUNTIME_SCOPE ?? (setupToken ? "team" : "user");
78252
78309
  const installationId = argValue(args, "--installation-id") ?? previousConfig.installationId ?? (0, import_node_crypto17.randomUUID)();
78253
78310
  if (scope !== "team" && scope !== "user") {
@@ -78270,7 +78327,7 @@ async function setupDaemon(args) {
78270
78327
  ...teamId ? { teamId } : {},
78271
78328
  ...setupToken ? { setupToken, registrationAttemptId } : {},
78272
78329
  displayName,
78273
- hostname: (0, import_node_os11.hostname)(),
78330
+ hostname: (0, import_node_os12.hostname)(),
78274
78331
  runtimeKind: "machine",
78275
78332
  managementKind: "user_managed",
78276
78333
  hostKind: "daemon",
@@ -78354,7 +78411,7 @@ async function loginWithDeviceCode(args) {
78354
78411
  }
78355
78412
  const previousConfig = readConfigForRegistration();
78356
78413
  const { apiUrl, wsUrl, endpointProfile } = resolveEndpoints(args);
78357
- const displayName = argValue(args, "--name") ?? (0, import_node_os11.hostname)();
78414
+ const displayName = argValue(args, "--name") ?? (0, import_node_os12.hostname)();
78358
78415
  const maxPolls = Number.parseInt(argValue(args, "--max-polls") ?? "300", 10);
78359
78416
  const resumed = readPendingDeviceAuthorization(apiUrl);
78360
78417
  const installationId = resumed?.installationId ?? previousConfig.installationId ?? (0, import_node_crypto17.randomUUID)();
@@ -78366,7 +78423,7 @@ async function loginWithDeviceCode(args) {
78366
78423
  headers: { "content-type": "application/json" },
78367
78424
  body: JSON.stringify({
78368
78425
  displayName,
78369
- hostname: (0, import_node_os11.hostname)(),
78426
+ hostname: (0, import_node_os12.hostname)(),
78370
78427
  capabilities: discoverCapabilities(),
78371
78428
  metadata: {
78372
78429
  ...await collectRuntimeMetadataWithProviderLimits(),
@@ -78790,25 +78847,18 @@ async function printDoctor(args = []) {
78790
78847
  // src/mcp-config-adapters.ts
78791
78848
  var import_node_crypto18 = require("crypto");
78792
78849
  var import_node_fs21 = require("fs");
78793
- var import_node_os12 = require("os");
78794
- var import_node_path23 = require("path");
78850
+ var import_node_os13 = require("os");
78851
+ var import_node_path24 = require("path");
78795
78852
  var log = {
78796
78853
  info: (...args) => console.info("[mcp-config-adapters]", ...args),
78797
78854
  warn: (...args) => console.warn("[mcp-config-adapters]", ...args),
78798
78855
  debug: () => {
78799
78856
  }
78800
78857
  };
78801
- var HOME = (0, import_node_os12.homedir)();
78802
- var PATHS = {
78803
- claude: (0, import_node_path23.join)(HOME, ".claude.json"),
78804
- codex: (0, import_node_path23.join)(HOME, ".codex", "config.toml"),
78805
- cursor: (0, import_node_path23.join)(HOME, ".cursor", "mcp.json"),
78806
- antigravity: (0, import_node_path23.join)(HOME, ".gemini", "config", "mcp_config.json"),
78807
- kimi: (0, import_node_path23.join)(HOME, ".kimi", "mcp.json"),
78808
- opencode: (0, import_node_path23.join)(HOME, ".config", "opencode", "opencode.json"),
78809
- factory: (0, import_node_path23.join)(HOME, ".factory", "mcp.json"),
78810
- amp: (0, import_node_path23.join)(HOME, ".config", "amp", "settings.json")
78811
- };
78858
+ var homeDirectoryOverride;
78859
+ function homeDirectory() {
78860
+ return homeDirectoryOverride ?? (0, import_node_os13.homedir)();
78861
+ }
78812
78862
  var MalformedToolConfigError = class extends Error {
78813
78863
  };
78814
78864
  function parseJsonSafe2(content) {
@@ -78826,7 +78876,7 @@ function readFileOr(path2) {
78826
78876
  return (0, import_node_fs21.existsSync)(path2) ? (0, import_node_fs21.readFileSync)(path2, "utf-8") : null;
78827
78877
  }
78828
78878
  function acquireConfigLock2(path2) {
78829
- (0, import_node_fs21.mkdirSync)((0, import_node_path23.dirname)(path2), { recursive: true });
78879
+ (0, import_node_fs21.mkdirSync)((0, import_node_path24.dirname)(path2), { recursive: true });
78830
78880
  const lockPath = `${path2}.alan-lock`;
78831
78881
  const startedAt = Date.now();
78832
78882
  while (true) {
@@ -78852,7 +78902,7 @@ function acquireConfigLock2(path2) {
78852
78902
  }
78853
78903
  }
78854
78904
  function writeFileSafe2(path2, content) {
78855
- (0, import_node_fs21.mkdirSync)((0, import_node_path23.dirname)(path2), { recursive: true });
78905
+ (0, import_node_fs21.mkdirSync)((0, import_node_path24.dirname)(path2), { recursive: true });
78856
78906
  const pendingPath = `${path2}.alan-pending-${process.pid}-${(0, import_node_crypto18.randomBytes)(6).toString("hex")}`;
78857
78907
  try {
78858
78908
  (0, import_node_fs21.writeFileSync)(pendingPath, content, { encoding: "utf8", mode: 384, flag: "wx" });
@@ -78869,9 +78919,12 @@ function saveMalformedBackup2(path2, content) {
78869
78919
  }
78870
78920
  var claudeAdapter = {
78871
78921
  cli: "Claude Code",
78872
- configPath: PATHS.claude,
78873
- guardDir: HOME,
78874
- // ~/.claude.json lives in home — always exists
78922
+ get configPath() {
78923
+ return (0, import_node_path24.join)(homeDirectory(), ".claude.json");
78924
+ },
78925
+ get guardDir() {
78926
+ return homeDirectory();
78927
+ },
78875
78928
  merge(existing, servers) {
78876
78929
  const config2 = parseJsonSafe2(existing);
78877
78930
  const mcpServers = config2.mcpServers ?? {};
@@ -78899,8 +78952,12 @@ var claudeAdapter = {
78899
78952
  };
78900
78953
  var codexAdapter = {
78901
78954
  cli: "Codex",
78902
- configPath: PATHS.codex,
78903
- guardDir: (0, import_node_path23.join)(HOME, ".codex"),
78955
+ get configPath() {
78956
+ return (0, import_node_path24.join)(homeDirectory(), ".codex", "config.toml");
78957
+ },
78958
+ get guardDir() {
78959
+ return (0, import_node_path24.join)(homeDirectory(), ".codex");
78960
+ },
78904
78961
  merge(existing, servers) {
78905
78962
  let config2 = {};
78906
78963
  if (existing) {
@@ -78941,8 +78998,12 @@ var codexAdapter = {
78941
78998
  };
78942
78999
  var cursorAdapter = {
78943
79000
  cli: "Cursor",
78944
- configPath: PATHS.cursor,
78945
- guardDir: (0, import_node_path23.join)(HOME, ".cursor"),
79001
+ get configPath() {
79002
+ return (0, import_node_path24.join)(homeDirectory(), ".cursor", "mcp.json");
79003
+ },
79004
+ get guardDir() {
79005
+ return (0, import_node_path24.join)(homeDirectory(), ".cursor");
79006
+ },
78946
79007
  merge(existing, servers) {
78947
79008
  const config2 = parseJsonSafe2(existing);
78948
79009
  const mcpServers = config2.mcpServers ?? {};
@@ -78971,8 +79032,12 @@ var cursorAdapter = {
78971
79032
  function createAntigravityAdapter() {
78972
79033
  return {
78973
79034
  cli: "Antigravity CLI",
78974
- configPath: PATHS.antigravity,
78975
- guardDir: (0, import_node_path23.join)(HOME, ".gemini", "config"),
79035
+ get configPath() {
79036
+ return (0, import_node_path24.join)(homeDirectory(), ".gemini", "config", "mcp_config.json");
79037
+ },
79038
+ get guardDir() {
79039
+ return (0, import_node_path24.join)(homeDirectory(), ".gemini", "config");
79040
+ },
78976
79041
  merge(existing, servers) {
78977
79042
  const config2 = parseJsonSafe2(existing);
78978
79043
  const mcpServers = config2.mcpServers ?? {};
@@ -79002,8 +79067,12 @@ function createAntigravityAdapter() {
79002
79067
  var antigravityAdapter = createAntigravityAdapter();
79003
79068
  var kimiAdapter = {
79004
79069
  cli: "Kimi CLI",
79005
- configPath: PATHS.kimi,
79006
- guardDir: (0, import_node_path23.join)(HOME, ".kimi"),
79070
+ get configPath() {
79071
+ return (0, import_node_path24.join)(homeDirectory(), ".kimi", "mcp.json");
79072
+ },
79073
+ get guardDir() {
79074
+ return (0, import_node_path24.join)(homeDirectory(), ".kimi");
79075
+ },
79007
79076
  merge(existing, servers) {
79008
79077
  const config2 = parseJsonSafe2(existing);
79009
79078
  const mcpServers = config2.mcpServers ?? {};
@@ -79031,8 +79100,12 @@ var kimiAdapter = {
79031
79100
  };
79032
79101
  var opencodeAdapter = {
79033
79102
  cli: "OpenCode",
79034
- configPath: PATHS.opencode,
79035
- guardDir: (0, import_node_path23.join)(HOME, ".config", "opencode"),
79103
+ get configPath() {
79104
+ return (0, import_node_path24.join)(homeDirectory(), ".config", "opencode", "opencode.json");
79105
+ },
79106
+ get guardDir() {
79107
+ return (0, import_node_path24.join)(homeDirectory(), ".config", "opencode");
79108
+ },
79036
79109
  merge(existing, servers) {
79037
79110
  const config2 = parseJsonSafe2(existing);
79038
79111
  const mcp = config2.mcp ?? {};
@@ -79060,8 +79133,12 @@ var opencodeAdapter = {
79060
79133
  };
79061
79134
  var factoryAdapter = {
79062
79135
  cli: "Factory Droid",
79063
- configPath: PATHS.factory,
79064
- guardDir: (0, import_node_path23.join)(HOME, ".factory"),
79136
+ get configPath() {
79137
+ return (0, import_node_path24.join)(homeDirectory(), ".factory", "mcp.json");
79138
+ },
79139
+ get guardDir() {
79140
+ return (0, import_node_path24.join)(homeDirectory(), ".factory");
79141
+ },
79065
79142
  merge(existing, servers) {
79066
79143
  const config2 = parseJsonSafe2(existing);
79067
79144
  const mcpServers = config2.mcpServers ?? {};
@@ -79096,8 +79173,12 @@ var factoryAdapter = {
79096
79173
  };
79097
79174
  var ampAdapter = {
79098
79175
  cli: "Amp",
79099
- configPath: PATHS.amp,
79100
- guardDir: (0, import_node_path23.join)(HOME, ".config", "amp"),
79176
+ get configPath() {
79177
+ return (0, import_node_path24.join)(homeDirectory(), ".config", "amp", "settings.json");
79178
+ },
79179
+ get guardDir() {
79180
+ return (0, import_node_path24.join)(homeDirectory(), ".config", "amp");
79181
+ },
79101
79182
  merge(existing, servers) {
79102
79183
  const config2 = parseJsonSafe2(existing);
79103
79184
  const mcpServers = config2["amp.mcpServers"] ?? {};
@@ -79203,6 +79284,77 @@ function normalizeAlanRuntimeEntry(actual, expected) {
79203
79284
  function matchesAlanManagedEntry(actual, expected) {
79204
79285
  return entriesMatch(actual, expected) || entriesMatch(normalizeAlanRuntimeEntry(actual, expected), expected);
79205
79286
  }
79287
+ var LOCAL_ALAN_MCP_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0"]);
79288
+ var LEGACY_LOCAL_ALAN_MCP_PORTS = /* @__PURE__ */ new Set(["8400"]);
79289
+ var ALAN_MCP_HOST_SUFFIXES = [".tryalan.ai"];
79290
+ function normalizeMcpPathname(pathname) {
79291
+ const trimmed = pathname.replace(/\/+$/, "");
79292
+ return trimmed.length > 0 ? trimmed : "/";
79293
+ }
79294
+ function urlsShareAlanMcpEndpoint(left, right) {
79295
+ try {
79296
+ const a = new URL(left);
79297
+ const b = new URL(right);
79298
+ return a.origin === b.origin && normalizeMcpPathname(a.pathname) === normalizeMcpPathname(b.pathname);
79299
+ } catch {
79300
+ return left === right;
79301
+ }
79302
+ }
79303
+ function configuredAlanMcpUrlsFromEnv() {
79304
+ const urls = [];
79305
+ for (const raw of [
79306
+ process.env.ALAN_MCP_DESKTOP_URL,
79307
+ process.env.ALAN_MCP_PUBLIC_URL,
79308
+ process.env.ALAN_LOCAL_API_URL
79309
+ ]) {
79310
+ const value2 = raw?.trim();
79311
+ if (!value2) continue;
79312
+ try {
79313
+ const parsed = new URL(value2);
79314
+ if (normalizeMcpPathname(parsed.pathname) === "/mcp") {
79315
+ urls.push(parsed.toString());
79316
+ continue;
79317
+ }
79318
+ parsed.pathname = "/mcp";
79319
+ urls.push(parsed.toString());
79320
+ } catch {
79321
+ urls.push(value2.endsWith("/mcp") ? value2 : `${value2.replace(/\/$/, "")}/mcp`);
79322
+ }
79323
+ }
79324
+ return urls;
79325
+ }
79326
+ function extractHttpUrlFromEntry(entry) {
79327
+ if (!entry || typeof entry !== "object") return void 0;
79328
+ const record2 = entry;
79329
+ for (const key of ["url", "serverUrl"]) {
79330
+ const value2 = record2[key];
79331
+ if (typeof value2 === "string" && value2.length > 0) return value2;
79332
+ }
79333
+ for (const value2 of Object.values(record2)) {
79334
+ if (!value2 || typeof value2 !== "object") continue;
79335
+ const nested = extractHttpUrlFromEntry(value2);
79336
+ if (nested) return nested;
79337
+ }
79338
+ return void 0;
79339
+ }
79340
+ function isAlanSelfRegistrationEntry(entry) {
79341
+ const url3 = extractHttpUrlFromEntry(entry);
79342
+ if (!url3) return false;
79343
+ try {
79344
+ const parsed = new URL(url3);
79345
+ if (normalizeMcpPathname(parsed.pathname) !== "/mcp") return false;
79346
+ const host = parsed.hostname.toLowerCase();
79347
+ if (LOCAL_ALAN_MCP_HOSTS.has(host) && LEGACY_LOCAL_ALAN_MCP_PORTS.has(parsed.port)) {
79348
+ return true;
79349
+ }
79350
+ if (ALAN_MCP_HOST_SUFFIXES.some((suffix) => host.endsWith(suffix))) return true;
79351
+ return configuredAlanMcpUrlsFromEnv().some(
79352
+ (configured) => urlsShareAlanMcpEndpoint(configured, url3)
79353
+ );
79354
+ } catch {
79355
+ return false;
79356
+ }
79357
+ }
79206
79358
  function hasAlanManagedSignature(entry) {
79207
79359
  if (!entry || typeof entry !== "object") return false;
79208
79360
  for (const [key, value2] of Object.entries(entry)) {
@@ -79223,6 +79375,9 @@ function expectedServerEntry(adapter, server) {
79223
79375
  function isManagedServerList(entries) {
79224
79376
  return entries.length === 0 || typeof entries[0] !== "string";
79225
79377
  }
79378
+ function isAlanOwnedMcpEntry(entry, desiredEntry, previousEntry) {
79379
+ return hasAlanManagedSignature(entry) || isAlanSelfRegistrationEntry(entry) || matchesAlanManagedEntry(entry, desiredEntry) || previousEntry !== void 0 && matchesAlanManagedEntry(entry, previousEntry);
79380
+ }
79226
79381
  function syncMcpToAllClis(servers, oldManagedServers = []) {
79227
79382
  const written = [];
79228
79383
  const failures = [];
@@ -79237,6 +79392,7 @@ function syncMcpToAllClis(servers, oldManagedServers = []) {
79237
79392
  try {
79238
79393
  const existing = readFileOr(adapter.configPath);
79239
79394
  const previousServers = isManagedServerList(oldManagedServers) ? oldManagedServers : [];
79395
+ const previousNames = isManagedServerList(oldManagedServers) ? oldManagedServers.map((server) => server.name) : oldManagedServers;
79240
79396
  const previousByName = new Map(previousServers.map((server) => [server.name, server]));
79241
79397
  if (existing) {
79242
79398
  for (const server of servers) {
@@ -79245,21 +79401,20 @@ function syncMcpToAllClis(servers, oldManagedServers = []) {
79245
79401
  const desiredEntry = expectedServerEntry(adapter, server);
79246
79402
  const previous = previousByName.get(server.name);
79247
79403
  const previousEntry = previous ? expectedServerEntry(adapter, previous) : void 0;
79248
- if (!hasAlanManagedSignature(currentEntry) && !matchesAlanManagedEntry(currentEntry, desiredEntry) && (!previousEntry || !matchesAlanManagedEntry(currentEntry, previousEntry))) {
79404
+ if (!isAlanOwnedMcpEntry(currentEntry, desiredEntry, previousEntry)) {
79249
79405
  throw new Error(`an unowned entry already uses the name ${server.name}`);
79250
79406
  }
79251
79407
  }
79252
79408
  }
79253
79409
  const currentNames = new Set(servers.map((s) => s.name));
79254
- const toRemove = previousServers.filter((server) => !currentNames.has(server.name));
79410
+ const toRemove = previousNames.filter((name) => !currentNames.has(name));
79255
79411
  let content;
79256
79412
  if (toRemove.length > 0) {
79257
- const ownedNames = existing ? toRemove.filter(
79258
- (server) => matchesAlanManagedEntry(
79259
- serverEntry(adapter, existing, server.name),
79260
- expectedServerEntry(adapter, server)
79261
- )
79262
- ).map((server) => server.name) : [];
79413
+ const ownedNames = existing ? toRemove.filter((name) => {
79414
+ const entry = serverEntry(adapter, existing, name);
79415
+ const previous = previousByName.get(name);
79416
+ return hasAlanManagedSignature(entry) || isAlanSelfRegistrationEntry(entry) || previous !== void 0 && matchesAlanManagedEntry(entry, expectedServerEntry(adapter, previous));
79417
+ }) : [];
79263
79418
  const cleaned = adapter.remove(existing, ownedNames);
79264
79419
  content = adapter.merge(cleaned, servers);
79265
79420
  } else {
@@ -79344,7 +79499,9 @@ function inspectAlanMcpPresence(expectedServers = [], candidateNames = DEFAULT_A
79344
79499
  if (entry === void 0) continue;
79345
79500
  const expected = expectedByName.get(name);
79346
79501
  const matchesExpected = expected ? matchesAlanManagedEntry(entry, expectedServerEntry(adapter, expected)) : false;
79347
- if (!hasAlanManagedSignature(entry) && !matchesExpected) continue;
79502
+ if (!hasAlanManagedSignature(entry) && !matchesExpected && !isAlanSelfRegistrationEntry(entry)) {
79503
+ continue;
79504
+ }
79348
79505
  foundOnCli = true;
79349
79506
  serverNamesFound.add(name);
79350
79507
  }
@@ -79392,7 +79549,8 @@ var McpSyncService = class {
79392
79549
  managedServerNames;
79393
79550
  legacyServerNames;
79394
79551
  getStatus() {
79395
- const presence = inspectAlanMcpPresence([], this.managedServerNames);
79552
+ const candidateNames = [.../* @__PURE__ */ new Set([...this.managedServerNames, ...this.legacyServerNames])];
79553
+ const presence = inspectAlanMcpPresence([], candidateNames);
79396
79554
  return {
79397
79555
  configured: presence.configured,
79398
79556
  lastSyncAt: null,
@@ -79444,8 +79602,12 @@ var McpSyncService = class {
79444
79602
 
79445
79603
  // src/native-hook-config.ts
79446
79604
  var import_node_fs22 = require("fs");
79447
- var import_node_os13 = require("os");
79448
- var import_node_path24 = require("path");
79605
+ var import_node_os14 = require("os");
79606
+ var import_node_path25 = require("path");
79607
+ var ALAN_HOOK_MARKER = "# alan-native-session-hook";
79608
+ var ALAN_KIMI_HOOKS_START = "# alan-native-session-hooks:start";
79609
+ var ALAN_KIMI_HOOKS_END = "# alan-native-session-hooks:end";
79610
+ var ALAN_OPENCODE_PLUGIN_MARKER = "// alan-native-session-plugin";
79449
79611
  var CLAUDE_HOOK_EVENTS = [
79450
79612
  "SessionStart",
79451
79613
  "UserPromptSubmit",
@@ -79455,15 +79617,59 @@ var CLAUDE_HOOK_EVENTS = [
79455
79617
  "SubagentStop",
79456
79618
  "SessionEnd"
79457
79619
  ];
79458
- var ALAN_HOOK_MARKER = "# alan-native-session-hook";
79620
+ var CODEX_HOOK_EVENTS = [
79621
+ "SessionStart",
79622
+ "UserPromptSubmit",
79623
+ "PostToolUse",
79624
+ "Stop",
79625
+ "SubagentStart",
79626
+ "SubagentStop",
79627
+ "SessionEnd"
79628
+ ];
79629
+ var COPILOT_HOOK_EVENTS = [
79630
+ "SessionStart",
79631
+ "UserPromptSubmit",
79632
+ "PostToolUse",
79633
+ "Stop",
79634
+ "SubagentStop",
79635
+ "SessionEnd"
79636
+ ];
79637
+ var CURSOR_HOOK_EVENTS = [
79638
+ "sessionStart",
79639
+ "beforeSubmitPrompt",
79640
+ "afterAgentResponse",
79641
+ "stop",
79642
+ "sessionEnd"
79643
+ ];
79644
+ var KIMI_HOOK_EVENTS = [
79645
+ "SessionStart",
79646
+ "UserPromptSubmit",
79647
+ "PostToolUse",
79648
+ "Stop",
79649
+ "Interrupt",
79650
+ "SubagentStart",
79651
+ "SubagentStop",
79652
+ "SessionEnd"
79653
+ ];
79654
+ var GROK_HOOK_EVENTS = [
79655
+ "SessionStart",
79656
+ "UserPromptSubmit",
79657
+ "PostToolUse",
79658
+ "Stop",
79659
+ "StopFailure",
79660
+ "StopCancelled",
79661
+ "SubagentStart",
79662
+ "SubagentStop",
79663
+ "SessionEnd"
79664
+ ];
79459
79665
  function shellQuote(value2) {
79460
79666
  return `'${value2.replaceAll("'", `'\\''`)}'`;
79461
79667
  }
79462
79668
  function powershellQuote(value2) {
79463
79669
  return `'${value2.replaceAll("'", "''")}'`;
79464
79670
  }
79465
- function nativeHookCommand(input2) {
79466
- const args = [
79671
+ function hookArgs(input2) {
79672
+ return [
79467
79673
  input2.cliEntry,
79468
79674
  "hook",
79469
79675
  "--config-path",
@@ -79474,21 +79680,23 @@ function nativeHookCommand(input2) {
79474
79680
  input2.event,
79475
79681
  ALAN_HOOK_MARKER
79476
79682
  ];
79477
- const environment = Object.entries(input2.environment ?? {});
79478
- for (const [key] of environment) {
79683
+ }
79684
+ function checkedEnvironment(environment) {
79685
+ const entries = Object.entries(environment ?? {});
79686
+ for (const [key] of entries) {
79479
79687
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
79480
79688
  throw new Error(`Invalid native hook environment variable: ${key}`);
79481
79689
  }
79482
79690
  }
79691
+ return entries;
79692
+ }
79693
+ function nativeHookCommand(input2) {
79694
+ const args = hookArgs(input2);
79695
+ const environment = checkedEnvironment(input2.environment);
79483
79696
  if (environment.length === 0) {
79484
- return {
79485
- type: "command",
79486
- command: input2.nodeExecutable,
79487
- args,
79488
- timeout: 5
79489
- };
79697
+ return { type: "command", command: input2.nodeExecutable, args, timeout: 5 };
79490
79698
  }
79491
- if ((input2.platform ?? (0, import_node_os13.platform)()) === "win32") {
79699
+ if ((input2.platform ?? (0, import_node_os14.platform)()) === "win32") {
79492
79700
  const environmentPrefix2 = environment.map(([key, value2]) => `$env:${key}=${powershellQuote(value2)}`).join("; ");
79493
79701
  const command2 = [input2.nodeExecutable, ...args].map(powershellQuote).join(" ");
79494
79702
  return {
@@ -79507,7 +79715,40 @@ function nativeHookCommand(input2) {
79507
79715
  timeout: 5
79508
79716
  };
79509
79717
  }
79510
- function readSettings(path2) {
79718
+ function nativeShellCommand(runtime, provider, event, platform6 = runtime.platform) {
79719
+ const args = hookArgs({
79720
+ configPath: runtime.configPath,
79721
+ cliEntry: runtime.cliEntry,
79722
+ provider,
79723
+ event
79724
+ });
79725
+ const environment = checkedEnvironment(runtime.environment);
79726
+ if (platform6 === "win32") {
79727
+ const prefix2 = environment.map(([key, value2]) => `$env:${key}=${powershellQuote(value2)}`).join("; ");
79728
+ const command2 = `& ${[runtime.nodeExecutable, ...args].map(powershellQuote).join(" ")}`;
79729
+ return prefix2 ? `${prefix2}; ${command2}` : command2;
79730
+ }
79731
+ const prefix = environment.map(([key, value2]) => `${key}=${shellQuote(value2)}`).join(" ");
79732
+ const command = [runtime.nodeExecutable, ...args].map(shellQuote).join(" ");
79733
+ return prefix ? `${prefix} ${command}` : command;
79734
+ }
79735
+ function resolveRuntime(input2 = {}) {
79736
+ const cliEntry = input2.cliEntry ?? process.argv[1];
79737
+ const configPath = input2.configPath ?? process.env.ALAN_AGENT_CONFIG_PATH;
79738
+ if (!cliEntry) throw new Error("Cannot resolve the alan-agent CLI entrypoint");
79739
+ if (!configPath?.trim()) {
79740
+ throw new Error("Cannot install native hooks without an exact Alan agent config path");
79741
+ }
79742
+ return {
79743
+ configPath,
79744
+ homeDir: input2.homeDir ?? (0, import_node_os14.homedir)(),
79745
+ nodeExecutable: input2.nodeExecutable ?? process.execPath,
79746
+ cliEntry,
79747
+ environment: input2.environment,
79748
+ platform: input2.platform ?? (0, import_node_os14.platform)()
79749
+ };
79750
+ }
79751
+ function readSettings(path2, providerLabel) {
79511
79752
  if (!(0, import_node_fs22.existsSync)(path2)) return {};
79512
79753
  try {
79513
79754
  const value2 = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
@@ -79519,78 +79760,363 @@ function readSettings(path2) {
79519
79760
  const backup = `${path2}.malformed-${Date.now()}.bak`;
79520
79761
  (0, import_node_fs22.copyFileSync)(path2, backup);
79521
79762
  throw new Error(
79522
- `Claude settings were malformed and moved to ${backup}: ${error61 instanceof Error ? error61.message : String(error61)}`
79763
+ `${providerLabel} settings were malformed and copied to ${backup}: ${error61 instanceof Error ? error61.message : String(error61)}`
79523
79764
  );
79524
79765
  }
79525
79766
  }
79526
- function withoutAlanHookGroups(value2) {
79767
+ function withoutAlanEntries(value2) {
79527
79768
  if (!Array.isArray(value2)) return [];
79528
- return value2.filter((group) => !JSON.stringify(group).includes(ALAN_HOOK_MARKER));
79769
+ return value2.filter((entry) => !JSON.stringify(entry).includes(ALAN_HOOK_MARKER));
79529
79770
  }
79530
79771
  function writeSettings(path2, settings) {
79531
- (0, import_node_fs22.mkdirSync)((0, import_node_path24.dirname)(path2), { recursive: true, mode: 448 });
79772
+ const serialized = `${JSON.stringify(settings, null, 2)}
79773
+ `;
79774
+ if ((0, import_node_fs22.existsSync)(path2) && (0, import_node_fs22.readFileSync)(path2, "utf8") === serialized) return false;
79775
+ (0, import_node_fs22.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true, mode: 448 });
79532
79776
  const temporary = `${path2}.${process.pid}.tmp`;
79533
- (0, import_node_fs22.writeFileSync)(temporary, `${JSON.stringify(settings, null, 2)}
79534
- `, { mode: 384 });
79777
+ (0, import_node_fs22.writeFileSync)(temporary, serialized, { mode: 384 });
79535
79778
  (0, import_node_fs22.renameSync)(temporary, path2);
79779
+ return true;
79536
79780
  }
79537
- function reconcileClaudeNativeHooks(input2) {
79538
- const homeDir = input2?.homeDir ?? (0, import_node_os13.homedir)();
79539
- const settingsPath = (0, import_node_path24.join)(homeDir, ".claude", "settings.json");
79540
- const nodeExecutable = input2?.nodeExecutable ?? process.execPath;
79541
- const cliEntry = input2?.cliEntry ?? process.argv[1];
79542
- const configPath = input2?.configPath ?? process.env.ALAN_AGENT_CONFIG_PATH;
79543
- if (!cliEntry) throw new Error("Cannot resolve the alan-agent CLI entrypoint");
79544
- if (!configPath?.trim()) {
79545
- throw new Error("Cannot install Claude hooks without an exact Alan agent config path");
79781
+ function writeTextFile(path2, content) {
79782
+ if ((0, import_node_fs22.existsSync)(path2) && (0, import_node_fs22.readFileSync)(path2, "utf8") === content) return false;
79783
+ (0, import_node_fs22.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true, mode: 448 });
79784
+ const temporary = `${path2}.${process.pid}.tmp`;
79785
+ (0, import_node_fs22.writeFileSync)(temporary, content, { mode: 384 });
79786
+ (0, import_node_fs22.renameSync)(temporary, path2);
79787
+ return true;
79788
+ }
79789
+ function withoutMarkedSection(content, start, end) {
79790
+ const startIndex = content.indexOf(start);
79791
+ const endIndex = content.indexOf(end);
79792
+ if (startIndex < 0 && endIndex < 0) return content;
79793
+ if (startIndex < 0 || endIndex < startIndex) {
79794
+ throw new Error(`Malformed Alan-owned configuration section: ${start}`);
79546
79795
  }
79547
- const settings = readSettings(settingsPath);
79796
+ const afterEnd = endIndex + end.length;
79797
+ return `${content.slice(0, startIndex).trimEnd()}
79798
+ ${content.slice(afterEnd).trimStart()}`.trim();
79799
+ }
79800
+ function reconcileNestedCommandHooks(input2) {
79801
+ const settings = readSettings(input2.path, input2.providerLabel);
79548
79802
  const currentHooks = settings.hooks && typeof settings.hooks === "object" && !Array.isArray(settings.hooks) ? settings.hooks : {};
79549
79803
  const hooks = { ...currentHooks };
79550
- for (const event of CLAUDE_HOOK_EVENTS) {
79804
+ for (const event of input2.events) {
79805
+ hooks[event] = [...withoutAlanEntries(currentHooks[event]), { hooks: [input2.command(event)] }];
79806
+ }
79807
+ return writeSettings(input2.path, { ...settings, hooks });
79808
+ }
79809
+ function removeNestedCommandHooks(path2, providerLabel) {
79810
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
79811
+ const settings = readSettings(path2, providerLabel);
79812
+ if (!settings.hooks || typeof settings.hooks !== "object" || Array.isArray(settings.hooks)) {
79813
+ return false;
79814
+ }
79815
+ const hooks = {};
79816
+ let removed = false;
79817
+ for (const [event, groups] of Object.entries(settings.hooks)) {
79818
+ const retained = withoutAlanEntries(groups);
79819
+ if (Array.isArray(groups) && retained.length !== groups.length) removed = true;
79820
+ if (retained.length > 0) hooks[event] = retained;
79821
+ }
79822
+ return removed ? writeSettings(path2, { ...settings, hooks }) : false;
79823
+ }
79824
+ function reconcileClaudeNativeHooks(input2 = {}) {
79825
+ const runtime = resolveRuntime(input2);
79826
+ return reconcileNestedCommandHooks({
79827
+ path: (0, import_node_path25.join)(runtime.homeDir, ".claude", "settings.json"),
79828
+ providerLabel: "Claude",
79829
+ events: CLAUDE_HOOK_EVENTS,
79830
+ command: (event) => ({
79831
+ ...nativeHookCommand({
79832
+ ...runtime,
79833
+ provider: "claude_cli",
79834
+ event
79835
+ })
79836
+ })
79837
+ });
79838
+ }
79839
+ function removeClaudeNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
79840
+ return removeNestedCommandHooks((0, import_node_path25.join)(homeDir, ".claude", "settings.json"), "Claude");
79841
+ }
79842
+ function reconcileCodexNativeHooks(input2 = {}) {
79843
+ const runtime = resolveRuntime(input2);
79844
+ return reconcileNestedCommandHooks({
79845
+ path: (0, import_node_path25.join)(runtime.homeDir, ".codex", "hooks.json"),
79846
+ providerLabel: "Codex",
79847
+ events: CODEX_HOOK_EVENTS,
79848
+ command: (event) => ({
79849
+ type: "command",
79850
+ command: nativeShellCommand(runtime, "codex_app_server", event, "darwin"),
79851
+ commandWindows: nativeShellCommand(runtime, "codex_app_server", event, "win32"),
79852
+ timeout: event === "SessionEnd" ? 3 : 5
79853
+ })
79854
+ });
79855
+ }
79856
+ function removeCodexNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
79857
+ return removeNestedCommandHooks((0, import_node_path25.join)(homeDir, ".codex", "hooks.json"), "Codex");
79858
+ }
79859
+ function reconcileCopilotNativeHooks(input2 = {}) {
79860
+ const runtime = resolveRuntime(input2);
79861
+ const path2 = (0, import_node_path25.join)(runtime.homeDir, ".copilot", "hooks", "alan-native-session.json");
79862
+ if ((0, import_node_fs22.existsSync)(path2) && !(0, import_node_fs22.readFileSync)(path2, "utf8").includes(ALAN_HOOK_MARKER)) {
79863
+ throw new Error(`Refusing to overwrite non-Alan Copilot hook configuration at ${path2}`);
79864
+ }
79865
+ const hooks = Object.fromEntries(
79866
+ COPILOT_HOOK_EVENTS.map((event) => [
79867
+ event,
79868
+ [
79869
+ {
79870
+ type: "command",
79871
+ bash: nativeShellCommand(runtime, "copilot_cli", event, "darwin"),
79872
+ powershell: nativeShellCommand(runtime, "copilot_cli", event, "win32"),
79873
+ timeoutSec: event === "SessionEnd" ? 3 : 5
79874
+ }
79875
+ ]
79876
+ ])
79877
+ );
79878
+ return writeSettings(path2, { version: 1, hooks });
79879
+ }
79880
+ function removeCopilotNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
79881
+ const path2 = (0, import_node_path25.join)(homeDir, ".copilot", "hooks", "alan-native-session.json");
79882
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
79883
+ if (!(0, import_node_fs22.readFileSync)(path2, "utf8").includes(ALAN_HOOK_MARKER)) return false;
79884
+ (0, import_node_fs22.rmSync)(path2);
79885
+ return true;
79886
+ }
79887
+ function reconcileCursorNativeHooks(input2 = {}) {
79888
+ const runtime = resolveRuntime(input2);
79889
+ const path2 = (0, import_node_path25.join)(runtime.homeDir, ".cursor", "hooks.json");
79890
+ const settings = readSettings(path2, "Cursor");
79891
+ const currentHooks = settings.hooks && typeof settings.hooks === "object" && !Array.isArray(settings.hooks) ? settings.hooks : {};
79892
+ const hooks = { ...currentHooks };
79893
+ for (const event of CURSOR_HOOK_EVENTS) {
79551
79894
  hooks[event] = [
79552
- ...withoutAlanHookGroups(currentHooks[event]),
79895
+ ...withoutAlanEntries(currentHooks[event]),
79553
79896
  {
79554
- hooks: [
79555
- nativeHookCommand({
79556
- configPath,
79557
- nodeExecutable,
79558
- cliEntry,
79559
- environment: input2?.environment,
79560
- platform: input2?.platform,
79561
- provider: "claude_cli",
79562
- event
79563
- })
79564
- ]
79897
+ type: "command",
79898
+ command: nativeShellCommand(runtime, "cursor_agent_cli", event),
79899
+ timeout: 5
79565
79900
  }
79566
79901
  ];
79567
79902
  }
79568
- const next = { ...settings, hooks };
79569
- const previous = (0, import_node_fs22.existsSync)(settingsPath) ? (0, import_node_fs22.readFileSync)(settingsPath, "utf8") : null;
79570
- const serialized = `${JSON.stringify(next, null, 2)}
79571
- `;
79572
- if (previous === serialized) return false;
79573
- writeSettings(settingsPath, next);
79574
- return true;
79903
+ return writeSettings(path2, { ...settings, version: settings.version ?? 1, hooks });
79575
79904
  }
79576
- function removeClaudeNativeHooks(homeDir = (0, import_node_os13.homedir)()) {
79577
- const settingsPath = (0, import_node_path24.join)(homeDir, ".claude", "settings.json");
79578
- if (!(0, import_node_fs22.existsSync)(settingsPath)) return false;
79579
- const settings = readSettings(settingsPath);
79905
+ function removeCursorNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
79906
+ const path2 = (0, import_node_path25.join)(homeDir, ".cursor", "hooks.json");
79907
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
79908
+ const settings = readSettings(path2, "Cursor");
79580
79909
  if (!settings.hooks || typeof settings.hooks !== "object" || Array.isArray(settings.hooks)) {
79581
79910
  return false;
79582
79911
  }
79583
79912
  const hooks = {};
79584
79913
  let removed = false;
79585
- for (const [event, groups] of Object.entries(settings.hooks)) {
79586
- const retained = withoutAlanHookGroups(groups);
79587
- if (Array.isArray(groups) && retained.length !== groups.length) removed = true;
79914
+ for (const [event, entries] of Object.entries(settings.hooks)) {
79915
+ const retained = withoutAlanEntries(entries);
79916
+ if (Array.isArray(entries) && retained.length !== entries.length) removed = true;
79588
79917
  if (retained.length > 0) hooks[event] = retained;
79589
79918
  }
79590
- if (!removed) return false;
79591
- writeSettings(settingsPath, { ...settings, hooks });
79919
+ return removed ? writeSettings(path2, { ...settings, hooks }) : false;
79920
+ }
79921
+ function kimiHookSection(runtime) {
79922
+ const hooks = KIMI_HOOK_EVENTS.map(
79923
+ (event) => [
79924
+ "[[hooks]]",
79925
+ `event = ${JSON.stringify(event)}`,
79926
+ `command = ${JSON.stringify(nativeShellCommand(runtime, "kimi_cli", event))}`,
79927
+ `timeout = ${event === "SessionEnd" ? 3 : 5}`
79928
+ ].join("\n")
79929
+ ).join("\n\n");
79930
+ return `${ALAN_KIMI_HOOKS_START}
79931
+ ${hooks}
79932
+ ${ALAN_KIMI_HOOKS_END}`;
79933
+ }
79934
+ function reconcileKimiNativeHooks(input2 = {}) {
79935
+ const runtime = resolveRuntime(input2);
79936
+ const path2 = (0, import_node_path25.join)(runtime.homeDir, ".kimi-code", "config.toml");
79937
+ const current = (0, import_node_fs22.existsSync)(path2) ? (0, import_node_fs22.readFileSync)(path2, "utf8") : "";
79938
+ const userContent = withoutMarkedSection(current, ALAN_KIMI_HOOKS_START, ALAN_KIMI_HOOKS_END);
79939
+ const content = `${userContent.trimEnd()}${userContent.trim() ? "\n\n" : ""}${kimiHookSection(runtime)}
79940
+ `;
79941
+ return writeTextFile(path2, content);
79942
+ }
79943
+ function removeKimiNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
79944
+ const path2 = (0, import_node_path25.join)(homeDir, ".kimi-code", "config.toml");
79945
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
79946
+ const current = (0, import_node_fs22.readFileSync)(path2, "utf8");
79947
+ const content = withoutMarkedSection(current, ALAN_KIMI_HOOKS_START, ALAN_KIMI_HOOKS_END);
79948
+ if (content === current) return false;
79949
+ return writeTextFile(path2, content ? `${content.trimEnd()}
79950
+ ` : "");
79951
+ }
79952
+ function reconcileGrokNativeHooks(input2 = {}) {
79953
+ const runtime = resolveRuntime(input2);
79954
+ const path2 = (0, import_node_path25.join)(runtime.homeDir, ".grok", "hooks", "alan-native-session.json");
79955
+ if ((0, import_node_fs22.existsSync)(path2) && !(0, import_node_fs22.readFileSync)(path2, "utf8").includes(ALAN_HOOK_MARKER)) {
79956
+ throw new Error(`Refusing to overwrite non-Alan Grok hook configuration at ${path2}`);
79957
+ }
79958
+ return reconcileNestedCommandHooks({
79959
+ path: path2,
79960
+ providerLabel: "Grok",
79961
+ events: GROK_HOOK_EVENTS,
79962
+ command: (event) => ({
79963
+ type: "command",
79964
+ command: nativeShellCommand(runtime, "grok_cli", event),
79965
+ timeout: event === "SessionEnd" ? 3 : 5
79966
+ })
79967
+ });
79968
+ }
79969
+ function removeGrokNativeHooks(homeDir = (0, import_node_os14.homedir)()) {
79970
+ const path2 = (0, import_node_path25.join)(homeDir, ".grok", "hooks", "alan-native-session.json");
79971
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
79972
+ if (!(0, import_node_fs22.readFileSync)(path2, "utf8").includes(ALAN_HOOK_MARKER)) return false;
79973
+ (0, import_node_fs22.rmSync)(path2);
79974
+ return true;
79975
+ }
79976
+ function opencodePluginSource(runtime) {
79977
+ const command = [
79978
+ runtime.nodeExecutable,
79979
+ runtime.cliEntry,
79980
+ "hook",
79981
+ "--config-path",
79982
+ runtime.configPath,
79983
+ "--provider",
79984
+ "opencode_cli"
79985
+ ];
79986
+ const environment = runtime.environment ?? {};
79987
+ return `${ALAN_OPENCODE_PLUGIN_MARKER}
79988
+ const command = ${JSON.stringify(command)}
79989
+ const environment = ${JSON.stringify(environment)}
79990
+
79991
+ export const AlanNativeSessionPlugin = async ({ directory }) => {
79992
+ const textByPart = new Map()
79993
+ const userPartIdsBySession = new Map()
79994
+ const send = async (event, payload) => {
79995
+ const proc = Bun.spawn({
79996
+ cmd: [...command, "--event", event, ${JSON.stringify(ALAN_HOOK_MARKER)}],
79997
+ env: { ...process.env, ...environment },
79998
+ stdin: "pipe",
79999
+ stdout: "ignore",
80000
+ stderr: "ignore",
80001
+ })
80002
+ proc.stdin.write(JSON.stringify({ ...payload, cwd: payload.cwd ?? directory }))
80003
+ proc.stdin.end()
80004
+ await proc.exited
80005
+ }
80006
+
80007
+ return {
80008
+ "chat.message": async (input, output) => {
80009
+ userPartIdsBySession.set(
80010
+ input.sessionID,
80011
+ new Set(output.parts.map((part) => part.id).filter(Boolean)),
80012
+ )
80013
+ const prompt = output.parts
80014
+ .filter((part) => part.type === "text")
80015
+ .map((part) => part.text)
80016
+ .join("\\n")
80017
+ await send("user_prompt", { session_id: input.sessionID, prompt })
80018
+ },
80019
+ event: async ({ event }) => {
80020
+ if (event.type === "session.created") {
80021
+ await send("session_start", { session_id: event.properties.info.id })
80022
+ return
80023
+ }
80024
+ if (event.type === "session.idle") {
80025
+ await send("stop", { session_id: event.properties.sessionID })
80026
+ return
80027
+ }
80028
+ if (event.type === "session.deleted") {
80029
+ userPartIdsBySession.delete(event.properties.info.id)
80030
+ await send("session_end", { session_id: event.properties.info.id })
80031
+ return
80032
+ }
80033
+ if (event.type === "session.error" && event.properties.sessionID) {
80034
+ await send("stop", {
80035
+ session_id: event.properties.sessionID,
80036
+ error: event.properties.error,
80037
+ })
80038
+ return
80039
+ }
80040
+ if (event.type !== "message.part.updated") return
80041
+ const part = event.properties.part
80042
+ if (part.type !== "text" && part.type !== "reasoning") return
80043
+ if (userPartIdsBySession.get(part.sessionID)?.has(part.id)) return
80044
+ const previous = textByPart.get(part.id) ?? ""
80045
+ const complete = typeof part.text === "string" ? part.text : ""
80046
+ const text = event.properties.delta ?? (complete.startsWith(previous) ? complete.slice(previous.length) : complete)
80047
+ textByPart.set(part.id, complete)
80048
+ if (!text) return
80049
+ await send("transcript_update", {
80050
+ session_id: part.sessionID,
80051
+ source_cursor: part.id + ":" + complete.length,
80052
+ ...(part.type === "reasoning" ? { thinking: text } : { transcript_delta: text }),
80053
+ })
80054
+ },
80055
+ }
80056
+ }
80057
+ `;
80058
+ }
80059
+ function reconcileOpencodeNativePlugin(input2 = {}) {
80060
+ const runtime = resolveRuntime(input2);
80061
+ const path2 = (0, import_node_path25.join)(runtime.homeDir, ".config", "opencode", "plugins", "alan-native-session.js");
80062
+ if ((0, import_node_fs22.existsSync)(path2) && !(0, import_node_fs22.readFileSync)(path2, "utf8").includes(ALAN_OPENCODE_PLUGIN_MARKER)) {
80063
+ throw new Error(`Refusing to overwrite non-Alan OpenCode plugin at ${path2}`);
80064
+ }
80065
+ const source = opencodePluginSource(runtime);
80066
+ if ((0, import_node_fs22.existsSync)(path2) && (0, import_node_fs22.readFileSync)(path2, "utf8") === source) return false;
80067
+ (0, import_node_fs22.mkdirSync)((0, import_node_path25.dirname)(path2), { recursive: true, mode: 448 });
80068
+ const temporary = `${path2}.${process.pid}.tmp`;
80069
+ (0, import_node_fs22.writeFileSync)(temporary, source, { mode: 384 });
80070
+ (0, import_node_fs22.renameSync)(temporary, path2);
79592
80071
  return true;
79593
80072
  }
80073
+ function removeOpencodeNativePlugin(homeDir = (0, import_node_os14.homedir)()) {
80074
+ const path2 = (0, import_node_path25.join)(homeDir, ".config", "opencode", "plugins", "alan-native-session.js");
80075
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
80076
+ if (!(0, import_node_fs22.readFileSync)(path2, "utf8").includes(ALAN_OPENCODE_PLUGIN_MARKER)) return false;
80077
+ (0, import_node_fs22.rmSync)(path2);
80078
+ return true;
80079
+ }
80080
+ function configFileContainsMarker(path2, marker) {
80081
+ if (!(0, import_node_fs22.existsSync)(path2)) return false;
80082
+ try {
80083
+ return (0, import_node_fs22.readFileSync)(path2, "utf8").includes(marker);
80084
+ } catch {
80085
+ return false;
80086
+ }
80087
+ }
80088
+ function inspectNativeHooksConfigured(providerKind, homeDir = (0, import_node_os14.homedir)()) {
80089
+ switch (providerKind) {
80090
+ case "claude_cli":
80091
+ return configFileContainsMarker((0, import_node_path25.join)(homeDir, ".claude", "settings.json"), ALAN_HOOK_MARKER);
80092
+ case "codex_app_server":
80093
+ return configFileContainsMarker((0, import_node_path25.join)(homeDir, ".codex", "hooks.json"), ALAN_HOOK_MARKER);
80094
+ case "copilot_cli":
80095
+ return configFileContainsMarker(
80096
+ (0, import_node_path25.join)(homeDir, ".copilot", "hooks", "alan-native-session.json"),
80097
+ ALAN_HOOK_MARKER
80098
+ );
80099
+ case "cursor_agent_cli":
80100
+ return configFileContainsMarker((0, import_node_path25.join)(homeDir, ".cursor", "hooks.json"), ALAN_HOOK_MARKER);
80101
+ case "kimi_cli":
80102
+ return configFileContainsMarker(
80103
+ (0, import_node_path25.join)(homeDir, ".kimi-code", "config.toml"),
80104
+ ALAN_KIMI_HOOKS_START
80105
+ );
80106
+ case "grok_cli":
80107
+ return configFileContainsMarker(
80108
+ (0, import_node_path25.join)(homeDir, ".grok", "hooks", "alan-native-session.json"),
80109
+ ALAN_HOOK_MARKER
80110
+ );
80111
+ case "opencode_cli":
80112
+ return configFileContainsMarker(
80113
+ (0, import_node_path25.join)(homeDir, ".config", "opencode", "plugins", "alan-native-session.js"),
80114
+ ALAN_OPENCODE_PLUGIN_MARKER
80115
+ );
80116
+ default:
80117
+ return false;
80118
+ }
80119
+ }
79594
80120
 
79595
80121
  // src/integration-cli.ts
79596
80122
  function alanMcpServers(apiUrl) {
@@ -79601,12 +80127,41 @@ function alanMcpServers(apiUrl) {
79601
80127
  }
79602
80128
  };
79603
80129
  }
80130
+ function reconcileInstalledNativeHooks(options) {
80131
+ const environment = getDaemonCliEnvironment();
80132
+ const nativeRuntime = {
80133
+ configPath: options.configPath ?? getConfigPath(),
80134
+ nodeExecutable: options.nativeHookRuntime?.executable,
80135
+ cliEntry: options.nativeHookRuntime?.cliEntry,
80136
+ environment: options.nativeHookRuntime?.environment
80137
+ };
80138
+ return [
80139
+ resolveCliExecutable("claude", environment) ? reconcileClaudeNativeHooks(nativeRuntime) : false,
80140
+ resolveCliExecutable("codex", environment) ? reconcileCodexNativeHooks(nativeRuntime) : false,
80141
+ resolveCliExecutable("copilot", environment) ? reconcileCopilotNativeHooks(nativeRuntime) : false,
80142
+ resolveCliExecutable("cursor-agent", environment) ? reconcileCursorNativeHooks(nativeRuntime) : false,
80143
+ resolveCliExecutable("kimi-cli", environment) ? reconcileKimiNativeHooks(nativeRuntime) : false,
80144
+ resolveCliExecutable("grok", environment) ? reconcileGrokNativeHooks(nativeRuntime) : false,
80145
+ resolveCliExecutable("opencode", environment) ? reconcileOpencodeNativePlugin(nativeRuntime) : false
80146
+ ].some(Boolean);
80147
+ }
80148
+ function removeNativeHooksOnly() {
80149
+ removeClaudeNativeHooks();
80150
+ removeCodexNativeHooks();
80151
+ removeCopilotNativeHooks();
80152
+ removeCursorNativeHooks();
80153
+ removeKimiNativeHooks();
80154
+ removeGrokNativeHooks();
80155
+ removeOpencodeNativePlugin();
80156
+ }
79604
80157
  function runMcpIntegrationCommand(args, options = {}) {
79605
80158
  bindConfigPath(args);
79606
80159
  const action = args[0] ?? "status";
79607
80160
  const config2 = readConfig();
79608
80161
  const endpoints = resolveEndpoints(args.slice(1), config2);
79609
80162
  const service = new McpSyncService({ enabled: true });
80163
+ const reconcileMcp = options.reconcileMcp ?? true;
80164
+ const reconcileHooks = options.reconcileHooks ?? true;
79610
80165
  if (action === "status") {
79611
80166
  process.stdout.write(`${JSON.stringify(service.getStatus(), null, 2)}
79612
80167
  `);
@@ -79618,23 +80173,26 @@ function runMcpIntegrationCommand(args, options = {}) {
79618
80173
  "Alan is not configured. Run `alan-agent login` or `alan-agent setup` first."
79619
80174
  );
79620
80175
  }
79621
- const result = service.syncServers(alanMcpServers(endpoints.apiUrl), endpoints.apiUrl);
79622
- if (result.errors.length > 0) throw new Error(result.errors.join("; "));
79623
- const hooksUpdated = resolveCliExecutable("claude", getDaemonCliEnvironment()) ? reconcileClaudeNativeHooks({
79624
- configPath: getConfigPath(),
79625
- nodeExecutable: options.nativeHookRuntime?.executable,
79626
- cliEntry: options.nativeHookRuntime?.cliEntry,
79627
- environment: options.nativeHookRuntime?.environment
79628
- }) : false;
80176
+ let mcpServersUpdated = false;
80177
+ if (reconcileMcp) {
80178
+ const result = service.syncServers(alanMcpServers(endpoints.apiUrl), endpoints.apiUrl);
80179
+ if (result.errors.length > 0) throw new Error(result.errors.join("; "));
80180
+ mcpServersUpdated = result.mcpServersUpdated;
80181
+ }
80182
+ const hooksUpdated = reconcileHooks ? reconcileInstalledNativeHooks(options) : false;
79629
80183
  process.stdout.write(
79630
- `${result.mcpServersUpdated || hooksUpdated ? "Alan CLI integrations updated" : "Alan CLI integrations already current"}.
80184
+ `${mcpServersUpdated || hooksUpdated ? "Alan CLI integrations updated" : "Alan CLI integrations already current"}.
79631
80185
  `
79632
80186
  );
79633
80187
  return;
79634
80188
  }
79635
80189
  if (action === "uninstall") {
79636
- service.cleanup(toManagedMcpServers(alanMcpServers(endpoints.apiUrl)));
79637
- removeClaudeNativeHooks();
80190
+ if (reconcileMcp) {
80191
+ service.cleanup(toManagedMcpServers(alanMcpServers(endpoints.apiUrl)));
80192
+ }
80193
+ if (reconcileHooks) {
80194
+ removeNativeHooksOnly();
80195
+ }
79638
80196
  process.stdout.write("Removed Alan-owned MCP configuration.\n");
79639
80197
  return;
79640
80198
  }
@@ -79716,7 +80274,8 @@ function omitUndefined(record2) {
79716
80274
  // src/native-hook-command.ts
79717
80275
  var import_node_crypto19 = require("crypto");
79718
80276
  var import_node_fs23 = require("fs");
79719
- var import_node_path25 = require("path");
80277
+ var import_node_os15 = require("os");
80278
+ var import_node_path26 = require("path");
79720
80279
 
79721
80280
  // src/native-session.ts
79722
80281
  var NATIVE_SESSION_PROVIDER_CAPABILITIES = [
@@ -79748,28 +80307,64 @@ var NATIVE_SESSION_PROVIDER_CAPABILITIES = [
79748
80307
  command: "codex",
79749
80308
  capabilities: {
79750
80309
  mcp: true,
79751
- lifecycleHooks: false,
79752
- transcriptDelta: false,
79753
- subagents: false,
79754
- sessionEnd: false,
79755
- state: "degraded",
79756
- reason: "Codex exposes a turn-complete notification, not full lifecycle hooks."
80310
+ lifecycleHooks: true,
80311
+ transcriptDelta: true,
80312
+ subagents: true,
80313
+ sessionEnd: true,
80314
+ state: "supported"
79757
80315
  },
79758
- supportedHookEvents: ["agent-turn-complete"]
80316
+ supportedHookEvents: [
80317
+ "SessionStart",
80318
+ "UserPromptSubmit",
80319
+ "PostToolUse",
80320
+ "Stop",
80321
+ "SubagentStart",
80322
+ "SubagentStop",
80323
+ "SessionEnd"
80324
+ ]
79759
80325
  },
79760
80326
  {
79761
80327
  providerKind: "copilot_cli",
79762
80328
  provider: "copilot",
79763
80329
  command: "copilot",
79764
- capabilities: unsupportedMcpOnlyCapability(),
79765
- supportedHookEvents: []
80330
+ capabilities: {
80331
+ mcp: true,
80332
+ lifecycleHooks: true,
80333
+ transcriptDelta: true,
80334
+ subagents: false,
80335
+ sessionEnd: true,
80336
+ state: "supported",
80337
+ reason: "Copilot exposes stable subagent identity only on SubagentStop, so paired subagent lifecycle is not projected."
80338
+ },
80339
+ supportedHookEvents: [
80340
+ "SessionStart",
80341
+ "UserPromptSubmit",
80342
+ "PostToolUse",
80343
+ "Stop",
80344
+ "SubagentStop",
80345
+ "SessionEnd"
80346
+ ]
79766
80347
  },
79767
80348
  {
79768
80349
  providerKind: "cursor_agent_cli",
79769
80350
  provider: "cursor",
79770
80351
  command: "cursor-agent",
79771
- capabilities: unsupportedMcpOnlyCapability(),
79772
- supportedHookEvents: []
80352
+ capabilities: {
80353
+ mcp: true,
80354
+ lifecycleHooks: true,
80355
+ transcriptDelta: true,
80356
+ subagents: false,
80357
+ sessionEnd: true,
80358
+ state: "supported",
80359
+ reason: "Cursor's subagent stop hook does not expose the stable subagent id from subagent start."
80360
+ },
80361
+ supportedHookEvents: [
80362
+ "sessionStart",
80363
+ "beforeSubmitPrompt",
80364
+ "afterAgentResponse",
80365
+ "stop",
80366
+ "sessionEnd"
80367
+ ]
79773
80368
  },
79774
80369
  {
79775
80370
  providerKind: "antigravity_cli",
@@ -79782,22 +80377,70 @@ var NATIVE_SESSION_PROVIDER_CAPABILITIES = [
79782
80377
  providerKind: "kimi_cli",
79783
80378
  provider: "kimi",
79784
80379
  command: "kimi-cli",
79785
- capabilities: unsupportedMcpOnlyCapability(),
79786
- supportedHookEvents: []
80380
+ capabilities: {
80381
+ mcp: true,
80382
+ lifecycleHooks: true,
80383
+ transcriptDelta: true,
80384
+ subagents: false,
80385
+ sessionEnd: true,
80386
+ state: "supported",
80387
+ reason: "Kimi hooks identify subagents by name but do not expose a stable child session id."
80388
+ },
80389
+ supportedHookEvents: [
80390
+ "SessionStart",
80391
+ "UserPromptSubmit",
80392
+ "PostToolUse",
80393
+ "Stop",
80394
+ "Interrupt",
80395
+ "SubagentStart",
80396
+ "SubagentStop",
80397
+ "SessionEnd"
80398
+ ]
79787
80399
  },
79788
80400
  {
79789
80401
  providerKind: "grok_cli",
79790
80402
  provider: "grok",
79791
80403
  command: "grok",
79792
- capabilities: unsupportedMcpOnlyCapability(),
79793
- supportedHookEvents: []
80404
+ capabilities: {
80405
+ mcp: true,
80406
+ lifecycleHooks: true,
80407
+ transcriptDelta: false,
80408
+ subagents: false,
80409
+ sessionEnd: true,
80410
+ state: "supported",
80411
+ reason: "Grok supplies the final assistant message on terminal hooks, but not incremental transcript deltas or stable child session ids."
80412
+ },
80413
+ supportedHookEvents: [
80414
+ "SessionStart",
80415
+ "UserPromptSubmit",
80416
+ "PostToolUse",
80417
+ "Stop",
80418
+ "StopFailure",
80419
+ "StopCancelled",
80420
+ "SubagentStart",
80421
+ "SubagentStop",
80422
+ "SessionEnd"
80423
+ ]
79794
80424
  },
79795
80425
  {
79796
80426
  providerKind: "opencode_cli",
79797
80427
  provider: "opencode",
79798
80428
  command: "opencode",
79799
- capabilities: unsupportedMcpOnlyCapability(),
79800
- supportedHookEvents: []
80429
+ capabilities: {
80430
+ mcp: true,
80431
+ lifecycleHooks: true,
80432
+ transcriptDelta: true,
80433
+ subagents: false,
80434
+ sessionEnd: true,
80435
+ state: "supported",
80436
+ reason: "OpenCode exposes root session and message events; subagent lifecycle is not distinct."
80437
+ },
80438
+ supportedHookEvents: [
80439
+ "session.created",
80440
+ "message.part.updated",
80441
+ "session.idle",
80442
+ "session.deleted"
80443
+ ]
79801
80444
  },
79802
80445
  {
79803
80446
  providerKind: "droid_cli",
@@ -79847,6 +80490,17 @@ function stringField4(payload, ...names) {
79847
80490
  }
79848
80491
  return void 0;
79849
80492
  }
80493
+ function firstStringArrayField(payload, ...names) {
80494
+ for (const name of names) {
80495
+ const value2 = payload[name];
80496
+ if (!Array.isArray(value2)) continue;
80497
+ const first = value2.find(
80498
+ (entry) => typeof entry === "string" && entry.trim().length > 0
80499
+ );
80500
+ if (first) return first.trim();
80501
+ }
80502
+ return void 0;
80503
+ }
79850
80504
  function nonNegativeIntegerField(payload, ...names) {
79851
80505
  for (const name of names) {
79852
80506
  const value2 = payload[name];
@@ -79854,19 +80508,77 @@ function nonNegativeIntegerField(payload, ...names) {
79854
80508
  }
79855
80509
  return void 0;
79856
80510
  }
80511
+ function resolveCodexSessionIdFromTranscriptPath(transcriptPath) {
80512
+ const fileName = (0, import_node_path26.basename)(transcriptPath);
80513
+ 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(
80514
+ fileName
80515
+ );
80516
+ return match?.[1];
80517
+ }
80518
+ function resolveKimiTranscriptPath(externalSessionId, kimiHomeDir = process.env.KIMI_CODE_HOME?.trim() || (0, import_node_path26.join)((0, import_node_os15.homedir)(), ".kimi-code")) {
80519
+ if ((0, import_node_path26.basename)(externalSessionId) !== externalSessionId) return void 0;
80520
+ const sessionsDir = (0, import_node_path26.join)(kimiHomeDir, "sessions");
80521
+ if (!(0, import_node_fs23.existsSync)(sessionsDir)) return void 0;
80522
+ for (const workspace of (0, import_node_fs23.readdirSync)(sessionsDir, { withFileTypes: true })) {
80523
+ if (!workspace.isDirectory()) continue;
80524
+ const transcriptPath = (0, import_node_path26.join)(
80525
+ sessionsDir,
80526
+ workspace.name,
80527
+ externalSessionId,
80528
+ "agents",
80529
+ "main",
80530
+ "wire.jsonl"
80531
+ );
80532
+ if ((0, import_node_fs23.existsSync)(transcriptPath)) return transcriptPath;
80533
+ }
80534
+ return void 0;
80535
+ }
80536
+ function enrichProviderPayload(provider, payload) {
80537
+ if (provider === "codex_app_server") {
80538
+ const externalSessionId2 = stringField4(
80539
+ payload,
80540
+ "session_id",
80541
+ "sessionId",
80542
+ "thread_id",
80543
+ "threadId"
80544
+ );
80545
+ if (externalSessionId2) return payload;
80546
+ const transcriptPath2 = stringField4(payload, "transcript_path", "transcriptPath");
80547
+ if (!transcriptPath2) return payload;
80548
+ const derivedSessionId = resolveCodexSessionIdFromTranscriptPath(transcriptPath2);
80549
+ return derivedSessionId ? { ...payload, session_id: derivedSessionId } : payload;
80550
+ }
80551
+ if (provider !== "kimi_cli") return payload;
80552
+ const externalSessionId = stringField4(payload, "session_id", "sessionId");
80553
+ if (!externalSessionId || stringField4(payload, "transcript_path", "transcriptPath")) {
80554
+ return payload;
80555
+ }
80556
+ const transcriptPath = resolveKimiTranscriptPath(externalSessionId);
80557
+ return transcriptPath ? { ...payload, transcript_path: transcriptPath } : payload;
80558
+ }
79857
80559
  function parseNativeHookEnvelope(input2) {
79858
80560
  if (!isNativeSessionProviderKind(input2.provider)) {
79859
80561
  throw new Error(`unsupported native session provider: ${input2.provider}`);
79860
80562
  }
79861
- const rawHookEvent = input2.hookEvent ?? stringField4(input2.payload, "hook_event_name", "hookEvent", "type") ?? "notification";
79862
- const cwd = stringField4(input2.payload, "cwd", "working_directory", "workingDirectory");
79863
- const transcriptPath = stringField4(input2.payload, "transcript_path", "transcriptPath");
80563
+ const payload = enrichProviderPayload(input2.provider, input2.payload);
80564
+ const rawHookEvent = input2.hookEvent ?? stringField4(payload, "hook_event_name", "hookEvent", "hookEventName", "type") ?? "notification";
80565
+ const eventType = normalizeHookEvent(rawHookEvent);
80566
+ const cwd = stringField4(payload, "cwd", "working_directory", "workingDirectory") ?? firstStringArrayField(payload, "workspace_roots", "workspaceRoots");
80567
+ const transcriptPath = eventType === "subagent_start" || eventType === "subagent_end" ? stringField4(
80568
+ payload,
80569
+ "agent_transcript_path",
80570
+ "agentTranscriptPath",
80571
+ "transcript_path",
80572
+ "transcriptPath"
80573
+ ) : stringField4(payload, "transcript_path", "transcriptPath");
79864
80574
  const capability = NATIVE_SESSION_PROVIDER_CAPABILITIES.find(
79865
80575
  (candidate) => candidate.providerKind === input2.provider
79866
80576
  );
79867
80577
  if (!capability) throw new Error(`unsupported native session provider: ${input2.provider}`);
79868
- const externalSessionId = stringField4(
79869
- input2.payload,
80578
+ const parentSessionId = stringField4(
80579
+ payload,
80580
+ "parent_session_id",
80581
+ "parentSessionId",
79870
80582
  "session_id",
79871
80583
  "sessionId",
79872
80584
  "conversation_id",
@@ -79874,20 +80586,30 @@ function parseNativeHookEnvelope(input2) {
79874
80586
  "thread_id",
79875
80587
  "threadId"
79876
80588
  );
80589
+ const externalSessionId = eventType === "subagent_start" || eventType === "subagent_end" ? stringField4(
80590
+ payload,
80591
+ "agent_id",
80592
+ "agentId",
80593
+ "subagent_id",
80594
+ "subagentId",
80595
+ "task_id",
80596
+ "taskId"
80597
+ ) ?? parentSessionId : parentSessionId;
79877
80598
  if (!externalSessionId) throw new Error("hook payload is missing a provider session id");
79878
- const cursor = stringField4(input2.payload, "source_cursor", "sourceCursor") ?? nonNegativeIntegerField(input2.payload, "byte_offset", "byteOffset")?.toString() ?? nonNegativeIntegerField(input2.payload, "sequence", "seq")?.toString();
80599
+ const cursor = stringField4(payload, "source_cursor", "sourceCursor") ?? nonNegativeIntegerField(payload, "byte_offset", "byteOffset")?.toString() ?? nonNegativeIntegerField(payload, "sequence", "seq")?.toString();
80600
+ const providerPayload = capability.providerKind === "cursor_agent_cli" && eventType === "transcript_update" && !transcriptPath && typeof payload.text === "string" ? { ...payload, assistant_response: payload.text } : payload;
79879
80601
  return {
79880
80602
  schemaVersion: 1,
79881
80603
  eventId: (0, import_node_crypto19.randomUUID)(),
79882
80604
  provider: capability.provider,
79883
- eventType: normalizeHookEvent(rawHookEvent),
80605
+ eventType,
79884
80606
  observedAt: (input2.now ?? /* @__PURE__ */ new Date()).toISOString(),
79885
80607
  externalSessionId,
79886
- parentExternalSessionId: stringField4(input2.payload, "parent_session_id", "parentSessionId"),
79887
- ...cwd ? { cwd: (0, import_node_path25.resolve)(cwd) } : {},
79888
- ...transcriptPath ? { transcriptPath: (0, import_node_path25.resolve)(transcriptPath) } : {},
80608
+ ...(eventType === "subagent_start" || eventType === "subagent_end") && parentSessionId ? { parentExternalSessionId: parentSessionId } : {},
80609
+ ...cwd ? { cwd: (0, import_node_path26.resolve)(cwd) } : {},
80610
+ ...transcriptPath ? { transcriptPath: (0, import_node_path26.resolve)(transcriptPath) } : {},
79889
80611
  ...cursor ? { sourceCursor: cursor } : {},
79890
- providerPayload: input2.payload
80612
+ providerPayload
79891
80613
  };
79892
80614
  }
79893
80615
  function normalizeHookEvent(raw) {
@@ -79896,6 +80618,8 @@ function normalizeHookEvent(raw) {
79896
80618
  case "session_start":
79897
80619
  return "session_start";
79898
80620
  case "userpromptsubmit":
80621
+ case "userpromptsubmitted":
80622
+ case "beforesubmitprompt":
79899
80623
  case "user_prompt":
79900
80624
  return "user_prompt";
79901
80625
  case "subagentstart":
@@ -79908,8 +80632,19 @@ function normalizeHookEvent(raw) {
79908
80632
  case "session_end":
79909
80633
  return "session_end";
79910
80634
  case "stop":
80635
+ case "agentstop":
80636
+ case "agent_stop":
79911
80637
  case "agent_turn_complete":
80638
+ case "stopfailure":
80639
+ case "stop_failure":
80640
+ case "stopcancelled":
80641
+ case "stop_cancelled":
80642
+ case "interrupt":
79912
80643
  return "stop";
80644
+ case "afteragentresponse":
80645
+ case "message.part.updated":
80646
+ case "transcript_update":
80647
+ return "transcript_update";
79913
80648
  default:
79914
80649
  return "transcript_update";
79915
80650
  }
@@ -79954,21 +80689,34 @@ function runNativeHookCommand(args) {
79954
80689
  try {
79955
80690
  const payload = readBoundedHookPayload();
79956
80691
  const enqueued = enqueueNativeHookFromConfig({ args, payload });
79957
- const hookEvent = argumentValue(args, "--event")?.toLowerCase();
79958
- if (enqueued && (hookEvent === "userpromptsubmit" || hookEvent === "user_prompt")) {
80692
+ const hookEvent = argumentValue(args, "--event");
80693
+ const normalizedEvent = normalizeHookEvent(hookEvent ?? "notification");
80694
+ if (enqueued && (normalizedEvent === "user_prompt" || normalizedEvent === "session_start")) {
79959
80695
  const providerKind = argumentValue(args, "--provider");
79960
- const externalSessionId = stringField4(payload, "session_id", "sessionId");
80696
+ const externalSessionId = stringField4(
80697
+ payload,
80698
+ "session_id",
80699
+ "sessionId",
80700
+ "conversation_id",
80701
+ "conversationId",
80702
+ "thread_id",
80703
+ "threadId"
80704
+ );
79961
80705
  const capability = providerKind ? NATIVE_SESSION_PROVIDER_CAPABILITIES.find(
79962
80706
  (candidate) => candidate.providerKind === providerKind
79963
80707
  ) : void 0;
79964
- if (capability && externalSessionId) {
80708
+ const shouldInjectLinkingContext = capability && externalSessionId && (capability.providerKind === "claude_cli" || capability.providerKind === "codex_app_server" || capability.providerKind === "kimi_cli" ? normalizedEvent === "user_prompt" : capability.providerKind === "cursor_agent_cli" && normalizedEvent === "session_start");
80709
+ if (shouldInjectLinkingContext && capability && externalSessionId) {
80710
+ const additionalContext = `First call get_native_session_link_status with provider=${capability.provider} and externalSessionId=${externalSessionId}. If status is linked, continue without asking or linking again. If status is syncing, wait briefly and retry the status check. Only when status is pending, ask the user one question: work on an Alan task or continue as a direct session. Resolve a named task with find_records, then call link_native_session. Do not guess a task and do not change task status.`;
79965
80711
  process.stdout.write(
79966
- `${JSON.stringify({
79967
- hookSpecificOutput: {
79968
- hookEventName: "UserPromptSubmit",
79969
- additionalContext: `First call get_native_session_link_status with provider=${capability.provider} and externalSessionId=${externalSessionId}. If status is linked, continue without asking or linking again. If status is syncing, wait briefly and retry the status check. Only when status is pending, ask the user one question: work on an Alan task or continue as a direct session. Resolve a named task with find_records, then call link_native_session. Do not guess a task and do not change task status.`
80712
+ `${JSON.stringify(
80713
+ capability.providerKind === "cursor_agent_cli" ? { additional_context: additionalContext } : {
80714
+ hookSpecificOutput: {
80715
+ hookEventName: "UserPromptSubmit",
80716
+ additionalContext
80717
+ }
79970
80718
  }
79971
- })}
80719
+ )}
79972
80720
  `
79973
80721
  );
79974
80722
  }
@@ -79986,10 +80734,12 @@ function collectNativeIntegrationStatus(args = []) {
79986
80734
  bindConfigPath(args);
79987
80735
  const config2 = readConfig();
79988
80736
  const env = getDaemonCliEnvironment();
80737
+ const homeDir = (0, import_node_os15.homedir)();
79989
80738
  return NATIVE_SESSION_PROVIDER_CAPABILITIES.map((capability) => ({
79990
80739
  provider: capability.providerKind,
79991
80740
  command: capability.command,
79992
80741
  installed: resolveCliExecutable(capability.command, env) !== null,
80742
+ hooksConfigured: inspectNativeHooksConfigured(capability.providerKind, homeDir),
79993
80743
  hookCoverage: capability.capabilities.lifecycleHooks ? "lifecycle" : capability.capabilities.state === "degraded" ? "notification" : "none",
79994
80744
  transcriptStreaming: capability.capabilities.transcriptDelta,
79995
80745
  inboxReady: Boolean(config2.eventSpoolKey)
@@ -80013,7 +80763,7 @@ function decodeResumeFallbackContext(encoded) {
80013
80763
  }
80014
80764
 
80015
80765
  // src/sandbox.ts
80016
- var import_node_os14 = require("os");
80766
+ var import_node_os16 = require("os");
80017
80767
 
80018
80768
  // src/execution-activity-tracker.ts
80019
80769
  var ExecutionActivityTracker = class {
@@ -81310,7 +82060,7 @@ async function runSandbox(config2) {
81310
82060
  }
81311
82061
  const presenter = new WebPresenter(wsClient, config2.sessionId, config2.projectPath);
81312
82062
  presenter.setSuppressSessionLifecycle(true);
81313
- const runtimeSkillManager = await RuntimeSkillManager.open({ homeDirectory: (0, import_node_os14.homedir)() });
82063
+ const runtimeSkillManager = await RuntimeSkillManager.open({ homeDirectory: (0, import_node_os16.homedir)() });
81314
82064
  let lastProviderSessionId = config2.providerSessionId;
81315
82065
  let resumeFallbackContext = config2.resumeFallbackContext;
81316
82066
  let activeBackendKind = config2.backendKind || "claude_cli";
@@ -81610,8 +82360,8 @@ async function runSandbox(config2) {
81610
82360
  // src/service-manager.ts
81611
82361
  var import_node_child_process9 = require("child_process");
81612
82362
  var import_node_fs25 = require("fs");
81613
- var import_node_os15 = require("os");
81614
- var import_node_path26 = require("path");
82363
+ var import_node_os17 = require("os");
82364
+ var import_node_path27 = require("path");
81615
82365
  var SERVICE_LABEL = "ai.tryalan.agent";
81616
82366
  var SYSTEMD_UNIT = "alan-agent.service";
81617
82367
  var WINDOWS_TASK = "Alan Agent";
@@ -81631,8 +82381,8 @@ function buildDaemonServicePlan(input2) {
81631
82381
  if (userId === void 0) throw new Error("Cannot determine the current macOS user ID");
81632
82382
  const domain2 = `gui/${userId}`;
81633
82383
  const serviceTarget = `${domain2}/${SERVICE_LABEL}`;
81634
- const manifestPath = (0, import_node_path26.join)(input2.homeDir, "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
81635
- const logDir = (0, import_node_path26.join)(input2.homeDir, ".alan", "agent", "logs");
82384
+ const manifestPath = (0, import_node_path27.join)(input2.homeDir, "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
82385
+ const logDir = (0, import_node_path27.join)(input2.homeDir, ".alan", "agent", "logs");
81636
82386
  const programArguments = daemonArgs.map((arg) => ` <string>${xml(arg)}</string>`).join("\n");
81637
82387
  const environmentEntries = Object.entries(input2.environment ?? {}).map(([key, value2]) => ` <key>${xml(key)}</key>
81638
82388
  <string>${xml(value2)}</string>`).join("\n");
@@ -81661,9 +82411,9 @@ ${environmentBlock} <key>RunAtLoad</key>
81661
82411
  <key>ThrottleInterval</key>
81662
82412
  <integer>5</integer>
81663
82413
  <key>StandardOutPath</key>
81664
- <string>${xml((0, import_node_path26.join)(logDir, "daemon.log"))}</string>
82414
+ <string>${xml((0, import_node_path27.join)(logDir, "daemon.log"))}</string>
81665
82415
  <key>StandardErrorPath</key>
81666
- <string>${xml((0, import_node_path26.join)(logDir, "daemon-error.log"))}</string>
82416
+ <string>${xml((0, import_node_path27.join)(logDir, "daemon-error.log"))}</string>
81667
82417
  </dict>
81668
82418
  </plist>
81669
82419
  `;
@@ -81702,7 +82452,7 @@ ${environmentBlock} <key>RunAtLoad</key>
81702
82452
  };
81703
82453
  }
81704
82454
  if (input2.platform === "linux") {
81705
- const manifestPath = (0, import_node_path26.join)(input2.homeDir, ".config", "systemd", "user", SYSTEMD_UNIT);
82455
+ const manifestPath = (0, import_node_path27.join)(input2.homeDir, ".config", "systemd", "user", SYSTEMD_UNIT);
81706
82456
  const environmentLines = Object.entries(input2.environment ?? {}).map(([key, value2]) => `Environment=${systemdArg(`${key}=${value2}`)}`).join("\n");
81707
82457
  const manifest = `[Unit]
81708
82458
  Description=Alan local agent daemon
@@ -81803,7 +82553,7 @@ WantedBy=default.target
81803
82553
  };
81804
82554
  }
81805
82555
  function currentServicePlan(args, runtime) {
81806
- const currentPlatform = (0, import_node_os15.platform)();
82556
+ const currentPlatform = (0, import_node_os17.platform)();
81807
82557
  if (currentPlatform !== "darwin" && currentPlatform !== "linux" && currentPlatform !== "win32") {
81808
82558
  throw new Error(`Daemon service installation is not supported on ${currentPlatform}`);
81809
82559
  }
@@ -81812,15 +82562,15 @@ function currentServicePlan(args, runtime) {
81812
82562
  if (!cliEntry) throw new Error("Cannot determine the alan-agent executable path");
81813
82563
  return buildDaemonServicePlan({
81814
82564
  platform: currentPlatform,
81815
- homeDir: (0, import_node_os15.homedir)(),
82565
+ homeDir: (0, import_node_os17.homedir)(),
81816
82566
  nodeExecutable: runtime?.executable ?? process.execPath,
81817
- cliEntry: (0, import_node_path26.resolve)(cliEntry),
82567
+ cliEntry: (0, import_node_path27.resolve)(cliEntry),
81818
82568
  profile,
81819
82569
  environment: runtime?.environment
81820
82570
  });
81821
82571
  }
81822
82572
  function writeManifest(path2, contents) {
81823
- (0, import_node_fs25.mkdirSync)((0, import_node_path26.dirname)(path2), { recursive: true, mode: 448 });
82573
+ (0, import_node_fs25.mkdirSync)((0, import_node_path27.dirname)(path2), { recursive: true, mode: 448 });
81824
82574
  const pendingPath = `${path2}.pending-${process.pid}`;
81825
82575
  try {
81826
82576
  (0, import_node_fs25.writeFileSync)(pendingPath, contents, { mode: 384 });
@@ -81849,8 +82599,8 @@ function installDaemonService(args = [], runtime) {
81849
82599
  }
81850
82600
  const plan = currentServicePlan(args, runtime);
81851
82601
  if (plan.manifestPath && plan.manifest) {
81852
- if ((0, import_node_os15.platform)() === "darwin") {
81853
- (0, import_node_fs25.mkdirSync)((0, import_node_path26.join)((0, import_node_os15.homedir)(), ".alan", "agent", "logs"), { recursive: true, mode: 448 });
82602
+ if ((0, import_node_os17.platform)() === "darwin") {
82603
+ (0, import_node_fs25.mkdirSync)((0, import_node_path27.join)((0, import_node_os17.homedir)(), ".alan", "agent", "logs"), { recursive: true, mode: 448 });
81854
82604
  }
81855
82605
  writeManifest(plan.manifestPath, plan.manifest);
81856
82606
  }
@@ -81872,16 +82622,16 @@ function printDaemonServiceStatus(args = []) {
81872
82622
 
81873
82623
  // src/skills/skill-cli.ts
81874
82624
  var import_promises6 = require("fs/promises");
81875
- var import_node_os16 = require("os");
81876
- var import_node_path27 = require("path");
82625
+ var import_node_os18 = require("os");
82626
+ var import_node_path28 = require("path");
81877
82627
  async function runSkillsCommand(args) {
81878
82628
  const [subcommand, ...options] = args;
81879
- const homeDirectory = option(options, "--home") ?? (0, import_node_os16.homedir)();
81880
- const manager = await RuntimeSkillManager.open({ homeDirectory });
82629
+ const homeDirectory2 = option(options, "--home") ?? (0, import_node_os18.homedir)();
82630
+ const manager = await RuntimeSkillManager.open({ homeDirectory: homeDirectory2 });
81881
82631
  if (subcommand === "scan") {
81882
82632
  const inputPath = option(options, "--input");
81883
82633
  const declaredInput = inputPath ? scanSkillsInputSchema.parse(await readProtectedJson(inputPath)) : null;
81884
- const input2 = declaredInput ? options.includes("--include-configured") ? await resolveSkillScanInput(homeDirectory, declaredInput) : declaredInput : await defaultScanInput(homeDirectory);
82634
+ const input2 = declaredInput ? options.includes("--include-configured") ? await resolveSkillScanInput(homeDirectory2, declaredInput) : declaredInput : await defaultScanInput(homeDirectory2);
81885
82635
  const outcome = await manager.scan(input2);
81886
82636
  process.stdout.write(`${JSON.stringify(outcome)}
81887
82637
  `);
@@ -81908,8 +82658,8 @@ async function runSkillsCommand(args) {
81908
82658
  "Usage: alan-agent skills scan [--input <0600-json>] [--include-configured] [--home <path>] | skills reconcile --manifest <0600-json> [--home <path>] | skills publish --input <0600-json> [--home <path>]"
81909
82659
  );
81910
82660
  }
81911
- async function defaultScanInput(homeDirectory) {
81912
- return resolveSkillScanInput(homeDirectory, {
82661
+ async function defaultScanInput(homeDirectory2) {
82662
+ return resolveSkillScanInput(homeDirectory2, {
81913
82663
  mode: "audit",
81914
82664
  reason: "refresh",
81915
82665
  enabledProviderKinds: [],
@@ -81917,7 +82667,7 @@ async function defaultScanInput(homeDirectory) {
81917
82667
  });
81918
82668
  }
81919
82669
  async function readProtectedJson(path2) {
81920
- const absolutePath = (0, import_node_path27.resolve)(path2);
82670
+ const absolutePath = (0, import_node_path28.resolve)(path2);
81921
82671
  const stat2 = await (0, import_promises6.lstat)(absolutePath);
81922
82672
  if (!stat2.isFile()) throw new Error(`Skill input is not a regular file: ${absolutePath}`);
81923
82673
  if (process.platform !== "win32" && (stat2.mode & 63) !== 0) {