oh-my-opencode 4.18.1 → 4.19.0
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/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +4 -4
- package/README.ru.md +2 -2
- package/README.zh-cn.md +2 -2
- package/bin/AGENTS.md +33 -0
- package/dist/agents/atlas/agent.d.ts +6 -5
- package/dist/agents/sisyphus/index.d.ts +5 -0
- package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
- package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
- package/dist/agents/sisyphus-junior/index.d.ts +2 -0
- package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +690 -139
- package/dist/cli-node/index.js +690 -139
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/browser-automation.d.ts +1 -0
- package/dist/config/schema/commands.d.ts +1 -3
- package/dist/config/schema/default-mode.d.ts +1 -1
- package/dist/config/schema/goal.d.ts +7 -0
- package/dist/config/schema/hooks.d.ts +1 -1
- package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
- package/dist/config/schema/ralph-loop.d.ts +1 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/create-hooks.d.ts +1 -1
- package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
- package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
- package/dist/hooks/auto-slash-command/executor.d.ts +1 -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/goal/command-arguments.d.ts +13 -0
- package/dist/hooks/goal/controller.d.ts +26 -0
- package/dist/hooks/goal/index.d.ts +23 -0
- package/dist/hooks/goal/prompt.d.ts +3 -0
- package/dist/hooks/goal/store.d.ts +8 -0
- package/dist/hooks/goal/tools.d.ts +10 -0
- package/dist/hooks/goal/types.d.ts +93 -0
- package/dist/hooks/goal/validation.d.ts +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/keyword-detector/hook.d.ts +1 -2
- package/dist/hooks/ralph-loop/types.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
- package/dist/index.js +3706 -4329
- package/dist/oh-my-opencode.schema.json +23 -19
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
- package/dist/plugin/chat-message/types.d.ts +23 -10
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
- package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
- package/dist/plugin/messages-transform.d.ts +1 -0
- package/dist/plugin/stop-continuation.d.ts +2 -2
- package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
- package/dist/shared/system-directive.d.ts +0 -1
- package/dist/skills/ulw-plan/SKILL.md +11 -7
- package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/dist/skills/ulw-research/SKILL.md +3 -3
- package/dist/tools/delegate-task/types.d.ts +0 -1
- package/dist/tui.js +115 -28
- package/package.json +14 -14
- 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/dist/cli.js +352 -17
- 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/AGENTS.md +7 -6
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
- 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/hook-exclusion.test.ts +1 -1
- 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/AGENTS.md +1 -0
- 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/AGENTS.md +8 -0
- 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 +148 -61
- 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 +4 -72
- package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
- package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -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/AGENTS.md +10 -10
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
- 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/ultrawork/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- 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/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
- 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/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
- package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
- package/dist/skills/ultraresearch/SKILL.md +0 -10
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
- package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
package/dist/tui.js
CHANGED
|
@@ -19890,7 +19890,8 @@ var init_browser_automation = __esm(() => {
|
|
|
19890
19890
|
"playwright-cli"
|
|
19891
19891
|
]);
|
|
19892
19892
|
BrowserAutomationConfigSchema = exports_external.object({
|
|
19893
|
-
provider: BrowserAutomationProviderSchema.default("playwright")
|
|
19893
|
+
provider: BrowserAutomationProviderSchema.default("playwright"),
|
|
19894
|
+
playwright_mcp_args: exports_external.array(exports_external.string()).optional()
|
|
19894
19895
|
});
|
|
19895
19896
|
});
|
|
19896
19897
|
|
|
@@ -19978,9 +19979,7 @@ var BuiltinCommandNameSchema;
|
|
|
19978
19979
|
var init_commands = __esm(() => {
|
|
19979
19980
|
init_zod();
|
|
19980
19981
|
BuiltinCommandNameSchema = exports_external.enum([
|
|
19981
|
-
"
|
|
19982
|
-
"ulw-loop",
|
|
19983
|
-
"cancel-ralph",
|
|
19982
|
+
"goal",
|
|
19984
19983
|
"refactor",
|
|
19985
19984
|
"start-work",
|
|
19986
19985
|
"stop-continuation",
|
|
@@ -19995,7 +19994,7 @@ var init_default_mode = __esm(() => {
|
|
|
19995
19994
|
init_zod();
|
|
19996
19995
|
DefaultModeConfigSchema = exports_external.object({
|
|
19997
19996
|
ultrawork: exports_external.boolean().default(false),
|
|
19998
|
-
|
|
19997
|
+
goal: exports_external.boolean().default(false)
|
|
19999
19998
|
});
|
|
20000
19999
|
});
|
|
20001
20000
|
|
|
@@ -20056,6 +20055,17 @@ var init_experimental = __esm(() => {
|
|
|
20056
20055
|
});
|
|
20057
20056
|
});
|
|
20058
20057
|
|
|
20058
|
+
// packages/omo-opencode/src/config/schema/goal.ts
|
|
20059
|
+
var GoalConfigSchema;
|
|
20060
|
+
var init_goal = __esm(() => {
|
|
20061
|
+
init_zod();
|
|
20062
|
+
GoalConfigSchema = exports_external.object({
|
|
20063
|
+
enabled: exports_external.boolean().default(false),
|
|
20064
|
+
auto_start: exports_external.boolean().default(false),
|
|
20065
|
+
default_max_iterations: exports_external.number().min(1).max(1000).default(100)
|
|
20066
|
+
});
|
|
20067
|
+
});
|
|
20068
|
+
|
|
20059
20069
|
// packages/skills-loader-core/src/config/git-env-prefix.ts
|
|
20060
20070
|
function isValidGitEnvPrefix(value) {
|
|
20061
20071
|
if (value === "") {
|
|
@@ -20116,7 +20126,7 @@ var init_hooks = __esm(() => {
|
|
|
20116
20126
|
"interactive-bash-session",
|
|
20117
20127
|
"tool-pair-validator",
|
|
20118
20128
|
"monitor-status-injector",
|
|
20119
|
-
"
|
|
20129
|
+
"goal",
|
|
20120
20130
|
"category-skill-reminder",
|
|
20121
20131
|
"compaction-context-injector",
|
|
20122
20132
|
"compaction-todo-preserver",
|
|
@@ -20264,18 +20274,6 @@ var init_monitor = __esm(() => {
|
|
|
20264
20274
|
});
|
|
20265
20275
|
});
|
|
20266
20276
|
|
|
20267
|
-
// packages/omo-opencode/src/config/schema/ralph-loop.ts
|
|
20268
|
-
var RalphLoopConfigSchema;
|
|
20269
|
-
var init_ralph_loop = __esm(() => {
|
|
20270
|
-
init_zod();
|
|
20271
|
-
RalphLoopConfigSchema = exports_external.object({
|
|
20272
|
-
enabled: exports_external.boolean().default(false),
|
|
20273
|
-
default_max_iterations: exports_external.number().min(1).max(1000).default(100),
|
|
20274
|
-
state_dir: exports_external.string().optional(),
|
|
20275
|
-
default_strategy: exports_external.enum(["reset", "continue"]).default("continue")
|
|
20276
|
-
});
|
|
20277
|
-
});
|
|
20278
|
-
|
|
20279
20277
|
// packages/omo-opencode/src/config/schema/runtime-fallback.ts
|
|
20280
20278
|
var RuntimeFallbackConfigSchema;
|
|
20281
20279
|
var init_runtime_fallback = __esm(() => {
|
|
@@ -20536,8 +20534,8 @@ var init_oh_my_opencode_config = __esm(() => {
|
|
|
20536
20534
|
init_notification();
|
|
20537
20535
|
init_openclaw();
|
|
20538
20536
|
init_model_capabilities();
|
|
20537
|
+
init_goal();
|
|
20539
20538
|
init_monitor();
|
|
20540
|
-
init_ralph_loop();
|
|
20541
20539
|
init_runtime_fallback();
|
|
20542
20540
|
init_team_mode();
|
|
20543
20541
|
init_skills();
|
|
@@ -20572,7 +20570,8 @@ var init_oh_my_opencode_config = __esm(() => {
|
|
|
20572
20570
|
experimental: ExperimentalConfigSchema.optional(),
|
|
20573
20571
|
auto_update: exports_external.boolean().optional(),
|
|
20574
20572
|
skills: SkillsConfigSchema.optional(),
|
|
20575
|
-
|
|
20573
|
+
goal: GoalConfigSchema.optional(),
|
|
20574
|
+
ralph_loop: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
20576
20575
|
runtime_fallback: exports_external.union([exports_external.boolean(), RuntimeFallbackConfigSchema]).optional(),
|
|
20577
20576
|
background_task: BackgroundTaskConfigSchema.optional(),
|
|
20578
20577
|
notification: NotificationConfigSchema.optional(),
|
|
@@ -20617,6 +20616,7 @@ var init_schema = __esm(() => {
|
|
|
20617
20616
|
init_dynamic_context_pruning();
|
|
20618
20617
|
init_experimental();
|
|
20619
20618
|
init_fallback_models();
|
|
20619
|
+
init_goal();
|
|
20620
20620
|
init_git_env_prefix2();
|
|
20621
20621
|
init_git_master();
|
|
20622
20622
|
init_hooks();
|
|
@@ -20625,7 +20625,6 @@ var init_schema = __esm(() => {
|
|
|
20625
20625
|
init_model_capabilities();
|
|
20626
20626
|
init_notification();
|
|
20627
20627
|
init_oh_my_opencode_config();
|
|
20628
|
-
init_ralph_loop();
|
|
20629
20628
|
init_runtime_fallback();
|
|
20630
20629
|
init_team_mode();
|
|
20631
20630
|
init_skills();
|
|
@@ -20671,6 +20670,7 @@ var init_agent_model_requirements = __esm(() => {
|
|
|
20671
20670
|
model: "claude-opus-4-7",
|
|
20672
20671
|
variant: "max"
|
|
20673
20672
|
},
|
|
20673
|
+
{ providers: ["opencode-go", "kimi-for-coding", "moonshotai", "opencode", "vercel"], model: "kimi-k3" },
|
|
20674
20674
|
{ providers: ["opencode-go", "vercel"], model: "kimi-k2.6" },
|
|
20675
20675
|
{ providers: ["kimi-for-coding"], model: "k2p5" },
|
|
20676
20676
|
{
|
|
@@ -20695,7 +20695,7 @@ var init_agent_model_requirements = __esm(() => {
|
|
|
20695
20695
|
hephaestus: {
|
|
20696
20696
|
fallbackChain: [
|
|
20697
20697
|
{
|
|
20698
|
-
providers: ["openai", "vercel"],
|
|
20698
|
+
providers: ["openai", "github-copilot", "vercel"],
|
|
20699
20699
|
model: "gpt-5.6-sol",
|
|
20700
20700
|
variant: "high"
|
|
20701
20701
|
},
|
|
@@ -20803,8 +20803,13 @@ var init_agent_model_requirements = __esm(() => {
|
|
|
20803
20803
|
fallbackChain: [
|
|
20804
20804
|
{
|
|
20805
20805
|
providers: ["openai", "vercel"],
|
|
20806
|
-
model: "gpt-5.6-
|
|
20807
|
-
variant: "
|
|
20806
|
+
model: "gpt-5.6-terra",
|
|
20807
|
+
variant: "high"
|
|
20808
|
+
},
|
|
20809
|
+
{
|
|
20810
|
+
providers: ["github-copilot"],
|
|
20811
|
+
model: "gpt-5.6-terra",
|
|
20812
|
+
variant: "high"
|
|
20808
20813
|
},
|
|
20809
20814
|
{
|
|
20810
20815
|
providers: ["openai", "github-copilot", "opencode", "vercel"],
|
|
@@ -20884,6 +20889,11 @@ var init_category_model_requirements = __esm(() => {
|
|
|
20884
20889
|
model: "gpt-5.6-sol",
|
|
20885
20890
|
variant: "xhigh"
|
|
20886
20891
|
},
|
|
20892
|
+
{
|
|
20893
|
+
providers: ["github-copilot"],
|
|
20894
|
+
model: "gpt-5.6-sol",
|
|
20895
|
+
variant: "high"
|
|
20896
|
+
},
|
|
20887
20897
|
{
|
|
20888
20898
|
providers: ["openai", "opencode", "vercel"],
|
|
20889
20899
|
model: "gpt-5.5",
|
|
@@ -20910,7 +20920,12 @@ var init_category_model_requirements = __esm(() => {
|
|
|
20910
20920
|
variant: "xhigh"
|
|
20911
20921
|
},
|
|
20912
20922
|
{
|
|
20913
|
-
providers: ["
|
|
20923
|
+
providers: ["github-copilot"],
|
|
20924
|
+
model: "gpt-5.6-terra",
|
|
20925
|
+
variant: "high"
|
|
20926
|
+
},
|
|
20927
|
+
{
|
|
20928
|
+
providers: ["openai", "github-copilot", "vercel"],
|
|
20914
20929
|
model: "gpt-5.6-sol",
|
|
20915
20930
|
variant: "high"
|
|
20916
20931
|
},
|
|
@@ -20977,6 +20992,11 @@ var init_category_model_requirements = __esm(() => {
|
|
|
20977
20992
|
model: "gpt-5.6-luna",
|
|
20978
20993
|
variant: "xhigh"
|
|
20979
20994
|
},
|
|
20995
|
+
{
|
|
20996
|
+
providers: ["github-copilot"],
|
|
20997
|
+
model: "gpt-5.6-luna",
|
|
20998
|
+
variant: "high"
|
|
20999
|
+
},
|
|
20980
21000
|
{
|
|
20981
21001
|
providers: ["anthropic", "github-copilot", "opencode", "vercel"],
|
|
20982
21002
|
model: "claude-sonnet-4-6"
|
|
@@ -21066,9 +21086,12 @@ function stripProviderPrefixForAliasLookup(normalizedModelID) {
|
|
|
21066
21086
|
}
|
|
21067
21087
|
return normalizedModelID.slice(slashIndex + 1);
|
|
21068
21088
|
}
|
|
21069
|
-
function resolveModelIDAlias(modelID) {
|
|
21089
|
+
function resolveModelIDAlias(modelID, providerID) {
|
|
21070
21090
|
const requestedModelID = normalizeLookupModelID(modelID);
|
|
21071
21091
|
const aliasLookupModelID = stripProviderPrefixForAliasLookup(requestedModelID);
|
|
21092
|
+
const normalizedProviderID = providerID ? normalizeLookupModelID(providerID) : undefined;
|
|
21093
|
+
const providerPrefixEnd = requestedModelID.indexOf("/");
|
|
21094
|
+
const embeddedProviderID = providerPrefixEnd > 0 ? requestedModelID.slice(0, providerPrefixEnd) : undefined;
|
|
21072
21095
|
const exactRule = EXACT_ALIAS_RULES_BY_MODEL.get(aliasLookupModelID);
|
|
21073
21096
|
if (exactRule) {
|
|
21074
21097
|
return {
|
|
@@ -21079,6 +21102,13 @@ function resolveModelIDAlias(modelID) {
|
|
|
21079
21102
|
};
|
|
21080
21103
|
}
|
|
21081
21104
|
for (const rule of PATTERN_ALIAS_RULES) {
|
|
21105
|
+
if (rule.providerIDs) {
|
|
21106
|
+
const matchesProviderID = normalizedProviderID !== undefined && rule.providerIDs.includes(normalizedProviderID);
|
|
21107
|
+
const matchesEmbeddedProviderID = normalizedProviderID !== undefined && rule.allowedSubproviderHosts?.includes(normalizedProviderID) === true && embeddedProviderID !== undefined && rule.providerIDs.includes(embeddedProviderID);
|
|
21108
|
+
if (!matchesProviderID && !matchesEmbeddedProviderID) {
|
|
21109
|
+
continue;
|
|
21110
|
+
}
|
|
21111
|
+
}
|
|
21082
21112
|
if (!rule.match(aliasLookupModelID)) {
|
|
21083
21113
|
continue;
|
|
21084
21114
|
}
|
|
@@ -21119,6 +21149,14 @@ var init_model_capability_aliases = __esm(() => {
|
|
|
21119
21149
|
];
|
|
21120
21150
|
EXACT_ALIAS_RULES_BY_MODEL = new Map(EXACT_ALIAS_RULES.map((rule) => [rule.aliasModelID, rule]));
|
|
21121
21151
|
PATTERN_ALIAS_RULES = [
|
|
21152
|
+
{
|
|
21153
|
+
ruleID: "openai-gpt-5.6-fast-service-tier-alias",
|
|
21154
|
+
description: "Normalizes OpenCode's OpenAI GPT-5.6 fast service-tier IDs to canonical snapshot IDs.",
|
|
21155
|
+
providerIDs: ["openai"],
|
|
21156
|
+
allowedSubproviderHosts: ["vercel"],
|
|
21157
|
+
match: (normalizedModelID) => /^gpt-5\.6-(?:sol|terra|luna)-fast$/.test(normalizedModelID),
|
|
21158
|
+
canonicalize: (normalizedModelID) => normalizedModelID.slice(0, -"-fast".length)
|
|
21159
|
+
},
|
|
21122
21160
|
{
|
|
21123
21161
|
ruleID: "claude-thinking-legacy-alias",
|
|
21124
21162
|
description: "Normalizes the legacy claude-opus-4-7-thinking id to the canonical snapshot ID.",
|
|
@@ -21343,6 +21381,21 @@ var init_runtime_fallback_model = () => {};
|
|
|
21343
21381
|
var SUPPLEMENTAL_MODEL_CAPABILITIES;
|
|
21344
21382
|
var init_supplemental_entries = __esm(() => {
|
|
21345
21383
|
SUPPLEMENTAL_MODEL_CAPABILITIES = {
|
|
21384
|
+
"kimi-k3": {
|
|
21385
|
+
id: "kimi-k3",
|
|
21386
|
+
family: "kimi",
|
|
21387
|
+
reasoning: true,
|
|
21388
|
+
temperature: true,
|
|
21389
|
+
toolCall: true,
|
|
21390
|
+
modalities: {
|
|
21391
|
+
input: ["text", "image", "video"],
|
|
21392
|
+
output: ["text"]
|
|
21393
|
+
},
|
|
21394
|
+
limit: {
|
|
21395
|
+
context: 262144,
|
|
21396
|
+
output: 262144
|
|
21397
|
+
}
|
|
21398
|
+
},
|
|
21346
21399
|
"kimi-k2.6": {
|
|
21347
21400
|
id: "kimi-k2.6",
|
|
21348
21401
|
family: "kimi",
|
|
@@ -21596,7 +21649,7 @@ function getProviderOverride(providerID, modelID) {
|
|
|
21596
21649
|
return GITHUB_COPILOT_GPT5_MODEL.test(normalizeLookupModelID2(modelID)) ? GITHUB_COPILOT_GPT5_OVERRIDE : undefined;
|
|
21597
21650
|
}
|
|
21598
21651
|
function getModelCapabilities(input) {
|
|
21599
|
-
const canonicalization = resolveModelIDAlias(input.modelID);
|
|
21652
|
+
const canonicalization = resolveModelIDAlias(input.modelID, input.providerID);
|
|
21600
21653
|
const override = getOverride(input.modelID);
|
|
21601
21654
|
const providerOverride = getProviderOverride(input.providerID, canonicalization.canonicalModelID);
|
|
21602
21655
|
const runtimeModel = readRuntimeModel(input.runtimeModel ?? input.providerCache?.findProviderModelMetadata(input.providerID, input.modelID));
|
|
@@ -22460,6 +22513,7 @@ var init_opencode_storage_detection = __esm(() => {
|
|
|
22460
22513
|
var opencodePluginsCache;
|
|
22461
22514
|
var init_load_opencode_plugins = __esm(() => {
|
|
22462
22515
|
init_jsonc_parser2();
|
|
22516
|
+
init_opencode_config_dir();
|
|
22463
22517
|
opencodePluginsCache = new Map;
|
|
22464
22518
|
});
|
|
22465
22519
|
|
|
@@ -76190,13 +76244,45 @@ function mergeLoadedConfig(userLayersNearestFirst, projectLayersNearestFirst) {
|
|
|
76190
76244
|
config3 = mergeConfigs(config3, layer.config);
|
|
76191
76245
|
}
|
|
76192
76246
|
const userMcpEnvAllowlist = config3.mcp_env_allowlist ?? [];
|
|
76247
|
+
const userPlaywrightMcpArgs = config3.browser_automation_engine?.playwright_mcp_args;
|
|
76193
76248
|
for (const layer of [...projectLayersNearestFirst].reverse()) {
|
|
76194
76249
|
if (layer.config)
|
|
76195
76250
|
config3 = mergeConfigs(config3, layer.config);
|
|
76196
76251
|
}
|
|
76197
76252
|
config3 = { ...config3, mcp_env_allowlist: userMcpEnvAllowlist };
|
|
76253
|
+
if (config3.browser_automation_engine) {
|
|
76254
|
+
const {
|
|
76255
|
+
playwright_mcp_args: _projectPlaywrightMcpArgs,
|
|
76256
|
+
...browserAutomationEngine
|
|
76257
|
+
} = config3.browser_automation_engine;
|
|
76258
|
+
config3 = {
|
|
76259
|
+
...config3,
|
|
76260
|
+
browser_automation_engine: userPlaywrightMcpArgs !== undefined ? { ...browserAutomationEngine, playwright_mcp_args: userPlaywrightMcpArgs } : browserAutomationEngine
|
|
76261
|
+
};
|
|
76262
|
+
}
|
|
76198
76263
|
return applyDisabledProviders(config3);
|
|
76199
76264
|
}
|
|
76265
|
+
function migrateRalphLoopConfig(config3) {
|
|
76266
|
+
const legacy = config3.ralph_loop;
|
|
76267
|
+
if (legacy === undefined) {
|
|
76268
|
+
return config3;
|
|
76269
|
+
}
|
|
76270
|
+
const enabled = typeof legacy.enabled === "boolean" ? legacy.enabled : undefined;
|
|
76271
|
+
const defaultMaxIterations = typeof legacy.default_max_iterations === "number" ? legacy.default_max_iterations : undefined;
|
|
76272
|
+
if (enabled === undefined && defaultMaxIterations === undefined) {
|
|
76273
|
+
return config3;
|
|
76274
|
+
}
|
|
76275
|
+
log2("[config] ralph_loop is deprecated and will be removed in a future release. Use goal instead.");
|
|
76276
|
+
const existingGoal = config3.goal;
|
|
76277
|
+
return {
|
|
76278
|
+
...config3,
|
|
76279
|
+
goal: {
|
|
76280
|
+
enabled: existingGoal?.enabled ?? enabled ?? false,
|
|
76281
|
+
auto_start: existingGoal?.auto_start ?? false,
|
|
76282
|
+
default_max_iterations: existingGoal?.default_max_iterations ?? defaultMaxIterations ?? 100
|
|
76283
|
+
}
|
|
76284
|
+
};
|
|
76285
|
+
}
|
|
76200
76286
|
function validatePluginConfig(directory) {
|
|
76201
76287
|
const userLayersNearestFirst = discoverUserLayers().map((layer) => parseLayerConfig(layer.path));
|
|
76202
76288
|
const projectLayersNearestFirst = discoverProjectLayersNearestFirst(directory).map((layer) => parseLayerConfig(layer.path));
|
|
@@ -76206,7 +76292,7 @@ function validatePluginConfig(directory) {
|
|
|
76206
76292
|
valid: messages.length === 0,
|
|
76207
76293
|
messages,
|
|
76208
76294
|
path: firstFailingPath(layers) ?? firstPath(layers),
|
|
76209
|
-
config: mergeLoadedConfig(userLayersNearestFirst, projectLayersNearestFirst)
|
|
76295
|
+
config: migrateRalphLoopConfig(mergeLoadedConfig(userLayersNearestFirst, projectLayersNearestFirst))
|
|
76210
76296
|
};
|
|
76211
76297
|
}
|
|
76212
76298
|
var init_validate = __esm(() => {
|
|
@@ -76215,6 +76301,7 @@ var init_validate = __esm(() => {
|
|
|
76215
76301
|
init_single_config_loader();
|
|
76216
76302
|
init_shared();
|
|
76217
76303
|
init_disabled_providers();
|
|
76304
|
+
init_logger2();
|
|
76218
76305
|
init_plugin_identity();
|
|
76219
76306
|
init_schema();
|
|
76220
76307
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.19.0",
|
|
4
4
|
"description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"install:codex-dev": "bun run script/build-codex-install.ts && bun run script/install-codex-dev.ts",
|
|
111
111
|
"build:codex-plugin": "npm --prefix packages/omo-codex/plugin ci && bun run --cwd packages/omo-codex/plugin build",
|
|
112
112
|
"build:senpi-plugin": "bun run build:lsp-daemon && bun run build:senpi-plugin:stage",
|
|
113
|
-
"build:senpi-plugin:stage": "node packages/omo-senpi/plugin/scripts/stage-lsp-daemon-runtime.mjs && node packages/omo-senpi/plugin/scripts/build-extension.mjs && node packages/omo-senpi/plugin/scripts/sync-skills.mjs && node packages/omo-senpi/plugin/scripts/embed-directive.mjs --check && node packages/omo-senpi/plugin/scripts/build-install.mjs",
|
|
113
|
+
"build:senpi-plugin:stage": "bun run build:materialize-frontend && node packages/omo-senpi/plugin/scripts/stage-lsp-daemon-runtime.mjs && node packages/omo-senpi/plugin/scripts/build-extension.mjs && node packages/omo-senpi/plugin/scripts/sync-skills.mjs && node packages/omo-senpi/plugin/scripts/embed-directive.mjs --check && node packages/omo-senpi/plugin/scripts/build-install.mjs",
|
|
114
114
|
"build:materialize-frontend": "node packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs --strict",
|
|
115
115
|
"build:shared-skills-assets": "bun run build:materialize-frontend && rm -rf dist/skills && cp -R packages/shared-skills/skills dist/skills",
|
|
116
116
|
"build:lsp-tools-mcp": "npm --prefix packages/lsp-tools-mcp ci && npm --prefix packages/lsp-tools-mcp run build",
|
|
@@ -212,18 +212,18 @@
|
|
|
212
212
|
"typescript": "^6.0.3"
|
|
213
213
|
},
|
|
214
214
|
"optionalDependencies": {
|
|
215
|
-
"oh-my-opencode-darwin-arm64": "4.
|
|
216
|
-
"oh-my-opencode-darwin-x64": "4.
|
|
217
|
-
"oh-my-opencode-darwin-x64-baseline": "4.
|
|
218
|
-
"oh-my-opencode-linux-arm64": "4.
|
|
219
|
-
"oh-my-opencode-linux-arm64-musl": "4.
|
|
220
|
-
"oh-my-opencode-linux-x64": "4.
|
|
221
|
-
"oh-my-opencode-linux-x64-baseline": "4.
|
|
222
|
-
"oh-my-opencode-linux-x64-musl": "4.
|
|
223
|
-
"oh-my-opencode-linux-x64-musl-baseline": "4.
|
|
224
|
-
"oh-my-opencode-windows-arm64": "4.
|
|
225
|
-
"oh-my-opencode-windows-x64": "4.
|
|
226
|
-
"oh-my-opencode-windows-x64-baseline": "4.
|
|
215
|
+
"oh-my-opencode-darwin-arm64": "4.19.0",
|
|
216
|
+
"oh-my-opencode-darwin-x64": "4.19.0",
|
|
217
|
+
"oh-my-opencode-darwin-x64-baseline": "4.19.0",
|
|
218
|
+
"oh-my-opencode-linux-arm64": "4.19.0",
|
|
219
|
+
"oh-my-opencode-linux-arm64-musl": "4.19.0",
|
|
220
|
+
"oh-my-opencode-linux-x64": "4.19.0",
|
|
221
|
+
"oh-my-opencode-linux-x64-baseline": "4.19.0",
|
|
222
|
+
"oh-my-opencode-linux-x64-musl": "4.19.0",
|
|
223
|
+
"oh-my-opencode-linux-x64-musl-baseline": "4.19.0",
|
|
224
|
+
"oh-my-opencode-windows-arm64": "4.19.0",
|
|
225
|
+
"oh-my-opencode-windows-x64": "4.19.0",
|
|
226
|
+
"oh-my-opencode-windows-x64-baseline": "4.19.0"
|
|
227
227
|
},
|
|
228
228
|
"overrides": {
|
|
229
229
|
"@earendil-works/pi-agent-core": "0.80.3",
|
|
@@ -17,6 +17,9 @@ function errorResponse(id, code, message, data) {
|
|
|
17
17
|
function jsonRpcId(value) {
|
|
18
18
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
19
19
|
}
|
|
20
|
+
function messageFromError(error) {
|
|
21
|
+
return error instanceof Error ? error.message : String(error);
|
|
22
|
+
}
|
|
20
23
|
// ../mcp-stdio-core/src/transport.ts
|
|
21
24
|
var HEADER_SEPARATOR = Buffer.from(`\r
|
|
22
25
|
\r
|
|
@@ -39,16 +42,45 @@ async function* readStdioJsonRpcMessages(input) {
|
|
|
39
42
|
yield parseJsonPayload(trailing, "line");
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
|
-
function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
45
|
+
async function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
43
46
|
const body = JSON.stringify(response);
|
|
44
|
-
|
|
45
|
-
output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
47
|
+
const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
46
48
|
\r
|
|
47
|
-
${body}`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
${body}` : `${body}
|
|
50
|
+
`;
|
|
51
|
+
await writeChunk(output, payload);
|
|
52
|
+
}
|
|
53
|
+
function writeChunk(output, chunk) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
let settled = false;
|
|
56
|
+
const onError = (error) => {
|
|
57
|
+
if (settled)
|
|
58
|
+
return;
|
|
59
|
+
settled = true;
|
|
60
|
+
reject(error);
|
|
61
|
+
};
|
|
62
|
+
output.once("error", onError);
|
|
63
|
+
try {
|
|
64
|
+
output.write(chunk, (error) => {
|
|
65
|
+
if (settled)
|
|
66
|
+
return;
|
|
67
|
+
settled = true;
|
|
68
|
+
if (error) {
|
|
69
|
+
queueMicrotask(() => output.removeListener("error", onError));
|
|
70
|
+
reject(error);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
output.removeListener("error", onError);
|
|
74
|
+
resolve();
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
output.removeListener("error", onError);
|
|
78
|
+
if (settled)
|
|
79
|
+
return;
|
|
80
|
+
settled = true;
|
|
81
|
+
reject(error);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
52
84
|
}
|
|
53
85
|
function readNextMessage(buffer) {
|
|
54
86
|
if (buffer.length === 0)
|
|
@@ -144,40 +176,70 @@ async function runJsonRpcStdioServer(config) {
|
|
|
144
176
|
break;
|
|
145
177
|
idleTimer.arm();
|
|
146
178
|
if (message.kind === "parse_error") {
|
|
147
|
-
handleParseError(message, config, log)
|
|
179
|
+
if (!await handleParseError(message, config, log))
|
|
180
|
+
break;
|
|
148
181
|
continue;
|
|
149
182
|
}
|
|
150
|
-
await handleRequest(message, config, log)
|
|
183
|
+
if (!await handleRequest(message, config, log))
|
|
184
|
+
break;
|
|
151
185
|
}
|
|
152
186
|
} finally {
|
|
153
187
|
idleTimer.clear();
|
|
154
188
|
log("stdio_stopped");
|
|
155
189
|
}
|
|
156
190
|
}
|
|
157
|
-
function handleParseError(message, config, log) {
|
|
191
|
+
async function handleParseError(message, config, log) {
|
|
158
192
|
log("parse_error", { message: message.message });
|
|
159
193
|
const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
|
|
160
|
-
if (response
|
|
161
|
-
|
|
162
|
-
|
|
194
|
+
if (response === undefined)
|
|
195
|
+
return true;
|
|
196
|
+
return writeResponse(response, {
|
|
197
|
+
output: config.output,
|
|
198
|
+
responseMode: message.responseMode,
|
|
199
|
+
log
|
|
200
|
+
});
|
|
163
201
|
}
|
|
164
202
|
async function handleRequest(message, config, log) {
|
|
165
203
|
const parsed = message.payload;
|
|
166
204
|
const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
167
205
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
168
206
|
log("request", { id: id === null ? null : String(id), method });
|
|
207
|
+
let response;
|
|
169
208
|
try {
|
|
170
|
-
|
|
171
|
-
if (response === undefined)
|
|
172
|
-
return;
|
|
173
|
-
writeStdioJsonRpcResponse(config.output, response, message.responseMode);
|
|
174
|
-
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
209
|
+
response = await config.handler(parsed, config.handlerOptions);
|
|
175
210
|
} catch (error) {
|
|
176
211
|
if (config.onHandlerError === undefined)
|
|
177
212
|
throw error;
|
|
178
213
|
config.onHandlerError(error);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
if (response === undefined)
|
|
217
|
+
return true;
|
|
218
|
+
if (!await writeResponse(response, {
|
|
219
|
+
output: config.output,
|
|
220
|
+
responseMode: message.responseMode,
|
|
221
|
+
log
|
|
222
|
+
}))
|
|
223
|
+
return false;
|
|
224
|
+
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
async function writeResponse(response, context) {
|
|
228
|
+
try {
|
|
229
|
+
await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
|
|
230
|
+
return true;
|
|
231
|
+
} catch (error) {
|
|
232
|
+
if (!isTerminalOutputError(error))
|
|
233
|
+
throw error;
|
|
234
|
+
context.log("output_error", { message: messageFromError(error) });
|
|
235
|
+
return false;
|
|
179
236
|
}
|
|
180
237
|
}
|
|
238
|
+
function isTerminalOutputError(error) {
|
|
239
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
240
|
+
return false;
|
|
241
|
+
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
242
|
+
}
|
|
181
243
|
function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
182
244
|
let timer = null;
|
|
183
245
|
let isClosed = false;
|
|
@@ -148,7 +148,7 @@ describe("LspClient diagnostics freshness", () => {
|
|
|
148
148
|
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
149
149
|
diagnosticResponses: [
|
|
150
150
|
{
|
|
151
|
-
delayMs:
|
|
151
|
+
delayMs: 200,
|
|
152
152
|
report: { kind: "full", resultId: "v1", items: [diagnostic("pull-stale")] },
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -156,7 +156,7 @@ describe("LspClient diagnostics freshness", () => {
|
|
|
156
156
|
},
|
|
157
157
|
],
|
|
158
158
|
},
|
|
159
|
-
{ diagnosticsFreshnessTimeoutMs:
|
|
159
|
+
{ diagnosticsFreshnessTimeoutMs: 800, versionlessPublishQuiescenceMs: 5 },
|
|
160
160
|
);
|
|
161
161
|
await context.client.openFile(context.source);
|
|
162
162
|
|
|
@@ -209,7 +209,7 @@ describe("LspClient diagnostics freshness", () => {
|
|
|
209
209
|
capabilities: { diagnosticProvider: { interFileDependencies: false, workspaceDiagnostics: false } },
|
|
210
210
|
diagnosticResponses: [{ action: "close" }],
|
|
211
211
|
},
|
|
212
|
-
{ diagnosticsFreshnessTimeoutMs:
|
|
212
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5 },
|
|
213
213
|
);
|
|
214
214
|
await context.client.openFile(context.source);
|
|
215
215
|
|
|
@@ -229,7 +229,7 @@ describe("LspClient diagnostics freshness", () => {
|
|
|
229
229
|
],
|
|
230
230
|
diagnosticResponses: [{ error: { code: -32601, message: "Method not found" } }],
|
|
231
231
|
},
|
|
232
|
-
{ diagnosticsFreshnessTimeoutMs:
|
|
232
|
+
{ diagnosticsFreshnessTimeoutMs: 500, versionlessPublishQuiescenceMs: 5 },
|
|
233
233
|
);
|
|
234
234
|
|
|
235
235
|
const result = await context.client.diagnostics(context.source);
|
|
@@ -5,7 +5,8 @@ import { join } from "node:path";
|
|
|
5
5
|
import { describe, expect, it } from "bun:test";
|
|
6
6
|
|
|
7
7
|
import { aggregateDiagnosticsForDirectory } from "./directory-diagnostics.js";
|
|
8
|
-
import
|
|
8
|
+
import { LspClient } from "./client.js";
|
|
9
|
+
import { LspManager } from "./manager.js";
|
|
9
10
|
import type { Diagnostic, ResolvedServer } from "./types.js";
|
|
10
11
|
|
|
11
12
|
describe("directory diagnostics", () => {
|
|
@@ -94,8 +95,124 @@ describe("directory diagnostics", () => {
|
|
|
94
95
|
rmSync(workspace, { recursive: true, force: true });
|
|
95
96
|
}
|
|
96
97
|
});
|
|
98
|
+
|
|
99
|
+
it("#given cold client acquisition is pending #when directory diagnostics are aborted #then acquisition settles and cleans up before startup releases", async () => {
|
|
100
|
+
const workspace = mkdtempSync(join(tmpdir(), "lsp-directory-diag-cold-cancel-"));
|
|
101
|
+
const controller = new AbortController();
|
|
102
|
+
const startupStarted = deferred();
|
|
103
|
+
const startupRelease = deferred();
|
|
104
|
+
const server: ResolvedServer = {
|
|
105
|
+
id: "typescript",
|
|
106
|
+
command: ["typescript-language-server"],
|
|
107
|
+
extensions: [".ts"],
|
|
108
|
+
priority: 1,
|
|
109
|
+
};
|
|
110
|
+
const client = new PendingStartLspClient({
|
|
111
|
+
root: workspace,
|
|
112
|
+
server,
|
|
113
|
+
startupStarted,
|
|
114
|
+
startupRelease,
|
|
115
|
+
});
|
|
116
|
+
const manager = new LspManager({
|
|
117
|
+
clientFactory: () => client,
|
|
118
|
+
reaperIntervalMs: 60_000,
|
|
119
|
+
});
|
|
120
|
+
const aggregation = aggregateDiagnosticsForDirectory(workspace, ".ts", "all", 1, {
|
|
121
|
+
manager,
|
|
122
|
+
listFiles: () => [join(workspace, "a.ts")],
|
|
123
|
+
workspaceRoot: workspace,
|
|
124
|
+
server,
|
|
125
|
+
signal: controller.signal,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
await startupStarted.promise;
|
|
130
|
+
controller.abort();
|
|
131
|
+
|
|
132
|
+
const settledBeforeStartupRelease = await settlesWithin(aggregation, 100);
|
|
133
|
+
|
|
134
|
+
expect(settledBeforeStartupRelease).toBe(true);
|
|
135
|
+
await expect(aggregation).rejects.toHaveProperty("name", "AbortError");
|
|
136
|
+
expect(manager.clientCount()).toBe(0);
|
|
137
|
+
expect(client.stopCallCount).toBe(1);
|
|
138
|
+
} finally {
|
|
139
|
+
startupRelease.resolve();
|
|
140
|
+
await aggregation.catch(() => undefined);
|
|
141
|
+
await manager.stopAll();
|
|
142
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
143
|
+
}
|
|
144
|
+
});
|
|
97
145
|
});
|
|
98
146
|
|
|
147
|
+
class PendingStartLspClient extends LspClient {
|
|
148
|
+
stopCallCount = 0;
|
|
149
|
+
private readonly startupStarted: Deferred;
|
|
150
|
+
private readonly startupRelease: Deferred;
|
|
151
|
+
|
|
152
|
+
constructor(options: PendingStartLspClientOptions) {
|
|
153
|
+
super(options.root, options.server);
|
|
154
|
+
this.startupStarted = options.startupStarted;
|
|
155
|
+
this.startupRelease = options.startupRelease;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
override async start(): Promise<void> {
|
|
159
|
+
this.startupStarted.resolve();
|
|
160
|
+
await this.startupRelease.promise;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
override async initialize(): Promise<void> {}
|
|
164
|
+
|
|
165
|
+
override async stop(): Promise<void> {
|
|
166
|
+
this.stopCallCount += 1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
override isAlive(): boolean {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
override async diagnostics(): Promise<{ readonly items: Diagnostic[] }> {
|
|
174
|
+
return { items: [] };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface PendingStartLspClientOptions {
|
|
179
|
+
readonly root: string;
|
|
180
|
+
readonly server: ResolvedServer;
|
|
181
|
+
readonly startupStarted: Deferred;
|
|
182
|
+
readonly startupRelease: Deferred;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
interface Deferred {
|
|
186
|
+
readonly promise: Promise<void>;
|
|
187
|
+
resolve(): void;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function deferred(): Deferred {
|
|
191
|
+
let resolvePromise: (() => void) | undefined;
|
|
192
|
+
const promise = new Promise<void>((resolve) => {
|
|
193
|
+
resolvePromise = resolve;
|
|
194
|
+
});
|
|
195
|
+
return { promise, resolve: () => resolvePromise?.() };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function settlesWithin(promise: Promise<unknown>, timeoutMs: number): Promise<boolean> {
|
|
199
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
200
|
+
try {
|
|
201
|
+
return await Promise.race([
|
|
202
|
+
promise.then(
|
|
203
|
+
() => true,
|
|
204
|
+
() => true,
|
|
205
|
+
),
|
|
206
|
+
new Promise<boolean>((resolve) => {
|
|
207
|
+
timer = setTimeout(() => resolve(false), timeoutMs);
|
|
208
|
+
timer.unref();
|
|
209
|
+
}),
|
|
210
|
+
]);
|
|
211
|
+
} finally {
|
|
212
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
99
216
|
function diagnostic(message: string): Diagnostic {
|
|
100
217
|
return {
|
|
101
218
|
range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } },
|