oh-my-opencode 4.17.1 → 4.18.1
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/SKILL.md +2 -0
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +3654 -0
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +3071 -0
- package/.agents/skills/work-with-pr/SKILL.md +16 -37
- package/.agents/skills/work-with-pr-workspace/evals/evals.json +3 -3
- package/.opencode/skills/work-with-pr/SKILL.md +16 -37
- package/.opencode/skills/work-with-pr-workspace/evals/evals.json +3 -3
- package/dist/cli/get-local-version/types.d.ts +1 -1
- package/dist/cli/index.js +498 -165
- package/dist/cli-node/index.js +498 -165
- package/dist/index.js +425 -392
- package/dist/skills/frontend/SKILL.md +1 -1
- package/dist/skills/frontend/references/design/README.md +9 -0
- package/dist/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/dist/skills/frontend/references/design/layout-skill.md +107 -0
- package/dist/skills/programming/SKILL.md +12 -2
- package/package.json +17 -16
- package/packages/lsp-core/package.json +4 -0
- package/packages/lsp-core/src/index.ts +1 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.ts +12 -3
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +261 -0
- package/packages/lsp-core/src/lsp/client-wrapper.test.ts +63 -0
- package/packages/lsp-core/src/lsp/client-wrapper.ts +35 -5
- package/packages/lsp-core/src/lsp/client.ts +262 -80
- package/packages/lsp-core/src/lsp/config-loader.ts +5 -17
- package/packages/lsp-core/src/lsp/connection.ts +12 -6
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +104 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +60 -27
- package/packages/lsp-core/src/lsp/errors.ts +11 -0
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +215 -0
- package/packages/lsp-core/src/lsp/formatters.ts +3 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection.ts +73 -5
- package/packages/lsp-core/src/lsp/server-install-state.ts +3 -6
- package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
- package/packages/lsp-core/src/lsp/transport.ts +96 -70
- package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +214 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +67 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.ts +368 -0
- package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
- package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
- package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
- package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
- package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
- package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
- package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
- package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
- package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
- package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
- package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
- package/packages/lsp-core/src/lsp/workspace-edit.ts +49 -200
- package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
- package/packages/lsp-core/src/mcp.ts +18 -7
- package/packages/lsp-core/src/missing-dependency-result.test.ts +105 -0
- package/packages/lsp-core/src/missing-dependency-result.ts +57 -0
- package/packages/lsp-core/src/post-edit/index.ts +1 -0
- package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
- package/packages/lsp-core/src/post-edit/orchestration.ts +178 -0
- package/packages/lsp-core/src/request-context.test.ts +171 -0
- package/packages/lsp-core/src/request-context.ts +222 -9
- package/packages/lsp-core/src/tool-surface.test.ts +4 -1
- package/packages/lsp-core/src/tools/diagnostics.ts +32 -13
- package/packages/lsp-core/src/tools/navigation.ts +12 -12
- package/packages/lsp-core/src/tools/rename.ts +10 -15
- package/packages/lsp-core/src/tools/symbols.ts +11 -11
- package/packages/lsp-core/src/tools/types.ts +2 -1
- package/packages/lsp-daemon/dist/cli.js +3114 -747
- package/packages/lsp-daemon/dist/client.d.ts +105 -0
- package/packages/lsp-daemon/dist/client.js +5851 -0
- package/packages/lsp-daemon/dist/daemon-client.d.ts +11 -6
- package/packages/lsp-daemon/dist/daemon-client.js +113 -30
- package/packages/lsp-daemon/dist/daemon-server.d.ts +1 -0
- package/packages/lsp-daemon/dist/daemon-server.js +40 -15
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +8 -7
- package/packages/lsp-daemon/dist/ensure-daemon.js +67 -44
- package/packages/lsp-daemon/dist/index.d.ts +2 -2
- package/packages/lsp-daemon/dist/index.js +2862 -754
- package/packages/lsp-daemon/dist/ipc-protocol.d.ts +46 -0
- package/packages/lsp-daemon/dist/ipc-protocol.js +187 -0
- package/packages/lsp-daemon/dist/lock.js +14 -4
- package/packages/lsp-daemon/dist/ownership.d.ts +49 -0
- package/packages/lsp-daemon/dist/ownership.js +168 -0
- package/packages/lsp-daemon/dist/paths.d.ts +33 -9
- package/packages/lsp-daemon/dist/paths.js +72 -33
- package/packages/lsp-daemon/dist/proxy.d.ts +3 -0
- package/packages/lsp-daemon/dist/proxy.js +54 -3
- package/packages/lsp-daemon/dist/request-routing.d.ts +7 -2
- package/packages/lsp-daemon/dist/request-routing.js +71 -22
- package/packages/lsp-daemon/dist/run-daemon.js +9 -2
- package/packages/lsp-daemon/dist/runtime-contract.d.ts +21 -0
- package/packages/lsp-daemon/dist/runtime-contract.js +58 -0
- package/packages/lsp-daemon/dist/socket-jsonrpc.js +6 -1
- package/packages/lsp-daemon/package.json +12 -3
- package/packages/lsp-tools-mcp/dist/cli.js +2115 -442
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +1741 -148
- package/packages/lsp-tools-mcp/dist/mcp.js +2127 -454
- package/packages/lsp-tools-mcp/dist/request-context.js +176 -6
- package/packages/lsp-tools-mcp/dist/tools.js +2118 -446
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -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/package.json +1 -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/dist/.omo-runtime-manifest.json +55 -0
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +2959 -944
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +0 -4
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +5 -2
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +41 -62
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +24 -15
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +3 -7
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +23 -49
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +3 -2
- package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +31 -1
- package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.test.mjs +76 -0
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +201 -0
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.test.mjs +55 -0
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +0 -4
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +49 -71
- package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +26 -15
- package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +26 -64
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +16 -17
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +30 -4
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +19 -5
- 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 +8 -6
- 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/directive.md +1 -1
- 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/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 +37 -10
- 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 +37 -10
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +37 -10
- 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/SKILL.md +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +10 -9
- 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 +26 -14
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +2 -3
- package/packages/omo-codex/plugin/scripts/build-components.mjs +13 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +9 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/layout-skill.md +107 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +12 -2
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +37 -10
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +10 -9
- package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +8 -0
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +128 -15
- package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +10 -0
- package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +351 -74
- package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/README.md +9 -0
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/packages/shared-skills/skills/frontend/references/design/layout-skill.md +107 -0
- package/packages/shared-skills/skills/programming/SKILL.md +12 -2
|
@@ -3,15 +3,10 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
import type { PostEditDiagnosticsOutcome } from "@oh-my-opencode/lsp-core/post-edit";
|
|
6
7
|
|
|
7
8
|
import { runLspPostCompactHook, runLspPostToolUseHook } from "../src/codex-hook.js";
|
|
8
9
|
|
|
9
|
-
const MARKSMAN_INITIALIZE_TIMEOUT = [
|
|
10
|
-
"LSP request timeout (method: initialize)",
|
|
11
|
-
'recent stderr: [01:16:41 INF] <LSP Entry> Starting Marksman LSP server: {"arch":"Arm64"}',
|
|
12
|
-
'[01:16:41 INF] <Folder> Loading folder documents: {"uri":"file:///repo"}',
|
|
13
|
-
].join("\n");
|
|
14
|
-
|
|
15
10
|
const DAEMON_UNREACHABLE = [
|
|
16
11
|
"LSP daemon unreachable: daemon did not become reachable.",
|
|
17
12
|
"The MCP server is a thin proxy and never runs language servers in-process.",
|
|
@@ -37,7 +32,7 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
37
32
|
// when
|
|
38
33
|
const firstOutput = await runLspPostToolUseHook(input, async () => {
|
|
39
34
|
calls += 1;
|
|
40
|
-
return
|
|
35
|
+
return markdownNotConfigured();
|
|
41
36
|
});
|
|
42
37
|
const secondOutput = await runLspPostToolUseHook(input, async () => {
|
|
43
38
|
calls += 1;
|
|
@@ -60,7 +55,7 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
60
55
|
await withPluginData(pluginData, async () => {
|
|
61
56
|
await runLspPostToolUseHook(input, async () => {
|
|
62
57
|
calls += 1;
|
|
63
|
-
return
|
|
58
|
+
return markdownNotConfigured();
|
|
64
59
|
});
|
|
65
60
|
await runLspPostToolUseHook(input, async () => {
|
|
66
61
|
calls += 1;
|
|
@@ -80,7 +75,7 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
80
75
|
const compactOutput = await runLspPostCompactHook(compactInput);
|
|
81
76
|
const afterCompactOutput = await runLspPostToolUseHook(input, async () => {
|
|
82
77
|
calls += 1;
|
|
83
|
-
return
|
|
78
|
+
return markdownNotConfigured();
|
|
84
79
|
});
|
|
85
80
|
await runLspPostToolUseHook(input, async () => {
|
|
86
81
|
calls += 1;
|
|
@@ -103,7 +98,7 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
103
98
|
await withPluginData(pluginData, async () => {
|
|
104
99
|
await runLspPostToolUseHook(input, async () => {
|
|
105
100
|
calls += 1;
|
|
106
|
-
return
|
|
101
|
+
return markdownNotConfigured();
|
|
107
102
|
});
|
|
108
103
|
await runLspPostCompactHook({ session_id: "session-compact-clean" });
|
|
109
104
|
|
|
@@ -154,11 +149,11 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
154
149
|
const input = postToolUseInput("session-daemon-down-probe", ".omo/ulw-loop/evidence/note.md");
|
|
155
150
|
let calls = 0;
|
|
156
151
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
await withPluginData(pluginData, async () => {
|
|
153
|
+
await runLspPostToolUseHook(input, async () => {
|
|
154
|
+
calls += 1;
|
|
155
|
+
return markdownNotConfigured();
|
|
156
|
+
});
|
|
162
157
|
await runLspPostToolUseHook(input, async () => {
|
|
163
158
|
calls += 1;
|
|
164
159
|
return "error[markdown] (1000) at 1:1: cached call should have been skipped.";
|
|
@@ -172,7 +167,7 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
172
167
|
});
|
|
173
168
|
const retriedProbeOutput = await runLspPostToolUseHook(input, async () => {
|
|
174
169
|
calls += 1;
|
|
175
|
-
return
|
|
170
|
+
return markdownNotConfigured();
|
|
176
171
|
});
|
|
177
172
|
await runLspPostToolUseHook(input, async () => {
|
|
178
173
|
calls += 1;
|
|
@@ -193,7 +188,7 @@ describe("codex PostToolUse unavailable LSP suppression", () => {
|
|
|
193
188
|
const typescriptInput = postToolUseInput("session-real-diagnostics", "src/broken.ts");
|
|
194
189
|
|
|
195
190
|
await withPluginData(pluginData, async () => {
|
|
196
|
-
await runLspPostToolUseHook(markdownInput, async () =>
|
|
191
|
+
await runLspPostToolUseHook(markdownInput, async () => markdownNotConfigured());
|
|
197
192
|
|
|
198
193
|
// when
|
|
199
194
|
const output = await runLspPostToolUseHook(
|
|
@@ -248,6 +243,10 @@ function tempPluginData(): string {
|
|
|
248
243
|
return dir;
|
|
249
244
|
}
|
|
250
245
|
|
|
246
|
+
function markdownNotConfigured(): PostEditDiagnosticsOutcome {
|
|
247
|
+
return { kind: "not_configured", extension: ".md" };
|
|
248
|
+
}
|
|
249
|
+
|
|
251
250
|
interface PostToolUseHookOutput {
|
|
252
251
|
readonly decision: "block";
|
|
253
252
|
readonly reason: string;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
import type { PostEditDiagnosticsOutcome } from "@oh-my-opencode/lsp-core/post-edit";
|
|
6
7
|
|
|
7
|
-
import { extractMutatedFilePaths, runLspPostToolUseHook } from "../src/codex-hook.js";
|
|
8
|
+
import { codexLspRequestContext, extractMutatedFilePaths, runLspPostToolUseHook } from "../src/codex-hook.js";
|
|
8
9
|
|
|
9
10
|
const tempDirs: string[] = [];
|
|
10
11
|
|
|
@@ -15,6 +16,21 @@ afterEach(() => {
|
|
|
15
16
|
});
|
|
16
17
|
|
|
17
18
|
describe("codex PostToolUse hook", () => {
|
|
19
|
+
it("#given CODEX_HOME #when building the daemon request context #then Codex config paths are exact and capability is enabled", () => {
|
|
20
|
+
const cwd = tempDir("codex-lsp-cwd-");
|
|
21
|
+
const codexHome = tempDir("codex-lsp-home-");
|
|
22
|
+
|
|
23
|
+
const context = codexLspRequestContext({ CODEX_HOME: codexHome }, cwd);
|
|
24
|
+
|
|
25
|
+
expect(context).toEqual({
|
|
26
|
+
cwd: realpathSync(cwd),
|
|
27
|
+
projectConfigPaths: [path.join(realpathSync(cwd), ".codex", "lsp-client.json")],
|
|
28
|
+
userConfigPath: path.join(codexHome, "lsp-client.json"),
|
|
29
|
+
installDecisionsPath: path.join(codexHome, "lsp-install-decisions.json"),
|
|
30
|
+
capabilities: { installDecisionTool: true },
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
18
34
|
it("extracts files from Codex apply_patch command payloads", () => {
|
|
19
35
|
const paths = extractMutatedFilePaths({
|
|
20
36
|
tool_name: "apply_patch",
|
|
@@ -174,7 +190,7 @@ describe("codex PostToolUse hook", () => {
|
|
|
174
190
|
return "error[typescript] (2322) at 1:7: Type 'number' is not assignable to type 'string'.";
|
|
175
191
|
}
|
|
176
192
|
if (filePath === "README.md") {
|
|
177
|
-
return
|
|
193
|
+
return markdownNotConfigured();
|
|
178
194
|
}
|
|
179
195
|
return "No diagnostics found";
|
|
180
196
|
},
|
|
@@ -286,7 +302,7 @@ describe("codex PostToolUse hook", () => {
|
|
|
286
302
|
},
|
|
287
303
|
tool_response: "Success. Updated files.",
|
|
288
304
|
},
|
|
289
|
-
async () =>
|
|
305
|
+
async () => markdownNotConfigured(),
|
|
290
306
|
);
|
|
291
307
|
|
|
292
308
|
expect(output).toBe("");
|
|
@@ -356,3 +372,13 @@ function isPostToolUseHookOutput(value: unknown): value is PostToolUseHookOutput
|
|
|
356
372
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
357
373
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
358
374
|
}
|
|
375
|
+
|
|
376
|
+
function tempDir(prefix: string): string {
|
|
377
|
+
const dir = mkdtempSync(path.join(tmpdir(), prefix));
|
|
378
|
+
tempDirs.push(dir);
|
|
379
|
+
return dir;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function markdownNotConfigured(): PostEditDiagnosticsOutcome {
|
|
383
|
+
return { kind: "not_configured", extension: ".md" };
|
|
384
|
+
}
|
|
@@ -31,11 +31,12 @@ describe("plugin package metadata", () => {
|
|
|
31
31
|
expect(packageJson.type).toBe("module");
|
|
32
32
|
expect(packageJson.packageManager).toBe("npm@11.12.1");
|
|
33
33
|
expect(packageJson.dependencies).toEqual({
|
|
34
|
+
"@oh-my-opencode/lsp-core": "file:../../../../lsp-core",
|
|
34
35
|
"@code-yeongyu/lsp-daemon": "file:../../../../lsp-daemon",
|
|
35
36
|
});
|
|
36
37
|
expect(packageJson.bin["omo-lsp"]).toBe("./dist/cli.js");
|
|
37
38
|
expect(packageJson.bin["codex-lsp"]).toBeUndefined();
|
|
38
|
-
expect(scripts["build"]).toBe("node scripts/
|
|
39
|
+
expect(scripts["build"]).toBe("node scripts/build-runtime.mjs");
|
|
39
40
|
expect(scripts["pretest"]).toBe("npm run build --silent");
|
|
40
41
|
expect(cliSource.startsWith("#!/usr/bin/env node")).toBe(true);
|
|
41
42
|
expect(cliSource).toContain("Usage: omo-lsp [mcp | hook post-tool-use | hook post-compact]");
|
|
@@ -45,15 +46,28 @@ describe("plugin package metadata", () => {
|
|
|
45
46
|
expect(lspServer?.args).toEqual(["../../../../lsp-daemon/dist/cli.js", "mcp"]);
|
|
46
47
|
expect(cliSource).not.toContain("./lazy-lsp-mcp.js");
|
|
47
48
|
expect(cliSource).toContain("resolveLspDaemonCliPath");
|
|
48
|
-
expect(daemonCliPathSource).toContain("@code-yeongyu/lsp-daemon/
|
|
49
|
+
expect(daemonCliPathSource).toContain("@code-yeongyu/lsp-daemon/cli");
|
|
49
50
|
expect(daemonCliPathSource).toContain("../../lsp-daemon/dist/cli.js");
|
|
50
|
-
expect(daemonCliPathSource).toContain("
|
|
51
|
+
expect(daemonCliPathSource).toContain("OMO_LSP_DAEMON_VERSION");
|
|
51
52
|
expect(cliSource).not.toContain("../../../../../lsp-daemon/dist/cli.js");
|
|
52
53
|
expect(codexHookSource).toContain("ensureLspDaemonCliEnv");
|
|
53
|
-
expect(codexHookCliSource).toContain("@code-yeongyu/lsp-daemon");
|
|
54
|
-
expect(codexHookSource).toContain("@code-yeongyu/lsp-daemon");
|
|
54
|
+
expect(codexHookCliSource).not.toContain("@code-yeongyu/lsp-daemon");
|
|
55
|
+
expect(codexHookSource).toContain("@code-yeongyu/lsp-daemon/client");
|
|
56
|
+
expect(codexHookSource).toContain("@oh-my-opencode/lsp-core/post-edit");
|
|
57
|
+
expect(codexHookSource).toContain("CODEX_HOME");
|
|
55
58
|
expect(codexHookCliSource).not.toContain("../../../../../lsp-daemon");
|
|
56
59
|
expect(codexHookSource).not.toContain("../../../../../lsp-daemon");
|
|
57
60
|
expect(sourceFiles.filter((name) => name.startsWith("lazy-mcp") || name === "lazy-lsp-mcp.ts")).toEqual([]);
|
|
58
61
|
});
|
|
62
|
+
|
|
63
|
+
it("#given built component CLI #when runtime imports are inspected #then it is self-contained except Node builtins", () => {
|
|
64
|
+
const cliSource = readTextFile("dist/cli.js");
|
|
65
|
+
const imports = [
|
|
66
|
+
...cliSource.matchAll(/\bimport\s+(?:[^'";]+?\s+from\s+)?["']([^"']+)["']/g),
|
|
67
|
+
...cliSource.matchAll(/\bimport\s*\(\s*["']([^"']+)["']\s*\)/g),
|
|
68
|
+
].flatMap((match) => (match[1] === undefined ? [] : [match[1]]));
|
|
69
|
+
expect(imports.filter((specifier) => !specifier.startsWith("node:"))).toEqual([]);
|
|
70
|
+
expect(cliSource).not.toContain("@code-yeongyu/lsp-daemon/client");
|
|
71
|
+
expect(cliSource).not.toContain("@oh-my-opencode/lsp-core");
|
|
72
|
+
});
|
|
59
73
|
});
|
|
@@ -74,7 +74,7 @@ Diagnostics catch type errors, not logic bugs; tests cover only what their autho
|
|
|
74
74
|
|
|
75
75
|
# Global Review and Debugging Gate
|
|
76
76
|
|
|
77
|
-
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills. For everything else, the gate above is the whole gate: once you have personally observed the artifact working, report your evidence. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
|
|
77
|
+
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills. A passing review lane binds to the exact commit SHA it reviewed: NEVER re-run a lane at a SHA where that same lane already passed this task; every lane that has not passed at the current SHA still runs. For everything else, the gate above is the whole gate: once you have personally observed the artifact working, report your evidence. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
|
|
78
78
|
|
|
79
79
|
# Failure Recovery
|
|
80
80
|
|
|
@@ -9,7 +9,7 @@ You are Hephaestus, an autonomous deep worker based on GPT-5.6. You and the user
|
|
|
9
9
|
|
|
10
10
|
User instructions override these defaults; newer instructions override older. Safety and type-safety constraints never yield.
|
|
11
11
|
|
|
12
|
-
Implement, don't propose. "How does X work?" means understand, then fix; "Why is A broken?" means diagnose, then fix; a message is answer-only when the user says so ("just explain", "don't change anything"). State your read in one line before acting: "I detect [intent type] - [reason]. [What I'm doing now]." That line commits you to finish the named work this turn.
|
|
12
|
+
Implement, don't propose. "How does X work?" means understand, then fix; "Why is A broken?" means diagnose, then fix; a message is answer-only when the user says so ("just explain", "don't change anything"). State your read in one line before acting: "I detect [intent type] - [reason]. [What I'm doing now]. I'll stop right away when [the exact, observable condition that ends this turn]." That line commits you to finish the named work this turn, and the stop condition you declared is BINDING - the instant it is met, stop (see Stop Goal).
|
|
13
13
|
|
|
14
14
|
Requests to answer, review, diagnose, or plan: inspect and report. Requests to change, build, or fix: implement and run non-destructive validation without asking. Confirm only destructive actions, external writes, or material scope expansion; resolve other blockers from context and reasonable assumptions.
|
|
15
15
|
|
|
@@ -29,13 +29,15 @@ Implement surgically, matching codebase style (naming, indentation, imports, err
|
|
|
29
29
|
|
|
30
30
|
# Subagents
|
|
31
31
|
|
|
32
|
-
Read-only Codex subagent roles live in `CODEX_HOME/agents/`. Spawn: `multi_agent_v1.spawn_agent({"message":"TASK: act as a <role>. ...","fork_context":false})`. If your tool list instead has a flat `spawn_agent` with a required `task_name` (`multi_agent_v2`): `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":"TASK: act as a <role>. ...","fork_turns":"none"})` - finished agents end on their own; `wait_agent` takes only `timeout_ms`.
|
|
32
|
+
Read-only Codex subagent roles live in `CODEX_HOME/agents/`. Spawn: `multi_agent_v1.spawn_agent({"message":"TASK: act as a <role>. GOAL: ... STOP WHEN: ... EVIDENCE: ...","fork_context":false})`. If your tool list instead has a flat `spawn_agent` with a required `task_name` (`multi_agent_v2`): `spawn_agent({"task_name":"<lowercase_digits_underscores>","message":"TASK: act as a <role>. GOAL: ... STOP WHEN: ... EVIDENCE: ...","fork_turns":"none"})` - finished agents end on their own; `wait_agent` takes only `timeout_ms`.
|
|
33
33
|
|
|
34
34
|
- `explorer` - codebase search
|
|
35
35
|
- `librarian` - external docs, OSS code, API contracts
|
|
36
36
|
- `plan` - planning when design is still open after discovery; never for a known checklist or for work being delegated onward
|
|
37
37
|
- `lazycodex-gate-reviewer` - final verification of a finished change
|
|
38
38
|
|
|
39
|
+
Every spawn message MUST fill all three labels - **GOAL** (the one outcome that makes the child done), **STOP WHEN** (the exact, observable condition that ends its run; the child stops the moment it holds, exactly like your own intent line), **EVIDENCE** (what the child returns so you can SEE, not trust, that the condition held). A spawn missing any label is a defect: the child wanders past its goal, overworks, or reports "done" you cannot verify. Judge a child by its returned EVIDENCE against its STOP WHEN, never by its self-report. Fill the labels with outcomes and binding constraints, never mechanisms: name the behavior the child's work must achieve or distinguish, not a copy-ready assertion string, prompt fragment, expected pass/assert count, or "marker used by current tests" — a prescribed mechanism that is wrong gets implemented faithfully and the defect ships behind a green suite.
|
|
40
|
+
|
|
39
41
|
Spawn in parallel for independent investigations; do non-overlapping prep while they run, integrate on return. Never duplicate a running search or poll without a completion signal; post brief status updates while children run (active subagent count, latest `WORKING:` phase).
|
|
40
42
|
|
|
41
43
|
# Manual QA Gate
|
|
@@ -50,7 +52,7 @@ Diagnostics catch type errors, not logic bugs; tests cover only what their autho
|
|
|
50
52
|
|
|
51
53
|
"This should work" from reading source does not pass. A defect found in usage is yours to fix this turn.
|
|
52
54
|
|
|
53
|
-
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills. For everything else, the gate above is the whole gate: once you have personally observed the artifact working, report your evidence. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
|
|
55
|
+
Run `review-work` plus a `debugging` runtime audit only before a PR handoff or when the user asks for a review; lane pass/fail semantics live in those skills. A passing review lane binds to the exact commit SHA it reviewed: NEVER re-run a lane at a SHA where that same lane already passed this task; every lane that has not passed at the current SHA still runs. For everything else, the gate above is the whole gate: once you have personally observed the artifact working, report your evidence. Redact secrets, tokens, and PII from ledgers, PR bodies, and handoffs.
|
|
54
56
|
|
|
55
57
|
# Failure Recovery
|
|
56
58
|
|
|
@@ -68,16 +70,16 @@ On a multi-step task, open with one or two visible sentences naming the first st
|
|
|
68
70
|
|
|
69
71
|
Final message: lead with the result, group by outcome, no conversational openers. Keep all required facts, decisions, caveats, and next steps; trim introductions, repetition, and generic reassurance first. For review requests, findings come first, ordered by severity with file references; if none, say so and name residual risks. No emojis or em dashes unless requested. Never output broken inline citations like `【F:README.md†L5-L14】` - they break the CLI.
|
|
70
72
|
|
|
71
|
-
#
|
|
73
|
+
# Stop Goal
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
Your STOP GOAL — the turn is over the moment ALL of these hold:
|
|
74
76
|
|
|
75
77
|
- Every requested behavior implemented - no partial delivery.
|
|
76
78
|
- Diagnostics clean on changed files; build exits 0; tests pass or pre-existing failures are named.
|
|
77
79
|
- The artifact passed the Manual QA Gate this turn.
|
|
78
80
|
- The final message reports what you did, verified, could not verify (and why), and pre-existing issues left alone.
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
Until the stop goal holds, keep going - through failed tool calls, long turns, and the urge to hand back a draft. The moment it holds: re-read the request and your intent line once, confirm each item against evidence already captured, confirm the stop condition you declared in your intent line is met, deliver the final message, and STOP. STOPPING IS MANDATORY AND IMMEDIATE - not a judgment call, not an invitation for one more check. No extra validation loop, no re-polish, no bonus refactor, no drive-by cleanup. Every action past the stop goal is a defect, not diligence.
|
|
81
83
|
|
|
82
84
|
Hard invariants, regardless of pressure to ship:
|
|
83
85
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 4.
|
|
10
|
+
"statusMessage": "(OmO 4.18.1) Loading Project Rules"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "command",
|
|
20
20
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
|
|
21
21
|
"timeout": 10,
|
|
22
|
-
"statusMessage": "(OmO 4.
|
|
22
|
+
"statusMessage": "(OmO 4.18.1) Loading Project Rules"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"type": "command",
|
|
33
33
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
|
|
34
34
|
"timeout": 10,
|
|
35
|
-
"statusMessage": "(OmO 4.
|
|
35
|
+
"statusMessage": "(OmO 4.18.1) Matching Project Rules"
|
|
36
36
|
}
|
|
37
37
|
]
|
|
38
38
|
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"type": "command",
|
|
46
46
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
|
|
47
47
|
"timeout": 10,
|
|
48
|
-
"statusMessage": "(OmO 4.
|
|
48
|
+
"statusMessage": "(OmO 4.18.1) Resetting Project Rule Cache"
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
}
|
|
@@ -40,7 +40,7 @@ You are mid-flight on a Prometheus work plan; this turn is an automatic continua
|
|
|
40
40
|
|
|
41
41
|
# Final gate
|
|
42
42
|
|
|
43
|
-
Before completion, run `review-work` and a `debugging` runtime audit; inconclusive lanes fail. Do not create a PR, PR handoff, branch handoff, merge, or final completion answer until this gate passes. For PR/branch work, stay in the task-owned worktree: create/update the PR, wait for CI/review/Cubic gates, merge by default unless explicitly opted out, then clean up. Redact secrets, tokens, credentials, auth headers, cookies, env dumps, logs, and PII.
|
|
43
|
+
Before completion, run `review-work` and a `debugging` runtime audit; inconclusive lanes fail. The gate's pass binds to the commit SHA it reviewed — never re-run it on an already-passed SHA; re-run only when new commits land. Do not create a PR, PR handoff, branch handoff, merge, or final completion answer until this gate passes. For PR/branch work, stay in the task-owned worktree: create/update the PR, wait for CI/review/Cubic gates, merge by default unless explicitly opted out, then clean up. Redact secrets, tokens, credentials, auth headers, cookies, env dumps, logs, and PII.
|
|
44
44
|
|
|
45
45
|
# Stop conditions for THIS turn
|
|
46
46
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook stop",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 4.
|
|
10
|
+
"statusMessage": "(OmO 4.18.1) Checking Start-Work Continuation"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "command",
|
|
20
20
|
"command": "node \"${PLUGIN_ROOT}/components/start-work-continuation/dist/cli.js\" hook subagent-stop",
|
|
21
21
|
"timeout": 10,
|
|
22
|
-
"statusMessage": "(OmO 4.
|
|
22
|
+
"statusMessage": "(OmO 4.18.1) Checking Start-Work Continuation"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -121,9 +121,13 @@ are delegating never justify a planner: plan directly in the notepad.
|
|
|
121
121
|
Never spawn `plan` before the discovery wave has returned.
|
|
122
122
|
|
|
123
123
|
## 1. Create the goal with binding success criteria
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
You MUST register the goal with the `create_goal` tool — NOT prose,
|
|
125
|
+
NOT the notepad, NOT the plan: the registered goal is the binding
|
|
126
|
+
contract for the whole run, and skipping it is a defect. Call it with
|
|
127
|
+
exactly `objective`; do not include `status`. Only when no goal tool
|
|
128
|
+
exists on this surface, open your reply with a `# Goal` block treated
|
|
129
|
+
as binding. Goals are unlimited; never invent a numeric budget or
|
|
130
|
+
limit.
|
|
127
131
|
The criteria MUST list, upfront:
|
|
128
132
|
- The user-visible deliverable in one line, and the tier with its
|
|
129
133
|
justification.
|
|
@@ -136,6 +140,9 @@ The criteria MUST list, upfront:
|
|
|
136
140
|
- For each criterion, the failing-first proof (test id or scenario)
|
|
137
141
|
that will be captured RED BEFORE the implementation and GREEN after.
|
|
138
142
|
Evidence added after the green code does NOT satisfy this.
|
|
143
|
+
- WHEN TO STOP, in one line: "I'll stop right away when <the exact
|
|
144
|
+
observable state that ends this run>". The Stop rules bind to this
|
|
145
|
+
line — the moment it holds, you stop.
|
|
139
146
|
|
|
140
147
|
These scenarios are the contract. You are not done until every one of
|
|
141
148
|
them PASSES with its evidence captured.
|
|
@@ -236,6 +243,18 @@ Until every success criterion PASSES with its evidence captured:
|
|
|
236
243
|
scenario captured failing when no test seam exists. It must fail
|
|
237
244
|
for the RIGHT reason (not a syntax error, not a missing import).
|
|
238
245
|
Paste RED output into the notepad. No production code yet.
|
|
246
|
+
TEST-ONLY TARGET (regression coverage for behavior that is already
|
|
247
|
+
correct): there is no natural RED and no production change to make
|
|
248
|
+
— this is the sole exception to the production-RED/GREEN steps.
|
|
249
|
+
Substitute a mutation proof: temporarily force the exact regression
|
|
250
|
+
each new assertion names (revert the fix commit or break the seam,
|
|
251
|
+
never committed), capture the assertion failing, then revert the
|
|
252
|
+
mutation and capture GREEN. An assertion that stays green under its
|
|
253
|
+
mutation is not coverage — fix the fixture (a value equal to the
|
|
254
|
+
default it must override proves nothing) or assert the artifact the
|
|
255
|
+
criterion names, never an expected value re-derived from the output
|
|
256
|
+
under test. Reverting the probe IS the GREEN; skip step 3's
|
|
257
|
+
production change for a TEST-ONLY task and go to step 4.
|
|
239
258
|
PROSE TARGET (prompt, SKILL.md, rule, markdown): the wording is
|
|
240
259
|
NOT the behavior — never pin sentences, phrase presence/absence,
|
|
241
260
|
or word/char counts. PIN only a machine-consumed value (parsed
|
|
@@ -244,7 +263,8 @@ Until every success criterion PASSES with its evidence captured:
|
|
|
244
263
|
two shipped copies. A pure-prose change with no machine consumer
|
|
245
264
|
has NO seam: ship it on review + QA-by-read, NO test — a text grep
|
|
246
265
|
is pretend-coverage, not RED proof.
|
|
247
|
-
3. GREEN
|
|
266
|
+
3. GREEN (skip for TEST-ONLY — reverting the mutation is GREEN): write
|
|
267
|
+
the SMALLEST production change that flips RED→GREEN.
|
|
248
268
|
Before GREEN work that depends on external review, PR, issue, or
|
|
249
269
|
branch state, refresh current branch/PR/issue state and preserve existing ordering/policy;
|
|
250
270
|
separate compatibility detection from policy changes unless the goal
|
|
@@ -382,10 +402,11 @@ message + present for approval.
|
|
|
382
402
|
revert, capture the proof failing, then redo the change. Exempt
|
|
383
403
|
only: pure formatting, comment-only edits, dependency bumps with no
|
|
384
404
|
behavior delta, rename-only moves — justify each in `## Findings`.
|
|
385
|
-
- A test that
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
405
|
+
- A test that cannot fail for the regression it names is NOT
|
|
406
|
+
evidence: mock-call assertions, pinned constants, a fixture equal
|
|
407
|
+
to the default it must override, an expected value re-derived from
|
|
408
|
+
the output under test. Prefer a real-surface proof with no new
|
|
409
|
+
test over a tautological one.
|
|
389
410
|
- Refactors: characterization tests pinning current observable
|
|
390
411
|
behavior FIRST, green against the old code, green throughout.
|
|
391
412
|
- Smallest correct change. No drive-by refactors.
|
|
@@ -407,9 +428,15 @@ message + present for approval.
|
|
|
407
428
|
- After each result, ask whether the user's core request can now be
|
|
408
429
|
answered with useful evidence in hand. If yes, answer now — skip any
|
|
409
430
|
remaining retrieval, ceremony, or verification that adds no evidence.
|
|
410
|
-
-
|
|
431
|
+
- The STOP GOAL: every scenario PASSES with captured evidence, every
|
|
411
432
|
cleanup receipt is recorded, notepad is current, and (if gate
|
|
412
|
-
triggered) reviewer approved unconditionally.
|
|
433
|
+
triggered) reviewer approved unconditionally. Above ALL of that, the
|
|
434
|
+
decisive test — outranking every other consideration — is: are the
|
|
435
|
+
completion conditions FUNDAMENTALLY fulfilled, is the user's problem
|
|
436
|
+
ACTUALLY SOLVED in observable behavior? If no, you are NOT done,
|
|
437
|
+
whatever the ledger says. If yes, deliver the final message and STOP
|
|
438
|
+
— no hesitation, no extra verification pass, no polish loop. Work
|
|
439
|
+
past the stop goal is scope creep, not diligence.
|
|
413
440
|
- Leftover QA state (live process, `tmux` session, browser context,
|
|
414
441
|
bound port, temp file / dir) means NOT done. Tear it down, record
|
|
415
442
|
the receipt, then continue.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-ultrawork",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.18.1",
|
|
4
4
|
"description": "Codex plugin that injects the ultrawork orchestration directive and ships LazyCodex planning, review, QA, and gate agent roles.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
|
@@ -128,9 +128,13 @@ are delegating never justify a planner: plan directly in the notepad.
|
|
|
128
128
|
Never spawn `plan` before the discovery wave has returned.
|
|
129
129
|
|
|
130
130
|
## 1. Create the goal with binding success criteria
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
You MUST register the goal with the `create_goal` tool — NOT prose,
|
|
132
|
+
NOT the notepad, NOT the plan: the registered goal is the binding
|
|
133
|
+
contract for the whole run, and skipping it is a defect. Call it with
|
|
134
|
+
exactly `objective`; do not include `status`. Only when no goal tool
|
|
135
|
+
exists on this surface, open your reply with a `# Goal` block treated
|
|
136
|
+
as binding. Goals are unlimited; never invent a numeric budget or
|
|
137
|
+
limit.
|
|
134
138
|
The criteria MUST list, upfront:
|
|
135
139
|
- The user-visible deliverable in one line, and the tier with its
|
|
136
140
|
justification.
|
|
@@ -143,6 +147,9 @@ The criteria MUST list, upfront:
|
|
|
143
147
|
- For each criterion, the failing-first proof (test id or scenario)
|
|
144
148
|
that will be captured RED BEFORE the implementation and GREEN after.
|
|
145
149
|
Evidence added after the green code does NOT satisfy this.
|
|
150
|
+
- WHEN TO STOP, in one line: "I'll stop right away when <the exact
|
|
151
|
+
observable state that ends this run>". The Stop rules bind to this
|
|
152
|
+
line — the moment it holds, you stop.
|
|
146
153
|
|
|
147
154
|
These scenarios are the contract. You are not done until every one of
|
|
148
155
|
them PASSES with its evidence captured.
|
|
@@ -243,6 +250,18 @@ Until every success criterion PASSES with its evidence captured:
|
|
|
243
250
|
scenario captured failing when no test seam exists. It must fail
|
|
244
251
|
for the RIGHT reason (not a syntax error, not a missing import).
|
|
245
252
|
Paste RED output into the notepad. No production code yet.
|
|
253
|
+
TEST-ONLY TARGET (regression coverage for behavior that is already
|
|
254
|
+
correct): there is no natural RED and no production change to make
|
|
255
|
+
— this is the sole exception to the production-RED/GREEN steps.
|
|
256
|
+
Substitute a mutation proof: temporarily force the exact regression
|
|
257
|
+
each new assertion names (revert the fix commit or break the seam,
|
|
258
|
+
never committed), capture the assertion failing, then revert the
|
|
259
|
+
mutation and capture GREEN. An assertion that stays green under its
|
|
260
|
+
mutation is not coverage — fix the fixture (a value equal to the
|
|
261
|
+
default it must override proves nothing) or assert the artifact the
|
|
262
|
+
criterion names, never an expected value re-derived from the output
|
|
263
|
+
under test. Reverting the probe IS the GREEN; skip step 3's
|
|
264
|
+
production change for a TEST-ONLY task and go to step 4.
|
|
246
265
|
PROSE TARGET (prompt, SKILL.md, rule, markdown): the wording is
|
|
247
266
|
NOT the behavior — never pin sentences, phrase presence/absence,
|
|
248
267
|
or word/char counts. PIN only a machine-consumed value (parsed
|
|
@@ -251,7 +270,8 @@ Until every success criterion PASSES with its evidence captured:
|
|
|
251
270
|
two shipped copies. A pure-prose change with no machine consumer
|
|
252
271
|
has NO seam: ship it on review + QA-by-read, NO test — a text grep
|
|
253
272
|
is pretend-coverage, not RED proof.
|
|
254
|
-
3. GREEN
|
|
273
|
+
3. GREEN (skip for TEST-ONLY — reverting the mutation is GREEN): write
|
|
274
|
+
the SMALLEST production change that flips RED→GREEN.
|
|
255
275
|
Before GREEN work that depends on external review, PR, issue, or
|
|
256
276
|
branch state, refresh current branch/PR/issue state and preserve existing ordering/policy;
|
|
257
277
|
separate compatibility detection from policy changes unless the goal
|
|
@@ -389,10 +409,11 @@ message + present for approval.
|
|
|
389
409
|
revert, capture the proof failing, then redo the change. Exempt
|
|
390
410
|
only: pure formatting, comment-only edits, dependency bumps with no
|
|
391
411
|
behavior delta, rename-only moves — justify each in `## Findings`.
|
|
392
|
-
- A test that
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
412
|
+
- A test that cannot fail for the regression it names is NOT
|
|
413
|
+
evidence: mock-call assertions, pinned constants, a fixture equal
|
|
414
|
+
to the default it must override, an expected value re-derived from
|
|
415
|
+
the output under test. Prefer a real-surface proof with no new
|
|
416
|
+
test over a tautological one.
|
|
396
417
|
- Refactors: characterization tests pinning current observable
|
|
397
418
|
behavior FIRST, green against the old code, green throughout.
|
|
398
419
|
- Smallest correct change. No drive-by refactors.
|
|
@@ -414,9 +435,15 @@ message + present for approval.
|
|
|
414
435
|
- After each result, ask whether the user's core request can now be
|
|
415
436
|
answered with useful evidence in hand. If yes, answer now — skip any
|
|
416
437
|
remaining retrieval, ceremony, or verification that adds no evidence.
|
|
417
|
-
-
|
|
438
|
+
- The STOP GOAL: every scenario PASSES with captured evidence, every
|
|
418
439
|
cleanup receipt is recorded, notepad is current, and (if gate
|
|
419
|
-
triggered) reviewer approved unconditionally.
|
|
440
|
+
triggered) reviewer approved unconditionally. Above ALL of that, the
|
|
441
|
+
decisive test — outranking every other consideration — is: are the
|
|
442
|
+
completion conditions FUNDAMENTALLY fulfilled, is the user's problem
|
|
443
|
+
ACTUALLY SOLVED in observable behavior? If no, you are NOT done,
|
|
444
|
+
whatever the ledger says. If yes, deliver the final message and STOP
|
|
445
|
+
— no hesitation, no extra verification pass, no polish loop. Work
|
|
446
|
+
past the stop goal is scope creep, not diligence.
|
|
420
447
|
- Leftover QA state (live process, `tmux` session, browser context,
|
|
421
448
|
bound port, temp file / dir) means NOT done. Tear it down, record
|
|
422
449
|
the receipt, then continue.
|