oh-my-opencode 4.18.1 → 4.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +39 -16
  2. package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
  3. package/README.ja.md +2 -2
  4. package/README.ko.md +2 -2
  5. package/README.md +4 -4
  6. package/README.ru.md +2 -2
  7. package/README.zh-cn.md +2 -2
  8. package/bin/AGENTS.md +33 -0
  9. package/dist/agents/atlas/agent.d.ts +6 -5
  10. package/dist/agents/sisyphus/index.d.ts +5 -0
  11. package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
  12. package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
  13. package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
  14. package/dist/agents/sisyphus-junior/index.d.ts +2 -0
  15. package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
  16. package/dist/agents/types.d.ts +2 -2
  17. package/dist/cli/index.js +690 -139
  18. package/dist/cli-node/index.js +690 -139
  19. package/dist/config/index.d.ts +1 -1
  20. package/dist/config/schema/browser-automation.d.ts +1 -0
  21. package/dist/config/schema/commands.d.ts +1 -3
  22. package/dist/config/schema/default-mode.d.ts +1 -1
  23. package/dist/config/schema/goal.d.ts +7 -0
  24. package/dist/config/schema/hooks.d.ts +1 -1
  25. package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
  26. package/dist/config/schema/ralph-loop.d.ts +1 -1
  27. package/dist/config/schema.d.ts +1 -1
  28. package/dist/create-hooks.d.ts +1 -1
  29. package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
  30. package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
  31. package/dist/features/builtin-commands/types.d.ts +1 -1
  32. package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
  33. package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
  34. package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
  35. package/dist/hooks/comment-checker/hook.d.ts +8 -1
  36. package/dist/hooks/goal/command-arguments.d.ts +13 -0
  37. package/dist/hooks/goal/controller.d.ts +26 -0
  38. package/dist/hooks/goal/index.d.ts +23 -0
  39. package/dist/hooks/goal/prompt.d.ts +3 -0
  40. package/dist/hooks/goal/store.d.ts +8 -0
  41. package/dist/hooks/goal/tools.d.ts +10 -0
  42. package/dist/hooks/goal/types.d.ts +93 -0
  43. package/dist/hooks/goal/validation.d.ts +4 -0
  44. package/dist/hooks/index.d.ts +1 -0
  45. package/dist/hooks/keyword-detector/hook.d.ts +1 -2
  46. package/dist/hooks/ralph-loop/types.d.ts +1 -1
  47. package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
  48. package/dist/index.js +3706 -4329
  49. package/dist/oh-my-opencode.schema.json +23 -19
  50. package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
  51. package/dist/plugin/chat-message/types.d.ts +23 -10
  52. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
  53. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
  54. package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
  55. package/dist/plugin/messages-transform.d.ts +1 -0
  56. package/dist/plugin/stop-continuation.d.ts +2 -2
  57. package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
  58. package/dist/shared/system-directive.d.ts +0 -1
  59. package/dist/skills/ulw-plan/SKILL.md +11 -7
  60. package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
  61. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  62. package/dist/skills/ulw-research/SKILL.md +3 -3
  63. package/dist/tools/delegate-task/types.d.ts +0 -1
  64. package/dist/tui.js +115 -28
  65. package/package.json +14 -14
  66. package/packages/git-bash-mcp/dist/cli.js +81 -19
  67. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
  68. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
  69. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
  70. package/packages/lsp-daemon/dist/cli.js +262 -63
  71. package/packages/lsp-daemon/dist/client.js +194 -50
  72. package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
  73. package/packages/lsp-daemon/dist/daemon-client.js +26 -2
  74. package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
  75. package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
  76. package/packages/lsp-daemon/dist/index.js +262 -63
  77. package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
  78. package/packages/lsp-daemon/dist/proxy.js +79 -23
  79. package/packages/lsp-tools-mcp/dist/cli.js +82 -20
  80. package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
  81. package/packages/lsp-tools-mcp/dist/tools.js +1 -1
  82. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  83. package/packages/omo-codex/plugin/.mcp.json +2 -1
  84. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +352 -17
  85. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  86. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  87. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +7 -6
  88. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
  89. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
  90. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  91. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
  92. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
  93. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
  94. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
  95. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -1
  96. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  97. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  98. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  99. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  100. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  101. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  102. package/packages/omo-codex/plugin/components/lsp/.mcp.json +2 -1
  103. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
  104. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  105. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
  106. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  107. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  108. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +1 -0
  109. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
  110. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
  111. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  112. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  113. package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +8 -0
  114. package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
  115. package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
  116. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +148 -61
  117. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  118. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  119. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +4 -72
  120. package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
  121. package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
  122. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
  123. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
  124. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
  125. package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -0
  126. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  127. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  128. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  129. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  130. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -10
  131. package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
  132. package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
  133. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  134. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  135. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +50 -33
  136. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -7
  137. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
  138. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  139. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
  140. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
  141. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
  142. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  143. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  144. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
  145. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
  146. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -2
  147. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  148. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  149. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  150. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  151. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  152. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  153. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  154. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  155. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  156. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  157. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  158. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  159. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  160. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  161. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  162. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  163. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  164. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  165. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  166. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  170. package/packages/omo-codex/plugin/package-lock.json +13 -13
  171. package/packages/omo-codex/plugin/package.json +1 -1
  172. package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
  173. package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
  174. package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
  175. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
  176. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
  177. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
  178. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
  179. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
  180. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -7
  181. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
  182. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  183. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
  184. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
  185. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
  186. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
  187. package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
  188. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
  189. package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
  190. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
  191. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
  192. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
  193. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
  194. package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
  195. package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
  196. package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
  197. package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
  198. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
  199. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
  200. package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
  201. package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
  202. package/dist/skills/ultraresearch/SKILL.md +0 -10
  203. package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
  204. package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
  205. package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
  206. package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
  207. package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
  208. package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
  209. package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
  210. package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
  211. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
  212. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
  213. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
  214. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
  215. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
  216. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
  217. /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
