oh-my-opencode 1.1.7 → 1.1.9
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 +332 -231
- 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 +3 -0
- package/dist/tools/grep/downloader.test.d.ts +1 -0
- package/package.json +2 -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, readdirSync as readdirSync7 } 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,28 +23871,29 @@ 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 readdirSync8, 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
|
-
const entries =
|
|
23881
|
+
const entries = readdirSync8(commandsDir, { withFileTypes: true });
|
|
23784
23882
|
const commands = [];
|
|
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 readdirSync9, 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,19 +24059,19 @@ 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
|
-
const entries =
|
|
24065
|
+
const entries = readdirSync9(skillsDir, { withFileTypes: true });
|
|
23967
24066
|
const skills = [];
|
|
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) ? readdirSync9(referencesDir).filter((f) => !f.startsWith(".")) : [];
|
|
24123
|
+
const scripts = existsSync32(scriptsDir) ? readdirSync9(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
|
|
24124
|
+
const assets = existsSync32(assetsDir) ? readdirSync9(assetsDir).filter((f) => !f.startsWith(".")) : [];
|
|
24026
24125
|
return {
|
|
24027
24126
|
name: metadata.name,
|
|
24028
24127
|
path: resolvedPath,
|
|
@@ -24038,15 +24137,15 @@ 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
|
-
const entries =
|
|
24143
|
+
const entries = readdirSync9(skillsDir, { withFileTypes: true });
|
|
24045
24144
|
const skills = [];
|
|
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);
|
|
@@ -24392,15 +24491,15 @@ function createBackgroundOutput(manager, client2) {
|
|
|
24392
24491
|
}
|
|
24393
24492
|
const shouldBlock = args.block === true;
|
|
24394
24493
|
const timeoutMs = Math.min(args.timeout ?? 60000, 600000);
|
|
24395
|
-
if (!shouldBlock) {
|
|
24396
|
-
return formatTaskStatus(task);
|
|
24397
|
-
}
|
|
24398
24494
|
if (task.status === "completed") {
|
|
24399
24495
|
return await formatTaskResult(task, client2);
|
|
24400
24496
|
}
|
|
24401
24497
|
if (task.status === "error" || task.status === "cancelled") {
|
|
24402
24498
|
return formatTaskStatus(task);
|
|
24403
24499
|
}
|
|
24500
|
+
if (!shouldBlock) {
|
|
24501
|
+
return formatTaskStatus(task);
|
|
24502
|
+
}
|
|
24404
24503
|
const startTime = Date.now();
|
|
24405
24504
|
while (Date.now() - startTime < timeoutMs) {
|
|
24406
24505
|
await delay(1000);
|
|
@@ -24531,9 +24630,10 @@ Description: ${task.description}
|
|
|
24531
24630
|
Agent: ${task.agent} (subagent)
|
|
24532
24631
|
Status: ${task.status}
|
|
24533
24632
|
|
|
24534
|
-
|
|
24535
|
-
|
|
24536
|
-
- 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)`;
|
|
24537
24637
|
} catch (error45) {
|
|
24538
24638
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
24539
24639
|
return `Failed to launch background agent task: ${message}`;
|
|
@@ -24575,7 +24675,8 @@ async function executeSync(args, toolContext, ctx) {
|
|
|
24575
24675
|
agent: args.subagent_type,
|
|
24576
24676
|
tools: {
|
|
24577
24677
|
task: false,
|
|
24578
|
-
call_omo_agent: false
|
|
24678
|
+
call_omo_agent: false,
|
|
24679
|
+
background_task: false
|
|
24579
24680
|
},
|
|
24580
24681
|
parts: [{ type: "text", text: args.prompt }]
|
|
24581
24682
|
}
|
|
@@ -24795,10 +24896,9 @@ class BackgroundManager {
|
|
|
24795
24896
|
body: {
|
|
24796
24897
|
agent: input.agent,
|
|
24797
24898
|
tools: {
|
|
24798
|
-
|
|
24799
|
-
|
|
24800
|
-
|
|
24801
|
-
call_omo_agent: false
|
|
24899
|
+
task: false,
|
|
24900
|
+
call_omo_agent: false,
|
|
24901
|
+
background_task: false
|
|
24802
24902
|
},
|
|
24803
24903
|
parts: [{ type: "text", text: input.prompt }]
|
|
24804
24904
|
}
|
|
@@ -25117,6 +25217,7 @@ var HookNameSchema = exports_external.enum([
|
|
|
25117
25217
|
"session-notification",
|
|
25118
25218
|
"comment-checker",
|
|
25119
25219
|
"grep-output-truncator",
|
|
25220
|
+
"tool-output-truncator",
|
|
25120
25221
|
"directory-agents-injector",
|
|
25121
25222
|
"directory-readme-injector",
|
|
25122
25223
|
"empty-task-response-detector",
|
|
@@ -25125,7 +25226,7 @@ var HookNameSchema = exports_external.enum([
|
|
|
25125
25226
|
"rules-injector",
|
|
25126
25227
|
"background-notification",
|
|
25127
25228
|
"auto-update-checker",
|
|
25128
|
-
"
|
|
25229
|
+
"keyword-detector",
|
|
25129
25230
|
"agent-usage-reminder"
|
|
25130
25231
|
]);
|
|
25131
25232
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
@@ -25249,7 +25350,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25249
25350
|
sessionRecovery.setOnRecoveryCompleteCallback(todoContinuationEnforcer.markRecoveryComplete);
|
|
25250
25351
|
}
|
|
25251
25352
|
const commentChecker = isHookEnabled("comment-checker") ? createCommentCheckerHooks() : null;
|
|
25252
|
-
const
|
|
25353
|
+
const toolOutputTruncator = isHookEnabled("tool-output-truncator") ? createToolOutputTruncatorHook(ctx) : null;
|
|
25253
25354
|
const directoryAgentsInjector = isHookEnabled("directory-agents-injector") ? createDirectoryAgentsInjectorHook(ctx) : null;
|
|
25254
25355
|
const directoryReadmeInjector = isHookEnabled("directory-readme-injector") ? createDirectoryReadmeInjectorHook(ctx) : null;
|
|
25255
25356
|
const emptyTaskResponseDetector = isHookEnabled("empty-task-response-detector") ? createEmptyTaskResponseDetectorHook(ctx) : null;
|
|
@@ -25260,7 +25361,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25260
25361
|
const anthropicAutoCompact = isHookEnabled("anthropic-auto-compact") ? createAnthropicAutoCompactHook(ctx) : null;
|
|
25261
25362
|
const rulesInjector = isHookEnabled("rules-injector") ? createRulesInjectorHook(ctx) : null;
|
|
25262
25363
|
const autoUpdateChecker = isHookEnabled("auto-update-checker") ? createAutoUpdateCheckerHook(ctx) : null;
|
|
25263
|
-
const
|
|
25364
|
+
const keywordDetector = isHookEnabled("keyword-detector") ? createKeywordDetectorHook() : null;
|
|
25264
25365
|
const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx) : null;
|
|
25265
25366
|
updateTerminalTitle({ sessionId: "main" });
|
|
25266
25367
|
const backgroundManager = new BackgroundManager(ctx);
|
|
@@ -25279,7 +25380,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25279
25380
|
},
|
|
25280
25381
|
"chat.message": async (input, output) => {
|
|
25281
25382
|
await claudeCodeHooks["chat.message"]?.(input, output);
|
|
25282
|
-
await
|
|
25383
|
+
await keywordDetector?.["chat.message"]?.(input, output);
|
|
25283
25384
|
},
|
|
25284
25385
|
config: async (config3) => {
|
|
25285
25386
|
const builtinAgents = createBuiltinAgents(pluginConfig.disabled_agents, pluginConfig.agents);
|
|
@@ -25359,7 +25460,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25359
25460
|
await rulesInjector?.event(input);
|
|
25360
25461
|
await thinkMode?.event(input);
|
|
25361
25462
|
await anthropicAutoCompact?.event(input);
|
|
25362
|
-
await
|
|
25463
|
+
await keywordDetector?.event(input);
|
|
25363
25464
|
await agentUsageReminder?.event(input);
|
|
25364
25465
|
const { event } = input;
|
|
25365
25466
|
const props = event.properties;
|
|
@@ -25454,7 +25555,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25454
25555
|
},
|
|
25455
25556
|
"tool.execute.after": async (input, output) => {
|
|
25456
25557
|
await claudeCodeHooks["tool.execute.after"](input, output);
|
|
25457
|
-
await
|
|
25558
|
+
await toolOutputTruncator?.["tool.execute.after"](input, output);
|
|
25458
25559
|
await contextWindowMonitor?.["tool.execute.after"](input, output);
|
|
25459
25560
|
await commentChecker?.["tool.execute.after"](input, output);
|
|
25460
25561
|
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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
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,8 @@
|
|
|
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
54
|
"hono": "^4.10.4",
|
|
55
55
|
"picomatch": "^4.0.2",
|
|
56
56
|
"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
|
-
}
|