oh-my-opencode-slim 2.1.1 → 2.2.1
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 +113 -118
- package/README.ko-KR.md +141 -123
- package/README.md +102 -145
- package/README.zh-CN.md +112 -118
- package/dist/agents/index.d.ts +0 -4
- package/dist/cli/index.js +57 -20
- package/dist/cli/providers.d.ts +11 -4
- package/dist/config/constants.d.ts +11 -1
- 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 +1992 -455
- 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/multiplexer/zellij/index.d.ts +1 -1
- package/dist/tools/smartfetch/utils.d.ts +3 -1
- package/dist/tui-state.d.ts +5 -5
- package/dist/tui.js +87 -27
- 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 +5 -3
- package/src/skills/deepwork/SKILL.md +17 -6
- package/src/skills/verification-planning/SKILL.md +102 -0
- package/src/skills/worktrees/SKILL.md +14 -7
- package/src/skills/release-smoke-test/SKILL.md +0 -159
package/dist/tui.js
CHANGED
|
@@ -130,7 +130,7 @@ var DEFAULT_MODELS = {
|
|
|
130
130
|
var POLL_INTERVAL_BACKGROUND_MS = 2000;
|
|
131
131
|
var MAX_POLL_TIME_MS = 5 * 60 * 1000;
|
|
132
132
|
var DEFAULT_MAX_SUBAGENT_DEPTH = 3;
|
|
133
|
-
var PHASE_REMINDER_TEXT = `!IMPORTANT! Scheduler workflow: plan lanes/dependencies → dispatch background specialists → track task IDs → wait for hook-driven completion → reconcile terminal results → verify. Do not poll running jobs, consume running-job output, or advance dependent work. !END!`;
|
|
133
|
+
var PHASE_REMINDER_TEXT = `!IMPORTANT! Scheduler workflow: First choose the lightest workflow that fits the work. If direct execution is justified, complete it and verify proportionately. Otherwise: plan lanes/dependencies → dispatch background specialists → track task IDs → wait for hook-driven completion → reconcile terminal results → verify. Do not poll running jobs, consume running-job output, or advance dependent work. !END!`;
|
|
134
134
|
function formatSystemReminder(text) {
|
|
135
135
|
return `<system-reminder>
|
|
136
136
|
${text}
|
|
@@ -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",
|
|
@@ -538,12 +582,6 @@ var CUSTOM_SKILLS = [
|
|
|
538
582
|
allowedAgents: ["orchestrator"],
|
|
539
583
|
sourcePath: "src/skills/oh-my-opencode-slim"
|
|
540
584
|
},
|
|
541
|
-
{
|
|
542
|
-
name: "release-smoke-test",
|
|
543
|
-
description: "Validate packed release candidates and bugfixes before public publish",
|
|
544
|
-
allowedAgents: ["orchestrator"],
|
|
545
|
-
sourcePath: "src/skills/release-smoke-test"
|
|
546
|
-
},
|
|
547
585
|
{
|
|
548
586
|
name: "worktrees",
|
|
549
587
|
description: "Manage Git worktrees as OMO safe isolated coding lanes for complex/risky/parallel work",
|
|
@@ -630,6 +668,23 @@ function findConfigPathInDirs(configDirs, baseName) {
|
|
|
630
668
|
}
|
|
631
669
|
return null;
|
|
632
670
|
}
|
|
671
|
+
function validateFinalImageRouting(config, configPath, options) {
|
|
672
|
+
if (config.image_routing !== "auto")
|
|
673
|
+
return true;
|
|
674
|
+
const disabledAgents = config.disabled_agents ?? DEFAULT_DISABLED_AGENTS;
|
|
675
|
+
if (!disabledAgents.includes("observer"))
|
|
676
|
+
return true;
|
|
677
|
+
const message = 'image_routing "auto" requires observer to be enabled. ' + 'Remove "observer" from disabled_agents.';
|
|
678
|
+
options?.onWarning?.({
|
|
679
|
+
path: configPath,
|
|
680
|
+
kind: "invalid-schema",
|
|
681
|
+
message
|
|
682
|
+
});
|
|
683
|
+
if (!options?.silent) {
|
|
684
|
+
console.warn(`[oh-my-opencode-slim] Invalid config: ${message}`);
|
|
685
|
+
}
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
633
688
|
function findPluginConfigPaths(directory) {
|
|
634
689
|
const userConfigPath = findConfigPathInDirs(getConfigSearchDirs(), "oh-my-opencode-slim");
|
|
635
690
|
const projectConfigBasePath = path.join(directory, ".opencode", "oh-my-opencode-slim");
|
|
@@ -711,6 +766,7 @@ function loadPluginConfig(directory, options) {
|
|
|
711
766
|
debug: config.companion.debug ?? false
|
|
712
767
|
};
|
|
713
768
|
}
|
|
769
|
+
validateFinalImageRouting(config, projectConfigPath ?? userConfigPath ?? "", options);
|
|
714
770
|
return config;
|
|
715
771
|
}
|
|
716
772
|
function loadAgentPrompt(agentName, optionsOrPreset) {
|
|
@@ -776,6 +832,7 @@ function migrateTmuxToMultiplexer(config) {
|
|
|
776
832
|
}
|
|
777
833
|
|
|
778
834
|
// src/tui-state.ts
|
|
835
|
+
import { createHash } from "node:crypto";
|
|
779
836
|
import * as fs2 from "node:fs";
|
|
780
837
|
import * as os from "node:os";
|
|
781
838
|
import * as path2 from "node:path";
|
|
@@ -784,8 +841,11 @@ var STATE_FILE = "tui-state.json";
|
|
|
784
841
|
function dataDir() {
|
|
785
842
|
return process.env.XDG_DATA_HOME ?? path2.join(os.homedir(), ".local", "share");
|
|
786
843
|
}
|
|
787
|
-
function
|
|
788
|
-
return path2.
|
|
844
|
+
function projectScope(projectDir) {
|
|
845
|
+
return createHash("sha256").update(path2.resolve(projectDir)).digest("hex").slice(0, 12);
|
|
846
|
+
}
|
|
847
|
+
function getTuiStatePath(projectDir) {
|
|
848
|
+
return path2.join(dataDir(), "opencode", "storage", STATE_DIR, projectScope(projectDir), STATE_FILE);
|
|
789
849
|
}
|
|
790
850
|
function emptySnapshot() {
|
|
791
851
|
return {
|
|
@@ -806,42 +866,42 @@ function parseSnapshot(value) {
|
|
|
806
866
|
agentVariants: parsed.agentVariants ?? {}
|
|
807
867
|
};
|
|
808
868
|
}
|
|
809
|
-
function readTuiSnapshot() {
|
|
869
|
+
function readTuiSnapshot(projectDir) {
|
|
810
870
|
try {
|
|
811
|
-
return parseSnapshot(fs2.readFileSync(getTuiStatePath(), "utf8"));
|
|
871
|
+
return parseSnapshot(fs2.readFileSync(getTuiStatePath(projectDir), "utf8"));
|
|
812
872
|
} catch {
|
|
813
873
|
return emptySnapshot();
|
|
814
874
|
}
|
|
815
875
|
}
|
|
816
|
-
async function readTuiSnapshotAsync() {
|
|
876
|
+
async function readTuiSnapshotAsync(projectDir) {
|
|
817
877
|
try {
|
|
818
|
-
return parseSnapshot(await fs2.promises.readFile(getTuiStatePath(), "utf8"));
|
|
878
|
+
return parseSnapshot(await fs2.promises.readFile(getTuiStatePath(projectDir), "utf8"));
|
|
819
879
|
} catch {
|
|
820
880
|
return emptySnapshot();
|
|
821
881
|
}
|
|
822
882
|
}
|
|
823
|
-
function writeTuiSnapshot(snapshot) {
|
|
883
|
+
function writeTuiSnapshot(snapshot, projectDir) {
|
|
824
884
|
try {
|
|
825
|
-
const filePath = getTuiStatePath();
|
|
885
|
+
const filePath = getTuiStatePath(projectDir);
|
|
826
886
|
fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
827
887
|
fs2.writeFileSync(filePath, `${JSON.stringify(snapshot)}
|
|
828
888
|
`);
|
|
829
889
|
} catch {}
|
|
830
890
|
}
|
|
831
|
-
function updateSnapshot(mutator) {
|
|
832
|
-
const snapshot = readTuiSnapshot();
|
|
891
|
+
function updateSnapshot(projectDir, mutator) {
|
|
892
|
+
const snapshot = readTuiSnapshot(projectDir);
|
|
833
893
|
mutator(snapshot);
|
|
834
894
|
snapshot.updatedAt = Date.now();
|
|
835
|
-
writeTuiSnapshot(snapshot);
|
|
895
|
+
writeTuiSnapshot(snapshot, projectDir);
|
|
836
896
|
}
|
|
837
|
-
function recordTuiAgentModels(input) {
|
|
838
|
-
updateSnapshot((snapshot) => {
|
|
897
|
+
function recordTuiAgentModels(input, projectDir) {
|
|
898
|
+
updateSnapshot(projectDir, (snapshot) => {
|
|
839
899
|
snapshot.agentModels = { ...input.agentModels };
|
|
840
900
|
snapshot.agentVariants = { ...input.agentVariants ?? {} };
|
|
841
901
|
});
|
|
842
902
|
}
|
|
843
|
-
function recordTuiAgentModel(input) {
|
|
844
|
-
updateSnapshot((snapshot) => {
|
|
903
|
+
function recordTuiAgentModel(input, projectDir) {
|
|
904
|
+
updateSnapshot(projectDir, (snapshot) => {
|
|
845
905
|
snapshot.agentModels[input.agentName] = input.model;
|
|
846
906
|
if (input.variant !== undefined) {
|
|
847
907
|
if (input.variant === null) {
|
|
@@ -1017,11 +1077,11 @@ var plugin = {
|
|
|
1017
1077
|
const version = meta.version ?? await readPackageVersion() ?? "dev";
|
|
1018
1078
|
let configDirectory = getTuiDirectory(api);
|
|
1019
1079
|
let { configInvalid, compactSidebar } = readConfigState(configDirectory);
|
|
1020
|
-
let snapshot = readTuiSnapshot();
|
|
1080
|
+
let snapshot = readTuiSnapshot(configDirectory);
|
|
1021
1081
|
const renderTimer = setInterval(async () => {
|
|
1022
1082
|
try {
|
|
1023
|
-
snapshot = await readTuiSnapshotAsync();
|
|
1024
1083
|
const currentDirectory = getTuiDirectory(api);
|
|
1084
|
+
snapshot = await readTuiSnapshotAsync(currentDirectory);
|
|
1025
1085
|
if (currentDirectory !== configDirectory) {
|
|
1026
1086
|
configDirectory = currentDirectory;
|
|
1027
1087
|
({ 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. */
|