opencode-repos 0.2.0 → 0.3.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.md +180 -0
- package/README.md +103 -3
- package/TODO.md +3 -0
- package/index.ts +1590 -158
- package/oh-my-opencode/.github/FUNDING.yml +15 -0
- package/oh-my-opencode/.github/ISSUE_TEMPLATE/bug_report.yml +129 -0
- package/oh-my-opencode/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/oh-my-opencode/.github/ISSUE_TEMPLATE/feature_request.yml +100 -0
- package/oh-my-opencode/.github/ISSUE_TEMPLATE/general.yml +83 -0
- package/oh-my-opencode/.github/assets/google.jpg +0 -0
- package/oh-my-opencode/.github/assets/hero.jpg +0 -0
- package/oh-my-opencode/.github/assets/indent.jpg +0 -0
- package/oh-my-opencode/.github/assets/microsoft.jpg +0 -0
- package/oh-my-opencode/.github/assets/omo.png +0 -0
- package/oh-my-opencode/.github/assets/orchestrator-atlas.png +0 -0
- package/oh-my-opencode/.github/assets/sisyphus.png +0 -0
- package/oh-my-opencode/.github/assets/sisyphuslabs.png +0 -0
- package/oh-my-opencode/.github/pull_request_template.md +34 -0
- package/oh-my-opencode/.github/workflows/ci.yml +138 -0
- package/oh-my-opencode/.github/workflows/cla.yml +41 -0
- package/oh-my-opencode/.github/workflows/lint-workflows.yml +22 -0
- package/oh-my-opencode/.github/workflows/publish.yml +165 -0
- package/oh-my-opencode/.github/workflows/sisyphus-agent.yml +500 -0
- package/oh-my-opencode/.opencode/background-tasks.json +27 -0
- package/oh-my-opencode/.opencode/command/get-unpublished-changes.md +84 -0
- package/oh-my-opencode/.opencode/command/omomomo.md +37 -0
- package/oh-my-opencode/.opencode/command/publish.md +257 -0
- package/oh-my-opencode/AGENTS.md +179 -0
- package/oh-my-opencode/CLA.md +58 -0
- package/oh-my-opencode/CONTRIBUTING.md +268 -0
- package/oh-my-opencode/LICENSE.md +82 -0
- package/oh-my-opencode/README.ja.md +370 -0
- package/oh-my-opencode/README.md +376 -0
- package/oh-my-opencode/README.zh-cn.md +380 -0
- package/oh-my-opencode/assets/oh-my-opencode.schema.json +2171 -0
- package/oh-my-opencode/bin/oh-my-opencode.js +80 -0
- package/oh-my-opencode/bin/platform.js +38 -0
- package/oh-my-opencode/bin/platform.test.ts +148 -0
- package/oh-my-opencode/bun.lock +314 -0
- package/oh-my-opencode/bunfig.toml +2 -0
- package/oh-my-opencode/docs/category-skill-guide.md +200 -0
- package/oh-my-opencode/docs/cli-guide.md +272 -0
- package/oh-my-opencode/docs/configurations.md +654 -0
- package/oh-my-opencode/docs/features.md +550 -0
- package/oh-my-opencode/docs/guide/installation.md +288 -0
- package/oh-my-opencode/docs/guide/overview.md +97 -0
- package/oh-my-opencode/docs/guide/understanding-orchestration-system.md +445 -0
- package/oh-my-opencode/docs/orchestration-guide.md +152 -0
- package/oh-my-opencode/docs/ultrawork-manifesto.md +197 -0
- package/oh-my-opencode/package.json +89 -0
- package/oh-my-opencode/packages/darwin-arm64/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/darwin-arm64/package.json +22 -0
- package/oh-my-opencode/packages/darwin-x64/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/darwin-x64/package.json +22 -0
- package/oh-my-opencode/packages/linux-arm64/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/linux-arm64/package.json +25 -0
- package/oh-my-opencode/packages/linux-arm64-musl/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/linux-arm64-musl/package.json +25 -0
- package/oh-my-opencode/packages/linux-x64/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/linux-x64/package.json +25 -0
- package/oh-my-opencode/packages/linux-x64-musl/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/linux-x64-musl/package.json +25 -0
- package/oh-my-opencode/packages/windows-x64/bin/.gitkeep +0 -0
- package/oh-my-opencode/packages/windows-x64/package.json +22 -0
- package/oh-my-opencode/postinstall.mjs +43 -0
- package/oh-my-opencode/script/build-binaries.ts +103 -0
- package/oh-my-opencode/script/build-schema.ts +28 -0
- package/oh-my-opencode/script/generate-changelog.ts +92 -0
- package/oh-my-opencode/script/publish.ts +344 -0
- package/oh-my-opencode/signatures/cla.json +676 -0
- package/oh-my-opencode/src/agents/AGENTS.md +67 -0
- package/oh-my-opencode/src/agents/atlas.ts +1383 -0
- package/oh-my-opencode/src/agents/dynamic-agent-prompt-builder.ts +400 -0
- package/oh-my-opencode/src/agents/explore.ts +122 -0
- package/oh-my-opencode/src/agents/index.ts +13 -0
- package/oh-my-opencode/src/agents/librarian.ts +326 -0
- package/oh-my-opencode/src/agents/metis.ts +315 -0
- package/oh-my-opencode/src/agents/momus.test.ts +57 -0
- package/oh-my-opencode/src/agents/momus.ts +444 -0
- package/oh-my-opencode/src/agents/multimodal-looker.ts +56 -0
- package/oh-my-opencode/src/agents/oracle.ts +122 -0
- package/oh-my-opencode/src/agents/prometheus-prompt.test.ts +22 -0
- package/oh-my-opencode/src/agents/prometheus-prompt.ts +1196 -0
- package/oh-my-opencode/src/agents/sisyphus-junior.test.ts +232 -0
- package/oh-my-opencode/src/agents/sisyphus-junior.ts +134 -0
- package/oh-my-opencode/src/agents/sisyphus.ts +633 -0
- package/oh-my-opencode/src/agents/types.ts +80 -0
- package/oh-my-opencode/src/agents/utils.test.ts +311 -0
- package/oh-my-opencode/src/agents/utils.ts +240 -0
- package/oh-my-opencode/src/cli/AGENTS.md +91 -0
- package/oh-my-opencode/src/cli/config-manager.test.ts +364 -0
- package/oh-my-opencode/src/cli/config-manager.ts +641 -0
- package/oh-my-opencode/src/cli/doctor/checks/auth.test.ts +114 -0
- package/oh-my-opencode/src/cli/doctor/checks/auth.ts +115 -0
- package/oh-my-opencode/src/cli/doctor/checks/config.test.ts +103 -0
- package/oh-my-opencode/src/cli/doctor/checks/config.ts +123 -0
- package/oh-my-opencode/src/cli/doctor/checks/dependencies.test.ts +152 -0
- package/oh-my-opencode/src/cli/doctor/checks/dependencies.ts +163 -0
- package/oh-my-opencode/src/cli/doctor/checks/gh.test.ts +151 -0
- package/oh-my-opencode/src/cli/doctor/checks/gh.ts +171 -0
- package/oh-my-opencode/src/cli/doctor/checks/index.ts +34 -0
- package/oh-my-opencode/src/cli/doctor/checks/lsp.test.ts +134 -0
- package/oh-my-opencode/src/cli/doctor/checks/lsp.ts +77 -0
- package/oh-my-opencode/src/cli/doctor/checks/mcp.test.ts +115 -0
- package/oh-my-opencode/src/cli/doctor/checks/mcp.ts +128 -0
- package/oh-my-opencode/src/cli/doctor/checks/opencode.test.ts +227 -0
- package/oh-my-opencode/src/cli/doctor/checks/opencode.ts +178 -0
- package/oh-my-opencode/src/cli/doctor/checks/plugin.test.ts +109 -0
- package/oh-my-opencode/src/cli/doctor/checks/plugin.ts +124 -0
- package/oh-my-opencode/src/cli/doctor/checks/version.test.ts +148 -0
- package/oh-my-opencode/src/cli/doctor/checks/version.ts +135 -0
- package/oh-my-opencode/src/cli/doctor/constants.ts +72 -0
- package/oh-my-opencode/src/cli/doctor/formatter.test.ts +218 -0
- package/oh-my-opencode/src/cli/doctor/formatter.ts +140 -0
- package/oh-my-opencode/src/cli/doctor/index.ts +11 -0
- package/oh-my-opencode/src/cli/doctor/runner.test.ts +153 -0
- package/oh-my-opencode/src/cli/doctor/runner.ts +132 -0
- package/oh-my-opencode/src/cli/doctor/types.ts +113 -0
- package/oh-my-opencode/src/cli/get-local-version/formatter.ts +66 -0
- package/oh-my-opencode/src/cli/get-local-version/index.ts +106 -0
- package/oh-my-opencode/src/cli/get-local-version/types.ts +14 -0
- package/oh-my-opencode/src/cli/index.ts +153 -0
- package/oh-my-opencode/src/cli/install.ts +523 -0
- package/oh-my-opencode/src/cli/model-fallback.ts +246 -0
- package/oh-my-opencode/src/cli/run/completion.test.ts +170 -0
- package/oh-my-opencode/src/cli/run/completion.ts +79 -0
- package/oh-my-opencode/src/cli/run/events.test.ts +155 -0
- package/oh-my-opencode/src/cli/run/events.ts +325 -0
- package/oh-my-opencode/src/cli/run/index.ts +2 -0
- package/oh-my-opencode/src/cli/run/runner.ts +159 -0
- package/oh-my-opencode/src/cli/run/types.ts +76 -0
- package/oh-my-opencode/src/cli/types.ts +40 -0
- package/oh-my-opencode/src/config/index.ts +26 -0
- package/oh-my-opencode/src/config/schema.test.ts +444 -0
- package/oh-my-opencode/src/config/schema.ts +339 -0
- package/oh-my-opencode/src/features/AGENTS.md +77 -0
- package/oh-my-opencode/src/features/background-agent/concurrency.test.ts +418 -0
- package/oh-my-opencode/src/features/background-agent/concurrency.ts +137 -0
- package/oh-my-opencode/src/features/background-agent/index.ts +3 -0
- package/oh-my-opencode/src/features/background-agent/manager.test.ts +1928 -0
- package/oh-my-opencode/src/features/background-agent/manager.ts +1335 -0
- package/oh-my-opencode/src/features/background-agent/types.ts +66 -0
- package/oh-my-opencode/src/features/boulder-state/constants.ts +13 -0
- package/oh-my-opencode/src/features/boulder-state/index.ts +3 -0
- package/oh-my-opencode/src/features/boulder-state/storage.test.ts +250 -0
- package/oh-my-opencode/src/features/boulder-state/storage.ts +150 -0
- package/oh-my-opencode/src/features/boulder-state/types.ts +26 -0
- package/oh-my-opencode/src/features/builtin-commands/commands.ts +89 -0
- package/oh-my-opencode/src/features/builtin-commands/index.ts +2 -0
- package/oh-my-opencode/src/features/builtin-commands/templates/init-deep.ts +300 -0
- package/oh-my-opencode/src/features/builtin-commands/templates/ralph-loop.ts +38 -0
- package/oh-my-opencode/src/features/builtin-commands/templates/refactor.ts +619 -0
- package/oh-my-opencode/src/features/builtin-commands/templates/start-work.ts +72 -0
- package/oh-my-opencode/src/features/builtin-commands/types.ts +9 -0
- package/oh-my-opencode/src/features/builtin-skills/frontend-ui-ux/SKILL.md +78 -0
- package/oh-my-opencode/src/features/builtin-skills/git-master/SKILL.md +1105 -0
- package/oh-my-opencode/src/features/builtin-skills/index.ts +2 -0
- package/oh-my-opencode/src/features/builtin-skills/skills.ts +1203 -0
- package/oh-my-opencode/src/features/builtin-skills/types.ts +16 -0
- package/oh-my-opencode/src/features/claude-code-agent-loader/index.ts +2 -0
- package/oh-my-opencode/src/features/claude-code-agent-loader/loader.ts +90 -0
- package/oh-my-opencode/src/features/claude-code-agent-loader/types.ts +17 -0
- package/oh-my-opencode/src/features/claude-code-command-loader/index.ts +2 -0
- package/oh-my-opencode/src/features/claude-code-command-loader/loader.ts +144 -0
- package/oh-my-opencode/src/features/claude-code-command-loader/types.ts +46 -0
- package/oh-my-opencode/src/features/claude-code-mcp-loader/env-expander.ts +27 -0
- package/oh-my-opencode/src/features/claude-code-mcp-loader/index.ts +11 -0
- package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.test.ts +162 -0
- package/oh-my-opencode/src/features/claude-code-mcp-loader/loader.ts +113 -0
- package/oh-my-opencode/src/features/claude-code-mcp-loader/transformer.ts +53 -0
- package/oh-my-opencode/src/features/claude-code-mcp-loader/types.ts +42 -0
- package/oh-my-opencode/src/features/claude-code-plugin-loader/index.ts +3 -0
- package/oh-my-opencode/src/features/claude-code-plugin-loader/loader.ts +486 -0
- package/oh-my-opencode/src/features/claude-code-plugin-loader/types.ts +210 -0
- package/oh-my-opencode/src/features/claude-code-session-state/index.ts +1 -0
- package/oh-my-opencode/src/features/claude-code-session-state/state.test.ts +126 -0
- package/oh-my-opencode/src/features/claude-code-session-state/state.ts +37 -0
- package/oh-my-opencode/src/features/context-injector/collector.test.ts +330 -0
- package/oh-my-opencode/src/features/context-injector/collector.ts +85 -0
- package/oh-my-opencode/src/features/context-injector/index.ts +14 -0
- package/oh-my-opencode/src/features/context-injector/injector.test.ts +122 -0
- package/oh-my-opencode/src/features/context-injector/injector.ts +167 -0
- package/oh-my-opencode/src/features/context-injector/types.ts +91 -0
- package/oh-my-opencode/src/features/hook-message-injector/constants.ts +6 -0
- package/oh-my-opencode/src/features/hook-message-injector/index.ts +4 -0
- package/oh-my-opencode/src/features/hook-message-injector/injector.ts +195 -0
- package/oh-my-opencode/src/features/hook-message-injector/types.ts +47 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.test.ts +448 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/async-loader.ts +180 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/blocking.test.ts +210 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/blocking.ts +62 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/discover-worker.ts +59 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/index.ts +4 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/loader.test.ts +273 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/loader.ts +259 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/merger.ts +267 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.test.ts +267 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/skill-content.ts +206 -0
- package/oh-my-opencode/src/features/opencode-skill-loader/types.ts +38 -0
- package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.test.ts +201 -0
- package/oh-my-opencode/src/features/skill-mcp-manager/env-cleaner.ts +27 -0
- package/oh-my-opencode/src/features/skill-mcp-manager/index.ts +2 -0
- package/oh-my-opencode/src/features/skill-mcp-manager/manager.test.ts +611 -0
- package/oh-my-opencode/src/features/skill-mcp-manager/manager.ts +520 -0
- package/oh-my-opencode/src/features/skill-mcp-manager/types.ts +14 -0
- package/oh-my-opencode/src/features/task-toast-manager/index.ts +2 -0
- package/oh-my-opencode/src/features/task-toast-manager/manager.test.ts +249 -0
- package/oh-my-opencode/src/features/task-toast-manager/manager.ts +215 -0
- package/oh-my-opencode/src/features/task-toast-manager/types.ts +24 -0
- package/oh-my-opencode/src/hooks/AGENTS.md +73 -0
- package/oh-my-opencode/src/hooks/agent-usage-reminder/constants.ts +54 -0
- package/oh-my-opencode/src/hooks/agent-usage-reminder/index.ts +109 -0
- package/oh-my-opencode/src/hooks/agent-usage-reminder/storage.ts +42 -0
- package/oh-my-opencode/src/hooks/agent-usage-reminder/types.ts +6 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.test.ts +307 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/executor.ts +485 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/index.ts +151 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/parser.ts +201 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.test.ts +33 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-deduplication.ts +184 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/pruning-types.ts +44 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.test.ts +77 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/storage.ts +250 -0
- package/oh-my-opencode/src/hooks/anthropic-context-window-limit-recovery/types.ts +42 -0
- package/oh-my-opencode/src/hooks/atlas/index.test.ts +953 -0
- package/oh-my-opencode/src/hooks/atlas/index.ts +771 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/constants.ts +12 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/detector.test.ts +296 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/detector.ts +65 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/executor.ts +205 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/index.test.ts +254 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/index.ts +89 -0
- package/oh-my-opencode/src/hooks/auto-slash-command/types.ts +23 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/cache.ts +93 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/checker.test.ts +24 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/checker.ts +284 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/constants.ts +64 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/index.test.ts +254 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/index.ts +260 -0
- package/oh-my-opencode/src/hooks/auto-update-checker/types.ts +29 -0
- package/oh-my-opencode/src/hooks/background-compaction/index.ts +87 -0
- package/oh-my-opencode/src/hooks/background-notification/index.ts +28 -0
- package/oh-my-opencode/src/hooks/background-notification/types.ts +5 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/AGENTS.md +70 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/config-loader.ts +107 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/config.ts +103 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/index.ts +401 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/plugin-config.ts +12 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/post-tool-use.ts +199 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/pre-compact.ts +109 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/pre-tool-use.ts +172 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/stop.ts +118 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/todo.ts +76 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/tool-input-cache.ts +47 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/transcript.ts +252 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/types.ts +204 -0
- package/oh-my-opencode/src/hooks/claude-code-hooks/user-prompt-submit.ts +117 -0
- package/oh-my-opencode/src/hooks/comment-checker/cli.test.ts +68 -0
- package/oh-my-opencode/src/hooks/comment-checker/cli.ts +221 -0
- package/oh-my-opencode/src/hooks/comment-checker/downloader.ts +196 -0
- package/oh-my-opencode/src/hooks/comment-checker/index.ts +171 -0
- package/oh-my-opencode/src/hooks/comment-checker/types.ts +33 -0
- package/oh-my-opencode/src/hooks/compaction-context-injector/index.ts +61 -0
- package/oh-my-opencode/src/hooks/context-window-monitor.ts +99 -0
- package/oh-my-opencode/src/hooks/delegate-task-retry/index.test.ts +119 -0
- package/oh-my-opencode/src/hooks/delegate-task-retry/index.ts +136 -0
- package/oh-my-opencode/src/hooks/directory-agents-injector/constants.ts +9 -0
- package/oh-my-opencode/src/hooks/directory-agents-injector/index.ts +182 -0
- package/oh-my-opencode/src/hooks/directory-agents-injector/storage.ts +48 -0
- package/oh-my-opencode/src/hooks/directory-agents-injector/types.ts +5 -0
- package/oh-my-opencode/src/hooks/directory-readme-injector/constants.ts +9 -0
- package/oh-my-opencode/src/hooks/directory-readme-injector/index.ts +177 -0
- package/oh-my-opencode/src/hooks/directory-readme-injector/storage.ts +48 -0
- package/oh-my-opencode/src/hooks/directory-readme-injector/types.ts +5 -0
- package/oh-my-opencode/src/hooks/edit-error-recovery/index.test.ts +126 -0
- package/oh-my-opencode/src/hooks/edit-error-recovery/index.ts +57 -0
- package/oh-my-opencode/src/hooks/empty-task-response-detector.ts +27 -0
- package/oh-my-opencode/src/hooks/index.ts +32 -0
- package/oh-my-opencode/src/hooks/interactive-bash-session/constants.ts +15 -0
- package/oh-my-opencode/src/hooks/interactive-bash-session/index.ts +262 -0
- package/oh-my-opencode/src/hooks/interactive-bash-session/storage.ts +59 -0
- package/oh-my-opencode/src/hooks/interactive-bash-session/types.ts +11 -0
- package/oh-my-opencode/src/hooks/keyword-detector/constants.ts +300 -0
- package/oh-my-opencode/src/hooks/keyword-detector/detector.ts +52 -0
- package/oh-my-opencode/src/hooks/keyword-detector/index.test.ts +529 -0
- package/oh-my-opencode/src/hooks/keyword-detector/index.ts +100 -0
- package/oh-my-opencode/src/hooks/keyword-detector/types.ts +4 -0
- package/oh-my-opencode/src/hooks/non-interactive-env/constants.ts +70 -0
- package/oh-my-opencode/src/hooks/non-interactive-env/detector.ts +19 -0
- package/oh-my-opencode/src/hooks/non-interactive-env/index.test.ts +323 -0
- package/oh-my-opencode/src/hooks/non-interactive-env/index.ts +63 -0
- package/oh-my-opencode/src/hooks/non-interactive-env/types.ts +3 -0
- package/oh-my-opencode/src/hooks/prometheus-md-only/constants.ts +32 -0
- package/oh-my-opencode/src/hooks/prometheus-md-only/index.test.ts +488 -0
- package/oh-my-opencode/src/hooks/prometheus-md-only/index.ts +136 -0
- package/oh-my-opencode/src/hooks/ralph-loop/constants.ts +5 -0
- package/oh-my-opencode/src/hooks/ralph-loop/index.test.ts +835 -0
- package/oh-my-opencode/src/hooks/ralph-loop/index.ts +417 -0
- package/oh-my-opencode/src/hooks/ralph-loop/storage.ts +115 -0
- package/oh-my-opencode/src/hooks/ralph-loop/types.ts +19 -0
- package/oh-my-opencode/src/hooks/rules-injector/constants.ts +30 -0
- package/oh-my-opencode/src/hooks/rules-injector/finder.test.ts +381 -0
- package/oh-my-opencode/src/hooks/rules-injector/finder.ts +263 -0
- package/oh-my-opencode/src/hooks/rules-injector/index.ts +223 -0
- package/oh-my-opencode/src/hooks/rules-injector/matcher.ts +63 -0
- package/oh-my-opencode/src/hooks/rules-injector/parser.test.ts +226 -0
- package/oh-my-opencode/src/hooks/rules-injector/parser.ts +211 -0
- package/oh-my-opencode/src/hooks/rules-injector/storage.ts +59 -0
- package/oh-my-opencode/src/hooks/rules-injector/types.ts +57 -0
- package/oh-my-opencode/src/hooks/session-notification-utils.ts +140 -0
- package/oh-my-opencode/src/hooks/session-notification.test.ts +361 -0
- package/oh-my-opencode/src/hooks/session-notification.ts +330 -0
- package/oh-my-opencode/src/hooks/session-recovery/constants.ts +10 -0
- package/oh-my-opencode/src/hooks/session-recovery/index.test.ts +223 -0
- package/oh-my-opencode/src/hooks/session-recovery/index.ts +435 -0
- package/oh-my-opencode/src/hooks/session-recovery/storage.ts +390 -0
- package/oh-my-opencode/src/hooks/session-recovery/types.ts +98 -0
- package/oh-my-opencode/src/hooks/start-work/index.test.ts +402 -0
- package/oh-my-opencode/src/hooks/start-work/index.ts +242 -0
- package/oh-my-opencode/src/hooks/task-resume-info/index.ts +36 -0
- package/oh-my-opencode/src/hooks/think-mode/detector.ts +57 -0
- package/oh-my-opencode/src/hooks/think-mode/index.test.ts +353 -0
- package/oh-my-opencode/src/hooks/think-mode/index.ts +89 -0
- package/oh-my-opencode/src/hooks/think-mode/switcher.test.ts +461 -0
- package/oh-my-opencode/src/hooks/think-mode/switcher.ts +222 -0
- package/oh-my-opencode/src/hooks/think-mode/types.ts +21 -0
- package/oh-my-opencode/src/hooks/thinking-block-validator/index.ts +171 -0
- package/oh-my-opencode/src/hooks/todo-continuation-enforcer.test.ts +876 -0
- package/oh-my-opencode/src/hooks/todo-continuation-enforcer.ts +480 -0
- package/oh-my-opencode/src/hooks/tool-output-truncator.test.ts +168 -0
- package/oh-my-opencode/src/hooks/tool-output-truncator.ts +61 -0
- package/oh-my-opencode/src/index.ts +589 -0
- package/oh-my-opencode/src/mcp/AGENTS.md +70 -0
- package/oh-my-opencode/src/mcp/context7.ts +6 -0
- package/oh-my-opencode/src/mcp/grep-app.ts +6 -0
- package/oh-my-opencode/src/mcp/index.test.ts +86 -0
- package/oh-my-opencode/src/mcp/index.ts +32 -0
- package/oh-my-opencode/src/mcp/types.ts +9 -0
- package/oh-my-opencode/src/mcp/websearch.ts +10 -0
- package/oh-my-opencode/src/plugin-config.test.ts +119 -0
- package/oh-my-opencode/src/plugin-config.ts +135 -0
- package/oh-my-opencode/src/plugin-handlers/config-handler.test.ts +103 -0
- package/oh-my-opencode/src/plugin-handlers/config-handler.ts +399 -0
- package/oh-my-opencode/src/plugin-handlers/index.ts +1 -0
- package/oh-my-opencode/src/plugin-state.ts +30 -0
- package/oh-my-opencode/src/shared/AGENTS.md +63 -0
- package/oh-my-opencode/src/shared/agent-tool-restrictions.ts +44 -0
- package/oh-my-opencode/src/shared/agent-variant.test.ts +83 -0
- package/oh-my-opencode/src/shared/agent-variant.ts +40 -0
- package/oh-my-opencode/src/shared/claude-config-dir.test.ts +60 -0
- package/oh-my-opencode/src/shared/claude-config-dir.ts +11 -0
- package/oh-my-opencode/src/shared/command-executor.ts +225 -0
- package/oh-my-opencode/src/shared/config-errors.ts +18 -0
- package/oh-my-opencode/src/shared/config-path.ts +47 -0
- package/oh-my-opencode/src/shared/data-path.ts +22 -0
- package/oh-my-opencode/src/shared/deep-merge.test.ts +336 -0
- package/oh-my-opencode/src/shared/deep-merge.ts +53 -0
- package/oh-my-opencode/src/shared/dynamic-truncator.ts +193 -0
- package/oh-my-opencode/src/shared/external-plugin-detector.test.ts +133 -0
- package/oh-my-opencode/src/shared/external-plugin-detector.ts +132 -0
- package/oh-my-opencode/src/shared/file-reference-resolver.ts +85 -0
- package/oh-my-opencode/src/shared/file-utils.ts +40 -0
- package/oh-my-opencode/src/shared/first-message-variant.test.ts +32 -0
- package/oh-my-opencode/src/shared/first-message-variant.ts +28 -0
- package/oh-my-opencode/src/shared/frontmatter.test.ts +262 -0
- package/oh-my-opencode/src/shared/frontmatter.ts +31 -0
- package/oh-my-opencode/src/shared/hook-disabled.ts +22 -0
- package/oh-my-opencode/src/shared/index.ts +29 -0
- package/oh-my-opencode/src/shared/jsonc-parser.test.ts +266 -0
- package/oh-my-opencode/src/shared/jsonc-parser.ts +66 -0
- package/oh-my-opencode/src/shared/logger.ts +20 -0
- package/oh-my-opencode/src/shared/migration.test.ts +602 -0
- package/oh-my-opencode/src/shared/migration.ts +191 -0
- package/oh-my-opencode/src/shared/model-resolver.test.ts +101 -0
- package/oh-my-opencode/src/shared/model-resolver.ts +35 -0
- package/oh-my-opencode/src/shared/model-sanitizer.ts +12 -0
- package/oh-my-opencode/src/shared/opencode-config-dir.test.ts +318 -0
- package/oh-my-opencode/src/shared/opencode-config-dir.ts +142 -0
- package/oh-my-opencode/src/shared/opencode-version.test.ts +223 -0
- package/oh-my-opencode/src/shared/opencode-version.ts +72 -0
- package/oh-my-opencode/src/shared/pattern-matcher.ts +29 -0
- package/oh-my-opencode/src/shared/permission-compat.test.ts +134 -0
- package/oh-my-opencode/src/shared/permission-compat.ts +77 -0
- package/oh-my-opencode/src/shared/session-cursor.test.ts +66 -0
- package/oh-my-opencode/src/shared/session-cursor.ts +85 -0
- package/oh-my-opencode/src/shared/shell-env.test.ts +278 -0
- package/oh-my-opencode/src/shared/shell-env.ts +111 -0
- package/oh-my-opencode/src/shared/snake-case.ts +49 -0
- package/oh-my-opencode/src/shared/system-directive.ts +40 -0
- package/oh-my-opencode/src/shared/tool-name.ts +26 -0
- package/oh-my-opencode/src/shared/zip-extractor.ts +83 -0
- package/oh-my-opencode/src/tools/AGENTS.md +74 -0
- package/oh-my-opencode/src/tools/ast-grep/cli.ts +230 -0
- package/oh-my-opencode/src/tools/ast-grep/constants.ts +261 -0
- package/oh-my-opencode/src/tools/ast-grep/downloader.ts +128 -0
- package/oh-my-opencode/src/tools/ast-grep/index.ts +13 -0
- package/oh-my-opencode/src/tools/ast-grep/tools.ts +112 -0
- package/oh-my-opencode/src/tools/ast-grep/types.ts +61 -0
- package/oh-my-opencode/src/tools/ast-grep/utils.ts +102 -0
- package/oh-my-opencode/src/tools/background-task/constants.ts +7 -0
- package/oh-my-opencode/src/tools/background-task/index.ts +7 -0
- package/oh-my-opencode/src/tools/background-task/tools.ts +479 -0
- package/oh-my-opencode/src/tools/background-task/types.ts +16 -0
- package/oh-my-opencode/src/tools/call-omo-agent/constants.ts +7 -0
- package/oh-my-opencode/src/tools/call-omo-agent/index.ts +3 -0
- package/oh-my-opencode/src/tools/call-omo-agent/tools.ts +338 -0
- package/oh-my-opencode/src/tools/call-omo-agent/types.ts +27 -0
- package/oh-my-opencode/src/tools/delegate-task/constants.ts +205 -0
- package/oh-my-opencode/src/tools/delegate-task/index.ts +3 -0
- package/oh-my-opencode/src/tools/delegate-task/tools.test.ts +1575 -0
- package/oh-my-opencode/src/tools/delegate-task/tools.ts +885 -0
- package/oh-my-opencode/src/tools/delegate-task/types.ts +9 -0
- package/oh-my-opencode/src/tools/glob/cli.test.ts +158 -0
- package/oh-my-opencode/src/tools/glob/cli.ts +191 -0
- package/oh-my-opencode/src/tools/glob/constants.ts +12 -0
- package/oh-my-opencode/src/tools/glob/index.ts +3 -0
- package/oh-my-opencode/src/tools/glob/tools.ts +41 -0
- package/oh-my-opencode/src/tools/glob/types.ts +22 -0
- package/oh-my-opencode/src/tools/glob/utils.ts +26 -0
- package/oh-my-opencode/src/tools/grep/cli.ts +229 -0
- package/oh-my-opencode/src/tools/grep/constants.ts +127 -0
- package/oh-my-opencode/src/tools/grep/downloader.test.ts +103 -0
- package/oh-my-opencode/src/tools/grep/downloader.ts +145 -0
- package/oh-my-opencode/src/tools/grep/index.ts +3 -0
- package/oh-my-opencode/src/tools/grep/tools.ts +40 -0
- package/oh-my-opencode/src/tools/grep/types.ts +39 -0
- package/oh-my-opencode/src/tools/grep/utils.ts +53 -0
- package/oh-my-opencode/src/tools/index.ts +72 -0
- package/oh-my-opencode/src/tools/interactive-bash/constants.ts +18 -0
- package/oh-my-opencode/src/tools/interactive-bash/index.ts +4 -0
- package/oh-my-opencode/src/tools/interactive-bash/tools.ts +126 -0
- package/oh-my-opencode/src/tools/interactive-bash/utils.ts +71 -0
- package/oh-my-opencode/src/tools/look-at/constants.ts +3 -0
- package/oh-my-opencode/src/tools/look-at/index.ts +3 -0
- package/oh-my-opencode/src/tools/look-at/tools.test.ts +73 -0
- package/oh-my-opencode/src/tools/look-at/tools.ts +173 -0
- package/oh-my-opencode/src/tools/look-at/types.ts +4 -0
- package/oh-my-opencode/src/tools/lsp/client.ts +596 -0
- package/oh-my-opencode/src/tools/lsp/config.test.ts +130 -0
- package/oh-my-opencode/src/tools/lsp/config.ts +285 -0
- package/oh-my-opencode/src/tools/lsp/constants.ts +390 -0
- package/oh-my-opencode/src/tools/lsp/index.ts +7 -0
- package/oh-my-opencode/src/tools/lsp/tools.ts +261 -0
- package/oh-my-opencode/src/tools/lsp/types.ts +124 -0
- package/oh-my-opencode/src/tools/lsp/utils.ts +406 -0
- package/oh-my-opencode/src/tools/session-manager/constants.ts +97 -0
- package/oh-my-opencode/src/tools/session-manager/index.ts +3 -0
- package/oh-my-opencode/src/tools/session-manager/storage.test.ts +315 -0
- package/oh-my-opencode/src/tools/session-manager/storage.ts +238 -0
- package/oh-my-opencode/src/tools/session-manager/tools.test.ts +124 -0
- package/oh-my-opencode/src/tools/session-manager/tools.ts +146 -0
- package/oh-my-opencode/src/tools/session-manager/types.ts +99 -0
- package/oh-my-opencode/src/tools/session-manager/utils.test.ts +160 -0
- package/oh-my-opencode/src/tools/session-manager/utils.ts +199 -0
- package/oh-my-opencode/src/tools/skill/constants.ts +8 -0
- package/oh-my-opencode/src/tools/skill/index.ts +3 -0
- package/oh-my-opencode/src/tools/skill/tools.test.ts +239 -0
- package/oh-my-opencode/src/tools/skill/tools.ts +200 -0
- package/oh-my-opencode/src/tools/skill/types.ts +31 -0
- package/oh-my-opencode/src/tools/skill-mcp/constants.ts +3 -0
- package/oh-my-opencode/src/tools/skill-mcp/index.ts +3 -0
- package/oh-my-opencode/src/tools/skill-mcp/tools.test.ts +215 -0
- package/oh-my-opencode/src/tools/skill-mcp/tools.ts +172 -0
- package/oh-my-opencode/src/tools/skill-mcp/types.ts +8 -0
- package/oh-my-opencode/src/tools/slashcommand/index.ts +2 -0
- package/oh-my-opencode/src/tools/slashcommand/tools.ts +252 -0
- package/oh-my-opencode/src/tools/slashcommand/types.ts +28 -0
- package/oh-my-opencode/test-setup.ts +6 -0
- package/oh-my-opencode/tsconfig.json +20 -0
- package/package.json +1 -1
- package/src/__tests__/git.test.ts +7 -2
- package/src/__tests__/manifest.test.ts +5 -5
- package/src/agents/repo-explorer.ts +2 -1
- package/src/git.ts +18 -3
- package/src/manifest.ts +22 -15
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, mock } from "bun:test"
|
|
2
|
+
import { TaskToastManager } from "./manager"
|
|
3
|
+
import type { ConcurrencyManager } from "../background-agent/concurrency"
|
|
4
|
+
|
|
5
|
+
describe("TaskToastManager", () => {
|
|
6
|
+
let mockClient: {
|
|
7
|
+
tui: {
|
|
8
|
+
showToast: ReturnType<typeof mock>
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
let toastManager: TaskToastManager
|
|
12
|
+
let mockConcurrencyManager: ConcurrencyManager
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
mockClient = {
|
|
16
|
+
tui: {
|
|
17
|
+
showToast: mock(() => Promise.resolve()),
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
mockConcurrencyManager = {
|
|
21
|
+
getConcurrencyLimit: mock(() => 5),
|
|
22
|
+
} as unknown as ConcurrencyManager
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
toastManager = new TaskToastManager(mockClient as any, mockConcurrencyManager)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe("skills in toast message", () => {
|
|
28
|
+
test("should display skills when provided", () => {
|
|
29
|
+
// #given - a task with skills
|
|
30
|
+
const task = {
|
|
31
|
+
id: "task_1",
|
|
32
|
+
description: "Test task",
|
|
33
|
+
agent: "Sisyphus-Junior",
|
|
34
|
+
isBackground: true,
|
|
35
|
+
skills: ["playwright", "git-master"],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// #when - addTask is called
|
|
39
|
+
toastManager.addTask(task)
|
|
40
|
+
|
|
41
|
+
// #then - toast message should include skills
|
|
42
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
43
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
44
|
+
expect(call.body.message).toContain("playwright")
|
|
45
|
+
expect(call.body.message).toContain("git-master")
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test("should not display skills section when no skills provided", () => {
|
|
49
|
+
// #given - a task without skills
|
|
50
|
+
const task = {
|
|
51
|
+
id: "task_2",
|
|
52
|
+
description: "Test task without skills",
|
|
53
|
+
agent: "explore",
|
|
54
|
+
isBackground: true,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// #when - addTask is called
|
|
58
|
+
toastManager.addTask(task)
|
|
59
|
+
|
|
60
|
+
// #then - toast message should not include skills prefix
|
|
61
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
62
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
63
|
+
expect(call.body.message).not.toContain("Skills:")
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
describe("concurrency info in toast message", () => {
|
|
68
|
+
test("should display concurrency status in toast", () => {
|
|
69
|
+
// #given - multiple running tasks
|
|
70
|
+
toastManager.addTask({
|
|
71
|
+
id: "task_1",
|
|
72
|
+
description: "First task",
|
|
73
|
+
agent: "explore",
|
|
74
|
+
isBackground: true,
|
|
75
|
+
})
|
|
76
|
+
toastManager.addTask({
|
|
77
|
+
id: "task_2",
|
|
78
|
+
description: "Second task",
|
|
79
|
+
agent: "librarian",
|
|
80
|
+
isBackground: true,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// #when - third task is added
|
|
84
|
+
toastManager.addTask({
|
|
85
|
+
id: "task_3",
|
|
86
|
+
description: "Third task",
|
|
87
|
+
agent: "explore",
|
|
88
|
+
isBackground: true,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// #then - toast should show concurrency info
|
|
92
|
+
expect(mockClient.tui.showToast).toHaveBeenCalledTimes(3)
|
|
93
|
+
const lastCall = mockClient.tui.showToast.mock.calls[2][0]
|
|
94
|
+
// Should show "Running (3):" header
|
|
95
|
+
expect(lastCall.body.message).toContain("Running (3):")
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test("should display concurrency limit info when available", () => {
|
|
99
|
+
// #given - a concurrency manager with known limit
|
|
100
|
+
const mockConcurrencyWithCounts = {
|
|
101
|
+
getConcurrencyLimit: mock(() => 5),
|
|
102
|
+
getRunningCount: mock(() => 2),
|
|
103
|
+
getQueuedCount: mock(() => 1),
|
|
104
|
+
} as unknown as ConcurrencyManager
|
|
105
|
+
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
|
+
const managerWithConcurrency = new TaskToastManager(mockClient as any, mockConcurrencyWithCounts)
|
|
108
|
+
|
|
109
|
+
// #when - a task is added
|
|
110
|
+
managerWithConcurrency.addTask({
|
|
111
|
+
id: "task_1",
|
|
112
|
+
description: "Test task",
|
|
113
|
+
agent: "explore",
|
|
114
|
+
isBackground: true,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
// #then - toast should show concurrency status like "2/5 slots"
|
|
118
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
119
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
120
|
+
expect(call.body.message).toMatch(/\d+\/\d+/)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe("combined skills and concurrency display", () => {
|
|
125
|
+
test("should display both skills and concurrency info together", () => {
|
|
126
|
+
// #given - a task with skills and concurrency manager
|
|
127
|
+
const task = {
|
|
128
|
+
id: "task_1",
|
|
129
|
+
description: "Full info task",
|
|
130
|
+
agent: "Sisyphus-Junior",
|
|
131
|
+
isBackground: true,
|
|
132
|
+
skills: ["frontend-ui-ux"],
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// #when - addTask is called
|
|
136
|
+
toastManager.addTask(task)
|
|
137
|
+
|
|
138
|
+
// #then - toast should include both skills and task count
|
|
139
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
140
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
141
|
+
expect(call.body.message).toContain("frontend-ui-ux")
|
|
142
|
+
expect(call.body.message).toContain("Running (1):")
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
describe("model fallback info in toast message", () => {
|
|
147
|
+
test("should NOT display warning when model is category-default (normal behavior)", () => {
|
|
148
|
+
// #given - category-default is the intended behavior, not a fallback
|
|
149
|
+
const task = {
|
|
150
|
+
id: "task_1",
|
|
151
|
+
description: "Task with category default model",
|
|
152
|
+
agent: "Sisyphus-Junior",
|
|
153
|
+
isBackground: false,
|
|
154
|
+
modelInfo: { model: "google/gemini-3-pro-preview", type: "category-default" as const },
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// #when - addTask is called
|
|
158
|
+
toastManager.addTask(task)
|
|
159
|
+
|
|
160
|
+
// #then - toast should NOT show warning - category default is expected
|
|
161
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
162
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
163
|
+
expect(call.body.message).not.toContain("⚠️")
|
|
164
|
+
expect(call.body.message).not.toContain("(category default)")
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
test("should display warning when model falls back to system-default", () => {
|
|
168
|
+
// #given - system-default is a fallback (no category default, no user config)
|
|
169
|
+
const task = {
|
|
170
|
+
id: "task_1b",
|
|
171
|
+
description: "Task with system default model",
|
|
172
|
+
agent: "Sisyphus-Junior",
|
|
173
|
+
isBackground: false,
|
|
174
|
+
modelInfo: { model: "anthropic/claude-sonnet-4-5", type: "system-default" as const },
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// #when - addTask is called
|
|
178
|
+
toastManager.addTask(task)
|
|
179
|
+
|
|
180
|
+
// #then - toast should show fallback warning
|
|
181
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
182
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
183
|
+
expect(call.body.message).toContain("⚠️")
|
|
184
|
+
expect(call.body.message).toContain("anthropic/claude-sonnet-4-5")
|
|
185
|
+
expect(call.body.message).toContain("(system default fallback)")
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test("should display warning when model is inherited from parent", () => {
|
|
189
|
+
// #given - inherited is a fallback (custom category without model definition)
|
|
190
|
+
const task = {
|
|
191
|
+
id: "task_2",
|
|
192
|
+
description: "Task with inherited model",
|
|
193
|
+
agent: "Sisyphus-Junior",
|
|
194
|
+
isBackground: false,
|
|
195
|
+
modelInfo: { model: "cliproxy/claude-opus-4-5", type: "inherited" as const },
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// #when - addTask is called
|
|
199
|
+
toastManager.addTask(task)
|
|
200
|
+
|
|
201
|
+
// #then - toast should show fallback warning
|
|
202
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
203
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
204
|
+
expect(call.body.message).toContain("⚠️")
|
|
205
|
+
expect(call.body.message).toContain("cliproxy/claude-opus-4-5")
|
|
206
|
+
expect(call.body.message).toContain("(inherited from parent)")
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
test("should not display model info when user-defined", () => {
|
|
210
|
+
// #given - a task with user-defined model
|
|
211
|
+
const task = {
|
|
212
|
+
id: "task_3",
|
|
213
|
+
description: "Task with user model",
|
|
214
|
+
agent: "Sisyphus-Junior",
|
|
215
|
+
isBackground: false,
|
|
216
|
+
modelInfo: { model: "my-provider/my-model", type: "user-defined" as const },
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// #when - addTask is called
|
|
220
|
+
toastManager.addTask(task)
|
|
221
|
+
|
|
222
|
+
// #then - toast should NOT show model warning
|
|
223
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
224
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
225
|
+
expect(call.body.message).not.toContain("⚠️ Model:")
|
|
226
|
+
expect(call.body.message).not.toContain("(inherited)")
|
|
227
|
+
expect(call.body.message).not.toContain("(category default)")
|
|
228
|
+
expect(call.body.message).not.toContain("(system default)")
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
test("should not display model info when not provided", () => {
|
|
232
|
+
// #given - a task without model info
|
|
233
|
+
const task = {
|
|
234
|
+
id: "task_4",
|
|
235
|
+
description: "Task without model info",
|
|
236
|
+
agent: "explore",
|
|
237
|
+
isBackground: true,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// #when - addTask is called
|
|
241
|
+
toastManager.addTask(task)
|
|
242
|
+
|
|
243
|
+
// #then - toast should NOT show model warning
|
|
244
|
+
expect(mockClient.tui.showToast).toHaveBeenCalled()
|
|
245
|
+
const call = mockClient.tui.showToast.mock.calls[0][0]
|
|
246
|
+
expect(call.body.message).not.toContain("⚠️ Model:")
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
})
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin"
|
|
2
|
+
import type { TrackedTask, TaskStatus, ModelFallbackInfo } from "./types"
|
|
3
|
+
import type { ConcurrencyManager } from "../background-agent/concurrency"
|
|
4
|
+
|
|
5
|
+
type OpencodeClient = PluginInput["client"]
|
|
6
|
+
|
|
7
|
+
export class TaskToastManager {
|
|
8
|
+
private tasks: Map<string, TrackedTask> = new Map()
|
|
9
|
+
private client: OpencodeClient
|
|
10
|
+
private concurrencyManager?: ConcurrencyManager
|
|
11
|
+
|
|
12
|
+
constructor(client: OpencodeClient, concurrencyManager?: ConcurrencyManager) {
|
|
13
|
+
this.client = client
|
|
14
|
+
this.concurrencyManager = concurrencyManager
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setConcurrencyManager(manager: ConcurrencyManager): void {
|
|
18
|
+
this.concurrencyManager = manager
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
addTask(task: {
|
|
22
|
+
id: string
|
|
23
|
+
description: string
|
|
24
|
+
agent: string
|
|
25
|
+
isBackground: boolean
|
|
26
|
+
status?: TaskStatus
|
|
27
|
+
skills?: string[]
|
|
28
|
+
modelInfo?: ModelFallbackInfo
|
|
29
|
+
}): void {
|
|
30
|
+
const trackedTask: TrackedTask = {
|
|
31
|
+
id: task.id,
|
|
32
|
+
description: task.description,
|
|
33
|
+
agent: task.agent,
|
|
34
|
+
status: task.status ?? "running",
|
|
35
|
+
startedAt: new Date(),
|
|
36
|
+
isBackground: task.isBackground,
|
|
37
|
+
skills: task.skills,
|
|
38
|
+
modelInfo: task.modelInfo,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.tasks.set(task.id, trackedTask)
|
|
42
|
+
this.showTaskListToast(trackedTask)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Update task status
|
|
47
|
+
*/
|
|
48
|
+
updateTask(id: string, status: TaskStatus): void {
|
|
49
|
+
const task = this.tasks.get(id)
|
|
50
|
+
if (task) {
|
|
51
|
+
task.status = status
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Remove completed/error task
|
|
57
|
+
*/
|
|
58
|
+
removeTask(id: string): void {
|
|
59
|
+
this.tasks.delete(id)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get all running tasks (newest first)
|
|
64
|
+
*/
|
|
65
|
+
getRunningTasks(): TrackedTask[] {
|
|
66
|
+
const running = Array.from(this.tasks.values())
|
|
67
|
+
.filter((t) => t.status === "running")
|
|
68
|
+
.sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime())
|
|
69
|
+
return running
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get all queued tasks
|
|
74
|
+
*/
|
|
75
|
+
getQueuedTasks(): TrackedTask[] {
|
|
76
|
+
return Array.from(this.tasks.values())
|
|
77
|
+
.filter((t) => t.status === "queued")
|
|
78
|
+
.sort((a, b) => a.startedAt.getTime() - b.startedAt.getTime())
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Format duration since task started
|
|
83
|
+
*/
|
|
84
|
+
private formatDuration(startedAt: Date): string {
|
|
85
|
+
const seconds = Math.floor((Date.now() - startedAt.getTime()) / 1000)
|
|
86
|
+
if (seconds < 60) return `${seconds}s`
|
|
87
|
+
const minutes = Math.floor(seconds / 60)
|
|
88
|
+
if (minutes < 60) return `${minutes}m ${seconds % 60}s`
|
|
89
|
+
const hours = Math.floor(minutes / 60)
|
|
90
|
+
return `${hours}h ${minutes % 60}m`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private getConcurrencyInfo(): string {
|
|
94
|
+
if (!this.concurrencyManager) return ""
|
|
95
|
+
const running = this.getRunningTasks()
|
|
96
|
+
const queued = this.getQueuedTasks()
|
|
97
|
+
const total = running.length + queued.length
|
|
98
|
+
const limit = this.concurrencyManager.getConcurrencyLimit("default")
|
|
99
|
+
if (limit === Infinity) return ""
|
|
100
|
+
return ` [${total}/${limit}]`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private buildTaskListMessage(newTask: TrackedTask): string {
|
|
104
|
+
const running = this.getRunningTasks()
|
|
105
|
+
const queued = this.getQueuedTasks()
|
|
106
|
+
const concurrencyInfo = this.getConcurrencyInfo()
|
|
107
|
+
|
|
108
|
+
const lines: string[] = []
|
|
109
|
+
|
|
110
|
+
const isFallback = newTask.modelInfo && (
|
|
111
|
+
newTask.modelInfo.type === "inherited" || newTask.modelInfo.type === "system-default"
|
|
112
|
+
)
|
|
113
|
+
if (isFallback) {
|
|
114
|
+
const suffixMap: Record<"inherited" | "system-default", string> = {
|
|
115
|
+
inherited: " (inherited from parent)",
|
|
116
|
+
"system-default": " (system default fallback)",
|
|
117
|
+
}
|
|
118
|
+
const suffix = suffixMap[newTask.modelInfo!.type as "inherited" | "system-default"]
|
|
119
|
+
lines.push(`⚠️ Model fallback: ${newTask.modelInfo!.model}${suffix}`)
|
|
120
|
+
lines.push("")
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (running.length > 0) {
|
|
124
|
+
lines.push(`Running (${running.length}):${concurrencyInfo}`)
|
|
125
|
+
for (const task of running) {
|
|
126
|
+
const duration = this.formatDuration(task.startedAt)
|
|
127
|
+
const bgIcon = task.isBackground ? "⚡" : "🔄"
|
|
128
|
+
const isNew = task.id === newTask.id ? " ← NEW" : ""
|
|
129
|
+
const skillsInfo = task.skills?.length ? ` [${task.skills.join(", ")}]` : ""
|
|
130
|
+
lines.push(`${bgIcon} ${task.description} (${task.agent})${skillsInfo} - ${duration}${isNew}`)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (queued.length > 0) {
|
|
135
|
+
if (lines.length > 0) lines.push("")
|
|
136
|
+
lines.push(`Queued (${queued.length}):`)
|
|
137
|
+
for (const task of queued) {
|
|
138
|
+
const bgIcon = task.isBackground ? "⏳" : "⏸️"
|
|
139
|
+
const skillsInfo = task.skills?.length ? ` [${task.skills.join(", ")}]` : ""
|
|
140
|
+
const isNew = task.id === newTask.id ? " ← NEW" : ""
|
|
141
|
+
lines.push(`${bgIcon} ${task.description} (${task.agent})${skillsInfo} - Queued${isNew}`)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return lines.join("\n")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Show consolidated toast with all running/queued tasks
|
|
150
|
+
*/
|
|
151
|
+
private showTaskListToast(newTask: TrackedTask): void {
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
+
const tuiClient = this.client as any
|
|
154
|
+
if (!tuiClient.tui?.showToast) return
|
|
155
|
+
|
|
156
|
+
const message = this.buildTaskListMessage(newTask)
|
|
157
|
+
const running = this.getRunningTasks()
|
|
158
|
+
const queued = this.getQueuedTasks()
|
|
159
|
+
|
|
160
|
+
const title = newTask.isBackground
|
|
161
|
+
? `⚡ New Background Task`
|
|
162
|
+
: `🔄 New Task Executed`
|
|
163
|
+
|
|
164
|
+
tuiClient.tui.showToast({
|
|
165
|
+
body: {
|
|
166
|
+
title,
|
|
167
|
+
message: message || `${newTask.description} (${newTask.agent})`,
|
|
168
|
+
variant: "info",
|
|
169
|
+
duration: running.length + queued.length > 2 ? 5000 : 3000,
|
|
170
|
+
},
|
|
171
|
+
}).catch(() => {})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Show task completion toast
|
|
176
|
+
*/
|
|
177
|
+
showCompletionToast(task: { id: string; description: string; duration: string }): void {
|
|
178
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
179
|
+
const tuiClient = this.client as any
|
|
180
|
+
if (!tuiClient.tui?.showToast) return
|
|
181
|
+
|
|
182
|
+
this.removeTask(task.id)
|
|
183
|
+
|
|
184
|
+
const remaining = this.getRunningTasks()
|
|
185
|
+
const queued = this.getQueuedTasks()
|
|
186
|
+
|
|
187
|
+
let message = `✅ "${task.description}" finished in ${task.duration}`
|
|
188
|
+
if (remaining.length > 0 || queued.length > 0) {
|
|
189
|
+
message += `\n\nStill running: ${remaining.length} | Queued: ${queued.length}`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
tuiClient.tui.showToast({
|
|
193
|
+
body: {
|
|
194
|
+
title: "Task Completed",
|
|
195
|
+
message,
|
|
196
|
+
variant: "success",
|
|
197
|
+
duration: 5000,
|
|
198
|
+
},
|
|
199
|
+
}).catch(() => {})
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let instance: TaskToastManager | null = null
|
|
204
|
+
|
|
205
|
+
export function getTaskToastManager(): TaskToastManager | null {
|
|
206
|
+
return instance
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function initTaskToastManager(
|
|
210
|
+
client: OpencodeClient,
|
|
211
|
+
concurrencyManager?: ConcurrencyManager
|
|
212
|
+
): TaskToastManager {
|
|
213
|
+
instance = new TaskToastManager(client, concurrencyManager)
|
|
214
|
+
return instance
|
|
215
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type TaskStatus = "running" | "queued" | "completed" | "error"
|
|
2
|
+
|
|
3
|
+
export interface ModelFallbackInfo {
|
|
4
|
+
model: string
|
|
5
|
+
type: "user-defined" | "inherited" | "category-default" | "system-default"
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface TrackedTask {
|
|
9
|
+
id: string
|
|
10
|
+
description: string
|
|
11
|
+
agent: string
|
|
12
|
+
status: TaskStatus
|
|
13
|
+
startedAt: Date
|
|
14
|
+
isBackground: boolean
|
|
15
|
+
skills?: string[]
|
|
16
|
+
modelInfo?: ModelFallbackInfo
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TaskToastOptions {
|
|
20
|
+
title: string
|
|
21
|
+
message: string
|
|
22
|
+
variant: "info" | "success" | "warning" | "error"
|
|
23
|
+
duration?: number
|
|
24
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# HOOKS KNOWLEDGE BASE
|
|
2
|
+
|
|
3
|
+
## OVERVIEW
|
|
4
|
+
|
|
5
|
+
31 lifecycle hooks intercepting/modifying agent behavior. Events: PreToolUse, PostToolUse, UserPromptSubmit, Stop, onSummarize.
|
|
6
|
+
|
|
7
|
+
## STRUCTURE
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
hooks/
|
|
11
|
+
├── atlas/ # Main orchestration & delegation (771 lines)
|
|
12
|
+
├── anthropic-context-window-limit-recovery/ # Auto-summarize at token limit
|
|
13
|
+
├── todo-continuation-enforcer.ts # Force TODO completion
|
|
14
|
+
├── ralph-loop/ # Self-referential dev loop until done
|
|
15
|
+
├── claude-code-hooks/ # settings.json hook compat layer (13 files)
|
|
16
|
+
├── comment-checker/ # Prevents AI slop/excessive comments
|
|
17
|
+
├── auto-slash-command/ # Detects /command patterns
|
|
18
|
+
├── rules-injector/ # Conditional rules from .claude/rules/
|
|
19
|
+
├── directory-agents-injector/ # Auto-injects AGENTS.md files
|
|
20
|
+
├── directory-readme-injector/ # Auto-injects README.md files
|
|
21
|
+
├── preemptive-compaction/ # Triggers summary at 85% context
|
|
22
|
+
├── edit-error-recovery/ # Recovers from tool failures
|
|
23
|
+
├── thinking-block-validator/ # Ensures valid <thinking> format
|
|
24
|
+
├── context-window-monitor.ts # Reminds agents of remaining headroom
|
|
25
|
+
├── session-recovery/ # Auto-recovers from crashes
|
|
26
|
+
├── think-mode/ # Dynamic thinking budget
|
|
27
|
+
├── keyword-detector/ # ultrawork/search/analyze modes
|
|
28
|
+
├── background-notification/ # OS notification on task completion
|
|
29
|
+
└── tool-output-truncator.ts # Prevents context bloat
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## HOOK EVENTS
|
|
33
|
+
|
|
34
|
+
| Event | Timing | Can Block | Use Case |
|
|
35
|
+
|-------|--------|-----------|----------|
|
|
36
|
+
| PreToolUse | Before tool | Yes | Validate/modify inputs, inject context |
|
|
37
|
+
| PostToolUse | After tool | No | Append warnings, truncate output |
|
|
38
|
+
| UserPromptSubmit | On prompt | Yes | Keyword detection, mode switching |
|
|
39
|
+
| Stop | Session idle | No | Auto-continue (todo-continuation, ralph-loop) |
|
|
40
|
+
| onSummarize | Compaction | No | Preserve critical state |
|
|
41
|
+
|
|
42
|
+
## EXECUTION ORDER
|
|
43
|
+
|
|
44
|
+
**chat.message**: keywordDetector → claudeCodeHooks → autoSlashCommand → startWork → ralphLoop
|
|
45
|
+
|
|
46
|
+
**tool.execute.before**: claudeCodeHooks → nonInteractiveEnv → commentChecker → directoryAgentsInjector → directoryReadmeInjector → rulesInjector
|
|
47
|
+
|
|
48
|
+
**tool.execute.after**: editErrorRecovery → delegateTaskRetry → commentChecker → toolOutputTruncator → emptyTaskResponseDetector → claudeCodeHooks
|
|
49
|
+
|
|
50
|
+
## HOW TO ADD
|
|
51
|
+
|
|
52
|
+
1. Create `src/hooks/name/` with `index.ts` exporting `createMyHook(ctx)`
|
|
53
|
+
2. Implement event handlers: `"tool.execute.before"`, `"tool.execute.after"`, etc.
|
|
54
|
+
3. Add hook name to `HookNameSchema` in `src/config/schema.ts`
|
|
55
|
+
4. Register in `src/index.ts`:
|
|
56
|
+
```typescript
|
|
57
|
+
const myHook = isHookEnabled("my-hook") ? createMyHook(ctx) : null
|
|
58
|
+
// Add to event handlers
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## PATTERNS
|
|
62
|
+
|
|
63
|
+
- **Session-scoped state**: `Map<sessionID, Set<string>>` for tracking per-session
|
|
64
|
+
- **Conditional execution**: Check `input.tool` before processing
|
|
65
|
+
- **Output modification**: `output.output += "\n${REMINDER}"` to append context
|
|
66
|
+
- **Async state**: Use promises for CLI path resolution, cache results
|
|
67
|
+
|
|
68
|
+
## ANTI-PATTERNS
|
|
69
|
+
|
|
70
|
+
- **Blocking non-critical**: Use PostToolUse warnings instead of PreToolUse blocks
|
|
71
|
+
- **Heavy computation**: Keep PreToolUse light - slows every tool call
|
|
72
|
+
- **Redundant injection**: Track injected files to prevent duplicates
|
|
73
|
+
- **Verbose output**: Keep hook messages technical, brief
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { getOpenCodeStorageDir } from "../../shared/data-path";
|
|
3
|
+
|
|
4
|
+
export const OPENCODE_STORAGE = getOpenCodeStorageDir();
|
|
5
|
+
export const AGENT_USAGE_REMINDER_STORAGE = join(
|
|
6
|
+
OPENCODE_STORAGE,
|
|
7
|
+
"agent-usage-reminder",
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
// All tool names normalized to lowercase for case-insensitive matching
|
|
11
|
+
export const TARGET_TOOLS = new Set([
|
|
12
|
+
"grep",
|
|
13
|
+
"safe_grep",
|
|
14
|
+
"glob",
|
|
15
|
+
"safe_glob",
|
|
16
|
+
"webfetch",
|
|
17
|
+
"context7_resolve-library-id",
|
|
18
|
+
"context7_query-docs",
|
|
19
|
+
"websearch_web_search_exa",
|
|
20
|
+
"context7_get-library-docs",
|
|
21
|
+
"grep_app_searchgithub",
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
export const AGENT_TOOLS = new Set([
|
|
25
|
+
"task",
|
|
26
|
+
"call_omo_agent",
|
|
27
|
+
"delegate_task",
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
export const REMINDER_MESSAGE = `
|
|
31
|
+
[Agent Usage Reminder]
|
|
32
|
+
|
|
33
|
+
You called a search/fetch tool directly without leveraging specialized agents.
|
|
34
|
+
|
|
35
|
+
RECOMMENDED: Use delegate_task with explore/librarian agents for better results:
|
|
36
|
+
|
|
37
|
+
\`\`\`
|
|
38
|
+
// Parallel exploration - fire multiple agents simultaneously
|
|
39
|
+
delegate_task(agent="explore", prompt="Find all files matching pattern X")
|
|
40
|
+
delegate_task(agent="explore", prompt="Search for implementation of Y")
|
|
41
|
+
delegate_task(agent="librarian", prompt="Lookup documentation for Z")
|
|
42
|
+
|
|
43
|
+
// Then continue your work while they run in background
|
|
44
|
+
// System will notify you when each completes
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
WHY:
|
|
48
|
+
- Agents can perform deeper, more thorough searches
|
|
49
|
+
- Background tasks run in parallel, saving time
|
|
50
|
+
- Specialized agents have domain expertise
|
|
51
|
+
- Reduces context window usage in main session
|
|
52
|
+
|
|
53
|
+
ALWAYS prefer: Multiple parallel delegate_task calls > Direct tool calls
|
|
54
|
+
`;
|