oh-my-opencode 3.5.1 → 3.5.2
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/dist/cli/index.js +25 -21
- package/dist/config/schema/categories.d.ts +2 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +1 -0
- package/dist/hooks/auto-update-checker/checker/pinned-version-updater.d.ts +1 -0
- package/dist/hooks/auto-update-checker/checker.d.ts +1 -1
- package/dist/index.js +87 -57
- package/dist/shared/merge-categories.d.ts +6 -0
- package/package.json +8 -8
package/dist/cli/index.js
CHANGED
|
@@ -8326,10 +8326,9 @@ var init_cached_version = __esm(() => {
|
|
|
8326
8326
|
|
|
8327
8327
|
// src/hooks/auto-update-checker/checker/pinned-version-updater.ts
|
|
8328
8328
|
import * as fs9 from "fs";
|
|
8329
|
-
function
|
|
8329
|
+
function replacePluginEntry(configPath, oldEntry, newEntry) {
|
|
8330
8330
|
try {
|
|
8331
8331
|
const content = fs9.readFileSync(configPath, "utf-8");
|
|
8332
|
-
const newEntry = `${PACKAGE_NAME3}@${newVersion}`;
|
|
8333
8332
|
const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
|
|
8334
8333
|
if (!pluginMatch || pluginMatch.index === undefined) {
|
|
8335
8334
|
log(`[auto-update-checker] No "plugin" array found in ${configPath}`);
|
|
@@ -8368,6 +8367,10 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
|
|
|
8368
8367
|
return false;
|
|
8369
8368
|
}
|
|
8370
8369
|
}
|
|
8370
|
+
function revertPinnedVersion(configPath, failedVersion, originalEntry) {
|
|
8371
|
+
const failedEntry = `${PACKAGE_NAME3}@${failedVersion}`;
|
|
8372
|
+
return replacePluginEntry(configPath, failedEntry, originalEntry);
|
|
8373
|
+
}
|
|
8371
8374
|
var init_pinned_version_updater = __esm(() => {
|
|
8372
8375
|
init_logger();
|
|
8373
8376
|
init_constants3();
|
|
@@ -8642,23 +8645,23 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
|
|
|
8642
8645
|
return;
|
|
8643
8646
|
}
|
|
8644
8647
|
if (pluginInfo.isPinned) {
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
log("[auto-update-checker] Failed to update pinned version in config");
|
|
8649
|
-
return;
|
|
8650
|
-
}
|
|
8651
|
-
log(`[auto-update-checker] Config updated: ${pluginInfo.entry} \u2192 ${PACKAGE_NAME3}@${latestVersion}`);
|
|
8648
|
+
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
8649
|
+
log(`[auto-update-checker] User-pinned version detected (${pluginInfo.entry}), skipping auto-update. Notification only.`);
|
|
8650
|
+
return;
|
|
8652
8651
|
}
|
|
8653
8652
|
invalidatePackage(PACKAGE_NAME3);
|
|
8654
8653
|
const installSuccess = await runBunInstallSafe();
|
|
8655
8654
|
if (installSuccess) {
|
|
8656
8655
|
await showAutoUpdatedToast(ctx, currentVersion, latestVersion);
|
|
8657
8656
|
log(`[auto-update-checker] Update installed: ${currentVersion} \u2192 ${latestVersion}`);
|
|
8658
|
-
|
|
8659
|
-
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
8660
|
-
log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)");
|
|
8657
|
+
return;
|
|
8661
8658
|
}
|
|
8659
|
+
if (pluginInfo.isPinned) {
|
|
8660
|
+
revertPinnedVersion(pluginInfo.configPath, latestVersion, pluginInfo.entry);
|
|
8661
|
+
log("[auto-update-checker] Config reverted due to install failure");
|
|
8662
|
+
}
|
|
8663
|
+
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
8664
|
+
log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)");
|
|
8662
8665
|
}
|
|
8663
8666
|
var init_background_update_check = __esm(() => {
|
|
8664
8667
|
init_config_manager();
|
|
@@ -8867,7 +8870,7 @@ var {
|
|
|
8867
8870
|
// package.json
|
|
8868
8871
|
var package_default = {
|
|
8869
8872
|
name: "oh-my-opencode",
|
|
8870
|
-
version: "3.5.
|
|
8873
|
+
version: "3.5.2",
|
|
8871
8874
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
8872
8875
|
main: "dist/index.js",
|
|
8873
8876
|
types: "dist/index.d.ts",
|
|
@@ -8941,13 +8944,13 @@ var package_default = {
|
|
|
8941
8944
|
typescript: "^5.7.3"
|
|
8942
8945
|
},
|
|
8943
8946
|
optionalDependencies: {
|
|
8944
|
-
"oh-my-opencode-darwin-arm64": "3.5.
|
|
8945
|
-
"oh-my-opencode-darwin-x64": "3.5.
|
|
8946
|
-
"oh-my-opencode-linux-arm64": "3.5.
|
|
8947
|
-
"oh-my-opencode-linux-arm64-musl": "3.5.
|
|
8948
|
-
"oh-my-opencode-linux-x64": "3.5.
|
|
8949
|
-
"oh-my-opencode-linux-x64-musl": "3.5.
|
|
8950
|
-
"oh-my-opencode-windows-x64": "3.5.
|
|
8947
|
+
"oh-my-opencode-darwin-arm64": "3.5.2",
|
|
8948
|
+
"oh-my-opencode-darwin-x64": "3.5.2",
|
|
8949
|
+
"oh-my-opencode-linux-arm64": "3.5.2",
|
|
8950
|
+
"oh-my-opencode-linux-arm64-musl": "3.5.2",
|
|
8951
|
+
"oh-my-opencode-linux-x64": "3.5.2",
|
|
8952
|
+
"oh-my-opencode-linux-x64-musl": "3.5.2",
|
|
8953
|
+
"oh-my-opencode-windows-x64": "3.5.2"
|
|
8951
8954
|
},
|
|
8952
8955
|
trustedDependencies: [
|
|
8953
8956
|
"@ast-grep/cli",
|
|
@@ -22716,7 +22719,8 @@ var CategoryConfigSchema = exports_external.object({
|
|
|
22716
22719
|
textVerbosity: exports_external.enum(["low", "medium", "high"]).optional(),
|
|
22717
22720
|
tools: exports_external.record(exports_external.string(), exports_external.boolean()).optional(),
|
|
22718
22721
|
prompt_append: exports_external.string().optional(),
|
|
22719
|
-
is_unstable_agent: exports_external.boolean().optional()
|
|
22722
|
+
is_unstable_agent: exports_external.boolean().optional(),
|
|
22723
|
+
disable: exports_external.boolean().optional()
|
|
22720
22724
|
});
|
|
22721
22725
|
var BuiltinCategoryNameSchema = exports_external.enum([
|
|
22722
22726
|
"visual-engineering",
|
|
@@ -27,6 +27,7 @@ export declare const CategoryConfigSchema: z.ZodObject<{
|
|
|
27
27
|
tools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
28
28
|
prompt_append: z.ZodOptional<z.ZodString>;
|
|
29
29
|
is_unstable_agent: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
disable: z.ZodOptional<z.ZodBoolean>;
|
|
30
31
|
}, z.core.$strip>;
|
|
31
32
|
export declare const BuiltinCategoryNameSchema: z.ZodEnum<{
|
|
32
33
|
"visual-engineering": "visual-engineering";
|
|
@@ -66,6 +67,7 @@ export declare const CategoriesConfigSchema: z.ZodRecord<z.ZodString, z.ZodObjec
|
|
|
66
67
|
tools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
67
68
|
prompt_append: z.ZodOptional<z.ZodString>;
|
|
68
69
|
is_unstable_agent: z.ZodOptional<z.ZodBoolean>;
|
|
70
|
+
disable: z.ZodOptional<z.ZodBoolean>;
|
|
69
71
|
}, z.core.$strip>>;
|
|
70
72
|
export type CategoryConfig = z.infer<typeof CategoryConfigSchema>;
|
|
71
73
|
export type CategoriesConfig = z.infer<typeof CategoriesConfigSchema>;
|
|
@@ -1158,6 +1158,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
|
|
|
1158
1158
|
tools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
1159
1159
|
prompt_append: z.ZodOptional<z.ZodString>;
|
|
1160
1160
|
is_unstable_agent: z.ZodOptional<z.ZodBoolean>;
|
|
1161
|
+
disable: z.ZodOptional<z.ZodBoolean>;
|
|
1161
1162
|
}, z.core.$strip>>>;
|
|
1162
1163
|
claude_code: z.ZodOptional<z.ZodObject<{
|
|
1163
1164
|
mcp: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -3,6 +3,6 @@ export { getLocalDevVersion } from "./checker/local-dev-version";
|
|
|
3
3
|
export { findPluginEntry } from "./checker/plugin-entry";
|
|
4
4
|
export type { PluginEntryInfo } from "./checker/plugin-entry";
|
|
5
5
|
export { getCachedVersion } from "./checker/cached-version";
|
|
6
|
-
export { updatePinnedVersion } from "./checker/pinned-version-updater";
|
|
6
|
+
export { updatePinnedVersion, revertPinnedVersion } from "./checker/pinned-version-updater";
|
|
7
7
|
export { getLatestVersion } from "./checker/latest-version";
|
|
8
8
|
export { checkForUpdate } from "./checker/check-for-update";
|
package/dist/index.js
CHANGED
|
@@ -12252,7 +12252,14 @@ function readBoulderState(directory) {
|
|
|
12252
12252
|
}
|
|
12253
12253
|
try {
|
|
12254
12254
|
const content = readFileSync(filePath, "utf-8");
|
|
12255
|
-
|
|
12255
|
+
const parsed = JSON.parse(content);
|
|
12256
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12257
|
+
return null;
|
|
12258
|
+
}
|
|
12259
|
+
if (!Array.isArray(parsed.session_ids)) {
|
|
12260
|
+
parsed.session_ids = [];
|
|
12261
|
+
}
|
|
12262
|
+
return parsed;
|
|
12256
12263
|
} catch {
|
|
12257
12264
|
return null;
|
|
12258
12265
|
}
|
|
@@ -12274,7 +12281,10 @@ function appendSessionId(directory, sessionId) {
|
|
|
12274
12281
|
const state = readBoulderState(directory);
|
|
12275
12282
|
if (!state)
|
|
12276
12283
|
return null;
|
|
12277
|
-
if (!state.session_ids
|
|
12284
|
+
if (!state.session_ids?.includes(sessionId)) {
|
|
12285
|
+
if (!Array.isArray(state.session_ids)) {
|
|
12286
|
+
state.session_ids = [];
|
|
12287
|
+
}
|
|
12278
12288
|
state.session_ids.push(sessionId);
|
|
12279
12289
|
if (writeBoulderState(directory, state)) {
|
|
12280
12290
|
return state;
|
|
@@ -26785,7 +26795,7 @@ function createCommentCheckerHooks(config2) {
|
|
|
26785
26795
|
"tool.execute.after": async (input, output) => {
|
|
26786
26796
|
debugLog3("tool.execute.after:", { tool: input.tool, callID: input.callID });
|
|
26787
26797
|
const toolLower = input.tool.toLowerCase();
|
|
26788
|
-
const outputLower = output.output.toLowerCase();
|
|
26798
|
+
const outputLower = (output.output ?? "").toLowerCase();
|
|
26789
26799
|
const isToolFailure = outputLower.includes("error:") || outputLower.includes("failed to") || outputLower.includes("could not") || outputLower.startsWith("error");
|
|
26790
26800
|
if (isToolFailure) {
|
|
26791
26801
|
debugLog3("skipping due to tool failure in output");
|
|
@@ -36389,10 +36399,9 @@ function getCachedVersion() {
|
|
|
36389
36399
|
// src/hooks/auto-update-checker/checker/pinned-version-updater.ts
|
|
36390
36400
|
init_logger();
|
|
36391
36401
|
import * as fs12 from "fs";
|
|
36392
|
-
function
|
|
36402
|
+
function replacePluginEntry(configPath, oldEntry, newEntry) {
|
|
36393
36403
|
try {
|
|
36394
36404
|
const content = fs12.readFileSync(configPath, "utf-8");
|
|
36395
|
-
const newEntry = `${PACKAGE_NAME}@${newVersion}`;
|
|
36396
36405
|
const pluginMatch = content.match(/"plugin"\s*:\s*\[/);
|
|
36397
36406
|
if (!pluginMatch || pluginMatch.index === undefined) {
|
|
36398
36407
|
log(`[auto-update-checker] No "plugin" array found in ${configPath}`);
|
|
@@ -36431,6 +36440,10 @@ function updatePinnedVersion(configPath, oldEntry, newVersion) {
|
|
|
36431
36440
|
return false;
|
|
36432
36441
|
}
|
|
36433
36442
|
}
|
|
36443
|
+
function revertPinnedVersion(configPath, failedVersion, originalEntry) {
|
|
36444
|
+
const failedEntry = `${PACKAGE_NAME}@${failedVersion}`;
|
|
36445
|
+
return replacePluginEntry(configPath, failedEntry, originalEntry);
|
|
36446
|
+
}
|
|
36434
36447
|
// src/hooks/auto-update-checker/checker/latest-version.ts
|
|
36435
36448
|
async function getLatestVersion(channel = "latest") {
|
|
36436
36449
|
const controller = new AbortController;
|
|
@@ -36673,23 +36686,23 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
|
|
|
36673
36686
|
return;
|
|
36674
36687
|
}
|
|
36675
36688
|
if (pluginInfo.isPinned) {
|
|
36676
|
-
|
|
36677
|
-
|
|
36678
|
-
|
|
36679
|
-
log("[auto-update-checker] Failed to update pinned version in config");
|
|
36680
|
-
return;
|
|
36681
|
-
}
|
|
36682
|
-
log(`[auto-update-checker] Config updated: ${pluginInfo.entry} \u2192 ${PACKAGE_NAME}@${latestVersion}`);
|
|
36689
|
+
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
36690
|
+
log(`[auto-update-checker] User-pinned version detected (${pluginInfo.entry}), skipping auto-update. Notification only.`);
|
|
36691
|
+
return;
|
|
36683
36692
|
}
|
|
36684
36693
|
invalidatePackage(PACKAGE_NAME);
|
|
36685
36694
|
const installSuccess = await runBunInstallSafe();
|
|
36686
36695
|
if (installSuccess) {
|
|
36687
36696
|
await showAutoUpdatedToast(ctx, currentVersion, latestVersion);
|
|
36688
36697
|
log(`[auto-update-checker] Update installed: ${currentVersion} \u2192 ${latestVersion}`);
|
|
36689
|
-
|
|
36690
|
-
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
36691
|
-
log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)");
|
|
36698
|
+
return;
|
|
36692
36699
|
}
|
|
36700
|
+
if (pluginInfo.isPinned) {
|
|
36701
|
+
revertPinnedVersion(pluginInfo.configPath, latestVersion, pluginInfo.entry);
|
|
36702
|
+
log("[auto-update-checker] Config reverted due to install failure");
|
|
36703
|
+
}
|
|
36704
|
+
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage);
|
|
36705
|
+
log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)");
|
|
36693
36706
|
}
|
|
36694
36707
|
|
|
36695
36708
|
// src/hooks/auto-update-checker/hook/config-errors-toast.ts
|
|
@@ -42832,7 +42845,7 @@ function createEditErrorRecoveryHook(_ctx) {
|
|
|
42832
42845
|
"tool.execute.after": async (input, output) => {
|
|
42833
42846
|
if (input.tool.toLowerCase() !== "edit")
|
|
42834
42847
|
return;
|
|
42835
|
-
const outputLower = output.output.toLowerCase();
|
|
42848
|
+
const outputLower = (output.output ?? "").toLowerCase();
|
|
42836
42849
|
const hasEditError = EDIT_ERROR_PATTERNS.some((pattern) => outputLower.includes(pattern.toLowerCase()));
|
|
42837
42850
|
if (hasEditError) {
|
|
42838
42851
|
output.output += `
|
|
@@ -42965,7 +42978,7 @@ function getAgentFromSession(sessionID, directory) {
|
|
|
42965
42978
|
if (memoryAgent)
|
|
42966
42979
|
return memoryAgent;
|
|
42967
42980
|
const boulderState = readBoulderState(directory);
|
|
42968
|
-
if (boulderState?.session_ids
|
|
42981
|
+
if (boulderState?.session_ids?.includes(sessionID) && boulderState.agent) {
|
|
42969
42982
|
return boulderState.agent;
|
|
42970
42983
|
}
|
|
42971
42984
|
return getAgentFromMessageFiles(sessionID);
|
|
@@ -43120,15 +43133,16 @@ function createTaskResumeInfoHook() {
|
|
|
43120
43133
|
const toolExecuteAfter = async (input, output) => {
|
|
43121
43134
|
if (!TARGET_TOOLS2.includes(input.tool))
|
|
43122
43135
|
return;
|
|
43123
|
-
|
|
43136
|
+
const outputText = output.output ?? "";
|
|
43137
|
+
if (outputText.startsWith("Error:") || outputText.startsWith("Failed"))
|
|
43124
43138
|
return;
|
|
43125
|
-
if (
|
|
43139
|
+
if (outputText.includes(`
|
|
43126
43140
|
to continue:`))
|
|
43127
43141
|
return;
|
|
43128
|
-
const sessionId = extractSessionId(
|
|
43142
|
+
const sessionId = extractSessionId(outputText);
|
|
43129
43143
|
if (!sessionId)
|
|
43130
43144
|
return;
|
|
43131
|
-
output.output =
|
|
43145
|
+
output.output = outputText.trimEnd() + `
|
|
43132
43146
|
|
|
43133
43147
|
to continue: task(session_id="${sessionId}", prompt="...")`;
|
|
43134
43148
|
};
|
|
@@ -43629,7 +43643,7 @@ function createAtlasEventHandler(input) {
|
|
|
43629
43643
|
return;
|
|
43630
43644
|
log(`[${HOOK_NAME7}] session.idle`, { sessionID });
|
|
43631
43645
|
const boulderState = readBoulderState(ctx.directory);
|
|
43632
|
-
const isBoulderSession = boulderState?.session_ids
|
|
43646
|
+
const isBoulderSession = boulderState?.session_ids?.includes(sessionID) ?? false;
|
|
43633
43647
|
const isBackgroundTaskSession = subagentSessions.has(sessionID);
|
|
43634
43648
|
if (!isBackgroundTaskSession && !isBoulderSession) {
|
|
43635
43649
|
log(`[${HOOK_NAME7}] Skipped: not boulder or background task session`, { sessionID });
|
|
@@ -43798,7 +43812,23 @@ function buildOrchestratorReminder(planName, progress, sessionId) {
|
|
|
43798
43812
|
|
|
43799
43813
|
${buildVerificationReminder(sessionId)}
|
|
43800
43814
|
|
|
43801
|
-
**STEP 5:
|
|
43815
|
+
**STEP 5: READ SUBAGENT NOTEPAD (LEARNINGS, ISSUES, PROBLEMS)**
|
|
43816
|
+
|
|
43817
|
+
The subagent was instructed to record findings in notepad files. Read them NOW:
|
|
43818
|
+
\`\`\`
|
|
43819
|
+
Glob(".sisyphus/notepads/${planName}/*.md")
|
|
43820
|
+
\`\`\`
|
|
43821
|
+
Then \`Read\` each file found \u2014 especially:
|
|
43822
|
+
- **learnings.md**: Patterns, conventions, successful approaches discovered
|
|
43823
|
+
- **issues.md**: Problems, blockers, gotchas encountered during work
|
|
43824
|
+
- **problems.md**: Unresolved issues, technical debt flagged
|
|
43825
|
+
|
|
43826
|
+
**USE this information to:**
|
|
43827
|
+
- Inform your next delegation (avoid known pitfalls)
|
|
43828
|
+
- Adjust your plan if blockers were discovered
|
|
43829
|
+
- Propagate learnings to subsequent subagents
|
|
43830
|
+
|
|
43831
|
+
**STEP 6: CHECK BOULDER STATE DIRECTLY (EVERY TIME \u2014 NO EXCEPTIONS)**
|
|
43802
43832
|
|
|
43803
43833
|
Do NOT rely on cached progress. Read the plan file NOW:
|
|
43804
43834
|
\`\`\`
|
|
@@ -43807,7 +43837,7 @@ Read(".sisyphus/plans/${planName}.md")
|
|
|
43807
43837
|
Count exactly: how many \`- [ ]\` remain? How many \`- [x]\` completed?
|
|
43808
43838
|
This is YOUR ground truth. Use it to decide what comes next.
|
|
43809
43839
|
|
|
43810
|
-
**STEP
|
|
43840
|
+
**STEP 7: MARK COMPLETION IN PLAN FILE (IMMEDIATELY)**
|
|
43811
43841
|
|
|
43812
43842
|
RIGHT NOW - Do not delay. Verification passed \u2192 Mark IMMEDIATELY.
|
|
43813
43843
|
|
|
@@ -43817,12 +43847,12 @@ Update the plan file \`.sisyphus/plans/${planName}.md\`:
|
|
|
43817
43847
|
|
|
43818
43848
|
**DO THIS BEFORE ANYTHING ELSE. Unmarked = Untracked = Lost progress.**
|
|
43819
43849
|
|
|
43820
|
-
**STEP
|
|
43850
|
+
**STEP 8: COMMIT ATOMIC UNIT**
|
|
43821
43851
|
|
|
43822
43852
|
- Stage ONLY the verified changes
|
|
43823
43853
|
- Commit with clear message describing what was done
|
|
43824
43854
|
|
|
43825
|
-
**STEP
|
|
43855
|
+
**STEP 9: PROCEED TO NEXT TASK**
|
|
43826
43856
|
|
|
43827
43857
|
- Read the plan file AGAIN to identify the next \`- [ ]\` task
|
|
43828
43858
|
- Start immediately - DO NOT STOP
|
|
@@ -43916,7 +43946,7 @@ function createToolExecuteAfterHandler2(input) {
|
|
|
43916
43946
|
const boulderState = readBoulderState(ctx.directory);
|
|
43917
43947
|
if (boulderState) {
|
|
43918
43948
|
const progress = getPlanProgress(boulderState.active_plan);
|
|
43919
|
-
if (toolInput.sessionID && !boulderState.session_ids
|
|
43949
|
+
if (toolInput.sessionID && !boulderState.session_ids?.includes(toolInput.sessionID)) {
|
|
43920
43950
|
appendSessionId(ctx.directory, toolInput.sessionID);
|
|
43921
43951
|
log(`[${HOOK_NAME7}] Appended session to boulder`, {
|
|
43922
43952
|
sessionID: toolInput.sessionID,
|
|
@@ -49526,10 +49556,7 @@ async function createOrGetSession(args, toolContext, ctx) {
|
|
|
49526
49556
|
const createResult = await ctx.client.session.create({
|
|
49527
49557
|
body: {
|
|
49528
49558
|
parentID: toolContext.sessionID,
|
|
49529
|
-
title: `${args.description} (@${args.subagent_type} subagent)
|
|
49530
|
-
permission: [
|
|
49531
|
-
{ permission: "question", action: "deny", pattern: "*" }
|
|
49532
|
-
]
|
|
49559
|
+
title: `${args.description} (@${args.subagent_type} subagent)`
|
|
49533
49560
|
},
|
|
49534
49561
|
query: {
|
|
49535
49562
|
directory: parentDirectory
|
|
@@ -49552,6 +49579,7 @@ Original error: ${createResult.error}`);
|
|
|
49552
49579
|
}
|
|
49553
49580
|
const sessionID = createResult.data.id;
|
|
49554
49581
|
log(`[call_omo_agent] Created session: ${sessionID}`);
|
|
49582
|
+
subagentSessions.add(sessionID);
|
|
49555
49583
|
return { sessionID, isNew: true };
|
|
49556
49584
|
}
|
|
49557
49585
|
}
|
|
@@ -50027,6 +50055,15 @@ Original error: ${createResult.error}`;
|
|
|
50027
50055
|
}
|
|
50028
50056
|
// src/tools/delegate-task/tools.ts
|
|
50029
50057
|
init_constants();
|
|
50058
|
+
|
|
50059
|
+
// src/shared/merge-categories.ts
|
|
50060
|
+
init_constants();
|
|
50061
|
+
function mergeCategories(userCategories) {
|
|
50062
|
+
const merged = userCategories ? { ...DEFAULT_CATEGORIES, ...userCategories } : { ...DEFAULT_CATEGORIES };
|
|
50063
|
+
return Object.fromEntries(Object.entries(merged).filter(([, config3]) => !config3.disable));
|
|
50064
|
+
}
|
|
50065
|
+
|
|
50066
|
+
// src/tools/delegate-task/tools.ts
|
|
50030
50067
|
init_logger();
|
|
50031
50068
|
|
|
50032
50069
|
// src/tools/delegate-task/prompt-builder.ts
|
|
@@ -50848,10 +50885,7 @@ async function createSyncSession(client2, input) {
|
|
|
50848
50885
|
const createResult = await client2.session.create({
|
|
50849
50886
|
body: {
|
|
50850
50887
|
parentID: input.parentSessionID,
|
|
50851
|
-
title: `${input.description} (@${input.agentToUse} subagent)
|
|
50852
|
-
permission: [
|
|
50853
|
-
{ permission: "question", action: "deny", pattern: "*" }
|
|
50854
|
-
]
|
|
50888
|
+
title: `${input.description} (@${input.agentToUse} subagent)`
|
|
50855
50889
|
},
|
|
50856
50890
|
query: {
|
|
50857
50891
|
directory: parentDirectory
|
|
@@ -51035,9 +51069,6 @@ session_id: ${sessionID}
|
|
|
51035
51069
|
}
|
|
51036
51070
|
}
|
|
51037
51071
|
}
|
|
51038
|
-
// src/tools/delegate-task/category-resolver.ts
|
|
51039
|
-
init_constants();
|
|
51040
|
-
|
|
51041
51072
|
// src/tools/delegate-task/sisyphus-junior-agent.ts
|
|
51042
51073
|
var SISYPHUS_JUNIOR_AGENT2 = "sisyphus-junior";
|
|
51043
51074
|
|
|
@@ -51049,6 +51080,9 @@ function resolveCategoryConfig(categoryName, options) {
|
|
|
51049
51080
|
const defaultConfig = DEFAULT_CATEGORIES[categoryName];
|
|
51050
51081
|
const userConfig = userCategories?.[categoryName];
|
|
51051
51082
|
const hasExplicitUserConfig = userConfig !== undefined;
|
|
51083
|
+
if (userConfig?.disable) {
|
|
51084
|
+
return null;
|
|
51085
|
+
}
|
|
51052
51086
|
const categoryReq = CATEGORY_MODEL_REQUIREMENTS[categoryName];
|
|
51053
51087
|
if (categoryReq?.requiresModel && availableModels && !hasExplicitUserConfig) {
|
|
51054
51088
|
if (!isModelAvailable(categoryReq.requiresModel, availableModels)) {
|
|
@@ -51198,7 +51232,8 @@ async function resolveCategoryExecution(args, executorCtx, inheritedModel, syste
|
|
|
51198
51232
|
const { client: client2, userCategories, sisyphusJuniorModel } = executorCtx;
|
|
51199
51233
|
const availableModels = await getAvailableModelsForDelegateTask(client2);
|
|
51200
51234
|
const categoryName = args.category;
|
|
51201
|
-
const
|
|
51235
|
+
const enabledCategories = mergeCategories(userCategories);
|
|
51236
|
+
const categoryExists = enabledCategories[categoryName] !== undefined;
|
|
51202
51237
|
const resolved = resolveCategoryConfig(categoryName, {
|
|
51203
51238
|
userCategories,
|
|
51204
51239
|
inheritedModel,
|
|
@@ -51207,7 +51242,7 @@ async function resolveCategoryExecution(args, executorCtx, inheritedModel, syste
|
|
|
51207
51242
|
});
|
|
51208
51243
|
if (!resolved) {
|
|
51209
51244
|
const requirement2 = CATEGORY_MODEL_REQUIREMENTS[categoryName];
|
|
51210
|
-
const allCategoryNames = Object.keys(
|
|
51245
|
+
const allCategoryNames = Object.keys(enabledCategories).join(", ");
|
|
51211
51246
|
if (categoryExists && requirement2?.requiresModel) {
|
|
51212
51247
|
return {
|
|
51213
51248
|
agentToUse: "",
|
|
@@ -51282,7 +51317,7 @@ Available categories: ${allCategoryNames}`
|
|
|
51282
51317
|
}
|
|
51283
51318
|
const categoryPromptAppend = resolved.promptAppend || undefined;
|
|
51284
51319
|
if (!categoryModel && !actualModel) {
|
|
51285
|
-
const categoryNames = Object.keys(
|
|
51320
|
+
const categoryNames = Object.keys(enabledCategories);
|
|
51286
51321
|
return {
|
|
51287
51322
|
agentToUse: "",
|
|
51288
51323
|
categoryModel: undefined,
|
|
@@ -51392,7 +51427,7 @@ Create the work plan directly - that's your job as the planning agent.`
|
|
|
51392
51427
|
// src/tools/delegate-task/tools.ts
|
|
51393
51428
|
function createDelegateTask(options) {
|
|
51394
51429
|
const { userCategories } = options;
|
|
51395
|
-
const allCategories =
|
|
51430
|
+
const allCategories = mergeCategories(userCategories);
|
|
51396
51431
|
const categoryNames = Object.keys(allCategories);
|
|
51397
51432
|
const categoryExamples = categoryNames.map((k) => `'${k}'`).join(", ");
|
|
51398
51433
|
const availableCategories = options.availableCategories ?? Object.entries(allCategories).map(([name, categoryConfig]) => {
|
|
@@ -52764,14 +52799,10 @@ class BackgroundManager {
|
|
|
52764
52799
|
});
|
|
52765
52800
|
const parentDirectory = parentSession?.data?.directory ?? this.directory;
|
|
52766
52801
|
log(`[background-agent] Parent dir: ${parentSession?.data?.directory}, using: ${parentDirectory}`);
|
|
52767
|
-
const inheritedPermission = parentSession?.data?.permission;
|
|
52768
|
-
const permissionRules = Array.isArray(inheritedPermission) ? inheritedPermission.filter((r) => r?.permission !== "question") : [];
|
|
52769
|
-
permissionRules.push({ permission: "question", action: "deny", pattern: "*" });
|
|
52770
52802
|
const createResult = await this.client.session.create({
|
|
52771
52803
|
body: {
|
|
52772
52804
|
parentID: input.parentSessionID,
|
|
52773
|
-
title: `${input.description} (@${input.agent} subagent)
|
|
52774
|
-
permission: permissionRules
|
|
52805
|
+
title: `${input.description} (@${input.agent} subagent)`
|
|
52775
52806
|
},
|
|
52776
52807
|
query: {
|
|
52777
52808
|
directory: parentDirectory
|
|
@@ -62230,7 +62261,7 @@ ${rows.join(`
|
|
|
62230
62261
|
`)}`;
|
|
62231
62262
|
}
|
|
62232
62263
|
function buildCategorySection(userCategories) {
|
|
62233
|
-
const allCategories =
|
|
62264
|
+
const allCategories = mergeCategories(userCategories);
|
|
62234
62265
|
const categoryRows = Object.entries(allCategories).map(([name, config3]) => {
|
|
62235
62266
|
const temp = config3.temperature ?? 0.5;
|
|
62236
62267
|
return `| \`${name}\` | ${temp} | ${getCategoryDescription(name, userCategories)} |`;
|
|
@@ -62306,7 +62337,7 @@ task(category="[category]", load_skills=["skill-1", "skill-2"], run_in_backgroun
|
|
|
62306
62337
|
- Missing a relevant skill = suboptimal output quality`;
|
|
62307
62338
|
}
|
|
62308
62339
|
function buildDecisionMatrix(agents, userCategories) {
|
|
62309
|
-
const allCategories =
|
|
62340
|
+
const allCategories = mergeCategories(userCategories);
|
|
62310
62341
|
const categoryRows = Object.entries(allCategories).map(([name]) => `| ${getCategoryDescription(name, userCategories)} | \`category="${name}", load_skills=[...]\` |`);
|
|
62311
62342
|
const agentRows = agents.map((a) => {
|
|
62312
62343
|
const shortDesc = truncateDescription(a.description);
|
|
@@ -62324,7 +62355,6 @@ ${agentRows.join(`
|
|
|
62324
62355
|
**NEVER provide both category AND agent - they are mutually exclusive.**`;
|
|
62325
62356
|
}
|
|
62326
62357
|
// src/agents/atlas/agent.ts
|
|
62327
|
-
init_constants();
|
|
62328
62358
|
var MODE7 = "primary";
|
|
62329
62359
|
function getAtlasPromptSource(model) {
|
|
62330
62360
|
if (model && isGptModel2(model)) {
|
|
@@ -62347,7 +62377,7 @@ function buildDynamicOrchestratorPrompt(ctx) {
|
|
|
62347
62377
|
const skills = ctx?.availableSkills ?? [];
|
|
62348
62378
|
const userCategories = ctx?.userCategories;
|
|
62349
62379
|
const model = ctx?.model;
|
|
62350
|
-
const allCategories =
|
|
62380
|
+
const allCategories = mergeCategories(userCategories);
|
|
62351
62381
|
const availableCategories = Object.entries(allCategories).map(([name]) => ({
|
|
62352
62382
|
name,
|
|
62353
62383
|
description: getCategoryDescription(name, userCategories)
|
|
@@ -63223,13 +63253,12 @@ function buildAvailableSkills(discoveredSkills, browserProvider, disabledSkills)
|
|
|
63223
63253
|
}
|
|
63224
63254
|
|
|
63225
63255
|
// src/agents/agent-builder.ts
|
|
63226
|
-
init_constants();
|
|
63227
63256
|
function isFactory(source) {
|
|
63228
63257
|
return typeof source === "function";
|
|
63229
63258
|
}
|
|
63230
63259
|
function buildAgent(source, model, categories, gitMasterConfig, browserProvider, disabledSkills) {
|
|
63231
63260
|
const base = isFactory(source) ? source(model) : { ...source };
|
|
63232
|
-
const categoryConfigs = categories
|
|
63261
|
+
const categoryConfigs = mergeCategories(categories);
|
|
63233
63262
|
const agentWithCategory = base;
|
|
63234
63263
|
if (agentWithCategory.category) {
|
|
63235
63264
|
const categoryConfig = categoryConfigs[agentWithCategory.category];
|
|
@@ -63639,7 +63668,7 @@ async function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, dir
|
|
|
63639
63668
|
});
|
|
63640
63669
|
const isFirstRunNoCache = availableModels.size === 0 && (!connectedProviders || connectedProviders.length === 0);
|
|
63641
63670
|
const result = {};
|
|
63642
|
-
const mergedCategories = categories
|
|
63671
|
+
const mergedCategories = mergeCategories(categories);
|
|
63643
63672
|
const availableCategories = Object.entries(mergedCategories).map(([name]) => ({
|
|
63644
63673
|
name,
|
|
63645
63674
|
description: categories?.[name]?.description ?? CATEGORY_DESCRIPTIONS[name] ?? "General tasks"
|
|
@@ -66682,8 +66711,8 @@ function createManagers(args) {
|
|
|
66682
66711
|
// src/plugin/available-categories.ts
|
|
66683
66712
|
init_constants();
|
|
66684
66713
|
function createAvailableCategories(pluginConfig) {
|
|
66685
|
-
const
|
|
66686
|
-
return Object.entries(
|
|
66714
|
+
const categories = mergeCategories(pluginConfig.categories);
|
|
66715
|
+
return Object.entries(categories).map(([name, categoryConfig]) => {
|
|
66687
66716
|
const model = typeof categoryConfig.model === "string" ? categoryConfig.model : undefined;
|
|
66688
66717
|
return {
|
|
66689
66718
|
name,
|
|
@@ -67431,7 +67460,8 @@ var CategoryConfigSchema = exports_external.object({
|
|
|
67431
67460
|
textVerbosity: exports_external.enum(["low", "medium", "high"]).optional(),
|
|
67432
67461
|
tools: exports_external.record(exports_external.string(), exports_external.boolean()).optional(),
|
|
67433
67462
|
prompt_append: exports_external.string().optional(),
|
|
67434
|
-
is_unstable_agent: exports_external.boolean().optional()
|
|
67463
|
+
is_unstable_agent: exports_external.boolean().optional(),
|
|
67464
|
+
disable: exports_external.boolean().optional()
|
|
67435
67465
|
});
|
|
67436
67466
|
var BuiltinCategoryNameSchema = exports_external.enum([
|
|
67437
67467
|
"visual-engineering",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CategoriesConfig, CategoryConfig } from "../config/schema";
|
|
2
|
+
/**
|
|
3
|
+
* Merge default and user categories, filtering out disabled ones.
|
|
4
|
+
* Single source of truth for category merging across the codebase.
|
|
5
|
+
*/
|
|
6
|
+
export declare function mergeCategories(userCategories?: CategoriesConfig): Record<string, CategoryConfig>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.2",
|
|
4
4
|
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -74,13 +74,13 @@
|
|
|
74
74
|
"typescript": "^5.7.3"
|
|
75
75
|
},
|
|
76
76
|
"optionalDependencies": {
|
|
77
|
-
"oh-my-opencode-darwin-arm64": "3.5.
|
|
78
|
-
"oh-my-opencode-darwin-x64": "3.5.
|
|
79
|
-
"oh-my-opencode-linux-arm64": "3.5.
|
|
80
|
-
"oh-my-opencode-linux-arm64-musl": "3.5.
|
|
81
|
-
"oh-my-opencode-linux-x64": "3.5.
|
|
82
|
-
"oh-my-opencode-linux-x64-musl": "3.5.
|
|
83
|
-
"oh-my-opencode-windows-x64": "3.5.
|
|
77
|
+
"oh-my-opencode-darwin-arm64": "3.5.2",
|
|
78
|
+
"oh-my-opencode-darwin-x64": "3.5.2",
|
|
79
|
+
"oh-my-opencode-linux-arm64": "3.5.2",
|
|
80
|
+
"oh-my-opencode-linux-arm64-musl": "3.5.2",
|
|
81
|
+
"oh-my-opencode-linux-x64": "3.5.2",
|
|
82
|
+
"oh-my-opencode-linux-x64-musl": "3.5.2",
|
|
83
|
+
"oh-my-opencode-windows-x64": "3.5.2"
|
|
84
84
|
},
|
|
85
85
|
"trustedDependencies": [
|
|
86
86
|
"@ast-grep/cli",
|