oh-my-opencode 4.11.0 → 4.12.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.
Files changed (177) hide show
  1. package/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
  2. package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
  3. package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
  4. package/.agents/skills/work-with-pr/SKILL.md +19 -5
  5. package/.opencode/skills/work-with-pr/SKILL.md +19 -5
  6. package/dist/agents/atlas/agent.d.ts +3 -2
  7. package/dist/agents/sisyphus/glm-5-2.d.ts +4 -0
  8. package/dist/agents/sisyphus/index.d.ts +1 -0
  9. package/dist/agents/sisyphus-agent-config.d.ts +1 -0
  10. package/dist/agents/sisyphus-junior/agent.d.ts +1 -1
  11. package/dist/agents/sisyphus-junior/glm-5-2.d.ts +1 -0
  12. package/dist/agents/sisyphus-junior/index.d.ts +1 -0
  13. package/dist/agents/types.d.ts +7 -6
  14. package/dist/cli/index.js +449 -318
  15. package/dist/cli-node/index.js +449 -318
  16. package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
  17. package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
  18. package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
  19. package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
  20. package/dist/hooks/keyword-detector/ultrawork/glm.d.ts +2 -0
  21. package/dist/hooks/keyword-detector/ultrawork/index.d.ts +4 -2
  22. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +5 -4
  23. package/dist/index.js +1185 -87
  24. package/dist/plugin/tool-execute-before.d.ts +2 -0
  25. package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
  26. package/dist/skills/init-deep/SKILL.md +21 -26
  27. package/dist/skills/programming/SKILL.md +25 -121
  28. package/dist/skills/programming/references/code-smells.md +390 -0
  29. package/dist/skills/ulw-plan/SKILL.md +2 -1
  30. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  31. package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
  32. package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
  33. package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
  34. package/dist/tui.js +16 -7
  35. package/package.json +13 -13
  36. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +22 -2
  37. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +51 -21
  38. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  39. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +18 -7
  41. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +9 -2
  42. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  43. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +8 -7
  44. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +7 -2
  45. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +2 -1
  46. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +20 -19
  47. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
  48. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
  49. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  50. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  51. package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
  52. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  53. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  54. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  55. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  56. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  57. package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
  58. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
  59. package/packages/omo-codex/plugin/components/rules/dist/cli.js +2 -2
  60. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  61. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +2 -2
  63. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +12 -92
  64. package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +3 -0
  65. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
  66. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  67. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -2
  68. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
  69. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
  70. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
  71. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
  72. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
  73. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
  74. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
  75. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  76. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  77. package/packages/omo-codex/plugin/components/test-support/package-smoke-fixture.ts +158 -0
  78. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  79. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  80. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
  81. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
  82. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  83. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
  84. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
  85. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  86. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  87. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
  88. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
  89. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
  90. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
  91. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
  92. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
  93. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
  94. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
  95. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
  96. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
  97. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
  98. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
  99. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
  100. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
  101. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
  102. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
  103. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
  104. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
  105. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
  106. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
  107. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
  108. package/packages/omo-codex/plugin/package-lock.json +12 -22
  109. package/packages/omo-codex/plugin/package.json +1 -1
  110. package/packages/omo-codex/plugin/scripts/auto-update.mjs +1 -1
  111. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +14 -11
  112. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
  113. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
  114. package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
  115. package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
  116. package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
  117. package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
  118. package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
  119. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +21 -26
  120. package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
  121. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  122. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
  123. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  124. package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
  125. package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
  126. package/packages/omo-codex/plugin/skills/programming/SKILL.md +25 -121
  127. package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
  128. package/packages/omo-codex/plugin/skills/programming/references/code-smells.md +390 -0
  129. package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
  130. package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
  131. package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
  132. package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
  133. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
  134. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
  135. package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
  136. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
  137. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
  138. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
  139. package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
  140. package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
  141. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
  142. package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
  143. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  144. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
  145. package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
  146. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +34 -33
  147. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +5 -2
  148. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +13 -0
  149. package/packages/omo-codex/plugin/test/auto-update.test.mjs +1 -1
  150. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
  151. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
  152. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
  153. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +31 -0
  154. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +3 -3
  155. package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
  156. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +30 -19
  157. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
  158. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
  159. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
  160. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
  161. package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
  162. package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
  163. package/packages/omo-codex/scripts/install-dist/install-local.mjs +412 -216
  164. package/packages/omo-codex/scripts/install-git-bash-mcp-env.test.mjs +24 -0
  165. package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
  166. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
  167. package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
  168. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
  169. package/packages/omo-codex/scripts/install-local.mjs +1 -0
  170. package/packages/omo-codex/scripts/install-mcp-runtime.test.mjs +36 -0
  171. package/packages/shared-skills/skills/init-deep/SKILL.md +21 -26
  172. package/packages/shared-skills/skills/programming/SKILL.md +25 -121
  173. package/packages/shared-skills/skills/programming/references/code-smells.md +390 -0
  174. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
  175. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  176. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
  177. package/packages/omo-codex/plugin/hooks/hooks.json +0 -214
