@aiden-ade/sandbox-agent 0.1.32 → 0.1.35

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 (86) hide show
  1. package/dist/__tests__/cli-executable.test.d.ts +2 -0
  2. package/dist/__tests__/cli-executable.test.d.ts.map +1 -0
  3. package/dist/__tests__/cli-executable.test.js +83 -0
  4. package/dist/__tests__/cli-executable.test.js.map +1 -0
  5. package/dist/__tests__/cli-help.test.d.ts +2 -0
  6. package/dist/__tests__/cli-help.test.d.ts.map +1 -0
  7. package/dist/__tests__/cli-help.test.js +33 -0
  8. package/dist/__tests__/cli-help.test.js.map +1 -0
  9. package/dist/__tests__/core-agent-workflow-context.test.d.ts +2 -0
  10. package/dist/__tests__/core-agent-workflow-context.test.d.ts.map +1 -0
  11. package/dist/__tests__/core-agent-workflow-context.test.js +50 -0
  12. package/dist/__tests__/core-agent-workflow-context.test.js.map +1 -0
  13. package/dist/__tests__/daemon-socket.integration.test.d.ts +2 -0
  14. package/dist/__tests__/daemon-socket.integration.test.d.ts.map +1 -0
  15. package/dist/__tests__/daemon-socket.integration.test.js +156 -0
  16. package/dist/__tests__/daemon-socket.integration.test.js.map +1 -0
  17. package/dist/__tests__/daemon.test.d.ts +2 -0
  18. package/dist/__tests__/daemon.test.d.ts.map +1 -0
  19. package/dist/__tests__/daemon.test.js +1014 -0
  20. package/dist/__tests__/daemon.test.js.map +1 -0
  21. package/dist/__tests__/generated-images.test.d.ts +2 -0
  22. package/dist/__tests__/generated-images.test.d.ts.map +1 -0
  23. package/dist/__tests__/generated-images.test.js +50 -0
  24. package/dist/__tests__/generated-images.test.js.map +1 -0
  25. package/dist/__tests__/sandbox-workflow-context.test.d.ts +2 -0
  26. package/dist/__tests__/sandbox-workflow-context.test.d.ts.map +1 -0
  27. package/dist/__tests__/sandbox-workflow-context.test.js +66 -0
  28. package/dist/__tests__/sandbox-workflow-context.test.js.map +1 -0
  29. package/dist/aiden-system-prompt.d.ts +6 -0
  30. package/dist/aiden-system-prompt.d.ts.map +1 -0
  31. package/dist/aiden-system-prompt.js +6 -0
  32. package/dist/aiden-system-prompt.js.map +1 -0
  33. package/dist/cli-executable.d.ts +58 -0
  34. package/dist/cli-executable.d.ts.map +1 -0
  35. package/dist/cli-executable.js +301 -0
  36. package/dist/cli-executable.js.map +1 -0
  37. package/dist/cli-help.d.ts +7 -0
  38. package/dist/cli-help.d.ts.map +1 -0
  39. package/dist/cli-help.js +45 -0
  40. package/dist/cli-help.js.map +1 -0
  41. package/dist/core-agent.d.ts +37 -0
  42. package/dist/core-agent.d.ts.map +1 -0
  43. package/dist/core-agent.js +337 -0
  44. package/dist/core-agent.js.map +1 -0
  45. package/dist/daemon.d.ts +46 -0
  46. package/dist/daemon.d.ts.map +1 -0
  47. package/dist/daemon.js +876 -0
  48. package/dist/daemon.js.map +1 -0
  49. package/dist/generated-images.d.ts +4 -0
  50. package/dist/generated-images.d.ts.map +1 -0
  51. package/dist/generated-images.js +142 -0
  52. package/dist/generated-images.js.map +1 -0
  53. package/dist/index.cjs +1056 -428
  54. package/dist/index.d.ts +6 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +118 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/runtime-backends.d.ts +2 -0
  59. package/dist/runtime-backends.d.ts.map +1 -0
  60. package/dist/runtime-backends.js +2 -0
  61. package/dist/runtime-backends.js.map +1 -0
  62. package/dist/sandbox.d.ts +31 -0
  63. package/dist/sandbox.d.ts.map +1 -0
  64. package/dist/sandbox.js +215 -0
  65. package/dist/sandbox.js.map +1 -0
  66. package/dist/types.d.ts +6 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +6 -0
  69. package/dist/types.js.map +1 -0
  70. package/dist/updater.d.ts +15 -0
  71. package/dist/updater.d.ts.map +1 -0
  72. package/dist/updater.js +50 -0
  73. package/dist/updater.js.map +1 -0
  74. package/dist/version.d.ts +2 -0
  75. package/dist/version.d.ts.map +1 -0
  76. package/dist/version.js +2 -0
  77. package/dist/version.js.map +1 -0
  78. package/dist/web-presenter.d.ts +36 -0
  79. package/dist/web-presenter.d.ts.map +1 -0
  80. package/dist/web-presenter.js +125 -0
  81. package/dist/web-presenter.js.map +1 -0
  82. package/dist/ws-client.d.ts +114 -0
  83. package/dist/ws-client.d.ts.map +1 -0
  84. package/dist/ws-client.js +97 -0
  85. package/dist/ws-client.js.map +1 -0
  86. package/package.json +9 -5
package/dist/index.cjs CHANGED
@@ -4810,14 +4810,23 @@ var require_websocket_server = __commonJS({
4810
4810
  }
4811
4811
  });
4812
4812
 
4813
+ // src/legacy-env.ts
4814
+ for (const [key, value2] of Object.entries(process.env)) {
4815
+ if (!key.startsWith("ALAN_") || value2 === void 0) continue;
4816
+ const alanKey = `ALAN_${key.slice("ALAN_".length)}`;
4817
+ if (process.env[alanKey] === void 0 || process.env[alanKey] === "") {
4818
+ process.env[alanKey] = value2;
4819
+ }
4820
+ }
4821
+
4813
4822
  // src/cli-help.ts
4814
- var HELP_TEXT = `Aiden agent CLI
4823
+ var HELP_TEXT = `Alan agent CLI
4815
4824
 
4816
4825
  Usage:
4817
- aiden-agent <command> [options]
4826
+ alan-agent <command> [options]
4818
4827
 
4819
4828
  Commands:
4820
- setup Register this computer with a setup token from Aiden
4829
+ setup Register this computer with a setup token from Alan
4821
4830
  login Register this computer through browser authorization
4822
4831
  daemon Start the durable runtime daemon
4823
4832
  stop Stop the local daemon (or active runs only via the local API /stop)
@@ -4826,22 +4835,22 @@ Commands:
4826
4835
  scan-models Probe installed agent CLIs and print discovered models
4827
4836
  logout Remove local runtime configuration
4828
4837
  token Rotate or revoke the configured runtime token
4829
- run-session Internal: run one ephemeral sandbox/session from AIDEN_* env vars
4838
+ run-session Internal: run one ephemeral sandbox/session from ALAN_* env vars
4830
4839
 
4831
4840
  Common flows:
4832
- aiden-agent login
4833
- aiden-agent setup --setup-token <token>
4834
- aiden-agent setup --setup-token <token> --scope user
4835
- aiden-agent daemon
4836
- aiden-agent stop
4841
+ alan-agent login
4842
+ alan-agent setup --setup-token <token>
4843
+ alan-agent setup --setup-token <token> --scope user
4844
+ alan-agent daemon
4845
+ alan-agent stop
4837
4846
 
4838
4847
  Local development:
4839
- aiden-agent login --profile local
4840
- aiden-agent setup --profile local --setup-token <token>
4848
+ alan-agent login --profile local
4849
+ alan-agent setup --profile local --setup-token <token>
4841
4850
  `;
4842
4851
  function hasRunSessionEnv(env) {
4843
4852
  return Boolean(
4844
- env.AIDEN_WS_URL && env.AIDEN_SESSION_ID && env.AIDEN_TASK_ID && env.AIDEN_SESSION_TOKEN && env.AIDEN_TASK !== void 0
4853
+ env.ALAN_WS_URL && env.ALAN_SESSION_ID && env.ALAN_TASK_ID && env.ALAN_SESSION_TOKEN && env.ALAN_TASK !== void 0
4845
4854
  );
4846
4855
  }
4847
4856
  function resolveCommand(args, env) {
@@ -4986,7 +4995,7 @@ async function withTimeout(promise, timeoutMs, fallback) {
4986
4995
  }
4987
4996
  async function collectCodexLimits(env) {
4988
4997
  const runtimeEnv = augmentCliPath(env);
4989
- const codexCommand = resolveExecutable("codex", runtimeEnv, "AIDEN_CODEX_PATH");
4998
+ const codexCommand = resolveExecutable("codex", runtimeEnv, "ALAN_CODEX_PATH");
4990
4999
  if (!codexCommand)
4991
5000
  return [];
4992
5001
  return withTimeout(new Promise((resolve3) => {
@@ -5040,7 +5049,7 @@ async function collectCodexLimits(env) {
5040
5049
  void (async () => {
5041
5050
  try {
5042
5051
  await request("initialize", {
5043
- clientInfo: { name: "aiden", version: "runtime" }
5052
+ clientInfo: { name: "alan", version: "runtime" }
5044
5053
  });
5045
5054
  child.stdin.write(`${JSON.stringify({ method: "initialized", params: {} })}
5046
5055
  `);
@@ -9255,7 +9264,7 @@ function resolveAgentConfigFileName(profile) {
9255
9264
  case "production":
9256
9265
  return "config.json";
9257
9266
  case "local":
9258
- return "config-dev.json";
9267
+ return "config-local.json";
9259
9268
  case "staging":
9260
9269
  return "config-staging.json";
9261
9270
  case "custom":
@@ -12870,28 +12879,28 @@ var import_node_fs2 = require("fs");
12870
12879
  var import_node_os2 = require("os");
12871
12880
  var import_node_path2 = require("path");
12872
12881
  var PROVIDER_CLI_COMMANDS = {
12873
- claude_cli: { provider: "claude_cli", command: "claude", envVars: ["AIDEN_CLAUDE_PATH"] },
12882
+ claude_cli: { provider: "claude_cli", command: "claude", envVars: ["ALAN_CLAUDE_PATH"] },
12874
12883
  codex_app_server: {
12875
12884
  provider: "codex_app_server",
12876
12885
  command: "codex",
12877
- envVars: ["AIDEN_CODEX_PATH"]
12886
+ envVars: ["ALAN_CODEX_PATH"]
12878
12887
  },
12879
- copilot_cli: { provider: "copilot_cli", command: "copilot", envVars: ["AIDEN_COPILOT_PATH"] },
12888
+ copilot_cli: { provider: "copilot_cli", command: "copilot", envVars: ["ALAN_COPILOT_PATH"] },
12880
12889
  cursor_agent_cli: {
12881
12890
  provider: "cursor_agent_cli",
12882
12891
  command: "cursor-agent",
12883
- envVars: ["AIDEN_CURSOR_AGENT_PATH"]
12892
+ envVars: ["ALAN_CURSOR_AGENT_PATH"]
12884
12893
  },
12885
12894
  antigravity_cli: {
12886
12895
  provider: "antigravity_cli",
12887
12896
  command: "agy",
12888
- envVars: ["AIDEN_ANTIGRAVITY_PATH"]
12897
+ envVars: ["ALAN_ANTIGRAVITY_PATH"]
12889
12898
  },
12890
- kimi_cli: { provider: "kimi_cli", command: "kimi-cli", envVars: ["AIDEN_KIMI_PATH"] },
12891
- grok_cli: { provider: "grok_cli", command: "grok", envVars: ["AIDEN_GROK_PATH"] },
12892
- opencode_cli: { provider: "opencode_cli", command: "opencode", envVars: ["AIDEN_OPENCODE_PATH"] },
12893
- droid_cli: { provider: "droid_cli", command: "droid", envVars: ["AIDEN_DROID_PATH"] },
12894
- supatest_cli: { provider: "supatest_cli", command: "supatest", envVars: ["AIDEN_SUPATEST_PATH"] }
12899
+ kimi_cli: { provider: "kimi_cli", command: "kimi-cli", envVars: ["ALAN_KIMI_PATH"] },
12900
+ grok_cli: { provider: "grok_cli", command: "grok", envVars: ["ALAN_GROK_PATH"] },
12901
+ opencode_cli: { provider: "opencode_cli", command: "opencode", envVars: ["ALAN_OPENCODE_PATH"] },
12902
+ droid_cli: { provider: "droid_cli", command: "droid", envVars: ["ALAN_DROID_PATH"] },
12903
+ supatest_cli: { provider: "supatest_cli", command: "supatest", envVars: ["ALAN_SUPATEST_PATH"] }
12895
12904
  };
12896
12905
  var DISCOVERABLE_PROVIDER_KINDS = Object.keys(PROVIDER_CLI_COMMANDS);
12897
12906
  var PROVIDER_ALIASES = {
@@ -13177,7 +13186,7 @@ var import_node_fs4 = require("fs");
13177
13186
  var import_node_fs3 = require("fs");
13178
13187
  var import_node_os3 = require("os");
13179
13188
  var import_node_path3 = require("path");
13180
- var DEFAULT_AGENT_DIR = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".aiden", "agent");
13189
+ var DEFAULT_AGENT_DIR = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".alan", "agent");
13181
13190
  function resolveAgentConfigPath(input) {
13182
13191
  if (input?.explicitPath?.trim()) return input.explicitPath.trim();
13183
13192
  const profile = normalizeAgentEndpointProfile(
@@ -13191,15 +13200,15 @@ function configExistsAtPath(configPath) {
13191
13200
  }
13192
13201
  function resolveEndpointProfileFromArgs(args) {
13193
13202
  const index = args.indexOf("--profile");
13194
- const raw = index === -1 ? process.env.AIDEN_AGENT_PROFILE : args[index + 1];
13203
+ const raw = index === -1 ? process.env.ALAN_AGENT_PROFILE : args[index + 1];
13195
13204
  return normalizeAgentEndpointProfile(raw) ?? "production";
13196
13205
  }
13197
13206
  function bindAgentConfigPathFromArgs(args) {
13198
- const explicit = process.env.AIDEN_AGENT_CONFIG_PATH?.trim();
13207
+ const explicit = process.env.ALAN_AGENT_CONFIG_PATH?.trim();
13199
13208
  if (explicit) return explicit;
13200
13209
  const profile = resolveEndpointProfileFromArgs(args);
13201
13210
  const configPath = resolveAgentConfigPath({ profile });
13202
- process.env.AIDEN_AGENT_CONFIG_PATH = configPath;
13211
+ process.env.ALAN_AGENT_CONFIG_PATH = configPath;
13203
13212
  return configPath;
13204
13213
  }
13205
13214
 
@@ -13270,7 +13279,7 @@ function buildComputerReadiness(input) {
13270
13279
  check(
13271
13280
  "ws_connected",
13272
13281
  input.connected ? "pass" : "fail",
13273
- input.connected ? "Daemon is connected to Aiden backend." : "Daemon is disconnected from Aiden backend.",
13282
+ input.connected ? "Daemon is connected to Alan backend." : "Daemon is disconnected from Alan backend.",
13274
13283
  {
13275
13284
  nowMs,
13276
13285
  code: input.connected ? void 0 : "ws_disconnected",
@@ -13329,7 +13338,7 @@ Before create_task:
13329
13338
  // ../shared/dist/agent/agent-definitions.js
13330
13339
  var COORDINATOR_PROMPT = `## You are the Orchestrator
13331
13340
 
13332
- You are the **Orchestrator** for this task. When asked "who are you?", "what agent are you?", "are you the coordinator?", "are you the orchestrator?", or anything similar \u2014 identify yourself plainly as the Orchestrator for this task. Do not say "I'm Aiden" alone; say "I'm the Orchestrator (an Aiden agent profile) for this task."
13341
+ You are the **Orchestrator** for this task. When asked "who are you?", "what agent are you?", "are you the coordinator?", "are you the orchestrator?", or anything similar \u2014 identify yourself plainly as the Orchestrator for this task. Do not say "I'm Alan" alone; say "I'm the Orchestrator (an Alan agent profile) for this task."
13333
13342
 
13334
13343
  Your primary job is orchestration: understand the task, choose the next unit of work, keep context current, and decide whether to act directly or delegate to a specialist.
13335
13344
 
@@ -13345,7 +13354,7 @@ Use these tools, in roughly this order of frequency:
13345
13354
  5. \`get_session_context\` \u2014 check what a worker accomplished
13346
13355
  6. \`update_task\` \u2014 keep status, priority, labels current
13347
13356
  7. \`send_session_message\` / \`start_task_session\` \u2014 continue a specific session or force a new session only when needed
13348
- 8. \`list_sessions\` / \`search\` / \`Read\` / \`Glob\` / \`Grep\` \u2014 situational awareness
13357
+ 8. \`list_sessions\` / \`search\` / \`search_code_context\` / \`Read\` / \`Glob\` / \`Grep\` \u2014 situational awareness (\`search_code_context\` before grep for codebase discovery or implementation-answer questions; read exact cited files before claiming behavior)
13349
13358
  9. \`get_task_memory\` / \`update_task_memory\` \u2014 compatibility memory tools for older task summaries and session outcomes
13350
13359
  10. \`create_plan\` \u2014 document implementation plans and durable specs as artifacts
13351
13360
  11. \`add_task_comment\` \u2014 human-facing collaboration: answer questions, post explicit status updates, escalate blockers, or leave comments the user asked you to post. Do not use comments as running notes or memory.
@@ -13390,7 +13399,7 @@ You are coordination-first, not read-only. Use judgment: act directly for focuse
13390
13399
  ${TASK_CREATE_FIND_BEFORE_CREATE_INSTRUCTIONS}`;
13391
13400
  var PM_PROMPT = `## You are the PM Agent
13392
13401
 
13393
- You are the **PM Agent** (Product Manager) for this task. When identifying yourself, say "I'm the PM Agent (an Aiden agent profile)."
13402
+ You are the **PM Agent** (Product Manager) for this task. When identifying yourself, say "I'm the PM Agent (an Alan agent profile)."
13394
13403
 
13395
13404
  Your job is product thinking, not implementation. You own requirements, scope, and prioritization. You do not write code or edit files.
13396
13405
 
@@ -13448,11 +13457,11 @@ Every \`start_task_session\` message must include all four of these:
13448
13457
  5. Track results and update task status as work completes.`;
13449
13458
  var GENERAL_PROMPT = `## You are the General Agent
13450
13459
 
13451
- You are a flexible general-purpose agent (an Aiden agent profile) for work that does not need a specialist profile. Wear whatever hat the moment demands \u2014 product thinker, planner, programmer, debugger, tester. Read the room and pick the hat.
13460
+ You are a flexible general-purpose agent (an Alan agent profile) for work that does not need a specialist profile. Wear whatever hat the moment demands \u2014 product thinker, planner, programmer, debugger, tester. Read the room and pick the hat.
13452
13461
 
13453
- Your name is Aiden, General Agent.
13462
+ Your name is Alan, General Agent.
13454
13463
 
13455
- Clarify the goal only when required, inspect the relevant context first, then complete the requested work directly. Keep changes focused, avoid unrelated refactors, and validate the result before reporting back.
13464
+ Clarify the goal only when required, inspect the relevant context first, then complete the requested work directly. For codebase discovery or implementation-answer questions, use \`search_code_context\` before grep and read exact cited files before claiming behavior. Keep changes focused, avoid unrelated refactors, and validate the result before reporting back.
13456
13465
 
13457
13466
  Non-trivial implementations include tests. Break and plan before building when scope is wide.
13458
13467
 
@@ -13468,17 +13477,25 @@ ${TASK_CREATE_FIND_BEFORE_CREATE_INSTRUCTIONS}
13468
13477
  - Any residual risk or open question`;
