oh-my-opencode 5.1.12 → 5.1.14

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.
Files changed (101) hide show
  1. package/dist/cli/index.js +45 -18
  2. package/dist/cli-node/index.js +45 -18
  3. package/dist/features/background-agent/fallback-provider-model-filter.d.ts +12 -0
  4. package/dist/features/background-agent/manager.d.ts +1 -0
  5. package/dist/features/background-agent/session-stopped-on-error.d.ts +9 -0
  6. package/dist/features/background-agent/types.d.ts +2 -0
  7. package/dist/index.js +173 -29
  8. package/dist/oh-my-opencode.schema.json +0 -107
  9. package/dist/shared/posthog.d.ts +1 -0
  10. package/dist/skills/browser/SKILL.md +26 -2
  11. package/dist/skills/browser/references/commands.md +10 -1
  12. package/dist/skills/browser/references/install.md +7 -0
  13. package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
  14. package/dist/skills/browser/scripts/browser-engine-guard.mjs +506 -0
  15. package/dist/skills/browser/scripts/omowright.mjs +29 -2
  16. package/dist/tui.js +16 -16
  17. package/package.json +14 -14
  18. package/packages/lsp-core/src/post-edit/not-installed.test.ts +2 -2
  19. package/packages/lsp-core/src/post-edit/orchestration.test.ts +13 -13
  20. package/packages/lsp-core/src/post-edit/orchestration.ts +9 -3
  21. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  22. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  23. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  25. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  26. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  27. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  29. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  30. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +4 -4
  31. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +33 -19
  32. package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +27 -17
  33. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  34. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  35. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +36 -18
  36. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-not-installed.test.ts +203 -0
  37. package/packages/omo-codex/plugin/components/rules/CHANGELOG.md +1 -0
  38. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  39. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +1 -1
  40. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-6.md +2 -2
  41. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  42. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  43. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  46. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  47. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  48. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  49. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  50. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  51. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +89 -28
  52. package/packages/omo-codex/plugin/components/ulw-loop/dist/registered-agent-roles.d.ts +1 -0
  53. package/packages/omo-codex/plugin/components/ulw-loop/dist/registered-agent-roles.js +61 -0
  54. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +2 -1
  55. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-role-guard.d.ts +1 -1
  56. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-role-guard.js +6 -2
  57. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  58. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  59. package/packages/omo-codex/plugin/components/ulw-loop/src/registered-agent-roles.ts +60 -0
  60. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +2 -1
  61. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-role-guard.ts +8 -2
  62. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-role-matrix.test.ts +1 -0
  63. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-role-registered.test.ts +128 -0
  64. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  71. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  72. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  73. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  74. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  75. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  76. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  77. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  78. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  79. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  80. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  81. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  82. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  83. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  84. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  85. package/packages/omo-codex/plugin/package-lock.json +12 -12
  86. package/packages/omo-codex/plugin/package.json +1 -1
  87. package/packages/omo-codex/plugin/skills/browser/SKILL.md +26 -2
  88. package/packages/omo-codex/plugin/skills/browser/references/commands.md +10 -1
  89. package/packages/omo-codex/plugin/skills/browser/references/install.md +7 -0
  90. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  91. package/packages/omo-codex/plugin/skills/browser/scripts/browser-engine-guard.mjs +506 -0
  92. package/packages/omo-codex/plugin/skills/browser/scripts/omowright.mjs +29 -2
  93. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +4 -3
  94. package/packages/omo-codex/plugin/test/aggregate.test.mjs +2 -2
  95. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
  96. package/packages/shared-skills/skills/browser/SKILL.md +26 -2
  97. package/packages/shared-skills/skills/browser/references/commands.md +10 -1
  98. package/packages/shared-skills/skills/browser/references/install.md +7 -0
  99. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  100. package/packages/shared-skills/skills/browser/scripts/browser-engine-guard.mjs +506 -0
  101. package/packages/shared-skills/skills/browser/scripts/omowright.mjs +29 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
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",
@@ -177,7 +177,7 @@
177
177
  },
178
178
  "devDependencies": {
179
179
  "@clack/prompts": "^1.8.1",
180
- "@code-yeongyu/senpi": "2026.10.2",
180
+ "@code-yeongyu/senpi": "2026.10.5",
181
181
  "@modelcontextprotocol/sdk": "^1.30.0",
182
182
  "@oh-my-opencode/agents-md-core": "workspace:*",
183
183
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
@@ -235,18 +235,18 @@
235
235
  "typescript": "^7.0.2"
236
236
  },
