oh-my-opencode-slim 2.1.1 → 2.2.0
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.ja-JP.md +13 -12
- package/README.ko-KR.md +13 -12
- package/README.md +29 -16
- package/README.zh-CN.md +13 -12
- package/dist/agents/index.d.ts +0 -4
- package/dist/cli/index.js +49 -6
- package/dist/config/constants.d.ts +10 -0
- package/dist/config/schema.d.ts +680 -2
- package/dist/config/strip-orchestrator-model.d.ts +9 -0
- package/dist/hooks/command-hook-utils.d.ts +5 -0
- package/dist/hooks/foreground-fallback/index.d.ts +40 -28
- package/dist/hooks/image-hook.d.ts +1 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/index.js +1871 -326
- package/dist/interview/document.d.ts +2 -1
- package/dist/interview/ui.d.ts +0 -1
- package/dist/multiplexer/cmux/close-policy.d.ts +20 -0
- package/dist/multiplexer/cmux/index.d.ts +102 -0
- package/dist/multiplexer/cmux/session-lifecycle.d.ts +92 -0
- package/dist/multiplexer/cmux/session-state.d.ts +45 -0
- package/dist/multiplexer/factory.d.ts +0 -9
- package/dist/multiplexer/herdr/index.d.ts +2 -0
- package/dist/multiplexer/index.d.ts +3 -1
- package/dist/multiplexer/session-manager.d.ts +10 -2
- package/dist/multiplexer/shared.d.ts +8 -1
- package/dist/multiplexer/types.d.ts +5 -2
- package/dist/tools/smartfetch/utils.d.ts +3 -1
- package/dist/tui-state.d.ts +5 -5
- package/dist/tui.js +86 -20
- package/dist/utils/escape-html.d.ts +1 -0
- package/dist/utils/frontmatter.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/logger.d.ts +0 -2
- package/oh-my-opencode-slim.schema.json +717 -2
- package/package.json +1 -1
- package/src/skills/clonedeps/SKILL.md +32 -29
- package/src/skills/codemap.md +7 -3
- package/src/skills/deepwork/SKILL.md +17 -6
- package/src/skills/verification-planning/SKILL.md +103 -0
- package/src/skills/worktrees/SKILL.md +14 -7
package/dist/tui.js
CHANGED
|
@@ -155,6 +155,13 @@ var NO_SHELL_READONLY_FILE_OPERATIONS_RULES = `**File Operations Rules**:
|
|
|
155
155
|
var TMUX_SPAWN_DELAY_MS = 500;
|
|
156
156
|
var COUNCILLOR_STAGGER_MS = 250;
|
|
157
157
|
var DEFAULT_DISABLED_AGENTS = ["observer"];
|
|
158
|
+
var DEFAULT_MAX_SESSIONS_PER_AGENT = 2;
|
|
159
|
+
var DEFAULT_READ_CONTEXT_MIN_LINES = 10;
|
|
160
|
+
var DEFAULT_READ_CONTEXT_MAX_FILES = 8;
|
|
161
|
+
var DEFAULT_IMAGE_ROUTING = "auto";
|
|
162
|
+
function resolveImageRouting(imageRouting) {
|
|
163
|
+
return imageRouting ?? DEFAULT_IMAGE_ROUTING;
|
|
164
|
+
}
|
|
158
165
|
|
|
159
166
|
// src/config/loader.ts
|
|
160
167
|
import * as fs from "node:fs";
|
|
@@ -307,6 +314,33 @@ var ManualPlanSchema = z2.object({
|
|
|
307
314
|
librarian: ManualAgentPlanSchema,
|
|
308
315
|
fixer: ManualAgentPlanSchema
|
|
309
316
|
}).strict();
|
|
317
|
+
var PermissionActionSchema = z2.enum(["ask", "allow", "deny"]);
|
|
318
|
+
var PermissionRuleSchema = z2.union([
|
|
319
|
+
PermissionActionSchema,
|
|
320
|
+
z2.record(z2.string(), PermissionActionSchema)
|
|
321
|
+
]);
|
|
322
|
+
var PermissionObjectSchema = z2.object({
|
|
323
|
+
read: PermissionRuleSchema.optional(),
|
|
324
|
+
edit: PermissionRuleSchema.optional(),
|
|
325
|
+
glob: PermissionRuleSchema.optional(),
|
|
326
|
+
grep: PermissionRuleSchema.optional(),
|
|
327
|
+
list: PermissionRuleSchema.optional(),
|
|
328
|
+
bash: PermissionRuleSchema.optional(),
|
|
329
|
+
task: PermissionRuleSchema.optional(),
|
|
330
|
+
external_directory: PermissionRuleSchema.optional(),
|
|
331
|
+
lsp: PermissionRuleSchema.optional(),
|
|
332
|
+
skill: PermissionRuleSchema.optional(),
|
|
333
|
+
todowrite: PermissionActionSchema.optional(),
|
|
334
|
+
question: PermissionActionSchema.optional(),
|
|
335
|
+
webfetch: PermissionActionSchema.optional(),
|
|
336
|
+
websearch: PermissionActionSchema.optional(),
|
|
337
|
+
codesearch: PermissionActionSchema.optional(),
|
|
338
|
+
doom_loop: PermissionActionSchema.optional()
|
|
339
|
+
}).catchall(PermissionRuleSchema);
|
|
340
|
+
var PermissionConfigSchema = z2.union([
|
|
341
|
+
PermissionActionSchema,
|
|
342
|
+
PermissionObjectSchema
|
|
343
|
+
]);
|
|
310
344
|
var AgentOverrideConfigSchema = z2.object({
|
|
311
345
|
model: z2.union([
|
|
312
346
|
z2.string(),
|
|
@@ -325,13 +359,15 @@ var AgentOverrideConfigSchema = z2.object({
|
|
|
325
359
|
prompt: z2.string().min(1).optional(),
|
|
326
360
|
orchestratorPrompt: z2.string().min(1).optional(),
|
|
327
361
|
options: z2.record(z2.string(), z2.unknown()).optional(),
|
|
328
|
-
displayName: z2.string().min(1).optional()
|
|
362
|
+
displayName: z2.string().min(1).optional(),
|
|
363
|
+
permission: PermissionConfigSchema.optional()
|
|
329
364
|
}).strict();
|
|
330
365
|
var MultiplexerTypeSchema = z2.enum([
|
|
331
366
|
"auto",
|
|
332
367
|
"tmux",
|
|
333
368
|
"zellij",
|
|
334
369
|
"herdr",
|
|
370
|
+
"cmux",
|
|
335
371
|
"none"
|
|
336
372
|
]);
|
|
337
373
|
var MultiplexerLayoutSchema = z2.enum([
|
|
@@ -377,7 +413,7 @@ var FailoverConfigSchema = z2.object({
|
|
|
377
413
|
retryDelayMs: z2.number().min(0).default(500),
|
|
378
414
|
maxRetries: z2.number().int().min(0).default(3).describe("Number of consecutive 429/rate-limit responses tolerated on the " + "same model before aborting (or swapping to the next fallback " + "model when a chain is configured)."),
|
|
379
415
|
retry_on_empty: z2.boolean().default(true).describe("When true (default), empty provider responses are treated as failures, " + "triggering fallback/retry. Set to false to treat them as successes."),
|
|
380
|
-
runtimeOverride: z2.boolean().
|
|
416
|
+
runtimeOverride: z2.boolean().optional().describe("DEPRECATED: no longer used. Previously controlled whether out-of-chain " + "runtime model picks triggered fallback. Fallback is now always " + "disabled when a user explicitly selects a model via /model.")
|
|
381
417
|
}).strict();
|
|
382
418
|
var CompanionConfigSchema = z2.object({
|
|
383
419
|
enabled: z2.boolean().optional(),
|
|
@@ -419,11 +455,13 @@ var PluginConfigSchema = z2.object({
|
|
|
419
455
|
preset: z2.string().optional(),
|
|
420
456
|
setDefaultAgent: z2.boolean().optional(),
|
|
421
457
|
compactSidebar: z2.boolean().optional().describe("Use the compact TUI sidebar layout. Defaults to true; set false to use the expanded layout."),
|
|
458
|
+
stripOrchestratorModel: z2.boolean().optional().describe("When true, omit orchestrator.model and orchestrator.variant from the SDK config so OpenCode uses the session model selected with /model after subagent dispatch. An explicitly selected preset that sets orchestrator.model is preserved. Defaults to false."),
|
|
422
459
|
autoUpdate: z2.boolean().optional().describe("Disable automatic installation of plugin updates when false. Defaults to true."),
|
|
423
460
|
presets: z2.record(z2.string(), PresetSchema).optional(),
|
|
424
461
|
agents: z2.record(z2.string(), AgentOverrideConfigSchema).optional(),
|
|
425
462
|
disabled_agents: z2.array(z2.string()).optional().describe("Agent names to disable completely. " + "Disabled agents are not instantiated and cannot be delegated to. " + "Orchestrator and council internal agents (councillor) cannot be disabled. " + "By default, 'observer' is disabled. Remove it from this list and configure a vision-capable model to enable."),
|
|
426
|
-
|
|
463
|
+
image_routing: z2.enum(["auto", "direct"]).optional().describe("How image attachments are handled. " + "When omitted, preserves legacy conditional behavior: intercept " + 'attachments only when observer is enabled. "auto": requires ' + "observer to be enabled and saves attachments to disk before " + 'nudging delegation to @observer. "direct": always passes ' + "attachments to the orchestrator untouched."),
|
|
464
|
+
disabled_mcps: z2.array(z2.string()).optional().describe("MCP server names to disable completely. Disabled servers are not " + "started and cannot be used by agents."),
|
|
427
465
|
disabled_tools: z2.array(z2.string()).optional().describe("Tool names to disable completely. Disabled tools are not registered with OpenCode and cannot be used by agents."),
|
|
428
466
|
disabled_skills: z2.array(z2.string()).optional().describe("Skill names to disable completely. Disabled skills are not granted to agents, even when referenced by presets or agent overrides."),
|
|
429
467
|
multiplexer: MultiplexerConfigSchema.optional(),
|
|
@@ -526,6 +564,12 @@ var CUSTOM_SKILLS = [
|
|
|
526
564
|
allowedAgents: ["orchestrator"],
|
|
527
565
|
sourcePath: "src/skills/deepwork"
|
|
528
566
|
},
|
|
567
|
+
{
|
|
568
|
+
name: "verification-planning",
|
|
569
|
+
description: "Plan credible, proportionate evidence before non-trivial implementation",
|
|
570
|
+
allowedAgents: ["orchestrator"],
|
|
571
|
+
sourcePath: "src/skills/verification-planning"
|
|
572
|
+
},
|
|
529
573
|
{
|
|
530
574
|
name: "reflect",
|
|
531
575
|
description: "Review repeated work and suggest reusable workflow improvements",
|
|
@@ -630,6 +674,23 @@ function findConfigPathInDirs(configDirs, baseName) {
|
|
|
630
674
|
}
|
|
631
675
|
return null;
|
|
632
676
|
}
|
|
677
|
+
function validateFinalImageRouting(config, configPath, options) {
|
|
678
|
+
if (config.image_routing !== "auto")
|
|
679
|
+
return true;
|
|
680
|
+
const disabledAgents = config.disabled_agents ?? DEFAULT_DISABLED_AGENTS;
|
|
681
|
+
if (!disabledAgents.includes("observer"))
|
|
682
|
+
return true;
|
|
683
|
+
const message = 'image_routing "auto" requires observer to be enabled. ' + 'Remove "observer" from disabled_agents.';
|
|
684
|
+
options?.onWarning?.({
|
|
685
|
+
path: configPath,
|
|
686
|
+
kind: "invalid-schema",
|
|
687
|
+
message
|
|
688
|
+
});
|
|
689
|
+
if (!options?.silent) {
|
|
690
|
+
console.warn(`[oh-my-opencode-slim] Invalid config: ${message}`);
|
|
691
|
+
}
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
633
694
|
function findPluginConfigPaths(directory) {
|
|
634
695
|
const userConfigPath = findConfigPathInDirs(getConfigSearchDirs(), "oh-my-opencode-slim");
|
|
635
696
|
const projectConfigBasePath = path.join(directory, ".opencode", "oh-my-opencode-slim");
|
|
@@ -711,6 +772,7 @@ function loadPluginConfig(directory, options) {
|
|
|
711
772
|
debug: config.companion.debug ?? false
|
|
712
773
|
};
|
|
713
774
|
}
|
|
775
|
+
validateFinalImageRouting(config, projectConfigPath ?? userConfigPath ?? "", options);
|
|
714
776
|
return config;
|
|
715
777
|
}
|
|
716
778
|
function loadAgentPrompt(agentName, optionsOrPreset) {
|
|
@@ -776,6 +838,7 @@ function migrateTmuxToMultiplexer(config) {
|
|
|
776
838
|
}
|
|
777
839
|
|
|
778
840
|
// src/tui-state.ts
|
|
841
|
+
import { createHash } from "node:crypto";
|
|
779
842
|
import * as fs2 from "node:fs";
|
|
780
843
|
import * as os from "node:os";
|
|
781
844
|
import * as path2 from "node:path";
|
|
@@ -784,8 +847,11 @@ var STATE_FILE = "tui-state.json";
|
|
|
784
847
|
function dataDir() {
|
|
785
848
|
return process.env.XDG_DATA_HOME ?? path2.join(os.homedir(), ".local", "share");
|
|
786
849
|
}
|
|
787
|
-
function
|
|
788
|
-
return path2.
|
|
850
|
+
function projectScope(projectDir) {
|
|
851
|
+
return createHash("sha256").update(path2.resolve(projectDir)).digest("hex").slice(0, 12);
|
|
852
|
+
}
|
|
853
|
+
function getTuiStatePath(projectDir) {
|
|
854
|
+
return path2.join(dataDir(), "opencode", "storage", STATE_DIR, projectScope(projectDir), STATE_FILE);
|
|
789
855
|
}
|
|
790
856
|
function emptySnapshot() {
|
|
791
857
|
return {
|
|
@@ -806,42 +872,42 @@ function parseSnapshot(value) {
|
|
|
806
872
|
agentVariants: parsed.agentVariants ?? {}
|
|
807
873
|
};
|
|
808
874
|
}
|
|
809
|
-
function readTuiSnapshot() {
|
|
875
|
+
function readTuiSnapshot(projectDir) {
|
|
810
876
|
try {
|
|
811
|
-
return parseSnapshot(fs2.readFileSync(getTuiStatePath(), "utf8"));
|
|
877
|
+
return parseSnapshot(fs2.readFileSync(getTuiStatePath(projectDir), "utf8"));
|
|
812
878
|
} catch {
|
|
813
879
|
return emptySnapshot();
|
|
814
880
|
}
|
|
815
881
|
}
|
|
816
|
-
async function readTuiSnapshotAsync() {
|
|
882
|
+
async function readTuiSnapshotAsync(projectDir) {
|
|
817
883
|
try {
|
|
818
|
-
return parseSnapshot(await fs2.promises.readFile(getTuiStatePath(), "utf8"));
|
|
884
|
+
return parseSnapshot(await fs2.promises.readFile(getTuiStatePath(projectDir), "utf8"));
|
|
819
885
|
} catch {
|
|
820
886
|
return emptySnapshot();
|
|
821
887
|
}
|
|
822
888
|
}
|
|
823
|
-
function writeTuiSnapshot(snapshot) {
|
|
889
|
+
function writeTuiSnapshot(snapshot, projectDir) {
|
|
824
890
|
try {
|
|
825
|
-
const filePath = getTuiStatePath();
|
|
891
|
+
const filePath = getTuiStatePath(projectDir);
|
|
826
892
|
fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
827
893
|
fs2.writeFileSync(filePath, `${JSON.stringify(snapshot)}
|
|
828
894
|
`);
|
|
829
895
|
} catch {}
|
|
830
896
|
}
|
|
831
|
-
function updateSnapshot(mutator) {
|
|
832
|
-
const snapshot = readTuiSnapshot();
|
|
897
|
+
function updateSnapshot(projectDir, mutator) {
|
|
898
|
+
const snapshot = readTuiSnapshot(projectDir);
|
|
833
899
|
mutator(snapshot);
|
|
834
900
|
snapshot.updatedAt = Date.now();
|
|
835
|
-
writeTuiSnapshot(snapshot);
|
|
901
|
+
writeTuiSnapshot(snapshot, projectDir);
|
|
836
902
|
}
|
|
837
|
-
function recordTuiAgentModels(input) {
|
|
838
|
-
updateSnapshot((snapshot) => {
|
|
903
|
+
function recordTuiAgentModels(input, projectDir) {
|
|
904
|
+
updateSnapshot(projectDir, (snapshot) => {
|
|
839
905
|
snapshot.agentModels = { ...input.agentModels };
|
|
840
906
|
snapshot.agentVariants = { ...input.agentVariants ?? {} };
|
|
841
907
|
});
|
|
842
908
|
}
|
|
843
|
-
function recordTuiAgentModel(input) {
|
|
844
|
-
updateSnapshot((snapshot) => {
|
|
909
|
+
function recordTuiAgentModel(input, projectDir) {
|
|
910
|
+
updateSnapshot(projectDir, (snapshot) => {
|
|
845
911
|
snapshot.agentModels[input.agentName] = input.model;
|
|
846
912
|
if (input.variant !== undefined) {
|
|
847
913
|
if (input.variant === null) {
|
|
@@ -1017,11 +1083,11 @@ var plugin = {
|
|
|
1017
1083
|
const version = meta.version ?? await readPackageVersion() ?? "dev";
|
|
1018
1084
|
let configDirectory = getTuiDirectory(api);
|
|
1019
1085
|
let { configInvalid, compactSidebar } = readConfigState(configDirectory);
|
|
1020
|
-
let snapshot = readTuiSnapshot();
|
|
1086
|
+
let snapshot = readTuiSnapshot(configDirectory);
|
|
1021
1087
|
const renderTimer = setInterval(async () => {
|
|
1022
1088
|
try {
|
|
1023
|
-
snapshot = await readTuiSnapshotAsync();
|
|
1024
1089
|
const currentDirectory = getTuiDirectory(api);
|
|
1090
|
+
snapshot = await readTuiSnapshotAsync(currentDirectory);
|
|
1025
1091
|
if (currentDirectory !== configDirectory) {
|
|
1026
1092
|
configDirectory = currentDirectory;
|
|
1027
1093
|
({ configInvalid, compactSidebar } = readConfigState(configDirectory));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function escapeHtml(value: string): string;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from './background-job-board';
|
|
|
3
3
|
export * from './background-job-coordinator';
|
|
4
4
|
export * from './background-job-store';
|
|
5
5
|
export * from './internal-initiator';
|
|
6
|
-
export {
|
|
6
|
+
export { initLogger, log } from './logger';
|
|
7
7
|
export * from './polling';
|
|
8
8
|
export * from './session';
|
|
9
9
|
export * from './task';
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
declare function getLogDir(): string;
|
|
2
1
|
export declare function initLogger(sessionId: string): void;
|
|
3
|
-
export { getLogDir };
|
|
4
2
|
/** @internal Reset logger state for testing */
|
|
5
3
|
export declare function resetLogger(): void;
|
|
6
4
|
/** @internal Wait for queued log writes in tests. */
|