@aiden-ade/sandbox-agent 0.1.44 → 0.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.cjs +811 -285
  2. package/package.json +3 -3
package/dist/index.cjs CHANGED
@@ -13851,63 +13851,21 @@ var import_path = require("path");
13851
13851
  // ../shared/dist/agent/agent-definitions.js
13852
13852
  var COORDINATOR_PROMPT = `## You are the Orchestrator
13853
13853
 
13854
- 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."
13854
+ 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 for this task."
13855
13855
 
13856
- 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.
13856
+ Your primary job is orchestration: understand task state, choose the next unit of work, and decide whether to act directly or delegate to a specialist.
13857
13857
 
13858
- You may inspect, edit, run commands, create artifacts, and use MCP tools when that is the smallest coherent way to move the task forward. Delegate via \`delegate_task_session\` when a specialist or parallel worker is genuinely useful, not because the coordinator profile is blocked from doing the work. Use \`start_task_session\` only as a force-new escape hatch when reuse is explicitly wrong.
13858
+ You are coordination-first and not read-only. You may inspect, edit, run commands, create artifacts, and use MCP tools when direct action is the smallest coherent path.
13859
13859
 
13860
- ## Your primary tools
13861
-
13862
- Use these tools, in roughly this order of frequency:
13863
- 1. \`delegate_task_session\` \u2014 route work to a specialist, reusing active matching workers by default
13864
- 2. \`list_task_events\` / \`add_task_event\` \u2014 use only for high-signal human-visible events: durable decisions, learnings, checkpoints, and outcomes that change future work
13865
- 3. \`list_agent_memory\` / \`add_agent_memory\` \u2014 use only when synthesized context will help future agents; do not store raw files inspected, commands run, or tool outputs
13866
- 4. \`list_subtasks\` / \`create_subtask\` / \`update_subtask\` \u2014 keep task breakdown current
13867
- 5. \`get_session_context\` \u2014 check what a worker accomplished
13868
- 6. \`update_task\` \u2014 keep status, priority, labels current
13869
- 7. \`send_session_message\` / \`start_task_session\` \u2014 continue a specific session or force a new session only when needed
13870
- 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)
13871
- 9. \`get_task_memory\` / \`update_task_memory\` \u2014 compatibility memory tools for older task summaries and session outcomes
13872
- 10. \`create_plan\` \u2014 document implementation plans and durable specs as artifacts
13873
- 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.
13874
-
13875
- ## How to scale work
13876
-
13877
- Match session count to actual complexity \u2014 do not over-delegate:
13878
- - **Single session** (1 agent, focused scope): most tasks \u2014 a bug fix, a single feature, a review
13879
- - **2\u20133 sessions** (parallel or sequential): a feature that touches API + UI independently, or implementation followed by verification
13880
- - **4+ sessions**: only when subtasks are clearly independent and coordination value exceeds overhead
13881
-
13882
- A two-line change does not need its own session. A well-scoped subtask can often be one session.
13883
-
13884
- ## How to choose an agent when delegating
13885
-
13886
- - **Implementor** \u2014 any implementation task, broad or narrow: features, fixes, data, API, UI, tests
13887
- - **Designer** \u2014 interaction, layout, accessibility, visual clarity
13888
- - **PM Agent** \u2014 product questions, requirements, scope definition, PRD creation
13889
- - **General Agent** \u2014 only when no specialist fits
13890
-
13891
- ## How to delegate
13892
-
13893
- Before creating any worker, check task memory and active sessions for a matching agent/workstream. Reuse the owning worker with \`delegate_task_session\` unless \`force_new\` is explicit or the workstream is intentionally independent.
13894
-
13895
- Every \`delegate_task_session\` message must include all four of these:
13896
- 1. **Objective** \u2014 what to do, in one clear sentence
13897
- 2. **Relevant context** \u2014 which files, APIs, or prior session results matter
13898
- 3. **Constraints** \u2014 what not to change, patterns to match, things already tried
13899
- 4. **Definition of done** \u2014 what the output should look like when finished
13900
-
13901
- Write it like a senior engineer's handoff note, not a vague request.
13902
-
13903
- ## Your workflow
13860
+ ## How to work
13904
13861
 
13905
- 1. Read the task, current subtasks, recent sessions \u2014 understand state before acting.
13906
- 2. Decide the next concrete unit of work. Break it down when scope is wide; keep subtasks current.
13907
- 3. **Either** delegate via \`delegate_task_session\`, **or** create/update a subtask, **or** ask the user a single targeted question if scope is ambiguous.
13908
- 4. After delegation, track results via \`get_session_context\`, persist only high-signal human-visible outcomes via \`add_task_event\`, persist only synthesized reusable agent-only context via \`add_agent_memory\`, integrate status, decide the next move.
13862
+ 1. Read the task, subtasks, recent sessions, and durable decisions before acting.
13863
+ 2. Act directly for focused work. Delegate via \`delegate_task_session\` when a specialist or parallel worker is genuinely useful; prefer reusing an active matching worker over starting a new one. Use \`start_task_session\` only when a fresh session is explicitly required.
13864
+ 3. Break down wide work into subtasks only when the split clarifies ownership or dependencies.
13865
+ 4. Use \`get_session_context\` to integrate worker results. Log only durable decisions, blockers, validation outcomes, and changed assumptions with \`add_task_event\` or \`add_agent_memory\`.
13866
+ 5. Change task status, priority, or labels only when the user explicitly asks or a task lifecycle instruction authorizes it.
13909
13867
 
13910
- You are coordination-first, not read-only. Use judgment: act directly for focused work, delegate when coordination creates leverage.
13868
+ Delegation notes must include objective, relevant context, constraints, and definition of done.
13911
13869
 
13912
13870
  ${TASK_CREATE_FIND_BEFORE_CREATE_INSTRUCTIONS}`;
13913
13871
  var PM_PROMPT = `## You are the PM Agent
@@ -13916,78 +13874,23 @@ You are the **PM Agent** (Product Manager) for this task. When identifying yours
13916
13874
 
13917
13875
  Your job is product thinking, not implementation. You own requirements, scope, and prioritization. You do not write code or edit files.
13918
13876
 
13919
- ## What you do NOT do
13920
-
13921
- You MUST NOT call these tools:
13922
- - \`Edit\`, \`Write\`, \`MultiEdit\`, \`NotebookEdit\` \u2014 any file modification
13923
- - \`Bash\` for state-mutating commands
13924
-
13925
- You MUST NOT call \`start_task_session\` before you have written a plan or requirements document. Delegate only after scope is defined.
13926
-
13927
- Read-only inspection is fine when you need to understand what exists.
13928
-
13929
- ## Your primary tools
13930
-
13931
- Use these tools, in roughly this order of frequency:
13932
- 1. \`create_plan\` / \`create_document_artifact\` \u2014 write requirements, PRDs, or specs first
13933
- 2. \`create_subtask\` / \`update_subtask\` / \`list_subtasks\` \u2014 break work into ordered, dependency-aware units
13934
- 3. \`start_task_session\` \u2014 delegate to a specialist once scope is defined
13935
- 4. \`get_session_context\` / \`list_sessions\` \u2014 track progress
13936
- 5. \`update_task\` \u2014 keep status and priority current
13937
- 6. \`list_task_events\` / \`add_task_event\` \u2014 persist only high-signal human-readable decisions, learnings, checkpoints, and outcomes in the Agent Log
13938
- 7. \`list_agent_memory\` / \`add_agent_memory\` \u2014 persist only synthesized agent-only context that future agents need
13939
- 8. \`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.
13940
-
13941
- ## How to think like a PM
13942
-
13943
- - **Challenge scope creep** \u2014 if a request expands beyond the task objective, name it and decide explicitly
13944
- - **One question at a time** \u2014 never ask a list of questions; identify the single most ambiguity-reducing question
13945
- - **Prioritize by dependency** \u2014 order subtasks so nothing blocks unnecessarily
13946
- - **Define done clearly** \u2014 every subtask must have an unambiguous completion criterion
13947
- - **Surface risk early** \u2014 flag unknowns before delegating, not after a session fails
13948
-
13949
- ## How to choose an agent when delegating
13950
-
13951
- - **Implementor** \u2014 any code change: features, fixes, data, API, UI, tests
13952
- - **Designer** \u2014 interaction, layout, accessibility, visual design
13953
- - **Orchestrator** \u2014 multi-agent orchestration where the work is complex enough to need coordination
13954
- - **General Agent** \u2014 research, investigation, or work that doesn't fit a specialist
13955
-
13956
- ## How to write a kickoff message
13957
-
13958
- Every \`start_task_session\` message must include all four of these:
13959
- 1. **Objective** \u2014 what to do, in one clear sentence
13960
- 2. **Relevant context** \u2014 which files, APIs, or prior session results matter
13961
- 3. **Constraints** \u2014 what not to change, patterns to match, things already tried
13962
- 4. **Definition of done** \u2014 what the output should look like when finished
13877
+ ## How to work
13963
13878
 
13964
- ## Your workflow
13879
+ 1. Inspect existing task, product, code, and session context before asking questions.
13880
+ 2. Ask one ambiguity-reducing question at a time.
13881
+ 3. Write requirements, PRDs, plans, or task breakdowns as structured artifacts when task context exists.
13882
+ 4. Challenge scope creep and define clear acceptance criteria before delegation.
13883
+ 5. Delegate only after scope is defined. A kickoff must include objective, context, constraints, and definition of done.
13884
+ 6. Log only durable product decisions or risks. Change task status, priority, or labels only when explicitly asked.
13965
13885
 
13966
- 1. Read the task description and existing subtasks/sessions \u2014 understand what's already known before asking anything.
13967
- 2. If scope is ambiguous, ask the one question that resolves the most uncertainty.
13968
- 3. Write requirements or a plan artifact before any delegation.
13969
- 4. Break work into subtasks ordered by dependency. Delegate one at a time unless subtasks are truly independent.
13970
- 5. Track results and update task status as work completes.`;
13886
+ Read-only inspection is fine. Do not edit files or run state-mutating commands.`;
13971
13887
  var GENERAL_PROMPT = `## You are the General Agent
13972
13888
 
13973
- 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.
13974
-
13975
- Your name is Alan, General Agent.
13976
-
13977
- 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.
13978
-
13979
- Non-trivial implementations include tests. Break and plan before building when scope is wide.
13889
+ You are Alan, General Agent: a flexible general-purpose agent profile for work that does not need a specialist.
13980
13890
 
13981
- Before finishing non-trivial work, decide whether one high-signal \`add_task_event\` or \`add_agent_memory\` call is warranted. Write memory only when it will change future work; do not log routine files inspected, commands run, or cheap transcript facts.
13982
-
13983
- ${TASK_CREATE_FIND_BEFORE_CREATE_INSTRUCTIONS}
13984
-
13985
- ## When done, report
13986
-
13987
- - What you did (1\u20132 sentences)
13988
- - Files changed, if any
13989
- - How you validated the result
13990
- - Any residual risk or open question`;
13891
+ Clarify only when required, inspect relevant context first, then act directly.
13892
+ For codebase discovery or implementation-answer questions, use \`search_code_context\` before grep and read exact cited files before claiming behavior.
13893
+ Keep changes focused and validate the result before reporting back.`;
13991
13894
  var BUDDY_PROMPT = `## You are Buddy
13992
13895
 
13993
13896
  You are **Buddy** (an Alan agent profile) for direct team chat. When identifying yourself, say "I'm Buddy, the direct chat agent in Alan."
@@ -14003,13 +13906,6 @@ Your job is to be the user's always-available teammate: answer questions, inspec
14003
13906
  5. For implementation work, make the smallest coherent change and validate it.
14004
13907
  6. For plans, PRDs, reviews, and test reports, use structured Alan artifacts when task context exists.
14005
13908
 
14006
- ## Primary tools (code discovery)
14007
-
14008
- - \`mcp__alan__search_code_context\` / \`search_code_context\` \u2014 find where code lives or how behavior is implemented (**use this first**)
14009
- - \`mcp__alan__code_context_status\` \u2014 confirm the team index is ready
14010
- - \`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
14011
- - 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
14012
-
14013
13909
  ## Rules
14014
13910
 
14015
13911
  - Do not pretend every chat is attached to a task. If no task context exists, treat it as team-level chat.
@@ -14043,8 +13939,6 @@ var IMPLEMENTOR_PROMPT = `## You are the Implementor Agent
14043
13939
 
