oh-my-opencode-slim 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +35 -7
  2. package/dist/agents/council-master.d.ts +2 -0
  3. package/dist/agents/council.d.ts +28 -0
  4. package/dist/agents/councillor.d.ts +2 -0
  5. package/dist/agents/orchestrator.d.ts +6 -0
  6. package/dist/background/background-manager.d.ts +6 -1
  7. package/dist/background/index.d.ts +1 -0
  8. package/dist/background/subagent-depth.d.ts +35 -0
  9. package/dist/cli/config-io.d.ts +1 -1
  10. package/dist/cli/custom-skills.d.ts +2 -2
  11. package/dist/cli/index.js +173 -56
  12. package/dist/cli/paths.d.ts +22 -0
  13. package/dist/cli/providers.d.ts +4 -4
  14. package/dist/cli/types.d.ts +2 -0
  15. package/dist/config/constants.d.ts +7 -2
  16. package/dist/config/council-schema.d.ts +134 -0
  17. package/dist/config/index.d.ts +1 -0
  18. package/dist/config/loader.d.ts +2 -1
  19. package/dist/config/schema.d.ts +27 -0
  20. package/dist/council/council-manager.d.ts +40 -0
  21. package/dist/council/index.d.ts +1 -0
  22. package/dist/hooks/foreground-fallback/index.d.ts +72 -0
  23. package/dist/hooks/index.d.ts +2 -1
  24. package/dist/hooks/json-error-recovery/hook.d.ts +1 -1
  25. package/dist/hooks/phase-reminder/index.d.ts +1 -1
  26. package/dist/hooks/post-file-tool-nudge/index.d.ts +18 -0
  27. package/dist/index.js +2273 -879
  28. package/dist/tools/council.d.ts +9 -0
  29. package/dist/tools/index.d.ts +2 -2
  30. package/dist/tools/lsp/config-store.d.ts +29 -0
  31. package/dist/tools/lsp/constants.d.ts +18 -2
  32. package/dist/tools/lsp/index.d.ts +1 -0
  33. package/dist/tools/lsp/types.d.ts +7 -0
  34. package/dist/tools/lsp/utils.d.ts +14 -1
  35. package/dist/utils/index.d.ts +1 -0
  36. package/dist/utils/session.d.ts +59 -0
  37. package/oh-my-opencode-slim.schema.json +78 -0
  38. package/package.json +3 -1
package/dist/cli/index.js CHANGED
@@ -11,6 +11,9 @@ var __export = (target, all) => {
11
11
  });
12
12
  };
13
13
 
14
+ // src/cli/install.ts
15
+ import { existsSync as existsSync4 } from "fs";
16
+
14
17
  // src/cli/config-io.ts
