@zcy2nn/agent-forge 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +247 -247
  2. package/agent-forge.schema.json +2 -133
  3. package/dist/cli/index.js +109 -204
  4. package/dist/cli/providers.d.ts +0 -44
  5. package/dist/config/constants.d.ts +3 -4
  6. package/dist/config/index.d.ts +0 -1
  7. package/dist/config/schema.d.ts +2 -72
  8. package/dist/index.js +191 -995
  9. package/dist/tools/index.d.ts +0 -1
  10. package/dist/tui.js +5 -18
  11. package/package.json +104 -104
  12. package/src/skills/brainstorming/SKILL.md +185 -186
  13. package/src/skills/brainstorming/scripts/frame-template.html +214 -214
  14. package/src/skills/brainstorming/scripts/server.cjs +354 -354
  15. package/src/skills/brainstorming/spec-document-reviewer-prompt.md +1 -1
  16. package/src/skills/codemap/README.md +3 -3
  17. package/src/skills/codemap/SKILL.md +5 -5
  18. package/src/skills/codemap/codemap.md +4 -4
  19. package/src/skills/codemap/scripts/codemap.mjs +1 -1
  20. package/src/skills/codemap/scripts/codemap.test.ts +1 -1
  21. package/src/skills/requesting-code-review/SKILL.md +1 -1
  22. package/src/skills/subagent-driven-development/SKILL.md +1 -1
  23. package/src/skills/systematic-debugging/SKILL.md +318 -318
  24. package/src/skills/test-driven-development/SKILL.md +392 -392
  25. package/src/skills/verification-before-completion/SKILL.md +153 -153
  26. package/src/skills/writing-plans/SKILL.md +2 -2
  27. package/src/skills/writing-skills/graphviz-conventions.dot +171 -171
  28. package/dist/agents/council.d.ts +0 -27
  29. package/dist/agents/councillor.d.ts +0 -2
  30. package/dist/agents/designer.d.ts +0 -2
  31. package/dist/agents/explorer.d.ts +0 -2
  32. package/dist/agents/fixer.d.ts +0 -2
  33. package/dist/agents/implementer.d.ts +0 -2
  34. package/dist/agents/librarian.d.ts +0 -2
  35. package/dist/agents/observer.d.ts +0 -2
  36. package/dist/agents/oracle.d.ts +0 -2
  37. package/dist/agents/reviewer.d.ts +0 -2
  38. package/dist/cli/migration.d.ts +0 -46
  39. package/dist/config/council-schema.d.ts +0 -127
  40. package/dist/council/council-manager.d.ts +0 -49
  41. package/dist/council/index.d.ts +0 -1
  42. package/dist/skills/systematic-debugging/condition-based-waiting-example.d.ts +0 -51
  43. package/dist/tools/council.d.ts +0 -10
  44. package/src/skills/using-git-worktrees/SKILL.md +0 -226