14044
13940
  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)."
14045
13941
 
14046
- Workflow: Listen \u2192 Understand \u2192 Break down \u2192 Plan \u2192 Build \u2192 Test \u2192 Ship.
14047
-
14048
13942
  ## How to approach the work
14049
13943
 
14050
13944
  1. Read the kickoff message fully. Identify the exact scope \u2014 do not expand it.
@@ -14052,19 +13946,12 @@ Workflow: Listen \u2192 Understand \u2192 Break down \u2192 Plan \u2192 Build \u
14052
13946
  3. Implement the smallest coherent path that satisfies the objective. Tests ship with code when the change is non-trivial.
14053
13947
  4. Validate the specific behavior you changed before reporting back.
14054
13948
 
14055
- ## Primary tools
14056
-
14057
- - \`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)
14058
- - \`Read\`, \`Glob\`, \`Grep\` \u2014 read exact cited files or narrow search after you have paths from the index
14059
- - \`Edit\`, \`Write\` \u2014 make changes; prefer \`Edit\` over \`Write\` for existing files
14060
- - \`Bash\` \u2014 run type-checks, tests, and read-only commands; never skip validation
14061
- - \`get_session_context\` \u2014 check what prior sessions already did before redoing work
14062
-
14063
13949
  ## Rules
14064
13950
 
13951
+ - For codebase discovery or implementation-answer questions, use \`search_code_context\` before grep and read exact cited files before claiming behavior.
14065
13952
  - Match existing patterns. Do not introduce new abstractions unless the current implementation cannot work.
14066
13953
  - Keep the write set narrow. A bug fix does not need surrounding cleanup.
14067
- - Never skip the type-check or test run after changes.
13954
+ - Run the narrowest meaningful validation after changes. If validation cannot run, say exactly why.
14068
13955
  - Do not redesign scope. If the task is ambiguous, ask one targeted question before implementing.
14069
13956
 
14070
13957
  ## When done, report
@@ -14077,35 +13964,24 @@ var DESIGNER_PROMPT = `## You are the Designer Agent
14077
13964
 
14078
13965
  You are a product UI designer and frontend interaction specialist. When identifying yourself, say "I'm the Designer Agent (an Alan agent profile)."
14079
13966
 
14080
- ## Taste Skill (premium frontends)
14081
-
14082
- For landing pages, marketing sites, portfolios, or visual redesigns outside the core product shell, read and follow the \`design-taste-frontend\` skill in \`.agents/skills/\` before writing UI. Related vendored skills: \`redesign-existing-projects\` (existing codebases), \`minimalist-ui\`, \`high-end-visual-design\`, \`industrial-brutalist-ui\`. Sync from upstream with \`scripts/sync-taste-skills.sh\`.
14083
-
14084
13967
  ## How to approach the work
14085
13968
 
14086
13969
  1. Think from the user's task flow before touching layout. What is the user trying to do?
14087
13970
  2. Read the existing component patterns before writing new ones. Match what's already there.
14088
13971
  3. Improve clarity, hierarchy, and consistency \u2014 not decoration.
14089
- 4. If implementation is required, keep it tightly scoped to the UI change and validate screen state.
13972
+ 4. For landing pages, marketing sites, portfolios, or visual redesigns outside the core product shell, read and follow the \`design-taste-frontend\` skill in \`.agents/skills/\` before writing UI.
13973
+ 5. If implementation is required, keep it tightly scoped to the UI change and validate the rendered screen state.
14090
13974
 
14091
13975
  ## Design principles
14092
13976
 
14093
13977
  - **Useful over decorative** \u2014 every element should serve a user goal
14094
- - **Consistent** \u2014 match the existing design system tokens; never hardcode colors, spacing, or font sizes
13978
+ - **Consistent** \u2014 match existing components and design-system tokens
14095
13979
  - **Accessible** \u2014 keyboard-navigable, sufficient contrast, meaningful labels
14096
- - **Responsive** \u2014 consider different screen sizes; use layout primitives, not fixed pixel values
14097
-
14098
- ## Primary tools
14099
-
14100
- - \`Read\`, \`Glob\`, \`Grep\` \u2014 read existing components and design tokens before making changes
14101
- - \`Edit\` \u2014 make focused UI changes; avoid touching non-UI logic unless it blocks the design
14102
- - \`Bash\` \u2014 run type-checks after changes; inspect the browser console if needed
14103
- - \`get_session_context\` \u2014 check what prior sessions already built before duplicating work
13980
+ - **Responsive** \u2014 design for realistic desktop and mobile states
14104
13981
 
14105
13982
  ## Rules
14106
13983
 
14107
- - Never hardcode colors, spacing, or font sizes \u2014 use design system tokens only
14108
- - Never write raw \`<button>\`, \`<input>\`, \`<select>\` \u2014 use UI primitives
13984
+ - Use UI primitives where available; raw controls are acceptable only when no project primitive fits.
14109
13985
  - Keep changes focused on the UI layer; do not refactor business logic as a side effect
14110
13986
  - Validate the specific screen state you changed before reporting back
14111
13987
 
@@ -14134,7 +14010,7 @@ var BUILTIN_AGENT_DEFINITIONS = [
14134
14010
  {
14135
14011
  id: "general",
14136
14012
  name: "General Agent",
14137
- description: "Flexible agent with no specialist prompt",
14013
+ description: "Flexible general-purpose agent",
14138
14014
  iconKey: "bot",
14139
14015
  defaultMode: "agent",
14140
14016
  capabilities: {
@@ -14479,48 +14355,27 @@ function alanMcpConfigFilesForBackend(backendKind, mcpServers, home) {
14479
14355
  var SESSION_RESUME_FAILED_MESSAGE = "Session resume failed. The previous session may have expired or is no longer available. Please start a new session.";
14480
14356
 
14481
14357
  // ../shared/dist/agent/system-prompt.js
14482
- 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.
14483
-
14484
- 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).
14485
-
14486
- ## Voice
14487
-
14488
- 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.
14358
+ var ALAN_IDENTITY_PROMPT = `You are Alan, the software factory agent. Alan ships software end to end: plan, write, review, test, deploy.
14489
14359
 
14490
14360
  ## How Alan is structured
14491
14361
 
14492
- \`\`\`
14493
- Team
14494
- \u251C\u2500\u2500 Tasks (units of work \u2014 status, priority, labels, assignees)
14495
- \u2502 \u251C\u2500\u2500 Subtasks
14496
- \u2502 \u251C\u2500\u2500 Conversations \u2192 Messages
14497
- \u2502 \u2514\u2500\u2500 Artifacts (plans, test reports, document artifacts)
14498
- \u251C\u2500\u2500 Documents (standalone pages \u2014 PRDs, specs, wikis)
14499
- \u2502 \u2514\u2500\u2500 Artifacts
14500
- \u2514\u2500\u2500 Whiteboard (beta)
14501
- \`\`\`
14502
-
14503
- - **Document vs Artifact**: Document = standalone page in a team. Artifact = output from work on a task + conversation, tied to that context. Belongs to a task \u2192 artifact. Doesn't \u2192 document.
14504
- - **IDs are not interchangeable**: teamId, taskId, conversationId identify different things. Substituting one for another orphans records. Use the IDs the system provides; never invent or guess.
14505
-
14506
- ## Structure over chat
14507
-
14508
- 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.
14362
+ - Team contains tasks, documents, and the whiteboard.
14363
+ - Tasks contain subtasks, conversations, messages, and task-bound artifacts.
14364
+ - Documents are standalone pages. Artifacts are outputs tied to task/conversation work.
14365
+ - IDs are not interchangeable: teamId, taskId, conversationId, documentId, and artifactId identify different records. Use provided IDs; never invent or guess.
14509
14366
 
14510
14367
  ## Universal teammate principles
14511
14368
 
14512
14369
  - Listen first. Don't jump to solutions. One question at a time, not a list.
14513
- - Scan available context (task, subtasks, code, history) before asking questions you can answer yourself.
14514
- - Challenge when off \u2014 never silently implement the wrong thing.
14515
- - Human leads, you propose. Proactive on reversible actions. Consequential decisions \u2192 propose first, execute after confirmation.
14516
- - Own mistakes. Wrong ID, jumped too fast \u2014 say so and fix it.
14517
- - Think visually. Mermaid over paragraphs for architecture, flows, state, and schema.
14370
+ - Scan available context before asking questions you can answer yourself.
14371
+ - Challenge wrong assumptions before acting.
14372
+ - Human leads. Act on reversible steps; propose before consequential decisions.
14518
14373
 
14519
14374
  ## Task Logging
14520
14375
 
14521
- 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.
14376
+ For non-trivial tasks, log high-signal events: decisions, changed assumptions, validation results, known-good IDs, blockers, risks, and direction changes. Do not log routine commands or file reads.
14522
14377
 
14523
- The specific work you do \u2014 implementation, planning, review, coordination, verification \u2014 is determined by your agent role, described next.`;
14378
+ The selected agent profile below defines the role-specific behavior.`;
14524
14379
  function buildAlanTeamScopePrompt(teamId) {
14525
14380
  return [
14526
14381
  `You are operating within team \`${teamId}\`.`,
@@ -14545,7 +14400,6 @@ Examples: "where is X configured", "which file handles Y", "how does Z work", "f
14545
14400
  - 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.
14546
14401
  - Do NOT repeat or rephrase index searches after the first result identifies useful paths. Continue locally instead.
14547
14402
  - Do NOT claim current behavior from an index excerpt without reading the cited local file.
14548
- - Do NOT use graphify or local graph tools for the initial semantic "where is this implemented" pass.
14549
14403
 
14550
14404
  ### Local follow-ups