15
18
  import {
16
19
  copyFileSync as copyFileSync2,
@@ -24,20 +27,47 @@ import {
24
27
  // src/cli/paths.ts
25
28
  import { existsSync, mkdirSync } from "fs";
26
29
  import { homedir } from "os";
27
- import { join } from "path";
28
- function getConfigDir() {
30
+ import { dirname, join } from "path";
31
+ function getDefaultOpenCodeConfigDir() {
29
32
  const userConfigDir = process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join(homedir(), ".config");
30
33
  return join(userConfigDir, "opencode");
31
34
  }
35
+ function getCustomOpenCodeConfigDir() {
36
+ const configDir = process.env.OPENCODE_CONFIG_DIR?.trim();
37
+ return configDir || undefined;
38
+ }
39
+ function getConfigDir() {
40
+ const customConfigDir = getCustomOpenCodeConfigDir();
41
+ if (customConfigDir) {
42
+ return customConfigDir;
43
+ }
44
+ return getDefaultOpenCodeConfigDir();
45
+ }
46
+ function getOpenCodeConfigPaths() {
47
+ const configDir = getDefaultOpenCodeConfigDir();
48
+ return [join(configDir, "opencode.json"), join(configDir, "opencode.jsonc")];
49
+ }
32
50
  function getConfigJson() {
33
- return join(getConfigDir(), "opencode.json");
51
+ return getOpenCodeConfigPaths()[0];
34
52
  }
35
53
  function getConfigJsonc() {
36
- return join(getConfigDir(), "opencode.jsonc");
54
+ return getOpenCodeConfigPaths()[1];
37
55
  }
38
56
  function getLiteConfig() {
39
57
  return join(getConfigDir(), "oh-my-opencode-slim.json");
40
58
  }
59
+ function getLiteConfigJsonc() {
60
+ return join(getConfigDir(), "oh-my-opencode-slim.jsonc");
61
+ }
62
+ function getExistingLiteConfigPath() {
63
+ const jsonPath = getLiteConfig();
64
+ if (existsSync(jsonPath))
65
+ return jsonPath;
66
+ const jsoncPath = getLiteConfigJsonc();
67
+ if (existsSync(jsoncPath))
68
+ return jsoncPath;
69
+ return jsonPath;
70
+ }
41
71
  function getExistingConfigPath() {
42
72
  const jsonPath = getConfigJson();
43
73
  if (existsSync(jsonPath))
@@ -53,6 +83,12 @@ function ensureConfigDir() {
53
83
  mkdirSync(configDir, { recursive: true });
54
84
  }
55
85
  }
86
+ function ensureOpenCodeConfigDir() {
87
+ const configDir = dirname(getConfigJson());
88
+ if (!existsSync(configDir)) {
89
+ mkdirSync(configDir, { recursive: true });
90
+ }
91
+ }
56
92
 
57
93
  // src/config/constants.ts
58
94
  var SUBAGENT_NAMES = [
@@ -60,7 +96,10 @@ var SUBAGENT_NAMES = [
60
96
  "librarian",
61
97
  "oracle",
62
98
  "designer",
63
- "fixer"
99
+ "fixer",
100
+ "council",
101
+ "councillor",
102
+ "council-master"
64
103
  ];
65
104
  var ORCHESTRATOR_NAME = "orchestrator";
66
105
  var ALL_AGENT_NAMES = [ORCHESTRATOR_NAME, ...SUBAGENT_NAMES];
@@ -2305,7 +2344,7 @@ class Doc {
2305
2344
  var version = {
2306
2345
  major: 4,
2307
2346
  minor: 3,
2308
- patch: 5
2347
+ patch: 6
2309
2348
  };
2310
2349
 
2311
2350
  // node_modules/zod/v4/core/schemas.js
@@ -3591,7 +3630,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
3591
3630
  if (keyResult instanceof Promise) {
3592
3631
  throw new Error("Async schemas not supported in object keys currently");
3593
3632
  }
3594
- const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length && keyResult.issues.some((iss) => iss.code === "invalid_type" && iss.expected === "number");
3633
+ const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
3595
3634
  if (checkNumericKey) {
3596
3635
  const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
3597
3636
  if (retryResult instanceof Promise) {
@@ -10962,7 +11001,7 @@ function finalize(ctx, schema) {
10962
11001
  }
10963
11002
  }
10964
11003
  }
10965
- if (refSchema.$ref) {
11004
+ if (refSchema.$ref && refSeen.def) {
10966
11005
  for (const key in schema2) {
10967
11006
  if (key === "$ref" || key === "allOf")
10968
11007
  continue;
@@ -13598,6 +13637,61 @@ function date4(params) {
13598
13637
 
13599
13638
  // node_modules/zod/v4/classic/external.js
13600
13639
  config(en_default());
13640
+ // src/config/council-schema.ts
13641
+ var ModelIdSchema = exports_external.string().regex(/^[^/\s]+\/[^\s]+$/, 'Expected provider/model format (e.g. "openai/gpt-5.4-mini")');
13642
+ var CouncillorConfigSchema = exports_external.object({
13643
+ model: ModelIdSchema.describe('Model ID in provider/model format (e.g. "openai/gpt-5.4-mini")'),
13644
+ variant: exports_external.string().optional(),
13645
+ prompt: exports_external.string().optional().describe("Optional role/guidance injected into the councillor user prompt")
13646
+ });
13647
+ var PresetMasterOverrideSchema = exports_external.object({
13648
+ model: ModelIdSchema.optional().describe("Override the master model for this preset"),
13649
+ variant: exports_external.string().optional().describe("Override the master variant for this preset"),
13650
+ prompt: exports_external.string().optional().describe("Override the master synthesis guidance for this preset")
13651
+ });
13652
+ var CouncilPresetSchema = exports_external.record(exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())).transform((entries, ctx) => {
13653
+ const councillors = {};
13654
+ let masterOverride;
13655
+ for (const [key, raw] of Object.entries(entries)) {
13656
+ if (key === "master") {
13657
+ const parsed = PresetMasterOverrideSchema.safeParse(raw);
13658
+ if (!parsed.success) {
13659
+ ctx.addIssue(`Invalid master override in preset: ${parsed.error.issues.map((i) => i.message).join(", ")}`);
13660
+ return exports_external.NEVER;
13661
+ }
13662
+ masterOverride = parsed.data;
13663
+ } else {
13664
+ const parsed = CouncillorConfigSchema.safeParse(raw);
13665
+ if (!parsed.success) {
13666
+ ctx.addIssue(`Invalid councillor "${key}": ${parsed.error.issues.map((i) => i.message).join(", ")}`);
13667
+ return exports_external.NEVER;
13668
+ }
13669
+ councillors[key] = parsed.data;
13670
+ }
13671
+ }
13672
+ return { councillors, master: masterOverride };
13673
+ });
13674
+ var CouncilMasterConfigSchema = exports_external.object({
13675
+ model: ModelIdSchema.describe('Model ID for the council master (e.g. "anthropic/claude-opus-4-6")'),
13676
+ variant: exports_external.string().optional(),
13677
+ prompt: exports_external.string().optional().describe("Optional role/guidance injected into the master synthesis prompt")
13678
+ });
13679
+ var CouncilConfigSchema = exports_external.object({
13680
+ master: CouncilMasterConfigSchema,
13681
+ presets: exports_external.record(exports_external.string(), CouncilPresetSchema),
13682
+ master_timeout: exports_external.number().min(0).default(300000),
13683
+ councillors_timeout: exports_external.number().min(0).default(180000),
13684
+ default_preset: exports_external.string().default("default"),
13685
+ master_fallback: exports_external.array(ModelIdSchema).optional().transform((val) => {
13686
+ if (!val)
13687
+ return val;
13688
+ const unique = [...new Set(val)];
13689
+ if (unique.length !== val.length) {
13690
+ return unique;
13691
+ }
13692
+ return val;
13693
+ }).describe("Fallback models for the council master. Tried in order if the primary model fails. " + 'Example: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4"]')
13694
+ });
13601
13695
  // src/config/schema.ts
13602
13696
  var ProviderModelIdSchema = exports_external.string().regex(/^[^/\s]+\/[^\s]+$/, "Expected provider/model format (provider/.../model)");
13603
13697
  var ManualAgentPlanSchema = exports_external.object({
@@ -13672,10 +13766,12 @@ var BackgroundTaskConfigSchema = exports_external.object({
13672
13766
  var FailoverConfigSchema = exports_external.object({
13673
13767
  enabled: exports_external.boolean().default(true),
13674
13768
  timeoutMs: exports_external.number().min(0).default(15000),
13769
+ retryDelayMs: exports_external.number().min(0).default(500),
13675
13770
  chains: FallbackChainsSchema.default({})
13676
13771
  });
13677
13772
  var PluginConfigSchema = exports_external.object({
13678
13773
  preset: exports_external.string().optional(),
13774
+ setDefaultAgent: exports_external.boolean().optional(),
13679
13775
  scoringEngineVersion: exports_external.enum(["v1", "v2-shadow", "v2"]).optional(),
13680
13776
  balanceProviderUsage: exports_external.boolean().optional(),
13681
13777
  manualPlan: ManualPlanSchema.optional(),
@@ -13684,7 +13780,8 @@ var PluginConfigSchema = exports_external.object({
13684
13780
  disabled_mcps: exports_external.array(exports_external.string()).optional(),
13685
13781
  tmux: TmuxConfigSchema.optional(),
13686
13782
  background: BackgroundTaskConfigSchema.optional(),
13687
- fallback: FailoverConfigSchema.optional()
13783
+ fallback: FailoverConfigSchema.optional(),
13784
+ council: CouncilConfigSchema.optional()
13688
13785
  });
13689
13786
  // src/config/agent-mcps.ts
13690
13787
  var DEFAULT_AGENT_MCPS = {
@@ -13693,7 +13790,10 @@ var DEFAULT_AGENT_MCPS = {
13693
13790
  oracle: [],
13694
13791
  librarian: ["websearch", "context7", "grep_app"],
13695
13792
  explorer: [],
13696
- fixer: []
13793
+ fixer: [],
13794
+ council: [],
13795
+ councillor: [],
13796
+ "council-master": []
13697
13797
  };
13698
13798
 
13699
13799
  // src/cli/skills.ts
@@ -13707,8 +13807,7 @@ import {
13707
13807
  readdirSync,
13708
13808
  statSync
13709
13809
  } from "fs";
13710
- import { homedir as homedir2 } from "os";
13711
- import { dirname, join as join2 } from "path";
13810
+ import { dirname as dirname2, join as join2 } from "path";
13712
13811
  import { fileURLToPath } from "url";
13713
13812
  var CUSTOM_SKILLS = [
13714
13813
  {
@@ -13719,7 +13818,7 @@ var CUSTOM_SKILLS = [
13719
13818
  }
13720
13819
  ];
13721
13820
  function getCustomSkillsDir() {
13722
- return join2(homedir2(), ".config", "opencode", "skills");
13821
+ return join2(getConfigDir(), "skills");
13723
13822
  }
13724
13823
  function copyDirRecursive(src, dest) {
13725
13824
  if (!existsSync2(dest)) {
@@ -13733,7 +13832,7 @@ function copyDirRecursive(src, dest) {
13733
13832
  if (stat.isDirectory()) {
13734
13833
  copyDirRecursive(srcPath, destPath);
13735
13834
  } else {
13736
- const destDir = dirname(destPath);
13835
+ const destDir = dirname2(destPath);
13737
13836
  if (!existsSync2(destDir)) {
13738
13837
  mkdirSync2(destDir, { recursive: true });
13739
13838
  }
@@ -13819,10 +13918,10 @@ var MODEL_MAPPINGS = {
13819
13918
  openai: {
13820
13919
  orchestrator: { model: "openai/gpt-5.4" },
13821
13920
  oracle: { model: "openai/gpt-5.4", variant: "high" },
13822
- librarian: { model: "openai/gpt-5-codex", variant: "low" },
13823
- explorer: { model: "openai/gpt-5-codex", variant: "low" },
13824
- designer: { model: "openai/gpt-5-codex", variant: "medium" },
13825
- fixer: { model: "openai/gpt-5-codex", variant: "low" }
13921
+ librarian: { model: "openai/gpt-5.4-mini", variant: "low" },
13922
+ explorer: { model: "openai/gpt-5.4-mini", variant: "low" },
13923
+ designer: { model: "openai/gpt-5.4-mini", variant: "medium" },
13924
+ fixer: { model: "openai/gpt-5.4-mini", variant: "low" }
13826
13925
  },
13827
13926
  kimi: {
13828
13927
  orchestrator: { model: "kimi-for-coding/k2p5" },
@@ -13837,7 +13936,10 @@ var MODEL_MAPPINGS = {
13837
13936
  oracle: { model: "github-copilot/claude-opus-4.6", variant: "high" },
13838
13937
  librarian: { model: "github-copilot/grok-code-fast-1", variant: "low" },
13839
13938
  explorer: { model: "github-copilot/grok-code-fast-1", variant: "low" },
13840
- designer: { model: "github-copilot/gemini-3.1-pro-preview", variant: "medium" },
13939
+ designer: {
13940
+ model: "github-copilot/gemini-3.1-pro-preview",
13941
+ variant: "medium"
13942
+ },
13841
13943
  fixer: { model: "github-copilot/claude-sonnet-4.6", variant: "low" }
13842
13944
  },
13843
13945
  "zai-plan": {
@@ -13932,16 +14034,16 @@ function writeConfig(configPath, config2) {
13932
14034
  renameSync(tmpPath, configPath);
13933
14035
  }
13934
14036
  async function addPluginToOpenCodeConfig() {
14037
+ const configPath = getExistingConfigPath();
13935
14038
  try {
13936
- ensureConfigDir();
14039
+ ensureOpenCodeConfigDir();
13937
14040
  } catch (err) {
13938
14041
  return {
13939
14042
  success: false,
13940
- configPath: getConfigDir(),
14043
+ configPath,
13941
14044
  error: `Failed to create config directory: ${err}`
13942
14045
  };
13943
14046
  }
13944
- const configPath = getExistingConfigPath();
13945
14047
  try {
13946
14048
  const { config: parsedConfig, error: error48 } = parseConfig(configPath);
13947
14049
  if (error48) {
@@ -13966,8 +14068,8 @@ async function addPluginToOpenCodeConfig() {
13966
14068
  };
13967
14069
  }
13968
14070
  }
13969
- function writeLiteConfig(installConfig) {
13970
- const configPath = getLiteConfig();
14071
+ function writeLiteConfig(installConfig, targetPath) {
14072
+ const configPath = targetPath ?? getLiteConfig();
13971
14073
  try {
13972
14074
  ensureConfigDir();
13973
14075
  const config2 = generateLiteConfig(installConfig);
@@ -13992,7 +14094,7 @@ function writeLiteConfig(installConfig) {
13992
14094
  function disableDefaultAgents() {
13993
14095
  const configPath = getExistingConfigPath();
13994
14096
  try {
13995
- ensureConfigDir();
14097
+ ensureOpenCodeConfigDir();
13996
14098
  const { config: parsedConfig, error: error48 } = parseConfig(configPath);
13997
14099
  if (error48) {
13998
14100
  return {
@@ -14207,7 +14309,9 @@ async function checkOpenCodeInstalled() {
14207
14309
  }
14208
14310
  const version2 = await getOpenCodeVersion();
14209
14311
  const path = getOpenCodePath();
14210
- printSuccess(`OpenCode ${version2 ?? ""} detected${path ? ` (${DIM}${path}${RESET})` : ""}`);
14312
+ const detectedVersion = version2 ?? "";
14313
+ const pathInfo = path ? ` (${DIM}${path}${RESET})` : "";
14314
+ printSuccess(`OpenCode ${detectedVersion} detected${pathInfo}`);
14211
14315
  return { ok: true, version: version2 ?? undefined, path: path ?? undefined };
14212
14316
  }
14213
14317
  function handleStepResult(result, successMsg) {
@@ -14224,9 +14328,10 @@ function formatConfigSummary() {
14224
14328
  lines.push("");
14225
14329
  lines.push(` ${BOLD}Preset:${RESET} ${BLUE}openai${RESET}`);
14226
14330
  lines.push(` ${SYMBOLS.check} OpenAI (default)`);
14227
- lines.push(` ${DIM}\u25CB Kimi \u2014 see docs/provider-configurations.md${RESET}`);
14228
- lines.push(` ${DIM}\u25CB GitHub Copilot \u2014 see docs/provider-configurations.md${RESET}`);
14229
- lines.push(` ${DIM}\u25CB ZAI Coding Plan \u2014 see docs/provider-configurations.md${RESET}`);
14331
+ const seeDocs = "see docs/provider-configurations.md";
14332
+ lines.push(` ${DIM}\u25CB Kimi \u2014 ${seeDocs}${RESET}`);
14333
+ lines.push(` ${DIM}\u25CB GitHub Copilot \u2014 ${seeDocs}${RESET}`);
14334
+ lines.push(` ${DIM}\u25CB ZAI Coding Plan \u2014 ${seeDocs}${RESET}`);
14230
14335
  return lines.join(`
14231
14336
  `);
14232
14337
  }
@@ -14248,25 +14353,21 @@ async function runInstall(config2) {
14248
14353
  if (!ok)
14249
14354
  return 1;
14250
14355
  }
14251
- {
14252
- printStep(step++, totalSteps, "Adding oh-my-opencode-slim plugin...");
14253
- if (config2.dryRun) {
14254
- printInfo("Dry run mode - skipping plugin installation");
14255
- } else {
14256
- const pluginResult = await addPluginToOpenCodeConfig();
14257
- if (!handleStepResult(pluginResult, "Plugin added"))
14258
- return 1;
14259
- }
14356
+ printStep(step++, totalSteps, "Adding oh-my-opencode-slim plugin...");
14357
+ if (config2.dryRun) {
14358
+ printInfo("Dry run mode - skipping plugin installation");
14359
+ } else {
14360
+ const pluginResult = await addPluginToOpenCodeConfig();
14361
+ if (!handleStepResult(pluginResult, "Plugin added"))
14362
+ return 1;
14260
14363
  }
14261
- {
14262
- printStep(step++, totalSteps, "Disabling OpenCode default agents...");
14263
- if (config2.dryRun) {
14264
- printInfo("Dry run mode - skipping agent disabling");
14265
- } else {
14266
- const agentResult = disableDefaultAgents();
14267
- if (!handleStepResult(agentResult, "Default agents disabled"))
14268
- return 1;
14269
- }
14364
+ printStep(step++, totalSteps, "Disabling OpenCode default agents...");
14365
+ if (config2.dryRun) {
14366
+ printInfo("Dry run mode - skipping agent disabling");
14367
+ } else {
14368
+ const agentResult = disableDefaultAgents();
14369
+ if (!handleStepResult(agentResult, "Default agents disabled"))
14370
+ return 1;
14270
14371
  }
14271
14372
  printStep(step++, totalSteps, "Writing oh-my-opencode-slim configuration...");
14272
14373
  if (config2.dryRun) {
@@ -14276,9 +14377,15 @@ async function runInstall(config2) {
14276
14377
  ${JSON.stringify(liteConfig, null, 2)}
14277
14378
  `);
14278
14379
  } else {
14279
- const liteResult = writeLiteConfig(config2);
14280
- if (!handleStepResult(liteResult, "Config written"))
14281
- return 1;
14380
+ const configPath = getExistingLiteConfigPath();
14381
+ const configExists = existsSync4(configPath);
14382
+ if (configExists && !config2.reset) {
14383
+ printInfo(`Configuration already exists at ${configPath}. ` + "Use --reset to overwrite.");
14384
+ } else {
14385
+ const liteResult = writeLiteConfig(config2, configExists ? configPath : undefined);
14386
+ if (!handleStepResult(liteResult, configExists ? "Config reset" : "Config written"))
14387
+ return 1;
14388
+ }
14282
14389
  }
14283
14390
  if (config2.installSkills) {
14284
14391
  printStep(step++, totalSteps, "Installing recommended skills...");
@@ -14319,22 +14426,27 @@ ${JSON.stringify(liteConfig, null, 2)}
14319
14426
  printInfo(`Skipped: ${skill.name} (already installed)`);
14320
14427
  }
14321
14428
  }
14322
- printSuccess(`${customSkillsInstalled}/${CUSTOM_SKILLS.length} custom skills processed`);
14429
+ const totalCustom = CUSTOM_SKILLS.length;
14430
+ printSuccess(`${customSkillsInstalled}/${totalCustom} custom skills processed`);
14323
14431
  }
14324
14432
  }
14325
14433
  console.log();
14326
14434
  console.log(formatConfigSummary());
14327
14435
  console.log();
14328
- console.log(`${SYMBOLS.star} ${BOLD}${GREEN}${isUpdate ? "Configuration updated!" : "Installation complete!"}${RESET}`);
14436
+ const statusMsg = isUpdate ? "Configuration updated!" : "Installation complete!";
14437
+ console.log(`${SYMBOLS.star} ${BOLD}${GREEN}${statusMsg}${RESET}`);
14329
14438
  console.log();
14330
14439
  console.log(`${BOLD}Next steps:${RESET}`);
14331
14440
  console.log();
14332
14441
  console.log(` 1. Start OpenCode:`);
14333
14442
  console.log(` ${BLUE}$ opencode${RESET}`);
14334
14443
  console.log();
14335
- console.log(`${BOLD}Default configuration uses OpenAI models (gpt-5.4 / gpt-5-codex).${RESET}`);
14336
- console.log(`${BOLD}For alternative providers (Kimi, GitHub Copilot, ZAI Coding Plan), see:${RESET}`);
14337
- console.log(` ${BLUE}https://github.com/alvinunreal/oh-my-opencode-slim/blob/main/docs/provider-configurations.md${RESET}`);
14444
+ const modelsInfo = "Default configuration uses OpenAI models (gpt-5.4 / gpt-5.4-mini).";
14445
+ console.log(`${BOLD}${modelsInfo}${RESET}`);
14446
+ const altProviders = "For alternative providers (Kimi, GitHub Copilot, ZAI Coding Plan)";
14447
+ console.log(`${BOLD}${altProviders}, see:${RESET}`);
14448
+ const docsUrl = "https://github.com/alvinunreal/oh-my-opencode-slim/" + "blob/master/docs/provider-configurations.md";
14449
+ console.log(` ${BLUE}${docsUrl}${RESET}`);
14338
14450
  console.log();
14339
14451
  return 0;
14340
14452
  }
@@ -14343,7 +14455,8 @@ async function install(args) {
14343
14455
  hasTmux: args.tmux === "yes",
14344
14456
  installSkills: args.skills === "yes",
14345
14457
  installCustomSkills: args.skills === "yes",
14346
- dryRun: args.dryRun
14458
+ dryRun: args.dryRun,
14459
+ reset: args.reset ?? false
14347
14460
  };
14348
14461
  return runInstall(config2);
14349
14462
  }
@@ -14362,6 +14475,8 @@ function parseArgs(args) {
14362
14475
  result.skills = arg.split("=")[1];
14363
14476
  } else if (arg === "--dry-run") {
14364
14477
  result.dryRun = true;
14478
+ } else if (arg === "--reset") {
14479
+ result.reset = true;
14365
14480
  } else if (arg === "-h" || arg === "--help") {
14366
14481
  printHelp();
14367
14482
  process.exit(0);
@@ -14380,6 +14495,7 @@ Options:
14380
14495
  --skills=yes|no Install recommended skills (yes/no)
14381
14496
  --no-tui Non-interactive mode
14382
14497
  --dry-run Simulate install without writing files
14498
+ --reset Force overwrite of existing configuration
14383
14499
  -h, --help Show this help message
14384
14500
 
14385
14501
  The installer generates an OpenAI configuration by default.
@@ -14388,6 +14504,7 @@ For alternative providers, see docs/provider-configurations.md.
14388
14504
  Examples:
14389
14505
  bunx oh-my-opencode-slim install
14390
14506
  bunx oh-my-opencode-slim install --no-tui --tmux=no --skills=yes
14507
+ bunx oh-my-opencode-slim install --reset
14391
14508
  `);
14392
14509
  }
14393
14510
  async function main() {
@@ -1,4 +1,22 @@
1
+ /**
2
+ * Get the OpenCode plugin config directory.
3
+ *
4
+ * Resolution order:
5
+ * 1. OPENCODE_CONFIG_DIR (custom OpenCode directory)
6
+ * 2. XDG_CONFIG_HOME/opencode
7
+ * 3. ~/.config/opencode
8
+ */
1
9
  export declare function getConfigDir(): string;
10
+ /**
11
+ * Get OpenCode config directories in read/search order.
12
+ *
13
+ * Resolution order:
14
+ * 1. OPENCODE_CONFIG_DIR (if set)
15
+ * 2. XDG_CONFIG_HOME/opencode or ~/.config/opencode
16
+ *
17
+ * Duplicate entries are removed.
18
+ */
19
+ export declare function getConfigSearchDirs(): string[];
2
20
  export declare function getOpenCodeConfigPaths(): string[];
3
21
  export declare function getConfigJson(): string;
4
22
  export declare function getConfigJsonc(): string;
@@ -7,3 +25,7 @@ export declare function getLiteConfigJsonc(): string;
7
25
  export declare function getExistingLiteConfigPath(): string;
8
26
  export declare function getExistingConfigPath(): string;
9
27
  export declare function ensureConfigDir(): void;
28
+ /**
29
+ * Ensure the directory for OpenCode's main config file exists.
30
+ */
31
+ export declare function ensureOpenCodeConfigDir(): void;
@@ -9,19 +9,19 @@ export declare const MODEL_MAPPINGS: {
9
9
  readonly variant: "high";
10
10
  };
11
11
  readonly librarian: {
12
- readonly model: "openai/gpt-5-codex";
12
+ readonly model: "openai/gpt-5.4-mini";
13
13
  readonly variant: "low";
14
14
  };
15
15
  readonly explorer: {
16
- readonly model: "openai/gpt-5-codex";
16
+ readonly model: "openai/gpt-5.4-mini";
17
17
  readonly variant: "low";
18
18
  };
19
19
  readonly designer: {
20
- readonly model: "openai/gpt-5-codex";
20
+ readonly model: "openai/gpt-5.4-mini";
21
21
  readonly variant: "medium";
22
22
  };
23
23
  readonly fixer: {
24
- readonly model: "openai/gpt-5-codex";
24
+ readonly model: "openai/gpt-5.4-mini";
25
25
  readonly variant: "low";
26
26
  };
27
27
  };
@@ -4,6 +4,7 @@ export interface InstallArgs {
4
4
  tmux?: BooleanArg;
5
5
  skills?: BooleanArg;
6
6
  dryRun?: boolean;
7
+ reset?: boolean;
7
8
  }
8
9
  export interface OpenCodeConfig {
9
10
  plugin?: string[];
@@ -16,6 +17,7 @@ export interface InstallConfig {
16
17
  installSkills: boolean;
17
18
  installCustomSkills: boolean;
18
19
  dryRun?: boolean;
20
+ reset: boolean;
19
21
  }
20
22
  export interface ConfigMergeResult {
21
23
  success: boolean;
@@ -1,8 +1,9 @@
1
1
  export declare const AGENT_ALIASES: Record<string, string>;
2
- export declare const SUBAGENT_NAMES: readonly ["explorer", "librarian", "oracle", "designer", "fixer"];
2
+ export declare const SUBAGENT_NAMES: readonly ["explorer", "librarian", "oracle", "designer", "fixer", "council", "councillor", "council-master"];
3
3
  export declare const ORCHESTRATOR_NAME: "orchestrator";
4
- export declare const ALL_AGENT_NAMES: readonly ["orchestrator", "explorer", "librarian", "oracle", "designer", "fixer"];
4
+ export declare const ALL_AGENT_NAMES: readonly ["orchestrator", "explorer", "librarian", "oracle", "designer", "fixer", "council", "councillor", "council-master"];
5
5
  export type AgentName = (typeof ALL_AGENT_NAMES)[number];
6
+ export declare const ORCHESTRATABLE_AGENTS: readonly ["explorer", "librarian", "oracle", "designer", "fixer", "council"];
6
7
  export declare const SUBAGENT_DELEGATION_RULES: Record<AgentName, readonly string[]>;
7
8
  export declare const DEFAULT_MODELS: Record<AgentName, string | undefined>;
8
9
  export declare const POLL_INTERVAL_MS = 500;
@@ -11,4 +12,8 @@ export declare const POLL_INTERVAL_BACKGROUND_MS = 2000;
11
12
  export declare const DEFAULT_TIMEOUT_MS: number;
12
13
  export declare const MAX_POLL_TIME_MS: number;
13
14
  export declare const FALLBACK_FAILOVER_TIMEOUT_MS = 15000;
15
+ export declare const DEFAULT_MAX_SUBAGENT_DEPTH = 3;
16
+ export declare const PHASE_REMINDER_TEXT = "Recall Workflow Rules:\nUnderstand \u2192 build the best path (delegated based on Agent rules, split and parallelized as much as possible) \u2192 execute \u2192 verify.\nIf delegating, launch the specialist in the same turn you mention it.";
17
+ export declare const TMUX_SPAWN_DELAY_MS = 500;
18
+ export declare const COUNCILLOR_STAGGER_MS = 250;
14
19
  export declare const STABLE_POLLS_THRESHOLD = 3;
@@ -0,0 +1,134 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Configuration for a single councillor within a preset.
4
+ * Each councillor is an independent LLM that processes the same prompt.
5
+ *
6
+ * Councillors run as agent sessions with read-only codebase access
7
+ * (read, glob, grep, lsp, list). They can examine the codebase but
8
+ * cannot modify files or spawn subagents.
9
+ */
10
+ export declare const CouncillorConfigSchema: z.ZodObject<{
11
+ model: z.ZodString;
12
+ variant: z.ZodOptional<z.ZodString>;
13
+ prompt: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strip>;
15
+ export type CouncillorConfig = z.infer<typeof CouncillorConfigSchema>;
16
+ /**
17
+ * Per-preset master override. All fields are optional — any field
18
+ * provided here overrides the global `council.master` for this preset.
19
+ * Fields not provided fall back to the global master config.
20
+ */
21
+ export declare const PresetMasterOverrideSchema: z.ZodObject<{
22
+ model: z.ZodOptional<z.ZodString>;
23
+ variant: z.ZodOptional<z.ZodString>;
24
+ prompt: z.ZodOptional<z.ZodString>;
25
+ }, z.core.$strip>;
26
+ export type PresetMasterOverride = z.infer<typeof PresetMasterOverrideSchema>;
27
+ /**
28
+ * A named preset grouping several councillors with an optional master override.
29
+ *
30
+ * The reserved key `"master"` provides per-preset overrides for the council
31
+ * master (model, variant, prompt). All other keys are treated as councillor
32
+ * names mapping to councillor configs.
33
+ *
34
+ * After parsing, the preset resolves to:
35
+ * `{ councillors: Record<string, CouncillorConfig>, master?: PresetMasterOverride }`
36
+ */
37
+ export declare const CouncilPresetSchema: z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, z.ZodTransform<{
38
+ councillors: Record<string, {
39
+ model: string;
40
+ variant?: string | undefined;
41
+ prompt?: string | undefined;
42
+ }>;
43
+ master: {
44
+ model?: string | undefined;
45
+ variant?: string | undefined;
46
+ prompt?: string | undefined;
47
+ } | undefined;
48
+ }, Record<string, Record<string, unknown>>>>;
49
+ export type CouncilPreset = z.infer<typeof CouncilPresetSchema>;
50
+ /**
51
+ * Council Master configuration.
52
+ * The master receives all councillor responses and produces the final synthesis.
53
+ *
54
+ * Note: The master runs as a council-master agent session with zero
55
+ * permissions (deny all). Synthesis is a text-in/text-out operation —
56
+ * no tools or MCPs are needed.
57
+ */
58
+ export declare const CouncilMasterConfigSchema: z.ZodObject<{
59
+ model: z.ZodString;
60
+ variant: z.ZodOptional<z.ZodString>;
61
+ prompt: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strip>;
63
+ export type CouncilMasterConfig = z.infer<typeof CouncilMasterConfigSchema>;
64
+ /**
65
+ * Top-level council configuration.
66
+ *
67
+ * Example JSONC:
68
+ * ```jsonc
69
+ * {
70
+ * "council": {
71
+ * "master": { "model": "anthropic/claude-opus-4-6" },
72
+ * "presets": {
73
+ * "default": {
74
+ * "alpha": { "model": "openai/gpt-5.4-mini" },
75
+ * "beta": { "model": "openai/gpt-5.3-codex" },
76
+ * "gamma": { "model": "google/gemini-3-pro" }
77
+ * }
78
+ * },
79
+ * "master_timeout": 300000,
80
+ * "councillors_timeout": 180000
81
+ * }
82
+ * }
83
+ * ```
84
+ */
85
+ export declare const CouncilConfigSchema: z.ZodObject<{
86
+ master: z.ZodObject<{
87
+ model: z.ZodString;
88
+ variant: z.ZodOptional<z.ZodString>;
89
+ prompt: z.ZodOptional<z.ZodString>;
90
+ }, z.core.$strip>;
91
+ presets: z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, z.ZodTransform<{
92
+ councillors: Record<string, {
93
+ model: string;
94
+ variant?: string | undefined;
95
+ prompt?: string | undefined;
96
+ }>;
97
+ master: {
98
+ model?: string | undefined;
99
+ variant?: string | undefined;
100
+ prompt?: string | undefined;
101
+ } | undefined;
102
+ }, Record<string, Record<string, unknown>>>>>;
103
+ master_timeout: z.ZodDefault<z.ZodNumber>;
104
+ councillors_timeout: z.ZodDefault<z.ZodNumber>;
105
+ default_preset: z.ZodDefault<z.ZodString>;
106
+ master_fallback: z.ZodPipe<z.ZodOptional<z.ZodArray<z.ZodString>>, z.ZodTransform<string[] | undefined, string[] | undefined>>;
107
+ }, z.core.$strip>;
108
+ export type CouncilConfig = z.infer<typeof CouncilConfigSchema>;
109
+ /**
110
+ * A sensible default council configuration that users can copy into their
111
+ * opencode.jsonc. Provides a 3-councillor preset using common models.
112
+ *
113
+ * Users should replace models with ones they have access to.
114
+ *
115
+ * ```jsonc
116
+ * "council": DEFAULT_COUNCIL_CONFIG
117
+ * ```
118
+ */
119
+ export declare const DEFAULT_COUNCIL_CONFIG: z.input<typeof CouncilConfigSchema>;
120
+ /**
121
+ * Result of a council session.
122
+ */
123
+ export interface CouncilResult {
124
+ success: boolean;
125
+ result?: string;
126
+ error?: string;
127
+ councillorResults: Array<{
128
+ name: string;
129
+ model: string;
130
+ status: 'completed' | 'failed' | 'timed_out';
131
+ result?: string;
132
+ error?: string;
133
+ }>;
134
+ }