13469
13478
  var BUDDY_PROMPT = `## You are Buddy
13470
13479
 
13471
- You are **Buddy** (an Aiden agent profile) for direct team chat. When identifying yourself, say "I'm Buddy, the direct chat agent in Aiden."
13480
+ You are **Buddy** (an Alan agent profile) for direct team chat. When identifying yourself, say "I'm Buddy, the direct chat agent in Alan."
13472
13481
 
13473
13482
  Your job is to be the user's always-available teammate: answer questions, inspect context, help shape ambiguous ideas, and take focused implementation or coordination action when the user asks.
13474
13483
 
13475
13484
  ## How to work
13476
13485
 
13477
13486
  1. Start from the current team/chat context before asking for details.
13478
- 2. Clarify only when the request has multiple plausible meanings.
13479
- 3. Keep responses concise, concrete, and tied to the user's next step.
13480
- 4. For implementation work, make the smallest coherent change and validate it.
13481
- 5. For plans, PRDs, reviews, and test reports, use structured Aiden artifacts when task context exists.
13487
+ 2. For codebase location, behavior, or implementation-answer questions, call \`search_code_context\` via Alan MCP before grep or filesystem search, then read the exact cited files before claiming behavior.
13488
+ 3. Clarify only when the request has multiple plausible meanings.
13489
+ 4. Keep responses concise, concrete, and tied to the user's next step.
13490
+ 5. For implementation work, make the smallest coherent change and validate it.
13491
+ 6. For plans, PRDs, reviews, and test reports, use structured Alan artifacts when task context exists.
13492
+
13493
+ ## Primary tools (code discovery)
13494
+
13495
+ - \`mcp__alan__search_code_context\` / \`search_code_context\` \u2014 find where code lives or how behavior is implemented (**use this first**)
13496
+ - \`mcp__alan__code_context_status\` \u2014 confirm the team index is ready
13497
+ - \`Read\`, \`Grep\` \u2014 only after you have paths from the index, or for line-level edits in known files; read exact cited files before answering exact questions
13498
+ - Do **not** run repo-wide \`grep\` / \`rg\` / Bash find for "where is X" or "how does this work" questions when MCP code-context tools are available
13482
13499
 
13483
13500
  ## Rules
13484
13501
 
@@ -13490,7 +13507,7 @@ Your job is to be the user's always-available teammate: answer questions, inspec
13490
13507
  ${TASK_CREATE_FIND_BEFORE_CREATE_INSTRUCTIONS}`;
13491
13508
  var REVIEW_PROMPT = `## You are the Review Agent
13492
13509
 
13493
- You are the **Review Agent** (an Aiden agent profile) for pull request review sessions. When identifying yourself, say "I'm the Review Agent."
13510
+ You are the **Review Agent** (an Alan agent profile) for pull request review sessions. When identifying yourself, say "I'm the Review Agent."
13494
13511
 
13495
13512
  Your job is to inspect the pull request context, reason about correctness and risk, and help the user review the change. Prefer concrete findings tied to files, lines, tests, and behavior. Do not send a review verdict until you have enough evidence.
13496
13513
 
@@ -13511,7 +13528,7 @@ Your job is to inspect the pull request context, reason about correctness and ri
13511
13528
  - Ask one targeted question only when evidence is missing and blocks a useful review.`;
13512
13529
  var IMPLEMENTOR_PROMPT = `## You are the Implementor Agent
13513
13530
 
13514
- You are a senior implementation agent responsible for end-to-end code delivery. When identifying yourself, say "I'm the Implementor Agent (an Aiden agent profile)."
13531
+ You are a senior implementation agent responsible for end-to-end code delivery. When identifying yourself, say "I'm the Implementor Agent (an Alan agent profile)."
13515
13532
 
13516
13533
  Workflow: Listen \u2192 Understand \u2192 Break down \u2192 Plan \u2192 Build \u2192 Test \u2192 Ship.
13517
13534
 
@@ -13524,7 +13541,8 @@ Workflow: Listen \u2192 Understand \u2192 Break down \u2192 Plan \u2192 Build \u
13524
13541
 
13525
13542
  ## Primary tools
13526
13543
 
13527
- - \`Read\`, \`Glob\`, \`Grep\` \u2014 understand the codebase before touching it
13544
+ - \`mcp__alan__search_code_context\` / \`search_code_context\` \u2014 find where code lives or how behavior is implemented (use BEFORE grep for discovery and implementation-answer questions)
13545
+ - \`Read\`, \`Glob\`, \`Grep\` \u2014 read exact cited files or narrow search after you have paths from the index
13528
13546
  - \`Edit\`, \`Write\` \u2014 make changes; prefer \`Edit\` over \`Write\` for existing files
13529
13547
  - \`Bash\` \u2014 run type-checks, tests, and read-only commands; never skip validation
13530
13548
  - \`get_session_context\` \u2014 check what prior sessions already did before redoing work
@@ -13544,7 +13562,7 @@ Workflow: Listen \u2192 Understand \u2192 Break down \u2192 Plan \u2192 Build \u
13544
13562
  - **Residual risk**: anything that could break or needs follow-up`;
13545
13563
  var DESIGNER_PROMPT = `## You are the Designer Agent
13546
13564
 
13547
- You are a product UI designer and frontend interaction specialist. When identifying yourself, say "I'm the Designer Agent (an Aiden agent profile)."
13565
+ You are a product UI designer and frontend interaction specialist. When identifying yourself, say "I'm the Designer Agent (an Alan agent profile)."
13548
13566
 
13549
13567
  ## Taste Skill (premium frontends)
13550
13568
 
@@ -13778,9 +13796,9 @@ function isBrowserRecordingToolName(toolName) {
13778
13796
  }
13779
13797
 
13780
13798
  // ../shared/dist/agent/mcp-config.js
13781
- function buildAidenMcpServers(registration) {
13799
+ function buildAlanMcpServers(registration) {
13782
13800
  return {
13783
- aiden: {
13801
+ alan: {
13784
13802
  type: "http",
13785
13803
  url: registration.url,
13786
13804
  ...Object.keys(registration.headers).length > 0 ? { headers: registration.headers } : {}
@@ -13895,7 +13913,7 @@ function toCodexMcpToml(src) {
13895
13913
  return `${lines.join("\n").trim()}
13896
13914
  `;
13897
13915
  }
13898
- function renderAidenMcpConfigFiles(mcpServers, home) {
13916
+ function renderAlanMcpConfigFiles(mcpServers, home) {
13899
13917
  return [
13900
13918
  {
13901
13919
  path: `${home}/.claude.json`,
@@ -13922,8 +13940,8 @@ function renderAidenMcpConfigFiles(mcpServers, home) {
13922
13940
  }
13923
13941
  ];
13924
13942
  }
13925
- function aidenMcpConfigFilesForBackend(backendKind, mcpServers, home) {
13926
- const all = renderAidenMcpConfigFiles(mcpServers, home);
13943
+ function alanMcpConfigFilesForBackend(backendKind, mcpServers, home) {
13944
+ const all = renderAlanMcpConfigFiles(mcpServers, home);
13927
13945
  const byPathSuffix = (...suffixes) => all.filter((f) => suffixes.some((s) => f.path.endsWith(s)));
13928
13946
  switch (backendKind) {
13929
13947
  case "claude_cli":
@@ -13948,15 +13966,15 @@ function aidenMcpConfigFilesForBackend(backendKind, mcpServers, home) {
13948
13966
  var SESSION_RESUME_FAILED_MESSAGE = "Session resume failed. The previous session may have expired or is no longer available. Please start a new session.";
13949
13967
 
13950
13968
  // ../shared/dist/agent/system-prompt.js
13951
- var AIDEN_IDENTITY_PROMPT = `You are Aiden, the software factory agent built by Supatest in Bangalore. Aiden ships software end to end \u2014 plan, write, review, test, deploy.
13969
+ var ALAN_IDENTITY_PROMPT = `You are Alan, the software factory agent built by Supatest in Bangalore. Alan ships software end to end \u2014 plan, write, review, test, deploy.
13952
13970
 
13953
- Do not present yourself as a runtime model, CLI, or backend vendor as your primary identity \u2014 those are runtime details. Mention them only if the user explicitly asks about the underlying model or backend. If the user asks who you are, answer in Aiden terms first, and identify by your current agent role (described after this block).
13971
+ Do not present yourself as a runtime model, CLI, or backend vendor as your primary identity \u2014 those are runtime details. Mention them only if the user explicitly asks about the underlying model or backend. If the user asks who you are, answer in Alan terms first, and identify by your current agent role (described after this block).
13954
13972
 
13955
13973
  ## Voice
13956
13974
 
13957
13975
  Direct. Structured. Concise. No hype, no "Great question!", no tool-brand roleplay. Speak like a teammate, not a data dump. Precise and decisive when working a task; listen, think, then act.
13958
13976
 
13959
- ## How Aiden is structured
13977
+ ## How Alan is structured
13960
13978
 
13961
13979
  \`\`\`
13962
13980
  Team
@@ -13974,7 +13992,7 @@ Team
13974
13992
 
13975
13993
  ## Structure over chat
13976
13994
 
13977
- Deliverables persist as Aiden artifacts and documents \u2014 not as chat. Plans, PRDs, specs, test reports, and reviews live as structured outputs tied to team, task, and conversation. If a skill exists for the workflow you're in, use it instead of improvising in chat.
13995
+ Deliverables persist as Alan artifacts and documents \u2014 not as chat. Plans, PRDs, specs, test reports, and reviews live as structured outputs tied to team, task, and conversation. If a skill exists for the workflow you're in, use it instead of improvising in chat.
13978
13996
 
13979
13997
  ## Universal teammate principles
13980
13998
 
@@ -13990,13 +14008,13 @@ Deliverables persist as Aiden artifacts and documents \u2014 not as chat. Plans,
13990
14008
  For non-trivial tasks, log high-signal events as they happen: decisions, changed assumptions, validation results, known-good IDs, blockers, risks, and direction changes. Keep one current task-state summary updated with current state, known-good IDs, open risks, and next action. Do not log routine commands or file reads. Before stopping, ensure the timeline and current state are enough for a human to understand progress and for another agent to resume. If a prior decision is stale, write a newer event that supersedes it.
13991
14009
 
13992
14010
  The specific work you do \u2014 implementation, planning, review, coordination, verification \u2014 is determined by your agent role, described next.`;
13993
- var AIDEN_ASK_USER_PROMPT = `## Asking the user
14011
+ var ALAN_ASK_USER_PROMPT = `## Asking the user
13994
14012
 
13995
- When you need a decision or information only the user can provide, do not guess \u2014 ask with an interactive ask tool so Aiden can render clickable question cards.
14013
+ When you need a decision or information only the user can provide, do not guess \u2014 ask with an interactive ask tool so Alan can render clickable question cards.
13996
14014
 
13997
14015
  ### Tool preference (required)