237
237
  "optionalDependencies": {
238
- "oh-my-opencode-darwin-arm64": "5.1.12",
239
- "oh-my-opencode-darwin-x64": "5.1.12",
240
- "oh-my-opencode-darwin-x64-baseline": "5.1.12",
241
- "oh-my-opencode-linux-arm64": "5.1.12",
242
- "oh-my-opencode-linux-arm64-musl": "5.1.12",
243
- "oh-my-opencode-linux-x64": "5.1.12",
244
- "oh-my-opencode-linux-x64-baseline": "5.1.12",
245
- "oh-my-opencode-linux-x64-musl": "5.1.12",
246
- "oh-my-opencode-linux-x64-musl-baseline": "5.1.12",
247
- "oh-my-opencode-windows-arm64": "5.1.12",
248
- "oh-my-opencode-windows-x64": "5.1.12",
249
- "oh-my-opencode-windows-x64-baseline": "5.1.12"
238
+ "oh-my-opencode-darwin-arm64": "5.1.14",
239
+ "oh-my-opencode-darwin-x64": "5.1.14",
240
+ "oh-my-opencode-darwin-x64-baseline": "5.1.14",
241
+ "oh-my-opencode-linux-arm64": "5.1.14",
242
+ "oh-my-opencode-linux-arm64-musl": "5.1.14",
243
+ "oh-my-opencode-linux-x64": "5.1.14",
244
+ "oh-my-opencode-linux-x64-baseline": "5.1.14",
245
+ "oh-my-opencode-linux-x64-musl": "5.1.14",
246
+ "oh-my-opencode-linux-x64-musl-baseline": "5.1.14",
247
+ "oh-my-opencode-windows-arm64": "5.1.14",
248
+ "oh-my-opencode-windows-x64": "5.1.14",
249
+ "oh-my-opencode-windows-x64-baseline": "5.1.14"
250
250
  },
251
251
  "overrides": {
252
252
  "hono": "^4.13.8",
@@ -152,7 +152,7 @@ describe("collectPostEditDiagnostics not-installed guidance", () => {
152
152
  locateFile: at("project"),
153
153
  });
154
154
 
155
- expect(result.blocks).toEqual([{ filePath: "src/a.ts", diagnostics: `${FULL_NUDGE} (typescript)` }]);
155
+ expect(result.blocks).toEqual([{ filePath: "src/a.ts", diagnostics: `${FULL_NUDGE} (typescript)`, blocking: false }]);
156
156
  });
157
157
 
158
158
  it("#given no decision tool #when repeated edits hit missing servers #then each server is nudged once per session", async () => {
@@ -219,6 +219,6 @@ describe("collectPostEditDiagnostics not-installed guidance", () => {
219
219
  runDiagnostics: async () => notInstalled("typescript"),
220
220
  });
221
221
 
222
- expect(result.blocks).toEqual([{ filePath: "a.ts", diagnostics: `${FULL_NUDGE} (typescript)` }]);
222
+ expect(result.blocks).toEqual([{ filePath: "a.ts", diagnostics: `${FULL_NUDGE} (typescript)`, blocking: false }]);
223
223
  });
224
224
  });
@@ -30,9 +30,9 @@ describe("collectPostEditDiagnostics", () => {
30
30
 
31
31
  expect(calls).toBe(2);
32
32
  expect(first.blocks).toEqual([
33
- { filePath: "a.foo", diagnostics: "No LSP server configured for extension: .foo\n\nordinary text from a renderer" },
33
+ { filePath: "a.foo", diagnostics: "No LSP server configured for extension: .foo\n\nordinary text from a renderer", blocking: true },
34
34
  ]);
35
- expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "diagnostic for b.foo" }]);
35
+ expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "diagnostic for b.foo", blocking: true }]);
36
36
  expect([...cache.notConfiguredExtensions]).toEqual([]);
37
37
  });
38
38
 
