oh-my-opencode-serverlocal 0.1.2 → 0.1.3

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.
package/dist/index.js CHANGED
@@ -18476,12 +18476,10 @@ var SUBAGENT_NAMES = [
18476
18476
  "oracle",
18477
18477
  "designer",
18478
18478
  "fixer",
18479
- "observer",
18480
- "council",
18481
- "councillor"
18479
+ "observer"
18482
18480
  ];
18483
18481
  var ALL_AGENT_NAMES = ["orchestrator", ...SUBAGENT_NAMES];
18484
- var PROTECTED_AGENTS = new Set(["orchestrator", "councillor"]);
18482
+ var PROTECTED_AGENTS = new Set(["orchestrator"]);
18485
18483
  var DEFAULT_MODELS = {
18486
18484
  orchestrator: undefined,
18487
18485
  oracle: undefined,
@@ -18489,9 +18487,7 @@ var DEFAULT_MODELS = {
18489
18487
  explorer: undefined,
18490
18488
  designer: undefined,
18491
18489
  fixer: undefined,
18492
- observer: undefined,
18493
- council: undefined,
18494
- councillor: undefined
18490
+ observer: undefined
18495
18491
  };
18496
18492
  var POLL_INTERVAL_BACKGROUND_MS = 2000;
18497
18493
  var MAX_POLL_TIME_MS = 5 * 60 * 1000;
@@ -18514,12 +18510,6 @@ var READONLY_FILE_OPERATIONS_RULES = `**File Operations Rules**:
18514
18510
  - Prefer dedicated file tools for codebase inspection: glob/grep/ast_grep_search for discovery and read for file contents.
18515
18511
  - Bash is allowed for non-mutating diagnostics and shell-native inspection when it is the clearest tool, but not for modifying files.
18516
18512
  - Do not use cat/head/tail/sed/awk only to read code into context; use read/grep unless a shell pipeline is genuinely the better diagnostic.`;
18517
- var NO_SHELL_READONLY_FILE_OPERATIONS_RULES = `**File Operations Rules**:
18518
- - READ-ONLY: inspect and report; do not modify files.
18519
- - Use glob/grep/ast_grep_search for discovery and read for file contents.
18520
- - Do not use bash or shell commands.`;
18521
- var TMUX_SPAWN_DELAY_MS = 500;
18522
- var COUNCILLOR_STAGGER_MS = 250;
18523
18513
  var DEFAULT_DISABLED_AGENTS = ["observer"];
18524
18514
  var DEFAULT_MAX_SESSIONS_PER_AGENT = 2;
18525
18515
  var DEFAULT_READ_CONTEXT_MIN_LINES = 10;
@@ -18528,92 +18518,6 @@ var DEFAULT_IMAGE_ROUTING = "auto";
18528
18518
  function resolveImageRouting(imageRouting) {
18529
18519
  return imageRouting ?? DEFAULT_IMAGE_ROUTING;
18530
18520
  }
18531
- // src/config/council-schema.ts
18532
- import { z } from "zod";
18533
-
18534
- // src/utils/councillor-models.ts
18535
- function normalizeCouncillorModels(model, fallbackVariant) {
18536
- const raw = Array.isArray(model) ? model : [model];
18537
- return raw.map((entry) => typeof entry === "string" ? { id: entry, variant: fallbackVariant } : { id: entry.id, variant: entry.variant ?? fallbackVariant });
18538
- }
18539
-
18540
- // src/config/council-schema.ts
18541
- var ModelIdSchema = z.string().regex(/^[^/\s]+\/[^\s]+$/, 'Expected provider/model format (e.g. "openai/gpt-5.6-luna")');
18542
- var CouncillorModelEntrySchema = z.object({
18543
- id: ModelIdSchema,
18544
- variant: z.string().optional()
18545
- });
18546
- var CouncillorModelSchema = z.union([
18547
- ModelIdSchema,
18548
- z.array(z.union([ModelIdSchema, CouncillorModelEntrySchema])).min(1)
18549
- ]).describe('Model ID in provider/model format (e.g. "openai/gpt-5.6-luna"), or an ' + "ordered fallback chain (array of model IDs or { id, variant } entries) " + "tried in order until one responds.");
18550
- var CouncillorConfigSchema = z.object({
18551
- model: CouncillorModelSchema,
18552
- variant: z.string().optional(),
18553
- prompt: z.string().optional().describe("Optional role/guidance injected into the councillor user prompt")
18554
- }).transform((c) => {
18555
- const models = normalizeCouncillorModels(c.model, c.variant);
18556
- return {
18557
- model: models[0].id,
18558
- variant: c.variant,
18559
- prompt: c.prompt,
18560
- models
18561
- };
18562
- });
18563
- var CouncilPresetSchema = z.record(z.string(), z.record(z.string(), z.unknown())).transform((entries, ctx) => {
18564
- const councillors = {};
18565
- for (const [key, raw] of Object.entries(entries)) {
18566
- if (key === "master")
18567
- continue;
18568
- if (key === "councillors" && typeof raw === "object" && raw !== null) {
18569
- for (const [innerKey, innerRaw] of Object.entries(raw)) {
18570
- const innerParsed = CouncillorConfigSchema.safeParse(innerRaw);
18571
- if (!innerParsed.success) {
18572
- ctx.addIssue({
18573
- code: z.ZodIssueCode.custom,
18574
- message: `Invalid councillor "${innerKey}" (nested under legacy "councillors" key): ${innerParsed.error.issues.map((i) => i.message).join(", ")}`
18575
- });
18576
- return z.NEVER;
18577
- }
18578
- councillors[innerKey] = innerParsed.data;
18579
- }
18580
- continue;
18581
- }
18582
- const parsed = CouncillorConfigSchema.safeParse(raw);
18583
- if (!parsed.success) {
18584
- ctx.addIssue({
18585
- code: z.ZodIssueCode.custom,
18586
- message: `Invalid councillor "${key}": ${parsed.error.issues.map((i) => i.message).join(", ")}`
18587
- });
18588
- return z.NEVER;
18589
- }
18590
- councillors[key] = parsed.data;
18591
- }
18592
- return councillors;
18593
- });
18594
- var CouncillorExecutionModeSchema = z.enum(["parallel", "serial"]).default("parallel").describe('Execution mode for councillors. Use "serial" for single-model systems to avoid conflicts. ' + 'Use "parallel" for multi-model systems for faster execution.');
18595
- var CouncilConfigSchema = z.object({
18596
- presets: z.record(z.string(), CouncilPresetSchema),
18597
- timeout: z.number().min(0).default(180000),
18598
- default_preset: z.string().default("default"),
18599
- councillor_execution_mode: CouncillorExecutionModeSchema.describe('Execution mode for councillors. "serial" runs them one at a time (required for single-model systems). "parallel" runs them concurrently (default, faster for multi-model systems).'),
18600
- councillor_retries: z.number().int().min(0).max(5).default(3).describe("Number of retry attempts for councillors that return empty responses " + "(e.g. due to provider rate limiting). Default: 3 retries."),
18601
- master: z.unknown().optional().describe("DEPRECATED - ignored. Council agent synthesizes directly.")
18602
- }).transform((data) => {
18603
- const deprecated = [];
18604
- if (data.master !== undefined)
18605
- deprecated.push("master");
18606
- const legacyMasterModel = typeof data.master === "object" && data.master !== null && "model" in data.master && typeof data.master.model === "string" ? data.master.model : undefined;
18607
- return {
18608
- presets: data.presets,
18609
- timeout: data.timeout,
18610
- default_preset: data.default_preset,
18611
- councillor_execution_mode: data.councillor_execution_mode,
18612
- councillor_retries: data.councillor_retries,
18613
- _deprecated: deprecated.length > 0 ? deprecated : undefined,
18614
- _legacyMasterModel: legacyMasterModel
18615
- };
18616
- });
18617
18521
  // src/config/loader.ts
18618
18522
  import * as fs from "node:fs";
18619
18523
  import * as path from "node:path";
@@ -18629,9 +18533,7 @@ var DEFAULT_AGENT_MCPS = {
18629
18533
  librarian: ["websearch", "context7", "gh_grep"],
18630
18534
  explorer: [],
18631
18535
  fixer: [],
18632
- observer: [],
18633
- council: [],
18634
- councillor: []
18536
+ observer: []
18635
18537
  };
18636
18538
  function parseList(items, allAvailable) {
18637
18539
  if (!items || items.length === 0) {
@@ -18664,9 +18566,9 @@ function stripJsonComments(json) {
18664
18566
  }
18665
18567
 
18666
18568
  // src/config/schema.ts
18667
- import { z as z2 } from "zod";
18668
- var ProviderModelIdSchema = z2.string().regex(/^[^/\s]+\/[^\s]+$/, "Expected provider/model format (provider/.../model)");
18669
- var ManualAgentPlanSchema = z2.object({
18569
+ import { z } from "zod";
18570
+ var ProviderModelIdSchema = z.string().regex(/^[^/\s]+\/[^\s]+$/, "Expected provider/model format (provider/.../model)");
18571
+ var ManualAgentPlanSchema = z.object({
18670
18572
  primary: ProviderModelIdSchema,
18671
18573
  fallback1: ProviderModelIdSchema,
18672
18574
  fallback2: ProviderModelIdSchema,
@@ -18680,12 +18582,12 @@ var ManualAgentPlanSchema = z2.object({
18680
18582
  ]);
18681
18583
  if (unique.size !== 4) {
18682
18584
  ctx.addIssue({
18683
- code: z2.ZodIssueCode.custom,
18585
+ code: z.ZodIssueCode.custom,
18684
18586
  message: "primary and fallbacks must be unique per agent"
18685
18587
  });
18686
18588
  }
18687
18589
  });
18688
- var ManualPlanSchema = z2.object({
18590
+ var ManualPlanSchema = z.object({
18689
18591
  orchestrator: ManualAgentPlanSchema,
18690
18592
  oracle: ManualAgentPlanSchema,
18691
18593
  designer: ManualAgentPlanSchema,
@@ -18693,12 +18595,12 @@ var ManualPlanSchema = z2.object({
18693
18595
  librarian: ManualAgentPlanSchema,
18694
18596
  fixer: ManualAgentPlanSchema
18695
18597
  }).strict();
18696
- var PermissionActionSchema = z2.enum(["ask", "allow", "deny"]);
18697
- var PermissionRuleSchema = z2.union([
18598
+ var PermissionActionSchema = z.enum(["ask", "allow", "deny"]);
18599
+ var PermissionRuleSchema = z.union([
18698
18600
  PermissionActionSchema,
18699
- z2.record(z2.string(), PermissionActionSchema)
18601
+ z.record(z.string(), PermissionActionSchema)
18700
18602
  ]);
18701
- var PermissionObjectSchema = z2.object({
18603
+ var PermissionObjectSchema = z.object({
18702
18604
  read: PermissionRuleSchema.optional(),
18703
18605
  edit: PermissionRuleSchema.optional(),
18704
18606
  glob: PermissionRuleSchema.optional(),
@@ -18716,32 +18618,32 @@ var PermissionObjectSchema = z2.object({
18716
18618
  codesearch: PermissionActionSchema.optional(),
18717
18619
  doom_loop: PermissionActionSchema.optional()
18718
18620
  }).catchall(PermissionRuleSchema);
18719
- var PermissionConfigSchema = z2.union([
18621
+ var PermissionConfigSchema = z.union([
18720
18622
  PermissionActionSchema,
18721
18623
  PermissionObjectSchema
18722
18624
  ]);
18723
- var AgentOverrideConfigSchema = z2.object({
18724
- model: z2.union([
18725
- z2.string(),
18726
- z2.array(z2.union([
18727
- z2.string(),
18728
- z2.object({
18729
- id: z2.string(),
18730
- variant: z2.string().optional()
18625
+ var AgentOverrideConfigSchema = z.object({
18626
+ model: z.union([
18627
+ z.string(),
18628
+ z.array(z.union([
18629
+ z.string(),
18630
+ z.object({
18631
+ id: z.string(),
18632
+ variant: z.string().optional()
18731
18633
  })
18732
18634
  ])).min(1)
18733
18635
  ]).optional(),
18734
- temperature: z2.number().min(0).max(2).optional(),
18735
- variant: z2.string().optional().catch(undefined),
18736
- skills: z2.array(z2.string()).optional(),
18737
- mcps: z2.array(z2.string()).optional(),
18738
- prompt: z2.string().min(1).optional(),
18739
- orchestratorPrompt: z2.string().min(1).optional(),
18740
- options: z2.record(z2.string(), z2.unknown()).optional(),
18741
- displayName: z2.string().min(1).optional(),
18636
+ temperature: z.number().min(0).max(2).optional(),
18637
+ variant: z.string().optional().catch(undefined),
18638
+ skills: z.array(z.string()).optional(),
18639
+ mcps: z.array(z.string()).optional(),
18640
+ prompt: z.string().min(1).optional(),
18641
+ orchestratorPrompt: z.string().min(1).optional(),
18642
+ options: z.record(z.string(), z.unknown()).optional(),
18643
+ displayName: z.string().min(1).optional(),
18742
18644
  permission: PermissionConfigSchema.optional()
18743
18645
  }).strict();
18744
- var MultiplexerTypeSchema = z2.enum([
18646
+ var MultiplexerTypeSchema = z.enum([
18745
18647
  "auto",
18746
18648
  "tmux",
18747
18649
  "zellij",
@@ -18749,107 +18651,106 @@ var MultiplexerTypeSchema = z2.enum([
18749
18651
  "cmux",
18750
18652
  "none"
18751
18653
  ]);
18752
- var MultiplexerLayoutSchema = z2.enum([
18654
+ var MultiplexerLayoutSchema = z.enum([
18753
18655
  "main-horizontal",
18754
18656
  "main-vertical",
18755
18657
  "tiled",
18756
18658
  "even-horizontal",
18757
18659
  "even-vertical"
18758
18660
  ]);
18759
- var ZellijPaneModeSchema = z2.enum(["agent-tab", "current-tab"]);
18661
+ var ZellijPaneModeSchema = z.enum(["agent-tab", "current-tab"]);
18760
18662
  var TmuxLayoutSchema = MultiplexerLayoutSchema;
18761
- var MultiplexerConfigSchema = z2.object({
18663
+ var MultiplexerConfigSchema = z.object({
18762
18664
  type: MultiplexerTypeSchema.default("none"),
18763
18665
  layout: MultiplexerLayoutSchema.default("main-vertical"),
18764
- main_pane_size: z2.number().min(20).max(80).default(60),
18666
+ main_pane_size: z.number().min(20).max(80).default(60),
18765
18667
  zellij_pane_mode: ZellijPaneModeSchema.default("agent-tab")
18766
18668
  });
18767
- var TmuxConfigSchema = z2.object({
18768
- enabled: z2.boolean().default(false),
18669
+ var TmuxConfigSchema = z.object({
18670
+ enabled: z.boolean().default(false),
18769
18671
  layout: TmuxLayoutSchema.default("main-vertical"),
18770
- main_pane_size: z2.number().min(20).max(80).default(60)
18672
+ main_pane_size: z.number().min(20).max(80).default(60)
18771
18673
  });
18772
- var PresetSchema = z2.record(z2.string(), AgentOverrideConfigSchema);
18773
- var WebsearchConfigSchema = z2.object({
18774
- provider: z2.enum(["exa", "tavily"]).default("exa")
18674
+ var PresetSchema = z.record(z.string(), AgentOverrideConfigSchema);
18675
+ var WebsearchConfigSchema = z.object({
18676
+ provider: z.enum(["exa", "tavily"]).default("exa")
18775
18677
  });
18776
- var McpNameSchema = z2.enum(["websearch", "context7", "gh_grep"]);
18777
- var InterviewConfigSchema = z2.object({
18778
- maxQuestions: z2.number().int().min(1).max(10).default(2),
18779
- outputFolder: z2.string().min(1).default("interview"),
18780
- autoOpenBrowser: z2.boolean().default(true).describe("Automatically open the interview UI in your default browser during interactive runs. Disabled automatically in tests and CI."),
18781
- port: z2.number().int().min(0).max(65535).default(0),
18782
- dashboard: z2.boolean().default(false)
18678
+ var McpNameSchema = z.enum(["websearch", "context7", "gh_grep"]);
18679
+ var InterviewConfigSchema = z.object({
18680
+ maxQuestions: z.number().int().min(1).max(10).default(2),
18681
+ outputFolder: z.string().min(1).default("interview"),
18682
+ autoOpenBrowser: z.boolean().default(true).describe("Automatically open the interview UI in your default browser during interactive runs. Disabled automatically in tests and CI."),
18683
+ port: z.number().int().min(0).max(65535).default(0),
18684
+ dashboard: z.boolean().default(false)
18783
18685
  });
18784
- var BackgroundJobsConfigSchema = z2.object({
18785
- maxSessionsPerAgent: z2.number().int().min(1).max(10).default(2),
18786
- readContextMinLines: z2.number().int().min(0).max(1000).default(10),
18787
- readContextMaxFiles: z2.number().int().min(0).max(50).default(8)
18686
+ var BackgroundJobsConfigSchema = z.object({
18687
+ maxSessionsPerAgent: z.number().int().min(1).max(10).default(2),
18688
+ readContextMinLines: z.number().int().min(0).max(1000).default(10),
18689
+ readContextMaxFiles: z.number().int().min(0).max(50).default(8)
18788
18690
  });
18789
- var FailoverConfigSchema = z2.object({
18790
- enabled: z2.boolean().default(true),
18791
- timeoutMs: z2.number().min(0).default(15000),
18792
- retryDelayMs: z2.number().min(0).default(500),
18793
- maxRetries: z2.number().int().min(0).default(3).describe("Number of consecutive 429/rate-limit responses tolerated on the " + "same model before aborting (or swapping to the next fallback " + "model when a chain is configured)."),
18794
- retry_on_empty: z2.boolean().default(true).describe("When true (default), empty provider responses are treated as failures, " + "triggering fallback/retry. Set to false to treat them as successes."),
18795
- runtimeOverride: z2.boolean().optional().describe("DEPRECATED: no longer used. Previously controlled whether out-of-chain " + "runtime model picks triggered fallback. Fallback is now always " + "disabled when a user explicitly selects a model via /model.")
18691
+ var FailoverConfigSchema = z.object({
18692
+ enabled: z.boolean().default(true),
18693
+ timeoutMs: z.number().min(0).default(15000),
18694
+ retryDelayMs: z.number().min(0).default(500),
18695
+ maxRetries: z.number().int().min(0).default(3).describe("Number of consecutive 429/rate-limit responses tolerated on the " + "same model before aborting (or swapping to the next fallback " + "model when a chain is configured)."),
18696
+ retry_on_empty: z.boolean().default(true).describe("When true (default), empty provider responses are treated as failures, " + "triggering fallback/retry. Set to false to treat them as successes."),
18697
+ runtimeOverride: z.boolean().optional().describe("DEPRECATED: no longer used. Previously controlled whether out-of-chain " + "runtime model picks triggered fallback. Fallback is now always " + "disabled when a user explicitly selects a model via /model.")
18796
18698
  }).strict();
18797
- var CompanionConfigSchema = z2.object({
18798
- enabled: z2.boolean().optional(),
18799
- binaryPath: z2.string().min(1).optional().describe("Path to a custom companion binary to launch."),
18800
- position: z2.enum(["bottom-right", "bottom-left", "top-right", "top-left"]).optional(),
18801
- size: z2.enum(["small", "medium", "large"]).optional(),
18802
- gifPack: z2.enum(["default"]).optional().describe("Bundled companion animation pack to use."),
18803
- loopStyle: z2.enum(["classic", "smooth"]).optional().describe("Companion animation playback style: classic loops or smooth ping-pong playback."),
18804
- speed: z2.number().min(0.25).max(4).optional().describe("Companion animation playback speed multiplier. Defaults to 1."),
18805
- debug: z2.boolean().optional().describe("Enable verbose native companion debug logs.")
18699
+ var CompanionConfigSchema = z.object({
18700
+ enabled: z.boolean().optional(),
18701
+ binaryPath: z.string().min(1).optional().describe("Path to a custom companion binary to launch."),
18702
+ position: z.enum(["bottom-right", "bottom-left", "top-right", "top-left"]).optional(),
18703
+ size: z.enum(["small", "medium", "large"]).optional(),
18704
+ gifPack: z.enum(["default"]).optional().describe("Bundled companion animation pack to use."),
18705
+ loopStyle: z.enum(["classic", "smooth"]).optional().describe("Companion animation playback style: classic loops or smooth ping-pong playback."),
18706
+ speed: z.number().min(0.25).max(4).optional().describe("Companion animation playback speed multiplier. Defaults to 1."),
18707
+ debug: z.boolean().optional().describe("Enable verbose native companion debug logs.")
18806
18708
  });
18807
- var AcpAgentPermissionModeSchema = z2.enum(["ask", "allow", "reject"]);
18709
+ var AcpAgentPermissionModeSchema = z.enum(["ask", "allow", "reject"]);
18808
18710
  var MAX_ACP_TIMEOUT_MS = 2147483647;
18809
- var AcpAgentConfigSchema = z2.object({
18810
- command: z2.string().min(1),
18811
- args: z2.array(z2.string()).default([]),
18812
- env: z2.record(z2.string(), z2.string()).default({}),
18813
- cwd: z2.string().min(1).optional(),
18814
- description: z2.string().min(1).optional(),
18815
- prompt: z2.string().min(1).optional(),
18816
- orchestratorPrompt: z2.string().min(1).optional(),
18711
+ var AcpAgentConfigSchema = z.object({
18712
+ command: z.string().min(1),
18713
+ args: z.array(z.string()).default([]),
18714
+ env: z.record(z.string(), z.string()).default({}),
18715
+ cwd: z.string().min(1).optional(),
18716
+ description: z.string().min(1).optional(),
18717
+ prompt: z.string().min(1).optional(),
18718
+ orchestratorPrompt: z.string().min(1).optional(),
18817
18719
  wrapperModel: ProviderModelIdSchema.optional(),
18818
- timeoutMs: z2.number().int().min(0).max(MAX_ACP_TIMEOUT_MS).default(0).describe("Timeout for a single ACP run in milliseconds. Set to 0 to disable the timeout."),
18720
+ timeoutMs: z.number().int().min(0).max(MAX_ACP_TIMEOUT_MS).default(0).describe("Timeout for a single ACP run in milliseconds. Set to 0 to disable the timeout."),
18819
18721
  permissionMode: AcpAgentPermissionModeSchema.default("ask")
18820
18722
  }).strict();
18821
- var AcpAgentsConfigSchema = z2.record(z2.string(), AcpAgentConfigSchema);
18723
+ var AcpAgentsConfigSchema = z.record(z.string(), AcpAgentConfigSchema);
18822
18724
  function rejectOrchestratorPromptOnOrchestrator(overrides, ctx, pathPrefix) {
18823
18725
  for (const [name, override] of Object.entries(overrides)) {
18824
18726
  if (name === "orchestrator" && override.orchestratorPrompt !== undefined) {
18825
18727
  ctx.addIssue({
18826
- code: z2.ZodIssueCode.custom,
18728
+ code: z.ZodIssueCode.custom,
18827
18729
  path: [...pathPrefix, name, "orchestratorPrompt"],
18828
18730
  message: "orchestratorPrompt is not supported for the orchestrator agent"
18829
18731
  });
18830
18732
  }
18831
18733
  }
18832
18734
  }
18833
- var PluginConfigSchema = z2.object({
18834
- preset: z2.string().optional(),
18835
- setDefaultAgent: z2.boolean().optional(),
18836
- compactSidebar: z2.boolean().optional().describe("Use the compact TUI sidebar layout. Defaults to true; set false to use the expanded layout."),
18837
- stripOrchestratorModel: z2.boolean().optional().describe("When true, omit orchestrator.model and orchestrator.variant from the SDK config so OpenCode uses the session model selected with /model after subagent dispatch. An explicitly selected preset that sets orchestrator.model is preserved. Defaults to false."),
18838
- autoUpdate: z2.boolean().optional().describe("Disable automatic installation of plugin updates when false. Defaults to true."),
18839
- presets: z2.record(z2.string(), PresetSchema).optional(),
18840
- agents: z2.record(z2.string(), AgentOverrideConfigSchema).optional(),
18841
- disabled_agents: z2.array(z2.string()).optional().describe("Agent names to disable completely. " + "Disabled agents are not instantiated and cannot be delegated to. " + "Orchestrator and council internal agents (councillor) cannot be disabled. " + "By default, 'observer' is disabled. Remove it from this list and configure a vision-capable model to enable."),
18842
- image_routing: z2.enum(["auto", "direct"]).optional().describe("How image attachments are handled. " + "When omitted, preserves legacy conditional behavior: intercept " + 'attachments only when observer is enabled. "auto": requires ' + "observer to be enabled and saves attachments to disk before " + 'nudging delegation to @observer. "direct": always passes ' + "attachments to the orchestrator untouched."),
18843
- disabled_mcps: z2.array(z2.string()).optional().describe("MCP server names to disable completely. Disabled servers are not " + "started and cannot be used by agents."),
18844
- disabled_tools: z2.array(z2.string()).optional().describe("Tool names to disable completely. Disabled tools are not registered with OpenCode and cannot be used by agents."),
18845
- disabled_skills: z2.array(z2.string()).optional().describe("Skill names to disable completely. Disabled skills are not granted to agents, even when referenced by presets or agent overrides."),
18735
+ var PluginConfigSchema = z.object({
18736
+ preset: z.string().optional(),
18737
+ setDefaultAgent: z.boolean().optional(),
18738
+ compactSidebar: z.boolean().optional().describe("Use the compact TUI sidebar layout. Defaults to true; set false to use the expanded layout."),
18739
+ stripOrchestratorModel: z.boolean().optional().describe("When true, omit orchestrator.model and orchestrator.variant from the SDK config so OpenCode uses the session model selected with /model after subagent dispatch. An explicitly selected preset that sets orchestrator.model is preserved. Defaults to false."),
18740
+ autoUpdate: z.boolean().optional().describe("Disable automatic installation of plugin updates when false. Defaults to true."),
18741
+ presets: z.record(z.string(), PresetSchema).optional(),
18742
+ agents: z.record(z.string(), AgentOverrideConfigSchema).optional(),
18743
+ disabled_agents: z.array(z.string()).optional().describe("Agent names to disable completely. " + "Disabled agents are not instantiated and cannot be delegated to. " + "Orchestrator cannot be disabled. " + "By default, 'observer' is disabled. Remove it from this list and configure a vision-capable model to enable."),
18744
+ image_routing: z.enum(["auto", "direct"]).optional().describe("How image attachments are handled. " + "When omitted, preserves legacy conditional behavior: intercept " + 'attachments only when observer is enabled. "auto": requires ' + "observer to be enabled and saves attachments to disk before " + 'nudging delegation to @observer. "direct": always passes ' + "attachments to the orchestrator untouched."),
18745
+ disabled_mcps: z.array(z.string()).optional().describe("MCP server names to disable completely. Disabled servers are not " + "started and cannot be used by agents."),
18746
+ disabled_tools: z.array(z.string()).optional().describe("Tool names to disable completely. Disabled tools are not registered with OpenCode and cannot be used by agents."),
18747
+ disabled_skills: z.array(z.string()).optional().describe("Skill names to disable completely. Disabled skills are not granted to agents, even when referenced by presets or agent overrides."),
18846
18748
  multiplexer: MultiplexerConfigSchema.optional(),
18847
18749
  tmux: TmuxConfigSchema.optional(),
18848
18750
  websearch: WebsearchConfigSchema.optional(),
18849
18751
  interview: InterviewConfigSchema.optional(),
18850
18752
  backgroundJobs: BackgroundJobsConfigSchema.optional(),
18851
18753
  fallback: FailoverConfigSchema.optional(),
18852
- council: CouncilConfigSchema.optional(),
18853
18754
  companion: CompanionConfigSchema.optional(),
18854
18755
  acpAgents: AcpAgentsConfigSchema.optional()
18855
18756
  }).superRefine((value, ctx) => {
@@ -18971,7 +18872,6 @@ function mergePluginConfigs(base, override) {
18971
18872
  interview: deepMerge(base.interview, override.interview),
18972
18873
  backgroundJobs: deepMerge(base.backgroundJobs, override.backgroundJobs),
18973
18874
  fallback: deepMerge(base.fallback, override.fallback),
18974
- council: deepMerge(base.council, override.council),
18975
18875
  acpAgents: deepMerge(base.acpAgents, override.acpAgents),
18976
18876
  companion: deepMerge(base.companion, override.companion)
18977
18877
  };
@@ -19116,625 +19016,71 @@ function getCustomAgentNames(config) {
19116
19016
  function getAcpAgentNames(config) {
19117
19017
  return Object.keys(config?.acpAgents ?? {});
19118
19018
  }
19119
- // src/utils/session.ts
19120
- var SESSION_ABORT_TIMEOUT_MS = 1000;
19121
-
19122
- class OperationTimeoutError extends Error {
19123
- constructor(message) {
19124
- super(message);
19125
- this.name = "OperationTimeoutError";
19126
- }
19127
- }
19128
- async function withTimeout(operation, timeoutMs, message) {
19129
- if (timeoutMs <= 0)
19130
- return operation;
19131
- let timer;
19132
- try {
19133
- return await Promise.race([
19134
- operation,
19135
- new Promise((_, reject) => {
19136
- timer = setTimeout(() => {
19137
- reject(new OperationTimeoutError(message));
19138
- }, timeoutMs);
19139
- })
19140
- ]);
19141
- } finally {
19142
- clearTimeout(timer);
19143
- }
19144
- }
19145
- async function abortSessionWithTimeout(client, sessionId, timeoutMs = SESSION_ABORT_TIMEOUT_MS) {
19146
- await withTimeout(client.session.abort({ path: { id: sessionId } }), timeoutMs, `Session abort timed out after ${timeoutMs}ms`);
19147
- }
19148
- function shortModelLabel(model) {
19149
- return model.split("/").pop() ?? model;
19150
- }
19151
- function parseModelReference(model) {
19152
- const slashIndex = model.indexOf("/");
19153
- if (slashIndex <= 0 || slashIndex >= model.length - 1) {
19154
- return null;
19155
- }
19156
- return {
19157
- providerID: model.slice(0, slashIndex),
19158
- modelID: model.slice(slashIndex + 1)
19159
- };
19160
- }
19161
- async function promptWithTimeout(client, args, timeoutMs, signal) {
19162
- if (signal?.aborted)
19163
- throw new Error("Prompt cancelled");
19164
- const sessionId = args.path.id;
19165
- const hasTimeout = timeoutMs > 0;
19166
- let timer;
19167
- let onAbort;
19168
- try {
19169
- const promptPromise = client.session.prompt(args);
19170
- promptPromise.catch(() => {});
19171
- const racers = [promptPromise];
19172
- if (hasTimeout) {
19173
- racers.push(new Promise((_, reject) => {
19174
- timer = setTimeout(() => {
19175
- reject(new OperationTimeoutError(`Prompt timed out after ${timeoutMs}ms`));
19176
- }, timeoutMs);
19177
- }));
19178
- }
19179
- if (signal) {
19180
- racers.push(new Promise((_, reject) => {
19181
- if (signal.aborted) {
19182
- reject(new Error("Prompt cancelled"));
19183
- return;
19184
- }
19185
- onAbort = () => reject(new Error("Prompt cancelled"));
19186
- signal.addEventListener("abort", onAbort, { once: true });
19187
- }));
19188
- }
19189
- await Promise.race(racers);
19190
- } catch (error) {
19191
- if (error instanceof OperationTimeoutError) {
19192
- try {
19193
- await abortSessionWithTimeout(client, sessionId);
19194
- } catch {}
19195
- }
19196
- throw error;
19197
- } finally {
19198
- clearTimeout(timer);
19199
- if (onAbort)
19200
- signal?.removeEventListener("abort", onAbort);
19201
- }
19202
- }
19203
- async function extractSessionResult(client, sessionId, options) {
19204
- const includeReasoning = options?.includeReasoning ?? true;
19205
- const messagesResult = await client.session.messages({
19206
- path: { id: sessionId },
19207
- ...options?.directory ? { query: { directory: options.directory } } : {}
19208
- });
19209
- const messages = messagesResult.data ?? [];
19210
- const assistantMessages = messages.filter((m) => m.info?.role === "assistant");
19211
- const extractedContent = [];
19212
- for (const message of assistantMessages) {
19213
- for (const part of message.parts ?? []) {
19214
- const allowed = includeReasoning ? part.type === "text" || part.type === "reasoning" : part.type === "text";
19215
- if (allowed && part.text) {
19216
- extractedContent.push(part.text);
19217
- }
19218
- }
19219
- }
19220
- const text = extractedContent.filter((t) => t.length > 0).join(`
19221
-
19222
- `);
19223
- return { text, empty: text.length === 0 };
19224
- }
19019
+ // src/agents/designer.ts
19020
+ var DESIGNER_PROMPT = `You are a Designer - a frontend UI/UX specialist who creates and reviews intentional, polished experiences.
19225
19021
 
19226
- // src/agents/orchestrator.ts
19227
- function resolvePrompt(base, customPrompt, customAppendPrompt) {
19228
- const effectiveBase = customPrompt !== undefined ? customPrompt : base;
19229
- return customAppendPrompt !== undefined ? `${effectiveBase}
19022
+ **Role**: Craft and review cohesive UI/UX that balances visual impact with usability.
19230
19023
 
19231
- ${customAppendPrompt}` : effectiveBase;
19232
- }
19233
- var AGENT_DESCRIPTIONS = {
19234
- explorer: `@explorer
19235
- - Lane: Fast codebase recon that returns compressed context
19236
- - Permissions: read_files
19237
- - Stats: 2x faster codebase search than orchestrator, 1/2 cost of orchestrator
19238
- - Capabilities: Glob, grep, AST queries to locate files, symbols, patterns
19239
- - **Delegate when:** Need to discover what exists before planning • Parallel searches speed discovery • Need summarized map vs full contents • Broad/uncertain scope
19240
- - **Don't delegate when:** Know the path and need actual content • Need full file anyway • Single specific lookup • About to edit the file`,
19241
- librarian: `@librarian
19242
- - Lane: External knowledge and library research, fast web research
19243
- - Role: Authoritative source for current library docs, API references, examples, bug investigations, and web retrieval
19244
- - Stats: 2x faster web research than orchestrator, 1/2 cost of orchestrator
19245
- - **Delegate when:** Libraries with frequent API changes (React, Next.js, AI SDKs) • Complex APIs needing official examples (ORMs, auth) • Version-specific behavior matters • Unfamiliar library • Edge cases or advanced features • Nuanced best practices • Working on fixing tricky bug or problem and need latest web research information
19246
- - **Don't delegate when:** Standard usage you're confident • Simple stable APIs • General programming knowledge • Info already in conversation • Built-in language features
19247
- - **Rule of thumb:** "How does this library work?" → @librarian. "How does programming work?" → answer directly. How does others solve or workaround this tricky issue?" → @librarian.`,
19248
- oracle: `@oracle
19249
- - Lane: Architecture, risk, debugging strategy, and review
19250
- - Role: Strategic advisor for high-stakes decisions and persistent problems, code reviewer
19251
- - Permissions: read_files
19252
- - Stats: 5x better decision maker, problem solver, investigator than orchestrator, 0.8x speed of orchestrator, same cost.
19253
- - Capabilities: Deep architectural reasoning, system-level trade-offs, complex debugging, code review, simplification, maintainability review
19254
- - **Delegate when:** Major architectural decisions with long-term impact • Problems persisting after 2+ fix attempts • High-risk multi-system refactors • Costly trade-offs (performance vs maintainability) • Complex debugging with unclear root cause • Security/scalability/data integrity decisions • Genuinely uncertain and cost of wrong choice is high • Code needs simplification or YAGNI scrutiny
19255
- - **Review use:** Oracle is an escalation, not a default verification step. Request independent Oracle review only when its analysis is expected to materially reduce risk or uncertainty.
19256
- - **Don't delegate when:** Routine decisions you're confident about • First bug fix attempt • Straightforward trade-offs • Tactical "how" vs strategic "should" • Time-sensitive good-enough decisions • Quick research/testing can answer
19257
- - **Rule of thumb:** Need senior architect review? → @oracle. Need code review or simplification? → @oracle. Routine coordination or final synthesis? → handle directly.`,
19258
- designer: `@designer
19259
- - Lane: UI/UX design, related edits, design polish and review
19260
- - Permissions: read_files, write_files
19261
- - Stats: 10x better UI/UX than orchestrator
19262
- - Capabilities: Good design taste, visual relevant edits, interactions, responsive layouts, design systems with aesthetic intent, deep UI/UX knowledge.
19263
- - Owns visual and interaction quality: layout, hierarchy, spacing, motion, affordances, responsive behavior, and overall feel.
19264
- - Weakness: copywriting. Ask designer to use grounded, normal wording, then have orchestrator review/fix copy after design work without changing visual or interaction intent.
19265
- - Avoid: "Let me us designer how it should look and implement yourself" → instead: "Let me ask designer to design and implement the UI/UX changes for me"
19266
- - **Delegate when:** User-facing interfaces needing polish • Responsive layouts • UX-critical components (forms, nav, dashboards) • Visual consistency systems • Animations/micro-interactions • Landing/marketing pages • Refining functional→delightful • Reviewing existing UI/UX quality
19267
- - **Don't delegate when:** Backend/logic with no visual • Quick prototypes where design doesn't matter yet.
19268
- - **Rule of thumb:** Users see it and polish matters? → @designer. Headless/functional implementation? → schedule @fixer.`,
19269
- fixer: `@fixer
19270
- - Lane: Bounded implementation and executioner
19271
- - Role: Fast execution specialist for well-defined tasks
19272
- - Permissions: read_files, write_files
19273
- - Stats: 2x faster code edits, 1/2 cost of orchestrator
19274
- - Weakness: design, taste
19275
- - Tools/Constraints: Execution-focused-no research, no architectural decisions
19276
- - **Delegate when:** For implementation work, think and triage first. If the change is non-trivial or multi-file, hand bounded execution to @fixer • Parallelization benefits: Task involves multiple folders and multiple files modification, scoping work per folder and spawning parallel @fixers for each folder.
19277
- - **Don't delegate when:** Needs discovery/research/decisions • Single small change (<20 lines, one file) • Unclear requirements needing iteration • Explaining to fixer > doing • Tight integration with your current work • Requires design taste, visual hierarchy, interaction polish, responsive layout decisions, animation/motion, component feel, or UI copy/design trade-offs
19278
- - **Rule of thumb:** Headless/mechanical implementation → @fixer. User-visible design or polish → @designer. If @designer already set direction, @fixer may only do bounded mechanical follow-up that preserves that design exactly.`,
19279
- council: `@council
19280
- - Lane: High-stakes multi-model decision support
19281
- - Role: Multi-LLM consensus engine that runs several councillors, synthesizes their views, and returns a structured council report.
19282
- - Permissions: Read files
19283
- - Stats: 3x slower than orchestrator, 3x or more cost of orchestrator
19284
- - Capabilities: Runs multiple models in parallel, compares their answers, resolves disagreements, and produces a final synthesized answer plus councillor details and consensus summary.
19285
- - **Delegate when:** Critical decisions need multiple independent perspectives • High-stakes architectural/security/data-integrity choices • Ambiguous problems where disagreement is useful signal • You want confidence beyond a single model • The user explicitly asks for council/consensus/multiple opinions.
19286
- - **Don't delegate when:** Straightforward tasks you're confident about • Speed matters more than confidence • Routine implementation/debugging • A single specialist is clearly the right tool • You only need current docs/search/code review rather than multi-model consensus.
19287
- - **How to call:** Send the full question/task and relevant context. Be explicit about what decision, trade-off, or answer the council should resolve. Do not ask council to do routine code edits.
19288
- - **Result handling:** Council returns a structured response that may include: synthesized Council Response, individual Councillor Details, and Council Summary/confidence. Preserve that structure when the user asked for council output. Do not pretend the council only returned a final answer. If you need to act on the council result, first briefly state the council's recommendation, then proceed.
19289
- - **Rule of thumb:** Need second/third opinions from different models? → @council. Need one expert lane? → use the specialist. Need final synthesis? → handle directly.`,
19290
- observer: `@observer
19291
- - Lane: Visual/media analysis isolated from orchestrator context
19292
- - Role: Visual analysis specialist for images, PDFs, and diagrams
19293
- - Permissions: Read files
19294
- - Stats: Saves main context tokens - Observer processes raw files, returns structured observations
19295
- - Capabilities: Interprets images, screenshots, PDFs, and diagrams via native read tool; extracts UI elements, layouts, text, relationships
19296
- - **Delegate when:** Need to analyze a multimedia file• Extract information
19297
- - **Don't delegate when:** Plain text files that Read can handle directly • Files that need editing afterward (need literal content from Read)
19298
- - **Rule of thumb:** Even if your model supports vision, delegate visual analysis to @observer - it isolates large image/PDF bytes from your context window, returning only concise structured text. Need exact file contents for routing? → Read only the minimal context yourself.
19299
- - **IMPORTANT:** When delegating to @observer, always include the **full file path** in the prompt so it can read the file. Example: "Analyze the screenshot at /path/to/file.png - describe the UI elements and error messages."`
19300
- };
19301
- var PARALLEL_DELEGATION_EXAMPLES = [
19302
- "- Multiple @explorer searches across different domains?",
19303
- "- @explorer + @librarian research in parallel?",
19304
- "- Multiple @fixer instances for faster, scoped implementation?",
19305
- "- @observer + @explorer in parallel (visual analysis + code search)?"
19306
- ];
19307
- function buildOrchestratorPrompt(disabledAgents) {
19308
- const enabledAgents = Object.entries(AGENT_DESCRIPTIONS).filter(([name]) => !disabledAgents?.has(name)).map(([, desc]) => desc).join(`
19024
+ ## Design Principles
19309
19025
 
19310
- `);
19311
- const enabledParallelExamples = PARALLEL_DELEGATION_EXAMPLES.filter((line) => {
19312
- const mentions = [...line.matchAll(/@(\w+)/g)].map((m) => m[1]);
19313
- if (mentions.length === 0)
19314
- return true;
19315
- return mentions.every((name) => !disabledAgents?.has(name));
19316
- }).join(`
19317
- `);
19318
- return `<Role>
19319
- You are a workflow manager for coding work. Your job is to plan, schedule, delegate, monitor, reconcile, and verify specialist-agent work. You are not the default implementation worker.
19026
+ **Typography**
19027
+ - Choose distinctive, characterful fonts that elevate aesthetics
19028
+ - Avoid generic defaults (Arial, Inter)-opt for unexpected, beautiful choices
19029
+ - Pair display fonts with refined body fonts for hierarchy
19320
19030
 
19321
- For non-trivial coding work, identify separable lanes first and delegate bounded work to the appropriate specialist. Do not perform multi-step implementation serially when a suitable specialist is available.
19031
+ **Color & Theme**
19032
+ - Commit to a cohesive aesthetic with clear color variables
19033
+ - Dominant colors with sharp accents > timid, evenly-distributed palettes
19034
+ - Create atmosphere through intentional color relationships
19322
19035
 
19323
- Handle work directly only when it is one isolated, clear, low-risk action and delegation overhead exceeds doing it yourself.
19036
+ **Motion & Interaction**
19037
+ - Leverage framework animation utilities when available (Tailwind's transition/animation classes)
19038
+ - Focus on high-impact moments: orchestrated page loads with staggered reveals
19039
+ - Use scroll-triggers and hover states that surprise and delight
19040
+ - One well-timed animation > scattered micro-interactions
19041
+ - Drop to custom CSS/JS only when utilities can't achieve the vision
19324
19042
 
19325
- Optimize for quality, speed, cost, and reliability by dispatching the right specialist lanes, tracking background task state, and integrating terminal results into one coherent outcome.
19326
- You have perfect understanding of agent's context management, understand well the cost of building content and reusing context of existing agents when it's best or when it's best to spawn a new agent.
19327
- </Role>
19043
+ **Spatial Composition**
19044
+ - Break conventions: asymmetry, overlap, diagonal flow, grid-breaking
19045
+ - Generous negative space OR controlled density-commit to the choice
19046
+ - Unexpected layouts that guide the eye
19328
19047
 
19329
- <Agents>
19048
+ **Visual Depth**
19049
+ - Create atmosphere beyond solid colors: gradient meshes, noise textures, geometric patterns
19050
+ - Layer transparencies, dramatic shadows, decorative borders
19051
+ - Contextual effects that match the aesthetic (grain overlays, custom cursors)
19330
19052
 
19331
- ${enabledAgents}
19053
+ **Styling Approach**
19054
+ - Default to Tailwind CSS utility classes when available-fast, maintainable, consistent
19055
+ - Use custom CSS when the vision requires it: complex animations, unique effects, advanced compositions
19056
+ - Balance utility-first speed with creative freedom where it matters
19332
19057
 
19333
- </Agents>
19058
+ **Match Vision to Execution**
19059
+ - Maximalist designs → elaborate implementation, extensive animations, rich effects
19060
+ - Minimalist designs → restraint, precision, careful spacing and typography
19061
+ - Elegance comes from executing the chosen vision fully, not halfway
19334
19062
 
19335
- <Workflow>
19063
+ ## Constraints
19064
+ - Respect existing design systems when present
19065
+ - Leverage component libraries where available
19066
+ - Prioritize visual excellence-code perfection comes second
19067
+ - Use grounded, normal, regular english - don't use jargon or overly technical language
19336
19068
 
19337
- ## 1. Understand
19338
- Parse request: explicit requirements + implicit needs.
19069
+ ${WRITABLE_FILE_OPERATIONS_RULES}
19339
19070
 
19340
- ## 2. Path Selection
19341
- Evaluate approach by: quality, speed and cost.
19342
- Choose the path that optimizes all four.
19071
+ ## Review Responsibilities
19072
+ - Review existing UI for usability, responsiveness, visual consistency, and polish when asked
19073
+ - Call out concrete UX issues and improvements, not just abstract design advice
19074
+ - When validating, focus on what users actually see and feel
19343
19075
 
19344
- ## 3. Delegation Check
19345
- Review available agents and lane rules. Before beginning non-trivial work, identify which parts can proceed independently.
19346
-
19347
- **Routing threshold:**
19348
- - Handle directly only for one isolated, clear, low-risk action where delegation would cost more than execution.
19349
- - For multi-step implementation, broad discovery, external research, visual work, or complex debugging, delegate to the suitable specialist.
19350
- - If two or more parts can proceed independently, dispatch them in parallel before starting dependent work.
19351
- - Do not delegate merely because an agent exists. Do not keep substantive work entirely in the orchestrator merely because each individual step seems easy.
19352
-
19353
- **Dispatch efficiency:**
19354
- - Reference paths/lines, don't paste files (\`src/app.ts:42\` not full contents)
19355
- - Brief user on delegation goal before each call
19356
- - Record task IDs, state, and advisory ownership/dependency labels
19357
- - Do not immediately wait after spawning independent background tasks unless the next step truly depends on their result
19358
- - Reconcile results, resolve conflicts, and gate dependent lanes
19359
-
19360
- ${WRITABLE_FILE_OPERATIONS_RULES}
19361
-
19362
- ## 4. Plan and Parallelize
19363
- When the routing threshold calls for delegation, build a short work graph before dispatching:
19364
- - Independent lanes that can run now
19365
- - Dependency-ordered lanes that must wait
19366
- - Advisory ownership for write-capable lanes
19367
- - Verification/review lanes that run after implementation
19368
-
19369
- ### Todo Continuity
19370
- - When the user adds a new task while a todo list exists, append the new task to the end of the existing todo list instead of replacing the list.
19371
- - Preserve existing todo order, statuses, and priorities unless the user explicitly asks to reprioritize, cancel, or replace them.
19372
- - Finish the current in-progress task before starting the newly appended task unless the current task is blocked or the user explicitly overrides the order.
19373
-
19374
- Can tasks be split into background specialist work?
19375
- ${enabledParallelExamples}
19376
-
19377
- Balance: respect dependencies, avoid parallelizing what must be sequential, and avoid overlapping write ownership.
19378
-
19379
- ### Background Task Discipline
19380
- - Prefer \`task(..., background: true)\` for delegated work that can run independently.
19381
- - For work already chosen for delegation, launch independent specialist lanes in the background so the orchestrator stays unblocked and can reconcile results when they return.
19382
- - Track each task's specialist, objective, task/session ID, and file/topic ownership.
19383
- - Continue orchestration only on non-overlapping work; otherwise briefly report what was launched and stop.
19384
- - Before local edits or another writer task, compare against running task scopes.
19385
- - Parallel background tasks are allowed only when their write scopes do not conflict.
19386
- - Before final response, reconcile any terminal jobs shown in the Background Job Board.
19387
- - Use \`cancel_task\` only when the user asks, or when a running lane is obsolete, wrong, or conflicts with a safer replacement plan.
19388
- - Cancellation is not rollback: if cancelling a writer, inspect and reconcile partial file changes before launching a replacement lane.
19389
-
19390
- ### Design Handoff Discipline
19391
- - When @designer completes UI/UX work, treat layout, spacing, hierarchy, motion, color, affordances, and component feel as intentional design output.
19392
- - Do not later simplify, normalize, or refactor it in ways that flatten the design.
19393
- - The orchestrator should review and improve user-facing copy after designer work, because designer copy may be weak.
19394
- - Copy edits must preserve the designer's visual structure and interaction intent.
19395
- - If follow-up work is purely mechanical and preserves the design exactly, @fixer can handle it. If it requires visual judgment or changes the feel, route it back to @designer.
19396
-
19397
- ### Session Reuse
19398
- - Smartly reuse an available specialist session - context reuse saves time and tokens
19399
- - When too much unrelated, and really needed, start a fresh session with the specialist
19400
- - If multiple remembered sessions fit, prefer the most recently used matching session.
19401
- - Prefer re-uses over creating new sessions all the time
19402
- - When reusing a specialist session, you MUST pass the existing session or alias in the task tool's \`task_id\` argument. Saying "reuse" in prose is not enough.
19403
- - If the Background Job Board lists \`fix-1 / ses_abc / fixer\`, call task with \`subagent_type: "fixer"\` and \`task_id: "fix-1"\` or \`task_id: "ses_abc"\`.
19404
- - Do not leave \`task_id\` empty when intending to reuse; omitted or empty \`task_id\` creates a new specialist session.
19405
-
19406
- ## 6. Verify
19407
- - Define the observable success criteria from the user's request.
19408
- - Choose the minimum verification that produces meaningful evidence for the change's scope, risk, uncertainty, and potential impact.
19409
- - Start with the narrowest relevant validation. Broaden verification only when integration scope, uncertainty, risk, or a failed focused check justifies it.
19410
- - Do not run project-wide checks by habit or merely because files changed.
19411
- - Do not treat verification as a fixed checklist; select evidence that can actually confirm the requested behavior.
19412
- - Request independent review only when its expected risk reduction justifies its coordination cost.
19413
- - Report what was verified and any material remaining uncertainty.
19414
-
19415
- </Workflow>
19416
-
19417
- <Communication>
19418
-
19419
- ## Clarity Over Assumptions
19420
- - If request is vague or has multiple valid interpretations, ask a targeted question before proceeding
19421
- - Don't guess at critical details (file paths, API choices, architectural decisions)
19422
- - Do make reasonable assumptions for minor details and state them briefly
19423
-
19424
- ## Concise Execution
19425
- - Answer directly, no preamble
19426
- - Don't summarize what you did unless asked
19427
- - Don't explain code unless asked
19428
- - One-word answers are fine when appropriate
19429
- - Default to the minimum response that fully resolves the user's request; expand only when detail is necessary or the user asks for it.
19430
- - Do not restate the user's request or narrate routine work.
19431
- - Brief delegation notices: "Checking docs via @librarian..." not "I'm going to delegate to @librarian because..."
19432
-
19433
- ## No Flattery
19434
- Never: "Great question!" "Excellent idea!" "Smart choice!" or any praise of user input.
19435
-
19436
- ## Honest Pushback
19437
- When user's approach seems problematic:
19438
- - State concern + alternative concisely
19439
- - Ask if they want to proceed anyway
19440
- - Don't lecture, don't blindly implement
19441
-
19442
- ## Example
19443
- **Bad:** "Great question! Let me think about the best approach here. I'm going to delegate to @librarian to check the latest Next.js documentation for the App Router, and then I'll implement the solution for you."
19444
-
19445
- **Good:** "Checking Next.js App Router docs via @librarian..."
19446
- [continues scheduling or integration]
19447
-
19448
- </Communication>
19449
- `;
19450
- }
19451
- function createOrchestratorAgent(model, customPrompt, customAppendPrompt, disabledAgents) {
19452
- const basePrompt = buildOrchestratorPrompt(disabledAgents);
19453
- const prompt = resolvePrompt(basePrompt, customPrompt, customAppendPrompt);
19454
- const definition = {
19455
- name: "orchestrator",
19456
- description: "AI coding orchestrator that delegates tasks to specialist agents for optimal quality, speed, and cost",
19457
- config: {
19458
- temperature: 0.1,
19459
- prompt
19460
- }
19461
- };
19462
- if (Array.isArray(model)) {
19463
- definition._modelArray = model.map((m) => typeof m === "string" ? { id: m } : m);
19464
- } else if (typeof model === "string" && model) {
19465
- definition.config.model = model;
19466
- }
19467
- return definition;
19468
- }
19469
-
19470
- // src/agents/permissions.ts
19471
- function createReadOnlyAgentPermission() {
19472
- return {
19473
- "*": "deny",
19474
- bash: "deny",
19475
- edit: "deny",
19476
- write: "deny",
19477
- apply_patch: "deny",
19478
- ast_grep_replace: "deny",
19479
- task: "deny",
19480
- question: "deny",
19481
- read: "allow",
19482
- glob: "allow",
19483
- grep: "allow",
19484
- lsp: "allow",
19485
- list: "allow",
19486
- codesearch: "allow",
19487
- ast_grep_search: "allow"
19488
- };
19489
- }
19490
-
19491
- // src/agents/council.ts
19492
- var COUNCIL_AGENT_PROMPT = `You are the Council agent - a multi-LLM orchestration system that runs consensus across multiple models.
19493
-
19494
- **Tool**: You have access to the \`council_session\` tool. You also have read-only codebase inspection tools. You do not have write, edit, shell, or subagent-delegation tools.
19495
-
19496
- **When to use**:
19497
- - When invoked by a user with a request
19498
- - When you want multiple expert opinions on a complex problem
19499
- - When higher confidence is needed through model consensus
19500
-
19501
- **Usage**:
19502
- 1. Call the \`council_session\` tool with the user's prompt
19503
- 2. Optionally specify a preset (omit to use the configured default)
19504
- 3. Receive the councillor responses formatted for synthesis
19505
- 4. Follow the Synthesis Process below
19506
- 5. Present the result to the user
19507
-
19508
- **Synthesis Process** (MANDATORY - follow in order):
19509
- 1. Read the original user prompt
19510
- 2. Review each councillor's response individually - note each councillor's key insight and unique contribution by name
19511
- 3. Identify agreements and contradictions between councillors
19512
- 4. Resolve contradictions with explicit reasoning
19513
- 5. Synthesize the optimal final answer
19514
- 6. Format output per the Required Output Format below
19515
-
19516
- **Behavior**:
19517
- - Delegate requests directly to council_session
19518
- - Don't pre-analyze or filter the prompt before calling council_session
19519
- - Credit specific insights from individual councillors using their names
19520
- - If councillors disagree, explain why you chose one approach over another
19521
- - Do not omit per-councillor details from the final response
19522
- - Do not collapse the output into only a final summary
19523
- - Be transparent about trade-offs when different approaches have valid pros/cons
19524
- - Don't just average responses - choose the best approach and improve upon it
19525
-
19526
- ${READONLY_FILE_OPERATIONS_RULES}
19527
-
19528
- **Required Output Format**:
19529
- Always include these sections in your final response:
19530
-
19531
- ## Council Response
19532
- Provide the best synthesized answer. Integrate the strongest points from the councillors, resolve disagreements, and give the user a clear final recommendation or answer. Include relevant code examples and concrete details.
19533
-
19534
- ## Councillor Details
19535
- Include each councillor's response separately.
19536
-
19537
- Use each councillor name exactly as provided in the tool result.
19538
-
19539
- Format each councillor like:
19540
-
19541
- ### <councillor name>
19542
- <that councillor's response>
19543
-
19544
- If a councillor failed or timed out, include that status briefly.
19545
-
19546
- ## Council Summary
19547
- Summarize where councillors agreed, where they disagreed, why you chose the final answer, and any remaining uncertainty. Include a consensus confidence rating: unanimous, majority, or split.`;
19548
- function createCouncilAgent(model, customPrompt, customAppendPrompt) {
19549
- const prompt = resolvePrompt(COUNCIL_AGENT_PROMPT, customPrompt, customAppendPrompt);
19550
- const definition = {
19551
- name: "council",
19552
- description: "Multi-LLM council agent that synthesizes responses from multiple models for higher-quality outputs",
19553
- config: {
19554
- temperature: 0.1,
19555
- prompt,
19556
- permission: {
19557
- ...createReadOnlyAgentPermission(),
19558
- council_session: "allow"
19559
- }
19560
- }
19561
- };
19562
- if (model) {
19563
- definition.config.model = model;
19564
- }
19565
- return definition;
19566
- }
19567
- function formatCouncillorPrompt(userPrompt, councillorPrompt) {
19568
- if (!councillorPrompt)
19569
- return userPrompt;
19570
- return `${councillorPrompt}
19571
-
19572
- ---
19573
-
19574
- ${userPrompt}`;
19575
- }
19576
- function formatCouncillorResults(originalPrompt, councillorResults) {
19577
- const completedWithResults = councillorResults.filter((cr) => cr.status === "completed" && cr.result);
19578
- const councillorSection = completedWithResults.map((cr) => {
19579
- const shortModel = shortModelLabel(cr.model);
19580
- return `**${cr.name}** (${shortModel}):
19581
- ${cr.result}`;
19582
- }).join(`
19583
-
19584
- `);
19585
- const failedSection = councillorResults.filter((cr) => cr.status !== "completed").map((cr) => `**${cr.name}**: ${cr.status} - ${cr.error ?? "Unknown"}`).join(`
19586
- `);
19587
- if (completedWithResults.length === 0) {
19588
- const errorDetails = councillorResults.map((cr) => `**${cr.name}** (${shortModelLabel(cr.model)}): ${cr.status} - ${cr.error ?? "Unknown"}`).join(`
19589
- `);
19590
- return `---
19591
-
19592
- **Original Prompt**:
19593
- ${originalPrompt}
19594
-
19595
- ---
19596
-
19597
- **Councillor Responses**:
19598
- All councillors failed to produce output:
19599
- ${errorDetails}
19600
-
19601
- Please generate a response based on the original prompt alone.`;
19602
- }
19603
- let prompt = `---
19604
-
19605
- **Original Prompt**:
19606
- ${originalPrompt}
19607
-
19608
- ---
19609
-
19610
- **Councillor Responses**:
19611
- ${councillorSection}`;
19612
- if (failedSection) {
19613
- prompt += `
19614
-
19615
- ---
19616
-
19617
- **Failed/Timed-out Councillors**:
19618
- ${failedSection}`;
19619
- }
19620
- prompt += `
19621
-
19622
- ---
19623
-
19624
- You MUST follow the Synthesis Process steps before producing output: review each councillor response individually, then produce the required output with a synthesized Council Response, per-councillor details using their exact names, and a Council Summary with consensus confidence rating (unanimous, majority, or split).`;
19625
- return prompt;
19626
- }
19627
-
19628
- // src/agents/councillor.ts
19629
- var COUNCILLOR_PROMPT = `You are a councillor in a multi-model council.
19630
-
19631
- **Role**: Provide your best independent analysis and solution to the given problem.
19632
-
19633
- **Capabilities**: You have read-only access to the codebase. You can:
19634
- - Read files (read)
19635
- - Search by name patterns (glob)
19636
- - Search by content (grep)
19637
- - Search code patterns (ast_grep_search)
19638
- - Use OpenCode's built-in \`lsp\` tool when available
19639
- - Search external docs (if MCPs are configured for this agent)
19640
-
19641
- You CANNOT edit files, write files, run shell commands, or delegate to other agents. You are an advisor, not an implementer.
19642
-
19643
- ${NO_SHELL_READONLY_FILE_OPERATIONS_RULES}
19644
-
19645
- **Behavior**:
19646
- - **Examine the codebase** before answering - your read access is what makes council valuable. Don't guess at code you can see.
19647
- - Analyze the problem thoroughly
19648
- - Provide a complete, well-reasoned response
19649
- - Focus on the quality and correctness of your solution
19650
- - Be direct and concise
19651
- - Don't be influenced by what other councillors might say - you won't see their responses
19652
-
19653
- **Output**:
19654
- - Give your honest assessment
19655
- - Reference specific files and line numbers when relevant
19656
- - Include relevant reasoning
19657
- - State any assumptions clearly
19658
- - Note any uncertainties`;
19659
- function createCouncillorAgent(model, customPrompt, customAppendPrompt) {
19660
- const prompt = resolvePrompt(COUNCILLOR_PROMPT, customPrompt, customAppendPrompt);
19661
- return {
19662
- name: "councillor",
19663
- description: "Read-only council advisor. Examines codebase and provides independent analysis. Spawned internally by the council system.",
19664
- config: {
19665
- model,
19666
- temperature: 0.2,
19667
- prompt,
19668
- permission: createReadOnlyAgentPermission()
19669
- }
19670
- };
19671
- }
19672
-
19673
- // src/agents/designer.ts
19674
- var DESIGNER_PROMPT = `You are a Designer - a frontend UI/UX specialist who creates and reviews intentional, polished experiences.
19675
-
19676
- **Role**: Craft and review cohesive UI/UX that balances visual impact with usability.
19677
-
19678
- ## Design Principles
19679
-
19680
- **Typography**
19681
- - Choose distinctive, characterful fonts that elevate aesthetics
19682
- - Avoid generic defaults (Arial, Inter)-opt for unexpected, beautiful choices
19683
- - Pair display fonts with refined body fonts for hierarchy
19684
-
19685
- **Color & Theme**
19686
- - Commit to a cohesive aesthetic with clear color variables
19687
- - Dominant colors with sharp accents > timid, evenly-distributed palettes
19688
- - Create atmosphere through intentional color relationships
19689
-
19690
- **Motion & Interaction**
19691
- - Leverage framework animation utilities when available (Tailwind's transition/animation classes)
19692
- - Focus on high-impact moments: orchestrated page loads with staggered reveals
19693
- - Use scroll-triggers and hover states that surprise and delight
19694
- - One well-timed animation > scattered micro-interactions
19695
- - Drop to custom CSS/JS only when utilities can't achieve the vision
19696
-
19697
- **Spatial Composition**
19698
- - Break conventions: asymmetry, overlap, diagonal flow, grid-breaking
19699
- - Generous negative space OR controlled density-commit to the choice
19700
- - Unexpected layouts that guide the eye
19701
-
19702
- **Visual Depth**
19703
- - Create atmosphere beyond solid colors: gradient meshes, noise textures, geometric patterns
19704
- - Layer transparencies, dramatic shadows, decorative borders
19705
- - Contextual effects that match the aesthetic (grain overlays, custom cursors)
19706
-
19707
- **Styling Approach**
19708
- - Default to Tailwind CSS utility classes when available-fast, maintainable, consistent
19709
- - Use custom CSS when the vision requires it: complex animations, unique effects, advanced compositions
19710
- - Balance utility-first speed with creative freedom where it matters
19711
-
19712
- **Match Vision to Execution**
19713
- - Maximalist designs → elaborate implementation, extensive animations, rich effects
19714
- - Minimalist designs → restraint, precision, careful spacing and typography
19715
- - Elegance comes from executing the chosen vision fully, not halfway
19716
-
19717
- ## Constraints
19718
- - Respect existing design systems when present
19719
- - Leverage component libraries where available
19720
- - Prioritize visual excellence-code perfection comes second
19721
- - Use grounded, normal, regular english - don't use jargon or overly technical language
19722
-
19723
- ${WRITABLE_FILE_OPERATIONS_RULES}
19724
-
19725
- ## Review Responsibilities
19726
- - Review existing UI for usability, responsiveness, visual consistency, and polish when asked
19727
- - Call out concrete UX issues and improvements, not just abstract design advice
19728
- - When validating, focus on what users actually see and feel
19729
-
19730
- ## Output Quality
19731
- You're capable of extraordinary creative work. Commit fully to distinctive visions and show what's possible when breaking conventions thoughtfully.`;
19732
- function createDesignerAgent(model, customPrompt, customAppendPrompt) {
19733
- let prompt = DESIGNER_PROMPT;
19734
- if (customPrompt) {
19735
- prompt = customPrompt;
19736
- } else if (customAppendPrompt) {
19737
- prompt = `${DESIGNER_PROMPT}
19076
+ ## Output Quality
19077
+ You're capable of extraordinary creative work. Commit fully to distinctive visions and show what's possible when breaking conventions thoughtfully.`;
19078
+ function createDesignerAgent(model, customPrompt, customAppendPrompt) {
19079
+ let prompt = DESIGNER_PROMPT;
19080
+ if (customPrompt) {
19081
+ prompt = customPrompt;
19082
+ } else if (customAppendPrompt) {
19083
+ prompt = `${DESIGNER_PROMPT}
19738
19084
 
19739
19085
  ${customAppendPrompt}`;
19740
19086
  }
@@ -19915,90 +19261,333 @@ var OBSERVER_PROMPT = `You are Observer - a visual analysis specialist.
19915
19261
 
19916
19262
  **Role**: Interpret images, screenshots, PDFs, and diagrams. Extract structured observations for the Orchestrator to act on.
19917
19263
 
19918
- **Behavior**:
19919
- - Read the file(s) specified in the prompt
19920
- - Analyze visual content - layouts, UI elements, text, relationships, flows
19921
- - For screenshots with text/code/errors: extract the **exact text** via OCR - never paraphrase error messages or code
19922
- - For multiple files: analyze each, then compare or relate as requested
19923
- - Return ONLY the extracted information relevant to the goal
19924
- - If the image is unclear, blurry, or partially visible: state what you CAN see and explicitly note what is uncertain - never guess or fabricate details
19264
+ **Behavior**:
19265
+ - Read the file(s) specified in the prompt
19266
+ - Analyze visual content - layouts, UI elements, text, relationships, flows
19267
+ - For screenshots with text/code/errors: extract the **exact text** via OCR - never paraphrase error messages or code
19268
+ - For multiple files: analyze each, then compare or relate as requested
19269
+ - Return ONLY the extracted information relevant to the goal
19270
+ - If the image is unclear, blurry, or partially visible: state what you CAN see and explicitly note what is uncertain - never guess or fabricate details
19271
+
19272
+ **Constraints**:
19273
+ - READ-ONLY: Analyze and report, don't modify files
19274
+ - Save context tokens - the Orchestrator never processes the raw file
19275
+ - Match the language of the request
19276
+ - If info not found, state clearly what's missing
19277
+
19278
+ ${READONLY_FILE_OPERATIONS_RULES}
19279
+ `;
19280
+ function createObserverAgent(model, customPrompt, customAppendPrompt) {
19281
+ let prompt = OBSERVER_PROMPT;
19282
+ if (customPrompt) {
19283
+ prompt = customPrompt;
19284
+ } else if (customAppendPrompt) {
19285
+ prompt = `${OBSERVER_PROMPT}
19286
+
19287
+ ${customAppendPrompt}`;
19288
+ }
19289
+ return {
19290
+ name: "observer",
19291
+ description: "Visual analysis. Use for interpreting images, screenshots, PDFs, and diagrams - extracts structured observations without loading raw files into main context. Requires a vision-capable model.",
19292
+ config: {
19293
+ model,
19294
+ temperature: 0.1,
19295
+ prompt
19296
+ }
19297
+ };
19298
+ }
19299
+
19300
+ // src/agents/oracle.ts
19301
+ var ORACLE_PROMPT = `You are Oracle - a strategic technical advisor and code reviewer.
19302
+
19303
+ **Role**: High-IQ debugging, architecture decisions, code review, simplification, and engineering guidance.
19304
+
19305
+ **Capabilities**:
19306
+ - Analyze complex codebases and identify root causes
19307
+ - Propose architectural solutions with tradeoffs
19308
+ - Review code for correctness, performance, maintainability, and unnecessary complexity
19309
+ - Enforce YAGNI and suggest simpler designs when abstractions are not pulling their weight
19310
+ - Guide debugging when standard approaches fail
19311
+
19312
+ **Behavior**:
19313
+ - Be direct and concise
19314
+ - Provide actionable recommendations
19315
+ - Explain reasoning briefly
19316
+ - Acknowledge uncertainty when present
19317
+ - Prefer simpler designs unless complexity clearly earns its keep
19318
+
19319
+ **Constraints**:
19320
+ - READ-ONLY: You advise, you don't implement
19321
+ - Focus on strategy, not execution
19322
+ - Point to specific files/lines when relevant
19323
+
19324
+ ${READONLY_FILE_OPERATIONS_RULES}
19325
+ `;
19326
+ function createOracleAgent(model, customPrompt, customAppendPrompt) {
19327
+ let prompt = ORACLE_PROMPT;
19328
+ if (customPrompt) {
19329
+ prompt = customPrompt;
19330
+ } else if (customAppendPrompt) {
19331
+ prompt = `${ORACLE_PROMPT}
19332
+
19333
+ ${customAppendPrompt}`;
19334
+ }
19335
+ return {
19336
+ name: "oracle",
19337
+ description: "Strategic technical advisor. Use for architecture decisions, complex debugging, code review, simplification, and engineering guidance.",
19338
+ config: {
19339
+ model,
19340
+ temperature: 0.1,
19341
+ prompt
19342
+ }
19343
+ };
19344
+ }
19345
+
19346
+ // src/agents/orchestrator.ts
19347
+ function resolvePrompt(base, customPrompt, customAppendPrompt) {
19348
+ const effectiveBase = customPrompt !== undefined ? customPrompt : base;
19349
+ return customAppendPrompt !== undefined ? `${effectiveBase}
19350
+
19351
+ ${customAppendPrompt}` : effectiveBase;
19352
+ }
19353
+ var AGENT_DESCRIPTIONS = {
19354
+ explorer: `@explorer
19355
+ - Lane: Fast codebase recon that returns compressed context
19356
+ - Permissions: read_files
19357
+ - Stats: 2x faster codebase search than orchestrator, 1/2 cost of orchestrator
19358
+ - Capabilities: Glob, grep, AST queries to locate files, symbols, patterns
19359
+ - **Delegate when:** Need to discover what exists before planning • Parallel searches speed discovery • Need summarized map vs full contents • Broad/uncertain scope
19360
+ - **Don't delegate when:** Know the path and need actual content • Need full file anyway • Single specific lookup • About to edit the file`,
19361
+ librarian: `@librarian
19362
+ - Lane: External knowledge and library research, fast web research
19363
+ - Role: Authoritative source for current library docs, API references, examples, bug investigations, and web retrieval
19364
+ - Stats: 2x faster web research than orchestrator, 1/2 cost of orchestrator
19365
+ - **Delegate when:** Libraries with frequent API changes (React, Next.js, AI SDKs) • Complex APIs needing official examples (ORMs, auth) • Version-specific behavior matters • Unfamiliar library • Edge cases or advanced features • Nuanced best practices • Working on fixing tricky bug or problem and need latest web research information
19366
+ - **Don't delegate when:** Standard usage you're confident • Simple stable APIs • General programming knowledge • Info already in conversation • Built-in language features
19367
+ - **Rule of thumb:** "How does this library work?" → @librarian. "How does programming work?" → answer directly. How does others solve or workaround this tricky issue?" → @librarian.`,
19368
+ oracle: `@oracle
19369
+ - Lane: Architecture, risk, debugging strategy, and review
19370
+ - Role: Strategic advisor for high-stakes decisions and persistent problems, code reviewer
19371
+ - Permissions: read_files
19372
+ - Stats: 5x better decision maker, problem solver, investigator than orchestrator, 0.8x speed of orchestrator, same cost.
19373
+ - Capabilities: Deep architectural reasoning, system-level trade-offs, complex debugging, code review, simplification, maintainability review
19374
+ - **Delegate when:** Major architectural decisions with long-term impact • Problems persisting after 2+ fix attempts • High-risk multi-system refactors • Costly trade-offs (performance vs maintainability) • Complex debugging with unclear root cause • Security/scalability/data integrity decisions • Genuinely uncertain and cost of wrong choice is high • Code needs simplification or YAGNI scrutiny
19375
+ - **Review use:** Oracle is an escalation, not a default verification step. Request independent Oracle review only when its analysis is expected to materially reduce risk or uncertainty.
19376
+ - **Don't delegate when:** Routine decisions you're confident about • First bug fix attempt • Straightforward trade-offs • Tactical "how" vs strategic "should" • Time-sensitive good-enough decisions • Quick research/testing can answer
19377
+ - **Rule of thumb:** Need senior architect review? → @oracle. Need code review or simplification? → @oracle. Routine coordination or final synthesis? → handle directly.`,
19378
+ designer: `@designer
19379
+ - Lane: UI/UX design, related edits, design polish and review
19380
+ - Permissions: read_files, write_files
19381
+ - Stats: 10x better UI/UX than orchestrator
19382
+ - Capabilities: Good design taste, visual relevant edits, interactions, responsive layouts, design systems with aesthetic intent, deep UI/UX knowledge.
19383
+ - Owns visual and interaction quality: layout, hierarchy, spacing, motion, affordances, responsive behavior, and overall feel.
19384
+ - Weakness: copywriting. Ask designer to use grounded, normal wording, then have orchestrator review/fix copy after design work without changing visual or interaction intent.
19385
+ - Avoid: "Let me us designer how it should look and implement yourself" → instead: "Let me ask designer to design and implement the UI/UX changes for me"
19386
+ - **Delegate when:** User-facing interfaces needing polish • Responsive layouts • UX-critical components (forms, nav, dashboards) • Visual consistency systems • Animations/micro-interactions • Landing/marketing pages • Refining functional→delightful • Reviewing existing UI/UX quality
19387
+ - **Don't delegate when:** Backend/logic with no visual • Quick prototypes where design doesn't matter yet.
19388
+ - **Rule of thumb:** Users see it and polish matters? → @designer. Headless/functional implementation? → schedule @fixer.`,
19389
+ fixer: `@fixer
19390
+ - Lane: Bounded implementation and executioner
19391
+ - Role: Fast execution specialist for well-defined tasks
19392
+ - Permissions: read_files, write_files
19393
+ - Stats: 2x faster code edits, 1/2 cost of orchestrator
19394
+ - Weakness: design, taste
19395
+ - Tools/Constraints: Execution-focused-no research, no architectural decisions
19396
+ - **Delegate when:** For implementation work, think and triage first. If the change is non-trivial or multi-file, hand bounded execution to @fixer • Parallelization benefits: Task involves multiple folders and multiple files modification, scoping work per folder and spawning parallel @fixers for each folder.
19397
+ - **Don't delegate when:** Needs discovery/research/decisions • Single small change (<20 lines, one file) • Unclear requirements needing iteration • Explaining to fixer > doing • Tight integration with your current work • Requires design taste, visual hierarchy, interaction polish, responsive layout decisions, animation/motion, component feel, or UI copy/design trade-offs
19398
+ - **Rule of thumb:** Headless/mechanical implementation → @fixer. User-visible design or polish → @designer. If @designer already set direction, @fixer may only do bounded mechanical follow-up that preserves that design exactly.`,
19399
+ council: `@council
19400
+ - Lane: High-stakes multi-model decision support
19401
+ - Role: Multi-LLM consensus engine that runs several councillors, synthesizes their views, and returns a structured council report.
19402
+ - Permissions: Read files
19403
+ - Stats: 3x slower than orchestrator, 3x or more cost of orchestrator
19404
+ - Capabilities: Runs multiple models in parallel, compares their answers, resolves disagreements, and produces a final synthesized answer plus councillor details and consensus summary.
19405
+ - **Delegate when:** Critical decisions need multiple independent perspectives • High-stakes architectural/security/data-integrity choices • Ambiguous problems where disagreement is useful signal • You want confidence beyond a single model • The user explicitly asks for council/consensus/multiple opinions.
19406
+ - **Don't delegate when:** Straightforward tasks you're confident about • Speed matters more than confidence • Routine implementation/debugging • A single specialist is clearly the right tool • You only need current docs/search/code review rather than multi-model consensus.
19407
+ - **How to call:** Send the full question/task and relevant context. Be explicit about what decision, trade-off, or answer the council should resolve. Do not ask council to do routine code edits.
19408
+ - **Result handling:** Council returns a structured response that may include: synthesized Council Response, individual Councillor Details, and Council Summary/confidence. Preserve that structure when the user asked for council output. Do not pretend the council only returned a final answer. If you need to act on the council result, first briefly state the council's recommendation, then proceed.
19409
+ - **Rule of thumb:** Need second/third opinions from different models? → @council. Need one expert lane? → use the specialist. Need final synthesis? → handle directly.`,
19410
+ observer: `@observer
19411
+ - Lane: Visual/media analysis isolated from orchestrator context
19412
+ - Role: Visual analysis specialist for images, PDFs, and diagrams
19413
+ - Permissions: Read files
19414
+ - Stats: Saves main context tokens - Observer processes raw files, returns structured observations
19415
+ - Capabilities: Interprets images, screenshots, PDFs, and diagrams via native read tool; extracts UI elements, layouts, text, relationships
19416
+ - **Delegate when:** Need to analyze a multimedia file• Extract information
19417
+ - **Don't delegate when:** Plain text files that Read can handle directly • Files that need editing afterward (need literal content from Read)
19418
+ - **Rule of thumb:** Even if your model supports vision, delegate visual analysis to @observer - it isolates large image/PDF bytes from your context window, returning only concise structured text. Need exact file contents for routing? → Read only the minimal context yourself.
19419
+ - **IMPORTANT:** When delegating to @observer, always include the **full file path** in the prompt so it can read the file. Example: "Analyze the screenshot at /path/to/file.png - describe the UI elements and error messages."`
19420
+ };
19421
+ var PARALLEL_DELEGATION_EXAMPLES = [
19422
+ "- Multiple @explorer searches across different domains?",
19423
+ "- @explorer + @librarian research in parallel?",
19424
+ "- Multiple @fixer instances for faster, scoped implementation?",
19425
+ "- @observer + @explorer in parallel (visual analysis + code search)?"
19426
+ ];
19427
+ function buildOrchestratorPrompt(disabledAgents) {
19428
+ const enabledAgents = Object.entries(AGENT_DESCRIPTIONS).filter(([name]) => !disabledAgents?.has(name)).map(([, desc]) => desc).join(`
19429
+
19430
+ `);
19431
+ const enabledParallelExamples = PARALLEL_DELEGATION_EXAMPLES.filter((line) => {
19432
+ const mentions = [...line.matchAll(/@(\w+)/g)].map((m) => m[1]);
19433
+ if (mentions.length === 0)
19434
+ return true;
19435
+ return mentions.every((name) => !disabledAgents?.has(name));
19436
+ }).join(`
19437
+ `);
19438
+ return `<Role>
19439
+ You are a workflow manager for coding work. Your job is to plan, schedule, delegate, monitor, reconcile, and verify specialist-agent work. You are not the default implementation worker.
19440
+
19441
+ For non-trivial coding work, identify separable lanes first and delegate bounded work to the appropriate specialist. Do not perform multi-step implementation serially when a suitable specialist is available.
19442
+
19443
+ Handle work directly only when it is one isolated, clear, low-risk action and delegation overhead exceeds doing it yourself.
19444
+
19445
+ Optimize for quality, speed, cost, and reliability by dispatching the right specialist lanes, tracking background task state, and integrating terminal results into one coherent outcome.
19446
+ You have perfect understanding of agent's context management, understand well the cost of building content and reusing context of existing agents when it's best or when it's best to spawn a new agent.
19447
+ </Role>
19448
+
19449
+ <Agents>
19450
+
19451
+ ${enabledAgents}
19452
+
19453
+ </Agents>
19454
+
19455
+ <Workflow>
19456
+
19457
+ ## 1. Understand
19458
+ Parse request: explicit requirements + implicit needs.
19459
+
19460
+ ## 2. Path Selection
19461
+ Evaluate approach by: quality, speed and cost.
19462
+ Choose the path that optimizes all four.
19463
+
19464
+ ## 3. Delegation Check
19465
+ Review available agents and lane rules. Before beginning non-trivial work, identify which parts can proceed independently.
19466
+
19467
+ **Routing threshold:**
19468
+ - Handle directly only for one isolated, clear, low-risk action where delegation would cost more than execution.
19469
+ - For multi-step implementation, broad discovery, external research, visual work, or complex debugging, delegate to the suitable specialist.
19470
+ - If two or more parts can proceed independently, dispatch them in parallel before starting dependent work.
19471
+ - Do not delegate merely because an agent exists. Do not keep substantive work entirely in the orchestrator merely because each individual step seems easy.
19472
+
19473
+ **Dispatch efficiency:**
19474
+ - Reference paths/lines, don't paste files (\`src/app.ts:42\` not full contents)
19475
+ - Brief user on delegation goal before each call
19476
+ - Record task IDs, state, and advisory ownership/dependency labels
19477
+ - Do not immediately wait after spawning independent background tasks unless the next step truly depends on their result
19478
+ - Reconcile results, resolve conflicts, and gate dependent lanes
19479
+
19480
+ ${WRITABLE_FILE_OPERATIONS_RULES}
19481
+
19482
+ ## 4. Plan and Parallelize
19483
+ When the routing threshold calls for delegation, build a short work graph before dispatching:
19484
+ - Independent lanes that can run now
19485
+ - Dependency-ordered lanes that must wait
19486
+ - Advisory ownership for write-capable lanes
19487
+ - Verification/review lanes that run after implementation
19488
+
19489
+ ### Todo Continuity
19490
+ - When the user adds a new task while a todo list exists, append the new task to the end of the existing todo list instead of replacing the list.
19491
+ - Preserve existing todo order, statuses, and priorities unless the user explicitly asks to reprioritize, cancel, or replace them.
19492
+ - Finish the current in-progress task before starting the newly appended task unless the current task is blocked or the user explicitly overrides the order.
19493
+
19494
+ Can tasks be split into background specialist work?
19495
+ ${enabledParallelExamples}
19496
+
19497
+ Balance: respect dependencies, avoid parallelizing what must be sequential, and avoid overlapping write ownership.
19498
+
19499
+ ### Background Task Discipline
19500
+ - Prefer \`task(..., background: true)\` for delegated work that can run independently.
19501
+ - For work already chosen for delegation, launch independent specialist lanes in the background so the orchestrator stays unblocked and can reconcile results when they return.
19502
+ - Track each task's specialist, objective, task/session ID, and file/topic ownership.
19503
+ - Continue orchestration only on non-overlapping work; otherwise briefly report what was launched and stop.
19504
+ - Before local edits or another writer task, compare against running task scopes.
19505
+ - Parallel background tasks are allowed only when their write scopes do not conflict.
19506
+ - Before final response, reconcile any terminal jobs shown in the Background Job Board.
19507
+ - Use \`cancel_task\` only when the user asks, or when a running lane is obsolete, wrong, or conflicts with a safer replacement plan.
19508
+ - Cancellation is not rollback: if cancelling a writer, inspect and reconcile partial file changes before launching a replacement lane.
19509
+
19510
+ ### Design Handoff Discipline
19511
+ - When @designer completes UI/UX work, treat layout, spacing, hierarchy, motion, color, affordances, and component feel as intentional design output.
19512
+ - Do not later simplify, normalize, or refactor it in ways that flatten the design.
19513
+ - The orchestrator should review and improve user-facing copy after designer work, because designer copy may be weak.
19514
+ - Copy edits must preserve the designer's visual structure and interaction intent.
19515
+ - If follow-up work is purely mechanical and preserves the design exactly, @fixer can handle it. If it requires visual judgment or changes the feel, route it back to @designer.
19516
+
19517
+ ### Session Reuse
19518
+ - Smartly reuse an available specialist session - context reuse saves time and tokens
19519
+ - When too much unrelated, and really needed, start a fresh session with the specialist
19520
+ - If multiple remembered sessions fit, prefer the most recently used matching session.
19521
+ - Prefer re-uses over creating new sessions all the time
19522
+ - When reusing a specialist session, you MUST pass the existing session or alias in the task tool's \`task_id\` argument. Saying "reuse" in prose is not enough.
19523
+ - If the Background Job Board lists \`fix-1 / ses_abc / fixer\`, call task with \`subagent_type: "fixer"\` and \`task_id: "fix-1"\` or \`task_id: "ses_abc"\`.
19524
+ - Do not leave \`task_id\` empty when intending to reuse; omitted or empty \`task_id\` creates a new specialist session.
19525
+
19526
+ ## 6. Verify
19527
+ - Define the observable success criteria from the user's request.
19528
+ - Choose the minimum verification that produces meaningful evidence for the change's scope, risk, uncertainty, and potential impact.
19529
+ - Start with the narrowest relevant validation. Broaden verification only when integration scope, uncertainty, risk, or a failed focused check justifies it.
19530
+ - Do not run project-wide checks by habit or merely because files changed.
19531
+ - Do not treat verification as a fixed checklist; select evidence that can actually confirm the requested behavior.
19532
+ - Request independent review only when its expected risk reduction justifies its coordination cost.
19533
+ - Report what was verified and any material remaining uncertainty.
19925
19534
 
19926
- **Constraints**:
19927
- - READ-ONLY: Analyze and report, don't modify files
19928
- - Save context tokens - the Orchestrator never processes the raw file
19929
- - Match the language of the request
19930
- - If info not found, state clearly what's missing
19535
+ </Workflow>
19931
19536
 
19932
- ${READONLY_FILE_OPERATIONS_RULES}
19933
- `;
19934
- function createObserverAgent(model, customPrompt, customAppendPrompt) {
19935
- let prompt = OBSERVER_PROMPT;
19936
- if (customPrompt) {
19937
- prompt = customPrompt;
19938
- } else if (customAppendPrompt) {
19939
- prompt = `${OBSERVER_PROMPT}
19537
+ <Communication>
19940
19538
 
19941
- ${customAppendPrompt}`;
19942
- }
19943
- return {
19944
- name: "observer",
19945
- description: "Visual analysis. Use for interpreting images, screenshots, PDFs, and diagrams - extracts structured observations without loading raw files into main context. Requires a vision-capable model.",
19946
- config: {
19947
- model,
19948
- temperature: 0.1,
19949
- prompt
19950
- }
19951
- };
19952
- }
19539
+ ## Clarity Over Assumptions
19540
+ - If request is vague or has multiple valid interpretations, ask a targeted question before proceeding
19541
+ - Don't guess at critical details (file paths, API choices, architectural decisions)
19542
+ - Do make reasonable assumptions for minor details and state them briefly
19953
19543
 
19954
- // src/agents/oracle.ts
19955
- var ORACLE_PROMPT = `You are Oracle - a strategic technical advisor and code reviewer.
19544
+ ## Concise Execution
19545
+ - Answer directly, no preamble
19546
+ - Don't summarize what you did unless asked
19547
+ - Don't explain code unless asked
19548
+ - One-word answers are fine when appropriate
19549
+ - Default to the minimum response that fully resolves the user's request; expand only when detail is necessary or the user asks for it.
19550
+ - Do not restate the user's request or narrate routine work.
19551
+ - Brief delegation notices: "Checking docs via @librarian..." not "I'm going to delegate to @librarian because..."
19956
19552
 
19957
- **Role**: High-IQ debugging, architecture decisions, code review, simplification, and engineering guidance.
19553
+ ## No Flattery
19554
+ Never: "Great question!" "Excellent idea!" "Smart choice!" or any praise of user input.
19958
19555
 
19959
- **Capabilities**:
19960
- - Analyze complex codebases and identify root causes
19961
- - Propose architectural solutions with tradeoffs
19962
- - Review code for correctness, performance, maintainability, and unnecessary complexity
19963
- - Enforce YAGNI and suggest simpler designs when abstractions are not pulling their weight
19964
- - Guide debugging when standard approaches fail
19556
+ ## Honest Pushback
19557
+ When user's approach seems problematic:
19558
+ - State concern + alternative concisely
19559
+ - Ask if they want to proceed anyway
19560
+ - Don't lecture, don't blindly implement
19965
19561
 
19966
- **Behavior**:
19967
- - Be direct and concise
19968
- - Provide actionable recommendations
19969
- - Explain reasoning briefly
19970
- - Acknowledge uncertainty when present
19971
- - Prefer simpler designs unless complexity clearly earns its keep
19562
+ ## Example
19563
+ **Bad:** "Great question! Let me think about the best approach here. I'm going to delegate to @librarian to check the latest Next.js documentation for the App Router, and then I'll implement the solution for you."
19972
19564
 
19973
- **Constraints**:
19974
- - READ-ONLY: You advise, you don't implement
19975
- - Focus on strategy, not execution
19976
- - Point to specific files/lines when relevant
19565
+ **Good:** "Checking Next.js App Router docs via @librarian..."
19566
+ [continues scheduling or integration]
19977
19567
 
19978
- ${READONLY_FILE_OPERATIONS_RULES}
19568
+ </Communication>
19979
19569
  `;
19980
- function createOracleAgent(model, customPrompt, customAppendPrompt) {
19981
- let prompt = ORACLE_PROMPT;
19982
- if (customPrompt) {
19983
- prompt = customPrompt;
19984
- } else if (customAppendPrompt) {
19985
- prompt = `${ORACLE_PROMPT}
19986
-
19987
- ${customAppendPrompt}`;
19988
- }
19989
- return {
19990
- name: "oracle",
19991
- description: "Strategic technical advisor. Use for architecture decisions, complex debugging, code review, simplification, and engineering guidance.",
19570
+ }
19571
+ function createOrchestratorAgent(model, customPrompt, customAppendPrompt, disabledAgents) {
19572
+ const basePrompt = buildOrchestratorPrompt(disabledAgents);
19573
+ const prompt = resolvePrompt(basePrompt, customPrompt, customAppendPrompt);
19574
+ const definition = {
19575
+ name: "orchestrator",
19576
+ description: "AI coding orchestrator that delegates tasks to specialist agents for optimal quality, speed, and cost",
19992
19577
  config: {
19993
- model,
19994
19578
  temperature: 0.1,
19995
19579
  prompt
19996
19580
  }
19997
19581
  };
19582
+ if (Array.isArray(model)) {
19583
+ definition._modelArray = model.map((m) => typeof m === "string" ? { id: m } : m);
19584
+ } else if (typeof model === "string" && model) {
19585
+ definition.config.model = model;
19586
+ }
19587
+ return definition;
19998
19588
  }
19999
19589
 
20000
19590
  // src/agents/index.ts
20001
- var COUNCIL_TOOL_ALLOWED_AGENTS = new Set(["council"]);
20002
19591
  var CANCEL_TASK_ALLOWED_AGENTS = new Set(["orchestrator"]);
20003
19592
  var SAFE_AGENT_ALIAS_RE = /^[a-z][a-z0-9_-]*$/i;
20004
19593
  function normalizeDisplayName(displayName) {
@@ -20146,12 +19735,10 @@ function applyDefaultPermissions(agent, configuredSkills, disabledSkills) {
20146
19735
  const existing = agent.config.permission ?? {};
20147
19736
  const skillPermissions = getSkillPermissionsForAgent(agent.name, configuredSkills, disabledSkills);
20148
19737
  const questionPerm = existing.question === "deny" ? "deny" : "allow";
20149
- const councilSessionPerm = COUNCIL_TOOL_ALLOWED_AGENTS.has(agent.name) ? existing.council_session ?? "allow" : "deny";
20150
19738
  const cancelTaskPerm = CANCEL_TASK_ALLOWED_AGENTS.has(agent.name) ? existing.cancel_task ?? "allow" : "deny";
20151
19739
  agent.config.permission = {
20152
19740
  ...existing,
20153
19741
  question: questionPerm,
20154
- council_session: councilSessionPerm,
20155
19742
  cancel_task: cancelTaskPerm,
20156
19743
  skill: {
20157
19744
  ...typeof existing.skill === "object" ? existing.skill : {},
@@ -20168,15 +19755,10 @@ var SUBAGENT_FACTORIES = {
20168
19755
  oracle: createOracleAgent,
20169
19756
  designer: createDesignerAgent,
20170
19757
  fixer: createFixerAgent,
20171
- observer: createObserverAgent,
20172
- council: createCouncilAgent,
20173
- councillor: createCouncillorAgent
19758
+ observer: createObserverAgent
20174
19759
  };
20175
19760
  function createAgents(config, options) {
20176
19761
  const disabled = getDisabledAgents(config);
20177
- if (!config?.council) {
20178
- disabled.add("council");
20179
- }
20180
19762
  const primaryModel = getConfigPrimaryModel(config);
20181
19763
  const getModelForAgent = (name) => {
20182
19764
  if (name === "fixer" && !getAgentOverride(config, "fixer")?.model) {
@@ -20254,13 +19836,6 @@ function createAgents(config, options) {
20254
19836
  applyDefaultPermissions(agent, override?.skills, config?.disabled_skills);
20255
19837
  return agent;
20256
19838
  });
20257
- const legacyMasterModel = config?.council?._legacyMasterModel;
20258
- if (legacyMasterModel) {
20259
- const councilAgent = builtInSubAgents.find((a) => a.name === "council");
20260
- if (councilAgent && !getAgentOverride(config, "council")?.model && councilAgent.config.model === DEFAULT_MODELS.council) {
20261
- councilAgent.config.model = legacyMasterModel;
20262
- }
20263
- }
20264
19839
  const customSubAgents = protoCustomAgents.map((agent) => {
20265
19840
  const override = getAgentOverride(config, agent.name);
20266
19841
  if (override) {
@@ -20369,12 +19944,7 @@ ${rewrittenAcps.join(`
20369
19944
  function getAgentConfigs(config, options) {
20370
19945
  const agents = createAgents(config, options);
20371
19946
  const applyClassification = (name, sdkConfig) => {
20372
- if (name === "council") {
20373
- sdkConfig.mode = "all";
20374
- } else if (name === "councillor") {
20375
- sdkConfig.mode = "subagent";
20376
- sdkConfig.hidden = true;
20377
- } else if (isSubagent(name)) {
19947
+ if (isSubagent(name)) {
20378
19948
  sdkConfig.mode = "subagent";
20379
19949
  } else if (name === "orchestrator") {
20380
19950
  sdkConfig.mode = "primary";
@@ -20382,7 +19952,7 @@ function getAgentConfigs(config, options) {
20382
19952
  sdkConfig.mode = "subagent";
20383
19953
  }
20384
19954
  };
20385
- const isInternalOnly = (name) => name === "councillor";
19955
+ const isInternalOnly = (_name) => false;
20386
19956
  const entries = [];
20387
19957
  for (const a of agents) {
20388
19958
  const sdkConfig = {
@@ -21282,270 +20852,6 @@ function applyOrchestratorModelConfig(input) {
21282
20852
  stripOrchestratorModel(input.agents, input.enabled, presetName ? input.presets?.[presetName] : undefined);
21283
20853
  }
21284
20854
 
21285
- // src/council/council-manager.ts
21286
- class CouncilManager {
21287
- client;
21288
- directory;
21289
- config;
21290
- depthTracker;
21291
- tmuxEnabled;
21292
- deprecatedFields;
21293
- legacyMasterModel;
21294
- constructor(ctx, config, depthTracker, tmuxEnabled = false) {
21295
- this.client = ctx.client;
21296
- this.directory = ctx.directory;
21297
- this.config = config;
21298
- this.deprecatedFields = config?.council?._deprecated;
21299
- this.legacyMasterModel = config?.council?._legacyMasterModel;
21300
- this.depthTracker = depthTracker;
21301
- this.tmuxEnabled = tmuxEnabled;
21302
- }
21303
- getDeprecatedFields() {
21304
- return this.deprecatedFields;
21305
- }
21306
- getLegacyMasterModel() {
21307
- return this.legacyMasterModel;
21308
- }
21309
- async runCouncil(prompt, presetName, parentSessionId) {
21310
- if (this.depthTracker) {
21311
- const parentDepth = this.depthTracker.getDepth(parentSessionId);
21312
- if (parentDepth + 1 > this.depthTracker.maxDepth) {
21313
- log("[council-manager] spawn blocked: max depth exceeded", {
21314
- parentSessionId,
21315
- parentDepth,
21316
- maxDepth: this.depthTracker.maxDepth
21317
- });
21318
- return {
21319
- success: false,
21320
- error: "Subagent depth exceeded",
21321
- councillorResults: []
21322
- };
21323
- }
21324
- }
21325
- const councilConfig = this.config?.council;
21326
- if (!councilConfig) {
21327
- log("[council-manager] Council configuration not found");
21328
- return {
21329
- success: false,
21330
- error: "Council not configured",
21331
- councillorResults: []
21332
- };
21333
- }
21334
- const resolvedPreset = presetName ?? councilConfig.default_preset ?? "default";
21335
- const preset = councilConfig.presets[resolvedPreset];
21336
- if (!preset) {
21337
- const available = Object.keys(councilConfig.presets).join(", ");
21338
- log(`[council-manager] Preset "${resolvedPreset}" not found`);
21339
- return {
21340
- success: false,
21341
- error: `Preset "${resolvedPreset}" does not exist. Omit the preset parameter to use the default, or call again with one of: ${available}`,
21342
- councillorResults: []
21343
- };
21344
- }
21345
- if (Object.keys(preset).length === 0) {
21346
- log(`[council-manager] Preset "${resolvedPreset}" has no councillors`);
21347
- return {
21348
- success: false,
21349
- error: `Preset "${resolvedPreset}" has no councillors configured. Note: the reserved key "master" is ignored - use councillor names as keys`,
21350
- councillorResults: []
21351
- };
21352
- }
21353
- const timeout = councilConfig.timeout ?? 180000;
21354
- const executionMode = councilConfig.councillor_execution_mode ?? "parallel";
21355
- const maxRetries = councilConfig.councillor_retries ?? 3;
21356
- const councillorCount = Object.keys(preset).length;
21357
- log(`[council-manager] Starting council with preset "${resolvedPreset}"`, {
21358
- councillors: Object.keys(preset)
21359
- });
21360
- this.sendStartNotification(parentSessionId, councillorCount).catch((err) => {
21361
- log("[council-manager] Failed to send start notification", {
21362
- error: err instanceof Error ? err.message : String(err)
21363
- });
21364
- });
21365
- const councillorResults = await this.runCouncillors(prompt, preset, parentSessionId, timeout, executionMode, maxRetries);
21366
- const completedCount = councillorResults.filter((r) => r.status === "completed").length;
21367
- log(`[council-manager] Councillors completed: ${completedCount}/${councillorResults.length}`);
21368
- if (completedCount === 0) {
21369
- return {
21370
- success: false,
21371
- error: "All councillors failed or timed out",
21372
- councillorResults
21373
- };
21374
- }
21375
- const formattedCouncillorResults = formatCouncillorResults(prompt, councillorResults);
21376
- log("[council-manager] Council completed successfully");
21377
- return {
21378
- success: true,
21379
- result: formattedCouncillorResults,
21380
- councillorResults
21381
- };
21382
- }
21383
- async sendStartNotification(parentSessionId, councillorCount) {
21384
- const message = [
21385
- `⎔ Council starting - ${councillorCount} councillors launching - ctrl+x ↓ to watch`,
21386
- "",
21387
- "[system status: continue without acknowledging this notification]"
21388
- ].join(`
21389
- `);
21390
- await this.client.session.prompt({
21391
- path: { id: parentSessionId },
21392
- body: {
21393
- noReply: true,
21394
- parts: [{ type: "text", text: message }]
21395
- }
21396
- });
21397
- }
21398
- async runAgentSession(options) {
21399
- const modelRef = parseModelReference(options.model);
21400
- if (!modelRef) {
21401
- throw new Error(`Invalid model format: ${options.model}`);
21402
- }
21403
- let sessionId;
21404
- try {
21405
- const session = await this.client.session.create({
21406
- body: {
21407
- parentID: options.parentSessionId,
21408
- title: options.title
21409
- },
21410
- query: { directory: this.directory }
21411
- });
21412
- if (!session.data?.id) {
21413
- throw new Error("Failed to create session");
21414
- }
21415
- sessionId = session.data.id;
21416
- if (this.depthTracker) {
21417
- const registered = this.depthTracker.registerChild(options.parentSessionId, sessionId);
21418
- if (!registered) {
21419
- throw new Error("Subagent depth exceeded");
21420
- }
21421
- }
21422
- if (this.tmuxEnabled) {
21423
- await new Promise((r) => setTimeout(r, TMUX_SPAWN_DELAY_MS));
21424
- }
21425
- const body = {
21426
- agent: options.agent,
21427
- model: modelRef,
21428
- tools: {
21429
- task: false,
21430
- question: false,
21431
- edit: false,
21432
- write: false,
21433
- apply_patch: false,
21434
- ast_grep_replace: false,
21435
- bash: false
21436
- },
21437
- parts: [{ type: "text", text: options.promptText }]
21438
- };
21439
- if (options.variant) {
21440
- body.variant = options.variant;
21441
- }
21442
- await promptWithTimeout(this.client, {
21443
- path: { id: sessionId },
21444
- body,
21445
- query: { directory: this.directory }
21446
- }, options.timeout);
21447
- const extraction = await extractSessionResult(this.client, sessionId, {
21448
- includeReasoning: options.includeReasoning
21449
- });
21450
- if (extraction.empty) {
21451
- const retryOnEmpty = this.config?.fallback?.retry_on_empty ?? true;
21452
- if (retryOnEmpty) {
21453
- throw new Error("Empty response from provider");
21454
- }
21455
- }
21456
- return extraction.text;
21457
- } finally {
21458
- if (sessionId) {
21459
- this.client.session.abort({ path: { id: sessionId } }).catch(() => {});
21460
- if (this.depthTracker) {
21461
- this.depthTracker.cleanup(sessionId);
21462
- }
21463
- }
21464
- }
21465
- }
21466
- async runCouncillors(prompt, councillors, parentSessionId, timeout, executionMode = "parallel", maxRetries) {
21467
- const entries = Object.entries(councillors);
21468
- const results = [];
21469
- if (executionMode === "serial") {
21470
- for (const [name, config] of entries) {
21471
- results.push(await this.runCouncillorWithRetry(name, config, prompt, parentSessionId, timeout, maxRetries));
21472
- }
21473
- } else {
21474
- const promises = entries.map(([name, config], index) => (async () => {
21475
- if (this.tmuxEnabled && index > 0) {
21476
- await new Promise((r) => setTimeout(r, index * COUNCILLOR_STAGGER_MS));
21477
- }
21478
- return this.runCouncillorWithRetry(name, config, prompt, parentSessionId, timeout, maxRetries);
21479
- })());
21480
- const settled = await Promise.allSettled(promises);
21481
- for (let index = 0;index < settled.length; index++) {
21482
- const result = settled[index];
21483
- const [name, cfg] = entries[index];
21484
- if (result.status === "fulfilled") {
21485
- results.push(result.value);
21486
- } else {
21487
- results.push({
21488
- name,
21489
- model: cfg.model,
21490
- status: "failed",
21491
- error: result.reason instanceof Error ? result.reason.message : String(result.reason)
21492
- });
21493
- }
21494
- }
21495
- }
21496
- return results;
21497
- }
21498
- async runCouncillorWithRetry(name, config, prompt, parentSessionId, timeout, maxRetries) {
21499
- const models = config.models ?? normalizeCouncillorModels(config.model, config.variant);
21500
- const totalAttempts = 1 + maxRetries;
21501
- let lastModel = models[0].id;
21502
- let lastStatus = "failed";
21503
- let lastError = `Councillor "${name}": no model responded`;
21504
- for (let modelIndex = 0;modelIndex < models.length; modelIndex++) {
21505
- const entry = models[modelIndex];
21506
- const modelLabel = shortModelLabel(entry.id);
21507
- lastModel = entry.id;
21508
- for (let attempt = 1;attempt <= totalAttempts; attempt++) {
21509
- if (attempt > 1) {
21510
- log(`[council-manager] Retrying councillor "${name}" (${modelLabel}), attempt ${attempt}/${totalAttempts}`);
21511
- } else if (modelIndex > 0) {
21512
- log(`[council-manager] Councillor "${name}" falling back to ${modelLabel} (model ${modelIndex + 1}/${models.length})`);
21513
- }
21514
- try {
21515
- const result = await this.runAgentSession({
21516
- parentSessionId,
21517
- title: `Council ${name} (${modelLabel})`,
21518
- agent: "councillor",
21519
- model: entry.id,
21520
- promptText: formatCouncillorPrompt(prompt, config.prompt),
21521
- variant: entry.variant,
21522
- timeout,
21523
- includeReasoning: false
21524
- });
21525
- return {
21526
- name,
21527
- model: entry.id,
21528
- status: "completed",
21529
- result
21530
- };
21531
- } catch (error) {
21532
- const msg = error instanceof Error ? error.message : String(error);
21533
- lastStatus = msg.includes("timed out") ? "timed_out" : "failed";
21534
- lastError = `Councillor "${name}": ${msg}`;
21535
- const isEmptyResponse = msg.includes("Empty response from provider");
21536
- if (!(attempt < totalAttempts && isEmptyResponse))
21537
- break;
21538
- }
21539
- }
21540
- }
21541
- return {
21542
- name,
21543
- model: lastModel,
21544
- status: lastStatus,
21545
- error: lastError
21546
- };
21547
- }
21548
- }
21549
20855
  // src/hooks/apply-patch/errors.ts
21550
20856
  var APPLY_PATCH_ERROR_PREFIX = {
21551
20857
  blocked: "apply_patch blocked",
@@ -24776,7 +24082,6 @@ var TERMINAL_STATES = new Set([
24776
24082
  "cancelled"
24777
24083
  ]);
24778
24084
  var AGENT_PREFIX = {
24779
- council: "cou",
24780
24085
  designer: "des",
24781
24086
  explorer: "exp",
24782
24087
  fixer: "fix",
@@ -25360,6 +24665,45 @@ function isInternalInitiatorPart(part) {
25360
24665
  }
25361
24666
  return part.metadata[INTERNAL_INITIATOR_METADATA_KEY] === true;
25362
24667
  }
24668
+ // src/utils/session.ts
24669
+ var SESSION_ABORT_TIMEOUT_MS = 1000;
24670
+
24671
+ class OperationTimeoutError extends Error {
24672
+ constructor(message) {
24673
+ super(message);
24674
+ this.name = "OperationTimeoutError";
24675
+ }
24676
+ }
24677
+ async function withTimeout(operation, timeoutMs, message) {
24678
+ if (timeoutMs <= 0)
24679
+ return operation;
24680
+ let timer;
24681
+ try {
24682
+ return await Promise.race([
24683
+ operation,
24684
+ new Promise((_, reject) => {
24685
+ timer = setTimeout(() => {
24686
+ reject(new OperationTimeoutError(message));
24687
+ }, timeoutMs);
24688
+ })
24689
+ ]);
24690
+ } finally {
24691
+ clearTimeout(timer);
24692
+ }
24693
+ }
24694
+ async function abortSessionWithTimeout(client, sessionId, timeoutMs = SESSION_ABORT_TIMEOUT_MS) {
24695
+ await withTimeout(client.session.abort({ path: { id: sessionId } }), timeoutMs, `Session abort timed out after ${timeoutMs}ms`);
24696
+ }
24697
+ function parseModelReference(model) {
24698
+ const slashIndex = model.indexOf("/");
24699
+ if (slashIndex <= 0 || slashIndex >= model.length - 1) {
24700
+ return null;
24701
+ }
24702
+ return {
24703
+ providerID: model.slice(0, slashIndex),
24704
+ modelID: model.slice(slashIndex + 1)
24705
+ };
24706
+ }
25363
24707
 
25364
24708
  // src/utils/index.ts
25365
24709
  init_zip_extractor();
@@ -30855,17 +30199,17 @@ import * as fs8 from "node:fs/promises";
30855
30199
  import * as path15 from "node:path";
30856
30200
 
30857
30201
  // src/interview/types.ts
30858
- import { z as z3 } from "zod";
30859
- var RawQuestionSchema = z3.object({
30860
- id: z3.string().optional(),
30861
- question: z3.string().optional(),
30862
- options: z3.array(z3.unknown()).optional(),
30863
- suggested: z3.unknown().optional()
30202
+ import { z as z2 } from "zod";
30203
+ var RawQuestionSchema = z2.object({
30204
+ id: z2.string().optional(),
30205
+ question: z2.string().optional(),
30206
+ options: z2.array(z2.unknown()).optional(),
30207
+ suggested: z2.unknown().optional()
30864
30208
  });
30865
- var RawInterviewStateSchema = z3.object({
30866
- summary: z3.unknown().optional(),
30867
- title: z3.unknown().optional(),
30868
- questions: z3.array(z3.unknown()).optional()
30209
+ var RawInterviewStateSchema = z2.object({
30210
+ summary: z2.unknown().optional(),
30211
+ title: z2.unknown().optional(),
30212
+ questions: z2.array(z2.unknown()).optional()
30869
30213
  });
30870
30214
 
30871
30215
  // src/interview/parser.ts
@@ -34940,7 +34284,7 @@ class MultiplexerSessionManager {
34940
34284
  import { spawn as spawn3 } from "node:child_process";
34941
34285
  import { createInterface } from "node:readline";
34942
34286
  import { tool } from "@opencode-ai/plugin";
34943
- var z4 = tool.schema;
34287
+ var z3 = tool.schema;
34944
34288
 
34945
34289
  class AcpClient {
34946
34290
  name;
@@ -35160,10 +34504,10 @@ function createAcpRunTool(agents = {}) {
35160
34504
  return tool({
35161
34505
  description: "Run a configured external ACP-compatible coding agent and return its streamed result. Use for configured ACP agents such as Claude Code ACP, Gemini ACP, or custom ACP servers.",
35162
34506
  args: {
35163
- agent: z4.string().describe("Configured ACP agent name"),
35164
- prompt: z4.string().describe("Task or question to send to the ACP agent"),
35165
- cwd: z4.string().optional().describe("Optional absolute working directory override"),
35166
- timeout_ms: z4.number().int().min(0).max(MAX_ACP_TIMEOUT_MS).optional().describe("Optional timeout override in milliseconds. Set to 0 to disable the timeout.")
34507
+ agent: z3.string().describe("Configured ACP agent name"),
34508
+ prompt: z3.string().describe("Task or question to send to the ACP agent"),
34509
+ cwd: z3.string().optional().describe("Optional absolute working directory override"),
34510
+ timeout_ms: z3.number().int().min(0).max(MAX_ACP_TIMEOUT_MS).optional().describe("Optional timeout override in milliseconds. Set to 0 to disable the timeout.")
35167
34511
  },
35168
34512
  async execute(args, ctx) {
35169
34513
  if (ctx.agent !== args.agent) {
@@ -35824,7 +35168,7 @@ var ast_grep_replace = tool2({
35824
35168
  import {
35825
35169
  tool as tool3
35826
35170
  } from "@opencode-ai/plugin";
35827
- var z5 = tool3.schema;
35171
+ var z4 = tool3.schema;
35828
35172
 
35829
35173
  class SessionStillRunningError extends Error {
35830
35174
  }
@@ -35834,8 +35178,8 @@ function createCancelTaskTool(options) {
35834
35178
 
35835
35179
  Use only for obsolete, wrong, conflicting, or user-requested cancellation. Accepts either the native task_id/session ID or the parent-scoped alias shown in the Background Job Board. Cancellation is not rollback: if cancelling a writer, inspect and reconcile partial file changes before replacing the lane.`,
35836
35180
  args: {
35837
- task_id: z5.string().describe("Tracked background task ID or Background Job Board alias"),
35838
- reason: z5.string().optional().describe("Short cancellation reason")
35181
+ task_id: z4.string().describe("Tracked background task ID or Background Job Board alias"),
35182
+ reason: z4.string().optional().describe("Short cancellation reason")
35839
35183
  },
35840
35184
  async execute(args, toolContext) {
35841
35185
  const parentSessionID = toolContext?.sessionID;
@@ -36217,72 +35561,6 @@ function unknownTaskOutput(taskID, message) {
36217
35561
  ].join(`
36218
35562
  `);
36219
35563
  }
36220
- // src/tools/council.ts
36221
- import {
36222
- tool as tool4
36223
- } from "@opencode-ai/plugin";
36224
- var z6 = tool4.schema;
36225
- function formatModelComposition(councillorResults) {
36226
- return councillorResults.map((cr) => {
36227
- const shortModel = shortModelLabel(cr.model);
36228
- return `${cr.name}: ${shortModel}`;
36229
- }).join(", ");
36230
- }
36231
- function createCouncilTool(_ctx, councilManager) {
36232
- const council_session = tool4({
36233
- description: `Launch a multi-LLM council session for consensus-based analysis.
36234
-
36235
- Sends the prompt to multiple models (councillors) in parallel and returns their formatted responses for you to synthesize.
36236
-
36237
- Returns the councillor responses with a summary footer.`,
36238
- args: {
36239
- prompt: z6.string().describe("The prompt to send to all councillors"),
36240
- preset: z6.string().optional().describe("Council preset to use. Omit to use the configured default. Must match a preset in the council config.")
36241
- },
36242
- async execute(args, toolContext) {
36243
- if (!toolContext || typeof toolContext !== "object" || !("sessionID" in toolContext)) {
36244
- throw new Error("Invalid toolContext: missing sessionID");
36245
- }
36246
- const allowedAgents = ["council"];
36247
- const callingAgent = toolContext.agent;
36248
- if (callingAgent && !allowedAgents.includes(callingAgent)) {
36249
- throw new Error(`Council sessions can only be invoked by the council agent. Current agent: ${callingAgent}`);
36250
- }
36251
- const prompt = String(args.prompt);
36252
- const preset = typeof args.preset === "string" ? args.preset : undefined;
36253
- const parentSessionId = toolContext.sessionID;
36254
- const result = await councilManager.runCouncil(prompt, preset, parentSessionId);
36255
- if (!result.success) {
36256
- return `Council session failed: ${result.error}`;
36257
- }
36258
- let output = result.result ?? "(No output)";
36259
- const completed = result.councillorResults.filter((cr) => cr.status === "completed").length;
36260
- const total = result.councillorResults.length;
36261
- const composition = formatModelComposition(result.councillorResults);
36262
- output += `
36263
-
36264
- ---
36265
- *Council: ${completed}/${total} councillors responded (${composition})*`;
36266
- const deprecated = councilManager.getDeprecatedFields();
36267
- if (deprecated && deprecated.length > 0) {
36268
- const legacyMasterModel = councilManager.getLegacyMasterModel();
36269
- const hasMaster = deprecated.includes("master");
36270
- const trulyIgnored = hasMaster && !legacyMasterModel ? deprecated : deprecated.filter((f) => f !== "master");
36271
- const parts = [];
36272
- if (hasMaster && legacyMasterModel) {
36273
- parts.push(`\`council.master\` is deprecated and will be removed in a future version. Its \`model\` is currently used as a fallback for the council agent - add a \`council\` entry to your preset to make this explicit.`);
36274
- }
36275
- if (trulyIgnored.length > 0) {
36276
- parts.push(`${trulyIgnored.map((f) => `\`council.${f}\``).join(", ")} ${trulyIgnored.length === 1 ? "is" : "are"} deprecated and ignored - remove ${trulyIgnored.length === 1 ? "it" : "them"} from your config.`);
36277
- }
36278
- output += `
36279
- ⚠ Config warning: ${parts.join(" ")}`;
36280
- }
36281
- return output;
36282
- }
36283
- });
36284
- return { council_session };
36285
- }
36286
35564
  // src/tools/preset-manager.ts
36287
35565
  import * as fs10 from "node:fs";
36288
35566
 
@@ -36554,7 +35832,7 @@ var WEBFETCH_DESCRIPTION = "Fetch a URL with better extraction for static/docs p
36554
35832
  import os7 from "node:os";
36555
35833
  import path22 from "node:path";
36556
35834
  import {
36557
- tool as tool5
35835
+ tool as tool4
36558
35836
  } from "@opencode-ai/plugin";
36559
35837
 
36560
35838
  // src/tools/smartfetch/binary.ts
@@ -36722,7 +36000,7 @@ var L = class u2 {
36722
36000
  return this.#S;
36723
36001
  }
36724
36002
  constructor(e) {
36725
- let { max: t = 0, ttl: i, ttlResolution: s = 1, ttlAutopurge: n, updateAgeOnGet: o, updateAgeOnHas: r, allowStale: h, dispose: l, onInsert: c, disposeAfter: f, noDisposeOnSet: g, noUpdateTTL: p, maxSize: T = 0, maxEntrySize: w = 0, sizeCalculation: y, fetchMethod: a, memoMethod: m, noDeleteOnFetchRejection: _, noDeleteOnStaleGet: b, allowStaleOnFetchRejection: d, allowStaleOnFetchAbort: A, ignoreFetchAbort: z7, perf: x } = e;
36003
+ let { max: t = 0, ttl: i, ttlResolution: s = 1, ttlAutopurge: n, updateAgeOnGet: o, updateAgeOnHas: r, allowStale: h, dispose: l, onInsert: c, disposeAfter: f, noDisposeOnSet: g, noUpdateTTL: p, maxSize: T = 0, maxEntrySize: w = 0, sizeCalculation: y, fetchMethod: a, memoMethod: m, noDeleteOnFetchRejection: _, noDeleteOnStaleGet: b, allowStaleOnFetchRejection: d, allowStaleOnFetchAbort: A, ignoreFetchAbort: z5, perf: x } = e;
36726
36004
  if (x !== undefined && typeof x?.now != "function")
36727
36005
  throw new TypeError("perf option must have a now() method if specified");
36728
36006
  if (this.#m = x ?? G, t !== 0 && !F(t))
@@ -36740,7 +36018,7 @@ var L = class u2 {
36740
36018
  throw new TypeError("memoMethod must be a function if defined");
36741
36019
  if (this.#U = m, a !== undefined && typeof a != "function")
36742
36020
  throw new TypeError("fetchMethod must be a function if specified");
36743
- if (this.#M = a, this.#W = !!a, this.#s = new Map, this.#i = Array.from({ length: t }).fill(undefined), this.#t = Array.from({ length: t }).fill(undefined), this.#a = new v(t), this.#c = new v(t), this.#l = 0, this.#h = 0, this.#y = R.create(t), this.#n = 0, this.#b = 0, typeof l == "function" && (this.#w = l), typeof c == "function" && (this.#D = c), typeof f == "function" ? (this.#S = f, this.#r = []) : (this.#S = undefined, this.#r = undefined), this.#T = !!this.#w, this.#j = !!this.#D, this.#f = !!this.#S, this.noDisposeOnSet = !!g, this.noUpdateTTL = !!p, this.noDeleteOnFetchRejection = !!_, this.allowStaleOnFetchRejection = !!d, this.allowStaleOnFetchAbort = !!A, this.ignoreFetchAbort = !!z7, this.maxEntrySize !== 0) {
36021
+ if (this.#M = a, this.#W = !!a, this.#s = new Map, this.#i = Array.from({ length: t }).fill(undefined), this.#t = Array.from({ length: t }).fill(undefined), this.#a = new v(t), this.#c = new v(t), this.#l = 0, this.#h = 0, this.#y = R.create(t), this.#n = 0, this.#b = 0, typeof l == "function" && (this.#w = l), typeof c == "function" && (this.#D = c), typeof f == "function" ? (this.#S = f, this.#r = []) : (this.#S = undefined, this.#r = undefined), this.#T = !!this.#w, this.#j = !!this.#D, this.#f = !!this.#S, this.noDisposeOnSet = !!g, this.noUpdateTTL = !!p, this.noDeleteOnFetchRejection = !!_, this.allowStaleOnFetchRejection = !!d, this.allowStaleOnFetchAbort = !!A, this.ignoreFetchAbort = !!z5, this.maxEntrySize !== 0) {
36744
36022
  if (this.#u !== 0 && !F(this.#u))
36745
36023
  throw new TypeError("maxSize must be a positive integer if specified");
36746
36024
  if (!F(this.maxEntrySize))
@@ -37120,8 +36398,8 @@ var L = class u2 {
37120
36398
  let A = this.#p(b);
37121
36399
  if (!y && !A)
37122
36400
  return a && (a.fetch = "hit"), this.#L(b), s && this.#x(b), a && this.#E(a, b), d;
37123
- let z7 = this.#P(e, b, _, w), v = z7.__staleWhileFetching !== undefined && i;
37124
- return a && (a.fetch = A ? "stale" : "refresh", v && A && (a.returnedStale = true)), v ? z7.__staleWhileFetching : z7.__returned = z7;
36401
+ let z5 = this.#P(e, b, _, w), v = z5.__staleWhileFetching !== undefined && i;
36402
+ return a && (a.fetch = A ? "stale" : "refresh", v && A && (a.returnedStale = true)), v ? z5.__staleWhileFetching : z5.__returned = z5;
37125
36403
  }
37126
36404
  }
37127
36405
  forceFetch(e, t = {}) {
@@ -38341,20 +37619,20 @@ async function runSecondaryModelWithFallback(client, directory, models, prompt,
38341
37619
  }
38342
37620
 
38343
37621
  // src/tools/smartfetch/tool.ts
38344
- var z7 = tool5.schema;
37622
+ var z5 = tool4.schema;
38345
37623
  function createWebfetchTool(pluginCtx, options = {}) {
38346
37624
  const binaryDir = options.binaryDir || path22.join(os7.tmpdir(), "opencode-smartfetch");
38347
- return tool5({
37625
+ return tool4({
38348
37626
  description: WEBFETCH_DESCRIPTION,
38349
37627
  args: {
38350
- url: z7.httpUrl(),
38351
- format: z7.enum(["text", "markdown", "html"]).default("markdown"),
38352
- timeout: z7.number().positive().max(MAX_TIMEOUT_SECONDS).optional().describe("Timeout in seconds, max 120."),
38353
- prompt: z7.string().optional().describe("Optional extraction task to run on the fetched content using a cheap secondary model."),
38354
- extract_main: z7.boolean().default(true),
38355
- prefer_llms_txt: z7.enum(["auto", "always", "never"]).default("auto"),
38356
- include_metadata: z7.boolean().default(true),
38357
- save_binary: z7.boolean().default(false).describe("Save binary payload to disk when it fits within the active download limit.")
37628
+ url: z5.httpUrl(),
37629
+ format: z5.enum(["text", "markdown", "html"]).default("markdown"),
37630
+ timeout: z5.number().positive().max(MAX_TIMEOUT_SECONDS).optional().describe("Timeout in seconds, max 120."),
37631
+ prompt: z5.string().optional().describe("Optional extraction task to run on the fetched content using a cheap secondary model."),
37632
+ extract_main: z5.boolean().default(true),
37633
+ prefer_llms_txt: z5.enum(["auto", "always", "never"]).default("auto"),
37634
+ include_metadata: z5.boolean().default(true),
37635
+ save_binary: z5.boolean().default(false).describe("Save binary payload to disk when it fits within the active download limit.")
38358
37636
  },
38359
37637
  async execute(args, ctx) {
38360
37638
  const secondaryModels = await readSecondaryModelFromConfig(ctx.directory || pluginCtx.directory);
@@ -38964,7 +38242,7 @@ var OhMyOpenCodeLite = async (ctx) => {
38964
38242
  let interviewManager;
38965
38243
  let presetManager;
38966
38244
  let companionManager;
38967
- let councilTools;
38245
+ let councilTools = {};
38968
38246
  let cancelTaskTools;
38969
38247
  let acpRunTools;
38970
38248
  let webfetch;
@@ -39011,7 +38289,7 @@ var OhMyOpenCodeLite = async (ctx) => {
39011
38289
  startAvailabilityCheck(multiplexerConfig);
39012
38290
  }
39013
38291
  depthTracker = new SubagentDepthTracker;
39014
- councilTools = config.council ? createCouncilTool(ctx, new CouncilManager(ctx, config, depthTracker, multiplexerEnabled)) : {};
38292
+ councilTools = {};
39015
38293
  mcps = createBuiltinMcps(config.disabled_mcps, config.websearch);
39016
38294
  acpRunTools = Object.keys(config.acpAgents ?? {}).length > 0 ? { acp_run: createAcpRunTool(config.acpAgents) } : {};
39017
38295
  webfetch = createWebfetchTool(ctx);
@@ -39310,7 +38588,7 @@ var OhMyOpenCodeLite = async (ctx) => {
39310
38588
  const tuiAgentModels = {};
39311
38589
  const tuiAgentVariants = {};
39312
38590
  for (const agentDef of agentDefs) {
39313
- if (agentDef.name === "councillor")
38591
+ if (agentDef.name === "councillor" || agentDef.name === "council")
39314
38592
  continue;
39315
38593
  const entry = configAgent[agentDef.name];
39316
38594
  const resolvedModel = typeof entry?.model === "string" ? entry.model : runtimeChains[agentDef.name]?.[0] ? runtimeChains[agentDef.name][0] : typeof agentDef.config.model === "string" ? agentDef.config.model : undefined;