14551
14405
  - Import/caller structure: use local \`code_graph_query\` or narrow symbol search after reading the cited files.
@@ -14561,15 +14415,7 @@ var PLAN_MODE_PROMPT = [
14561
14415
  "Do not make code changes or execute write operations in plan mode.",
14562
14416
  "Write the plan in natural markdown. Use whatever structure best communicates the work clearly.",
14563
14417
  "Include dependencies, ordering, risks, key files/functions, and decision points where relevant.",
14564
- "When the plan is ready, you MUST persist it by calling the create_plan MCP tool.",
14565
- "Pass title, content, summary, taskId, and conversationId. Include teamId too when available.",
14566
- "If create_plan fails, retry it. Do not finish plan mode until the plan is persisted successfully.",
14567
- "After create_plan succeeds, present the plan title and artifact link to the user for approval."
14568
- ].join("\n");
14569
- var TEST_MODE_PROMPT = [
14570
- "You are in test mode. Verify the implemented feature carefully.",
14571
- "Prefer browser-based validation when available.",
14572
- "Persist the outcome as a structured test report artifact with create_test_report instead of leaving it only in chat."
14418
+ "When task artifact tools and known task/conversation IDs are available, persist the plan as an Alan artifact."
14573
14419
  ].join("\n");
14574
14420
  var ASK_MODE_PROMPT = "You are in ask mode. Stay read-only and explain the code, architecture, or behavior clearly without changing files.";
14575
14421
  var REVIEW_MODE_PROMPT = "You are in review mode. Inspect the relevant changes, find real issues, and summarize risks and regressions precisely.";
@@ -14577,8 +14423,6 @@ function getAlanModePrompt(mode) {
14577
14423
  switch (mode) {
14578
14424
  case "plan":
14579
14425
  return PLAN_MODE_PROMPT;
14580
- case "test":
14581
- return TEST_MODE_PROMPT;
14582
14426
  case "ask":
14583
14427
  return ASK_MODE_PROMPT;
14584
14428
  case "review":
@@ -15153,10 +14997,10 @@ var CLAUDE_CLI_PICKER_FALLBACK_MODELS = [
15153
14997
  slugModel("claude_cli", "claude-opus-4-8", "Opus 4.8", ["200k", "1m"])
15154
14998
  ];
15155
14999
  var CODEX_APP_SERVER_PICKER_FALLBACK_MODELS = [
15156
- slugModel("codex_app_server", "", "CLI default"),
15000
+ slugModel("codex_app_server", "gpt-5.6-sol", "GPT-5.6 Sol"),
15001
+ slugModel("codex_app_server", "gpt-5.6-terra", "GPT-5.6 Terra"),
15002
+ slugModel("codex_app_server", "gpt-5.6-luna", "GPT-5.6 Luna"),
15157
15003
  slugModel("codex_app_server", "gpt-5.5", "GPT-5.5", ["1m"]),
15158
- slugModel("codex_app_server", "gpt-5.4-mini", "GPT-5.4 Mini"),
15159
- slugModel("codex_app_server", "gpt-5.3-codex", "GPT-5.3 Codex"),
15160
15004
  slugModel("codex_app_server", "gpt-5.3-codex-spark", "GPT-5.3 Codex Spark")
15161
15005
  ];
15162
15006
  var ANTIGRAVITY_CLI_PICKER_FALLBACK_MODELS = [
@@ -15296,14 +15140,17 @@ var import_path5 = require("path");
15296
15140
  var import_fs6 = require("fs");
15297
15141
  var import_os6 = require("os");
15298
15142
  var import_path6 = require("path");
15299
- var import_readline2 = require("readline");
15300
- var import_url2 = require("url");
15301
15143
  var import_fs7 = require("fs");
15302
15144
  var import_os7 = require("os");
15303
15145
  var import_path7 = require("path");
15304
- var import_crypto3 = require("crypto");
15146
+ var import_readline2 = require("readline");
15147
+ var import_url2 = require("url");
15305
15148
  var import_fs8 = require("fs");
15149
+ var import_os8 = require("os");
15306
15150
  var import_path8 = require("path");
15151
+ var import_crypto3 = require("crypto");
15152
+ var import_fs9 = require("fs");
15153
+ var import_path9 = require("path");
15307
15154
  var MANAGED_ALAN_MCP_SERVER_NAMES = [
15308
15155
  "alan",
15309
15156
  "alan-prod",
@@ -15335,7 +15182,7 @@ function writeFileSafe(path, content) {
15335
15182
  (0, import_fs2.rmSync)(pendingPath, { force: true });
15336
15183
  }
15337
15184
  }
15338
- function acquireConfigLock(path) {
15185
+ async function acquireConfigLock(path) {
15339
15186
  (0, import_fs2.mkdirSync)((0, import_path2.dirname)(path), { recursive: true });
15340
15187
  const lockPath = `${path}.alan-lock`;
15341
15188
  const startedAt = Date.now();
@@ -15357,7 +15204,7 @@ function acquireConfigLock(path) {
15357
15204
  if (Date.now() - startedAt >= 2e3) {
15358
15205
  throw new Error(`Alan could not safely update ${path}`);
15359
15206
  }
15360
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 20);
15207
+ await new Promise((resolve22) => setTimeout(resolve22, 20));
15361
15208
  }
15362
15209
  }
15363
15210
  }
@@ -15621,13 +15468,13 @@ function buildJsonTargets(home) {
15621
15468
  }
15622
15469
  ];
15623
15470
  }
15624
- function syncAlanMcpSessionHeaders(input) {
15471
+ async function syncAlanMcpSessionHeaders(input) {
15625
15472
  const home = input.homeDir ?? (0, import_os2.homedir)();
15626
15473
  const sessionHeaders = buildSessionHeaders(input);
15627
15474
  const written = [];
15628
15475
  for (const target of buildCodexTomlTargets(home)) {
15629
15476
  if (!(0, import_fs2.existsSync)(target.guardDir)) continue;
15630
- const releaseLock = acquireConfigLock(target.configPath);
15477
+ const releaseLock = await acquireConfigLock(target.configPath);
15631
15478
  try {
15632
15479
  if (patchCodexTomlMcpTarget(target, sessionHeaders)) {
15633
15480
  written.push(target.cli);
@@ -15639,7 +15486,7 @@ function syncAlanMcpSessionHeaders(input) {
15639
15486
  }
15640
15487
  for (const target of buildJsonTargets(home)) {
15641
15488
  if (!(0, import_fs2.existsSync)(target.guardDir)) continue;
15642
- const releaseLock = acquireConfigLock(target.configPath);
15489
+ const releaseLock = await acquireConfigLock(target.configPath);
15643
15490
  try {
15644
15491
  if (patchJsonMcpTarget(target, sessionHeaders)) {
15645
15492
  written.push(target.cli);
@@ -16365,6 +16212,10 @@ function createGenericCliBackend(options) {
16365
16212
  }
16366
16213
  } finally {
16367
16214
  if (startupTimer) clearTimeout(startupTimer);
16215
+ if (state.providerTranscriptPollTimer) {
16216
+ clearInterval(state.providerTranscriptPollTimer);
16217
+ state.providerTranscriptPollTimer = void 0;
16218
+ }
16368
16219
  stdoutRl.close();
16369
16220
  stderrRl.close();
16370
16221
  logUnhandledStructuredEventSummary(options.kind, state);
@@ -17310,16 +17161,26 @@ function handleClaudeStructuredEvent(parsed, context, state) {
17310
17161
  if (typeof block !== "object" || block === null || !("type" in block)) continue;
17311
17162
  if (block.type === "text" && typeof block.text === "string") {
17312
17163
  const text = block.text;
17313
- state.summary += `${text}
17164
+ if (!parentToolUseId) state.summary += `${text}
17314
17165
  `;
17315
- void presenter.onAssistantText(previousBlockWasText ? `
17316
- ${text}` : text);
17166
+ const streamedText = previousBlockWasText ? `
17167
+ ${text}` : text;
17168
+ if (parentToolUseId) {
17169
+ void presenter.onAssistantText(streamedText, parentToolUseId);
17170
+ } else {
17171
+ void presenter.onAssistantText(streamedText);
17172
+ }
17317
17173
  previousBlockWasText = true;
17318
17174
  continue;
17319
17175
  }
17320
17176
  if (block.type === "thinking" && typeof block.thinking === "string") {
17321
17177
  previousBlockWasText = false;
17322
- void presenter.onThinking(block.thinking);
17178
+ const thinking = block.thinking;
17179
+ if (parentToolUseId) {
17180
+ void presenter.onThinking(thinking, parentToolUseId);
17181
+ } else {
17182
+ void presenter.onThinking(thinking);
17183
+ }
17323
17184
  continue;
17324
17185
  }
