oh-my-opencode-serverlocal 0.1.1 → 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/cli/index.js +128 -220
- package/dist/config/constants.d.ts +3 -3
- package/dist/config/index.d.ts +0 -1
- package/dist/config/loader.d.ts +4 -4
- package/dist/config/schema.d.ts +0 -41
- package/dist/hooks/auto-update-checker/skill-sync.d.ts +2 -2
- package/dist/hooks/phase-reminder/index.d.ts +1 -1
- package/dist/hooks/task-session-manager/index.d.ts +1 -1
- package/dist/index.js +576 -1298
- package/dist/tools/index.d.ts +0 -1
- package/dist/tui.js +103 -203
- package/dist/utils/internal-initiator.d.ts +2 -2
- package/dist/utils/session.d.ts +1 -1
- package/dist/utils/subagent-depth.d.ts +2 -2
- package/package.json +1 -1
- package/src/companion/companion-manifest.json +6 -6
- package/src/skills/clonedeps/SKILL.md +4 -4
- package/src/skills/codemap/README.md +1 -1
- package/src/skills/codemap/SKILL.md +3 -3
- package/src/skills/codemap.md +2 -2
- package/src/skills/{oh-my-opencode-slim → oh-my-opencode-serverlocal}/SKILL.md +24 -24
- package/src/skills/reflect/SKILL.md +5 -5
- package/src/skills/simplify/README.md +1 -1
- package/src/skills/worktrees/SKILL.md +4 -4
- package/dist/agents/council.d.ts +0 -27
- package/dist/agents/councillor.d.ts +0 -2
- package/dist/config/council-schema.d.ts +0 -137
- package/dist/council/council-manager.d.ts +0 -53
- package/dist/council/index.d.ts +0 -1
- package/dist/tools/council.d.ts +0 -10
- package/dist/utils/councillor-models.d.ts +0 -20
package/dist/index.js
CHANGED
|
@@ -18376,10 +18376,10 @@ var CUSTOM_SKILLS = [
|
|
|
18376
18376
|
sourcePath: "src/skills/reflect"
|
|
18377
18377
|
},
|
|
18378
18378
|
{
|
|
18379
|
-
name: "oh-my-opencode-
|
|
18380
|
-
description: "Configure, customize, and safely improve oh-my-opencode-
|
|
18379
|
+
name: "oh-my-opencode-serverlocal",
|
|
18380
|
+
description: "Configure, customize, and safely improve oh-my-opencode-serverlocal setups",
|
|
18381
18381
|
allowedAgents: ["orchestrator"],
|
|
18382
|
-
sourcePath: "src/skills/oh-my-opencode-
|
|
18382
|
+
sourcePath: "src/skills/oh-my-opencode-serverlocal"
|
|
18383
18383
|
},
|
|
18384
18384
|
{
|
|
18385
18385
|
name: "worktrees",
|
|
@@ -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"
|
|
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
|
|
18668
|
-
var ProviderModelIdSchema =
|
|
18669
|
-
var ManualAgentPlanSchema =
|
|
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:
|
|
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 =
|
|
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 =
|
|
18697
|
-
var PermissionRuleSchema =
|
|
18598
|
+
var PermissionActionSchema = z.enum(["ask", "allow", "deny"]);
|
|
18599
|
+
var PermissionRuleSchema = z.union([
|
|
18698
18600
|
PermissionActionSchema,
|
|
18699
|
-
|
|
18601
|
+
z.record(z.string(), PermissionActionSchema)
|
|
18700
18602
|
]);
|
|
18701
|
-
var PermissionObjectSchema =
|
|
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 =
|
|
18621
|
+
var PermissionConfigSchema = z.union([
|
|
18720
18622
|
PermissionActionSchema,
|
|
18721
18623
|
PermissionObjectSchema
|
|
18722
18624
|
]);
|
|
18723
|
-
var AgentOverrideConfigSchema =
|
|
18724
|
-
model:
|
|
18725
|
-
|
|
18726
|
-
|
|
18727
|
-
|
|
18728
|
-
|
|
18729
|
-
id:
|
|
18730
|
-
variant:
|
|
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:
|
|
18735
|
-
variant:
|
|
18736
|
-
skills:
|
|
18737
|
-
mcps:
|
|
18738
|
-
prompt:
|
|
18739
|
-
orchestratorPrompt:
|
|
18740
|
-
options:
|
|
18741
|
-
displayName:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
18661
|
+
var ZellijPaneModeSchema = z.enum(["agent-tab", "current-tab"]);
|
|
18760
18662
|
var TmuxLayoutSchema = MultiplexerLayoutSchema;
|
|
18761
|
-
var MultiplexerConfigSchema =
|
|
18663
|
+
var MultiplexerConfigSchema = z.object({
|
|
18762
18664
|
type: MultiplexerTypeSchema.default("none"),
|
|
18763
18665
|
layout: MultiplexerLayoutSchema.default("main-vertical"),
|
|
18764
|
-
main_pane_size:
|
|
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 =
|
|
18768
|
-
enabled:
|
|
18669
|
+
var TmuxConfigSchema = z.object({
|
|
18670
|
+
enabled: z.boolean().default(false),
|
|
18769
18671
|
layout: TmuxLayoutSchema.default("main-vertical"),
|
|
18770
|
-
main_pane_size:
|
|
18672
|
+
main_pane_size: z.number().min(20).max(80).default(60)
|
|
18771
18673
|
});
|
|
18772
|
-
var PresetSchema =
|
|
18773
|
-
var WebsearchConfigSchema =
|
|
18774
|
-
provider:
|
|
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 =
|
|
18777
|
-
var InterviewConfigSchema =
|
|
18778
|
-
maxQuestions:
|
|
18779
|
-
outputFolder:
|
|
18780
|
-
autoOpenBrowser:
|
|
18781
|
-
port:
|
|
18782
|
-
dashboard:
|
|
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 =
|
|
18785
|
-
maxSessionsPerAgent:
|
|
18786
|
-
readContextMinLines:
|
|
18787
|
-
readContextMaxFiles:
|
|
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 =
|
|
18790
|
-
enabled:
|
|
18791
|
-
timeoutMs:
|
|
18792
|
-
retryDelayMs:
|
|
18793
|
-
maxRetries:
|
|
18794
|
-
retry_on_empty:
|
|
18795
|
-
runtimeOverride:
|
|
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 =
|
|
18798
|
-
enabled:
|
|
18799
|
-
binaryPath:
|
|
18800
|
-
position:
|
|
18801
|
-
size:
|
|
18802
|
-
gifPack:
|
|
18803
|
-
loopStyle:
|
|
18804
|
-
speed:
|
|
18805
|
-
debug:
|
|
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 =
|
|
18709
|
+
var AcpAgentPermissionModeSchema = z.enum(["ask", "allow", "reject"]);
|
|
18808
18710
|
var MAX_ACP_TIMEOUT_MS = 2147483647;
|
|
18809
|
-
var AcpAgentConfigSchema =
|
|
18810
|
-
command:
|
|
18811
|
-
args:
|
|
18812
|
-
env:
|
|
18813
|
-
cwd:
|
|
18814
|
-
description:
|
|
18815
|
-
prompt:
|
|
18816
|
-
orchestratorPrompt:
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
18834
|
-
preset:
|
|
18835
|
-
setDefaultAgent:
|
|
18836
|
-
compactSidebar:
|
|
18837
|
-
stripOrchestratorModel:
|
|
18838
|
-
autoUpdate:
|
|
18839
|
-
presets:
|
|
18840
|
-
agents:
|
|
18841
|
-
disabled_agents:
|
|
18842
|
-
image_routing:
|
|
18843
|
-
disabled_mcps:
|
|
18844
|
-
disabled_tools:
|
|
18845
|
-
disabled_skills:
|
|
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) => {
|
|
@@ -18884,7 +18785,7 @@ function loadConfigFromPath(configPath, options) {
|
|
|
18884
18785
|
message
|
|
18885
18786
|
});
|
|
18886
18787
|
if (!options?.silent) {
|
|
18887
|
-
console.warn(`[oh-my-opencode-
|
|
18788
|
+
console.warn(`[oh-my-opencode-serverlocal] Invalid JSON in ${configPath}:`, message);
|
|
18888
18789
|
}
|
|
18889
18790
|
return null;
|
|
18890
18791
|
}
|
|
@@ -18897,7 +18798,7 @@ function loadConfigFromPath(configPath, options) {
|
|
|
18897
18798
|
formatted: result.error.format()
|
|
18898
18799
|
});
|
|
18899
18800
|
if (!options?.silent) {
|
|
18900
|
-
console.warn(`[oh-my-opencode-
|
|
18801
|
+
console.warn(`[oh-my-opencode-serverlocal] Invalid config at ${configPath}:`);
|
|
18901
18802
|
console.warn(result.error.format());
|
|
18902
18803
|
}
|
|
18903
18804
|
return null;
|
|
@@ -18911,7 +18812,7 @@ function loadConfigFromPath(configPath, options) {
|
|
|
18911
18812
|
message: error.message
|
|
18912
18813
|
});
|
|
18913
18814
|
if (!options?.silent) {
|
|
18914
|
-
console.warn(`[oh-my-opencode-
|
|
18815
|
+
console.warn(`[oh-my-opencode-serverlocal] Error reading config from ${configPath}:`, error.message);
|
|
18915
18816
|
}
|
|
18916
18817
|
}
|
|
18917
18818
|
return null;
|
|
@@ -18950,7 +18851,7 @@ function validateFinalImageRouting(config, configPath, options) {
|
|
|
18950
18851
|
message
|
|
18951
18852
|
});
|
|
18952
18853
|
if (!options?.silent) {
|
|
18953
|
-
console.warn(`[oh-my-opencode-
|
|
18854
|
+
console.warn(`[oh-my-opencode-serverlocal] Invalid config: ${message}`);
|
|
18954
18855
|
}
|
|
18955
18856
|
return false;
|
|
18956
18857
|
}
|
|
@@ -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
|
};
|
|
@@ -19019,7 +18919,7 @@ function loadPluginConfig(directory, options) {
|
|
|
19019
18919
|
message
|
|
19020
18920
|
});
|
|
19021
18921
|
if (!options?.silent) {
|
|
19022
|
-
console.warn(`[oh-my-opencode-
|
|
18922
|
+
console.warn(`[oh-my-opencode-serverlocal] ${message}`);
|
|
19023
18923
|
}
|
|
19024
18924
|
}
|
|
19025
18925
|
}
|
|
@@ -19072,7 +18972,7 @@ function loadAgentPrompt(agentName, optionsOrPreset) {
|
|
|
19072
18972
|
try {
|
|
19073
18973
|
return fs.readFileSync(promptPath, "utf-8");
|
|
19074
18974
|
} catch (error) {
|
|
19075
|
-
console.warn(`[oh-my-opencode-
|
|
18975
|
+
console.warn(`[oh-my-opencode-serverlocal] ${errorPrefix} ${promptPath}:`, error instanceof Error ? error.message : String(error));
|
|
19076
18976
|
}
|
|
19077
18977
|
}
|
|
19078
18978
|
return;
|
|
@@ -19116,625 +19016,71 @@ function getCustomAgentNames(config) {
|
|
|
19116
19016
|
function getAcpAgentNames(config) {
|
|
19117
19017
|
return Object.keys(config?.acpAgents ?? {});
|
|
19118
19018
|
}
|
|
19119
|
-
// src/
|
|
19120
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19312
|
-
|
|
19313
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19338
|
-
Parse request: explicit requirements + implicit needs.
|
|
19069
|
+
${WRITABLE_FILE_OPERATIONS_RULES}
|
|
19339
19070
|
|
|
19340
|
-
##
|
|
19341
|
-
|
|
19342
|
-
|
|
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
|
-
##
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
|
|
19349
|
-
|
|
19350
|
-
|
|
19351
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
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
|
-
|
|
19955
|
-
|
|
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
|
-
|
|
19553
|
+
## No Flattery
|
|
19554
|
+
Never: "Great question!" "Excellent idea!" "Smart choice!" or any praise of user input.
|
|
19958
19555
|
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
-
|
|
19962
|
-
-
|
|
19963
|
-
-
|
|
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
|
-
|
|
19967
|
-
|
|
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
|
-
**
|
|
19974
|
-
|
|
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
|
-
|
|
19568
|
+
</Communication>
|
|
19979
19569
|
`;
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
19983
|
-
|
|
19984
|
-
|
|
19985
|
-
|
|
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
|
|
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 = (
|
|
19955
|
+
const isInternalOnly = (_name) => false;
|
|
20386
19956
|
const entries = [];
|
|
20387
19957
|
for (const a of agents) {
|
|
20388
19958
|
const sdkConfig = {
|
|
@@ -20435,7 +20005,7 @@ import * as fs2 from "node:fs";
|
|
|
20435
20005
|
import { appendFile } from "node:fs/promises";
|
|
20436
20006
|
import * as os from "node:os";
|
|
20437
20007
|
import * as path2 from "node:path";
|
|
20438
|
-
var LOG_PREFIX = "oh-my-opencode-
|
|
20008
|
+
var LOG_PREFIX = "oh-my-opencode-serverlocal.";
|
|
20439
20009
|
var LOG_SUFFIX = ".log";
|
|
20440
20010
|
var RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
|
20441
20011
|
var logFile = null;
|
|
@@ -20513,12 +20083,12 @@ var activeManagers = new Set;
|
|
|
20513
20083
|
function stateFilePath() {
|
|
20514
20084
|
const xdg = process.env.XDG_DATA_HOME?.trim();
|
|
20515
20085
|
const base = xdg && path3.isAbsolute(xdg) ? xdg : path3.join(os2.homedir(), ".local", "share");
|
|
20516
|
-
return path3.join(base, "opencode", "storage", "oh-my-opencode-
|
|
20086
|
+
return path3.join(base, "opencode", "storage", "oh-my-opencode-serverlocal", "companion-state.json");
|
|
20517
20087
|
}
|
|
20518
20088
|
function pidFilePath() {
|
|
20519
20089
|
const xdg = process.env.XDG_DATA_HOME?.trim();
|
|
20520
20090
|
const base = xdg && path3.isAbsolute(xdg) ? xdg : path3.join(os2.homedir(), ".local", "share");
|
|
20521
|
-
return path3.join(base, "opencode", "storage", "oh-my-opencode-
|
|
20091
|
+
return path3.join(base, "opencode", "storage", "oh-my-opencode-serverlocal", "companion.pid");
|
|
20522
20092
|
}
|
|
20523
20093
|
function isProcessAlive(pid) {
|
|
20524
20094
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
@@ -20589,8 +20159,8 @@ function pidFileLockHasLiveOwner(lock) {
|
|
|
20589
20159
|
function defaultBinaryPath() {
|
|
20590
20160
|
const xdg = process.env.XDG_DATA_HOME?.trim();
|
|
20591
20161
|
const base = xdg && path3.isAbsolute(xdg) ? xdg : path3.join(os2.homedir(), ".local", "share");
|
|
20592
|
-
const binaryName = os2.platform() === "win32" ? "oh-my-opencode-
|
|
20593
|
-
return path3.join(base, "opencode", "storage", "oh-my-opencode-
|
|
20162
|
+
const binaryName = os2.platform() === "win32" ? "oh-my-opencode-serverlocal-companion.exe" : "oh-my-opencode-serverlocal-companion";
|
|
20163
|
+
return path3.join(base, "opencode", "storage", "oh-my-opencode-serverlocal", "bin", binaryName);
|
|
20594
20164
|
}
|
|
20595
20165
|
function resolveCompanionBinaryPath(config) {
|
|
20596
20166
|
const configured = config?.binaryPath?.trim();
|
|
@@ -20940,13 +20510,13 @@ var FIRST_METADATA_VERSION = "0.1.2";
|
|
|
20940
20510
|
var COMPANION_MANIFEST = {
|
|
20941
20511
|
version: "0.1.3",
|
|
20942
20512
|
tag: "companion-v0.1.3",
|
|
20943
|
-
repo: "
|
|
20513
|
+
repo: "Darthph0enix7/oh-my-opencode-serverlocal",
|
|
20944
20514
|
checksums: {
|
|
20945
|
-
"oh-my-opencode-
|
|
20946
|
-
"oh-my-opencode-
|
|
20947
|
-
"oh-my-opencode-
|
|
20948
|
-
"oh-my-opencode-
|
|
20949
|
-
"oh-my-opencode-
|
|
20515
|
+
"oh-my-opencode-serverlocal-companion-v0.1.3-aarch64-apple-darwin.tar.gz": "b4885f9b1900c02376e5f8f5ae6f3b8a89d26f7514b03f836d7e3d618164a0ed",
|
|
20516
|
+
"oh-my-opencode-serverlocal-companion-v0.1.3-aarch64-unknown-linux-gnu.tar.gz": "ed7cffc583e1eaa78c9bea702e6b6aa3bbc5bb4d881713fb2050237ba6b7aca5",
|
|
20517
|
+
"oh-my-opencode-serverlocal-companion-v0.1.3-x86_64-apple-darwin.tar.gz": "98d8ea7c7bc4415b18e0d4c524adb4eb9a84c872919840fdc021f0f50c61f808",
|
|
20518
|
+
"oh-my-opencode-serverlocal-companion-v0.1.3-x86_64-pc-windows-msvc.zip": "9316a49bf01f3b4fb1ce2d62edfc46094e73bb153d6ce023fb7df085afcf77bd",
|
|
20519
|
+
"oh-my-opencode-serverlocal-companion-v0.1.3-x86_64-unknown-linux-gnu.tar.gz": "33f5fd4b6c80155a019391e5efb13904ca9531ba8dd8c6cba30a161f1b07b764"
|
|
20950
20520
|
}
|
|
20951
20521
|
};
|
|
20952
20522
|
function getCompanionTarget() {
|
|
@@ -20971,7 +20541,7 @@ function getCompanionTarget() {
|
|
|
20971
20541
|
function getCompanionBinaryPath() {
|
|
20972
20542
|
const xdg = process.env.XDG_DATA_HOME?.trim();
|
|
20973
20543
|
const base = xdg && path4.isAbsolute(xdg) ? xdg : path4.join(homedir4(), ".local", "share");
|
|
20974
|
-
return path4.join(base, "opencode", "storage", "oh-my-opencode-
|
|
20544
|
+
return path4.join(base, "opencode", "storage", "oh-my-opencode-serverlocal", "bin", platform2() === "win32" ? "oh-my-opencode-serverlocal-companion.exe" : "oh-my-opencode-serverlocal-companion");
|
|
20975
20545
|
}
|
|
20976
20546
|
function loadCompanionManifestFromPackageRoot(packageRoot) {
|
|
20977
20547
|
const manifestPath = path4.join(packageRoot, "src", "companion", "companion-manifest.json");
|
|
@@ -21115,7 +20685,7 @@ async function installCompanionArchive(finalBinaryPath, target, manifest, downlo
|
|
|
21115
20685
|
};
|
|
21116
20686
|
}
|
|
21117
20687
|
}
|
|
21118
|
-
const binaryName = isWindows ? "oh-my-opencode-
|
|
20688
|
+
const binaryName = isWindows ? "oh-my-opencode-serverlocal-companion.exe" : "oh-my-opencode-serverlocal-companion";
|
|
21119
20689
|
const extractedBinaryPath = path4.join(extractedDir, binaryName);
|
|
21120
20690
|
if (!existsSync3(extractedBinaryPath)) {
|
|
21121
20691
|
return {
|
|
@@ -21223,7 +20793,7 @@ async function withCompanionInstallLock(binaryPath, timeoutMs, staleMs, run) {
|
|
|
21223
20793
|
}
|
|
21224
20794
|
function companionArchiveName(version, target, isWindows = process.platform === "win32") {
|
|
21225
20795
|
const ext = isWindows ? "zip" : "tar.gz";
|
|
21226
|
-
return `oh-my-opencode-
|
|
20796
|
+
return `oh-my-opencode-serverlocal-companion-v${version}-${target}.${ext}`;
|
|
21227
20797
|
}
|
|
21228
20798
|
function compareSemver(a, b) {
|
|
21229
20799
|
const left = parseSemver(a);
|
|
@@ -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",
|
|
@@ -23935,7 +23241,7 @@ function syncBundledSkillsFromPackage(packageRoot, options = {}) {
|
|
|
23935
23241
|
} catch (err) {
|
|
23936
23242
|
log(`[skill-sync] Failed to read package version from ${packageRoot}:`, err);
|
|
23937
23243
|
}
|
|
23938
|
-
const manifestDir = path10.join(getConfigDir(), ".oh-my-opencode-
|
|
23244
|
+
const manifestDir = path10.join(getConfigDir(), ".oh-my-opencode-serverlocal");
|
|
23939
23245
|
const lockDir = path10.join(manifestDir, "skills.lock");
|
|
23940
23246
|
try {
|
|
23941
23247
|
mkdirSync4(manifestDir, { recursive: true });
|
|
@@ -24613,8 +23919,8 @@ Version is pinned. Update your plugin config to apply.`, "info", 8000);
|
|
|
24613
23919
|
}
|
|
24614
23920
|
}
|
|
24615
23921
|
function showMajorUpgradeToast(ctx, version) {
|
|
24616
|
-
showToast(ctx, `oh-my-opencode-
|
|
24617
|
-
Run: bunx oh-my-opencode-
|
|
23922
|
+
showToast(ctx, `oh-my-opencode-serverlocal v${version} is available.`, `It requires OpenCode background subagents.
|
|
23923
|
+
Run: bunx oh-my-opencode-serverlocal@latest install`, "info", 12000);
|
|
24618
23924
|
}
|
|
24619
23925
|
async function runBunInstallSafe(installDir) {
|
|
24620
23926
|
try {
|
|
@@ -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",
|
|
@@ -25341,7 +24646,7 @@ function isRecord2(value) {
|
|
|
25341
24646
|
|
|
25342
24647
|
// src/utils/internal-initiator.ts
|
|
25343
24648
|
var SLIM_INTERNAL_INITIATOR_MARKER = "<!-- SLIM_INTERNAL_INITIATOR -->";
|
|
25344
|
-
var INTERNAL_INITIATOR_METADATA_KEY = "oh-my-opencode-
|
|
24649
|
+
var INTERNAL_INITIATOR_METADATA_KEY = "oh-my-opencode-serverlocal.internalInitiator";
|
|
25345
24650
|
function createInternalAgentTextPart(text) {
|
|
25346
24651
|
return {
|
|
25347
24652
|
type: "text",
|
|
@@ -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();
|
|
@@ -26405,7 +25749,7 @@ function createLoopCommandHook() {
|
|
|
26405
25749
|
};
|
|
26406
25750
|
}
|
|
26407
25751
|
// src/hooks/phase-reminder/index.ts
|
|
26408
|
-
var PHASE_REMINDER_METADATA_KEY = "oh-my-opencode-
|
|
25752
|
+
var PHASE_REMINDER_METADATA_KEY = "oh-my-opencode-serverlocal.phaseReminder";
|
|
26409
25753
|
function hasPhaseReminder(part) {
|
|
26410
25754
|
return part.synthetic === true && isRecord2(part.metadata) && part.metadata[PHASE_REMINDER_METADATA_KEY] === true;
|
|
26411
25755
|
}
|
|
@@ -26700,7 +26044,7 @@ function extractReadFiles(root, output) {
|
|
|
26700
26044
|
}
|
|
26701
26045
|
|
|
26702
26046
|
// src/hooks/task-session-manager/index.ts
|
|
26703
|
-
var BACKGROUND_JOB_BOARD_METADATA_KEY = "oh-my-opencode-
|
|
26047
|
+
var BACKGROUND_JOB_BOARD_METADATA_KEY = "oh-my-opencode-serverlocal.backgroundJobBoard";
|
|
26704
26048
|
var BACKGROUND_COMPLETION_COMPLETED = /^Background task completed: /;
|
|
26705
26049
|
var BACKGROUND_COMPLETION_FAILED = /^Background task failed: /;
|
|
26706
26050
|
var MAX_PROCESSED_INJECTED_COMPLETIONS = 500;
|
|
@@ -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
|
|
30859
|
-
var RawQuestionSchema =
|
|
30860
|
-
id:
|
|
30861
|
-
question:
|
|
30862
|
-
options:
|
|
30863
|
-
suggested:
|
|
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 =
|
|
30866
|
-
summary:
|
|
30867
|
-
title:
|
|
30868
|
-
questions:
|
|
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
|
|
@@ -33788,7 +33132,7 @@ class CmuxClosePolicy {
|
|
|
33788
33132
|
}
|
|
33789
33133
|
|
|
33790
33134
|
// src/multiplexer/cmux/session-state.ts
|
|
33791
|
-
var STORE_KEY = Symbol.for("oh-my-opencode-
|
|
33135
|
+
var STORE_KEY = Symbol.for("oh-my-opencode-serverlocal.cmux-session-store");
|
|
33792
33136
|
function records() {
|
|
33793
33137
|
const globalStore = globalThis;
|
|
33794
33138
|
globalStore[STORE_KEY] ??= new Map;
|
|
@@ -34396,7 +33740,7 @@ class CmuxSessionLifecycle {
|
|
|
34396
33740
|
}
|
|
34397
33741
|
|
|
34398
33742
|
// src/multiplexer/session-manager.ts
|
|
34399
|
-
var SHARED_STATE_KEY = Symbol.for("oh-my-opencode-
|
|
33743
|
+
var SHARED_STATE_KEY = Symbol.for("oh-my-opencode-serverlocal.multiplexer-session-manager.state");
|
|
34400
33744
|
function getSharedState() {
|
|
34401
33745
|
const globalWithState = globalThis;
|
|
34402
33746
|
globalWithState[SHARED_STATE_KEY] ??= {
|
|
@@ -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
|
|
34287
|
+
var z3 = tool.schema;
|
|
34944
34288
|
|
|
34945
34289
|
class AcpClient {
|
|
34946
34290
|
name;
|
|
@@ -34993,8 +34337,8 @@ class AcpClient {
|
|
|
34993
34337
|
protocolVersion: 1,
|
|
34994
34338
|
clientCapabilities: {},
|
|
34995
34339
|
clientInfo: {
|
|
34996
|
-
name: "oh-my-opencode-
|
|
34997
|
-
title: "oh-my-opencode-
|
|
34340
|
+
name: "oh-my-opencode-serverlocal",
|
|
34341
|
+
title: "oh-my-opencode-serverlocal ACP bridge"
|
|
34998
34342
|
}
|
|
34999
34343
|
});
|
|
35000
34344
|
this.authMethods = readAuthMethods(init);
|
|
@@ -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:
|
|
35164
|
-
prompt:
|
|
35165
|
-
cwd:
|
|
35166
|
-
timeout_ms:
|
|
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) {
|
|
@@ -35314,11 +34658,11 @@ function getCacheDir2() {
|
|
|
35314
34658
|
if (process.platform === "win32") {
|
|
35315
34659
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
35316
34660
|
const base2 = localAppData || join14(homedir6(), "AppData", "Local");
|
|
35317
|
-
return join14(base2, "oh-my-opencode-
|
|
34661
|
+
return join14(base2, "oh-my-opencode-serverlocal", "bin");
|
|
35318
34662
|
}
|
|
35319
34663
|
const xdgCache = process.env.XDG_CACHE_HOME;
|
|
35320
34664
|
const base = xdgCache || join14(homedir6(), ".cache");
|
|
35321
|
-
return join14(base, "oh-my-opencode-
|
|
34665
|
+
return join14(base, "oh-my-opencode-serverlocal", "bin");
|
|
35322
34666
|
}
|
|
35323
34667
|
function getBinaryName() {
|
|
35324
34668
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
@@ -35331,7 +34675,7 @@ async function downloadAstGrep(version = DEFAULT_VERSION) {
|
|
|
35331
34675
|
const platformKey = `${process.platform}-${process.arch}`;
|
|
35332
34676
|
const platformInfo = PLATFORM_MAP[platformKey];
|
|
35333
34677
|
if (!platformInfo) {
|
|
35334
|
-
console.error(`[oh-my-opencode-
|
|
34678
|
+
console.error(`[oh-my-opencode-serverlocal] Unsupported platform for ast-grep: ${platformKey}`);
|
|
35335
34679
|
return null;
|
|
35336
34680
|
}
|
|
35337
34681
|
const cacheDir = getCacheDir2();
|
|
@@ -35343,7 +34687,7 @@ async function downloadAstGrep(version = DEFAULT_VERSION) {
|
|
|
35343
34687
|
const { arch, os: os6 } = platformInfo;
|
|
35344
34688
|
const assetName = `app-${arch}-${os6}.zip`;
|
|
35345
34689
|
const downloadUrl = `https://github.com/${REPO}/releases/download/${version}/${assetName}`;
|
|
35346
|
-
console.log(`[oh-my-opencode-
|
|
34690
|
+
console.log(`[oh-my-opencode-serverlocal] Downloading ast-grep binary...`);
|
|
35347
34691
|
try {
|
|
35348
34692
|
if (!existsSync10(cacheDir)) {
|
|
35349
34693
|
mkdirSync7(cacheDir, { recursive: true });
|
|
@@ -35362,10 +34706,10 @@ async function downloadAstGrep(version = DEFAULT_VERSION) {
|
|
|
35362
34706
|
if (process.platform !== "win32" && existsSync10(binaryPath)) {
|
|
35363
34707
|
chmodSync2(binaryPath, 493);
|
|
35364
34708
|
}
|
|
35365
|
-
console.log(`[oh-my-opencode-
|
|
34709
|
+
console.log(`[oh-my-opencode-serverlocal] ast-grep binary ready.`);
|
|
35366
34710
|
return binaryPath;
|
|
35367
34711
|
} catch (err) {
|
|
35368
|
-
console.error(`[oh-my-opencode-
|
|
34712
|
+
console.error(`[oh-my-opencode-serverlocal] Failed to download ast-grep: ${err instanceof Error ? err.message : err}`);
|
|
35369
34713
|
return null;
|
|
35370
34714
|
}
|
|
35371
34715
|
}
|
|
@@ -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
|
|
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:
|
|
35838
|
-
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
|
|
|
@@ -36406,7 +35684,7 @@ function createPresetManager(ctx, config) {
|
|
|
36406
35684
|
const preset = presets[presetName];
|
|
36407
35685
|
if (!preset) {
|
|
36408
35686
|
const available = Object.keys(presets);
|
|
36409
|
-
const hint = available.length > 0 ? `Available presets: ${available.join(", ")}` : "No presets configured. Define presets in oh-my-opencode-
|
|
35687
|
+
const hint = available.length > 0 ? `Available presets: ${available.join(", ")}` : "No presets configured. Define presets in oh-my-opencode-serverlocal.jsonc.";
|
|
36410
35688
|
output.parts.push(createInternalAgentTextPart(`Preset "${presetName}" not found. ${hint}`));
|
|
36411
35689
|
return;
|
|
36412
35690
|
}
|
|
@@ -36491,7 +35769,7 @@ ${summaryParts.join(`
|
|
|
36491
35769
|
function formatPresetList(presets) {
|
|
36492
35770
|
const names = Object.keys(presets);
|
|
36493
35771
|
if (names.length === 0) {
|
|
36494
|
-
return 'No presets configured. Define presets in oh-my-opencode-
|
|
35772
|
+
return 'No presets configured. Define presets in oh-my-opencode-serverlocal.jsonc under the "presets" field.';
|
|
36495
35773
|
}
|
|
36496
35774
|
const lines = ["Available presets:"];
|
|
36497
35775
|
for (const name of names) {
|
|
@@ -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
|
|
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:
|
|
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 = !!
|
|
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
|
|
37124
|
-
return a && (a.fetch = A ? "stale" : "refresh", v && A && (a.returnedStale = true)), v ?
|
|
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
|
|
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
|
|
37625
|
+
return tool4({
|
|
38348
37626
|
description: WEBFETCH_DESCRIPTION,
|
|
38349
37627
|
args: {
|
|
38350
|
-
url:
|
|
38351
|
-
format:
|
|
38352
|
-
timeout:
|
|
38353
|
-
prompt:
|
|
38354
|
-
extract_main:
|
|
38355
|
-
prefer_llms_txt:
|
|
38356
|
-
include_metadata:
|
|
38357
|
-
save_binary:
|
|
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);
|
|
@@ -38904,7 +38182,7 @@ async function appLog(ctx, level, message) {
|
|
|
38904
38182
|
});
|
|
38905
38183
|
} catch {
|
|
38906
38184
|
const prefix2 = level === "error" ? "ERROR" : level === "warn" ? "WARN" : "INFO";
|
|
38907
|
-
console.error(`[oh-my-opencode-
|
|
38185
|
+
console.error(`[oh-my-opencode-serverlocal] ${prefix2}: ${message}`);
|
|
38908
38186
|
}
|
|
38909
38187
|
}
|
|
38910
38188
|
var HEALTH_CHECK = {
|
|
@@ -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 =
|
|
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);
|
|
@@ -39103,7 +38381,7 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
39103
38381
|
toolCount = Object.keys(tools).length;
|
|
39104
38382
|
} catch (err) {
|
|
39105
38383
|
log("[plugin] FATAL: init failed", String(err));
|
|
39106
|
-
await appLog(ctx, "error", `INIT FAILED: ${String(err)}. Report at github.com/
|
|
38384
|
+
await appLog(ctx, "error", `INIT FAILED: ${String(err)}. Report at github.com/Darthph0enix7/oh-my-opencode-serverlocal/issues/310`);
|
|
39107
38385
|
throw err;
|
|
39108
38386
|
}
|
|
39109
38387
|
const agentCount = Object.keys(agents).length;
|
|
@@ -39117,7 +38395,7 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
39117
38395
|
` mcps: ${mcpCount} (expected >=${mcpThreshold})`,
|
|
39118
38396
|
"This usually means a dependency failed to resolve (jsdom, etc).",
|
|
39119
38397
|
"If you recently updated opencode, see:",
|
|
39120
|
-
" github.com/
|
|
38398
|
+
" github.com/Darthph0enix7/oh-my-opencode-serverlocal/issues/310"
|
|
39121
38399
|
].join(`
|
|
39122
38400
|
`);
|
|
39123
38401
|
log(`[plugin] WARN: ${msg}`);
|
|
@@ -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;
|