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.
- package/README.md +35 -7
- package/dist/agents/council-master.d.ts +2 -0
- package/dist/agents/council.d.ts +28 -0
- package/dist/agents/councillor.d.ts +2 -0
- package/dist/agents/orchestrator.d.ts +6 -0
- package/dist/background/background-manager.d.ts +6 -1
- package/dist/background/index.d.ts +1 -0
- package/dist/background/subagent-depth.d.ts +35 -0
- package/dist/cli/config-io.d.ts +1 -1
- package/dist/cli/custom-skills.d.ts +2 -2
- package/dist/cli/index.js +173 -56
- package/dist/cli/paths.d.ts +22 -0
- package/dist/cli/providers.d.ts +4 -4
- package/dist/cli/types.d.ts +2 -0
- package/dist/config/constants.d.ts +7 -2
- package/dist/config/council-schema.d.ts +134 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/loader.d.ts +2 -1
- package/dist/config/schema.d.ts +27 -0
- package/dist/council/council-manager.d.ts +40 -0
- package/dist/council/index.d.ts +1 -0
- package/dist/hooks/foreground-fallback/index.d.ts +72 -0
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/json-error-recovery/hook.d.ts +1 -1
- package/dist/hooks/phase-reminder/index.d.ts +1 -1
- package/dist/hooks/post-file-tool-nudge/index.d.ts +18 -0
- package/dist/index.js +2273 -879
- package/dist/tools/council.d.ts +9 -0
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/lsp/config-store.d.ts +29 -0
- package/dist/tools/lsp/constants.d.ts +18 -2
- package/dist/tools/lsp/index.d.ts +1 -0
- package/dist/tools/lsp/types.d.ts +7 -0
- package/dist/tools/lsp/utils.d.ts +14 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/session.d.ts +59 -0
- package/oh-my-opencode-slim.schema.json +78 -0
- 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
|
|
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
|
|
51
|
+
return getOpenCodeConfigPaths()[0];
|
|
34
52
|
}
|
|
35
53
|
function getConfigJsonc() {
|
|
36
|
-
return
|
|
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:
|
|
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
|
|
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 {
|
|
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(
|
|
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 =
|
|
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-
|
|
13823
|
-
explorer: { model: "openai/gpt-5-
|
|
13824
|
-
designer: { model: "openai/gpt-5-
|
|
13825
|
-
fixer: { model: "openai/gpt-5-
|
|
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: {
|
|
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
|
-
|
|
14039
|
+
ensureOpenCodeConfigDir();
|
|
13937
14040
|
} catch (err) {
|
|
13938
14041
|
return {
|
|
13939
14042
|
success: false,
|
|
13940
|
-
configPath
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14228
|
-
lines.push(` ${DIM}\u25CB
|
|
14229
|
-
lines.push(` ${DIM}\u25CB
|
|
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
|
-
|
|
14253
|
-
|
|
14254
|
-
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
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
|
-
|
|
14263
|
-
|
|
14264
|
-
|
|
14265
|
-
|
|
14266
|
-
|
|
14267
|
-
|
|
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
|
|
14280
|
-
|
|
14281
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14336
|
-
console.log(`${BOLD}
|
|
14337
|
-
|
|
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() {
|
package/dist/cli/paths.d.ts
CHANGED
|
@@ -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;
|
package/dist/cli/providers.d.ts
CHANGED
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
24
|
+
readonly model: "openai/gpt-5.4-mini";
|
|
25
25
|
readonly variant: "low";
|
|
26
26
|
};
|
|
27
27
|
};
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -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
|
+
}
|