@@ -49,8 +49,8 @@ describe("collectPostEditDiagnostics", () => {
49
49
 
50
50
  expect(calls).toEqual(["a.ts", "b.ts", "c.ts"]);
51
51
  expect(result.blocks).toEqual([
52
- { filePath: "a.ts", diagnostics: "diagnostic for a.ts" },
53
- { filePath: "c.ts", diagnostics: "diagnostic for c.ts" },
52
+ { filePath: "a.ts", diagnostics: "diagnostic for a.ts", blocking: true },
53
+ { filePath: "c.ts", diagnostics: "diagnostic for c.ts", blocking: true },
54
54
  ]);
55
55
  });
56
56
 
@@ -72,11 +72,11 @@ describe("collectPostEditDiagnostics", () => {
72
72
 
73
73
  expect(maxActive).toBe(4);
74
74
  expect(result.blocks).toEqual([
75
- { filePath: "a.ts", diagnostics: "diagnostic for a.ts" },
76
- { filePath: "b.ts", diagnostics: "diagnostic for b.ts" },
77
- { filePath: "c.ts", diagnostics: "server exploded" },
78
- { filePath: "d.ts", diagnostics: "diagnostic for d.ts" },
79
- { filePath: "f.ts", diagnostics: "diagnostic for f.ts" },
75
+ { filePath: "a.ts", diagnostics: "diagnostic for a.ts", blocking: true },
76
+ { filePath: "b.ts", diagnostics: "diagnostic for b.ts", blocking: true },
77
+ { filePath: "c.ts", diagnostics: "server exploded", blocking: true },
78
+ { filePath: "d.ts", diagnostics: "diagnostic for d.ts", blocking: true },
79
+ { filePath: "f.ts", diagnostics: "diagnostic for f.ts", blocking: true },
80
80
  ]);
81
81
  });
82
82
 
@@ -99,7 +99,7 @@ describe("collectPostEditDiagnostics", () => {
99
99
  });
100
100
 
101
101
  expect(calls).toEqual(["a.foo", "c.bar"]);
102
- expect(first.blocks).toEqual([{ filePath: "c.bar", diagnostics: "LSP server 'bar' for .bar is NOT INSTALLED." }]);
102
+ expect(first.blocks).toEqual([{ filePath: "c.bar", diagnostics: "LSP server 'bar' for .bar is NOT INSTALLED.", blocking: true }]);
103
103
 
104
104
  const cached = await collectPostEditDiagnostics({
105
105
  filePaths: ["b.foo"],
@@ -124,7 +124,7 @@ describe("collectPostEditDiagnostics", () => {
124
124
  },
125
125
  });
126
126
 
127
- expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "diagnostic should be skipped" }]);
127
+ expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "diagnostic should be skipped", blocking: true }]);
128
128
  expect(calls).toEqual(["a.foo", "c.bar", "a.foo", "b.foo"]);
129
129
  });
130
130
 
@@ -150,8 +150,8 @@ describe("collectPostEditDiagnostics", () => {
150
150
  });
151
151
 
152
152
  expect(calls).toBe(2);
153
- expect(first.blocks).toEqual([{ filePath: "a.foo", diagnostics: "LSP server 'foo' for .foo is NOT INSTALLED." }]);
154
- expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "daemon unavailable" }]);
153
+ expect(first.blocks).toEqual([{ filePath: "a.foo", diagnostics: "LSP server 'foo' for .foo is NOT INSTALLED.", blocking: true }]);
154
+ expect(second.blocks).toEqual([{ filePath: "b.foo", diagnostics: "daemon unavailable", blocking: true }]);
155
155
  expect([...cache.notConfiguredExtensions]).toEqual([]);
156
156
  });
157
157
  });
@@ -19,6 +19,8 @@ export type DiagnosticsRunner = (filePath: string) => Promise<PostEditDiagnostic
19
19
  export interface PostEditDiagnosticsBlock {
20
20
  readonly filePath: string;
21
21
  readonly diagnostics: string;
22
+ /** False for missing-server guidance: it is feedback for the model, not a defect in the edit. */
23
+ readonly blocking: boolean;
22
24
  }
23
25
 