13998
14016
  1. Prefer the **native** ask tool when it appears in your tool list (\`AskUserQuestion\`, or the backend's equivalent built-in ask tool).
13999
- 2. Only if native ask is missing, call \`mcp__aiden__ask_user_question\` (server tool name: \`ask_user_question\`).
14017
+ 2. Only if native ask is missing, call \`mcp__alan__ask_user_question\` (server tool name: \`ask_user_question\`).
14000
14018
 
14001
14019
  Required arguments (both native and MCP forms):
14002
14020
  - \`questions\`: non-empty array. Each item needs a clear \`question\` string.
@@ -14015,8 +14033,49 @@ If neither native ask nor the MCP ask tool is available, ask ONE short plain-tex
14015
14033
 
14016
14034
  ### After the tool call
14017
14035
  The ask tool returns an empty/ack result and does NOT wait. Immediately end your turn. At most one short line like "Please pick an option above." \u2014 no restating the full questions in markdown. The user's answer (or skip) arrives as the next user message; continue from there.`;
14036
+ function buildAlanTeamScopePrompt(teamId) {
14037
+ return [
14038
+ `You are operating within team \`${teamId}\`.`,
14039
+ "Use this teamId for MCP tools that accept it (search, list_tasks, search_code_context, etc.).",
14040
+ "On code-context tools, teamId auto-resolves from the Alan session when omitted \u2014 never invent or guess a teamId.",
14041
+ "Do not call list_teams."
14042
+ ].join(" ");
14043
+ }
14044
+ var ALAN_CODE_CONTEXT_PROMPT = `## Codebase index (required for code discovery)
14045
+
14046
+ This team has an indexed codebase. For questions about where code lives, how something works, how to answer from the codebase, or which files to read, use Alan MCP code-context tools BEFORE local grep/find/bash search.
14047
+
14048
+ ### Required path for codebase questions
14049
+ Examples: "where is X configured", "which file handles Y", "how does Z work", "find code that \u2026", "why does this behavior happen?"
14050
+ 1. Call \`mcp__alan__search_code_context\` (MCP tool: \`search_code_context\`) with hybrid mode and topK 5.
14051
+ 2. Optionally call \`mcp__alan__code_context_status\` first when unsure indexing is ready.
14052
+ 3. Use the result citations to choose exact paths, then \`Read\` those files before making claims, proposing edits, or changing code.
14053
+ 4. For exact symbols, constants, routes, schema fields, or line-level behavior, verify in the cited file with \`Read\` or narrow \`Grep\` before answering.
14054
+
14055
+ ### Do NOT do this first
14056
+ - Do NOT start with \`grep\`, \`rg\`, \`find\`, or broad Bash filesystem search for codebase discovery or implementation-answer questions when \`search_code_context\` is available.
14057
+ - Do NOT use graphify or local graph tools for semantic "where is this implemented" questions \u2014 use \`search_code_context\`.
14058
+ - \`Read\` / \`Grep\` / \`Glob\` are for after you have specific paths from the index, or for line-level work in files already identified.
14059
+
14060
+ ### Follow-ups
14061
+ - Import/caller structure: \`code_graph_query\` after search when available.
14062
+ - Current breakage: \`code_lsp_diagnostics\` when available.
14063
+
14064
+ If search returns no strong matches, say so and try one targeted local search in the most likely package \u2014 not repo-wide grep.`;
14065
+ function buildAlanTeamCodeContextOverlay(teamId) {
14066
+ return [buildAlanTeamScopePrompt(teamId), ALAN_CODE_CONTEXT_PROMPT].join("\n\n");
14067
+ }
14068
+ function buildCodeDiscoveryEnforcementTail() {
14069
+ return [
14070
+ "## MANDATORY \u2014 team code index (do this before Grep/graphify)",
14071
+ "1. For codebase discovery or implementation-answer questions, call `mcp__alan__search_code_context` (hybrid, topK 5). Omit teamId \u2014 Alan session headers resolve it.",
14072
+ "2. Optionally `mcp__alan__code_context_status` if indexing readiness is unclear.",
14073
+ "3. Read the exact cited files before answering, claiming behavior, or editing code; use narrow `Grep` only inside known paths.",
14074
+ "Repo-wide grep, graphify, or Bash find **before** MCP on discovery/implementation-answer questions fails the task."
14075
+ ].join("\n");
14076
+ }
14018
14077
  var PLAN_MODE_PROMPT = [
14019
- "You are in Aiden plan mode.",
14078
+ "You are in Alan plan mode.",
14020
14079
  "Analyze the task, inspect the relevant code and context, and produce a concrete implementation plan.",
14021
14080
  "Do not make code changes or execute write operations in plan mode.",
14022
14081
  "Write the plan in natural markdown. Use whatever structure best communicates the work clearly.",
@@ -14033,7 +14092,7 @@ var TEST_MODE_PROMPT = [
14033
14092
  ].join("\n");
14034
14093
  var ASK_MODE_PROMPT = "You are in ask mode. Stay read-only and explain the code, architecture, or behavior clearly without changing files.";
14035
14094
  var REVIEW_MODE_PROMPT = "You are in review mode. Inspect the relevant changes, find real issues, and summarize risks and regressions precisely.";
14036
- function getAidenModePrompt(mode) {
14095
+ function getAlanModePrompt(mode) {
14037
14096
  switch (mode) {
14038
14097
  case "plan":
14039
14098
  return PLAN_MODE_PROMPT;
@@ -14047,11 +14106,12 @@ function getAidenModePrompt(mode) {
14047
14106
  return void 0;
14048
14107
  }
14049
14108
  }
14050
- function getAidenAgentPrompt(agentId) {
14109
+ function getAlanAgentPrompt(agentId) {
14051
14110
  return getAgentSystemPrompt(agentId);
14052
14111
  }
14053
14112
 
14054
14113
  // ../shared/dist/types/frontend.js
14114
+ var EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
14055
14115
  var CLAUDE_48_EFFORT_LEVELS = [
14056
14116
  "minimal",
14057
14117
  "low",
@@ -14338,9 +14398,18 @@ var CLAUDE_5_EFFORT_LEVELS2 = [
14338
14398
  var CODEX_5X_EFFORT_LEVELS2 = ["low", "medium", "high", "xhigh"];
14339
14399
  var GPT_5_5_EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh"];
14340
14400
  var GPT_5_4_EFFORT_LEVELS = ["low", "medium", "high"];
14401
+ var GPT_5_6_EFFORT_LEVELS = [
14402
+ "low",
14403
+ "medium",
14404
+ "high",
14405
+ "xhigh",
14406
+ "max",
14407
+ "ultra"
14408
+ ];
14341
14409
  var CURSOR_EFFORT_SUFFIXES = [
14342
14410
  { suffix: "-extra-high", level: "xhigh" },
14343
14411
  { suffix: "-xhigh", level: "xhigh" },
14412
+ { suffix: "-ultra", level: "ultra" },
14344
14413
  { suffix: "-max", level: "max" },
14345
14414
  { suffix: "-high", level: "high" },
14346
14415
  { suffix: "-medium", level: "medium" },
@@ -14436,7 +14505,11 @@ function mergeEffortLevels(existing, discovered) {
14436
14505
  const merged = new Set(existing ?? []);
14437
14506
  for (const level of discovered)
14438
14507
  merged.add(level);
14439
- return Array.from(merged);
14508
+ return orderEffortLevels(merged);
14509
+ }
14510
+ function orderEffortLevels(levels) {
14511
+ const set = levels instanceof Set ? levels : new Set(levels);
14512
+ return EFFORT_LEVELS.filter((level) => set.has(level));
14440
14513
  }
14441
14514
  function lookupKnownModelCapabilities(modelId) {
14442
14515
  for (const catalog of [AVAILABLE_MODELS, CURSOR_AGENT_MODELS]) {
@@ -14460,6 +14533,13 @@ function inferSlugModelCapabilities(providerKind, modelId) {
14460
14533
  if (id === "gpt-5.4" || id === "gpt-5.4-mini") {
14461
14534
  return { contextWindows: [], effortLevels: GPT_5_4_EFFORT_LEVELS };
14462
14535
  }
14536
+ if (/^gpt-5\.6-/.test(id)) {
14537
+ const hasUltra = id.includes("-sol") || id.includes("-terra");
14538
+ return {
14539
+ contextWindows: [],
14540
+ effortLevels: hasUltra ? GPT_5_6_EFFORT_LEVELS : GPT_5_6_EFFORT_LEVELS.filter((level) => level !== "ultra")
14541
+ };
14542
+ }
14463
14543
  if (id.includes("codex") || /^gpt-5\.[0-3]/.test(id)) {
14464
14544
  return { contextWindows: [], effortLevels: CODEX_5X_EFFORT_LEVELS2 };
14465
14545
  }
@@ -14618,6 +14698,7 @@ function baseCatalogForProvider(providerKind) {
14618
14698
  }
14619
14699
  return staticCatalog;
14620
14700
  }
14701
+ var PROVIDER_MODEL_INFERENCE_IDS = Object.keys(PROVIDER_MODELS).filter((providerId) => providerId !== "antigravity_cli");
14621
14702
  function catalogModelsForProvider(providerKind, modelsFromConfig) {
14622
14703
  const catalog = baseCatalogForProvider(providerKind);
14623
14704
  if (!modelsFromConfig)
@@ -14630,13 +14711,18 @@ function catalogModelsForProvider(providerKind, modelsFromConfig) {
14630
14711
  }
14631
14712
 
14632
14713
  // ../agent-core/dist/index.js
14633
- var import_child_process = require("child_process");
14634
14714
  var import_fs2 = require("fs");
14635
14715
  var import_os2 = require("os");
14636
14716
  var import_path2 = require("path");
14717
+ var import_child_process = require("child_process");
14718
+ var import_fs3 = require("fs");
14719
+ var import_os3 = require("os");
14720
+ var import_path3 = require("path");
14637
14721
  var import_readline = require("readline");
14638
14722
  var import_child_process2 = require("child_process");
14639
14723
  var import_crypto = require("crypto");
14724
+ var import_child_process3 = require("child_process");
14725
+ var import_util10 = require("util");
14640
14726
 
14641
14727
  // ../shared/dist/constants/agent.js
14642
14728
  var INTERACTIVE_TOOL_NAMES = /* @__PURE__ */ new Set(["askuserquestion", "exitplanmode", "enterplanmode"]);
@@ -14645,8 +14731,11 @@ function normalizeToolName2(name) {
14645
14731
  const mcp = lower.match(/^mcp__[a-z0-9-]+__(.+)$/);
14646
14732
  let bare = mcp ? mcp[1] : lower;
14647
14733
  bare = bare.replace(/[_\s-]/g, "");
14648
- if (bare.startsWith("aiden") && bare.length > "aiden".length) {
14649
- bare = bare.slice("aiden".length);
14734
+ for (const vendor of ["alan", "alan"]) {
14735
+ if (bare.startsWith(vendor) && bare.length > vendor.length) {
14736
+ bare = bare.slice(vendor.length);
14737
+ break;
14738
+ }
14650
14739
  }
14651
14740
  return bare;
14652
14741
  }
@@ -14685,8 +14774,8 @@ function isInteractiveToolName(name, input) {
14685
14774
  return true;
14686
14775
  return isAskUserQuestionTool(name, input);
14687
14776
  }
14688
- var AIDEN_AGENT_WORKOS_USER_ID_PREFIX = "aiden-agent:";
14689
- var AIDEN_AGENT_WORKOS_USER_ID_LIKE_PATTERN = `${AIDEN_AGENT_WORKOS_USER_ID_PREFIX}%`;
14777
+ var ALAN_AGENT_WORKOS_USER_ID_PREFIX = "alan-agent:";
14778
+ var ALAN_AGENT_WORKOS_USER_ID_LIKE_PATTERN = `${ALAN_AGENT_WORKOS_USER_ID_PREFIX}%`;
14690
14779
 
14691
14780
  // ../shared/dist/constants/colors.js
14692
14781
  var CATEGORICAL_COLORS = {
@@ -14925,18 +15014,289 @@ var PRIORITY_OPTIONS = [
14925
15014
  ];
14926
15015
 
14927
15016
  // ../agent-core/dist/index.js
14928
- var import_fs3 = require("fs");
14929
- var import_os3 = require("os");
14930
- var import_path3 = require("path");
14931
15017
  var import_fs4 = require("fs");
14932
15018
  var import_os4 = require("os");
14933
15019
  var import_path4 = require("path");
14934
15020
  var import_fs5 = require("fs");
14935
15021
  var import_os5 = require("os");
14936
15022
  var import_path5 = require("path");
14937
- var import_crypto2 = require("crypto");
14938
15023
  var import_fs6 = require("fs");
15024
+ var import_os6 = require("os");
14939
15025
  var import_path6 = require("path");
15026
+ var import_crypto2 = require("crypto");
15027
+ var import_fs7 = require("fs");
15028
+ var import_path7 = require("path");
15029
+ var MANAGED_ALAN_MCP_SERVER_NAMES = [
15030
+ "alan",
15031
+ "alan-prod",
15032
+ "alan-staging",
15033
+ "alan-local"
15034
+ ];
15035
+ function parseJsonSafe(content) {
15036
+ if (!content) return {};
15037
+ try {
15038
+ return JSON.parse(content);
15039
+ } catch {
15040
+ return {};
15041
+ }
15042
+ }
15043
+ function readFileOrNull(path) {
15044
+ try {
15045
+ if ((0, import_fs2.existsSync)(path)) return (0, import_fs2.readFileSync)(path, "utf-8");
15046
+ } catch {
15047
+ }
15048
+ return null;
15049
+ }
15050
+ function writeFileSafe(path, content) {
15051
+ (0, import_fs2.mkdirSync)((0, import_path2.dirname)(path), { recursive: true });
15052
+ (0, import_fs2.writeFileSync)(path, content, "utf-8");
15053
+ }
15054
+ function formatTomlKey2(key) {
15055
+ return /^[A-Za-z0-9_-]+$/.test(key) ? key : JSON.stringify(key);
15056
+ }
15057
+ function parseJsonStringOrNull(raw) {
15058
+ try {
15059
+ const value2 = JSON.parse(raw);
15060
+ return typeof value2 === "string" ? value2 : null;
15061
+ } catch {
15062
+ return null;
15063
+ }
15064
+ }
15065
+ function splitTomlInlineEntries(body) {
15066
+ const entries = [];
15067
+ let current = "";
15068
+ let inString = false;
15069
+ let escaping = false;
15070
+ for (const char of body) {
15071
+ if (escaping) {
15072
+ current += char;
15073
+ escaping = false;
15074
+ continue;
15075
+ }
15076
+ if (char === "\\") {
15077
+ current += char;
15078
+ escaping = inString;
15079
+ continue;
15080
+ }
15081
+ if (char === '"') inString = !inString;
15082
+ if (char === "," && !inString) {
15083
+ if (current.trim()) entries.push(current.trim());
15084
+ current = "";
15085
+ continue;
15086
+ }
15087
+ current += char;
15088
+ }
15089
+ if (current.trim()) entries.push(current.trim());
15090
+ return entries;
15091
+ }
15092
+ function parseTomlInlineStringTable(raw) {
15093
+ const trimmed = raw.trim();
15094
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return {};
15095
+ const body = trimmed.slice(1, -1).trim();
15096
+ if (!body) return {};
15097
+ const headers = {};
15098
+ for (const entry of splitTomlInlineEntries(body)) {
15099
+ const equalsIndex = entry.indexOf("=");
15100
+ if (equalsIndex < 0) continue;
15101
+ const rawKey = entry.slice(0, equalsIndex).trim();
15102
+ const rawValue = entry.slice(equalsIndex + 1).trim();
15103
+ const key = rawKey.startsWith('"') ? parseJsonStringOrNull(rawKey) : rawKey;
15104
+ const value2 = rawValue.startsWith('"') ? parseJsonStringOrNull(rawValue) : rawValue;
15105
+ if (key && value2 !== null) headers[key] = value2;
15106
+ }
15107
+ return headers;
15108
+ }
15109
+ function buildTomlInlineStringTable(record) {
15110
+ return `{ ${Object.entries(record).map(([key, value2]) => `${formatTomlKey2(key)} = ${JSON.stringify(value2)}`).join(", ")} }`;
15111
+ }
15112
+ function findManagedAlanServer(servers) {
15113
+ for (const name of MANAGED_ALAN_MCP_SERVER_NAMES) {
15114
+ const server = servers[name];
15115
+ if (server && typeof server === "object") {
15116
+ return { name, server };
15117
+ }
15118
+ }
15119
+ return null;
15120
+ }
15121
+ function buildSessionHeaders(input) {
15122
+ const headers = {
15123
+ "x-conversation-id": input.conversationId
15124
+ };
15125
+ if (input.teamId) headers["x-team-id"] = input.teamId;
15126
+ if (input.allowedTools?.length) {
15127
+ headers["x-allowed-tools"] = input.allowedTools.join(",");
15128
+ }
15129
+ return headers;
15130
+ }
15131
+ function getTomlSectionName(line) {
15132
+ const match = line.match(/^\s*\[mcp_servers\.(?:"([^"]+)"|([A-Za-z0-9_-]+))\]\s*$/);
15133
+ return match?.[1] ?? match?.[2] ?? null;
15134
+ }
15135
+ function patchCodexTomlMcpConfig(content, sessionHeaders) {
15136
+ const newline = content.includes("\r\n") ? "\r\n" : "\n";
15137
+ const lines = content.split(/\r?\n/);
15138
+ const sectionStart = lines.findIndex((line) => {
15139
+ const name = getTomlSectionName(line);
15140
+ return Boolean(name && MANAGED_ALAN_MCP_SERVER_NAMES.includes(name));
15141
+ });
15142
+ if (sectionStart < 0) return null;
15143
+ let sectionEnd = lines.findIndex((line, index) => index > sectionStart && /^\s*\[/.test(line));
15144
+ if (sectionEnd < 0) sectionEnd = lines.length;
15145
+ const headerLineIndex = lines.findIndex(
15146
+ (line, index) => index > sectionStart && index < sectionEnd && /^\s*http_headers\s*=/.test(line)
15147
+ );
15148
+ if (headerLineIndex >= 0) {
15149
+ const rawInlineTable = lines[headerLineIndex]?.replace(/^\s*http_headers\s*=\s*/, "") ?? "";
15150
+ const currentHeaders = parseTomlInlineStringTable(rawInlineTable);
15151
+ lines[headerLineIndex] = `http_headers = ${buildTomlInlineStringTable({
15152
+ ...currentHeaders,
15153
+ ...sessionHeaders
15154
+ })}`;
15155
+ } else {
15156
+ const insertAfterUrl = lines.findIndex(
15157
+ (line, index) => index > sectionStart && index < sectionEnd && /^\s*url\s*=/.test(line)
15158
+ );
15159
+ lines.splice(
15160
+ insertAfterUrl >= 0 ? insertAfterUrl + 1 : sectionStart + 1,
15161
+ 0,
15162
+ `http_headers = ${buildTomlInlineStringTable(sessionHeaders)}`
15163
+ );
15164
+ }
15165
+ const updated = lines.join(newline);
15166
+ return updated.endsWith(newline) ? updated : `${updated}${newline}`;
15167
+ }
15168
+ function patchCodexTomlMcpTarget(target, sessionHeaders) {
15169
+ if (!(0, import_fs2.existsSync)(target.guardDir)) return false;
15170
+ const existing = readFileOrNull(target.configPath);
15171
+ if (existing === null) return false;
15172
+ const updated = patchCodexTomlMcpConfig(existing, sessionHeaders);
15173
+ if (updated === null || updated === existing) return false;
15174
+ writeFileSafe(target.configPath, updated);
15175
+ return true;
15176
+ }
15177
+ function patchJsonMcpTarget(target, sessionHeaders) {
15178
+ if (!(0, import_fs2.existsSync)(target.guardDir)) return false;
15179
+ const existing = readFileOrNull(target.configPath);
15180
+ const config = parseJsonSafe(existing);
15181
+ const servers = target.readServers(config);
15182
+ const match = findManagedAlanServer(servers);
15183
+ if (!match) return false;
15184
+ const currentHeaders = target.readHeaders(match.server) ?? {};
15185
+ target.writeHeaders(match.server, { ...currentHeaders, ...sessionHeaders });
15186
+ servers[match.name] = match.server;
15187
+ target.writeServers(config, servers);
15188
+ writeFileSafe(target.configPath, `${JSON.stringify(config, null, 2)}
15189
+ `);
15190
+ return true;
15191
+ }
15192
+ function jsonMcpServersTarget(cli, home, configRelativePath, guardRelativePath) {
15193
+ const configPath = (0, import_path2.join)(home, ...configRelativePath);
15194
+ const guardDir = guardRelativePath.length > 0 ? (0, import_path2.join)(home, ...guardRelativePath) : home;
15195
+ return {
15196
+ cli,
15197
+ configPath,
15198
+ guardDir,
15199
+ readServers: (config) => config.mcpServers ?? {},
15200
+ writeServers: (config, servers) => {
15201
+ config.mcpServers = servers;
15202
+ },
15203
+ readHeaders: (server) => server.headers,
15204
+ writeHeaders: (server, headers) => {
15205
+ server.headers = headers;
15206
+ }
15207
+ };
15208
+ }
15209
+ function buildCodexTomlTargets(home) {
15210
+ return [
15211
+ {
15212
+ cli: "Codex",
15213
+ configPath: (0, import_path2.join)(home, ".codex", "config.toml"),
15214
+ guardDir: (0, import_path2.join)(home, ".codex")
15215
+ }
15216
+ ];
15217
+ }
15218
+ function buildJsonTargets(home) {
15219
+ return [
15220
+ jsonMcpServersTarget("Cursor", home, [".cursor", "mcp.json"], [".cursor"]),
15221
+ jsonMcpServersTarget("Claude Code", home, [".claude.json"], []),
15222
+ jsonMcpServersTarget("Kimi CLI", home, [".kimi", "mcp.json"], [".kimi"]),
15223
+ jsonMcpServersTarget("Factory Droid", home, [".factory", "mcp.json"], [".factory"]),
15224
+ {
15225
+ cli: "OpenCode",
15226
+ configPath: (0, import_path2.join)(home, ".config", "opencode", "opencode.json"),
15227
+ guardDir: (0, import_path2.join)(home, ".config", "opencode"),
15228
+ readServers: (config) => config.mcp ?? {},
15229
+ writeServers: (config, servers) => {
15230
+ config.mcp = servers;
15231
+ },
15232
+ readHeaders: (server) => server.headers,
15233
+ writeHeaders: (server, headers) => {
15234
+ server.headers = headers;
15235
+ }
15236
+ },
15237
+ {
15238
+ cli: "Amp",
15239
+ configPath: (0, import_path2.join)(home, ".config", "amp", "settings.json"),
15240
+ guardDir: (0, import_path2.join)(home, ".config", "amp"),
15241
+ readServers: (config) => config["amp.mcpServers"] ?? {},
15242
+ writeServers: (config, servers) => {
15243
+ config["amp.mcpServers"] = servers;
15244
+ },
15245
+ readHeaders: (server) => server.headers,
15246
+ writeHeaders: (server, headers) => {
15247
+ server.headers = headers;
15248
+ }
15249
+ },
15250
+ {
15251
+ cli: "Antigravity",
15252
+ configPath: (0, import_path2.join)(home, ".gemini", "settings.json"),
15253
+ guardDir: (0, import_path2.join)(home, ".gemini"),
15254
+ readServers: (config) => config.mcpServers ?? {},
15255
+ writeServers: (config, servers) => {
15256
+ config.mcpServers = servers;
15257
+ },
15258
+ readHeaders: (server) => server.headers,
15259
+ writeHeaders: (server, headers) => {
15260
+ server.headers = headers;
15261
+ }
15262
+ },
15263
+ {
15264
+ cli: "Antigravity CLI",
15265
+ configPath: (0, import_path2.join)(home, ".gemini", "antigravity-cli", "settings.json"),
15266
+ guardDir: (0, import_path2.join)(home, ".gemini"),
15267
+ readServers: (config) => config.mcpServers ?? {},
15268
+ writeServers: (config, servers) => {
15269
+ config.mcpServers = servers;
15270
+ },
15271
+ readHeaders: (server) => server.headers,
15272
+ writeHeaders: (server, headers) => {
15273
+ server.headers = headers;
15274
+ }
15275
+ }
15276
+ ];
15277
+ }
15278
+ function syncAlanMcpSessionHeaders(input) {
15279
+ const home = input.homeDir ?? (0, import_os2.homedir)();
15280
+ const sessionHeaders = buildSessionHeaders(input);
15281
+ const written = [];
15282
+ for (const target of buildCodexTomlTargets(home)) {
15283
+ try {
15284
+ if (patchCodexTomlMcpTarget(target, sessionHeaders)) {
15285
+ written.push(target.cli);
15286
+ }
15287
+ } catch {
15288
+ }
15289
+ }
15290
+ for (const target of buildJsonTargets(home)) {
15291
+ try {
15292
+ if (patchJsonMcpTarget(target, sessionHeaders)) {
15293
+ written.push(target.cli);
15294
+ }
15295
+ } catch {
15296
+ }
15297
+ }
15298
+ return written;
15299
+ }
14940
15300
  function buildPromptWithSystem(config, promptText) {
14941
15301
  const parts2 = [
14942
15302
  config.systemPrompt?.trim(),
@@ -14961,16 +15321,16 @@ function imageFileExtension(mimeType) {
14961
15321
  }
14962
15322
  function createImageTempDirectory(cwd) {
14963
15323
  const candidates = [
14964
- cwd ? (0, import_path2.join)(cwd, ".aiden-images-") : null,
14965
- (0, import_path2.join)((0, import_os2.tmpdir)(), "aiden-images-")
15324
+ cwd ? (0, import_path3.join)(cwd, ".alan-images-") : null,
15325
+ (0, import_path3.join)((0, import_os3.tmpdir)(), "alan-images-")
14966
15326
  ].filter((value2) => Boolean(value2));
14967
15327
  for (const candidate of candidates) {
14968
15328
  try {
14969
- return (0, import_fs2.mkdtempSync)(candidate);
15329
+ return (0, import_fs3.mkdtempSync)(candidate);
14970
15330
  } catch {
14971
15331
  }
14972
15332
  }
14973
- return (0, import_fs2.mkdtempSync)((0, import_path2.join)((0, import_os2.tmpdir)(), "aiden-images-"));
15333
+ return (0, import_fs3.mkdtempSync)((0, import_path3.join)((0, import_os3.tmpdir)(), "alan-images-"));
14974
15334
  }
14975
15335
  function safeFilename(filename) {
14976
15336
  const safe = filename.replace(/[^a-zA-Z0-9._-]/g, "_").replace(/^_+/, "");
@@ -14984,8 +15344,8 @@ function writeImagesToTempFiles(images, cwd) {
14984
15344
  const files = [];
14985
15345
  for (const img of images) {
14986
15346
  const ext = imageFileExtension(img.mimeType);
14987
- const filePath = (0, import_path2.join)(directory, `aiden-img-${img.id}.${ext}`);
14988
- (0, import_fs2.writeFileSync)(filePath, Buffer.from(img.data, "base64"));
15347
+ const filePath = (0, import_path3.join)(directory, `alan-img-${img.id}.${ext}`);
15348
+ (0, import_fs3.writeFileSync)(filePath, Buffer.from(img.data, "base64"));
14989
15349
  paths.push(filePath);
14990
15350
  files.push({
14991
15351
  filename: img.filename,
@@ -15000,7 +15360,7 @@ function writeImagesToTempFiles(images, cwd) {
15000
15360
  files,
15001
15361
  cleanup: () => {
15002
15362
  try {
15003
- (0, import_fs2.rmSync)(directory, { recursive: true, force: true });
15363
+ (0, import_fs3.rmSync)(directory, { recursive: true, force: true });
15004
15364
  } catch {
15005
15365
  }
15006
15366
  }
@@ -15026,8 +15386,8 @@ function writeFilesToTempFiles(files, cwd) {
15026
15386
  }
15027
15387
  for (const file of dataFiles) {
15028
15388
  if (!directory || file.data === void 0) continue;
15029
- const filePath = (0, import_path2.join)(directory, `${file.id}-${safeFilename(file.filename)}`);
15030
- (0, import_fs2.writeFileSync)(filePath, Buffer.from(file.data, "base64"));
15389
+ const filePath = (0, import_path3.join)(directory, `${file.id}-${safeFilename(file.filename)}`);
15390
+ (0, import_fs3.writeFileSync)(filePath, Buffer.from(file.data, "base64"));
15031
15391
  paths.push(filePath);
15032
15392
  tempFiles.push({
15033
15393
  filename: file.filename,
@@ -15042,7 +15402,7 @@ function writeFilesToTempFiles(files, cwd) {
15042
15402
  cleanup: () => {
15043
15403
  if (!directory) return;
15044
15404
  try {
15045
- (0, import_fs2.rmSync)(directory, { recursive: true, force: true });
15405
+ (0, import_fs3.rmSync)(directory, { recursive: true, force: true });
15046
15406
  } catch {
15047
15407
  }
15048
15408
  }
@@ -15964,6 +16324,30 @@ function createAntigravityCliBackend(command = "agy", defaultArgs = []) {
15964
16324
  }
15965
16325
  };
15966
16326
  }
16327
+ var execFileAsync = (0, import_util10.promisify)(import_child_process3.execFile);
16328
+ var flagSupportCache = /* @__PURE__ */ new Map();
16329
+ function helpAdvertisesFlag(helpText, flag) {
16330
+ return helpText.includes(flag);
16331
+ }
16332
+ async function cliSupportsFlag(command, flag, env = {}) {
16333
+ const key = `${command}::${flag}`;
16334
+ const cached = flagSupportCache.get(key);
16335
+ if (cached !== void 0) return cached;
16336
+ let supported = false;
16337
+ try {
16338
+ const { stdout, stderr } = await execFileAsync(command, ["--help"], {
16339
+ env: { ...process.env, ...env },
16340
+ timeout: 5e3,
16341
+ maxBuffer: 4 * 1024 * 1024
16342
+ });
16343
+ supported = helpAdvertisesFlag(`${stdout ?? ""}${stderr ?? ""}`, flag);
16344
+ } catch (error) {
16345
+ const withOutput = error;
16346
+ supported = helpAdvertisesFlag(`${withOutput.stdout ?? ""}${withOutput.stderr ?? ""}`, flag);
16347
+ }
16348
+ flagSupportCache.set(key, supported);
16349
+ return supported;
16350
+ }
15967
16351
  function stringField(record, key) {
15968
16352
  const value2 = record[key];
15969
16353
  return typeof value2 === "string" && value2.trim().length > 0 ? value2 : void 0;
@@ -16070,7 +16454,7 @@ function maybeFinalizeDeferredResult(kind, context, state) {
16070
16454
  state.resultDeferredOnBackgroundWork = false;
16071
16455
  finalizeStructuredResult(kind, state);
16072
16456
  }
16073
- var DEBUG_ASK = process.env.AIDEN_DEBUG_ASK === "1" || process.env.AIDEN_DEBUG === "1";
16457
+ var DEBUG_ASK = process.env.ALAN_DEBUG_ASK === "1" || process.env.ALAN_DEBUG === "1";
16074
16458
  function debugAskLog(message) {
16075
16459
  if (DEBUG_ASK) console.info(message);
16076
16460
  }
@@ -16333,13 +16717,13 @@ function createClaudeCliBackend(command = "claude", defaultArgs = []) {
16333
16717
  args.push("--disallowedTools", disallowedTools.join(","));
16334
16718
  }
16335
16719
  const resumeId = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
16336
- if (!resumeId) {
16337
- if (context.config.systemPrompt?.trim()) {
16338
- args.push("--system-prompt", context.config.systemPrompt.trim());
16339
- }
16340
- if (context.config.systemPromptAppend?.trim()) {
16341
- args.push("--append-system-prompt", context.config.systemPromptAppend.trim());
16342
- }
16720
+ if (!resumeId && context.config.systemPrompt?.trim()) {
16721
+ args.push("--system-prompt", context.config.systemPrompt.trim());
16722
+ } else if (resumeId && context.config.systemPromptAppend?.trim()) {
16723
+ args.push("--append-system-prompt", context.config.systemPromptAppend.trim());
16724
+ }
16725
+ if (context.config.teamId?.trim() && await cliSupportsFlag(command, "--approve-mcps", context.env)) {
16726
+ args.push("--approve-mcps");
16343
16727
  }
16344
16728
  const baseModel = context.config.selectedModel?.trim();
16345
16729
  if (baseModel) {
@@ -16424,26 +16808,26 @@ function normalizeCodexMcpToolResult(output) {
16424
16808
  return raw;
16425
16809
  }
16426
16810
  function findCodexSessionLog(runtimeSessionId, codexHome) {
16427
- if (!runtimeSessionId || !(0, import_fs3.existsSync)(codexHome)) return null;
16428
- const root = (0, import_path3.join)(codexHome, "sessions");
16429
- if (!(0, import_fs3.existsSync)(root)) return null;
16811
+ if (!runtimeSessionId || !(0, import_fs4.existsSync)(codexHome)) return null;
16812
+ const root = (0, import_path4.join)(codexHome, "sessions");
16813
+ if (!(0, import_fs4.existsSync)(root)) return null;
16430
16814
  const matches = [];
16431
16815
  const stack = [root];
16432
16816
  while (stack.length > 0) {
16433
16817
  const dir = stack.pop();
16434
16818
  let entries;
16435
16819
  try {
16436
- entries = (0, import_fs3.readdirSync)(dir, { withFileTypes: true });
16820
+ entries = (0, import_fs4.readdirSync)(dir, { withFileTypes: true });
16437
16821
  } catch {
16438
16822
  continue;
16439
16823
  }
16440
16824
  for (const entry of entries) {
16441
- const path = (0, import_path3.join)(dir, entry.name);
16825
+ const path = (0, import_path4.join)(dir, entry.name);
16442
16826
  if (entry.isDirectory()) {
16443
16827
  stack.push(path);
16444
16828
  } else if (entry.isFile() && entry.name.includes(runtimeSessionId) && entry.name.endsWith(".jsonl")) {
16445
16829
  try {
16446
- matches.push({ path, mtimeMs: (0, import_fs3.statSync)(path).mtimeMs });
16830
+ matches.push({ path, mtimeMs: (0, import_fs4.statSync)(path).mtimeMs });
16447
16831
  } catch {
16448
16832
  matches.push({ path, mtimeMs: 0 });
16449
16833
  }
@@ -16476,10 +16860,10 @@ function latestUserMessageLineIndex(lines) {
16476
16860
  async function replayCodexMcpToolEventsFromSessionLog(context, state) {
16477
16861
  const runtimeSessionId = state.runtimeSessionId;
16478
16862
  if (!runtimeSessionId) return;
16479
- const codexHome = context.env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path3.join)((0, import_os3.homedir)(), ".codex");
16863
+ const codexHome = context.env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path4.join)((0, import_os4.homedir)(), ".codex");
16480
16864
  const logPath = findCodexSessionLog(runtimeSessionId, codexHome);
16481
16865
  if (!logPath) return;
16482
- const allLines = (0, import_fs3.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
16866
+ const allLines = (0, import_fs4.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
16483
16867
  const latestUserLineIndex = latestUserMessageLineIndex(allLines);
16484
16868
  const lines = latestUserLineIndex >= 0 ? allLines.slice(latestUserLineIndex + 1) : allLines;
16485
16869
  const emittedToolIds = /* @__PURE__ */ new Set();
@@ -17117,6 +17501,7 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
17117
17501
  context.config.images,
17118
17502
  context.cwd
17119
17503
  );
17504
+ const approveMcps = context.config.teamId?.trim() ? await cliSupportsFlag(command, "--approve-mcps", context.env) : false;
17120
17505
  try {
17121
17506
  return await createGenericCliBackend({
17122
17507
  kind: "cursor_agent_cli",
@@ -17129,10 +17514,12 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
17129
17514
  "--output-format",
17130
17515
  "stream-json",
17131
17516
  "--trust",
17132
- "--approve-mcps",
17133
17517
  "--workspace",
17134
17518
  ctx.cwd
17135
17519
  ];
17520
+ if (approveMcps) {
17521
+ args.push("--approve-mcps");
17522
+ }
17136
17523
  const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
17137
17524
  if (shouldForceCursorAgent(ctx.config)) args.push("--force");
17138
17525
  if (ctx.config.mode === "plan" || ctx.config.mode === "review") {
@@ -17167,7 +17554,12 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
17167
17554
  // with zero output; without this watchdog only the 30-min server reaper
17168
17555
  // would end the run.
17169
17556
  startupTimeoutMs: 18e4,
17170
- augmentPrompt: (ctx) => buildPromptWithImagePathReferences(ctx, imageFiles),
17557
+ augmentPrompt: (ctx) => {
17558
+ const prompt = buildPromptWithImagePathReferences(ctx, imageFiles);
17559
+ return ctx.config.teamId?.trim() ? `${prompt}
17560
+
17561
+ ${buildCodeDiscoveryEnforcementTail()}` : prompt;
17562
+ },
17171
17563
  parseStructuredLine: parseCursorStructuredLine
17172
17564
  }).run(context);
17173
17565
  } finally {
@@ -17305,174 +17697,259 @@ function createDroidCliBackend(command = "droid", defaultArgs = []) {
17305
17697
  }
17306
17698
  };
17307
17699
  }
17700
+ var ACP_PROTOCOL_VERSION = 1;
17308
17701
  function asRecord(value2) {
17309
- return value2 && typeof value2 === "object" ? value2 : null;
17702
+ return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
17310
17703
  }
17311
- function extractToolName2(parsed) {
17312
- for (const key of ["toolName", "name", "tool", "tool_name"]) {
17313
- const value2 = parsed[key];
17314
- if (typeof value2 === "string" && value2.trim()) return value2.trim();
17704
+ function asString(value2) {
17705
+ return typeof value2 === "string" ? value2 : "";
17706
+ }
17707
+ function resumeSessionId(context) {
17708
+ return context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim() || "";
17709
+ }
17710
+ function chunkText(content) {
17711
+ const record = asRecord(content);
17712
+ if (!record) return "";
17713
+ if (typeof record.text === "string") return record.text;
17714
+ return chunkText(record.content);
17715
+ }
17716
+ function toolResultText(update) {
17717
+ const content = update.content;
17718
+ if (Array.isArray(content)) {
17719
+ const parts2 = content.map((item) => chunkText(item)).filter((text) => text.length > 0);
17720
+ if (parts2.length) return parts2.join("\n");
17315
17721
  }
17316
- const toolCall = asRecord(parsed.toolCall) ?? asRecord(parsed.tool_call);
17317
- if (toolCall) {
17318
- for (const key of ["name", "toolName", "tool"]) {
17319
- const value2 = toolCall[key];
17320
- if (typeof value2 === "string" && value2.trim()) return value2.trim();
17722
+ const rawOutput = update.rawOutput;
17723
+ if (rawOutput !== void 0) return JSON.stringify(rawOutput, null, 2);
17724
+ return "";
17725
+ }
17726
+ function toolMetaName(update) {
17727
+ const meta = asRecord(update._meta);
17728
+ const tool = asRecord(meta?.["x.ai/tool"]);
17729
+ return asString(tool?.name);
17730
+ }
17731
+ function resolvePermission(params, context) {
17732
+ const record = asRecord(params);
17733
+ const options = Array.isArray(record?.options) ? record?.options : [];
17734
+ const toolCall = asRecord(record?.toolCall);
17735
+ const meta = asRecord(toolCall?._meta);
17736
+ const tool = asRecord(meta?.["x.ai/tool"]);
17737
+ const isReadOnlyTool = tool?.read_only === true || asString(tool?.kind) === "read";
17738
+ const allow = !shouldUseReadOnlyRuntimePermissions(context.config) || isReadOnlyTool;
17739
+ const allowKinds = ["allow_always", "allow_once", "allow"];
17740
+ const rejectKinds = ["reject_always", "reject_once", "reject", "deny"];
17741
+ const wanted = allow ? allowKinds : rejectKinds;
17742
+ const chosen = options.find((option) => wanted.includes(asString(asRecord(option)?.kind))) ?? (allow ? options[0] : options[options.length - 1]);
17743
+ const optionId = asString(asRecord(chosen)?.optionId);
17744
+ if (!optionId) return { outcome: { outcome: "cancelled" } };
17745
+ return { outcome: { outcome: "selected", optionId } };
17746
+ }
17747
+ function createGrokAcpDriver(imageFiles) {
17748
+ let stdin = null;
17749
+ let nextId = 0;
17750
+ let initId = -1;
17751
+ let sessionOpId = -1;
17752
+ let promptId = -1;
17753
+ let attemptedNewSession = false;
17754
+ let finalized = false;
17755
+ function write(message) {
17756
+ try {
17757
+ stdin?.write(`${JSON.stringify(message)}
17758
+ `);
17759
+ } catch {
17321
17760
  }
17322
17761
  }
17323
- return "Grok Tool";
17324
- }
17325
- function extractToolId2(parsed, fallback) {
17326
- for (const key of ["toolCallId", "callId", "call_id", "id"]) {
17327
- const value2 = parsed[key];
17328
- if (typeof value2 === "string" && value2.trim()) return value2.trim();
17762
+ function request(method, params) {
17763
+ const id = ++nextId;
17764
+ write({ jsonrpc: "2.0", id, method, params });
17765
+ return id;
17329
17766
  }
17330
- const toolCall = asRecord(parsed.toolCall) ?? asRecord(parsed.tool_call);
17331
- if (toolCall) {
17332
- for (const key of ["id", "toolCallId", "callId"]) {
17333
- const value2 = toolCall[key];
17334
- if (typeof value2 === "string" && value2.trim()) return value2.trim();
17335
- }
17767
+ function respond(id, result) {
17768
+ write({ jsonrpc: "2.0", id, result });
17336
17769
  }
17337
- return fallback;
17338
- }
17339
- function extractToolArgs(parsed) {
17340
- for (const key of ["args", "arguments", "input", "params"]) {
17341
- if (parsed[key] !== void 0) return parsed[key];
17770
+ function newSession(context) {
17771
+ attemptedNewSession = true;
17772
+ sessionOpId = request("session/new", { cwd: context.cwd, mcpServers: [] });
17342
17773
  }
17343
- const toolCall = asRecord(parsed.toolCall) ?? asRecord(parsed.tool_call);
17344
- if (toolCall) {
17345
- for (const key of ["args", "arguments", "input", "params"]) {
17346
- if (toolCall[key] !== void 0) return toolCall[key];
17774
+ function beginSession(context, state) {
17775
+ const resume = resumeSessionId(context);
17776
+ if (resume) {
17777
+ state.runtimeSessionId = resume;
17778
+ sessionOpId = request("session/load", {
17779
+ sessionId: resume,
17780
+ cwd: context.cwd,
17781
+ mcpServers: []
17782
+ });
17783
+ return;
17347
17784
  }
17785
+ newSession(context);
17348
17786
  }
17349
- return parsed;
17350
- }
17351
- function extractToolResultText(parsed) {
17352
- for (const key of ["result", "output", "content", "data", "message"]) {
17353
- const value2 = parsed[key];
17354
- if (typeof value2 === "string" && value2.trim()) return value2;
17787
+ function sendPrompt(context, state) {
17788
+ const text = buildPromptWithImagePathReferences(context, imageFiles);
17789
+ promptId = request("session/prompt", {
17790
+ sessionId: state.runtimeSessionId,
17791
+ prompt: [{ type: "text", text }]
17792
+ });
17355
17793
  }
17356
- return JSON.stringify(parsed, null, 2);
17357
- }
17358
- function handleGrokStructuredEvent(parsed, context, state) {
17359
- const presenter = context.presenter;
17360
- const type = typeof parsed.type === "string" ? parsed.type : "";
17361
- if (!type) return false;
17362
- for (const key of ["sessionId", "session_id"]) {
17363
- const value2 = parsed[key];
17364
- if (typeof value2 === "string" && value2.trim()) {
17365
- state.runtimeSessionId = value2.trim();
17366
- break;
17794
+ function finalize(state) {
17795
+ if (finalized) return;
17796
+ finalized = true;
17797
+ state.resultReceived = true;
17798
+ state.onResultReceived?.();
17799
+ try {
17800
+ stdin?.end();
17801
+ } catch {
17367
17802
  }
17368
17803
  }
17369
- if (typeof parsed.model === "string" && parsed.model.trim()) {
17370
- state.activeModel = parsed.model.trim();
17371
- }
17372
- switch (type) {
17373
- case "thought":
17374
- case "thinking":
17375
- case "reasoning": {
17376
- const text = typeof parsed.data === "string" ? parsed.data : "";
17377
- if (!text) return true;
17378
- state.iterations = Math.max(state.iterations, 1);
17379
- void presenter.onThinking(text);
17380
- return true;
17804
+ function handleResponse(message, context, state) {
17805
+ if (message.error && message.id === sessionOpId && !attemptedNewSession) {
17806
+ newSession(context);
17807
+ return;
17381
17808
  }
17382
- case "text":
17383
- case "assistant":
17384
- case "message": {
17385
- const text = typeof parsed.data === "string" ? parsed.data : typeof parsed.text === "string" ? parsed.text : typeof parsed.content === "string" ? parsed.content : "";
17386
- if (!text) return true;
17387
- state.iterations = Math.max(state.iterations, 1);
17388
- state.summary += text;
17389
- void presenter.onAssistantText(text);
17390
- return true;
17809
+ if (message.error) {
17810
+ state.error = message.error.message?.trim() || "Grok agent error";
17811
+ void context.presenter.onError(state.error);
17812
+ finalize(state);
17813
+ return;
17391
17814
  }
17392
- case "tool":
17393
- case "tool_call":
17394
- case "tool_use":
17395
- case "toolCall": {
17396
- const toolId = extractToolId2(parsed, `grok-tool-${Date.now()}`);
17397
- const toolName = extractToolName2(parsed);
17398
- const toolArgs = extractToolArgs(parsed);
17399
- const subtype = typeof parsed.subtype === "string" ? parsed.subtype : "";
17400
- const status = typeof parsed.status === "string" ? parsed.status : "";
17401
- state.iterations = Math.max(state.iterations, 1);
17402
- if (subtype === "completed" || subtype === "result" || status === "completed" || status === "done" || parsed.result !== void 0 || parsed.output !== void 0) {
17403
- void presenter.onToolResult?.(toolId, extractToolResultText(parsed));
17404
- return true;
17405
- }
17406
- void presenter.onToolUse(toolName, toolArgs, toolId);
17407
- return true;
17815
+ const result = asRecord(message.result);
17816
+ if (message.id === initId) {
17817
+ const modelState = asRecord(asRecord(result?._meta)?.modelState);
17818
+ const model = asString(modelState?.currentModelId);
17819
+ if (model) state.activeModel = model;
17820
+ beginSession(context, state);
17821
+ return;
17408
17822
  }
17409
- case "tool_result":
17410
- case "toolResult": {
17411
- const toolId = extractToolId2(parsed, `grok-tool-${Date.now()}`);
17823
+ if (message.id === sessionOpId) {
17824
+ const sessionId = asString(result?.sessionId);
17825
+ if (sessionId) state.runtimeSessionId = sessionId;
17412
17826
  state.iterations = Math.max(state.iterations, 1);
17413
- void presenter.onToolResult?.(toolId, extractToolResultText(parsed));
17414
- return true;
17415
- }
17416
- case "error": {
17417
- const message = typeof parsed.message === "string" && parsed.message.trim() ? parsed.message.trim() : typeof parsed.data === "string" && parsed.data.trim() ? parsed.data.trim() : "Grok Build run failed";
17418
- state.error = message;
17419
- void presenter.onError(message);
17420
- state.resultReceived = true;
17421
- state.onResultReceived?.();
17422
- return true;
17827
+ sendPrompt(context, state);
17828
+ return;
17423
17829
  }
17424
- case "end":
17425
- case "result": {
17426
- const stopReason = typeof parsed.stopReason === "string" ? parsed.stopReason : "";
17830
+ if (message.id === promptId) {
17831
+ const meta = asRecord(result?._meta);
17832
+ const model = asString(meta?.modelId) || state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel.trim() : "grok");
17833
+ const inputTokens = typeof meta?.inputTokens === "number" ? meta.inputTokens : 0;
17834
+ const outputTokens = typeof meta?.outputTokens === "number" ? meta.outputTokens : 0;
17835
+ const cacheReadTokens = typeof meta?.cachedReadTokens === "number" ? meta.cachedReadTokens : 0;
17427
17836
  state.iterations = Math.max(state.iterations, 1);
17428
17837
  state.usage = {
17429
- model: state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel : "grok"),
17838
+ model,
17430
17839
  numTurns: Math.max(state.iterations, 1),
17431
- durationMs: typeof parsed.duration_ms === "number" ? parsed.duration_ms : 0,
17432
- inputTokens: 0,
17433
- outputTokens: 0,
17434
- cacheReadTokens: 0,
17840
+ durationMs: 0,
17841
+ inputTokens,
17842
+ outputTokens,
17843
+ cacheReadTokens,
17435
17844
  cacheCreationTokens: 0,
17436
17845
  costUsd: 0
17437
17846
  };
17438
- void presenter.onUsageUpdate?.({
17439
- model: state.usage.model,
17440
- inputTokens: 0,
17441
- outputTokens: 0,
17442
- cacheReadTokens: 0,
17847
+ void context.presenter.onUsageUpdate?.({
17848
+ model,
17849
+ inputTokens,
17850
+ outputTokens,
17851
+ cacheReadTokens,
17443
17852
  cacheCreationTokens: 0
17444
17853
  });
17445
- if ((stopReason.toLowerCase().includes("error") || parsed.is_error === true) && !state.error) {
17854
+ const stopReason = asString(result?.stopReason).toLowerCase();
17855
+ if (stopReason.includes("error") && !state.error) {
17446
17856
  state.error = "Grok Build run failed";
17447
- void presenter.onError(state.error);
17857
+ void context.presenter.onError(state.error);
17448
17858
  }
17449
- state.resultReceived = true;
17450
- state.onResultReceived?.();
17451
- return true;
17859
+ finalize(state);
17452
17860
  }
17453
- default:
17454
- return false;
17455
17861
  }
17862
+ function handleServerRequest(message, context, _state) {
17863
+ const id = message.id;
17864
+ switch (message.method) {
17865
+ case "session/request_permission":
17866
+ respond(id, resolvePermission(message.params, context));
17867
+ return;
17868
+ case "fs/read_text_file":
17869
+ respond(id, { content: "" });
17870
+ return;
17871
+ default:
17872
+ respond(id, null);
17873
+ }
17874
+ }
17875
+ function handleNotification(message, context, state) {
17876
+ const params = asRecord(message.params);
17877
+ const update = asRecord(params?.update);
17878
+ if (!update) return;
17879
+ const presenter = context.presenter;
17880
+ switch (asString(update.sessionUpdate)) {
17881
+ case "agent_thought_chunk": {
17882
+ const text = chunkText(update.content);
17883
+ if (!text) return;
17884
+ state.iterations = Math.max(state.iterations, 1);
17885
+ void presenter.onThinking(text);
17886
+ return;
17887
+ }
17888
+ case "agent_message_chunk": {
17889
+ const text = chunkText(update.content);
17890
+ if (!text) return;
17891
+ state.iterations = Math.max(state.iterations, 1);
17892
+ state.summary += text;
17893
+ void presenter.onAssistantText(text);
17894
+ return;
17895
+ }
17896
+ case "tool_call": {
17897
+ const toolId = asString(update.toolCallId);
17898
+ const toolName = asString(update.title) || toolMetaName(update) || "Grok Tool";
17899
+ const input = update.rawInput ?? {};
17900
+ state.iterations = Math.max(state.iterations, 1);
17901
+ void presenter.onToolUse(toolName, input, toolId);
17902
+ return;
17903
+ }
17904
+ case "tool_call_update": {
17905
+ const status = asString(update.status).toLowerCase();
17906
+ if (status !== "completed" && status !== "failed" && status !== "error") return;
17907
+ const toolId = asString(update.toolCallId);
17908
+ void presenter.onToolResult?.(toolId, toolResultText(update));
17909
+ return;
17910
+ }
17911
+ default:
17912
+ return;
17913
+ }
17914
+ }
17915
+ function handleLine(line, context, state) {
17916
+ if (!stdin && state.stdin) stdin = state.stdin;
17917
+ let parsed;
17918
+ try {
17919
+ parsed = JSON.parse(line);
17920
+ } catch {
17921
+ if (line.trim().length > 0) void context.presenter.onLog(`[grok_cli] ${line}`);
17922
+ return;
17923
+ }
17924
+ const message = asRecord(parsed);
17925
+ if (!message) return;
17926
+ if (message.id !== void 0 && message.method === void 0) {
17927
+ handleResponse(message, context, state);
17928
+ return;
17929
+ }
17930
+ if (message.method && message.id !== void 0) {
17931
+ handleServerRequest(message, context, state);
17932
+ return;
17933
+ }
17934
+ if (message.method) {
17935
+ handleNotification(message, context, state);
17936
+ }
17937
+ }
17938
+ function start(stdinStream, _context) {
17939
+ stdin = stdinStream;
17940
+ initId = request("initialize", {
17941
+ protocolVersion: ACP_PROTOCOL_VERSION,
17942
+ clientCapabilities: {
17943
+ fs: { readTextFile: false, writeTextFile: false },
17944
+ terminal: false
17945
+ }
17946
+ });
17947
+ }
17948
+ return { start, handleLine };
17456
17949
  }
17457
- var parseGrokStructuredLine = createStructuredLineParser(
17458
- "grok_cli",
17459
- handleGrokStructuredEvent
17460
- );
17461
17950
  function isGrokCliModelId(model) {
17462
17951
  return model === "auto" || /^grok-/.test(model) || /^grok_/.test(model) || model.startsWith("grok-composer-");
17463
17952
  }
17464
- function resolveGrokPermissionMode(config) {
17465
- if (shouldUseReadOnlyRuntimePermissions(config)) return "plan";
17466
- switch (config.mode) {
17467
- case "plan":
17468
- case "review":
17469
- return "plan";
17470
- case "ask":
17471
- return "dontAsk";
17472
- default:
17473
- return "bypassPermissions";
17474
- }
17475
- }
17476
17953
  function createGrokCliBackend(command = "grok", defaultArgs = []) {
17477
17954
  return {
17478
17955
  kind: "grok_cli",
@@ -17482,34 +17959,17 @@ function createGrokCliBackend(command = "grok", defaultArgs = []) {
17482
17959
  context.config.images,
17483
17960
  context.cwd
17484
17961
  );
17962
+ const driver = createGrokAcpDriver(imageFiles);
17485
17963
  try {
17486
17964
  return await createGenericCliBackend({
17487
17965
  kind: "grok_cli",
17488
17966
  supportTier: "structured",
17489
17967
  command,
17490
17968
  args: [],
17491
- buildArgs: (ctx, prompt) => {
17492
- const args = [
17493
- "-p",
17494
- prompt,
17495
- "--output-format",
17496
- "streaming-json",
17497
- "--cwd",
17498
- ctx.cwd,
17499
- "--permission-mode",
17500
- resolveGrokPermissionMode(ctx.config)
17501
- ];
17502
- if (!shouldUseReadOnlyRuntimePermissions(ctx.config)) {
17503
- args.push("--always-approve");
17504
- }
17505
- const resumeId = ctx.config.runtimeSessionId?.trim() || ctx.config.providerSessionId?.trim();
17506
- if (resumeId) args.push("--resume", resumeId);
17507
- const model = ctx.config.selectedModel?.trim();
17508
- if (model && isGrokCliModelId(model)) args.push("--model", model);
17509
- return [...args, ...defaultArgs];
17510
- },
17511
- augmentPrompt: (ctx) => buildPromptWithImagePathReferences(ctx, imageFiles),
17512
- parseStructuredLine: parseGrokStructuredLine
17969
+ buildArgs: (ctx) => buildGrokAgentArgs(ctx.config, defaultArgs),
17970
+ keepStdinOpen: true,
17971
+ stdinWriter: (stdin, ctx) => driver.start(stdin, ctx),
17972
+ parseStructuredLine: driver.handleLine
17513
17973
  }).run(context);
17514
17974
  } finally {
17515
17975
  cleanup();
@@ -17517,10 +17977,20 @@ function createGrokCliBackend(command = "grok", defaultArgs = []) {
17517
17977
  }
17518
17978
  };
17519
17979
  }
17980
+ function buildGrokAgentArgs(config, defaultArgs = []) {
17981
+ const args = ["agent"];
17982
+ if (!shouldUseReadOnlyRuntimePermissions(config)) {
17983
+ args.push("--always-approve");
17984
+ }
17985
+ const model = config.selectedModel?.trim();
17986
+ if (model && isGrokCliModelId(model)) args.push("--model", model);
17987
+ args.push(...defaultArgs, "stdio");
17988
+ return args;
17989
+ }
17520
17990
  var DEFAULT_SKILL_ROOTS = [
17521
- (0, import_path4.join)((0, import_os4.homedir)(), ".agents", "skills"),
17522
- (0, import_path4.join)((0, import_os4.homedir)(), ".claude", "skills"),
17523
- (0, import_path4.join)((0, import_os4.homedir)(), ".config", "opencode", "skills")
17991
+ (0, import_path5.join)((0, import_os5.homedir)(), ".agents", "skills"),
17992
+ (0, import_path5.join)((0, import_os5.homedir)(), ".claude", "skills"),
17993
+ (0, import_path5.join)((0, import_os5.homedir)(), ".config", "opencode", "skills")
17524
17994
  ];
17525
17995
  function parseFrontmatter(content) {
17526
17996
  if (!content.startsWith("---\n")) return {};
@@ -17536,12 +18006,12 @@ function parseFrontmatter(content) {
17536
18006
  return result;
17537
18007
  }
17538
18008
  function listSkillFiles(root) {
17539
- if (!(0, import_fs4.existsSync)(root)) return [];
18009
+ if (!(0, import_fs5.existsSync)(root)) return [];
17540
18010
  const files = [];
17541
- for (const entry of (0, import_fs4.readdirSync)(root, { withFileTypes: true })) {
18011
+ for (const entry of (0, import_fs5.readdirSync)(root, { withFileTypes: true })) {
17542
18012
  if (!entry.isDirectory()) continue;
17543
- const skillPath = (0, import_path4.join)(root, entry.name, "SKILL.md");
17544
- if ((0, import_fs4.existsSync)(skillPath)) files.push(skillPath);
18013
+ const skillPath = (0, import_path5.join)(root, entry.name, "SKILL.md");
18014
+ if ((0, import_fs5.existsSync)(skillPath)) files.push(skillPath);
17545
18015
  }
17546
18016
  return files;
17547
18017
  }
@@ -17550,7 +18020,7 @@ function loadInstalledSkills(roots = DEFAULT_SKILL_ROOTS) {
17550
18020
  for (const root of roots) {
17551
18021
  for (const skillPath of listSkillFiles(root)) {
17552
18022
  try {
17553
- const frontmatter = parseFrontmatter((0, import_fs4.readFileSync)(skillPath, "utf8"));
18023
+ const frontmatter = parseFrontmatter((0, import_fs5.readFileSync)(skillPath, "utf8"));
17554
18024
  const name = frontmatter.name;
17555
18025
  const description = frontmatter.description;
17556
18026
  if (!name || !description || skills.has(name)) continue;
@@ -18047,40 +18517,40 @@ function parseSkillInvocation(text) {
18047
18517
  function candidateRoots(cwd) {
18048
18518
  const roots = [];
18049
18519
  if (cwd) {
18050
- roots.push((0, import_path5.join)(cwd, ".agents", "skills"));
18051
- roots.push((0, import_path5.join)(cwd, ".claude", "skills"));
18052
- roots.push((0, import_path5.join)(cwd, ".codex", "skills"));
18053
- if ((0, import_fs5.existsSync)(cwd)) {
18520
+ roots.push((0, import_path6.join)(cwd, ".agents", "skills"));
18521
+ roots.push((0, import_path6.join)(cwd, ".claude", "skills"));
18522
+ roots.push((0, import_path6.join)(cwd, ".codex", "skills"));
18523
+ if ((0, import_fs6.existsSync)(cwd)) {
18054
18524
  let entries = [];
18055
18525
  try {
18056
- entries = (0, import_fs5.readdirSync)(cwd, { withFileTypes: true });
18526
+ entries = (0, import_fs6.readdirSync)(cwd, { withFileTypes: true });
18057
18527
  } catch {
18058
18528
  }
18059
18529
  for (const entry of entries) {
18060
18530
  if (!entry.isDirectory()) continue;
18061
18531
  if (entry.name.startsWith(".")) continue;
18062
- const child = (0, import_path5.join)(cwd, entry.name);
18063
- roots.push((0, import_path5.join)(child, ".agents", "skills"));
18064
- roots.push((0, import_path5.join)(child, ".claude", "skills"));
18065
- roots.push((0, import_path5.join)(child, ".codex", "skills"));
18532
+ const child = (0, import_path6.join)(cwd, entry.name);
18533
+ roots.push((0, import_path6.join)(child, ".agents", "skills"));
18534
+ roots.push((0, import_path6.join)(child, ".claude", "skills"));
18535
+ roots.push((0, import_path6.join)(child, ".codex", "skills"));
18066
18536
  }
18067
18537
  }
18068
18538
  }
18069
- const home = (0, import_os5.homedir)();
18070
- roots.push((0, import_path5.join)(home, ".agents", "skills"));
18071
- roots.push((0, import_path5.join)(home, ".claude", "skills"));
18072
- roots.push((0, import_path5.join)(home, ".codex", "skills"));
18539
+ const home = (0, import_os6.homedir)();
18540
+ roots.push((0, import_path6.join)(home, ".agents", "skills"));
18541
+ roots.push((0, import_path6.join)(home, ".claude", "skills"));
18542
+ roots.push((0, import_path6.join)(home, ".codex", "skills"));
18073
18543
  return Array.from(new Set(roots));
18074
18544
  }
18075
18545
  function resolveSkillInvocation(text, cwd) {
18076
18546
  const parsed = parseSkillInvocation(text);
18077
18547
  if (!parsed) return null;
18078
18548
  for (const root of candidateRoots(cwd)) {
18079
- const skillPath = (0, import_path5.join)(root, parsed.command, "SKILL.md");
18080
- if (!(0, import_fs5.existsSync)(skillPath)) continue;
18549
+ const skillPath = (0, import_path6.join)(root, parsed.command, "SKILL.md");
18550
+ if (!(0, import_fs6.existsSync)(skillPath)) continue;
18081
18551
  let content;
18082
18552
  try {
18083
- content = (0, import_fs5.readFileSync)(skillPath, "utf-8");
18553
+ content = (0, import_fs6.readFileSync)(skillPath, "utf-8");
18084
18554
  } catch {
18085
18555
  continue;
18086
18556
  }
@@ -18190,7 +18660,7 @@ function buildTaskLifecyclePrompt(config) {
18190
18660
  return [
18191
18661
  "## Task Lifecycle",
18192
18662
  `This session is attached to taskId "${taskId}".`,
18193
- `Do not change the task status on your own. The user manages this task's status. Only change it by calling the Aiden MCP update_task tool when the user explicitly asks you to (for example: "move this to review" or "mark it done"). Do not update the status proactively as you move through research, implementation, testing, or review phases.`,
18663
+ `Do not change the task status on your own. The user manages this task's status. Only change it by calling the Alan MCP update_task tool when the user explicitly asks you to (for example: "move this to review" or "mark it done"). Do not update the status proactively as you move through research, implementation, testing, or review phases.`,
18194
18664
  ...statusLines,
18195
18665
  "",
18196
18666
  "When the user asks you to change the status, use exact status IDs from the available statuses. Do not invent status IDs. If none of the available statuses clearly matches the request, ask which one they mean instead of guessing."
@@ -18309,12 +18779,12 @@ var BaseMachineAgent = class _BaseMachineAgent {
18309
18779
  buildRuntimeConfig(config, safeProjectPath) {
18310
18780
  const backendKind = this.resolveBackendKind(config);
18311
18781
  const supportTier = config.supportTier || this.getDefaultSupportTier(backendKind);
18312
- const systemPromptParts = [AIDEN_IDENTITY_PROMPT];
18313
- const agentPrompt = config.agentPrompt?.trim() || getAidenAgentPrompt(config.agentId);
18782
+ const systemPromptParts = [ALAN_IDENTITY_PROMPT];
18783
+ const agentPrompt = config.agentPrompt?.trim() || getAlanAgentPrompt(config.agentId);
18314
18784
  if (agentPrompt) systemPromptParts.push(agentPrompt);
18315
- const modeHint = getAidenModePrompt(config.mode);
18785
+ const modeHint = getAlanModePrompt(config.mode);
18316
18786
  if (modeHint) systemPromptParts.push(modeHint);
18317
- systemPromptParts.push(AIDEN_ASK_USER_PROMPT);
18787
+ systemPromptParts.push(ALAN_ASK_USER_PROMPT);
18318
18788
  const operatorSystemPrompt = config.systemPrompt?.trim();
18319
18789
  if (operatorSystemPrompt) systemPromptParts.push(operatorSystemPrompt);
18320
18790
  const workingDir = config.worktreePath || safeProjectPath;
@@ -18326,8 +18796,14 @@ Prefer relative paths and keep your work scoped to this project.`
18326
18796
  }
18327
18797
  const lifecyclePrompt = buildTaskLifecyclePrompt(config);
18328
18798
  if (lifecyclePrompt) systemPromptParts.push(lifecyclePrompt);
18799
+ const teamId = config.teamId;
18800
+ const teamCodeOverlay = teamId ? buildAlanTeamCodeContextOverlay(teamId) : void 0;
18801
+ if (teamCodeOverlay) {
18802
+ systemPromptParts.push(teamCodeOverlay);
18803
+ }
18329
18804
  const extra = this.buildExtraSystemPromptParts(config);
18330
18805
  systemPromptParts.push(...extra);
18806
+ const mergedAppend = [config.systemPromptAppend?.trim(), teamCodeOverlay].filter((value2) => Boolean(value2 && value2.length > 0)).join("\n\n");
18331
18807
  return {
18332
18808
  ...config,
18333
18809
  backendKind,
@@ -18335,12 +18811,13 @@ Prefer relative paths and keep your work scoped to this project.`
18335
18811
  runtimeCommand: config.runtimeCommand || this.runtime.runtimeCommand,
18336
18812
  runtimeArgs: config.runtimeArgs || this.runtime.runtimeArgs,
18337
18813
  selectedModel: config.selectedModel || defaultSelectedModelForBackend(backendKind),
18338
- systemPrompt: systemPromptParts.join("\n\n") || void 0
18814
+ systemPrompt: systemPromptParts.join("\n\n") || void 0,
18815
+ systemPromptAppend: mergedAppend || void 0
18339
18816
  };
18340
18817
  }
18341
18818
  async runCliBackend(config, safeProjectPath) {
18342
18819
  const backendKind = this.resolveBackendKind(config);
18343
- const defaultCwd = (0, import_path.join)((0, import_os.homedir)(), "Documents", "aiden");
18820
+ const defaultCwd = (0, import_path.join)((0, import_os.homedir)(), "Documents", "alan");
18344
18821
  if (!(0, import_fs.existsSync)(defaultCwd)) {
18345
18822
  (0, import_fs.mkdirSync)(defaultCwd, { recursive: true });
18346
18823
  }
@@ -18479,6 +18956,19 @@ Prefer relative paths and keep your work scoped to this project.`
18479
18956
  this.presenter.onComplete(result);
18480
18957
  return result;
18481
18958
  }
18959
+ if (initialConfig.conversationId) {
18960
+ try {
18961
+ const writtenClis = syncAlanMcpSessionHeaders({
18962
+ conversationId: initialConfig.conversationId,
18963
+ teamId: initialConfig.teamId
18964
+ });
18965
+ if (writtenClis.length > 0) {
18966
+ void this.presenter.onLog(`Synced Alan MCP session headers to ${writtenClis.join(", ")}`);
18967
+ }
18968
+ } catch (error) {
18969
+ console.warn("[base-machine-agent] Failed to sync MCP session headers", error);
18970
+ }
18971
+ }
18482
18972
  try {
18483
18973
  return await this.runCliBackend(initialConfig, safeProjectPath);
18484
18974
  } catch (error) {
@@ -18520,8 +19010,8 @@ var MAX_SESSION_VIDEO_BYTES = 100 * 1024 * 1024;
18520
19010
  function isRecord(value2) {
18521
19011
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
18522
19012
  }
18523
- function shouldExtractGeneratedImagesFromToolResult(toolName, content, options = {}) {
18524
- return isGeneratedImageToolName(toolName) || isBrowserScreenshotToolName(toolName) || isAgentBrowserMediaInvocation(toolName, content, options.toolInput, "image");
19013
+ function shouldExtractGeneratedImagesFromToolResult(toolName, _content, _options = {}) {
19014
+ return isGeneratedImageToolName(toolName);
18525
19015
  }
18526
19016
  function collectStringValues(value2, out) {
18527
19017
  if (typeof value2 === "string") {
@@ -18585,14 +19075,14 @@ function normalizePath(candidate, cwd) {
18585
19075
  } catch {
18586
19076
  }
18587
19077
  if (path.startsWith("~/")) return null;
18588
- if ((0, import_path6.isAbsolute)(path)) return path;
18589
- return cwd ? (0, import_path6.join)(cwd, path) : null;
19078
+ if ((0, import_path7.isAbsolute)(path)) return path;
19079
+ return cwd ? (0, import_path7.join)(cwd, path) : null;
18590
19080
  }
18591
19081
  function resolveToolCwd(cwd, toolInput) {
18592
19082
  if (!isRecord(toolInput)) return cwd;
18593
19083
  const raw = typeof toolInput.cwd === "string" ? toolInput.cwd : typeof toolInput.workdir === "string" ? toolInput.workdir : typeof toolInput.workingDirectory === "string" ? toolInput.workingDirectory : null;
18594
19084
  if (!raw) return cwd;
18595
- return (0, import_path6.isAbsolute)(raw) || !cwd ? raw : (0, import_path6.join)(cwd, raw);
19085
+ return (0, import_path7.isAbsolute)(raw) || !cwd ? raw : (0, import_path7.join)(cwd, raw);
18596
19086
  }
18597
19087
  function extractBrowserMediaPathHints(content, cwd, toolName, options = {}, kind = "video") {
18598
19088
  if (!isAgentBrowserMediaInvocation(toolName, content, options.toolInput, kind)) return [];
@@ -18635,19 +19125,19 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
18635
19125
  const effectiveCwd = resolveToolCwd(cwd, options.toolInput);
18636
19126
  for (const candidate of extractPathCandidates(content, options)) {
18637
19127
  const path = normalizePath(candidate, effectiveCwd);
18638
- if (!path || seen.has(path) || !(0, import_fs6.existsSync)(path)) continue;
19128
+ if (!path || seen.has(path) || !(0, import_fs7.existsSync)(path)) continue;
18639
19129
  seen.add(path);
18640
- const ext = (0, import_path6.extname)(path).toLowerCase();
19130
+ const ext = (0, import_path7.extname)(path).toLowerCase();
18641
19131
  const mimeType = IMAGE_MIME_BY_EXT[ext];
18642
19132
  if (!mimeType) continue;
18643
- const stat = (0, import_fs6.statSync)(path);
19133
+ const stat = (0, import_fs7.statSync)(path);
18644
19134
  if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_GENERATED_IMAGE_BYTES) continue;
18645
- const buffer = (0, import_fs6.readFileSync)(path);
19135
+ const buffer = (0, import_fs7.readFileSync)(path);
18646
19136
  const { width, height } = readImageDimensions2(buffer, mimeType);
18647
19137
  images.push({
18648
19138
  type: "generated_image",
18649
19139
  id: (0, import_crypto2.randomUUID)(),
18650
- filename: (0, import_path6.basename)(path),
19140
+ filename: (0, import_path7.basename)(path),
18651
19141
  mimeType,
18652
19142
  size: buffer.length,
18653
19143
  width,
@@ -18662,27 +19152,36 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
18662
19152
  return images;
18663
19153
  }
18664
19154
  function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, options = {}) {
18665
- if (!isAgentBrowserMediaInvocation(toolName, content, options.toolInput, "video")) return [];
19155
+ const isImage = isAgentBrowserMediaInvocation(toolName, content, options.toolInput, "image");
19156
+ const isVideo = isAgentBrowserMediaInvocation(toolName, content, options.toolInput, "video");
19157
+ if (!isImage && !isVideo) return [];
18666
19158
  const media = [];
18667
19159
  const seen = /* @__PURE__ */ new Set();
18668
19160
  const effectiveCwd = resolveToolCwd(cwd, options.toolInput);
18669
- for (const candidate of extractPathCandidates(content, options, "mp4|webm|mov")) {
19161
+ const kind = isVideo ? "video" : "image";
19162
+ const extensionsPattern = kind === "video" ? "mp4|webm|mov" : "png|jpe?g|gif|webp";
19163
+ const maxBytes = kind === "video" ? MAX_SESSION_VIDEO_BYTES : MAX_GENERATED_IMAGE_BYTES;
19164
+ const mimeByExt = kind === "video" ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT;
19165
+ for (const candidate of extractPathCandidates(content, options, extensionsPattern)) {
18670
19166
  const path = normalizePath(candidate, effectiveCwd);
18671
- if (!path || seen.has(path) || !(0, import_fs6.existsSync)(path)) continue;
19167
+ if (!path || seen.has(path) || !(0, import_fs7.existsSync)(path)) continue;
18672
19168
  seen.add(path);
18673
- const ext = (0, import_path6.extname)(path).toLowerCase();
18674
- const mimeType = VIDEO_MIME_BY_EXT[ext];
19169
+ const ext = (0, import_path7.extname)(path).toLowerCase();
19170
+ const mimeType = mimeByExt[ext];
18675
19171
  if (!mimeType) continue;
18676
- const stat = (0, import_fs6.statSync)(path);
18677
- if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_SESSION_VIDEO_BYTES) continue;
18678
- const buffer = (0, import_fs6.readFileSync)(path);
19172
+ const stat = (0, import_fs7.statSync)(path);
19173
+ if (!stat.isFile() || stat.size <= 0 || stat.size > maxBytes) continue;
19174
+ const buffer = (0, import_fs7.readFileSync)(path);
19175
+ const dimensions = kind === "image" ? readImageDimensions2(buffer, mimeType) : null;
18679
19176
  media.push({
18680
19177
  type: "session_media",
18681
- kind: "video",
19178
+ kind,
18682
19179
  id: (0, import_crypto2.randomUUID)(),
18683
- filename: (0, import_path6.basename)(path),
19180
+ filename: (0, import_path7.basename)(path),
18684
19181
  mimeType,
18685
19182
  size: buffer.length,
19183
+ width: dimensions?.width,
19184
+ height: dimensions?.height,
18686
19185
  data: buffer.toString("base64"),
18687
19186
  sourcePath: path,
18688
19187
  sourceHash: (0, import_crypto2.createHash)("sha256").update(buffer).digest("hex"),
@@ -18928,11 +19427,11 @@ ${meta.description}`);
18928
19427
  }
18929
19428
  parts2.push(lines.join("\n"));
18930
19429
  }
18931
- const taskId = config.taskId ?? process.env.AIDEN_TASK_ID;
18932
- const workflowId = config.workflowId ?? process.env.AIDEN_WORKFLOW_ID;
18933
- const workflowExecutionId = config.workflowExecutionId ?? process.env.AIDEN_WORKFLOW_EXECUTION_ID;
18934
- const conversationId = config.conversationId ?? process.env.AIDEN_SESSION_ID;
18935
- const teamId = config.teamId;
19430
+ const taskId = config.taskId ?? process.env.ALAN_TASK_ID;
19431
+ const workflowId = config.workflowId ?? process.env.ALAN_WORKFLOW_ID;
19432
+ const workflowExecutionId = config.workflowExecutionId ?? process.env.ALAN_WORKFLOW_EXECUTION_ID;
19433
+ const conversationId = config.conversationId ?? process.env.ALAN_SESSION_ID;
19434
+ const teamId = config.teamId ?? process.env.ALAN_TEAM_ID;
18936
19435
  const artifactIds = [];
18937
19436
  if (teamId) artifactIds.push(`- teamId: "${teamId}"`);
18938
19437
  const isWorkflowSession = !!(workflowId || workflowExecutionId);
@@ -18956,7 +19455,7 @@ ${meta.description}`);
18956
19455
  [
18957
19456
  "## Prototype Artifacts",
18958
19457
  "When the user asks to create, build, modify, or iterate on a prototype, do not create local prototype files such as prototype/index.html.",
18959
- "Instead, generate a Vite React TypeScript source snapshot and call the Aiden MCP tool upsert_prototype_version with teamId, workflowId, workflowExecutionId, conversationId, title, sourceSnapshot, and packageJson.",
19458
+ "Instead, generate a Vite React TypeScript source snapshot and call the Alan MCP tool upsert_prototype_version with teamId, workflowId, workflowExecutionId, conversationId, title, sourceSnapshot, and packageJson.",
18960
19459
  "For follow-up changes to the same prototype, call list_prototypes (with workflowId) or get_prototype if needed, then call upsert_prototype_version again with the existing prototypeId and parentVersionId."
18961
19460
  ].join("\n")
18962
19461
  );
@@ -18965,16 +19464,11 @@ ${meta.description}`);
18965
19464
  [
18966
19465
  "## Prototype Artifacts",
18967
19466
  "When the user asks to create, build, modify, or iterate on a prototype, do not create local prototype files such as prototype/index.html.",
18968
- "Instead, generate a Vite React TypeScript source snapshot and call the Aiden MCP tool upsert_prototype_version with teamId, taskId, conversationId, title, sourceSnapshot, and packageJson.",
19467
+ "Instead, generate a Vite React TypeScript source snapshot and call the Alan MCP tool upsert_prototype_version with teamId, taskId, conversationId, title, sourceSnapshot, and packageJson.",
18969
19468
  "For follow-up changes to the same prototype, call list_prototypes or get_prototype if needed, then call upsert_prototype_version again with the existing prototypeId and parentVersionId so the task Prototypes panel renders the new version."
18970
19469
  ].join("\n")
18971
19470
  );
18972
19471
  }
18973
- if (teamId) {
18974
- parts2.push(
18975
- `You are operating within team \`${teamId}\`. Always use this as the \`teamId\` for all MCP tool calls that accept it (list_tasks, search, start_task_session, etc.). Do not call list_teams.`
18976
- );
18977
- }
18978
19472
  return parts2;
18979
19473
  }
18980
19474
  };
@@ -18983,10 +19477,10 @@ ${meta.description}`);
18983
19477
  var import_node_fs5 = require("fs");
18984
19478
  var import_node_os5 = require("os");
18985
19479
  var import_node_path4 = require("path");
18986
- function ensureAidenMcpRegistered(backendKind, registration, home = (0, import_node_os5.homedir)()) {
19480
+ function ensureAlanMcpRegistered(backendKind, registration, home = (0, import_node_os5.homedir)()) {
18987
19481
  try {
18988
- const mcpServers = buildAidenMcpServers(registration);
18989
- const files = aidenMcpConfigFilesForBackend(backendKind, mcpServers, home);
19482
+ const mcpServers = buildAlanMcpServers(registration);
19483
+ const files = alanMcpConfigFilesForBackend(backendKind, mcpServers, home);
18990
19484
  const paths = [];
18991
19485
  for (const file of files) {
18992
19486
  (0, import_node_fs5.mkdirSync)((0, import_node_path4.dirname)(file.path), { recursive: true });
@@ -19010,8 +19504,8 @@ function ensureAidenMcpRegistered(backendKind, registration, home = (0, import_n
19010
19504
  return { ok: false, paths: [], error: err instanceof Error ? err.message : String(err) };
19011
19505
  }
19012
19506
  }
19013
- function verifyAidenMcpRegistered(backendKind, home = (0, import_node_os5.homedir)()) {
19014
- const files = aidenMcpConfigFilesForBackend(backendKind, {}, home);
19507
+ function verifyAlanMcpRegistered(backendKind, home = (0, import_node_os5.homedir)()) {
19508
+ const files = alanMcpConfigFilesForBackend(backendKind, {}, home);
19015
19509
  const missing = files.map((f) => f.path).filter((p) => !(0, import_node_fs5.existsSync)(p));
19016
19510
  return { ok: missing.length === 0, missing };
19017
19511
  }
@@ -19163,20 +19657,40 @@ function extractModelIdsFromJson(value2) {
19163
19657
  }
19164
19658
  return [];
19165
19659
  }
19166
- function extractCodexModelSlugsFromDebugJson(value2) {
19660
+ function normalizeCodexReasoningEffort(effort) {
19661
+ const normalized = effort.trim().toLowerCase();
19662
+ if (!normalized) return null;
19663
+ if (normalized === "none") return "minimal";
19664
+ if (normalized === "minimal" || normalized === "low" || normalized === "medium" || normalized === "high" || normalized === "xhigh" || normalized === "max" || normalized === "ultra") {
19665
+ return normalized;
19666
+ }
19667
+ return null;
19668
+ }
19669
+ function extractCodexDiscoveredModelIdsFromDebugJson(value2) {
19167
19670
  if (!value2 || typeof value2 !== "object") return [];
19168
19671
  const models = value2.models;
19169
19672
  if (!Array.isArray(models)) return [];
19170
- const slugs = [];
19673
+ const ids = [];
19171
19674
  for (const entry of models) {
19172
19675
  if (!entry || typeof entry !== "object") continue;
19173
19676
  const record = entry;
19174
19677
  const visibility = typeof record.visibility === "string" ? record.visibility.toLowerCase() : "list";
19175
19678
  if (visibility === "hidden" || visibility === "hide") continue;
19176
19679
  const slug = readModelId(record.slug);
19177
- if (slug) slugs.push(slug);
19680
+ if (!slug) continue;
19681
+ const reasoningLevels = record.supported_reasoning_levels;
19682
+ if (Array.isArray(reasoningLevels) && reasoningLevels.length > 0) {
19683
+ for (const levelEntry of reasoningLevels) {
19684
+ if (!levelEntry || typeof levelEntry !== "object") continue;
19685
+ const effort = typeof levelEntry.effort === "string" ? levelEntry.effort : null;
19686
+ const normalized = effort ? normalizeCodexReasoningEffort(effort) : null;
19687
+ if (normalized) ids.push(`${slug}-${normalized}`);
19688
+ }
19689
+ continue;
19690
+ }
19691
+ ids.push(slug);
19178
19692
  }
19179
- return [...new Set(slugs)];
19693
+ return [...new Set(ids)];
19180
19694
  }
19181
19695
  function extractModelIdsFromText(value2) {
19182
19696
  const ansiPattern = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
@@ -19267,8 +19781,8 @@ async function probeJsonOrTextModels(executable, env, argSets, options) {
19267
19781
  if (!result || result.error || result.status !== 0 || !result.stdout.trim()) continue;
19268
19782
  try {
19269
19783
  const parsed = JSON.parse(result.stdout);
19270
- const codexSlugs = extractCodexModelSlugsFromDebugJson(parsed);
19271
- if (codexSlugs.length > 0) return codexSlugs;
19784
+ const codexModels = extractCodexDiscoveredModelIdsFromDebugJson(parsed);
19785
+ if (codexModels.length > 0) return codexModels;
19272
19786
  const models = extractModelIdsFromJson(parsed);
19273
19787
  if (models.length > 0) return models;
19274
19788
  } catch {
@@ -19349,13 +19863,13 @@ async function discoverProviderModels(provider, executable, env) {
19349
19863
  }
19350
19864
 
19351
19865
  // src/version.ts
19352
- var AGENT_VERSION = "0.1.32";
19866
+ var AGENT_VERSION = "0.1.35";
19353
19867
 
19354
19868
  // src/daemon.ts
19355
- var STAGING_API_URL = process.env.AIDEN_STAGING_API_URL ?? "https://api.staging.aiden-platform.com";
19356
- var STAGING_WS_URL = process.env.AIDEN_STAGING_WS_URL ?? "wss://ws.staging.aiden-platform.com";
19357
- var PRODUCTION_API_URL = "https://api.aiden-platform.com";
19358
- var PRODUCTION_WS_URL = "wss://ws.aiden-platform.com";
19869
+ var STAGING_API_URL = process.env.ALAN_STAGING_API_URL ?? "https://staging-api.tryalan.ai";
19870
+ var STAGING_WS_URL = process.env.ALAN_STAGING_WS_URL ?? "wss://alan-staging-ws.tryalan.ai";
19871
+ var PRODUCTION_API_URL = "https://api.tryalan.ai";
19872
+ var PRODUCTION_WS_URL = "wss://ws.tryalan.ai";
19359
19873
  var LOCAL_API_URL = "http://localhost:8400";
19360
19874
  var LOCAL_WS_URL = "ws://localhost:8401";
19361
19875
  function requiredString(params, key) {
@@ -19405,10 +19919,10 @@ function gitSafe(cwd, args) {
19405
19919
  }
19406
19920
  function worktreeDir(projectPath) {
19407
19921
  const resolved = (0, import_node_path5.resolve)(projectPath);
19408
- return (0, import_node_path5.join)((0, import_node_path5.dirname)(resolved), `${(0, import_node_path5.basename)(resolved)}-aiden-worktrees`);
19922
+ return (0, import_node_path5.join)((0, import_node_path5.dirname)(resolved), `${(0, import_node_path5.basename)(resolved)}-alan-worktrees`);
19409
19923
  }
19410
19924
  function pathSegment(value2) {
19411
- return value2.toLowerCase().replace(/^aiden\//, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "task";
19925
+ return value2.toLowerCase().replace(/^alan\//, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "task";
19412
19926
  }
19413
19927
  function repoName(repoUrl, localPath) {
19414
19928
  return repoUrl.replace(/\.git$/, "").split("/").pop() || (0, import_node_path5.basename)(localPath) || "repo";
@@ -19579,7 +20093,7 @@ async function probeLocalDaemonEndpoint(port, token, timeoutMs = 750) {
19579
20093
  }
19580
20094
  }
19581
20095
  function describeOccupiedLocalDaemon(port) {
19582
- return `local daemon API port ${port} is already in use. If Aiden desktop is open, it manages the daemon automatically. Quit Aiden desktop or stop the existing daemon before starting another.`;
20096
+ return `local daemon API port ${port} is already in use. If Alan desktop is open, it manages the daemon automatically. Quit Alan desktop or stop the existing daemon before starting another.`;
19583
20097
  }
19584
20098
  var boundAgentConfigPath = null;
19585
20099
  function bindConfigPath(args) {
@@ -19587,10 +20101,10 @@ function bindConfigPath(args) {
19587
20101
  return boundAgentConfigPath;
19588
20102
  }
19589
20103
  function getConfigPath() {
19590
- return process.env.AIDEN_AGENT_CONFIG_PATH ?? boundAgentConfigPath ?? resolveAgentConfigPath({ profile: "production" });
20104
+ return process.env.ALAN_AGENT_CONFIG_PATH ?? boundAgentConfigPath ?? resolveAgentConfigPath({ profile: "production" });
19591
20105
  }
19592
20106
  function getEndpointDefaultsPath() {
19593
- return process.env.AIDEN_AGENT_ENDPOINTS_PATH ?? (0, import_node_path5.join)((0, import_node_path5.dirname)(getConfigPath()), "endpoints.json");
20107
+ return process.env.ALAN_AGENT_ENDPOINTS_PATH ?? (0, import_node_path5.join)((0, import_node_path5.dirname)(getConfigPath()), "endpoints.json");
19594
20108
  }
19595
20109
  function readConfig() {
19596
20110
  const configPath = getConfigPath();
@@ -19609,7 +20123,14 @@ function readEndpointDefaults() {
19609
20123
  function writeConfig(config) {
19610
20124
  const configPath = getConfigPath();
19611
20125
  (0, import_node_fs7.mkdirSync)((0, import_node_path5.dirname)(configPath), { recursive: true, mode: 448 });
19612
- (0, import_node_fs7.writeFileSync)(configPath, JSON.stringify(config, null, 2), { mode: 384 });
20126
+ const pendingPath = `${configPath}.pending-${process.pid}-${(0, import_node_crypto.randomBytes)(6).toString("hex")}`;
20127
+ try {
20128
+ (0, import_node_fs7.writeFileSync)(pendingPath, JSON.stringify(config, null, 2), { mode: 384 });
20129
+ (0, import_node_fs7.chmodSync)(pendingPath, 384);
20130
+ (0, import_node_fs7.renameSync)(pendingPath, configPath);
20131
+ } finally {
20132
+ (0, import_node_fs7.rmSync)(pendingPath, { force: true });
20133
+ }
19613
20134
  }
19614
20135
  function removeConfig() {
19615
20136
  const configPath = getConfigPath();
@@ -19629,8 +20150,8 @@ function resolveEndpoints(args, stored = {}) {
19629
20150
  const profileApiUrl = requestedProfile === "local" ? LOCAL_API_URL : requestedProfile === "staging" ? STAGING_API_URL : PRODUCTION_API_URL;
19630
20151
  const profileWsUrl = requestedProfile === "local" ? LOCAL_WS_URL : requestedProfile === "staging" ? STAGING_WS_URL : PRODUCTION_WS_URL;
19631
20152
  const endpointDefaults = readEndpointDefaults();
19632
- const apiUrl = argValue(args, "--api-url") ?? process.env.AIDEN_API_URL ?? stored.apiUrl ?? endpointDefaults.apiUrl ?? profileApiUrl;
19633
- const wsUrl = argValue(args, "--ws-url") ?? process.env.AIDEN_WS_URL ?? stored.wsUrl ?? endpointDefaults.wsUrl ?? profileWsUrl;
20153
+ const apiUrl = argValue(args, "--api-url") ?? process.env.ALAN_API_URL ?? stored.apiUrl ?? endpointDefaults.apiUrl ?? profileApiUrl;
20154
+ const wsUrl = argValue(args, "--ws-url") ?? process.env.ALAN_WS_URL ?? stored.wsUrl ?? endpointDefaults.wsUrl ?? profileWsUrl;
19634
20155
  const endpointProfile = apiUrl === profileApiUrl && wsUrl === profileWsUrl ? requestedProfile : apiUrl === endpointDefaults.apiUrl && wsUrl === endpointDefaults.wsUrl && endpointDefaults.endpointProfile ? endpointDefaults.endpointProfile : "custom";
19635
20156
  return { apiUrl, wsUrl, endpointProfile };
19636
20157
  }
@@ -19640,9 +20161,12 @@ function isLocalEndpoint(url2) {
19640
20161
  function checkStoredEndpointConsistency(stored, endpointDefaults) {
19641
20162
  const profile = stored.endpointProfile;
19642
20163
  if (profile !== "production" && profile !== "staging") return null;
20164
+ const builtInApiUrl = profile === "production" ? PRODUCTION_API_URL : STAGING_API_URL;
20165
+ const builtInWsUrl = profile === "production" ? PRODUCTION_WS_URL : STAGING_WS_URL;
20166
+ if (stored.apiUrl === builtInApiUrl && stored.wsUrl === builtInWsUrl) return null;
19643
20167
  const defaultsMatchProfile = endpointDefaults.endpointProfile === profile;
19644
- const expectedApiUrl = (defaultsMatchProfile ? endpointDefaults.apiUrl : void 0) ?? (profile === "production" ? PRODUCTION_API_URL : STAGING_API_URL);
19645
- const expectedWsUrl = (defaultsMatchProfile ? endpointDefaults.wsUrl : void 0) ?? (profile === "production" ? PRODUCTION_WS_URL : STAGING_WS_URL);
20168
+ const expectedApiUrl = (defaultsMatchProfile ? endpointDefaults.apiUrl : void 0) ?? builtInApiUrl;
20169
+ const expectedWsUrl = (defaultsMatchProfile ? endpointDefaults.wsUrl : void 0) ?? builtInWsUrl;
19646
20170
  const issues = [];
19647
20171
  if (stored.wsUrl && stored.wsUrl !== expectedWsUrl) {
19648
20172
  issues.push(`wsUrl ${stored.wsUrl} (expected ${expectedWsUrl})`);
@@ -19658,7 +20182,7 @@ function checkStoredEndpointConsistency(stored, endpointDefaults) {
19658
20182
  };
19659
20183
  }
19660
20184
  function getLocalApiPort(args, stored) {
19661
- const raw = argValue(args, "--local-api-port") ?? process.env.AIDEN_AGENT_LOCAL_API_PORT;
20185
+ const raw = argValue(args, "--local-api-port") ?? process.env.ALAN_AGENT_LOCAL_API_PORT;
19662
20186
  if (raw) return Number.parseInt(raw, 10);
19663
20187
  const storedPort = stored.localApiPort;
19664
20188
  if (storedPort && storedPort > 0) return storedPort;
@@ -20189,17 +20713,17 @@ var RuntimePresenter = class {
20189
20713
  async function setupDaemon(args) {
20190
20714
  bindConfigPath(args);
20191
20715
  const { apiUrl, wsUrl, endpointProfile } = resolveEndpoints(args);
20192
- const teamId = argValue(args, "--team") ?? process.env.AIDEN_TEAM_ID;
20193
- const setupToken = argValue(args, "--setup-token") ?? process.env.AIDEN_RUNTIME_SETUP_TOKEN;
20194
- const token = argValue(args, "--token") ?? process.env.AIDEN_SETUP_TOKEN;
20716
+ const teamId = argValue(args, "--team") ?? process.env.ALAN_TEAM_ID;
20717
+ const setupToken = argValue(args, "--setup-token") ?? process.env.ALAN_RUNTIME_SETUP_TOKEN;
20718
+ const token = argValue(args, "--token") ?? process.env.ALAN_SETUP_TOKEN;
20195
20719
  const displayName = argValue(args, "--name") ?? (0, import_node_os6.hostname)();
20196
- const scope = argValue(args, "--scope") ?? process.env.AIDEN_RUNTIME_SCOPE ?? "team";
20720
+ const scope = argValue(args, "--scope") ?? process.env.ALAN_RUNTIME_SCOPE ?? "team";
20197
20721
  if (scope !== "team" && scope !== "user") {
20198
20722
  throw new Error("setup --scope must be either 'team' or 'user'");
20199
20723
  }
20200
20724
  if (!setupToken && (!teamId || !token)) {
20201
20725
  throw new Error(
20202
- "setup requires --setup-token <token> or --team <team-id> and --token <aiden PAT>.\nFor normal setup, copy the setup token from Aiden and run: aiden-agent setup --setup-token <token>\nFor browser authorization, run: aiden-agent login"
20726
+ "setup requires --setup-token <token> or --team <team-id> and --token <alan PAT>.\nFor normal setup, copy the setup token from Alan and run: alan-agent setup --setup-token <token>\nFor browser authorization, run: alan-agent login"
20203
20727
  );
20204
20728
  }
20205
20729
  const response = await fetch(
@@ -20241,7 +20765,7 @@ async function setupDaemon(args) {
20241
20765
  localApiToken: (0, import_node_crypto.randomBytes)(24).toString("hex"),
20242
20766
  displayName: body.runtime.displayName ?? displayName
20243
20767
  });
20244
- console.info("[aiden-agent] Runtime registered", {
20768
+ console.info("[alan-agent] Runtime registered", {
20245
20769
  runtimeId: body.runtime.id,
20246
20770
  configPath: getConfigPath()
20247
20771
  });
@@ -20266,8 +20790,8 @@ async function loginWithDeviceCode(args) {
20266
20790
  }
20267
20791
  const authorization = await start.json();
20268
20792
  const intervalMs = Math.max(0, (authorization.intervalSeconds ?? 2) * 1e3);
20269
- console.info(`[aiden-agent] Open ${authorization.verificationUri}`);
20270
- console.info(`[aiden-agent] Enter code ${authorization.userCode}`);
20793
+ console.info(`[alan-agent] Open ${authorization.verificationUri}`);
20794
+ console.info(`[alan-agent] Enter code ${authorization.userCode}`);
20271
20795
  for (let attempt = 0; attempt < maxPolls; attempt += 1) {
20272
20796
  if (attempt > 0) await sleep(intervalMs);
20273
20797
  const token = await fetch(`${apiUrl}/public/runtimes/device-authorizations/token`, {
@@ -20293,7 +20817,7 @@ async function loginWithDeviceCode(args) {
20293
20817
  localApiToken: (0, import_node_crypto.randomBytes)(24).toString("hex"),
20294
20818
  displayName: body.runtime.displayName ?? displayName
20295
20819
  });
20296
- console.info("[aiden-agent] Runtime registered", {
20820
+ console.info("[alan-agent] Runtime registered", {
20297
20821
  runtimeId: body.runtime.id,
20298
20822
  configPath: getConfigPath()
20299
20823
  });
@@ -20308,14 +20832,14 @@ async function startDaemon(args) {
20308
20832
  const endpointProfile = stored.endpointProfile ?? resolveEndpointProfile(args);
20309
20833
  const daemonSessionId = (0, import_node_crypto.randomUUID)();
20310
20834
  let heartbeatSeq = 0;
20311
- const runtimeId = argValue(args, "--runtime-id") ?? process.env.AIDEN_RUNTIME_ID ?? stored.runtimeId;
20312
- const runtimeToken = argValue(args, "--token") ?? process.env.AIDEN_RUNTIME_TOKEN ?? stored.runtimeToken;
20313
- const wsUrlOverride = argValue(args, "--ws-url") ?? process.env.AIDEN_WS_URL;
20835
+ const runtimeId = argValue(args, "--runtime-id") ?? process.env.ALAN_RUNTIME_ID ?? stored.runtimeId;
20836
+ const runtimeToken = argValue(args, "--token") ?? process.env.ALAN_RUNTIME_TOKEN ?? stored.runtimeToken;
20837
+ const wsUrlOverride = argValue(args, "--ws-url") ?? process.env.ALAN_WS_URL;
20314
20838
  const endpointMismatch = wsUrlOverride ? null : checkStoredEndpointConsistency(stored, readEndpointDefaults());
20315
20839
  let wsUrl = wsUrlOverride ?? stored.wsUrl;
20316
20840
  if (endpointMismatch && stored.wsUrl && stored.wsUrl !== endpointMismatch.expectedWsUrl) {
20317
20841
  console.warn(
20318
- "[aiden-agent] Stored config does not match its endpoint profile \u2014 connecting with the profile endpoints instead. Re-run setup to repair the stored config.",
20842
+ "[alan-agent] Stored config does not match its endpoint profile \u2014 connecting with the profile endpoints instead. Re-run setup to repair the stored config.",
20319
20843
  { configPath: getConfigPath(), detail: endpointMismatch.detail }
20320
20844
  );
20321
20845
  wsUrl = endpointMismatch.expectedWsUrl;
@@ -20329,6 +20853,8 @@ async function startDaemon(args) {
20329
20853
  }
20330
20854
  const activeAgents = /* @__PURE__ */ new Map();
20331
20855
  let disconnectedSinceMs = null;
20856
+ let lastConnectError = null;
20857
+ let lastConnectErrorCode = null;
20332
20858
  const pendingDeliveryLost = [];
20333
20859
  const currentCapabilities = () => discoverCapabilities();
20334
20860
  const currentMetadata = () => collectRuntimeMetadataWithProviderLimits();
@@ -20397,9 +20923,11 @@ async function startDaemon(args) {
20397
20923
  }, VERSION_REFRESH_INTERVAL_MS);
20398
20924
  socket.on("connect", () => {
20399
20925
  disconnectedSinceMs = null;
20926
+ lastConnectError = null;
20927
+ lastConnectErrorCode = null;
20400
20928
  setConnectedRuntimeSocket(socket);
20401
20929
  pushLog(`connected runtime=${runtimeId}`);
20402
- console.info("[aiden-agent] Daemon connected", { runtimeId, wsUrl, version: AGENT_VERSION });
20930
+ console.info("[alan-agent] Daemon connected", { runtimeId, wsUrl, version: AGENT_VERSION });
20403
20931
  flushPendingDeliveryLostEvents({
20404
20932
  socket,
20405
20933
  activeAgents,
@@ -20434,18 +20962,23 @@ async function startDaemon(args) {
20434
20962
  let lastConnectErrorLogAt = 0;
20435
20963
  socket.on("connect_error", (error) => {
20436
20964
  if (!socket.connected && disconnectedSinceMs === null) disconnectedSinceMs = Date.now();
20437
- pushLog(`connect_error ${error.message}`);
20965
+ lastConnectError = error.message;
20966
+ const errorCode = error?.data?.code;
20967
+ lastConnectErrorCode = typeof errorCode === "string" ? errorCode : null;
20968
+ pushLog(
20969
+ `connect_error ${error.message}${lastConnectErrorCode ? ` code=${lastConnectErrorCode}` : ""}`
20970
+ );
20438
20971
  const now = Date.now();
20439
20972
  if (now - lastConnectErrorLogAt < 5e3) return;
20440
20973
  lastConnectErrorLogAt = now;
20441
20974
  const wsHint = isLocalEndpoint(wsUrl) ? ` Nothing is listening at ${wsUrl}. For local dev run setup with --profile local and start the stack (WS on ws://localhost:8401).` : ` Verify wsUrl in ${getConfigPath()} and that you can reach ${wsUrl}.`;
20442
- console.warn("[aiden-agent] Daemon connection error:", `${error.message}.${wsHint}`);
20975
+ console.warn("[alan-agent] Daemon connection error:", `${error.message}.${wsHint}`);
20443
20976
  });
20444
20977
  socket.on("disconnect", (reason) => {
20445
20978
  setConnectedRuntimeSocket(null);
20446
20979
  if (disconnectedSinceMs === null) disconnectedSinceMs = Date.now();
20447
20980
  pushLog(`disconnected ${reason}`);
20448
- console.info("[aiden-agent] Daemon disconnected:", reason);
20981
+ console.info("[alan-agent] Daemon disconnected:", reason);
20449
20982
  for (const [runId, entry] of activeAgents.entries()) {
20450
20983
  if (entry.stage === "completed" || entry.stage === "failed" || entry.stage === "aborted" || entry.stage === "delivery_lost") {
20451
20984
  continue;
@@ -20548,7 +21081,7 @@ async function startDaemon(args) {
20548
21081
  agentVersion: AGENT_VERSION
20549
21082
  });
20550
21083
  pushLog(`accepted run=${payload.runId}`);
20551
- console.info("[aiden-agent] Agent run accepted", correlation);
21084
+ console.info("[alan-agent] Agent run accepted", correlation);
20552
21085
  if (!payload.worktreeInfo?.worktreePath && payload.sharedCheckout?.branchName) {
20553
21086
  const repoTargets = resolveSharedCheckoutTargets({
20554
21087
  cwd,
@@ -20578,14 +21111,14 @@ async function startDaemon(args) {
20578
21111
  };
20579
21112
  const releaseActiveRun = () => {
20580
21113
  if (!activeAgents.delete(payload.runId)) return;
20581
- console.info("[aiden-agent] Agent run finished", correlation);
21114
+ console.info("[alan-agent] Agent run finished", correlation);
20582
21115
  };
20583
21116
  if (backendKind) {
20584
21117
  if (payload.aidenMcp) {
20585
- const registration = ensureAidenMcpRegistered(backendKind, payload.aidenMcp);
21118
+ const registration = ensureAlanMcpRegistered(backendKind, payload.aidenMcp);
20586
21119
  if (registration.ok) {
20587
21120
  pushLog(`mcp-registered run=${payload.runId} url=${payload.aidenMcp.url}`);
20588
- console.info("[aiden-agent] Aiden MCP registered for run", {
21121
+ console.info("[alan-agent] Alan MCP registered for run", {
20589
21122
  ...correlation,
20590
21123
  mcpUrl: payload.aidenMcp.url,
20591
21124
  paths: registration.paths
@@ -20593,16 +21126,16 @@ async function startDaemon(args) {
20593
21126
  } else {
20594
21127
  pushLog(`mcp-registration-failed run=${payload.runId} ${registration.error}`);
20595
21128
  console.warn(
20596
- "[aiden-agent] Aiden MCP registration failed \u2014 Aiden tools may be unavailable this run",
21129
+ "[alan-agent] Alan MCP registration failed \u2014 Alan tools may be unavailable this run",
20597
21130
  { ...correlation, error: registration.error }
20598
21131
  );
20599
21132
  }
20600
21133
  } else {
20601
- const check2 = verifyAidenMcpRegistered(backendKind);
21134
+ const check2 = verifyAlanMcpRegistered(backendKind);
20602
21135
  if (!check2.ok) {
20603
21136
  pushLog(`mcp-config-missing run=${payload.runId}`);
20604
21137
  console.warn(
20605
- "[aiden-agent] Aiden MCP config missing \u2014 Aiden tools may be unavailable this run",
21138
+ "[alan-agent] Alan MCP config missing \u2014 Alan tools may be unavailable this run",
20606
21139
  { ...correlation, missing: check2.missing }
20607
21140
  );
20608
21141
  }
@@ -20668,7 +21201,7 @@ async function startDaemon(args) {
20668
21201
  }).catch((error) => {
20669
21202
  const message = error instanceof Error ? error.message : String(error);
20670
21203
  pushLog(`failed run=${payload.runId} ${message}`);
20671
- console.error("[aiden-agent] Agent run failed", {
21204
+ console.error("[alan-agent] Agent run failed", {
20672
21205
  ...correlation,
20673
21206
  error: message
20674
21207
  });
@@ -20695,7 +21228,7 @@ async function startDaemon(args) {
20695
21228
  abortActiveAgent(entry);
20696
21229
  activeAgents.delete(payload.runId);
20697
21230
  pushLog(`aborted run=${payload.runId}`);
20698
- console.info("[aiden-agent] Agent run aborted", {
21231
+ console.info("[alan-agent] Agent run aborted", {
20699
21232
  runId: payload.runId,
20700
21233
  agentVersion: AGENT_VERSION
20701
21234
  });
@@ -20801,6 +21334,8 @@ async function startDaemon(args) {
20801
21334
  staleRunCount: runnerSummary.staleRunCount,
20802
21335
  lastRunActivityAtMs: runnerSummary.lastRunActivityAtMs,
20803
21336
  disconnectedSinceMs: runnerSummary.disconnectedSinceMs,
21337
+ lastConnectError,
21338
+ lastConnectErrorCode,
20804
21339
  daemonSessionId,
20805
21340
  heartbeatSeq,
20806
21341
  endpointProfile,
@@ -20827,6 +21362,15 @@ async function startDaemon(args) {
20827
21362
  res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true }));
20828
21363
  return;
20829
21364
  }
21365
+ if (req.method === "POST" && req.url === "/reconnect") {
21366
+ pushLog("reconnect requested via local API");
21367
+ lastConnectError = null;
21368
+ lastConnectErrorCode = null;
21369
+ socket.disconnect();
21370
+ socket.connect();
21371
+ res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ ok: true }));
21372
+ return;
21373
+ }
20830
21374
  if (req.method === "POST" && req.url?.startsWith("/stop_run")) {
20831
21375
  const runId = new URL(req.url, "http://127.0.0.1").searchParams.get("runId");
20832
21376
  if (!runId) {
@@ -20881,7 +21425,7 @@ async function startDaemon(args) {
20881
21425
  clearInterval(versionRefresh);
20882
21426
  socket.disconnect();
20883
21427
  throw new Error(
20884
- `${describeOccupiedLocalDaemon(localApiPort)} The token in ${getConfigPath()} no longer matches the running daemon; quit Aiden desktop or run setup again.`
21428
+ `${describeOccupiedLocalDaemon(localApiPort)} The token in ${getConfigPath()} no longer matches the running daemon; quit Alan desktop or run setup again.`
20885
21429
  );
20886
21430
  }
20887
21431
  await new Promise((resolve3, reject) => {
@@ -20911,7 +21455,7 @@ async function startDaemon(args) {
20911
21455
  const address = localServer.address();
20912
21456
  if (address && typeof address === "object") localApiPort = address.port;
20913
21457
  pushLog(`local_api listening port=${localApiPort}`);
20914
- console.info("[aiden-agent] Local daemon API listening", { port: localApiPort });
21458
+ console.info("[alan-agent] Local daemon API listening", { port: localApiPort });
20915
21459
  resolve3();
20916
21460
  });
20917
21461
  });
@@ -20953,11 +21497,11 @@ async function stopDaemon(args) {
20953
21497
  const probe = await probeLocalDaemonEndpoint(localApiPort, localApiToken);
20954
21498
  if (probe.state === "listening_unauthorized") {
20955
21499
  throw new Error(
20956
- `Daemon is listening on port ${localApiPort} but rejected this config token. Quit Aiden desktop or rerun setup/login to refresh config.`
21500
+ `Daemon is listening on port ${localApiPort} but rejected this config token. Quit Alan desktop or rerun setup/login to refresh config.`
20957
21501
  );
20958
21502
  }
20959
21503
  if (probe.state === "absent") {
20960
- console.info("[aiden-agent] No daemon listening", { port: localApiPort });
21504
+ console.info("[alan-agent] No daemon listening", { port: localApiPort });
20961
21505
  return;
20962
21506
  }
20963
21507
  const response = await fetch(`http://127.0.0.1:${localApiPort}/shutdown`, {
@@ -20968,7 +21512,7 @@ async function stopDaemon(args) {
20968
21512
  if (!response.ok) {
20969
21513
  throw new Error(`Failed to stop daemon: HTTP ${response.status}`);
20970
21514
  }
20971
- console.info("[aiden-agent] Daemon stopped", {
21515
+ console.info("[alan-agent] Daemon stopped", {
20972
21516
  port: localApiPort,
20973
21517
  runtimeId: probe.status.runtimeId
20974
21518
  });
@@ -20980,18 +21524,18 @@ async function runDaemon(args) {
20980
21524
  const localApiToken = stored.localApiToken;
20981
21525
  const existingProbe = await probeLocalDaemonEndpoint(localApiPort, localApiToken);
20982
21526
  if (existingProbe.state === "running") {
20983
- console.info("[aiden-agent] Daemon already running", {
21527
+ console.info("[alan-agent] Daemon already running", {
20984
21528
  port: localApiPort,
20985
21529
  runtimeId: existingProbe.status.runtimeId,
20986
21530
  connected: existingProbe.status.connected,
20987
- hint: "If Aiden desktop is open, it manages the daemon automatically."
21531
+ hint: "If Alan desktop is open, it manages the daemon automatically."
20988
21532
  });
20989
21533
  return;
20990
21534
  }
20991
21535
  if (existingProbe.state === "listening_unauthorized") {
20992
- console.info("[aiden-agent] Daemon already running", {
21536
+ console.info("[alan-agent] Daemon already running", {
20993
21537
  port: localApiPort,
20994
- hint: `Aiden desktop is using a different local API token than ${getConfigPath()}. Quit the desktop app or rerun setup if you need a fresh daemon.`
21538
+ hint: `Alan desktop is using a different local API token than ${getConfigPath()}. Quit the desktop app or rerun setup if you need a fresh daemon.`
20995
21539
  });
20996
21540
  return;
20997
21541
  }
@@ -21008,11 +21552,11 @@ async function runDaemon(args) {
21008
21552
  async function rotateRuntimeToken(args) {
21009
21553
  bindConfigPath(args);
21010
21554
  const stored = readConfig();
21011
- const apiUrl = argValue(args, "--api-url") ?? process.env.AIDEN_API_URL ?? stored.apiUrl;
21012
- const runtimeId = argValue(args, "--runtime-id") ?? process.env.AIDEN_RUNTIME_ID ?? stored.runtimeId;
21013
- const token = argValue(args, "--token") ?? process.env.AIDEN_SETUP_TOKEN;
21555
+ const apiUrl = argValue(args, "--api-url") ?? process.env.ALAN_API_URL ?? stored.apiUrl;
21556
+ const runtimeId = argValue(args, "--runtime-id") ?? process.env.ALAN_RUNTIME_ID ?? stored.runtimeId;
21557
+ const token = argValue(args, "--token") ?? process.env.ALAN_SETUP_TOKEN;
21014
21558
  if (!apiUrl || !runtimeId || !token) {
21015
- throw new Error("token rotate requires configured api/runtime plus --token <aiden PAT>");
21559
+ throw new Error("token rotate requires configured api/runtime plus --token <alan PAT>");
21016
21560
  }
21017
21561
  const response = await fetch(`${apiUrl}/public/runtimes/${runtimeId}/tokens/rotate`, {
21018
21562
  method: "POST",
@@ -21023,16 +21567,16 @@ async function rotateRuntimeToken(args) {
21023
21567
  }
21024
21568
  const body = await response.json();
21025
21569
  writeConfig({ ...stored, apiUrl, runtimeId, runtimeToken: body.runtimeToken });
21026
- console.info("[aiden-agent] Runtime token rotated", { runtimeId });
21570
+ console.info("[alan-agent] Runtime token rotated", { runtimeId });
21027
21571
  }
21028
21572
  async function revokeRuntimeToken(args) {
21029
21573
  bindConfigPath(args);
21030
21574
  const stored = readConfig();
21031
- const apiUrl = argValue(args, "--api-url") ?? process.env.AIDEN_API_URL ?? stored.apiUrl;
21032
- const runtimeId = argValue(args, "--runtime-id") ?? process.env.AIDEN_RUNTIME_ID ?? stored.runtimeId;
21033
- const token = argValue(args, "--token") ?? process.env.AIDEN_SETUP_TOKEN;
21575
+ const apiUrl = argValue(args, "--api-url") ?? process.env.ALAN_API_URL ?? stored.apiUrl;
21576
+ const runtimeId = argValue(args, "--runtime-id") ?? process.env.ALAN_RUNTIME_ID ?? stored.runtimeId;
21577
+ const token = argValue(args, "--token") ?? process.env.ALAN_SETUP_TOKEN;
21034
21578
  if (!apiUrl || !runtimeId || !token) {
21035
- throw new Error("token revoke requires configured api/runtime plus --token <aiden PAT>");
21579
+ throw new Error("token revoke requires configured api/runtime plus --token <alan PAT>");
21036
21580
  }
21037
21581
  const response = await fetch(`${apiUrl}/public/runtimes/${runtimeId}/tokens/revoke`, {
21038
21582
  method: "POST",
@@ -21042,12 +21586,12 @@ async function revokeRuntimeToken(args) {
21042
21586
  throw new Error(`runtime token revoke failed: ${response.status} ${await response.text()}`);
21043
21587
  }
21044
21588
  removeConfig();
21045
- console.info("[aiden-agent] Runtime token revoked", { runtimeId });
21589
+ console.info("[alan-agent] Runtime token revoked", { runtimeId });
21046
21590
  }
21047
21591
  function logoutDaemon(args = []) {
21048
21592
  bindConfigPath(args);
21049
21593
  removeConfig();
21050
- console.info("[aiden-agent] Runtime config removed", { configPath: getConfigPath() });
21594
+ console.info("[alan-agent] Runtime config removed", { configPath: getConfigPath() });
21051
21595
  }
21052
21596
  async function printStatus(args = []) {
21053
21597
  bindConfigPath(args);
@@ -21075,7 +21619,7 @@ async function printStatus(args = []) {
21075
21619
  localDaemonRunning,
21076
21620
  hasLocalApiToken: Boolean(config.localApiToken),
21077
21621
  configPath: getConfigPath(),
21078
- note: configured ? localDaemonRunning ? "Local daemon is running. Stop it with: aiden-agent stop" : "Durable runtime config is present. Start it with: aiden-agent daemon" : "No durable runtime configured. Cloud sandbox sessions are launched by Aiden with session env vars and do not appear in this local config.",
21622
+ note: configured ? localDaemonRunning ? "Local daemon is running. Stop it with: alan-agent stop" : "Durable runtime config is present. Start it with: alan-agent daemon" : "No durable runtime configured. Cloud sandbox sessions are launched by Alan with session env vars and do not appear in this local config.",
21079
21623
  warnings
21080
21624
  },
21081
21625
  null,
@@ -21166,7 +21710,7 @@ var AgentLifecycleLogger = class _AgentLifecycleLogger {
21166
21710
  const record = omitUndefined({
21167
21711
  ts: (/* @__PURE__ */ new Date()).toISOString(),
21168
21712
  level,
21169
- component: "sandbox-agent",
21713
+ component: "agent-manager",
21170
21714
  event,
21171
21715
  ...this.context,
21172
21716
  ...normalizeFields(fields)
@@ -21176,12 +21720,12 @@ var AgentLifecycleLogger = class _AgentLifecycleLogger {
21176
21720
  };
21177
21721
  function lifecycleContextFromEnv(env) {
21178
21722
  return normalizeContext({
21179
- taskId: env.AIDEN_TASK_ID,
21180
- conversationId: env.AIDEN_SESSION_ID,
21181
- runId: env.AIDEN_RUN_ID,
21182
- sandboxId: env.AIDEN_SANDBOX_ID,
21183
- provider: env.AIDEN_SANDBOX_PROVIDER,
21184
- backendKind: env.AIDEN_BACKEND_KIND,
21723
+ taskId: env.ALAN_TASK_ID,
21724
+ conversationId: env.ALAN_SESSION_ID,
21725
+ runId: env.ALAN_RUN_ID,
21726
+ sandboxId: env.ALAN_SANDBOX_ID,
21727
+ provider: env.ALAN_SANDBOX_PROVIDER,
21728
+ backendKind: env.ALAN_BACKEND_KIND,
21185
21729
  agentVersion: AGENT_VERSION
21186
21730
  });
21187
21731
  }
@@ -21370,11 +21914,41 @@ var WebPresenter = class {
21370
21914
  }
21371
21915
  };
21372
21916
 
21917
+ // src/ws-client.ts
21918
+ var import_node_crypto2 = require("crypto");
21919
+
21920
+ // ../shared/dist/agent-liveness.js
21921
+ var AGENT_LIVENESS_PROTOCOL_VERSION = 1;
21922
+ var AGENT_HEARTBEAT_INTERVAL_MS = 15e3;
21923
+ var agentRunStateSchema = external_exports.object({
21924
+ /** True when no run is currently executing in this agent process. */
21925
+ idle: external_exports.boolean(),
21926
+ /** Run ids currently executing (cloud sandbox agent runs one at a time, but keep it a list). */
21927
+ activeRunIds: external_exports.array(external_exports.string()).default([])
21928
+ });
21929
+ var agentHeartbeatSchema = external_exports.object({
21930
+ /** Stable id for this agent OS process; changes only on a fresh agent start. */
21931
+ agentSessionId: external_exports.string().min(1),
21932
+ /** Monotonic per-process sequence number; advances on every heartbeat. */
21933
+ seq: external_exports.number().int().nonnegative(),
21934
+ /** Capability marker — presence is what distinguishes a new agent from a legacy one. */
21935
+ protocolVersion: external_exports.number().int().positive(),
21936
+ runState: agentRunStateSchema,
21937
+ agentVersion: external_exports.string().optional()
21938
+ });
21939
+ var agentProbeAckSchema = external_exports.object({
21940
+ agentSessionId: external_exports.string().min(1),
21941
+ seq: external_exports.number().int().nonnegative().optional(),
21942
+ protocolVersion: external_exports.number().int().positive().optional()
21943
+ });
21944
+
21373
21945
  // src/ws-client.ts
21374
21946
  var WSClient = class {
21375
21947
  constructor(wsUrl, sessionId, taskId, token, callbacks, agentVersion, lifecycle) {
21376
21948
  this.lifecycle = lifecycle;
21377
21949
  this.lifecycle?.info("sandbox_agent_ws_socket_create", { wsUrl });
21950
+ this.agentVersion = agentVersion ?? "";
21951
+ this.getRunState = callbacks.getRunState;
21378
21952
  this.socket = lookup(wsUrl, {
21379
21953
  query: { type: "agent", sessionId, taskId, agentVersion: agentVersion ?? "" },
21380
21954
  auth: { token },
@@ -21390,6 +21964,48 @@ var WSClient = class {
21390
21964
  this.setupListeners(callbacks);
21391
21965
  }
21392
21966
  socket;
21967
+ /** Stable id for this agent process; fences stale heartbeats server-side. */
21968
+ agentSessionId = (0, import_node_crypto2.randomUUID)();
21969
+ /** Monotonic heartbeat sequence — advances on every hello + heartbeat. */
21970
+ heartbeatSeq = 0;
21971
+ heartbeatTimer = null;
21972
+ agentVersion;
21973
+ getRunState;
21974
+ currentRunState() {
21975
+ try {
21976
+ return this.getRunState?.() ?? { idle: true, activeRunIds: [] };
21977
+ } catch {
21978
+ return { idle: true, activeRunIds: [] };
21979
+ }
21980
+ }
21981
+ buildHeartbeat() {
21982
+ this.heartbeatSeq += 1;
21983
+ return {
21984
+ agentSessionId: this.agentSessionId,
21985
+ seq: this.heartbeatSeq,
21986
+ protocolVersion: AGENT_LIVENESS_PROTOCOL_VERSION,
21987
+ runState: this.currentRunState(),
21988
+ agentVersion: this.agentVersion || void 0
21989
+ };
21990
+ }
21991
+ /** Emit `agent.hello` on (re)connect and (re)start the heartbeat interval. */
21992
+ startHeartbeat() {
21993
+ if (this.socket.connected) {
21994
+ this.socket.emit("agent.hello", this.buildHeartbeat());
21995
+ }
21996
+ if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
21997
+ this.heartbeatTimer = setInterval(() => {
21998
+ if (!this.socket.connected) return;
21999
+ this.socket.emit("agent.heartbeat", this.buildHeartbeat());
22000
+ }, AGENT_HEARTBEAT_INTERVAL_MS);
22001
+ this.heartbeatTimer.unref?.();
22002
+ }
22003
+ stopHeartbeat() {
22004
+ if (this.heartbeatTimer) {
22005
+ clearInterval(this.heartbeatTimer);
22006
+ this.heartbeatTimer = null;
22007
+ }
22008
+ }
21393
22009
  emitEvent(event) {
21394
22010
  this.socket.emit("agent_event", event);
21395
22011
  }
@@ -21421,17 +22037,27 @@ var WSClient = class {
21421
22037
  }
21422
22038
  close() {
21423
22039
  this.lifecycle?.info("sandbox_agent_ws_close_requested");
22040
+ this.stopHeartbeat();
21424
22041
  this.socket.disconnect();
21425
22042
  }
21426
22043
  setupListeners(callbacks) {
21427
22044
  this.socket.on("connect", () => {
21428
22045
  this.lifecycle?.info("sandbox_agent_ws_socket_connected", { socketId: this.socket.id });
22046
+ this.startHeartbeat();
21429
22047
  callbacks.onConnect?.();
21430
22048
  });
21431
22049
  this.socket.on("disconnect", (reason) => {
21432
22050
  this.lifecycle?.info("sandbox_agent_ws_socket_disconnected", { reason });
22051
+ this.stopHeartbeat();
21433
22052
  callbacks.onDisconnect?.(reason);
21434
22053
  });
22054
+ this.socket.on("agent.probe", (_data, ack) => {
22055
+ ack?.({
22056
+ agentSessionId: this.agentSessionId,
22057
+ seq: this.heartbeatSeq,
22058
+ protocolVersion: AGENT_LIVENESS_PROTOCOL_VERSION
22059
+ });
22060
+ });
21435
22061
  this.socket.on("connect_error", (error) => {
21436
22062
  this.lifecycle?.warn("sandbox_agent_ws_socket_connect_error", {
21437
22063
  error: error instanceof Error ? error : new Error(String(error))
@@ -21596,7 +22222,9 @@ async function runSandbox(config) {
21596
22222
  }
21597
22223
  },
21598
22224
  onConnect: () => lifecycle.info("sandbox_agent_ws_connected"),
21599
- onDisconnect: (reason) => lifecycle.info("sandbox_agent_ws_disconnected", { reason })
22225
+ onDisconnect: (reason) => lifecycle.info("sandbox_agent_ws_disconnected", { reason }),
22226
+ // Liveness heartbeat run state: a run is active while CoreAgent is executing.
22227
+ getRunState: () => currentAgent ? { idle: false, activeRunIds: currentRunId ? [currentRunId] : [] } : { idle: true, activeRunIds: [] }
21600
22228
  },
21601
22229
  AGENT_VERSION,
21602
22230
  lifecycle
@@ -21619,7 +22247,7 @@ async function runSandbox(config) {
21619
22247
  let activeContextWindow = config.contextWindow;
21620
22248
  let activeEffortLevel = config.effortLevel;
21621
22249
  let activeMode = config.mode || "agent";
21622
- let currentAidenMcp;
22250
+ let currentAlanMcp;
21623
22251
  while (!stopped) {
21624
22252
  if (currentTask?.trim()) {
21625
22253
  const agent = new CoreAgent(presenter, {
@@ -21653,8 +22281,8 @@ async function runSandbox(config) {
21653
22281
  model: activeModel,
21654
22282
  maxIterations: currentMaxIterations
21655
22283
  });
21656
- if (currentAidenMcp) {
21657
- const registration = ensureAidenMcpRegistered(activeBackendKind, currentAidenMcp);
22284
+ if (currentAlanMcp) {
22285
+ const registration = ensureAlanMcpRegistered(activeBackendKind, currentAlanMcp);
21658
22286
  if (registration.ok) {
21659
22287
  lifecycle.info("sandbox_agent_mcp_registered", {
21660
22288
  backendKind: activeBackendKind,
@@ -21666,18 +22294,18 @@ async function runSandbox(config) {
21666
22294
  error: registration.error
21667
22295
  });
21668
22296
  presenter.onLog(
21669
- `[sandbox] Aiden MCP registration failed \u2014 Aiden tools may be unavailable this run: ${registration.error}`
22297
+ `[sandbox] Alan MCP registration failed \u2014 Alan tools may be unavailable this run: ${registration.error}`
21670
22298
  );
21671
22299
  }
21672
22300
  } else {
21673
- const check2 = verifyAidenMcpRegistered(activeBackendKind);
22301
+ const check2 = verifyAlanMcpRegistered(activeBackendKind);
21674
22302
  if (!check2.ok) {
21675
22303
  lifecycle.warn("sandbox_agent_mcp_config_missing", {
21676
22304
  backendKind: activeBackendKind,
21677
22305
  missing: check2.missing
21678
22306
  });
21679
22307
  presenter.onLog(
21680
- `[sandbox] Aiden MCP config missing for ${activeBackendKind} \u2014 Aiden tools may be unavailable this run`
22308
+ `[sandbox] Alan MCP config missing for ${activeBackendKind} \u2014 Alan tools may be unavailable this run`
21681
22309
  );
21682
22310
  }
21683
22311
  }
@@ -21789,8 +22417,8 @@ async function runSandbox(config) {
21789
22417
  if (nextPayload.mode) {
21790
22418
  activeMode = nextPayload.mode;
21791
22419
  }
21792
- if (nextPayload.aidenMcp !== void 0) {
21793
- currentAidenMcp = nextPayload.aidenMcp;
22420
+ if (nextPayload.alanMcp !== void 0) {
22421
+ currentAlanMcp = nextPayload.alanMcp;
21794
22422
  }
21795
22423
  if (nextPayload.taskMeta !== void 0) {
21796
22424
  currentTaskMeta = nextPayload.taskMeta;
@@ -21839,26 +22467,26 @@ async function runSandbox(config) {
21839
22467
 
21840
22468
  // src/index.ts
21841
22469
  async function runSessionFromEnv() {
21842
- const wsUrl = process.env.AIDEN_WS_URL;
21843
- const sessionId = process.env.AIDEN_SESSION_ID;
21844
- const taskId = process.env.AIDEN_TASK_ID;
21845
- const sessionToken = process.env.AIDEN_SESSION_TOKEN;
21846
- const task = process.env.AIDEN_TASK;
21847
- const teamId = process.env.AIDEN_TEAM_ID || void 0;
21848
- const projectPath = process.env.AIDEN_PROJECT_PATH || "/home/user/workspace";
21849
- const backendKind = process.env.AIDEN_BACKEND_KIND || "claude_cli";
21850
- const agentId = process.env.AIDEN_AGENT_ID || void 0;
21851
- const agentPrompt = process.env.AIDEN_AGENT_PROMPT || void 0;
21852
- const mode = process.env.AIDEN_MODE || "agent";
21853
- const model = process.env.AIDEN_MODEL;
21854
- const contextWindow = process.env.AIDEN_CONTEXT_WINDOW || void 0;
21855
- const effortLevel = process.env.AIDEN_EFFORT_LEVEL || void 0;
21856
- const providerSessionId = process.env.AIDEN_PROVIDER_SESSION_ID || void 0;
21857
- const workflowId = process.env.AIDEN_WORKFLOW_ID || void 0;
21858
- const workflowExecutionId = process.env.AIDEN_WORKFLOW_EXECUTION_ID || void 0;
21859
- const sandboxId = process.env.AIDEN_SANDBOX_ID || void 0;
21860
- const provider = process.env.AIDEN_SANDBOX_PROVIDER || void 0;
21861
- const runId = process.env.AIDEN_RUN_ID || void 0;
22470
+ const wsUrl = process.env.ALAN_WS_URL;
22471
+ const sessionId = process.env.ALAN_SESSION_ID;
22472
+ const taskId = process.env.ALAN_TASK_ID;
22473
+ const sessionToken = process.env.ALAN_SESSION_TOKEN;
22474
+ const task = process.env.ALAN_TASK;
22475
+ const teamId = process.env.ALAN_TEAM_ID || void 0;
22476
+ const projectPath = process.env.ALAN_PROJECT_PATH || "/home/user/workspace";
22477
+ const backendKind = process.env.ALAN_BACKEND_KIND || "claude_cli";
22478
+ const agentId = process.env.ALAN_AGENT_ID || void 0;
22479
+ const agentPrompt = process.env.ALAN_AGENT_PROMPT || void 0;
22480
+ const mode = process.env.ALAN_MODE || "agent";
22481
+ const model = process.env.ALAN_MODEL;
22482
+ const contextWindow = process.env.ALAN_CONTEXT_WINDOW || void 0;
22483
+ const effortLevel = process.env.ALAN_EFFORT_LEVEL || void 0;
22484
+ const providerSessionId = process.env.ALAN_PROVIDER_SESSION_ID || void 0;
22485
+ const workflowId = process.env.ALAN_WORKFLOW_ID || void 0;
22486
+ const workflowExecutionId = process.env.ALAN_WORKFLOW_EXECUTION_ID || void 0;
22487
+ const sandboxId = process.env.ALAN_SANDBOX_ID || void 0;
22488
+ const provider = process.env.ALAN_SANDBOX_PROVIDER || void 0;
22489
+ const runId = process.env.ALAN_RUN_ID || void 0;
21862
22490
  const lifecycle = new AgentLifecycleLogger(lifecycleContextFromEnv(process.env));
21863
22491
  if (!wsUrl || !sessionId || !taskId || !sessionToken || task == null) {
21864
22492
  lifecycle.error("sandbox_agent_bootstrap_missing_env", {
@@ -21869,7 +22497,7 @@ async function runSessionFromEnv() {
21869
22497
  hasTask: task != null
21870
22498
  });
21871
22499
  throw new Error(
21872
- "run-session is an internal Aiden sandbox/session command and must be launched by Aiden with session env vars. Missing required env vars: AIDEN_WS_URL, AIDEN_SESSION_ID, AIDEN_TASK_ID, AIDEN_SESSION_TOKEN, AIDEN_TASK"
22500
+ "run-session is an internal Alan sandbox/session command and must be launched by Alan with session env vars. Missing required env vars: ALAN_WS_URL, ALAN_SESSION_ID, ALAN_TASK_ID, ALAN_SESSION_TOKEN, ALAN_TASK"
21873
22501
  );
21874
22502
  }
21875
22503
  lifecycle.info("sandbox_agent_process_start", {