@@ -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": "LazyCodex(4.11.0): Recommending Git Bash MCP"
11
+ "statusMessage": "(OmO) 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": "LazyCodex(4.11.0): Resetting Git Bash MCP Reminder"
23
+ "statusMessage": "(OmO) 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": "4.11.0",
3
+ "version": "4.12.0",
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": "LazyCodex(4.11.0): Verifying LazyCodex Executor Evidence"
11
+ "statusMessage": "(OmO) 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": "4.11.0",
3
+ "version": "4.12.0",
4
4
  "description": "Codex SubagentStop evidence verifier for LazyCodex executor completions.",
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 post-tool-use",
10
10
  "timeout": 60,
11
- "statusMessage": "LazyCodex(4.11.0): Checking LSP Diagnostics"
11
+ "statusMessage": "(OmO) 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": "LazyCodex(4.11.0): Resetting LSP Diagnostics Cache"
24
+ "statusMessage": "(OmO) 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": "4.11.0",
3
+ "version": "4.12.0",
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",
@@ -39,7 +39,7 @@
39
39
  "bootstrap": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
40
40
  "prebuild": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
41
41
  "build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
42
- "pretest": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
42
+ "pretest": "npm run build --silent",
43
43
  "test": "node scripts/test.mjs",
44
44
  "test:watch": "vitest",
45
45
  "pretypecheck": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
@@ -1,53 +1,12 @@
1
- import { readdirSync, readFileSync } from "node:fs";
2
1
  import { describe, expect, it } from "vitest";
3
-
4
- type PackageJson = {
5
- readonly version: string;
6
- readonly type: string;
7
- readonly packageManager: string;
8
- readonly bin: Record<string, string>;
9
- readonly dependencies: Record<string, string>;
10
- readonly scripts: Record<string, string>;
11
- };
12
-
13
- type HookCommand = {
14
- readonly command: string;
15
- };
16
-
17
- type HookEntry = {
18
- readonly hooks: readonly HookCommand[];
19
- };
20
-
21
- type HooksJson = {
22
- readonly hooks: Record<string, readonly HookEntry[]>;
23
- };
24
-
25
- type McpServer = {
26
- readonly command: string;
27
- readonly args: readonly string[];
28
- };
29
-
30
- type McpJson = {
31
- readonly mcpServers: Record<string, McpServer>;
32
- };
33
-
34
- function readPackageJson(path: string): PackageJson {
35
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
36
- if (!isPackageJson(parsed)) throw new TypeError(`Invalid package metadata: ${path}`);
37
- return parsed;
38
- }
39
-
40
- function readHooksJson(path: string): HooksJson {
41
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
42
- if (!isHooksJson(parsed)) throw new TypeError(`Invalid hooks metadata: ${path}`);
43
- return parsed;
44
- }
45
-
46
- function readMcpJson(path: string): McpJson {
47
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
48
- if (!isMcpJson(parsed)) throw new TypeError(`Invalid MCP metadata: ${path}`);
49
- return parsed;
50
- }
2
+ import {
3
+ listDirectoryEntries,
4
+ readHooksJson,
5
+ readMcpJson,
6
+ readPackageJson,
7
+ readTextFile,
8
+ requireScripts,
9
+ } from "../../test-support/package-smoke-fixture.js";
51
10
 
