oh-my-opencode-slim 2.0.5 → 2.1.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 +64 -38
- package/README.ko-KR.md +62 -36
- package/README.md +82 -47
- package/README.zh-CN.md +63 -39
- package/dist/agents/council.d.ts +1 -1
- package/dist/agents/index.d.ts +7 -2
- package/dist/agents/orchestrator.d.ts +1 -1
- package/dist/cli/custom-skills-registry.d.ts +18 -0
- package/dist/cli/custom-skills.d.ts +3 -19
- package/dist/cli/index.js +1130 -195
- package/dist/cli/providers.d.ts +12 -16
- package/dist/cli/skills.d.ts +2 -2
- package/dist/companion/manager.d.ts +10 -0
- package/dist/config/constants.d.ts +2 -1
- package/dist/config/council-schema.d.ts +37 -12
- package/dist/config/loader.d.ts +5 -2
- package/dist/config/schema.d.ts +17 -6
- package/dist/council/council-manager.d.ts +7 -3
- package/dist/hooks/auto-update-checker/skill-sync.d.ts +59 -1
- package/dist/hooks/filter-available-skills/index.d.ts +1 -2
- package/dist/hooks/foreground-fallback/index.d.ts +40 -2
- package/dist/hooks/image-hook.d.ts +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/loop-command/index.d.ts +13 -0
- package/dist/hooks/phase-reminder/index.d.ts +4 -3
- package/dist/hooks/post-file-tool-nudge/index.d.ts +15 -9
- package/dist/hooks/session-lifecycle.d.ts +11 -0
- package/dist/hooks/task-session-manager/index.d.ts +15 -4
- package/dist/hooks/task-session-manager/pending-call-tracker.d.ts +13 -0
- package/dist/hooks/task-session-manager/task-context-tracker.d.ts +14 -0
- package/dist/hooks/types.d.ts +3 -1
- package/dist/index.js +2890 -986
- package/dist/interview/dashboard-manager.d.ts +21 -0
- package/dist/interview/manager.d.ts +0 -14
- package/dist/interview/service.d.ts +9 -0
- package/dist/interview/session-server.d.ts +21 -0
- package/dist/interview/types.d.ts +3 -1
- package/dist/loop/loop-session.d.ts +64 -0
- package/dist/multiplexer/factory.d.ts +5 -5
- package/dist/multiplexer/herdr/index.d.ts +33 -0
- package/dist/multiplexer/index.d.ts +1 -0
- package/dist/multiplexer/session-manager.d.ts +6 -5
- package/dist/multiplexer/shared.d.ts +24 -0
- package/dist/multiplexer/tmux/index.d.ts +0 -1
- package/dist/multiplexer/types.d.ts +4 -4
- package/dist/multiplexer/zellij/index.d.ts +0 -1
- package/dist/tools/cancel-task.d.ts +2 -2
- package/dist/tui.d.ts +1 -0
- package/dist/tui.js +123 -45
- package/dist/utils/background-job-board.d.ts +22 -2
- package/dist/utils/background-job-coordinator.d.ts +72 -0
- package/dist/utils/background-job-store.d.ts +46 -0
- package/dist/utils/councillor-models.d.ts +20 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/internal-initiator.d.ts +6 -1
- package/dist/utils/session.d.ts +2 -2
- package/oh-my-opencode-slim.schema.json +18 -1
- package/package.json +1 -1
- package/src/skills/clonedeps/SKILL.md +2 -2
- package/src/skills/clonedeps/codemap.md +23 -32
- package/src/skills/codemap/SKILL.md +2 -2
- package/src/skills/codemap.md +63 -36
- package/src/skills/loop-engineering/SKILL.md +30 -0
- package/src/skills/oh-my-opencode-slim/SKILL.md +3 -3
- package/src/skills/reflect/SKILL.md +133 -0
- package/src/skills/release-smoke-test/SKILL.md +159 -0
- package/src/skills/simplify/SKILL.md +6 -6
package/dist/cli/providers.d.ts
CHANGED
|
@@ -3,28 +3,28 @@ export declare const GENERATED_PRESETS: readonly ["openai", "opencode-go"];
|
|
|
3
3
|
export declare const MODEL_MAPPINGS: {
|
|
4
4
|
readonly openai: {
|
|
5
5
|
readonly orchestrator: {
|
|
6
|
-
readonly model: "openai/gpt-5.
|
|
6
|
+
readonly model: "openai/gpt-5.6-terra";
|
|
7
7
|
readonly variant: "medium";
|
|
8
8
|
};
|
|
9
9
|
readonly oracle: {
|
|
10
|
-
readonly model: "openai/gpt-5.
|
|
10
|
+
readonly model: "openai/gpt-5.6-sol";
|
|
11
11
|
readonly variant: "high";
|
|
12
12
|
};
|
|
13
13
|
readonly librarian: {
|
|
14
|
-
readonly model: "openai/gpt-5.
|
|
14
|
+
readonly model: "openai/gpt-5.6-luna";
|
|
15
15
|
readonly variant: "low";
|
|
16
16
|
};
|
|
17
17
|
readonly explorer: {
|
|
18
|
-
readonly model: "openai/gpt-5.
|
|
18
|
+
readonly model: "openai/gpt-5.6-luna";
|
|
19
19
|
readonly variant: "low";
|
|
20
20
|
};
|
|
21
21
|
readonly designer: {
|
|
22
|
-
readonly model: "openai/gpt-5.
|
|
22
|
+
readonly model: "openai/gpt-5.6-luna";
|
|
23
23
|
readonly variant: "medium";
|
|
24
24
|
};
|
|
25
25
|
readonly fixer: {
|
|
26
|
-
readonly model: "openai/gpt-5.
|
|
27
|
-
readonly variant: "
|
|
26
|
+
readonly model: "openai/gpt-5.6-luna";
|
|
27
|
+
readonly variant: "medium";
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
readonly kimi: {
|
|
@@ -104,24 +104,20 @@ export declare const MODEL_MAPPINGS: {
|
|
|
104
104
|
};
|
|
105
105
|
readonly 'opencode-go': {
|
|
106
106
|
readonly orchestrator: {
|
|
107
|
-
readonly model: "opencode-go/glm-5.
|
|
107
|
+
readonly model: "opencode-go/glm-5.2";
|
|
108
108
|
};
|
|
109
109
|
readonly oracle: {
|
|
110
|
-
readonly model: "opencode-go/
|
|
110
|
+
readonly model: "opencode-go/qwen3.7-max";
|
|
111
111
|
readonly variant: "max";
|
|
112
112
|
};
|
|
113
|
-
readonly council: {
|
|
114
|
-
readonly model: "opencode-go/deepseek-v4-pro";
|
|
115
|
-
readonly variant: "high";
|
|
116
|
-
};
|
|
117
113
|
readonly librarian: {
|
|
118
|
-
readonly model: "opencode-go/
|
|
114
|
+
readonly model: "opencode-go/deepseek-v4-flash";
|
|
119
115
|
};
|
|
120
116
|
readonly explorer: {
|
|
121
|
-
readonly model: "opencode-go/
|
|
117
|
+
readonly model: "opencode-go/deepseek-v4-flash";
|
|
122
118
|
};
|
|
123
119
|
readonly designer: {
|
|
124
|
-
readonly model: "opencode-go/kimi-k2.
|
|
120
|
+
readonly model: "opencode-go/kimi-k2.7-code";
|
|
125
121
|
readonly variant: "medium";
|
|
126
122
|
};
|
|
127
123
|
readonly fixer: {
|
package/dist/cli/skills.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* permission grants but is NOT installed by this plugin's CLI.
|
|
4
4
|
*/
|
|
5
5
|
export interface PermissionOnlySkill {
|
|
6
|
-
/** Skill name
|
|
6
|
+
/** Skill name - must match the name OpenCode uses for permission checks */
|
|
7
7
|
name: string;
|
|
8
8
|
/** List of agents that should auto-allow this skill */
|
|
9
9
|
allowedAgents: string[];
|
|
@@ -12,7 +12,7 @@ export interface PermissionOnlySkill {
|
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Skills managed externally (not installed by this plugin's CLI).
|
|
15
|
-
* Entries here only affect agent permission grants
|
|
15
|
+
* Entries here only affect agent permission grants - nothing is installed.
|
|
16
16
|
*/
|
|
17
17
|
export declare const PERMISSION_ONLY_SKILLS: PermissionOnlySkill[];
|
|
18
18
|
/**
|
|
@@ -17,8 +17,17 @@ export declare class CompanionManager {
|
|
|
17
17
|
private readonly busyAgentSessions;
|
|
18
18
|
private readonly config?;
|
|
19
19
|
private companionProcess;
|
|
20
|
+
private wasSpawner;
|
|
21
|
+
private spawnedCompanionPid;
|
|
20
22
|
constructor(sessionId: string, cwd: string, config?: CompanionConfig);
|
|
21
23
|
onLoad(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Register this manager behind a single process `exit` listener. Re-inits for
|
|
26
|
+
* the same OpenCode session dispose the superseded manager immediately so its
|
|
27
|
+
* detached child does not survive until process exit.
|
|
28
|
+
*/
|
|
29
|
+
private registerActiveManager;
|
|
30
|
+
private static disposeActiveManagers;
|
|
22
31
|
/**
|
|
23
32
|
* Feed every session.status event here, with the agent name resolved
|
|
24
33
|
* from sessionAgentMap. Orchestrator sessions drive overall status;
|
|
@@ -33,6 +42,7 @@ export declare class CompanionManager {
|
|
|
33
42
|
onWaitingInput(): void;
|
|
34
43
|
onInputResolved(): void;
|
|
35
44
|
onExit(): void;
|
|
45
|
+
private removeOwnedPidFileIfNoSessionsRemain;
|
|
36
46
|
/** One entry per running agent instance (two fixers → two cells). */
|
|
37
47
|
private activeAgents;
|
|
38
48
|
private flush;
|
|
@@ -15,7 +15,8 @@ export declare const POLL_INTERVAL_BACKGROUND_MS = 2000;
|
|
|
15
15
|
export declare const MAX_POLL_TIME_MS: number;
|
|
16
16
|
export declare const DEFAULT_MAX_SUBAGENT_DEPTH = 3;
|
|
17
17
|
export declare const PHASE_REMINDER_TEXT = "!IMPORTANT! Scheduler workflow: plan lanes/dependencies \u2192 dispatch background specialists \u2192 track task IDs \u2192 wait for hook-driven completion \u2192 reconcile terminal results \u2192 verify. Do not poll running jobs, consume running-job output, or advance dependent work. !END!";
|
|
18
|
-
export declare
|
|
18
|
+
export declare function formatSystemReminder(text: string): string;
|
|
19
|
+
export declare const PHASE_REMINDER: string;
|
|
19
20
|
export declare const WRITABLE_FILE_OPERATIONS_RULES = "**File Operations Rules**:\n- Prefer dedicated file tools for normal code work: glob/grep/ast_grep_search for discovery, read for file contents, and edit/write/apply_patch for targeted source changes.\n- Use bash for execution and automation: git, package managers, tests, builds, scripts, diagnostics, and shell-native filesystem operations.\n- Shell is acceptable for bulk or mechanical filesystem changes when it is clearer or safer than many individual edits (for example: truncate generated logs, remove build artifacts, batch rename/move files), especially when the user explicitly asks for that shell operation.\n- Before destructive or broad shell operations, verify the target set and quote paths. Prefer a dry-run/listing first when practical.\n- Do not use cat/head/tail/sed/awk only to read code into context; use read/grep unless a shell pipeline is genuinely the better diagnostic.";
|
|
20
21
|
export declare const READONLY_FILE_OPERATIONS_RULES = "**File Operations Rules**:\n- READ-ONLY: inspect and report; do not modify files.\n- Prefer dedicated file tools for codebase inspection: glob/grep/ast_grep_search for discovery and read for file contents.\n- Bash is allowed for non-mutating diagnostics and shell-native inspection when it is the clearest tool, but not for modifying files.\n- Do not use cat/head/tail/sed/awk only to read code into context; use read/grep unless a shell pipeline is genuinely the better diagnostic.";
|
|
21
22
|
export declare const NO_SHELL_READONLY_FILE_OPERATIONS_RULES = "**File Operations Rules**:\n- READ-ONLY: inspect and report; do not modify files.\n- Use glob/grep/ast_grep_search for discovery and read for file contents.\n- Do not use bash or shell commands.";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { type CouncillorModelEntry } from '../utils/councillor-models';
|
|
3
|
+
export type { CouncillorModelEntry };
|
|
2
4
|
/**
|
|
3
5
|
* Configuration for a single councillor within a preset.
|
|
4
6
|
* Each councillor is an independent LLM that processes the same prompt.
|
|
@@ -6,12 +8,31 @@ import { z } from 'zod';
|
|
|
6
8
|
* Councillors run as agent sessions with read-only codebase access
|
|
7
9
|
* (read, glob, grep, lsp, list). They can examine the codebase but
|
|
8
10
|
* cannot modify files or spawn subagents.
|
|
11
|
+
*
|
|
12
|
+
* `model` accepts a single ID or an ordered fallback chain. The parsed config
|
|
13
|
+
* exposes `models` (the normalized chain) plus `model` (the primary, for
|
|
14
|
+
* backward compatibility).
|
|
9
15
|
*/
|
|
10
|
-
export declare const CouncillorConfigSchema: z.ZodObject<{
|
|
11
|
-
model: z.ZodString
|
|
16
|
+
export declare const CouncillorConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
17
|
+
model: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
18
|
+
id: z.ZodString;
|
|
19
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>]>>]>;
|
|
12
21
|
variant: z.ZodOptional<z.ZodString>;
|
|
13
22
|
prompt: z.ZodOptional<z.ZodString>;
|
|
14
|
-
}, z.core.$strip
|
|
23
|
+
}, z.core.$strip>, z.ZodTransform<{
|
|
24
|
+
model: string;
|
|
25
|
+
variant: string | undefined;
|
|
26
|
+
prompt: string | undefined;
|
|
27
|
+
models: CouncillorModelEntry[];
|
|
28
|
+
}, {
|
|
29
|
+
model: string | (string | {
|
|
30
|
+
id: string;
|
|
31
|
+
variant?: string | undefined;
|
|
32
|
+
})[];
|
|
33
|
+
variant?: string | undefined;
|
|
34
|
+
prompt?: string | undefined;
|
|
35
|
+
}>>;
|
|
15
36
|
export type CouncillorConfig = z.infer<typeof CouncillorConfigSchema>;
|
|
16
37
|
/**
|
|
17
38
|
* A named preset grouping several councillors.
|
|
@@ -22,8 +43,9 @@ export type CouncillorConfig = z.infer<typeof CouncillorConfigSchema>;
|
|
|
22
43
|
*/
|
|
23
44
|
export declare const CouncilPresetSchema: z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, z.ZodTransform<Record<string, {
|
|
24
45
|
model: string;
|
|
25
|
-
variant
|
|
26
|
-
prompt
|
|
46
|
+
variant: string | undefined;
|
|
47
|
+
prompt: string | undefined;
|
|
48
|
+
models: CouncillorModelEntry[];
|
|
27
49
|
}>, Record<string, Record<string, unknown>>>>;
|
|
28
50
|
export type CouncilPreset = z.infer<typeof CouncilPresetSchema>;
|
|
29
51
|
/**
|
|
@@ -44,7 +66,7 @@ export declare const CouncillorExecutionModeSchema: z.ZodDefault<z.ZodEnum<{
|
|
|
44
66
|
* "council": {
|
|
45
67
|
* "presets": {
|
|
46
68
|
* "default": {
|
|
47
|
-
* "alpha": { "model": "openai/gpt-5.
|
|
69
|
+
* "alpha": { "model": "openai/gpt-5.6-luna" },
|
|
48
70
|
* "beta": { "model": "openai/gpt-5.3-codex" },
|
|
49
71
|
* "gamma": { "model": "google/gemini-3-pro" }
|
|
50
72
|
* }
|
|
@@ -58,8 +80,9 @@ export declare const CouncillorExecutionModeSchema: z.ZodDefault<z.ZodEnum<{
|
|
|
58
80
|
export declare const CouncilConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
59
81
|
presets: z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, z.ZodTransform<Record<string, {
|
|
60
82
|
model: string;
|
|
61
|
-
variant
|
|
62
|
-
prompt
|
|
83
|
+
variant: string | undefined;
|
|
84
|
+
prompt: string | undefined;
|
|
85
|
+
models: CouncillorModelEntry[];
|
|
63
86
|
}>, Record<string, Record<string, unknown>>>>>;
|
|
64
87
|
timeout: z.ZodDefault<z.ZodNumber>;
|
|
65
88
|
default_preset: z.ZodDefault<z.ZodString>;
|
|
@@ -72,8 +95,9 @@ export declare const CouncilConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
72
95
|
}, z.core.$strip>, z.ZodTransform<{
|
|
73
96
|
presets: Record<string, Record<string, {
|
|
74
97
|
model: string;
|
|
75
|
-
variant
|
|
76
|
-
prompt
|
|
98
|
+
variant: string | undefined;
|
|
99
|
+
prompt: string | undefined;
|
|
100
|
+
models: CouncillorModelEntry[];
|
|
77
101
|
}>>;
|
|
78
102
|
timeout: number;
|
|
79
103
|
default_preset: string;
|
|
@@ -84,8 +108,9 @@ export declare const CouncilConfigSchema: z.ZodPipe<z.ZodObject<{
|
|
|
84
108
|
}, {
|
|
85
109
|
presets: Record<string, Record<string, {
|
|
86
110
|
model: string;
|
|
87
|
-
variant
|
|
88
|
-
prompt
|
|
111
|
+
variant: string | undefined;
|
|
112
|
+
prompt: string | undefined;
|
|
113
|
+
models: CouncillorModelEntry[];
|
|
89
114
|
}>>;
|
|
90
115
|
timeout: number;
|
|
91
116
|
default_preset: string;
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -76,10 +76,13 @@ export declare function loadPluginConfig(directory: string, options?: LoadPlugin
|
|
|
76
76
|
* then falls back to the root prompts directory.
|
|
77
77
|
*
|
|
78
78
|
* @param agentName - Name of the agent (e.g., "orchestrator", "explorer")
|
|
79
|
-
* @param
|
|
79
|
+
* @param optionsOrPreset - Optional preset name or options configuration
|
|
80
80
|
* @returns Object with prompt and/or appendPrompt if files exist
|
|
81
81
|
*/
|
|
82
|
-
export declare function loadAgentPrompt(agentName: string,
|
|
82
|
+
export declare function loadAgentPrompt(agentName: string, optionsOrPreset?: string | {
|
|
83
|
+
preset?: string;
|
|
84
|
+
projectDirectory?: string;
|
|
85
|
+
}): {
|
|
83
86
|
prompt?: string;
|
|
84
87
|
appendPrompt?: string;
|
|
85
88
|
};
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export declare const MultiplexerTypeSchema: z.ZodEnum<{
|
|
|
66
66
|
auto: "auto";
|
|
67
67
|
tmux: "tmux";
|
|
68
68
|
zellij: "zellij";
|
|
69
|
+
herdr: "herdr";
|
|
69
70
|
none: "none";
|
|
70
71
|
}>;
|
|
71
72
|
export type MultiplexerType = z.infer<typeof MultiplexerTypeSchema>;
|
|
@@ -95,6 +96,7 @@ export declare const MultiplexerConfigSchema: z.ZodObject<{
|
|
|
95
96
|
auto: "auto";
|
|
96
97
|
tmux: "tmux";
|
|
97
98
|
zellij: "zellij";
|
|
99
|
+
herdr: "herdr";
|
|
98
100
|
none: "none";
|
|
99
101
|
}>>;
|
|
100
102
|
layout: z.ZodDefault<z.ZodEnum<{
|
|
@@ -175,7 +177,9 @@ export declare const FailoverConfigSchema: z.ZodObject<{
|
|
|
175
177
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
176
178
|
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
177
179
|
retryDelayMs: z.ZodDefault<z.ZodNumber>;
|
|
180
|
+
maxRetries: z.ZodDefault<z.ZodNumber>;
|
|
178
181
|
retry_on_empty: z.ZodDefault<z.ZodBoolean>;
|
|
182
|
+
runtimeOverride: z.ZodDefault<z.ZodBoolean>;
|
|
179
183
|
}, z.core.$strict>;
|
|
180
184
|
export type FailoverConfig = z.infer<typeof FailoverConfigSchema>;
|
|
181
185
|
export declare const CompanionConfigSchema: z.ZodObject<{
|
|
@@ -247,6 +251,7 @@ export type AcpAgentsConfig = z.infer<typeof AcpAgentsConfigSchema>;
|
|
|
247
251
|
export declare const PluginConfigSchema: z.ZodObject<{
|
|
248
252
|
preset: z.ZodOptional<z.ZodString>;
|
|
249
253
|
setDefaultAgent: z.ZodOptional<z.ZodBoolean>;
|
|
254
|
+
compactSidebar: z.ZodOptional<z.ZodBoolean>;
|
|
250
255
|
autoUpdate: z.ZodOptional<z.ZodBoolean>;
|
|
251
256
|
presets: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
252
257
|
model: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
@@ -285,6 +290,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
285
290
|
auto: "auto";
|
|
286
291
|
tmux: "tmux";
|
|
287
292
|
zellij: "zellij";
|
|
293
|
+
herdr: "herdr";
|
|
288
294
|
none: "none";
|
|
289
295
|
}>>;
|
|
290
296
|
layout: z.ZodDefault<z.ZodEnum<{
|
|
@@ -333,13 +339,16 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
333
339
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
334
340
|
timeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
335
341
|
retryDelayMs: z.ZodDefault<z.ZodNumber>;
|
|
342
|
+
maxRetries: z.ZodDefault<z.ZodNumber>;
|
|
336
343
|
retry_on_empty: z.ZodDefault<z.ZodBoolean>;
|
|
344
|
+
runtimeOverride: z.ZodDefault<z.ZodBoolean>;
|
|
337
345
|
}, z.core.$strict>>;
|
|
338
346
|
council: z.ZodOptional<z.ZodPipe<z.ZodObject<{
|
|
339
347
|
presets: z.ZodRecord<z.ZodString, z.ZodPipe<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>, z.ZodTransform<Record<string, {
|
|
340
348
|
model: string;
|
|
341
|
-
variant
|
|
342
|
-
prompt
|
|
349
|
+
variant: string | undefined;
|
|
350
|
+
prompt: string | undefined;
|
|
351
|
+
models: import("./council-schema").CouncillorModelEntry[];
|
|
343
352
|
}>, Record<string, Record<string, unknown>>>>>;
|
|
344
353
|
timeout: z.ZodDefault<z.ZodNumber>;
|
|
345
354
|
default_preset: z.ZodDefault<z.ZodString>;
|
|
@@ -352,8 +361,9 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
352
361
|
}, z.core.$strip>, z.ZodTransform<{
|
|
353
362
|
presets: Record<string, Record<string, {
|
|
354
363
|
model: string;
|
|
355
|
-
variant
|
|
356
|
-
prompt
|
|
364
|
+
variant: string | undefined;
|
|
365
|
+
prompt: string | undefined;
|
|
366
|
+
models: import("./council-schema").CouncillorModelEntry[];
|
|
357
367
|
}>>;
|
|
358
368
|
timeout: number;
|
|
359
369
|
default_preset: string;
|
|
@@ -364,8 +374,9 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
364
374
|
}, {
|
|
365
375
|
presets: Record<string, Record<string, {
|
|
366
376
|
model: string;
|
|
367
|
-
variant
|
|
368
|
-
prompt
|
|
377
|
+
variant: string | undefined;
|
|
378
|
+
prompt: string | undefined;
|
|
379
|
+
models: import("./council-schema").CouncillorModelEntry[];
|
|
369
380
|
}>>;
|
|
370
381
|
timeout: number;
|
|
371
382
|
default_preset: string;
|
|
@@ -41,9 +41,13 @@ export declare class CouncilManager {
|
|
|
41
41
|
private runAgentSession;
|
|
42
42
|
private runCouncillors;
|
|
43
43
|
/**
|
|
44
|
-
* Run a single councillor
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* Run a single councillor across its configured model chain.
|
|
45
|
+
*
|
|
46
|
+
* For each model in the chain, empty responses are retried up to
|
|
47
|
+
* `maxRetries` times (providers that silently rate-limit). Any other
|
|
48
|
+
* failure or timeout advances to the next model in the chain. The
|
|
49
|
+
* councillor only fails once every model has been exhausted; the reported
|
|
50
|
+
* `model` and `error` reflect the last model tried.
|
|
47
51
|
*/
|
|
48
52
|
private runCouncillorWithRetry;
|
|
49
53
|
}
|
|
@@ -2,8 +2,66 @@ export interface SkillSyncResult {
|
|
|
2
2
|
installed: string[];
|
|
3
3
|
skippedExisting: string[];
|
|
4
4
|
failed: string[];
|
|
5
|
+
staged: string[];
|
|
6
|
+
adopted: string[];
|
|
7
|
+
customized: string[];
|
|
5
8
|
}
|
|
9
|
+
export interface SkillManifestEntry {
|
|
10
|
+
status: 'managed' | 'customized' | 'deleted' | 'conflict';
|
|
11
|
+
packageVersion: string;
|
|
12
|
+
sourceHash: string;
|
|
13
|
+
lastManagedHash: string;
|
|
14
|
+
lastSeenHash: string;
|
|
15
|
+
stagedPath?: string;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SkillsManifest {
|
|
19
|
+
schemaVersion: number;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
skills: Record<string, SkillManifestEntry>;
|
|
22
|
+
}
|
|
23
|
+
interface ManagedSkillSource {
|
|
24
|
+
name: string;
|
|
25
|
+
sourcePath: string;
|
|
26
|
+
}
|
|
27
|
+
interface SkillSyncOptions {
|
|
28
|
+
skills?: ManagedSkillSource[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Hashes of historically managed versions of skills.
|
|
32
|
+
* When a release changes skill content, this table must be populated
|
|
33
|
+
* from the published npm package tarballs to allow upgrading existing users.
|
|
34
|
+
*
|
|
35
|
+
* How to populate:
|
|
36
|
+
* 1. Download previous releases of the npm package: `npm pack oh-my-opencode-slim@<version>`
|
|
37
|
+
* 2. Compute directory hash for each legacy skill directory inside the unpacked tarball:
|
|
38
|
+
* `import { computeDirectoryHash } from './skill-sync';`
|
|
39
|
+
* `const hash = computeDirectoryHash('path/to/extracted/package/src/skills/<skill-name>');`
|
|
40
|
+
* 3. Append the hash to the skill's string array below:
|
|
41
|
+
* ```typescript
|
|
42
|
+
* export const LEGACY_MANAGED_SKILL_HASHES: Record<string, string[]> = {
|
|
43
|
+
* 'simplify': ['hash1', 'hash2'],
|
|
44
|
+
* 'codemap': ['hash3']
|
|
45
|
+
* };
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare const LEGACY_MANAGED_SKILL_HASHES: Record<string, string[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Computes a deterministic SHA-256 hash of a directory's files.
|
|
51
|
+
*/
|
|
52
|
+
export declare function computeDirectoryHash(dirPath: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Acquires a simple lock under .oh-my-opencode-slim.
|
|
55
|
+
* Avoids stealing active locks purely by time; writes owner metadata
|
|
56
|
+
* and only steals dead same-host pid if detectable.
|
|
57
|
+
*/
|
|
58
|
+
export declare function acquireLock(lockDir: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Releases the lock.
|
|
61
|
+
*/
|
|
62
|
+
export declare function releaseLock(lockDir: string): void;
|
|
6
63
|
/**
|
|
7
64
|
* Synchronizes bundled skills from the newly installed package root to OpenCode config skills directory.
|
|
8
65
|
*/
|
|
9
|
-
export declare function syncBundledSkillsFromPackage(packageRoot: string): SkillSyncResult;
|
|
66
|
+
export declare function syncBundledSkillsFromPackage(packageRoot: string, options?: SkillSyncOptions): SkillSyncResult;
|
|
67
|
+
export {};
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
7
7
|
import { type PluginConfig } from '../../config';
|
|
8
|
-
import type { MessageWithParts } from '../types';
|
|
9
8
|
type SkillRule = 'allow' | 'ask' | 'deny';
|
|
10
9
|
declare function filterAvailableSkillsText(text: string, permissionRules: Record<string, SkillRule>): string;
|
|
11
10
|
/**
|
|
@@ -14,7 +13,7 @@ declare function filterAvailableSkillsText(text: string, permissionRules: Record
|
|
|
14
13
|
*/
|
|
15
14
|
export declare function createFilterAvailableSkillsHook(_ctx: PluginInput, config: PluginConfig): {
|
|
16
15
|
'experimental.chat.messages.transform': (_input: Record<string, never>, output: {
|
|
17
|
-
messages
|
|
16
|
+
messages?: unknown;
|
|
18
17
|
}) => Promise<void>;
|
|
19
18
|
};
|
|
20
19
|
export { filterAvailableSkillsText };
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 1. Looks up the next untried model in the agent's configured chain
|
|
7
7
|
* 2. Aborts the rate-limited prompt via client.session.abort()
|
|
8
8
|
* 3. Re-queues the last user message via client.session.promptAsync()
|
|
9
|
-
* with the new model
|
|
9
|
+
* with the new model - promptAsync returns immediately so we never
|
|
10
10
|
* block the event handler waiting for a full LLM response.
|
|
11
11
|
*
|
|
12
12
|
* This mirrors the same fallback loop used for delegated sessions, but operates
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* try/catch, which is not possible for interactive (foreground) sessions.
|
|
15
15
|
*/
|
|
16
16
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
17
|
+
import type { SessionLifecycle } from '../session-lifecycle';
|
|
17
18
|
type OpencodeClient = PluginInput['client'];
|
|
18
19
|
export declare function isRateLimitError(error: unknown): boolean;
|
|
19
20
|
/**
|
|
@@ -31,6 +32,15 @@ export declare class ForegroundFallbackManager {
|
|
|
31
32
|
*/
|
|
32
33
|
private readonly chains;
|
|
33
34
|
private readonly enabled;
|
|
35
|
+
/** Consecutive 429s tolerated on the same model before swap/abort. */
|
|
36
|
+
private readonly maxRetries;
|
|
37
|
+
/**
|
|
38
|
+
* When true (default), a runtime model outside the configured chain
|
|
39
|
+
* still triggers fallback on rate-limit errors. When false, out-of-chain
|
|
40
|
+
* runtime picks are respected and the error surfaces instead. Models
|
|
41
|
+
* that are members of the chain always fall back regardless.
|
|
42
|
+
*/
|
|
43
|
+
private readonly runtimeOverride;
|
|
34
44
|
/** sessionID → last observed model string ("providerID/modelID") */
|
|
35
45
|
private readonly sessionModel;
|
|
36
46
|
/** sessionID → agent name (populated from message.updated info.agent field) */
|
|
@@ -41,18 +51,46 @@ export declare class ForegroundFallbackManager {
|
|
|
41
51
|
private readonly inProgress;
|
|
42
52
|
/** sessionID → timestamp of last trigger (for deduplication) */
|
|
43
53
|
private readonly lastTrigger;
|
|
54
|
+
/** sessionID → model in use when lastTrigger was set; dedup is bypassed
|
|
55
|
+
* when the model has changed, allowing the cascade to continue when a
|
|
56
|
+
* new fallback model also fails within the dedup window. */
|
|
57
|
+
private readonly lastTriggerModel;
|
|
58
|
+
/** sessionID → consecutive 429 count for the current model.
|
|
59
|
+
* Reset on model swap or session deletion. */
|
|
60
|
+
private readonly sessionRetries;
|
|
61
|
+
/** Exposed for task-session-manager: prevents idle reconciliation
|
|
62
|
+
* while a fallback abort/re-prompt is in flight for this session. */
|
|
63
|
+
isFallbackInProgress(sessionID: string): boolean;
|
|
44
64
|
constructor(client: OpencodeClient,
|
|
45
65
|
/**
|
|
46
66
|
* Ordered fallback chains per agent.
|
|
47
67
|
* e.g. { orchestrator: ['anthropic/claude-opus-4-5', 'openai/gpt-4o'] }
|
|
48
68
|
* The first model that hasn't been tried yet is selected on each fallback.
|
|
49
69
|
*/
|
|
50
|
-
chains: Record<string, string[]>, enabled: boolean
|
|
70
|
+
chains: Record<string, string[]>, enabled: boolean,
|
|
71
|
+
/** Consecutive 429s tolerated on the same model before swap/abort. */
|
|
72
|
+
maxRetries?: number, coordinator?: SessionLifecycle,
|
|
73
|
+
/**
|
|
74
|
+
* When true (default), a runtime model outside the configured chain
|
|
75
|
+
* still triggers fallback on rate-limit errors. When false, out-of-chain
|
|
76
|
+
* runtime picks are respected and the error surfaces instead. Models
|
|
77
|
+
* that are members of the chain always fall back regardless.
|
|
78
|
+
*/
|
|
79
|
+
runtimeOverride?: boolean);
|
|
51
80
|
/**
|
|
52
81
|
* Process an OpenCode plugin event.
|
|
53
82
|
* Call this from the plugin's `event` hook for every event received.
|
|
54
83
|
*/
|
|
55
84
|
handleEvent(rawEvent: unknown): Promise<void>;
|
|
85
|
+
/** Increment retry counter and return true when the budget is exhausted.
|
|
86
|
+
* Used by the session.status retry path — each retry counts toward the
|
|
87
|
+
* budget and only triggers fallback after maxRetries - 1 absorptions.
|
|
88
|
+
* Non-retry paths (session.error / message.updated) use shouldIntervene(),
|
|
89
|
+
* which bypasses the counter on first occurrence. */
|
|
90
|
+
private checkRetryBudget;
|
|
91
|
+
/** For non-retry paths (session.error, message.updated): intervene immediately
|
|
92
|
+
* unless the session is already in a retry window (has prior retries). */
|
|
93
|
+
private shouldIntervene;
|
|
56
94
|
private tryFallback;
|
|
57
95
|
/**
|
|
58
96
|
* Determine the fallback chain to use for a session.
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -8,7 +8,9 @@ export { createFilterAvailableSkillsHook } from './filter-available-skills';
|
|
|
8
8
|
export { ForegroundFallbackManager, isRateLimitError, } from './foreground-fallback';
|
|
9
9
|
export { processImageAttachments } from './image-hook';
|
|
10
10
|
export { createJsonErrorRecoveryHook } from './json-error-recovery/hook';
|
|
11
|
+
export { createLoopCommandHook } from './loop-command';
|
|
11
12
|
export { createPhaseReminderHook } from './phase-reminder';
|
|
12
13
|
export { createPostFileToolNudgeHook } from './post-file-tool-nudge';
|
|
13
14
|
export { createReflectCommandHook } from './reflect';
|
|
15
|
+
export { SessionLifecycle } from './session-lifecycle';
|
|
14
16
|
export { createTaskSessionManagerHook } from './task-session-manager';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function createLoopCommandHook(): {
|
|
2
|
+
registerCommand: (config: Record<string, unknown>) => void;
|
|
3
|
+
handleCommandExecuteBefore: (input: {
|
|
4
|
+
command: string;
|
|
5
|
+
sessionID: string;
|
|
6
|
+
arguments: string;
|
|
7
|
+
}, output: {
|
|
8
|
+
parts: Array<{
|
|
9
|
+
type: string;
|
|
10
|
+
text?: string;
|
|
11
|
+
}>;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
};
|
|
@@ -6,15 +6,16 @@
|
|
|
6
6
|
* of the user's actual turn.
|
|
7
7
|
*/
|
|
8
8
|
import { PHASE_REMINDER } from '../../config/constants';
|
|
9
|
-
import type {
|
|
9
|
+
import type { SessionLifecycle } from '../session-lifecycle';
|
|
10
10
|
export { PHASE_REMINDER };
|
|
11
|
+
export declare const PHASE_REMINDER_METADATA_KEY = "oh-my-opencode-slim.phaseReminder";
|
|
11
12
|
/**
|
|
12
13
|
* Creates the experimental.chat.messages.transform hook for phase reminder injection.
|
|
13
14
|
* This hook runs right before sending to API, so it doesn't affect UI display.
|
|
14
15
|
* Only injects for the orchestrator agent.
|
|
15
16
|
*/
|
|
16
|
-
export declare function createPhaseReminderHook(): {
|
|
17
|
+
export declare function createPhaseReminderHook(coordinator?: SessionLifecycle): {
|
|
17
18
|
'experimental.chat.messages.transform': (_input: Record<string, never>, output: {
|
|
18
|
-
messages
|
|
19
|
+
messages?: unknown;
|
|
19
20
|
}) => Promise<void>;
|
|
20
21
|
};
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Post-tool nudge - queues a delegation reminder after file reads/writes.
|
|
3
3
|
* Catches the "inspect/edit files → implement myself" anti-pattern.
|
|
4
|
+
*
|
|
5
|
+
* The reminder is ephemeral: recorded on tool execution, injected via
|
|
6
|
+
* system.transform, and consumed once. File tool output stays clean.
|
|
4
7
|
*/
|
|
5
|
-
|
|
6
|
-
tool: string;
|
|
7
|
-
sessionID?: string;
|
|
8
|
-
callID?: string;
|
|
9
|
-
}
|
|
10
|
-
interface ToolExecuteAfterOutput {
|
|
11
|
-
output?: unknown;
|
|
12
|
-
}
|
|
8
|
+
import type { SessionLifecycle } from '../session-lifecycle';
|
|
13
9
|
interface PostFileToolNudgeOptions {
|
|
14
10
|
shouldInject?: (sessionID: string) => boolean;
|
|
11
|
+
coordinator?: SessionLifecycle;
|
|
15
12
|
}
|
|
16
13
|
export declare function createPostFileToolNudgeHook(options?: PostFileToolNudgeOptions): {
|
|
17
|
-
'tool.execute.after': (input:
|
|
14
|
+
'tool.execute.after': (input: {
|
|
15
|
+
tool: string;
|
|
16
|
+
sessionID?: string;
|
|
17
|
+
callID?: string;
|
|
18
|
+
}, _output: unknown) => Promise<void>;
|
|
19
|
+
'experimental.chat.system.transform': (input: {
|
|
20
|
+
sessionID?: string;
|
|
21
|
+
}, output: {
|
|
22
|
+
system: string[];
|
|
23
|
+
}) => Promise<void>;
|
|
18
24
|
};
|
|
19
25
|
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class SessionLifecycle {
|
|
2
|
+
#private;
|
|
3
|
+
constructor(log: (msg: string, meta?: Record<string, unknown>) => void);
|
|
4
|
+
onSessionDeleted(callback: (sessionId: string) => void): void;
|
|
5
|
+
dispatchSessionDeleted(sessionId: string): void;
|
|
6
|
+
markPending(sessionId: string): void;
|
|
7
|
+
/** Atomic — only one caller gets true per markPending call. */
|
|
8
|
+
consumePending(sessionId: string): boolean;
|
|
9
|
+
hasPendingSession(sessionId: string): boolean;
|
|
10
|
+
clearSession(sessionId: string): void;
|
|
11
|
+
}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
-
import {
|
|
3
|
-
import type {
|
|
2
|
+
import { type BackgroundJobStore } from '../../utils';
|
|
3
|
+
import type { SessionLifecycle } from '../session-lifecycle';
|
|
4
|
+
export declare const BACKGROUND_JOB_BOARD_METADATA_KEY = "oh-my-opencode-slim.backgroundJobBoard";
|
|
4
5
|
export declare function createTaskSessionManagerHook(_ctx: PluginInput, options: {
|
|
5
6
|
maxSessionsPerAgent: number;
|
|
6
7
|
readContextMinLines?: number;
|
|
7
8
|
readContextMaxFiles?: number;
|
|
8
|
-
backgroundJobBoard?:
|
|
9
|
+
backgroundJobBoard?: BackgroundJobStore;
|
|
9
10
|
shouldManageSession: (sessionID: string) => boolean;
|
|
11
|
+
/** Register a session as orchestrator when the transform hook detects
|
|
12
|
+
* an orchestrator message but the session isn't in the agent map yet. */
|
|
13
|
+
registerSessionAsOrchestrator?: (sessionID: string) => void;
|
|
14
|
+
/** Optional guard: when provided, idle events for a session that is
|
|
15
|
+
* currently undergoing a foreground-fallback abort/re-prompt cycle
|
|
16
|
+
* will NOT trigger idle reconciliation. prevents marking a still-
|
|
17
|
+
* active child job as completed when the session was aborted for
|
|
18
|
+
* model fallback rather than natural completion. */
|
|
19
|
+
isFallbackInProgress?: (sessionID: string) => boolean;
|
|
20
|
+
coordinator?: SessionLifecycle;
|
|
10
21
|
}): {
|
|
11
22
|
'tool.execute.before': (input: {
|
|
12
23
|
tool: string;
|
|
@@ -24,7 +35,7 @@ export declare function createTaskSessionManagerHook(_ctx: PluginInput, options:
|
|
|
24
35
|
metadata?: unknown;
|
|
25
36
|
}) => Promise<void>;
|
|
26
37
|
'experimental.chat.messages.transform': (_input: Record<string, never>, output: {
|
|
27
|
-
messages
|
|
38
|
+
messages?: unknown;
|
|
28
39
|
}) => Promise<void>;
|
|
29
40
|
event: (input: {
|
|
30
41
|
event: {
|