24
26
  export interface PostEditDiagnosticsObservation {
@@ -91,7 +93,11 @@ export async function collectPostEditDiagnostics(
91
93
  observations.push({ filePath: result.filePath, kind: "not_configured" });
92
94
  break;
93
95
  case "block":
94
- blocks.push({ filePath: result.filePath, diagnostics: classification.diagnostics });
96
+ blocks.push({ filePath: result.filePath, diagnostics: classification.diagnostics, blocking: true });
97
+ observations.push({ filePath: result.filePath, kind: "block" });
98
+ break;
99
+ case "guidance":
100
+ blocks.push({ filePath: result.filePath, diagnostics: classification.text, blocking: false });
95
101
  observations.push({ filePath: result.filePath, kind: "block" });
96
102
  break;
97
103
  default: {
@@ -166,8 +172,8 @@ function normalizeDiagnosticsOutcome(outcome: PostEditDiagnosticsOutcome): PostE
166
172
 
167
173
  function classifyNotInstalled(
168
174
  guidance: string | undefined,
169
- ): { readonly kind: "not_installed" } | { readonly kind: "block"; readonly diagnostics: string } {
170
- return guidance === undefined ? { kind: "not_installed" } : { kind: "block", diagnostics: guidance };
175
+ ): { readonly kind: "not_installed" } | { readonly kind: "guidance"; readonly text: string } {
176
+ return guidance === undefined ? { kind: "not_installed" } : { kind: "guidance", text: guidance };
171
177
  }
172
178
 
173
179
  function normalizeDiagnosticsText(text: string): string {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omo",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "description": "One Codex plugin namespace for Yeongyu's local Codex components.",
5
5
  "author": {
6
6
  "name": "Yeongyu Kim",
@@ -8,7 +8,7 @@
8
8
  "command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
9
9
  "commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 5.1.12) Checking Bootstrap Provisioning"
11
+ "statusMessage": "(OmO 5.1.14) Checking Bootstrap Provisioning"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-bootstrap",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "description": "Codex SessionStart bootstrap component that provisions LazyCodex runtime dependencies from a detached worker.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 30,
11
- "statusMessage": "(OmO 5.1.12) Checking Comments"
11
+ "statusMessage": "(OmO 5.1.14) Checking Comments"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-comment-checker",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "description": "Codex plugin that runs comment-checker after edit-like PostToolUse hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
10
10
  "timeout": 5,
11
- "statusMessage": "(OmO 5.1.12) Recommending Git Bash MCP"
11
+ "statusMessage": "(OmO 5.1.14) Recommending Git Bash MCP"
12
12
  }
13
13
  ]
14
14
  }
@@ -20,7 +20,7 @@
20
20
  "type": "command",
21
21
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
22
22
  "timeout": 5,
23
- "statusMessage": "(OmO 5.1.12) Resetting Git Bash MCP Reminder"
23
+ "statusMessage": "(OmO 5.1.14) Resetting Git Bash MCP Reminder"
24
24
  }
25
25
  ]
26
26
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-git-bash-hook",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "description": "Codex hook component that reminds Windows sessions to prefer the OMO git_bash MCP.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
10
10
  "timeout": 10,
11
- "statusMessage": "(OmO 5.1.12) Verifying LazyCodex Executor Evidence"
11
+ "statusMessage": "(OmO 5.1.14) Verifying LazyCodex Executor Evidence"
12
12
  }
