oh-my-opencode 4.18.1 → 4.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +39 -16
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +4 -4
- package/README.ru.md +2 -2
- package/README.zh-cn.md +2 -2
- package/bin/AGENTS.md +33 -0
- package/dist/agents/atlas/agent.d.ts +6 -5
- package/dist/agents/sisyphus/index.d.ts +5 -0
- package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
- package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
- package/dist/agents/sisyphus-junior/index.d.ts +2 -0
- package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +690 -139
- package/dist/cli-node/index.js +690 -139
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/browser-automation.d.ts +1 -0
- package/dist/config/schema/commands.d.ts +1 -3
- package/dist/config/schema/default-mode.d.ts +1 -1
- package/dist/config/schema/goal.d.ts +7 -0
- package/dist/config/schema/hooks.d.ts +1 -1
- package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
- package/dist/config/schema/ralph-loop.d.ts +1 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/create-hooks.d.ts +1 -1
- package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
- package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
- package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
- package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
- package/dist/hooks/comment-checker/hook.d.ts +8 -1
- package/dist/hooks/goal/command-arguments.d.ts +13 -0
- package/dist/hooks/goal/controller.d.ts +26 -0
- package/dist/hooks/goal/index.d.ts +23 -0
- package/dist/hooks/goal/prompt.d.ts +3 -0
- package/dist/hooks/goal/store.d.ts +8 -0
- package/dist/hooks/goal/tools.d.ts +10 -0
- package/dist/hooks/goal/types.d.ts +93 -0
- package/dist/hooks/goal/validation.d.ts +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/keyword-detector/hook.d.ts +1 -2
- package/dist/hooks/ralph-loop/types.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
- package/dist/index.js +3706 -4329
- package/dist/oh-my-opencode.schema.json +23 -19
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
- package/dist/plugin/chat-message/types.d.ts +23 -10
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
- package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
- package/dist/plugin/messages-transform.d.ts +1 -0
- package/dist/plugin/stop-continuation.d.ts +2 -2
- package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
- package/dist/shared/system-directive.d.ts +0 -1
- package/dist/skills/ulw-plan/SKILL.md +11 -7
- package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/dist/skills/ulw-research/SKILL.md +3 -3
- package/dist/tools/delegate-task/types.d.ts +0 -1
- package/dist/tui.js +115 -28
- package/package.json +14 -14
- package/packages/git-bash-mcp/dist/cli.js +81 -19
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
- package/packages/lsp-daemon/dist/cli.js +262 -63
- package/packages/lsp-daemon/dist/client.js +194 -50
- package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
- package/packages/lsp-daemon/dist/daemon-client.js +26 -2
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
- package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
- package/packages/lsp-daemon/dist/index.js +262 -63
- package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
- package/packages/lsp-daemon/dist/proxy.js +79 -23
- package/packages/lsp-tools-mcp/dist/cli.js +82 -20
- package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
- package/packages/lsp-tools-mcp/dist/tools.js +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +352 -17
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +7 -6
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +1 -0
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +8 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +148 -61
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +4 -72
- package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
- package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -10
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -2
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
- package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
- package/dist/skills/ultraresearch/SKILL.md +0 -10
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
- package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
|
@@ -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
|
|
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
|
-
-
|
|
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
|
|
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
|
-
-
|
|
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.
|