52
11
  describe("plugin package metadata", () => {
53
12
  it("#given packaged component files #when validating entrypoints #then hook command stays local and MCP command references the package", () => {
@@ -55,10 +14,11 @@ describe("plugin package metadata", () => {
55
14
  const packageJson = readPackageJson("package.json");
56
15
  const hooksJson = readHooksJson("hooks/hooks.json");
57
16
  const mcpJson = readMcpJson(".mcp.json");
58
- const cliSource = readFileSync("src/cli.ts", "utf8");
59
- const codexHookCliSource = readFileSync("src/codex-hook-cli.ts", "utf8");
60
- const codexHookSource = readFileSync("src/codex-hook.ts", "utf8");
61
- const sourceFiles = readdirSync("src");
17
+ const cliSource = readTextFile("src/cli.ts");
18
+ const codexHookCliSource = readTextFile("src/codex-hook-cli.ts");
19
+ const codexHookSource = readTextFile("src/codex-hook.ts");
20
+ const sourceFiles = listDirectoryEntries("src");
21
+ const scripts = requireScripts(packageJson, "package.json");
62
22
 
63
23
  // when
64
24
  const postToolUseCommand = hooksJson.hooks["PostToolUse"]?.[0]?.hooks[0]?.command;
@@ -74,7 +34,8 @@ describe("plugin package metadata", () => {
74
34
  });
75
35
  expect(packageJson.bin["omo-lsp"]).toBe("./dist/cli.js");
76
36
  expect(packageJson.bin["codex-lsp"]).toBeUndefined();
77
- expect(packageJson.scripts["build"]).toBe("node scripts/clean-dist.mjs && tsc -p tsconfig.build.json");
37
+ expect(scripts["build"]).toBe("node scripts/clean-dist.mjs && tsc -p tsconfig.build.json");
38
+ expect(scripts["pretest"]).toBe("npm run build --silent");
78
39
  expect(cliSource.startsWith("#!/usr/bin/env node")).toBe(true);
79
40
  expect(cliSource).toContain("Usage: omo-lsp [mcp | hook post-tool-use | hook post-compact]");
80
41
  expect(postToolUseCommand).toBe(`node "${pluginRoot}/dist/cli.js" hook post-tool-use`);
@@ -91,55 +52,16 @@ describe("plugin package metadata", () => {
91
52
  expect(sourceFiles.filter((name) => name.startsWith("lazy-mcp") || name === "lazy-lsp-mcp.ts")).toEqual([]);
92
53
  });
93
54
 
94
- });
95
-
96
- function isPackageJson(value: unknown): value is PackageJson {
97
- return (
98
- isRecord(value) &&
99
- typeof value["version"] === "string" &&
100
- value["type"] === "module" &&
101
- value["packageManager"] === "npm@11.12.1" &&
102
- isStringRecord(value["bin"]) &&
103
- isStringRecord(value["dependencies"]) &&
104
- isStringRecord(value["scripts"])
105
- );
106
- }
107
-
108
- function isHooksJson(value: unknown): value is HooksJson {
109
- if (!isRecord(value) || !isRecord(value["hooks"])) return false;
110
- return Object.values(value["hooks"]).every(isHookEntries);
111
- }
112
-
113
- function isHookEntries(value: unknown): value is readonly HookEntry[] {
114
- return Array.isArray(value) && value.every(isHookEntry);
115
- }
116
-
117
- function isHookEntry(value: unknown): value is HookEntry {
118
- return isRecord(value) && Array.isArray(value["hooks"]) && value["hooks"].every(isHookCommand);
119
- }
120
-
121
- function isHookCommand(value: unknown): value is HookCommand {
122
- return isRecord(value) && typeof value["command"] === "string";
123
- }
124
-
125
- function isMcpJson(value: unknown): value is McpJson {
126
- if (!isRecord(value) || !isRecord(value["mcpServers"])) return false;
127
- return Object.values(value["mcpServers"]).every(isMcpServer);
128
- }
129
-
130
- function isMcpServer(value: unknown): value is McpServer {
131
- return (
132
- isRecord(value) &&
133
- typeof value["command"] === "string" &&
134
- Array.isArray(value["args"]) &&
135
- value["args"].every((item) => typeof item === "string")
136
- );
137
- }
55
+ it("#given LSP skill guidance #when validating MCP tool instructions #then tool names are not framed as shell commands", () => {
56
+ // given
57
+ const skill = readTextFile("skills/lsp/SKILL.md");
138
58
 
139
- function isStringRecord(value: unknown): value is Record<string, string> {
140
- return isRecord(value) && Object.values(value).every((item) => typeof item === "string");
141
- }
59
+ // when
60
+ const mentionsToolInterface = skill.includes("through the tool interface");
61
+ const rejectsShellExecution = skill.includes("not shell commands");
142
62
 
143
- function isRecord(value: unknown): value is Record<string, unknown> {
144
- return typeof value === "object" && value !== null && !Array.isArray(value);
145
- }
63
+ // then
64
+ expect(mentionsToolInterface).toBe(true);
65
+ expect(rejectsShellExecution).toBe(true);
66
+ });
67
+ });
@@ -4036,9 +4036,9 @@ function getSparkShellRuntimeAwareness(env = process.env, deps = {}) {
4036
4036
  `- Use \`${command} sparkshell --shell '<command>'\` only when shell metacharacters are required.`,
4037
4037
  `- Use \`${command} sparkshell --tmux-pane <pane-id> --tail-lines 400\` to inspect an existing tmux pane. Tail lines must stay between 100 and 1000.`,
4038
4038
  "- When no native sidecar or appserver is available, Sparkshell silently falls back to raw command execution. `OMO_SPARKSHELL_BIN` selects a native sidecar path.",
4039
- "- When `CODEX_THREAD_ID` identifies a Codex session, Sparkshell appends recent session context (first/latest user request + last 5 conversation messages) after the shell result so output consumers stay aligned with the session goals. `OMO_SPARKSHELL_SESSION_CONTEXT=0` disables it.",
4039
+ "- When `CODEX_THREAD_ID` identifies a Codex session, Sparkshell feeds recent session context (first/latest user request + last 5 conversation messages) into oversized-output condensation for relevance ranking, but never appends that context to command output. `OMO_SPARKSHELL_SESSION_CONTEXT=0` disables the lookup.",
4040
4040
  `- Route potentially huge output (full log files, big diffs, \`cat\`/\`grep\` over large artifacts) through \`${command} sparkshell\` instead of reading it raw: oversized output is condensed to a budget while preserving error signatures, repeated patterns, session-goal-relevant lines, and head/tail. Tune with \`--budget <chars>\`; disable with \`OMO_SPARKSHELL_CONDENSE=0\`.`,
4041
- "- Oversized output is first summarized by the spark model (`codex exec`, default `gpt-5.3-codex-spark`) fed with the session context: the summary reproduces the output as-is (no masking) and ends with a `[sparkshell caption]` line describing what ran and which lines were omitted. `OMO_SPARKSHELL_SPARK=0` skips the model and uses deterministic condensation directly."
4041
+ "- Oversized output is first summarized by the spark model (`codex exec`, default `gpt-5.3-codex-spark`) fed with the shell output plus session context: the summary keeps selected output as-is (no masking) and ends with a `[sparkshell caption]` line describing what ran, what the full output contained, and which lines were omitted. `OMO_SPARKSHELL_SPARK=0` skips the model and uses deterministic condensation directly."
4042
4042
  ].join(`
4043
4043
  `);
4044
4044
  }
@@ -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": "LazyCodex(4.11.0): Loading Project Rules"
10
+ "statusMessage": "(OmO) 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": "LazyCodex(4.11.0): Loading Project Rules"
22
+ "statusMessage": "(OmO) 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": "LazyCodex(4.11.0): Matching Project Rules"
35
+ "statusMessage": "(OmO) 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": "LazyCodex(4.11.0): Resetting Project Rule Cache"
48
+ "statusMessage": "(OmO) Resetting Project Rule Cache"
49
49
  }
