@super-one/cli 0.73.0 → 0.74.0-alpha

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 (3) hide show
  1. package/MANIFEST.json +2 -2
  2. package/lib/cli.mjs +1220 -164
  3. package/package.json +1 -1
package/lib/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- process.env.SUPERONE_VARIANT = "stable";
1
+ process.env.SUPERONE_VARIANT = "alpha";
2
2
  import { createRequire as __superoneCreateRequire } from 'node:module';
3
3
  import { fileURLToPath as __superoneFileURLToPath } from 'node:url';
4
4
  import { dirname as __superoneDirname } from 'node:path';
@@ -137,8 +137,8 @@ import { fileURLToPath } from "node:url";
137
137
  function resolveCliReleaseVersion() {
138
138
  const fromEnv = process.env.SUPERONE_CLI_VERSION?.trim();
139
139
  if (fromEnv) return fromEnv;
140
- if ("0.73.0".trim()) {
141
- return "0.73.0".trim();
140
+ if ("0.74.0-alpha".trim()) {
141
+ return "0.74.0-alpha".trim();
142
142
  }
143
143
  const fromDist = readDistManifestVersion();
144
144
  if (fromDist) return fromDist;
@@ -409,7 +409,7 @@ var init_interaction_memory = __esm({
409
409
  });
410
410
 
411
411
  // ../../packages/shared/src/superone-tool-descriptions.ts
412
- var MANUAL_READ_DESCRIPTION, SETUP_MINI_APP_DEV_DESCRIPTION, REGISTER_DEV_MINIAPP_DESCRIPTION, PACK_MINI_APP_DESCRIPTION, UPDATE_SUPERONE_TYPES_DESCRIPTION, MINIAPP_DEV_PREVIEW_DESCRIPTION, MINIAPP_DEV_RELOAD_DESCRIPTION, MINIAPP_DEV_PREVIEW_INPUT_SCHEMA, MINIAPP_DEV_RELOAD_INPUT_SCHEMA, RENAME_SESSION_DESCRIPTION, SESSION_TAG_DESCRIPTION, SESSION_TAG_LIST_DESCRIPTION, PROJECT_LIST_DESCRIPTION, SESSION_LIST_DESCRIPTION, SESSION_SEARCH_DESCRIPTION, SESSION_READ_DESCRIPTION, SESSION_READ_MESSAGE_ID_DESCRIPTION, SESSION_READ_AROUND_DESCRIPTION, SESSION_READ_CURSOR_DESCRIPTION, SESSION_READ_LIMIT_DESCRIPTION, SESSION_READ_THINKING_DESCRIPTION, SESSION_TAGS_FILTER_DESCRIPTION, SESSION_TAG_MATCH_DESCRIPTION, SESSION_CLEANUP_DESCRIPTION, CONFIG_READ_DESCRIPTION, CONFIG_APPLY_DESCRIPTION, LIST_MEDIA_PROVIDERS_DESCRIPTION, GENERATE_IMAGE_DESCRIPTION, GENERATE_VIDEO_DESCRIPTION, VIDEO_STATUS_DESCRIPTION, SESSION_LIST_AGENTS_DESCRIPTION, SESSION_REQUEST_AGENTS_DESCRIPTION, LAUNCH_SUMMARY_DESCRIPTION, START_LAUNCH_ID_DESCRIPTION, LAUNCH_TASK_DESCRIPTION, LAUNCH_MODE_DESCRIPTION, LAUNCH_SESSION_ID_DESCRIPTION, LAUNCH_PERMISSION_MODE_DESCRIPTION, LAUNCH_ENVIRONMENT_DESCRIPTION, LAUNCH_CWD_DESCRIPTION, LAUNCH_WORKTREE_DESCRIPTION, LAUNCH_BRANCH_NAME_DESCRIPTION, SESSION_START_DESCRIPTION, SESSION_SEND_DESCRIPTION, SESSION_SEND_TO_DESCRIPTION, SESSION_SEND_CONTENT_DESCRIPTION, SESSION_RETRIEVE_DESCRIPTION, SESSION_RETRIEVE_FROM_DESCRIPTION, SESSION_SUGGEST_TASK_DESCRIPTION, SUGGEST_TASK_TITLE_DESCRIPTION, SUGGEST_TASK_TLDR_DESCRIPTION, SUGGEST_TASK_PROMPT_DESCRIPTION, SUGGEST_TASK_CWD_DESCRIPTION, AUTOMATION_LIST_DESCRIPTION, AUTOMATION_APPLY_DESCRIPTION, AUTOMATION_DELETE_DESCRIPTION, TERMINAL_TABS_DESCRIPTION, TERMINAL_SNAPSHOT_DESCRIPTION, TERMINAL_ACT_DESCRIPTION, TERMINAL_WAIT_FOR_DESCRIPTION, ENVIRONMENT_GET_INFO_DESCRIPTION, ENVIRONMENT_GET_INFO_IDS_DESCRIPTION, ENVIRONMENT_GET_INFO_INCLUDE_DESCRIPTION, ARCHIVE_ENVIRONMENT_DESCRIPTION;
412
+ var MANUAL_READ_DESCRIPTION, SETUP_MINI_APP_DEV_DESCRIPTION, REGISTER_DEV_MINIAPP_DESCRIPTION, PACK_MINI_APP_DESCRIPTION, UPDATE_SUPERONE_TYPES_DESCRIPTION, MINIAPP_DEV_PREVIEW_DESCRIPTION, MINIAPP_DEV_RELOAD_DESCRIPTION, MINIAPP_DEV_PREVIEW_INPUT_SCHEMA, MINIAPP_DEV_RELOAD_INPUT_SCHEMA, RENAME_SESSION_DESCRIPTION, SESSION_TAG_DESCRIPTION, SESSION_TAG_LIST_DESCRIPTION, PROJECT_LIST_DESCRIPTION, SESSION_LIST_DESCRIPTION, SESSION_SEARCH_DESCRIPTION, SESSION_READ_DESCRIPTION, SESSION_READ_MESSAGE_ID_DESCRIPTION, SESSION_READ_AROUND_DESCRIPTION, SESSION_READ_CURSOR_DESCRIPTION, SESSION_READ_LIMIT_DESCRIPTION, SESSION_READ_THINKING_DESCRIPTION, SESSION_TAGS_FILTER_DESCRIPTION, SESSION_TAG_MATCH_DESCRIPTION, SESSION_CLEANUP_DESCRIPTION, CONFIG_READ_DESCRIPTION, CONFIG_APPLY_DESCRIPTION, LIST_MEDIA_PROVIDERS_DESCRIPTION, GENERATE_IMAGE_DESCRIPTION, GENERATE_VIDEO_DESCRIPTION, VIDEO_STATUS_DESCRIPTION, SESSION_LIST_AGENTS_DESCRIPTION, SESSION_REQUEST_AGENTS_DESCRIPTION, LAUNCH_SUMMARY_DESCRIPTION, START_LAUNCH_ID_DESCRIPTION, LAUNCH_TASK_DESCRIPTION, LAUNCH_MODE_DESCRIPTION, LAUNCH_SESSION_ID_DESCRIPTION, LAUNCH_PERMISSION_MODE_DESCRIPTION, LAUNCH_ENVIRONMENT_DESCRIPTION, LAUNCH_CWD_DESCRIPTION, LAUNCH_WORKTREE_DESCRIPTION, LAUNCH_BRANCH_NAME_DESCRIPTION, SESSION_START_DESCRIPTION, SESSION_SEND_DESCRIPTION, SESSION_SEND_TO_DESCRIPTION, SESSION_SEND_CONTENT_DESCRIPTION, SESSION_RETRIEVE_DESCRIPTION, SESSION_RETRIEVE_FROM_DESCRIPTION, SESSION_SUGGEST_TASK_DESCRIPTION, SUGGEST_TASK_TITLE_DESCRIPTION, SUGGEST_TASK_TLDR_DESCRIPTION, SUGGEST_TASK_PROMPT_DESCRIPTION, SUGGEST_TASK_CWD_DESCRIPTION, AUTOMATION_LIST_DESCRIPTION, AUTOMATION_APPLY_DESCRIPTION, AUTOMATION_DELETE_DESCRIPTION, AGENT_PROFILE_LIST_DESCRIPTION, AGENT_PROFILE_APPLY_DESCRIPTION, AGENT_PROFILE_DELETE_DESCRIPTION, TERMINAL_TABS_DESCRIPTION, TERMINAL_SNAPSHOT_DESCRIPTION, TERMINAL_ACT_DESCRIPTION, TERMINAL_WAIT_FOR_DESCRIPTION, ENVIRONMENT_GET_INFO_DESCRIPTION, ENVIRONMENT_GET_INFO_IDS_DESCRIPTION, ENVIRONMENT_GET_INFO_INCLUDE_DESCRIPTION, ARCHIVE_ENVIRONMENT_DESCRIPTION, LAYOUT_SNAPSHOT_DESCRIPTION, LAYOUT_ACT_DESCRIPTION, LAYOUT_ACT_PATH_DESCRIPTION, LAYOUT_ACT_LINE_DESCRIPTION, LAYOUT_ACT_TAB_DESCRIPTION, LAYOUT_ACT_DIRECTION_DESCRIPTION, LAYOUT_ACT_SESSION_DESCRIPTION;
413
413
  var init_superone_tool_descriptions = __esm({
414
414
  "../../packages/shared/src/superone-tool-descriptions.ts"() {
415
415
  "use strict";
@@ -463,7 +463,7 @@ var init_superone_tool_descriptions = __esm({
463
463
  GENERATE_IMAGE_DESCRIPTION = "Generate or edit an image; pass source files in reference_image_paths for edits. Discover configured providers with media_list_providers when not already known. Read the matching media provider-task topic for unfamiliar options. Inspect previewPaths; savedPaths holds originals for export or edits. Check warnings for ignored options. Results display automatically; do not embed them again.";
464
464
  GENERATE_VIDEO_DESCRIPTION = "Submit a video generation; the tool opens a parameter review for user approval. Stop on cancelled or error; use returned feedback before retrying. Poll media_video_status about every 30s until generated or error. Results display automatically. Use media_list_providers for configured providers and the matching media provider-task manual for unfamiliar options.";
465
465
  VIDEO_STATUS_DESCRIPTION = "Advance a submitted video job and read its status: running, generated with savedPaths, or error with message. Poll about every 30 seconds while running: these calls download and save the completed video. Report it ready only after generated; stop on error.";
466
- SESSION_LIST_AGENTS_DESCRIPTION = "List the agent profiles available for user-approved child sessions. Only launchable agents are returned. Agents on other connected machines are listed under environments[] with the environmentId to launch them with. defaultConfig is the user's launch setup for the agent (model, effort, permission, sandbox, apiProviderId); leave out the config fields it already covers. apiProviders lists the subscription accounts and API keys it can run on. You may reuse one agentId for multiple launches. Skip this call when the user already named an agent with @ \u2014 that mention carries its agentId.";
466
+ SESSION_LIST_AGENTS_DESCRIPTION = "List the agents available for user-approved child sessions (launchable ones only): id, name, harness, description. Agents on other connected machines are listed under environments[] with the environmentId to launch them with. A launch without config runs on the user's setup for that agent. To set config, pass id (and environment for another machine): returns its defaultConfig, models with their efforts, and the apiProviders (accounts, API keys) it can run on. You may reuse one agentId for multiple launches. Skip this call when the user already named an agent with @ \u2014 that mention carries its agentId.";
467
467
  SESSION_REQUEST_AGENTS_DESCRIPTION = 'Request user approval for collaboration launches. See the mode field for spawn vs handoff vs link. Spawn/handoff: pick an agentId from session_collab_list_agents; require name, role, summary. Link: require sessionId + summary. Read read_manual({ domain: "product", topic: "collaboration" }) before the first launch in a session. User must approve; returns a launchId per launch. Pass the task to session_collab_start, not here.';
468
468
  LAUNCH_SUMMARY_DESCRIPTION = "Short 2\u20133 sentence summary the user approves in the confirm dialog. The full brief goes to session_collab_start.";
469
469
  START_LAUNCH_ID_DESCRIPTION = "A launchId returned by session_collab_request in this session.";
@@ -481,7 +481,7 @@ var init_superone_tool_descriptions = __esm({
481
481
  SESSION_SEND_CONTENT_DESCRIPTION = "Mailbox message body in Markdown. Prefer structured Markdown (headings, lists, code fences) for agent-to-agent handoffs; the SuperOne UI renders it as a Markdown preview.";
482
482
  SESSION_RETRIEVE_DESCRIPTION = 'Read queued Markdown messages from your collaboration peers and list those peers (session id, name, relation). Child peers may also report state (running, awaiting_approval, stalled, idle, error), lastActivityAt, and runningTool. Call after a collaboration wake, before acting on peer input, or to find out who you can message. This is a non-blocking read: status "empty" is not a retry signal. Do not sleep or poll; end your turn and wait for the next wake.';
483
483
  SESSION_RETRIEVE_FROM_DESCRIPTION = "Only read messages from these peer session ids. Omit to read from every peer.";
484
- SESSION_SUGGEST_TASK_DESCRIPTION = "Suggest a side task the user can launch later as its own session. Use when you notice a real issue outside the current task (a bug, cleanup, or follow-up) that should not derail it. Returns a taskId at once, without an approval prompt; keep working. The user sees a card and may launch it as a new top-level session or dismiss it; if it goes stale, say so in your reply. To hand work over now, use session_collab_request instead.";
484
+ SESSION_SUGGEST_TASK_DESCRIPTION = "Suggest a side task the user can launch later as its own session. Use when you notice a real issue outside the current task (a bug, cleanup, or follow-up) that should not derail it. Returns a taskId at once, without an approval prompt; keep working. The user sees a card and may launch it as a new top-level session; if it goes stale, say so in your reply. To hand work over now, use session_collab_request instead.";
485
485
  SUGGEST_TASK_TITLE_DESCRIPTION = "Card title, starting with a verb.";
486
486
  SUGGEST_TASK_TLDR_DESCRIPTION = "One or two sentences shown on the card.";
487
487
  SUGGEST_TASK_PROMPT_DESCRIPTION = "Markdown brief delivered as the new session's opening turn. The receiver cannot ask you anything, so include the context, file paths, and what done looks like.";
@@ -489,6 +489,9 @@ var init_superone_tool_descriptions = __esm({
489
489
  AUTOMATION_LIST_DESCRIPTION = "List project automations with schedule and last/next run. Pass id for full prompt, agentConfig, and schedule; filter by query or enabled. Find unknown ids here before automation_apply or automation_delete; check for duplicates before creation when needed.";
490
490
  AUTOMATION_APPLY_DESCRIPTION = 'Create or update a project automation. create needs name, prompt, schedule; update needs id plus any field (pause via enabled=false). Call automation_list first for ids; remove with automation_delete. Always opens a user confirmation dialog and applies nothing without approval. For schedule and agentConfig shapes see read_manual({ domain: "product", topic: "automation" }).';
491
491
  AUTOMATION_DELETE_DESCRIPTION = "Permanently delete project automations by id (from automation_list). Always opens a user confirmation dialog. Current project only. Prefer automation_list to choose ids first.";
492
+ AGENT_PROFILE_LIST_DESCRIPTION = "List agent profiles: named agents that session_collab_list_agents offers for delegation, plus the built-in <harness>-base rows. Without id: one row per profile (id, name, harness, base, short description). Pass id for its full description and instructions, runtime, launch defaults, and what that harness accepts: models, their efforts, permission modes, and its own options (each harness has different ones). Read this before agent_profile_apply or agent_profile_delete.";
493
+ AGENT_PROFILE_APPLY_DESCRIPTION = "Create or update an agent profile. create needs harnessId, name, description; update needs id plus the fields to change (empty string clears model, effort, permissionMode or instructions; null clears an option). description is what other agents read to pick a delegate, so say what this agent is for. model, effort, permissionMode and options must be ones the harness accepts: read agent_profile_list with the <harness>-base id first. Built-in <harness>-base rows are read-only; remove profiles with agent_profile_delete. Always opens a user confirmation dialog, where the user may edit a new profile before approving; applies nothing without approval.";
494
+ AGENT_PROFILE_DELETE_DESCRIPTION = "Permanently delete agent profiles by id (from agent_profile_list). Sessions already started on one fall back to its built-in harness agent. Built-in <harness>-base rows cannot be deleted. Always opens a user confirmation dialog.";
492
495
  TERMINAL_TABS_DESCRIPTION = "Only for commands that run until stopped (servers, watchers) or need keyboard input (REPLs, TUIs, ssh, wizards). Non-interactive commands that finish (build, test, install, git) use your shell tool, even if slow. action=list (default) returns this session's tabs plus the user's as a TOON table; other sessions' tabs are hidden. action=run asks to approve `command`, types it into a new or idle tab, and returns the screen; you control the tab only while that command is in the foreground. action=attach asks to control a command already running in a user tab. action=close kills a tab you opened, never one the user is using. For open tabs: terminal_act / terminal_wait_for / terminal_snapshot.";
493
496
  TERMINAL_SNAPSHOT_DESCRIPTION = "Read a terminal tab as rendered text. `include` picks sections: screen (visible rows, default), scrollback (last `tail` lines including scrolled-off output), cursor, meta (title, cwd, status, foreground command, control). Use screen for prompts and full-screen programs, scrollback for server logs. Output over the tail cap is spilled to a file and returned as path + preview. Prefer this before terminal_act; use terminal_wait_for instead of polling.";
494
497
  TERMINAL_ACT_DESCRIPTION = 'Send input to a terminal tab you control. actions is an array, e.g. [{type:"type",text:"yes"}] or [{type:"key",key:"Ctrl+C"}]; types: type (Enter by default), key (Enter, Tab, Escape, Up, Ctrl+C, F1\u2026), raw, resize, wait. ONE action per call by default; batch 2\u201320 only for an uninterruptible sequence (answer a wizard). Fail-fast. expect holds the call open until a screen condition is met (text, textGone, idleMs, exited); the screen after the batch is returned. Rejected with status=rejected when the approved command has exited or the user took over \u2014 do not retry, call terminal_tabs run again or ask. description is shown to the user instead of raw keystrokes.';
@@ -497,15 +500,30 @@ var init_superone_tool_descriptions = __esm({
497
500
  ENVIRONMENT_GET_INFO_IDS_DESCRIPTION = "Environments to read; omit for all.";
498
501
  ENVIRONMENT_GET_INFO_INCLUDE_DESCRIPTION = 'Detail groups to add. Default ["hardware"]; [] returns IDs, labels and state only.';
499
502
  ARCHIVE_ENVIRONMENT_DESCRIPTION = "Target environment ID from environment_get_info. Omit or use localhost for the calling session host.";
503
+ LAYOUT_SNAPSHOT_DESCRIPTION = "Read the SuperOne desktop layout around your session: whether the user can see your chat, the sidebar, your activity panel (open, side, maximized) and its tabs (id, kind, title, active, openedBy), your bottom terminal, and the split view. Call it for tab ids before layout_act focus/close/split, or to check what the user is looking at.";
504
+ LAYOUT_ACT_DESCRIPTION = "Arrange the SuperOne desktop for the user: open a file (path, line) as a tab; focus, split or close tabs by id; show, hide, maximize or move your activity panel; show or hide your bottom terminal; collapse the sidebar; put a session you launched beside yours (split_session / close_split). Open browser and terminal tabs with browser_tabs / terminal_tabs. You can close only tabs and panes you opened. It never moves the user: in the background your own layout changes wait for them (status queued) and window-wide ones are skipped. `visible` says whether the user sees the result now.";
505
+ LAYOUT_ACT_PATH_DESCRIPTION = "open_file: the file, absolute or relative to your working folder.";
506
+ LAYOUT_ACT_LINE_DESCRIPTION = "open_file: 1-based line to reveal.";
507
+ LAYOUT_ACT_TAB_DESCRIPTION = "Tab id from layout_snapshot (browser_tabs / terminal_tabs ids work too). focus_tab, close_tab, split_tab; maximize_panel defaults to the active tab.";
508
+ LAYOUT_ACT_DIRECTION_DESCRIPTION = "split_tab / split_session. Default right.";
509
+ LAYOUT_ACT_SESSION_DESCRIPTION = "split_session / close_split: a session you launched with session_collab_*.";
500
510
  }
501
511
  });
502
512
 
503
513
  // ../../packages/shared/src/environment/host-action-collaboration-descriptors.ts
504
- var SESSION_SUGGEST_TASK_INPUT_SCHEMA, HOST_ACTION_COLLABORATION_DESCRIPTORS;
514
+ var SESSION_LIST_AGENTS_INPUT_SCHEMA, SESSION_SUGGEST_TASK_INPUT_SCHEMA, HOST_ACTION_COLLABORATION_DESCRIPTORS;
505
515
  var init_host_action_collaboration_descriptors = __esm({
506
516
  "../../packages/shared/src/environment/host-action-collaboration-descriptors.ts"() {
507
517
  "use strict";
508
518
  init_superone_tool_descriptions();
519
+ SESSION_LIST_AGENTS_INPUT_SCHEMA = {
520
+ type: "object",
521
+ properties: {
522
+ id: { type: "string", description: "An agent id from the list. Returns what a launch of that agent can set." },
523
+ environment: { type: "string", description: "With id: the environmentId the agent is listed under in environments[]." }
524
+ },
525
+ additionalProperties: false
526
+ };
509
527
  SESSION_SUGGEST_TASK_INPUT_SCHEMA = {
510
528
  type: "object",
511
529
  properties: {
@@ -521,11 +539,7 @@ var init_host_action_collaboration_descriptors = __esm({
521
539
  {
522
540
  "name": "session_collab_list_agents",
523
541
  "description": SESSION_LIST_AGENTS_DESCRIPTION,
524
- "inputSchema": {
525
- "type": "object",
526
- "properties": {},
527
- "additionalProperties": false
528
- }
542
+ "inputSchema": SESSION_LIST_AGENTS_INPUT_SCHEMA
529
543
  },
530
544
  {
531
545
  "name": "session_collab_request",
@@ -3616,6 +3630,85 @@ var init_host_action_automation_descriptors = __esm({
3616
3630
  }
3617
3631
  });
3618
3632
 
3633
+ // ../../packages/shared/src/environment/host-action-agent-profile-descriptors.ts
3634
+ var AGENT_PROFILE_LIST_INPUT_SCHEMA, AGENT_PROFILE_APPLY_INPUT_SCHEMA, AGENT_PROFILE_DELETE_INPUT_SCHEMA, HOST_ACTION_AGENT_PROFILE_DESCRIPTORS;
3635
+ var init_host_action_agent_profile_descriptors = __esm({
3636
+ "../../packages/shared/src/environment/host-action-agent-profile-descriptors.ts"() {
3637
+ "use strict";
3638
+ init_superone_tool_descriptions();
3639
+ AGENT_PROFILE_LIST_INPUT_SCHEMA = {
3640
+ type: "object",
3641
+ properties: {
3642
+ id: {
3643
+ type: "string",
3644
+ description: "Profile id. Returns full instructions, launch defaults, and the harness model options."
3645
+ }
3646
+ },
3647
+ additionalProperties: false
3648
+ };
3649
+ AGENT_PROFILE_APPLY_INPUT_SCHEMA = {
3650
+ type: "object",
3651
+ properties: {
3652
+ action: { type: "string", enum: ["create", "update"], description: "create a new profile, or update an existing one." },
3653
+ id: { type: "string", description: "Required for update. Profile id from agent_profile_list." },
3654
+ harnessId: {
3655
+ type: "string",
3656
+ enum: ["claude", "codex", "acp", "opencode", "cursor", "dsh"],
3657
+ description: "Required for create; fixed afterwards."
3658
+ },
3659
+ name: { type: "string", description: "Display name and @-mention label. Required for create." },
3660
+ description: { type: "string", description: "What this agent is for, read by other agents choosing a delegate. Required for create." },
3661
+ instructions: { type: "string", description: "Added to the agent's system prompt on every launch." },
3662
+ model: { type: "string", description: "Base model id from the harness catalog. Omit to follow the user's default." },
3663
+ effort: { type: "string", description: "Effort level the model supports." },
3664
+ permissionMode: {
3665
+ type: "string",
3666
+ description: "Permission mode new sessions start in; one of the harness's modes (agent_profile_list({ id }) lists them). Omit to follow the user's default."
3667
+ },
3668
+ options: {
3669
+ type: "object",
3670
+ description: "The harness's own settings; agent_profile_list({ id }) lists which ones its models accept. null clears one.",
3671
+ properties: {
3672
+ ultracode: { type: ["boolean", "null"], description: "Claude: Ultracode, on models with xhigh effort." },
3673
+ fastMode: { type: ["boolean", "null"], description: "Codex: the model's Fast service tier." },
3674
+ contextWindow: { type: ["integer", "null"], description: "ACP: one of the model's context windows, in tokens." },
3675
+ mode: { type: ["string", "null"], description: "ACP: a session mode the agent lists." },
3676
+ agent: { type: ["string", "null"], description: "OpenCode: native agent id." },
3677
+ agentPreset: { type: ["string", "null"], description: "DeepSeek: agent preset id." },
3678
+ modelParams: {
3679
+ type: ["object", "null"],
3680
+ additionalProperties: { type: "string" },
3681
+ description: "Cursor: model parameter values by parameter id."
3682
+ }
3683
+ },
3684
+ additionalProperties: false
3685
+ }
3686
+ },
3687
+ required: ["action"],
3688
+ additionalProperties: false
3689
+ };
3690
+ AGENT_PROFILE_DELETE_INPUT_SCHEMA = {
3691
+ type: "object",
3692
+ properties: {
3693
+ ids: {
3694
+ type: "array",
3695
+ items: { type: "string" },
3696
+ minItems: 1,
3697
+ maxItems: 20,
3698
+ description: "Profile ids from agent_profile_list."
3699
+ }
3700
+ },
3701
+ required: ["ids"],
3702
+ additionalProperties: false
3703
+ };
3704
+ HOST_ACTION_AGENT_PROFILE_DESCRIPTORS = [
3705
+ { name: "agent_profile_list", description: AGENT_PROFILE_LIST_DESCRIPTION, inputSchema: AGENT_PROFILE_LIST_INPUT_SCHEMA },
3706
+ { name: "agent_profile_apply", description: AGENT_PROFILE_APPLY_DESCRIPTION, inputSchema: AGENT_PROFILE_APPLY_INPUT_SCHEMA },
3707
+ { name: "agent_profile_delete", description: AGENT_PROFILE_DELETE_DESCRIPTION, inputSchema: AGENT_PROFILE_DELETE_INPUT_SCHEMA }
3708
+ ];
3709
+ }
3710
+ });
3711
+
3619
3712
  // ../../packages/shared/src/environment/host-action-device-descriptors.ts
3620
3713
  var HOST_ACTION_DEVICE_DESCRIPTORS;
3621
3714
  var init_host_action_device_descriptors = __esm({
@@ -4468,6 +4561,66 @@ var init_host_action_terminal_descriptors = __esm({
4468
4561
  }
4469
4562
  });
4470
4563
 
4564
+ // ../../packages/shared/src/layout-control.ts
4565
+ var LAYOUT_ACT_ACTIONS;
4566
+ var init_layout_control = __esm({
4567
+ "../../packages/shared/src/layout-control.ts"() {
4568
+ "use strict";
4569
+ LAYOUT_ACT_ACTIONS = [
4570
+ "open_file",
4571
+ "focus_tab",
4572
+ "close_tab",
4573
+ "split_tab",
4574
+ "show_panel",
4575
+ "hide_panel",
4576
+ "maximize_panel",
4577
+ "restore_panel",
4578
+ "panel_side",
4579
+ "show_sidebar",
4580
+ "hide_sidebar",
4581
+ "show_terminal",
4582
+ "hide_terminal",
4583
+ "split_session",
4584
+ "close_split"
4585
+ ];
4586
+ }
4587
+ });
4588
+
4589
+ // ../../packages/shared/src/environment/host-action-layout-descriptors.ts
4590
+ var HOST_ACTION_LAYOUT_DESCRIPTORS;
4591
+ var init_host_action_layout_descriptors = __esm({
4592
+ "../../packages/shared/src/environment/host-action-layout-descriptors.ts"() {
4593
+ "use strict";
4594
+ init_layout_control();
4595
+ init_superone_tool_descriptions();
4596
+ HOST_ACTION_LAYOUT_DESCRIPTORS = [
4597
+ {
4598
+ name: "layout_snapshot",
4599
+ description: LAYOUT_SNAPSHOT_DESCRIPTION,
4600
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
4601
+ },
4602
+ {
4603
+ name: "layout_act",
4604
+ description: LAYOUT_ACT_DESCRIPTION,
4605
+ inputSchema: {
4606
+ type: "object",
4607
+ properties: {
4608
+ action: { type: "string", enum: [...LAYOUT_ACT_ACTIONS] },
4609
+ path: { type: "string", description: LAYOUT_ACT_PATH_DESCRIPTION },
4610
+ line: { type: "integer", minimum: 1, description: LAYOUT_ACT_LINE_DESCRIPTION },
4611
+ tab: { type: "string", description: LAYOUT_ACT_TAB_DESCRIPTION },
4612
+ direction: { type: "string", enum: ["right", "down"], description: LAYOUT_ACT_DIRECTION_DESCRIPTION },
4613
+ side: { type: "string", enum: ["left", "right"], description: "panel_side." },
4614
+ sessionId: { type: "string", description: LAYOUT_ACT_SESSION_DESCRIPTION }
4615
+ },
4616
+ required: ["action"],
4617
+ additionalProperties: false
4618
+ }
4619
+ }
4620
+ ];
4621
+ }
4622
+ });
4623
+
4471
4624
  // ../../packages/shared/src/environment/host-action-superone-descriptors.ts
4472
4625
  var HOST_ACTION_SUPERONE_TOOL_DESCRIPTORS;
4473
4626
  var init_host_action_superone_descriptors = __esm({
@@ -4483,9 +4636,11 @@ var init_host_action_superone_descriptors = __esm({
4483
4636
  init_host_action_computer_descriptors();
4484
4637
  init_host_action_widget_descriptors();
4485
4638
  init_host_action_automation_descriptors();
4639
+ init_host_action_agent_profile_descriptors();
4486
4640
  init_host_action_device_descriptors();
4487
4641
  init_host_action_browser_perf_descriptors();
4488
4642
  init_host_action_terminal_descriptors();
4643
+ init_host_action_layout_descriptors();
4489
4644
  HOST_ACTION_SUPERONE_TOOL_DESCRIPTORS = [
4490
4645
  ...INTERACTION_MEMORY_TOOL_DEFS,
4491
4646
  ...HOST_ACTION_COLLABORATION_DESCRIPTORS,
@@ -4497,7 +4652,9 @@ var init_host_action_superone_descriptors = __esm({
4497
4652
  ...HOST_ACTION_COMPUTER_DESCRIPTORS,
4498
4653
  ...HOST_ACTION_WIDGET_DESCRIPTORS,
4499
4654
  ...HOST_ACTION_AUTOMATION_DESCRIPTORS,
4655
+ ...HOST_ACTION_AGENT_PROFILE_DESCRIPTORS,
4500
4656
  ...HOST_ACTION_TERMINAL_DESCRIPTORS,
4657
+ ...HOST_ACTION_LAYOUT_DESCRIPTORS,
4501
4658
  ...HOST_ACTION_DEVICE_DESCRIPTORS,
4502
4659
  ...HOST_ACTION_BROWSER_PERF_DESCRIPTORS
4503
4660
  ];
@@ -4508,6 +4665,9 @@ var init_host_action_superone_descriptors = __esm({
4508
4665
  function isNodeLocalSuperoneTool(name) {
4509
4666
  return NODE_LOCAL_SUPERONE_TOOL_NAMES.includes(name);
4510
4667
  }
4668
+ function isLocalSessionOnlySuperoneTool(name) {
4669
+ return LOCAL_SESSION_ONLY_SUPERONE_TOOL_NAMES.includes(name);
4670
+ }
4511
4671
  function classifyHostActionTool(name) {
4512
4672
  if (BROWSER_READ_NAMES.has(name)) {
4513
4673
  return {
@@ -4537,7 +4697,7 @@ function classifyHostActionTool(name) {
4537
4697
  function listHostActionSuperoneTools() {
4538
4698
  return HOST_ACTION_SUPERONE_TOOL_CATALOG;
4539
4699
  }
4540
- var BROWSER_READ_NAMES, BROWSER_ACT_PREFIX, COMPUTER_PREFIX, NODE_LOCAL_SUPERONE_TOOL_NAMES, SUPERONE_READ_NAMES, HOST_ACTION_BROWSER_TOOL_CATALOG, HOST_ACTION_SUPERONE_TOOL_CATALOG;
4700
+ var BROWSER_READ_NAMES, BROWSER_ACT_PREFIX, COMPUTER_PREFIX, NODE_LOCAL_SUPERONE_TOOL_NAMES, LOCAL_SESSION_ONLY_SUPERONE_TOOL_NAMES, SUPERONE_READ_NAMES, HOST_ACTION_BROWSER_TOOL_CATALOG, HOST_ACTION_SUPERONE_TOOL_CATALOG;
4541
4701
  var init_host_action_browser_catalog = __esm({
4542
4702
  "../../packages/shared/src/environment/host-action-browser-catalog.ts"() {
4543
4703
  "use strict";
@@ -4572,6 +4732,11 @@ var init_host_action_browser_catalog = __esm({
4572
4732
  "session_collab_retrieve",
4573
4733
  "session_suggest_task"
4574
4734
  ];
4735
+ LOCAL_SESSION_ONLY_SUPERONE_TOOL_NAMES = [
4736
+ "agent_profile_list",
4737
+ "agent_profile_apply",
4738
+ "agent_profile_delete"
4739
+ ];
4575
4740
  SUPERONE_READ_NAMES = /* @__PURE__ */ new Set([
4576
4741
  "read_manual",
4577
4742
  "config_read",
@@ -4580,6 +4745,7 @@ var init_host_action_browser_catalog = __esm({
4580
4745
  "widget_list_templates",
4581
4746
  "miniapp_list",
4582
4747
  "automation_list",
4748
+ "agent_profile_list",
4583
4749
  "device_list",
4584
4750
  "device_snapshot",
4585
4751
  "device_query",
@@ -4591,7 +4757,7 @@ var init_host_action_browser_catalog = __esm({
4591
4757
  "computer_query",
4592
4758
  "computer_wait_for"
4593
4759
  ]);
4594
- HOST_ACTION_BROWSER_TOOL_CATALOG = HOST_ACTION_SUPERONE_TOOL_DESCRIPTORS.filter((d) => !isNodeLocalSuperoneTool(d.name)).map(
4760
+ HOST_ACTION_BROWSER_TOOL_CATALOG = HOST_ACTION_SUPERONE_TOOL_DESCRIPTORS.filter((d) => !isNodeLocalSuperoneTool(d.name) && !isLocalSessionOnlySuperoneTool(d.name)).map(
4595
4761
  (d) => {
4596
4762
  const cls = classifyHostActionTool(d.name);
4597
4763
  return {
@@ -9302,7 +9468,7 @@ function isStaticHostOwnedSuperoneToolQualified(qualifiedName) {
9302
9468
  function isNeverAutoAllowSuperoneBareName(bare) {
9303
9469
  return NEVER_AUTO_ALLOW_SUPERONE_BARE_NAMES.includes(bare);
9304
9470
  }
9305
- var MCP_SUPERONE_TOOL_PREFIX, BROWSER_PRIMITIVE_TOOL_NAMES, BROWSER_ACTION_TOOL_NAMES, BROWSER_LEGACY_TOOL_NAMES, BROWSER_COMPACT_TOOL_NAMES, BROWSER_TOOL_NAMES, COMPUTER_USE_TOOL_NAMES, DEVICE_AGENT_TOOL_NAMES, TERMINAL_TOOL_NAMES, BUILT_IN_SUPERONE_TOOL_NAMES, MINIAPP_LIST_BARE_NAME, MINIAPP_CALL_BARE_NAME, NEVER_AUTO_ALLOW_SUPERONE_BARE_NAMES, STATIC_HOST_OWNED_SUPERONE_QUALIFIED_TOOL_NAMES;
9471
+ var MCP_SUPERONE_TOOL_PREFIX, BROWSER_PRIMITIVE_TOOL_NAMES, BROWSER_ACTION_TOOL_NAMES, BROWSER_LEGACY_TOOL_NAMES, BROWSER_COMPACT_TOOL_NAMES, BROWSER_TOOL_NAMES, COMPUTER_USE_TOOL_NAMES, DEVICE_AGENT_TOOL_NAMES, TERMINAL_TOOL_NAMES, LAYOUT_TOOL_NAMES, BUILT_IN_SUPERONE_TOOL_NAMES, MINIAPP_LIST_BARE_NAME, MINIAPP_CALL_BARE_NAME, NEVER_AUTO_ALLOW_SUPERONE_BARE_NAMES, STATIC_HOST_OWNED_SUPERONE_QUALIFIED_TOOL_NAMES;
9306
9472
  var init_superone_host_owned_tools = __esm({
9307
9473
  "../../packages/shared/src/superone-host-owned-tools.ts"() {
9308
9474
  "use strict";
@@ -9398,6 +9564,7 @@ var init_superone_host_owned_tools = __esm({
9398
9564
  "terminal_act",
9399
9565
  "terminal_wait_for"
9400
9566
  ];
9567
+ LAYOUT_TOOL_NAMES = ["layout_snapshot", "layout_act"];
9401
9568
  BUILT_IN_SUPERONE_TOOL_NAMES = [
9402
9569
  "browser_memory_read",
9403
9570
  "browser_memory_write",
@@ -9438,9 +9605,13 @@ var init_superone_host_owned_tools = __esm({
9438
9605
  "automation_list",
9439
9606
  "automation_apply",
9440
9607
  "automation_delete",
9608
+ "agent_profile_list",
9609
+ "agent_profile_apply",
9610
+ "agent_profile_delete",
9441
9611
  ...BROWSER_TOOL_NAMES,
9442
9612
  ...DEVICE_AGENT_TOOL_NAMES,
9443
- ...TERMINAL_TOOL_NAMES
9613
+ ...TERMINAL_TOOL_NAMES,
9614
+ ...LAYOUT_TOOL_NAMES
9444
9615
  ];
9445
9616
  MINIAPP_LIST_BARE_NAME = "miniapp_list";
9446
9617
  MINIAPP_CALL_BARE_NAME = "miniapp_call";
@@ -11589,6 +11760,42 @@ var init_artifact_wakes = __esm({
11589
11760
  }
11590
11761
  });
11591
11762
 
11763
+ // ../../packages/runtime/src/session/input-admission.ts
11764
+ var InputAdmission;
11765
+ var init_input_admission = __esm({
11766
+ "../../packages/runtime/src/session/input-admission.ts"() {
11767
+ "use strict";
11768
+ InputAdmission = class {
11769
+ constructor(delivery) {
11770
+ this.delivery = delivery;
11771
+ this.promise = new Promise((resolve21, reject) => {
11772
+ this.resolve = resolve21;
11773
+ this.rejectPromise = reject;
11774
+ });
11775
+ }
11776
+ delivery;
11777
+ promise;
11778
+ resolve;
11779
+ rejectPromise;
11780
+ settled = false;
11781
+ accept() {
11782
+ if (this.settled) return;
11783
+ this.delivery.onInputAccepted();
11784
+ this.settled = true;
11785
+ this.resolve();
11786
+ }
11787
+ beforeInput() {
11788
+ this.delivery.beforeInput?.();
11789
+ }
11790
+ reject(error51) {
11791
+ if (this.settled) return;
11792
+ this.settled = true;
11793
+ this.rejectPromise(error51);
11794
+ }
11795
+ };
11796
+ }
11797
+ });
11798
+
11592
11799
  // ../../packages/shared/src/codex-accounts.ts
11593
11800
  function isCodexAccountProvider(id) {
11594
11801
  return !!id?.startsWith(CODEX_ACCOUNT_PREFIX);
@@ -12932,7 +13139,11 @@ function createNodeSessionEventMapper(ctx) {
12932
13139
  }
12933
13140
  const interruptedId = lastAssistantId ?? asString2(payload.messageId);
12934
13141
  if (interruptedId) {
12935
- push({ type: "message_interrupted", messageId: interruptedId });
13142
+ push({
13143
+ type: "message_interrupted",
13144
+ messageId: interruptedId,
13145
+ ...typeof payload.reason === "string" ? { reason: payload.reason } : {}
13146
+ });
12936
13147
  }
12937
13148
  lastAssistantId = null;
12938
13149
  push({ type: "status_change", status: "idle" });
@@ -15043,6 +15254,7 @@ var init_session_runtime = __esm({
15043
15254
  init_mcp_apps_index();
15044
15255
  init_attachment_state();
15045
15256
  init_artifact_wakes();
15257
+ init_input_admission();
15046
15258
  init_codex_accounts();
15047
15259
  init_session_send();
15048
15260
  init_send_failure();
@@ -15781,7 +15993,7 @@ var init_session_runtime = __esm({
15781
15993
  * Host-initiated turn without a control lease (collaboration initial task).
15782
15994
  * Still rejects closed/disposing sessions. Falls back to durable session settings.
15783
15995
  */
15784
- async sendWithoutLease(input) {
15996
+ async sendWithoutLease(input, delivery) {
15785
15997
  if (this.disposing) {
15786
15998
  throw Object.assign(new Error("runtime is shutting down"), { code: "failed_precondition" });
15787
15999
  }
@@ -15796,7 +16008,9 @@ var init_session_runtime = __esm({
15796
16008
  if (typeof stored === "string" && stored.trim()) return stored.trim();
15797
16009
  return stored ?? void 0;
15798
16010
  };
16011
+ const admission = delivery ? new InputAdmission(delivery) : void 0;
15799
16012
  const turnOpts = {
16013
+ inputAdmission: admission,
15800
16014
  text: input.text,
15801
16015
  requestId: input.requestId,
15802
16016
  model: pick4(input.model, session.model),
@@ -15825,12 +16039,15 @@ var init_session_runtime = __esm({
15825
16039
  turnOpts.turnKind = "steer";
15826
16040
  }
15827
16041
  this.beginTurn(session, turnOpts);
16042
+ if (admission) await admission.promise;
15828
16043
  return this.clone(session);
15829
16044
  }
15830
16045
  this.enqueueTurn(session, turnOpts);
16046
+ if (admission) await admission.promise;
15831
16047
  return this.clone(session);
15832
16048
  }
15833
16049
  this.beginTurn(session, turnOpts);
16050
+ if (admission) await admission.promise;
15834
16051
  return this.clone(session);
15835
16052
  }
15836
16053
  /**
@@ -16109,12 +16326,15 @@ var init_session_runtime = __esm({
16109
16326
  const requestId = opts.requestId;
16110
16327
  let started = false;
16111
16328
  const markStarted = () => {
16329
+ opts.inputAdmission?.accept();
16112
16330
  started = true;
16113
16331
  };
16332
+ let inputFailure = new Error("Harness did not accept notification input");
16114
16333
  const permissionMode = typeof opts.permissionMode === "string" && opts.permissionMode.trim() ? opts.permissionMode.trim() : void 0;
16115
16334
  const sandboxMode = typeof opts.sandboxMode === "string" && opts.sandboxMode.trim() ? opts.sandboxMode.trim() : void 0;
16116
16335
  try {
16117
16336
  const modelInput = mcpAppModelInput({ text: opts.text, images: opts.images?.map((image) => ({ ...image, name: image.name ?? "Attachment" })) }, this.mcpAppContextInput(session.sessionId));
16337
+ opts.inputAdmission?.beforeInput();
16118
16338
  const result3 = await this.turnRunner({
16119
16339
  session: this.clone(session),
16120
16340
  messageId: assistantId,
@@ -16144,7 +16364,7 @@ var init_session_runtime = __esm({
16144
16364
  this.persist(session);
16145
16365
  },
16146
16366
  onDelta: (delta) => {
16147
- if (delta) started = true;
16367
+ if (delta) markStarted();
16148
16368
  if (abort.signal.aborted) return;
16149
16369
  assistantText += delta;
16150
16370
  this.events.appendSession({
@@ -16155,13 +16375,13 @@ var init_session_runtime = __esm({
16155
16375
  });
16156
16376
  },
16157
16377
  onEvent: (event) => {
16158
- if (event.kind !== "status") started = true;
16378
+ if (event.kind !== "status") markStarted();
16159
16379
  this.projectOnEvent(session, event, abort.signal, requestId, (delta) => {
16160
16380
  assistantText += delta;
16161
16381
  });
16162
16382
  },
16163
16383
  onAgentEvent: (event) => {
16164
- if (isAgentOutputEvent(event)) started = true;
16384
+ if (isAgentOutputEvent(event)) markStarted();
16165
16385
  if (abort.signal.aborted) return;
16166
16386
  this.appendAgentEvent(session.sessionId, event, requestId);
16167
16387
  if (session.harnessId === "opencode" && event.type === "message_interrupted" && event.messageId === assistantId) abort.abort();
@@ -16187,6 +16407,8 @@ var init_session_runtime = __esm({
16187
16407
  onQuestion: (interaction) => (markStarted(), this.waitForQuestionDecision(session, interaction, abort.signal, requestId)),
16188
16408
  onPlan: (interaction) => (markStarted(), this.waitForPlanDecision(session, interaction, abort.signal, requestId))
16189
16409
  });
16410
+ if (result3.finalText) markStarted();
16411
+ if (opts.inputAdmission && !started) throw inputFailure;
16190
16412
  if (session.closed) {
16191
16413
  } else if (abort.signal.aborted) {
16192
16414
  session.status = "interrupted";
@@ -16228,6 +16450,7 @@ var init_session_runtime = __esm({
16228
16450
  }
16229
16451
  }
16230
16452
  } catch (err) {
16453
+ inputFailure = err;
16231
16454
  if (session.closed) {
16232
16455
  } else if (abort.signal.aborted) {
16233
16456
  session.status = "interrupted";
@@ -16261,6 +16484,7 @@ var init_session_runtime = __esm({
16261
16484
  }
16262
16485
  }
16263
16486
  } finally {
16487
+ if (!started) opts.inputAdmission?.reject(inputFailure);
16264
16488
  const sid = session.sessionId;
16265
16489
  const remainingAfter = Math.max(0, (this.activeTurnCounts.get(sid) ?? 1) - 1);
16266
16490
  if (remainingAfter <= 0) this.activeTurnCounts.delete(sid);
@@ -16294,6 +16518,7 @@ var init_session_runtime = __esm({
16294
16518
  } else if (session.closed || session.status === "interrupted" || session.status === "error") {
16295
16519
  const dropped = this.turnQueues.get(sid) ?? [];
16296
16520
  this.turnQueues.delete(sid);
16521
+ for (const item of dropped) item.inputAdmission?.reject(new Error(QUEUED_SEND_DROPPED));
16297
16522
  if (!session.closed) {
16298
16523
  const marked = dropped.filter((item) => this.markSendFailed(session, item.userBlockId, QUEUED_SEND_DROPPED));
16299
16524
  if (marked.length > 0) this.persist(session);
@@ -20706,6 +20931,521 @@ var init_session_provider_definitions = __esm({
20706
20931
  }
20707
20932
  });
20708
20933
 
20934
+ // ../../packages/shared/src/launch-options.ts
20935
+ var HARNESS_LAUNCH_OPTIONS;
20936
+ var init_launch_options = __esm({
20937
+ "../../packages/shared/src/launch-options.ts"() {
20938
+ "use strict";
20939
+ HARNESS_LAUNCH_OPTIONS = {
20940
+ claude: { permissionModes: ["default", "plan", "auto", "acceptEdits", "dontAsk", "bypassPermissions"], sandboxModes: ["off", "on", "auto"], defaultPermissionMode: "default" },
20941
+ codex: { permissionModes: ["default", "auto", "bypassPermissions"], sandboxModes: [], defaultPermissionMode: "default" },
20942
+ acp: { permissionModes: ["default", "plan", "auto", "bypassPermissions"], sandboxModes: [], defaultPermissionMode: "default" },
20943
+ // OpenCode selects native agents; permissions come from its own configuration.
20944
+ opencode: { permissionModes: [], sandboxModes: [], defaultPermissionMode: "default" },
20945
+ cursor: { permissionModes: ["agent", "plan", "bypassPermissions"], sandboxModes: ["off", "on"], defaultPermissionMode: "agent" },
20946
+ // Read-only first for display; dsh's own default preset is `workspace-write` (`default`).
20947
+ dsh: { permissionModes: ["plan", "default", "bypassPermissions"], sandboxModes: [], defaultPermissionMode: "default" }
20948
+ };
20949
+ }
20950
+ });
20951
+
20952
+ // ../../packages/shared/src/codex-fast-mode.ts
20953
+ function findCodexFastServiceTier(model) {
20954
+ return model?.serviceTiers?.find((tier) => tier.id === "fast" || tier.id === "priority" || tier.name.trim().toLowerCase() === "fast");
20955
+ }
20956
+ var init_codex_fast_mode = __esm({
20957
+ "../../packages/shared/src/codex-fast-mode.ts"() {
20958
+ "use strict";
20959
+ }
20960
+ });
20961
+
20962
+ // ../../packages/shared/src/model-option-params.ts
20963
+ function isEffortCatalogParam(param) {
20964
+ if (param.id === "thinking" || /^thinking$/i.test(param.displayName ?? "")) return false;
20965
+ return /^(effort|reasoning)$/i.test(param.id) || /effort|reasoning/i.test(param.displayName ?? "");
20966
+ }
20967
+ function findEffortCatalogParam(parameters) {
20968
+ const candidates = parameters.filter(isEffortCatalogParam);
20969
+ return candidates.find((param) => param.id === "effort") ?? candidates.find((param) => param.id === "reasoning") ?? candidates[0];
20970
+ }
20971
+ function isToggleCatalogParam(param) {
20972
+ const values = new Set(param.values.map((value) => value.value));
20973
+ return values.size === 2 && values.has("true") && values.has("false");
20974
+ }
20975
+ function normalizeCatalogEffortValue(raw) {
20976
+ const value = raw.trim().toLowerCase();
20977
+ if (EFFORT_VALUES.has(value)) return value;
20978
+ if (value === "extra high" || value === "extra_high" || value === "extra-high" || value === "ultrathink") return "xhigh";
20979
+ if (value === "minimal" || value === "min") return "low";
20980
+ return null;
20981
+ }
20982
+ function parseCatalogContextWindow(raw) {
20983
+ if (!raw) return null;
20984
+ const match = /^(\d+(?:\.\d+)?)\s*([km])?$/i.exec(raw.trim());
20985
+ if (!match) return null;
20986
+ const amount = Number(match[1]);
20987
+ if (!Number.isFinite(amount) || amount <= 0) return null;
20988
+ const unit = match[2]?.toLowerCase();
20989
+ return Math.round(amount * (unit === "m" ? 1e6 : unit === "k" ? 1e3 : 1));
20990
+ }
20991
+ function firstParseableContextValue(values) {
20992
+ for (const item of values ?? []) {
20993
+ if (parseCatalogContextWindow(item.value) != null) return item.value;
20994
+ }
20995
+ return null;
20996
+ }
20997
+ function defaultCatalogContextWindow(modelId) {
20998
+ return modelId && GPT_5_6_MODEL_RE.test(modelId) ? CODEX_GPT_5_6_CONTEXT_WINDOW : DEFAULT_CONTEXT_WINDOW;
20999
+ }
21000
+ function selectedCatalogContextWindow(selected, model) {
21001
+ const parsed = parseCatalogContextWindow(selected);
21002
+ if (parsed != null) return parsed;
21003
+ return parseCatalogContextWindow(
21004
+ firstParseableContextValue(model?.parameters?.find((param) => param.id === "context")?.values)
21005
+ );
21006
+ }
21007
+ function resolveCatalogContextWindow(selected, model, modelId) {
21008
+ return selectedCatalogContextWindow(selected, model) ?? defaultCatalogContextWindow(modelId);
21009
+ }
21010
+ function catalogParamLabel(param) {
21011
+ if (param.displayName?.trim()) return param.displayName.trim();
21012
+ if (param.id === "optimize_for") return "Optimize for";
21013
+ if (param.id === "context") return "Context";
21014
+ if (param.id === "thinking") return "Thinking";
21015
+ if (param.id === "fast") return "Fast";
21016
+ if (param.id === "effort") return "Effort";
21017
+ if (param.id === "reasoning") return "Reasoning";
21018
+ return param.id.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
21019
+ }
21020
+ function catalogParamValueLabel(value, displayName) {
21021
+ if (displayName?.trim()) return displayName.trim();
21022
+ if (value === "extra-high" || value === "extra_high") return "Extra High";
21023
+ if (value === "1m") return "1M";
21024
+ if (value === "300k") return "300K";
21025
+ if (value === "272k") return "272K";
21026
+ if (value === "200k") return "200K";
21027
+ return value.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
21028
+ }
21029
+ function defaultCatalogParams(model) {
21030
+ const out = {};
21031
+ for (const param of model?.parameters ?? []) {
21032
+ if (!param.values.length) continue;
21033
+ if (param.id === "optimize_for") {
21034
+ out[param.id] = param.values.find((value) => value.value === "balanced")?.value ?? param.values[0].value;
21035
+ continue;
21036
+ }
21037
+ if (isEffortCatalogParam(param)) {
21038
+ out[param.id] = param.values.find((value) => normalizeCatalogEffortValue(value.value) === "medium")?.value ?? param.values.find((value) => normalizeCatalogEffortValue(value.value) != null)?.value ?? param.values[0].value;
21039
+ continue;
21040
+ }
21041
+ if (isToggleCatalogParam(param)) {
21042
+ out[param.id] = param.values.find((value) => value.value === "false")?.value ?? param.values[0].value;
21043
+ continue;
21044
+ }
21045
+ if (param.id === "context") {
21046
+ out[param.id] = firstParseableContextValue(param.values) ?? param.values[0].value;
21047
+ continue;
21048
+ }
21049
+ out[param.id] = param.values[0].value;
21050
+ }
21051
+ return out;
21052
+ }
21053
+ function selectorCatalogParams(model, selected = {}) {
21054
+ const parameters = model?.parameters ?? [];
21055
+ const effortParam = findEffortCatalogParam(parameters);
21056
+ const defaults2 = defaultCatalogParams(model);
21057
+ return parameters.filter((param) => !isEffortCatalogParam(param) && param.id !== effortParam?.id).filter((param) => param.values.length > 0).map((param) => ({
21058
+ id: param.id,
21059
+ label: catalogParamLabel(param),
21060
+ kind: isToggleCatalogParam(param) ? "toggle" : "choice",
21061
+ values: param.values.map((value) => ({
21062
+ value: value.value,
21063
+ label: catalogParamValueLabel(value.value, value.displayName)
21064
+ })),
21065
+ selected: selected[param.id] ?? defaults2[param.id] ?? param.values[0].value
21066
+ }));
21067
+ }
21068
+ var EFFORT_VALUES, GPT_5_6_MODEL_RE;
21069
+ var init_model_option_params = __esm({
21070
+ "../../packages/shared/src/model-option-params.ts"() {
21071
+ "use strict";
21072
+ init_agent_types();
21073
+ EFFORT_VALUES = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
21074
+ GPT_5_6_MODEL_RE = /(^|[/-])gpt-5\.6(?:$|-)/i;
21075
+ }
21076
+ });
21077
+
21078
+ // ../../packages/shared/src/agent-profile-options.ts
21079
+ function isModelBoundOption(key) {
21080
+ return MODEL_BOUND.has(key);
21081
+ }
21082
+ function formatContextWindow(tokens2) {
21083
+ if (tokens2 >= 1e6 && tokens2 % 1e6 === 0) return `${tokens2 / 1e6}M`;
21084
+ if (tokens2 >= 1e3) return `${Math.round(tokens2 / 1e3)}K`;
21085
+ return String(tokens2);
21086
+ }
21087
+ function choicesFor(key, model, host) {
21088
+ switch (key) {
21089
+ case "ultracode":
21090
+ return model.supportedEffortLevels?.includes("xhigh") ? { kind: "toggle" } : null;
21091
+ case "fastMode":
21092
+ return findCodexFastServiceTier(model) ? { kind: "toggle" } : null;
21093
+ case "contextWindow": {
21094
+ const windows = model.contextWindows ?? [];
21095
+ return windows.length > 1 ? { kind: "choice", values: windows.map((value) => ({ value, label: formatContextWindow(value) })) } : null;
21096
+ }
21097
+ case "modelParams": {
21098
+ const params = selectorCatalogParams(model);
21099
+ return params.length ? { kind: "params", params } : null;
21100
+ }
21101
+ case "mode":
21102
+ case "agent":
21103
+ case "agentPreset": {
21104
+ const list = host.lists?.[key];
21105
+ if (!list) return { kind: "unlisted" };
21106
+ return list.length ? { kind: "choice", values: [...list] } : null;
21107
+ }
21108
+ }
21109
+ }
21110
+ function agentProfileOptionChoices(harnessId, models, host = {}) {
21111
+ const out = {};
21112
+ for (const key of HARNESS_PROFILE_OPTIONS[harnessId]) {
21113
+ if (host.appliable && !host.appliable.includes(key)) {
21114
+ out[key] = null;
21115
+ continue;
21116
+ }
21117
+ if (!isModelBoundOption(key)) {
21118
+ out[key] = choicesFor(key, { id: "" }, host);
21119
+ continue;
21120
+ }
21121
+ out[key] = models.map((model) => choicesFor(key, model, host)).find((choice) => choice !== null) ?? null;
21122
+ }
21123
+ return out;
21124
+ }
21125
+ function optionValueError(key, value, choices) {
21126
+ if (choices.kind === "toggle" || choices.kind === "unlisted") return null;
21127
+ if (choices.kind === "choice") {
21128
+ if (choices.values.some((choice) => choice.value === value)) return null;
21129
+ return `options.${key} ${JSON.stringify(value)} is not one of: ${choices.values.map((choice) => JSON.stringify(choice.value)).join(", ")}.`;
21130
+ }
21131
+ const params = value;
21132
+ for (const [id, raw] of Object.entries(params)) {
21133
+ const param = choices.params.find((candidate) => candidate.id === id);
21134
+ if (!param) return `options.modelParams.${id} is not a parameter of this model (parameters: ${choices.params.map((p3) => p3.id).join(", ")}).`;
21135
+ if (!param.values.some((candidate) => candidate.value === raw)) {
21136
+ return `options.modelParams.${id} "${raw}" is not one of: ${param.values.map((candidate) => candidate.value).join(", ")}.`;
21137
+ }
21138
+ }
21139
+ return null;
21140
+ }
21141
+ function optionShapeError(key, value) {
21142
+ const kind = OPTION_KINDS[key];
21143
+ if (!kind) return `profile.runtime.options has unknown field: ${key}.`;
21144
+ const label = `profile.runtime.options.${key}`;
21145
+ switch (kind) {
21146
+ case "boolean":
21147
+ return typeof value === "boolean" ? null : `${label} must be a boolean.`;
21148
+ case "number":
21149
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? null : `${label} must be a positive integer.`;
21150
+ case "string":
21151
+ return typeof value === "string" && value.trim() ? null : `${label} must be a non-empty string.`;
21152
+ case "params": {
21153
+ const ok = !!value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0 && Object.values(value).every((entry3) => typeof entry3 === "string" && entry3.length > 0);
21154
+ return ok ? null : `${label} must map parameter ids to non-empty string values.`;
21155
+ }
21156
+ }
21157
+ }
21158
+ var HARNESS_PROFILE_OPTIONS, MODEL_BOUND, MODEL_REQUIRED_OPTIONS, OPTION_KINDS, AGENT_PROFILE_OPTION_KEYS;
21159
+ var init_agent_profile_options = __esm({
21160
+ "../../packages/shared/src/agent-profile-options.ts"() {
21161
+ "use strict";
21162
+ init_codex_fast_mode();
21163
+ init_model_option_params();
21164
+ HARNESS_PROFILE_OPTIONS = {
21165
+ claude: ["ultracode"],
21166
+ codex: ["fastMode"],
21167
+ acp: ["contextWindow", "mode"],
21168
+ opencode: ["agent"],
21169
+ cursor: ["modelParams"],
21170
+ dsh: ["agentPreset"]
21171
+ };
21172
+ MODEL_BOUND = /* @__PURE__ */ new Set(["ultracode", "fastMode", "contextWindow", "modelParams"]);
21173
+ MODEL_REQUIRED_OPTIONS = /* @__PURE__ */ new Set(["contextWindow", "modelParams"]);
21174
+ OPTION_KINDS = {
21175
+ ultracode: "boolean",
21176
+ fastMode: "boolean",
21177
+ contextWindow: "number",
21178
+ mode: "string",
21179
+ agent: "string",
21180
+ agentPreset: "string",
21181
+ modelParams: "params"
21182
+ };
21183
+ AGENT_PROFILE_OPTION_KEYS = Object.keys(OPTION_KINDS);
21184
+ }
21185
+ });
21186
+
21187
+ // ../../packages/shared/src/agent-profile.ts
21188
+ function isRecord2(value) {
21189
+ return !!value && typeof value === "object" && !Array.isArray(value);
21190
+ }
21191
+ function nonEmpty(value) {
21192
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
21193
+ }
21194
+ function parseOptions2(raw, harnessId) {
21195
+ if (raw === void 0) return { ok: true, value: void 0 };
21196
+ if (!isRecord2(raw)) return { ok: false, error: "profile.runtime.options must be an object." };
21197
+ const allowed = harnessId ? HARNESS_PROFILE_OPTIONS[harnessId] : void 0;
21198
+ const options = {};
21199
+ for (const [key, value] of Object.entries(raw)) {
21200
+ const shape = optionShapeError(key, value);
21201
+ if (shape) return { ok: false, error: shape };
21202
+ if (allowed && !allowed.includes(key)) {
21203
+ return { ok: false, error: `profile.runtime.options.${key} is not a ${harnessId} setting (${harnessId} has: ${allowed.join(", ") || "none"}).` };
21204
+ }
21205
+ options[key] = typeof value === "string" ? value.trim() : value;
21206
+ }
21207
+ return { ok: true, value: Object.keys(options).length ? options : void 0 };
21208
+ }
21209
+ function parseRuntime(raw, harnessId) {
21210
+ if (raw === void 0) return { ok: true, value: void 0 };
21211
+ if (!isRecord2(raw)) return { ok: false, error: "profile.runtime must be an object." };
21212
+ const unknown2 = Object.keys(raw).filter((key) => !["model", "effort", "options", "permissionMode"].includes(key));
21213
+ if (unknown2.length) return { ok: false, error: `profile.runtime has unknown field(s): ${unknown2.join(", ")}.` };
21214
+ const runtime = {};
21215
+ if (raw.model !== void 0) {
21216
+ const model = nonEmpty(raw.model);
21217
+ if (!model) return { ok: false, error: "profile.runtime.model must be a non-empty string." };
21218
+ runtime.model = model;
21219
+ }
21220
+ if (raw.effort !== void 0) {
21221
+ const effort = nonEmpty(raw.effort);
21222
+ if (!effort) return { ok: false, error: "profile.runtime.effort must be a non-empty string." };
21223
+ runtime.effort = effort;
21224
+ }
21225
+ if (raw.permissionMode !== void 0) {
21226
+ const mode = nonEmpty(raw.permissionMode);
21227
+ if (!mode) return { ok: false, error: "profile.runtime.permissionMode must be a non-empty string." };
21228
+ if (harnessId) {
21229
+ const offered = HARNESS_LAUNCH_OPTIONS[harnessId].permissionModes;
21230
+ if (!offered.includes(mode)) {
21231
+ return {
21232
+ ok: false,
21233
+ error: offered.length ? `profile.runtime.permissionMode "${mode}" is not a ${harnessId} mode (${harnessId} has: ${offered.join(", ")}).` : `profile.runtime.permissionMode is not supported by ${harnessId}: it runs its own permission configuration.`
21234
+ };
21235
+ }
21236
+ }
21237
+ runtime.permissionMode = mode;
21238
+ }
21239
+ const options = parseOptions2(raw.options, harnessId);
21240
+ if (!options.ok) return options;
21241
+ if (options.value) {
21242
+ const needsModel = Object.keys(options.value).find((key) => MODEL_REQUIRED_OPTIONS.has(key));
21243
+ if (needsModel && !runtime.model) return { ok: false, error: `profile.runtime.options.${needsModel} requires profile.runtime.model.` };
21244
+ runtime.options = options.value;
21245
+ }
21246
+ return { ok: true, value: Object.keys(runtime).length ? runtime : void 0 };
21247
+ }
21248
+ function parseAgentProfileSpec(raw, harnessId) {
21249
+ if (!isRecord2(raw)) return { ok: false, error: "profile must be an object." };
21250
+ if (raw.version !== AGENT_PROFILE_VERSION) {
21251
+ return { ok: false, error: `profile.version must be ${AGENT_PROFILE_VERSION}.` };
21252
+ }
21253
+ const unknown2 = Object.keys(raw).filter((key) => !["version", "identity", "instructions", "runtime"].includes(key));
21254
+ if (unknown2.length) return { ok: false, error: `profile has unknown field(s): ${unknown2.join(", ")}.` };
21255
+ const identity = isRecord2(raw.identity) ? raw.identity : null;
21256
+ const name = nonEmpty(identity?.name);
21257
+ if (!name) return { ok: false, error: "profile.identity.name must be a non-empty string." };
21258
+ if (name.length > AGENT_PROFILE_NAME_MAX) {
21259
+ return { ok: false, error: `profile.identity.name must be at most ${AGENT_PROFILE_NAME_MAX} characters.` };
21260
+ }
21261
+ const description = nonEmpty(identity?.description);
21262
+ if (!description) return { ok: false, error: "profile.identity.description must be a non-empty string." };
21263
+ if (description.length > AGENT_PROFILE_DESCRIPTION_MAX) {
21264
+ return { ok: false, error: `profile.identity.description must be at most ${AGENT_PROFILE_DESCRIPTION_MAX} characters.` };
21265
+ }
21266
+ let instructions;
21267
+ if (raw.instructions !== void 0) {
21268
+ if (typeof raw.instructions !== "string") return { ok: false, error: "profile.instructions must be a string." };
21269
+ instructions = raw.instructions.trim() || void 0;
21270
+ if (instructions && instructions.length > AGENT_PROFILE_INSTRUCTIONS_MAX) {
21271
+ return { ok: false, error: `profile.instructions must be at most ${AGENT_PROFILE_INSTRUCTIONS_MAX} characters.` };
21272
+ }
21273
+ }
21274
+ const runtime = parseRuntime(raw.runtime, harnessId);
21275
+ if (!runtime.ok) return runtime;
21276
+ return {
21277
+ ok: true,
21278
+ value: {
21279
+ version: AGENT_PROFILE_VERSION,
21280
+ identity: { name, description },
21281
+ ...instructions ? { instructions } : {},
21282
+ ...runtime.value ? { runtime: runtime.value } : {}
21283
+ }
21284
+ };
21285
+ }
21286
+ function readAgentProfile(config2) {
21287
+ if (!isRecord2(config2) || config2.profile === void 0) return null;
21288
+ const parsed = parseAgentProfileSpec(config2.profile);
21289
+ return parsed.ok ? parsed.value : null;
21290
+ }
21291
+ function providerLaunchRuntime(config2) {
21292
+ const profile = readAgentProfile(config2);
21293
+ if (profile) return profile.runtime;
21294
+ if (!isRecord2(config2)) return void 0;
21295
+ const model = nonEmpty(config2.model);
21296
+ const effort = nonEmpty(config2.effort) ?? nonEmpty(config2.reasoningEffort);
21297
+ const runtime = {
21298
+ ...model ? { model } : {},
21299
+ ...effort ? { effort } : {},
21300
+ ...typeof config2.fastMode === "boolean" ? { options: { fastMode: config2.fastMode } } : {}
21301
+ };
21302
+ return Object.keys(runtime).length ? runtime : void 0;
21303
+ }
21304
+ function composeSystemPromptAppend(...parts) {
21305
+ const text2 = parts.map((part) => part?.trim()).filter(Boolean).join("\n\n");
21306
+ return text2 || void 0;
21307
+ }
21308
+ function agentProfilePrompt(profile) {
21309
+ const { name, description } = profile.identity;
21310
+ return [
21311
+ "<superone-agent-profile>",
21312
+ `You are running as "${name}", an agent profile the user saved in SuperOne. What it is for: ${description}`,
21313
+ ...profile.instructions ? [
21314
+ "Follow the profile instructions below for this whole session.",
21315
+ "<instructions>",
21316
+ profile.instructions,
21317
+ "</instructions>"
21318
+ ] : [],
21319
+ "</superone-agent-profile>"
21320
+ ].join("\n");
21321
+ }
21322
+ function providerSystemPromptAppend(config2, protocol) {
21323
+ const profile = readAgentProfile(config2);
21324
+ return composeSystemPromptAppend(profile ? agentProfilePrompt(profile) : void 0, protocol);
21325
+ }
21326
+ function findModel(catalog, id) {
21327
+ return id ? catalog.models.find((model) => model.id === id) : void 0;
21328
+ }
21329
+ function modelEfforts(catalog, model) {
21330
+ if (model?.supportedEffortLevels) return [...model.supportedEffortLevels];
21331
+ if (model?.supportedReasoningEfforts) return model.supportedReasoningEfforts.map((effort) => effort.value);
21332
+ return [...catalog.efforts ?? []];
21333
+ }
21334
+ function validateAgentProfileRuntime(runtime, catalog, harness) {
21335
+ if (!runtime) return [];
21336
+ const optionKeys = Object.keys(runtime.options ?? {});
21337
+ const needsCatalog = !!runtime.model || !!runtime.effort || optionKeys.some(isModelBoundOption);
21338
+ if (needsCatalog && catalog.models.length === 0) {
21339
+ return [`${harness.name} has no model catalog yet. Open a ${harness.name} session once, or leave runtime out.`];
21340
+ }
21341
+ const errors = [];
21342
+ const model = findModel(catalog, runtime.model);
21343
+ if (runtime.model && !model) {
21344
+ const ids = catalog.models.map((option) => option.id);
21345
+ return [`runtime.model "${runtime.model}" is not in the ${harness.name} catalog. Available: ${ids.slice(0, 30).join(", ")}.`];
21346
+ }
21347
+ const label = model ? `${harness.name} model "${model.id}"` : harness.name;
21348
+ if (runtime.effort) {
21349
+ const efforts = model ? modelEfforts(catalog, model) : [...new Set(catalog.models.flatMap((option) => modelEfforts(catalog, option)))];
21350
+ if (!efforts.includes(runtime.effort)) {
21351
+ errors.push(efforts.length ? `runtime.effort "${runtime.effort}" is not supported by ${model ? label : `any ${harness.name} model`} (supported: ${efforts.join(", ")}).` : `runtime.effort is not supported by ${label}.`);
21352
+ }
21353
+ }
21354
+ const choices = agentProfileOptionChoices(harness.id, model ? [model] : catalog.models, catalog.host);
21355
+ for (const key of optionKeys) {
21356
+ const choice = choices[key];
21357
+ if (choice === void 0) {
21358
+ errors.push(`options.${key} is not a ${harness.name} setting.`);
21359
+ } else if (choice === null) {
21360
+ errors.push(`options.${key} is not supported by ${label}.`);
21361
+ } else if (choice.kind === "unlisted") {
21362
+ errors.push(`${harness.name} has not listed its ${key} values yet. Open a ${harness.name} session once, or leave options.${key} out.`);
21363
+ } else {
21364
+ const invalid11 = optionValueError(key, runtime.options[key], choice);
21365
+ if (invalid11) errors.push(invalid11);
21366
+ }
21367
+ }
21368
+ return errors;
21369
+ }
21370
+ function fallbackEffort(model, supported) {
21371
+ if (model?.defaultReasoningEffort && supported.includes(model.defaultReasoningEffort)) return model.defaultReasoningEffort;
21372
+ if (supported.includes("high")) return "high";
21373
+ if (supported.includes("medium")) return "medium";
21374
+ return supported[0];
21375
+ }
21376
+ function resolveAgentLaunchDefaults(input) {
21377
+ const { harnessId, catalog, base, profile } = input;
21378
+ const launch2 = input.launch ?? {};
21379
+ const appliable = catalog.host?.appliable;
21380
+ const uncatalogued = catalog.models.length === 0 || !!launch2.model && !findModel(catalog, launch2.model);
21381
+ const model = uncatalogued ? void 0 : findModel(catalog, launch2.model) ?? findModel(catalog, profile?.model) ?? findModel(catalog, base.model);
21382
+ const choices = agentProfileOptionChoices(harnessId, model ? [model] : [], catalog.host);
21383
+ const options = {};
21384
+ for (const key of HARNESS_PROFILE_OPTIONS[harnessId]) {
21385
+ if (launch2.options?.[key] !== void 0) {
21386
+ options[key] = launch2.options[key];
21387
+ continue;
21388
+ }
21389
+ const value = profile?.options?.[key] ?? base.options?.[key];
21390
+ if (value === void 0 || appliable && !appliable.includes(key)) continue;
21391
+ const choice = model || !isModelBoundOption(key) ? choices[key] : { kind: "unlisted" };
21392
+ if (choice && !optionValueError(key, value, choice)) options[key] = value;
21393
+ }
21394
+ const offeredModes = HARNESS_LAUNCH_OPTIONS[harnessId].permissionModes;
21395
+ const permissionMode = [launch2.permissionMode, profile?.permissionMode, base.permissionMode].find((mode) => mode && offeredModes.includes(mode));
21396
+ const result3 = (modelId, effort2) => ({
21397
+ ...modelId ? { model: modelId } : {},
21398
+ ...effort2 ? { effort: effort2 } : {},
21399
+ ...Object.keys(options).length ? { options } : {},
21400
+ ...permissionMode ? { permissionMode } : {}
21401
+ });
21402
+ if (uncatalogued) {
21403
+ return result3(launch2.model ?? profile?.model ?? base.model, launch2.effort ?? profile?.effort ?? base.effort);
21404
+ }
21405
+ const supported = modelEfforts(catalog, model);
21406
+ const effort = launch2.effort ?? [profile?.effort, base.effort].find((value) => value && supported.includes(value)) ?? fallbackEffort(model, supported);
21407
+ return result3(model?.id ?? base.model, effort);
21408
+ }
21409
+ function agentLaunchErrors(harness, catalog, model, launch2) {
21410
+ const options = launch2.options && Object.keys(launch2.options).length ? launch2.options : void 0;
21411
+ if (!model || !findModel(catalog, model) || !launch2.effort && !options) return [];
21412
+ return validateAgentProfileRuntime({
21413
+ model,
21414
+ ...launch2.effort ? { effort: launch2.effort } : {},
21415
+ ...options ? { options } : {}
21416
+ }, catalog, harness).map((message) => message.replace(/^runtime\./, "config.").replace(/^options\.fastMode/, "config.fastMode").replace(/^options\./, "config.options."));
21417
+ }
21418
+ function launchConfigFromDefaults(defaults2) {
21419
+ const { fastMode, ...options } = defaults2.options ?? {};
21420
+ return {
21421
+ ...defaults2.model ? { model: defaults2.model } : {},
21422
+ ...defaults2.effort ? { effort: defaults2.effort } : {},
21423
+ ...fastMode !== void 0 ? { fastMode } : {},
21424
+ ...Object.keys(options).length ? { options } : {},
21425
+ ...defaults2.permissionMode ? { permissionMode: defaults2.permissionMode } : {}
21426
+ };
21427
+ }
21428
+ function launchDefaultsFromConfig(config2) {
21429
+ const options = { ...config2?.options, ...typeof config2?.fastMode === "boolean" ? { fastMode: config2.fastMode } : {} };
21430
+ return {
21431
+ ...config2?.model ? { model: config2.model } : {},
21432
+ ...config2?.effort ? { effort: config2.effort } : {},
21433
+ ...Object.keys(options).length ? { options } : {}
21434
+ };
21435
+ }
21436
+ var AGENT_PROFILE_VERSION, AGENT_PROFILE_NAME_MAX, AGENT_PROFILE_DESCRIPTION_MAX, AGENT_PROFILE_INSTRUCTIONS_MAX;
21437
+ var init_agent_profile = __esm({
21438
+ "../../packages/shared/src/agent-profile.ts"() {
21439
+ "use strict";
21440
+ init_launch_options();
21441
+ init_agent_profile_options();
21442
+ AGENT_PROFILE_VERSION = 1;
21443
+ AGENT_PROFILE_NAME_MAX = 60;
21444
+ AGENT_PROFILE_DESCRIPTION_MAX = 500;
21445
+ AGENT_PROFILE_INSTRUCTIONS_MAX = 2e4;
21446
+ }
21447
+ });
21448
+
20709
21449
  // ../../packages/runtime/src/session/session-provider-store.ts
20710
21450
  import { randomUUID as randomUUID5 } from "node:crypto";
20711
21451
  function assertHarnessId(raw) {
@@ -20714,12 +21454,25 @@ function assertHarnessId(raw) {
20714
21454
  }
20715
21455
  return raw;
20716
21456
  }
20717
- function normalizeConfig(config2) {
21457
+ function normalizeConfig(harnessId, config2) {
20718
21458
  if (config2 === void 0 || config2 === null) return {};
20719
21459
  if (typeof config2 !== "object" || Array.isArray(config2)) {
20720
21460
  throw Object.assign(new Error("config must be an object"), { code: "invalid_argument" });
20721
21461
  }
20722
- return config2;
21462
+ const profile = config2.profile;
21463
+ if (profile === void 0) return config2;
21464
+ const parsed = parseAgentProfileSpec(profile, harnessId);
21465
+ if (!parsed.ok) throw Object.assign(new Error(parsed.error), { code: "invalid_argument" });
21466
+ return { ...config2, profile: parsed.value };
21467
+ }
21468
+ function hasProfile(config2) {
21469
+ return !!config2 && typeof config2 === "object" && config2.profile !== void 0;
21470
+ }
21471
+ function profileWriteRefused() {
21472
+ return Object.assign(
21473
+ new Error("Agent profiles change only through agent_profile_apply / agent_profile_delete, which ask the user first."),
21474
+ { code: "failed_precondition" }
21475
+ );
20723
21476
  }
20724
21477
  function rowToProvider(row2) {
20725
21478
  let config2 = {};
@@ -20776,9 +21529,12 @@ function settingsFromSessionProviderConfig(config2) {
20776
21529
  const v3 = c[key];
20777
21530
  return typeof v3 === "string" && v3.trim() ? v3.trim() : void 0;
20778
21531
  };
21532
+ const runtime = providerLaunchRuntime(config2);
21533
+ const model = runtime?.model;
21534
+ const effort = runtime?.effort;
20779
21535
  return {
20780
- ...str5("model") ? { model: str5("model") } : {},
20781
- ...str5("effort") || str5("reasoningEffort") ? { effort: str5("effort") ?? str5("reasoningEffort") } : {},
21536
+ ...model ? { model } : {},
21537
+ ...effort ? { effort } : {},
20782
21538
  ...str5("permissionMode") ? { permissionMode: str5("permissionMode") } : {},
20783
21539
  ...str5("sandboxMode") ? { sandboxMode: str5("sandboxMode") } : {}
20784
21540
  };
@@ -20786,7 +21542,7 @@ function settingsFromSessionProviderConfig(config2) {
20786
21542
  function createSessionProviderStore(db, options = {}) {
20787
21543
  ensureSessionProvidersTable(db);
20788
21544
  const validConfig = (harnessId, config2) => {
20789
- const normalized = normalizeConfig(config2);
21545
+ const normalized = normalizeConfig(harnessId, config2);
20790
21546
  if (!options.validateConfig) return normalized;
20791
21547
  try {
20792
21548
  return options.validateConfig(harnessId, normalized);
@@ -20819,7 +21575,7 @@ function createSessionProviderStore(db, options = {}) {
20819
21575
  }
20820
21576
  return p3;
20821
21577
  };
20822
- const create = (input) => {
21578
+ const insert = (input) => {
20823
21579
  const harnessId = assertHarnessId(String(input.harnessId ?? ""));
20824
21580
  const name = String(input.name ?? "").trim();
20825
21581
  if (!name) {
@@ -20839,35 +21595,66 @@ function createSessionProviderStore(db, options = {}) {
20839
21595
  if (!created) throw Object.assign(new Error(`Failed to create provider: ${id}`), { code: "internal" });
20840
21596
  return created;
20841
21597
  };
20842
- const update = (id, patch) => {
21598
+ const existingCustom = (id, action) => {
20843
21599
  const existing = get3(id);
20844
21600
  if (!existing) {
21601
+ if (action === "delete") return null;
20845
21602
  throw Object.assign(new Error(`Provider not found: ${id}`), { code: "not_found" });
20846
21603
  }
20847
21604
  if (existing.isBase) {
20848
- throw Object.assign(new Error(`Cannot update base provider: ${id}`), {
21605
+ throw Object.assign(new Error(`Cannot ${action} base provider: ${id}`), {
20849
21606
  code: "failed_precondition"
20850
21607
  });
20851
21608
  }
21609
+ return existing;
21610
+ };
21611
+ const write = (existing, patch) => {
20852
21612
  const name = patch.name !== void 0 ? String(patch.name).trim() || existing.name : existing.name;
20853
21613
  const config2 = patch.config !== void 0 ? validConfig(existing.harnessId, patch.config) : existing.config;
20854
21614
  const now = (/* @__PURE__ */ new Date()).toISOString();
20855
21615
  db.prepare(
20856
21616
  "UPDATE session_providers SET name = ?, config_json = ?, updated_at = ? WHERE id = ?"
20857
- ).run(name, JSON.stringify(config2), now, id);
20858
- return get3(id);
21617
+ ).run(name, JSON.stringify(config2), now, existing.id);
21618
+ return get3(existing.id);
21619
+ };
21620
+ const remove = (id) => {
21621
+ db.prepare("DELETE FROM session_providers WHERE id = ?").run(id);
21622
+ };
21623
+ const assertUnchanged = (current, expected) => {
21624
+ if (current.name === expected.name && JSON.stringify(current.config) === JSON.stringify(expected.config)) return;
21625
+ throw Object.assign(new Error(`Agent profile ${current.id} changed while waiting for confirmation.`), { code: "aborted" });
21626
+ };
21627
+ const create = (input) => {
21628
+ if (hasProfile(input.config)) throw profileWriteRefused();
21629
+ return insert(input);
21630
+ };
21631
+ const update = (id, patch) => {
21632
+ const existing = existingCustom(id, "update");
21633
+ if (hasProfile(existing.config) || hasProfile(patch.config)) throw profileWriteRefused();
21634
+ return write(existing, patch);
20859
21635
  };
20860
21636
  const del = (id) => {
20861
- const existing = get3(id);
21637
+ const existing = existingCustom(id, "delete");
20862
21638
  if (!existing) return false;
20863
- if (existing.isBase) {
20864
- throw Object.assign(new Error(`Cannot delete base provider: ${id}`), {
20865
- code: "failed_precondition"
20866
- });
20867
- }
20868
- db.prepare("DELETE FROM session_providers WHERE id = ?").run(id);
21639
+ if (hasProfile(existing.config)) throw profileWriteRefused();
21640
+ remove(id);
20869
21641
  return true;
20870
21642
  };
21643
+ const profiles = {
21644
+ create: insert,
21645
+ update: (id, patch, expected) => {
21646
+ const existing = existingCustom(id, "update");
21647
+ assertUnchanged(existing, expected);
21648
+ return write(existing, patch);
21649
+ },
21650
+ delete: (id, expected) => {
21651
+ const existing = existingCustom(id, "delete");
21652
+ if (!existing) return false;
21653
+ assertUnchanged(existing, expected);
21654
+ remove(id);
21655
+ return true;
21656
+ }
21657
+ };
20871
21658
  return {
20872
21659
  list,
20873
21660
  listByHarness,
@@ -20875,7 +21662,8 @@ function createSessionProviderStore(db, options = {}) {
20875
21662
  getBase,
20876
21663
  create,
20877
21664
  update,
20878
- delete: del
21665
+ delete: del,
21666
+ profiles
20879
21667
  };
20880
21668
  }
20881
21669
  var VALID_HARNESS_IDS;
@@ -20883,6 +21671,7 @@ var init_session_provider_store = __esm({
20883
21671
  "../../packages/runtime/src/session/session-provider-store.ts"() {
20884
21672
  "use strict";
20885
21673
  init_session_provider_definitions();
21674
+ init_agent_profile();
20886
21675
  VALID_HARNESS_IDS = new Set(
20887
21676
  BASE_SESSION_PROVIDER_DEFINITIONS.map((provider2) => provider2.harnessId)
20888
21677
  );
@@ -30467,13 +31256,13 @@ var require_public_api = __commonJS({
30467
31256
  var identity = require_identity();
30468
31257
  var lineCounter = require_line_counter();
30469
31258
  var parser = require_parser();
30470
- function parseOptions2(options) {
31259
+ function parseOptions3(options) {
30471
31260
  const prettyErrors = options.prettyErrors !== false;
30472
31261
  const lineCounter$1 = options.lineCounter || prettyErrors && new lineCounter.LineCounter() || null;
30473
31262
  return { lineCounter: lineCounter$1, prettyErrors };
30474
31263
  }
30475
31264
  function parseAllDocuments(source, options = {}) {
30476
- const { lineCounter: lineCounter2, prettyErrors } = parseOptions2(options);
31265
+ const { lineCounter: lineCounter2, prettyErrors } = parseOptions3(options);
30477
31266
  const parser$1 = new parser.Parser(lineCounter2?.addNewLine);
30478
31267
  const composer$1 = new composer.Composer(options);
30479
31268
  const docs = Array.from(composer$1.compose(parser$1.parse(source)));
@@ -30487,7 +31276,7 @@ var require_public_api = __commonJS({
30487
31276
  return Object.assign([], { empty: true }, composer$1.streamInfo());
30488
31277
  }
30489
31278
  function parseDocument2(source, options = {}) {
30490
- const { lineCounter: lineCounter2, prettyErrors } = parseOptions2(options);
31279
+ const { lineCounter: lineCounter2, prettyErrors } = parseOptions3(options);
30491
31280
  const parser$1 = new parser.Parser(lineCounter2?.addNewLine);
30492
31281
  const composer$1 = new composer.Composer(options);
30493
31282
  let doc = null;
@@ -32110,8 +32899,9 @@ async function readClaudeRateLimits(credentialDir, opts = {}) {
32110
32899
  resp = await fetchUsage(refreshed);
32111
32900
  }
32112
32901
  if (resp.status === 429) {
32113
- log2.warn("[claude-usage] rate limited (429)");
32114
- return { fingerprint: claudeCredentialFingerprint(creds), rateLimitedForMs: retryAfterMs(resp) ?? 0 };
32902
+ const retryMs = retryAfterMs(resp);
32903
+ log2.warn("[claude-usage] rate limited (429) retryAfterMs=%s", retryMs ?? "none");
32904
+ return { fingerprint: claudeCredentialFingerprint(creds), rateLimitedForMs: retryMs ?? 0 };
32115
32905
  }
32116
32906
  const fingerprint = claudeCredentialFingerprint(creds);
32117
32907
  if (!resp.ok) return { fingerprint, error: `Claude usage request failed (HTTP ${resp.status}).` };
@@ -65868,17 +66658,17 @@ function isResponseMessage(value) {
65868
66658
  function isNotificationMessage(value) {
65869
66659
  return isJsonRpcEnvelope(value) && !("id" in value) && typeof value["method"] === "string";
65870
66660
  }
65871
- function isRecord2(value) {
66661
+ function isRecord3(value) {
65872
66662
  return typeof value === "object" && value !== null;
65873
66663
  }
65874
66664
  function isJsonRpcEnvelope(value) {
65875
- return isRecord2(value) && value["jsonrpc"] === "2.0";
66665
+ return isRecord3(value) && value["jsonrpc"] === "2.0";
65876
66666
  }
65877
66667
  function isJsonRpcId(value) {
65878
66668
  return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
65879
66669
  }
65880
66670
  function isResponseShapedMessage(value) {
65881
- return isRecord2(value) && !("method" in value) && ("id" in value || "result" in value || "error" in value);
66671
+ return isRecord3(value) && !("method" in value) && ("id" in value || "result" in value || "error" in value);
65882
66672
  }
65883
66673
  function isResponseBatch(batch) {
65884
66674
  let hasValidCall = false;
@@ -65888,7 +66678,7 @@ function isResponseBatch(batch) {
65888
66678
  for (const entry3 of batch) {
65889
66679
  hasValidCall ||= isRequestMessage(entry3) || isNotificationMessage(entry3);
65890
66680
  hasValidResponse ||= isResponseMessage(entry3);
65891
- if (!isRecord2(entry3)) {
66681
+ if (!isRecord3(entry3)) {
65892
66682
  continue;
65893
66683
  }
65894
66684
  hasCallShape ||= "method" in entry3;
@@ -65903,13 +66693,13 @@ function isResponseBatch(batch) {
65903
66693
  return hasResponseShape && !hasCallShape;
65904
66694
  }
65905
66695
  function cancelRequestId(params) {
65906
- if (!isRecord2(params) || !isJsonRpcId(params["requestId"])) {
66696
+ if (!isRecord3(params) || !isJsonRpcId(params["requestId"])) {
65907
66697
  return void 0;
65908
66698
  }
65909
66699
  return params["requestId"];
65910
66700
  }
65911
66701
  function isErrorResponse(value) {
65912
- return isRecord2(value) && typeof value["code"] === "number" && Number.isInteger(value["code"]) && typeof value["message"] === "string";
66702
+ return isRecord3(value) && typeof value["code"] === "number" && Number.isInteger(value["code"]) && typeof value["message"] === "string";
65913
66703
  }
65914
66704
  function rejectedPromise(error51) {
65915
66705
  const promise2 = Promise.reject(error51);
@@ -66465,7 +67255,7 @@ var init_jsonrpc = __esm({
66465
67255
  if (this.abortController.signal.aborted) {
66466
67256
  return Promise.resolve();
66467
67257
  }
66468
- if (!isRecord2(message)) {
67258
+ if (!isRecord3(message)) {
66469
67259
  console.error("Invalid message", { message });
66470
67260
  return Promise.resolve();
66471
67261
  }
@@ -66868,7 +67658,7 @@ function ndJsonStream(output, input) {
66868
67658
  await writeJson(protocolErrorResponse(RequestError.parseError()));
66869
67659
  return;
66870
67660
  }
66871
- if (isRecord2(message) || Array.isArray(message)) {
67661
+ if (isRecord3(message) || Array.isArray(message)) {
66872
67662
  controller.enqueue(message);
66873
67663
  } else {
66874
67664
  await writeJson(protocolErrorResponse(RequestError.invalidRequest(message)));
@@ -85809,44 +86599,6 @@ var init_cursor_sdk = __esm({
85809
86599
  }
85810
86600
  });
85811
86601
 
85812
- // ../../packages/shared/src/model-option-params.ts
85813
- function parseCatalogContextWindow(raw) {
85814
- if (!raw) return null;
85815
- const match = /^(\d+(?:\.\d+)?)\s*([km])?$/i.exec(raw.trim());
85816
- if (!match) return null;
85817
- const amount = Number(match[1]);
85818
- if (!Number.isFinite(amount) || amount <= 0) return null;
85819
- const unit = match[2]?.toLowerCase();
85820
- return Math.round(amount * (unit === "m" ? 1e6 : unit === "k" ? 1e3 : 1));
85821
- }
85822
- function firstParseableContextValue(values) {
85823
- for (const item of values ?? []) {
85824
- if (parseCatalogContextWindow(item.value) != null) return item.value;
85825
- }
85826
- return null;
85827
- }
85828
- function defaultCatalogContextWindow(modelId) {
85829
- return modelId && GPT_5_6_MODEL_RE.test(modelId) ? CODEX_GPT_5_6_CONTEXT_WINDOW : DEFAULT_CONTEXT_WINDOW;
85830
- }
85831
- function selectedCatalogContextWindow(selected, model) {
85832
- const parsed = parseCatalogContextWindow(selected);
85833
- if (parsed != null) return parsed;
85834
- return parseCatalogContextWindow(
85835
- firstParseableContextValue(model?.parameters?.find((param) => param.id === "context")?.values)
85836
- );
85837
- }
85838
- function resolveCatalogContextWindow(selected, model, modelId) {
85839
- return selectedCatalogContextWindow(selected, model) ?? defaultCatalogContextWindow(modelId);
85840
- }
85841
- var GPT_5_6_MODEL_RE;
85842
- var init_model_option_params = __esm({
85843
- "../../packages/shared/src/model-option-params.ts"() {
85844
- "use strict";
85845
- init_agent_types();
85846
- GPT_5_6_MODEL_RE = /(^|[/-])gpt-5\.6(?:$|-)/i;
85847
- }
85848
- });
85849
-
85850
86602
  // ../../packages/cursor/src/cursor-model-selection.ts
85851
86603
  function resolveCursorContextWindow(selected, model, modelId) {
85852
86604
  return resolveCatalogContextWindow(selected, model, modelId);
@@ -97854,6 +98606,8 @@ var SUPERONE_TOOL_SUMMARY_FIELDS = {
97854
98606
  read_manual: ["domain", "topic"],
97855
98607
  // The card, never the brief: the phone cannot launch it.
97856
98608
  session_suggest_task: ["title", "tldr"],
98609
+ // The layout row's verb and subject; the row reads file names out of `tab`.
98610
+ layout_act: ["action", "path", "line", "side", "tab"],
97857
98611
  miniapp_dev_register: ["name", "directory", "appDir"],
97858
98612
  miniapp_dev_update_types: ["appDir"],
97859
98613
  miniapp_dev_setup: ["name", "directory", "description"],
@@ -97892,6 +98646,9 @@ function sanitizeWorkflowInput(toolName, input) {
97892
98646
  "automation_list",
97893
98647
  "automation_apply",
97894
98648
  "automation_delete",
98649
+ "agent_profile_list",
98650
+ "agent_profile_apply",
98651
+ "agent_profile_delete",
97895
98652
  "config_apply",
97896
98653
  "environment_get_info",
97897
98654
  "project_list",
@@ -97918,6 +98675,12 @@ function sanitizeWorkflowInput(toolName, input) {
97918
98675
  copyDefined(source, safe, ["action", "name", "enabled"]);
97919
98676
  } else if (bare === "automation_delete" && Array.isArray(source.ids)) {
97920
98677
  safe.ids = source.ids.map(() => "");
98678
+ } else if (bare === "agent_profile_list") {
98679
+ copyDefined(source, safe, ["id"]);
98680
+ } else if (bare === "agent_profile_apply") {
98681
+ copyDefined(source, safe, ["action", "name", "harnessId"]);
98682
+ } else if (bare === "agent_profile_delete" && Array.isArray(source.ids)) {
98683
+ safe.ids = source.ids.map(() => "");
97921
98684
  } else if (bare === "config_apply") {
97922
98685
  const resource = source.resource && typeof source.resource === "object" && !Array.isArray(source.resource) ? source.resource : null;
97923
98686
  if (resource && typeof resource.operation === "string") {
@@ -108222,8 +108985,191 @@ import Database5 from "better-sqlite3";
108222
108985
  import { mkdirSync as mkdirSync24 } from "node:fs";
108223
108986
  import { dirname as dirname20 } from "node:path";
108224
108987
 
108988
+ // ../../packages/shared/src/session-interruption.ts
108989
+ function isNodeRestartInterruption(reason) {
108990
+ return reason === "node_restart" || reason === "node_restart_non_reattachable";
108991
+ }
108992
+
108993
+ // ../../packages/runtime/src/collaboration/wake-queue.ts
108994
+ var COLLABORATION_WAKE_TABLE_DDL = `
108995
+ CREATE TABLE IF NOT EXISTS collaboration_wakes (
108996
+ session_id TEXT NOT NULL,
108997
+ notification_id TEXT NOT NULL,
108998
+ content TEXT NOT NULL,
108999
+ state TEXT NOT NULL DEFAULT 'queued',
109000
+ attempts INTEGER NOT NULL DEFAULT 0,
109001
+ next_attempt_at INTEGER NOT NULL DEFAULT 0,
109002
+ last_error TEXT,
109003
+ created_at INTEGER NOT NULL,
109004
+ PRIMARY KEY (session_id, notification_id)
109005
+ );
109006
+ CREATE INDEX IF NOT EXISTS idx_collaboration_wakes_pending
109007
+ ON collaboration_wakes(state, next_attempt_at);
109008
+ CREATE TABLE IF NOT EXISTS collaboration_wake_recipients (
109009
+ session_id TEXT PRIMARY KEY NOT NULL,
109010
+ paused INTEGER NOT NULL DEFAULT 0
109011
+ );
109012
+ `;
109013
+ var COLLABORATION_WAKE_MAX_ATTEMPTS = 3;
109014
+ var RETRY_DELAYS_MS = [1e4, 3e4];
109015
+ var CollaborationWakeDeferredError = class extends Error {
109016
+ };
109017
+ var CollaborationWakeQueue = class {
109018
+ constructor(db, deps) {
109019
+ this.db = db;
109020
+ this.deps = deps;
109021
+ db.exec(COLLABORATION_WAKE_TABLE_DDL);
109022
+ db.prepare(`INSERT INTO collaboration_wake_recipients (session_id, paused)
109023
+ SELECT DISTINCT session_id, 1 FROM collaboration_wakes WHERE state = 'dispatching'
109024
+ ON CONFLICT (session_id) DO UPDATE SET paused = 1`).run();
109025
+ db.prepare(`UPDATE collaboration_wakes SET state = 'uncertain',
109026
+ last_error = 'Notification admission interrupted before acknowledgement; automatic replay paused'
109027
+ WHERE state = 'dispatching'`).run();
109028
+ db.prepare("UPDATE collaboration_wakes SET state = 'queued' WHERE state = 'preparing'").run();
109029
+ for (const row2 of db.prepare("SELECT session_id FROM collaboration_wake_recipients WHERE paused = 1").all()) {
109030
+ this.paused.add(row2.session_id);
109031
+ }
109032
+ }
109033
+ db;
109034
+ deps;
109035
+ delivering = /* @__PURE__ */ new Set();
109036
+ paused = /* @__PURE__ */ new Set();
109037
+ timer = null;
109038
+ closed = false;
109039
+ scheduled = false;
109040
+ enqueue(sessionId, notificationId, content) {
109041
+ if (this.closed) throw new Error("Collaboration notification queue is closed");
109042
+ if (!sessionId || !notificationId || !content.trim()) throw new Error("Invalid collaboration notification");
109043
+ this.db.prepare(`
109044
+ INSERT INTO collaboration_wakes (session_id, notification_id, content, created_at)
109045
+ VALUES (?, ?, ?, ?) ON CONFLICT (session_id, notification_id) DO NOTHING
109046
+ `).run(sessionId, notificationId, content, this.now());
109047
+ this.start();
109048
+ }
109049
+ /** Resume queued admission attempts, retaining their budget across restarts. */
109050
+ start() {
109051
+ if (this.closed || this.scheduled) return;
109052
+ this.scheduled = true;
109053
+ queueMicrotask(() => {
109054
+ this.scheduled = false;
109055
+ if (!this.closed) this.flush();
109056
+ });
109057
+ }
109058
+ now() {
109059
+ return (this.deps.now ?? Date.now)();
109060
+ }
109061
+ /** Runtime errors and human stops pause consumption, without rejecting new mail. */
109062
+ observe(sessionId, event) {
109063
+ if (this.closed) return;
109064
+ if (event.type === "message_interrupted" && isNodeRestartInterruption(event.reason)) return;
109065
+ if (event.type === "message_error" || event.type === "message_interrupted") {
109066
+ this.pause(sessionId);
109067
+ } else if (event.type === "content_delta" || event.type === "message_complete") {
109068
+ if (!this.paused.has(sessionId)) return;
109069
+ this.db.prepare("UPDATE collaboration_wake_recipients SET paused = 0 WHERE session_id = ?").run(sessionId);
109070
+ this.paused.delete(sessionId);
109071
+ this.start();
109072
+ }
109073
+ }
109074
+ pause(sessionId) {
109075
+ if (this.paused.has(sessionId)) return;
109076
+ this.db.prepare(`INSERT INTO collaboration_wake_recipients (session_id, paused)
109077
+ VALUES (?, 1) ON CONFLICT (session_id) DO UPDATE SET paused = 1`).run(sessionId);
109078
+ this.paused.add(sessionId);
109079
+ }
109080
+ flush() {
109081
+ if (this.closed) return;
109082
+ if (this.timer) clearTimeout(this.timer);
109083
+ this.timer = null;
109084
+ const rows = this.db.prepare(`
109085
+ SELECT session_id, notification_id, content, attempts, next_attempt_at
109086
+ FROM collaboration_wakes w WHERE state = 'queued' AND NOT EXISTS (
109087
+ SELECT 1 FROM collaboration_wake_recipients r WHERE r.session_id = w.session_id AND r.paused = 1
109088
+ ) ORDER BY created_at, rowid
109089
+ `).all();
109090
+ let nextAttemptAt = Infinity;
109091
+ for (const row2 of rows) {
109092
+ if (this.delivering.has(row2.session_id) || this.paused.has(row2.session_id)) continue;
109093
+ if (this.deps.canAdmit?.(row2.session_id) === false) continue;
109094
+ if (row2.attempts >= COLLABORATION_WAKE_MAX_ATTEMPTS) {
109095
+ this.db.prepare(`UPDATE collaboration_wakes SET state = 'failed'
109096
+ WHERE session_id = ? AND notification_id = ?`).run(row2.session_id, row2.notification_id);
109097
+ this.pause(row2.session_id);
109098
+ continue;
109099
+ }
109100
+ if (row2.next_attempt_at > this.now()) {
109101
+ nextAttemptAt = Math.min(nextAttemptAt, row2.next_attempt_at);
109102
+ continue;
109103
+ }
109104
+ this.delivering.add(row2.session_id);
109105
+ this.db.prepare(`UPDATE collaboration_wakes SET state = 'preparing', attempts = attempts + 1
109106
+ WHERE session_id = ? AND notification_id = ?`).run(row2.session_id, row2.notification_id);
109107
+ void this.admit(row2);
109108
+ }
109109
+ if (Number.isFinite(nextAttemptAt)) {
109110
+ this.timer = setTimeout(() => {
109111
+ this.timer = null;
109112
+ this.flush();
109113
+ }, Math.max(1, nextAttemptAt - this.now()));
109114
+ this.timer.unref?.();
109115
+ }
109116
+ }
109117
+ async admit(row2) {
109118
+ let admitted = false;
109119
+ let deferred = false;
109120
+ const confirm = () => {
109121
+ if (admitted) return;
109122
+ this.db.prepare(`UPDATE collaboration_wakes SET state = 'dispatching'
109123
+ WHERE session_id = ? AND notification_id = ?`).run(row2.session_id, row2.notification_id);
109124
+ admitted = true;
109125
+ try {
109126
+ this.db.prepare(`UPDATE collaboration_wakes SET state = 'admitted', last_error = NULL
109127
+ WHERE session_id = ? AND notification_id = ?`).run(row2.session_id, row2.notification_id);
109128
+ } catch (error51) {
109129
+ this.paused.add(row2.session_id);
109130
+ this.deps.warn(`[collaboration-wake] accepted input receipt failed sid=${row2.session_id}: ${String(error51)}`);
109131
+ }
109132
+ };
109133
+ try {
109134
+ await this.deps.admit(row2.session_id, row2.content, row2.notification_id, confirm, () => {
109135
+ if (this.closed || this.paused.has(row2.session_id)) throw new CollaborationWakeDeferredError("Notification recipient is paused or shutting down");
109136
+ });
109137
+ confirm();
109138
+ } catch (error51) {
109139
+ if (!admitted) {
109140
+ const message = error51 instanceof Error ? error51.message : String(error51);
109141
+ deferred = this.closed || error51 instanceof CollaborationWakeDeferredError;
109142
+ const attempts = row2.attempts + (deferred ? 0 : 1);
109143
+ this.db.prepare(`UPDATE collaboration_wakes SET state = ?, attempts = ?, next_attempt_at = ?, last_error = ?
109144
+ WHERE session_id = ? AND notification_id = ?`).run(
109145
+ attempts >= COLLABORATION_WAKE_MAX_ATTEMPTS ? "failed" : "queued",
109146
+ attempts,
109147
+ deferred ? 0 : this.now() + (RETRY_DELAYS_MS[attempts - 1] ?? 0),
109148
+ message,
109149
+ row2.session_id,
109150
+ row2.notification_id
109151
+ );
109152
+ if (attempts >= COLLABORATION_WAKE_MAX_ATTEMPTS) {
109153
+ this.pause(row2.session_id);
109154
+ }
109155
+ if (!deferred) this.deps.warn(`[collaboration-wake] admission failed sid=${row2.session_id} attempt=${attempts}/${COLLABORATION_WAKE_MAX_ATTEMPTS}: ${message}`);
109156
+ }
109157
+ } finally {
109158
+ this.delivering.delete(row2.session_id);
109159
+ if (!this.closed && !deferred) this.start();
109160
+ }
109161
+ }
109162
+ /** Leave durable work and attempt counts intact when the host shuts down. */
109163
+ dispose() {
109164
+ this.closed = true;
109165
+ if (this.timer) clearTimeout(this.timer);
109166
+ this.timer = null;
109167
+ }
109168
+ };
109169
+
108225
109170
  // ../../packages/runtime/src/db/schema.ts
108226
109171
  var SCHEMA_SQL = `
109172
+ ${COLLABORATION_WAKE_TABLE_DDL}
108227
109173
  PRAGMA foreign_keys = ON;
108228
109174
 
108229
109175
  CREATE TABLE IF NOT EXISTS meta (
@@ -110818,7 +111764,7 @@ async function handleHarnessResources(payload, ctx) {
110818
111764
  ctx.projects.touch(projectId);
110819
111765
  const harnessId = typeof p3.harnessId === "string" && p3.harnessId.trim() ? p3.harnessId.trim() : null;
110820
111766
  const apiProviderId = typeof p3.apiProviderId === "string" && p3.apiProviderId.trim() ? p3.apiProviderId.trim() : p3.apiProviderId === null ? null : void 0;
110821
- const providerOptions = {
111767
+ const providerOptions2 = {
110822
111768
  experimentalClaudeOpenAiChatEnabled: ctx.experimentalClaudeOpenAiChatEnabled ?? false
110823
111769
  };
110824
111770
  const openCodeProvider = !harnessId || harnessId === "opencode" ? resolveNodeOpenCodeProvider(ctx.providers, apiProviderId) : null;
@@ -110829,7 +111775,7 @@ async function handleHarnessResources(payload, ctx) {
110829
111775
  ctx.providers,
110830
111776
  hid,
110831
111777
  apiId ?? null,
110832
- providerOptions
111778
+ providerOptions2
110833
111779
  );
110834
111780
  };
110835
111781
  const probeModels = async (hid) => {
@@ -110844,7 +111790,7 @@ async function handleHarnessResources(payload, ctx) {
110844
111790
  ctx.providers,
110845
111791
  hid,
110846
111792
  apiProviderId ?? null,
110847
- providerOptions
111793
+ providerOptions2
110848
111794
  );
110849
111795
  };
110850
111796
  const bundle = await collectHarnessResources({
@@ -111702,6 +112648,9 @@ init_codex_turn_runner();
111702
112648
  // src/session/harness-manager.ts
111703
112649
  init_harness();
111704
112650
 
112651
+ // src/session/collaboration.ts
112652
+ init_environment();
112653
+
111705
112654
  // ../../packages/runtime/src/collaboration/errors.ts
111706
112655
  var CollaborationError = class extends Error {
111707
112656
  constructor(message, code) {
@@ -112106,6 +113055,13 @@ var CollaborationStore = class {
112106
113055
  WHERE child_session_id IS NOT NULL AND COALESCE(kind, 'spawn') = 'spawn'
112107
113056
  `).all();
112108
113057
  }
113058
+ /** Started handoff grants; the session each created is `config_json.handoffSessionId`. */
113059
+ startedHandoffGrants() {
113060
+ return this.db.prepare(`
113061
+ SELECT ${GRANT_COLUMNS} FROM session_collaboration_grants
113062
+ WHERE kind = 'handoff' AND started_at IS NOT NULL
113063
+ `).all();
113064
+ }
112109
113065
  /**
112110
113066
  * Open mailbox channels of `sessionId`: spawn grants with a bound child and
112111
113067
  * started link grants, oldest first. Handoff grants are never channels.
@@ -112343,30 +113299,29 @@ init_text();
112343
113299
  function sessionTitle(ctx) {
112344
113300
  return (sessionId) => ctx.deps.sessions.get(sessionId)?.title ?? null;
112345
113301
  }
112346
- async function wakePeer(ctx, sessionId, fromSessionId) {
112347
- if (!ctx.deps.sessions.get(sessionId)) return;
113302
+ function wakePeer(ctx, sessionId, fromSessionId, messageId) {
112348
113303
  const fromTitle = ctx.deps.sessions.get(fromSessionId)?.title?.trim() || fromSessionId.slice(0, 8);
112349
- try {
112350
- await ctx.deps.sessions.sendWithoutLease({
112351
- sessionId,
112352
- text: mailboxWakeText({ sessionId: fromSessionId, title: fromTitle }),
112353
- source: "task-notification",
112354
- requestId: `collab-wake-${fromSessionId.slice(0, 8)}-${Date.now()}`
112355
- });
112356
- } catch {
112357
- }
113304
+ ctx.wakes.enqueue(
113305
+ sessionId,
113306
+ `collab-message:${messageId}`,
113307
+ mailboxWakeText({ sessionId: fromSessionId, title: fromTitle })
113308
+ );
112358
113309
  }
112359
113310
  function sendCollaborationMessage(ctx, input) {
112360
113311
  const channel = resolveSendChannel(ctx.store, input.sessionId, input.to, sessionTitle(ctx));
112361
113312
  const content = normalizeMailboxContent(input.content);
112362
113313
  const recipientSessionId = channel.peer.sessionId;
112363
- const insert = ctx.store.appendMessage({
112364
- grantId: channel.grant.grant_id,
112365
- senderSessionId: input.sessionId,
112366
- recipientSessionId,
112367
- clientMessageId: input.clientMessageId,
112368
- content
112369
- });
113314
+ const insert = ctx.deps.db.transaction(() => {
113315
+ const inserted = ctx.store.appendMessage({
113316
+ grantId: channel.grant.grant_id,
113317
+ senderSessionId: input.sessionId,
113318
+ recipientSessionId,
113319
+ clientMessageId: input.clientMessageId,
113320
+ content
113321
+ });
113322
+ wakePeer(ctx, recipientSessionId, input.sessionId, inserted.row.id);
113323
+ return inserted;
113324
+ })();
112370
113325
  if (!insert.reused) {
112371
113326
  ctx.deps.events.append({
112372
113327
  aggregateType: "session",
@@ -112379,7 +113334,6 @@ function sendCollaborationMessage(ctx, input) {
112379
113334
  sequence: insert.row.sequence
112380
113335
  }
112381
113336
  });
112382
- void wakePeer(ctx, recipientSessionId, input.sessionId);
112383
113337
  }
112384
113338
  return {
112385
113339
  status: "sent",
@@ -112402,57 +113356,77 @@ function retrieveCollaborationMessages(ctx, input) {
112402
113356
  }
112403
113357
 
112404
113358
  // src/session/collaboration-profiles.ts
113359
+ init_agent_profile();
112405
113360
  init_environment();
113361
+ init_harness_capabilities();
112406
113362
 
112407
113363
  // ../../packages/shared/src/acp-brand.ts
112408
113364
  init_acp_brand();
112409
113365
 
112410
113366
  // src/session/collaboration-profiles.ts
112411
113367
  init_resolve_service();
113368
+ function providerOptions(deps) {
113369
+ return { experimentalClaudeOpenAiChatEnabled: deps.experimentalClaudeOpenAiChatEnabled?.() ?? false };
113370
+ }
113371
+ var NODE_APPLIABLE_OPTIONS = ["agent"];
113372
+ function launchResolution(deps, harnessId, config2, launch2) {
113373
+ const harnessModels = listHarnessModels(deps.providers, harnessId, null, providerOptions(deps));
113374
+ const defaultModel = harnessModels.find((m3) => m3.isDefault) ?? harnessModels[0];
113375
+ const efforts = /* @__PURE__ */ new Set();
113376
+ for (const m3 of harnessModels) {
113377
+ for (const e of m3.supportedEffortLevels ?? []) efforts.add(e);
113378
+ }
113379
+ const catalog = { models: harnessModels, host: { appliable: NODE_APPLIABLE_OPTIONS } };
113380
+ const defaults2 = resolveAgentLaunchDefaults({
113381
+ harnessId,
113382
+ catalog,
113383
+ base: {
113384
+ model: defaultModel?.id,
113385
+ effort: efforts.has("high") ? "high" : efforts.has("medium") ? "medium" : [...efforts][0]
113386
+ },
113387
+ profile: providerLaunchRuntime(config2),
113388
+ launch: launch2
113389
+ });
113390
+ return { harnessModels, efforts, catalog, defaults: defaults2 };
113391
+ }
113392
+ function collaborationLaunchDefaults(deps, profile, launch2) {
113393
+ const explicit = launchDefaultsFromConfig(launch2);
113394
+ if (!Object.keys(explicit).length) return profile.defaultConfig;
113395
+ const { catalog, defaults: defaults2 } = launchResolution(deps, profile.harnessId, deps.sessionProviders?.get(profile.id)?.config, explicit);
113396
+ const harness = { id: profile.harnessId, name: HARNESS_CAPABILITIES[profile.harnessId]?.displayName ?? profile.harnessId };
113397
+ const errors = agentLaunchErrors(harness, catalog, defaults2.model, explicit);
113398
+ if (errors.length) throw new CollaborationError(errors.join(" "), "invalid_argument");
113399
+ return launchConfigFromDefaults(defaults2);
113400
+ }
112412
113401
  function listCollaborationProfiles(deps) {
112413
113402
  const { harnesses, providers, sessions, sessionProviders } = deps;
112414
113403
  const profiles = [];
112415
113404
  const seen = /* @__PURE__ */ new Set();
112416
- const providerOptions = {
112417
- experimentalClaudeOpenAiChatEnabled: deps.experimentalClaudeOpenAiChatEnabled?.() ?? false
112418
- };
112419
113405
  const pushProfile = (profileId, harnessId, name, description, profileConfig) => {
112420
113406
  if (seen.has(profileId)) return;
112421
113407
  if (!harnesses.isSessionHarnessRunnable(harnessId)) return;
112422
113408
  seen.add(profileId);
112423
- const harnessModels = listHarnessModels(providers, harnessId, null, providerOptions);
113409
+ const { harnessModels, efforts, defaults: defaults2 } = launchResolution(deps, harnessId, profileConfig);
112424
113410
  const models = harnessModels.map((m3) => ({
112425
113411
  id: m3.id,
112426
113412
  name: m3.name || m3.id,
112427
113413
  ...m3.description ? { description: m3.description } : {},
112428
113414
  ...m3.serviceTiers?.length ? { serviceTiers: m3.serviceTiers } : {}
112429
113415
  }));
112430
- const defaultModel = harnessModels.find((m3) => m3.isDefault) ?? harnessModels[0];
112431
- const efforts = /* @__PURE__ */ new Set();
112432
- for (const m3 of harnessModels) {
112433
- for (const e of m3.supportedEffortLevels ?? []) efforts.add(e);
112434
- }
112435
113416
  const cfg = profileConfig && typeof profileConfig === "object" && !Array.isArray(profileConfig) ? profileConfig : {};
112436
- const cfgModel = typeof cfg.model === "string" && cfg.model.trim() ? cfg.model.trim() : void 0;
112437
- const cfgEffort = typeof cfg.effort === "string" && cfg.effort.trim() ? cfg.effort.trim() : typeof cfg.reasoningEffort === "string" && cfg.reasoningEffort.trim() ? cfg.reasoningEffort.trim() : void 0;
112438
113417
  const acpAgentId = harnessId === "acp" && typeof cfg.agentId === "string" && cfg.agentId.trim() ? cfg.agentId.trim() : null;
112439
- const modelDefault = cfgModel ?? defaultModel?.id;
112440
- const effortDefault = cfgEffort ?? (efforts.has("high") ? "high" : efforts.has("medium") ? "medium" : efforts.size > 0 ? [...efforts][0] : void 0);
113418
+ const profile = readAgentProfile(profileConfig);
112441
113419
  profiles.push({
112442
113420
  id: profileId,
112443
- name: harnessId === "acp" ? acpAgentDisplayName(acpAgentId) : name,
113421
+ name: profile ? name : harnessId === "acp" ? acpAgentDisplayName(acpAgentId) : name,
112444
113422
  harnessId,
112445
113423
  ...acpAgentId ? { acpAgentId } : {},
112446
113424
  brandKey: resolveHarnessBrandKey(harnessId, acpAgentId),
112447
- description,
112448
- defaultConfig: {
112449
- ...modelDefault ? { model: modelDefault } : {},
112450
- ...effortDefault ? { effort: effortDefault } : {},
112451
- ...harnessId === "codex" ? { fastMode: typeof cfg.fastMode === "boolean" ? cfg.fastMode : false } : {}
112452
- },
113425
+ description: profile?.identity.description ?? description,
113426
+ defaultConfig: launchConfigFromDefaults(defaults2),
112453
113427
  models: models.length > 0 ? models : [{ id: "default", name: "Default" }],
112454
113428
  efforts: [...efforts],
112455
- apiProviders: listHarnessApiProviders(providers, harnessId, providerOptions)
113429
+ apiProviders: listHarnessApiProviders(providers, harnessId, providerOptions(deps))
112456
113430
  });
112457
113431
  };
112458
113432
  if (sessionProviders) {
@@ -112478,6 +113452,16 @@ function listCollaborationProfiles(deps) {
112478
113452
  }
112479
113453
  return profiles;
112480
113454
  }
113455
+ function collaborationAgentPromptAppend(deps, agentId, protocol) {
113456
+ return providerSystemPromptAppend(deps.sessionProviders?.get(agentId)?.config, protocol);
113457
+ }
113458
+ function launchedSessionPromptAppend(deps, grant) {
113459
+ return collaborationAgentPromptAppend(
113460
+ deps,
113461
+ grant.agent_id,
113462
+ grant.kind === "handoff" ? void 0 : collaborationSystemPrompt(grant.parent_session_id)
113463
+ );
113464
+ }
112481
113465
 
112482
113466
  // src/session/collaboration-request.ts
112483
113467
  import { randomUUID as randomUUID21 } from "node:crypto";
@@ -112559,7 +113543,7 @@ function normalizeLaunches(ctx, input, profileList) {
112559
113543
  name,
112560
113544
  role,
112561
113545
  config: {
112562
- ...profile.defaultConfig,
113546
+ ...collaborationLaunchDefaults(ctx.deps, profile, safe),
112563
113547
  ...safe,
112564
113548
  permissionMode: "default",
112565
113549
  sandboxMode: "off",
@@ -112667,21 +113651,16 @@ async function deliverInitialTask(ctx, grant, childSessionId) {
112667
113651
  }
112668
113652
  ctx.store.markTaskSent(grant.grant_id);
112669
113653
  }
112670
- async function wakeLinkPeer(ctx, sessionId, grant, hasOpening) {
112671
- if (!ctx.deps.sessions.get(sessionId)) return;
112672
- try {
112673
- await ctx.deps.sessions.sendWithoutLease({
112674
- sessionId,
112675
- text: linkActivationWakeText({
112676
- initiatorSessionId: grant.parent_session_id,
112677
- initiatorTitle: initiatorTitleOf(ctx, grant),
112678
- hasOpening
112679
- }),
112680
- source: "task-notification",
112681
- requestId: `collab-link-wake-${grant.grant_id.slice(0, 12)}-${Date.now()}`
112682
- });
112683
- } catch {
112684
- }
113654
+ function wakeLinkPeer(ctx, sessionId, grant, hasOpening) {
113655
+ ctx.wakes.enqueue(
113656
+ sessionId,
113657
+ `collab-link:${grant.grant_id}`,
113658
+ linkActivationWakeText({
113659
+ initiatorSessionId: grant.parent_session_id,
113660
+ initiatorTitle: initiatorTitleOf(ctx, grant),
113661
+ hasOpening
113662
+ })
113663
+ );
112685
113664
  }
112686
113665
  async function startLink(ctx, grant) {
112687
113666
  if (!grant.child_session_id) {
@@ -112730,12 +113709,7 @@ async function startCollaboration(ctx, input) {
112730
113709
  if (isHandoff2 && !existing) {
112731
113710
  throw new CollaborationError(`The handoff session no longer exists: ${existingSessionId}`, "not_found");
112732
113711
  }
112733
- if (existing && !isHandoff2) {
112734
- ctx.deps.sessions.setSystemPromptAppend(
112735
- existing.sessionId,
112736
- collaborationSystemPrompt(grant.parent_session_id)
112737
- );
112738
- }
113712
+ if (existing) ctx.deps.sessions.setSystemPromptAppend(existing.sessionId, launchedSessionPromptAppend(ctx.deps, grant));
112739
113713
  if (existing) await deliverInitialTask(ctx, grant, existingSessionId);
112740
113714
  const peer = describeLaunchedPeer(grant);
112741
113715
  return {
@@ -112781,9 +113755,10 @@ async function startCollaboration(ctx, input) {
112781
113755
  permissionMode: config2.permissionMode ?? null,
112782
113756
  sandboxMode: config2.sandboxMode ?? null,
112783
113757
  apiProviderId: config2.apiProviderId ?? null,
113758
+ // The one profile option this node's runtime takes (see NODE_APPLIABLE_OPTIONS).
113759
+ agent: config2.options?.agent ?? null,
112784
113760
  controllerClientSessionId: input.controllerClientSessionId ?? parent.controllerClientSessionId,
112785
- // Handoff is one-way by construction: the receiver gets no collaboration prompt.
112786
- ...isHandoff2 ? {} : { systemPromptAppend: collaborationSystemPrompt(grant.parent_session_id) }
113761
+ systemPromptAppend: launchedSessionPromptAppend(ctx.deps, grant) ?? null
112787
113762
  });
112788
113763
  ctx.store.bindStartedSession(grant, child.sessionId, config2);
112789
113764
  } catch (err) {
@@ -112831,14 +113806,59 @@ async function startCollaboration(ctx, input) {
112831
113806
  var CollaborationService = class {
112832
113807
  constructor(deps) {
112833
113808
  this.deps = deps;
113809
+ const wakes = new CollaborationWakeQueue(deps.db, {
113810
+ canAdmit: (sessionId) => {
113811
+ const session = deps.sessions.get(sessionId);
113812
+ if (!session) return true;
113813
+ if (session.status === "error" || session.status === "streaming" || session.pendingInteraction) return false;
113814
+ if (session.status !== "interrupted") return true;
113815
+ const latest = deps.db.prepare(`SELECT payload_json FROM environment_events
113816
+ WHERE aggregate_type = 'session' AND aggregate_id = ? AND event_type = ?
113817
+ ORDER BY sequence DESC LIMIT 1`).get(sessionId, SESSION_DURABLE_EVENT.turnInterrupted);
113818
+ if (!latest) return false;
113819
+ try {
113820
+ return isNodeRestartInterruption(JSON.parse(latest.payload_json)?.reason);
113821
+ } catch {
113822
+ return false;
113823
+ }
113824
+ },
113825
+ admit: (sessionId, text2, requestId, onInputAccepted, beforeInput) => deps.sessions.sendWithoutLease({
113826
+ sessionId,
113827
+ text: text2,
113828
+ requestId,
113829
+ source: "task-notification"
113830
+ }, { onInputAccepted, beforeInput }),
113831
+ warn: (message) => console.warn(message)
113832
+ });
112834
113833
  this.ctx = {
112835
113834
  deps,
112836
113835
  store: new CollaborationStore(deps.db),
113836
+ wakes,
112837
113837
  listProfiles: () => this.listProfiles()
112838
113838
  };
113839
+ this.unsubscribe = deps.events.onAppend((event) => {
113840
+ if (event.aggregateType !== "session") return;
113841
+ const agentEvent = event.payload?.event;
113842
+ if (agentEvent) wakes.observe(event.aggregateId, agentEvent);
113843
+ if (event.eventType === SESSION_DURABLE_EVENT.turnError) {
113844
+ wakes.observe(event.aggregateId, { type: "message_error", messageId: "", error: "turn failed" });
113845
+ } else if (event.eventType === SESSION_DURABLE_EVENT.turnInterrupted) {
113846
+ const reason = event.payload?.reason;
113847
+ wakes.observe(event.aggregateId, { type: "message_interrupted", messageId: "", reason });
113848
+ } else if (event.eventType === SESSION_DURABLE_EVENT.turnCompleted) {
113849
+ wakes.observe(event.aggregateId, { type: "message_complete", messageId: "" });
113850
+ }
113851
+ if (!event.ephemeral) wakes.start();
113852
+ });
113853
+ wakes.start();
112839
113854
  }
112840
113855
  deps;
112841
113856
  ctx;
113857
+ unsubscribe;
113858
+ dispose() {
113859
+ this.unsubscribe();
113860
+ this.ctx.wakes.dispose();
113861
+ }
112842
113862
  /** Agent profiles from session_providers (+ ready-harness fallback). */
112843
113863
  isSpawnChild(sessionId) {
112844
113864
  return this.ctx.store.isSpawnChild(sessionId);
@@ -112858,11 +113878,18 @@ var CollaborationService = class {
112858
113878
  retrieve(input) {
112859
113879
  return retrieveCollaborationMessages(this.ctx, input);
112860
113880
  }
112861
- /** Reconstruct system-prompt append for spawn children after restart (never link). */
113881
+ /** Reconstruct the system-prompt append of launched sessions after restart (never link). */
112862
113882
  rehydrateSystemPrompts() {
112863
- for (const grant of this.ctx.store.startedSpawnGrants()) {
112864
- if (!grant.child_session_id || !this.deps.sessions.get(grant.child_session_id)) continue;
112865
- this.deps.sessions.setSystemPromptAppend(grant.child_session_id, collaborationSystemPrompt(grant.parent_session_id));
113883
+ const launched = [
113884
+ ...this.ctx.store.startedSpawnGrants().map((grant) => ({ grant, sessionId: grant.child_session_id })),
113885
+ ...this.ctx.store.startedHandoffGrants().map((grant) => ({
113886
+ grant,
113887
+ sessionId: parseGrantConfig(grant.config_json).handoffSessionId
113888
+ }))
113889
+ ];
113890
+ for (const { grant, sessionId } of launched) {
113891
+ if (!sessionId || !this.deps.sessions.get(sessionId)) continue;
113892
+ this.deps.sessions.setSystemPromptAppend(sessionId, launchedSessionPromptAppend(this.deps, grant));
112866
113893
  }
112867
113894
  }
112868
113895
  };
@@ -125143,6 +126170,24 @@ function widgetShowShortContent(args) {
125143
126170
  ];
125144
126171
  }
125145
126172
 
126173
+ // ../../packages/shared/src/collab-agent-catalog.ts
126174
+ function collabAgentSummary(profile) {
126175
+ return {
126176
+ id: profile.id,
126177
+ name: profile.name,
126178
+ harnessId: profile.harnessId,
126179
+ ...profile.acpAgentId ? { acpAgentId: profile.acpAgentId } : {},
126180
+ ...profile.description ? { description: profile.description } : {}
126181
+ };
126182
+ }
126183
+ function collabAgentDetail(profile) {
126184
+ const { brandKey: _brandKey, ...detail } = profile;
126185
+ return detail;
126186
+ }
126187
+ function unknownCollabAgentMessage(id, environment) {
126188
+ return environment ? `Agent ${id} is not available on environment ${environment}. Call session_collab_list_agents without id and pick one from environments[].agents.` : `Unknown agent ${id}. Call session_collab_list_agents without id to see the available agents.`;
126189
+ }
126190
+
125146
126191
  // src/session/json-schema-to-zod.ts
125147
126192
  function numberConstraint(value) {
125148
126193
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
@@ -125338,12 +126383,22 @@ function registerNodeCollabTools(server, superoneSessionId, collab) {
125338
126383
  "session_collab_list_agents",
125339
126384
  {
125340
126385
  description: listDesc.description,
125341
- inputSchema: {}
126386
+ inputSchema: jsonSchemaToZodShape(listDesc.inputSchema)
125342
126387
  },
125343
- async () => {
126388
+ async (args) => {
125344
126389
  try {
126390
+ const { id, environment } = args ?? {};
126391
+ if (environment?.trim()) {
126392
+ return collabErrorResult(Object.assign(
126393
+ new Error("Agents on other machines are only listed from the SuperOne desktop app."),
126394
+ { code: "failed_precondition" }
126395
+ ));
126396
+ }
125345
126397
  const agents = await collab.listAgents(superoneSessionId);
125346
- return toolResultJson({ agents });
126398
+ const wanted = id?.trim();
126399
+ if (!wanted) return toolResultJson({ agents: agents.map(collabAgentSummary) });
126400
+ const agent = agents.find((profile) => profile.id === wanted);
126401
+ return agent ? toolResultJson(collabAgentDetail(agent)) : collabErrorResult(Object.assign(new Error(unknownCollabAgentMessage(wanted)), { code: "not_found" }));
125347
126402
  } catch (err) {
125348
126403
  return collabErrorResult(err);
125349
126404
  }
@@ -127248,6 +128303,7 @@ async function startNodeRuntime(partial2 = {}) {
127248
128303
  startedAt,
127249
128304
  async stop() {
127250
128305
  automationService.stop();
128306
+ collaboration.dispose();
127251
128307
  const disposePromise = sessions.dispose();
127252
128308
  await server.close();
127253
128309
  await disposePromise;