oh-my-opencode 4.15.0 → 4.16.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/dist/cli/doctor/checks/tui-plugin-config.d.ts +4 -4
- package/dist/cli/index.js +1149 -1040
- package/dist/cli/install-senpi/index.d.ts +1 -0
- package/dist/cli/run/poll-for-completion.d.ts +4 -0
- package/dist/cli/run/session-resolver.d.ts +1 -0
- package/dist/cli/senpi-platform-flag.d.ts +4 -0
- package/dist/cli/types.d.ts +2 -1
- package/dist/cli-node/index.js +1149 -1040
- package/dist/features/background-agent/manager.d.ts +16 -0
- package/dist/hooks/anthropic-context-window-limit-recovery/aggressive-truncation-strategy.d.ts +1 -0
- package/dist/index.js +1334 -1146
- package/dist/skills/debugging/references/methodology/06-fix.md +6 -0
- package/dist/skills/frontend/ATTRIBUTION.md +13 -3
- package/dist/skills/frontend/SKILL.md +8 -3
- package/dist/skills/frontend/references/design/README.md +1 -1
- package/dist/skills/frontend/references/design/_INDEX.md +1 -1
- package/dist/skills/frontend/references/design/lazyweb.md +77 -0
- package/dist/skills/frontend/references/design/stitch-design-example.md +121 -0
- package/dist/skills/frontend/references/designpowers/EVIDENCE.md +10 -2
- package/dist/skills/frontend/references/designpowers/UPSTREAM.md +1 -1
- package/dist/skills/programming/SKILL.md +10 -1
- package/dist/skills/programming/references/logging.md +91 -0
- package/dist/skills/ulw-plan/SKILL.md +5 -5
- package/dist/skills/ulw-plan/references/full-workflow.md +7 -7
- package/dist/skills/ulw-plan/references/intent-unclear.md +3 -3
- package/dist/skills/ulw-research/ATTRIBUTION.md +2 -2
- package/dist/skills/ulw-research/SKILL.md +28 -7
- package/dist/tools/skill/description-formatter.d.ts +1 -0
- package/dist/tools/skill/description-formatter.test-support.d.ts +9 -0
- package/dist/tools/skill/zauc-mocks-skill-tools/test-support.d.ts +25 -0
- package/dist/tui.js +121 -419
- package/package.json +32 -15
- package/packages/git-bash-mcp/dist/cli.js +2 -2
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/AGENTS.md +55 -0
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +212 -117
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +51 -0
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +936 -248
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +233 -135
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +29 -0
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +13 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +25 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +30 -1
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +16 -2
- package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +80 -0
- package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +107 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +26 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +29 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +8 -21
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +108 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +76 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +17 -111
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +45 -67
- package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +56 -0
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +31 -0
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +45 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus.md +37 -102
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/AGENTS.md +46 -0
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +6 -0
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +6 -0
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +5 -2
- package/packages/omo-codex/plugin/components/ultrawork/CHANGELOG.md +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/README.md +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +51 -2
- package/packages/omo-codex/plugin/components/ultrawork/package.json +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +14 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +380 -0
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +5 -2
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +5 -3
- package/packages/omo-codex/plugin/components/ultrawork/src/skill-pointer.ts +56 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +12 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +1 -0
- package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +82 -0
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +56 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-hook.js +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.d.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-directive.js +5 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-skill-pointer.d.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ultrawork-skill-pointer.js +46 -0
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-directive.ts +9 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/ultrawork-skill-pointer.ts +55 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +49 -0
- 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/auto-update-plan.mjs +147 -2
- package/packages/omo-codex/plugin/scripts/auto-update-release-notes.mjs +33 -0
- package/packages/omo-codex/plugin/scripts/auto-update.mjs +48 -10
- package/packages/omo-codex/plugin/scripts/build-components.mjs +63 -17
- package/packages/omo-codex/plugin/scripts/materialize-shared-upstreams.mjs +10 -3
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +19 -0
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +18 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/06-fix.md +6 -0
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +13 -3
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +8 -3
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/lazyweb.md +77 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/stitch-design-example.md +121 -0
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/EVIDENCE.md +10 -2
- package/packages/omo-codex/plugin/skills/frontend/references/designpowers/UPSTREAM.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +10 -1
- package/packages/omo-codex/plugin/skills/programming/references/logging.md +91 -0
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +380 -0
- package/packages/omo-codex/plugin/skills/ultrawork/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +5 -2
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +4 -4
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/ATTRIBUTION.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +31 -10
- package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +32 -0
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +153 -3
- package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +20 -1
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +39 -10
- package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +56 -0
- package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +98 -0
- package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +25 -7
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +612 -4193
- package/packages/shared-skills/skills/debugging/references/methodology/06-fix.md +6 -0
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +13 -3
- package/packages/shared-skills/skills/frontend/SKILL.md +8 -3
- package/packages/shared-skills/skills/frontend/references/design/README.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/lazyweb.md +77 -0
- package/packages/shared-skills/skills/frontend/references/design/stitch-design-example.md +121 -0
- package/packages/shared-skills/skills/frontend/references/designpowers/EVIDENCE.md +10 -2
- package/packages/shared-skills/skills/frontend/references/designpowers/UPSTREAM.md +1 -1
- package/packages/shared-skills/skills/programming/SKILL.md +10 -1
- package/packages/shared-skills/skills/programming/references/logging.md +91 -0
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +5 -5
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +7 -7
- package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +3 -3
- package/packages/shared-skills/skills/ulw-research/ATTRIBUTION.md +2 -2
- package/packages/shared-skills/skills/ulw-research/SKILL.md +28 -7
- package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +0 -10
- package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +0 -2
- /package/dist/skills/frontend/references/designpowers/vendor/skills/accessible-content/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-debate/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-handoff/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-md/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-retrospective/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-review/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/interaction-design/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/motion-choreography/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/research-planning/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/taste-feedback/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/taste-report/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/token-architecture/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/ui-composition/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/usability-testing/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/{SKILL.md → reference.md} +0 -0
- /package/dist/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/accessible-content/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debate/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-handoff/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-md/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-retrospective/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-review/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/interaction-design/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/motion-choreography/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/research-planning/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-feedback/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/taste-report/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/token-architecture/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/ui-composition/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/usability-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/{SKILL.md → reference.md} +0 -0
- /package/packages/omo-codex/plugin/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/accessible-content/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/adaptive-interfaces/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/cognitive-accessibility/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debate/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-debt-tracker/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-handoff/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-md/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-retrospective/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-review/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/design-system-alignment/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/designpowers-critique/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/heuristic-evaluation/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inclusive-personas/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/inspiration-scouting/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/interaction-design/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/motion-choreography/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/research-planning/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/responsive-patterns/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/synthetic-user-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-feedback/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/taste-report/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/token-architecture/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/ui-composition/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/usability-testing/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/verification-before-shipping/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/voice-and-tone/{SKILL.md → reference.md} +0 -0
- /package/packages/shared-skills/skills/frontend/references/designpowers/vendor/skills/writing-design-plans/{SKILL.md → reference.md} +0 -0
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { execFile, spawn } from "node:child_process";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
cwd as processCwd,
|
|
6
|
+
env as processEnv,
|
|
7
|
+
stderr as processStderr,
|
|
8
|
+
stdin as processStdin,
|
|
9
|
+
stdout as processStdout,
|
|
10
|
+
} from "node:process";
|
|
5
11
|
import type { Readable } from "node:stream";
|
|
6
12
|
import { fileURLToPath } from "node:url";
|
|
7
13
|
|
|
8
14
|
import { buildCodegraphChildEnv, buildCodegraphEnv } from "../../../../../utils/src/codegraph/env.ts";
|
|
9
15
|
import { buildCodegraphInitGuidanceForToolResult } from "../../../../../utils/src/codegraph/guidance.ts";
|
|
10
16
|
import { resolveCodegraphCommand } from "../../../../../utils/src/codegraph/resolve.ts";
|
|
17
|
+
import { shouldExcludeCodegraphProject } from "../../../../../utils/src/codegraph/workspace.ts";
|
|
11
18
|
import { getCodexOmoConfig } from "../../../shared/src/config-loader.ts";
|
|
19
|
+
import { pruneCodegraphProjectStoresBestEffort } from "./cache-gc.js";
|
|
20
|
+
import { sweepCodegraphZombiesBestEffort } from "./hook-sweep.js";
|
|
12
21
|
import { resolveCodegraphCommandInvocation, SESSION_START_CWD_ENV } from "./session-start-worker.js";
|
|
13
22
|
import type {
|
|
14
23
|
HookStdout,
|
|
@@ -57,10 +66,25 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
|
|
|
57
66
|
const projectRoot = resolveProjectRoot(input, options.cwd ?? processCwd());
|
|
58
67
|
const homeDir = resolveHomeDir(env);
|
|
59
68
|
const config = options.config ?? getCodexOmoConfig({ cwd: projectRoot, env, homeDir });
|
|
69
|
+
pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
|
|
70
|
+
await sweepCodegraphZombiesBestEffort({
|
|
71
|
+
env,
|
|
72
|
+
homeDir,
|
|
73
|
+
...(config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir }),
|
|
74
|
+
log: writeDebugLog,
|
|
75
|
+
}, options.sweepZombies);
|
|
60
76
|
|
|
61
77
|
if (config.codegraph?.enabled === false) {
|
|
62
78
|
return { action: "skipped-disabled", exitCode: 0 };
|
|
63
79
|
}
|
|
80
|
+
const excludedRoots = config.codegraph?.excluded_roots;
|
|
81
|
+
const exclusion = shouldExcludeCodegraphProject(projectRoot, {
|
|
82
|
+
homeDir,
|
|
83
|
+
...(excludedRoots === undefined ? {} : { excludedRoots }),
|
|
84
|
+
});
|
|
85
|
+
if (exclusion.excluded) {
|
|
86
|
+
return { action: "skipped-excluded", exitCode: 0 };
|
|
87
|
+
}
|
|
64
88
|
|
|
65
89
|
const isInitialized = await (options.statusProbe ?? isCodegraphProjectInitialized)({
|
|
66
90
|
env,
|
|
@@ -193,6 +217,11 @@ function writeHookJson(stdout: HookStdout): void {
|
|
|
193
217
|
stdout.write(`${JSON.stringify(output)}\n`);
|
|
194
218
|
}
|
|
195
219
|
|
|
220
|
+
function writeDebugLog(message: string): void {
|
|
221
|
+
if (processEnv["OMO_CODEGRAPH_DEBUG"] !== "1") return;
|
|
222
|
+
processStderr.write(`${message}\n`);
|
|
223
|
+
}
|
|
224
|
+
|
|
196
225
|
function spawnDetachedWorker(invocation: WorkerSpawnInvocation): void {
|
|
197
226
|
const child = spawn(invocation.command, [...invocation.args], { detached: true, env: invocation.env, stdio: "ignore" });
|
|
198
227
|
child.unref();
|
|
@@ -12,7 +12,11 @@ import {
|
|
|
12
12
|
import type { Readable, Writable } from "node:stream";
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
CODEGRAPH_NO_DAEMON_ENV,
|
|
17
|
+
buildCodegraphChildEnv,
|
|
18
|
+
buildCodegraphEnv,
|
|
19
|
+
} from "../../../../../utils/src/codegraph/env.ts";
|
|
16
20
|
import {
|
|
17
21
|
buildCodegraphNodeSkipHint,
|
|
18
22
|
evaluateCodegraphNodeSupport,
|
|
@@ -27,6 +31,7 @@ import {
|
|
|
27
31
|
type CodegraphCommandResolution,
|
|
28
32
|
type ResolveCodegraphCommandOptions,
|
|
29
33
|
} from "../../../../../utils/src/codegraph/resolve.ts";
|
|
34
|
+
import { shouldExcludeCodegraphProject } from "../../../../../utils/src/codegraph/workspace.ts";
|
|
30
35
|
import { getCodexOmoConfig, type CodexOmoConfig } from "../../../shared/src/config-loader.ts";
|
|
31
36
|
import type { CodegraphConfig } from "./hook.js";
|
|
32
37
|
import { runBridgedCodegraphProcess } from "./mcp-bridge.js";
|
|
@@ -78,6 +83,7 @@ const CODEGRAPH_SKIP_HINT =
|
|
|
78
83
|
"CodeGraph MCP skipped: codegraph binary not found. Install CodeGraph or set OMO_CODEGRAPH_BIN.\n";
|
|
79
84
|
const CODEGRAPH_DISABLED_HINT =
|
|
80
85
|
"CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.\n";
|
|
86
|
+
const CODEGRAPH_EXCLUDED_HINT = "CodeGraph MCP skipped: project excluded by OMO CodeGraph policy.\n";
|
|
81
87
|
const CODEGRAPH_VERSION = "1.0.1";
|
|
82
88
|
const PROJECT_CWD_ENV_KEYS = ["OMO_CODEGRAPH_PROJECT_CWD", SESSION_START_CWD_ENV, "PWD"] as const;
|
|
83
89
|
|
|
@@ -91,6 +97,14 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
|
|
|
91
97
|
if (codegraphConfig.enabled === false) {
|
|
92
98
|
return runUnavailableMcp(CODEGRAPH_DISABLED_HINT, options);
|
|
93
99
|
}
|
|
100
|
+
const excludedRoots = codegraphConfig.excluded_roots;
|
|
101
|
+
const exclusion = shouldExcludeCodegraphProject(projectCwd, {
|
|
102
|
+
homeDir,
|
|
103
|
+
...(excludedRoots === undefined ? {} : { excludedRoots }),
|
|
104
|
+
});
|
|
105
|
+
if (exclusion.excluded) {
|
|
106
|
+
return runUnavailableMcp(CODEGRAPH_EXCLUDED_HINT, options);
|
|
107
|
+
}
|
|
94
108
|
|
|
95
109
|
const trustedInstallDir = config.trustedCodegraphInstallDir;
|
|
96
110
|
const resolutionOptions = {
|
|
@@ -183,7 +197,7 @@ function codegraphEnvForConfig(
|
|
|
183
197
|
homeDir: string,
|
|
184
198
|
buildEnv: ((options: { readonly homeDir: string }) => Record<string, string>) | undefined,
|
|
185
199
|
): Record<string, string> {
|
|
186
|
-
const env = buildEnv?.({ homeDir }) ?? buildCodegraphEnv({ homeDir });
|
|
200
|
+
const env = { ...(buildEnv?.({ homeDir }) ?? buildCodegraphEnv({ homeDir })), [CODEGRAPH_NO_DAEMON_ENV]: "1" };
|
|
187
201
|
return trustedInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: trustedInstallDir };
|
|
188
202
|
}
|
|
189
203
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { HookStdout } from "./hook-types.js";
|
|
2
|
+
import {
|
|
3
|
+
sweepCodegraphZombies,
|
|
4
|
+
type CodegraphZombieProcess,
|
|
5
|
+
type SweepCodegraphZombiesOptions,
|
|
6
|
+
type SweepCodegraphZombiesResult,
|
|
7
|
+
} from "../../../../../utils/src/codegraph/process-sweep.ts";
|
|
8
|
+
|
|
9
|
+
export interface RunCodegraphSweepCliOptions extends SweepCodegraphZombiesOptions {
|
|
10
|
+
readonly argv?: readonly string[];
|
|
11
|
+
readonly stdout?: HookStdout;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SweepCliArgs {
|
|
15
|
+
readonly dryRun: boolean;
|
|
16
|
+
readonly force: boolean;
|
|
17
|
+
readonly roots: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function runCodegraphSweepCli(options: RunCodegraphSweepCliOptions = {}): Promise<number> {
|
|
21
|
+
const args = parseSweepCliArgs(options.argv ?? process.argv);
|
|
22
|
+
const result = await sweepCodegraphZombies({
|
|
23
|
+
...options,
|
|
24
|
+
dryRun: args.dryRun,
|
|
25
|
+
extraRoots: args.roots,
|
|
26
|
+
force: args.force,
|
|
27
|
+
...(args.roots.length > 0 ? { ownedRoots: args.roots } : {}),
|
|
28
|
+
});
|
|
29
|
+
writeSweepReport(options.stdout ?? process.stdout, result);
|
|
30
|
+
return result.action === "failed" ? 1 : 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseSweepCliArgs(argv: readonly string[]): SweepCliArgs {
|
|
34
|
+
const roots: string[] = [];
|
|
35
|
+
let dryRun = false;
|
|
36
|
+
let force = false;
|
|
37
|
+
for (let index = 3; index < argv.length; index += 1) {
|
|
38
|
+
const arg = argv[index];
|
|
39
|
+
if (arg === "--dry-run") {
|
|
40
|
+
dryRun = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (arg === "--force") {
|
|
44
|
+
force = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (arg === "--root") {
|
|
48
|
+
const value = argv[index + 1];
|
|
49
|
+
if (value !== undefined && value.trim().length > 0) roots.push(value);
|
|
50
|
+
index += 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { dryRun, force, roots };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function writeSweepReport(stdout: HookStdout, result: SweepCodegraphZombiesResult): void {
|
|
57
|
+
stdout.write(`${JSON.stringify({
|
|
58
|
+
action: result.action,
|
|
59
|
+
candidates: result.candidates.map(formatProcess),
|
|
60
|
+
dryRun: result.dryRun,
|
|
61
|
+
failed: result.failed,
|
|
62
|
+
killed: result.killed.map(formatProcess),
|
|
63
|
+
ownedRoots: result.ownedRoots,
|
|
64
|
+
stampFile: result.stampFile,
|
|
65
|
+
})}\n`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function formatProcess(processInfo: CodegraphZombieProcess): {
|
|
69
|
+
readonly matchKind: string;
|
|
70
|
+
readonly matchedRoot: string;
|
|
71
|
+
readonly pid: number;
|
|
72
|
+
readonly ppid: number;
|
|
73
|
+
} {
|
|
74
|
+
return {
|
|
75
|
+
matchKind: processInfo.matchKind,
|
|
76
|
+
matchedRoot: processInfo.matchedRoot,
|
|
77
|
+
pid: processInfo.pid,
|
|
78
|
+
ppid: processInfo.ppid,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { pruneCodegraphProjectStoresBestEffort } from "../src/cache-gc.ts";
|
|
4
|
+
|
|
5
|
+
describe("CodeGraph cache GC wrapper", () => {
|
|
6
|
+
it("#given cache GC hits an expected filesystem race #when best-effort wrapper runs #then it logs and continues", () => {
|
|
7
|
+
const logs: string[] = [];
|
|
8
|
+
const error = Object.assign(new Error("project cache vanished"), { code: "ENOENT" });
|
|
9
|
+
|
|
10
|
+
pruneCodegraphProjectStoresBestEffort("/home/test", {
|
|
11
|
+
debugLog: (message) => logs.push(message),
|
|
12
|
+
prune: () => {
|
|
13
|
+
throw error;
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
expect(logs).toEqual(["CodeGraph cache GC skipped: project cache vanished"]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("#given cache GC hits an unknown code bug #when best-effort wrapper runs #then it rethrows", () => {
|
|
21
|
+
const logs: string[] = [];
|
|
22
|
+
const error = new Error("metadata invariant broken");
|
|
23
|
+
|
|
24
|
+
expect(() =>
|
|
25
|
+
pruneCodegraphProjectStoresBestEffort("/home/test", {
|
|
26
|
+
debugLog: (message) => logs.push(message),
|
|
27
|
+
prune: () => {
|
|
28
|
+
throw error;
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
).toThrow("metadata invariant broken");
|
|
32
|
+
expect(logs).toEqual([]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
executeCodegraphSessionStartHook,
|
|
9
|
+
type WorkerSpawnInvocation,
|
|
10
|
+
} from "../src/hook.ts";
|
|
11
|
+
|
|
12
|
+
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
13
|
+
|
|
14
|
+
function createAllowedWorkspace(prefix: string): string {
|
|
15
|
+
return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("CodeGraph SessionStart exclusion policy", () => {
|
|
19
|
+
it("#given project root is inside an OMO state directory #when SessionStart fires #then it skips before probing or spawning", async () => {
|
|
20
|
+
// given
|
|
21
|
+
const stdout: string[] = [];
|
|
22
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
23
|
+
const stateRoot = createAllowedWorkspace("codegraph-omo-state");
|
|
24
|
+
const workspace = join(stateRoot, ".omo", "ultraresearch", "run", "clones", "repo");
|
|
25
|
+
mkdirSync(workspace, { recursive: true });
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// when
|
|
29
|
+
const result = await executeCodegraphSessionStartHook({
|
|
30
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
31
|
+
cwd: workspace,
|
|
32
|
+
env: { HOME: "/tmp/home" },
|
|
33
|
+
stdin: Readable.from(["{}"]),
|
|
34
|
+
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
35
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
36
|
+
statusProbe: () => {
|
|
37
|
+
throw new Error("excluded projects must not probe CodeGraph status");
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// then
|
|
42
|
+
expect(result).toEqual({ action: "skipped-excluded", exitCode: 0 });
|
|
43
|
+
expect(spawned).toEqual([]);
|
|
44
|
+
expect(stdout.join("")).toBe("");
|
|
45
|
+
} finally {
|
|
46
|
+
rmSync(stateRoot, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("#given project root is under a configured excluded root #when SessionStart fires #then it skips before spawning", async () => {
|
|
51
|
+
// given
|
|
52
|
+
const stdout: string[] = [];
|
|
53
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
54
|
+
const excludedRoot = createAllowedWorkspace("codegraph-custom-excluded");
|
|
55
|
+
const workspace = join(excludedRoot, "repo");
|
|
56
|
+
mkdirSync(workspace, { recursive: true });
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// when
|
|
60
|
+
const result = await executeCodegraphSessionStartHook({
|
|
61
|
+
config: { codegraph: { enabled: true, excluded_roots: [excludedRoot] }, sources: [], warnings: [] },
|
|
62
|
+
cwd: workspace,
|
|
63
|
+
env: { HOME: "/tmp/home" },
|
|
64
|
+
stdin: Readable.from(["{}"]),
|
|
65
|
+
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
66
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
67
|
+
statusProbe: () => Promise.resolve(false),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// then
|
|
71
|
+
expect(result).toEqual({ action: "skipped-excluded", exitCode: 0 });
|
|
72
|
+
expect(spawned).toEqual([]);
|
|
73
|
+
expect(stdout.join("")).toBe("");
|
|
74
|
+
} finally {
|
|
75
|
+
rmSync(excludedRoot, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("#given project root is under /tmp #when SessionStart fires on POSIX #then it skips before spawning", async () => {
|
|
80
|
+
if (process.platform === "win32") return;
|
|
81
|
+
|
|
82
|
+
// given
|
|
83
|
+
const stdout: string[] = [];
|
|
84
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
85
|
+
const workspace = mkdtempSync(join("/tmp", "omo-codegraph-excluded-"));
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
// when
|
|
89
|
+
const result = await executeCodegraphSessionStartHook({
|
|
90
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
91
|
+
cwd: workspace,
|
|
92
|
+
env: { HOME: "/tmp/home" },
|
|
93
|
+
stdin: Readable.from(["{}"]),
|
|
94
|
+
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
95
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
96
|
+
statusProbe: () => Promise.resolve(false),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// then
|
|
100
|
+
expect(result).toEqual({ action: "skipped-excluded", exitCode: 0 });
|
|
101
|
+
expect(spawned).toEqual([]);
|
|
102
|
+
expect(stdout.join("")).toBe("");
|
|
103
|
+
} finally {
|
|
104
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
7
|
+
const pluginConfigPath = resolve(pluginRoot, ".codex-plugin/plugin.json");
|
|
8
|
+
|
|
9
|
+
describe("CodeGraph hook registration", () => {
|
|
10
|
+
it("#given plugin hook config #when inspected #then CodeGraph is registered after bootstrap SessionStart", () => {
|
|
11
|
+
// given
|
|
12
|
+
const pluginConfig: unknown = JSON.parse(readFileSync(pluginConfigPath, "utf8"));
|
|
13
|
+
|
|
14
|
+
// when
|
|
15
|
+
const hookPaths =
|
|
16
|
+
typeof pluginConfig === "object" && pluginConfig !== null && "hooks" in pluginConfig && Array.isArray(pluginConfig.hooks)
|
|
17
|
+
? pluginConfig.hooks.filter((hookPath): hookPath is string => typeof hookPath === "string")
|
|
18
|
+
: [];
|
|
19
|
+
|
|
20
|
+
// then
|
|
21
|
+
expect(hookPaths).toContain("./hooks/session-start-checking-codegraph-bootstrap.json");
|
|
22
|
+
expect(hookPaths.indexOf("./hooks/session-start-checking-bootstrap-provisioning.json")).toBeLessThan(
|
|
23
|
+
hookPaths.indexOf("./hooks/session-start-checking-codegraph-bootstrap.json"),
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
|
|
4
|
+
import { executeCodegraphSessionStartHook, type WorkerSpawnInvocation } from "../src/hook.ts";
|
|
5
|
+
|
|
6
|
+
describe("CodeGraph SessionStart zombie sweep", () => {
|
|
7
|
+
it("#given the zombie sweep fails #when SessionStart fires #then the hook still exits zero", async () => {
|
|
8
|
+
// given
|
|
9
|
+
const stdout: string[] = [];
|
|
10
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
11
|
+
|
|
12
|
+
// when
|
|
13
|
+
const result = await executeCodegraphSessionStartHook({
|
|
14
|
+
config: { codegraph: { enabled: false }, sources: [], warnings: [] },
|
|
15
|
+
env: { HOME: "/tmp/home" },
|
|
16
|
+
stdin: Readable.from(["{}"]),
|
|
17
|
+
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
18
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
19
|
+
sweepZombies: () => {
|
|
20
|
+
throw new Error("ps unavailable");
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// then
|
|
25
|
+
expect(result).toEqual({ action: "skipped-disabled", exitCode: 0 });
|
|
26
|
+
expect(spawned).toEqual([]);
|
|
27
|
+
expect(stdout.join("")).toBe("");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { mkdirSync, mkdtempSync,
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
@@ -13,7 +13,10 @@ import {
|
|
|
13
13
|
} from "../src/hook.ts";
|
|
14
14
|
|
|
15
15
|
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
function createAllowedWorkspace(prefix: string): string {
|
|
18
|
+
return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
function expectOmoCodegraphProjectStoreGuidance(context: string): void {
|
|
19
22
|
expect(context).toContain(".omo");
|
|
@@ -32,7 +35,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
32
35
|
// when
|
|
33
36
|
const exitCode = await runCodegraphCli({
|
|
34
37
|
argv: ["node", "cli.js", "hook", "session-start"],
|
|
35
|
-
cwd:
|
|
38
|
+
cwd: createAllowedWorkspace("codegraph-hook-workspace"),
|
|
36
39
|
env: { HOME: homeDir },
|
|
37
40
|
stdin: Readable.from(["{}"]),
|
|
38
41
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
@@ -212,7 +215,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
212
215
|
// given
|
|
213
216
|
const stdout: string[] = [];
|
|
214
217
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
215
|
-
const workspace =
|
|
218
|
+
const workspace = createAllowedWorkspace("codegraph-workspace");
|
|
216
219
|
|
|
217
220
|
try {
|
|
218
221
|
// when
|
|
@@ -256,7 +259,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
256
259
|
// given
|
|
257
260
|
const stdout: string[] = [];
|
|
258
261
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
259
|
-
const workspace =
|
|
262
|
+
const workspace = createAllowedWorkspace("codegraph-initialized-workspace");
|
|
260
263
|
|
|
261
264
|
try {
|
|
262
265
|
// when
|
|
@@ -299,20 +302,4 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
299
302
|
expect(stdout.join("")).toBe("");
|
|
300
303
|
});
|
|
301
304
|
|
|
302
|
-
it("#given plugin hook config #when inspected #then CodeGraph is registered after bootstrap SessionStart", () => {
|
|
303
|
-
// given
|
|
304
|
-
const pluginConfig: unknown = JSON.parse(readFileSync(pluginConfigPath, "utf8"));
|
|
305
|
-
|
|
306
|
-
// when
|
|
307
|
-
const hookPaths =
|
|
308
|
-
typeof pluginConfig === "object" && pluginConfig !== null && "hooks" in pluginConfig && Array.isArray(pluginConfig.hooks)
|
|
309
|
-
? pluginConfig.hooks.filter((hookPath): hookPath is string => typeof hookPath === "string")
|
|
310
|
-
: [];
|
|
311
|
-
|
|
312
|
-
// then
|
|
313
|
-
expect(hookPaths).toContain("./hooks/session-start-checking-codegraph-bootstrap.json");
|
|
314
|
-
expect(hookPaths.indexOf("./hooks/session-start-checking-bootstrap-provisioning.json")).toBeLessThan(
|
|
315
|
-
hookPaths.indexOf("./hooks/session-start-checking-codegraph-bootstrap.json"),
|
|
316
|
-
);
|
|
317
|
-
});
|
|
318
305
|
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { chmodSync, writeFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
export function writeFakeNewlineCodegraph(filePath: string): void {
|
|
4
|
+
writeFileSync(
|
|
5
|
+
filePath,
|
|
6
|
+
[
|
|
7
|
+
"#!/usr/bin/env node",
|
|
8
|
+
"const fs = require('node:fs');",
|
|
9
|
+
"const readline = require('node:readline');",
|
|
10
|
+
"fs.writeFileSync(process.env.CODEGRAPH_FAKE_LOG, `cwd=${process.cwd()}\\n`);",
|
|
11
|
+
"const rl = readline.createInterface({ input: process.stdin });",
|
|
12
|
+
"rl.on('line', (line) => {",
|
|
13
|
+
" const request = JSON.parse(line);",
|
|
14
|
+
" if (request.method === 'initialize') {",
|
|
15
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.0.1' } } }) + '\\n');",
|
|
16
|
+
" }",
|
|
17
|
+
" if (request.method === 'tools/list') {",
|
|
18
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: [{ name: 'codegraph_search' }, { name: 'codegraph_node' }, { name: 'codegraph_explore' }, { name: 'codegraph_callers' }] } }) + '\\n');",
|
|
19
|
+
" }",
|
|
20
|
+
"});",
|
|
21
|
+
].join("\n"),
|
|
22
|
+
);
|
|
23
|
+
chmodSync(filePath, 0o755);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function writeFakeContractCodegraph(filePath: string): void {
|
|
27
|
+
writeFileSync(
|
|
28
|
+
filePath,
|
|
29
|
+
[
|
|
30
|
+
"#!/usr/bin/env node",
|
|
31
|
+
"const fs = require('node:fs');",
|
|
32
|
+
"const readline = require('node:readline');",
|
|
33
|
+
"fs.writeFileSync(process.env.CODEGRAPH_FAKE_LOG, `cwd=${process.cwd()}\\n`);",
|
|
34
|
+
"const rl = readline.createInterface({ input: process.stdin });",
|
|
35
|
+
"rl.on('line', (line) => {",
|
|
36
|
+
" const request = JSON.parse(line);",
|
|
37
|
+
" if (request.method === 'tools/list') {",
|
|
38
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: [",
|
|
39
|
+
" { name: 'codegraph_search', description: 'search stays unchanged' },",
|
|
40
|
+
" { name: 'codegraph_node', description: 'ONE SYMBOL you can name - its location, signature, verbatim source (includeCode=true) and caller/callee trail in one call', inputSchema: { type: 'object', properties: { includeCode: { type: 'boolean', description: \"Symbol mode: include the symbol's full body (default: false).\" }, symbol: { type: 'string' } } } }",
|
|
41
|
+
" ] } }) + '\\n');",
|
|
42
|
+
" }",
|
|
43
|
+
" if (request.method === 'tools/call') {",
|
|
44
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { content: [{ type: 'text', text: 'JsonlMCP\\nMembers (7)\\nStructural outline only. For full source, use the Read tool on this file or request a member.' }] } }) + '\\n');",
|
|
45
|
+
" }",
|
|
46
|
+
"});",
|
|
47
|
+
].join("\n"),
|
|
48
|
+
);
|
|
49
|
+
chmodSync(filePath, 0o755);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function frameMcpRequest(request: {
|
|
53
|
+
readonly id: number;
|
|
54
|
+
readonly method: string;
|
|
55
|
+
readonly params: Record<string, unknown>;
|
|
56
|
+
}): string {
|
|
57
|
+
const body = JSON.stringify({ jsonrpc: "2.0", ...request });
|
|
58
|
+
return `Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function parseMcpBodies(transcript: string): readonly unknown[] {
|
|
62
|
+
const bodies: unknown[] = [];
|
|
63
|
+
let cursor = 0;
|
|
64
|
+
while (cursor < transcript.length) {
|
|
65
|
+
const headerEnd = transcript.indexOf("\r\n\r\n", cursor);
|
|
66
|
+
if (headerEnd === -1) break;
|
|
67
|
+
const header = transcript.slice(cursor, headerEnd);
|
|
68
|
+
const match = /^Content-Length: (?<length>\d+)$/m.exec(header);
|
|
69
|
+
if (match?.groups?.["length"] === undefined) break;
|
|
70
|
+
const length = Number.parseInt(match.groups["length"], 10);
|
|
71
|
+
const bodyStart = headerEnd + 4;
|
|
72
|
+
const body = transcript.slice(bodyStart, bodyStart + length);
|
|
73
|
+
bodies.push(JSON.parse(body));
|
|
74
|
+
cursor = bodyStart + length;
|
|
75
|
+
}
|
|
76
|
+
return bodies;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function findTool(tools: readonly unknown[], name: string): Record<string, unknown> {
|
|
80
|
+
for (const tool of tools) {
|
|
81
|
+
const record = recordValue(tool);
|
|
82
|
+
if (record["name"] === name) return record;
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Missing tool ${name}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function arrayProperty(record: Record<string, unknown>, key: string): readonly unknown[] {
|
|
88
|
+
const value = record[key];
|
|
89
|
+
if (!Array.isArray(value)) throw new Error(`Expected ${key} to be an array`);
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function recordProperty(record: Record<string, unknown>, key: string): Record<string, unknown> {
|
|
94
|
+
return recordValue(record[key]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function stringProperty(record: Record<string, unknown>, key: string): string {
|
|
98
|
+
const value = record[key];
|
|
99
|
+
if (typeof value !== "string") throw new Error(`Expected ${key} to be a string`);
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function recordValue(value: unknown): Record<string, unknown> {
|
|
104
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
105
|
+
throw new Error("Expected record value");
|
|
106
|
+
}
|
|
107
|
+
return value as Record<string, unknown>;
|
|
108
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const componentRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
|
|
10
|
+
describe("built CodeGraph serve wrappers", () => {
|
|
11
|
+
it("#given built serve entry #when invoked with a fake CodeGraph binary #then it runs serve mcp exactly once", () => {
|
|
12
|
+
// given
|
|
13
|
+
const tempRoot = createFakeCodegraphRoot();
|
|
14
|
+
try {
|
|
15
|
+
// when
|
|
16
|
+
const result = runBuiltWrapper("dist/serve.js", tempRoot);
|
|
17
|
+
|
|
18
|
+
// then
|
|
19
|
+
expect(result.status).toBe(0);
|
|
20
|
+
expect(result.stderr).toBe("");
|
|
21
|
+
expect(readInvocations(tempRoot)).toEqual(['["serve","--mcp"]']);
|
|
22
|
+
} finally {
|
|
23
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("#given built cli entry #when invoked with a fake CodeGraph binary #then it runs serve mcp exactly once", () => {
|
|
28
|
+
// given
|
|
29
|
+
const tempRoot = createFakeCodegraphRoot();
|
|
30
|
+
try {
|
|
31
|
+
// when
|
|
32
|
+
const result = runBuiltWrapper("dist/cli.js", tempRoot);
|
|
33
|
+
|
|
34
|
+
// then
|
|
35
|
+
expect(result.status).toBe(0);
|
|
36
|
+
expect(result.stderr).toBe("");
|
|
37
|
+
expect(readInvocations(tempRoot)).toEqual(['["serve","--mcp"]']);
|
|
38
|
+
} finally {
|
|
39
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function createFakeCodegraphRoot(): string {
|
|
45
|
+
const tempRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-wrapper-"));
|
|
46
|
+
const fakeBinaryPath = join(tempRoot, "codegraph-fake.cjs");
|
|
47
|
+
writeFileSync(
|
|
48
|
+
fakeBinaryPath,
|
|
49
|
+
[
|
|
50
|
+
"#!/usr/bin/env node",
|
|
51
|
+
"const fs = require('node:fs');",
|
|
52
|
+
"fs.appendFileSync(process.env.CODEGRAPH_FAKE_LOG, JSON.stringify(process.argv.slice(2)) + '\\n');",
|
|
53
|
+
"",
|
|
54
|
+
].join("\n"),
|
|
55
|
+
);
|
|
56
|
+
chmodSync(fakeBinaryPath, 0o755);
|
|
57
|
+
return tempRoot;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function runBuiltWrapper(entryPath: string, tempRoot: string): ReturnType<typeof spawnSync> {
|
|
61
|
+
return spawnSync(process.execPath, [join(componentRoot, entryPath)], {
|
|
62
|
+
cwd: componentRoot,
|
|
63
|
+
encoding: "utf8",
|
|
64
|
+
env: {
|
|
65
|
+
...process.env,
|
|
66
|
+
CODEGRAPH_ALLOW_UNSAFE_NODE: "1",
|
|
67
|
+
CODEGRAPH_FAKE_LOG: join(tempRoot, "invocations.log"),
|
|
68
|
+
OMO_CODEGRAPH_BIN: join(tempRoot, "codegraph-fake.cjs"),
|
|
69
|
+
},
|
|
70
|
+
timeout: 5000,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function readInvocations(tempRoot: string): readonly string[] {
|
|
75
|
+
return readFileSync(join(tempRoot, "invocations.log"), "utf8").trim().split("\n");
|
|
76
|
+
}
|