50
50
  ]
51
51
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/codex-rules",
3
- "version": "4.11.0",
3
+ "version": "4.12.0",
4
4
  "description": "Codex plugin that injects project rule files into model context through lifecycle hooks.",
5
5
  "type": "module",
6
6
  "packageManager": "npm@11.12.1",
@@ -85,9 +85,9 @@ export function getSparkShellRuntimeAwareness(env: RuntimeEnv = process.env, dep
85
85
  `- Use \`${command} sparkshell --shell '<command>'\` only when shell metacharacters are required.`,
86
86
  `- Use \`${command} sparkshell --tmux-pane <pane-id> --tail-lines 400\` to inspect an existing tmux pane. Tail lines must stay between 100 and 1000.`,
87
87
  "- When no native sidecar or appserver is available, Sparkshell silently falls back to raw command execution. `OMO_SPARKSHELL_BIN` selects a native sidecar path.",
88
- "- When `CODEX_THREAD_ID` identifies a Codex session, Sparkshell appends recent session context (first/latest user request + last 5 conversation messages) after the shell result so output consumers stay aligned with the session goals. `OMO_SPARKSHELL_SESSION_CONTEXT=0` disables it.",
88
+ "- When `CODEX_THREAD_ID` identifies a Codex session, Sparkshell feeds recent session context (first/latest user request + last 5 conversation messages) into oversized-output condensation for relevance ranking, but never appends that context to command output. `OMO_SPARKSHELL_SESSION_CONTEXT=0` disables the lookup.",
89
89
  `- Route potentially huge output (full log files, big diffs, \`cat\`/\`grep\` over large artifacts) through \`${command} sparkshell\` instead of reading it raw: oversized output is condensed to a budget while preserving error signatures, repeated patterns, session-goal-relevant lines, and head/tail. Tune with \`--budget <chars>\`; disable with \`OMO_SPARKSHELL_CONDENSE=0\`.`,
90
- "- Oversized output is first summarized by the spark model (`codex exec`, default `gpt-5.3-codex-spark`) fed with the session context: the summary reproduces the output as-is (no masking) and ends with a `[sparkshell caption]` line describing what ran and which lines were omitted. `OMO_SPARKSHELL_SPARK=0` skips the model and uses deterministic condensation directly.",
90
+ "- Oversized output is first summarized by the spark model (`codex exec`, default `gpt-5.3-codex-spark`) fed with the shell output plus session context: the summary keeps selected output as-is (no masking) and ends with a `[sparkshell caption]` line describing what ran, what the full output contained, and which lines were omitted. `OMO_SPARKSHELL_SPARK=0` skips the model and uses deterministic condensation directly.",
91
91
  ].join("\n");