package/dist/index.js CHANGED
@@ -18190,7 +18190,7 @@ var CUSTOM_SKILLS = [
18190
18190
  {
18191
18191
  name: "simplify",
18192
18192
  description: "Code simplification and readability-focused refactoring",
18193
- allowedAgents: ["reviewer"],
18193
+ allowedAgents: ["orchestrator"],
18194
18194
  sourcePath: "src/skills/simplify"
18195
18195
  },
18196
18196
  {
@@ -18229,12 +18229,6 @@ var CUSTOM_SKILLS = [
18229
18229
  allowedAgents: ["orchestrator"],
18230
18230
  sourcePath: "src/skills/dispatching-parallel-agents"
18231
18231
  },
18232
- {
18233
- name: "using-git-worktrees",
18234
- description: "Create isolated git worktrees before executing implementation plans",
18235
- allowedAgents: ["orchestrator"],
18236
- sourcePath: "src/skills/using-git-worktrees"
18237
- },
18238
18232
  {
18239
18233
  name: "finishing-a-development-branch",
18240
18234
  description: "Guide completion of development work with structured merge/PR options",
@@ -18250,25 +18244,25 @@ var CUSTOM_SKILLS = [
18250
18244
  {
18251
18245
  name: "test-driven-development",
18252
18246
  description: "Write failing tests first, then minimal code to pass, before any implementation",
18253
- allowedAgents: ["implementer"],
18247
+ allowedAgents: ["orchestrator"],
18254
18248
  sourcePath: "src/skills/test-driven-development"
18255
18249
  },
18256
18250
  {
18257
18251
  name: "verification-before-completion",
18258
18252
  description: "Run verification commands and confirm output before claiming work is complete",
18259
- allowedAgents: ["implementer"],
18253
+ allowedAgents: ["orchestrator"],
18260
18254
  sourcePath: "src/skills/verification-before-completion"
18261
18255
  },
18262
18256
  {
18263
18257
  name: "systematic-debugging",
18264
18258
  description: "Find root cause before attempting fixes for any bug or test failure",
18265
- allowedAgents: ["reviewer"],
18259
+ allowedAgents: ["orchestrator"],
18266
18260
  sourcePath: "src/skills/systematic-debugging"
18267
18261
  },
18268
18262
  {
18269
18263
  name: "receiving-code-review",
18270
18264
  description: "Evaluate code review feedback with technical rigor before implementing suggestions",
18271
- allowedAgents: ["reviewer"],
18265
+ allowedAgents: ["orchestrator"],
18272
18266
  sourcePath: "src/skills/receiving-code-review"
18273
18267
  },
18274
18268
  {
@@ -18285,7 +18279,7 @@ var RECOMMENDED_SKILLS = [
18285
18279
  name: "agent-browser",
18286
18280
  repo: "https://github.com/vercel-labs/agent-browser",
18287
18281
  skillName: "agent-browser",
18288
- allowedAgents: ["implementer"],
18282
+ allowedAgents: ["orchestrator"],
18289
18283
  description: "High-performance browser automation",
18290
18284
  postInstallCommands: [
18291
18285
  "npm install -g agent-browser",
@@ -18334,28 +18328,17 @@ function getSkillPermissionsForAgent(agentName, skillList) {
18334
18328
 
18335
18329
  // src/config/constants.ts
18336
18330
  var SUBAGENT_NAMES = [
18337
- "researcher",
18338
- "reviewer",
18339
- "implementer",
18340
- "council",
18341
- "councillor"
18331
+ "researcher"
18342
18332
  ];
18343
18333
  var ORCHESTRATOR_NAME = "orchestrator";
18344
18334
  var ALL_AGENT_NAMES = [ORCHESTRATOR_NAME, ...SUBAGENT_NAMES];
18345
18335
  var PROTECTED_AGENTS = new Set([
18346
18336
  "orchestrator",
18347
- "researcher",
18348
- "reviewer",
18349
- "implementer",
18350
- "councillor"
18337
+ "researcher"
18351
18338
  ]);
18352
18339
  var DEFAULT_MODELS = {
18353
18340
  orchestrator: undefined,
18354
- reviewer: "openai/gpt-5.5",
18355
- researcher: "openai/gpt-5.4-mini",
18356
- implementer: "openai/gpt-5.4-mini",
18357
- council: "openai/gpt-5.4-mini",
18358
- councillor: "openai/gpt-5.4-mini"
18341
+ researcher: "openai/gpt-5.4-mini"
18359
18342
  };
18360
18343
  var POLL_INTERVAL_BACKGROUND_MS = 2000;
18361
18344
  var DEFAULT_TIMEOUT_MS = 2 * 60 * 1000;
@@ -18364,77 +18347,7 @@ var DEFAULT_MAX_SUBAGENT_DEPTH = 3;
18364
18347
  var PHASE_REMINDER_TEXT = `!IMPORTANT! Recall the workflow rules:
18365
18348
  Understand → choose the best parallelized path based on your capabilities and agents delegation rules → recall session reuse rules → execute → verify.
18366
18349
  If delegating, launch the specialist in the same turn you mention it !END!`;
18367
- var TMUX_SPAWN_DELAY_MS = 500;
18368
- var COUNCILLOR_STAGGER_MS = 250;
18369
- var DEFAULT_DISABLED_AGENTS = ["council"];
18370
- // src/config/council-schema.ts
18371
- import { z } from "zod";
18372
- var ModelIdSchema = z.string().regex(/^[^/\s]+\/[^\s]+$/, 'Expected provider/model format (e.g. "openai/gpt-5.4-mini")');
18373
- var CouncillorConfigSchema = z.object({
18374
- model: ModelIdSchema.describe('Model ID in provider/model format (e.g. "openai/gpt-5.4-mini")'),
18375
- variant: z.string().optional(),
18376
- prompt: z.string().optional().describe("Optional role/guidance injected into the councillor user prompt")
18377
- });
18378
- var CouncilPresetSchema = z.record(z.string(), z.record(z.string(), z.unknown())).transform((entries, ctx) => {
18379
- const councillors = {};
18380
- for (const [key, raw] of Object.entries(entries)) {
18381
- if (key === "master")
18382
- continue;
18383
- if (key === "councillors" && typeof raw === "object" && raw !== null) {
18384
- for (const [innerKey, innerRaw] of Object.entries(raw)) {
18385
- const innerParsed = CouncillorConfigSchema.safeParse(innerRaw);
18386
- if (!innerParsed.success) {
18387
- ctx.addIssue({
18388
- code: z.ZodIssueCode.custom,
18389
- message: `Invalid councillor "${innerKey}" (nested under legacy "councillors" key): ${innerParsed.error.issues.map((i) => i.message).join(", ")}`
18390
- });
18391
- return z.NEVER;
18392
- }
18393
- councillors[innerKey] = innerParsed.data;
18394
- }
18395
- continue;
18396
- }
18397
- const parsed = CouncillorConfigSchema.safeParse(raw);
18398
- if (!parsed.success) {
18399
- ctx.addIssue({
18400
- code: z.ZodIssueCode.custom,
18401
- message: `Invalid councillor "${key}": ${parsed.error.issues.map((i) => i.message).join(", ")}`
18402
- });
18403
- return z.NEVER;
18404
- }
18405
- councillors[key] = parsed.data;
18406
- }
18407
- return councillors;
18408
- });
18409
- 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.');
18410
- var CouncilConfigSchema = z.object({
18411
- presets: z.record(z.string(), CouncilPresetSchema),
18412
- timeout: z.number().min(0).default(180000),
18413
- default_preset: z.string().default("default"),
18414
- 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).'),
18415
- 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."),
18416
- master: z.unknown().optional().describe("DEPRECATED — ignored. Council agent synthesizes directly."),
18417
- master_timeout: z.unknown().optional().describe('DEPRECATED — ignored. Use "timeout" instead.'),
18418
- master_fallback: z.unknown().optional().describe("DEPRECATED — ignored. No separate master session.")
18419
- }).transform((data) => {
18420
- const deprecated = [];
18421
- if (data.master !== undefined)
18422
- deprecated.push("master");
18423
- if (data.master_timeout !== undefined)
18424
- deprecated.push("master_timeout");
18425
- if (data.master_fallback !== undefined)
18426
- deprecated.push("master_fallback");
18427
- const legacyMasterModel = typeof data.master === "object" && data.master !== null && "model" in data.master && typeof data.master.model === "string" ? data.master.model : undefined;
18428
- return {
18429
- presets: data.presets,
18430
- timeout: data.timeout,
18431
- default_preset: data.default_preset,
18432
- councillor_execution_mode: data.councillor_execution_mode,
18433
- councillor_retries: data.councillor_retries,
18434
- _deprecated: deprecated.length > 0 ? deprecated : undefined,
18435
- _legacyMasterModel: legacyMasterModel
18436
- };
18437
- });
18350
+ var DEFAULT_DISABLED_AGENTS = [];
18438
18351
  // src/config/loader.ts
18439
18352
  import * as fs from "node:fs";
18440
18353
  import * as path from "node:path";
@@ -18464,11 +18377,7 @@ function getOpenCodeConfigPaths() {
18464
18377
  // src/config/agent-mcps.ts
18465
18378
  var DEFAULT_AGENT_MCPS = {
18466
18379
  orchestrator: ["*", "!context7"],
18467
- researcher: ["websearch", "context7", "grep_app"],
18468
- reviewer: [],
18469
- implementer: [],
18470
- council: [],
18471
- councillor: []
18380
+ researcher: ["websearch", "context7", "grep_app"]
18472
18381
  };
18473
18382
  function parseList(items, allAvailable) {
18474
18383
  if (!items || items.length === 0) {
@@ -18501,9 +18410,9 @@ function stripJsonComments(json) {
18501
18410
  }
18502
18411
 
18503
18412
  // src/config/schema.ts
18504
- import { z as z2 } from "zod";
18505
- var ProviderModelIdSchema = z2.string().regex(/^[^/\s]+\/[^\s]+$/, "Expected provider/model format (provider/.../model)");
18506
- var ManualAgentPlanSchema = z2.object({
18413
+ import { z } from "zod";
18414
+ var ProviderModelIdSchema = z.string().regex(/^[^/\s]+\/[^\s]+$/, "Expected provider/model format (provider/.../model)");
18415
+ var ManualAgentPlanSchema = z.object({
18507
18416
  primary: ProviderModelIdSchema,
18508
18417
  fallback1: ProviderModelIdSchema,
18509
18418
  fallback2: ProviderModelIdSchema,
@@ -18517,46 +18426,42 @@ var ManualAgentPlanSchema = z2.object({
18517
18426
  ]);
18518
18427
  if (unique.size !== 4) {
18519
18428
  ctx.addIssue({
18520
- code: z2.ZodIssueCode.custom,
18429
+ code: z.ZodIssueCode.custom,
18521
18430
  message: "primary and fallbacks must be unique per agent"
18522
18431
  });
18523
18432
  }
18524
18433
  });
18525
- var ManualPlanSchema = z2.object({
18434
+ var ManualPlanSchema = z.object({
18526
18435
  orchestrator: ManualAgentPlanSchema,
18527
- researcher: ManualAgentPlanSchema,
18528
- reviewer: ManualAgentPlanSchema,
18529
- implementer: ManualAgentPlanSchema
18436
+ researcher: ManualAgentPlanSchema
18530
18437
  }).strict();
18531
- var AgentModelChainSchema = z2.array(z2.string()).min(1);
18532
- var FallbackChainsSchema = z2.object({
18438
+ var AgentModelChainSchema = z.array(z.string()).min(1);
18439
+ var FallbackChainsSchema = z.object({
18533
18440
  orchestrator: AgentModelChainSchema.optional(),
18534
- researcher: AgentModelChainSchema.optional(),
18535
- reviewer: AgentModelChainSchema.optional(),
18536
- implementer: AgentModelChainSchema.optional()
18441
+ researcher: AgentModelChainSchema.optional()
18537
18442
  }).catchall(AgentModelChainSchema);
18538
- var AgentOverrideConfigSchema = z2.object({
18539
- model: z2.union([
18540
- z2.string(),
18541
- z2.array(z2.union([
18542
- z2.string(),
18543
- z2.object({
18544
- id: z2.string(),
18545
- variant: z2.string().optional()
18443
+ var AgentOverrideConfigSchema = z.object({
18444
+ model: z.union([
18445
+ z.string(),
18446
+ z.array(z.union([
18447
+ z.string(),
18448
+ z.object({
18449
+ id: z.string(),
18450
+ variant: z.string().optional()
18546
18451
  })
18547
18452
  ])).min(1)
18548
18453
  ]).optional(),
18549
- temperature: z2.number().min(0).max(2).optional(),
18550
- variant: z2.string().optional().catch(undefined),
18551
- skills: z2.array(z2.string()).optional(),
18552
- mcps: z2.array(z2.string()).optional(),
18553
- prompt: z2.string().min(1).optional(),
18554
- orchestratorPrompt: z2.string().min(1).optional(),
18555
- options: z2.record(z2.string(), z2.unknown()).optional(),
18556
- displayName: z2.string().min(1).optional()
18454
+ temperature: z.number().min(0).max(2).optional(),
18455
+ variant: z.string().optional().catch(undefined),
18456
+ skills: z.array(z.string()).optional(),
18457
+ mcps: z.array(z.string()).optional(),
18458
+ prompt: z.string().min(1).optional(),
18459
+ orchestratorPrompt: z.string().min(1).optional(),
18460
+ options: z.record(z.string(), z.unknown()).optional(),
18461
+ displayName: z.string().min(1).optional()
18557
18462
  }).strict();
18558
- var MultiplexerTypeSchema = z2.enum(["auto", "tmux", "zellij", "none"]);
18559
- var MultiplexerLayoutSchema = z2.enum([
18463
+ var MultiplexerTypeSchema = z.enum(["auto", "tmux", "zellij", "none"]);
18464
+ var MultiplexerLayoutSchema = z.enum([
18560
18465
  "main-horizontal",
18561
18466
  "main-vertical",
18562
18467
  "tiled",
@@ -18564,56 +18469,56 @@ var MultiplexerLayoutSchema = z2.enum([
18564
18469
  "even-vertical"
18565
18470
  ]);
18566
18471
  var TmuxLayoutSchema = MultiplexerLayoutSchema;
18567
- var MultiplexerConfigSchema = z2.object({
18472
+ var MultiplexerConfigSchema = z.object({
18568
18473
  type: MultiplexerTypeSchema.default("none"),
18569
18474
  layout: MultiplexerLayoutSchema.default("main-vertical"),
18570
- main_pane_size: z2.number().min(20).max(80).default(60)
18475
+ main_pane_size: z.number().min(20).max(80).default(60)
18571
18476
  });
18572
- var TmuxConfigSchema = z2.object({
18573
- enabled: z2.boolean().default(false),
18477
+ var TmuxConfigSchema = z.object({
18478
+ enabled: z.boolean().default(false),
18574
18479
  layout: TmuxLayoutSchema.default("main-vertical"),
18575
- main_pane_size: z2.number().min(20).max(80).default(60)
18480
+ main_pane_size: z.number().min(20).max(80).default(60)
18576
18481
  });
18577
- var PresetSchema = z2.record(z2.string(), AgentOverrideConfigSchema);
18578
- var WebsearchConfigSchema = z2.object({
18579
- provider: z2.enum(["exa", "tavily"]).default("exa")
18482
+ var PresetSchema = z.record(z.string(), AgentOverrideConfigSchema);
18483
+ var WebsearchConfigSchema = z.object({
18484
+ provider: z.enum(["exa", "tavily"]).default("exa")
18580
18485
  });
18581
- var McpNameSchema = z2.enum(["websearch", "context7", "grep_app"]);
18582
- var InterviewConfigSchema = z2.object({
18583
- maxQuestions: z2.number().int().min(1).max(10).default(2),
18584
- outputFolder: z2.string().min(1).default("interview"),
18585
- autoOpenBrowser: z2.boolean().default(true).describe("Automatically open the interview UI in your default browser during interactive runs. Disabled automatically in tests and CI."),
18586
- port: z2.number().int().min(0).max(65535).default(0),
18587
- dashboard: z2.boolean().default(false)
18486
+ var McpNameSchema = z.enum(["websearch", "context7", "grep_app"]);
18487
+ var InterviewConfigSchema = z.object({
18488
+ maxQuestions: z.number().int().min(1).max(10).default(2),
18489
+ outputFolder: z.string().min(1).default("interview"),
18490
+ autoOpenBrowser: z.boolean().default(true).describe("Automatically open the interview UI in your default browser during interactive runs. Disabled automatically in tests and CI."),
18491
+ port: z.number().int().min(0).max(65535).default(0),
18492
+ dashboard: z.boolean().default(false)
18588
18493
  });
18589
- var SessionManagerConfigSchema = z2.object({
18590
- maxSessionsPerAgent: z2.number().int().min(1).max(10).default(2),
18591
- readContextMinLines: z2.number().int().min(0).max(1000).default(10),
18592
- readContextMaxFiles: z2.number().int().min(0).max(50).default(8)
18494
+ var SessionManagerConfigSchema = z.object({
18495
+ maxSessionsPerAgent: z.number().int().min(1).max(10).default(2),
18496
+ readContextMinLines: z.number().int().min(0).max(1000).default(10),
18497
+ readContextMaxFiles: z.number().int().min(0).max(50).default(8)
18593
18498
  });
18594
- var DivoomConfigSchema = z2.object({
18595
- enabled: z2.boolean().default(false),
18596
- python: z2.string().min(1).default("/Applications/Divoom MiniToo.app/Contents/Resources/.venv/bin/python"),
18597
- script: z2.string().min(1).default("/Applications/Divoom MiniToo.app/Contents/Resources/tools/divoom_send.py"),
18598
- size: z2.number().int().min(1).max(1024).default(128),
18599
- fps: z2.number().int().min(1).max(60).default(8),
18600
- speed: z2.number().int().min(1).max(1e4).default(125),
18601
- maxFrames: z2.number().int().min(1).max(500).default(24),
18602
- posterizeBits: z2.number().int().min(1).max(8).default(3),
18603
- gifs: z2.record(z2.string(), z2.string().min(1)).optional()
18499
+ var DivoomConfigSchema = z.object({
18500
+ enabled: z.boolean().default(false),
18501
+ python: z.string().min(1).default("/Applications/Divoom MiniToo.app/Contents/Resources/.venv/bin/python"),
18502
+ script: z.string().min(1).default("/Applications/Divoom MiniToo.app/Contents/Resources/tools/divoom_send.py"),
18503
+ size: z.number().int().min(1).max(1024).default(128),
18504
+ fps: z.number().int().min(1).max(60).default(8),
18505
+ speed: z.number().int().min(1).max(1e4).default(125),
18506
+ maxFrames: z.number().int().min(1).max(500).default(24),
18507
+ posterizeBits: z.number().int().min(1).max(8).default(3),
18508
+ gifs: z.record(z.string(), z.string().min(1)).optional()
18604
18509
  });
18605
- var TodoContinuationConfigSchema = z2.object({
18606
- maxContinuations: z2.number().int().min(1).max(50).default(5).describe("Maximum consecutive auto-continuations before stopping to ask user"),
18607
- cooldownMs: z2.number().int().min(0).max(30000).default(3000).describe("Delay in ms before auto-continuing (gives user time to abort)"),
18608
- autoEnable: z2.boolean().default(false).describe("Automatically enable auto-continue when the orchestrator session has enough todos"),
18609
- autoEnableThreshold: z2.number().int().min(1).max(50).default(4).describe("Number of todos that triggers auto-enable (only used when autoEnable is true)")
18510
+ var TodoContinuationConfigSchema = z.object({
18511
+ maxContinuations: z.number().int().min(1).max(50).default(5).describe("Maximum consecutive auto-continuations before stopping to ask user"),
18512
+ cooldownMs: z.number().int().min(0).max(30000).default(3000).describe("Delay in ms before auto-continuing (gives user time to abort)"),
18513
+ autoEnable: z.boolean().default(false).describe("Automatically enable auto-continue when the orchestrator session has enough todos"),
18514
+ autoEnableThreshold: z.number().int().min(1).max(50).default(4).describe("Number of todos that triggers auto-enable (only used when autoEnable is true)")
18610
18515
  });
18611
- var FailoverConfigSchema = z2.object({
18612
- enabled: z2.boolean().default(true),
18613
- timeoutMs: z2.number().min(0).default(15000),
18614
- retryDelayMs: z2.number().min(0).default(500),
18516
+ var FailoverConfigSchema = z.object({
18517
+ enabled: z.boolean().default(true),
18518
+ timeoutMs: z.number().min(0).default(15000),
18519
+ retryDelayMs: z.number().min(0).default(500),
18615
18520
  chains: FallbackChainsSchema.default({}),
18616
- 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.")
18521
+ 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.")
18617
18522
  });
18618
18523
  function validateCustomOnlyPromptFields(overrides, ctx, pathPrefix) {
18619
18524
  for (const [name, override] of Object.entries(overrides)) {
@@ -18623,31 +18528,31 @@ function validateCustomOnlyPromptFields(overrides, ctx, pathPrefix) {
18623
18528
  }
18624
18529
  if (override.prompt !== undefined) {
18625
18530
  ctx.addIssue({
18626
- code: z2.ZodIssueCode.custom,
18531
+ code: z.ZodIssueCode.custom,
18627
18532
  path: [...pathPrefix, name, "prompt"],
18628
18533
  message: "prompt is only supported for custom agents"
18629
18534
  });
18630
18535
  }
18631
18536
  if (override.orchestratorPrompt !== undefined) {
18632
18537
  ctx.addIssue({
18633
- code: z2.ZodIssueCode.custom,
18538
+ code: z.ZodIssueCode.custom,
18634
18539
  path: [...pathPrefix, name, "orchestratorPrompt"],
18635
18540
  message: "orchestratorPrompt is only supported for custom agents"
18636
18541
  });
18637
18542
  }
18638
18543
  }
18639
18544
  }
18640
- var PluginConfigSchema = z2.object({
18641
- preset: z2.string().optional(),
18642
- setDefaultAgent: z2.boolean().optional(),
18643
- scoringEngineVersion: z2.enum(["v1", "v2-shadow", "v2"]).optional(),
18644
- balanceProviderUsage: z2.boolean().optional(),
18645
- autoUpdate: z2.boolean().optional().describe("Disable automatic installation of plugin updates when false. Defaults to true."),
18545
+ var PluginConfigSchema = z.object({
18546
+ preset: z.string().optional(),
18547
+ setDefaultAgent: z.boolean().optional(),
18548
+ scoringEngineVersion: z.enum(["v1", "v2-shadow", "v2"]).optional(),
18549
+ balanceProviderUsage: z.boolean().optional(),
18550
+ autoUpdate: z.boolean().optional().describe("Disable automatic installation of plugin updates when false. Defaults to true."),
18646
18551
  manualPlan: ManualPlanSchema.optional(),
18647
- presets: z2.record(z2.string(), PresetSchema).optional(),
18648
- agents: z2.record(z2.string(), AgentOverrideConfigSchema).optional(),
18649
- disabled_agents: z2.array(z2.string()).optional().describe("Agent names to disable completely. " + "Disabled agents are not instantiated and cannot be delegated to. " + "Orchestrator, researcher, reviewer, implementer and council internal agents (councillor) cannot be disabled. " + "By default, only council is disabled."),
18650
- disabled_mcps: z2.array(z2.string()).optional(),
18552
+ presets: z.record(z.string(), PresetSchema).optional(),
18553
+ agents: z.record(z.string(), AgentOverrideConfigSchema).optional(),
18554
+ disabled_agents: z.array(z.string()).optional().describe("Agent names to disable completely. " + "Disabled agents are not instantiated and cannot be delegated to. " + "Orchestrator and researcher cannot be disabled."),
18555
+ disabled_mcps: z.array(z.string()).optional(),
18651
18556
  multiplexer: MultiplexerConfigSchema.optional(),
18652
18557
  tmux: TmuxConfigSchema.optional(),
18653
18558
  websearch: WebsearchConfigSchema.optional(),
@@ -18655,8 +18560,7 @@ var PluginConfigSchema = z2.object({
18655
18560
  sessionManager: SessionManagerConfigSchema.optional(),
18656
18561
  divoom: DivoomConfigSchema.optional(),
18657
18562
  todoContinuation: TodoContinuationConfigSchema.optional(),
18658
- fallback: FailoverConfigSchema.optional(),
18659
- council: CouncilConfigSchema.optional()
18563
+ fallback: FailoverConfigSchema.optional()
18660
18564
  }).superRefine((value, ctx) => {
18661
18565
  if (value.agents) {
18662
18566
  validateCustomOnlyPromptFields(value.agents, ctx, ["agents"]);
@@ -18724,8 +18628,7 @@ function mergePluginConfigs(base, override) {
18724
18628
  interview: deepMerge(base.interview, override.interview),
18725
18629
  sessionManager: deepMerge(base.sessionManager, override.sessionManager),
18726
18630
  divoom: deepMerge(base.divoom, override.divoom),
18727
- fallback: deepMerge(base.fallback, override.fallback),
18728
- council: deepMerge(base.council, override.council)
18631
+ fallback: deepMerge(base.fallback, override.fallback)
18729
18632
  };
18730
18633
  }
18731
18634
  function deepMerge(base, override) {
@@ -18821,99 +18724,6 @@ function getCustomAgentNames(config) {
18821
18724
  return !ALL_AGENT_NAMES.includes(name);
18822
18725
  });
18823
18726
  }
18824
- // src/utils/session.ts
18825
- var SESSION_ABORT_TIMEOUT_MS = 1000;
18826
-
18827
- class OperationTimeoutError extends Error {
18828
- constructor(message) {
18829
- super(message);
18830
- this.name = "OperationTimeoutError";
18831
- }
18832
- }
18833
- async function withTimeout(operation, timeoutMs, message) {
18834
- if (timeoutMs <= 0)
18835
- return operation;
18836
- let timer;
18837
- try {
18838
- return await Promise.race([
18839
- operation,
18840
- new Promise((_, reject) => {
18841
- timer = setTimeout(() => {
18842
- reject(new OperationTimeoutError(message));
18843
- }, timeoutMs);
18844
- })
18845
- ]);
18846
- } finally {
18847
- clearTimeout(timer);
18848
- }
18849
- }
18850
- async function abortSessionWithTimeout(client, sessionId, timeoutMs = SESSION_ABORT_TIMEOUT_MS) {
18851
- await withTimeout(client.session.abort({ path: { id: sessionId } }), timeoutMs, `Session abort timed out after ${timeoutMs}ms`);
18852
- }
18853
- function shortModelLabel(model) {
18854
- return model.split("/").pop() ?? model;
18855
- }
18856
- function parseModelReference(model) {
18857
- const slashIndex = model.indexOf("/");
18858
- if (slashIndex <= 0 || slashIndex >= model.length - 1) {
18859
- return null;
18860
- }
18861
- return {
18862
- providerID: model.slice(0, slashIndex),
18863
- modelID: model.slice(slashIndex + 1)
18864
- };
18865
- }
18866
- async function promptWithTimeout(client, args, timeoutMs) {
18867
- if (timeoutMs <= 0) {
18868
- await client.session.prompt(args);
18869
- return;
18870
- }
18871
- const sessionId = args.path.id;
18872
- let timer;
18873
- try {
18874
- const promptPromise = client.session.prompt(args);
18875
- promptPromise.catch(() => {});
18876
- await Promise.race([
18877
- promptPromise,
18878
- new Promise((_, reject) => {
18879
- timer = setTimeout(() => {
18880
- reject(new OperationTimeoutError(`Prompt timed out after ${timeoutMs}ms`));
18881
- }, timeoutMs);
18882
- })
18883
- ]);
18884
- } catch (error) {
18885
- if (error instanceof OperationTimeoutError) {
18886
- try {
18887
- await abortSessionWithTimeout(client, sessionId);
18888
- } catch {}
18889
- }
18890
- throw error;
18891
- } finally {
18892
- clearTimeout(timer);
18893
- }
18894
- }
18895
- async function extractSessionResult(client, sessionId, options) {
18896
- const includeReasoning = options?.includeReasoning ?? true;
18897
- const messagesResult = await client.session.messages({
18898
- path: { id: sessionId }
18899
- });
18900
- const messages = messagesResult.data ?? [];
18901
- const assistantMessages = messages.filter((m) => m.info?.role === "assistant");
18902
- const extractedContent = [];
18903
- for (const message of assistantMessages) {
18904
- for (const part of message.parts ?? []) {
18905
- const allowed = includeReasoning ? part.type === "text" || part.type === "reasoning" : part.type === "text";
18906
- if (allowed && part.text) {
18907
- extractedContent.push(part.text);
18908
- }
18909
- }
18910
- }
18911
- const text = extractedContent.filter((t) => t.length > 0).join(`
18912
-
18913
- `);
18914
- return { text, empty: text.length === 0 };
18915
- }
18916
-
18917
18727
  // src/agents/orchestrator.ts
18918
18728
  function resolvePrompt(base, customPrompt, customAppendPrompt) {
18919
18729
  if (customPrompt)
@@ -18930,33 +18740,13 @@ var AGENT_DESCRIPTIONS = {
18930
18740
  - 权限:只读
18931
18741
  - 能力:本地代码搜索(glob/grep/ast)+ 外部文档检索(websearch/context7/grep_app)
18932
18742
  - 委派给它当:需要发现代码库中有什么 • 需要查外部库文档 • 并行搜索加速发现
18933
- - 不委派当:知道路径需要实际内容 • 单次特定查找 • 即将编辑该文件`,
18934
- reviewer: `@reviewer
18935
- - 角色:战略顾问、代码审查者、调试专家
18936
- - 权限:只读(分析),写操作由 Orchestrator 协调 @implementer 执行
18937
- - 能力:深度推理、架构分析、根因追踪、代码审查
18938
- - 委派给它当:重大架构决策 • 复杂调试分析(Phase 1-3)• 代码审查 • 简化/YAGNI 审查
18939
- - 不委派当:常规决策 • 首次 bug 修复 • 简单权衡
18940
- - 协调模式:Reviewer 输出 <fix_plan> 时,委派 @implementer 执行修复`,
18941
- implementer: `@implementer
18942
- - 角色:快速执行专家
18943
- - 权限:读写
18944
- - 能力:代码实现、测试编写、UI/UX 实现
18945
- - 委派给它当:非平凡的实现任务 • 测试编写/更新 • 多文件修改
18946
- - 不委派当:需要研究/决策 • 单个小变更(<20 行)• 需求不清楚`,
18947
- council: `@council(可选,默认禁用)
18948
- - 角色:多 LLM 共识引擎`
18743
+ - 不委派当:知道路径需要实际内容 • 单次特定查找 • 即将编辑该文件`
18949
18744
  };
18950
18745
  var DELEGATION_RULES = [
18951
18746
  "- 需要搜索代码库或外部文档 → @researcher",
18952
- "- 需要代码审查、架构决策、调试分析@reviewer(只读,修复方案由 @implementer 执行)",
18953
- "- 非平凡的实现任务@implementer(UI 任务注明 [设计模式])",
18954
- "- Reviewer 输出 fix_plan 时 委派 @implementer 执行修复",
18955
- "- 知道路径需要内容 → 自己读",
18956
- "- 单个小变更(<20 行)→ 自己做",
18957
- "- 需求不清楚 → 问用户,不委派",
18958
- "- 跳过委派如果开销 ≥ 自己做(Skill 定义的审查流程除外)",
18959
- "- brainstorming HARD-GATE:设计未批准前,委派任务必须标注 [只读-搜索],禁止委派写入任务"
18747
+ "- 其他所有工作加载对应 Skill,按 Skill 定义的流程执行",
18748
+ "- 单个小变更(<20行)且不涉及设计决策可直接执行",
18749
+ "- 需求不清楚问用户,不委派"
18960
18750
  ];
18961
18751
  function buildOrchestratorPrompt(disabledAgents) {
18962
18752
  const enabledAgents = Object.entries(AGENT_DESCRIPTIONS).filter(([name]) => !disabledAgents?.has(name)).map(([, desc]) => desc).join(`
@@ -18997,13 +18787,10 @@ ${enabledAgents}
18997
18787
  <Workflow>
18998
18788
  1. 理解需求 → 加载 brainstorming skill(如需要)
18999
18789
  2. 制定计划 → 加载 writing-plans skill(如需要)
19000
- 3. 委派执行 → 加载 subagent-driven-development skill
19001
- ├─ 实现任务 → 委派 @implementer
19002
- ├─ 代码审查 → 委派 @reviewer(只读分析)
19003
- │ └─ 需要修复 → 委派 @implementer(执行修复)
18790
+ 3. 执行实现 → 加载 subagent-driven-development skill
18791
+ ├─ 实现任务 → 委派 implementer subagent
19004
18792
  ├─ 代码搜索 → 委派 @researcher
19005
- └─ 调试分析 → 委派 @reviewer(Phase 1-3)
19006
- └─ 需要修复 → 委派 @implementer(Phase 4 执行)
18793
+ └─ 审查 → 委派 spec/code quality reviewer subagent
19007
18794
  4. 验证完成 → 加载 verification-before-completion skill
19008
18795
  5. 收尾 → 加载 finishing-a-development-branch skill
19009
18796
  </Workflow>
@@ -19064,236 +18851,6 @@ function createOrchestratorAgent(model, customPrompt, customAppendPrompt, disabl
19064
18851
  return definition;
19065
18852
  }
19066
18853
 
19067
- // src/agents/council.ts
19068
- var COUNCIL_AGENT_PROMPT = `You are the Council agent — a multi-LLM orchestration system that runs consensus across multiple models.
19069
-
19070
- **Tool**: You have access to the \`council_session\` tool.
19071
-
19072
- **When to use**:
19073
- - When invoked by a user with a request
19074
- - When you want multiple expert opinions on a complex problem
19075
- - When higher confidence is needed through model consensus
19076
-
19077
- **Usage**:
19078
- 1. Call the \`council_session\` tool with the user's prompt
19079
- 2. Optionally specify a preset (default: "default")
19080
- 3. Receive the councillor responses formatted for synthesis
19081
- 4. Follow the Synthesis Process below
19082
- 5. Present the result to the user
19083
-
19084
- **Synthesis Process** (MANDATORY — follow in order):
19085
- 1. Read the original user prompt
19086
- 2. Review each councillor's response individually — note each councillor's key insight and unique contribution by name
19087
- 3. Identify agreements and contradictions between councillors
19088
- 4. Resolve contradictions with explicit reasoning
19089
- 5. Synthesize the optimal final answer
19090
- 6. Format output per the Required Output Format below
19091
-
19092
- **Behavior**:
19093
- - Delegate requests directly to council_session
19094
- - Don't pre-analyze or filter the prompt before calling council_session
19095
- - Credit specific insights from individual councillors using their names
19096
- - If councillors disagree, explain why you chose one approach over another
19097
- - Do not omit per-councillor details from the final response
19098
- - Do not collapse the output into only a final summary
19099
- - Be transparent about trade-offs when different approaches have valid pros/cons
19100
- - Don't just average responses — choose the best approach and improve upon it
19101
-
19102
- **Required Output Format**:
19103
- Always include these sections in your final response:
19104
-
19105
- ## Council Response
19106
- 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.
19107
-
19108
- ## Councillor Details
19109
- Include each councillor's response separately.
19110
-
19111
- Use each councillor name exactly as provided in the tool result.
19112
-
19113
- Format each councillor like:
19114
-
19115
- ### <councillor name>
19116
- <that councillor's response>
19117
-
19118
- If a councillor failed or timed out, include that status briefly.
19119
-
19120
- ## Council Summary
19121
- 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.`;
19122
- function createCouncilAgent(model, customPrompt, customAppendPrompt) {
19123
- const prompt = resolvePrompt(COUNCIL_AGENT_PROMPT, customPrompt, customAppendPrompt);
19124
- const definition = {
19125
- name: "council",
19126
- description: "Multi-LLM council agent that synthesizes responses from multiple models for higher-quality outputs",
19127
- config: {
19128
- temperature: 0.1,
19129
- prompt
19130
- }
19131
- };
19132
- if (model) {
19133
- definition.config.model = model;
19134
- }
19135
- return definition;
19136
- }
19137
- function formatCouncillorPrompt(userPrompt, councillorPrompt) {
19138
- if (!councillorPrompt)
19139
- return userPrompt;
19140
- return `${councillorPrompt}
19141
-
19142
- ---
19143
-
19144
- ${userPrompt}`;
19145
- }
19146
- function formatCouncillorResults(originalPrompt, councillorResults) {
19147
- const completedWithResults = councillorResults.filter((cr) => cr.status === "completed" && cr.result);
19148
- const councillorSection = completedWithResults.map((cr) => {
19149
- const shortModel = shortModelLabel(cr.model);
19150
- return `**${cr.name}** (${shortModel}):
19151
- ${cr.result}`;
19152
- }).join(`
19153
-
19154
- `);
19155
- const failedSection = councillorResults.filter((cr) => cr.status !== "completed").map((cr) => `**${cr.name}**: ${cr.status} — ${cr.error ?? "Unknown"}`).join(`
19156
- `);
19157
- if (completedWithResults.length === 0) {
19158
- const errorDetails = councillorResults.map((cr) => `**${cr.name}** (${shortModelLabel(cr.model)}): ${cr.status} — ${cr.error ?? "Unknown"}`).join(`
19159
- `);
19160
- return `---
19161
-
19162
- **Original Prompt**:
19163
- ${originalPrompt}
19164
-
19165
- ---
19166
-
19167
- **Councillor Responses**:
19168
- All councillors failed to produce output:
19169
- ${errorDetails}
19170
-
19171
- Please generate a response based on the original prompt alone.`;
19172
- }
19173
- let prompt = `---
19174
-
19175
- **Original Prompt**:
19176
- ${originalPrompt}
19177
-
19178
- ---
19179
-
19180
- **Councillor Responses**:
19181
- ${councillorSection}`;
19182
- if (failedSection) {
19183
- prompt += `
19184
-
19185
- ---
19186
-
19187
- **Failed/Timed-out Councillors**:
19188
- ${failedSection}`;
19189
- }
19190
- prompt += `
19191
-
19192
- ---
19193
-
19194
- 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).`;
19195
- return prompt;
19196
- }
19197
-
19198
- // src/agents/councillor.ts
19199
- var COUNCILLOR_PROMPT = `You are a councillor in a multi-model council.
19200
-
19201
- **Role**: Provide your best independent analysis and solution to the given problem.
19202
-
19203
- **Capabilities**: You have read-only access to the codebase. You can:
19204
- - Read files (read)
19205
- - Search by name patterns (glob)
19206
- - Search by content (grep)
19207
- - Search code patterns (ast_grep_search)
19208
- - Use OpenCode's built-in \`lsp\` tool when available
19209
- - Search external docs (if MCPs are configured for this agent)
19210
-
19211
- You CANNOT edit files, write files, run shell commands, or delegate to other agents. You are an advisor, not an implementer.
19212
-
19213
- **Behavior**:
19214
- - **Examine the codebase** before answering — your read access is what makes council valuable. Don't guess at code you can see.
19215
- - Analyze the problem thoroughly
19216
- - Provide a complete, well-reasoned response
19217
- - Focus on the quality and correctness of your solution
19218
- - Be direct and concise
19219
- - Don't be influenced by what other councillors might say — you won't see their responses
19220
-
19221
- **Output**:
19222
- - Give your honest assessment
19223
- - Reference specific files and line numbers when relevant
19224
- - Include relevant reasoning
19225
- - State any assumptions clearly
19226
- - Note any uncertainties`;
19227
- function createCouncillorAgent(model, customPrompt, customAppendPrompt) {
19228
- const prompt = resolvePrompt(COUNCILLOR_PROMPT, customPrompt, customAppendPrompt);
19229
- return {
19230
- name: "councillor",
19231
- description: "Read-only council advisor. Examines codebase and provides independent analysis. Spawned internally by the council system.",
19232
- config: {
19233
- model,
19234
- temperature: 0.2,
19235
- prompt,
19236
- permission: {
19237
- "*": "deny",
19238
- question: "deny",
19239
- read: "allow",
19240
- glob: "allow",
19241
- grep: "allow",
19242
- lsp: "allow",
19243
- list: "allow",
19244
- codesearch: "allow",
19245
- ast_grep_search: "allow"
19246
- }
19247
- }
19248
- };
19249
- }
19250
-
19251
- // src/agents/implementer.ts
19252
- var IMPLEMENTER_PROMPT = `You are Implementer — a fast execution specialist. Execute directly with complete context provided.
19253
-
19254
- **Role**: Receive complete task specs from the Orchestrator and implement efficiently.
19255
-
19256
- ## Modes
19257
- - **Execution Mode (default)**: Low-temperature precise execution. No divergence, no research. Implement the task directly.
19258
- - **Design Mode**: When Orchestrator marks [设计模式] in the prompt, switch to creative design thinking:
19259
- - Focus on aesthetics, layout, interaction details
19260
- - Follow design principles: typography, color themes, motion, spatial composition, visual depth
19261
- - Use Tailwind for responsive design
19262
-
19263
- ## Constraints
19264
- - NO external research (no websearch, context7, grep_app)
19265
- - NO delegation or spawning subagents
19266
- - No multi-step planning; direct execution
19267
- - When a loaded Skill indicates user input is needed, pause and request clarification
19268
- - When TDD Skill is loaded, follow red-green-refactor cycle
19269
-
19270
- ## Loadable Skills
19271
- You can load behavioral guides via the skill tool:
19272
- - test-driven-development: Load when implementing features or fixing bugs
19273
- - verification-before-completion: Load when verifying work before completion
19274
-
19275
- ## Output Format
19276
- <summary>Brief summary of what was implemented</summary>
19277
- <changes>
19278
- <file>file1.ts: Changed X to Y</file>
19279
- <file>file2.ts: Added Z function</file>
19280
- </changes>
19281
- <verification>
19282
- Tests passed: [yes/no/skip reason]
19283
- Validation: [passed/failed/skip reason]
19284
- </verification>`;
19285
- function createImplementerAgent(model, customPrompt, customAppendPrompt) {
19286
- return {
19287
- name: "implementer",
19288
- description: "Fast implementation specialist. Receives complete context and task spec, executes code changes efficiently. Supports execution and design modes.",
19289
- config: {
19290
- model,
19291
- temperature: 0.2,
19292
- prompt: resolvePrompt(IMPLEMENTER_PROMPT, customPrompt, customAppendPrompt)
19293
- }
19294
- };
19295
- }
19296
-
19297
18854
  // src/agents/researcher.ts
19298
18855
  var RESEARCHER_PROMPT = `You are Researcher — a codebase and external documentation search specialist.
19299
18856
 
@@ -19336,62 +18893,7 @@ function createResearcherAgent(model, customPrompt, customAppendPrompt) {
19336
18893
  };
19337
18894
  }
19338
18895
 
19339
- // src/agents/reviewer.ts
19340
- var REVIEWER_PROMPT = `You are Reviewer — a strategic advisor and code review expert. Analysis only, no execution.
19341
-
19342
- **Role**: High-IQ debugging, architecture decisions, code review, simplification, and engineering guidance.
19343
-
19344
- ## Responsibilities
19345
- - Architecture decisions and solution evaluation
19346
- - Code review (review diffs, not self-review)
19347
- - Root cause analysis for complex debugging (Phase 1-3)
19348
- - Simplification and YAGNI review
19349
-
19350
- ## Execution Boundary
19351
- You only analyze, never execute. When a Skill workflow requires writing code or running commands:
19352
- - Complete the analysis phase, output structured analysis results and fix plans
19353
- - Orchestrator coordinates Implementer to execute fixes
19354
- - Specific rules:
19355
- - systematic-debugging: You complete Phase 1-3, output fix plan for Phase 4
19356
- - receiving-code-review: You complete READ → VERIFY → EVALUATE, output fix plan for IMPLEMENT
19357
- - simplify: You analyze simplification opportunities, output plan for execution
19358
-
19359
- ## Principles
19360
- - Hold dissenting opinions until convinced by technical arguments
19361
- - Verify before agreeing — no performative agreement
19362
- - 3+ fix failures → question the architecture, don't keep patching
19363
- - receiving-code-review: explicitly forbidden from expressions of gratitude (e.g., "You're absolutely right!", "Great point!") — avoid performative agreement, go straight to technical verification
19364
-
19365
- ## Loadable Skills
19366
- You can load behavioral guides via the skill tool:
19367
- - systematic-debugging: Load when debugging complex bugs (Phase 1-3 analysis)
19368
- - receiving-code-review: Load when evaluating external feedback (READ → VERIFY → EVALUATE)
19369
- - simplify: Load when reviewing code for simplification (analyze opportunities, output plan)
19370
-
19371
- ## Output Format
19372
- <assessment>Overall assessment</assessment>
19373
- <strengths>What was done well</strengths>
19374
- <issues>
19375
- <issue severity="critical">Must-fix issues</issue>
19376
- <issue severity="important">Should-fix issues</issue>
19377
- <issue severity="minor">Nice-to-have improvements</issue>
19378
- </issues>
19379
- <fix_plan>Fix plan for Orchestrator to coordinate Implementer execution</fix_plan>
19380
- <recommendation>Recommended next steps</recommendation>`;
19381
- function createReviewerAgent(model, customPrompt, customAppendPrompt) {
19382
- return {
19383
- name: "reviewer",
19384
- description: "Strategic technical advisor. Use for architecture decisions, complex debugging, code review, simplification, and engineering guidance.",
19385
- config: {
19386
- model,
19387
- temperature: 0.1,
19388
- prompt: resolvePrompt(REVIEWER_PROMPT, customPrompt, customAppendPrompt)
19389
- }
19390
- };
19391
- }
19392
-
19393
18896
  // src/agents/index.ts
19394
- var COUNCIL_TOOL_ALLOWED_AGENTS = new Set(["council"]);
19395
18897
  var SAFE_AGENT_ALIAS_RE = /^[a-z][a-z0-9_-]*$/i;
19396
18898
  function normalizeDisplayName(displayName) {
19397
18899
  const trimmed = displayName.trim();
@@ -19446,7 +18948,7 @@ function buildCustomAgentDefinition(name, override, filePrompt, fileAppendPrompt
19446
18948
  return {
19447
18949
  name,
19448
18950
  config: {
19449
- model: typeof override.model === "string" ? override.model : DEFAULT_MODELS.orchestrator ?? DEFAULT_MODELS.reviewer,
18951
+ model: typeof override.model === "string" ? override.model : DEFAULT_MODELS.orchestrator ?? DEFAULT_MODELS.researcher,
19450
18952
  temperature: 0.2,
19451
18953
  prompt: resolvePrompt(basePrompt, filePrompt, fileAppendPrompt)
19452
18954
  }
@@ -19467,11 +18969,9 @@ function applyDefaultPermissions(agent, configuredSkills) {
19467
18969
  const existing = agent.config.permission ?? {};
19468
18970
  const skillPermissions = getSkillPermissionsForAgent(agent.name, configuredSkills);
19469
18971
  const questionPerm = existing.question === "deny" ? "deny" : "allow";
19470
- const councilSessionPerm = COUNCIL_TOOL_ALLOWED_AGENTS.has(agent.name) ? existing.council_session ?? "allow" : "deny";
19471
18972
  agent.config.permission = {
19472
18973
  ...existing,
19473
18974
  question: questionPerm,
19474
- council_session: councilSessionPerm,
19475
18975
  skill: {
19476
18976
  ...typeof existing.skill === "object" ? existing.skill : {},
19477
18977
  ...skillPermissions
@@ -19482,17 +18982,10 @@ function isSubagent(name) {
19482
18982
  return SUBAGENT_NAMES.includes(name);
19483
18983
  }
19484
18984
  var SUBAGENT_FACTORIES = {
19485
- researcher: createResearcherAgent,
19486
- reviewer: createReviewerAgent,
19487
- implementer: createImplementerAgent,
19488
- council: createCouncilAgent,
19489
- councillor: createCouncillorAgent
18985
+ researcher: createResearcherAgent
19490
18986
  };
19491
18987
  function createAgents(config) {
19492
18988
  const disabled = getDisabledAgents(config);
19493
- if (!config?.council) {
19494
- disabled.add("council");
19495
- }
19496
18989
  const protoSubAgents = Object.entries(SUBAGENT_FACTORIES).filter(([name]) => !disabled.has(name)).map(([name, factory]) => {
19497
18990
  const customPrompts = loadAgentPrompt(name, config?.preset);
19498
18991
  const model = DEFAULT_MODELS[name];
@@ -19526,13 +19019,6 @@ function createAgents(config) {
19526
19019
  applyDefaultPermissions(agent, override?.skills);
19527
19020
  return agent;
19528
19021
  });
19529
- const legacyMasterModel = config?.council?._legacyMasterModel;
19530
- if (legacyMasterModel) {
19531
- const councilAgent = builtInSubAgents.find((a) => a.name === "council");
19532
- if (councilAgent && !getAgentOverride(config, "council")?.model && councilAgent.config.model === DEFAULT_MODELS.council) {
19533
- councilAgent.config.model = legacyMasterModel;
19534
- }
19535
- }
19536
19022
  const customSubAgents = protoCustomAgents.map((agent) => {
19537
19023
  const override = getAgentOverride(config, agent.name);
19538
19024
  if (override) {
@@ -19599,12 +19085,7 @@ ${rewrittenPrompts.join(`
19599
19085
  function getAgentConfigs(config) {
19600
19086
  const agents = createAgents(config);
19601
19087
  const applyClassification = (name, sdkConfig) => {
19602
- if (name === "council") {
19603
- sdkConfig.mode = "all";
19604
- } else if (name === "councillor") {
19605
- sdkConfig.mode = "subagent";
19606
- sdkConfig.hidden = true;
19607
- } else if (isSubagent(name)) {
19088
+ if (isSubagent(name)) {
19608
19089
  sdkConfig.mode = "subagent";
19609
19090
  } else if (name === "orchestrator") {
19610
19091
  sdkConfig.mode = "primary";
@@ -19612,7 +19093,6 @@ function getAgentConfigs(config) {
19612
19093
  sdkConfig.mode = "subagent";
19613
19094
  }
19614
19095
  };
19615
- const isInternalOnly = (name) => name === "councillor";
19616
19096
  const entries = [];
19617
19097
  for (const a of agents) {
19618
19098
  const sdkConfig = {
@@ -19625,7 +19105,7 @@ function getAgentConfigs(config) {
19625
19105
  }
19626
19106
  applyClassification(a.name, sdkConfig);
19627
19107
  const normalizedDisplayName = a.displayName ? normalizeDisplayName(a.displayName) : undefined;
19628
- if (normalizedDisplayName && !isInternalOnly(a.name)) {
19108
+ if (normalizedDisplayName) {
19629
19109
  entries.push([normalizedDisplayName, sdkConfig]);
19630
19110
  entries.push([a.name, { ...sdkConfig, hidden: true }]);
19631
19111
  continue;
@@ -19667,6 +19147,13 @@ function rollbackRuntimePreset(previous) {
19667
19147
  previousRuntimePreset = null;
19668
19148
  }
19669
19149
 
19150
+ // src/divoom/manager.ts
19151
+ import { spawn } from "node:child_process";
19152
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "node:fs";
19153
+ import * as os2 from "node:os";
19154
+ import path3 from "node:path";
19155
+ import { fileURLToPath } from "node:url";
19156
+
19670
19157
  // src/utils/logger.ts
19671
19158
  import * as fs2 from "node:fs";
19672
19159
  import { appendFile } from "node:fs/promises";
@@ -19744,263 +19231,7 @@ function log(message, data) {
19744
19231
  } catch {}
19745
19232
  }
19746
19233
 
19747
- // src/council/council-manager.ts
19748
- class CouncilManager {
19749
- client;
19750
- directory;
19751
- config;
19752
- depthTracker;
19753
- tmuxEnabled;
19754
- deprecatedFields;
19755
- legacyMasterModel;
19756
- constructor(ctx, config, depthTracker, tmuxEnabled = false) {
19757
- this.client = ctx.client;
19758
- this.directory = ctx.directory;
19759
- this.config = config;
19760
- this.deprecatedFields = config?.council?._deprecated;
19761
- this.legacyMasterModel = config?.council?._legacyMasterModel;
19762
- this.depthTracker = depthTracker;
19763
- this.tmuxEnabled = tmuxEnabled;
19764
- }
19765
- getDeprecatedFields() {
19766
- return this.deprecatedFields;
19767
- }
19768
- getLegacyMasterModel() {
19769
- return this.legacyMasterModel;
19770
- }
19771
- async runCouncil(prompt, presetName, parentSessionId) {
19772
- if (this.depthTracker) {
19773
- const parentDepth = this.depthTracker.getDepth(parentSessionId);
19774
- if (parentDepth + 1 > this.depthTracker.maxDepth) {
19775
- log("[council-manager] spawn blocked: max depth exceeded", {
19776
- parentSessionId,
19777
- parentDepth,
19778
- maxDepth: this.depthTracker.maxDepth
19779
- });
19780
- return {
19781
- success: false,
19782
- error: "Subagent depth exceeded",
19783
- councillorResults: []
19784
- };
19785
- }
19786
- }
19787
- const councilConfig = this.config?.council;
19788
- if (!councilConfig) {
19789
- log("[council-manager] Council configuration not found");
19790
- return {
19791
- success: false,
19792
- error: "Council not configured",
19793
- councillorResults: []
19794
- };
19795
- }
19796
- const resolvedPreset = presetName ?? councilConfig.default_preset ?? "default";
19797
- const preset = councilConfig.presets[resolvedPreset];
19798
- if (!preset) {
19799
- const available = Object.keys(councilConfig.presets).join(", ");
19800
- log(`[council-manager] Preset "${resolvedPreset}" not found`);
19801
- return {
19802
- success: false,
19803
- error: `Preset "${resolvedPreset}" does not exist. Omit the preset parameter to use the default, or call again with one of: ${available}`,
19804
- councillorResults: []
19805
- };
19806
- }
19807
- if (Object.keys(preset).length === 0) {
19808
- log(`[council-manager] Preset "${resolvedPreset}" has no councillors`);
19809
- return {
19810
- success: false,
19811
- error: `Preset "${resolvedPreset}" has no councillors configured. Note: the reserved key "master" is ignored — use councillor names as keys`,
19812
- councillorResults: []
19813
- };
19814
- }
19815
- const timeout = councilConfig.timeout ?? 180000;
19816
- const executionMode = councilConfig.councillor_execution_mode ?? "parallel";
19817
- const maxRetries = councilConfig.councillor_retries ?? 3;
19818
- const councillorCount = Object.keys(preset).length;
19819
- log(`[council-manager] Starting council with preset "${resolvedPreset}"`, {
19820
- councillors: Object.keys(preset)
19821
- });
19822
- this.sendStartNotification(parentSessionId, councillorCount).catch((err) => {
19823
- log("[council-manager] Failed to send start notification", {
19824
- error: err instanceof Error ? err.message : String(err)
19825
- });
19826
- });
19827
- const councillorResults = await this.runCouncillors(prompt, preset, parentSessionId, timeout, executionMode, maxRetries);
19828
- const completedCount = councillorResults.filter((r) => r.status === "completed").length;
19829
- log(`[council-manager] Councillors completed: ${completedCount}/${councillorResults.length}`);
19830
- if (completedCount === 0) {
19831
- return {
19832
- success: false,
19833
- error: "All councillors failed or timed out",
19834
- councillorResults
19835
- };
19836
- }
19837
- const formattedCouncillorResults = formatCouncillorResults(prompt, councillorResults);
19838
- log("[council-manager] Council completed successfully");
19839
- return {
19840
- success: true,
19841
- result: formattedCouncillorResults,
19842
- councillorResults
19843
- };
19844
- }
19845
- async sendStartNotification(parentSessionId, councillorCount) {
19846
- const message = [
19847
- `⎔ Council starting — ${councillorCount} councillors launching — ctrl+x ↓ to watch`,
19848
- "",
19849
- "[system status: continue without acknowledging this notification]"
19850
- ].join(`
19851
- `);
19852
- await this.client.session.prompt({
19853
- path: { id: parentSessionId },
19854
- body: {
19855
- noReply: true,
19856
- parts: [{ type: "text", text: message }]
19857
- }
19858
- });
19859
- }
19860
- async runAgentSession(options) {
19861
- const modelRef = parseModelReference(options.model);
19862
- if (!modelRef) {
19863
- throw new Error(`Invalid model format: ${options.model}`);
19864
- }
19865
- let sessionId;
19866
- try {
19867
- const session = await this.client.session.create({
19868
- body: {
19869
- parentID: options.parentSessionId,
19870
- title: options.title
19871
- },
19872
- query: { directory: this.directory }
19873
- });
19874
- if (!session.data?.id) {
19875
- throw new Error("Failed to create session");
19876
- }
19877
- sessionId = session.data.id;
19878
- if (this.depthTracker) {
19879
- const registered = this.depthTracker.registerChild(options.parentSessionId, sessionId);
19880
- if (!registered) {
19881
- throw new Error("Subagent depth exceeded");
19882
- }
19883
- }
19884
- if (this.tmuxEnabled) {
19885
- await new Promise((r) => setTimeout(r, TMUX_SPAWN_DELAY_MS));
19886
- }
19887
- const body = {
19888
- agent: options.agent,
19889
- model: modelRef,
19890
- tools: { task: false },
19891
- parts: [{ type: "text", text: options.promptText }]
19892
- };
19893
- if (options.variant) {
19894
- body.variant = options.variant;
19895
- }
19896
- await promptWithTimeout(this.client, {
19897
- path: { id: sessionId },
19898
- body,
19899
- query: { directory: this.directory }
19900
- }, options.timeout);
19901
- const extraction = await extractSessionResult(this.client, sessionId, {
19902
- includeReasoning: options.includeReasoning
19903
- });
19904
- if (extraction.empty) {
19905
- const retryOnEmpty = this.config?.fallback?.retry_on_empty ?? true;
19906
- if (retryOnEmpty) {
19907
- throw new Error("Empty response from provider");
19908
- }
19909
- }
19910
- return extraction.text;
19911
- } finally {
19912
- if (sessionId) {
19913
- this.client.session.abort({ path: { id: sessionId } }).catch(() => {});
19914
- if (this.depthTracker) {
19915
- this.depthTracker.cleanup(sessionId);
19916
- }
19917
- }
19918
- }
19919
- }
19920
- async runCouncillors(prompt, councillors, parentSessionId, timeout, executionMode = "parallel", maxRetries) {
19921
- const entries = Object.entries(councillors);
19922
- const results = [];
19923
- if (executionMode === "serial") {
19924
- for (const [name, config] of entries) {
19925
- results.push(await this.runCouncillorWithRetry(name, config, prompt, parentSessionId, timeout, maxRetries));
19926
- }
19927
- } else {
19928
- const promises = entries.map(([name, config], index) => (async () => {
19929
- if (this.tmuxEnabled && index > 0) {
19930
- await new Promise((r) => setTimeout(r, index * COUNCILLOR_STAGGER_MS));
19931
- }
19932
- return this.runCouncillorWithRetry(name, config, prompt, parentSessionId, timeout, maxRetries);
19933
- })());
19934
- const settled = await Promise.allSettled(promises);
19935
- for (let index = 0;index < settled.length; index++) {
19936
- const result = settled[index];
19937
- const [name, cfg] = entries[index];
19938
- if (result.status === "fulfilled") {
19939
- results.push(result.value);
19940
- } else {
19941
- results.push({
19942
- name,
19943
- model: cfg.model,
19944
- status: "failed",
19945
- error: result.reason instanceof Error ? result.reason.message : String(result.reason)
19946
- });
19947
- }
19948
- }
19949
- }
19950
- return results;
19951
- }
19952
- async runCouncillorWithRetry(name, config, prompt, parentSessionId, timeout, maxRetries) {
19953
- const modelLabel = shortModelLabel(config.model);
19954
- const totalAttempts = 1 + maxRetries;
19955
- for (let attempt = 1;attempt <= totalAttempts; attempt++) {
19956
- if (attempt > 1) {
19957
- log(`[council-manager] Retrying councillor "${name}" (${modelLabel}), attempt ${attempt}/${totalAttempts}`);
19958
- }
19959
- try {
19960
- const result = await this.runAgentSession({
19961
- parentSessionId,
19962
- title: `Council ${name} (${modelLabel})`,
19963
- agent: "councillor",
19964
- model: config.model,
19965
- promptText: formatCouncillorPrompt(prompt, config.prompt),
19966
- variant: config.variant,
19967
- timeout,
19968
- includeReasoning: false
19969
- });
19970
- return {
19971
- name,
19972
- model: config.model,
19973
- status: "completed",
19974
- result
19975
- };
19976
- } catch (error) {
19977
- const msg = error instanceof Error ? error.message : String(error);
19978
- const isEmptyResponse = msg.includes("Empty response from provider");
19979
- const canRetry = attempt < totalAttempts && isEmptyResponse;
19980
- if (!canRetry) {
19981
- return {
19982
- name,
19983
- model: config.model,
19984
- status: msg.includes("timed out") ? "timed_out" : "failed",
19985
- error: `Councillor "${name}": ${msg}`
19986
- };
19987
- }
19988
- }
19989
- }
19990
- return {
19991
- name,
19992
- model: config.model,
19993
- status: "failed",
19994
- error: `Councillor "${name}": max retries exhausted`
19995
- };
19996
- }
19997
- }
19998
19234
  // src/divoom/manager.ts
19999
- import { spawn } from "node:child_process";
20000
- import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "node:fs";
20001
- import * as os2 from "node:os";
20002
- import path3 from "node:path";
20003
- import { fileURLToPath } from "node:url";
20004
19235
  var AGENT_GIFS = {
20005
19236
  council: "council.gif",
20006
19237
  councillor: "council.gif",
@@ -22319,6 +21550,45 @@ function hasInternalInitiatorMarker(part) {
22319
21550
  }
22320
21551
  return part.text.includes(SLIM_INTERNAL_INITIATOR_MARKER);
22321
21552
  }
21553
+ // src/utils/session.ts
21554
+ var SESSION_ABORT_TIMEOUT_MS = 1000;
21555
+
21556
+ class OperationTimeoutError extends Error {
21557
+ constructor(message) {
21558
+ super(message);
21559
+ this.name = "OperationTimeoutError";
21560
+ }
21561
+ }
21562
+ async function withTimeout(operation, timeoutMs, message) {
21563
+ if (timeoutMs <= 0)
21564
+ return operation;
21565
+ let timer;
21566
+ try {
21567
+ return await Promise.race([
21568
+ operation,
21569
+ new Promise((_, reject) => {
21570
+ timer = setTimeout(() => {
21571
+ reject(new OperationTimeoutError(message));
21572
+ }, timeoutMs);
21573
+ })
21574
+ ]);
21575
+ } finally {
21576
+ clearTimeout(timer);
21577
+ }
21578
+ }
21579
+ async function abortSessionWithTimeout(client, sessionId, timeoutMs = SESSION_ABORT_TIMEOUT_MS) {
21580
+ await withTimeout(client.session.abort({ path: { id: sessionId } }), timeoutMs, `Session abort timed out after ${timeoutMs}ms`);
21581
+ }
21582
+ function parseModelReference(model) {
21583
+ const slashIndex = model.indexOf("/");
21584
+ if (slashIndex <= 0 || slashIndex >= model.length - 1) {
21585
+ return null;
21586
+ }
21587
+ return {
21588
+ providerID: model.slice(0, slashIndex),
21589
+ modelID: model.slice(slashIndex + 1)
21590
+ };
21591
+ }
22322
21592
  // src/utils/session-manager.ts
22323
21593
  var MIN_CONTEXT_FILE_LINES = 10;
22324
21594
  var MAX_CONTEXT_FILES_PER_SESSION = 8;
@@ -22326,14 +21596,6 @@ function aliasPrefix(agentType) {
22326
21596
  switch (agentType) {
22327
21597
  case "researcher":
22328
21598
  return "res";
22329
- case "reviewer":
22330
- return "rev";
22331
- case "implementer":
22332
- return "imp";
22333
- case "council":
22334
- return "cnc";
22335
- case "councillor":
22336
- return "clr";
22337
21599
  case "orchestrator":
22338
21600
  return "orc";
22339
21601
  }
@@ -23493,11 +22755,7 @@ ${originalText}`;
23493
22755
  import path9 from "node:path";
23494
22756
  var AGENT_NAME_SET = new Set([
23495
22757
  "orchestrator",
23496
- "researcher",
23497
- "reviewer",
23498
- "implementer",
23499
- "council",
23500
- "councillor"
22758
+ "researcher"
23501
22759
  ]);
23502
22760
  var MAX_PENDING_TASK_CALLS = 100;
23503
22761
  var RESUMABLE_SESSIONS_START = "<resumable_sessions>";
@@ -27264,17 +26522,17 @@ import * as fs8 from "node:fs/promises";
27264
26522
  import * as path12 from "node:path";
27265
26523
 
27266
26524
  // src/interview/types.ts
27267
- import { z as z3 } from "zod";
27268
- var RawQuestionSchema = z3.object({
27269
- id: z3.string().optional(),
27270
- question: z3.string().optional(),
27271
- options: z3.array(z3.unknown()).optional(),
27272
- suggested: z3.unknown().optional()
26525
+ import { z as z2 } from "zod";
26526
+ var RawQuestionSchema = z2.object({
26527
+ id: z2.string().optional(),
26528
+ question: z2.string().optional(),
26529
+ options: z2.array(z2.unknown()).optional(),
26530
+ suggested: z2.unknown().optional()
27273
26531
  });
27274
- var RawInterviewStateSchema = z3.object({
27275
- summary: z3.unknown().optional(),
27276
- title: z3.unknown().optional(),
27277
- questions: z3.array(z3.unknown()).optional()
26532
+ var RawInterviewStateSchema = z2.object({
26533
+ summary: z2.unknown().optional(),
26534
+ title: z2.unknown().optional(),
26535
+ questions: z2.array(z2.unknown()).optional()
27278
26536
  });
27279
26537
 
27280
26538
  // src/interview/parser.ts
@@ -29763,72 +29021,6 @@ var ast_grep_replace = tool2({
29763
29021
  }
29764
29022
  }
29765
29023
  });
29766
- // src/tools/council.ts
29767
- import {
29768
- tool as tool3
29769
- } from "@opencode-ai/plugin";
29770
- var z4 = tool3.schema;
29771
- function formatModelComposition(councillorResults) {
29772
- return councillorResults.map((cr) => {
29773
- const shortModel = shortModelLabel(cr.model);
29774
- return `${cr.name}: ${shortModel}`;
29775
- }).join(", ");
29776
- }
29777
- function createCouncilTool(_ctx, councilManager) {
29778
- const council_session = tool3({
29779
- description: `Launch a multi-LLM council session for consensus-based analysis.
29780
-
29781
- Sends the prompt to multiple models (councillors) in parallel and returns their formatted responses for you to synthesize.
29782
-
29783
- Returns the councillor responses with a summary footer.`,
29784
- args: {
29785
- prompt: z4.string().describe("The prompt to send to all councillors"),
29786
- preset: z4.string().optional().describe('Council preset to use (default: "default"). Must match a preset in the council config.')
29787
- },
29788
- async execute(args, toolContext) {
29789
- if (!toolContext || typeof toolContext !== "object" || !("sessionID" in toolContext)) {
29790
- throw new Error("Invalid toolContext: missing sessionID");
29791
- }
29792
- const allowedAgents = ["council"];
29793
- const callingAgent = toolContext.agent;
29794
- if (callingAgent && !allowedAgents.includes(callingAgent)) {
29795
- throw new Error(`Council sessions can only be invoked by the council agent. Current agent: ${callingAgent}`);
29796
- }
29797
- const prompt = String(args.prompt);
29798
- const preset = typeof args.preset === "string" ? args.preset : undefined;
29799
- const parentSessionId = toolContext.sessionID;
29800
- const result = await councilManager.runCouncil(prompt, preset, parentSessionId);
29801
- if (!result.success) {
29802
- return `Council session failed: ${result.error}`;
29803
- }
29804
- let output = result.result ?? "(No output)";
29805
- const completed = result.councillorResults.filter((cr) => cr.status === "completed").length;
29806
- const total = result.councillorResults.length;
29807
- const composition = formatModelComposition(result.councillorResults);
29808
- output += `
29809
-
29810
- ---
29811
- *Council: ${completed}/${total} councillors responded (${composition})*`;
29812
- const deprecated = councilManager.getDeprecatedFields();
29813
- if (deprecated && deprecated.length > 0) {
29814
- const legacyMasterModel = councilManager.getLegacyMasterModel();
29815
- const hasMaster = deprecated.includes("master");
29816
- const trulyIgnored = hasMaster && !legacyMasterModel ? deprecated : deprecated.filter((f) => f !== "master");
29817
- const parts = [];
29818
- if (hasMaster && legacyMasterModel) {
29819
- 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.`);
29820
- }
29821
- if (trulyIgnored.length > 0) {
29822
- 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.`);
29823
- }
29824
- output += `
29825
- ⚠ Config warning: ${parts.join(" ")}`;
29826
- }
29827
- return output;
29828
- }
29829
- });
29830
- return { council_session };
29831
- }
29832
29024
  // src/tui-state.ts
29833
29025
  import * as fs9 from "node:fs";
29834
29026
  import * as os5 from "node:os";
@@ -30064,13 +29256,19 @@ Usage: /preset <name> to switch.`);
30064
29256
  // src/tools/skill.ts
30065
29257
  import { existsSync as existsSync10, readFileSync as readFileSync5 } from "node:fs";
30066
29258
  import { join as join13 } from "node:path";
30067
- import { tool as tool4 } from "@opencode-ai/plugin/tool";
30068
- var z5 = tool4.schema;
29259
+ import { tool as tool3 } from "@opencode-ai/plugin/tool";
29260
+ var z3 = tool3.schema;
30069
29261
  function resolveSkillPath(skillName) {
30070
- const packageRoot = join13(import.meta.dirname, "..", "..");
30071
- const bundledPath = join13(packageRoot, "src", "skills", skillName, "SKILL.md");
30072
- if (existsSync10(bundledPath)) {
30073
- return bundledPath;
29262
+ let dir = import.meta.dirname;
29263
+ for (let i = 0;i < 5; i++) {
29264
+ const candidate = join13(dir, "src", "skills", skillName, "SKILL.md");
29265
+ if (existsSync10(candidate)) {
29266
+ return candidate;
29267
+ }
29268
+ const parent = join13(dir, "..");
29269
+ if (parent === dir)
29270
+ break;
29271
+ dir = parent;
30074
29272
  }
30075
29273
  return;
30076
29274
  }
@@ -30084,14 +29282,14 @@ function isSkillAllowedForAgent(agentName, skillName, config) {
30084
29282
  return permissions["*"] === "allow";
30085
29283
  }
30086
29284
  function createSkillTool(config) {
30087
- const skill = tool4({
29285
+ const skill = tool3({
30088
29286
  description: `Load a Skill behavior guide by name.
30089
29287
 
30090
29288
  Returns the full SKILL.md content so you can follow its workflow.
30091
29289
  Skills are temporary behavior overlays — they apply to the current turn only
30092
29290
  and do not permanently modify your system prompt.`,
30093
29291
  args: {
30094
- name: z5.string().describe('Skill name (e.g. "brainstorming", "simplify", "codemap").')
29292
+ name: z3.string().describe('Skill name (e.g. "brainstorming", "simplify", "codemap").')
30095
29293
  },
30096
29294
  execute: async (args, toolContext) => {
30097
29295
  const skillName = args.name.trim();
@@ -30147,7 +29345,7 @@ var WEBFETCH_DESCRIPTION = "Fetch a URL with better extraction for static/docs p
30147
29345
  import os6 from "node:os";
30148
29346
  import path18 from "node:path";
30149
29347
  import {
30150
- tool as tool5
29348
+ tool as tool4
30151
29349
  } from "@opencode-ai/plugin";
30152
29350
 
30153
29351
  // src/tools/smartfetch/binary.ts
@@ -30315,7 +29513,7 @@ var M = class u2 {
30315
29513
  return this.#S;
30316
29514
  }
30317
29515
  constructor(e) {
30318
- 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: z6, perf: x } = e;
29516
+ 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: z4, perf: x } = e;
30319
29517
  if (x !== undefined && typeof x?.now != "function")
30320
29518
  throw new TypeError("perf option must have a now() method if specified");
30321
29519
  if (this.#m = x ?? C, t !== 0 && !F(t))
@@ -30333,7 +29531,7 @@ var M = class u2 {
30333
29531
  throw new TypeError("memoMethod must be a function if defined");
30334
29532
  if (this.#U = m, a !== undefined && typeof a != "function")
30335
29533
  throw new TypeError("fetchMethod must be a function if specified");
30336
- 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.#x = c), typeof f == "function" ? (this.#S = f, this.#r = []) : (this.#S = undefined, this.#r = undefined), this.#T = !!this.#w, this.#j = !!this.#x, this.#f = !!this.#S, this.noDisposeOnSet = !!g, this.noUpdateTTL = !!p, this.noDeleteOnFetchRejection = !!_, this.allowStaleOnFetchRejection = !!d, this.allowStaleOnFetchAbort = !!A, this.ignoreFetchAbort = !!z6, this.maxEntrySize !== 0) {
29534
+ 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.#x = c), typeof f == "function" ? (this.#S = f, this.#r = []) : (this.#S = undefined, this.#r = undefined), this.#T = !!this.#w, this.#j = !!this.#x, this.#f = !!this.#S, this.noDisposeOnSet = !!g, this.noUpdateTTL = !!p, this.noDeleteOnFetchRejection = !!_, this.allowStaleOnFetchRejection = !!d, this.allowStaleOnFetchAbort = !!A, this.ignoreFetchAbort = !!z4, this.maxEntrySize !== 0) {
30337
29535
  if (this.#u !== 0 && !F(this.#u))
30338
29536
  throw new TypeError("maxSize must be a positive integer if specified");
30339
29537
  if (!F(this.maxEntrySize))
@@ -30713,8 +29911,8 @@ var M = class u2 {
30713
29911
  let A = this.#p(b);
30714
29912
  if (!y && !A)
30715
29913
  return a && (a.fetch = "hit"), this.#L(b), s && this.#D(b), a && this.#E(a, b), d;
30716
- let z6 = this.#P(e, b, _, w), v = z6.__staleWhileFetching !== undefined && i;
30717
- return a && (a.fetch = A ? "stale" : "refresh", v && A && (a.returnedStale = true)), v ? z6.__staleWhileFetching : z6.__returned = z6;
29914
+ let z4 = this.#P(e, b, _, w), v = z4.__staleWhileFetching !== undefined && i;
29915
+ return a && (a.fetch = A ? "stale" : "refresh", v && A && (a.returnedStale = true)), v ? z4.__staleWhileFetching : z4.__returned = z4;
30718
29916
  }
30719
29917
  }
30720
29918
  forceFetch(e, t = {}) {
@@ -31929,20 +31127,20 @@ async function runSecondaryModelWithFallback(client, directory, models, prompt,
31929
31127
  }
31930
31128
 
31931
31129
  // src/tools/smartfetch/tool.ts
31932
- var z6 = tool5.schema;
31130
+ var z4 = tool4.schema;
31933
31131
  function createWebfetchTool(pluginCtx, options = {}) {
31934
31132
  const binaryDir = options.binaryDir || path18.join(os6.tmpdir(), "opencode-smartfetch");
31935
- return tool5({
31133
+ return tool4({
31936
31134
  description: WEBFETCH_DESCRIPTION,
31937
31135
  args: {
31938
- url: z6.httpUrl(),
31939
- format: z6.enum(["text", "markdown", "html"]).default("markdown"),
31940
- timeout: z6.number().positive().max(MAX_TIMEOUT_SECONDS).optional().describe("Timeout in seconds, max 120."),
31941
- prompt: z6.string().optional().describe("Optional extraction task to run on the fetched content using a cheap secondary model."),
31942
- extract_main: z6.boolean().default(true),
31943
- prefer_llms_txt: z6.enum(["auto", "always", "never"]).default("auto"),
31944
- include_metadata: z6.boolean().default(true),
31945
- save_binary: z6.boolean().default(false).describe("Save binary payload to disk when it fits within the active download limit.")
31136
+ url: z4.httpUrl(),
31137
+ format: z4.enum(["text", "markdown", "html"]).default("markdown"),
31138
+ timeout: z4.number().positive().max(MAX_TIMEOUT_SECONDS).optional().describe("Timeout in seconds, max 120."),
31139
+ prompt: z4.string().optional().describe("Optional extraction task to run on the fetched content using a cheap secondary model."),
31140
+ extract_main: z4.boolean().default(true),
31141
+ prefer_llms_txt: z4.enum(["auto", "always", "never"]).default("auto"),
31142
+ include_metadata: z4.boolean().default(true),
31143
+ save_binary: z4.boolean().default(false).describe("Save binary payload to disk when it fits within the active download limit.")
31946
31144
  },
31947
31145
  async execute(args, ctx) {
31948
31146
  const secondaryModels = await readSecondaryModelFromConfig(ctx.directory || pluginCtx.directory);
@@ -32486,7 +31684,7 @@ async function appLog(ctx, level, message) {
32486
31684
  }
32487
31685
  }
32488
31686
  var HEALTH_CHECK = {
32489
- minAgents: 5,
31687
+ minAgents: 2,
32490
31688
  minTools: 5,
32491
31689
  minMcps: 1
32492
31690
  };
@@ -32592,7 +31790,7 @@ var OhMyOpenCodeLite = async (ctx) => {
32592
31790
  startAvailabilityCheck(multiplexerConfig);
32593
31791
  }
32594
31792
  depthTracker = new SubagentDepthTracker;
32595
- councilTools = config.council ? createCouncilTool(ctx, new CouncilManager(ctx, config, depthTracker, multiplexerEnabled)) : {};
31793
+ councilTools = {};
32596
31794
  mcps = createBuiltinMcps(config.disabled_mcps, config.websearch);
32597
31795
  webfetch = createWebfetchTool(ctx);
32598
31796
  skillTools = createSkillTool(config);
@@ -32627,7 +31825,7 @@ var OhMyOpenCodeLite = async (ctx) => {
32627
31825
  interviewManager = createInterviewManager(ctx, config);
32628
31826
  presetManager = createPresetManager(ctx, config);
32629
31827
  divoomManager = createDivoomManager(config.divoom);
32630
- toolCount = Object.keys(councilTools).length + Object.keys(todoContinuationHook.tool).length + 1 + 1 + 2;
31828
+ toolCount = Object.keys(todoContinuationHook.tool).length + 1 + 1 + 2;
32631
31829
  } catch (err) {
32632
31830
  log("[plugin] FATAL: init failed", String(err));
32633
31831
  await appLog(ctx, "error", `INIT FAILED: ${String(err)}. Report at cnb.cool/zcyoop/ai-assistant/agent-forge/issues/310`);
@@ -32821,8 +32019,6 @@ var OhMyOpenCodeLite = async (ctx) => {
32821
32019
  }
32822
32020
  const tuiAgentModels = {};
32823
32021
  for (const agentDef of agentDefs) {
32824
- if (agentDef.name === "councillor")
32825
- continue;
32826
32022
  const entry = configAgent[agentDef.name];
32827
32023
  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;
32828
32024
  tuiAgentModels[agentDef.name] = resolvedModel ?? "default";