13
13
  ]
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-lazycodex-executor-verify",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "description": "Codex SubagentStop evidence verifier for LazyCodex executor completions.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "5.1.12",
4
- "inputDigest": "sha256:f517d3f26ad40930383addf0f4d9fb57550a14d8564264f4d6b04c20b6057e7a",
3
+ "version": "5.1.14",
4
+ "inputDigest": "sha256:d1ee8c51725f4649bd6437bbe0a02cf6f922ce19e2229d12d02c4d3ddccdafde",
5
5
  "outputs": [
6
6
  {
7
7
  "path": "cli.d.ts",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  {
11
11
  "path": "cli.js",
12
- "sha256": "d793d83fb82b1fafe52e619f545c5195398498d1f95f15d84904fe3d0a20befe"
12
+ "sha256": "f2776c0f9c2a893136e9e8e36c2e086172f10c0ab3566a730cff4443b712f956"
13
13
  },
14
14
  {
15
15
  "path": "codex-hook-cli.d.ts",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  {
27
27
  "path": "codex-hook.js",
28
- "sha256": "9a4f53b980521752f603c9a46de8001294c1b964a31f7945eb48ecdae4bf12ac"
28
+ "sha256": "6e054189fe9efc941916d3469f1342344aadc20215c91fa6209e2f98139d6ed5"
29
29
  },
30
30
  {
31
31
  "path": "daemon-cli-path.d.ts",
@@ -5958,7 +5958,11 @@ async function collectPostEditDiagnostics(input) {
5958
5958
  observations.push({ filePath: result.filePath, kind: "not_configured" });
5959
5959
  break;
5960
5960
  case "block":
5961
- blocks.push({ filePath: result.filePath, diagnostics: classification.diagnostics });
5961
+ blocks.push({ filePath: result.filePath, diagnostics: classification.diagnostics, blocking: true });
5962
+ observations.push({ filePath: result.filePath, kind: "block" });
5963
+ break;
5964
+ case "guidance":
5965
+ blocks.push({ filePath: result.filePath, diagnostics: classification.text, blocking: false });
5962
5966
  observations.push({ filePath: result.filePath, kind: "block" });
5963
5967
  break;
5964
5968
  default: {
@@ -6020,7 +6024,7 @@ function normalizeDiagnosticsOutcome(outcome) {
6020
6024
  return outcome;
6021
6025
  }
6022
6026
  function classifyNotInstalled(guidance) {
6023
- return guidance === undefined ? { kind: "not_installed" } : { kind: "block", diagnostics: guidance };
6027
+ return guidance === undefined ? { kind: "not_installed" } : { kind: "guidance", text: guidance };
6024
6028
  }
6025
6029
  function normalizeDiagnosticsText(text) {
6026
6030
  return text.trim();
@@ -6277,22 +6281,33 @@ async function runLspDiagnosticsText(filePath) {
6277
6281
  return postEditOutcomeFromDaemonResult(result);
6278
6282
  }
6279
6283
  function postEditOutcomeFromDaemonResult(result) {
6280
- const availability = notConfiguredAvailability(result.details);
6281
- if (availability !== undefined)
6282
- return { kind: "not_configured", extension: availability.extension };
6283
- return result.content.map((block) => block.text).join(`
6284
+ const text = result.content.map((block) => block.text).join(`
6284
6285
  `);
6286
+ const availability = availabilityDetails2(result.details);
6287
+ if (availability === undefined)
6288
+ return text;
6289
+ if (availability["kind"] === "not_configured") {
6290
+ const extension = availability["extension"];
6291
+ return typeof extension === "string" && extension.length > 0 ? { kind: "not_configured", extension } : text;
6292
+ }
6293
+ if (availability["kind"] === "not_installed")
6294
+ return notInstalledOutcome(availability, text) ?? text;
6295
+ return text;
6285
6296
  }
6286
- function notConfiguredAvailability(details) {
6297
+ function availabilityDetails2(details) {
6287
6298
  if (!isRecord11(details))
6288
6299
  return;
6289
6300
  const availability = details["availability"];
6290
- if (!isRecord11(availability))
6291
- return;
6292
- if (availability["kind"] !== "not_configured")
6301
+ return isRecord11(availability) ? availability : undefined;
6302
+ }
6303
+ function notInstalledOutcome(availability, text) {
6304
+ const serverId = availability["serverId"];
6305
+ const installDecisionTool = availability["installDecisionTool"];
6306
+ if (typeof serverId !== "string" || serverId.length === 0 || typeof installDecisionTool !== "boolean")
6293
6307
  return;
6294
- const extension = availability["extension"];
6295
- return typeof extension === "string" && extension.length > 0 ? { extension } : undefined;
6308
+ const decision = availability["decision"];
6309
+ const base = { kind: "not_installed", serverId, installDecisionTool, text };
6310
+ return decision === "declined" || decision === "allowed" ? { ...base, decision } : base;
6296
6311
  }
6297
6312
  function codexLspRequestContext(env = process.env, cwd = process.cwd()) {
6298
6313
  const canonicalCwd = realpathSync7(resolve11(cwd));
@@ -6320,14 +6335,13 @@ async function runLspPostToolUseHook(input, runDiagnostics = runLspDiagnosticsTe
6320
6335
 
6321
6336
  `);
6322
6337
  const reason = limitHookText(rawReason, hookFeedbackLimit(input.transcript_path));
6323
- const output = {
6324
- decision: "block",
6325
- reason,
6326
- hookSpecificOutput: {
6327
- hookEventName: "PostToolUse",
6328
- additionalContext: reason
6329
- }
6338
+ const context = {
6339
+ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: reason }
6330
6340
  };
6341
+ if (!blocks.some((block) => block.blocking))
6342
+ return `${JSON.stringify(context)}
6343
+ `;
6344
+ const output = { decision: "block", reason, ...context };
6331
6345
  return `${JSON.stringify(output)}
6332
6346
  `;
6333
6347
  }
@@ -27,21 +27,32 @@ export async function runLspDiagnosticsText(filePath) {
27
27
  return postEditOutcomeFromDaemonResult(result);
28
28
  }
29
29
  function postEditOutcomeFromDaemonResult(result) {
30
- const availability = notConfiguredAvailability(result.details);
31
- if (availability !== undefined)
32
- return { kind: "not_configured", extension: availability.extension };
33
- return result.content.map((block) => block.text).join("\n");
30
+ const text = result.content.map((block) => block.text).join("\n");
31
+ const availability = availabilityDetails(result.details);
32
+ if (availability === undefined)
33
+ return text;
34
+ if (availability["kind"] === "not_configured") {
35
+ const extension = availability["extension"];
36
+ return typeof extension === "string" && extension.length > 0 ? { kind: "not_configured", extension } : text;
37
+ }
38
+ if (availability["kind"] === "not_installed")
39
+ return notInstalledOutcome(availability, text) ?? text;
40
+ return text;
34
41
  }
35
- function notConfiguredAvailability(details) {
42
+ function availabilityDetails(details) {
36
43
  if (!isRecord(details))
37
44
  return undefined;
38
45
  const availability = details["availability"];
39
- if (!isRecord(availability))
40
- return undefined;
41
- if (availability["kind"] !== "not_configured")
46
+ return isRecord(availability) ? availability : undefined;
47
+ }
48
+ function notInstalledOutcome(availability, text) {
49
+ const serverId = availability["serverId"];
50
+ const installDecisionTool = availability["installDecisionTool"];
51
+ if (typeof serverId !== "string" || serverId.length === 0 || typeof installDecisionTool !== "boolean")
42
52
  return undefined;
43
- const extension = availability["extension"];
44
- return typeof extension === "string" && extension.length > 0 ? { extension } : undefined;
53
+ const decision = availability["decision"];
54
+ const base = { kind: "not_installed", serverId, installDecisionTool, text };
55
+ return decision === "declined" || decision === "allowed" ? { ...base, decision } : base;
45
56
  }
46
57
  export function codexLspRequestContext(env = process.env, cwd = process.cwd()) {
47
58
  const canonicalCwd = realpathSync(resolve(cwd));
@@ -67,14 +78,13 @@ export async function runLspPostToolUseHook(input, runDiagnostics = runLspDiagno
67
78
  return "";
68
79
  const rawReason = blocks.map(formatDiagnosticBlock).join("\n\n");
69
80
  const reason = limitHookText(rawReason, hookFeedbackLimit(input.transcript_path));
70
- const output = {
71
- decision: "block",
72
- reason,
73
- hookSpecificOutput: {
74
- hookEventName: "PostToolUse",
75
- additionalContext: reason,
76
- },
81
+ const context = {
82
+ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: reason },
77
83
  };
84
+ // Missing-server guidance alone is a note for the model; only real diagnostics block the edit.
85
+ if (!blocks.some((block) => block.blocking))
86
+ return `${JSON.stringify(context)}\n`;
87
+ const output = { decision: "block", reason, ...context };
78
88
  return `${JSON.stringify(output)}\n`;
79
89
  }
80
90
  export async function runLspPostCompactHook(input) {
@@ -8,7 +8,7 @@
8
8
  "type": "command",
9
9
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
10
10
  "timeout": 60,
11
- "statusMessage": "(OmO 5.1.12) Checking LSP Diagnostics"
11
+ "statusMessage": "(OmO 5.1.14) Checking LSP Diagnostics"
12
12
  }
13
13
  ]
14
14
  }
@@ -21,7 +21,7 @@
21
21
  "type": "command",
22
22
  "command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
23
23
  "timeout": 5,
24
- "statusMessage": "(OmO 5.1.12) Resetting LSP Diagnostics Cache"
24
+ "statusMessage": "(OmO 5.1.14) Resetting LSP Diagnostics Cache"
25
25
  }
26
26
  ]
27
27
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-lsp",
3
- "version": "5.1.12",
3
+ "version": "5.1.14",
4
4
  "description": "Codex plugin that exposes Language Server Protocol tools and post-edit diagnostics.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -35,17 +35,21 @@ export interface CodexPostCompactInput {
35
35
  interface DiagnosticBlock {
36
36
  filePath: string;
37
37
  diagnostics: string;
38
+ blocking: boolean;
38
39
  }
39
40
 
40
- interface PostToolUseHookOutput {
41
- decision: "block";
42
- reason: string;
41
+ interface PostToolUseHookContext {
43
42
  hookSpecificOutput: {
44
43
  hookEventName: "PostToolUse";
45
44
  additionalContext: string;
46
45
  };
47
46
  }
48
47
 
48
+ interface PostToolUseHookOutput extends PostToolUseHookContext {
49
+ decision: "block";
50
+ reason: string;
51
+ }
52
+
49
53
  const DIAGNOSTIC_START_PATTERN = /(?:error|warning|information|hint)\[[^\]\r\n]+\] \(\d+\) at \d+:\d+:/g;
50
54
  const DIAGNOSTIC_CHUNK_PATTERN = /^(?:error|warning|information|hint)\[[^\]\r\n]+\] \(\d+\) at \d+:\d+:/;
51
55
  const DEFAULT_MAX_HOOK_FEEDBACK_CHARS = 8000;
@@ -70,18 +74,34 @@ function postEditOutcomeFromDaemonResult(result: {
70
74
  readonly content: readonly { readonly type: string; readonly text?: string }[];
71
75
  readonly details?: unknown;
72
76
  }): PostEditDiagnosticsOutcome {
73
- const availability = notConfiguredAvailability(result.details);
74
- if (availability !== undefined) return { kind: "not_configured", extension: availability.extension };
75
- return result.content.map((block) => block.text).join("\n");
77
+ const text = result.content.map((block) => block.text).join("\n");
78
+ const availability = availabilityDetails(result.details);
79
+ if (availability === undefined) return text;
80
+ if (availability["kind"] === "not_configured") {
81
+ const extension = availability["extension"];
82
+ return typeof extension === "string" && extension.length > 0 ? { kind: "not_configured", extension } : text;
83
+ }
84
+ if (availability["kind"] === "not_installed") return notInstalledOutcome(availability, text) ?? text;
85
+ return text;
76
86
  }
77
87
 
78
- function notConfiguredAvailability(details: unknown): { readonly extension: string } | undefined {
88
+ function availabilityDetails(details: unknown): Record<string, unknown> | undefined {
79
89
  if (!isRecord(details)) return undefined;
80
90
  const availability = details["availability"];
81
- if (!isRecord(availability)) return undefined;
82
- if (availability["kind"] !== "not_configured") return undefined;
83
- const extension = availability["extension"];
84
- return typeof extension === "string" && extension.length > 0 ? { extension } : undefined;
91
+ return isRecord(availability) ? availability : undefined;
92
+ }
93
+
94
+ function notInstalledOutcome(
95
+ availability: Record<string, unknown>,
96
+ text: string,
97
+ ): PostEditDiagnosticsOutcome | undefined {
98
+ const serverId = availability["serverId"];
99
+ const installDecisionTool = availability["installDecisionTool"];
100
+ if (typeof serverId !== "string" || serverId.length === 0 || typeof installDecisionTool !== "boolean")
101
+ return undefined;
102
+ const decision = availability["decision"];
103
+ const base = { kind: "not_installed", serverId, installDecisionTool, text } as const;
104
+ return decision === "declined" || decision === "allowed" ? { ...base, decision } : base;
85
105
  }
86
106
 
87
107
  export function codexLspRequestContext(
@@ -116,14 +136,12 @@ export async function runLspPostToolUseHook(
116
136
 
117
137
  const rawReason = blocks.map(formatDiagnosticBlock).join("\n\n");
118
138
  const reason = limitHookText(rawReason, hookFeedbackLimit(input.transcript_path));
119
- const output: PostToolUseHookOutput = {
120
- decision: "block",
121
- reason,
122
- hookSpecificOutput: {
123
- hookEventName: "PostToolUse",
124
- additionalContext: reason,
125
- },
139
+ const context: PostToolUseHookContext = {
140
+ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: reason },
126
141
  };
142
+ // Missing-server guidance alone is a note for the model; only real diagnostics block the edit.
143
+ if (!blocks.some((block) => block.blocking)) return `${JSON.stringify(context)}\n`;
144
+ const output: PostToolUseHookOutput = { decision: "block", reason, ...context };
127
145
  return `${JSON.stringify(output)}\n`;
128
146
  }
129
147