oh-my-opencode-slim 2.0.3 → 2.0.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.ja-JP.md +14 -0
- package/README.ko-KR.md +14 -0
- package/README.md +32 -1
- package/README.zh-CN.md +14 -0
- package/dist/agents/permissions.d.ts +10 -0
- package/dist/cli/index.js +27 -10
- package/dist/cli/skills.d.ts +1 -1
- package/dist/companion/manager.d.ts +1 -0
- package/dist/config/constants.d.ts +3 -2
- package/dist/config/schema.d.ts +3 -0
- package/dist/index.js +1430 -260
- package/dist/interview/dashboard.d.ts +5 -0
- package/dist/interview/document.d.ts +4 -1
- package/dist/interview/server.d.ts +2 -0
- package/dist/interview/service.d.ts +2 -0
- package/dist/interview/types.d.ts +13 -0
- package/dist/multiplexer/session-manager.d.ts +2 -0
- package/dist/tools/acp-run.d.ts +1 -1
- package/dist/tui-state.d.ts +3 -0
- package/dist/tui.d.ts +4 -1
- package/dist/tui.js +66 -22
- package/dist/utils/background-job-board.d.ts +4 -0
- package/dist/utils/env.d.ts +3 -0
- package/oh-my-opencode-slim.schema.json +18 -3
- package/package.json +1 -1
|
@@ -45,6 +45,11 @@ export declare function createDashboardServer(config: DashboardConfig): {
|
|
|
45
45
|
answer: string;
|
|
46
46
|
}> | null;
|
|
47
47
|
consumeNudgeAction: (interviewId: string) => 'more-questions' | 'confirm-complete' | null;
|
|
48
|
+
consumeBlockComment: (interviewId: string) => {
|
|
49
|
+
section: string;
|
|
50
|
+
comment: string;
|
|
51
|
+
} | null;
|
|
52
|
+
consumeChatMessage: (interviewId: string) => string | null;
|
|
48
53
|
authToken: string;
|
|
49
54
|
discoverSessionDirectories: () => Promise<void>;
|
|
50
55
|
addManualFolder: (dir: string) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InterviewAnswer, InterviewQuestion, InterviewRecord } from './types';
|
|
1
|
+
import type { InterviewAnswer, InterviewQuestion, InterviewRecord, SpecBlock } from './types';
|
|
2
2
|
export declare const DEFAULT_OUTPUT_FOLDER = "interview";
|
|
3
3
|
export declare function normalizeOutputFolder(outputFolder: string): string;
|
|
4
4
|
export declare function createInterviewDirectoryPath(directory: string, outputFolder: string): string;
|
|
@@ -16,6 +16,8 @@ export declare function extractTitle(document: string): string;
|
|
|
16
16
|
export declare function buildInterviewDocument(idea: string, summary: string, history: string, meta?: {
|
|
17
17
|
sessionID?: string;
|
|
18
18
|
baseMessageCount?: number;
|
|
19
|
+
owner?: string;
|
|
20
|
+
tags?: string[];
|
|
19
21
|
}): string;
|
|
20
22
|
/** Parse frontmatter from a .md file. Returns null if no frontmatter. */
|
|
21
23
|
export declare function parseFrontmatter(content: string): Record<string, string> | null;
|
|
@@ -23,3 +25,4 @@ export declare function ensureInterviewFile(record: InterviewRecord): Promise<vo
|
|
|
23
25
|
export declare function readInterviewDocument(record: InterviewRecord): Promise<string>;
|
|
24
26
|
export declare function rewriteInterviewDocument(record: InterviewRecord, summary: string): Promise<string>;
|
|
25
27
|
export declare function appendInterviewAnswers(record: InterviewRecord, questions: InterviewQuestion[], answers: InterviewAnswer[]): Promise<void>;
|
|
28
|
+
export declare function parseSpecBlocks(markdown: string): SpecBlock[];
|
|
@@ -4,6 +4,8 @@ export declare function createInterviewServer(deps: {
|
|
|
4
4
|
listInterviewFiles: () => Promise<InterviewFileItem[]>;
|
|
5
5
|
listInterviews: () => InterviewListItem[];
|
|
6
6
|
submitAnswers: (interviewId: string, answers: InterviewAnswer[]) => Promise<void>;
|
|
7
|
+
submitBlockComment: (interviewId: string, section: string, comment: string) => Promise<void>;
|
|
8
|
+
submitChat: (interviewId: string, message: string) => Promise<void>;
|
|
7
9
|
handleNudgeAction: (interviewId: string, action: 'more-questions' | 'confirm-complete') => Promise<void>;
|
|
8
10
|
outputFolder: string;
|
|
9
11
|
port: number;
|
|
@@ -30,5 +30,7 @@ export declare function createInterviewService(ctx: PluginInput, config?: Interv
|
|
|
30
30
|
listInterviewFiles: () => Promise<InterviewFileItem[]>;
|
|
31
31
|
listInterviews: () => InterviewListItem[];
|
|
32
32
|
submitAnswers: (interviewId: string, answers: InterviewAnswer[]) => Promise<void>;
|
|
33
|
+
submitBlockComment: (interviewId: string, section: string, comment: string) => Promise<void>;
|
|
34
|
+
submitChat: (interviewId: string, message: string) => Promise<void>;
|
|
33
35
|
handleNudgeAction: (interviewId: string, action: 'more-questions' | 'confirm-complete') => Promise<void>;
|
|
34
36
|
};
|
|
@@ -61,6 +61,11 @@ export interface InterviewFileItem {
|
|
|
61
61
|
sessionID?: string;
|
|
62
62
|
directory?: string;
|
|
63
63
|
}
|
|
64
|
+
export interface SpecBlock {
|
|
65
|
+
id: string;
|
|
66
|
+
title: string;
|
|
67
|
+
content: string;
|
|
68
|
+
}
|
|
64
69
|
export interface InterviewState {
|
|
65
70
|
interview: InterviewRecord;
|
|
66
71
|
url: string;
|
|
@@ -71,6 +76,7 @@ export interface InterviewState {
|
|
|
71
76
|
summary: string;
|
|
72
77
|
questions: InterviewQuestion[];
|
|
73
78
|
document: string;
|
|
79
|
+
blocks: SpecBlock[];
|
|
74
80
|
}
|
|
75
81
|
/** Wire format for dashboard state cache entries. */
|
|
76
82
|
export interface InterviewStateEntry {
|
|
@@ -93,4 +99,11 @@ export interface InterviewStateEntry {
|
|
|
93
99
|
lastUpdatedAt: number;
|
|
94
100
|
filePath: string;
|
|
95
101
|
nudgeAction: 'more-questions' | 'confirm-complete' | null;
|
|
102
|
+
pendingBlockComment: {
|
|
103
|
+
section: string;
|
|
104
|
+
comment: string;
|
|
105
|
+
} | null;
|
|
106
|
+
pendingChatMessage: string | null;
|
|
107
|
+
document?: string;
|
|
108
|
+
blocks?: SpecBlock[];
|
|
96
109
|
}
|
|
@@ -33,6 +33,7 @@ export declare class MultiplexerSessionManager {
|
|
|
33
33
|
private knownSessions;
|
|
34
34
|
private spawningSessions;
|
|
35
35
|
private closingSessions;
|
|
36
|
+
private deferredIdleCloses;
|
|
36
37
|
private pollInterval?;
|
|
37
38
|
private enabled;
|
|
38
39
|
constructor(ctx: PluginInput, config: MultiplexerConfig, backgroundJobBoard?: BackgroundJobBoard | undefined);
|
|
@@ -49,6 +50,7 @@ export declare class MultiplexerSessionManager {
|
|
|
49
50
|
private updatePolling;
|
|
50
51
|
private getSessionId;
|
|
51
52
|
private isRunningBackgroundJob;
|
|
53
|
+
retryDeferredIdleClose(sessionId: string): Promise<void>;
|
|
52
54
|
cleanup(): Promise<void>;
|
|
53
55
|
}
|
|
54
56
|
/**
|
package/dist/tools/acp-run.d.ts
CHANGED
package/dist/tui-state.d.ts
CHANGED
|
@@ -2,14 +2,17 @@ export interface TuiSnapshot {
|
|
|
2
2
|
version: 1;
|
|
3
3
|
updatedAt: number;
|
|
4
4
|
agentModels: Record<string, string>;
|
|
5
|
+
agentVariants: Record<string, string>;
|
|
5
6
|
}
|
|
6
7
|
export declare function getTuiStatePath(): string;
|
|
7
8
|
export declare function readTuiSnapshot(): TuiSnapshot;
|
|
8
9
|
export declare function readTuiSnapshotAsync(): Promise<TuiSnapshot>;
|
|
9
10
|
export declare function recordTuiAgentModels(input: {
|
|
10
11
|
agentModels: Record<string, string>;
|
|
12
|
+
agentVariants?: Record<string, string>;
|
|
11
13
|
}): void;
|
|
12
14
|
export declare function recordTuiAgentModel(input: {
|
|
13
15
|
agentName: string;
|
|
14
16
|
model: string;
|
|
17
|
+
variant?: string | null;
|
|
15
18
|
}): void;
|
package/dist/tui.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { TuiPluginModule } from '@opencode-ai/plugin/tui';
|
|
2
2
|
import { type TuiSnapshot } from './tui-state';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function splitSidebarModelId(model: string): {
|
|
4
|
+
provider?: string;
|
|
5
|
+
model: string;
|
|
6
|
+
};
|
|
4
7
|
export declare function getSidebarAgentNames(snapshot: TuiSnapshot): string[];
|
|
5
8
|
export declare function readConfigInvalid(directory: string): boolean;
|
|
6
9
|
declare const plugin: TuiPluginModule & {
|
package/dist/tui.js
CHANGED
|
@@ -118,14 +118,14 @@ var ALL_AGENT_NAMES = ["orchestrator", ...SUBAGENT_NAMES];
|
|
|
118
118
|
var PROTECTED_AGENTS = new Set(["orchestrator", "councillor"]);
|
|
119
119
|
var DEFAULT_MODELS = {
|
|
120
120
|
orchestrator: undefined,
|
|
121
|
-
oracle:
|
|
122
|
-
librarian:
|
|
123
|
-
explorer:
|
|
124
|
-
designer:
|
|
125
|
-
fixer:
|
|
126
|
-
observer:
|
|
127
|
-
council:
|
|
128
|
-
councillor:
|
|
121
|
+
oracle: undefined,
|
|
122
|
+
librarian: undefined,
|
|
123
|
+
explorer: undefined,
|
|
124
|
+
designer: undefined,
|
|
125
|
+
fixer: undefined,
|
|
126
|
+
observer: undefined,
|
|
127
|
+
council: undefined,
|
|
128
|
+
councillor: undefined
|
|
129
129
|
};
|
|
130
130
|
var POLL_INTERVAL_BACKGROUND_MS = 2000;
|
|
131
131
|
var MAX_POLL_TIME_MS = 5 * 60 * 1000;
|
|
@@ -353,6 +353,7 @@ var CompanionConfigSchema = z2.object({
|
|
|
353
353
|
debug: z2.boolean().optional().describe("Enable verbose native companion debug logs.")
|
|
354
354
|
});
|
|
355
355
|
var AcpAgentPermissionModeSchema = z2.enum(["ask", "allow", "reject"]);
|
|
356
|
+
var MAX_ACP_TIMEOUT_MS = 2147483647;
|
|
356
357
|
var AcpAgentConfigSchema = z2.object({
|
|
357
358
|
command: z2.string().min(1),
|
|
358
359
|
args: z2.array(z2.string()).default([]),
|
|
@@ -362,7 +363,7 @@ var AcpAgentConfigSchema = z2.object({
|
|
|
362
363
|
prompt: z2.string().min(1).optional(),
|
|
363
364
|
orchestratorPrompt: z2.string().min(1).optional(),
|
|
364
365
|
wrapperModel: ProviderModelIdSchema.optional(),
|
|
365
|
-
timeoutMs: z2.number().int().min(
|
|
366
|
+
timeoutMs: z2.number().int().min(0).max(MAX_ACP_TIMEOUT_MS).default(0).describe("Timeout for a single ACP run in milliseconds. Set to 0 to disable the timeout."),
|
|
366
367
|
permissionMode: AcpAgentPermissionModeSchema.default("ask")
|
|
367
368
|
}).strict();
|
|
368
369
|
var AcpAgentsConfigSchema = z2.record(z2.string(), AcpAgentConfigSchema);
|
|
@@ -396,6 +397,8 @@ var PluginConfigSchema = z2.object({
|
|
|
396
397
|
agents: z2.record(z2.string(), AgentOverrideConfigSchema).optional(),
|
|
397
398
|
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."),
|
|
398
399
|
disabled_mcps: z2.array(z2.string()).optional(),
|
|
400
|
+
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."),
|
|
401
|
+
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."),
|
|
399
402
|
multiplexer: MultiplexerConfigSchema.optional(),
|
|
400
403
|
tmux: TmuxConfigSchema.optional(),
|
|
401
404
|
websearch: WebsearchConfigSchema.optional(),
|
|
@@ -732,7 +735,8 @@ function emptySnapshot() {
|
|
|
732
735
|
return {
|
|
733
736
|
version: 1,
|
|
734
737
|
updatedAt: Date.now(),
|
|
735
|
-
agentModels: {}
|
|
738
|
+
agentModels: {},
|
|
739
|
+
agentVariants: {}
|
|
736
740
|
};
|
|
737
741
|
}
|
|
738
742
|
function parseSnapshot(value) {
|
|
@@ -742,7 +746,8 @@ function parseSnapshot(value) {
|
|
|
742
746
|
return {
|
|
743
747
|
version: 1,
|
|
744
748
|
updatedAt: typeof parsed.updatedAt === "number" ? parsed.updatedAt : Date.now(),
|
|
745
|
-
agentModels: parsed.agentModels ?? {}
|
|
749
|
+
agentModels: parsed.agentModels ?? {},
|
|
750
|
+
agentVariants: parsed.agentVariants ?? {}
|
|
746
751
|
};
|
|
747
752
|
}
|
|
748
753
|
function readTuiSnapshot() {
|
|
@@ -776,14 +781,32 @@ function updateSnapshot(mutator) {
|
|
|
776
781
|
function recordTuiAgentModels(input) {
|
|
777
782
|
updateSnapshot((snapshot) => {
|
|
778
783
|
snapshot.agentModels = { ...input.agentModels };
|
|
784
|
+
snapshot.agentVariants = { ...input.agentVariants ?? {} };
|
|
779
785
|
});
|
|
780
786
|
}
|
|
781
787
|
function recordTuiAgentModel(input) {
|
|
782
788
|
updateSnapshot((snapshot) => {
|
|
783
789
|
snapshot.agentModels[input.agentName] = input.model;
|
|
790
|
+
if (input.variant !== undefined) {
|
|
791
|
+
if (input.variant === null) {
|
|
792
|
+
delete snapshot.agentVariants[input.agentName];
|
|
793
|
+
} else {
|
|
794
|
+
snapshot.agentVariants[input.agentName] = input.variant;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
784
797
|
});
|
|
785
798
|
}
|
|
786
799
|
|
|
800
|
+
// src/utils/env.ts
|
|
801
|
+
var TRUTHY_ENV_VALUES = new Set(["1", "true", "yes", "on"]);
|
|
802
|
+
var PLUGIN_DISABLE_ENV = "OH_MY_OPENCODE_SLIM_DISABLE";
|
|
803
|
+
function isTruthyEnvValue(value) {
|
|
804
|
+
return TRUTHY_ENV_VALUES.has(value?.trim().toLowerCase() ?? "");
|
|
805
|
+
}
|
|
806
|
+
function isPluginDisabledByEnv(env = process.env) {
|
|
807
|
+
return isTruthyEnvValue(env[PLUGIN_DISABLE_ENV]);
|
|
808
|
+
}
|
|
809
|
+
|
|
787
810
|
// src/tui.ts
|
|
788
811
|
var PLUGIN_NAME = "oh-my-opencode-slim";
|
|
789
812
|
var CONFIG_WARNING_COLOR = "orange";
|
|
@@ -816,24 +839,42 @@ function text(props, children) {
|
|
|
816
839
|
function box(props, children = []) {
|
|
817
840
|
return element("box", props, children);
|
|
818
841
|
}
|
|
819
|
-
function truncate(value, max = 24) {
|
|
820
|
-
return value.length > max ? `${value.slice(0, max - 1)}…` : value;
|
|
821
|
-
}
|
|
822
842
|
function getTuiDirectory(api) {
|
|
823
843
|
return api.state?.path?.directory ?? process.cwd();
|
|
824
844
|
}
|
|
825
|
-
function
|
|
826
|
-
const
|
|
827
|
-
|
|
845
|
+
function splitSidebarModelId(model) {
|
|
846
|
+
const slashIndex = model.indexOf("/");
|
|
847
|
+
if (slashIndex === -1) {
|
|
848
|
+
return { model };
|
|
849
|
+
}
|
|
850
|
+
return {
|
|
851
|
+
provider: model.slice(0, slashIndex),
|
|
852
|
+
model: model.slice(slashIndex + 1)
|
|
853
|
+
};
|
|
828
854
|
}
|
|
829
855
|
function getSidebarAgentNames(snapshot) {
|
|
830
856
|
const configuredAgents = Object.keys(snapshot.agentModels);
|
|
831
857
|
return configuredAgents.length > 0 ? configuredAgents : FALLBACK_SIDEBAR_AGENTS;
|
|
832
858
|
}
|
|
833
|
-
function
|
|
834
|
-
|
|
859
|
+
function agentRow(label, model, variant, theme) {
|
|
860
|
+
const modelParts = splitSidebarModelId(model);
|
|
861
|
+
const detailRows = [];
|
|
862
|
+
if (modelParts.provider) {
|
|
863
|
+
detailRows.push(agentDetailRow("provider", modelParts.provider, theme));
|
|
864
|
+
}
|
|
865
|
+
detailRows.push(agentDetailRow("model", modelParts.model, theme));
|
|
866
|
+
if (variant) {
|
|
867
|
+
detailRows.push(agentDetailRow("variant", variant, theme));
|
|
868
|
+
}
|
|
869
|
+
return box({ width: "100%", flexDirection: "column", marginBottom: 1 }, [
|
|
835
870
|
text({ fg: theme.textMuted }, [label]),
|
|
836
|
-
|
|
871
|
+
...detailRows
|
|
872
|
+
]);
|
|
873
|
+
}
|
|
874
|
+
function agentDetailRow(label, value, theme) {
|
|
875
|
+
return box({ width: "100%", flexDirection: "row", paddingLeft: 2 }, [
|
|
876
|
+
text({ fg: theme.textMuted, width: 9 }, [label]),
|
|
877
|
+
text({ fg: theme.textMuted }, [value])
|
|
837
878
|
]);
|
|
838
879
|
}
|
|
839
880
|
function renderSidebar(snapshot, version, theme, configInvalid) {
|
|
@@ -863,7 +904,8 @@ function renderSidebar(snapshot, version, theme, configInvalid) {
|
|
|
863
904
|
]),
|
|
864
905
|
...getSidebarAgentNames(snapshot).map((agentName) => {
|
|
865
906
|
const model = snapshot.agentModels[agentName] ?? "pending";
|
|
866
|
-
|
|
907
|
+
const variant = snapshot.agentVariants[agentName];
|
|
908
|
+
return agentRow(agentName, model, variant, theme);
|
|
867
909
|
})
|
|
868
910
|
]);
|
|
869
911
|
}
|
|
@@ -893,6 +935,8 @@ function readConfigInvalid(directory) {
|
|
|
893
935
|
var plugin = {
|
|
894
936
|
id: `${PLUGIN_NAME}:tui`,
|
|
895
937
|
tui: async (api, _options, meta) => {
|
|
938
|
+
if (isPluginDisabledByEnv())
|
|
939
|
+
return;
|
|
896
940
|
const version = meta.version ?? await readPackageVersion() ?? "dev";
|
|
897
941
|
let configDirectory = getTuiDirectory(api);
|
|
898
942
|
let configInvalid = readConfigInvalid(configDirectory);
|
|
@@ -923,8 +967,8 @@ var plugin = {
|
|
|
923
967
|
};
|
|
924
968
|
var tui_default = plugin;
|
|
925
969
|
export {
|
|
970
|
+
splitSidebarModelId,
|
|
926
971
|
readConfigInvalid,
|
|
927
972
|
getSidebarAgentNames,
|
|
928
|
-
formatSidebarModelName,
|
|
929
973
|
tui_default as default
|
|
930
974
|
};
|
|
@@ -51,13 +51,16 @@ export interface BackgroundJobStatusInput {
|
|
|
51
51
|
lastStatusError?: string;
|
|
52
52
|
now?: number;
|
|
53
53
|
}
|
|
54
|
+
type TerminalStateListener = (taskID: string) => void;
|
|
54
55
|
export declare class BackgroundJobBoard {
|
|
55
56
|
private readonly jobs;
|
|
56
57
|
private readonly counters;
|
|
58
|
+
private terminalStateListener?;
|
|
57
59
|
private readonly maxReusablePerAgent;
|
|
58
60
|
private readonly readContextMinLines;
|
|
59
61
|
private readonly readContextMaxFiles;
|
|
60
62
|
constructor(options?: BackgroundJobBoardOptions);
|
|
63
|
+
setTerminalStateListener(listener?: TerminalStateListener): void;
|
|
61
64
|
registerLaunch(input: BackgroundJobLaunchInput): BackgroundJobRecord;
|
|
62
65
|
updateStatus(input: BackgroundJobStatusInput): BackgroundJobRecord | undefined;
|
|
63
66
|
updateFromStatusOutput(output: string): BackgroundJobRecord | undefined;
|
|
@@ -87,3 +90,4 @@ export declare function deriveTaskSessionLabel(input: {
|
|
|
87
90
|
prompt?: string;
|
|
88
91
|
agentType: string;
|
|
89
92
|
}): string;
|
|
93
|
+
export {};
|
|
@@ -197,6 +197,20 @@
|
|
|
197
197
|
"type": "string"
|
|
198
198
|
}
|
|
199
199
|
},
|
|
200
|
+
"disabled_tools": {
|
|
201
|
+
"description": "Tool names to disable completely. Disabled tools are not registered with OpenCode and cannot be used by agents.",
|
|
202
|
+
"type": "array",
|
|
203
|
+
"items": {
|
|
204
|
+
"type": "string"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"disabled_skills": {
|
|
208
|
+
"description": "Skill names to disable completely. Disabled skills are not granted to agents, even when referenced by presets or agent overrides.",
|
|
209
|
+
"type": "array",
|
|
210
|
+
"items": {
|
|
211
|
+
"type": "string"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
200
214
|
"multiplexer": {
|
|
201
215
|
"type": "object",
|
|
202
216
|
"properties": {
|
|
@@ -515,10 +529,11 @@
|
|
|
515
529
|
"pattern": "^[^/\\s]+\\/[^\\s]+$"
|
|
516
530
|
},
|
|
517
531
|
"timeoutMs": {
|
|
518
|
-
"default":
|
|
532
|
+
"default": 0,
|
|
533
|
+
"description": "Timeout for a single ACP run in milliseconds. Set to 0 to disable the timeout.",
|
|
519
534
|
"type": "integer",
|
|
520
|
-
"minimum":
|
|
521
|
-
"maximum":
|
|
535
|
+
"minimum": 0,
|
|
536
|
+
"maximum": 2147483647
|
|
522
537
|
},
|
|
523
538
|
"permissionMode": {
|
|
524
539
|
"default": "ask",
|
package/package.json
CHANGED