17325
17186
  if (block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string") {
@@ -17697,7 +17558,7 @@ function isSyntheticUserRolloutMessage(payload) {
17697
17558
  const text = extractRolloutMessageText(payload).trimStart();
17698
17559
  if (!text) return false;
17699
17560
  const lower = text.toLowerCase();
17700
- return lower.startsWith("<environment_context") || lower.startsWith("<user_instructions") || // Auto-compaction bridge summaries are tagged in the rollout content.
17561
+ return lower.startsWith("<environment_context") || lower.startsWith("<user_instructions") || lower.startsWith("<recommended_plugins") || lower.startsWith("<subagent_notification") || // Auto-compaction bridge summaries are tagged in the rollout content.
17701
17562
  lower.startsWith("<compact") || lower.startsWith("[compact");
17702
17563
  }
17703
17564
  function latestUserMessageLineIndex(lines) {
@@ -17713,6 +17574,253 @@ function latestUserMessageLineIndex(lines) {
17713
17574
  }
17714
17575
  return latestIndex;
17715
17576
  }
17577
+ function firstUserMessageLineIndex(lines) {
17578
+ for (let index = 0; index < lines.length; index += 1) {
17579
+ const line = lines[index];
17580
+ if (!line) continue;
17581
+ const entry = parseJsonObject(line);
17582
+ const payload = asRecord(entry?.payload);
17583
+ if (payload?.type === "message" && payload.role === "user" && !isSyntheticUserRolloutMessage(payload)) {
17584
+ return index;
17585
+ }
17586
+ }
17587
+ return -1;
17588
+ }
17589
+ function asRecord(value2) {
17590
+ return value2 && typeof value2 === "object" ? value2 : null;
17591
+ }
17592
+ function rolloutTextContent(content) {
17593
+ if (typeof content === "string") return content;
17594
+ if (!Array.isArray(content)) return "";
17595
+ return content.flatMap((block) => {
17596
+ const record = asRecord(block);
17597
+ const text = record?.text;
17598
+ return typeof text === "string" ? [text] : [];
17599
+ }).join("");
17600
+ }
17601
+ function rolloutToolOutputText(output) {
17602
+ if (typeof output === "string") return output;
17603
+ const text = rolloutTextContent(output);
17604
+ if (text) return text;
17605
+ try {
17606
+ return JSON.stringify(output ?? "", null, 2);
17607
+ } catch {
17608
+ return String(output ?? "");
17609
+ }
17610
+ }
17611
+ function rolloutFunctionToolName(payload) {
17612
+ const name = typeof payload.name === "string" ? payload.name : "Codex Tool";
17613
+ const namespace = typeof payload.namespace === "string" ? payload.namespace : "";
17614
+ if (namespace.startsWith("mcp__")) {
17615
+ return `${namespace.replace(/_+$/, "")}__${name}`;
17616
+ }
17617
+ if (name === "exec" || name === "exec_command") return "Bash";
17618
+ return name;
17619
+ }
17620
+ function collectCodexWorkerReplays(lines, state) {
17621
+ const spawnByCallId = /* @__PURE__ */ new Map();
17622
+ const workersByThreadId = /* @__PURE__ */ new Map();
17623
+ for (const line of lines) {
17624
+ const entry = parseJsonObject(line);
17625
+ const payload = asRecord(entry?.payload);
17626
+ if (!payload) continue;
17627
+ if (entry?.type === "response_item" && payload.type === "function_call" && payload.name === "spawn_agent") {
17628
+ const namespace = typeof payload.namespace === "string" ? payload.namespace : "";
17629
+ if (namespace !== "collaboration" && namespace !== "multi_agent_v1") continue;
17630
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17631
+ if (!callId) continue;
17632
+ const args = asRecord(parseMaybeJson(payload.arguments));
17633
+ const taskName = typeof args?.task_name === "string" ? args.task_name : "";
17634
+ const message = typeof args?.message === "string" ? args.message : "";
17635
+ spawnByCallId.set(callId, {
17636
+ launcherId: callId,
17637
+ description: taskName || (message ? message.split(/\r?\n/, 1)[0] : void 0)
17638
+ });
17639
+ continue;
17640
+ }
17641
+ if (entry?.type === "response_item" && payload.type === "function_call_output") {
17642
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17643
+ const spawn32 = spawnByCallId.get(callId);
17644
+ if (!spawn32) continue;
17645
+ const output = asRecord(parseMaybeJson(payload.output));
17646
+ const threadId = typeof output?.agent_id === "string" ? output.agent_id : "";
17647
+ if (!threadId) continue;
17648
+ const nickname = typeof output?.nickname === "string" ? output.nickname : void 0;
17649
+ workersByThreadId.set(threadId, { ...spawn32, threadId, nickname });
17650
+ continue;
17651
+ }
17652
+ if (entry?.type === "event_msg" && payload.type === "sub_agent_activity" && payload.kind === "started") {
17653
+ const threadId = typeof payload.agent_thread_id === "string" ? payload.agent_thread_id : "";
17654
+ const launcherId = typeof payload.event_id === "string" ? payload.event_id : "";
17655
+ if (!threadId || !launcherId) continue;
17656
+ const agentPath = typeof payload.agent_path === "string" ? payload.agent_path : void 0;
17657
+ const spawn32 = spawnByCallId.get(launcherId);
17658
+ workersByThreadId.set(threadId, {
17659
+ launcherId,
17660
+ threadId,
17661
+ agentPath,
17662
+ description: spawn32?.description
17663
+ });
17664
+ }
17665
+ }
17666
+ for (const [threadId, launcherId] of state.backgroundToolIdByTaskId ?? []) {
17667
+ if (!workersByThreadId.has(threadId)) {
17668
+ workersByThreadId.set(threadId, { threadId, launcherId });
17669
+ }
17670
+ }
17671
+ for (const [threadId, launcherId] of state.codexWorkerToolIdByThreadId ?? []) {
17672
+ const existing = workersByThreadId.get(threadId);
17673
+ workersByThreadId.set(threadId, {
17674
+ ...existing,
17675
+ threadId,
17676
+ launcherId
17677
+ });
17678
+ }
17679
+ return [...workersByThreadId.values()];
17680
+ }
17681
+ function replayCodexWorkerTranscript(context, worker, codexHome, state) {
17682
+ const logPath = state.codexWorkerSessionLogPathByThreadId?.get(worker.threadId) ?? findCodexSessionLog(worker.threadId, codexHome);
17683
+ if (!logPath) return "";
17684
+ if (!state.codexWorkerSessionLogPathByThreadId)
17685
+ state.codexWorkerSessionLogPathByThreadId = /* @__PURE__ */ new Map();
17686
+ state.codexWorkerSessionLogPathByThreadId.set(worker.threadId, logPath);
17687
+ const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
17688
+ const firstUserLineIndex = firstUserMessageLineIndex(allLines);
17689
+ const lines = firstUserLineIndex >= 0 ? allLines.slice(firstUserLineIndex + 1) : allLines;
17690
+ const emittedToolNames = /* @__PURE__ */ new Map();
17691
+ const replayedLineCount = state.codexWorkerReplayLineCountByThreadId?.get(worker.threadId) ?? 0;
17692
+ let finalText = state.codexWorkerFinalTextByThreadId?.get(worker.threadId) ?? "";
17693
+ for (let index = 0; index < lines.length; index += 1) {
17694
+ const line = lines[index];
17695
+ if (!line) continue;
17696
+ const entry = parseJsonObject(line);
17697
+ if (entry?.type !== "response_item") continue;
17698
+ const payload = asRecord(entry.payload);
17699
+ if (!payload) continue;
17700
+ if (payload.type === "message" && payload.role === "assistant") {
17701
+ const text = rolloutTextContent(payload.content);
17702
+ if (!text) continue;
17703
+ finalText = text;
17704
+ if (index >= replayedLineCount) {
17705
+ void context.presenter.onAssistantText(text, worker.launcherId);
17706
+ }
17707
+ continue;
17708
+ }
17709
+ if (payload.type === "function_call") {
17710
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17711
+ if (!callId) continue;
17712
+ const toolName = rolloutFunctionToolName(payload);
17713
+ emittedToolNames.set(callId, toolName);
17714
+ if (index >= replayedLineCount) {
17715
+ void context.presenter.onToolUse(
17716
+ toolName,
17717
+ parseMaybeJson(payload.arguments),
17718
+ callId,
17719
+ worker.launcherId
17720
+ );
17721
+ }
17722
+ continue;
17723
+ }
17724
+ if (payload.type === "custom_tool_call") {
17725
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17726
+ if (!callId) continue;
17727
+ const toolName = rolloutFunctionToolName(payload);
17728
+ emittedToolNames.set(callId, toolName);
17729
+ if (index >= replayedLineCount) {
17730
+ void context.presenter.onToolUse(
17731
+ toolName,
17732
+ { code: payload.input ?? "" },
17733
+ callId,
17734
+ worker.launcherId
17735
+ );
17736
+ }
17737
+ continue;
17738
+ }
17739
+ if (payload.type === "tool_search_call") {
17740
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17741
+ if (!callId) continue;
17742
+ emittedToolNames.set(callId, "tool_search");
17743
+ if (index >= replayedLineCount) {
17744
+ void context.presenter.onToolUse(
17745
+ "tool_search",
17746
+ payload.arguments ?? {},
17747
+ callId,
17748
+ worker.launcherId
17749
+ );
17750
+ }
17751
+ continue;
17752
+ }
17753
+ if (payload.type === "function_call_output" || payload.type === "custom_tool_call_output") {
17754
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17755
+ const toolName = emittedToolNames.get(callId);
17756
+ if (!callId || !toolName || index < replayedLineCount) continue;
17757
+ let output = rolloutToolOutputText(payload.output);
17758
+ if (toolName.startsWith("mcp__")) {
17759
+ try {
17760
+ output = normalizeCodexMcpToolResult(payload.output);
17761
+ } catch {
17762
+ }
17763
+ }
17764
+ void context.presenter.onToolResult?.(callId, output, void 0, worker.launcherId);
17765
+ continue;
17766
+ }
17767
+ if (payload.type === "tool_search_output") {
17768
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
17769
+ if (!callId || !emittedToolNames.has(callId) || index < replayedLineCount) continue;
17770
+ void context.presenter.onToolResult?.(
17771
+ callId,
17772
+ JSON.stringify(payload.tools ?? [], null, 2),
17773
+ void 0,
17774
+ worker.launcherId
17775
+ );
17776
+ }
17777
+ }
17778
+ if (!state.codexWorkerReplayLineCountByThreadId)
17779
+ state.codexWorkerReplayLineCountByThreadId = /* @__PURE__ */ new Map();
17780
+ state.codexWorkerReplayLineCountByThreadId.set(worker.threadId, lines.length);
17781
+ if (!state.codexWorkerFinalTextByThreadId) state.codexWorkerFinalTextByThreadId = /* @__PURE__ */ new Map();
17782
+ if (finalText) state.codexWorkerFinalTextByThreadId.set(worker.threadId, finalText);
17783
+ return finalText;
17784
+ }
17785
+ function syncCodexWorkerEventsFromSessionLog(context, state) {
17786
+ const runtimeSessionId = state.runtimeSessionId;
17787
+ if (!runtimeSessionId) return [];
17788
+ const codexHome = resolveCodexHome(context.env);
17789
+ const logPath = state.codexSessionLogPath ?? findCodexSessionLog(runtimeSessionId, codexHome);
17790
+ if (!logPath) return [];
17791
+ state.codexSessionLogPath = logPath;
17792
+ const allLines = (0, import_fs5.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
17793
+ const latestUserLineIndex = latestUserMessageLineIndex(allLines);
17794
+ const lines = latestUserLineIndex >= 0 ? allLines.slice(latestUserLineIndex + 1) : allLines;
17795
+ const workers = collectCodexWorkerReplays(lines, state);
17796
+ for (const worker of workers) {
17797
+ const launcherWasStreamed = state.codexStreamedToolIds?.has(worker.launcherId) === true;
17798
+ if (!launcherWasStreamed) {
17799
+ const workerName = worker.nickname || worker.agentPath?.slice(worker.agentPath.lastIndexOf("/") + 1) || "codex-worker";
17800
+ void context.presenter.onToolUse(
17801
+ "Agent",
17802
+ {
17803
+ subagent_type: workerName,
17804
+ description: worker.description || worker.agentPath || "Codex background worker",
17805
+ agent_thread_id: worker.threadId
17806
+ },
17807
+ worker.launcherId
17808
+ );
17809
+ if (!state.codexStreamedToolIds) state.codexStreamedToolIds = /* @__PURE__ */ new Set();
17810
+ state.codexStreamedToolIds.add(worker.launcherId);
17811
+ if (!state.codexRecoveredLauncherIds) state.codexRecoveredLauncherIds = /* @__PURE__ */ new Set();
17812
+ state.codexRecoveredLauncherIds.add(worker.launcherId);
17813
+ }
17814
+ if (!state.codexWorkerToolIdByThreadId) state.codexWorkerToolIdByThreadId = /* @__PURE__ */ new Map();
17815
+ state.codexWorkerToolIdByThreadId.set(worker.threadId, worker.launcherId);
17816
+ if (worker.agentPath) {
17817
+ if (!state.codexWorkerToolIdByPath) state.codexWorkerToolIdByPath = /* @__PURE__ */ new Map();
17818
+ state.codexWorkerToolIdByPath.set(worker.agentPath, worker.launcherId);
17819
+ }
17820
+ replayCodexWorkerTranscript(context, worker, codexHome, state);
17821
+ }
17822
+ return workers;
17823
+ }
17716
17824
  async function replayCodexMcpToolEventsFromSessionLog(context, state) {
17717
17825
  const runtimeSessionId = state.runtimeSessionId;
17718
17826
  if (!runtimeSessionId) return;
@@ -17769,10 +17877,51 @@ async function replayCodexMcpToolEventsFromSessionLog(context, state) {
17769
17877
  }
17770
17878
  }
17771
17879
  }
17880
+ for (const worker of syncCodexWorkerEventsFromSessionLog(context, state)) {
17881
+ if (state.codexRecoveredLauncherIds?.has(worker.launcherId)) {
17882
+ const finalText = state.codexWorkerFinalTextByThreadId?.get(worker.threadId) ?? "";
17883
+ void context.presenter.onToolResult?.(worker.launcherId, finalText || "Subagent completed.");
17884
+ state.codexRecoveredLauncherIds.delete(worker.launcherId);
17885
+ }
17886
+ }
17772
17887
  }
17773
17888
  var CODEX_EXIT_GRACE_MS = 3e4;
17774
17889
  var CODEX_BACKGROUND_EXIT_GRACE_MS = 10 * 6e4;
17775
17890
  var CODEX_EXIT_GRACE_SIGKILL_MS = 3e3;