@@ -0,0 +1,455 @@
1
+ export function findTomlSection(config, headerLine) {
2
+ const targetHeaderPath = parseTomlTableHeader(headerLine);
3
+ const lines = config.match(/[^\n]*\n?|$/g) ?? [];
4
+ let offset = 0;
5
+ let start = -1;
6
+ let multilineQuote = null;
7
+ for (const line of lines) {
8
+ if (line.length === 0) break;
9
+ const multilineScan = scanTomlMultilineLine(line, multilineQuote);
10
+ multilineQuote = multilineScan.nextQuote;
11
+ if (multilineScan.wasInside) {
12
+ offset += line.length;
13
+ continue;
14
+ }
15
+ if (start === -1) {
16
+ if (tomlTableHeaderMatches(line, targetHeaderPath)) start = offset;
17
+ } else if (isTomlTableHeaderLine(line)) {
18
+ return { start, end: offset, text: config.slice(start, offset) };
19
+ }
20
+ offset += line.length;
21
+ }
22
+ if (start === -1) return null;
23
+ return { start, end: config.length, text: config.slice(start) };
24
+ }
25
+
26
+ export function hasTomlSetting(config, keyPath) {
27
+ const targetPath = parseTomlDottedKey(keyPath);
28
+ if (!targetPath) return false;
29
+
30
+ let tablePath = [];
31
+ let multilineQuote = null;
32
+ for (const line of config.split("\n")) {
33
+ const multilineScan = scanTomlMultilineLine(line, multilineQuote);
34
+ multilineQuote = multilineScan.nextQuote;
35
+ if (multilineScan.wasInside) continue;
36
+ const normalizedLine = stripUnquotedInlineComment(line).trim();
37
+ if (normalizedLine.length === 0) continue;
38
+
39
+ const headerPath = parseTomlTableHeader(normalizedLine);
40
+ if (headerPath) {
41
+ tablePath = headerPath;
42
+ continue;
43
+ }
44
+ if (isTomlTableHeaderLine(normalizedLine)) {
45
+ tablePath = null;
46
+ continue;
47
+ }
48
+ if (!tablePath) continue;
49
+
50
+ const assignmentIndex = findUnquotedAssignment(normalizedLine);
51
+ if (assignmentIndex < 0) continue;
52
+ const settingPath = parseTomlDottedKey(normalizedLine.slice(0, assignmentIndex).trim());
53
+ if (!settingPath) continue;
54
+ const fullPath = [...tablePath, ...settingPath];
55
+ if (fullPath.length !== targetPath.length) continue;
56
+ if (fullPath.every((part, index) => part === targetPath[index])) return true;
57
+ }
58
+ return false;
59
+ }
60
+
61
+ export function replaceOrInsertRootTomlSetting(config, keyPath, value) {
62
+ const targetPath = parseTomlDottedKey(keyPath);
63
+ if (!targetPath) return config;
64
+ const match = findRootTomlSetting(config, targetPath);
65
+ if (match) {
66
+ const commentIndex = findUnquotedComment(match.lineBody, match.assignmentIndex + 1);
67
+ const comment = commentIndex === -1 ? "" : ` ${match.lineBody.slice(commentIndex).trimStart()}`;
68
+ const replacement = `${match.lineBody.slice(0, match.assignmentIndex + 1)} ${value}${comment}${match.newline}`;
69
+ return config.slice(0, match.offset) + replacement + config.slice(match.offset + match.line.length);
70
+ }
71
+ const firstTable = findFirstTomlTableStart(config);
72
+ const root = config.slice(0, firstTable).trimEnd();
73
+ const suffix = config.slice(firstTable);
74
+ const replacement = `${root}${root.length > 0 ? "\n" : ""}${keyPath} = ${value}\n`;
75
+ if (suffix.length === 0) return replacement;
76
+ return `${replacement.trimEnd()}\n\n${suffix.trimStart()}`;
77
+ }
78
+
79
+ export function replaceOrInsertTomlSectionSetting(config, section, keyPath, value) {
80
+ const targetPath = parseTomlDottedKey(keyPath);
81
+ if (!targetPath) return config;
82
+ const lines = section.text.match(/[^\n]*\n?|$/g) ?? [];
83
+ let offset = 0;
84
+ let multilineQuote = null;
85
+ for (const line of lines) {
86
+ if (line.length === 0) break;
87
+ const multilineScan = scanTomlMultilineLine(line, multilineQuote);
88
+ multilineQuote = multilineScan.nextQuote;
89
+ if (multilineScan.wasInside) {
90
+ offset += line.length;
91
+ continue;
92
+ }
93
+ const assignmentIndex = findUnquotedAssignment(line);
94
+ if (assignmentIndex >= 0) {
95
+ const settingPath = parseTomlDottedKey(line.slice(0, assignmentIndex).trim());
96
+ if (settingPath && tomlPathMatches(settingPath, targetPath)) {
97
+ const replacement = replaceTomlAssignmentValue(line, assignmentIndex, value);
98
+ const patched = section.text.slice(0, offset) + replacement + section.text.slice(offset + line.length);
99
+ return config.slice(0, section.start) + patched + config.slice(section.end);
100
+ }
101
+ }
102
+ offset += line.length;
103
+ }
104
+ const headerEnd = section.text.indexOf("\n");
105
+ const insertAt = headerEnd === -1 ? section.text.length : headerEnd + 1;
106
+ const patched = `${section.text.slice(0, insertAt)}${headerEnd === -1 ? "\n" : ""}${keyPath} = ${value}\n${section.text.slice(insertAt)}`;
107
+ return config.slice(0, section.start) + patched + config.slice(section.end);
108
+ }
109
+
110
+ export function removeTomlSectionSetting(config, section, keyPath, expectedValue) {
111
+ const targetPath = parseTomlDottedKey(keyPath);
112
+ if (!targetPath) return config;
113
+ const lines = section.text.match(/[^\n]*\n?|$/g) ?? [];
114
+ let offset = 0;
115
+ let multilineQuote = null;
116
+ for (const line of lines) {
117
+ if (line.length === 0) break;
118
+ const multilineScan = scanTomlMultilineLine(line, multilineQuote);
119
+ multilineQuote = multilineScan.nextQuote;
120
+ if (multilineScan.wasInside) {
121
+ offset += line.length;
122
+ continue;
123
+ }
124
+ const assignmentIndex = findUnquotedAssignment(line);
125
+ if (assignmentIndex >= 0) {
126
+ const settingPath = parseTomlDottedKey(line.slice(0, assignmentIndex).trim());
127
+ if (settingPath && tomlPathMatches(settingPath, targetPath)) {
128
+ const lineBody = line.endsWith("\n") ? line.slice(0, -1) : line;
129
+ const commentIndex = findUnquotedComment(lineBody, assignmentIndex + 1);
130
+ const valueEnd = commentIndex === -1 ? lineBody.length : commentIndex;
131
+ if (lineBody.slice(assignmentIndex + 1, valueEnd).trim() !== expectedValue) return config;
132
+ const patched = section.text.slice(0, offset) + section.text.slice(offset + line.length);
133
+ return config.slice(0, section.start) + patched + config.slice(section.end);
134
+ }
135
+ }
136
+ offset += line.length;
137
+ }
138
+ return config;
139
+ }
140
+
141
+ export function removeRootTomlSetting(config, keyPath, expectedValue) {
142
+ const targetPath = parseTomlDottedKey(keyPath);
143
+ if (!targetPath) return config;
144
+ const match = findRootTomlSetting(config, targetPath);
145
+ if (!match) return config;
146
+ const commentIndex = findUnquotedComment(match.lineBody, match.assignmentIndex + 1);
147
+ const valueEnd = commentIndex === -1 ? match.lineBody.length : commentIndex;
148
+ if (match.lineBody.slice(match.assignmentIndex + 1, valueEnd).trim() !== expectedValue) return config;
149
+ return config.slice(0, match.offset) + config.slice(match.offset + match.line.length);
150
+ }
151
+
152
+ function tomlTableHeaderMatches(line, targetHeaderPath) {
153
+ if (!targetHeaderPath) return false;
154
+ const candidateHeaderPath = parseTomlTableHeader(line);
155
+ if (!candidateHeaderPath || candidateHeaderPath.length !== targetHeaderPath.length) return false;
156
+ return candidateHeaderPath.every((part, index) => part === targetHeaderPath[index]);
157
+ }
158
+
159
+ function isTomlTableHeaderLine(line) {
160
+ const normalizedLine = stripUnquotedInlineComment(line).trim();
161
+ return normalizedLine.startsWith("[") && normalizedLine.endsWith("]");
162
+ }
163
+
164
+ function scanTomlMultilineLine(line, currentQuote) {
165
+ if (currentQuote) {
166
+ return {
167
+ wasInside: true,
168
+ nextQuote: findTomlMultilineDelimiter(line, currentQuote, 0) === -1 ? currentQuote : null,
169
+ };
170
+ }
171
+
172
+ let quote = null;
173
+ let index = 0;
174
+ while (index < line.length) {
175
+ const char = line[index];
176
+ if (quote === '"') {
177
+ if (char === "\\") {
178
+ index += 2;
179
+ continue;
180
+ }
181
+ if (char === '"') quote = null;
182
+ index += 1;
183
+ continue;
184
+ }
185
+ if (quote === "'") {
186
+ if (char === "'") quote = null;
187
+ index += 1;
188
+ continue;
189
+ }
190
+ if (char === "#") break;
191
+ const delimiter = line.startsWith('"""', index) ? '"""' : line.startsWith("'''", index) ? "'''" : null;
192
+ if (delimiter) {
193
+ const closingIndex = findTomlMultilineDelimiter(line, delimiter, index + delimiter.length);
194
+ return { wasInside: false, nextQuote: closingIndex === -1 ? delimiter : null };
195
+ }
196
+ if (char === '"' || char === "'") quote = char;
197
+ index += 1;
198
+ }
199
+ return { wasInside: false, nextQuote: null };
200
+ }
201
+
202
+ function findTomlMultilineDelimiter(line, delimiter, startIndex) {
203
+ let index = line.indexOf(delimiter, startIndex);
204
+ while (index !== -1) {
205
+ if (delimiter === "'''" || countPrecedingBackslashes(line, index) % 2 === 0) return index;
206
+ index = line.indexOf(delimiter, index + 1);
207
+ }
208
+ return -1;
209
+ }
210
+
211
+ function countPrecedingBackslashes(line, index) {
212
+ let count = 0;
213
+ let cursor = index - 1;
214
+ while (cursor >= 0 && line[cursor] === "\\") {
215
+ count += 1;
216
+ cursor -= 1;
217
+ }
218
+ return count;
219
+ }
220
+
221
+ function findRootTomlSetting(config, targetPath) {
222
+ const lines = config.match(/[^\n]*\n?|$/g) ?? [];
223
+ let offset = 0;
224
+ let multilineQuote = null;
225
+ for (const line of lines) {
226
+ if (line.length === 0) break;
227
+ const multilineScan = scanTomlMultilineLine(line, multilineQuote);
228
+ multilineQuote = multilineScan.nextQuote;
229
+ if (multilineScan.wasInside) {
230
+ offset += line.length;
231
+ continue;
232
+ }
233
+ if (isTomlTableHeaderLine(line)) break;
234
+ const assignmentIndex = findUnquotedAssignment(line);
235
+ if (assignmentIndex >= 0) {
236
+ const settingPath = parseTomlDottedKey(line.slice(0, assignmentIndex).trim());
237
+ if (settingPath && tomlPathMatches(settingPath, targetPath)) {
238
+ const newline = line.endsWith("\n") ? "\n" : "";
239
+ return { line, lineBody: newline ? line.slice(0, -1) : line, newline, offset, assignmentIndex };
240
+ }
241
+ }
242
+ offset += line.length;
243
+ }
244
+ return null;
245
+ }
246
+
247
+ function findFirstTomlTableStart(config) {
248
+ const lines = config.match(/[^\n]*\n?|$/g) ?? [];
249
+ let offset = 0;
250
+ let multilineQuote = null;
251
+ for (const line of lines) {
252
+ if (line.length === 0) break;
253
+ const multilineScan = scanTomlMultilineLine(line, multilineQuote);
254
+ multilineQuote = multilineScan.nextQuote;
255
+ if (!multilineScan.wasInside && isTomlTableHeaderLine(line)) return offset;
256
+ offset += line.length;
257
+ }
258
+ return config.length;
259
+ }
260
+
261
+ function findUnquotedComment(line, startIndex) {
262
+ let quote = null;
263
+ let index = startIndex;
264
+ while (index < line.length) {
265
+ const char = line[index];
266
+ if (quote === '"') {
267
+ if (char === "\\") {
268
+ index += 2;
269
+ continue;
270
+ }
271
+ if (char === '"') quote = null;
272
+ index += 1;
273
+ continue;
274
+ }
275
+ if (quote === "'") {
276
+ if (char === "'") quote = null;
277
+ index += 1;
278
+ continue;
279
+ }
280
+ if (char === '"' || char === "'") quote = char;
281
+ else if (char === "#") return index;
282
+ index += 1;
283
+ }
284
+ return -1;
285
+ }
286
+
287
+ function tomlPathMatches(candidate, target) {
288
+ return candidate.length === target.length && candidate.every((part, index) => part === target[index]);
289
+ }
290
+
291
+ function replaceTomlAssignmentValue(line, assignmentIndex, value) {
292
+ const newline = line.endsWith("\n") ? "\n" : "";
293
+ const lineBody = newline ? line.slice(0, -1) : line;
294
+ const commentIndex = findUnquotedComment(lineBody, assignmentIndex + 1);
295
+ const comment = commentIndex === -1 ? "" : ` ${lineBody.slice(commentIndex).trimStart()}`;
296
+ return `${lineBody.slice(0, assignmentIndex + 1)} ${value}${comment}${newline}`;
297
+ }
298
+
299
+ function parseTomlTableHeader(line) {
300
+ const normalizedLine = stripUnquotedInlineComment(line).trim();
301
+ if (!normalizedLine.startsWith("[") || !normalizedLine.endsWith("]") || normalizedLine.startsWith("[[")) {
302
+ return null;
303
+ }
304
+ return parseTomlDottedKey(normalizedLine.slice(1, -1).trim());
305
+ }
306
+
307
+ function stripUnquotedInlineComment(line) {
308
+ let quote = null;
309
+ let index = 0;
310
+ while (index < line.length) {
311
+ const char = line[index];
312
+ if (quote === '"') {
313
+ if (char === "\\") {
314
+ index += 2;
315
+ continue;
316
+ }
317
+ if (char === '"') quote = null;
318
+ index += 1;
319
+ continue;
320
+ }
321
+ if (quote === "'") {
322
+ if (char === "'") quote = null;
323
+ index += 1;
324
+ continue;
325
+ }
326
+ if (char === '"' || char === "'") {
327
+ quote = char;
328
+ index += 1;
329
+ continue;
330
+ }
331
+ if (char === "#") return line.slice(0, index);
332
+ index += 1;
333
+ }
334
+ return line;
335
+ }
336
+
337
+ function findUnquotedAssignment(line) {
338
+ let quote = null;
339
+ let index = 0;
340
+ while (index < line.length) {
341
+ const char = line[index];
342
+ if (quote === '"') {
343
+ if (char === "\\") {
344
+ index += 2;
345
+ continue;
346
+ }
347
+ if (char === '"') quote = null;
348
+ index += 1;
349
+ continue;
350
+ }
351
+ if (quote === "'") {
352
+ if (char === "'") quote = null;
353
+ index += 1;
354
+ continue;
355
+ }
356
+ if (char === '"' || char === "'") {
357
+ quote = char;
358
+ index += 1;
359
+ continue;
360
+ }
361
+ if (char === "=") return index;
362
+ index += 1;
363
+ }
364
+ return -1;
365
+ }
366
+
367
+ function parseTomlDottedKey(input) {
368
+ const parts = [];
369
+ let index = 0;
370
+ while (index < input.length) {
371
+ index = skipWhitespace(input, index);
372
+ const parsedKey = parseTomlKeyPart(input, index);
373
+ if (!parsedKey) return null;
374
+ parts.push(parsedKey.value);
375
+ index = skipWhitespace(input, parsedKey.nextIndex);
376
+ if (index === input.length) return parts;
377
+ if (input[index] !== ".") return null;
378
+ index += 1;
379
+ }
380
+ return parts.length > 0 ? parts : null;
381
+ }
382
+
383
+ function parseTomlKeyPart(input, startIndex) {
384
+ const quote = input[startIndex];
385
+ if (quote === "'") return parseLiteralTomlString(input, startIndex);
386
+ if (quote === '"') return parseBasicTomlString(input, startIndex);
387
+ return parseBareTomlKey(input, startIndex);
388
+ }
389
+
390
+ function parseLiteralTomlString(input, startIndex) {
391
+ let index = startIndex + 1;
392
+ let value = "";
393
+ while (index < input.length) {
394
+ const char = input[index];
395
+ if (char === "'") return { value, nextIndex: index + 1 };
396
+ value += char;
397
+ index += 1;
398
+ }
399
+ return null;
400
+ }
401
+
402
+ function parseBasicTomlString(input, startIndex) {
403
+ let index = startIndex + 1;
404
+ let value = "";
405
+ while (index < input.length) {
406
+ const char = input[index];
407
+ if (char === '"') return { value, nextIndex: index + 1 };
408
+ if (char !== "\\") {
409
+ value += char;
410
+ index += 1;
411
+ continue;
412
+ }
413
+ const escaped = parseBasicTomlEscape(input, index);
414
+ if (!escaped) return null;
415
+ value += escaped.value;
416
+ index = escaped.nextIndex;
417
+ }
418
+ return null;
419
+ }
420
+
421
+ function parseBasicTomlEscape(input, backslashIndex) {
422
+ const escape = input[backslashIndex + 1];
423
+ if (escape === undefined) return null;
424
+ if (escape === "b") return { value: "\b", nextIndex: backslashIndex + 2 };
425
+ if (escape === "t") return { value: "\t", nextIndex: backslashIndex + 2 };
426
+ if (escape === "n") return { value: "\n", nextIndex: backslashIndex + 2 };
427
+ if (escape === "f") return { value: "\f", nextIndex: backslashIndex + 2 };
428
+ if (escape === "r") return { value: "\r", nextIndex: backslashIndex + 2 };
429
+ if (escape === '"') return { value: '"', nextIndex: backslashIndex + 2 };
430
+ if (escape === "\\") return { value: "\\", nextIndex: backslashIndex + 2 };
431
+ if (escape === "u") return parseUnicodeEscape(input, backslashIndex + 2, 4);
432
+ if (escape === "U") return parseUnicodeEscape(input, backslashIndex + 2, 8);
433
+ return null;
434
+ }
435
+
436
+ function parseUnicodeEscape(input, digitsStart, digitCount) {
437
+ const digits = input.slice(digitsStart, digitsStart + digitCount);
438
+ if (digits.length !== digitCount || !/^[0-9A-Fa-f]+$/.test(digits)) return null;
439
+ const codePoint = Number.parseInt(digits, 16);
440
+ if (codePoint > 0x10ffff) return null;
441
+ return { value: String.fromCodePoint(codePoint), nextIndex: digitsStart + digitCount };
442
+ }
443
+
444
+ function parseBareTomlKey(input, startIndex) {
445
+ let index = startIndex;
446
+ while (index < input.length && /[A-Za-z0-9_-]/.test(input[index])) index += 1;
447
+ if (index === startIndex) return null;
448
+ return { value: input.slice(startIndex, index), nextIndex: index };
449
+ }
450
+
451
+ function skipWhitespace(input, startIndex) {
452
+ let index = startIndex;
453
+ while (index < input.length && /\s/.test(input[index])) index += 1;
454
+ return index;
455
+ }
@@ -14,6 +14,9 @@ const ignoredSkillSourceDirNames = new Set([".mypy_cache", ".omo", ".pytest_cach
14
14
  const ignoredSkillSourceFileNames = new Set([".gitignore", ".npmignore", "pyrightconfig.json"]);
15
15
  const skillSources = [
16
16
  ["comment-checker", "components/comment-checker/skills/comment-checker"],
17
+ ["lcx-contribute-bug-fix", "components/lcx/skills/lcx-contribute-bug-fix"],
18
+ ["lcx-doctor", "components/lcx/skills/lcx-doctor"],
19
+ ["lcx-report-bug", "components/lcx/skills/lcx-report-bug"],
17
20
  ["lsp", "components/lsp/skills/lsp"],
18
21
  ["rules", "components/rules/skills/rules"],
19
22
  ["teammode", "components/teammode/skills/teammode"],
@@ -22,7 +25,6 @@ const skillSources = [
22
25
  ["ultrawork", "components/ultrawork/skills/ultrawork"],
23
26
  ];
24
27
  const componentSkillNames = new Set(skillSources.map(([name]) => name));
25
- const codexHiddenSharedSkillNames = new Set(["ultraresearch"]);
26
28
  const skillDisplayPrefix = "(OmO) ";
27
29
 
28
30
  function shouldCopySkillSource(source) {
@@ -132,9 +134,10 @@ const startWorkOriginalCompletion = `When all top-level checkboxes in \`## TODOs
132
134
  const startWorkCodexCompletion = `When all top-level checkboxes in \`## TODOs\` and \`## Final Verification Wave\` are complete:
133
135
 
134
136
  1. Run the plan's final verification commands.
135
- 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge. The gate's pass binds to the commit SHA it reviewed and covers every later checkpoint at that same SHA — never re-run it on an already-passed SHA; re-run only when new commits land:
137
+ 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
136
138
  - Invoke the \`review-work\` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, \`BLOCKED:\`, or inconclusive lane is a gate failure, not approval.
137
- - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to \`.omo/start-work/ledger.jsonl\`.
139
+ - Each passing review lane binds to the exact full commit SHA it reviewed. Immediately append a durable record to \`.omo/start-work/ledger.jsonl\` with the lane name, full SHA, PASS verdict, and report artifact/source. Before same-SHA reuse after any continuation or compaction, re-read the ledger record and require the exact lane/SHA pair; memory, chat history, or an unstamped report is not coverage. New commits require fresh applicable lane coverage.
140
+ - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append a separate durable record with the audit name, exact full SHA, verdict, and evidence artifact/source to \`.omo/start-work/ledger.jsonl\`. Reuse it only after re-reading an exact audit/SHA match.
138
141
  - If any review lane or debugging hypothesis fails, invoke the \`debugging\` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.
139
142
  - Evidence hygiene is mandatory: redact or mask secrets and sensitive user data before writing \`.omo/start-work/ledger.jsonl\`, a PR body, or a handoff. Never include raw tokens, credentials, auth headers, cookies, API keys, env dumps, private logs, or PII; use concise summaries, lengths, hashes, or short non-sensitive prefixes instead.
140
143
  - If the work includes creating, updating, or handing off a PR, refresh \`git status\` and the PR/branch state from the task-owned worktree after the gate, and include only redacted review/debugging evidence in the PR body or handoff.
@@ -156,6 +159,13 @@ failed, investigate the underlying uncertainty with the \`debugging\` skill when
156
159
  runtime behavior may be wrong, fix with evidence, and rerun the affected lane
157
160
  before claiming completion, creating or handing off a PR, or merging.
158
161
 
162
+ After each lane reaches PASS, immediately append a durable task-evidence record
163
+ to the active ledger with the lane name, exact full commit SHA, PASS verdict,
164
+ and report artifact/source. Before reusing coverage after continuation or
165
+ compaction, re-read that record and require the exact lane/SHA pair. Memory,
166
+ chat history, or an unstamped report is not coverage; a new commit requires
167
+ fresh applicable lane records.
168
+
159
169
  A rejecting lane must name its blockers inline in its final message — each
160
170
  blocker cites the violated goal criterion or requirement plus an evidence
161
171
  pointer. A bare REJECT/FAIL token without findings is not a verdict; treat it
@@ -174,22 +184,6 @@ prefixes when identity is needed.
174
184
  `;
175
185
 
176
186
  function applyCodexSkillOverlays(skillName, content) {
177
- if (skillName === "ulw-research") {
178
- return content
179
- .replace(
180
- ", the legacy alias 'ultraresearch', any 'ulw' research wording,",
181
- ", any 'ulw' research wording,",
182
- )
183
- .replace(
184
- 'the legacy alias "ultraresearch" (also `/ultraresearch`, `$ultraresearch`), ',
185
- "",
186
- )
187
- .replace(
188
- "answer those normally, and mention that `ulw-research` is available (legacy alias: `ultraresearch`) when a question would clearly benefit from it.",
189
- "answer those normally, and mention that `ulw-research` is available when a question would clearly benefit from it.",
190
- )
191
- .replace("# Ultraresearch Synthesis: <query>", "# ULW-Research Synthesis: <query>");
192
- }
193
187
  if (skillName === "start-work") {
194
188
  return content
195
189
  .replace(startWorkOriginalCompletion, startWorkCodexCompletion)
@@ -262,7 +256,6 @@ async function syncSkills() {
262
256
 
263
257
  for (const skillName of sharedSkillNames) {
264
258
  if (componentSkillNames.has(skillName)) continue;
265
- if (codexHiddenSharedSkillNames.has(skillName)) continue;
266
259
  await cp(join(sharedSkillsRoot, skillName), join(skillsRoot, skillName), {
267
260
  filter: shouldCopySkillSource,
268
261
  recursive: true,
@@ -70,6 +70,13 @@ failed, investigate the underlying uncertainty with the `debugging` skill when
70
70
  runtime behavior may be wrong, fix with evidence, and rerun the affected lane
71
71
  before claiming completion, creating or handing off a PR, or merging.
72
72
 
73
+ After each lane reaches PASS, immediately append a durable task-evidence record
74
+ to the active ledger with the lane name, exact full commit SHA, PASS verdict,
75
+ and report artifact/source. Before reusing coverage after continuation or
76
+ compaction, re-read that record and require the exact lane/SHA pair. Memory,
77
+ chat history, or an unstamped report is not coverage; a new commit requires
78
+ fresh applicable lane records.
79
+
73
80
  A rejecting lane must name its blockers inline in its final message — each
74
81
  blocker cites the violated goal criterion or requirement plus an evidence
75
82
  pointer. A bare REJECT/FAIL token without findings is not a verdict; treat it
@@ -176,9 +176,10 @@ Only after verification passes:
176
176
  When all top-level checkboxes in `## TODOs` and `## Final Verification Wave` are complete:
177
177
 
178
178
  1. Run the plan's final verification commands.
179
- 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge. The gate's pass binds to the commit SHA it reviewed and covers every later checkpoint at that same SHA — never re-run it on an already-passed SHA; re-run only when new commits land:
179
+ 2. Complete the **Global Review and Debugging Gate** before any completion claim, PR creation, PR handoff, branch handoff, or merge:
180
180
  - Invoke the `review-work` skill with the final diff, changed files, user goal, constraints, run command, and verification evidence. All five review lanes must return PASS. A timeout, missing deliverable, ack-only child, `BLOCKED:`, or inconclusive lane is a gate failure, not approval.
181
- - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append the ruled-out or confirmed result to `.omo/start-work/ledger.jsonl`.
181
+ - Each passing review lane binds to the exact full commit SHA it reviewed. Immediately append a durable record to `.omo/start-work/ledger.jsonl` with the lane name, full SHA, PASS verdict, and report artifact/source. Before same-SHA reuse after any continuation or compaction, re-read the ledger record and require the exact lane/SHA pair; memory, chat history, or an unstamped report is not coverage. New commits require fresh applicable lane coverage.
182
+ - Run a debugging-oriented runtime audit even when the review passes: name at least three plausible failure hypotheses for the changed surface, run the distinguishing checks against the actual artifact, and append a separate durable record with the audit name, exact full SHA, verdict, and evidence artifact/source to `.omo/start-work/ledger.jsonl`. Reuse it only after re-reading an exact audit/SHA match.
182
183
  - If any review lane or debugging hypothesis fails, invoke the `debugging` skill, confirm root cause with runtime evidence, add the minimal failing test or reproduction, fix it, rerun the affected verification, then rerun the Global Review and Debugging Gate.
183
184
  - Evidence hygiene is mandatory: redact or mask secrets and sensitive user data before writing `.omo/start-work/ledger.jsonl`, a PR body, or a handoff. Never include raw tokens, credentials, auth headers, cookies, API keys, env dumps, private logs, or PII; use concise summaries, lengths, hashes, or short non-sensitive prefixes instead.
184
185
  - If the work includes creating, updating, or handing off a PR, refresh `git status` and the PR/branch state from the task-owned worktree after the gate, and include only redacted review/debugging evidence in the PR body or handoff.