infra-kit 0.1.126 → 0.1.128
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/.eslintcache +1 -1
- package/.omc/state/agent-replay-036daa78-5fee-4c7d-9b44-53584acb0d87.jsonl +26 -0
- package/.omc/state/agent-replay-0a65ec83-9de7-458d-9d0f-e56e1a26c68e.jsonl +2 -0
- package/.omc/state/agent-replay-1b6ffc57-2d9b-4af4-b603-f1cef7e01b0a.jsonl +17 -0
- package/.omc/state/agent-replay-2ac0dcd0-01f7-41a8-a8c9-f2195599817b.jsonl +5 -0
- package/.omc/state/agent-replay-d02e6565-5168-40c8-8629-de219a29fa43.jsonl +2 -0
- package/.omc/state/idle-notif-cooldown.json +1 -1
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/mission-state.json +129 -0
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/pre-tool-advisory-throttle.json +34 -0
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/ralph-state.json +13 -0
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/ralplan-state.json +11 -0
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/subagent-tracking-state.json +80 -0
- package/.omc/state/sessions/036daa78-5fee-4c7d-9b44-53584acb0d87/ultrawork-state.json +11 -0
- package/.omc/state/sessions/0a65ec83-9de7-458d-9d0f-e56e1a26c68e/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/0a65ec83-9de7-458d-9d0f-e56e1a26c68e/skill-active-state.json +15 -0
- package/.omc/state/sessions/1b6ffc57-2d9b-4af4-b603-f1cef7e01b0a/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/1b6ffc57-2d9b-4af4-b603-f1cef7e01b0a/mission-state.json +139 -0
- package/.omc/state/sessions/1b6ffc57-2d9b-4af4-b603-f1cef7e01b0a/pre-tool-advisory-throttle.json +50 -0
- package/.omc/state/sessions/1b6ffc57-2d9b-4af4-b603-f1cef7e01b0a/ralplan-state.json +11 -0
- package/.omc/state/sessions/1b6ffc57-2d9b-4af4-b603-f1cef7e01b0a/subagent-tracking-state.json +90 -0
- package/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/mission-state.json +79 -0
- package/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/pre-tool-advisory-throttle.json +10 -0
- package/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/skill-active-state.json +15 -0
- package/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/subagent-tracking-state.json +26 -0
- package/.omc/state/sessions/7772f972-4ec1-4287-bf42-a92c14cf3ffc/pre-tool-advisory-throttle.json +10 -0
- package/.omc/state/sessions/d02e6565-5168-40c8-8629-de219a29fa43/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/d02e6565-5168-40c8-8629-de219a29fa43/mission-state.json +53 -0
- package/.omc/state/sessions/d02e6565-5168-40c8-8629-de219a29fa43/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/d02e6565-5168-40c8-8629-de219a29fa43/subagent-tracking-state.json +17 -0
- package/.omc/state/sessions/f9c17a0e-2dd8-4f7d-badf-631f266c5d4c/pre-tool-advisory-throttle.json +10 -0
- package/.turbo/turbo-build.log +7 -6
- package/.turbo/turbo-check.log +1 -1
- package/.turbo/turbo-eslint-check.log +2 -1
- package/.turbo/turbo-infra-kit-check.log +14 -0
- package/.turbo/turbo-prettier-check.log +1 -1
- package/.turbo/turbo-test.log +406 -128
- package/.turbo/turbo-ts-check.log +1 -1
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/cli/index.html +116 -0
- package/coverage/cli/package.json.html +283 -0
- package/coverage/cli/src/commands/audit/audit.ts.html +616 -0
- package/coverage/cli/src/commands/audit/index.html +131 -0
- package/coverage/cli/src/commands/audit/index.ts.html +88 -0
- package/coverage/cli/src/commands/doctor/doctor.ts.html +1654 -0
- package/coverage/cli/src/commands/doctor/index.html +131 -0
- package/coverage/cli/src/commands/doctor/index.ts.html +88 -0
- package/coverage/cli/src/commands/env-clear/env-clear.ts.html +370 -0
- package/coverage/cli/src/commands/env-clear/index.html +131 -0
- package/coverage/cli/src/commands/env-clear/index.ts.html +88 -0
- package/coverage/cli/src/commands/env-list/env-list.ts.html +229 -0
- package/coverage/cli/src/commands/env-list/index.html +131 -0
- package/coverage/cli/src/commands/env-list/index.ts.html +88 -0
- package/coverage/cli/src/commands/env-load/env-load.ts.html +1201 -0
- package/coverage/cli/src/commands/env-load/index.html +131 -0
- package/coverage/cli/src/commands/env-load/index.ts.html +91 -0
- package/coverage/cli/src/commands/env-status/env-status.ts.html +409 -0
- package/coverage/cli/src/commands/env-status/index.html +131 -0
- package/coverage/cli/src/commands/env-status/index.ts.html +88 -0
- package/coverage/cli/src/commands/gh-merge-dev/gh-merge-dev.ts.html +694 -0
- package/coverage/cli/src/commands/gh-merge-dev/index.html +131 -0
- package/coverage/cli/src/commands/gh-merge-dev/index.ts.html +88 -0
- package/coverage/cli/src/commands/gh-release-deliver/gh-release-deliver.ts.html +1495 -0
- package/coverage/cli/src/commands/gh-release-deliver/index.html +131 -0
- package/coverage/cli/src/commands/gh-release-deliver/index.ts.html +88 -0
- package/coverage/cli/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts.html +706 -0
- package/coverage/cli/src/commands/gh-release-deploy-all/index.html +131 -0
- package/coverage/cli/src/commands/gh-release-deploy-all/index.ts.html +88 -0
- package/coverage/cli/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts.html +994 -0
- package/coverage/cli/src/commands/gh-release-deploy-selected/index.html +131 -0
- package/coverage/cli/src/commands/gh-release-deploy-selected/index.ts.html +88 -0
- package/coverage/cli/src/commands/gh-release-list/gh-release-list.ts.html +355 -0
- package/coverage/cli/src/commands/gh-release-list/index.html +131 -0
- package/coverage/cli/src/commands/gh-release-list/index.ts.html +88 -0
- package/coverage/cli/src/commands/init/agent-files.ts.html +742 -0
- package/coverage/cli/src/commands/init/index.html +146 -0
- package/coverage/cli/src/commands/init/init.ts.html +1159 -0
- package/coverage/cli/src/commands/init/migrate-config.ts.html +1219 -0
- package/coverage/cli/src/commands/release-create/index.html +131 -0
- package/coverage/cli/src/commands/release-create/index.ts.html +88 -0
- package/coverage/cli/src/commands/release-create/release-create.ts.html +1426 -0
- package/coverage/cli/src/commands/release-desc-edit/index.html +131 -0
- package/coverage/cli/src/commands/release-desc-edit/index.ts.html +88 -0
- package/coverage/cli/src/commands/release-desc-edit/release-desc-edit.ts.html +766 -0
- package/coverage/cli/src/commands/vendor-check/index.html +131 -0
- package/coverage/cli/src/commands/vendor-check/index.ts.html +88 -0
- package/coverage/cli/src/commands/vendor-check/vendor-check.ts.html +466 -0
- package/coverage/cli/src/commands/vendor-config/index.html +116 -0
- package/coverage/cli/src/commands/vendor-config/vendor-config.ts.html +571 -0
- package/coverage/cli/src/commands/vendor-diff/index.html +131 -0
- package/coverage/cli/src/commands/vendor-diff/index.ts.html +88 -0
- package/coverage/cli/src/commands/vendor-diff/vendor-diff.ts.html +316 -0
- package/coverage/cli/src/commands/vendor-manifest/index.html +131 -0
- package/coverage/cli/src/commands/vendor-manifest/index.ts.html +88 -0
- package/coverage/cli/src/commands/vendor-manifest/vendor-manifest.ts.html +265 -0
- package/coverage/cli/src/commands/vendor-sync/index.html +131 -0
- package/coverage/cli/src/commands/vendor-sync/index.ts.html +88 -0
- package/coverage/cli/src/commands/vendor-sync/vendor-sync.ts.html +355 -0
- package/coverage/cli/src/commands/version/index.html +131 -0
- package/coverage/cli/src/commands/version/index.ts.html +88 -0
- package/coverage/cli/src/commands/version/version.ts.html +184 -0
- package/coverage/cli/src/commands/worktrees-add/index.html +131 -0
- package/coverage/cli/src/commands/worktrees-add/index.ts.html +88 -0
- package/coverage/cli/src/commands/worktrees-add/worktrees-add.ts.html +1183 -0
- package/coverage/cli/src/commands/worktrees-list/index.html +131 -0
- package/coverage/cli/src/commands/worktrees-list/index.ts.html +88 -0
- package/coverage/cli/src/commands/worktrees-list/worktrees-list.ts.html +400 -0
- package/coverage/cli/src/commands/worktrees-reload/index.html +131 -0
- package/coverage/cli/src/commands/worktrees-reload/index.ts.html +88 -0
- package/coverage/cli/src/commands/worktrees-reload/worktrees-reload.ts.html +775 -0
- package/coverage/cli/src/commands/worktrees-remove/index.html +131 -0
- package/coverage/cli/src/commands/worktrees-remove/index.ts.html +88 -0
- package/coverage/cli/src/commands/worktrees-remove/worktrees-remove.ts.html +682 -0
- package/coverage/cli/src/commands/worktrees-sync/index.html +131 -0
- package/coverage/cli/src/commands/worktrees-sync/index.ts.html +88 -0
- package/coverage/cli/src/commands/worktrees-sync/worktrees-sync.ts.html +679 -0
- package/coverage/cli/src/dev/__tests__/fixtures.ts.html +787 -0
- package/coverage/cli/src/dev/__tests__/index.html +116 -0
- package/coverage/cli/src/dev/dev-server.ts.html +1855 -0
- package/coverage/cli/src/dev/discovery.ts.html +598 -0
- package/coverage/cli/src/dev/index.html +191 -0
- package/coverage/cli/src/dev/interfaces.ts.html +223 -0
- package/coverage/cli/src/dev/logger.ts.html +1102 -0
- package/coverage/cli/src/dev/ports.ts.html +430 -0
- package/coverage/cli/src/dev/serverless-local-run.ts.html +916 -0
- package/coverage/cli/src/entry/dev-server.ts.html +409 -0
- package/coverage/cli/src/entry/index.html +116 -0
- package/coverage/cli/src/index.html +116 -0
- package/coverage/cli/src/integrations/cmux/canonicalize-cmux-title.ts.html +178 -0
- package/coverage/cli/src/integrations/cmux/close-workspace-by-title.ts.html +262 -0
- package/coverage/cli/src/integrations/cmux/index.html +191 -0
- package/coverage/cli/src/integrations/cmux/index.ts.html +100 -0
- package/coverage/cli/src/integrations/cmux/list-workspace-titles.ts.html +226 -0
- package/coverage/cli/src/integrations/cmux/open-workspace-with-layout.ts.html +325 -0
- package/coverage/cli/src/integrations/cmux/workspace-title.ts.html +154 -0
- package/coverage/cli/src/integrations/cursor/add-folders-to-workspace.ts.html +337 -0
- package/coverage/cli/src/integrations/cursor/index.html +206 -0
- package/coverage/cli/src/integrations/cursor/index.ts.html +103 -0
- package/coverage/cli/src/integrations/cursor/launch-cursor.ts.html +121 -0
- package/coverage/cli/src/integrations/cursor/open-cursor-workspace.ts.html +277 -0
- package/coverage/cli/src/integrations/cursor/reconcile-workspace-folders.ts.html +355 -0
- package/coverage/cli/src/integrations/cursor/remove-folders-from-workspace.ts.html +364 -0
- package/coverage/cli/src/integrations/cursor/resolve-workspace-path.ts.html +124 -0
- package/coverage/cli/src/integrations/doppler/doppler-cli-auth.ts.html +178 -0
- package/coverage/cli/src/integrations/doppler/doppler-errors.ts.html +349 -0
- package/coverage/cli/src/integrations/doppler/doppler-project.ts.html +355 -0
- package/coverage/cli/src/integrations/doppler/index.html +161 -0
- package/coverage/cli/src/integrations/doppler/index.ts.html +97 -0
- package/coverage/cli/src/integrations/gh/gh-cli-auth/gh-cli-auth.ts.html +172 -0
- package/coverage/cli/src/integrations/gh/gh-cli-auth/index.html +131 -0
- package/coverage/cli/src/integrations/gh/gh-cli-auth/index.ts.html +88 -0
- package/coverage/cli/src/integrations/gh/gh-release-prs/gh-release-prs.ts.html +703 -0
- package/coverage/cli/src/integrations/gh/gh-release-prs/index.html +131 -0
- package/coverage/cli/src/integrations/gh/gh-release-prs/index.ts.html +91 -0
- package/coverage/cli/src/integrations/gh/index.html +116 -0
- package/coverage/cli/src/integrations/gh/index.ts.html +94 -0
- package/coverage/cli/src/integrations/ide/add-ide-worktree-folders.ts.html +316 -0
- package/coverage/cli/src/integrations/ide/index.html +191 -0
- package/coverage/cli/src/integrations/ide/index.ts.html +103 -0
- package/coverage/cli/src/integrations/ide/open-ide-workspace.ts.html +238 -0
- package/coverage/cli/src/integrations/ide/provider-label.ts.html +157 -0
- package/coverage/cli/src/integrations/ide/remove-ide-worktree-folders.ts.html +520 -0
- package/coverage/cli/src/integrations/ide/types.ts.html +208 -0
- package/coverage/cli/src/integrations/jira/api.ts.html +1060 -0
- package/coverage/cli/src/integrations/jira/index.html +131 -0
- package/coverage/cli/src/integrations/jira/index.ts.html +142 -0
- package/coverage/cli/src/integrations/zed/add-folders-to-zed-workspace.ts.html +175 -0
- package/coverage/cli/src/integrations/zed/index.html +161 -0
- package/coverage/cli/src/integrations/zed/index.ts.html +94 -0
- package/coverage/cli/src/integrations/zed/open-zed-workspace.ts.html +238 -0
- package/coverage/cli/src/integrations/zed/reuse-zed-workspace.ts.html +256 -0
- package/coverage/cli/src/lib/assert-never/assert-never.ts.html +130 -0
- package/coverage/cli/src/lib/assert-never/index.html +131 -0
- package/coverage/cli/src/lib/assert-never/index.ts.html +88 -0
- package/coverage/cli/src/lib/command-catalog/command-catalog.ts.html +523 -0
- package/coverage/cli/src/lib/command-catalog/index.html +116 -0
- package/coverage/cli/src/lib/command-echo/command-echo.ts.html +319 -0
- package/coverage/cli/src/lib/command-echo/index.html +131 -0
- package/coverage/cli/src/lib/command-echo/index.ts.html +88 -0
- package/coverage/cli/src/lib/constants/constants.ts.html +472 -0
- package/coverage/cli/src/lib/constants/index.html +131 -0
- package/coverage/cli/src/lib/constants/index.ts.html +139 -0
- package/coverage/cli/src/lib/env-autoload/env-autoload.ts.html +1111 -0
- package/coverage/cli/src/lib/env-autoload/index.html +116 -0
- package/coverage/cli/src/lib/errors/format-zx-error.ts.html +247 -0
- package/coverage/cli/src/lib/errors/index.html +146 -0
- package/coverage/cli/src/lib/errors/is-prompt-cancellation.ts.html +199 -0
- package/coverage/cli/src/lib/errors/operation-error.ts.html +325 -0
- package/coverage/cli/src/lib/git-guard/git-guard.ts.html +250 -0
- package/coverage/cli/src/lib/git-guard/index.html +131 -0
- package/coverage/cli/src/lib/git-guard/index.ts.html +91 -0
- package/coverage/cli/src/lib/git-utils/git-utils.ts.html +622 -0
- package/coverage/cli/src/lib/git-utils/index.html +131 -0
- package/coverage/cli/src/lib/git-utils/index.ts.html +115 -0
- package/coverage/cli/src/lib/infra-kit-config/index.html +131 -0
- package/coverage/cli/src/lib/infra-kit-config/index.ts.html +142 -0
- package/coverage/cli/src/lib/infra-kit-config/infra-kit-config.ts.html +1447 -0
- package/coverage/cli/src/lib/json-output/index.html +116 -0
- package/coverage/cli/src/lib/json-output/json-output.ts.html +226 -0
- package/coverage/cli/src/lib/logger/index.html +116 -0
- package/coverage/cli/src/lib/logger/index.ts.html +205 -0
- package/coverage/cli/src/lib/managed-block/index.html +131 -0
- package/coverage/cli/src/lib/managed-block/index.ts.html +109 -0
- package/coverage/cli/src/lib/managed-block/managed-block.ts.html +520 -0
- package/coverage/cli/src/lib/package-config/index.html +146 -0
- package/coverage/cli/src/lib/package-config/index.ts.html +94 -0
- package/coverage/cli/src/lib/package-config/package-config-schema.ts.html +142 -0
- package/coverage/cli/src/lib/package-config/package-config.ts.html +376 -0
- package/coverage/cli/src/lib/package-validator/checks/config-check.ts.html +175 -0
- package/coverage/cli/src/lib/package-validator/checks/files-check.ts.html +172 -0
- package/coverage/cli/src/lib/package-validator/checks/index.html +176 -0
- package/coverage/cli/src/lib/package-validator/checks/index.ts.html +97 -0
- package/coverage/cli/src/lib/package-validator/checks/scripts-check.ts.html +154 -0
- package/coverage/cli/src/lib/package-validator/checks/turbo-check.ts.html +226 -0
- package/coverage/cli/src/lib/package-validator/fs-utils.ts.html +139 -0
- package/coverage/cli/src/lib/package-validator/index.html +146 -0
- package/coverage/cli/src/lib/package-validator/index.ts.html +94 -0
- package/coverage/cli/src/lib/package-validator/loader/config-loader.ts.html +316 -0
- package/coverage/cli/src/lib/package-validator/loader/index.html +146 -0
- package/coverage/cli/src/lib/package-validator/loader/index.ts.html +91 -0
- package/coverage/cli/src/lib/package-validator/loader/package-discovery.ts.html +379 -0
- package/coverage/cli/src/lib/package-validator/package-validator.ts.html +229 -0
- package/coverage/cli/src/lib/path-display/index.html +131 -0
- package/coverage/cli/src/lib/path-display/index.ts.html +88 -0
- package/coverage/cli/src/lib/path-display/path-display.ts.html +211 -0
- package/coverage/cli/src/lib/release-id/index.html +131 -0
- package/coverage/cli/src/lib/release-id/index.ts.html +130 -0
- package/coverage/cli/src/lib/release-id/release-id.ts.html +859 -0
- package/coverage/cli/src/lib/release-utils/index.html +131 -0
- package/coverage/cli/src/lib/release-utils/index.ts.html +130 -0
- package/coverage/cli/src/lib/release-utils/release-utils.ts.html +778 -0
- package/coverage/cli/src/lib/render/index.html +116 -0
- package/coverage/cli/src/lib/render/render.ts.html +157 -0
- package/coverage/cli/src/lib/vendor/__tests__/index.html +116 -0
- package/coverage/cli/src/lib/vendor/__tests__/zx-mock.ts.html +181 -0
- package/coverage/cli/src/lib/vendor/config-schema.ts.html +319 -0
- package/coverage/cli/src/lib/vendor/config.ts.html +259 -0
- package/coverage/cli/src/lib/vendor/factory-config-schema.ts.html +190 -0
- package/coverage/cli/src/lib/vendor/factory-config.ts.html +358 -0
- package/coverage/cli/src/lib/vendor/hash.ts.html +133 -0
- package/coverage/cli/src/lib/vendor/index.html +251 -0
- package/coverage/cli/src/lib/vendor/index.ts.html +154 -0
- package/coverage/cli/src/lib/vendor/manifest.ts.html +538 -0
- package/coverage/cli/src/lib/vendor/skip-sets.ts.html +229 -0
- package/coverage/cli/src/lib/vendor/sync-ops.ts.html +955 -0
- package/coverage/cli/src/lib/vendor/walk.ts.html +253 -0
- package/coverage/cli/src/lib/version-utils/index.html +161 -0
- package/coverage/cli/src/lib/version-utils/index.ts.html +139 -0
- package/coverage/cli/src/lib/version-utils/load-existing-versions.ts.html +343 -0
- package/coverage/cli/src/lib/version-utils/next-version.ts.html +934 -0
- package/coverage/cli/src/lib/version-utils/version-utils.ts.html +178 -0
- package/coverage/cli/src/lib/worktrees/index.html +131 -0
- package/coverage/cli/src/lib/worktrees/index.ts.html +88 -0
- package/coverage/cli/src/lib/worktrees/remove-worktrees.ts.html +283 -0
- package/coverage/cli/src/tui/boot.tsx.html +265 -0
- package/coverage/cli/src/tui/index.html +116 -0
- package/coverage/cli/src/tui/screens/command-palette.tsx.html +562 -0
- package/coverage/cli/src/tui/screens/index.html +116 -0
- package/coverage/cli/src/types.ts.html +283 -0
- package/coverage/clover.xml +4488 -0
- package/coverage/coverage-final.json +156 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +1076 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/chunk-DB6CTNBS.js +3 -0
- package/dist/chunk-DB6CTNBS.js.map +7 -0
- package/dist/chunk-QBHCWAAG.js +164 -0
- package/dist/chunk-QBHCWAAG.js.map +7 -0
- package/dist/chunk-YSBF5C7C.js +2 -0
- package/dist/chunk-YSBF5C7C.js.map +7 -0
- package/dist/cli.js +5 -5
- package/dist/cli.js.map +3 -3
- package/dist/dev-server.js +13 -0
- package/dist/dev-server.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/package.json +7 -2
- package/scripts/build.js +4 -4
- package/src/.omc/state/agent-replay-2ac0dcd0-01f7-41a8-a8c9-f2195599817b.jsonl +5 -0
- package/src/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/mission-state.json +79 -0
- package/src/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/pre-tool-advisory-throttle.json +26 -0
- package/src/.omc/state/sessions/2ac0dcd0-01f7-41a8-a8c9-f2195599817b/subagent-tracking-state.json +26 -0
- package/src/commands/audit/.omc/state/agent-replay-f9c17a0e-2dd8-4f7d-badf-631f266c5d4c.jsonl +4 -0
- package/src/commands/audit/.omc/state/sessions/f9c17a0e-2dd8-4f7d-badf-631f266c5d4c/mission-state.json +79 -0
- package/src/commands/audit/.omc/state/sessions/f9c17a0e-2dd8-4f7d-badf-631f266c5d4c/pre-tool-advisory-throttle.json +22 -0
- package/src/commands/audit/.omc/state/sessions/f9c17a0e-2dd8-4f7d-badf-631f266c5d4c/subagent-tracking-state.json +26 -0
- package/src/commands/audit/audit.ts +1 -1
- package/src/commands/doctor/doctor.ts +53 -0
- package/src/commands/env-autoload/env-autoload.ts +14 -2
- package/src/commands/env-clear/env-clear.ts +48 -7
- package/src/commands/env-load/env-load.ts +23 -1
- package/src/commands/init/__tests__/shell-body.test.ts +104 -3
- package/src/commands/init/init.ts +91 -9
- package/src/dev/__tests__/dev-server-options.test.ts +57 -0
- package/src/dev/__tests__/dev-server.test.ts +420 -0
- package/src/dev/__tests__/discovery.test.ts +181 -0
- package/src/dev/__tests__/fixtures.ts +257 -0
- package/src/dev/__tests__/ports.test.ts +98 -0
- package/src/dev/__tests__/serverless-local-run.test.ts +533 -0
- package/src/dev/dev-server.ts +796 -0
- package/src/dev/discovery.ts +229 -0
- package/src/dev/interfaces.ts +11 -0
- package/src/dev/managed-child.ts +73 -0
- package/src/dev/ports.ts +100 -0
- package/src/dev/serverless-local-run.ts +329 -0
- package/src/dev/turbo-watch.ts +62 -0
- package/src/dev/ui-dev.ts +62 -0
- package/src/entry/cli.ts +25 -6
- package/src/entry/dev-server.ts +103 -0
- package/src/lib/.omc/state/sessions/f9c17a0e-2dd8-4f7d-badf-631f266c5d4c/pre-tool-advisory-throttle.json +18 -0
- package/src/lib/command-catalog/__tests__/__snapshots__/command-catalog.test.ts.snap +1 -0
- package/src/lib/command-catalog/command-catalog.ts +4 -0
- package/src/lib/constants/constants.ts +38 -0
- package/src/lib/constants/index.ts +4 -0
- package/src/lib/env-autoload/__tests__/env-autoload.test.ts +25 -0
- package/src/lib/env-autoload/env-autoload.ts +35 -4
- package/src/lib/infra-kit-config/index.ts +2 -0
- package/src/lib/infra-kit-config/infra-kit-config.ts +22 -0
- package/src/lib/package-config/package-config.ts +2 -2
- package/src/lib/package-validator/.omc/state/sessions/f9c17a0e-2dd8-4f7d-badf-631f266c5d4c/pre-tool-advisory-throttle.json +10 -0
- package/src/lib/package-validator/__tests__/package-validator.test.ts +9 -2
- package/src/lib/warm-cache/__tests__/warm-cache.test.ts +164 -0
- package/src/lib/warm-cache/index.ts +7 -0
- package/src/lib/warm-cache/warm-cache.ts +136 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/chunk-EY5LDHXC.js +0 -164
- package/dist/chunk-EY5LDHXC.js.map +0 -7
- package/dist/chunk-WA4BQRDC.js +0 -2
- package/dist/chunk-WA4BQRDC.js.map +0 -7
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as path from 'node:path'
|
|
3
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
classifyDistChange,
|
|
7
|
+
discoverApiApps,
|
|
8
|
+
discoverUiApps,
|
|
9
|
+
findMonorepoRoot,
|
|
10
|
+
getAppDistDirs,
|
|
11
|
+
getPackageDistDirs,
|
|
12
|
+
getPackageName,
|
|
13
|
+
normalizeAppInclude,
|
|
14
|
+
} from 'src/dev/discovery'
|
|
15
|
+
|
|
16
|
+
import { createTempTracker, makeMonorepo } from './fixtures'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Filesystem discovery, driven by an explicit `root` argument — no chdir, no cast.
|
|
20
|
+
* Each spec builds a hermetic monorepo fixture and passes its path straight in.
|
|
21
|
+
*/
|
|
22
|
+
const temp = createTempTracker()
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
temp.cleanup()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('discoverApiApps — app discovery', () => {
|
|
29
|
+
it('discovers every apps/<app> that has an api/serverless.yml', () => {
|
|
30
|
+
const root = temp.register(makeMonorepo([{ name: 'client' }, { name: 'backoffice' }]))
|
|
31
|
+
|
|
32
|
+
const names = discoverApiApps(root)
|
|
33
|
+
.map((a) => {
|
|
34
|
+
return a.name
|
|
35
|
+
})
|
|
36
|
+
.sort()
|
|
37
|
+
|
|
38
|
+
expect(names).toEqual(['backoffice', 'client'])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('ignores app folders that have no serverless.yml', () => {
|
|
42
|
+
const root = temp.register(makeMonorepo([{ name: 'client' }, { name: 'web', api: false }]))
|
|
43
|
+
|
|
44
|
+
const names = discoverApiApps(root).map((a) => {
|
|
45
|
+
return a.name
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
expect(names).toEqual(['client'])
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('reads packageName from package.json, falling back to the folder name', () => {
|
|
52
|
+
const root = temp.register(
|
|
53
|
+
makeMonorepo([{ name: 'client', packageName: 'sls-trvl-client' }, { name: 'backoffice' }]),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const byName = new Map(
|
|
57
|
+
discoverApiApps(root).map((a) => {
|
|
58
|
+
return [a.name, a.packageName]
|
|
59
|
+
}),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
expect(byName.get('client')).toBe('sls-trvl-client')
|
|
63
|
+
expect(byName.get('backoffice')).toBe('backoffice')
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
describe('findMonorepoRoot — walk up to pnpm-workspace.yaml', () => {
|
|
68
|
+
it('returns the dir that holds pnpm-workspace.yaml when starting from a nested api dir', () => {
|
|
69
|
+
const root = temp.register(makeMonorepo([{ name: 'client' }]))
|
|
70
|
+
const startDir = path.join(root, 'apps', 'client', 'api')
|
|
71
|
+
|
|
72
|
+
expect(findMonorepoRoot(startDir)).toBe(root)
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('getPackageName — package.json name with fallback', () => {
|
|
77
|
+
it('returns the package.json name field when present', () => {
|
|
78
|
+
const root = temp.register(makeMonorepo([{ name: 'client', packageName: 'sls-trvl-client' }]))
|
|
79
|
+
const apiDir = path.join(root, 'apps', 'client', 'api')
|
|
80
|
+
|
|
81
|
+
expect(getPackageName(apiDir, 'client')).toBe('sls-trvl-client')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('falls back to the given app name when there is no package.json', () => {
|
|
85
|
+
const root = temp.register(makeMonorepo([{ name: 'backoffice' }]))
|
|
86
|
+
const apiDir = path.join(root, 'apps', 'backoffice', 'api')
|
|
87
|
+
|
|
88
|
+
expect(getPackageName(apiDir, 'backoffice')).toBe('backoffice')
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
describe('normalizeAppInclude — --app list normalization', () => {
|
|
93
|
+
it('normalizes empty, whitespace-only, undefined, and null lists to null', () => {
|
|
94
|
+
expect(normalizeAppInclude([])).toBeNull()
|
|
95
|
+
expect(normalizeAppInclude([''])).toBeNull()
|
|
96
|
+
expect(normalizeAppInclude(undefined)).toBeNull()
|
|
97
|
+
expect(normalizeAppInclude(null)).toBeNull()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('keeps a non-empty list and drops falsy entries', () => {
|
|
101
|
+
expect(normalizeAppInclude(['client', ''])).toEqual(['client'])
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
describe('classifyDistChange — route a compiled-output path to app vs package', () => {
|
|
106
|
+
const appDistDirs = ['/repo/apps/client/api/dist']
|
|
107
|
+
const packageDistDirs = ['/repo/packages/lib-core/dist']
|
|
108
|
+
|
|
109
|
+
it('classifies an app-dist path as an app change and returns the matched app dist dir', () => {
|
|
110
|
+
const change = classifyDistChange('/repo/apps/client/api/dist/controllers/x.js', appDistDirs, packageDistDirs)
|
|
111
|
+
|
|
112
|
+
expect(change).toEqual({ kind: 'app', app: '/repo/apps/client/api/dist' })
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('classifies a package-dist path as a package change (a lib was rebuilt → restart all)', () => {
|
|
116
|
+
const change = classifyDistChange('/repo/packages/lib-core/dist/index.js', appDistDirs, packageDistDirs)
|
|
117
|
+
|
|
118
|
+
expect(change).toEqual({ kind: 'package' })
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('returns an app change with undefined dir when nothing matches', () => {
|
|
122
|
+
const change = classifyDistChange('/repo/elsewhere/dist/x.js', appDistDirs, packageDistDirs)
|
|
123
|
+
|
|
124
|
+
expect(change).toEqual({ kind: 'app', app: undefined })
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe('getPackageDistDirs / getAppDistDirs — existing dist dirs only', () => {
|
|
129
|
+
it('returns packages/<pkg>/dist dirs that exist and skips those without a dist', () => {
|
|
130
|
+
const root = temp.register(makeMonorepo([{ name: 'client', withHandler: true }]))
|
|
131
|
+
|
|
132
|
+
// makeMonorepo only scaffolds apps/*; add a packages/ tree with one built + one unbuilt pkg.
|
|
133
|
+
fs.mkdirSync(path.join(root, 'packages', 'lib-core', 'dist'), { recursive: true })
|
|
134
|
+
fs.mkdirSync(path.join(root, 'packages', 'lib-unbuilt', 'src'), { recursive: true })
|
|
135
|
+
|
|
136
|
+
const distDirs = getPackageDistDirs(root)
|
|
137
|
+
|
|
138
|
+
expect(distDirs).toContain(path.join(root, 'packages', 'lib-core', 'dist'))
|
|
139
|
+
expect(distDirs).not.toContain(path.join(root, 'packages', 'lib-unbuilt', 'dist'))
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('returns <app.path>/dist dirs that exist (withHandler apps have one)', () => {
|
|
143
|
+
const root = temp.register(makeMonorepo([{ name: 'client', withHandler: true }]))
|
|
144
|
+
const apiDir = path.join(root, 'apps', 'client', 'api')
|
|
145
|
+
|
|
146
|
+
const distDirs = getAppDistDirs([{ path: apiDir }])
|
|
147
|
+
|
|
148
|
+
expect(distDirs).toEqual([path.join(apiDir, 'dist')])
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('discoverUiApps — frontends with a `dev` script', () => {
|
|
153
|
+
it('discovers apps/<app>/ui that declare a dev script, resolving the package name', () => {
|
|
154
|
+
const root = temp.register(
|
|
155
|
+
makeMonorepo([
|
|
156
|
+
{ name: 'backoffice', ui: { packageName: 'backoffice-ui' } },
|
|
157
|
+
{ name: 'client', ui: { packageName: 'website-ui' } },
|
|
158
|
+
]),
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
const uiApps = discoverUiApps(root)
|
|
162
|
+
|
|
163
|
+
expect(uiApps).toEqual([
|
|
164
|
+
{ name: 'backoffice', packageName: 'backoffice-ui', path: path.join(root, 'apps', 'backoffice', 'ui') },
|
|
165
|
+
{ name: 'client', packageName: 'website-ui', path: path.join(root, 'apps', 'client', 'ui') },
|
|
166
|
+
])
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('ignores a ui folder that has no dev script', () => {
|
|
170
|
+
const root = temp.register(makeMonorepo([{ name: 'seo', ui: { dev: false } }]))
|
|
171
|
+
|
|
172
|
+
expect(discoverUiApps(root)).toEqual([])
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('returns [] when there is no apps/ dir (UIs are optional, unlike api discovery)', () => {
|
|
176
|
+
const root = temp.register(makeMonorepo([]))
|
|
177
|
+
|
|
178
|
+
fs.rmSync(path.join(root, 'apps'), { recursive: true, force: true })
|
|
179
|
+
expect(discoverUiApps(root)).toEqual([])
|
|
180
|
+
})
|
|
181
|
+
})
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test fixtures for the dev-server suites.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is hermetic: temp dirs are created under the OS tmp dir and
|
|
5
|
+
* returned to the caller (register them with a {@link createTempTracker} so an
|
|
6
|
+
* `afterEach` can remove them). No module-level side effects — importing this
|
|
7
|
+
* file never touches the filesystem, cwd, or env.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs'
|
|
10
|
+
import * as net from 'node:net'
|
|
11
|
+
import * as os from 'node:os'
|
|
12
|
+
import * as path from 'node:path'
|
|
13
|
+
import process from 'node:process'
|
|
14
|
+
import { vi } from 'vitest'
|
|
15
|
+
|
|
16
|
+
import { ServerlessLocalRun } from 'src/dev/serverless-local-run'
|
|
17
|
+
|
|
18
|
+
/** Default URL prefix the fixtures serve routes under (matches the runner default). */
|
|
19
|
+
export const PREFIX = '/api/v1'
|
|
20
|
+
|
|
21
|
+
/** serverless.yml exposing ping (GET), echo (POST) and item (GET {id}) routes. */
|
|
22
|
+
const SERVERLESS_YML = [
|
|
23
|
+
'service: testapp',
|
|
24
|
+
'functions:',
|
|
25
|
+
' ping:',
|
|
26
|
+
' handler: dist/handler.ping',
|
|
27
|
+
' events:',
|
|
28
|
+
' - http:',
|
|
29
|
+
' method: get',
|
|
30
|
+
' path: ping',
|
|
31
|
+
' echo:',
|
|
32
|
+
' handler: dist/handler.echo',
|
|
33
|
+
' events:',
|
|
34
|
+
' - http:',
|
|
35
|
+
' method: post',
|
|
36
|
+
' path: echo',
|
|
37
|
+
' item:',
|
|
38
|
+
' handler: dist/handler.item',
|
|
39
|
+
' events:',
|
|
40
|
+
' - http:',
|
|
41
|
+
' method: get',
|
|
42
|
+
' path: item/{id}',
|
|
43
|
+
'',
|
|
44
|
+
].join('\n')
|
|
45
|
+
|
|
46
|
+
/** serverless.yml with a single ping (GET) route — used for monorepo app fixtures. */
|
|
47
|
+
const MONOREPO_SERVERLESS_YML = [
|
|
48
|
+
'service: svc',
|
|
49
|
+
'functions:',
|
|
50
|
+
' ping:',
|
|
51
|
+
' handler: dist/handler.ping',
|
|
52
|
+
' events:',
|
|
53
|
+
' - http:',
|
|
54
|
+
' method: get',
|
|
55
|
+
' path: ping',
|
|
56
|
+
'',
|
|
57
|
+
].join('\n')
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Compiled ESM handler written straight to `dist/*.js` (no build step). Each handler
|
|
61
|
+
* echoes the Lambda event back as its JSON body so the HTTP->Lambda transform can be
|
|
62
|
+
* asserted from the response. `version` lets a reload test tell v1 from v2 apart.
|
|
63
|
+
*/
|
|
64
|
+
export function handlerSource(version = 1): string {
|
|
65
|
+
return [
|
|
66
|
+
`const version = ${version}`,
|
|
67
|
+
'const reply = (event, extra) => ({',
|
|
68
|
+
' statusCode: 200,',
|
|
69
|
+
" headers: { 'content-type': 'application/json', 'x-handler-version': String(version) },",
|
|
70
|
+
' body: JSON.stringify({ version, event, ...extra }),',
|
|
71
|
+
'})',
|
|
72
|
+
'export const ping = async (event) => reply(event, { route: "ping" })',
|
|
73
|
+
'export const echo = async (event) => reply(event, { route: "echo" })',
|
|
74
|
+
'export const item = async (event) => reply(event, { route: "item" })',
|
|
75
|
+
'',
|
|
76
|
+
].join('\n')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Create an `apps/testapp/api`-shaped fixture with serverless.yml + a compiled dist handler. */
|
|
80
|
+
export function makeApiFixture(handlerVersion = 1): string {
|
|
81
|
+
const apiDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ik-sls-run-'))
|
|
82
|
+
|
|
83
|
+
fs.writeFileSync(path.join(apiDir, 'serverless.yml'), SERVERLESS_YML)
|
|
84
|
+
// type:module so Node loads the plain dist/*.js as ESM (named exports available).
|
|
85
|
+
fs.writeFileSync(path.join(apiDir, 'package.json'), JSON.stringify({ name: 'testapp-api', type: 'module' }))
|
|
86
|
+
fs.mkdirSync(path.join(apiDir, 'dist'), { recursive: true })
|
|
87
|
+
fs.writeFileSync(path.join(apiDir, 'dist', 'handler.js'), handlerSource(handlerVersion))
|
|
88
|
+
|
|
89
|
+
return apiDir
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** One app inside a monorepo fixture. */
|
|
93
|
+
export interface AppSpec {
|
|
94
|
+
/** App folder name (e.g. client, backoffice). */
|
|
95
|
+
name: string
|
|
96
|
+
/** package.json `name`. Omit to leave package.json out (discovery falls back to the folder name). */
|
|
97
|
+
packageName?: string
|
|
98
|
+
/** Set false to create the app folder WITHOUT serverless.yml (should be ignored by discovery). */
|
|
99
|
+
api?: boolean
|
|
100
|
+
/** Also write package.json (type:module) + a real dist/handler.js so the app can actually boot. */
|
|
101
|
+
withHandler?: boolean
|
|
102
|
+
/**
|
|
103
|
+
* Also scaffold `apps/<name>/ui/package.json`. `dev` (default true) controls whether it declares a
|
|
104
|
+
* `scripts.dev` — a UI without one must be ignored by {@link discoverUiApps}.
|
|
105
|
+
*/
|
|
106
|
+
ui?: { packageName?: string; dev?: boolean }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Build a hermetic monorepo: pnpm-workspace.yaml + `apps/<app>/api/serverless.yml` per spec. */
|
|
110
|
+
export function makeMonorepo(apps: AppSpec[]): string {
|
|
111
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ik-monorepo-'))
|
|
112
|
+
|
|
113
|
+
fs.writeFileSync(path.join(root, 'pnpm-workspace.yaml'), 'packages:\n - apps/*\n')
|
|
114
|
+
fs.mkdirSync(path.join(root, 'apps'), { recursive: true })
|
|
115
|
+
|
|
116
|
+
for (const app of apps) {
|
|
117
|
+
const apiDir = path.join(root, 'apps', app.name, 'api')
|
|
118
|
+
|
|
119
|
+
fs.mkdirSync(apiDir, { recursive: true })
|
|
120
|
+
if (app.api !== false) {
|
|
121
|
+
fs.writeFileSync(path.join(apiDir, 'serverless.yml'), MONOREPO_SERVERLESS_YML)
|
|
122
|
+
}
|
|
123
|
+
if (app.packageName != null || app.withHandler) {
|
|
124
|
+
fs.writeFileSync(
|
|
125
|
+
path.join(apiDir, 'package.json'),
|
|
126
|
+
JSON.stringify({ name: app.packageName ?? `${app.name}-api`, type: 'module' }),
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
if (app.withHandler) {
|
|
130
|
+
fs.mkdirSync(path.join(apiDir, 'dist'), { recursive: true })
|
|
131
|
+
fs.writeFileSync(path.join(apiDir, 'dist', 'handler.js'), handlerSource(1))
|
|
132
|
+
}
|
|
133
|
+
if (app.ui) {
|
|
134
|
+
const uiDir = path.join(root, 'apps', app.name, 'ui')
|
|
135
|
+
|
|
136
|
+
fs.mkdirSync(uiDir, { recursive: true })
|
|
137
|
+
const pkg: { name: string; scripts?: Record<string, string> } = {
|
|
138
|
+
name: app.ui.packageName ?? `${app.name}-ui`,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (app.ui.dev !== false) pkg.scripts = { dev: 'vite' }
|
|
142
|
+
fs.writeFileSync(path.join(uiDir, 'package.json'), JSON.stringify(pkg))
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return root
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Ask the OS for a currently-free TCP port on localhost, then release it. */
|
|
150
|
+
export async function getFreePort(): Promise<number> {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
const srv = net.createServer()
|
|
153
|
+
|
|
154
|
+
srv.unref()
|
|
155
|
+
srv.on('error', reject)
|
|
156
|
+
srv.listen(0, '127.0.0.1', () => {
|
|
157
|
+
const addr = srv.address()
|
|
158
|
+
const port = typeof addr === 'object' && addr != null ? addr.port : 0
|
|
159
|
+
|
|
160
|
+
srv.close(() => {
|
|
161
|
+
return resolve(port)
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** True if a fresh listener can bind `port` — i.e. the previous server released it. */
|
|
168
|
+
export async function canBind(port: number): Promise<boolean> {
|
|
169
|
+
return new Promise((resolve) => {
|
|
170
|
+
const srv = net.createServer()
|
|
171
|
+
|
|
172
|
+
srv.once('error', () => {
|
|
173
|
+
return resolve(false)
|
|
174
|
+
})
|
|
175
|
+
srv.listen(port, '127.0.0.1', () => {
|
|
176
|
+
return srv.close(() => {
|
|
177
|
+
return resolve(true)
|
|
178
|
+
})
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Boot a server against `apiDir` on `port`. No `chdir`: `ServerlessLocalRun` reads
|
|
185
|
+
* `serverless.yml` and imports the handler from `controllersPath` (absolute), so booting
|
|
186
|
+
* is cwd-independent. The caller owns the returned server's lifecycle (call `close()` in teardown).
|
|
187
|
+
*/
|
|
188
|
+
export async function boot(
|
|
189
|
+
apiDir: string,
|
|
190
|
+
port: number,
|
|
191
|
+
appName = 'testapp',
|
|
192
|
+
prefixUrl = PREFIX,
|
|
193
|
+
): Promise<ServerlessLocalRun> {
|
|
194
|
+
const server = new ServerlessLocalRun({ controllersPath: apiDir, prefixUrl, port, appName })
|
|
195
|
+
|
|
196
|
+
await server.start()
|
|
197
|
+
|
|
198
|
+
return server
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** A registry of temp dirs so an `afterEach` can remove everything created in a test. */
|
|
202
|
+
export interface TempTracker {
|
|
203
|
+
/** Register a dir for cleanup and return it (so calls can be inlined). */
|
|
204
|
+
register: (dir: string) => string
|
|
205
|
+
/** Remove every registered dir and clear the registry. */
|
|
206
|
+
cleanup: () => void
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function createTempTracker(): TempTracker {
|
|
210
|
+
const dirs: string[] = []
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
register: (dir: string): string => {
|
|
214
|
+
dirs.push(dir)
|
|
215
|
+
|
|
216
|
+
return dir
|
|
217
|
+
},
|
|
218
|
+
cleanup: (): void => {
|
|
219
|
+
for (const dir of dirs.splice(0)) {
|
|
220
|
+
fs.rmSync(dir, { recursive: true, force: true })
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Snapshot `process.env` so tests can restore it after mutating per-app port vars. */
|
|
227
|
+
export function snapshotEnv(): NodeJS.ProcessEnv {
|
|
228
|
+
return { ...process.env }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Restore a `process.env` snapshot taken by {@link snapshotEnv}. */
|
|
232
|
+
export function restoreEnv(snapshot: NodeJS.ProcessEnv): void {
|
|
233
|
+
process.env = { ...snapshot }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Snapshot the current working directory (fixtures chdir for serverless.yml resolution). */
|
|
237
|
+
export function snapshotCwd(): string {
|
|
238
|
+
return process.cwd()
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Restore a cwd snapshot taken by {@link snapshotCwd}. */
|
|
242
|
+
export function restoreCwd(dir: string): void {
|
|
243
|
+
process.chdir(dir)
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Spy `process.stdout.write`, pushing every written chunk into `sink`. The caller owns
|
|
248
|
+
* the returned spy's lifecycle (`spy.mockRestore()` in a `finally`). Used by the dev-server
|
|
249
|
+
* table / route-dump / request-log tests to assert on captured startup + request output.
|
|
250
|
+
*/
|
|
251
|
+
export function spyStdoutWrite(sink: string[]): ReturnType<typeof vi.spyOn> {
|
|
252
|
+
return vi.spyOn(process.stdout, 'write').mockImplementation(((chunk: unknown): boolean => {
|
|
253
|
+
sink.push(String(chunk))
|
|
254
|
+
|
|
255
|
+
return true
|
|
256
|
+
}) as never)
|
|
257
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_PORT,
|
|
5
|
+
DEFAULT_PREFIX_URL,
|
|
6
|
+
findPortConflicts,
|
|
7
|
+
parsePortString,
|
|
8
|
+
resolvePort,
|
|
9
|
+
resolvePrefixUrl,
|
|
10
|
+
} from 'src/dev/ports'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Pure port / prefix resolution. Every function is side-effect free, so these
|
|
14
|
+
* specs pass `env` and `devConfig` in as plain objects — no fixtures, no cwd,
|
|
15
|
+
* no process.env mutation.
|
|
16
|
+
*/
|
|
17
|
+
describe('resolvePort — precedence order', () => {
|
|
18
|
+
it('falls back to the 3010 default when nothing is set', () => {
|
|
19
|
+
expect(resolvePort('client', {}, {})).toBe(DEFAULT_PORT)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('uses dev.<app>.port from config over the default', () => {
|
|
23
|
+
expect(resolvePort('client', {}, { client: { port: 3200 } })).toBe(3200)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('lets PORT beat the config port', () => {
|
|
27
|
+
expect(resolvePort('client', { PORT: '3300' }, { client: { port: 3200 } })).toBe(3300)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('lets {APP}_PORT beat PORT and config', () => {
|
|
31
|
+
expect(resolvePort('client', { PORT: '3300', CLIENT_PORT: '3400' }, { client: { port: 3200 } })).toBe(3400)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('maps a hyphenated app name to UPPER_SNAKE_CASE for the {APP}_PORT key', () => {
|
|
35
|
+
expect(resolvePort('search-engine', { SEARCH_ENGINE_PORT: '3500' }, {})).toBe(3500)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('honors {APP}_PORT = 0 and does NOT fall through to a lower tier', () => {
|
|
39
|
+
// 0 is a valid "pick a free port" request; only null/undefined means "unset".
|
|
40
|
+
expect(resolvePort('client', { CLIENT_PORT: '0' }, { client: { port: 3200 } })).toBe(0)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('strips surrounding quotes on a {APP}_PORT env value', () => {
|
|
44
|
+
// Secrets managers can export values wrapped in quotes.
|
|
45
|
+
expect(resolvePort('client', { CLIENT_PORT: '"3400"' }, {})).toBe(3400)
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe('resolvePrefixUrl — config over default', () => {
|
|
50
|
+
it('defaults to /api/v1 when nothing is configured', () => {
|
|
51
|
+
expect(resolvePrefixUrl('client', {})).toBe(DEFAULT_PREFIX_URL)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('honors dev.<app>.prefixUrl over the default', () => {
|
|
55
|
+
expect(resolvePrefixUrl('client', { client: { prefixUrl: '/custom/v2' } })).toBe('/custom/v2')
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
describe('parsePortString — raw port coercion', () => {
|
|
60
|
+
it('strips a single pair of surrounding quotes', () => {
|
|
61
|
+
expect(parsePortString('"3400"')).toBe(3400)
|
|
62
|
+
expect(parsePortString("'3400'")).toBe(3400)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('returns undefined for non-numeric input', () => {
|
|
66
|
+
expect(parsePortString('abc')).toBeUndefined()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('returns undefined for undefined and blank input', () => {
|
|
70
|
+
expect(parsePortString(undefined)).toBeUndefined()
|
|
71
|
+
expect(parsePortString('')).toBeUndefined()
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe('findPortConflicts — duplicate detection', () => {
|
|
76
|
+
it('reports the duplicate port and every colliding app when two apps share a port', () => {
|
|
77
|
+
const result = findPortConflicts([
|
|
78
|
+
{ name: 'client', port: 3010 },
|
|
79
|
+
{ name: 'backoffice', port: 3010 },
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
expect(result.duplicatePorts).toEqual([3010])
|
|
83
|
+
expect(result.conflictingApps).toEqual([
|
|
84
|
+
{ name: 'client', port: 3010 },
|
|
85
|
+
{ name: 'backoffice', port: 3010 },
|
|
86
|
+
])
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('reports no conflict when every app resolves to a distinct port', () => {
|
|
90
|
+
const result = findPortConflicts([
|
|
91
|
+
{ name: 'client', port: 3010 },
|
|
92
|
+
{ name: 'backoffice', port: 3011 },
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
expect(result.duplicatePorts).toEqual([])
|
|
96
|
+
expect(result.conflictingApps).toEqual([])
|
|
97
|
+
})
|
|
98
|
+
})
|