@agentuity/cli 2.0.10 → 3.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cmd/ai/prompt/index.d.ts.map +1 -1
- package/dist/cmd/ai/prompt/index.js +2 -7
- package/dist/cmd/ai/prompt/index.js.map +1 -1
- package/dist/cmd/build/adapters/generic.d.ts +29 -0
- package/dist/cmd/build/adapters/generic.d.ts.map +1 -0
- package/dist/cmd/build/adapters/generic.js +190 -0
- package/dist/cmd/build/adapters/generic.js.map +1 -0
- package/dist/cmd/build/adapters/index.d.ts +15 -0
- package/dist/cmd/build/adapters/index.d.ts.map +1 -0
- package/dist/cmd/build/adapters/index.js +24 -0
- package/dist/cmd/build/adapters/index.js.map +1 -0
- package/dist/cmd/build/adapters/nextjs.d.ts +11 -0
- package/dist/cmd/build/adapters/nextjs.d.ts.map +1 -0
- package/dist/cmd/build/adapters/nextjs.js +118 -0
- package/dist/cmd/build/adapters/nextjs.js.map +1 -0
- package/dist/cmd/build/adapters/static-server.d.ts +23 -0
- package/dist/cmd/build/adapters/static-server.d.ts.map +1 -0
- package/dist/cmd/build/adapters/static-server.js +137 -0
- package/dist/cmd/build/adapters/static-server.js.map +1 -0
- package/dist/cmd/build/adapters/types.d.ts +71 -0
- package/dist/cmd/build/adapters/types.d.ts.map +1 -0
- package/dist/cmd/build/adapters/types.js +8 -0
- package/dist/cmd/build/adapters/types.js.map +1 -0
- package/dist/cmd/build/detect/engine.d.ts +24 -0
- package/dist/cmd/build/detect/engine.d.ts.map +1 -0
- package/dist/cmd/build/detect/engine.js +91 -0
- package/dist/cmd/build/detect/engine.js.map +1 -0
- package/dist/cmd/build/detect/frameworks.d.ts +66 -0
- package/dist/cmd/build/detect/frameworks.d.ts.map +1 -0
- package/dist/cmd/build/detect/frameworks.js +278 -0
- package/dist/cmd/build/detect/frameworks.js.map +1 -0
- package/dist/cmd/build/detect/generic.d.ts +13 -0
- package/dist/cmd/build/detect/generic.d.ts.map +1 -0
- package/dist/cmd/build/detect/generic.js +62 -0
- package/dist/cmd/build/detect/generic.js.map +1 -0
- package/dist/cmd/build/detect/index.d.ts +27 -0
- package/dist/cmd/build/detect/index.d.ts.map +1 -0
- package/dist/cmd/build/detect/index.js +76 -0
- package/dist/cmd/build/detect/index.js.map +1 -0
- package/dist/cmd/build/detect/types.d.ts +91 -0
- package/dist/cmd/build/detect/types.d.ts.map +1 -0
- package/dist/cmd/build/detect/types.js +9 -0
- package/dist/cmd/build/detect/types.js.map +1 -0
- package/dist/cmd/build/detect/util.d.ts +41 -0
- package/dist/cmd/build/detect/util.d.ts.map +1 -0
- package/dist/cmd/build/detect/util.js +101 -0
- package/dist/cmd/build/detect/util.js.map +1 -0
- package/dist/cmd/build/index.d.ts.map +1 -1
- package/dist/cmd/build/index.js +49 -22
- package/dist/cmd/build/index.js.map +1 -1
- package/dist/cmd/build/package/index.d.ts +30 -0
- package/dist/cmd/build/package/index.d.ts.map +1 -0
- package/dist/cmd/build/package/index.js +39 -0
- package/dist/cmd/build/package/index.js.map +1 -0
- package/dist/cmd/build/package/launch.d.ts +56 -0
- package/dist/cmd/build/package/launch.d.ts.map +1 -0
- package/dist/cmd/build/package/launch.js +56 -0
- package/dist/cmd/build/package/launch.js.map +1 -0
- package/dist/cmd/build/typecheck.d.ts.map +1 -1
- package/dist/cmd/build/typecheck.js +8 -0
- package/dist/cmd/build/typecheck.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +63 -13
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/coder/create.d.ts.map +1 -1
- package/dist/cmd/coder/create.js +18 -0
- package/dist/cmd/coder/create.js.map +1 -1
- package/dist/cmd/coder/index.d.ts.map +1 -1
- package/dist/cmd/coder/index.js +4 -0
- package/dist/cmd/coder/index.js.map +1 -1
- package/dist/cmd/coder/start.d.ts.map +1 -1
- package/dist/cmd/coder/start.js +49 -1
- package/dist/cmd/coder/start.js.map +1 -1
- package/dist/cmd/coder/update.d.ts.map +1 -1
- package/dist/cmd/coder/update.js +21 -1
- package/dist/cmd/coder/update.js.map +1 -1
- package/dist/cmd/coder/workspace/create.d.ts.map +1 -1
- package/dist/cmd/coder/workspace/create.js +17 -1
- package/dist/cmd/coder/workspace/create.js.map +1 -1
- package/dist/cmd/coder/workspace/list.js +2 -2
- package/dist/cmd/coder/workspace/list.js.map +1 -1
- package/dist/cmd/dev/index.d.ts +9 -0
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +127 -923
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/project/auth/shared.d.ts.map +1 -1
- package/dist/cmd/project/auth/shared.js +14 -38
- package/dist/cmd/project/auth/shared.js.map +1 -1
- package/dist/cmd/project/create.d.ts.map +1 -1
- package/dist/cmd/project/create.js +12 -19
- package/dist/cmd/project/create.js.map +1 -1
- package/dist/cmd/project/frameworks-ai-examples.d.ts +15 -0
- package/dist/cmd/project/frameworks-ai-examples.d.ts.map +1 -0
- package/dist/cmd/project/frameworks-ai-examples.js +160 -0
- package/dist/cmd/project/frameworks-ai-examples.js.map +1 -0
- package/dist/cmd/project/frameworks-landing-pages.d.ts +17 -0
- package/dist/cmd/project/frameworks-landing-pages.d.ts.map +1 -0
- package/dist/cmd/project/frameworks-landing-pages.js +242 -0
- package/dist/cmd/project/frameworks-landing-pages.js.map +1 -0
- package/dist/cmd/project/frameworks.d.ts +58 -0
- package/dist/cmd/project/frameworks.d.ts.map +1 -0
- package/dist/cmd/project/frameworks.js +152 -0
- package/dist/cmd/project/frameworks.js.map +1 -0
- package/dist/cmd/project/reconcile.d.ts.map +1 -1
- package/dist/cmd/project/reconcile.js +10 -23
- package/dist/cmd/project/reconcile.js.map +1 -1
- package/dist/cmd/project/remote-import.js +1 -1
- package/dist/cmd/project/scaffold.d.ts +58 -0
- package/dist/cmd/project/scaffold.d.ts.map +1 -0
- package/dist/cmd/project/scaffold.js +223 -0
- package/dist/cmd/project/scaffold.js.map +1 -0
- package/dist/cmd/project/template-flow.d.ts +8 -4
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +93 -144
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/deploy-metadata.d.ts +49 -0
- package/dist/deploy-metadata.d.ts.map +1 -0
- package/dist/deploy-metadata.js +183 -0
- package/dist/deploy-metadata.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +25 -31
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +13 -8
- package/src/cmd/ai/prompt/index.ts +2 -7
- package/src/cmd/build/adapters/generic.ts +239 -0
- package/src/cmd/build/adapters/index.ts +30 -0
- package/src/cmd/build/adapters/nextjs.ts +146 -0
- package/src/cmd/build/adapters/static-server.ts +143 -0
- package/src/cmd/build/adapters/types.ts +93 -0
- package/src/cmd/build/detect/engine.ts +111 -0
- package/src/cmd/build/detect/frameworks.ts +335 -0
- package/src/cmd/build/detect/generic.ts +71 -0
- package/src/cmd/build/detect/index.ts +122 -0
- package/src/cmd/build/detect/types.ts +109 -0
- package/src/cmd/build/detect/util.ts +104 -0
- package/src/cmd/build/index.ts +64 -24
- package/src/cmd/build/package/index.ts +66 -0
- package/src/cmd/build/package/launch.ts +104 -0
- package/src/cmd/build/typecheck.ts +9 -0
- package/src/cmd/cloud/deploy.ts +86 -13
- package/src/cmd/coder/create.ts +24 -1
- package/src/cmd/coder/index.ts +4 -0
- package/src/cmd/coder/start.ts +60 -1
- package/src/cmd/coder/update.ts +18 -1
- package/src/cmd/coder/workspace/create.ts +20 -2
- package/src/cmd/coder/workspace/list.ts +2 -2
- package/src/cmd/dev/index.ts +155 -1059
- package/src/cmd/project/auth/shared.ts +14 -39
- package/src/cmd/project/create.ts +14 -19
- package/src/cmd/project/frameworks-ai-examples.ts +166 -0
- package/src/cmd/project/frameworks-landing-pages.ts +267 -0
- package/src/cmd/project/frameworks.ts +223 -0
- package/src/cmd/project/reconcile.ts +10 -22
- package/src/cmd/project/remote-import.ts +1 -1
- package/src/cmd/project/scaffold.ts +300 -0
- package/src/cmd/project/template-flow.ts +102 -156
- package/src/deploy-metadata.ts +253 -0
- package/src/index.ts +0 -2
- package/src/types.ts +0 -31
- package/dist/agents-docs.d.ts +0 -23
- package/dist/agents-docs.d.ts.map +0 -1
- package/dist/agents-docs.js +0 -56
- package/dist/agents-docs.js.map +0 -1
- package/dist/cmd/ai/prompt/agent.d.ts +0 -10
- package/dist/cmd/ai/prompt/agent.d.ts.map +0 -1
- package/dist/cmd/ai/prompt/agent.js +0 -28
- package/dist/cmd/ai/prompt/agent.js.map +0 -1
- package/dist/cmd/build/app-router-detector.d.ts +0 -39
- package/dist/cmd/build/app-router-detector.d.ts.map +0 -1
- package/dist/cmd/build/app-router-detector.js +0 -229
- package/dist/cmd/build/app-router-detector.js.map +0 -1
- package/dist/cmd/build/format-schema.d.ts +0 -6
- package/dist/cmd/build/format-schema.d.ts.map +0 -1
- package/dist/cmd/build/format-schema.js +0 -60
- package/dist/cmd/build/format-schema.js.map +0 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts +0 -37
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +0 -1
- package/dist/cmd/build/vite/agent-discovery.js +0 -263
- package/dist/cmd/build/vite/agent-discovery.js.map +0 -1
- package/dist/cmd/build/vite/beacon-plugin.d.ts +0 -19
- package/dist/cmd/build/vite/beacon-plugin.d.ts.map +0 -1
- package/dist/cmd/build/vite/beacon-plugin.js +0 -137
- package/dist/cmd/build/vite/beacon-plugin.js.map +0 -1
- package/dist/cmd/build/vite/browser-env-plugin.d.ts +0 -9
- package/dist/cmd/build/vite/browser-env-plugin.d.ts.map +0 -1
- package/dist/cmd/build/vite/browser-env-plugin.js +0 -28
- package/dist/cmd/build/vite/browser-env-plugin.js.map +0 -1
- package/dist/cmd/build/vite/bun-dev-server.d.ts +0 -67
- package/dist/cmd/build/vite/bun-dev-server.d.ts.map +0 -1
- package/dist/cmd/build/vite/bun-dev-server.js +0 -340
- package/dist/cmd/build/vite/bun-dev-server.js.map +0 -1
- package/dist/cmd/build/vite/bundle-files.d.ts +0 -12
- package/dist/cmd/build/vite/bundle-files.d.ts.map +0 -1
- package/dist/cmd/build/vite/bundle-files.js +0 -107
- package/dist/cmd/build/vite/bundle-files.js.map +0 -1
- package/dist/cmd/build/vite/config-loader.d.ts +0 -29
- package/dist/cmd/build/vite/config-loader.d.ts.map +0 -1
- package/dist/cmd/build/vite/config-loader.js +0 -57
- package/dist/cmd/build/vite/config-loader.js.map +0 -1
- package/dist/cmd/build/vite/db-rewrite.d.ts +0 -50
- package/dist/cmd/build/vite/db-rewrite.d.ts.map +0 -1
- package/dist/cmd/build/vite/db-rewrite.js +0 -169
- package/dist/cmd/build/vite/db-rewrite.js.map +0 -1
- package/dist/cmd/build/vite/docs-generator.d.ts +0 -13
- package/dist/cmd/build/vite/docs-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/docs-generator.js +0 -97
- package/dist/cmd/build/vite/docs-generator.js.map +0 -1
- package/dist/cmd/build/vite/env-types-generator.d.ts +0 -26
- package/dist/cmd/build/vite/env-types-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/env-types-generator.js +0 -110
- package/dist/cmd/build/vite/env-types-generator.js.map +0 -1
- package/dist/cmd/build/vite/index.d.ts +0 -3
- package/dist/cmd/build/vite/index.d.ts.map +0 -1
- package/dist/cmd/build/vite/index.js +0 -4
- package/dist/cmd/build/vite/index.js.map +0 -1
- package/dist/cmd/build/vite/lifecycle-generator.d.ts +0 -19
- package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/lifecycle-generator.js +0 -328
- package/dist/cmd/build/vite/lifecycle-generator.js.map +0 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts +0 -36
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/metadata-generator.js +0 -575
- package/dist/cmd/build/vite/metadata-generator.js.map +0 -1
- package/dist/cmd/build/vite/prompt-generator.d.ts +0 -23
- package/dist/cmd/build/vite/prompt-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/prompt-generator.js +0 -123
- package/dist/cmd/build/vite/prompt-generator.js.map +0 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts +0 -45
- package/dist/cmd/build/vite/public-asset-path-plugin.d.ts.map +0 -1
- package/dist/cmd/build/vite/public-asset-path-plugin.js +0 -166
- package/dist/cmd/build/vite/public-asset-path-plugin.js.map +0 -1
- package/dist/cmd/build/vite/route-discovery.d.ts +0 -64
- package/dist/cmd/build/vite/route-discovery.d.ts.map +0 -1
- package/dist/cmd/build/vite/route-discovery.js +0 -187
- package/dist/cmd/build/vite/route-discovery.js.map +0 -1
- package/dist/cmd/build/vite/server-bundler.d.ts +0 -20
- package/dist/cmd/build/vite/server-bundler.d.ts.map +0 -1
- package/dist/cmd/build/vite/server-bundler.js +0 -388
- package/dist/cmd/build/vite/server-bundler.js.map +0 -1
- package/dist/cmd/build/vite/static-renderer.d.ts +0 -26
- package/dist/cmd/build/vite/static-renderer.d.ts.map +0 -1
- package/dist/cmd/build/vite/static-renderer.js +0 -188
- package/dist/cmd/build/vite/static-renderer.js.map +0 -1
- package/dist/cmd/build/vite/tailwind-source-plugin.d.ts +0 -15
- package/dist/cmd/build/vite/tailwind-source-plugin.d.ts.map +0 -1
- package/dist/cmd/build/vite/tailwind-source-plugin.js +0 -61
- package/dist/cmd/build/vite/tailwind-source-plugin.js.map +0 -1
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts +0 -24
- package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +0 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +0 -285
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +0 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts +0 -30
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +0 -1
- package/dist/cmd/build/vite/vite-asset-server.js +0 -109
- package/dist/cmd/build/vite/vite-asset-server.js.map +0 -1
- package/dist/cmd/build/vite/vite-builder.d.ts +0 -59
- package/dist/cmd/build/vite/vite-builder.d.ts.map +0 -1
- package/dist/cmd/build/vite/vite-builder.js +0 -401
- package/dist/cmd/build/vite/vite-builder.js.map +0 -1
- package/dist/cmd/build/vite/workbench-generator.d.ts +0 -10
- package/dist/cmd/build/vite/workbench-generator.d.ts.map +0 -1
- package/dist/cmd/build/vite/workbench-generator.js +0 -135
- package/dist/cmd/build/vite/workbench-generator.js.map +0 -1
- package/dist/cmd/build/vite/ws-proxy.d.ts +0 -53
- package/dist/cmd/build/vite/ws-proxy.d.ts.map +0 -1
- package/dist/cmd/build/vite/ws-proxy.js +0 -95
- package/dist/cmd/build/vite/ws-proxy.js.map +0 -1
- package/dist/cmd/build/vite-bundler.d.ts +0 -29
- package/dist/cmd/build/vite-bundler.d.ts.map +0 -1
- package/dist/cmd/build/vite-bundler.js +0 -93
- package/dist/cmd/build/vite-bundler.js.map +0 -1
- package/dist/cmd/dev/agents.d.ts +0 -2
- package/dist/cmd/dev/agents.d.ts.map +0 -1
- package/dist/cmd/dev/agents.js +0 -123
- package/dist/cmd/dev/agents.js.map +0 -1
- package/dist/cmd/dev/api.d.ts +0 -20
- package/dist/cmd/dev/api.d.ts.map +0 -1
- package/dist/cmd/dev/api.js +0 -42
- package/dist/cmd/dev/api.js.map +0 -1
- package/dist/cmd/dev/dev-lock.d.ts +0 -62
- package/dist/cmd/dev/dev-lock.d.ts.map +0 -1
- package/dist/cmd/dev/dev-lock.js +0 -250
- package/dist/cmd/dev/dev-lock.js.map +0 -1
- package/dist/cmd/dev/download.d.ts +0 -11
- package/dist/cmd/dev/download.d.ts.map +0 -1
- package/dist/cmd/dev/download.js +0 -94
- package/dist/cmd/dev/download.js.map +0 -1
- package/dist/cmd/dev/file-watcher.d.ts +0 -24
- package/dist/cmd/dev/file-watcher.d.ts.map +0 -1
- package/dist/cmd/dev/file-watcher.js +0 -349
- package/dist/cmd/dev/file-watcher.js.map +0 -1
- package/dist/cmd/dev/process-manager.d.ts +0 -104
- package/dist/cmd/dev/process-manager.d.ts.map +0 -1
- package/dist/cmd/dev/process-manager.js +0 -204
- package/dist/cmd/dev/process-manager.js.map +0 -1
- package/dist/cmd/dev/sync.d.ts +0 -12
- package/dist/cmd/dev/sync.d.ts.map +0 -1
- package/dist/cmd/dev/sync.js +0 -227
- package/dist/cmd/dev/sync.js.map +0 -1
- package/dist/cmd/dev/templates.d.ts +0 -3
- package/dist/cmd/dev/templates.d.ts.map +0 -1
- package/dist/cmd/dev/templates.js +0 -58
- package/dist/cmd/dev/templates.js.map +0 -1
- package/dist/cmd/project/download.d.ts +0 -35
- package/dist/cmd/project/download.d.ts.map +0 -1
- package/dist/cmd/project/download.js +0 -403
- package/dist/cmd/project/download.js.map +0 -1
- package/dist/cmd/project/templates.d.ts +0 -9
- package/dist/cmd/project/templates.d.ts.map +0 -1
- package/dist/cmd/project/templates.js +0 -34
- package/dist/cmd/project/templates.js.map +0 -1
- package/src/agents-docs.ts +0 -86
- package/src/cmd/ai/prompt/agent.md +0 -305
- package/src/cmd/ai/prompt/agent.ts +0 -31
- package/src/cmd/build/app-router-detector.ts +0 -320
- package/src/cmd/build/format-schema.ts +0 -66
- package/src/cmd/build/vite/agent-discovery.ts +0 -380
- package/src/cmd/build/vite/beacon-plugin.ts +0 -164
- package/src/cmd/build/vite/browser-env-plugin.ts +0 -34
- package/src/cmd/build/vite/bun-dev-server.ts +0 -458
- package/src/cmd/build/vite/bundle-files.ts +0 -135
- package/src/cmd/build/vite/config-loader.ts +0 -76
- package/src/cmd/build/vite/db-rewrite.ts +0 -189
- package/src/cmd/build/vite/docs-generator.ts +0 -103
- package/src/cmd/build/vite/env-types-generator.ts +0 -145
- package/src/cmd/build/vite/index.ts +0 -3
- package/src/cmd/build/vite/lifecycle-generator.ts +0 -381
- package/src/cmd/build/vite/metadata-generator.ts +0 -713
- package/src/cmd/build/vite/prompt-generator.ts +0 -169
- package/src/cmd/build/vite/public-asset-path-plugin.ts +0 -209
- package/src/cmd/build/vite/route-discovery.ts +0 -271
- package/src/cmd/build/vite/server-bundler.ts +0 -481
- package/src/cmd/build/vite/static-renderer.ts +0 -239
- package/src/cmd/build/vite/tailwind-source-plugin.ts +0 -73
- package/src/cmd/build/vite/vite-asset-server-config.ts +0 -349
- package/src/cmd/build/vite/vite-asset-server.ts +0 -154
- package/src/cmd/build/vite/vite-builder.ts +0 -503
- package/src/cmd/build/vite/workbench-generator.ts +0 -152
- package/src/cmd/build/vite/ws-proxy.ts +0 -126
- package/src/cmd/build/vite-bundler.ts +0 -137
- package/src/cmd/dev/agents.ts +0 -140
- package/src/cmd/dev/api.ts +0 -65
- package/src/cmd/dev/dev-lock.ts +0 -332
- package/src/cmd/dev/download.ts +0 -117
- package/src/cmd/dev/file-watcher.ts +0 -423
- package/src/cmd/dev/process-manager.ts +0 -261
- package/src/cmd/dev/sync.ts +0 -411
- package/src/cmd/dev/templates.ts +0 -66
- package/src/cmd/project/download.ts +0 -505
- package/src/cmd/project/templates.ts +0 -56
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File Watcher for Dev Server Hot Reload
|
|
3
|
-
*
|
|
4
|
-
* Watches source files and triggers server restart on changes.
|
|
5
|
-
* Handles both backend (API, agents, lib) and generates restart signals.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { watch, type FSWatcher, statSync, readdirSync, lstatSync } from 'node:fs';
|
|
9
|
-
import { resolve, relative } from 'node:path';
|
|
10
|
-
import type { Logger } from '../../types';
|
|
11
|
-
import { createAgentTemplates } from './templates';
|
|
12
|
-
|
|
13
|
-
export interface FileWatcherOptions {
|
|
14
|
-
rootDir: string;
|
|
15
|
-
logger: Logger;
|
|
16
|
-
onRestart: () => void;
|
|
17
|
-
additionalPaths?: string[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface FileWatcherManager {
|
|
21
|
-
start: () => void;
|
|
22
|
-
stop: () => void;
|
|
23
|
-
pause: () => void;
|
|
24
|
-
resume: () => void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Create a file watcher manager for hot reload
|
|
29
|
-
*/
|
|
30
|
-
export function createFileWatcher(options: FileWatcherOptions): FileWatcherManager {
|
|
31
|
-
const { rootDir, logger, onRestart, additionalPaths = [] } = options;
|
|
32
|
-
|
|
33
|
-
const watchers: FSWatcher[] = [];
|
|
34
|
-
let paused = false;
|
|
35
|
-
let buildCooldownTimer: NodeJS.Timeout | null = null;
|
|
36
|
-
|
|
37
|
-
// Directories to ignore - these are NEVER traversed into
|
|
38
|
-
// This prevents EMFILE errors from symlink cycles in node_modules
|
|
39
|
-
const ignoreDirs = new Set([
|
|
40
|
-
'.agentuity',
|
|
41
|
-
'.agents',
|
|
42
|
-
'.claude',
|
|
43
|
-
'.code',
|
|
44
|
-
'.opencode',
|
|
45
|
-
'node_modules',
|
|
46
|
-
'.git',
|
|
47
|
-
'.github',
|
|
48
|
-
'dist',
|
|
49
|
-
'build',
|
|
50
|
-
'.next',
|
|
51
|
-
'.turbo',
|
|
52
|
-
'.npm',
|
|
53
|
-
'.dist',
|
|
54
|
-
'.vscode',
|
|
55
|
-
'.idea',
|
|
56
|
-
'.DS_Store',
|
|
57
|
-
'.playwright',
|
|
58
|
-
'.bun',
|
|
59
|
-
'src/generated',
|
|
60
|
-
]);
|
|
61
|
-
|
|
62
|
-
// Paths to ignore for file change events (but may still be traversed)
|
|
63
|
-
const ignorePaths = [
|
|
64
|
-
'.agentuity',
|
|
65
|
-
'.agents',
|
|
66
|
-
'.claude',
|
|
67
|
-
'.code',
|
|
68
|
-
'.opencode',
|
|
69
|
-
'node_modules',
|
|
70
|
-
'.git',
|
|
71
|
-
'.github',
|
|
72
|
-
'dist',
|
|
73
|
-
'build',
|
|
74
|
-
'.next',
|
|
75
|
-
'.turbo',
|
|
76
|
-
'.npm',
|
|
77
|
-
'.dist',
|
|
78
|
-
'.vscode',
|
|
79
|
-
'.idea',
|
|
80
|
-
'.bun',
|
|
81
|
-
'.DS_Store',
|
|
82
|
-
'.playwright',
|
|
83
|
-
'src/web', // Vite handles frontend with HMR - no backend restart needed
|
|
84
|
-
'src/generated', // Generated files shouldn't trigger rebuilds
|
|
85
|
-
];
|
|
86
|
-
|
|
87
|
-
// File extensions to ignore - non-code files that shouldn't trigger reload
|
|
88
|
-
const ignoreExtensions = new Set([
|
|
89
|
-
'.md',
|
|
90
|
-
'.mdx',
|
|
91
|
-
'.txt',
|
|
92
|
-
'.log',
|
|
93
|
-
'.lock',
|
|
94
|
-
'.yaml',
|
|
95
|
-
'.yml',
|
|
96
|
-
'.toml',
|
|
97
|
-
'.csv',
|
|
98
|
-
'.svg',
|
|
99
|
-
'.png',
|
|
100
|
-
'.jpg',
|
|
101
|
-
'.jpeg',
|
|
102
|
-
'.gif',
|
|
103
|
-
'.webp',
|
|
104
|
-
'.ico',
|
|
105
|
-
'.woff',
|
|
106
|
-
'.woff2',
|
|
107
|
-
'.ttf',
|
|
108
|
-
'.eot',
|
|
109
|
-
'.mp4',
|
|
110
|
-
'.mp3',
|
|
111
|
-
'.wav',
|
|
112
|
-
'.ogg',
|
|
113
|
-
'.webm',
|
|
114
|
-
'.pdf',
|
|
115
|
-
'.zip',
|
|
116
|
-
'.tar',
|
|
117
|
-
'.gz',
|
|
118
|
-
'.map',
|
|
119
|
-
]);
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Check if a path should be ignored
|
|
123
|
-
*/
|
|
124
|
-
function shouldIgnorePath(changedFile: string | null, watchDir: string): boolean {
|
|
125
|
-
if (!changedFile) return false;
|
|
126
|
-
|
|
127
|
-
const absPath = resolve(watchDir, changedFile);
|
|
128
|
-
|
|
129
|
-
// Check against ignore list - match both relative path and absolute path
|
|
130
|
-
for (const ignorePath of ignorePaths) {
|
|
131
|
-
// Check relative path from watchDir
|
|
132
|
-
if (
|
|
133
|
-
changedFile === ignorePath ||
|
|
134
|
-
changedFile.startsWith(`${ignorePath}/`) ||
|
|
135
|
-
changedFile.startsWith(`${ignorePath}\\`)
|
|
136
|
-
) {
|
|
137
|
-
logger.trace('File change ignored (%s): %s', ignorePath, changedFile);
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Check if absolute path contains the ignore pattern
|
|
142
|
-
const ignoreAbsPath = resolve(rootDir, ignorePath);
|
|
143
|
-
if (
|
|
144
|
-
absPath === ignoreAbsPath ||
|
|
145
|
-
absPath.startsWith(`${ignoreAbsPath}/`) ||
|
|
146
|
-
absPath.startsWith(`${ignoreAbsPath}\\`)
|
|
147
|
-
) {
|
|
148
|
-
logger.trace('File change ignored (%s): %s', ignorePath, changedFile);
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Also check if changedFile path includes the ignore pattern anywhere
|
|
153
|
-
// This handles cases like "some/path/.agentuity/file.js"
|
|
154
|
-
const normalizedChanged = changedFile.replace(/\\/g, '/');
|
|
155
|
-
const normalizedIgnore = ignorePath.replace(/\\/g, '/');
|
|
156
|
-
if (
|
|
157
|
-
normalizedChanged.includes(`/${normalizedIgnore}/`) ||
|
|
158
|
-
normalizedChanged.includes(`/${normalizedIgnore}`)
|
|
159
|
-
) {
|
|
160
|
-
logger.trace('File change ignored (%s in path): %s', ignorePath, changedFile);
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Ignore temp files from editors
|
|
166
|
-
if (changedFile.match(/\.(tmp|swp|swo|swx)$|~$/)) {
|
|
167
|
-
logger.trace('File change ignored (temp file): %s', changedFile);
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Ignore files with non-code extensions
|
|
172
|
-
const extIndex = changedFile.lastIndexOf('.');
|
|
173
|
-
if (extIndex !== -1) {
|
|
174
|
-
const ext = changedFile.slice(extIndex).toLowerCase();
|
|
175
|
-
if (ignoreExtensions.has(ext)) {
|
|
176
|
-
logger.trace('File change ignored (%s): %s', ext, changedFile);
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Ignore hidden files (except .env)
|
|
182
|
-
if (changedFile.startsWith('.') && !changedFile.startsWith('.env')) {
|
|
183
|
-
logger.trace('File change ignored (hidden file): %s', changedFile);
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Handle file change event
|
|
192
|
-
*/
|
|
193
|
-
function handleFileChange(eventType: string, changedFile: string | null, watchDir: string) {
|
|
194
|
-
if (paused) {
|
|
195
|
-
logger.trace('File change ignored (watcher paused): %s', changedFile);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (shouldIgnorePath(changedFile, watchDir)) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// During build cooldown, ignore changes (they're likely build outputs)
|
|
204
|
-
if (buildCooldownTimer) {
|
|
205
|
-
logger.trace('File change ignored (build cooldown): %s', changedFile);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Get absolute path for checking
|
|
210
|
-
const absPath = changedFile ? resolve(watchDir, changedFile) : watchDir;
|
|
211
|
-
|
|
212
|
-
// Check if this is a directory
|
|
213
|
-
let isDirectory = false;
|
|
214
|
-
try {
|
|
215
|
-
const stats = statSync(absPath);
|
|
216
|
-
isDirectory = stats.isDirectory();
|
|
217
|
-
} catch {
|
|
218
|
-
// File doesn't exist (was deleted) - not a directory
|
|
219
|
-
isDirectory = false;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Check if an empty directory was created in src/agent/
|
|
223
|
-
// This helps with developer experience by auto-scaffolding template files
|
|
224
|
-
if (changedFile && eventType === 'rename' && isDirectory) {
|
|
225
|
-
try {
|
|
226
|
-
// Normalize the path for comparison (use forward slashes)
|
|
227
|
-
const normalizedPath = changedFile.replace(/\\/g, '/');
|
|
228
|
-
|
|
229
|
-
// Check if it's empty
|
|
230
|
-
const contents = readdirSync(absPath);
|
|
231
|
-
if (contents.length === 0) {
|
|
232
|
-
if (
|
|
233
|
-
normalizedPath.startsWith('src/agent/') ||
|
|
234
|
-
normalizedPath.includes('/src/agent/')
|
|
235
|
-
) {
|
|
236
|
-
logger.debug('Agent directory created: %s', changedFile);
|
|
237
|
-
createAgentTemplates(absPath);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
} catch (error) {
|
|
241
|
-
// File might have been deleted or doesn't exist yet - this is normal
|
|
242
|
-
logger.trace(
|
|
243
|
-
'Unable to check directory for template creation (%s): %s',
|
|
244
|
-
changedFile,
|
|
245
|
-
error
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Ignore directory-only change events (mtime updates when files inside change)
|
|
251
|
-
// We only care about actual file changes - the watcher will report those directly
|
|
252
|
-
if (isDirectory && eventType === 'change') {
|
|
253
|
-
logger.trace('File change ignored (directory mtime update): %s', changedFile);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
logger.debug('File changed (%s): %s', eventType, changedFile || watchDir);
|
|
258
|
-
onRestart();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Recursively collect all directories to watch, skipping ignored directories.
|
|
263
|
-
* This prevents EMFILE errors from symlink cycles in node_modules.
|
|
264
|
-
*/
|
|
265
|
-
function collectWatchDirs(dir: string, visited: Set<string> = new Set()): string[] {
|
|
266
|
-
const dirs: string[] = [dir];
|
|
267
|
-
|
|
268
|
-
try {
|
|
269
|
-
// Use lstat to check for symlinks - get the real path to detect cycles
|
|
270
|
-
const stat = lstatSync(dir);
|
|
271
|
-
|
|
272
|
-
// Skip symlinks to prevent following circular symlinks
|
|
273
|
-
if (stat.isSymbolicLink()) {
|
|
274
|
-
logger.trace('Skipping symlink: %s', dir);
|
|
275
|
-
return [];
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Track visited inodes to detect cycles
|
|
279
|
-
const key = `${stat.dev}:${stat.ino}`;
|
|
280
|
-
if (visited.has(key)) {
|
|
281
|
-
logger.trace('Skipping already visited directory (cycle detected): %s', dir);
|
|
282
|
-
return [];
|
|
283
|
-
}
|
|
284
|
-
visited.add(key);
|
|
285
|
-
|
|
286
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
287
|
-
|
|
288
|
-
for (const entry of entries) {
|
|
289
|
-
if (!entry.isDirectory()) continue;
|
|
290
|
-
|
|
291
|
-
const name = entry.name;
|
|
292
|
-
|
|
293
|
-
// Skip ignored directories entirely - this is the key fix
|
|
294
|
-
if (ignoreDirs.has(name)) {
|
|
295
|
-
logger.trace('Skipping ignored directory: %s', resolve(dir, name));
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Skip hidden directories (except specific ones like .env folders)
|
|
300
|
-
if (name.startsWith('.')) {
|
|
301
|
-
logger.trace('Skipping hidden directory: %s', resolve(dir, name));
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const fullPath = resolve(dir, name);
|
|
306
|
-
dirs.push(...collectWatchDirs(fullPath, visited));
|
|
307
|
-
}
|
|
308
|
-
} catch (error) {
|
|
309
|
-
logger.trace('Error reading directory %s: %s', dir, error);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return dirs;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Start watching files
|
|
317
|
-
*/
|
|
318
|
-
function start() {
|
|
319
|
-
logger.debug('Starting file watchers for hot reload...');
|
|
320
|
-
|
|
321
|
-
// Collect all directories to watch, excluding node_modules and other ignored dirs
|
|
322
|
-
const allDirs = collectWatchDirs(rootDir);
|
|
323
|
-
|
|
324
|
-
// Add additional paths
|
|
325
|
-
if (additionalPaths && additionalPaths.length > 0) {
|
|
326
|
-
for (const additionalPath of additionalPaths) {
|
|
327
|
-
const fullPath = resolve(rootDir, additionalPath);
|
|
328
|
-
allDirs.push(...collectWatchDirs(fullPath));
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// De-duplicate directories
|
|
333
|
-
const uniqueDirs = [...new Set(allDirs)];
|
|
334
|
-
|
|
335
|
-
logger.debug('Collected %d directories to watch', uniqueDirs.length);
|
|
336
|
-
|
|
337
|
-
// Watch each directory non-recursively
|
|
338
|
-
for (const watchPath of uniqueDirs) {
|
|
339
|
-
try {
|
|
340
|
-
// Use non-recursive watch to avoid traversing into node_modules
|
|
341
|
-
const watcher = watch(watchPath, { recursive: false }, (eventType, changedFile) => {
|
|
342
|
-
// Construct relative path from rootDir for consistent handling
|
|
343
|
-
const relPath = changedFile
|
|
344
|
-
? relative(rootDir, resolve(watchPath, changedFile))
|
|
345
|
-
: relative(rootDir, watchPath);
|
|
346
|
-
handleFileChange(eventType, relPath || changedFile, rootDir);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
watchers.push(watcher);
|
|
350
|
-
} catch (error) {
|
|
351
|
-
logger.trace('Failed to start watcher for %s: %s', watchPath, error);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
logger.debug('File watchers started (%d directories)', watchers.length);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Stop all watchers
|
|
360
|
-
*/
|
|
361
|
-
function stop() {
|
|
362
|
-
logger.debug('Stopping file watchers...');
|
|
363
|
-
|
|
364
|
-
for (const watcher of watchers) {
|
|
365
|
-
try {
|
|
366
|
-
watcher.close();
|
|
367
|
-
} catch (error) {
|
|
368
|
-
logger.trace('Error closing watcher: %s', error);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
watchers.length = 0;
|
|
373
|
-
|
|
374
|
-
if (buildCooldownTimer) {
|
|
375
|
-
clearTimeout(buildCooldownTimer);
|
|
376
|
-
buildCooldownTimer = null;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
logger.debug('File watchers stopped');
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Temporarily pause watching (e.g., during build)
|
|
384
|
-
*/
|
|
385
|
-
function pause() {
|
|
386
|
-
paused = true;
|
|
387
|
-
logger.trace('File watchers paused');
|
|
388
|
-
|
|
389
|
-
// Set cooldown timer to ignore changes for a bit after build
|
|
390
|
-
if (buildCooldownTimer) {
|
|
391
|
-
clearTimeout(buildCooldownTimer);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
buildCooldownTimer = setTimeout(() => {
|
|
395
|
-
buildCooldownTimer = null;
|
|
396
|
-
logger.trace('Build cooldown expired');
|
|
397
|
-
}, 500); // 500ms cooldown
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Resume watching
|
|
402
|
-
*/
|
|
403
|
-
function resume() {
|
|
404
|
-
paused = false;
|
|
405
|
-
|
|
406
|
-
// Clear any pending build cooldown timer so file changes are detected immediately.
|
|
407
|
-
// Without this, events arriving during the remaining cooldown window after a fast
|
|
408
|
-
// typecheck failure would be silently dropped.
|
|
409
|
-
if (buildCooldownTimer) {
|
|
410
|
-
clearTimeout(buildCooldownTimer);
|
|
411
|
-
buildCooldownTimer = null;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
logger.trace('File watchers resumed');
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
start,
|
|
419
|
-
stop,
|
|
420
|
-
pause,
|
|
421
|
-
resume,
|
|
422
|
-
};
|
|
423
|
-
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Process Manager for Dev Mode
|
|
3
|
-
*
|
|
4
|
-
* Tracks all spawned processes and ensures they're cleaned up on:
|
|
5
|
-
* - Startup failure (any server fails to start)
|
|
6
|
-
* - Runtime crash (uncaught exception)
|
|
7
|
-
* - Graceful shutdown (SIGINT/SIGTERM)
|
|
8
|
-
*
|
|
9
|
-
* This prevents orphan processes and port conflicts between dev sessions.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { Logger } from '../../types';
|
|
13
|
-
|
|
14
|
-
export interface ManagedProcess {
|
|
15
|
-
/** Process identifier for logging */
|
|
16
|
-
id: string;
|
|
17
|
-
/** The process handle */
|
|
18
|
-
process: {
|
|
19
|
-
kill: (signal?: number | NodeJS.Signals) => void;
|
|
20
|
-
exitCode: number | null;
|
|
21
|
-
pid?: number;
|
|
22
|
-
};
|
|
23
|
-
/** Human-readable description */
|
|
24
|
-
description: string;
|
|
25
|
-
/** The port this process uses (if any) */
|
|
26
|
-
port?: number;
|
|
27
|
-
/** Whether this process is critical (startup fails if it dies) */
|
|
28
|
-
critical?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ManagedServer {
|
|
32
|
-
/** Server identifier */
|
|
33
|
-
id: string;
|
|
34
|
-
/** The server handle */
|
|
35
|
-
server: {
|
|
36
|
-
close: () => void | Promise<void>;
|
|
37
|
-
};
|
|
38
|
-
/** Human-readable description */
|
|
39
|
-
description: string;
|
|
40
|
-
/** The port this server uses */
|
|
41
|
-
port?: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Process Manager
|
|
46
|
-
*
|
|
47
|
-
* Tracks all processes and servers started during dev mode and provides
|
|
48
|
-
* centralized cleanup on failure or shutdown.
|
|
49
|
-
*/
|
|
50
|
-
export class ProcessManager {
|
|
51
|
-
private processes: ManagedProcess[] = [];
|
|
52
|
-
private servers: ManagedServer[] = [];
|
|
53
|
-
private logger: Logger;
|
|
54
|
-
private cleaningUp = false;
|
|
55
|
-
|
|
56
|
-
constructor(logger: Logger) {
|
|
57
|
-
this.logger = logger;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Register a spawned process for tracking.
|
|
62
|
-
*/
|
|
63
|
-
registerProcess(proc: ManagedProcess): void {
|
|
64
|
-
this.processes.push(proc);
|
|
65
|
-
this.logger.debug(
|
|
66
|
-
'Registered process: %s (pid=%s, port=%s)',
|
|
67
|
-
proc.id,
|
|
68
|
-
proc.process.pid ?? 'unknown',
|
|
69
|
-
proc.port ?? 'n/a'
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Register a server for tracking.
|
|
75
|
-
*/
|
|
76
|
-
registerServer(server: ManagedServer): void {
|
|
77
|
-
this.servers.push(server);
|
|
78
|
-
this.logger.debug('Registered server: %s (port=%s)', server.id, server.port ?? 'n/a');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Unregister a process (e.g., after it exits normally).
|
|
83
|
-
*/
|
|
84
|
-
unregisterProcess(id: string): void {
|
|
85
|
-
const idx = this.processes.findIndex((p) => p.id === id);
|
|
86
|
-
if (idx !== -1) {
|
|
87
|
-
this.processes.splice(idx, 1);
|
|
88
|
-
this.logger.debug('Unregistered process: %s', id);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Unregister a server.
|
|
94
|
-
*/
|
|
95
|
-
unregisterServer(id: string): void {
|
|
96
|
-
const idx = this.servers.findIndex((s) => s.id === id);
|
|
97
|
-
if (idx !== -1) {
|
|
98
|
-
this.servers.splice(idx, 1);
|
|
99
|
-
this.logger.debug('Unregistered server: %s', id);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get all registered ports (for cleanup verification).
|
|
105
|
-
*/
|
|
106
|
-
getPorts(): number[] {
|
|
107
|
-
const ports: number[] = [];
|
|
108
|
-
for (const proc of this.processes) {
|
|
109
|
-
if (proc.port) ports.push(proc.port);
|
|
110
|
-
}
|
|
111
|
-
for (const server of this.servers) {
|
|
112
|
-
if (server.port) ports.push(server.port);
|
|
113
|
-
}
|
|
114
|
-
return ports;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Clean up all tracked processes and servers.
|
|
119
|
-
*
|
|
120
|
-
* @param reason - Why cleanup is happening (for logging)
|
|
121
|
-
* @param timeout - Max time to wait for graceful shutdown (ms)
|
|
122
|
-
*/
|
|
123
|
-
async cleanup(reason: string, timeout = 3000): Promise<void> {
|
|
124
|
-
if (this.cleaningUp) {
|
|
125
|
-
this.logger.debug('Cleanup already in progress, skipping');
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
this.cleaningUp = true;
|
|
129
|
-
|
|
130
|
-
this.logger.debug('Starting cleanup (reason: %s)', reason);
|
|
131
|
-
|
|
132
|
-
// Kill processes in reverse order (LIFO)
|
|
133
|
-
for (let i = this.processes.length - 1; i >= 0; i--) {
|
|
134
|
-
const proc = this.processes[i];
|
|
135
|
-
if (!proc) continue;
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
if (proc.process.exitCode === null) {
|
|
139
|
-
this.logger.debug(
|
|
140
|
-
'Killing process %s (pid=%s)',
|
|
141
|
-
proc.id,
|
|
142
|
-
proc.process.pid ?? 'unknown'
|
|
143
|
-
);
|
|
144
|
-
proc.process.kill('SIGTERM');
|
|
145
|
-
}
|
|
146
|
-
} catch (err) {
|
|
147
|
-
this.logger.debug('Error killing process %s: %s', proc.id, err);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Close servers
|
|
152
|
-
for (let i = this.servers.length - 1; i >= 0; i--) {
|
|
153
|
-
const server = this.servers[i];
|
|
154
|
-
if (!server) continue;
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
this.logger.debug('Closing server %s', server.id);
|
|
158
|
-
const closePromise = server.server.close();
|
|
159
|
-
if (closePromise instanceof Promise) {
|
|
160
|
-
await Promise.race([
|
|
161
|
-
closePromise,
|
|
162
|
-
new Promise<void>((resolve) => setTimeout(resolve, 1000)),
|
|
163
|
-
]);
|
|
164
|
-
}
|
|
165
|
-
} catch (err) {
|
|
166
|
-
this.logger.debug('Error closing server %s: %s', server.id, err);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Wait for processes to exit, then force-kill if needed
|
|
171
|
-
const startTime = Date.now();
|
|
172
|
-
while (Date.now() - startTime < timeout) {
|
|
173
|
-
const allExited = this.processes.every((p) => p.process.exitCode !== null);
|
|
174
|
-
if (allExited) break;
|
|
175
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Force kill any remaining
|
|
179
|
-
for (const proc of this.processes) {
|
|
180
|
-
if (proc.process.exitCode === null) {
|
|
181
|
-
try {
|
|
182
|
-
this.logger.debug('Force killing process %s', proc.id);
|
|
183
|
-
proc.process.kill('SIGKILL');
|
|
184
|
-
} catch (err) {
|
|
185
|
-
this.logger.debug('Error force killing process %s: %s', proc.id, err);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
this.logger.debug('Cleanup complete');
|
|
191
|
-
this.processes = [];
|
|
192
|
-
this.servers = [];
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Verify that all ports used by tracked processes are released.
|
|
197
|
-
* Used after cleanup to ensure no orphan processes remain.
|
|
198
|
-
*/
|
|
199
|
-
async verifyPortsReleased(): Promise<{ port: number; released: boolean }[]> {
|
|
200
|
-
const results: { port: number; released: boolean }[] = [];
|
|
201
|
-
const ports = this.getPorts();
|
|
202
|
-
|
|
203
|
-
for (const port of ports) {
|
|
204
|
-
const released = await this.isPortAvailable(port);
|
|
205
|
-
results.push({ port, released });
|
|
206
|
-
|
|
207
|
-
if (!released) {
|
|
208
|
-
this.logger.warn('Port %d is still in use after cleanup', port);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return results;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Check if a port is available.
|
|
217
|
-
*/
|
|
218
|
-
private isPortAvailable(port: number, host = '127.0.0.1'): Promise<boolean> {
|
|
219
|
-
return new Promise((resolve) => {
|
|
220
|
-
const net = require('node:net');
|
|
221
|
-
const server = net.createServer();
|
|
222
|
-
server.once('error', () => resolve(false));
|
|
223
|
-
server.listen(port, host, () => {
|
|
224
|
-
server.close(() => resolve(true));
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Global process manager instance for dev mode.
|
|
232
|
-
* Set in dev/index.ts during startup.
|
|
233
|
-
*/
|
|
234
|
-
let globalProcessManager: ProcessManager | null = null;
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get the global process manager (throws if not initialized).
|
|
238
|
-
*/
|
|
239
|
-
export function getProcessManager(): ProcessManager {
|
|
240
|
-
if (!globalProcessManager) {
|
|
241
|
-
throw new Error('ProcessManager not initialized. Call initProcessManager first.');
|
|
242
|
-
}
|
|
243
|
-
return globalProcessManager;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Initialize the global process manager.
|
|
248
|
-
*/
|
|
249
|
-
export function initProcessManager(logger: Logger): ProcessManager {
|
|
250
|
-
globalProcessManager = new ProcessManager(logger);
|
|
251
|
-
return globalProcessManager;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Cleanup helper that can be called from signal handlers or error handlers.
|
|
256
|
-
*/
|
|
257
|
-
export async function cleanupAll(reason: string): Promise<void> {
|
|
258
|
-
if (globalProcessManager) {
|
|
259
|
-
await globalProcessManager.cleanup(reason);
|
|
260
|
-
}
|
|
261
|
-
}
|