oh-my-opencode 4.18.2 → 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/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/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 +648 -136
- package/dist/cli-node/index.js +648 -136
- 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/auto-slash-command/executor.d.ts +1 -0
- 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/index.js +3515 -4365
- 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/stop-continuation.d.ts +2 -2
- 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 +73 -25
- package/package.json +14 -14
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -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 +97 -30
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- 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/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/dist/cli.js +147 -60
- 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 +3 -71
- 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 +198 -23
- 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 +6 -5
- 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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- 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/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- 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 +3 -18
- 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/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-test-support.mjs +3 -18
- 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
|
@@ -5903,7 +5903,7 @@ var package_default;
|
|
|
5903
5903
|
var init_package = __esm(() => {
|
|
5904
5904
|
package_default = {
|
|
5905
5905
|
name: "@oh-my-opencode/omo-codex",
|
|
5906
|
-
version: "4.
|
|
5906
|
+
version: "4.19.0",
|
|
5907
5907
|
type: "module",
|
|
5908
5908
|
private: true,
|
|
5909
5909
|
description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
|
|
@@ -7837,9 +7837,16 @@ function findTomlSection(config, header) {
|
|
|
7837
7837
|
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
7838
7838
|
let offset = 0;
|
|
7839
7839
|
let start = -1;
|
|
7840
|
+
let multilineQuote = null;
|
|
7840
7841
|
for (const line of lines) {
|
|
7841
7842
|
if (line.length === 0)
|
|
7842
7843
|
break;
|
|
7844
|
+
const multilineScan = scanTomlMultilineLine(line, multilineQuote);
|
|
7845
|
+
multilineQuote = multilineScan.nextQuote;
|
|
7846
|
+
if (multilineScan.wasInside) {
|
|
7847
|
+
offset += line.length;
|
|
7848
|
+
continue;
|
|
7849
|
+
}
|
|
7843
7850
|
const trimmed = line.trim();
|
|
7844
7851
|
if (start === -1) {
|
|
7845
7852
|
if (tomlTableHeaderMatches(trimmed, headerLine, targetHeaderPath))
|
|
@@ -7854,8 +7861,37 @@ function findTomlSection(config, header) {
|
|
|
7854
7861
|
return { start, end: config.length, text: config.slice(start) };
|
|
7855
7862
|
}
|
|
7856
7863
|
function replaceOrInsertSetting(config, section, key, value) {
|
|
7857
|
-
const
|
|
7858
|
-
|
|
7864
|
+
const targetPath = parseTomlDottedKey(key);
|
|
7865
|
+
if (!targetPath)
|
|
7866
|
+
return config;
|
|
7867
|
+
const lines = section.text.match(/[^\n]*\n?|$/g) ?? [];
|
|
7868
|
+
let offset = 0;
|
|
7869
|
+
let multilineQuote = null;
|
|
7870
|
+
for (const line of lines) {
|
|
7871
|
+
if (line.length === 0)
|
|
7872
|
+
break;
|
|
7873
|
+
const multilineScan = scanTomlMultilineLine(line, multilineQuote);
|
|
7874
|
+
multilineQuote = multilineScan.nextQuote;
|
|
7875
|
+
if (multilineScan.wasInside) {
|
|
7876
|
+
offset += line.length;
|
|
7877
|
+
continue;
|
|
7878
|
+
}
|
|
7879
|
+
const assignmentIndex = findUnquotedAssignment(line);
|
|
7880
|
+
if (assignmentIndex < 0) {
|
|
7881
|
+
offset += line.length;
|
|
7882
|
+
continue;
|
|
7883
|
+
}
|
|
7884
|
+
const settingPath = parseTomlDottedKey(line.slice(0, assignmentIndex).trim());
|
|
7885
|
+
if (!settingPath || !tomlPathMatches(settingPath, targetPath)) {
|
|
7886
|
+
offset += line.length;
|
|
7887
|
+
continue;
|
|
7888
|
+
}
|
|
7889
|
+
const replacement2 = replaceTomlAssignmentValue(line, assignmentIndex, value);
|
|
7890
|
+
const assignmentEnd = multilineScan.nextQuote ? findTomlMultilineValueEnd(section.text, offset + line.length, multilineScan.nextQuote) : offset + line.length;
|
|
7891
|
+
const sectionReplacement = section.text.slice(0, offset) + replacement2 + section.text.slice(assignmentEnd);
|
|
7892
|
+
return config.slice(0, section.start) + sectionReplacement + config.slice(section.end);
|
|
7893
|
+
}
|
|
7894
|
+
const replacement = insertSetting(section.text, key, value);
|
|
7859
7895
|
return config.slice(0, section.start) + replacement + config.slice(section.end);
|
|
7860
7896
|
}
|
|
7861
7897
|
function removeSetting(config, section, key) {
|
|
@@ -7875,6 +7911,50 @@ function replaceOrInsertRootSetting(config, key, value) {
|
|
|
7875
7911
|
return replacement;
|
|
7876
7912
|
return `${replacement.trimEnd()}
|
|
7877
7913
|
|
|
7914
|
+
${suffix.trimStart()}`;
|
|
7915
|
+
}
|
|
7916
|
+
function replaceOrInsertRootDottedSetting(config, keyPath, value) {
|
|
7917
|
+
const targetPath = parseTomlDottedKey(keyPath);
|
|
7918
|
+
if (!targetPath)
|
|
7919
|
+
return config;
|
|
7920
|
+
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
7921
|
+
let offset = 0;
|
|
7922
|
+
let multilineQuote = null;
|
|
7923
|
+
for (const line of lines) {
|
|
7924
|
+
if (line.length === 0)
|
|
7925
|
+
break;
|
|
7926
|
+
const multilineScan = scanTomlMultilineLine(line, multilineQuote);
|
|
7927
|
+
multilineQuote = multilineScan.nextQuote;
|
|
7928
|
+
if (multilineScan.wasInside) {
|
|
7929
|
+
offset += line.length;
|
|
7930
|
+
continue;
|
|
7931
|
+
}
|
|
7932
|
+
if (isTomlTableHeaderLine(line))
|
|
7933
|
+
break;
|
|
7934
|
+
const assignmentIndex = findUnquotedAssignment(line);
|
|
7935
|
+
if (assignmentIndex < 0) {
|
|
7936
|
+
offset += line.length;
|
|
7937
|
+
continue;
|
|
7938
|
+
}
|
|
7939
|
+
const settingPath = parseTomlDottedKey(line.slice(0, assignmentIndex).trim());
|
|
7940
|
+
if (!settingPath || !tomlPathMatches(settingPath, targetPath)) {
|
|
7941
|
+
offset += line.length;
|
|
7942
|
+
continue;
|
|
7943
|
+
}
|
|
7944
|
+
const replacement2 = replaceTomlAssignmentValue(line, assignmentIndex, value);
|
|
7945
|
+
const assignmentEnd = multilineScan.nextQuote ? findTomlMultilineValueEnd(config, offset + line.length, multilineScan.nextQuote) : offset + line.length;
|
|
7946
|
+
return config.slice(0, offset) + replacement2 + config.slice(assignmentEnd);
|
|
7947
|
+
}
|
|
7948
|
+
const sectionStart = findFirstTableStart(config);
|
|
7949
|
+
const root = config.slice(0, sectionStart).trimEnd();
|
|
7950
|
+
const suffix = config.slice(sectionStart);
|
|
7951
|
+
const replacement = `${root}${root.length > 0 ? `
|
|
7952
|
+
` : ""}${keyPath} = ${value}
|
|
7953
|
+
`;
|
|
7954
|
+
if (suffix.length === 0)
|
|
7955
|
+
return replacement;
|
|
7956
|
+
return `${replacement.trimEnd()}
|
|
7957
|
+
|
|
7878
7958
|
${suffix.trimStart()}`;
|
|
7879
7959
|
}
|
|
7880
7960
|
function appendBlock(config, block) {
|
|
@@ -7887,9 +7967,16 @@ function appendBlock(config, block) {
|
|
|
7887
7967
|
function findFirstTableStart(config) {
|
|
7888
7968
|
const lines = config.match(/[^\n]*\n?|$/g) ?? [];
|
|
7889
7969
|
let offset = 0;
|
|
7970
|
+
let multilineQuote = null;
|
|
7890
7971
|
for (const line of lines) {
|
|
7891
7972
|
if (line.length === 0)
|
|
7892
7973
|
break;
|
|
7974
|
+
const multilineScan = scanTomlMultilineLine(line, multilineQuote);
|
|
7975
|
+
multilineQuote = multilineScan.nextQuote;
|
|
7976
|
+
if (multilineScan.wasInside) {
|
|
7977
|
+
offset += line.length;
|
|
7978
|
+
continue;
|
|
7979
|
+
}
|
|
7893
7980
|
if (isTomlTableHeaderLine(line))
|
|
7894
7981
|
return offset;
|
|
7895
7982
|
offset += line.length;
|
|
@@ -7927,6 +8014,131 @@ function isTomlTableHeaderLine(line) {
|
|
|
7927
8014
|
const normalizedLine = stripUnquotedInlineComment(line).trim();
|
|
7928
8015
|
return normalizedLine.startsWith("[") && normalizedLine.endsWith("]");
|
|
7929
8016
|
}
|
|
8017
|
+
function scanTomlMultilineLine(line, currentQuote) {
|
|
8018
|
+
if (currentQuote) {
|
|
8019
|
+
return {
|
|
8020
|
+
wasInside: true,
|
|
8021
|
+
nextQuote: findTomlMultilineDelimiter(line, currentQuote, 0) === -1 ? currentQuote : null
|
|
8022
|
+
};
|
|
8023
|
+
}
|
|
8024
|
+
let quote = null;
|
|
8025
|
+
let index = 0;
|
|
8026
|
+
while (index < line.length) {
|
|
8027
|
+
const char = line[index];
|
|
8028
|
+
if (quote === '"') {
|
|
8029
|
+
if (char === "\\") {
|
|
8030
|
+
index += 2;
|
|
8031
|
+
continue;
|
|
8032
|
+
}
|
|
8033
|
+
if (char === '"')
|
|
8034
|
+
quote = null;
|
|
8035
|
+
index += 1;
|
|
8036
|
+
continue;
|
|
8037
|
+
}
|
|
8038
|
+
if (quote === "'") {
|
|
8039
|
+
if (char === "'")
|
|
8040
|
+
quote = null;
|
|
8041
|
+
index += 1;
|
|
8042
|
+
continue;
|
|
8043
|
+
}
|
|
8044
|
+
if (char === "#")
|
|
8045
|
+
break;
|
|
8046
|
+
const delimiter2 = line.startsWith('"""', index) ? '"""' : line.startsWith("'''", index) ? "'''" : null;
|
|
8047
|
+
if (delimiter2) {
|
|
8048
|
+
const closingIndex = findTomlMultilineDelimiter(line, delimiter2, index + delimiter2.length);
|
|
8049
|
+
return { wasInside: false, nextQuote: closingIndex === -1 ? delimiter2 : null };
|
|
8050
|
+
}
|
|
8051
|
+
if (char === '"' || char === "'")
|
|
8052
|
+
quote = char;
|
|
8053
|
+
index += 1;
|
|
8054
|
+
}
|
|
8055
|
+
return { wasInside: false, nextQuote: null };
|
|
8056
|
+
}
|
|
8057
|
+
function findTomlMultilineDelimiter(line, delimiter2, startIndex) {
|
|
8058
|
+
let index = line.indexOf(delimiter2, startIndex);
|
|
8059
|
+
while (index !== -1) {
|
|
8060
|
+
if (delimiter2 === "'''" || countPrecedingBackslashes(line, index) % 2 === 0)
|
|
8061
|
+
return index;
|
|
8062
|
+
index = line.indexOf(delimiter2, index + 1);
|
|
8063
|
+
}
|
|
8064
|
+
return -1;
|
|
8065
|
+
}
|
|
8066
|
+
function countPrecedingBackslashes(line, index) {
|
|
8067
|
+
let count = 0;
|
|
8068
|
+
let cursor = index - 1;
|
|
8069
|
+
while (cursor >= 0 && line[cursor] === "\\") {
|
|
8070
|
+
count += 1;
|
|
8071
|
+
cursor -= 1;
|
|
8072
|
+
}
|
|
8073
|
+
return count;
|
|
8074
|
+
}
|
|
8075
|
+
function findUnquotedAssignment(line) {
|
|
8076
|
+
return findUnquotedCharacter(line, "=", 0);
|
|
8077
|
+
}
|
|
8078
|
+
function findUnquotedComment(line, startIndex) {
|
|
8079
|
+
return findUnquotedCharacter(line, "#", startIndex);
|
|
8080
|
+
}
|
|
8081
|
+
function findUnquotedCharacter(line, target, startIndex) {
|
|
8082
|
+
let quote = null;
|
|
8083
|
+
let index = startIndex;
|
|
8084
|
+
while (index < line.length) {
|
|
8085
|
+
const char = line[index];
|
|
8086
|
+
if (quote === '"') {
|
|
8087
|
+
if (char === "\\") {
|
|
8088
|
+
index += 2;
|
|
8089
|
+
continue;
|
|
8090
|
+
}
|
|
8091
|
+
if (char === '"')
|
|
8092
|
+
quote = null;
|
|
8093
|
+
index += 1;
|
|
8094
|
+
continue;
|
|
8095
|
+
}
|
|
8096
|
+
if (quote === "'") {
|
|
8097
|
+
if (char === "'")
|
|
8098
|
+
quote = null;
|
|
8099
|
+
index += 1;
|
|
8100
|
+
continue;
|
|
8101
|
+
}
|
|
8102
|
+
if (char === '"' || char === "'") {
|
|
8103
|
+
quote = char;
|
|
8104
|
+
index += 1;
|
|
8105
|
+
continue;
|
|
8106
|
+
}
|
|
8107
|
+
if (char === target)
|
|
8108
|
+
return index;
|
|
8109
|
+
if (char === "#")
|
|
8110
|
+
return -1;
|
|
8111
|
+
index += 1;
|
|
8112
|
+
}
|
|
8113
|
+
return -1;
|
|
8114
|
+
}
|
|
8115
|
+
function tomlPathMatches(candidate, target) {
|
|
8116
|
+
return candidate.length === target.length && candidate.every((part, index) => part === target[index]);
|
|
8117
|
+
}
|
|
8118
|
+
function replaceTomlAssignmentValue(line, assignmentIndex, value) {
|
|
8119
|
+
const newline = line.endsWith(`
|
|
8120
|
+
`) ? `
|
|
8121
|
+
` : "";
|
|
8122
|
+
const lineBody = newline ? line.slice(0, -1) : line;
|
|
8123
|
+
const commentIndex = findUnquotedComment(lineBody, assignmentIndex + 1);
|
|
8124
|
+
const comment = commentIndex === -1 ? "" : ` ${lineBody.slice(commentIndex).trimStart()}`;
|
|
8125
|
+
return `${lineBody.slice(0, assignmentIndex + 1)} ${value}${comment}${newline}`;
|
|
8126
|
+
}
|
|
8127
|
+
function findTomlMultilineValueEnd(text, startOffset, quote) {
|
|
8128
|
+
const lines = text.slice(startOffset).match(/[^\n]*\n?|$/g) ?? [];
|
|
8129
|
+
let offset = startOffset;
|
|
8130
|
+
let currentQuote = quote;
|
|
8131
|
+
for (const line of lines) {
|
|
8132
|
+
if (line.length === 0)
|
|
8133
|
+
break;
|
|
8134
|
+
const scan = scanTomlMultilineLine(line, currentQuote);
|
|
8135
|
+
currentQuote = scan.nextQuote;
|
|
8136
|
+
offset += line.length;
|
|
8137
|
+
if (currentQuote === null)
|
|
8138
|
+
return offset;
|
|
8139
|
+
}
|
|
8140
|
+
return text.length;
|
|
8141
|
+
}
|
|
7930
8142
|
function stripUnquotedInlineComment(line) {
|
|
7931
8143
|
let quote = null;
|
|
7932
8144
|
let index = 0;
|
|
@@ -8257,13 +8469,137 @@ function delay(milliseconds) {
|
|
|
8257
8469
|
return new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds));
|
|
8258
8470
|
}
|
|
8259
8471
|
|
|
8472
|
+
// packages/omo-codex/src/install/toml-setting-reader.ts
|
|
8473
|
+
function hasTomlSetting(config, keyPath) {
|
|
8474
|
+
const targetPath = parseTomlDottedKey(keyPath);
|
|
8475
|
+
if (!targetPath)
|
|
8476
|
+
return false;
|
|
8477
|
+
return hasTomlAssignment(config, (tablePath, settingPath) => {
|
|
8478
|
+
const fullPath = [...tablePath, ...settingPath];
|
|
8479
|
+
return fullPath.length === targetPath.length && fullPath.every((part, index) => part === targetPath[index]);
|
|
8480
|
+
});
|
|
8481
|
+
}
|
|
8482
|
+
function hasTomlRootDottedKeyPrefix(config, rootKey) {
|
|
8483
|
+
return hasTomlAssignment(config, (tablePath, settingPath) => tablePath.length === 0 && settingPath.length > 1 && settingPath[0] === rootKey);
|
|
8484
|
+
}
|
|
8485
|
+
function hasTomlAssignment(config, predicate) {
|
|
8486
|
+
let tablePath = [];
|
|
8487
|
+
let multilineQuote = null;
|
|
8488
|
+
for (const line of config.split(`
|
|
8489
|
+
`)) {
|
|
8490
|
+
const multilineScan = scanTomlMultilineLine(line, multilineQuote);
|
|
8491
|
+
multilineQuote = multilineScan.nextQuote;
|
|
8492
|
+
if (multilineScan.wasInside)
|
|
8493
|
+
continue;
|
|
8494
|
+
const normalizedLine = stripUnquotedInlineComment2(line).trim();
|
|
8495
|
+
if (normalizedLine.length === 0)
|
|
8496
|
+
continue;
|
|
8497
|
+
const headerPath = parseTomlTableHeader2(normalizedLine);
|
|
8498
|
+
if (headerPath) {
|
|
8499
|
+
tablePath = headerPath;
|
|
8500
|
+
continue;
|
|
8501
|
+
}
|
|
8502
|
+
if (isTomlTableHeaderLine2(normalizedLine)) {
|
|
8503
|
+
tablePath = null;
|
|
8504
|
+
continue;
|
|
8505
|
+
}
|
|
8506
|
+
if (!tablePath)
|
|
8507
|
+
continue;
|
|
8508
|
+
const assignmentIndex = findUnquotedAssignment2(normalizedLine);
|
|
8509
|
+
if (assignmentIndex < 0)
|
|
8510
|
+
continue;
|
|
8511
|
+
const settingPath = parseTomlDottedKey(normalizedLine.slice(0, assignmentIndex).trim());
|
|
8512
|
+
if (!settingPath)
|
|
8513
|
+
continue;
|
|
8514
|
+
if (predicate(tablePath, settingPath))
|
|
8515
|
+
return true;
|
|
8516
|
+
}
|
|
8517
|
+
return false;
|
|
8518
|
+
}
|
|
8519
|
+
function parseTomlTableHeader2(line) {
|
|
8520
|
+
if (!line.startsWith("[") || !line.endsWith("]") || line.startsWith("[["))
|
|
8521
|
+
return null;
|
|
8522
|
+
return parseTomlDottedKey(line.slice(1, -1).trim());
|
|
8523
|
+
}
|
|
8524
|
+
function isTomlTableHeaderLine2(line) {
|
|
8525
|
+
return line.startsWith("[") && line.endsWith("]");
|
|
8526
|
+
}
|
|
8527
|
+
function stripUnquotedInlineComment2(line) {
|
|
8528
|
+
let quote = null;
|
|
8529
|
+
let index = 0;
|
|
8530
|
+
while (index < line.length) {
|
|
8531
|
+
const char = line[index];
|
|
8532
|
+
if (quote === '"') {
|
|
8533
|
+
if (char === "\\") {
|
|
8534
|
+
index += 2;
|
|
8535
|
+
continue;
|
|
8536
|
+
}
|
|
8537
|
+
if (char === '"')
|
|
8538
|
+
quote = null;
|
|
8539
|
+
index += 1;
|
|
8540
|
+
continue;
|
|
8541
|
+
}
|
|
8542
|
+
if (quote === "'") {
|
|
8543
|
+
if (char === "'")
|
|
8544
|
+
quote = null;
|
|
8545
|
+
index += 1;
|
|
8546
|
+
continue;
|
|
8547
|
+
}
|
|
8548
|
+
if (char === '"' || char === "'") {
|
|
8549
|
+
quote = char;
|
|
8550
|
+
index += 1;
|
|
8551
|
+
continue;
|
|
8552
|
+
}
|
|
8553
|
+
if (char === "#")
|
|
8554
|
+
return line.slice(0, index);
|
|
8555
|
+
index += 1;
|
|
8556
|
+
}
|
|
8557
|
+
return line;
|
|
8558
|
+
}
|
|
8559
|
+
function findUnquotedAssignment2(line) {
|
|
8560
|
+
let quote = null;
|
|
8561
|
+
let index = 0;
|
|
8562
|
+
while (index < line.length) {
|
|
8563
|
+
const char = line[index];
|
|
8564
|
+
if (quote === '"') {
|
|
8565
|
+
if (char === "\\") {
|
|
8566
|
+
index += 2;
|
|
8567
|
+
continue;
|
|
8568
|
+
}
|
|
8569
|
+
if (char === '"')
|
|
8570
|
+
quote = null;
|
|
8571
|
+
index += 1;
|
|
8572
|
+
continue;
|
|
8573
|
+
}
|
|
8574
|
+
if (quote === "'") {
|
|
8575
|
+
if (char === "'")
|
|
8576
|
+
quote = null;
|
|
8577
|
+
index += 1;
|
|
8578
|
+
continue;
|
|
8579
|
+
}
|
|
8580
|
+
if (char === '"' || char === "'") {
|
|
8581
|
+
quote = char;
|
|
8582
|
+
index += 1;
|
|
8583
|
+
continue;
|
|
8584
|
+
}
|
|
8585
|
+
if (char === "=")
|
|
8586
|
+
return index;
|
|
8587
|
+
index += 1;
|
|
8588
|
+
}
|
|
8589
|
+
return -1;
|
|
8590
|
+
}
|
|
8591
|
+
|
|
8260
8592
|
// packages/omo-codex/src/install/codex-config-features.ts
|
|
8261
8593
|
function ensureFeatureEnabled(config, featureName) {
|
|
8262
8594
|
const section = findTomlSection(config, "features");
|
|
8263
|
-
if (!section)
|
|
8595
|
+
if (!section) {
|
|
8596
|
+
if (hasTomlRootDottedKeyPrefix(config, "features")) {
|
|
8597
|
+
return replaceOrInsertRootDottedSetting(config, `features.${featureName}`, "true");
|
|
8598
|
+
}
|
|
8264
8599
|
return appendBlock(config, `[features]
|
|
8265
8600
|
${featureName} = true
|
|
8266
8601
|
`);
|
|
8602
|
+
}
|
|
8267
8603
|
return replaceOrInsertSetting(config, section, featureName, "true");
|
|
8268
8604
|
}
|
|
8269
8605
|
|
|
@@ -8331,7 +8667,7 @@ function ensureAutonomousPermissions(config) {
|
|
|
8331
8667
|
next = replaceOrInsertRootSetting(next, "sandbox_mode", JSON.stringify("danger-full-access"));
|
|
8332
8668
|
next = replaceOrInsertRootSetting(next, "network_access", JSON.stringify("enabled"));
|
|
8333
8669
|
for (const featureName of AUTONOMOUS_FEATURES) {
|
|
8334
|
-
next =
|
|
8670
|
+
next = ensureFeatureEnabled(next, featureName);
|
|
8335
8671
|
}
|
|
8336
8672
|
next = removeWindowsSandboxSetting(next);
|
|
8337
8673
|
next = ensureNoticeEnabled(next, "hide_full_access_warning");
|
|
@@ -8349,14 +8685,6 @@ function ensureNoticeEnabled(config, key) {
|
|
|
8349
8685
|
return appendNoticeBlock(config, key);
|
|
8350
8686
|
return replaceOrInsertSetting(config, section, key, "true");
|
|
8351
8687
|
}
|
|
8352
|
-
function ensureFeatureEnabled2(config, key) {
|
|
8353
|
-
const section = findTomlSection(config, "features");
|
|
8354
|
-
if (section === null)
|
|
8355
|
-
return appendBlock(config, `[features]
|
|
8356
|
-
${key} = true
|
|
8357
|
-
`);
|
|
8358
|
-
return replaceOrInsertSetting(config, section, key, "true");
|
|
8359
|
-
}
|
|
8360
8688
|
function appendNoticeBlock(config, key) {
|
|
8361
8689
|
return appendBlock(config, `[notice]
|
|
8362
8690
|
${key} = true
|
|
@@ -8428,7 +8756,7 @@ function readStringArraySetting(sectionText, key) {
|
|
|
8428
8756
|
const assignmentIndex = line.indexOf("=");
|
|
8429
8757
|
if (assignmentIndex === -1)
|
|
8430
8758
|
return null;
|
|
8431
|
-
return parseTomlStringArray(
|
|
8759
|
+
return parseTomlStringArray(stripUnquotedInlineComment3(line.slice(assignmentIndex + 1)).trim());
|
|
8432
8760
|
}
|
|
8433
8761
|
return null;
|
|
8434
8762
|
}
|
|
@@ -8472,7 +8800,7 @@ function parseTomlString(input, startIndex) {
|
|
|
8472
8800
|
}
|
|
8473
8801
|
return null;
|
|
8474
8802
|
}
|
|
8475
|
-
function
|
|
8803
|
+
function stripUnquotedInlineComment3(line) {
|
|
8476
8804
|
let quote = null;
|
|
8477
8805
|
let index = 0;
|
|
8478
8806
|
while (index < line.length) {
|
|
@@ -8686,24 +9014,27 @@ import { readFileSync } from "node:fs";
|
|
|
8686
9014
|
import { dirname as dirname7, isAbsolute as isAbsolute6, join as join18 } from "node:path";
|
|
8687
9015
|
var CODEX_AGENTS_HEADER = "agents";
|
|
8688
9016
|
var CODEX_MULTI_AGENT_V2_HEADER = "features.multi_agent_v2";
|
|
9017
|
+
var CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY = `${CODEX_MULTI_AGENT_V2_HEADER}.max_concurrent_threads_per_session`;
|
|
8689
9018
|
var CODEX_SUBAGENT_THREAD_LIMIT = 1000;
|
|
9019
|
+
var CODEX_MULTI_AGENT_V2_THREAD_LIMIT = 16;
|
|
8690
9020
|
function ensureCodexMultiAgentV2Config(config, options = {}) {
|
|
8691
9021
|
const featureFlag = removeFeatureFlagSetting(config, "multi_agent_v2");
|
|
8692
9022
|
const v2Preferred = options.multiAgentVersion === "v2";
|
|
8693
9023
|
const modelKnown = options.multiAgentVersion != null || readRootModel(featureFlag.config) !== null;
|
|
8694
9024
|
const agentsConfig = v2Preferred ? removeAgentsMaxThreads(featureFlag.config) : modelKnown ? ensureAgentsMaxThreads(featureFlag.config) : raiseExistingAgentsMaxThreads(featureFlag.config);
|
|
8695
|
-
const maxThreadsValue = CODEX_SUBAGENT_THREAD_LIMIT.toString();
|
|
8696
9025
|
const preserveDisable = featureFlag.value === false && !v2Preferred;
|
|
8697
9026
|
const featureConfig = preserveDisable ? setMultiAgentV2Disable(agentsConfig) : v2Preferred ? removeMultiAgentV2Disable(agentsConfig) : agentsConfig;
|
|
9027
|
+
if (hasTomlSetting(featureConfig, CODEX_MULTI_AGENT_V2_THREAD_LIMIT_KEY))
|
|
9028
|
+
return featureConfig;
|
|
8698
9029
|
const section = findTomlSection(featureConfig, CODEX_MULTI_AGENT_V2_HEADER);
|
|
8699
9030
|
if (!section) {
|
|
8700
9031
|
const enabledSetting = preserveDisable ? `enabled = false
|
|
8701
9032
|
` : "";
|
|
8702
9033
|
return appendBlock(featureConfig, `[${CODEX_MULTI_AGENT_V2_HEADER}]
|
|
8703
|
-
${enabledSetting}max_concurrent_threads_per_session = ${
|
|
9034
|
+
${enabledSetting}max_concurrent_threads_per_session = ${CODEX_MULTI_AGENT_V2_THREAD_LIMIT}
|
|
8704
9035
|
`);
|
|
8705
9036
|
}
|
|
8706
|
-
return replaceOrInsertSetting(featureConfig, section, "max_concurrent_threads_per_session",
|
|
9037
|
+
return replaceOrInsertSetting(featureConfig, section, "max_concurrent_threads_per_session", CODEX_MULTI_AGENT_V2_THREAD_LIMIT.toString());
|
|
8707
9038
|
}
|
|
8708
9039
|
function resolveCodexMultiAgentVersion(config, configPath) {
|
|
8709
9040
|
const model = readRootModel(config);
|
|
@@ -9061,6 +9392,10 @@ var MANAGED_REASONING_DEFAULT_UPGRADES = new Map([
|
|
|
9061
9392
|
{
|
|
9062
9393
|
previous: { model: "gpt-5.5", effort: "xhigh" },
|
|
9063
9394
|
current: { model: "gpt-5.6-sol", effort: "ultra" }
|
|
9395
|
+
},
|
|
9396
|
+
{
|
|
9397
|
+
previous: { model: "gpt-5.6-sol", effort: "ultra" },
|
|
9398
|
+
current: { model: "gpt-5.6-terra", effort: "high" }
|
|
9064
9399
|
}
|
|
9065
9400
|
]
|
|
9066
9401
|
],
|
|
@@ -75,7 +75,44 @@ test("#given no root model #when generated bundle updates config #then it does n
|
|
|
75
75
|
// then
|
|
76
76
|
const config = await readFile(configPath, "utf8");
|
|
77
77
|
assert.doesNotMatch(config, /^\s*max_threads\s*=/m);
|
|
78
|
-
assert.match(config, /max_concurrent_threads_per_session =
|
|
78
|
+
assert.match(config, /max_concurrent_threads_per_session = 16/);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("#given an inline-commented V2 thread cap #when generated bundle updates config twice #then preserves the line and ordering byte-for-byte", async () => {
|
|
82
|
+
// given
|
|
83
|
+
const root = await mkdtemp(join(tmpdir(), "omo-codex-generated-explicit-v2-cap-"));
|
|
84
|
+
const configPath = join(root, "config.toml");
|
|
85
|
+
await writeFile(
|
|
86
|
+
configPath,
|
|
87
|
+
[
|
|
88
|
+
"[features.multi_agent_v2]",
|
|
89
|
+
"usage_hint_enabled = false",
|
|
90
|
+
"max_concurrent_threads_per_session = 7 # user cap",
|
|
91
|
+
"show_tool_use = false",
|
|
92
|
+
"",
|
|
93
|
+
].join("\n"),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// when
|
|
97
|
+
const updateInput = {
|
|
98
|
+
configPath,
|
|
99
|
+
repoRoot: "/repo/packages/omo-codex",
|
|
100
|
+
marketplaceName: "debug",
|
|
101
|
+
marketplaceSource: { sourceType: "local", source: "/repo/packages/omo-codex" },
|
|
102
|
+
pluginNames: ["omo"],
|
|
103
|
+
};
|
|
104
|
+
await updateCodexConfig(updateInput);
|
|
105
|
+
const firstPass = await readFile(configPath, "utf8");
|
|
106
|
+
const firstV2Section = sectionText(firstPass, "[features.multi_agent_v2]");
|
|
107
|
+
await updateCodexConfig(updateInput);
|
|
108
|
+
|
|
109
|
+
// then
|
|
110
|
+
const secondPass = await readFile(configPath, "utf8");
|
|
111
|
+
assert.equal(sectionText(secondPass, "[features.multi_agent_v2]"), firstV2Section);
|
|
112
|
+
assert.match(
|
|
113
|
+
sectionText(secondPass, "[features.multi_agent_v2]"),
|
|
114
|
+
/usage_hint_enabled = false\nmax_concurrent_threads_per_session = 7 # user cap\nshow_tool_use = false/,
|
|
115
|
+
);
|
|
79
116
|
});
|
|
80
117
|
|
|
81
118
|
test("#given explicit v1 model_catalog_json and stale models_cache v2 #when generated bundle updates config #then explicit catalog preserves disable and cap", async () => {
|
|
@@ -153,7 +190,7 @@ test("#given explicit v2 model_catalog_json and stale models_cache v1 #when gene
|
|
|
153
190
|
const v2Section = sectionText(config, "[features.multi_agent_v2]");
|
|
154
191
|
assert.doesNotMatch(v2Section, /^enabled\s*=/m);
|
|
155
192
|
assert.doesNotMatch(config, /^\s*max_threads\s*=/m);
|
|
156
|
-
assert.match(v2Section, /max_concurrent_threads_per_session =
|
|
193
|
+
assert.match(v2Section, /max_concurrent_threads_per_session = 16/);
|
|
157
194
|
});
|
|
158
195
|
|
|
159
196
|
function sectionText(config, header) {
|
|
@@ -24,24 +24,28 @@ After grounding, make ONE judgment, record `intent: clear|unclear` plus `review_
|
|
|
24
24
|
|
|
25
25
|
- **OVERRIDE - explicit ask wins:** if the user explicitly asks to be questioned or interviewed ("ask me", "interview me", "why aren't you asking me" - in any language), route **CLEAR**, run the interview, and turn the adopt-default filter OFF: the user has claimed the forks, so every surviving one is ASKED, not defaulted. This beats the OUTCOME test below, even on a fuzzy brief.
|
|
26
26
|
- **CLEAR** - the user knows the outcome; the only open items are preferences/tradeoffs the repo cannot answer (genuine owner-decisions). Read **`references/intent-clear.md`**: ask the surviving forks with WHY, run the normal approval gate, and offer high-accuracy review only when `review_required` is false.
|
|
27
|
-
- **UNCLEAR** - the outcome itself is fuzzy (a vague brief, a bootstrap, `$start-work` with no selectable plan, a goal the user cannot yet articulate). Asking would offload your own job onto the user. Read **`references/intent-unclear.md`**: research maximally, adopt and ANNOUNCE best-practice defaults, do NOT ask the user extra questions, and
|
|
27
|
+
- **UNCLEAR** - the outcome itself is fuzzy (a vague brief, a bootstrap, `$start-work` with no selectable plan, a goal the user cannot yet articulate). Asking would offload your own job onto the user. Read **`references/intent-unclear.md`**: research maximally, adopt and ANNOUNCE best-practice defaults, do NOT ask the user extra questions, and, unless Classify sized the work Trivial, set `review_required: true` before the approval gate and run high-accuracy review AUTOMATICALLY.
|
|
28
28
|
- **ON THE FENCE** - when CLEAR vs UNCLEAR is genuinely ambiguous, treat it as CLEAR and ask exactly ONE question. A user wrongly silenced is worse than one extra question. The dominant failure to guard against is mis-routing a CLEAR request to UNCLEAR, which silently applies defaults and overrides forks the user wanted to own.
|
|
29
29
|
|
|
30
30
|
WORKED: "add a 5/min-per-IP rate-limit to `/login`" = CLEAR. "make auth better" = UNCLEAR.
|
|
31
31
|
|
|
32
32
|
Both intent paths ALSO read **`references/full-workflow.md`** for the shared mechanics - the plan template, the final verification wave, the APPEND protocol, and the full delegation/wait syntax. Read the phase you are in.
|
|
33
33
|
|
|
34
|
-
## RUN THE SCRIPT - do not hand-build
|
|
34
|
+
## RUN THE SCRIPT - do not hand-build artifacts
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
As soon as `<slug>` and intent are known, before recording draft state, RUN:
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
node "<skill-root>/scripts/scaffold-plan.mjs" <slug> [--clear|--unclear]
|
|
39
|
+
node "<skill-root>/scripts/scaffold-plan.mjs" <slug> [--clear|--unclear] --draft-only [--review-required]
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
(Replace `<skill-root>` with this skill's own directory; `bun` is
|
|
42
|
+
(Replace `<skill-root>` with this skill's own directory; `bun` is accepted.) This creates only `.omo/drafts/<slug>.md`, the compaction-safe resume point; it does not create a plan before approval. Include `--review-required` when an explicit modifier requires review or the classified route is non-Trivial UNCLEAR, so the first durable write contains the complete pending review request. After approval, rerun without `--draft-only` to create `.omo/plans/<slug>.md`, then **APPEND** task batches into `## Todos` - never rewrite script-emitted headers.
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
Both invocations are resume-safe no-ops for artifacts already present. Do NOT hand-build them; use `--reset` only for a structural reset (`--reset --force` discards edits). If a same-named non-artifact file exists, choose another slug.
|
|
45
|
+
|
|
46
|
+
## Plan artifact producer contract
|
|
47
|
+
|
|
48
|
+
When producing the plan, encode every executable item as a column-zero Markdown task row: implementation rows MUST match `- [ ] N. <title>` (where `N` is a positive decimal integer), and final-verifier rows MUST match `- [ ] F<number>. <title>`. Prose headings, numbered paragraphs, and ordinary bullets are not task substitutes and MUST NOT be counted as implementation or final-verifier tasks. Before handoff, run a structural self-check over the plan: verify that every implementation row and final-verifier row is column-zero, matches its required grammar, and appears in the intended `## Todos` or `## Final verification wave` section; verify that no prose heading or bullet is being used as a task; and repair the plan before handoff if any check fails.
|
|
45
49
|
|
|
46
50
|
## Universal invariants (hold on every path)
|
|
47
51
|
|
|
@@ -58,7 +62,7 @@ Run it ONCE at plan generation. A plain re-run on an existing plan is a safe no-
|
|
|
58
62
|
|
|
59
63
|
## Approval gate
|
|
60
64
|
|
|
61
|
-
When exploration is exhausted and the unknowns are answered, record the gate in the draft (`status: awaiting-approval`,
|
|
65
|
+
When exploration is exhausted and the unknowns are answered, record the gate in the draft (`status: awaiting-approval`, approach, and the next workflow action), present a short brief once, then **wait for the user's explicit okay**. Approval authorizes plan creation only; any already-required review runs afterward under its existing authorization. Full mechanics: `references/full-workflow.md`.
|
|
62
66
|
|
|
63
67
|
## Delegation (OpenCode-native)
|
|
64
68
|
|