oh-my-opencode-slim 2.1.0 → 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 +31 -30
- package/README.ko-KR.md +31 -30
- package/README.md +57 -33
- package/README.zh-CN.md +29 -28
- package/dist/agents/index.d.ts +0 -4
- package/dist/cli/index.js +90 -16
- package/dist/cli/providers.d.ts +7 -7
- package/dist/companion/manager.d.ts +3 -0
- package/dist/config/constants.d.ts +12 -1
- package/dist/config/council-schema.d.ts +37 -12
- package/dist/config/schema.d.ts +691 -6
- package/dist/config/strip-orchestrator-model.d.ts +9 -0
- package/dist/council/council-manager.d.ts +7 -3
- package/dist/hooks/command-hook-utils.d.ts +5 -0
- package/dist/hooks/foreground-fallback/index.d.ts +53 -7
- package/dist/hooks/image-hook.d.ts +1 -0
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/phase-reminder/index.d.ts +3 -1
- 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 +14 -2
- package/dist/index.js +2804 -801
- package/dist/interview/document.d.ts +2 -1
- package/dist/interview/service.d.ts +2 -0
- 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 +7 -3
- package/dist/multiplexer/index.d.ts +3 -1
- package/dist/multiplexer/session-manager.d.ts +14 -6
- package/dist/multiplexer/shared.d.ts +31 -0
- package/dist/multiplexer/tmux/index.d.ts +0 -1
- package/dist/multiplexer/types.d.ts +5 -2
- package/dist/multiplexer/zellij/index.d.ts +0 -1
- package/dist/tools/cancel-task.d.ts +2 -2
- package/dist/tools/smartfetch/utils.d.ts +3 -1
- package/dist/tui-state.d.ts +5 -5
- package/dist/tui.d.ts +1 -0
- package/dist/tui.js +130 -29
- package/dist/utils/background-job-board.d.ts +5 -1
- 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/escape-html.d.ts +1 -0
- package/dist/utils/frontmatter.d.ts +6 -0
- package/dist/utils/index.d.ts +3 -1
- package/dist/utils/internal-initiator.d.ts +6 -1
- package/dist/utils/logger.d.ts +0 -2
- package/dist/utils/session.d.ts +1 -1
- package/oh-my-opencode-slim.schema.json +728 -1
- 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/oh-my-opencode-slim/SKILL.md +3 -3
- package/src/skills/release-smoke-test/SKILL.md +2 -2
- package/src/skills/verification-planning/SKILL.md +103 -0
- package/src/skills/worktrees/SKILL.md +14 -7
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PluginConfig, Preset } from './schema';
|
|
2
|
+
export declare function stripOrchestratorModel(agents: Record<string, unknown>, enabled: boolean | undefined, preset: Preset | undefined): void;
|
|
3
|
+
export declare function applyOrchestratorModelConfig(input: {
|
|
4
|
+
agents: Record<string, unknown>;
|
|
5
|
+
enabled: boolean | undefined;
|
|
6
|
+
presets: PluginConfig['presets'];
|
|
7
|
+
configPreset: string | undefined;
|
|
8
|
+
runtimePreset: string | null;
|
|
9
|
+
}): void;
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register a command hook in the OpenCode config if it doesn't already exist.
|
|
3
|
+
* Returns true if the command was registered, false if it already existed.
|
|
4
|
+
*/
|
|
5
|
+
export declare function registerCommandHook(opencodeConfig: Record<string, unknown>, commandName: string, template: string, description: string): boolean;
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
* Runtime model fallback for foreground (interactive) agent sessions.
|
|
3
3
|
*
|
|
4
4
|
* When OpenCode fires a session.error, message.updated, or session.status
|
|
5
|
-
* event containing a rate-limit
|
|
5
|
+
* event containing a transient error (rate-limit, 403/Forbidden, etc.), this
|
|
6
|
+
* manager:
|
|
6
7
|
* 1. Looks up the next untried model in the agent's configured chain
|
|
7
|
-
* 2. Aborts the rate-limited prompt via client.session.abort()
|
|
8
|
+
* 2. Aborts the rate-limited prompt via client.session.abort() on the
|
|
9
|
+
* session.status retry path; session.error and message.updated paths
|
|
10
|
+
* re-prompt directly without abort.
|
|
8
11
|
* 3. Re-queues the last user message via client.session.promptAsync()
|
|
9
12
|
* with the new model - promptAsync returns immediately so we never
|
|
10
13
|
* block the event handler waiting for a full LLM response.
|
|
@@ -14,7 +17,15 @@
|
|
|
14
17
|
* try/catch, which is not possible for interactive (foreground) sessions.
|
|
15
18
|
*/
|
|
16
19
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
20
|
+
import type { SessionLifecycle } from '../session-lifecycle';
|
|
17
21
|
type OpencodeClient = PluginInput['client'];
|
|
22
|
+
export declare function isFailoverError(error: unknown): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Checks whether an error is a transient/retryable error (rate-limit,
|
|
25
|
+
* 403/Forbidden, etc.) that should trigger model fallback.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isRetryableError(error: unknown): boolean;
|
|
28
|
+
/** @deprecated Use isRetryableError instead. */
|
|
18
29
|
export declare function isRateLimitError(error: unknown): boolean;
|
|
19
30
|
/**
|
|
20
31
|
* Manages runtime model fallback for foreground agent sessions.
|
|
@@ -29,8 +40,10 @@ export declare class ForegroundFallbackManager {
|
|
|
29
40
|
* e.g. { orchestrator: ['anthropic/claude-opus-4-5', 'openai/gpt-4o'] }
|
|
30
41
|
* The first model that hasn't been tried yet is selected on each fallback.
|
|
31
42
|
*/
|
|
32
|
-
private
|
|
43
|
+
private chains;
|
|
33
44
|
private readonly enabled;
|
|
45
|
+
/** Consecutive 429s tolerated on the same model before swap/abort. */
|
|
46
|
+
private readonly maxRetries;
|
|
34
47
|
/** sessionID → last observed model string ("providerID/modelID") */
|
|
35
48
|
private readonly sessionModel;
|
|
36
49
|
/** sessionID → agent name (populated from message.updated info.agent field) */
|
|
@@ -45,27 +58,60 @@ export declare class ForegroundFallbackManager {
|
|
|
45
58
|
* when the model has changed, allowing the cascade to continue when a
|
|
46
59
|
* new fallback model also fails within the dedup window. */
|
|
47
60
|
private readonly lastTriggerModel;
|
|
61
|
+
/** sessionID → consecutive 429 count for the current model.
|
|
62
|
+
* Reset on model swap or session deletion. */
|
|
63
|
+
private readonly sessionRetries;
|
|
64
|
+
/** Exposed for task-session-manager: prevents idle reconciliation
|
|
65
|
+
* while a fallback abort/re-prompt is in flight for this session. */
|
|
66
|
+
isFallbackInProgress(sessionID: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Disable the fallback chain for a specific agent.
|
|
69
|
+
* After calling this, rate-limit errors for that agent surface instead of
|
|
70
|
+
* silently falling back through the chain.
|
|
71
|
+
*/
|
|
72
|
+
disableChain(agentName: string): void;
|
|
73
|
+
registerSessionAgent(sessionID: string, agentName: string): void;
|
|
48
74
|
constructor(client: OpencodeClient,
|
|
49
75
|
/**
|
|
50
76
|
* Ordered fallback chains per agent.
|
|
51
77
|
* e.g. { orchestrator: ['anthropic/claude-opus-4-5', 'openai/gpt-4o'] }
|
|
52
78
|
* The first model that hasn't been tried yet is selected on each fallback.
|
|
53
79
|
*/
|
|
54
|
-
chains: Record<string, string[]>, enabled: boolean
|
|
80
|
+
chains: Record<string, string[]>, enabled: boolean,
|
|
81
|
+
/** Consecutive 429s tolerated on the same model before swap/abort. */
|
|
82
|
+
maxRetries?: number, coordinator?: SessionLifecycle);
|
|
55
83
|
/**
|
|
56
84
|
* Process an OpenCode plugin event.
|
|
57
85
|
* Call this from the plugin's `event` hook for every event received.
|
|
58
86
|
*/
|
|
59
87
|
handleEvent(rawEvent: unknown): Promise<void>;
|
|
88
|
+
/** Increment retry counter and return true when the budget is exhausted.
|
|
89
|
+
* Used by shouldIntervene when tried > 0 — each retry counts toward the
|
|
90
|
+
* budget and only triggers fallback after maxRetries - 1 absorptions.
|
|
91
|
+
* First failover retry (tried === 0) bypasses the counter via shouldIntervene. */
|
|
92
|
+
private consumeRetryBudget;
|
|
93
|
+
/** Intervene immediately on first occurrence (tried === 0), otherwise
|
|
94
|
+
* delegate to retry budget. Used by all three event paths. */
|
|
95
|
+
private shouldTriggerFallback;
|
|
96
|
+
private isRecoveredStatus;
|
|
60
97
|
private tryFallback;
|
|
98
|
+
/**
|
|
99
|
+
* Fallback path for session.status retry events. Aborts the retry loop
|
|
100
|
+
* before falling back because promptAsync alone is ignored while the
|
|
101
|
+
* session is in retry mode. inProgress is set first so the
|
|
102
|
+
* task-session-manager sees isFallbackInProgress()=true during the
|
|
103
|
+
* abort idle window and does not cancel the pending task call.
|
|
104
|
+
*/
|
|
105
|
+
private tryFallbackWithAbort;
|
|
106
|
+
private isDeduped;
|
|
107
|
+
private execFallback;
|
|
61
108
|
/**
|
|
62
109
|
* Determine the fallback chain to use for a session.
|
|
63
110
|
*
|
|
64
111
|
* Priority:
|
|
65
112
|
* 1. Agent name known AND has a configured chain → return it directly
|
|
66
|
-
* 2. Agent name known but NO chain
|
|
67
|
-
*
|
|
68
|
-
* session with a model belonging to a completely different agent)
|
|
113
|
+
* 2. Agent name known but NO chain → return [] (no fallback; never
|
|
114
|
+
* bleed into other agents' chains)
|
|
69
115
|
* 3. Agent name unknown, current model known → search all chains for
|
|
70
116
|
* the model to infer which chain to use
|
|
71
117
|
* 4. Nothing matches → flatten all chains as a last resort (only
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -5,11 +5,12 @@ export { createChatHeadersHook } from './chat-headers';
|
|
|
5
5
|
export { createDeepworkCommandHook } from './deepwork';
|
|
6
6
|
export { createDelegateTaskRetryHook } from './delegate-task-retry/hook';
|
|
7
7
|
export { createFilterAvailableSkillsHook } from './filter-available-skills';
|
|
8
|
-
export { ForegroundFallbackManager,
|
|
8
|
+
export { ForegroundFallbackManager, isFailoverError, isRetryableError, } from './foreground-fallback';
|
|
9
9
|
export { processImageAttachments } from './image-hook';
|
|
10
10
|
export { createJsonErrorRecoveryHook } from './json-error-recovery/hook';
|
|
11
11
|
export { createLoopCommandHook } from './loop-command';
|
|
12
12
|
export { createPhaseReminderHook } from './phase-reminder';
|
|
13
13
|
export { createPostFileToolNudgeHook } from './post-file-tool-nudge';
|
|
14
14
|
export { createReflectCommandHook } from './reflect';
|
|
15
|
+
export { SessionLifecycle } from './session-lifecycle';
|
|
15
16
|
export { createTaskSessionManagerHook } from './task-session-manager';
|
|
@@ -6,13 +6,15 @@
|
|
|
6
6
|
* of the user's actual turn.
|
|
7
7
|
*/
|
|
8
8
|
import { PHASE_REMINDER } from '../../config/constants';
|
|
9
|
+
import type { SessionLifecycle } from '../session-lifecycle';
|
|
9
10
|
export { PHASE_REMINDER };
|
|
11
|
+
export declare const PHASE_REMINDER_METADATA_KEY = "oh-my-opencode-slim.phaseReminder";
|
|
10
12
|
/**
|
|
11
13
|
* Creates the experimental.chat.messages.transform hook for phase reminder injection.
|
|
12
14
|
* This hook runs right before sending to API, so it doesn't affect UI display.
|
|
13
15
|
* Only injects for the orchestrator agent.
|
|
14
16
|
*/
|
|
15
|
-
export declare function createPhaseReminderHook(): {
|
|
17
|
+
export declare function createPhaseReminderHook(coordinator?: SessionLifecycle): {
|
|
16
18
|
'experimental.chat.messages.transform': (_input: Record<string, never>, output: {
|
|
17
19
|
messages?: unknown;
|
|
18
20
|
}) => Promise<void>;
|
|
@@ -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,11 +1,23 @@
|
|
|
1
1
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
-
import {
|
|
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";
|
|
3
5
|
export declare function createTaskSessionManagerHook(_ctx: PluginInput, options: {
|
|
4
6
|
maxSessionsPerAgent: number;
|
|
5
7
|
readContextMinLines?: number;
|
|
6
8
|
readContextMaxFiles?: number;
|
|
7
|
-
backgroundJobBoard?:
|
|
9
|
+
backgroundJobBoard?: BackgroundJobStore;
|
|
8
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;
|
|
9
21
|
}): {
|
|
10
22
|
'tool.execute.before': (input: {
|
|
11
23
|
tool: string;
|