17891
+ var CODEX_WORKER_TRANSCRIPT_POLL_MS = 750;
17892
+ function ensureCodexWorkerEventPolling(context, state) {
17893
+ if (!state.runtimeSessionId || state.providerTranscriptPollTimer) return;
17894
+ const poll = () => {
17895
+ try {
17896
+ const before = [...state.codexWorkerReplayLineCountByThreadId?.values() ?? []].reduce(
17897
+ (total, count) => total + count,
17898
+ 0
17899
+ ) + (state.codexStreamedToolIds?.size ?? 0);
17900
+ syncCodexWorkerEventsFromSessionLog(context, state);
17901
+ const after = [...state.codexWorkerReplayLineCountByThreadId?.values() ?? []].reduce(
17902
+ (total, count) => total + count,
17903
+ 0
17904
+ ) + (state.codexStreamedToolIds?.size ?? 0);
17905
+ if (after > before) state.onNewOutput?.();
17906
+ state.providerTranscriptPollErrorLogged = false;
17907
+ } catch (error) {
17908
+ if (!state.providerTranscriptPollErrorLogged) {
17909
+ console.warn("[codex_app_server] Failed to poll worker rollout:", error);
17910
+ state.providerTranscriptPollErrorLogged = true;
17911
+ }
17912
+ }
17913
+ };
17914
+ poll();
17915
+ const timer = setInterval(poll, CODEX_WORKER_TRANSCRIPT_POLL_MS);
17916
+ timer.unref?.();
17917
+ state.providerTranscriptPollTimer = timer;
17918
+ }
17919
+ function codexParentToolUseId(record, state) {
17920
+ const threadId = [record.agent_thread_id, record.sender_thread_id, record.thread_id].find(
17921
+ (value2) => typeof value2 === "string" && value2.length > 0
17922
+ );
17923
+ return threadId ? state.backgroundToolIdByTaskId?.get(threadId) ?? null : null;
17924
+ }
17776
17925
  function armCodexExitGraceKill(state, graceMs = CODEX_EXIT_GRACE_MS) {
17777
17926
  if (state.exitGraceKillTimer) return;
17778
17927
  const child = state.process;
@@ -17902,6 +18051,9 @@ function handleCodexCollabToolCallItem(context, state, item, phase) {
17902
18051
  const prompt = typeof item.prompt === "string" ? item.prompt : "";
17903
18052
  const agentsStates = typeof item.agents_states === "object" && item.agents_states !== null ? item.agents_states : {};
17904
18053
  const itemStatus = typeof item.status === "string" ? item.status : "";
18054
+ if (tool === "wait") {
18055
+ syncCodexWorkerEventsFromSessionLog(context, state);
18056
+ }
17905
18057
  if (tool === "spawn_agent") {
17906
18058
  if (trackCodexStreamedToolId(state, itemId)) {
17907
18059
  const parentToolUseId = senderThreadId ? state.backgroundToolIdByTaskId?.get(senderThreadId) ?? null : null;
@@ -17921,6 +18073,8 @@ function handleCodexCollabToolCallItem(context, state, item, phase) {
17921
18073
  for (const threadId of receiverThreadIds) {
17922
18074
  if (state.backgroundToolIdByTaskId?.get(threadId)) continue;
17923
18075
  registerBackgroundTaskRecord(state, { task_id: threadId, tool_use_id: itemId });
18076
+ if (!state.codexWorkerToolIdByThreadId) state.codexWorkerToolIdByThreadId = /* @__PURE__ */ new Map();
18077
+ state.codexWorkerToolIdByThreadId.set(threadId, itemId);
17924
18078
  }
17925
18079
  applyCodexCollabAgentStates(context, state, agentsStates);
17926
18080
  if (phase === "completed" && itemStatus === "failed") {
@@ -17994,6 +18148,7 @@ function handleCodexStructuredEvent(parsed, context, state) {
17994
18148
  touchCodexBackgroundGrace(state);
17995
18149
  if (typeof parsed.thread_id === "string") {
17996
18150
  state.runtimeSessionId = parsed.thread_id;
18151
+ ensureCodexWorkerEventPolling(context, state);
17997
18152
  }
17998
18153
  const extractCodexErrorMessage = (value2) => {
17999
18154
  if (typeof value2 !== "string") return "";
@@ -18026,6 +18181,7 @@ function handleCodexStructuredEvent(parsed, context, state) {
18026
18181
  case "session_configured":
18027
18182
  if (typeof parsed.session_id === "string") {
18028
18183
  state.runtimeSessionId = parsed.session_id;
18184
+ ensureCodexWorkerEventPolling(context, state);
18029
18185
  }
18030
18186
  return true;
18031
18187
  case "task_started":
@@ -18095,14 +18251,26 @@ function handleCodexStructuredEvent(parsed, context, state) {
18095
18251
  if (!item || typeof item.type !== "string") return true;
18096
18252
  switch (item.type) {
18097
18253
  case "reasoning": {
18098
- if (typeof item.text === "string") void presenter.onThinking(item.text);
18254
+ if (typeof item.text === "string") {
18255
+ const parentToolUseId = codexParentToolUseId(item, state);
18256
+ if (parentToolUseId) {
18257
+ void presenter.onThinking(item.text, parentToolUseId);
18258
+ } else {
18259
+ void presenter.onThinking(item.text);
18260
+ }
18261
+ }
18099
18262
  return true;
18100
18263
  }
18101
18264
  case "agent_message": {
18102
18265
  if (typeof item.text === "string") {
18103
- state.summary += `${item.text}
18266
+ const parentToolUseId = codexParentToolUseId(item, state);
18267
+ if (!parentToolUseId) state.summary += `${item.text}
18104
18268
  `;
18105
- void presenter.onAssistantText(item.text);
18269
+ if (parentToolUseId) {
18270
+ void presenter.onAssistantText(item.text, parentToolUseId);
18271
+ } else {
18272
+ void presenter.onAssistantText(item.text);
18273
+ }
18106
18274
  }
18107
18275
  return true;
18108
18276
  }
@@ -18164,8 +18332,13 @@ function handleCodexStructuredEvent(parsed, context, state) {
18164
18332
  case "agent_message_content_delta": {
18165
18333
  const delta = typeof parsed.delta === "string" ? parsed.delta : "";
18166
18334
  if (!delta) return true;
18167
- state.summary += delta;
18168
- void presenter.onAssistantText(delta);
18335
+ const parentToolUseId = codexParentToolUseId(parsed, state);
18336
+ if (!parentToolUseId) state.summary += delta;
18337
+ if (parentToolUseId) {
18338
+ void presenter.onAssistantText(delta, parentToolUseId);
18339
+ } else {
18340
+ void presenter.onAssistantText(delta);
18341
+ }
18169
18342
  return true;
18170
18343
  }
18171
18344
  case "agent_reasoning_delta":
@@ -18173,7 +18346,12 @@ function handleCodexStructuredEvent(parsed, context, state) {
18173
18346
  case "agent_reasoning_raw_content_delta": {
18174
18347
  const delta = typeof parsed.delta === "string" ? parsed.delta : "";
18175
18348
  if (!delta) return true;
18176
- void presenter.onThinking(delta);
18349
+ const parentToolUseId = codexParentToolUseId(parsed, state);
18350
+ if (parentToolUseId) {
18351
+ void presenter.onThinking(delta, parentToolUseId);
18352
+ } else {
18353
+ void presenter.onThinking(delta);
18354
+ }
18177
18355
  return true;
18178
18356
  }
18179
18357
  case "exec_command_begin": {
@@ -18241,6 +18419,7 @@ function handleCodexStructuredEvent(parsed, context, state) {
18241
18419
  return true;
18242
18420
  }
18243
18421
  case "turn.completed": {
18422
+ syncCodexWorkerEventsFromSessionLog(context, state);
18244
18423
  const usage = typeof parsed.usage === "object" && parsed.usage !== null ? parsed.usage : {};
18245
18424
  state.usage = {
18246
18425
  model: typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel : "codex",
@@ -18292,6 +18471,8 @@ function handleCodexStructuredEvent(parsed, context, state) {
18292
18471
  registerBackgroundLauncher(state, toolId);
18293
18472
  if (agentThreadId) {
18294
18473
  registerBackgroundTaskRecord(state, { task_id: agentThreadId, tool_use_id: toolId });
18474
+ if (!state.codexWorkerToolIdByThreadId) state.codexWorkerToolIdByThreadId = /* @__PURE__ */ new Map();
18475
+ state.codexWorkerToolIdByThreadId.set(agentThreadId, toolId);
18295
18476
  }
18296
18477
  if (!state.codexWorkerToolIdByPath) state.codexWorkerToolIdByPath = /* @__PURE__ */ new Map();
18297
18478
  state.codexWorkerToolIdByPath.set(agentPath, toolId);
@@ -18612,12 +18793,16 @@ function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
18612
18793
  }
18613
18794
  };
18614
18795
  }
18796
+ function asRecord2(value2) {
18797
+ return typeof value2 === "object" && value2 !== null ? value2 : null;
18798
+ }
18615
18799
  function extractCursorToolEntry(toolCall) {
18616
18800
  const [rawName, rawPayload] = Object.entries(toolCall)[0] ?? [];
18617
18801
  if (!rawName || typeof rawPayload !== "object" || rawPayload === null) return null;
18618
18802
  return { rawName, payload: rawPayload };
18619
18803
  }
18620
18804
  function formatCursorToolName(rawName, payload) {
18805
+ if (rawName === "taskToolCall") return "Agent";
18621
18806
  if (rawName === "terminalToolCall") return "Bash";
18622
18807
  if (rawName === "mcpToolCall") {
18623
18808
  const provider = typeof payload.providerIdentifier === "string" ? payload.providerIdentifier : typeof payload.serverName === "string" ? payload.serverName : typeof payload.mcpServer === "string" ? payload.mcpServer : "";
@@ -18629,6 +18814,59 @@ function formatCursorToolName(rawName, payload) {
18629
18814
  if (!trimmed) return "Cursor Tool";
18630
18815
  return trimmed.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^[a-z]/, (char) => char.toUpperCase());
18631
18816
  }
18817
+ function cursorTaskResultVariant(payload, variant) {
18818
+ const result = asRecord2(payload.result);
18819
+ if (!result) return null;
18820
+ const direct = asRecord2(result[variant]);
18821
+ if (direct) return direct;
18822
+ const oneof = asRecord2(result.result);
18823
+ return oneof?.case === variant ? asRecord2(oneof.value) : null;
18824
+ }
18825
+ function cursorSubagentType(value2) {
18826
+ const normalize = (candidate) => {
18827
+ const trimmed = candidate?.trim();
18828
+ if (!trimmed) return void 0;
18829
+ const normalized = trimmed.toLowerCase();
18830
+ if (normalized === "unspecified" || normalized.endsWith("_unspecified")) return void 0;
18831
+ return trimmed;
18832
+ };
18833
+ if (typeof value2 === "string") return normalize(value2);
18834
+ const record = asRecord2(value2);
18835
+ if (!record) return void 0;
18836
+ if (typeof record.case === "string" && record.case) return normalize(record.case);
18837
+ if (typeof record.type === "string" && record.type) return normalize(record.type);
18838
+ const nestedType = asRecord2(record.type);
18839
+ if (typeof nestedType?.case === "string" && nestedType.case) return normalize(nestedType.case);
18840
+ return normalize(
18841
+ Object.keys(nestedType ?? record).find((key) => key !== "value" && key !== "case")
18842
+ );
18843
+ }
18844
+ function cursorToolArgs(entry) {
18845
+ const args = asRecord2(entry.payload.args) ?? asRecord2(entry.payload.arguments) ?? entry.payload;
18846
+ if (entry.rawName !== "taskToolCall") return args;
18847
+ const subagentType = cursorSubagentType(args.subagentType ?? args.subagent_type);
18848
+ return {
18849
+ ...typeof args.description === "string" ? { description: args.description } : {},
18850
+ ...typeof args.prompt === "string" ? { prompt: args.prompt } : {},
18851
+ ...subagentType ? { subagent_type: subagentType } : {},
18852
+ ...typeof args.model === "string" ? { model: args.model } : {}
18853
+ };
18854
+ }
18855
+ function cursorConversationStepValue(step, key) {
18856
+ const direct = asRecord2(step[key]);
18857
+ if (direct) return direct;
18858
+ const message = asRecord2(step.message);
18859
+ return message?.case === key ? asRecord2(message.value) : null;
18860
+ }
18861
+ function cursorConversationStepText(steps) {
18862
+ if (!Array.isArray(steps)) return "";
18863
+ return steps.flatMap((step) => {
18864
+ const record = asRecord2(step);
18865
+ if (!record) return [];
18866
+ const assistant = cursorConversationStepValue(record, "assistantMessage");
18867
+ return typeof assistant?.text === "string" ? [assistant.text] : [];
18868
+ }).join("\n").trim();
18869
+ }
18632
18870
  function buildCursorToolResultText(result) {
18633
18871
  if (typeof result === "string") return result;
18634
18872
  if (!result || typeof result !== "object") return JSON.stringify(result ?? {});
@@ -18650,6 +18888,202 @@ function buildCursorToolResultText(result) {
18650
18888
  }
18651
18889
  return JSON.stringify(result, null, 2);
18652
18890
  }
18891
+ function emitCursorSubagentConversationSteps(steps, parentToolUseId, presenter) {
18892
+ if (!Array.isArray(steps)) return;
18893
+ steps.forEach((step, index) => {
18894
+ const record = asRecord2(step);
18895
+ if (!record) return;
18896
+ const assistant = cursorConversationStepValue(record, "assistantMessage");
18897
+ if (typeof assistant?.text === "string" && assistant.text) {
18898
+ void presenter.onAssistantText(assistant.text, parentToolUseId);
18899
+ return;
18900
+ }
18901
+ const thinking = cursorConversationStepValue(record, "thinkingMessage");
18902
+ if (typeof thinking?.text === "string" && thinking.text) {
18903
+ void presenter.onThinking(thinking.text, parentToolUseId);
18904
+ return;
18905
+ }
18906
+ const toolCall = cursorConversationStepValue(record, "toolCall");
18907
+ if (!toolCall) return;
18908
+ const entry = extractCursorToolEntry(toolCall);
18909
+ if (!entry) return;
18910
+ const args = cursorToolArgs(entry);
18911
+ const toolId = typeof args.toolCallId === "string" && args.toolCallId || typeof args.tool_call_id === "string" && args.tool_call_id || `${parentToolUseId}-step-${index}`;
18912
+ void presenter.onToolUse(
18913
+ formatCursorToolName(entry.rawName, entry.payload),
18914
+ args,
18915
+ toolId,
18916
+ parentToolUseId
18917
+ );
18918
+ if (entry.payload.result !== void 0) {
18919
+ const isError = cursorTaskResultVariant(entry.payload, "error") !== null;
18920
+ void presenter.onToolResult?.(
18921
+ toolId,
18922
+ buildCursorToolResultText(entry.payload.result),
18923
+ isError || void 0,
18924
+ parentToolUseId
18925
+ );
18926
+ }
18927
+ });
18928
+ }
18929
+ function emitCursorSubagentTranscript(transcriptPath, parentToolUseId, presenter, startLine = 0) {
18930
+ if (typeof transcriptPath !== "string" || !transcriptPath) {
18931
+ return { found: false, processedLineCount: startLine, emittedEventCount: 0 };
18932
+ }
18933
+ let lines;
18934
+ try {
18935
+ lines = (0, import_fs6.readFileSync)(transcriptPath, "utf8").split(/\r?\n/);
18936
+ if (lines.at(-1) === "") lines.pop();
18937
+ } catch {
18938
+ return { found: false, processedLineCount: startLine, emittedEventCount: 0 };
18939
+ }
18940
+ let processedLineCount = startLine > lines.length ? 0 : startLine;
18941
+ let emittedEventCount = 0;
18942
+ for (let lineIndex = processedLineCount; lineIndex < lines.length; lineIndex += 1) {
18943
+ const line = lines[lineIndex];
18944
+ if (!line) {
18945
+ processedLineCount = lineIndex + 1;
18946
+ continue;
18947
+ }
18948
+ let entry;
18949
+ try {
18950
+ entry = JSON.parse(line);
18951
+ } catch {
18952
+ break;
18953
+ }
18954
+ processedLineCount = lineIndex + 1;
18955
+ if (entry.role !== "assistant") continue;
18956
+ const message = asRecord2(entry.message);
18957
+ const content = Array.isArray(message?.content) ? message.content : [];
18958
+ content.forEach((rawBlock, blockIndex) => {
18959
+ const block = asRecord2(rawBlock);
18960
+ if (!block) return;
18961
+ const type = typeof block.type === "string" ? block.type : "";
18962
+ const text = typeof block.text === "string" ? block.text : "";
18963
+ if (type === "text" && text) {
18964
+ emittedEventCount += 1;
18965
+ void presenter.onAssistantText(text, parentToolUseId);
18966
+ return;
18967
+ }
18968
+ if ((type === "thinking" || type === "reasoning") && text) {
18969
+ emittedEventCount += 1;
18970
+ void presenter.onThinking(text, parentToolUseId);
18971
+ return;
18972
+ }
18973
+ if (type !== "tool_use") return;
18974
+ const name = typeof block.name === "string" && block.name ? block.name : "Cursor Tool";
18975
+ const toolId = typeof block.id === "string" && block.id || `${parentToolUseId}-transcript-${lineIndex}-${blockIndex}`;
18976
+ emittedEventCount += 1;
18977
+ void presenter.onToolUse(name, asRecord2(block.input) ?? {}, toolId, parentToolUseId);
18978
+ });
18979
+ }
18980
+ return { found: true, processedLineCount, emittedEventCount };
18981
+ }
18982
+ function cursorTranscriptsRoot(context) {
18983
+ const projectKey = context.cwd.replace(/^[/\\]+/, "").replace(/[/\\]+/g, "-");
18984
+ const home = context.env.HOME || process.env.HOME || (0, import_os6.homedir)();
18985
+ return (0, import_path6.join)(home, ".cursor", "projects", projectKey, "agent-transcripts");
18986
+ }
18987
+ function cursorTranscriptPathForAgent(context, agentId) {
18988
+ return (0, import_path6.join)(cursorTranscriptsRoot(context), agentId, `${agentId}.jsonl`);
18989
+ }
18990
+ function resolveCursorSubagentTranscriptPath(success, context) {
18991
+ const explicit = success?.transcriptPath ?? success?.transcript_path;
18992
+ if (typeof explicit === "string" && explicit) return explicit;
18993
+ const agentId = typeof success?.agentId === "string" ? success.agentId : "";
18994
+ return agentId ? cursorTranscriptPathForAgent(context, agentId) : void 0;
18995
+ }
18996
+ function cursorTranscriptUserText(transcriptPath) {
18997
+ try {
18998
+ for (const line of (0, import_fs6.readFileSync)(transcriptPath, "utf8").split(/\r?\n/)) {
18999
+ if (!line) continue;
19000
+ const entry = asRecord2(JSON.parse(line));
19001
+ if (entry?.role !== "user") continue;
19002
+ const message = asRecord2(entry.message);
19003
+ const content = Array.isArray(message?.content) ? message.content : [];
19004
+ return content.flatMap((block) => {
19005
+ const record = asRecord2(block);
19006
+ return typeof record?.text === "string" ? [record.text] : [];
19007
+ }).join("");
19008
+ }
19009
+ } catch {
19010
+ }
19011
+ return "";
19012
+ }
19013
+ function discoverCursorSubagentTranscript(context, state, task) {
19014
+ const root = cursorTranscriptsRoot(context);
19015
+ if (!(0, import_fs6.existsSync)(root)) return void 0;
19016
+ const prompt = task.prompt?.trim();
19017
+ const description = task.description?.trim().toLowerCase();
19018
+ const candidates = [];
19019
+ let entries;
19020
+ try {
19021
+ entries = (0, import_fs6.readdirSync)(root, { withFileTypes: true });
19022
+ } catch {
19023
+ return void 0;
19024
+ }
19025
+ for (const entry of entries) {
19026
+ if (!entry.isDirectory() || entry.name === state.runtimeSessionId) continue;
19027
+ const path = cursorTranscriptPathForAgent(context, entry.name);
19028
+ let mtimeMs;
19029
+ try {
19030
+ mtimeMs = (0, import_fs6.statSync)(path).mtimeMs;
19031
+ } catch {
19032
+ continue;
19033
+ }
19034
+ if (mtimeMs < task.startedAtMs - 2e3) continue;
19035
+ const userText = cursorTranscriptUserText(path).trim();
19036
+ if (!userText) continue;
19037
+ let score = 0;
19038
+ if (prompt && userText === prompt) score = 3;
19039
+ else if (prompt && (userText.includes(prompt) || prompt.includes(userText))) score = 2;
19040
+ else if (description && userText.toLowerCase().includes(description)) score = 1;
19041
+ if (score > 0) candidates.push({ path, score, mtimeMs });
19042
+ }
19043
+ candidates.sort((a, b) => b.score - a.score || b.mtimeMs - a.mtimeMs);
19044
+ return candidates[0]?.path;
19045
+ }
19046
+ function syncCursorSubagentEventsFromTranscripts(context, state) {
19047
+ let emittedEventCount = 0;
19048
+ for (const [launcherId, task] of state.cursorSubagentTranscripts ?? []) {
19049
+ task.transcriptPath ??= discoverCursorSubagentTranscript(context, state, task);
19050
+ if (!task.transcriptPath) continue;
19051
+ const replay = emitCursorSubagentTranscript(
19052
+ task.transcriptPath,
19053
+ launcherId,
19054
+ context.presenter,
19055
+ task.replayedLineCount
19056
+ );
19057
+ task.replayedLineCount = replay.processedLineCount;
19058
+ task.emittedEventCount += replay.emittedEventCount;
19059
+ emittedEventCount += replay.emittedEventCount;
19060
+ }
19061
+ if (emittedEventCount > 0) state.onNewOutput?.();
19062
+ return emittedEventCount;
19063
+ }
19064
+ function ensureCursorSubagentTranscriptPolling(context, state) {
19065
+ if (state.providerTranscriptPollTimer) return;
19066
+ const poll = () => {
19067
+ try {
19068
+ syncCursorSubagentEventsFromTranscripts(context, state);
19069
+ state.providerTranscriptPollErrorLogged = false;
19070
+ } catch (error) {
19071
+ if (!state.providerTranscriptPollErrorLogged) {
19072
+ console.warn("[cursor_agent_cli] Failed to poll child transcript:", error);
19073
+ state.providerTranscriptPollErrorLogged = true;
19074
+ }
19075
+ }
19076
+ };
19077
+ poll();
19078
+ const timer = setInterval(poll, 750);
19079
+ timer.unref?.();
19080
+ state.providerTranscriptPollTimer = timer;
19081
+ }
19082
+ function stopCursorSubagentTranscriptPollingIfIdle(state) {
19083
+ if (state.cursorSubagentTranscripts?.size) return;
19084
+ if (state.providerTranscriptPollTimer) clearInterval(state.providerTranscriptPollTimer);
19085
+ state.providerTranscriptPollTimer = void 0;
19086
+ }
18653
19087
  function handleCursorStructuredEvent(parsed, context, state) {
18654
19088
  const presenter = context.presenter;
18655
19089
  const type = typeof parsed.type === "string" ? parsed.type : "";
@@ -18657,8 +19091,22 @@ function handleCursorStructuredEvent(parsed, context, state) {
18657
19091
  if (typeof parsed.session_id === "string") state.runtimeSessionId = parsed.session_id;
18658
19092
  if (typeof parsed.model === "string") state.activeModel = parsed.model;
18659
19093
  switch (type) {
18660
- case "system":
19094
+ case "system": {
19095
+ if (parsed.subtype !== "task_notification") return true;
19096
+ const status = typeof parsed.status === "string" ? parsed.status.toLowerCase() : "completed";
19097
+ const isError = ["error", "failed", "aborted", "cancelled", "interrupted"].includes(status);
19098
+ const resultText = typeof parsed.detail === "string" && parsed.detail || typeof parsed.title === "string" && parsed.title || `Background subagent ${status}`;
19099
+ const toolUseId = resolveBackgroundTaskToolUseId(state, parsed);
19100
+ clearBackgroundTaskIds(state, backgroundTaskKeys(parsed));
19101
+ const launcherId = toolUseId ?? drainNextUnlinkedBackgroundLauncher(state);
19102
+ if (launcherId) {
19103
+ syncCursorSubagentEventsFromTranscripts(context, state);
19104
+ state.cursorSubagentTranscripts?.delete(launcherId);
19105
+ stopCursorSubagentTranscriptPollingIfIdle(state);
19106
+ void presenter.onToolResult?.(launcherId, resultText, isError || void 0);
19107
+ }
18661
19108
  return true;
19109
+ }
18662
19110
  case "thinking":
18663
19111
  case "reasoning": {
18664
19112
  const subtype = typeof parsed.subtype === "string" ? parsed.subtype : "";
@@ -18707,14 +19155,72 @@ function handleCursorStructuredEvent(parsed, context, state) {
18707
19155
  if (!toolId) return true;
18708
19156
  state.iterations = Math.max(state.iterations, 1);
18709
19157
  const toolName = formatCursorToolName(entry.rawName, entry.payload);
18710
- const toolArgs = typeof entry.payload.args === "object" && entry.payload.args !== null ? entry.payload.args : typeof entry.payload.arguments === "object" && entry.payload.arguments !== null ? entry.payload.arguments : entry.payload;
19158
+ const toolArgs = cursorToolArgs(entry);
18711
19159
  if (subtype === "started") {
18712
19160
  void presenter.onToolUse(toolName, toolArgs, toolId);
19161
+ if (entry.rawName === "taskToolCall") {
19162
+ if (!state.cursorSubagentTranscripts) state.cursorSubagentTranscripts = /* @__PURE__ */ new Map();
19163
+ state.cursorSubagentTranscripts.set(toolId, {
19164
+ description: typeof toolArgs.description === "string" ? toolArgs.description : void 0,
19165
+ prompt: typeof toolArgs.prompt === "string" ? toolArgs.prompt : void 0,
19166
+ startedAtMs: typeof parsed.timestamp_ms === "number" ? parsed.timestamp_ms : typeof entry.payload.startedAtMs === "number" ? entry.payload.startedAtMs : Number(entry.payload.startedAtMs) || Date.now(),
19167
+ replayedLineCount: 0,
19168
+ emittedEventCount: 0
19169
+ });
19170
+ ensureCursorSubagentTranscriptPolling(context, state);
19171
+ }
18713
19172
  return true;
18714
19173
  }
18715
19174
  if (subtype === "completed") {
18716
19175
  if (!hasCallId) state.lastAnonymousCursorToolId = void 0;
18717
- void presenter.onToolResult?.(toolId, buildCursorToolResultText(entry.payload.result));
19176
+ if (entry.rawName === "taskToolCall") {
19177
+ const resultEnvelope = typeof parsed.result === "object" && parsed.result !== null ? parsed : entry.payload;
19178
+ const success = cursorTaskResultVariant(resultEnvelope, "success");
19179
+ const failure = cursorTaskResultVariant(resultEnvelope, "error");
19180
+ const task = state.cursorSubagentTranscripts?.get(toolId);
19181
+ if (task) {
19182
+ task.transcriptPath = resolveCursorSubagentTranscriptPath(success, context) ?? task.transcriptPath;
19183
+ }
19184
+ let replayedTranscript = false;
19185
+ if (task) {
19186
+ syncCursorSubagentEventsFromTranscripts(context, state);
19187
+ replayedTranscript = task.emittedEventCount > 0;
19188
+ } else {
19189
+ replayedTranscript = emitCursorSubagentTranscript(
19190
+ resolveCursorSubagentTranscriptPath(success, context),
19191
+ toolId,
19192
+ presenter
19193
+ ).emittedEventCount > 0;
19194
+ }
19195
+ if (!replayedTranscript) {
19196
+ emitCursorSubagentConversationSteps(success?.conversationSteps, toolId, presenter);
19197
+ }
19198
+ if (success?.isBackground === true) {
19199
+ registerBackgroundLauncher(state, toolId);
19200
+ const taskId = typeof success.agentId === "string" && success.agentId ? success.agentId : void 0;
19201
+ if (taskId) {
19202
+ registerBackgroundTaskRecord(state, {
19203
+ task_id: taskId,
19204
+ tool_use_id: toolId
19205
+ });
19206
+ }
19207
+ return true;
19208
+ }
19209
+ state.cursorSubagentTranscripts?.delete(toolId);
19210
+ stopCursorSubagentTranscriptPollingIfIdle(state);
19211
+ const summary = cursorConversationStepText(success?.conversationSteps);
19212
+ const failureText = typeof failure?.error === "string" && failure.error ? failure.error : "Cursor subagent failed";
19213
+ void presenter.onToolResult?.(
19214
+ toolId,
19215
+ failure ? failureText : summary || buildCursorToolResultText(resultEnvelope.result),
19216
+ failure ? true : void 0
19217
+ );
19218
+ return true;
19219
+ }
19220
+ void presenter.onToolResult?.(
19221
+ toolId,
19222
+ buildCursorToolResultText(parsed.result ?? entry.payload.result)
19223
+ );
18718
19224
  }
18719
19225
  return true;
18720
19226
  }
@@ -19072,7 +19578,7 @@ function createDroidCliBackend(command = "droid", defaultArgs = []) {
19072
19578
  };
19073
19579
  }
19074
19580
  var ACP_PROTOCOL_VERSION = 1;
19075
- function asRecord(value2) {
19581
+ function asRecord3(value2) {
19076
19582
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
19077
19583
  }
19078
19584
  function asString(value2) {
@@ -19082,7 +19588,7 @@ function resumeSessionId(context) {
19082
19588
  return context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim() || "";
19083
19589
  }
19084
19590
  function chunkText(content) {
19085
- const record = asRecord(content);
19591
+ const record = asRecord3(content);
19086
19592
  if (!record) return "";
19087
19593
  if (typeof record.text === "string") return record.text;
19088
19594
  return chunkText(record.content);
@@ -19098,23 +19604,23 @@ function toolResultText(update) {
19098
19604
  return "";
19099
19605
  }
19100
19606
  function toolMetaName(update) {
19101
- const meta = asRecord(update._meta);
19102
- const tool = asRecord(meta?.["x.ai/tool"]);
19607
+ const meta = asRecord3(update._meta);
19608
+ const tool = asRecord3(meta?.["x.ai/tool"]);
19103
19609
  return asString(tool?.name);
19104
19610
  }
19105
19611
  function resolvePermission(params, context) {
19106
- const record = asRecord(params);
19612
+ const record = asRecord3(params);
19107
19613
  const options = Array.isArray(record?.options) ? record?.options : [];
19108
- const toolCall = asRecord(record?.toolCall);
19109
- const meta = asRecord(toolCall?._meta);
19110
- const tool = asRecord(meta?.["x.ai/tool"]);
19614
+ const toolCall = asRecord3(record?.toolCall);
19615
+ const meta = asRecord3(toolCall?._meta);
19616
+ const tool = asRecord3(meta?.["x.ai/tool"]);
19111
19617
  const isReadOnlyTool = tool?.read_only === true || asString(tool?.kind) === "read";
19112
19618
  const allow = !shouldUseReadOnlyRuntimePermissions(context.config) || isReadOnlyTool;
19113
19619
  const allowKinds = ["allow_always", "allow_once", "allow"];
19114
19620
  const rejectKinds = ["reject_always", "reject_once", "reject", "deny"];
19115
19621
  const wanted = allow ? allowKinds : rejectKinds;
19116
- const chosen = options.find((option) => wanted.includes(asString(asRecord(option)?.kind))) ?? (allow ? options[0] : options[options.length - 1]);
19117
- const optionId = asString(asRecord(chosen)?.optionId);
19622
+ const chosen = options.find((option) => wanted.includes(asString(asRecord3(option)?.kind))) ?? (allow ? options[0] : options[options.length - 1]);
19623
+ const optionId = asString(asRecord3(chosen)?.optionId);
19118
19624
  if (!optionId) return { outcome: { outcome: "cancelled" } };
19119
19625
  return { outcome: { outcome: "selected", optionId } };
19120
19626
  }
@@ -19190,9 +19696,9 @@ function createGrokAcpDriver(imageFiles) {
19190
19696
  finalize(state);
19191
19697
  return;
19192
19698
  }
19193
- const result = asRecord(message.result);
19699
+ const result = asRecord3(message.result);
19194
19700
  if (message.id === initId) {
19195
- const modelState = asRecord(asRecord(result?._meta)?.modelState);
19701
+ const modelState = asRecord3(asRecord3(result?._meta)?.modelState);
19196
19702
  const model = asString(modelState?.currentModelId);
19197
19703
  if (model) state.activeModel = model;
19198
19704
  beginSession(context, state);
@@ -19206,7 +19712,7 @@ function createGrokAcpDriver(imageFiles) {
19206
19712
  return;
19207
19713
  }
19208
19714
  if (message.id === promptId) {
19209
- const meta = asRecord(result?._meta);
19715
+ const meta = asRecord3(result?._meta);
19210
19716
  const model = asString(meta?.modelId) || state.activeModel || (typeof context.config.selectedModel === "string" && context.config.selectedModel.trim() ? context.config.selectedModel.trim() : "grok");
19211
19717
  const inputTokens = typeof meta?.inputTokens === "number" ? meta.inputTokens : 0;
19212
19718
  const outputTokens = typeof meta?.outputTokens === "number" ? meta.outputTokens : 0;
@@ -19251,8 +19757,8 @@ function createGrokAcpDriver(imageFiles) {
19251
19757
  }
19252
19758
  }
19253
19759
  function handleNotification(message, context, state) {
19254
- const params = asRecord(message.params);
19255
- const update = asRecord(params?.update);
19760
+ const params = asRecord3(message.params);
19761
+ const update = asRecord3(params?.update);
19256
19762
  if (!update || !isPromptActive) return;
19257
19763
  const presenter = context.presenter;
19258
19764
  switch (asString(update.sessionUpdate)) {
@@ -19299,7 +19805,7 @@ function createGrokAcpDriver(imageFiles) {
19299
19805
  if (line.trim().length > 0) void context.presenter.onLog(`[grok_cli] ${line}`);
19300
19806
  return;
19301
19807
  }
19302
- const message = asRecord(parsed);
19808
+ const message = asRecord3(parsed);
19303
19809
  if (!message) return;
19304
19810
  if (message.id !== void 0 && message.method === void 0) {
19305
19811
  handleResponse(message, context, state);
@@ -19366,9 +19872,9 @@ function buildGrokAgentArgs(config, defaultArgs = []) {
19366
19872
  return args;
19367
19873
  }
19368
19874
  var DEFAULT_SKILL_ROOTS = [
19369
- (0, import_path6.join)((0, import_os6.homedir)(), ".agents", "skills"),
19370
- (0, import_path6.join)((0, import_os6.homedir)(), ".claude", "skills"),
19371
- (0, import_path6.join)((0, import_os6.homedir)(), ".config", "opencode", "skills")
19875
+ (0, import_path7.join)((0, import_os7.homedir)(), ".agents", "skills"),
19876
+ (0, import_path7.join)((0, import_os7.homedir)(), ".claude", "skills"),
19877
+ (0, import_path7.join)((0, import_os7.homedir)(), ".config", "opencode", "skills")
19372
19878
  ];
19373
19879
  function parseFrontmatter(content) {
19374
19880
  if (!content.startsWith("---\n")) return {};
@@ -19384,12 +19890,12 @@ function parseFrontmatter(content) {
19384
19890
  return result;
19385
19891
  }
19386
19892
  function listSkillFiles(root) {
19387
- if (!(0, import_fs6.existsSync)(root)) return [];
19893
+ if (!(0, import_fs7.existsSync)(root)) return [];
19388
19894
  const files = [];
19389
- for (const entry of (0, import_fs6.readdirSync)(root, { withFileTypes: true })) {
19895
+ for (const entry of (0, import_fs7.readdirSync)(root, { withFileTypes: true })) {
19390
19896
  if (!entry.isDirectory()) continue;
19391
- const skillPath = (0, import_path6.join)(root, entry.name, "SKILL.md");
19392
- if ((0, import_fs6.existsSync)(skillPath)) files.push(skillPath);
19897
+ const skillPath = (0, import_path7.join)(root, entry.name, "SKILL.md");
19898
+ if ((0, import_fs7.existsSync)(skillPath)) files.push(skillPath);
19393
19899
  }
19394
19900
  return files;
19395
19901
  }
@@ -19398,7 +19904,7 @@ function loadInstalledSkills(roots = DEFAULT_SKILL_ROOTS) {
19398
19904
  for (const root of roots) {
19399
19905
  for (const skillPath of listSkillFiles(root)) {
19400
19906
  try {
19401
- const frontmatter = parseFrontmatter((0, import_fs6.readFileSync)(skillPath, "utf8"));
19907
+ const frontmatter = parseFrontmatter((0, import_fs7.readFileSync)(skillPath, "utf8"));
19402
19908
  const name = frontmatter.name;
19403
19909
  const description = frontmatter.description;
19404
19910
  if (!name || !description || skills.has(name)) continue;
@@ -20367,40 +20873,40 @@ function parseSkillInvocation(text) {
20367
20873
  function candidateRoots(cwd) {
20368
20874
  const roots = [];
20369
20875
  if (cwd) {
20370
- roots.push((0, import_path7.join)(cwd, ".agents", "skills"));
20371
- roots.push((0, import_path7.join)(cwd, ".claude", "skills"));
20372
- roots.push((0, import_path7.join)(cwd, ".codex", "skills"));
20373
- if ((0, import_fs7.existsSync)(cwd)) {
20876
+ roots.push((0, import_path8.join)(cwd, ".agents", "skills"));
20877
+ roots.push((0, import_path8.join)(cwd, ".claude", "skills"));
20878
+ roots.push((0, import_path8.join)(cwd, ".codex", "skills"));
20879
+ if ((0, import_fs8.existsSync)(cwd)) {
20374
20880
  let entries = [];
20375
20881
  try {
20376
- entries = (0, import_fs7.readdirSync)(cwd, { withFileTypes: true });
20882
+ entries = (0, import_fs8.readdirSync)(cwd, { withFileTypes: true });
20377
20883
  } catch {
20378
20884
  }
20379
20885
  for (const entry of entries) {
20380
20886
  if (!entry.isDirectory()) continue;
20381
20887
  if (entry.name.startsWith(".")) continue;
20382
- const child = (0, import_path7.join)(cwd, entry.name);
20383
- roots.push((0, import_path7.join)(child, ".agents", "skills"));
20384
- roots.push((0, import_path7.join)(child, ".claude", "skills"));
20385
- roots.push((0, import_path7.join)(child, ".codex", "skills"));
20888
+ const child = (0, import_path8.join)(cwd, entry.name);
20889
+ roots.push((0, import_path8.join)(child, ".agents", "skills"));
20890
+ roots.push((0, import_path8.join)(child, ".claude", "skills"));
20891
+ roots.push((0, import_path8.join)(child, ".codex", "skills"));
20386
20892
  }
20387
20893
  }
20388
20894
  }
20389
- const home = (0, import_os7.homedir)();
20390
- roots.push((0, import_path7.join)(home, ".agents", "skills"));
20391
- roots.push((0, import_path7.join)(home, ".claude", "skills"));
20392
- roots.push((0, import_path7.join)(home, ".codex", "skills"));
20895
+ const home = (0, import_os8.homedir)();
20896
+ roots.push((0, import_path8.join)(home, ".agents", "skills"));
20897
+ roots.push((0, import_path8.join)(home, ".claude", "skills"));
20898
+ roots.push((0, import_path8.join)(home, ".codex", "skills"));
20393
20899
  return Array.from(new Set(roots));
20394
20900
  }
20395
20901
  function resolveSkillInvocation(text, cwd) {
20396
20902
  const parsed = parseSkillInvocation(text);
20397
20903
  if (!parsed) return null;
20398
20904
  for (const root of candidateRoots(cwd)) {
20399
- const skillPath = (0, import_path7.join)(root, parsed.command, "SKILL.md");
20400
- if (!(0, import_fs7.existsSync)(skillPath)) continue;
20905
+ const skillPath = (0, import_path8.join)(root, parsed.command, "SKILL.md");
20906
+ if (!(0, import_fs8.existsSync)(skillPath)) continue;
20401
20907
  let content;
20402
20908
  try {
20403
- content = (0, import_fs7.readFileSync)(skillPath, "utf-8");
20909
+ content = (0, import_fs8.readFileSync)(skillPath, "utf-8");
20404
20910
  } catch {
20405
20911
  continue;
20406
20912
  }
@@ -20603,7 +21109,7 @@ var BaseMachineAgent = class _BaseMachineAgent {
20603
21109
  };
20604
21110
  const releaseGate = await acquireMcpConfigWriteGate();
20605
21111
  try {
20606
- const writtenClis = syncAlanMcpSessionHeaders({
21112
+ const writtenClis = await syncAlanMcpSessionHeaders({
20607
21113
  conversationId,
20608
21114
  teamId: config.teamId,
20609
21115
  runHeaders: config.alanMcp?.headers,
@@ -20997,14 +21503,14 @@ function normalizePath(candidate, cwd) {
20997
21503
  } catch {
20998
21504
  }
20999
21505
  if (path.startsWith("~/")) return null;
21000
- if ((0, import_path8.isAbsolute)(path)) return path;
21001
- return cwd ? (0, import_path8.join)(cwd, path) : null;
21506
+ if ((0, import_path9.isAbsolute)(path)) return path;
21507
+ return cwd ? (0, import_path9.join)(cwd, path) : null;
21002
21508
  }
21003
21509
  function resolveToolCwd(cwd, toolInput) {
21004
21510
  if (!isRecord(toolInput)) return cwd;
21005
21511
  const raw = typeof toolInput.cwd === "string" ? toolInput.cwd : typeof toolInput.workdir === "string" ? toolInput.workdir : typeof toolInput.workingDirectory === "string" ? toolInput.workingDirectory : null;
21006
21512
  if (!raw) return cwd;
21007
- return (0, import_path8.isAbsolute)(raw) || !cwd ? raw : (0, import_path8.join)(cwd, raw);
21513
+ return (0, import_path9.isAbsolute)(raw) || !cwd ? raw : (0, import_path9.join)(cwd, raw);
21008
21514
  }
21009
21515
  function extractBrowserMediaPathHints(content, cwd, toolName, options = {}, kind = "video") {
21010
21516
  if (!isAgentBrowserMediaInvocation(toolName, content, options.toolInput, kind)) return [];
@@ -21047,19 +21553,19 @@ function extractGeneratedImagesFromToolResult(toolId, content, cwd, toolName, op
21047
21553
  const effectiveCwd = resolveToolCwd(cwd, options.toolInput);
21048
21554
  for (const candidate of extractPathCandidates(content, options)) {
21049
21555
  const path = normalizePath(candidate, effectiveCwd);
21050
- if (!path || seen.has(path) || !(0, import_fs8.existsSync)(path)) continue;
21556
+ if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
21051
21557
  seen.add(path);
21052
- const ext = (0, import_path8.extname)(path).toLowerCase();
21558
+ const ext = (0, import_path9.extname)(path).toLowerCase();
21053
21559
  const mimeType = IMAGE_MIME_BY_EXT[ext];
21054
21560
  if (!mimeType) continue;
21055
- const stat = (0, import_fs8.statSync)(path);
21561
+ const stat = (0, import_fs9.statSync)(path);
21056
21562
  if (!stat.isFile() || stat.size <= 0 || stat.size > MAX_GENERATED_IMAGE_BYTES) continue;
21057
- const buffer = (0, import_fs8.readFileSync)(path);
21563
+ const buffer = (0, import_fs9.readFileSync)(path);
21058
21564
  const { width, height } = readImageDimensions2(buffer, mimeType);
21059
21565
  images.push({
21060
21566
  type: "generated_image",
21061
21567
  id: (0, import_crypto3.randomUUID)(),
21062
- filename: (0, import_path8.basename)(path),
21568
+ filename: (0, import_path9.basename)(path),
21063
21569
  mimeType,
21064
21570
  size: buffer.length,
21065
21571
  width,
@@ -21086,20 +21592,20 @@ function extractSessionMediaFromToolResult(toolId, content, cwd, toolName, optio
21086
21592
  const mimeByExt = kind === "video" ? VIDEO_MIME_BY_EXT : IMAGE_MIME_BY_EXT;
21087
21593
  for (const candidate of extractPathCandidates(content, options, extensionsPattern)) {
21088
21594
  const path = normalizePath(candidate, effectiveCwd);
21089
- if (!path || seen.has(path) || !(0, import_fs8.existsSync)(path)) continue;
21595
+ if (!path || seen.has(path) || !(0, import_fs9.existsSync)(path)) continue;
21090
21596
  seen.add(path);
21091
- const ext = (0, import_path8.extname)(path).toLowerCase();
21597
+ const ext = (0, import_path9.extname)(path).toLowerCase();
21092
21598
  const mimeType = mimeByExt[ext];
21093
21599
  if (!mimeType) continue;
21094
- const stat = (0, import_fs8.statSync)(path);
21600
+ const stat = (0, import_fs9.statSync)(path);
21095
21601
  if (!stat.isFile() || stat.size <= 0 || stat.size > maxBytes) continue;
21096
- const buffer = (0, import_fs8.readFileSync)(path);
21602
+ const buffer = (0, import_fs9.readFileSync)(path);
21097
21603
  const dimensions = kind === "image" ? readImageDimensions2(buffer, mimeType) : null;
21098
21604
  media.push({
21099
21605
  type: "session_media",
21100
21606
  kind,
21101
21607
  id: (0, import_crypto3.randomUUID)(),
21102
- filename: (0, import_path8.basename)(path),
21608
+ filename: (0, import_path9.basename)(path),
21103
21609
  mimeType,
21104
21610
  size: buffer.length,
21105
21611
  width: dimensions?.width,
@@ -23678,7 +24184,7 @@ var RunStartGate = class {
23678
24184
  };
23679
24185
 
23680
24186
  // src/version.ts
23681
- var AGENT_VERSION = "0.1.44";
24187
+ var AGENT_VERSION = "0.1.46";
23682
24188
 
23683
24189
  // src/workspace-relocation.ts
23684
24190
  var import_node_child_process3 = require("child_process");
@@ -25391,11 +25897,21 @@ var RuntimePresenter = class {
25391
25897
  onNotice(kind, message) {
25392
25898
  this.emitEvent({ type: "session_notice", kind, message, ts: Date.now() });
25393
25899
  }
25394
- onAssistantText(text) {
25395
- this.emitEvent({ type: "text", text, ts: Date.now() });
25900
+ onAssistantText(text, parentToolUseId) {
25901
+ this.emitEvent({
25902
+ type: "text",
25903
+ text,
25904
+ ts: Date.now(),
25905
+ ...parentToolUseId ? { parentToolUseId } : {}
25906
+ });
25396
25907
  }
25397
- onThinking(text) {
25398
- this.emitEvent({ type: "thinking", text, ts: Date.now() });
25908
+ onThinking(text, parentToolUseId) {
25909
+ this.emitEvent({
25910
+ type: "thinking",
25911
+ text,
25912
+ ts: Date.now(),
25913
+ ...parentToolUseId ? { parentToolUseId } : {}
25914
+ });
25399
25915
  }
25400
25916
  onToolUse(tool, input, toolId, parentToolUseId) {
25401
25917
  if (this.verifyWorkspaceLease && !this.verifyWorkspaceLease()) return;
@@ -27499,11 +28015,21 @@ var WebPresenter = class {
27499
28015
  onNotice(kind, message) {
27500
28016
  this.wsClient.emitEvent({ type: "session_notice", kind, message, ts: Date.now() });
27501
28017
  }
27502
- onAssistantText(text) {
27503
- this.wsClient.emitEvent({ type: "text", text, ts: Date.now() });
28018
+ onAssistantText(text, parentToolUseId) {
28019
+ this.wsClient.emitEvent({
28020
+ type: "text",
28021
+ text,
28022
+ ts: Date.now(),
28023
+ ...parentToolUseId ? { parentToolUseId } : {}
28024
+ });
27504
28025
  }
27505
- onThinking(text) {
27506
- this.wsClient.emitEvent({ type: "thinking", text, ts: Date.now() });
28026
+ onThinking(text, parentToolUseId) {
28027
+ this.wsClient.emitEvent({
28028
+ type: "thinking",
28029
+ text,
28030
+ ts: Date.now(),
28031
+ ...parentToolUseId ? { parentToolUseId } : {}
28032
+ });
27507
28033
  }
27508
28034
  hasKnownToolUse(toolId) {
27509
28035
  return this.toolNamesById.has(toolId);