92
92
  }
93
93
 
@@ -1,48 +1,12 @@
1
- import { readdirSync, readFileSync } from "node:fs";
2
1
  import { describe, expect, it } from "vitest";
3
-
4
- type PackageJson = {
5
- readonly type: string;
6
- readonly packageManager: string;
7
- readonly bin: Record<string, string>;
8
- readonly files: readonly string[];
9
- readonly dependencies?: Record<string, unknown>;
10
- };
11
-
12
- type PluginJson = {
13
- readonly hooks: string;
14
- };
15
-
16
- type HookCommand = {
17
- readonly command: string;
18
- };
19
-
20
- type HookEntry = {
21
- readonly matcher?: string;
22
- readonly hooks: readonly HookCommand[];
23
- };
24
-
25
- type HooksJson = {
26
- readonly hooks: Record<string, readonly HookEntry[]>;
27
- };
28
-
29
- function readPackageJson(path: string): PackageJson {
30
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
31
- if (!isPackageJson(parsed)) throw new TypeError(`Invalid package metadata: ${path}`);
32
- return parsed;
33
- }
34
-
35
- function readPluginJson(path: string): PluginJson {
36
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
37
- if (!isPluginJson(parsed)) throw new TypeError(`Invalid plugin metadata: ${path}`);
38
- return parsed;
39
- }
40
-
41
- function readHooksJson(path: string): HooksJson {
42
- const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
43
- if (!isHooksJson(parsed)) throw new TypeError(`Invalid hooks metadata: ${path}`);
44
- return parsed;
45
- }
2
+ import {
3
+ listDirectoryEntries,
4
+ readHooksJson,
5
+ readPackageJson,
6
+ readPluginJson,
7
+ readTextFile,
8
+ requireFiles,
9
+ } from "../../test-support/package-smoke-fixture.js";
46
10
 
