oh-my-opencode 1.1.6 → 1.1.8
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.ko.md +2 -0
- package/README.md +1 -1
- package/dist/config/schema.d.ts +4 -2
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/keyword-detector/constants.d.ts +6 -0
- package/dist/hooks/keyword-detector/detector.d.ts +6 -0
- package/dist/hooks/{ultrawork-mode → keyword-detector}/index.d.ts +1 -14
- package/dist/hooks/keyword-detector/types.d.ts +4 -0
- package/dist/hooks/tool-output-truncator.d.ts +12 -0
- package/dist/index.js +373 -241
- package/dist/shared/dynamic-truncator.d.ts +27 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/model-sanitizer.d.ts +3 -11
- package/dist/tools/grep/constants.d.ts +1 -0
- package/dist/tools/grep/downloader.d.ts +2 -0
- package/package.json +3 -2
- package/dist/hooks/ultrawork-mode/constants.d.ts +0 -15
- package/dist/hooks/ultrawork-mode/detector.d.ts +0 -16
- package/dist/hooks/ultrawork-mode/types.d.ts +0 -20
package/README.ko.md
CHANGED
|
@@ -602,3 +602,5 @@ OpenCode 를 사용하여 이 프로젝트의 99% 를 작성했습니다. 기능
|
|
|
602
602
|
- [1.0.132](https://github.com/sst/opencode/releases/tag/v1.0.132) 혹은 이것보다 낮은 버전을 사용중이라면, OpenCode 의 버그로 인해 제대로 구성이 되지 않을 수 있습니다.
|
|
603
603
|
- [이를 고치는 PR 이 1.0.132 배포 이후에 병합되었으므로](https://github.com/sst/opencode/pull/5040) 이 변경사항이 포함된 최신 버전을 사용해주세요.
|
|
604
604
|
- TMI: PR 도 OhMyOpenCode 의 셋업의 Librarian, Explore, Oracle 을 활용하여 우연히 발견하고 해결되었습니다.
|
|
605
|
+
|
|
606
|
+
*멋진 히어로 이미지를 만들어주신 히어로 [@junhoyeo](https://github.com/junhoyeo) 께 감사드립니다*
|
package/README.md
CHANGED
|
@@ -604,4 +604,4 @@ I have no affiliation with any project or model mentioned here. This is purely p
|
|
|
604
604
|
- [The fix](https://github.com/sst/opencode/pull/5040) was merged after 1.0.132—use a newer version.
|
|
605
605
|
- Fun fact: That PR was discovered and fixed thanks to OhMyOpenCode's Librarian, Explore, and Oracle setup.
|
|
606
606
|
|
|
607
|
-
*Special thanks to @junhoyeo for this amazing hero image.*
|
|
607
|
+
*Special thanks to [@junhoyeo](https://github.com/junhoyeo) for this amazing hero image.*
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare const HookNameSchema: z.ZodEnum<{
|
|
|
33
33
|
"session-recovery": "session-recovery";
|
|
34
34
|
"session-notification": "session-notification";
|
|
35
35
|
"grep-output-truncator": "grep-output-truncator";
|
|
36
|
+
"tool-output-truncator": "tool-output-truncator";
|
|
36
37
|
"directory-agents-injector": "directory-agents-injector";
|
|
37
38
|
"directory-readme-injector": "directory-readme-injector";
|
|
38
39
|
"empty-task-response-detector": "empty-task-response-detector";
|
|
@@ -40,7 +41,7 @@ export declare const HookNameSchema: z.ZodEnum<{
|
|
|
40
41
|
"anthropic-auto-compact": "anthropic-auto-compact";
|
|
41
42
|
"background-notification": "background-notification";
|
|
42
43
|
"auto-update-checker": "auto-update-checker";
|
|
43
|
-
"
|
|
44
|
+
"keyword-detector": "keyword-detector";
|
|
44
45
|
}>;
|
|
45
46
|
export declare const AgentOverrideConfigSchema: z.ZodObject<{
|
|
46
47
|
model: z.ZodOptional<z.ZodString>;
|
|
@@ -443,6 +444,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
|
|
|
443
444
|
"session-recovery": "session-recovery";
|
|
444
445
|
"session-notification": "session-notification";
|
|
445
446
|
"grep-output-truncator": "grep-output-truncator";
|
|
447
|
+
"tool-output-truncator": "tool-output-truncator";
|
|
446
448
|
"directory-agents-injector": "directory-agents-injector";
|
|
447
449
|
"directory-readme-injector": "directory-readme-injector";
|
|
448
450
|
"empty-task-response-detector": "empty-task-response-detector";
|
|
@@ -450,7 +452,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
|
|
|
450
452
|
"anthropic-auto-compact": "anthropic-auto-compact";
|
|
451
453
|
"background-notification": "background-notification";
|
|
452
454
|
"auto-update-checker": "auto-update-checker";
|
|
453
|
-
"
|
|
455
|
+
"keyword-detector": "keyword-detector";
|
|
454
456
|
}>>>;
|
|
455
457
|
agents: z.ZodOptional<z.ZodObject<{
|
|
456
458
|
build: z.ZodOptional<z.ZodOptional<z.ZodObject<{
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { createSessionNotification } from "./session-notification";
|
|
|
4
4
|
export { createSessionRecoveryHook, type SessionRecoveryHook } from "./session-recovery";
|
|
5
5
|
export { createCommentCheckerHooks } from "./comment-checker";
|
|
6
6
|
export { createGrepOutputTruncatorHook } from "./grep-output-truncator";
|
|
7
|
+
export { createToolOutputTruncatorHook } from "./tool-output-truncator";
|
|
7
8
|
export { createDirectoryAgentsInjectorHook } from "./directory-agents-injector";
|
|
8
9
|
export { createDirectoryReadmeInjectorHook } from "./directory-readme-injector";
|
|
9
10
|
export { createEmptyTaskResponseDetectorHook } from "./empty-task-response-detector";
|
|
@@ -13,5 +14,5 @@ export { createClaudeCodeHooksHook } from "./claude-code-hooks";
|
|
|
13
14
|
export { createRulesInjectorHook } from "./rules-injector";
|
|
14
15
|
export { createBackgroundNotificationHook } from "./background-notification";
|
|
15
16
|
export { createAutoUpdateCheckerHook } from "./auto-update-checker";
|
|
16
|
-
export { createUltraworkModeHook } from "./ultrawork-mode";
|
|
17
17
|
export { createAgentUsageReminderHook } from "./agent-usage-reminder";
|
|
18
|
+
export { createKeywordDetectorHook } from "./keyword-detector";
|
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
export * from "./detector";
|
|
2
2
|
export * from "./constants";
|
|
3
3
|
export * from "./types";
|
|
4
|
-
export declare function
|
|
5
|
-
export declare function createUltraworkModeHook(): {
|
|
6
|
-
/**
|
|
7
|
-
* chat.message hook - detect ultrawork/ulw keywords, inject context via history
|
|
8
|
-
*
|
|
9
|
-
* Execution timing: AFTER claudeCodeHooks["chat.message"]
|
|
10
|
-
* Behavior:
|
|
11
|
-
* 1. Extract text from user prompt
|
|
12
|
-
* 2. Detect ultrawork/ulw keywords (excluding code blocks)
|
|
13
|
-
* 3. If detected, inject ULTRAWORK_CONTEXT via injectHookMessage (history injection)
|
|
14
|
-
*/
|
|
4
|
+
export declare function createKeywordDetectorHook(): {
|
|
15
5
|
"chat.message": (input: {
|
|
16
6
|
sessionID: string;
|
|
17
7
|
agent?: string;
|
|
@@ -28,9 +18,6 @@ export declare function createUltraworkModeHook(): {
|
|
|
28
18
|
[key: string]: unknown;
|
|
29
19
|
}>;
|
|
30
20
|
}) => Promise<void>;
|
|
31
|
-
/**
|
|
32
|
-
* event hook - cleanup session state on deletion
|
|
33
|
-
*/
|
|
34
21
|
event: ({ event, }: {
|
|
35
22
|
event: {
|
|
36
23
|
type: string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
export declare function createToolOutputTruncatorHook(ctx: PluginInput): {
|
|
3
|
+
"tool.execute.after": (input: {
|
|
4
|
+
tool: string;
|
|
5
|
+
sessionID: string;
|
|
6
|
+
callID: string;
|
|
7
|
+
}, output: {
|
|
8
|
+
title: string;
|
|
9
|
+
output: string;
|
|
10
|
+
metadata: unknown;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -2657,7 +2657,13 @@ async function resolveFileReferencesInText(text, cwd = process.cwd(), depth = 0,
|
|
|
2657
2657
|
return resolved;
|
|
2658
2658
|
}
|
|
2659
2659
|
// src/shared/model-sanitizer.ts
|
|
2660
|
-
function sanitizeModelField(
|
|
2660
|
+
function sanitizeModelField(model, source = "claude-code") {
|
|
2661
|
+
if (source === "claude-code") {
|
|
2662
|
+
return;
|
|
2663
|
+
}
|
|
2664
|
+
if (typeof model === "string" && model.trim().length > 0) {
|
|
2665
|
+
return model.trim();
|
|
2666
|
+
}
|
|
2661
2667
|
return;
|
|
2662
2668
|
}
|
|
2663
2669
|
// src/shared/logger.ts
|
|
@@ -2798,6 +2804,111 @@ function resolveSymlink(filePath) {
|
|
|
2798
2804
|
return filePath;
|
|
2799
2805
|
}
|
|
2800
2806
|
}
|
|
2807
|
+
// src/shared/dynamic-truncator.ts
|
|
2808
|
+
var ANTHROPIC_ACTUAL_LIMIT = 200000;
|
|
2809
|
+
var CHARS_PER_TOKEN_ESTIMATE = 4;
|
|
2810
|
+
var DEFAULT_TARGET_MAX_TOKENS = 50000;
|
|
2811
|
+
function estimateTokens(text) {
|
|
2812
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
|
|
2813
|
+
}
|
|
2814
|
+
function truncateToTokenLimit(output, maxTokens, preserveHeaderLines = 3) {
|
|
2815
|
+
const currentTokens = estimateTokens(output);
|
|
2816
|
+
if (currentTokens <= maxTokens) {
|
|
2817
|
+
return { result: output, truncated: false };
|
|
2818
|
+
}
|
|
2819
|
+
const lines = output.split(`
|
|
2820
|
+
`);
|
|
2821
|
+
if (lines.length <= preserveHeaderLines) {
|
|
2822
|
+
const maxChars = maxTokens * CHARS_PER_TOKEN_ESTIMATE;
|
|
2823
|
+
return {
|
|
2824
|
+
result: output.slice(0, maxChars) + `
|
|
2825
|
+
|
|
2826
|
+
[Output truncated due to context window limit]`,
|
|
2827
|
+
truncated: true
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2830
|
+
const headerLines = lines.slice(0, preserveHeaderLines);
|
|
2831
|
+
const contentLines = lines.slice(preserveHeaderLines);
|
|
2832
|
+
const headerText = headerLines.join(`
|
|
2833
|
+
`);
|
|
2834
|
+
const headerTokens = estimateTokens(headerText);
|
|
2835
|
+
const truncationMessageTokens = 50;
|
|
2836
|
+
const availableTokens = maxTokens - headerTokens - truncationMessageTokens;
|
|
2837
|
+
if (availableTokens <= 0) {
|
|
2838
|
+
return {
|
|
2839
|
+
result: headerText + `
|
|
2840
|
+
|
|
2841
|
+
[Content truncated due to context window limit]`,
|
|
2842
|
+
truncated: true,
|
|
2843
|
+
removedCount: contentLines.length
|
|
2844
|
+
};
|
|
2845
|
+
}
|
|
2846
|
+
const resultLines = [];
|
|
2847
|
+
let currentTokenCount = 0;
|
|
2848
|
+
for (const line of contentLines) {
|
|
2849
|
+
const lineTokens = estimateTokens(line + `
|
|
2850
|
+
`);
|
|
2851
|
+
if (currentTokenCount + lineTokens > availableTokens) {
|
|
2852
|
+
break;
|
|
2853
|
+
}
|
|
2854
|
+
resultLines.push(line);
|
|
2855
|
+
currentTokenCount += lineTokens;
|
|
2856
|
+
}
|
|
2857
|
+
const truncatedContent = [...headerLines, ...resultLines].join(`
|
|
2858
|
+
`);
|
|
2859
|
+
const removedCount = contentLines.length - resultLines.length;
|
|
2860
|
+
return {
|
|
2861
|
+
result: truncatedContent + `
|
|
2862
|
+
|
|
2863
|
+
[${removedCount} more lines truncated due to context window limit]`,
|
|
2864
|
+
truncated: true,
|
|
2865
|
+
removedCount
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
async function getContextWindowUsage(ctx, sessionID) {
|
|
2869
|
+
try {
|
|
2870
|
+
const response = await ctx.client.session.messages({
|
|
2871
|
+
path: { id: sessionID }
|
|
2872
|
+
});
|
|
2873
|
+
const messages = response.data ?? response;
|
|
2874
|
+
const assistantMessages = messages.filter((m) => m.info.role === "assistant").map((m) => m.info);
|
|
2875
|
+
if (assistantMessages.length === 0)
|
|
2876
|
+
return null;
|
|
2877
|
+
const lastAssistant = assistantMessages[assistantMessages.length - 1];
|
|
2878
|
+
const lastTokens = lastAssistant.tokens;
|
|
2879
|
+
const usedTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
|
|
2880
|
+
const remainingTokens = ANTHROPIC_ACTUAL_LIMIT - usedTokens;
|
|
2881
|
+
return {
|
|
2882
|
+
usedTokens,
|
|
2883
|
+
remainingTokens,
|
|
2884
|
+
usagePercentage: usedTokens / ANTHROPIC_ACTUAL_LIMIT
|
|
2885
|
+
};
|
|
2886
|
+
} catch {
|
|
2887
|
+
return null;
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
async function dynamicTruncate(ctx, sessionID, output, options = {}) {
|
|
2891
|
+
const { targetMaxTokens = DEFAULT_TARGET_MAX_TOKENS, preserveHeaderLines = 3 } = options;
|
|
2892
|
+
const usage = await getContextWindowUsage(ctx, sessionID);
|
|
2893
|
+
if (!usage) {
|
|
2894
|
+
return { result: output, truncated: false };
|
|
2895
|
+
}
|
|
2896
|
+
const maxOutputTokens = Math.min(usage.remainingTokens * 0.5, targetMaxTokens);
|
|
2897
|
+
if (maxOutputTokens <= 0) {
|
|
2898
|
+
return {
|
|
2899
|
+
result: "[Output suppressed - context window exhausted]",
|
|
2900
|
+
truncated: true
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
return truncateToTokenLimit(output, maxOutputTokens, preserveHeaderLines);
|
|
2904
|
+
}
|
|
2905
|
+
function createDynamicTruncator(ctx) {
|
|
2906
|
+
return {
|
|
2907
|
+
truncate: (sessionID, output, options) => dynamicTruncate(ctx, sessionID, output, options),
|
|
2908
|
+
getUsage: (sessionID) => getContextWindowUsage(ctx, sessionID),
|
|
2909
|
+
truncateSync: (output, maxTokens, preserveHeaderLines) => truncateToTokenLimit(output, maxTokens, preserveHeaderLines)
|
|
2910
|
+
};
|
|
2911
|
+
}
|
|
2801
2912
|
// src/agents/utils.ts
|
|
2802
2913
|
var allBuiltinAgents = {
|
|
2803
2914
|
oracle: oracleAgent,
|
|
@@ -3116,7 +3227,7 @@ function createTodoContinuationEnforcer(ctx) {
|
|
|
3116
3227
|
}
|
|
3117
3228
|
// src/hooks/context-window-monitor.ts
|
|
3118
3229
|
var ANTHROPIC_DISPLAY_LIMIT = 1e6;
|
|
3119
|
-
var
|
|
3230
|
+
var ANTHROPIC_ACTUAL_LIMIT2 = 200000;
|
|
3120
3231
|
var CONTEXT_WARNING_THRESHOLD = 0.7;
|
|
3121
3232
|
var CONTEXT_REMINDER = `[SYSTEM REMINDER - 1M Context Window]
|
|
3122
3233
|
|
|
@@ -3142,7 +3253,7 @@ function createContextWindowMonitorHook(ctx) {
|
|
|
3142
3253
|
return;
|
|
3143
3254
|
const lastTokens = lastAssistant.tokens;
|
|
3144
3255
|
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
|
|
3145
|
-
const actualUsagePercentage = totalInputTokens /
|
|
3256
|
+
const actualUsagePercentage = totalInputTokens / ANTHROPIC_ACTUAL_LIMIT2;
|
|
3146
3257
|
if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD)
|
|
3147
3258
|
return;
|
|
3148
3259
|
remindedSessions.add(sessionID);
|
|
@@ -4186,88 +4297,25 @@ ${result.message}`;
|
|
|
4186
4297
|
debugLog3("CLI: no comments detected");
|
|
4187
4298
|
}
|
|
4188
4299
|
}
|
|
4189
|
-
// src/hooks/
|
|
4190
|
-
var
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
if (lines.length <= 3) {
|
|
4204
|
-
const maxChars = maxTokens * CHARS_PER_TOKEN_ESTIMATE;
|
|
4205
|
-
return {
|
|
4206
|
-
result: output.slice(0, maxChars) + `
|
|
4207
|
-
|
|
4208
|
-
[Output truncated due to context window limit]`,
|
|
4209
|
-
truncated: true
|
|
4210
|
-
};
|
|
4211
|
-
}
|
|
4212
|
-
const headerLines = lines.slice(0, 3);
|
|
4213
|
-
const contentLines = lines.slice(3);
|
|
4214
|
-
const headerText = headerLines.join(`
|
|
4215
|
-
`);
|
|
4216
|
-
const headerTokens = estimateTokens(headerText);
|
|
4217
|
-
const availableTokens = maxTokens - headerTokens - 50;
|
|
4218
|
-
if (availableTokens <= 0) {
|
|
4219
|
-
return {
|
|
4220
|
-
result: headerText + `
|
|
4221
|
-
|
|
4222
|
-
[Content truncated due to context window limit]`,
|
|
4223
|
-
truncated: true
|
|
4224
|
-
};
|
|
4225
|
-
}
|
|
4226
|
-
let resultLines = [];
|
|
4227
|
-
let currentTokenCount = 0;
|
|
4228
|
-
for (const line of contentLines) {
|
|
4229
|
-
const lineTokens = estimateTokens(line + `
|
|
4230
|
-
`);
|
|
4231
|
-
if (currentTokenCount + lineTokens > availableTokens) {
|
|
4232
|
-
break;
|
|
4233
|
-
}
|
|
4234
|
-
resultLines.push(line);
|
|
4235
|
-
currentTokenCount += lineTokens;
|
|
4236
|
-
}
|
|
4237
|
-
const truncatedContent = [...headerLines, ...resultLines].join(`
|
|
4238
|
-
`);
|
|
4239
|
-
const removedCount = contentLines.length - resultLines.length;
|
|
4240
|
-
return {
|
|
4241
|
-
result: truncatedContent + `
|
|
4242
|
-
|
|
4243
|
-
[${removedCount} more lines truncated due to context window limit]`,
|
|
4244
|
-
truncated: true
|
|
4245
|
-
};
|
|
4246
|
-
}
|
|
4247
|
-
function createGrepOutputTruncatorHook(ctx) {
|
|
4248
|
-
const GREP_TOOLS = ["safe_grep", "Grep"];
|
|
4300
|
+
// src/hooks/tool-output-truncator.ts
|
|
4301
|
+
var TRUNCATABLE_TOOLS = [
|
|
4302
|
+
"Grep",
|
|
4303
|
+
"safe_grep",
|
|
4304
|
+
"Glob",
|
|
4305
|
+
"safe_glob",
|
|
4306
|
+
"lsp_find_references",
|
|
4307
|
+
"lsp_document_symbols",
|
|
4308
|
+
"lsp_workspace_symbols",
|
|
4309
|
+
"lsp_diagnostics",
|
|
4310
|
+
"ast_grep_search"
|
|
4311
|
+
];
|
|
4312
|
+
function createToolOutputTruncatorHook(ctx) {
|
|
4313
|
+
const truncator = createDynamicTruncator(ctx);
|
|
4249
4314
|
const toolExecuteAfter = async (input, output) => {
|
|
4250
|
-
if (!
|
|
4315
|
+
if (!TRUNCATABLE_TOOLS.includes(input.tool))
|
|
4251
4316
|
return;
|
|
4252
|
-
const { sessionID } = input;
|
|
4253
4317
|
try {
|
|
4254
|
-
const
|
|
4255
|
-
path: { id: sessionID }
|
|
4256
|
-
});
|
|
4257
|
-
const messages = response.data ?? response;
|
|
4258
|
-
const assistantMessages = messages.filter((m) => m.info.role === "assistant").map((m) => m.info);
|
|
4259
|
-
if (assistantMessages.length === 0)
|
|
4260
|
-
return;
|
|
4261
|
-
const lastAssistant = assistantMessages[assistantMessages.length - 1];
|
|
4262
|
-
const lastTokens = lastAssistant.tokens;
|
|
4263
|
-
const totalInputTokens = (lastTokens?.input ?? 0) + (lastTokens?.cache?.read ?? 0);
|
|
4264
|
-
const remainingTokens = ANTHROPIC_ACTUAL_LIMIT2 - totalInputTokens;
|
|
4265
|
-
const maxOutputTokens = Math.min(remainingTokens * 0.5, TARGET_MAX_TOKENS);
|
|
4266
|
-
if (maxOutputTokens <= 0) {
|
|
4267
|
-
output.output = "[Output suppressed - context window exhausted]";
|
|
4268
|
-
return;
|
|
4269
|
-
}
|
|
4270
|
-
const { result, truncated } = truncateToTokenLimit(output.output, maxOutputTokens);
|
|
4318
|
+
const { result, truncated } = await truncator.truncate(input.sessionID, output.output);
|
|
4271
4319
|
if (truncated) {
|
|
4272
4320
|
output.output = result;
|
|
4273
4321
|
}
|
|
@@ -6826,97 +6874,6 @@ function createAutoUpdateCheckerHook(ctx) {
|
|
|
6826
6874
|
}
|
|
6827
6875
|
};
|
|
6828
6876
|
}
|
|
6829
|
-
// src/hooks/ultrawork-mode/constants.ts
|
|
6830
|
-
var ULTRAWORK_PATTERNS = [/\bultrawork\b/i, /\bulw\b/i];
|
|
6831
|
-
var CODE_BLOCK_PATTERN2 = /```[\s\S]*?```/g;
|
|
6832
|
-
var INLINE_CODE_PATTERN2 = /`[^`]+`/g;
|
|
6833
|
-
var ULTRAWORK_CONTEXT = `<ultrawork-mode>
|
|
6834
|
-
[CODE RED] Maximum precision required. Ultrathink before acting.
|
|
6835
|
-
|
|
6836
|
-
YOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.
|
|
6837
|
-
TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
|
|
6838
|
-
|
|
6839
|
-
## AGENT UTILIZATION PRINCIPLES (by capability, not by name)
|
|
6840
|
-
- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS for file patterns, internal implementations, project structure
|
|
6841
|
-
- **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS for API references, examples, external library docs
|
|
6842
|
-
- **Planning & Strategy**: NEVER plan yourself - ALWAYS spawn a dedicated planning agent for work breakdown
|
|
6843
|
-
- **High-IQ Reasoning**: Leverage specialized agents for architecture decisions, code review, strategic planning
|
|
6844
|
-
- **Frontend/UI Tasks**: Delegate to UI-specialized agents for design and implementation
|
|
6845
|
-
|
|
6846
|
-
## EXECUTION RULES
|
|
6847
|
-
- **TODO**: Track EVERY step. Mark complete IMMEDIATELY after each.
|
|
6848
|
-
- **PARALLEL**: Fire independent agent calls simultaneously via background_task - NEVER wait sequentially.
|
|
6849
|
-
- **BACKGROUND FIRST**: Use background_task for exploration/research agents (10+ concurrent if needed).
|
|
6850
|
-
- **VERIFY**: Re-read request after completion. Check ALL requirements met before reporting done.
|
|
6851
|
-
- **DELEGATE**: Don't do everything yourself - orchestrate specialized agents for their strengths.
|
|
6852
|
-
|
|
6853
|
-
## WORKFLOW
|
|
6854
|
-
1. Analyze the request and identify required capabilities
|
|
6855
|
-
2. Spawn exploration/librarian agents via background_task in PARALLEL (10+ if needed)
|
|
6856
|
-
3. Use planning agents to create detailed work breakdown
|
|
6857
|
-
4. Execute with continuous verification against original requirements
|
|
6858
|
-
|
|
6859
|
-
</ultrawork-mode>
|
|
6860
|
-
|
|
6861
|
-
---
|
|
6862
|
-
|
|
6863
|
-
`;
|
|
6864
|
-
|
|
6865
|
-
// src/hooks/ultrawork-mode/detector.ts
|
|
6866
|
-
function removeCodeBlocks2(text) {
|
|
6867
|
-
return text.replace(CODE_BLOCK_PATTERN2, "").replace(INLINE_CODE_PATTERN2, "");
|
|
6868
|
-
}
|
|
6869
|
-
function detectUltraworkKeyword(text) {
|
|
6870
|
-
const textWithoutCode = removeCodeBlocks2(text);
|
|
6871
|
-
return ULTRAWORK_PATTERNS.some((pattern) => pattern.test(textWithoutCode));
|
|
6872
|
-
}
|
|
6873
|
-
function extractPromptText2(parts) {
|
|
6874
|
-
return parts.filter((p) => p.type === "text").map((p) => p.text || "").join("");
|
|
6875
|
-
}
|
|
6876
|
-
|
|
6877
|
-
// src/hooks/ultrawork-mode/index.ts
|
|
6878
|
-
var ultraworkModeState = new Map;
|
|
6879
|
-
function createUltraworkModeHook() {
|
|
6880
|
-
return {
|
|
6881
|
-
"chat.message": async (input, output) => {
|
|
6882
|
-
const state = {
|
|
6883
|
-
detected: false,
|
|
6884
|
-
injected: false
|
|
6885
|
-
};
|
|
6886
|
-
const promptText = extractPromptText2(output.parts);
|
|
6887
|
-
if (!detectUltraworkKeyword(promptText)) {
|
|
6888
|
-
ultraworkModeState.set(input.sessionID, state);
|
|
6889
|
-
return;
|
|
6890
|
-
}
|
|
6891
|
-
state.detected = true;
|
|
6892
|
-
log("Ultrawork keyword detected", { sessionID: input.sessionID });
|
|
6893
|
-
const message = output.message;
|
|
6894
|
-
const success = injectHookMessage(input.sessionID, ULTRAWORK_CONTEXT, {
|
|
6895
|
-
agent: message.agent,
|
|
6896
|
-
model: message.model,
|
|
6897
|
-
path: message.path,
|
|
6898
|
-
tools: message.tools
|
|
6899
|
-
});
|
|
6900
|
-
if (success) {
|
|
6901
|
-
state.injected = true;
|
|
6902
|
-
log("Ultrawork context injected via history", { sessionID: input.sessionID });
|
|
6903
|
-
} else {
|
|
6904
|
-
log("Ultrawork context injection failed", { sessionID: input.sessionID });
|
|
6905
|
-
}
|
|
6906
|
-
ultraworkModeState.set(input.sessionID, state);
|
|
6907
|
-
},
|
|
6908
|
-
event: async ({
|
|
6909
|
-
event
|
|
6910
|
-
}) => {
|
|
6911
|
-
if (event.type === "session.deleted") {
|
|
6912
|
-
const props = event.properties;
|
|
6913
|
-
if (props?.info?.id) {
|
|
6914
|
-
ultraworkModeState.delete(props.info.id);
|
|
6915
|
-
}
|
|
6916
|
-
}
|
|
6917
|
-
}
|
|
6918
|
-
};
|
|
6919
|
-
}
|
|
6920
6877
|
// src/hooks/agent-usage-reminder/storage.ts
|
|
6921
6878
|
import {
|
|
6922
6879
|
existsSync as existsSync19,
|
|
@@ -7067,6 +7024,123 @@ function createAgentUsageReminderHook(_ctx) {
|
|
|
7067
7024
|
event: eventHandler
|
|
7068
7025
|
};
|
|
7069
7026
|
}
|
|
7027
|
+
// src/hooks/keyword-detector/constants.ts
|
|
7028
|
+
var CODE_BLOCK_PATTERN2 = /```[\s\S]*?```/g;
|
|
7029
|
+
var INLINE_CODE_PATTERN2 = /`[^`]+`/g;
|
|
7030
|
+
var KEYWORD_DETECTORS = [
|
|
7031
|
+
{
|
|
7032
|
+
pattern: /\b(ultrawork|ulw)\b/i,
|
|
7033
|
+
message: `<ultrawork-mode>
|
|
7034
|
+
[CODE RED] Maximum precision required. Ultrathink before acting.
|
|
7035
|
+
|
|
7036
|
+
YOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.
|
|
7037
|
+
TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
|
|
7038
|
+
|
|
7039
|
+
## AGENT UTILIZATION PRINCIPLES (by capability, not by name)
|
|
7040
|
+
- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS for file patterns, internal implementations, project structure
|
|
7041
|
+
- **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS for API references, examples, external library docs
|
|
7042
|
+
- **Planning & Strategy**: NEVER plan yourself - ALWAYS spawn a dedicated planning agent for work breakdown
|
|
7043
|
+
- **High-IQ Reasoning**: Leverage specialized agents for architecture decisions, code review, strategic planning
|
|
7044
|
+
- **Frontend/UI Tasks**: Delegate to UI-specialized agents for design and implementation
|
|
7045
|
+
|
|
7046
|
+
## EXECUTION RULES
|
|
7047
|
+
- **TODO**: Track EVERY step. Mark complete IMMEDIATELY after each.
|
|
7048
|
+
- **PARALLEL**: Fire independent agent calls simultaneously via background_task - NEVER wait sequentially.
|
|
7049
|
+
- **BACKGROUND FIRST**: Use background_task for exploration/research agents (10+ concurrent if needed).
|
|
7050
|
+
- **VERIFY**: Re-read request after completion. Check ALL requirements met before reporting done.
|
|
7051
|
+
- **DELEGATE**: Don't do everything yourself - orchestrate specialized agents for their strengths.
|
|
7052
|
+
|
|
7053
|
+
## WORKFLOW
|
|
7054
|
+
1. Analyze the request and identify required capabilities
|
|
7055
|
+
2. Spawn exploration/librarian agents via background_task in PARALLEL (10+ if needed)
|
|
7056
|
+
3. Use planning agents to create detailed work breakdown
|
|
7057
|
+
4. Execute with continuous verification against original requirements
|
|
7058
|
+
|
|
7059
|
+
</ultrawork-mode>
|
|
7060
|
+
|
|
7061
|
+
---
|
|
7062
|
+
|
|
7063
|
+
`
|
|
7064
|
+
},
|
|
7065
|
+
{
|
|
7066
|
+
pattern: /\b(search|find|locate|lookup|look\s*up|explore|discover|scan|grep|query|browse|detect|trace|seek|track|pinpoint|hunt)\b|where\s+is|show\s+me|list\s+all|\uAC80\uC0C9|\uCC3E\uC544|\uD0D0\uC0C9|\uC870\uD68C|\uC2A4\uCE94|\uC11C\uCE58|\uB4A4\uC838|\uCC3E\uAE30|\uC5B4\uB514|\uCD94\uC801|\uD0D0\uC9C0|\uCC3E\uC544\uBD10|\uCC3E\uC544\uB0B4|\uBCF4\uC5EC\uC918|\uBAA9\uB85D|\u691C\u7D22|\u63A2\u3057\u3066|\u898B\u3064\u3051\u3066|\u30B5\u30FC\u30C1|\u63A2\u7D22|\u30B9\u30AD\u30E3\u30F3|\u3069\u3053|\u767A\u898B|\u635C\u7D22|\u898B\u3064\u3051\u51FA\u3059|\u4E00\u89A7|\u641C\u7D22|\u67E5\u627E|\u5BFB\u627E|\u67E5\u8BE2|\u68C0\u7D22|\u5B9A\u4F4D|\u626B\u63CF|\u53D1\u73B0|\u5728\u54EA\u91CC|\u627E\u51FA\u6765|\u5217\u51FA|t\u00ECm ki\u1EBFm|tra c\u1EE9u|\u0111\u1ECBnh v\u1ECB|qu\u00E9t|ph\u00E1t hi\u1EC7n|truy t\u00ECm|t\u00ECm ra|\u1EDF \u0111\u00E2u|li\u1EC7t k\u00EA/i,
|
|
7067
|
+
message: `[search-mode]
|
|
7068
|
+
MAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL:
|
|
7069
|
+
- explore agents (codebase patterns, file structures, ast-grep)
|
|
7070
|
+
- librarian agents (remote repos, official docs, GitHub examples)
|
|
7071
|
+
Plus direct tools: Grep, ripgrep (rg), ast-grep (sg)
|
|
7072
|
+
NEVER stop at first result - be exhaustive.`
|
|
7073
|
+
},
|
|
7074
|
+
{
|
|
7075
|
+
pattern: /\b(analyze|analyse|investigate|examine|research|study|deep[\s-]?dive|inspect|audit|evaluate|assess|review|diagnose|scrutinize|dissect|debug|comprehend|interpret|breakdown|understand)\b|why\s+is|how\s+does|how\s+to|\uBD84\uC11D|\uC870\uC0AC|\uD30C\uC545|\uC5F0\uAD6C|\uAC80\uD1A0|\uC9C4\uB2E8|\uC774\uD574|\uC124\uBA85|\uC6D0\uC778|\uC774\uC720|\uB72F\uC5B4\uBD10|\uB530\uC838\uBD10|\uD3C9\uAC00|\uD574\uC11D|\uB514\uBC84\uAE45|\uB514\uBC84\uADF8|\uC5B4\uB5BB\uAC8C|\uC65C|\uC0B4\uD3B4|\u5206\u6790|\u8ABF\u67FB|\u89E3\u6790|\u691C\u8A0E|\u7814\u7A76|\u8A3A\u65AD|\u7406\u89E3|\u8AAC\u660E|\u691C\u8A3C|\u7CBE\u67FB|\u7A76\u660E|\u30C7\u30D0\u30C3\u30B0|\u306A\u305C|\u3069\u3046|\u4ED5\u7D44\u307F|\u8C03\u67E5|\u68C0\u67E5|\u5256\u6790|\u6DF1\u5165|\u8BCA\u65AD|\u89E3\u91CA|\u8C03\u8BD5|\u4E3A\u4EC0\u4E48|\u539F\u7406|\u641E\u6E05\u695A|\u5F04\u660E\u767D|ph\u00E2n t\u00EDch|\u0111i\u1EC1u tra|nghi\u00EAn c\u1EE9u|ki\u1EC3m tra|xem x\u00E9t|ch\u1EA9n \u0111o\u00E1n|gi\u1EA3i th\u00EDch|t\u00ECm hi\u1EC3u|g\u1EE1 l\u1ED7i|t\u1EA1i sao/i,
|
|
7076
|
+
message: `[analyze-mode]
|
|
7077
|
+
DEEP ANALYSIS MODE. Execute in phases:
|
|
7078
|
+
|
|
7079
|
+
PHASE 1 - GATHER CONTEXT (10+ agents parallel):
|
|
7080
|
+
- 3+ explore agents (codebase structure, patterns, implementations)
|
|
7081
|
+
- 3+ librarian agents (official docs, best practices, examples)
|
|
7082
|
+
- 2+ general agents (different analytical perspectives)
|
|
7083
|
+
|
|
7084
|
+
PHASE 2 - EXPERT CONSULTATION (after Phase 1):
|
|
7085
|
+
- 3+ oracle agents in parallel with gathered context
|
|
7086
|
+
- Each oracle: different angle (architecture, performance, edge cases)
|
|
7087
|
+
|
|
7088
|
+
SYNTHESIZE: Cross-reference findings, identify consensus & contradictions.`
|
|
7089
|
+
}
|
|
7090
|
+
];
|
|
7091
|
+
|
|
7092
|
+
// src/hooks/keyword-detector/detector.ts
|
|
7093
|
+
function removeCodeBlocks2(text) {
|
|
7094
|
+
return text.replace(CODE_BLOCK_PATTERN2, "").replace(INLINE_CODE_PATTERN2, "");
|
|
7095
|
+
}
|
|
7096
|
+
function detectKeywords(text) {
|
|
7097
|
+
const textWithoutCode = removeCodeBlocks2(text);
|
|
7098
|
+
return KEYWORD_DETECTORS.filter(({ pattern }) => pattern.test(textWithoutCode)).map(({ message }) => message);
|
|
7099
|
+
}
|
|
7100
|
+
function extractPromptText2(parts) {
|
|
7101
|
+
return parts.filter((p) => p.type === "text").map((p) => p.text || "").join(" ");
|
|
7102
|
+
}
|
|
7103
|
+
|
|
7104
|
+
// src/hooks/keyword-detector/index.ts
|
|
7105
|
+
var injectedSessions = new Set;
|
|
7106
|
+
function createKeywordDetectorHook() {
|
|
7107
|
+
return {
|
|
7108
|
+
"chat.message": async (input, output) => {
|
|
7109
|
+
if (injectedSessions.has(input.sessionID)) {
|
|
7110
|
+
return;
|
|
7111
|
+
}
|
|
7112
|
+
const promptText = extractPromptText2(output.parts);
|
|
7113
|
+
const messages = detectKeywords(promptText);
|
|
7114
|
+
if (messages.length === 0) {
|
|
7115
|
+
return;
|
|
7116
|
+
}
|
|
7117
|
+
log(`Keywords detected: ${messages.length}`, { sessionID: input.sessionID });
|
|
7118
|
+
const message = output.message;
|
|
7119
|
+
const context = messages.join(`
|
|
7120
|
+
`);
|
|
7121
|
+
const success = injectHookMessage(input.sessionID, context, {
|
|
7122
|
+
agent: message.agent,
|
|
7123
|
+
model: message.model,
|
|
7124
|
+
path: message.path,
|
|
7125
|
+
tools: message.tools
|
|
7126
|
+
});
|
|
7127
|
+
if (success) {
|
|
7128
|
+
injectedSessions.add(input.sessionID);
|
|
7129
|
+
log("Keyword context injected", { sessionID: input.sessionID });
|
|
7130
|
+
}
|
|
7131
|
+
},
|
|
7132
|
+
event: async ({
|
|
7133
|
+
event
|
|
7134
|
+
}) => {
|
|
7135
|
+
if (event.type === "session.deleted") {
|
|
7136
|
+
const props = event.properties;
|
|
7137
|
+
if (props?.info?.id) {
|
|
7138
|
+
injectedSessions.delete(props.info.id);
|
|
7139
|
+
}
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
7142
|
+
};
|
|
7143
|
+
}
|
|
7070
7144
|
// src/auth/antigravity/constants.ts
|
|
7071
7145
|
var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
|
|
7072
7146
|
var ANTIGRAVITY_CLIENT_SECRET = "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";
|
|
@@ -8656,12 +8730,13 @@ ${body.trim()}
|
|
|
8656
8730
|
$ARGUMENTS
|
|
8657
8731
|
</user-request>`;
|
|
8658
8732
|
const formattedDescription = `(${scope}) ${data.description || ""}`;
|
|
8733
|
+
const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
|
|
8659
8734
|
const definition = {
|
|
8660
8735
|
name: commandName,
|
|
8661
8736
|
description: formattedDescription,
|
|
8662
8737
|
template: wrappedTemplate,
|
|
8663
8738
|
agent: data.agent,
|
|
8664
|
-
model: sanitizeModelField(data.model),
|
|
8739
|
+
model: sanitizeModelField(data.model, isOpencodeSource ? "opencode" : "claude-code"),
|
|
8665
8740
|
subtask: data.subtask,
|
|
8666
8741
|
argumentHint: data["argument-hint"]
|
|
8667
8742
|
};
|
|
@@ -23347,9 +23422,27 @@ var ast_grep_replace = tool({
|
|
|
23347
23422
|
var {spawn: spawn7 } = globalThis.Bun;
|
|
23348
23423
|
|
|
23349
23424
|
// src/tools/grep/constants.ts
|
|
23350
|
-
import { existsSync as
|
|
23351
|
-
import { join as
|
|
23425
|
+
import { existsSync as existsSync30 } from "fs";
|
|
23426
|
+
import { join as join34, dirname as dirname6 } from "path";
|
|
23352
23427
|
import { spawnSync } from "child_process";
|
|
23428
|
+
|
|
23429
|
+
// src/tools/grep/downloader.ts
|
|
23430
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync10, chmodSync as chmodSync3, unlinkSync as unlinkSync10 } from "fs";
|
|
23431
|
+
import { join as join33 } from "path";
|
|
23432
|
+
function getInstallDir() {
|
|
23433
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
23434
|
+
return join33(homeDir, ".cache", "oh-my-opencode", "bin");
|
|
23435
|
+
}
|
|
23436
|
+
function getRgPath() {
|
|
23437
|
+
const isWindows = process.platform === "win32";
|
|
23438
|
+
return join33(getInstallDir(), isWindows ? "rg.exe" : "rg");
|
|
23439
|
+
}
|
|
23440
|
+
function getInstalledRipgrepPath() {
|
|
23441
|
+
const rgPath = getRgPath();
|
|
23442
|
+
return existsSync29(rgPath) ? rgPath : null;
|
|
23443
|
+
}
|
|
23444
|
+
|
|
23445
|
+
// src/tools/grep/constants.ts
|
|
23353
23446
|
var cachedCli = null;
|
|
23354
23447
|
function findExecutable(name) {
|
|
23355
23448
|
const isWindows = process.platform === "win32";
|
|
@@ -23369,13 +23462,13 @@ function getOpenCodeBundledRg() {
|
|
|
23369
23462
|
const isWindows = process.platform === "win32";
|
|
23370
23463
|
const rgName = isWindows ? "rg.exe" : "rg";
|
|
23371
23464
|
const candidates = [
|
|
23372
|
-
|
|
23373
|
-
|
|
23374
|
-
|
|
23375
|
-
|
|
23465
|
+
join34(execDir, rgName),
|
|
23466
|
+
join34(execDir, "bin", rgName),
|
|
23467
|
+
join34(execDir, "..", "bin", rgName),
|
|
23468
|
+
join34(execDir, "..", "libexec", rgName)
|
|
23376
23469
|
];
|
|
23377
23470
|
for (const candidate of candidates) {
|
|
23378
|
-
if (
|
|
23471
|
+
if (existsSync30(candidate)) {
|
|
23379
23472
|
return candidate;
|
|
23380
23473
|
}
|
|
23381
23474
|
}
|
|
@@ -23394,6 +23487,11 @@ function resolveGrepCli() {
|
|
|
23394
23487
|
cachedCli = { path: systemRg, backend: "rg" };
|
|
23395
23488
|
return cachedCli;
|
|
23396
23489
|
}
|
|
23490
|
+
const installedRg = getInstalledRipgrepPath();
|
|
23491
|
+
if (installedRg) {
|
|
23492
|
+
cachedCli = { path: installedRg, backend: "rg" };
|
|
23493
|
+
return cachedCli;
|
|
23494
|
+
}
|
|
23397
23495
|
const grep = findExecutable("grep");
|
|
23398
23496
|
if (grep) {
|
|
23399
23497
|
cachedCli = { path: grep, backend: "grep" };
|
|
@@ -23773,11 +23871,11 @@ var glob = tool({
|
|
|
23773
23871
|
}
|
|
23774
23872
|
});
|
|
23775
23873
|
// src/tools/slashcommand/tools.ts
|
|
23776
|
-
import { existsSync as
|
|
23874
|
+
import { existsSync as existsSync31, readdirSync as readdirSync7, readFileSync as readFileSync18 } from "fs";
|
|
23777
23875
|
import { homedir as homedir15 } from "os";
|
|
23778
|
-
import { join as
|
|
23876
|
+
import { join as join35, basename as basename3, dirname as dirname7 } from "path";
|
|
23779
23877
|
function discoverCommandsFromDir(commandsDir, scope) {
|
|
23780
|
-
if (!
|
|
23878
|
+
if (!existsSync31(commandsDir)) {
|
|
23781
23879
|
return [];
|
|
23782
23880
|
}
|
|
23783
23881
|
const entries = readdirSync7(commandsDir, { withFileTypes: true });
|
|
@@ -23785,16 +23883,17 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
23785
23883
|
for (const entry of entries) {
|
|
23786
23884
|
if (!isMarkdownFile(entry))
|
|
23787
23885
|
continue;
|
|
23788
|
-
const commandPath =
|
|
23886
|
+
const commandPath = join35(commandsDir, entry.name);
|
|
23789
23887
|
const commandName = basename3(entry.name, ".md");
|
|
23790
23888
|
try {
|
|
23791
23889
|
const content = readFileSync18(commandPath, "utf-8");
|
|
23792
23890
|
const { data, body } = parseFrontmatter(content);
|
|
23891
|
+
const isOpencodeSource = scope === "opencode" || scope === "opencode-project";
|
|
23793
23892
|
const metadata = {
|
|
23794
23893
|
name: commandName,
|
|
23795
23894
|
description: data.description || "",
|
|
23796
23895
|
argumentHint: data["argument-hint"],
|
|
23797
|
-
model: sanitizeModelField(data.model),
|
|
23896
|
+
model: sanitizeModelField(data.model, isOpencodeSource ? "opencode" : "claude-code"),
|
|
23798
23897
|
agent: data.agent,
|
|
23799
23898
|
subtask: Boolean(data.subtask)
|
|
23800
23899
|
};
|
|
@@ -23812,10 +23911,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
23812
23911
|
return commands;
|
|
23813
23912
|
}
|
|
23814
23913
|
function discoverCommandsSync() {
|
|
23815
|
-
const userCommandsDir =
|
|
23816
|
-
const projectCommandsDir =
|
|
23817
|
-
const opencodeGlobalDir =
|
|
23818
|
-
const opencodeProjectDir =
|
|
23914
|
+
const userCommandsDir = join35(homedir15(), ".claude", "commands");
|
|
23915
|
+
const projectCommandsDir = join35(process.cwd(), ".claude", "commands");
|
|
23916
|
+
const opencodeGlobalDir = join35(homedir15(), ".config", "opencode", "command");
|
|
23917
|
+
const opencodeProjectDir = join35(process.cwd(), ".opencode", "command");
|
|
23819
23918
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
|
|
23820
23919
|
const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
|
|
23821
23920
|
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
|
|
@@ -23947,9 +24046,9 @@ var SkillFrontmatterSchema = exports_external.object({
|
|
|
23947
24046
|
metadata: exports_external.record(exports_external.string(), exports_external.string()).optional()
|
|
23948
24047
|
});
|
|
23949
24048
|
// src/tools/skill/tools.ts
|
|
23950
|
-
import { existsSync as
|
|
24049
|
+
import { existsSync as existsSync32, readdirSync as readdirSync8, readFileSync as readFileSync19 } from "fs";
|
|
23951
24050
|
import { homedir as homedir16 } from "os";
|
|
23952
|
-
import { join as
|
|
24051
|
+
import { join as join36, basename as basename4 } from "path";
|
|
23953
24052
|
function parseSkillFrontmatter(data) {
|
|
23954
24053
|
return {
|
|
23955
24054
|
name: typeof data.name === "string" ? data.name : "",
|
|
@@ -23960,7 +24059,7 @@ function parseSkillFrontmatter(data) {
|
|
|
23960
24059
|
};
|
|
23961
24060
|
}
|
|
23962
24061
|
function discoverSkillsFromDir(skillsDir, scope) {
|
|
23963
|
-
if (!
|
|
24062
|
+
if (!existsSync32(skillsDir)) {
|
|
23964
24063
|
return [];
|
|
23965
24064
|
}
|
|
23966
24065
|
const entries = readdirSync8(skillsDir, { withFileTypes: true });
|
|
@@ -23968,11 +24067,11 @@ function discoverSkillsFromDir(skillsDir, scope) {
|
|
|
23968
24067
|
for (const entry of entries) {
|
|
23969
24068
|
if (entry.name.startsWith("."))
|
|
23970
24069
|
continue;
|
|
23971
|
-
const skillPath =
|
|
24070
|
+
const skillPath = join36(skillsDir, entry.name);
|
|
23972
24071
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
23973
24072
|
const resolvedPath = resolveSymlink(skillPath);
|
|
23974
|
-
const skillMdPath =
|
|
23975
|
-
if (!
|
|
24073
|
+
const skillMdPath = join36(resolvedPath, "SKILL.md");
|
|
24074
|
+
if (!existsSync32(skillMdPath))
|
|
23976
24075
|
continue;
|
|
23977
24076
|
try {
|
|
23978
24077
|
const content = readFileSync19(skillMdPath, "utf-8");
|
|
@@ -23990,8 +24089,8 @@ function discoverSkillsFromDir(skillsDir, scope) {
|
|
|
23990
24089
|
return skills;
|
|
23991
24090
|
}
|
|
23992
24091
|
function discoverSkillsSync() {
|
|
23993
|
-
const userSkillsDir =
|
|
23994
|
-
const projectSkillsDir =
|
|
24092
|
+
const userSkillsDir = join36(homedir16(), ".claude", "skills");
|
|
24093
|
+
const projectSkillsDir = join36(process.cwd(), ".claude", "skills");
|
|
23995
24094
|
const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
|
|
23996
24095
|
const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
|
|
23997
24096
|
return [...projectSkills, ...userSkills];
|
|
@@ -24001,8 +24100,8 @@ var skillListForDescription = availableSkills.map((s) => `- ${s.name}: ${s.descr
|
|
|
24001
24100
|
`);
|
|
24002
24101
|
async function parseSkillMd(skillPath) {
|
|
24003
24102
|
const resolvedPath = resolveSymlink(skillPath);
|
|
24004
|
-
const skillMdPath =
|
|
24005
|
-
if (!
|
|
24103
|
+
const skillMdPath = join36(resolvedPath, "SKILL.md");
|
|
24104
|
+
if (!existsSync32(skillMdPath)) {
|
|
24006
24105
|
return null;
|
|
24007
24106
|
}
|
|
24008
24107
|
try {
|
|
@@ -24017,12 +24116,12 @@ async function parseSkillMd(skillPath) {
|
|
|
24017
24116
|
allowedTools: frontmatter2["allowed-tools"],
|
|
24018
24117
|
metadata: frontmatter2.metadata
|
|
24019
24118
|
};
|
|
24020
|
-
const referencesDir =
|
|
24021
|
-
const scriptsDir =
|
|
24022
|
-
const assetsDir =
|
|
24023
|
-
const references =
|
|
24024
|
-
const scripts =
|
|
24025
|
-
const assets =
|
|
24119
|
+
const referencesDir = join36(resolvedPath, "references");
|
|
24120
|
+
const scriptsDir = join36(resolvedPath, "scripts");
|
|
24121
|
+
const assetsDir = join36(resolvedPath, "assets");
|
|
24122
|
+
const references = existsSync32(referencesDir) ? readdirSync8(referencesDir).filter((f) => !f.startsWith(".")) : [];
|
|
24123
|
+
const scripts = existsSync32(scriptsDir) ? readdirSync8(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
|
|
24124
|
+
const assets = existsSync32(assetsDir) ? readdirSync8(assetsDir).filter((f) => !f.startsWith(".")) : [];
|
|
24026
24125
|
return {
|
|
24027
24126
|
name: metadata.name,
|
|
24028
24127
|
path: resolvedPath,
|
|
@@ -24038,7 +24137,7 @@ async function parseSkillMd(skillPath) {
|
|
|
24038
24137
|
}
|
|
24039
24138
|
}
|
|
24040
24139
|
async function discoverSkillsFromDirAsync(skillsDir) {
|
|
24041
|
-
if (!
|
|
24140
|
+
if (!existsSync32(skillsDir)) {
|
|
24042
24141
|
return [];
|
|
24043
24142
|
}
|
|
24044
24143
|
const entries = readdirSync8(skillsDir, { withFileTypes: true });
|
|
@@ -24046,7 +24145,7 @@ async function discoverSkillsFromDirAsync(skillsDir) {
|
|
|
24046
24145
|
for (const entry of entries) {
|
|
24047
24146
|
if (entry.name.startsWith("."))
|
|
24048
24147
|
continue;
|
|
24049
|
-
const skillPath =
|
|
24148
|
+
const skillPath = join36(skillsDir, entry.name);
|
|
24050
24149
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
24051
24150
|
const skillInfo = await parseSkillMd(skillPath);
|
|
24052
24151
|
if (skillInfo) {
|
|
@@ -24057,8 +24156,8 @@ async function discoverSkillsFromDirAsync(skillsDir) {
|
|
|
24057
24156
|
return skills;
|
|
24058
24157
|
}
|
|
24059
24158
|
async function discoverSkills() {
|
|
24060
|
-
const userSkillsDir =
|
|
24061
|
-
const projectSkillsDir =
|
|
24159
|
+
const userSkillsDir = join36(homedir16(), ".claude", "skills");
|
|
24160
|
+
const projectSkillsDir = join36(process.cwd(), ".claude", "skills");
|
|
24062
24161
|
const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
|
|
24063
24162
|
const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
|
|
24064
24163
|
return [...projectSkills, ...userSkills];
|
|
@@ -24087,7 +24186,7 @@ async function loadSkillWithReferences(skill, includeRefs) {
|
|
|
24087
24186
|
const referencesLoaded = [];
|
|
24088
24187
|
if (includeRefs && skill.references.length > 0) {
|
|
24089
24188
|
for (const ref of skill.references) {
|
|
24090
|
-
const refPath =
|
|
24189
|
+
const refPath = join36(skill.path, "references", ref);
|
|
24091
24190
|
try {
|
|
24092
24191
|
let content = readFileSync19(refPath, "utf-8");
|
|
24093
24192
|
content = await resolveCommandsInText(content);
|
|
@@ -24239,14 +24338,17 @@ function createBackgroundTask(manager) {
|
|
|
24239
24338
|
args: {
|
|
24240
24339
|
description: tool.schema.string().describe("Short task description (shown in status)"),
|
|
24241
24340
|
prompt: tool.schema.string().describe("Full detailed prompt for the agent"),
|
|
24242
|
-
agent: tool.schema.string().describe("Agent type to use (any agent
|
|
24341
|
+
agent: tool.schema.string().describe("Agent type to use (any registered agent)")
|
|
24243
24342
|
},
|
|
24244
24343
|
async execute(args, toolContext) {
|
|
24344
|
+
if (!args.agent || args.agent.trim() === "") {
|
|
24345
|
+
return `\u274C Agent parameter is required. Please specify which agent to use (e.g., "explore", "librarian", "build", etc.)`;
|
|
24346
|
+
}
|
|
24245
24347
|
try {
|
|
24246
24348
|
const task = await manager.launch({
|
|
24247
24349
|
description: args.description,
|
|
24248
24350
|
prompt: args.prompt,
|
|
24249
|
-
agent: args.agent,
|
|
24351
|
+
agent: args.agent.trim(),
|
|
24250
24352
|
parentSessionID: toolContext.sessionID,
|
|
24251
24353
|
parentMessageID: toolContext.messageID
|
|
24252
24354
|
});
|
|
@@ -24389,15 +24491,15 @@ function createBackgroundOutput(manager, client2) {
|
|
|
24389
24491
|
}
|
|
24390
24492
|
const shouldBlock = args.block === true;
|
|
24391
24493
|
const timeoutMs = Math.min(args.timeout ?? 60000, 600000);
|
|
24392
|
-
if (!shouldBlock) {
|
|
24393
|
-
return formatTaskStatus(task);
|
|
24394
|
-
}
|
|
24395
24494
|
if (task.status === "completed") {
|
|
24396
24495
|
return await formatTaskResult(task, client2);
|
|
24397
24496
|
}
|
|
24398
24497
|
if (task.status === "error" || task.status === "cancelled") {
|
|
24399
24498
|
return formatTaskStatus(task);
|
|
24400
24499
|
}
|
|
24500
|
+
if (!shouldBlock) {
|
|
24501
|
+
return formatTaskStatus(task);
|
|
24502
|
+
}
|
|
24401
24503
|
const startTime = Date.now();
|
|
24402
24504
|
while (Date.now() - startTime < timeoutMs) {
|
|
24403
24505
|
await delay(1000);
|
|
@@ -24528,9 +24630,10 @@ Description: ${task.description}
|
|
|
24528
24630
|
Agent: ${task.agent} (subagent)
|
|
24529
24631
|
Status: ${task.status}
|
|
24530
24632
|
|
|
24531
|
-
|
|
24532
|
-
|
|
24533
|
-
- block=
|
|
24633
|
+
The system will notify you when the task completes.
|
|
24634
|
+
Use \`background_output\` tool with task_id="${task.id}" to check progress:
|
|
24635
|
+
- block=false (default): Check status immediately - returns full status info
|
|
24636
|
+
- block=true: Wait for completion (rarely needed since system notifies)`;
|
|
24534
24637
|
} catch (error45) {
|
|
24535
24638
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
24536
24639
|
return `Failed to launch background agent task: ${message}`;
|
|
@@ -24565,17 +24668,37 @@ async function executeSync(args, toolContext, ctx) {
|
|
|
24565
24668
|
}
|
|
24566
24669
|
log(`[call_omo_agent] Sending prompt to session ${sessionID}`);
|
|
24567
24670
|
log(`[call_omo_agent] Prompt text:`, args.prompt.substring(0, 100));
|
|
24568
|
-
|
|
24569
|
-
|
|
24570
|
-
|
|
24571
|
-
|
|
24572
|
-
|
|
24573
|
-
|
|
24574
|
-
|
|
24575
|
-
|
|
24576
|
-
|
|
24671
|
+
try {
|
|
24672
|
+
await ctx.client.session.prompt({
|
|
24673
|
+
path: { id: sessionID },
|
|
24674
|
+
body: {
|
|
24675
|
+
agent: args.subagent_type,
|
|
24676
|
+
tools: {
|
|
24677
|
+
task: false,
|
|
24678
|
+
call_omo_agent: false,
|
|
24679
|
+
background_task: false,
|
|
24680
|
+
background_output: false,
|
|
24681
|
+
background_cancel: false
|
|
24682
|
+
},
|
|
24683
|
+
parts: [{ type: "text", text: args.prompt }]
|
|
24684
|
+
}
|
|
24685
|
+
});
|
|
24686
|
+
} catch (error45) {
|
|
24687
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
24688
|
+
log(`[call_omo_agent] Prompt error:`, errorMessage);
|
|
24689
|
+
if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
|
|
24690
|
+
return `Error: Agent "${args.subagent_type}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.
|
|
24691
|
+
|
|
24692
|
+
<task_metadata>
|
|
24693
|
+
session_id: ${sessionID}
|
|
24694
|
+
</task_metadata>`;
|
|
24577
24695
|
}
|
|
24578
|
-
|
|
24696
|
+
return `Error: Failed to send prompt: ${errorMessage}
|
|
24697
|
+
|
|
24698
|
+
<task_metadata>
|
|
24699
|
+
session_id: ${sessionID}
|
|
24700
|
+
</task_metadata>`;
|
|
24701
|
+
}
|
|
24579
24702
|
log(`[call_omo_agent] Prompt sent, fetching messages...`);
|
|
24580
24703
|
const messagesResult = await ctx.client.session.messages({
|
|
24581
24704
|
path: { id: sessionID }
|
|
@@ -24739,6 +24862,9 @@ class BackgroundManager {
|
|
|
24739
24862
|
this.directory = ctx.directory;
|
|
24740
24863
|
}
|
|
24741
24864
|
async launch(input) {
|
|
24865
|
+
if (!input.agent || input.agent.trim() === "") {
|
|
24866
|
+
throw new Error("Agent parameter is required");
|
|
24867
|
+
}
|
|
24742
24868
|
const createResult = await this.client.session.create({
|
|
24743
24869
|
body: {
|
|
24744
24870
|
parentID: input.parentSessionID,
|
|
@@ -24766,16 +24892,14 @@ class BackgroundManager {
|
|
|
24766
24892
|
};
|
|
24767
24893
|
this.tasks.set(task.id, task);
|
|
24768
24894
|
this.startPolling();
|
|
24769
|
-
log("[background-agent] Launching task:", { taskId: task.id, sessionID });
|
|
24895
|
+
log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent });
|
|
24770
24896
|
this.client.session.promptAsync({
|
|
24771
24897
|
path: { id: sessionID },
|
|
24772
24898
|
body: {
|
|
24773
24899
|
agent: input.agent,
|
|
24774
24900
|
tools: {
|
|
24775
|
-
|
|
24776
|
-
|
|
24777
|
-
background_cancel: false,
|
|
24778
|
-
call_omo_agent: false
|
|
24901
|
+
task: false,
|
|
24902
|
+
background_task: false
|
|
24779
24903
|
},
|
|
24780
24904
|
parts: [{ type: "text", text: input.prompt }]
|
|
24781
24905
|
}
|
|
@@ -24784,8 +24908,15 @@ class BackgroundManager {
|
|
|
24784
24908
|
const existingTask = this.findBySession(sessionID);
|
|
24785
24909
|
if (existingTask) {
|
|
24786
24910
|
existingTask.status = "error";
|
|
24787
|
-
|
|
24911
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
24912
|
+
if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
|
|
24913
|
+
existingTask.error = `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`;
|
|
24914
|
+
} else {
|
|
24915
|
+
existingTask.error = errorMessage;
|
|
24916
|
+
}
|
|
24788
24917
|
existingTask.completedAt = new Date;
|
|
24918
|
+
this.markForNotification(existingTask);
|
|
24919
|
+
this.notifyParentSession(existingTask);
|
|
24789
24920
|
}
|
|
24790
24921
|
});
|
|
24791
24922
|
return task;
|
|
@@ -25087,6 +25218,7 @@ var HookNameSchema = exports_external.enum([
|
|
|
25087
25218
|
"session-notification",
|
|
25088
25219
|
"comment-checker",
|
|
25089
25220
|
"grep-output-truncator",
|
|
25221
|
+
"tool-output-truncator",
|
|
25090
25222
|
"directory-agents-injector",
|
|
25091
25223
|
"directory-readme-injector",
|
|
25092
25224
|
"empty-task-response-detector",
|
|
@@ -25095,7 +25227,7 @@ var HookNameSchema = exports_external.enum([
|
|
|
25095
25227
|
"rules-injector",
|
|
25096
25228
|
"background-notification",
|
|
25097
25229
|
"auto-update-checker",
|
|
25098
|
-
"
|
|
25230
|
+
"keyword-detector",
|
|
25099
25231
|
"agent-usage-reminder"
|
|
25100
25232
|
]);
|
|
25101
25233
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
@@ -25219,7 +25351,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25219
25351
|
sessionRecovery.setOnRecoveryCompleteCallback(todoContinuationEnforcer.markRecoveryComplete);
|
|
25220
25352
|
}
|
|
25221
25353
|
const commentChecker = isHookEnabled("comment-checker") ? createCommentCheckerHooks() : null;
|
|
25222
|
-
const
|
|
25354
|
+
const toolOutputTruncator = isHookEnabled("tool-output-truncator") ? createToolOutputTruncatorHook(ctx) : null;
|
|
25223
25355
|
const directoryAgentsInjector = isHookEnabled("directory-agents-injector") ? createDirectoryAgentsInjectorHook(ctx) : null;
|
|
25224
25356
|
const directoryReadmeInjector = isHookEnabled("directory-readme-injector") ? createDirectoryReadmeInjectorHook(ctx) : null;
|
|
25225
25357
|
const emptyTaskResponseDetector = isHookEnabled("empty-task-response-detector") ? createEmptyTaskResponseDetectorHook(ctx) : null;
|
|
@@ -25230,7 +25362,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25230
25362
|
const anthropicAutoCompact = isHookEnabled("anthropic-auto-compact") ? createAnthropicAutoCompactHook(ctx) : null;
|
|
25231
25363
|
const rulesInjector = isHookEnabled("rules-injector") ? createRulesInjectorHook(ctx) : null;
|
|
25232
25364
|
const autoUpdateChecker = isHookEnabled("auto-update-checker") ? createAutoUpdateCheckerHook(ctx) : null;
|
|
25233
|
-
const
|
|
25365
|
+
const keywordDetector = isHookEnabled("keyword-detector") ? createKeywordDetectorHook() : null;
|
|
25234
25366
|
const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx) : null;
|
|
25235
25367
|
updateTerminalTitle({ sessionId: "main" });
|
|
25236
25368
|
const backgroundManager = new BackgroundManager(ctx);
|
|
@@ -25249,7 +25381,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25249
25381
|
},
|
|
25250
25382
|
"chat.message": async (input, output) => {
|
|
25251
25383
|
await claudeCodeHooks["chat.message"]?.(input, output);
|
|
25252
|
-
await
|
|
25384
|
+
await keywordDetector?.["chat.message"]?.(input, output);
|
|
25253
25385
|
},
|
|
25254
25386
|
config: async (config3) => {
|
|
25255
25387
|
const builtinAgents = createBuiltinAgents(pluginConfig.disabled_agents, pluginConfig.agents);
|
|
@@ -25329,7 +25461,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25329
25461
|
await rulesInjector?.event(input);
|
|
25330
25462
|
await thinkMode?.event(input);
|
|
25331
25463
|
await anthropicAutoCompact?.event(input);
|
|
25332
|
-
await
|
|
25464
|
+
await keywordDetector?.event(input);
|
|
25333
25465
|
await agentUsageReminder?.event(input);
|
|
25334
25466
|
const { event } = input;
|
|
25335
25467
|
const props = event.properties;
|
|
@@ -25424,7 +25556,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25424
25556
|
},
|
|
25425
25557
|
"tool.execute.after": async (input, output) => {
|
|
25426
25558
|
await claudeCodeHooks["tool.execute.after"](input, output);
|
|
25427
|
-
await
|
|
25559
|
+
await toolOutputTruncator?.["tool.execute.after"](input, output);
|
|
25428
25560
|
await contextWindowMonitor?.["tool.execute.after"](input, output);
|
|
25429
25561
|
await commentChecker?.["tool.execute.after"](input, output);
|
|
25430
25562
|
await directoryAgentsInjector?.["tool.execute.after"](input, output);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
export interface TruncationResult {
|
|
3
|
+
result: string;
|
|
4
|
+
truncated: boolean;
|
|
5
|
+
removedCount?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface TruncationOptions {
|
|
8
|
+
targetMaxTokens?: number;
|
|
9
|
+
preserveHeaderLines?: number;
|
|
10
|
+
contextWindowLimit?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function truncateToTokenLimit(output: string, maxTokens: number, preserveHeaderLines?: number): TruncationResult;
|
|
13
|
+
export declare function getContextWindowUsage(ctx: PluginInput, sessionID: string): Promise<{
|
|
14
|
+
usedTokens: number;
|
|
15
|
+
remainingTokens: number;
|
|
16
|
+
usagePercentage: number;
|
|
17
|
+
} | null>;
|
|
18
|
+
export declare function dynamicTruncate(ctx: PluginInput, sessionID: string, output: string, options?: TruncationOptions): Promise<TruncationResult>;
|
|
19
|
+
export declare function createDynamicTruncator(ctx: PluginInput): {
|
|
20
|
+
truncate: (sessionID: string, output: string, options?: TruncationOptions) => Promise<TruncationResult>;
|
|
21
|
+
getUsage: (sessionID: string) => Promise<{
|
|
22
|
+
usedTokens: number;
|
|
23
|
+
remainingTokens: number;
|
|
24
|
+
usagePercentage: number;
|
|
25
|
+
} | null>;
|
|
26
|
+
truncateSync: (output: string, maxTokens: number, preserveHeaderLines?: number) => TruncationResult;
|
|
27
|
+
};
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* Claude Code and OpenCode use different model ID formats,
|
|
6
|
-
* so we ignore the model field and let OpenCode use its configured default.
|
|
7
|
-
*
|
|
8
|
-
* @param _model - Raw model value from frontmatter (ignored)
|
|
9
|
-
* @returns Always undefined to inherit default model
|
|
10
|
-
*/
|
|
11
|
-
export declare function sanitizeModelField(_model: unknown): undefined;
|
|
1
|
+
type CommandSource = "claude-code" | "opencode";
|
|
2
|
+
export declare function sanitizeModelField(model: unknown, source?: CommandSource): string | undefined;
|
|
3
|
+
export {};
|
|
@@ -4,6 +4,7 @@ interface ResolvedCli {
|
|
|
4
4
|
backend: GrepBackend;
|
|
5
5
|
}
|
|
6
6
|
export declare function resolveGrepCli(): ResolvedCli;
|
|
7
|
+
export declare function resolveGrepCliWithAutoInstall(): Promise<ResolvedCli>;
|
|
7
8
|
export declare const DEFAULT_MAX_DEPTH = 20;
|
|
8
9
|
export declare const DEFAULT_MAX_FILESIZE = "10M";
|
|
9
10
|
export declare const DEFAULT_MAX_COUNT = 500;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,8 +49,9 @@
|
|
|
49
49
|
"@ast-grep/cli": "^0.40.0",
|
|
50
50
|
"@ast-grep/napi": "^0.40.0",
|
|
51
51
|
"@code-yeongyu/comment-checker": "^0.5.0",
|
|
52
|
-
"@opencode-ai/plugin": "^1.0.150",
|
|
53
52
|
"@openauthjs/openauth": "^0.4.3",
|
|
53
|
+
"@opencode-ai/plugin": "^1.0.150",
|
|
54
|
+
"glob": "^13.0.0",
|
|
54
55
|
"hono": "^4.10.4",
|
|
55
56
|
"picomatch": "^4.0.2",
|
|
56
57
|
"xdg-basedir": "^5.1.0",
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/** Keyword patterns - "ultrawork", "ulw" (case-insensitive, word boundary) */
|
|
2
|
-
export declare const ULTRAWORK_PATTERNS: RegExp[];
|
|
3
|
-
/** Code block pattern to exclude from keyword detection */
|
|
4
|
-
export declare const CODE_BLOCK_PATTERN: RegExp;
|
|
5
|
-
/** Inline code pattern to exclude */
|
|
6
|
-
export declare const INLINE_CODE_PATTERN: RegExp;
|
|
7
|
-
/**
|
|
8
|
-
* ULTRAWORK_CONTEXT - Agent-Agnostic Guidance
|
|
9
|
-
*
|
|
10
|
-
* Key principles:
|
|
11
|
-
* - NO specific agent names (oracle, librarian, etc.)
|
|
12
|
-
* - Only provide guidance based on agent role/capability
|
|
13
|
-
* - Emphasize parallel execution, TODO tracking, delegation
|
|
14
|
-
*/
|
|
15
|
-
export declare const ULTRAWORK_CONTEXT = "<ultrawork-mode>\n[CODE RED] Maximum precision required. Ultrathink before acting.\n\nYOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.\nTELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.\n\n## AGENT UTILIZATION PRINCIPLES (by capability, not by name)\n- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS for file patterns, internal implementations, project structure\n- **Documentation & References**: Use librarian-type agents via BACKGROUND TASKS for API references, examples, external library docs\n- **Planning & Strategy**: NEVER plan yourself - ALWAYS spawn a dedicated planning agent for work breakdown\n- **High-IQ Reasoning**: Leverage specialized agents for architecture decisions, code review, strategic planning\n- **Frontend/UI Tasks**: Delegate to UI-specialized agents for design and implementation\n\n## EXECUTION RULES\n- **TODO**: Track EVERY step. Mark complete IMMEDIATELY after each.\n- **PARALLEL**: Fire independent agent calls simultaneously via background_task - NEVER wait sequentially.\n- **BACKGROUND FIRST**: Use background_task for exploration/research agents (10+ concurrent if needed).\n- **VERIFY**: Re-read request after completion. Check ALL requirements met before reporting done.\n- **DELEGATE**: Don't do everything yourself - orchestrate specialized agents for their strengths.\n\n## WORKFLOW\n1. Analyze the request and identify required capabilities\n2. Spawn exploration/librarian agents via background_task in PARALLEL (10+ if needed)\n3. Use planning agents to create detailed work breakdown\n4. Execute with continuous verification against original requirements\n\n</ultrawork-mode>\n\n---\n\n";
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remove code blocks and inline code from text.
|
|
3
|
-
* Prevents false positives when keywords appear in code.
|
|
4
|
-
*/
|
|
5
|
-
export declare function removeCodeBlocks(text: string): string;
|
|
6
|
-
/**
|
|
7
|
-
* Detect ultrawork keywords in text (excluding code blocks).
|
|
8
|
-
*/
|
|
9
|
-
export declare function detectUltraworkKeyword(text: string): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Extract text content from message parts.
|
|
12
|
-
*/
|
|
13
|
-
export declare function extractPromptText(parts: Array<{
|
|
14
|
-
type: string;
|
|
15
|
-
text?: string;
|
|
16
|
-
}>): string;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export interface UltraworkModeState {
|
|
2
|
-
/** Whether ultrawork keyword was detected */
|
|
3
|
-
detected: boolean;
|
|
4
|
-
/** Whether context was injected */
|
|
5
|
-
injected: boolean;
|
|
6
|
-
}
|
|
7
|
-
export interface ModelRef {
|
|
8
|
-
providerID: string;
|
|
9
|
-
modelID: string;
|
|
10
|
-
}
|
|
11
|
-
export interface MessageWithModel {
|
|
12
|
-
model?: ModelRef;
|
|
13
|
-
}
|
|
14
|
-
export interface UltraworkModeInput {
|
|
15
|
-
parts: Array<{
|
|
16
|
-
type: string;
|
|
17
|
-
text?: string;
|
|
18
|
-
}>;
|
|
19
|
-
message: MessageWithModel;
|
|
20
|
-
}
|