oh-my-opencode 2.0.3 → 2.0.4
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 +1 -1
- package/README.md +1 -1
- package/dist/config/schema.d.ts +2 -0
- package/dist/hooks/auto-update-checker/constants.d.ts +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/non-interactive-env/constants.d.ts +2 -0
- package/dist/hooks/non-interactive-env/index.d.ts +12 -0
- package/dist/hooks/non-interactive-env/types.d.ts +3 -0
- package/dist/hooks/session-recovery/storage.d.ts +1 -0
- package/dist/index.js +85 -17
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -608,7 +608,7 @@ OmO를 비활성화하고 원래 build/plan 에이전트를 복원하려면:
|
|
|
608
608
|
}
|
|
609
609
|
```
|
|
610
610
|
|
|
611
|
-
사용 가능한 훅: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`
|
|
611
|
+
사용 가능한 훅: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`
|
|
612
612
|
|
|
613
613
|
### MCPs
|
|
614
614
|
|
package/README.md
CHANGED
|
@@ -609,7 +609,7 @@ Disable specific built-in hooks via `disabled_hooks` in `~/.config/opencode/oh-m
|
|
|
609
609
|
}
|
|
610
610
|
```
|
|
611
611
|
|
|
612
|
-
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`
|
|
612
|
+
Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`
|
|
613
613
|
|
|
614
614
|
### MCPs
|
|
615
615
|
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare const HookNameSchema: z.ZodEnum<{
|
|
|
33
33
|
"comment-checker": "comment-checker";
|
|
34
34
|
"rules-injector": "rules-injector";
|
|
35
35
|
"agent-usage-reminder": "agent-usage-reminder";
|
|
36
|
+
"non-interactive-env": "non-interactive-env";
|
|
36
37
|
"todo-continuation-enforcer": "todo-continuation-enforcer";
|
|
37
38
|
"context-window-monitor": "context-window-monitor";
|
|
38
39
|
"session-recovery": "session-recovery";
|
|
@@ -587,6 +588,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
|
|
|
587
588
|
"comment-checker": "comment-checker";
|
|
588
589
|
"rules-injector": "rules-injector";
|
|
589
590
|
"agent-usage-reminder": "agent-usage-reminder";
|
|
591
|
+
"non-interactive-env": "non-interactive-env";
|
|
590
592
|
"todo-continuation-enforcer": "todo-continuation-enforcer";
|
|
591
593
|
"context-window-monitor": "context-window-monitor";
|
|
592
594
|
"session-recovery": "session-recovery";
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -16,3 +16,4 @@ export { createBackgroundNotificationHook } from "./background-notification";
|
|
|
16
16
|
export { createAutoUpdateCheckerHook } from "./auto-update-checker";
|
|
17
17
|
export { createAgentUsageReminderHook } from "./agent-usage-reminder";
|
|
18
18
|
export { createKeywordDetectorHook } from "./keyword-detector";
|
|
19
|
+
export { createNonInteractiveEnvHook } from "./non-interactive-env";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
export * from "./constants";
|
|
3
|
+
export * from "./types";
|
|
4
|
+
export declare function createNonInteractiveEnvHook(_ctx: PluginInput): {
|
|
5
|
+
"tool.execute.before": (input: {
|
|
6
|
+
tool: string;
|
|
7
|
+
sessionID: string;
|
|
8
|
+
callID: string;
|
|
9
|
+
}, output: {
|
|
10
|
+
args: Record<string, unknown>;
|
|
11
|
+
}) => Promise<void>;
|
|
12
|
+
};
|
|
@@ -10,6 +10,7 @@ export declare function findEmptyMessages(sessionID: string): string[];
|
|
|
10
10
|
export declare function findEmptyMessageByIndex(sessionID: string, targetIndex: number): string | null;
|
|
11
11
|
export declare function findFirstEmptyMessage(sessionID: string): string | null;
|
|
12
12
|
export declare function findMessagesWithThinkingBlocks(sessionID: string): string[];
|
|
13
|
+
export declare function findMessagesWithThinkingOnly(sessionID: string): string[];
|
|
13
14
|
export declare function findMessagesWithOrphanThinking(sessionID: string): string[];
|
|
14
15
|
export declare function prependThinkingPart(sessionID: string, messageID: string): boolean;
|
|
15
16
|
export declare function stripThinkingParts(messageID: string): boolean;
|
package/dist/index.js
CHANGED
|
@@ -3879,7 +3879,7 @@ function findEmptyMessages(sessionID) {
|
|
|
3879
3879
|
}
|
|
3880
3880
|
function findEmptyMessageByIndex(sessionID, targetIndex) {
|
|
3881
3881
|
const messages = readMessages(sessionID);
|
|
3882
|
-
const indicesToTry = [targetIndex, targetIndex - 1];
|
|
3882
|
+
const indicesToTry = [targetIndex, targetIndex - 1, targetIndex - 2];
|
|
3883
3883
|
for (const idx of indicesToTry) {
|
|
3884
3884
|
if (idx < 0 || idx >= messages.length)
|
|
3885
3885
|
continue;
|
|
@@ -3904,6 +3904,23 @@ function findMessagesWithThinkingBlocks(sessionID) {
|
|
|
3904
3904
|
}
|
|
3905
3905
|
return result;
|
|
3906
3906
|
}
|
|
3907
|
+
function findMessagesWithThinkingOnly(sessionID) {
|
|
3908
|
+
const messages = readMessages(sessionID);
|
|
3909
|
+
const result = [];
|
|
3910
|
+
for (const msg of messages) {
|
|
3911
|
+
if (msg.role !== "assistant")
|
|
3912
|
+
continue;
|
|
3913
|
+
const parts = readParts(msg.id);
|
|
3914
|
+
if (parts.length === 0)
|
|
3915
|
+
continue;
|
|
3916
|
+
const hasThinking = parts.some((p) => THINKING_TYPES.has(p.type));
|
|
3917
|
+
const hasTextContent = parts.some(hasContent);
|
|
3918
|
+
if (hasThinking && !hasTextContent) {
|
|
3919
|
+
result.push(msg.id);
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
return result;
|
|
3923
|
+
}
|
|
3907
3924
|
function findMessagesWithOrphanThinking(sessionID) {
|
|
3908
3925
|
const messages = readMessages(sessionID);
|
|
3909
3926
|
const result = [];
|
|
@@ -4072,24 +4089,29 @@ async function recoverThinkingDisabledViolation(_client, sessionID, _failedAssis
|
|
|
4072
4089
|
}
|
|
4073
4090
|
return anySuccess;
|
|
4074
4091
|
}
|
|
4092
|
+
var PLACEHOLDER_TEXT = "[user interrupted]";
|
|
4075
4093
|
async function recoverEmptyContentMessage(_client, sessionID, failedAssistantMsg, _directory, error) {
|
|
4076
4094
|
const targetIndex = extractMessageIndex(error);
|
|
4077
4095
|
const failedID = failedAssistantMsg.info?.id;
|
|
4096
|
+
const thinkingOnlyIDs = findMessagesWithThinkingOnly(sessionID);
|
|
4097
|
+
for (const messageID of thinkingOnlyIDs) {
|
|
4098
|
+
injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT);
|
|
4099
|
+
}
|
|
4078
4100
|
if (targetIndex !== null) {
|
|
4079
4101
|
const targetMessageID = findEmptyMessageByIndex(sessionID, targetIndex);
|
|
4080
4102
|
if (targetMessageID) {
|
|
4081
|
-
return injectTextPart(sessionID, targetMessageID,
|
|
4103
|
+
return injectTextPart(sessionID, targetMessageID, PLACEHOLDER_TEXT);
|
|
4082
4104
|
}
|
|
4083
4105
|
}
|
|
4084
4106
|
if (failedID) {
|
|
4085
|
-
if (injectTextPart(sessionID, failedID,
|
|
4107
|
+
if (injectTextPart(sessionID, failedID, PLACEHOLDER_TEXT)) {
|
|
4086
4108
|
return true;
|
|
4087
4109
|
}
|
|
4088
4110
|
}
|
|
4089
4111
|
const emptyMessageIDs = findEmptyMessages(sessionID);
|
|
4090
|
-
let anySuccess =
|
|
4112
|
+
let anySuccess = thinkingOnlyIDs.length > 0;
|
|
4091
4113
|
for (const messageID of emptyMessageIDs) {
|
|
4092
|
-
if (injectTextPart(sessionID, messageID,
|
|
4114
|
+
if (injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT)) {
|
|
4093
4115
|
anySuccess = true;
|
|
4094
4116
|
}
|
|
4095
4117
|
}
|
|
@@ -6979,17 +7001,25 @@ function getUserConfigDir() {
|
|
|
6979
7001
|
}
|
|
6980
7002
|
var USER_CONFIG_DIR = getUserConfigDir();
|
|
6981
7003
|
var USER_OPENCODE_CONFIG = path3.join(USER_CONFIG_DIR, "opencode", "opencode.json");
|
|
7004
|
+
var USER_OPENCODE_CONFIG_JSONC = path3.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
|
|
6982
7005
|
|
|
6983
7006
|
// src/hooks/auto-update-checker/checker.ts
|
|
6984
7007
|
function isLocalDevMode(directory) {
|
|
6985
7008
|
return getLocalDevPath(directory) !== null;
|
|
6986
7009
|
}
|
|
6987
7010
|
function stripJsonComments(json) {
|
|
6988
|
-
return json.replace(
|
|
7011
|
+
return json.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m).replace(/,(\s*[}\]])/g, "$1");
|
|
7012
|
+
}
|
|
7013
|
+
function getConfigPaths(directory) {
|
|
7014
|
+
return [
|
|
7015
|
+
path4.join(directory, ".opencode", "opencode.json"),
|
|
7016
|
+
path4.join(directory, ".opencode", "opencode.jsonc"),
|
|
7017
|
+
USER_OPENCODE_CONFIG,
|
|
7018
|
+
USER_OPENCODE_CONFIG_JSONC
|
|
7019
|
+
];
|
|
6989
7020
|
}
|
|
6990
7021
|
function getLocalDevPath(directory) {
|
|
6991
|
-
const
|
|
6992
|
-
for (const configPath of [projectConfig, USER_OPENCODE_CONFIG]) {
|
|
7022
|
+
for (const configPath of getConfigPaths(directory)) {
|
|
6993
7023
|
try {
|
|
6994
7024
|
if (!fs4.existsSync(configPath))
|
|
6995
7025
|
continue;
|
|
@@ -6998,7 +7028,11 @@ function getLocalDevPath(directory) {
|
|
|
6998
7028
|
const plugins = config.plugin ?? [];
|
|
6999
7029
|
for (const entry of plugins) {
|
|
7000
7030
|
if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME)) {
|
|
7001
|
-
|
|
7031
|
+
try {
|
|
7032
|
+
return fileURLToPath(entry);
|
|
7033
|
+
} catch {
|
|
7034
|
+
return entry.replace("file://", "");
|
|
7035
|
+
}
|
|
7002
7036
|
}
|
|
7003
7037
|
}
|
|
7004
7038
|
} catch {
|
|
@@ -7045,8 +7079,7 @@ function getLocalDevVersion(directory) {
|
|
|
7045
7079
|
}
|
|
7046
7080
|
}
|
|
7047
7081
|
function findPluginEntry(directory) {
|
|
7048
|
-
const
|
|
7049
|
-
for (const configPath of [projectConfig, USER_OPENCODE_CONFIG]) {
|
|
7082
|
+
for (const configPath of getConfigPaths(directory)) {
|
|
7050
7083
|
try {
|
|
7051
7084
|
if (!fs4.existsSync(configPath))
|
|
7052
7085
|
continue;
|
|
@@ -7508,6 +7541,38 @@ function createKeywordDetectorHook() {
|
|
|
7508
7541
|
}
|
|
7509
7542
|
};
|
|
7510
7543
|
}
|
|
7544
|
+
// src/hooks/non-interactive-env/constants.ts
|
|
7545
|
+
var HOOK_NAME = "non-interactive-env";
|
|
7546
|
+
var NON_INTERACTIVE_ENV = {
|
|
7547
|
+
CI: "true",
|
|
7548
|
+
DEBIAN_FRONTEND: "noninteractive",
|
|
7549
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
7550
|
+
GCM_INTERACTIVE: "never",
|
|
7551
|
+
HOMEBREW_NO_AUTO_UPDATE: "1"
|
|
7552
|
+
};
|
|
7553
|
+
|
|
7554
|
+
// src/hooks/non-interactive-env/index.ts
|
|
7555
|
+
function createNonInteractiveEnvHook(_ctx) {
|
|
7556
|
+
return {
|
|
7557
|
+
"tool.execute.before": async (input, output) => {
|
|
7558
|
+
if (input.tool.toLowerCase() !== "bash") {
|
|
7559
|
+
return;
|
|
7560
|
+
}
|
|
7561
|
+
const command = output.args.command;
|
|
7562
|
+
if (!command) {
|
|
7563
|
+
return;
|
|
7564
|
+
}
|
|
7565
|
+
output.args.env = {
|
|
7566
|
+
...output.args.env,
|
|
7567
|
+
...NON_INTERACTIVE_ENV
|
|
7568
|
+
};
|
|
7569
|
+
log(`[${HOOK_NAME}] Set non-interactive environment variables`, {
|
|
7570
|
+
sessionID: input.sessionID,
|
|
7571
|
+
env: NON_INTERACTIVE_ENV
|
|
7572
|
+
});
|
|
7573
|
+
}
|
|
7574
|
+
};
|
|
7575
|
+
}
|
|
7511
7576
|
// src/auth/antigravity/constants.ts
|
|
7512
7577
|
var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
|
|
7513
7578
|
var ANTIGRAVITY_CLIENT_SECRET = "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";
|
|
@@ -9661,7 +9726,7 @@ function loadJsonFile(path6) {
|
|
|
9661
9726
|
return null;
|
|
9662
9727
|
}
|
|
9663
9728
|
}
|
|
9664
|
-
function
|
|
9729
|
+
function getConfigPaths2() {
|
|
9665
9730
|
const cwd = process.cwd();
|
|
9666
9731
|
return {
|
|
9667
9732
|
project: join31(cwd, ".opencode", "oh-my-opencode.json"),
|
|
@@ -9670,7 +9735,7 @@ function getConfigPaths() {
|
|
|
9670
9735
|
};
|
|
9671
9736
|
}
|
|
9672
9737
|
function loadAllConfigs() {
|
|
9673
|
-
const paths =
|
|
9738
|
+
const paths = getConfigPaths2();
|
|
9674
9739
|
const configs = new Map;
|
|
9675
9740
|
const project2 = loadJsonFile(paths.project);
|
|
9676
9741
|
if (project2)
|
|
@@ -20693,10 +20758,10 @@ function _property(property, schema, params) {
|
|
|
20693
20758
|
...normalizeParams(params)
|
|
20694
20759
|
});
|
|
20695
20760
|
}
|
|
20696
|
-
function _mime(
|
|
20761
|
+
function _mime(types11, params) {
|
|
20697
20762
|
return new $ZodCheckMimeType({
|
|
20698
20763
|
check: "mime_type",
|
|
20699
|
-
mime:
|
|
20764
|
+
mime: types11,
|
|
20700
20765
|
...normalizeParams(params)
|
|
20701
20766
|
});
|
|
20702
20767
|
}
|
|
@@ -22606,7 +22671,7 @@ var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
|
|
|
22606
22671
|
ZodType.init(inst, def);
|
|
22607
22672
|
inst.min = (size, params) => inst.check(_minSize(size, params));
|
|
22608
22673
|
inst.max = (size, params) => inst.check(_maxSize(size, params));
|
|
22609
|
-
inst.mime = (
|
|
22674
|
+
inst.mime = (types11, params) => inst.check(_mime(Array.isArray(types11) ? types11 : [types11], params));
|
|
22610
22675
|
});
|
|
22611
22676
|
function file(params) {
|
|
22612
22677
|
return _file(ZodFile, params);
|
|
@@ -25599,7 +25664,8 @@ var HookNameSchema = exports_external.enum([
|
|
|
25599
25664
|
"auto-update-checker",
|
|
25600
25665
|
"startup-toast",
|
|
25601
25666
|
"keyword-detector",
|
|
25602
|
-
"agent-usage-reminder"
|
|
25667
|
+
"agent-usage-reminder",
|
|
25668
|
+
"non-interactive-env"
|
|
25603
25669
|
]);
|
|
25604
25670
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
25605
25671
|
model: exports_external.string().optional(),
|
|
@@ -25765,6 +25831,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25765
25831
|
}) : null;
|
|
25766
25832
|
const keywordDetector = isHookEnabled("keyword-detector") ? createKeywordDetectorHook() : null;
|
|
25767
25833
|
const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx) : null;
|
|
25834
|
+
const nonInteractiveEnv = isHookEnabled("non-interactive-env") ? createNonInteractiveEnvHook(ctx) : null;
|
|
25768
25835
|
updateTerminalTitle({ sessionId: "main" });
|
|
25769
25836
|
const backgroundManager = new BackgroundManager(ctx);
|
|
25770
25837
|
const backgroundNotificationHook = isHookEnabled("background-notification") ? createBackgroundNotificationHook(backgroundManager) : null;
|
|
@@ -25957,6 +26024,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25957
26024
|
},
|
|
25958
26025
|
"tool.execute.before": async (input, output) => {
|
|
25959
26026
|
await claudeCodeHooks["tool.execute.before"](input, output);
|
|
26027
|
+
await nonInteractiveEnv?.["tool.execute.before"](input, output);
|
|
25960
26028
|
await commentChecker?.["tool.execute.before"](input, output);
|
|
25961
26029
|
if (input.sessionID === getMainSessionID()) {
|
|
25962
26030
|
updateTerminalTitle({
|