oh-my-opencode 4.18.1 → 4.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +39 -16
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
- package/bin/AGENTS.md +33 -0
- package/dist/cli/index.js +57 -18
- package/dist/cli-node/index.js +57 -18
- package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
- package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
- package/dist/hooks/comment-checker/hook.d.ts +8 -1
- package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
- package/dist/index.js +560 -333
- package/dist/plugin/messages-transform.d.ts +1 -0
- package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
- package/dist/tui.js +43 -4
- package/package.json +13 -13
- package/packages/git-bash-mcp/dist/cli.js +81 -19
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
- package/packages/lsp-daemon/dist/cli.js +262 -63
- package/packages/lsp-daemon/dist/client.js +194 -50
- package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
- package/packages/lsp-daemon/dist/daemon-client.js +26 -2
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
- package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
- package/packages/lsp-daemon/dist/index.js +262 -63
- package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
- package/packages/lsp-daemon/dist/proxy.js +79 -23
- package/packages/lsp-tools-mcp/dist/cli.js +82 -20
- package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
- package/packages/lsp-tools-mcp/dist/tools.js +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +100 -28
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +1 -0
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +15 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +20 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -2
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +10 -2
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +35 -4
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +1 -1
|
@@ -3021,6 +3021,9 @@ function errorResponse(id, code, message, data) {
|
|
|
3021
3021
|
function jsonRpcId(value) {
|
|
3022
3022
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
3023
3023
|
}
|
|
3024
|
+
function messageFromError(error) {
|
|
3025
|
+
return error instanceof Error ? error.message : String(error);
|
|
3026
|
+
}
|
|
3024
3027
|
// ../mcp-stdio-core/src/transport.ts
|
|
3025
3028
|
var HEADER_SEPARATOR2 = Buffer.from(`\r
|
|
3026
3029
|
\r
|
|
@@ -3043,16 +3046,45 @@ async function* readStdioJsonRpcMessages(input) {
|
|
|
3043
3046
|
yield parseJsonPayload(trailing, "line");
|
|
3044
3047
|
}
|
|
3045
3048
|
}
|
|
3046
|
-
function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
3049
|
+
async function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
3047
3050
|
const body = JSON.stringify(response);
|
|
3048
|
-
|
|
3049
|
-
output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
3051
|
+
const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
3050
3052
|
\r
|
|
3051
|
-
${body}`
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3053
|
+
${body}` : `${body}
|
|
3054
|
+
`;
|
|
3055
|
+
await writeChunk(output, payload);
|
|
3056
|
+
}
|
|
3057
|
+
function writeChunk(output, chunk) {
|
|
3058
|
+
return new Promise((resolve6, reject) => {
|
|
3059
|
+
let settled = false;
|
|
3060
|
+
const onError = (error) => {
|
|
3061
|
+
if (settled)
|
|
3062
|
+
return;
|
|
3063
|
+
settled = true;
|
|
3064
|
+
reject(error);
|
|
3065
|
+
};
|
|
3066
|
+
output.once("error", onError);
|
|
3067
|
+
try {
|
|
3068
|
+
output.write(chunk, (error) => {
|
|
3069
|
+
if (settled)
|
|
3070
|
+
return;
|
|
3071
|
+
settled = true;
|
|
3072
|
+
if (error) {
|
|
3073
|
+
queueMicrotask(() => output.removeListener("error", onError));
|
|
3074
|
+
reject(error);
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
output.removeListener("error", onError);
|
|
3078
|
+
resolve6();
|
|
3079
|
+
});
|
|
3080
|
+
} catch (error) {
|
|
3081
|
+
output.removeListener("error", onError);
|
|
3082
|
+
if (settled)
|
|
3083
|
+
return;
|
|
3084
|
+
settled = true;
|
|
3085
|
+
reject(error);
|
|
3086
|
+
}
|
|
3087
|
+
});
|
|
3056
3088
|
}
|
|
3057
3089
|
function readNextMessage(buffer) {
|
|
3058
3090
|
if (buffer.length === 0)
|
|
@@ -3148,39 +3180,69 @@ async function runJsonRpcStdioServer(config) {
|
|
|
3148
3180
|
break;
|
|
3149
3181
|
idleTimer.arm();
|
|
3150
3182
|
if (message.kind === "parse_error") {
|
|
3151
|
-
handleParseError(message, config, log)
|
|
3183
|
+
if (!await handleParseError(message, config, log))
|
|
3184
|
+
break;
|
|
3152
3185
|
continue;
|
|
3153
3186
|
}
|
|
3154
|
-
await handleRequest(message, config, log)
|
|
3187
|
+
if (!await handleRequest(message, config, log))
|
|
3188
|
+
break;
|
|
3155
3189
|
}
|
|
3156
3190
|
} finally {
|
|
3157
3191
|
idleTimer.clear();
|
|
3158
3192
|
log("stdio_stopped");
|
|
3159
3193
|
}
|
|
3160
3194
|
}
|
|
3161
|
-
function handleParseError(message, config, log) {
|
|
3195
|
+
async function handleParseError(message, config, log) {
|
|
3162
3196
|
log("parse_error", { message: message.message });
|
|
3163
3197
|
const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
|
|
3164
|
-
if (response
|
|
3165
|
-
|
|
3166
|
-
|
|
3198
|
+
if (response === undefined)
|
|
3199
|
+
return true;
|
|
3200
|
+
return writeResponse(response, {
|
|
3201
|
+
output: config.output,
|
|
3202
|
+
responseMode: message.responseMode,
|
|
3203
|
+
log
|
|
3204
|
+
});
|
|
3167
3205
|
}
|
|
3168
3206
|
async function handleRequest(message, config, log) {
|
|
3169
3207
|
const parsed = message.payload;
|
|
3170
3208
|
const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
3171
3209
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
3172
3210
|
log("request", { id: id === null ? null : String(id), method });
|
|
3211
|
+
let response;
|
|
3173
3212
|
try {
|
|
3174
|
-
|
|
3175
|
-
if (response === undefined)
|
|
3176
|
-
return;
|
|
3177
|
-
writeStdioJsonRpcResponse(config.output, response, message.responseMode);
|
|
3178
|
-
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
3213
|
+
response = await config.handler(parsed, config.handlerOptions);
|
|
3179
3214
|
} catch (error) {
|
|
3180
3215
|
if (config.onHandlerError === undefined)
|
|
3181
3216
|
throw error;
|
|
3182
3217
|
config.onHandlerError(error);
|
|
3218
|
+
return true;
|
|
3183
3219
|
}
|
|
3220
|
+
if (response === undefined)
|
|
3221
|
+
return true;
|
|
3222
|
+
if (!await writeResponse(response, {
|
|
3223
|
+
output: config.output,
|
|
3224
|
+
responseMode: message.responseMode,
|
|
3225
|
+
log
|
|
3226
|
+
}))
|
|
3227
|
+
return false;
|
|
3228
|
+
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
3229
|
+
return true;
|
|
3230
|
+
}
|
|
3231
|
+
async function writeResponse(response, context) {
|
|
3232
|
+
try {
|
|
3233
|
+
await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
|
|
3234
|
+
return true;
|
|
3235
|
+
} catch (error) {
|
|
3236
|
+
if (!isTerminalOutputError(error))
|
|
3237
|
+
throw error;
|
|
3238
|
+
context.log("output_error", { message: messageFromError(error) });
|
|
3239
|
+
return false;
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
function isTerminalOutputError(error) {
|
|
3243
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
3244
|
+
return false;
|
|
3245
|
+
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
3184
3246
|
}
|
|
3185
3247
|
function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
3186
3248
|
let timer = null;
|
|
@@ -4243,7 +4305,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4243
4305
|
const fileErrors = [];
|
|
4244
4306
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
4245
4307
|
options.signal?.throwIfAborted();
|
|
4246
|
-
const client = await manager2.getClient(root, server2);
|
|
4308
|
+
const client = await manager2.getClient(root, server2, options.signal);
|
|
4247
4309
|
try {
|
|
4248
4310
|
let nextIndex = 0;
|
|
4249
4311
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -12,6 +12,9 @@ function errorResponse(id, code, message, data) {
|
|
|
12
12
|
function jsonRpcId(value) {
|
|
13
13
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
14
14
|
}
|
|
15
|
+
function messageFromError(error) {
|
|
16
|
+
return error instanceof Error ? error.message : String(error);
|
|
17
|
+
}
|
|
15
18
|
// ../mcp-stdio-core/src/transport.ts
|
|
16
19
|
var HEADER_SEPARATOR = Buffer.from(`\r
|
|
17
20
|
\r
|
|
@@ -34,16 +37,45 @@ async function* readStdioJsonRpcMessages(input) {
|
|
|
34
37
|
yield parseJsonPayload(trailing, "line");
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
|
-
function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
40
|
+
async function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
38
41
|
const body = JSON.stringify(response);
|
|
39
|
-
|
|
40
|
-
output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
42
|
+
const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
41
43
|
\r
|
|
42
|
-
${body}`
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
${body}` : `${body}
|
|
45
|
+
`;
|
|
46
|
+
await writeChunk(output, payload);
|
|
47
|
+
}
|
|
48
|
+
function writeChunk(output, chunk) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
let settled = false;
|
|
51
|
+
const onError = (error) => {
|
|
52
|
+
if (settled)
|
|
53
|
+
return;
|
|
54
|
+
settled = true;
|
|
55
|
+
reject(error);
|
|
56
|
+
};
|
|
57
|
+
output.once("error", onError);
|
|
58
|
+
try {
|
|
59
|
+
output.write(chunk, (error) => {
|
|
60
|
+
if (settled)
|
|
61
|
+
return;
|
|
62
|
+
settled = true;
|
|
63
|
+
if (error) {
|
|
64
|
+
queueMicrotask(() => output.removeListener("error", onError));
|
|
65
|
+
reject(error);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
output.removeListener("error", onError);
|
|
69
|
+
resolve();
|
|
70
|
+
});
|
|
71
|
+
} catch (error) {
|
|
72
|
+
output.removeListener("error", onError);
|
|
73
|
+
if (settled)
|
|
74
|
+
return;
|
|
75
|
+
settled = true;
|
|
76
|
+
reject(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
47
79
|
}
|
|
48
80
|
function readNextMessage(buffer) {
|
|
49
81
|
if (buffer.length === 0)
|
|
@@ -139,40 +171,70 @@ async function runJsonRpcStdioServer(config) {
|
|
|
139
171
|
break;
|
|
140
172
|
idleTimer.arm();
|
|
141
173
|
if (message.kind === "parse_error") {
|
|
142
|
-
handleParseError(message, config, log)
|
|
174
|
+
if (!await handleParseError(message, config, log))
|
|
175
|
+
break;
|
|
143
176
|
continue;
|
|
144
177
|
}
|
|
145
|
-
await handleRequest(message, config, log)
|
|
178
|
+
if (!await handleRequest(message, config, log))
|
|
179
|
+
break;
|
|
146
180
|
}
|
|
147
181
|
} finally {
|
|
148
182
|
idleTimer.clear();
|
|
149
183
|
log("stdio_stopped");
|
|
150
184
|
}
|
|
151
185
|
}
|
|
152
|
-
function handleParseError(message, config, log) {
|
|
186
|
+
async function handleParseError(message, config, log) {
|
|
153
187
|
log("parse_error", { message: message.message });
|
|
154
188
|
const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
|
|
155
|
-
if (response
|
|
156
|
-
|
|
157
|
-
|
|
189
|
+
if (response === undefined)
|
|
190
|
+
return true;
|
|
191
|
+
return writeResponse(response, {
|
|
192
|
+
output: config.output,
|
|
193
|
+
responseMode: message.responseMode,
|
|
194
|
+
log
|
|
195
|
+
});
|
|
158
196
|
}
|
|
159
197
|
async function handleRequest(message, config, log) {
|
|
160
198
|
const parsed = message.payload;
|
|
161
199
|
const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
162
200
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
163
201
|
log("request", { id: id === null ? null : String(id), method });
|
|
202
|
+
let response;
|
|
164
203
|
try {
|
|
165
|
-
|
|
166
|
-
if (response === undefined)
|
|
167
|
-
return;
|
|
168
|
-
writeStdioJsonRpcResponse(config.output, response, message.responseMode);
|
|
169
|
-
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
204
|
+
response = await config.handler(parsed, config.handlerOptions);
|
|
170
205
|
} catch (error) {
|
|
171
206
|
if (config.onHandlerError === undefined)
|
|
172
207
|
throw error;
|
|
173
208
|
config.onHandlerError(error);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
if (response === undefined)
|
|
212
|
+
return true;
|
|
213
|
+
if (!await writeResponse(response, {
|
|
214
|
+
output: config.output,
|
|
215
|
+
responseMode: message.responseMode,
|
|
216
|
+
log
|
|
217
|
+
}))
|
|
218
|
+
return false;
|
|
219
|
+
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
async function writeResponse(response, context) {
|
|
223
|
+
try {
|
|
224
|
+
await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
|
|
225
|
+
return true;
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (!isTerminalOutputError(error))
|
|
228
|
+
throw error;
|
|
229
|
+
context.log("output_error", { message: messageFromError(error) });
|
|
230
|
+
return false;
|
|
174
231
|
}
|
|
175
232
|
}
|
|
233
|
+
function isTerminalOutputError(error) {
|
|
234
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
235
|
+
return false;
|
|
236
|
+
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
237
|
+
}
|
|
176
238
|
function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
177
239
|
let timer = null;
|
|
178
240
|
let isClosed = false;
|
|
@@ -4242,7 +4304,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4242
4304
|
const fileErrors = [];
|
|
4243
4305
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
4244
4306
|
options.signal?.throwIfAborted();
|
|
4245
|
-
const client = await manager.getClient(root, server2);
|
|
4307
|
+
const client = await manager.getClient(root, server2, options.signal);
|
|
4246
4308
|
try {
|
|
4247
4309
|
let nextIndex = 0;
|
|
4248
4310
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -4042,7 +4042,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4042
4042
|
const fileErrors = [];
|
|
4043
4043
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
4044
4044
|
options.signal?.throwIfAborted();
|
|
4045
|
-
const client = await manager.getClient(root, server);
|
|
4045
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4046
4046
|
try {
|
|
4047
4047
|
let nextIndex = 0;
|
|
4048
4048
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
|
|
9
9
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
|
|
10
10
|
"timeout": 30,
|
|
11
|
-
"statusMessage": "(OmO 4.18.
|
|
11
|
+
"statusMessage": "(OmO 4.18.2) Checking Bootstrap Provisioning"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -2989,6 +2989,9 @@ function errorResponse(id, code, message, data) {
|
|
|
2989
2989
|
function jsonRpcId(value) {
|
|
2990
2990
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
2991
2991
|
}
|
|
2992
|
+
function messageFromError(error) {
|
|
2993
|
+
return error instanceof Error ? error.message : String(error);
|
|
2994
|
+
}
|
|
2992
2995
|
// ../../mcp-stdio-core/src/transport.ts
|
|
2993
2996
|
var HEADER_SEPARATOR = Buffer.from(`\r
|
|
2994
2997
|
\r
|
|
@@ -3011,16 +3014,45 @@ async function* readStdioJsonRpcMessages(input) {
|
|
|
3011
3014
|
yield parseJsonPayload(trailing, "line");
|
|
3012
3015
|
}
|
|
3013
3016
|
}
|
|
3014
|
-
function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
3017
|
+
async function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
3015
3018
|
const body = JSON.stringify(response);
|
|
3016
|
-
|
|
3017
|
-
output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
3019
|
+
const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
3018
3020
|
\r
|
|
3019
|
-
${body}`
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3021
|
+
${body}` : `${body}
|
|
3022
|
+
`;
|
|
3023
|
+
await writeChunk(output, payload);
|
|
3024
|
+
}
|
|
3025
|
+
function writeChunk(output, chunk) {
|
|
3026
|
+
return new Promise((resolve5, reject) => {
|
|
3027
|
+
let settled = false;
|
|
3028
|
+
const onError = (error) => {
|
|
3029
|
+
if (settled)
|
|
3030
|
+
return;
|
|
3031
|
+
settled = true;
|
|
3032
|
+
reject(error);
|
|
3033
|
+
};
|
|
3034
|
+
output.once("error", onError);
|
|
3035
|
+
try {
|
|
3036
|
+
output.write(chunk, (error) => {
|
|
3037
|
+
if (settled)
|
|
3038
|
+
return;
|
|
3039
|
+
settled = true;
|
|
3040
|
+
if (error) {
|
|
3041
|
+
queueMicrotask(() => output.removeListener("error", onError));
|
|
3042
|
+
reject(error);
|
|
3043
|
+
return;
|
|
3044
|
+
}
|
|
3045
|
+
output.removeListener("error", onError);
|
|
3046
|
+
resolve5();
|
|
3047
|
+
});
|
|
3048
|
+
} catch (error) {
|
|
3049
|
+
output.removeListener("error", onError);
|
|
3050
|
+
if (settled)
|
|
3051
|
+
return;
|
|
3052
|
+
settled = true;
|
|
3053
|
+
reject(error);
|
|
3054
|
+
}
|
|
3055
|
+
});
|
|
3024
3056
|
}
|
|
3025
3057
|
function readNextMessage(buffer) {
|
|
3026
3058
|
if (buffer.length === 0)
|
|
@@ -3116,40 +3148,70 @@ async function runJsonRpcStdioServer(config) {
|
|
|
3116
3148
|
break;
|
|
3117
3149
|
idleTimer.arm();
|
|
3118
3150
|
if (message.kind === "parse_error") {
|
|
3119
|
-
handleParseError(message, config, log)
|
|
3151
|
+
if (!await handleParseError(message, config, log))
|
|
3152
|
+
break;
|
|
3120
3153
|
continue;
|
|
3121
3154
|
}
|
|
3122
|
-
await handleRequest(message, config, log)
|
|
3155
|
+
if (!await handleRequest(message, config, log))
|
|
3156
|
+
break;
|
|
3123
3157
|
}
|
|
3124
3158
|
} finally {
|
|
3125
3159
|
idleTimer.clear();
|
|
3126
3160
|
log("stdio_stopped");
|
|
3127
3161
|
}
|
|
3128
3162
|
}
|
|
3129
|
-
function handleParseError(message, config, log) {
|
|
3163
|
+
async function handleParseError(message, config, log) {
|
|
3130
3164
|
log("parse_error", { message: message.message });
|
|
3131
3165
|
const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
|
|
3132
|
-
if (response
|
|
3133
|
-
|
|
3134
|
-
|
|
3166
|
+
if (response === undefined)
|
|
3167
|
+
return true;
|
|
3168
|
+
return writeResponse(response, {
|
|
3169
|
+
output: config.output,
|
|
3170
|
+
responseMode: message.responseMode,
|
|
3171
|
+
log
|
|
3172
|
+
});
|
|
3135
3173
|
}
|
|
3136
3174
|
async function handleRequest(message, config, log) {
|
|
3137
3175
|
const parsed = message.payload;
|
|
3138
3176
|
const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
3139
3177
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
3140
3178
|
log("request", { id: id === null ? null : String(id), method });
|
|
3179
|
+
let response;
|
|
3141
3180
|
try {
|
|
3142
|
-
|
|
3143
|
-
if (response === undefined)
|
|
3144
|
-
return;
|
|
3145
|
-
writeStdioJsonRpcResponse(config.output, response, message.responseMode);
|
|
3146
|
-
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
3181
|
+
response = await config.handler(parsed, config.handlerOptions);
|
|
3147
3182
|
} catch (error) {
|
|
3148
3183
|
if (config.onHandlerError === undefined)
|
|
3149
3184
|
throw error;
|
|
3150
3185
|
config.onHandlerError(error);
|
|
3186
|
+
return true;
|
|
3187
|
+
}
|
|
3188
|
+
if (response === undefined)
|
|
3189
|
+
return true;
|
|
3190
|
+
if (!await writeResponse(response, {
|
|
3191
|
+
output: config.output,
|
|
3192
|
+
responseMode: message.responseMode,
|
|
3193
|
+
log
|
|
3194
|
+
}))
|
|
3195
|
+
return false;
|
|
3196
|
+
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
3197
|
+
return true;
|
|
3198
|
+
}
|
|
3199
|
+
async function writeResponse(response, context) {
|
|
3200
|
+
try {
|
|
3201
|
+
await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
|
|
3202
|
+
return true;
|
|
3203
|
+
} catch (error) {
|
|
3204
|
+
if (!isTerminalOutputError(error))
|
|
3205
|
+
throw error;
|
|
3206
|
+
context.log("output_error", { message: messageFromError(error) });
|
|
3207
|
+
return false;
|
|
3151
3208
|
}
|
|
3152
3209
|
}
|
|
3210
|
+
function isTerminalOutputError(error) {
|
|
3211
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
3212
|
+
return false;
|
|
3213
|
+
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
3214
|
+
}
|
|
3153
3215
|
function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
3154
3216
|
let timer = null;
|
|
3155
3217
|
let isClosed = false;
|
|
@@ -3230,18 +3292,28 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
3230
3292
|
resolveExit(signal === null ? 0 : 1);
|
|
3231
3293
|
});
|
|
3232
3294
|
});
|
|
3233
|
-
const
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
]);
|
|
3295
|
+
const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
3296
|
+
defaultResponseMode = mode;
|
|
3297
|
+
});
|
|
3298
|
+
const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode);
|
|
3299
|
+
const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
|
|
3300
|
+
const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
|
|
3239
3301
|
const destroyChildPipes = () => {
|
|
3240
3302
|
childInput.destroy();
|
|
3241
3303
|
childOutput.destroy();
|
|
3242
3304
|
};
|
|
3243
3305
|
childExit.then(destroyChildPipes, destroyChildPipes);
|
|
3244
|
-
|
|
3306
|
+
try {
|
|
3307
|
+
return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
|
|
3308
|
+
} catch (error) {
|
|
3309
|
+
destroyChildPipes();
|
|
3310
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
3311
|
+
child.kill("SIGKILL");
|
|
3312
|
+
await childExit.catch(() => {
|
|
3313
|
+
return;
|
|
3314
|
+
});
|
|
3315
|
+
throw error;
|
|
3316
|
+
}
|
|
3245
3317
|
}
|
|
3246
3318
|
async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode) {
|
|
3247
3319
|
for await (const message of readStdioJsonRpcMessages(input)) {
|
|
@@ -3265,7 +3337,7 @@ async function forwardClientToCodegraph(input, childInput, pendingResponses, set
|
|
|
3265
3337
|
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode) {
|
|
3266
3338
|
for await (const message of readStdioJsonRpcMessages(childOutput)) {
|
|
3267
3339
|
if (message.kind === "parse_error") {
|
|
3268
|
-
writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
3340
|
+
await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
3269
3341
|
continue;
|
|
3270
3342
|
}
|
|
3271
3343
|
const key = responseModeKey(message.payload);
|
|
@@ -3273,7 +3345,7 @@ async function forwardCodegraphToClient(childOutput, output, pendingResponses, d
|
|
|
3273
3345
|
const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
|
|
3274
3346
|
if (key !== null)
|
|
3275
3347
|
pendingResponses.delete(key);
|
|
3276
|
-
writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3348
|
+
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3277
3349
|
}
|
|
3278
3350
|
}
|
|
3279
3351
|
function responseModeKey(payload) {
|