47
11
  describe("plugin package metadata", () => {
48
12
  it("#given packaged plugin files #when validating entrypoints #then hook commands use portable plugin root interpolation", () => {
@@ -50,8 +14,9 @@ describe("plugin package metadata", () => {
50
14
  const packageJson = readPackageJson("package.json");
51
15
  const pluginJson = readPluginJson(".codex-plugin/plugin.json");
52
16
  const hooksJson = readHooksJson("hooks/hooks.json");
53
- const cliSource = readFileSync("src/cli.ts", "utf8");
54
- const bundledRules = readdirSync("bundled-rules").sort();
17
+ const cliSource = readTextFile("src/cli.ts");
18
+ const packageFiles = requireFiles(packageJson, "package.json");
19
+ const bundledRules = [...listDirectoryEntries("bundled-rules")].sort();
55
20
 
56
21
  // when
57
22
  const hookConfig = hooksJson.hooks;
@@ -69,7 +34,7 @@ describe("plugin package metadata", () => {
69
34
  expect(packageJson.packageManager).toBe("npm@11.12.1");
70
35
  expect(packageJson.dependencies ?? {}).toEqual({ picomatch: "^4.0.3" });
71
36
  expect(packageJson.bin["omo-rules"]).toBe("./dist/cli.js");
72
- expect(packageJson.files).toContain("bundled-rules");
37
+ expect(packageFiles).toContain("bundled-rules");
73
38
  expect(bundledRules).toContain("windows-git-bash.md");
74
39
  expect(pluginJson.hooks).toBe("./hooks/hooks.json");
75
40
  expect(cliSource.startsWith("#!/usr/bin/env node")).toBe(true);
@@ -106,48 +71,3 @@ describe("plugin package metadata", () => {
106
71
  ).toBe(false);
107
72
  });
108
73
  });
109
-
110
- function isPackageJson(value: unknown): value is PackageJson {
111
- if (!isRecord(value)) return false;
112
- const dependencies = value["dependencies"];
113
- return (
114
- value["type"] === "module" &&
115
- value["packageManager"] === "npm@11.12.1" &&
116
- isStringRecord(value["bin"]) &&
117
- isStringArray(value["files"]) &&
118
- (dependencies === undefined || isRecord(dependencies))
119
- );
120
- }
121
-
122
- function isStringArray(value: unknown): value is readonly string[] {
123
- return Array.isArray(value) && value.every((item) => typeof item === "string");
124
- }
125
-
126
- function isPluginJson(value: unknown): value is PluginJson {
127
- return isRecord(value) && typeof value["hooks"] === "string";
128
- }
129
-
130
- function isHooksJson(value: unknown): value is HooksJson {
131
- if (!isRecord(value) || !isRecord(value["hooks"])) return false;
132
- return Object.values(value["hooks"]).every(isHookEntries);
133
- }
134
-
135
- function isHookEntries(value: unknown): value is readonly HookEntry[] {
136
- return Array.isArray(value) && value.every(isHookEntry);
137
- }
138
-
139
- function isHookEntry(value: unknown): value is HookEntry {
140
- return isRecord(value) && Array.isArray(value["hooks"]) && value["hooks"].every(isHookCommand);
141
- }
142
-
143
- function isHookCommand(value: unknown): value is HookCommand {
144
- return isRecord(value) && typeof value["command"] === "string";
145
- }
146
-
147
- function isStringRecord(value: unknown): value is Record<string, string> {
148
- return isRecord(value) && Object.values(value).every((item) => typeof item === "string");
149
- }
150
-
151
- function isRecord(value: unknown): value is Record<string, unknown> {
152
- return typeof value === "object" && value !== null && !Array.isArray(value);
153
- }
@@ -90,7 +90,10 @@ describe("Codex Sparkshell awareness", () => {
90
90
  expect(parseAdditionalContext(output)).toContain("OMO_SPARKSHELL_CONDENSE");
91
91
  expect(parseAdditionalContext(output)).toContain("OMO_SPARKSHELL_SPARK");
92
92
  expect(parseAdditionalContext(output)).toContain("[sparkshell caption]");
93
+ expect(parseAdditionalContext(output)).toContain("never appends that context to command output");
94
+ expect(parseAdditionalContext(output)).toContain("what the full output contained");
93
95
  expect(parseAdditionalContext(output)).not.toContain("[REDACTED]");
96
+ expect(parseAdditionalContext(output)).not.toContain("appends recent session context");
94
97
  });
95
98
 
96
99
  it("#given inactive env #when SessionStart runs #then emits no Sparkshell guidance", async () => {