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,329 @@
|
|
|
1
|
+
import { Logger } from '@aws-lambda-powertools/logger'
|
|
2
|
+
import type { APIGatewayProxyEvent, APIGatewayProxyEventQueryStringParameters, Context } from 'aws-lambda'
|
|
3
|
+
import fastify from 'fastify'
|
|
4
|
+
import * as fs from 'node:fs'
|
|
5
|
+
import type { Server } from 'node:http'
|
|
6
|
+
import * as path from 'node:path'
|
|
7
|
+
import process from 'node:process'
|
|
8
|
+
import { pathToFileURL } from 'node:url'
|
|
9
|
+
import { parse as parseYaml } from 'yaml'
|
|
10
|
+
|
|
11
|
+
import type { ILogger } from './interfaces.js'
|
|
12
|
+
|
|
13
|
+
export interface IServerConfig {
|
|
14
|
+
controllersPath: string
|
|
15
|
+
prefixUrl?: string
|
|
16
|
+
port: number
|
|
17
|
+
/** App folder name, surfaced by the `/__health` endpoint. Optional. */
|
|
18
|
+
appName?: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type HandlerResult = Promise<{ body: string; headers: Record<string, string>; statusCode: number }>
|
|
22
|
+
|
|
23
|
+
/** Default simulated Lambda timeout; overridable via `DEV_SERVER_TIMEOUT_MS`. */
|
|
24
|
+
const DEFAULT_LAMBDA_TIMEOUT_MS = 30_000
|
|
25
|
+
|
|
26
|
+
/** Resolve the simulated Lambda timeout (ms), honoring `DEV_SERVER_TIMEOUT_MS` when it parses. */
|
|
27
|
+
const resolveLambdaTimeoutMs = (): number => {
|
|
28
|
+
const raw = Number.parseInt(process.env.DEV_SERVER_TIMEOUT_MS ?? '', 10)
|
|
29
|
+
|
|
30
|
+
return Number.isNaN(raw) ? DEFAULT_LAMBDA_TIMEOUT_MS : raw
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whether to emit a one-line `<method> <url> → <status> <ms>ms` log per request.
|
|
35
|
+
* Off by default; opt in with `DEV_SERVER_REQUEST_LOG=1` (kept out of the Powertools
|
|
36
|
+
* JSON logger so the line stays terminal-readable). Mirrors the env-reader precedent
|
|
37
|
+
* of {@link resolveLambdaTimeoutMs}.
|
|
38
|
+
*/
|
|
39
|
+
const isRequestLogEnabled = (): boolean => {
|
|
40
|
+
return process.env.DEV_SERVER_REQUEST_LOG === '1'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class ServerlessLocalRun {
|
|
44
|
+
/** Busts Node ESM `import()` cache on each new server instance (watch restart). */
|
|
45
|
+
private readonly importCacheBust: string
|
|
46
|
+
private readonly logger: Logger
|
|
47
|
+
private readonly server: ReturnType<typeof fastify>
|
|
48
|
+
private readonly controllers: Record<
|
|
49
|
+
string,
|
|
50
|
+
{
|
|
51
|
+
action: Record<string, (event: APIGatewayProxyEvent, ctx: Context, log: ILogger) => HandlerResult>
|
|
52
|
+
handler: string
|
|
53
|
+
}
|
|
54
|
+
> = {}
|
|
55
|
+
|
|
56
|
+
/** `method urlAction` keys reserved synchronously, so duplicates are caught before any async import. */
|
|
57
|
+
private readonly registeredRouteKeys = new Set<string>()
|
|
58
|
+
|
|
59
|
+
constructor(private readonly serverConfig: IServerConfig) {
|
|
60
|
+
this.importCacheBust = `${Date.now()}`
|
|
61
|
+
this.logger = new Logger({ serviceName: 'LocalServer', logLevel: 'DEBUG' })
|
|
62
|
+
this.serverConfig.prefixUrl = this.serverConfig.prefixUrl ?? ''
|
|
63
|
+
this.server = fastify({ logger: false })
|
|
64
|
+
|
|
65
|
+
// Add CORS support for local development
|
|
66
|
+
this.server.addHook(
|
|
67
|
+
'onRequest',
|
|
68
|
+
async (
|
|
69
|
+
request: { method: string },
|
|
70
|
+
reply: { header: (k: string, v: string) => unknown; status: (n: number) => { send: () => void } },
|
|
71
|
+
) => {
|
|
72
|
+
reply.header('Access-Control-Allow-Origin', '*')
|
|
73
|
+
reply.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
|
|
74
|
+
reply.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With')
|
|
75
|
+
|
|
76
|
+
// Handle preflight OPTIONS requests
|
|
77
|
+
if (request.method === 'OPTIONS') {
|
|
78
|
+
reply.status(204).send()
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
// Opt-in per-request log line (raw stdout, not the Powertools JSON logger) so live
|
|
84
|
+
// traffic is visible in the dev terminal. Off unless DEV_SERVER_REQUEST_LOG=1.
|
|
85
|
+
if (isRequestLogEnabled()) {
|
|
86
|
+
this.server.addHook(
|
|
87
|
+
'onResponse',
|
|
88
|
+
async (request: { method: string; url: string }, reply: { statusCode: number; elapsedTime: number }) => {
|
|
89
|
+
const ms = Math.round(reply.elapsedTime)
|
|
90
|
+
|
|
91
|
+
process.stdout.write(`${request.method} ${request.url} → ${reply.statusCode} ${ms}ms\n`)
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The registered `METHOD /path` route keys (sorted). Excludes the internal
|
|
99
|
+
* `/__health` liveness route, which is registered outside {@link defineRoute} and
|
|
100
|
+
* never added to {@link registeredRouteKeys}. Used by the runner's startup route dump.
|
|
101
|
+
*/
|
|
102
|
+
public getRegisteredRoutes(): string[] {
|
|
103
|
+
return [...this.registeredRouteKeys].sort()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public async start(): Promise<void> {
|
|
107
|
+
this.registerHealthRoute()
|
|
108
|
+
|
|
109
|
+
await Promise.all(this.loadRoutes())
|
|
110
|
+
|
|
111
|
+
await this.server.listen({ port: this.serverConfig.port, host: '127.0.0.1' })
|
|
112
|
+
|
|
113
|
+
this.logger.info(`Server listening on http://127.0.0.1:${this.serverConfig.port}`, {
|
|
114
|
+
address: `http://127.0.0.1:${this.serverConfig.port}`,
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Close the server (for watch/restart). */
|
|
119
|
+
public async close(): Promise<void> {
|
|
120
|
+
const raw = this.server.server as Server
|
|
121
|
+
|
|
122
|
+
if (typeof raw.closeAllConnections === 'function') {
|
|
123
|
+
raw.closeAllConnections()
|
|
124
|
+
}
|
|
125
|
+
await this.server.close()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Register a fixed `GET /__health` liveness route returning 200. The path is
|
|
130
|
+
* unprefixed (serverless.yml routes carry the `prefixUrl`, e.g. `/api/v1/...`),
|
|
131
|
+
* so it never collides with a handler route.
|
|
132
|
+
*/
|
|
133
|
+
private registerHealthRoute(): void {
|
|
134
|
+
this.server.route({
|
|
135
|
+
method: 'GET',
|
|
136
|
+
url: '/__health',
|
|
137
|
+
handler: (_request: unknown, reply: { code: (n: number) => { send: (body: unknown) => void } }) => {
|
|
138
|
+
return reply.code(200).send({
|
|
139
|
+
status: 'ok',
|
|
140
|
+
app: this.serverConfig.appName ?? null,
|
|
141
|
+
port: this.serverConfig.port,
|
|
142
|
+
})
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private loadRoutes(): Promise<void>[] {
|
|
148
|
+
const serverlessYmlPath = path.join(this.serverConfig.controllersPath, 'serverless.yml')
|
|
149
|
+
const fileContents = fs.readFileSync(serverlessYmlPath, 'utf8')
|
|
150
|
+
const data = parseYaml(fileContents) as {
|
|
151
|
+
functions: Record<string, { events?: Array<{ http?: { method: string; path: string } }>; handler?: string }>
|
|
152
|
+
}
|
|
153
|
+
const p: Promise<void>[] = []
|
|
154
|
+
|
|
155
|
+
if (!data?.functions) return p
|
|
156
|
+
|
|
157
|
+
for (const [funcName, funcDef] of Object.entries(data.functions)) {
|
|
158
|
+
if (!funcDef?.events?.length) continue
|
|
159
|
+
for (const element of funcDef.events) {
|
|
160
|
+
const http = element?.http
|
|
161
|
+
|
|
162
|
+
if (!http) continue
|
|
163
|
+
this.logger.debug(`Registering route: ${http.method} /${http.path} -> ${funcName}`)
|
|
164
|
+
p.push(this.defineRoute(http, funcDef))
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return p
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private async defineRoute(http: { method: string; path: string }, funcDef: { handler?: string }): Promise<void> {
|
|
172
|
+
let url = http.path.toString()
|
|
173
|
+
|
|
174
|
+
url = url.replaceAll('{', ':').replaceAll('}', '')
|
|
175
|
+
|
|
176
|
+
let urlAction = path.posix.join(this.serverConfig.prefixUrl ?? '', url)
|
|
177
|
+
|
|
178
|
+
urlAction = urlAction[0] === '/' ? urlAction : `/${urlAction}`
|
|
179
|
+
|
|
180
|
+
const validMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
|
|
181
|
+
const method = String(http.method).toUpperCase()
|
|
182
|
+
|
|
183
|
+
if (!validMethods.includes(method)) {
|
|
184
|
+
throw new Error(`Invalid HTTP method: "${http.method}" for URL: ${urlAction}`)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Key on method + path: two events can share a path but differ by method (e.g. GET/POST /users),
|
|
188
|
+
// so keying on the path alone would let one handler overwrite the other. Reserve the key
|
|
189
|
+
// synchronously (before the first `await`) so concurrent route loads detect a true duplicate.
|
|
190
|
+
const routeKey = `${method} ${urlAction}`
|
|
191
|
+
|
|
192
|
+
if (this.registeredRouteKeys.has(routeKey)) {
|
|
193
|
+
throw new Error(`Duplicate route: ${routeKey}`)
|
|
194
|
+
}
|
|
195
|
+
this.registeredRouteKeys.add(routeKey)
|
|
196
|
+
|
|
197
|
+
const handlerStr = funcDef.handler ?? ''
|
|
198
|
+
const parts = handlerStr.split('.')
|
|
199
|
+
const filepath = parts[0] ?? ''
|
|
200
|
+
const handler = parts[1] ?? ''
|
|
201
|
+
|
|
202
|
+
const controllerPath = path.join(this.serverConfig.controllersPath, `${filepath}.js`)
|
|
203
|
+
const fileUrl = pathToFileURL(controllerPath)
|
|
204
|
+
|
|
205
|
+
// Search params bust Node's ESM import cache so watch rebuilds load new `dist` output.
|
|
206
|
+
fileUrl.searchParams.set('v', this.importCacheBust)
|
|
207
|
+
const action = (await import(fileUrl.href)) as Record<
|
|
208
|
+
string,
|
|
209
|
+
(event: APIGatewayProxyEvent, ctx: Context, log: ILogger) => HandlerResult
|
|
210
|
+
>
|
|
211
|
+
|
|
212
|
+
this.controllers[routeKey] = { action, handler }
|
|
213
|
+
|
|
214
|
+
const traceLogger = this.logger.createChild({ serviceName: 'RequestLogger' })
|
|
215
|
+
|
|
216
|
+
this.logger.debug(`Adding fastify route: ${method} ${urlAction}`)
|
|
217
|
+
|
|
218
|
+
this.server.route({
|
|
219
|
+
method: method as 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS',
|
|
220
|
+
url: urlAction,
|
|
221
|
+
handler: async (
|
|
222
|
+
request: { body?: unknown; query?: unknown; params?: unknown; headers?: unknown },
|
|
223
|
+
reply: {
|
|
224
|
+
headers: (h: Record<string, string>) => unknown
|
|
225
|
+
code: (n: number) => { send: (body: unknown) => void }
|
|
226
|
+
},
|
|
227
|
+
) => {
|
|
228
|
+
const controller = this.controllers[routeKey]
|
|
229
|
+
|
|
230
|
+
if (!controller) throw new Error(`No controller for ${routeKey}`)
|
|
231
|
+
const handlerFn = controller.action[controller.handler]
|
|
232
|
+
|
|
233
|
+
if (!handlerFn) throw new Error(`No handler ${controller.handler} for ${urlAction}`)
|
|
234
|
+
const retVal = await handlerFn(
|
|
235
|
+
this.getEventObj(request.body, request.query, request.params, request.headers, method, urlAction),
|
|
236
|
+
this.getContext(),
|
|
237
|
+
traceLogger,
|
|
238
|
+
)
|
|
239
|
+
const responseBody = JSON.parse(retVal.body)
|
|
240
|
+
|
|
241
|
+
reply.headers(retVal.headers ?? {})
|
|
242
|
+
|
|
243
|
+
return reply.code(retVal?.statusCode ?? 500).send(responseBody)
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
this.logger.debug(`Route added successfully: ${method} ${urlAction}`)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private getEventObj(
|
|
251
|
+
requestBody?: unknown,
|
|
252
|
+
queryParams?: unknown,
|
|
253
|
+
pathParameters?: unknown,
|
|
254
|
+
headers?: unknown,
|
|
255
|
+
httpMethod = '',
|
|
256
|
+
path = '',
|
|
257
|
+
): APIGatewayProxyEvent {
|
|
258
|
+
const retVal = {
|
|
259
|
+
body: requestBody ? JSON.stringify(requestBody) : null,
|
|
260
|
+
headers: (headers ?? {}) as APIGatewayProxyEvent['headers'],
|
|
261
|
+
multiValueHeaders: {},
|
|
262
|
+
httpMethod,
|
|
263
|
+
isBase64Encoded: false,
|
|
264
|
+
path,
|
|
265
|
+
pathParameters: pathParameters ?? null,
|
|
266
|
+
queryStringParameters: (queryParams as APIGatewayProxyEventQueryStringParameters) ?? null,
|
|
267
|
+
multiValueQueryStringParameters: null,
|
|
268
|
+
stageVariables: null,
|
|
269
|
+
requestContext: {
|
|
270
|
+
accountId: '',
|
|
271
|
+
apiId: '',
|
|
272
|
+
authorizer: undefined,
|
|
273
|
+
protocol: '',
|
|
274
|
+
httpMethod,
|
|
275
|
+
identity: {
|
|
276
|
+
accessKey: null,
|
|
277
|
+
accountId: null,
|
|
278
|
+
apiKey: null,
|
|
279
|
+
apiKeyId: null,
|
|
280
|
+
caller: null,
|
|
281
|
+
clientCert: null,
|
|
282
|
+
cognitoAuthenticationProvider: null,
|
|
283
|
+
cognitoAuthenticationType: null,
|
|
284
|
+
cognitoIdentityId: null,
|
|
285
|
+
cognitoIdentityPoolId: null,
|
|
286
|
+
principalOrgId: null,
|
|
287
|
+
sourceIp: 'devIp',
|
|
288
|
+
user: null,
|
|
289
|
+
userAgent: null,
|
|
290
|
+
userArn: null,
|
|
291
|
+
},
|
|
292
|
+
path,
|
|
293
|
+
stage: '',
|
|
294
|
+
requestId: '',
|
|
295
|
+
requestTimeEpoch: 0,
|
|
296
|
+
resourceId: '',
|
|
297
|
+
resourcePath: path,
|
|
298
|
+
},
|
|
299
|
+
resource: path,
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
;(retVal as APIGatewayProxyEvent & { source: string }).source = 'aws.events'
|
|
303
|
+
|
|
304
|
+
return retVal as APIGatewayProxyEvent
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private getContext(): Context {
|
|
308
|
+
const startTime = Date.now()
|
|
309
|
+
const timeoutMs = resolveLambdaTimeoutMs()
|
|
310
|
+
const datePart = new Date().toISOString().split('T')[0] ?? ''
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
callbackWaitsForEmptyEventLoop: false,
|
|
314
|
+
functionName: 'local-dev',
|
|
315
|
+
functionVersion: '1.0.0',
|
|
316
|
+
invokedFunctionArn: 'arn:aws:lambda:local:000000000000:function:local-dev',
|
|
317
|
+
memoryLimitInMB: '1024',
|
|
318
|
+
awsRequestId: `local-${Date.now()}`,
|
|
319
|
+
logGroupName: '/aws/lambda/local-dev',
|
|
320
|
+
logStreamName: `${datePart}/local`,
|
|
321
|
+
getRemainingTimeInMillis: (): number => {
|
|
322
|
+
return Math.max(0, timeoutMs - (Date.now() - startTime))
|
|
323
|
+
},
|
|
324
|
+
done: (_error?: Error, _result?: unknown): void => {},
|
|
325
|
+
fail: (_error: string | Error): void => {},
|
|
326
|
+
succeed: (_messageOrObject: unknown): void => {},
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `pnpm` is resolved from PATH — the same trust posture as the rest of the dev-server, which
|
|
3
|
+
* already shells out to `pnpm exec turbo …`; the args are fixed literals plus discovered package
|
|
4
|
+
* names, never shell-interpolated. Matches the file-level disable in `scripts/build.js`.
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable sonarjs/no-os-command-from-path */
|
|
7
|
+
/**
|
|
8
|
+
* `turbo watch build` engine for `infra-kit dev --watch`.
|
|
9
|
+
*
|
|
10
|
+
* Spawns ONE long-lived `turbo watch build` child that owns incremental rebuilds and
|
|
11
|
+
* dependency-graph fan-out. Its stdout is teed to the runner log but NEVER parsed for
|
|
12
|
+
* control flow: piped `turbo watch` block-buffers stdout and emits no per-task completion
|
|
13
|
+
* marker for `tsc -b` tasks, so the dev-server derives "a build finished" from watching
|
|
14
|
+
* `dist/` output instead (see {@link file://./dev-server.ts} `setupWatch`).
|
|
15
|
+
*
|
|
16
|
+
* The child is a 5-deep tree (`sh → pnpm → node → turbo → native binary`); killing the
|
|
17
|
+
* wrapper PID orphans the rest. So it is spawned `detached` (its own process group) and
|
|
18
|
+
* torn down with a process-GROUP signal — verified to fully reap the tree.
|
|
19
|
+
*/
|
|
20
|
+
import { spawn } from 'node:child_process'
|
|
21
|
+
import * as fs from 'node:fs'
|
|
22
|
+
|
|
23
|
+
import { superviseChild } from './managed-child.js'
|
|
24
|
+
import type { ManagedChild } from './managed-child.js'
|
|
25
|
+
|
|
26
|
+
/** Handle to the running `turbo watch` child; `kill()` reaps the whole process group. */
|
|
27
|
+
export type TurboWatchHandle = ManagedChild
|
|
28
|
+
|
|
29
|
+
/** Injectable spawn seam so tests run the orchestrator without a real turbo child. */
|
|
30
|
+
export type TurboWatchFactory = (opts: TurboWatchOptions) => TurboWatchHandle
|
|
31
|
+
|
|
32
|
+
export interface TurboWatchOptions {
|
|
33
|
+
/** App package names; each becomes a `--filter=...<pkg>` (dependency-inclusive) arg. */
|
|
34
|
+
packageNames: string[]
|
|
35
|
+
/** Consumer repo cwd the child runs in (turbo resolves the consumer's own pin here). */
|
|
36
|
+
cwd: string
|
|
37
|
+
/** Runner log file; the child's stdout+stderr are appended to it. */
|
|
38
|
+
logFile: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Default factory: spawn `pnpm exec turbo watch build --filter=...<pkg> ... --continue=dependencies-successful
|
|
43
|
+
* --env-mode=loose` detached, tee output to `logFile`, and reap the process group on `kill()`.
|
|
44
|
+
*
|
|
45
|
+
* `--filter=...<pkg>` (the leading `...`) includes each app's dependencies, so editing a
|
|
46
|
+
* shared lib triggers a rebuild. `--continue=dependencies-successful` keeps the watcher
|
|
47
|
+
* alive when one package fails to compile, so a shared-lib type error never tears down the
|
|
48
|
+
* whole engine and the last-good `dist/` keeps serving.
|
|
49
|
+
*/
|
|
50
|
+
export const defaultTurboWatchFactory: TurboWatchFactory = ({ packageNames, cwd, logFile }) => {
|
|
51
|
+
const filters = packageNames.map((name) => {
|
|
52
|
+
return `--filter=...${name}`
|
|
53
|
+
})
|
|
54
|
+
const out = fs.openSync(logFile, 'a')
|
|
55
|
+
const child = spawn(
|
|
56
|
+
'pnpm',
|
|
57
|
+
['exec', 'turbo', 'watch', 'build', ...filters, '--continue=dependencies-successful', '--env-mode=loose'],
|
|
58
|
+
{ cwd, detached: true, stdio: ['ignore', out, out] },
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return superviseChild(child)
|
|
62
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `pnpm` is resolved from PATH — same trust posture as the rest of the dev-server (which already
|
|
3
|
+
* shells out to `pnpm exec turbo …`); args are fixed literals plus discovered package names, never
|
|
4
|
+
* shell-interpolated. Matches the file-level disable in `scripts/build.js`.
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable sonarjs/no-os-command-from-path */
|
|
7
|
+
/**
|
|
8
|
+
* Frontend dev engine for `infra-kit dev --ui`.
|
|
9
|
+
*
|
|
10
|
+
* Delegates FE to ONE `turbo run dev` child (turbo owns the `dev` fan-out, `^build` ordering
|
|
11
|
+
* and concurrency) rather than infra-kit spawning each framework itself — the same delegation
|
|
12
|
+
* choice already made for builds via `turbo watch`. infra-kit treats UIs opaquely: it runs their
|
|
13
|
+
* `dev` script (vite/vike/astro/…) and never encodes per-framework knowledge.
|
|
14
|
+
*
|
|
15
|
+
* Unlike the `turbo watch` child, this one's stdio is INHERITED — the framework dev servers own
|
|
16
|
+
* their own TTY output (HMR overlays, URLs, spinners), so it streams raw to the terminal below the
|
|
17
|
+
* BE server table rather than being teed into the runner log (which would corrupt it with ANSI).
|
|
18
|
+
*
|
|
19
|
+
* Detached → its own process group; reaped as a group (SIGTERM→SIGKILL) via {@link superviseChild}.
|
|
20
|
+
*/
|
|
21
|
+
import { spawn } from 'node:child_process'
|
|
22
|
+
|
|
23
|
+
import { superviseChild } from './managed-child.js'
|
|
24
|
+
import type { ManagedChild } from './managed-child.js'
|
|
25
|
+
|
|
26
|
+
/** Handle to the running `turbo run dev` child; `kill()` reaps the whole process group. */
|
|
27
|
+
export type UiDevHandle = ManagedChild
|
|
28
|
+
|
|
29
|
+
/** Injectable spawn seam so tests run the orchestrator without a real turbo child. */
|
|
30
|
+
export type UiDevFactory = (opts: UiDevOptions) => UiDevHandle
|
|
31
|
+
|
|
32
|
+
export interface UiDevOptions {
|
|
33
|
+
/** UI app package names; each becomes an exact `--filter=<pkg>` (turbo runs its `dev` task). */
|
|
34
|
+
packageNames: string[]
|
|
35
|
+
/** Consumer repo cwd the child runs in. */
|
|
36
|
+
cwd: string
|
|
37
|
+
/**
|
|
38
|
+
* Concurrency cap. Must be ≥ the number of selected UI `dev` tasks (they're persistent) —
|
|
39
|
+
* turbo hard-errors when persistent tasks exceed concurrency (default 10).
|
|
40
|
+
*/
|
|
41
|
+
concurrency: number
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default factory: spawn `pnpm exec turbo run dev --filter=<pkg> … --concurrency=N --env-mode=loose`
|
|
46
|
+
* detached, streaming to the parent terminal, and reap the process group on `kill()`.
|
|
47
|
+
*
|
|
48
|
+
* Exact `--filter=<pkg>` (no `...`) selects only the UI packages, so an API app that also defines a
|
|
49
|
+
* `dev` task is never picked up.
|
|
50
|
+
*/
|
|
51
|
+
export const defaultUiDevFactory: UiDevFactory = ({ packageNames, cwd, concurrency }) => {
|
|
52
|
+
const filters = packageNames.map((name) => {
|
|
53
|
+
return `--filter=${name}`
|
|
54
|
+
})
|
|
55
|
+
const child = spawn(
|
|
56
|
+
'pnpm',
|
|
57
|
+
['exec', 'turbo', 'run', 'dev', ...filters, `--concurrency=${concurrency}`, '--env-mode=loose'],
|
|
58
|
+
{ cwd, detached: true, stdio: ['ignore', 'inherit', 'inherit'] },
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return superviseChild(child)
|
|
62
|
+
}
|
package/src/entry/cli.ts
CHANGED
|
@@ -422,6 +422,20 @@ program
|
|
|
422
422
|
emit(await doctor())
|
|
423
423
|
})
|
|
424
424
|
|
|
425
|
+
program
|
|
426
|
+
.command('dev')
|
|
427
|
+
.description('Run local dev servers for every apps/<app>/api with a serverless.yml (watch, filter by --app)')
|
|
428
|
+
.option('-w, --watch', 'Rebuild and restart on file save')
|
|
429
|
+
.option('--app <names>', 'Only run these apps (comma-separated folder names)')
|
|
430
|
+
.option('--ui', 'Also run frontends (apps/<app>/ui with a `dev` script) via turbo run dev')
|
|
431
|
+
.action(async (options) => {
|
|
432
|
+
// Lazy import so fastify/chokidar (and the whole dev stack) never load on the
|
|
433
|
+
// eager cli graph — they land in a split chunk reached only for `infra-kit dev`.
|
|
434
|
+
const { runDevServer, toDevServerOptions } = await import('src/entry/dev-server')
|
|
435
|
+
|
|
436
|
+
await runDevServer(toDevServerOptions(options))
|
|
437
|
+
})
|
|
438
|
+
|
|
425
439
|
program
|
|
426
440
|
.command('version')
|
|
427
441
|
.description('Print the installed infra-kit CLI version')
|
|
@@ -461,8 +475,9 @@ program
|
|
|
461
475
|
program
|
|
462
476
|
.command('env-clear')
|
|
463
477
|
.description('Clear loaded env vars. Source the returned file path to apply.')
|
|
464
|
-
.
|
|
465
|
-
|
|
478
|
+
.option('--purge', "Also delete this project's warm cache outright (durable disable)")
|
|
479
|
+
.action(async (options) => {
|
|
480
|
+
emit(await envClear({ purge: Boolean(options.purge) }))
|
|
466
481
|
})
|
|
467
482
|
|
|
468
483
|
// Internal: driven by the init shell-startup integration (backgrounded). Writes
|
|
@@ -471,8 +486,11 @@ program
|
|
|
471
486
|
program
|
|
472
487
|
.command('env-autoload', { hidden: true })
|
|
473
488
|
.description('Internal: prime env for the shell-startup auto-load trigger')
|
|
474
|
-
|
|
475
|
-
|
|
489
|
+
// The shell passes its already-canonicalized (`${dir:A}`) project dir so node can
|
|
490
|
+
// key the warm cache identically; see writeEnvLoadFile / shouldWriteWarm.
|
|
491
|
+
.option('--project-dir <dir>', 'Canonical project dir for the warm-cache key (shell-startup only)')
|
|
492
|
+
.action(async (options) => {
|
|
493
|
+
await envAutoload({ projectDir: options.projectDir })
|
|
476
494
|
})
|
|
477
495
|
|
|
478
496
|
// Register `--json` on every command, then resolve the flag before each action
|
|
@@ -485,9 +503,10 @@ program.commands.forEach(addJsonOption)
|
|
|
485
503
|
// (avoids recursion — `env-autoload`/`env-load` would re-enter), plus the
|
|
486
504
|
// host-inspecting / meta commands where priming Doppler env would be surprising
|
|
487
505
|
// (`init` bootstraps the shell block, `doctor` inspects auth, `version` prints a
|
|
488
|
-
// string
|
|
506
|
+
// string, `dev` is a long-running server that manages its own env). `--help`/
|
|
507
|
+
// `--version`/the bare-arg menu don't fire preAction at all.
|
|
489
508
|
const isAutoLoadExcludedCommand = (name: string): boolean => {
|
|
490
|
-
return name.startsWith('env-') || name === 'init' || name === 'doctor' || name === 'version'
|
|
509
|
+
return name.startsWith('env-') || name === 'init' || name === 'doctor' || name === 'version' || name === 'dev'
|
|
491
510
|
}
|
|
492
511
|
|
|
493
512
|
program.hook('preAction', async (_thisCommand, actionCommand) => {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Long-running CLI entry for the local dev-server. Owns flag parsing, OS signal
|
|
3
|
+
* handling, and process exit — the orchestrator (`src/dev/dev-server`) is signal-
|
|
4
|
+
* and exit-agnostic. Kept off the eager cli.js graph: entry/cli.ts reaches this
|
|
5
|
+
* module (and the fastify/chokidar it pulls in) only via `await import(...)`, so
|
|
6
|
+
* those heavy deps never load on the machine command paths.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander'
|
|
9
|
+
import process from 'node:process'
|
|
10
|
+
import { pathToFileURL } from 'node:url'
|
|
11
|
+
|
|
12
|
+
import { run } from 'src/dev/dev-server'
|
|
13
|
+
import type { DevServerOptions } from 'src/dev/dev-server'
|
|
14
|
+
|
|
15
|
+
/** Raw option object as produced by Commander (comma-joined strings). */
|
|
16
|
+
export interface DevCliOptions {
|
|
17
|
+
watch?: boolean
|
|
18
|
+
app?: string
|
|
19
|
+
ui?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Split a comma-separated flag value into a trimmed, non-empty list (`null` when unset/empty). */
|
|
23
|
+
const splitList = (value: string | undefined): string[] | null => {
|
|
24
|
+
if (value == null) return null
|
|
25
|
+
|
|
26
|
+
const parts = value
|
|
27
|
+
.split(',')
|
|
28
|
+
.map((s) => {
|
|
29
|
+
return s.trim()
|
|
30
|
+
})
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
|
|
33
|
+
return parts.length > 0 ? parts : null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Map raw Commander flags to the orchestrator's typed options. Shared by the
|
|
38
|
+
* `infra-kit dev` subcommand and the standalone entry so the two never diverge.
|
|
39
|
+
*/
|
|
40
|
+
export const toDevServerOptions = (raw: DevCliOptions): DevServerOptions => {
|
|
41
|
+
return {
|
|
42
|
+
watch: raw.watch ?? false,
|
|
43
|
+
include: splitList(raw.app),
|
|
44
|
+
ui: raw.ui ?? false,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Start the dev-server, then wait for an OS signal and shut every server down
|
|
50
|
+
* cleanly before exiting. This is the ONLY place SIGINT/SIGTERM handlers and
|
|
51
|
+
* `process.exit` live for the dev-server feature.
|
|
52
|
+
*/
|
|
53
|
+
export const runDevServer = async (options: DevServerOptions): Promise<void> => {
|
|
54
|
+
const runner = await run(options)
|
|
55
|
+
|
|
56
|
+
let shuttingDown = false
|
|
57
|
+
|
|
58
|
+
const shutdown = (signal: NodeJS.Signals): void => {
|
|
59
|
+
if (shuttingDown) return
|
|
60
|
+
shuttingDown = true
|
|
61
|
+
|
|
62
|
+
void (async () => {
|
|
63
|
+
try {
|
|
64
|
+
process.stdout.write(`\nReceived ${signal}, shutting down dev-server...\n`)
|
|
65
|
+
await runner.shutdown()
|
|
66
|
+
} finally {
|
|
67
|
+
process.exit(0)
|
|
68
|
+
}
|
|
69
|
+
})()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
process.on('SIGINT', () => {
|
|
73
|
+
return shutdown('SIGINT')
|
|
74
|
+
})
|
|
75
|
+
process.on('SIGTERM', () => {
|
|
76
|
+
return shutdown('SIGTERM')
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Parse `node dist/dev-server.js ...` flags and start the server. */
|
|
81
|
+
const parseAndRun = async (argv: string[]): Promise<void> => {
|
|
82
|
+
const program = new Command()
|
|
83
|
+
|
|
84
|
+
program
|
|
85
|
+
.name('infra-kit-dev-server')
|
|
86
|
+
.description('Run local dev servers for every apps/<app>/api that has a serverless.yml')
|
|
87
|
+
.option('-w, --watch', 'Rebuild and restart on file save')
|
|
88
|
+
.option('--app <names>', 'Only run these apps (comma-separated folder names)')
|
|
89
|
+
.option('--ui', 'Also run frontends (apps/<app>/ui with a `dev` script) via turbo run dev')
|
|
90
|
+
|
|
91
|
+
program.parse(argv)
|
|
92
|
+
|
|
93
|
+
await runDevServer(toDevServerOptions(program.opts<DevCliOptions>()))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Self-execute only when run directly (`node dist/dev-server.js`), not when the
|
|
97
|
+
// `infra-kit dev` subcommand imports this module for its exported helpers.
|
|
98
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
|
|
99
|
+
parseAndRun(process.argv).catch((error: unknown) => {
|
|
100
|
+
console.error(error)
|
|
101
|
+
process.exit(1)
|
|
102
|
+
})
|
|
103
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"entries": {
|
|
4
|
+
"79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
|
|
5
|
+
"last_emitted_at_ms": 1783339798994,
|
|
6
|
+
"message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
|
|
7
|
+
},
|
|
8
|
+
"445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
|
|
9
|
+
"last_emitted_at_ms": 1783339766672,
|
|
10
|
+
"message": "Verify changes work after editing. Test functionality before marking complete."
|
|
11
|
+
},
|
|
12
|
+
"466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
|
|
13
|
+
"last_emitted_at_ms": 1783339749887,
|
|
14
|
+
"message": "Read multiple files in parallel when possible for faster analysis."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"updated_at": "2026-07-06T12:09:58.994Z"
|
|
18
|
+
}
|
|
@@ -109,6 +109,10 @@ export const commandCatalog: CommandCatalogEntry[] = [
|
|
|
109
109
|
{ cliName: 'vendor', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
110
110
|
{ cliName: 'vendor-config', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
111
111
|
{ cliName: 'doctor', menuGroup: 'environment', mcpTool: doctorMcpTool, mcpExposed: false },
|
|
112
|
+
// Long-running local dev server (fastify + chokidar). Not an MCP tool — it never
|
|
113
|
+
// returns, so it can't fit the request/response tool contract. menuGroup null:
|
|
114
|
+
// the no-arg picker drives one-shot commands, not a blocking foreground process.
|
|
115
|
+
{ cliName: 'dev', menuGroup: null, mcpTool: null, mcpExposed: false },
|
|
112
116
|
{ cliName: 'init', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
113
117
|
{ cliName: 'version', menuGroup: 'environment', mcpTool: versionMcpTool, mcpExposed: true },
|
|
114
118
|
{ cliName: 'config', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|