@vibesdotdev/pm 0.0.0-stage → 1.0.0-rc.2
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/LICENSE +18 -0
- package/README.md +227 -2
- package/dist/admission-store.d.ts +43 -0
- package/dist/admission-store.d.ts.map +1 -0
- package/dist/admission-store.js +108 -0
- package/dist/admission-store.js.map +1 -0
- package/dist/admission.d.ts +46 -0
- package/dist/admission.d.ts.map +1 -0
- package/dist/admission.js +81 -0
- package/dist/admission.js.map +1 -0
- package/dist/admitted-workspace.context.descriptor.d.ts +39 -0
- package/dist/admitted-workspace.context.descriptor.d.ts.map +1 -0
- package/dist/admitted-workspace.context.descriptor.js +18 -0
- package/dist/admitted-workspace.context.descriptor.js.map +1 -0
- package/dist/admitted-workspace.context.impl.consumer.d.ts +16 -0
- package/dist/admitted-workspace.context.impl.consumer.d.ts.map +1 -0
- package/dist/admitted-workspace.context.impl.consumer.js +7 -0
- package/dist/admitted-workspace.context.impl.consumer.js.map +1 -0
- package/dist/cli/admission-read.d.ts +12 -0
- package/dist/cli/admission-read.d.ts.map +1 -0
- package/dist/cli/admission-read.js +42 -0
- package/dist/cli/admission-read.js.map +1 -0
- package/dist/cli/command-input.d.ts +37 -0
- package/dist/cli/command-input.d.ts.map +1 -0
- package/dist/cli/command-input.js +34 -0
- package/dist/cli/command-input.js.map +1 -0
- package/dist/cli/consumer-components/startup-progress.d.ts +107 -0
- package/dist/cli/consumer-components/startup-progress.d.ts.map +1 -0
- package/dist/cli/consumer-components/startup-progress.js +392 -0
- package/dist/cli/consumer-components/startup-progress.js.map +1 -0
- package/dist/cli/consumer-services/control.d.ts +147 -0
- package/dist/cli/consumer-services/control.d.ts.map +1 -0
- package/dist/cli/consumer-services/control.js +209 -0
- package/dist/cli/consumer-services/control.js.map +1 -0
- package/dist/cli/daemon-launch-child.d.ts +35 -0
- package/dist/cli/daemon-launch-child.d.ts.map +1 -0
- package/dist/cli/daemon-launch-child.js +25 -0
- package/dist/cli/daemon-launch-child.js.map +1 -0
- package/dist/cli/docs/pm.cli.docs.descriptor.d.ts +4 -0
- package/dist/cli/docs/pm.cli.docs.descriptor.d.ts.map +1 -0
- package/dist/cli/docs/pm.cli.docs.descriptor.js +93 -0
- package/dist/cli/docs/pm.cli.docs.descriptor.js.map +1 -0
- package/dist/cli/filter-process-states.d.ts +12 -0
- package/dist/cli/filter-process-states.d.ts.map +1 -0
- package/dist/cli/filter-process-states.js +12 -0
- package/dist/cli/filter-process-states.js.map +1 -0
- package/dist/cli/output.d.ts +21 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +19 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/plugin.d.ts +3 -0
- package/dist/cli/plugin.d.ts.map +1 -0
- package/dist/cli/plugin.js +12 -0
- package/dist/cli/plugin.js.map +1 -0
- package/dist/cli/pm.cli-group.descriptor.d.ts +10 -0
- package/dist/cli/pm.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.cli-group.descriptor.js +18 -0
- package/dist/cli/pm.cli-group.descriptor.js.map +1 -0
- package/dist/cli/pm.completion.cli-group.descriptor.d.ts +9 -0
- package/dist/cli/pm.completion.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.completion.cli-group.descriptor.js +17 -0
- package/dist/cli/pm.completion.cli-group.descriptor.js.map +1 -0
- package/dist/cli/pm.completion.install.descriptor.d.ts +9 -0
- package/dist/cli/pm.completion.install.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.completion.install.descriptor.js +24 -0
- package/dist/cli/pm.completion.install.descriptor.js.map +1 -0
- package/dist/cli/pm.completion.install.impl.d.ts +11 -0
- package/dist/cli/pm.completion.install.impl.d.ts.map +1 -0
- package/dist/cli/pm.completion.install.impl.js +207 -0
- package/dist/cli/pm.completion.install.impl.js.map +1 -0
- package/dist/cli/pm.config.cli.descriptor.d.ts +10 -0
- package/dist/cli/pm.config.cli.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.config.cli.descriptor.js +25 -0
- package/dist/cli/pm.config.cli.descriptor.js.map +1 -0
- package/dist/cli/pm.config.impl.d.ts +12 -0
- package/dist/cli/pm.config.impl.d.ts.map +1 -0
- package/dist/cli/pm.config.impl.js +117 -0
- package/dist/cli/pm.config.impl.js.map +1 -0
- package/dist/cli/pm.daemon.cli-group.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.cli-group.descriptor.js +17 -0
- package/dist/cli/pm.daemon.cli-group.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.logs.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.logs.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.logs.descriptor.js +29 -0
- package/dist/cli/pm.daemon.logs.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.logs.impl.d.ts +11 -0
- package/dist/cli/pm.daemon.logs.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.logs.impl.js +53 -0
- package/dist/cli/pm.daemon.logs.impl.js.map +1 -0
- package/dist/cli/pm.daemon.reconcile.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.reconcile.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.reconcile.descriptor.js +24 -0
- package/dist/cli/pm.daemon.reconcile.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.reconcile.impl.d.ts +16 -0
- package/dist/cli/pm.daemon.reconcile.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.reconcile.impl.js +51 -0
- package/dist/cli/pm.daemon.reconcile.impl.js.map +1 -0
- package/dist/cli/pm.daemon.recover.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.recover.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.recover.descriptor.js +24 -0
- package/dist/cli/pm.daemon.recover.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.recover.impl.d.ts +16 -0
- package/dist/cli/pm.daemon.recover.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.recover.impl.js +66 -0
- package/dist/cli/pm.daemon.recover.impl.js.map +1 -0
- package/dist/cli/pm.daemon.restart.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.restart.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.restart.descriptor.js +25 -0
- package/dist/cli/pm.daemon.restart.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.restart.impl.d.ts +28 -0
- package/dist/cli/pm.daemon.restart.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.restart.impl.js +174 -0
- package/dist/cli/pm.daemon.restart.impl.js.map +1 -0
- package/dist/cli/pm.daemon.serve.descriptor.d.ts +10 -0
- package/dist/cli/pm.daemon.serve.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.serve.descriptor.js +28 -0
- package/dist/cli/pm.daemon.serve.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.serve.impl.d.ts +37 -0
- package/dist/cli/pm.daemon.serve.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.serve.impl.js +257 -0
- package/dist/cli/pm.daemon.serve.impl.js.map +1 -0
- package/dist/cli/pm.daemon.start.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.start.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.start.descriptor.js +28 -0
- package/dist/cli/pm.daemon.start.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.start.impl.d.ts +40 -0
- package/dist/cli/pm.daemon.start.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.start.impl.js +341 -0
- package/dist/cli/pm.daemon.start.impl.js.map +1 -0
- package/dist/cli/pm.daemon.status.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.status.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.status.descriptor.js +24 -0
- package/dist/cli/pm.daemon.status.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.status.impl.d.ts +11 -0
- package/dist/cli/pm.daemon.status.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.status.impl.js +123 -0
- package/dist/cli/pm.daemon.status.impl.js.map +1 -0
- package/dist/cli/pm.daemon.stop.descriptor.d.ts +9 -0
- package/dist/cli/pm.daemon.stop.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.daemon.stop.descriptor.js +24 -0
- package/dist/cli/pm.daemon.stop.descriptor.js.map +1 -0
- package/dist/cli/pm.daemon.stop.impl.d.ts +21 -0
- package/dist/cli/pm.daemon.stop.impl.d.ts.map +1 -0
- package/dist/cli/pm.daemon.stop.impl.js +108 -0
- package/dist/cli/pm.daemon.stop.impl.js.map +1 -0
- package/dist/cli/pm.dashboard.descriptor.d.ts +10 -0
- package/dist/cli/pm.dashboard.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.dashboard.descriptor.js +30 -0
- package/dist/cli/pm.dashboard.descriptor.js.map +1 -0
- package/dist/cli/pm.dashboard.impl.d.ts +16 -0
- package/dist/cli/pm.dashboard.impl.d.ts.map +1 -0
- package/dist/cli/pm.dashboard.impl.js +134 -0
- package/dist/cli/pm.dashboard.impl.js.map +1 -0
- package/dist/cli/pm.init.descriptor.d.ts +9 -0
- package/dist/cli/pm.init.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.init.descriptor.js +28 -0
- package/dist/cli/pm.init.descriptor.js.map +1 -0
- package/dist/cli/pm.init.impl.d.ts +11 -0
- package/dist/cli/pm.init.impl.d.ts.map +1 -0
- package/dist/cli/pm.init.impl.js +112 -0
- package/dist/cli/pm.init.impl.js.map +1 -0
- package/dist/cli/pm.list.descriptor.d.ts +9 -0
- package/dist/cli/pm.list.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.list.descriptor.js +44 -0
- package/dist/cli/pm.list.descriptor.js.map +1 -0
- package/dist/cli/pm.list.impl.d.ts +24 -0
- package/dist/cli/pm.list.impl.d.ts.map +1 -0
- package/dist/cli/pm.list.impl.js +204 -0
- package/dist/cli/pm.list.impl.js.map +1 -0
- package/dist/cli/pm.liveness.cli-group.descriptor.d.ts +25 -0
- package/dist/cli/pm.liveness.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.liveness.cli-group.descriptor.js +33 -0
- package/dist/cli/pm.liveness.cli-group.descriptor.js.map +1 -0
- package/dist/cli/pm.liveness.set.descriptor.d.ts +18 -0
- package/dist/cli/pm.liveness.set.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.liveness.set.descriptor.js +65 -0
- package/dist/cli/pm.liveness.set.descriptor.js.map +1 -0
- package/dist/cli/pm.liveness.set.impl.d.ts +6 -0
- package/dist/cli/pm.liveness.set.impl.d.ts.map +1 -0
- package/dist/cli/pm.liveness.set.impl.js +61 -0
- package/dist/cli/pm.liveness.set.impl.js.map +1 -0
- package/dist/cli/pm.logs.descriptor.d.ts +9 -0
- package/dist/cli/pm.logs.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.logs.descriptor.js +39 -0
- package/dist/cli/pm.logs.descriptor.js.map +1 -0
- package/dist/cli/pm.logs.impl.d.ts +11 -0
- package/dist/cli/pm.logs.impl.d.ts.map +1 -0
- package/dist/cli/pm.logs.impl.js +208 -0
- package/dist/cli/pm.logs.impl.js.map +1 -0
- package/dist/cli/pm.preset.cli-group.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.cli-group.descriptor.js +17 -0
- package/dist/cli/pm.preset.cli-group.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.list.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.list.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.list.descriptor.js +24 -0
- package/dist/cli/pm.preset.list.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.list.impl.d.ts +6 -0
- package/dist/cli/pm.preset.list.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.list.impl.js +67 -0
- package/dist/cli/pm.preset.list.impl.js.map +1 -0
- package/dist/cli/pm.preset.restart.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.restart.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.restart.descriptor.js +39 -0
- package/dist/cli/pm.preset.restart.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.restart.impl.d.ts +11 -0
- package/dist/cli/pm.preset.restart.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.restart.impl.js +85 -0
- package/dist/cli/pm.preset.restart.impl.js.map +1 -0
- package/dist/cli/pm.preset.show.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.show.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.show.descriptor.js +30 -0
- package/dist/cli/pm.preset.show.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.show.impl.d.ts +6 -0
- package/dist/cli/pm.preset.show.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.show.impl.js +92 -0
- package/dist/cli/pm.preset.show.impl.js.map +1 -0
- package/dist/cli/pm.preset.start.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.start.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.start.descriptor.js +39 -0
- package/dist/cli/pm.preset.start.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.start.impl.d.ts +11 -0
- package/dist/cli/pm.preset.start.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.start.impl.js +88 -0
- package/dist/cli/pm.preset.start.impl.js.map +1 -0
- package/dist/cli/pm.preset.status.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.status.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.status.descriptor.js +30 -0
- package/dist/cli/pm.preset.status.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.status.impl.d.ts +11 -0
- package/dist/cli/pm.preset.status.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.status.impl.js +166 -0
- package/dist/cli/pm.preset.status.impl.js.map +1 -0
- package/dist/cli/pm.preset.stop.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.stop.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.stop.descriptor.js +39 -0
- package/dist/cli/pm.preset.stop.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.stop.impl.d.ts +11 -0
- package/dist/cli/pm.preset.stop.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.stop.impl.js +68 -0
- package/dist/cli/pm.preset.stop.impl.js.map +1 -0
- package/dist/cli/pm.preset.teardown.descriptor.d.ts +9 -0
- package/dist/cli/pm.preset.teardown.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.preset.teardown.descriptor.js +43 -0
- package/dist/cli/pm.preset.teardown.descriptor.js.map +1 -0
- package/dist/cli/pm.preset.teardown.impl.d.ts +12 -0
- package/dist/cli/pm.preset.teardown.impl.d.ts.map +1 -0
- package/dist/cli/pm.preset.teardown.impl.js +91 -0
- package/dist/cli/pm.preset.teardown.impl.js.map +1 -0
- package/dist/cli/pm.presets.descriptor.d.ts +9 -0
- package/dist/cli/pm.presets.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.presets.descriptor.js +24 -0
- package/dist/cli/pm.presets.descriptor.js.map +1 -0
- package/dist/cli/pm.presets.impl.d.ts +11 -0
- package/dist/cli/pm.presets.impl.d.ts.map +1 -0
- package/dist/cli/pm.presets.impl.js +13 -0
- package/dist/cli/pm.presets.impl.js.map +1 -0
- package/dist/cli/pm.register.descriptor.d.ts +11 -0
- package/dist/cli/pm.register.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.register.descriptor.js +32 -0
- package/dist/cli/pm.register.descriptor.js.map +1 -0
- package/dist/cli/pm.register.impl.d.ts +15 -0
- package/dist/cli/pm.register.impl.d.ts.map +1 -0
- package/dist/cli/pm.register.impl.js +81 -0
- package/dist/cli/pm.register.impl.js.map +1 -0
- package/dist/cli/pm.resource.apply.descriptor.d.ts +15 -0
- package/dist/cli/pm.resource.apply.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.resource.apply.descriptor.js +41 -0
- package/dist/cli/pm.resource.apply.descriptor.js.map +1 -0
- package/dist/cli/pm.resource.apply.impl.d.ts +14 -0
- package/dist/cli/pm.resource.apply.impl.d.ts.map +1 -0
- package/dist/cli/pm.resource.apply.impl.js +91 -0
- package/dist/cli/pm.resource.apply.impl.js.map +1 -0
- package/dist/cli/pm.resource.cli-group.descriptor.d.ts +9 -0
- package/dist/cli/pm.resource.cli-group.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.resource.cli-group.descriptor.js +17 -0
- package/dist/cli/pm.resource.cli-group.descriptor.js.map +1 -0
- package/dist/cli/pm.resource.list.descriptor.d.ts +9 -0
- package/dist/cli/pm.resource.list.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.resource.list.descriptor.js +25 -0
- package/dist/cli/pm.resource.list.descriptor.js.map +1 -0
- package/dist/cli/pm.resource.list.impl.d.ts +11 -0
- package/dist/cli/pm.resource.list.impl.d.ts.map +1 -0
- package/dist/cli/pm.resource.list.impl.js +141 -0
- package/dist/cli/pm.resource.list.impl.js.map +1 -0
- package/dist/cli/pm.resource.recreate.descriptor.d.ts +4 -0
- package/dist/cli/pm.resource.recreate.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.resource.recreate.descriptor.js +29 -0
- package/dist/cli/pm.resource.recreate.descriptor.js.map +1 -0
- package/dist/cli/pm.resource.recreate.impl.d.ts +6 -0
- package/dist/cli/pm.resource.recreate.impl.d.ts.map +1 -0
- package/dist/cli/pm.resource.recreate.impl.js +123 -0
- package/dist/cli/pm.resource.recreate.impl.js.map +1 -0
- package/dist/cli/pm.resource.status.descriptor.d.ts +9 -0
- package/dist/cli/pm.resource.status.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.resource.status.descriptor.js +31 -0
- package/dist/cli/pm.resource.status.descriptor.js.map +1 -0
- package/dist/cli/pm.resource.status.impl.d.ts +11 -0
- package/dist/cli/pm.resource.status.impl.d.ts.map +1 -0
- package/dist/cli/pm.resource.status.impl.js +230 -0
- package/dist/cli/pm.resource.status.impl.js.map +1 -0
- package/dist/cli/pm.restart.descriptor.d.ts +9 -0
- package/dist/cli/pm.restart.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.restart.descriptor.js +40 -0
- package/dist/cli/pm.restart.descriptor.js.map +1 -0
- package/dist/cli/pm.restart.impl.d.ts +12 -0
- package/dist/cli/pm.restart.impl.d.ts.map +1 -0
- package/dist/cli/pm.restart.impl.js +109 -0
- package/dist/cli/pm.restart.impl.js.map +1 -0
- package/dist/cli/pm.show.descriptor.d.ts +9 -0
- package/dist/cli/pm.show.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.show.descriptor.js +30 -0
- package/dist/cli/pm.show.descriptor.js.map +1 -0
- package/dist/cli/pm.show.impl.d.ts +25 -0
- package/dist/cli/pm.show.impl.d.ts.map +1 -0
- package/dist/cli/pm.show.impl.js +175 -0
- package/dist/cli/pm.show.impl.js.map +1 -0
- package/dist/cli/pm.start-all.descriptor.d.ts +9 -0
- package/dist/cli/pm.start-all.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.start-all.descriptor.js +34 -0
- package/dist/cli/pm.start-all.descriptor.js.map +1 -0
- package/dist/cli/pm.start-all.impl.d.ts +12 -0
- package/dist/cli/pm.start-all.impl.d.ts.map +1 -0
- package/dist/cli/pm.start-all.impl.js +91 -0
- package/dist/cli/pm.start-all.impl.js.map +1 -0
- package/dist/cli/pm.start.descriptor.d.ts +9 -0
- package/dist/cli/pm.start.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.start.descriptor.js +40 -0
- package/dist/cli/pm.start.descriptor.js.map +1 -0
- package/dist/cli/pm.start.impl.d.ts +19 -0
- package/dist/cli/pm.start.impl.d.ts.map +1 -0
- package/dist/cli/pm.start.impl.js +170 -0
- package/dist/cli/pm.start.impl.js.map +1 -0
- package/dist/cli/pm.status.descriptor.d.ts +10 -0
- package/dist/cli/pm.status.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.status.descriptor.js +31 -0
- package/dist/cli/pm.status.descriptor.js.map +1 -0
- package/dist/cli/pm.status.impl.d.ts +96 -0
- package/dist/cli/pm.status.impl.d.ts.map +1 -0
- package/dist/cli/pm.status.impl.js +425 -0
- package/dist/cli/pm.status.impl.js.map +1 -0
- package/dist/cli/pm.stop-all.descriptor.d.ts +9 -0
- package/dist/cli/pm.stop-all.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.stop-all.descriptor.js +41 -0
- package/dist/cli/pm.stop-all.descriptor.js.map +1 -0
- package/dist/cli/pm.stop-all.impl.d.ts +14 -0
- package/dist/cli/pm.stop-all.impl.d.ts.map +1 -0
- package/dist/cli/pm.stop-all.impl.js +138 -0
- package/dist/cli/pm.stop-all.impl.js.map +1 -0
- package/dist/cli/pm.stop.descriptor.d.ts +9 -0
- package/dist/cli/pm.stop.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.stop.descriptor.js +40 -0
- package/dist/cli/pm.stop.descriptor.js.map +1 -0
- package/dist/cli/pm.stop.impl.d.ts +13 -0
- package/dist/cli/pm.stop.impl.d.ts.map +1 -0
- package/dist/cli/pm.stop.impl.js +120 -0
- package/dist/cli/pm.stop.impl.js.map +1 -0
- package/dist/cli/pm.unregister-all.descriptor.d.ts +9 -0
- package/dist/cli/pm.unregister-all.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.unregister-all.descriptor.js +28 -0
- package/dist/cli/pm.unregister-all.descriptor.js.map +1 -0
- package/dist/cli/pm.unregister-all.impl.d.ts +11 -0
- package/dist/cli/pm.unregister-all.impl.d.ts.map +1 -0
- package/dist/cli/pm.unregister-all.impl.js +106 -0
- package/dist/cli/pm.unregister-all.impl.js.map +1 -0
- package/dist/cli/pm.unregister.descriptor.d.ts +9 -0
- package/dist/cli/pm.unregister.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.unregister.descriptor.js +34 -0
- package/dist/cli/pm.unregister.descriptor.js.map +1 -0
- package/dist/cli/pm.unregister.impl.d.ts +11 -0
- package/dist/cli/pm.unregister.impl.d.ts.map +1 -0
- package/dist/cli/pm.unregister.impl.js +77 -0
- package/dist/cli/pm.unregister.impl.js.map +1 -0
- package/dist/cli/pm.validate.descriptor.d.ts +9 -0
- package/dist/cli/pm.validate.descriptor.d.ts.map +1 -0
- package/dist/cli/pm.validate.descriptor.js +24 -0
- package/dist/cli/pm.validate.descriptor.js.map +1 -0
- package/dist/cli/pm.validate.impl.d.ts +6 -0
- package/dist/cli/pm.validate.impl.d.ts.map +1 -0
- package/dist/cli/pm.validate.impl.js +235 -0
- package/dist/cli/pm.validate.impl.js.map +1 -0
- package/dist/cli/preset-execution-options.d.ts +8 -0
- package/dist/cli/preset-execution-options.d.ts.map +1 -0
- package/dist/cli/preset-execution-options.js +22 -0
- package/dist/cli/preset-execution-options.js.map +1 -0
- package/dist/cli/register-manifest.d.ts +23 -0
- package/dist/cli/register-manifest.d.ts.map +1 -0
- package/dist/cli/register-manifest.js +80 -0
- package/dist/cli/register-manifest.js.map +1 -0
- package/dist/cli/runtime.d.ts +3 -0
- package/dist/cli/runtime.d.ts.map +1 -0
- package/dist/cli/runtime.js +134 -0
- package/dist/cli/runtime.js.map +1 -0
- package/dist/cli/table-columns.d.ts +22 -0
- package/dist/cli/table-columns.d.ts.map +1 -0
- package/dist/cli/table-columns.js +61 -0
- package/dist/cli/table-columns.js.map +1 -0
- package/dist/client-replies.d.ts +1188 -0
- package/dist/client-replies.d.ts.map +1 -0
- package/dist/client-replies.js +145 -0
- package/dist/client-replies.js.map +1 -0
- package/dist/client.d.ts +345 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1005 -0
- package/dist/client.js.map +1 -0
- package/dist/config/pm.config.config.descriptor.d.ts +10 -0
- package/dist/config/pm.config.config.descriptor.d.ts.map +1 -0
- package/dist/config/pm.config.config.descriptor.js +37 -0
- package/dist/config/pm.config.config.descriptor.js.map +1 -0
- package/dist/context.d.ts +121 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +6 -0
- package/dist/context.js.map +1 -0
- package/dist/daemon/command-handler.d.ts +74 -0
- package/dist/daemon/command-handler.d.ts.map +1 -0
- package/dist/daemon/command-handler.js +220 -0
- package/dist/daemon/command-handler.js.map +1 -0
- package/dist/daemon/command-ids.d.ts +10 -0
- package/dist/daemon/command-ids.d.ts.map +1 -0
- package/dist/daemon/command-ids.js +51 -0
- package/dist/daemon/command-ids.js.map +1 -0
- package/dist/daemon/command-implementations.d.ts +30 -0
- package/dist/daemon/command-implementations.d.ts.map +1 -0
- package/dist/daemon/command-implementations.js +340 -0
- package/dist/daemon/command-implementations.js.map +1 -0
- package/dist/daemon/command-payload.d.ts +803 -0
- package/dist/daemon/command-payload.d.ts.map +1 -0
- package/dist/daemon/command-payload.js +128 -0
- package/dist/daemon/command-payload.js.map +1 -0
- package/dist/daemon/commands.plugin.d.ts +6 -0
- package/dist/daemon/commands.plugin.d.ts.map +1 -0
- package/dist/daemon/commands.plugin.js +22 -0
- package/dist/daemon/commands.plugin.js.map +1 -0
- package/dist/daemon/config-watcher.d.ts +125 -0
- package/dist/daemon/config-watcher.d.ts.map +1 -0
- package/dist/daemon/config-watcher.js +541 -0
- package/dist/daemon/config-watcher.js.map +1 -0
- package/dist/daemon/daemon-module-context.d.ts +16 -0
- package/dist/daemon/daemon-module-context.d.ts.map +1 -0
- package/dist/daemon/daemon-module-context.js +25 -0
- package/dist/daemon/daemon-module-context.js.map +1 -0
- package/dist/daemon/declared-commands.d.ts +39 -0
- package/dist/daemon/declared-commands.d.ts.map +1 -0
- package/dist/daemon/declared-commands.js +200 -0
- package/dist/daemon/declared-commands.js.map +1 -0
- package/dist/daemon/executable-freshness-reconciler.d.ts +99 -0
- package/dist/daemon/executable-freshness-reconciler.d.ts.map +1 -0
- package/dist/daemon/executable-freshness-reconciler.js +396 -0
- package/dist/daemon/executable-freshness-reconciler.js.map +1 -0
- package/dist/daemon/fleet-attach-state.d.ts +22 -0
- package/dist/daemon/fleet-attach-state.d.ts.map +1 -0
- package/dist/daemon/fleet-attach-state.js +39 -0
- package/dist/daemon/fleet-attach-state.js.map +1 -0
- package/dist/daemon/health-monitor.d.ts +105 -0
- package/dist/daemon/health-monitor.d.ts.map +1 -0
- package/dist/daemon/health-monitor.js +453 -0
- package/dist/daemon/health-monitor.js.map +1 -0
- package/dist/daemon/liveness-checker.d.ts +49 -0
- package/dist/daemon/liveness-checker.d.ts.map +1 -0
- package/dist/daemon/liveness-checker.js +330 -0
- package/dist/daemon/liveness-checker.js.map +1 -0
- package/dist/daemon/orphan-scanner.d.ts +114 -0
- package/dist/daemon/orphan-scanner.d.ts.map +1 -0
- package/dist/daemon/orphan-scanner.js +684 -0
- package/dist/daemon/orphan-scanner.js.map +1 -0
- package/dist/daemon/resource-health-monitor.d.ts +65 -0
- package/dist/daemon/resource-health-monitor.d.ts.map +1 -0
- package/dist/daemon/resource-health-monitor.js +247 -0
- package/dist/daemon/resource-health-monitor.js.map +1 -0
- package/dist/daemon/role.context.impl.d.ts +13 -0
- package/dist/daemon/role.context.impl.d.ts.map +1 -0
- package/dist/daemon/role.context.impl.js +7 -0
- package/dist/daemon/role.context.impl.js.map +1 -0
- package/dist/daemon/role.d.ts +56 -0
- package/dist/daemon/role.d.ts.map +1 -0
- package/dist/daemon/role.js +18 -0
- package/dist/daemon/role.js.map +1 -0
- package/dist/daemon/rpc-result.d.ts +9 -0
- package/dist/daemon/rpc-result.d.ts.map +1 -0
- package/dist/daemon/rpc-result.js +28 -0
- package/dist/daemon/rpc-result.js.map +1 -0
- package/dist/daemon/stray-daemons.d.ts +52 -0
- package/dist/daemon/stray-daemons.d.ts.map +1 -0
- package/dist/daemon/stray-daemons.js +101 -0
- package/dist/daemon/stray-daemons.js.map +1 -0
- package/dist/daemon/supervised-commands.d.ts +3 -0
- package/dist/daemon/supervised-commands.d.ts.map +1 -0
- package/dist/daemon/supervised-commands.js +51 -0
- package/dist/daemon/supervised-commands.js.map +1 -0
- package/dist/daemon.d.ts +329 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +1654 -0
- package/dist/daemon.js.map +1 -0
- package/dist/definitions.d.ts +2 -0
- package/dist/definitions.d.ts.map +1 -0
- package/dist/definitions.js +2 -0
- package/dist/definitions.js.map +1 -0
- package/dist/dev/command.d.ts +39 -0
- package/dist/dev/command.d.ts.map +1 -0
- package/dist/dev/command.js +79 -0
- package/dist/dev/command.js.map +1 -0
- package/dist/dev/defaults.d.ts +34 -0
- package/dist/dev/defaults.d.ts.map +1 -0
- package/dist/dev/defaults.js +58 -0
- package/dist/dev/defaults.js.map +1 -0
- package/dist/dev/env.d.ts +31 -0
- package/dist/dev/env.d.ts.map +1 -0
- package/dist/dev/env.js +56 -0
- package/dist/dev/env.js.map +1 -0
- package/dist/dev/index.d.ts +26 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +28 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/sveltekit.d.ts +41 -0
- package/dist/dev/sveltekit.d.ts.map +1 -0
- package/dist/dev/sveltekit.js +93 -0
- package/dist/dev/sveltekit.js.map +1 -0
- package/dist/dev/workspace-shape.d.ts +64 -0
- package/dist/dev/workspace-shape.d.ts.map +1 -0
- package/dist/dev/workspace-shape.js +19 -0
- package/dist/dev/workspace-shape.js.map +1 -0
- package/dist/docs/pm.daemon.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.daemon.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.daemon.docs.descriptor.js +48 -0
- package/dist/docs/pm.daemon.docs.descriptor.js.map +1 -0
- package/dist/docs/pm.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.docs.descriptor.js +45 -0
- package/dist/docs/pm.docs.descriptor.js.map +1 -0
- package/dist/docs/pm.preset.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.preset.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.preset.docs.descriptor.js +37 -0
- package/dist/docs/pm.preset.docs.descriptor.js.map +1 -0
- package/dist/docs/pm.queues.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.queues.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.queues.docs.descriptor.js +157 -0
- package/dist/docs/pm.queues.docs.descriptor.js.map +1 -0
- package/dist/docs/pm.resource.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.resource.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.resource.docs.descriptor.js +38 -0
- package/dist/docs/pm.resource.docs.descriptor.js.map +1 -0
- package/dist/docs/pm.tasks.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.tasks.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.tasks.docs.descriptor.js +242 -0
- package/dist/docs/pm.tasks.docs.descriptor.js.map +1 -0
- package/dist/docs/pm.workers.docs.descriptor.d.ts +4 -0
- package/dist/docs/pm.workers.docs.descriptor.d.ts.map +1 -0
- package/dist/docs/pm.workers.docs.descriptor.js +427 -0
- package/dist/docs/pm.workers.docs.descriptor.js.map +1 -0
- package/dist/errors.d.ts +262 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +479 -0
- package/dist/errors.js.map +1 -0
- package/dist/graph.d.ts +82 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +247 -0
- package/dist/graph.js.map +1 -0
- package/dist/helpers/failure.d.ts +10 -0
- package/dist/helpers/failure.d.ts.map +1 -0
- package/dist/helpers/failure.js +10 -0
- package/dist/helpers/failure.js.map +1 -0
- package/dist/helpers/launch-custody.d.ts +16 -0
- package/dist/helpers/launch-custody.d.ts.map +1 -0
- package/dist/helpers/launch-custody.js +117 -0
- package/dist/helpers/launch-custody.js.map +1 -0
- package/dist/helpers/launch-identity.d.ts +20 -0
- package/dist/helpers/launch-identity.d.ts.map +1 -0
- package/dist/helpers/launch-identity.js +70 -0
- package/dist/helpers/launch-identity.js.map +1 -0
- package/dist/helpers/managed-http-origin.d.ts +4 -0
- package/dist/helpers/managed-http-origin.d.ts.map +1 -0
- package/dist/helpers/managed-http-origin.js +9 -0
- package/dist/helpers/managed-http-origin.js.map +1 -0
- package/dist/helpers/managed-process-admission.d.ts +55 -0
- package/dist/helpers/managed-process-admission.d.ts.map +1 -0
- package/dist/helpers/managed-process-admission.js +102 -0
- package/dist/helpers/managed-process-admission.js.map +1 -0
- package/dist/helpers/managed-process-id.d.ts +13 -0
- package/dist/helpers/managed-process-id.d.ts.map +1 -0
- package/dist/helpers/managed-process-id.js +16 -0
- package/dist/helpers/managed-process-id.js.map +1 -0
- package/dist/helpers/node-path.d.ts +16 -0
- package/dist/helpers/node-path.d.ts.map +1 -0
- package/dist/helpers/node-path.js +67 -0
- package/dist/helpers/node-path.js.map +1 -0
- package/dist/helpers/output-redaction.d.ts +36 -0
- package/dist/helpers/output-redaction.d.ts.map +1 -0
- package/dist/helpers/output-redaction.js +120 -0
- package/dist/helpers/output-redaction.js.map +1 -0
- package/dist/helpers/process-credentials.d.ts +62 -0
- package/dist/helpers/process-credentials.d.ts.map +1 -0
- package/dist/helpers/process-credentials.js +107 -0
- package/dist/helpers/process-credentials.js.map +1 -0
- package/dist/helpers/process-env.d.ts +72 -0
- package/dist/helpers/process-env.d.ts.map +1 -0
- package/dist/helpers/process-env.js +265 -0
- package/dist/helpers/process-env.js.map +1 -0
- package/dist/helpers/process-watch.d.ts +7 -0
- package/dist/helpers/process-watch.d.ts.map +1 -0
- package/dist/helpers/process-watch.js +27 -0
- package/dist/helpers/process-watch.js.map +1 -0
- package/dist/helpers/rlimits.d.ts +10 -0
- package/dist/helpers/rlimits.d.ts.map +1 -0
- package/dist/helpers/rlimits.js +14 -0
- package/dist/helpers/rlimits.js.map +1 -0
- package/dist/helpers/runtime-files.d.ts +42 -0
- package/dist/helpers/runtime-files.d.ts.map +1 -0
- package/dist/helpers/runtime-files.js +155 -0
- package/dist/helpers/runtime-files.js.map +1 -0
- package/dist/helpers/worker-routing.d.ts +35 -0
- package/dist/helpers/worker-routing.d.ts.map +1 -0
- package/dist/helpers/worker-routing.js +70 -0
- package/dist/helpers/worker-routing.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/interface.d.ts +150 -0
- package/dist/interface.d.ts.map +1 -0
- package/dist/interface.js +6 -0
- package/dist/interface.js.map +1 -0
- package/dist/kinds/daemon-module.kind.d.ts +103 -0
- package/dist/kinds/daemon-module.kind.d.ts.map +1 -0
- package/dist/kinds/daemon-module.kind.js +38 -0
- package/dist/kinds/daemon-module.kind.js.map +1 -0
- package/dist/kinds/launch-preparation.kind.d.ts +24 -0
- package/dist/kinds/launch-preparation.kind.d.ts.map +1 -0
- package/dist/kinds/launch-preparation.kind.js +7 -0
- package/dist/kinds/launch-preparation.kind.js.map +1 -0
- package/dist/kinds/liveness-profile.kind.d.ts +33 -0
- package/dist/kinds/liveness-profile.kind.d.ts.map +1 -0
- package/dist/kinds/liveness-profile.kind.js +27 -0
- package/dist/kinds/liveness-profile.kind.js.map +1 -0
- package/dist/kinds/preset.kind.d.ts +59 -0
- package/dist/kinds/preset.kind.d.ts.map +1 -0
- package/dist/kinds/preset.kind.js +35 -0
- package/dist/kinds/preset.kind.js.map +1 -0
- package/dist/kinds/process-source.kind.d.ts +6 -0
- package/dist/kinds/process-source.kind.d.ts.map +1 -0
- package/dist/kinds/process-source.kind.js +24 -0
- package/dist/kinds/process-source.kind.js.map +1 -0
- package/dist/kinds/process.kind.d.ts +237 -0
- package/dist/kinds/process.kind.d.ts.map +1 -0
- package/dist/kinds/process.kind.js +36 -0
- package/dist/kinds/process.kind.js.map +1 -0
- package/dist/kinds/resource-provider.kind.d.ts +41 -0
- package/dist/kinds/resource-provider.kind.d.ts.map +1 -0
- package/dist/kinds/resource-provider.kind.js +56 -0
- package/dist/kinds/resource-provider.kind.js.map +1 -0
- package/dist/kinds/resource.kind.d.ts +73 -0
- package/dist/kinds/resource.kind.d.ts.map +1 -0
- package/dist/kinds/resource.kind.js +35 -0
- package/dist/kinds/resource.kind.js.map +1 -0
- package/dist/kinds/runtime-daemon-endpoint.d.ts +34 -0
- package/dist/kinds/runtime-daemon-endpoint.d.ts.map +1 -0
- package/dist/kinds/runtime-daemon-endpoint.js +83 -0
- package/dist/kinds/runtime-daemon-endpoint.js.map +1 -0
- package/dist/kinds/runtime-daemon-endpoint.kind.d.ts +144 -0
- package/dist/kinds/runtime-daemon-endpoint.kind.d.ts.map +1 -0
- package/dist/kinds/runtime-daemon-endpoint.kind.js +104 -0
- package/dist/kinds/runtime-daemon-endpoint.kind.js.map +1 -0
- package/dist/launch-preparation.d.ts +12 -0
- package/dist/launch-preparation.d.ts.map +1 -0
- package/dist/launch-preparation.js +42 -0
- package/dist/launch-preparation.js.map +1 -0
- package/dist/logging/pm-daemon.logger.descriptor.d.ts +7 -0
- package/dist/logging/pm-daemon.logger.descriptor.d.ts.map +1 -0
- package/dist/logging/pm-daemon.logger.descriptor.js +16 -0
- package/dist/logging/pm-daemon.logger.descriptor.js.map +1 -0
- package/dist/logging/pm-daemon.output.descriptor.d.ts +9 -0
- package/dist/logging/pm-daemon.output.descriptor.d.ts.map +1 -0
- package/dist/logging/pm-daemon.output.descriptor.js +22 -0
- package/dist/logging/pm-daemon.output.descriptor.js.map +1 -0
- package/dist/manager.d.ts +206 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +682 -0
- package/dist/manager.js.map +1 -0
- package/dist/managers/dependency-resolver.d.ts +85 -0
- package/dist/managers/dependency-resolver.d.ts.map +1 -0
- package/dist/managers/dependency-resolver.js +237 -0
- package/dist/managers/dependency-resolver.js.map +1 -0
- package/dist/managers/preset-executor.d.ts +138 -0
- package/dist/managers/preset-executor.d.ts.map +1 -0
- package/dist/managers/preset-executor.js +763 -0
- package/dist/managers/preset-executor.js.map +1 -0
- package/dist/managers/resource-manager.d.ts +142 -0
- package/dist/managers/resource-manager.d.ts.map +1 -0
- package/dist/managers/resource-manager.js +767 -0
- package/dist/managers/resource-manager.js.map +1 -0
- package/dist/migrations.generated.d.ts +14 -0
- package/dist/migrations.generated.d.ts.map +1 -0
- package/dist/migrations.generated.js +27 -0
- package/dist/migrations.generated.js.map +1 -0
- package/dist/pm.assets.runtime.d.ts +151 -0
- package/dist/pm.assets.runtime.d.ts.map +1 -0
- package/dist/pm.assets.runtime.js +30 -0
- package/dist/pm.assets.runtime.js.map +1 -0
- package/dist/pm.client.descriptor.d.ts +4 -0
- package/dist/pm.client.descriptor.d.ts.map +1 -0
- package/dist/pm.client.descriptor.js +8 -0
- package/dist/pm.client.descriptor.js.map +1 -0
- package/dist/pm.client.impl.consumer.d.ts +9 -0
- package/dist/pm.client.impl.consumer.d.ts.map +1 -0
- package/dist/pm.client.impl.consumer.js +13 -0
- package/dist/pm.client.impl.consumer.js.map +1 -0
- package/dist/pm.cloud.plugin.d.ts +29 -0
- package/dist/pm.cloud.plugin.d.ts.map +1 -0
- package/dist/pm.cloud.plugin.js +57 -0
- package/dist/pm.cloud.plugin.js.map +1 -0
- package/dist/pm.consumer.plugin.d.ts +3 -0
- package/dist/pm.consumer.plugin.d.ts.map +1 -0
- package/dist/pm.consumer.plugin.js +70 -0
- package/dist/pm.consumer.plugin.js.map +1 -0
- package/dist/pm.context.descriptor.d.ts +35 -0
- package/dist/pm.context.descriptor.d.ts.map +1 -0
- package/dist/pm.context.descriptor.js +12 -0
- package/dist/pm.context.descriptor.js.map +1 -0
- package/dist/pm.context.impl.consumer.d.ts +8 -0
- package/dist/pm.context.impl.consumer.d.ts.map +1 -0
- package/dist/pm.context.impl.consumer.js +6 -0
- package/dist/pm.context.impl.consumer.js.map +1 -0
- package/dist/pm.plugin.d.ts +6 -0
- package/dist/pm.plugin.d.ts.map +1 -0
- package/dist/pm.plugin.js +6 -0
- package/dist/pm.plugin.js.map +1 -0
- package/dist/presets/index.d.ts +5 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +5 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/preset/index.d.ts +2 -0
- package/dist/presets/preset/index.d.ts.map +1 -0
- package/dist/presets/preset/index.js +2 -0
- package/dist/presets/preset/index.js.map +1 -0
- package/dist/presets/preset/web-dev.d.ts +39 -0
- package/dist/presets/preset/web-dev.d.ts.map +1 -0
- package/dist/presets/preset/web-dev.js +69 -0
- package/dist/presets/preset/web-dev.js.map +1 -0
- package/dist/presets/process/index.d.ts +3 -0
- package/dist/presets/process/index.d.ts.map +1 -0
- package/dist/presets/process/index.js +3 -0
- package/dist/presets/process/index.js.map +1 -0
- package/dist/presets/process/sveltekit.d.ts +125 -0
- package/dist/presets/process/sveltekit.d.ts.map +1 -0
- package/dist/presets/process/sveltekit.js +52 -0
- package/dist/presets/process/sveltekit.js.map +1 -0
- package/dist/presets/process/web.d.ts +34 -0
- package/dist/presets/process/web.d.ts.map +1 -0
- package/dist/presets/process/web.js +52 -0
- package/dist/presets/process/web.js.map +1 -0
- package/dist/presets/resource/database.d.ts +39 -0
- package/dist/presets/resource/database.d.ts.map +1 -0
- package/dist/presets/resource/database.js +60 -0
- package/dist/presets/resource/database.js.map +1 -0
- package/dist/presets/resource/index.d.ts +2 -0
- package/dist/presets/resource/index.d.ts.map +1 -0
- package/dist/presets/resource/index.js +2 -0
- package/dist/presets/resource/index.js.map +1 -0
- package/dist/presets/types.d.ts +101 -0
- package/dist/presets/types.d.ts.map +1 -0
- package/dist/presets/types.js +53 -0
- package/dist/presets/types.js.map +1 -0
- package/dist/register-migrations.impl.consumer.d.ts +8 -0
- package/dist/register-migrations.impl.consumer.d.ts.map +1 -0
- package/dist/register-migrations.impl.consumer.js +145 -0
- package/dist/register-migrations.impl.consumer.js.map +1 -0
- package/dist/resources/index.d.ts +7 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +7 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/provider.d.ts +216 -0
- package/dist/resources/provider.d.ts.map +1 -0
- package/dist/resources/provider.js +54 -0
- package/dist/resources/provider.js.map +1 -0
- package/dist/resources/providers/builtin.assets.d.ts +8 -0
- package/dist/resources/providers/builtin.assets.d.ts.map +1 -0
- package/dist/resources/providers/builtin.assets.js +26 -0
- package/dist/resources/providers/builtin.assets.js.map +1 -0
- package/dist/resources/providers/index.d.ts +14 -0
- package/dist/resources/providers/index.d.ts.map +1 -0
- package/dist/resources/providers/index.js +14 -0
- package/dist/resources/providers/index.js.map +1 -0
- package/dist/resources/providers/local-mkcert.d.ts +31 -0
- package/dist/resources/providers/local-mkcert.d.ts.map +1 -0
- package/dist/resources/providers/local-mkcert.js +169 -0
- package/dist/resources/providers/local-mkcert.js.map +1 -0
- package/dist/resources/providers/shell-setup.d.ts +17 -0
- package/dist/resources/providers/shell-setup.d.ts.map +1 -0
- package/dist/resources/providers/shell-setup.js +41 -0
- package/dist/resources/providers/shell-setup.js.map +1 -0
- package/dist/resources/providers/tool-env.d.ts +63 -0
- package/dist/resources/providers/tool-env.d.ts.map +1 -0
- package/dist/resources/providers/tool-env.js +99 -0
- package/dist/resources/providers/tool-env.js.map +1 -0
- package/dist/resources/resource-state-summary.d.ts +3 -0
- package/dist/resources/resource-state-summary.d.ts.map +1 -0
- package/dist/resources/resource-state-summary.js +82 -0
- package/dist/resources/resource-state-summary.js.map +1 -0
- package/dist/resources/status-options.d.ts +4 -0
- package/dist/resources/status-options.d.ts.map +1 -0
- package/dist/resources/status-options.js +6 -0
- package/dist/resources/status-options.js.map +1 -0
- package/dist/runnable/executor.d.ts +11 -0
- package/dist/runnable/executor.d.ts.map +1 -0
- package/dist/runnable/executor.js +41 -0
- package/dist/runnable/executor.js.map +1 -0
- package/dist/runnable/plugin.d.ts +3 -0
- package/dist/runnable/plugin.d.ts.map +1 -0
- package/dist/runnable/plugin.js +12 -0
- package/dist/runnable/plugin.js.map +1 -0
- package/dist/runnable/schemas.d.ts +28 -0
- package/dist/runnable/schemas.d.ts.map +1 -0
- package/dist/runnable/schemas.js +10 -0
- package/dist/runnable/schemas.js.map +1 -0
- package/dist/runtime-daemon-supervisor.descriptor.d.ts +16 -0
- package/dist/runtime-daemon-supervisor.descriptor.d.ts.map +1 -0
- package/dist/runtime-daemon-supervisor.descriptor.js +17 -0
- package/dist/runtime-daemon-supervisor.descriptor.js.map +1 -0
- package/dist/runtime-daemon-supervisor.impl.consumer.d.ts +22 -0
- package/dist/runtime-daemon-supervisor.impl.consumer.d.ts.map +1 -0
- package/dist/runtime-daemon-supervisor.impl.consumer.js +66 -0
- package/dist/runtime-daemon-supervisor.impl.consumer.js.map +1 -0
- package/dist/schemas/action-error.d.ts +8 -0
- package/dist/schemas/action-error.d.ts.map +1 -0
- package/dist/schemas/action-error.js +8 -0
- package/dist/schemas/action-error.js.map +1 -0
- package/dist/schemas/admission.d.ts +36 -0
- package/dist/schemas/admission.d.ts.map +1 -0
- package/dist/schemas/admission.js +22 -0
- package/dist/schemas/admission.js.map +1 -0
- package/dist/schemas/builder.d.ts +402 -0
- package/dist/schemas/builder.d.ts.map +1 -0
- package/dist/schemas/builder.js +410 -0
- package/dist/schemas/builder.js.map +1 -0
- package/dist/schemas/client.d.ts +18 -0
- package/dist/schemas/client.d.ts.map +1 -0
- package/dist/schemas/client.js +2 -0
- package/dist/schemas/client.js.map +1 -0
- package/dist/schemas/commands.d.ts +315 -0
- package/dist/schemas/commands.d.ts.map +1 -0
- package/dist/schemas/commands.js +268 -0
- package/dist/schemas/commands.js.map +1 -0
- package/dist/schemas/common.d.ts +35 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +43 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/daemon-command.d.ts +61 -0
- package/dist/schemas/daemon-command.d.ts.map +1 -0
- package/dist/schemas/daemon-command.js +2 -0
- package/dist/schemas/daemon-command.js.map +1 -0
- package/dist/schemas/daemon-host.d.ts +70 -0
- package/dist/schemas/daemon-host.d.ts.map +1 -0
- package/dist/schemas/daemon-host.js +2 -0
- package/dist/schemas/daemon-host.js.map +1 -0
- package/dist/schemas/daemon-launch.d.ts +43 -0
- package/dist/schemas/daemon-launch.d.ts.map +1 -0
- package/dist/schemas/daemon-launch.js +3 -0
- package/dist/schemas/daemon-launch.js.map +1 -0
- package/dist/schemas/daemon.d.ts +98 -0
- package/dist/schemas/daemon.d.ts.map +1 -0
- package/dist/schemas/daemon.js +88 -0
- package/dist/schemas/daemon.js.map +1 -0
- package/dist/schemas/dev.d.ts +169 -0
- package/dist/schemas/dev.d.ts.map +1 -0
- package/dist/schemas/dev.js +8 -0
- package/dist/schemas/dev.js.map +1 -0
- package/dist/schemas/executable-freshness.d.ts +88 -0
- package/dist/schemas/executable-freshness.d.ts.map +1 -0
- package/dist/schemas/executable-freshness.js +2 -0
- package/dist/schemas/executable-freshness.js.map +1 -0
- package/dist/schemas/forward-config.d.ts +11 -0
- package/dist/schemas/forward-config.d.ts.map +1 -0
- package/dist/schemas/forward-config.js +15 -0
- package/dist/schemas/forward-config.js.map +1 -0
- package/dist/schemas/graph.d.ts +444 -0
- package/dist/schemas/graph.d.ts.map +1 -0
- package/dist/schemas/graph.js +59 -0
- package/dist/schemas/graph.js.map +1 -0
- package/dist/schemas/health.d.ts +43 -0
- package/dist/schemas/health.d.ts.map +1 -0
- package/dist/schemas/health.js +6 -0
- package/dist/schemas/health.js.map +1 -0
- package/dist/schemas/launch-preparation.d.ts +106 -0
- package/dist/schemas/launch-preparation.d.ts.map +1 -0
- package/dist/schemas/launch-preparation.js +50 -0
- package/dist/schemas/launch-preparation.js.map +1 -0
- package/dist/schemas/liveness-profile.d.ts +108 -0
- package/dist/schemas/liveness-profile.d.ts.map +1 -0
- package/dist/schemas/liveness-profile.js +33 -0
- package/dist/schemas/liveness-profile.js.map +1 -0
- package/dist/schemas/liveness.d.ts +37 -0
- package/dist/schemas/liveness.d.ts.map +1 -0
- package/dist/schemas/liveness.js +41 -0
- package/dist/schemas/liveness.js.map +1 -0
- package/dist/schemas/manager.d.ts +46 -0
- package/dist/schemas/manager.d.ts.map +1 -0
- package/dist/schemas/manager.js +5 -0
- package/dist/schemas/manager.js.map +1 -0
- package/dist/schemas/port-forward.d.ts +47 -0
- package/dist/schemas/port-forward.d.ts.map +1 -0
- package/dist/schemas/port-forward.js +27 -0
- package/dist/schemas/port-forward.js.map +1 -0
- package/dist/schemas/process-source.d.ts +354 -0
- package/dist/schemas/process-source.d.ts.map +1 -0
- package/dist/schemas/process-source.js +19 -0
- package/dist/schemas/process-source.js.map +1 -0
- package/dist/schemas/process-tree.d.ts +12 -0
- package/dist/schemas/process-tree.d.ts.map +1 -0
- package/dist/schemas/process-tree.js +2 -0
- package/dist/schemas/process-tree.js.map +1 -0
- package/dist/schemas/process.d.ts +944 -0
- package/dist/schemas/process.d.ts.map +1 -0
- package/dist/schemas/process.js +429 -0
- package/dist/schemas/process.js.map +1 -0
- package/dist/schemas/resource.d.ts +223 -0
- package/dist/schemas/resource.d.ts.map +1 -0
- package/dist/schemas/resource.js +92 -0
- package/dist/schemas/resource.js.map +1 -0
- package/dist/schemas/store.d.ts +97 -0
- package/dist/schemas/store.d.ts.map +1 -0
- package/dist/schemas/store.js +2 -0
- package/dist/schemas/store.js.map +1 -0
- package/dist/schemas/task-supervision.d.ts +16 -0
- package/dist/schemas/task-supervision.d.ts.map +1 -0
- package/dist/schemas/task-supervision.js +10 -0
- package/dist/schemas/task-supervision.js.map +1 -0
- package/dist/schemas/tui-state.d.ts +777 -0
- package/dist/schemas/tui-state.d.ts.map +1 -0
- package/dist/schemas/tui-state.js +119 -0
- package/dist/schemas/tui-state.js.map +1 -0
- package/dist/schemas/worker-manager.d.ts +19 -0
- package/dist/schemas/worker-manager.d.ts.map +1 -0
- package/dist/schemas/worker-manager.js +2 -0
- package/dist/schemas/worker-manager.js.map +1 -0
- package/dist/services/cleanup.d.ts +78 -0
- package/dist/services/cleanup.d.ts.map +1 -0
- package/dist/services/cleanup.js +329 -0
- package/dist/services/cleanup.js.map +1 -0
- package/dist/services/health.d.ts +81 -0
- package/dist/services/health.d.ts.map +1 -0
- package/dist/services/health.js +435 -0
- package/dist/services/health.js.map +1 -0
- package/dist/services/index.d.ts +11 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +10 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/lifecycle.d.ts +238 -0
- package/dist/services/lifecycle.d.ts.map +1 -0
- package/dist/services/lifecycle.js +1391 -0
- package/dist/services/lifecycle.js.map +1 -0
- package/dist/services/liveness-state.d.ts +95 -0
- package/dist/services/liveness-state.d.ts.map +1 -0
- package/dist/services/liveness-state.js +239 -0
- package/dist/services/liveness-state.js.map +1 -0
- package/dist/services/orphans.d.ts +72 -0
- package/dist/services/orphans.d.ts.map +1 -0
- package/dist/services/orphans.js +185 -0
- package/dist/services/orphans.js.map +1 -0
- package/dist/services/process-command.d.ts +25 -0
- package/dist/services/process-command.d.ts.map +1 -0
- package/dist/services/process-command.js +36 -0
- package/dist/services/process-command.js.map +1 -0
- package/dist/services/process-log-archive.d.ts +62 -0
- package/dist/services/process-log-archive.d.ts.map +1 -0
- package/dist/services/process-log-archive.js +150 -0
- package/dist/services/process-log-archive.js.map +1 -0
- package/dist/services/run-log-frames.d.ts +26 -0
- package/dist/services/run-log-frames.d.ts.map +1 -0
- package/dist/services/run-log-frames.js +45 -0
- package/dist/services/run-log-frames.js.map +1 -0
- package/dist/services/startup-warmup.d.ts +23 -0
- package/dist/services/startup-warmup.d.ts.map +1 -0
- package/dist/services/startup-warmup.js +21 -0
- package/dist/services/startup-warmup.js.map +1 -0
- package/dist/services/state-wait.d.ts +28 -0
- package/dist/services/state-wait.d.ts.map +1 -0
- package/dist/services/state-wait.js +57 -0
- package/dist/services/state-wait.js.map +1 -0
- package/dist/services/supervision-policy.d.ts +40 -0
- package/dist/services/supervision-policy.d.ts.map +1 -0
- package/dist/services/supervision-policy.js +48 -0
- package/dist/services/supervision-policy.js.map +1 -0
- package/dist/services/task-supervision.d.ts +14 -0
- package/dist/services/task-supervision.d.ts.map +1 -0
- package/dist/services/task-supervision.js +112 -0
- package/dist/services/task-supervision.js.map +1 -0
- package/dist/services/types/index.d.ts +74 -0
- package/dist/services/types/index.d.ts.map +1 -0
- package/dist/services/types/index.js +11 -0
- package/dist/services/types/index.js.map +1 -0
- package/dist/services/workers.d.ts +75 -0
- package/dist/services/workers.d.ts.map +1 -0
- package/dist/services/workers.js +212 -0
- package/dist/services/workers.js.map +1 -0
- package/dist/storage/workspaces.descriptor.d.ts +12 -0
- package/dist/storage/workspaces.descriptor.d.ts.map +1 -0
- package/dist/storage/workspaces.descriptor.js +33 -0
- package/dist/storage/workspaces.descriptor.js.map +1 -0
- package/dist/store/process-admission.d.ts +11 -0
- package/dist/store/process-admission.d.ts.map +1 -0
- package/dist/store/process-admission.js +46 -0
- package/dist/store/process-admission.js.map +1 -0
- package/dist/store/process-config.impl.consumer.d.ts +22 -0
- package/dist/store/process-config.impl.consumer.d.ts.map +1 -0
- package/dist/store/process-config.impl.consumer.js +84 -0
- package/dist/store/process-config.impl.consumer.js.map +1 -0
- package/dist/store/process-state.impl.consumer.d.ts +25 -0
- package/dist/store/process-state.impl.consumer.d.ts.map +1 -0
- package/dist/store/process-state.impl.consumer.js +140 -0
- package/dist/store/process-state.impl.consumer.js.map +1 -0
- package/dist/store/resource-state.impl.consumer.d.ts +9 -0
- package/dist/store/resource-state.impl.consumer.d.ts.map +1 -0
- package/dist/store/resource-state.impl.consumer.js +48 -0
- package/dist/store/resource-state.impl.consumer.js.map +1 -0
- package/dist/store.impl.consumer.d.ts +121 -0
- package/dist/store.impl.consumer.d.ts.map +1 -0
- package/dist/store.impl.consumer.js +436 -0
- package/dist/store.impl.consumer.js.map +1 -0
- package/dist/surface.d.ts +93 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +153 -0
- package/dist/surface.js.map +1 -0
- package/dist/svelte/components/PMOverview.svelte +527 -0
- package/dist/svelte/components/PMOverview.svelte.d.ts +12 -0
- package/dist/svelte/components/PMOverview.svelte.d.ts.map +1 -0
- package/dist/svelte/index.d.ts +4 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +2 -0
- package/dist/svelte/runtime.d.ts +33 -0
- package/dist/svelte/runtime.d.ts.map +1 -0
- package/dist/svelte/runtime.js +148 -0
- package/dist/svelte/styles.css +2 -0
- package/dist/tasks/completion.d.ts +6 -0
- package/dist/tasks/completion.d.ts.map +1 -0
- package/dist/tasks/completion.js +105 -0
- package/dist/tasks/completion.js.map +1 -0
- package/dist/tasks/index.d.ts +11 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +11 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/launch.d.ts +196 -0
- package/dist/tasks/launch.d.ts.map +1 -0
- package/dist/tasks/launch.js +10 -0
- package/dist/tasks/launch.js.map +1 -0
- package/dist/tasks/run-task.d.ts +11 -0
- package/dist/tasks/run-task.d.ts.map +1 -0
- package/dist/tasks/run-task.js +144 -0
- package/dist/tasks/run-task.js.map +1 -0
- package/dist/tasks/schemas.d.ts +83 -0
- package/dist/tasks/schemas.d.ts.map +1 -0
- package/dist/tasks/schemas.js +67 -0
- package/dist/tasks/schemas.js.map +1 -0
- package/dist/testing/daemon.d.ts +64 -0
- package/dist/testing/daemon.d.ts.map +1 -0
- package/dist/testing/daemon.js +125 -0
- package/dist/testing/daemon.js.map +1 -0
- package/dist/tui/components/DaemonHealthCard.d.ts +22 -0
- package/dist/tui/components/DaemonHealthCard.d.ts.map +1 -0
- package/dist/tui/components/DaemonHealthCard.js +30 -0
- package/dist/tui/components/DaemonHealthCard.js.map +1 -0
- package/dist/tui/components/ErrorDetailsPanel.d.ts +16 -0
- package/dist/tui/components/ErrorDetailsPanel.d.ts.map +1 -0
- package/dist/tui/components/ErrorDetailsPanel.js +22 -0
- package/dist/tui/components/ErrorDetailsPanel.js.map +1 -0
- package/dist/tui/components/FilterBar.d.ts +21 -0
- package/dist/tui/components/FilterBar.d.ts.map +1 -0
- package/dist/tui/components/FilterBar.js +31 -0
- package/dist/tui/components/FilterBar.js.map +1 -0
- package/dist/tui/components/StatsBar.d.ts +17 -0
- package/dist/tui/components/StatsBar.d.ts.map +1 -0
- package/dist/tui/components/StatsBar.js +28 -0
- package/dist/tui/components/StatsBar.js.map +1 -0
- package/dist/tui/components/index.d.ts +5 -0
- package/dist/tui/components/index.d.ts.map +1 -0
- package/dist/tui/components/index.js +5 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/index.d.ts +7 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +7 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/pm-dashboard.descriptor.d.ts +11 -0
- package/dist/tui/pm-dashboard.descriptor.d.ts.map +1 -0
- package/dist/tui/pm-dashboard.descriptor.js +26 -0
- package/dist/tui/pm-dashboard.descriptor.js.map +1 -0
- package/dist/tui/pm-dashboard.impl.consumer.d.ts +19 -0
- package/dist/tui/pm-dashboard.impl.consumer.d.ts.map +1 -0
- package/dist/tui/pm-dashboard.impl.consumer.js +839 -0
- package/dist/tui/pm-dashboard.impl.consumer.js.map +1 -0
- package/dist/tui/pm-open.descriptor.d.ts +10 -0
- package/dist/tui/pm-open.descriptor.d.ts.map +1 -0
- package/dist/tui/pm-open.descriptor.js +21 -0
- package/dist/tui/pm-open.descriptor.js.map +1 -0
- package/dist/tui/pm-open.impl.consumer.d.ts +9 -0
- package/dist/tui/pm-open.impl.consumer.d.ts.map +1 -0
- package/dist/tui/pm-open.impl.consumer.js +13 -0
- package/dist/tui/pm-open.impl.consumer.js.map +1 -0
- package/dist/tui/pm-processes.descriptor.d.ts +12 -0
- package/dist/tui/pm-processes.descriptor.d.ts.map +1 -0
- package/dist/tui/pm-processes.descriptor.js +30 -0
- package/dist/tui/pm-processes.descriptor.js.map +1 -0
- package/dist/tui/pm-processes.impl.consumer.d.ts +14 -0
- package/dist/tui/pm-processes.impl.consumer.d.ts.map +1 -0
- package/dist/tui/pm-processes.impl.consumer.js +214 -0
- package/dist/tui/pm-processes.impl.consumer.js.map +1 -0
- package/dist/tui/pm-state-keys.d.ts +316 -0
- package/dist/tui/pm-state-keys.d.ts.map +1 -0
- package/dist/tui/pm-state-keys.js +10 -0
- package/dist/tui/pm-state-keys.js.map +1 -0
- package/dist/tui/pm-status.descriptor.d.ts +11 -0
- package/dist/tui/pm-status.descriptor.d.ts.map +1 -0
- package/dist/tui/pm-status.descriptor.js +29 -0
- package/dist/tui/pm-status.descriptor.js.map +1 -0
- package/dist/tui/pm-status.impl.consumer.d.ts +11 -0
- package/dist/tui/pm-status.impl.consumer.d.ts.map +1 -0
- package/dist/tui/pm-status.impl.consumer.js +75 -0
- package/dist/tui/pm-status.impl.consumer.js.map +1 -0
- package/dist/tui/pm-tui.plugin.d.ts +13 -0
- package/dist/tui/pm-tui.plugin.d.ts.map +1 -0
- package/dist/tui/pm-tui.plugin.js +34 -0
- package/dist/tui/pm-tui.plugin.js.map +1 -0
- package/dist/utils/attempt.d.ts +31 -0
- package/dist/utils/attempt.d.ts.map +1 -0
- package/dist/utils/attempt.js +43 -0
- package/dist/utils/attempt.js.map +1 -0
- package/dist/utils/bounded-wait.d.ts +31 -0
- package/dist/utils/bounded-wait.d.ts.map +1 -0
- package/dist/utils/bounded-wait.js +35 -0
- package/dist/utils/bounded-wait.js.map +1 -0
- package/dist/utils/command-exists.d.ts +5 -0
- package/dist/utils/command-exists.d.ts.map +1 -0
- package/dist/utils/command-exists.js +8 -0
- package/dist/utils/command-exists.js.map +1 -0
- package/dist/utils/daemon-launch-lock.d.ts +143 -0
- package/dist/utils/daemon-launch-lock.d.ts.map +1 -0
- package/dist/utils/daemon-launch-lock.js +420 -0
- package/dist/utils/daemon-launch-lock.js.map +1 -0
- package/dist/utils/daemon-launch-recovery.d.ts +82 -0
- package/dist/utils/daemon-launch-recovery.d.ts.map +1 -0
- package/dist/utils/daemon-launch-recovery.js +173 -0
- package/dist/utils/daemon-launch-recovery.js.map +1 -0
- package/dist/utils/daemon-log-follower.d.ts +41 -0
- package/dist/utils/daemon-log-follower.d.ts.map +1 -0
- package/dist/utils/daemon-log-follower.js +124 -0
- package/dist/utils/daemon-log-follower.js.map +1 -0
- package/dist/utils/daemon-pid.d.ts +42 -0
- package/dist/utils/daemon-pid.d.ts.map +1 -0
- package/dist/utils/daemon-pid.js +80 -0
- package/dist/utils/daemon-pid.js.map +1 -0
- package/dist/utils/daemon-reachability.d.ts +87 -0
- package/dist/utils/daemon-reachability.d.ts.map +1 -0
- package/dist/utils/daemon-reachability.js +131 -0
- package/dist/utils/daemon-reachability.js.map +1 -0
- package/dist/utils/daemon-stdio-timestamps.d.ts +24 -0
- package/dist/utils/daemon-stdio-timestamps.d.ts.map +1 -0
- package/dist/utils/daemon-stdio-timestamps.js +59 -0
- package/dist/utils/daemon-stdio-timestamps.js.map +1 -0
- package/dist/utils/daemon-stop.d.ts +66 -0
- package/dist/utils/daemon-stop.d.ts.map +1 -0
- package/dist/utils/daemon-stop.js +100 -0
- package/dist/utils/daemon-stop.js.map +1 -0
- package/dist/utils/errno-failure.d.ts +16 -0
- package/dist/utils/errno-failure.d.ts.map +1 -0
- package/dist/utils/errno-failure.js +15 -0
- package/dist/utils/errno-failure.js.map +1 -0
- package/dist/utils/exec.d.ts +27 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +36 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/liveness.d.ts +100 -0
- package/dist/utils/liveness.d.ts.map +1 -0
- package/dist/utils/liveness.js +225 -0
- package/dist/utils/liveness.js.map +1 -0
- package/dist/utils/logging.d.ts +60 -0
- package/dist/utils/logging.d.ts.map +1 -0
- package/dist/utils/logging.js +169 -0
- package/dist/utils/logging.js.map +1 -0
- package/dist/utils/path-under.d.ts +15 -0
- package/dist/utils/path-under.d.ts.map +1 -0
- package/dist/utils/path-under.js +16 -0
- package/dist/utils/path-under.js.map +1 -0
- package/dist/utils/port-ownership.d.ts +160 -0
- package/dist/utils/port-ownership.d.ts.map +1 -0
- package/dist/utils/port-ownership.js +176 -0
- package/dist/utils/port-ownership.js.map +1 -0
- package/dist/utils/ports.d.ts +43 -0
- package/dist/utils/ports.d.ts.map +1 -0
- package/dist/utils/ports.js +200 -0
- package/dist/utils/ports.js.map +1 -0
- package/dist/utils/process-tree.d.ts +33 -0
- package/dist/utils/process-tree.d.ts.map +1 -0
- package/dist/utils/process-tree.js +197 -0
- package/dist/utils/process-tree.js.map +1 -0
- package/dist/utils/semaphore.d.ts +16 -0
- package/dist/utils/semaphore.d.ts.map +1 -0
- package/dist/utils/semaphore.js +30 -0
- package/dist/utils/semaphore.js.map +1 -0
- package/dist/utils/socket-inode.impl.consumer.d.ts +26 -0
- package/dist/utils/socket-inode.impl.consumer.d.ts.map +1 -0
- package/dist/utils/socket-inode.impl.consumer.js +30 -0
- package/dist/utils/socket-inode.impl.consumer.js.map +1 -0
- package/dist/utils/socket-paths.d.ts +121 -0
- package/dist/utils/socket-paths.d.ts.map +1 -0
- package/dist/utils/socket-paths.js +167 -0
- package/dist/utils/socket-paths.js.map +1 -0
- package/dist/utils/socket.d.ts +65 -0
- package/dist/utils/socket.d.ts.map +1 -0
- package/dist/utils/socket.js +87 -0
- package/dist/utils/socket.js.map +1 -0
- package/dist/utils/version.d.ts +40 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +65 -0
- package/dist/utils/version.js.map +1 -0
- package/dist/utils/vibes-home.d.ts +34 -0
- package/dist/utils/vibes-home.d.ts.map +1 -0
- package/dist/utils/vibes-home.js +27 -0
- package/dist/utils/vibes-home.js.map +1 -0
- package/dist/workspace-runtime.d.ts +38 -0
- package/dist/workspace-runtime.d.ts.map +1 -0
- package/dist/workspace-runtime.js +176 -0
- package/dist/workspace-runtime.js.map +1 -0
- package/package.json +465 -4
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,1654 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PM Daemon
|
|
3
|
+
* Long-lived process that manages all child processes via Unix socket IPC.
|
|
4
|
+
*
|
|
5
|
+
* Transport: the daemon is served by `runtime-rpc-unix` (three-verb protocol:
|
|
6
|
+
* invoke / release / stream). The legacy HTTP-over-unix `pm-command` wire is
|
|
7
|
+
* gone. Each pm-command maps to a method on the RPC root returned by
|
|
8
|
+
* `createPMRpcRoot()`; the PM client calls them via `connectUnix` + `wireConsumer`.
|
|
9
|
+
*/
|
|
10
|
+
import * as z from 'zod/v4';
|
|
11
|
+
import { resolveFileSystemAdapter } from '@vibesdotdev/filesystem/client/resolve-adapter';
|
|
12
|
+
import { chmodChecked } from '@vibesdotdev/filesystem/core';
|
|
13
|
+
import { getRuntimeSocketService } from '@vibesdotdev/kernel/socket';
|
|
14
|
+
import { ProcessManager } from "./manager.js";
|
|
15
|
+
import { PmTaskScopeSchema, processExitOf } from "./schemas/process.js";
|
|
16
|
+
import { getPMDaemonLogger, getPMDaemonStderrLogPath, getPMDaemonStdoutLogPath, PM_CAPTURE_ROTATION_POLICY, readPMDaemonLogTail } from "./utils/logging.js";
|
|
17
|
+
import { isManagedProcessId } from "./helpers/managed-process-id.js";
|
|
18
|
+
import { createProcessRunArchiver } from "./services/process-log-archive.js";
|
|
19
|
+
import { MIN_ACCEPTABLE_NOFILE, RECOMMENDED_NOFILE, fileDescriptorLimitRemediation, readFileDescriptorLimit } from "./helpers/rlimits.js";
|
|
20
|
+
import { ResourceManager } from "./managers/resource-manager.js";
|
|
21
|
+
import { PresetExecutor } from "./managers/preset-executor.js";
|
|
22
|
+
import { ResourceProviderRegistry } from "./resources/index.js";
|
|
23
|
+
import { ProcessStore } from "./store.impl.consumer.js";
|
|
24
|
+
import { getPMSocketPath, getSocketBasePath } from "./utils/socket-paths.js";
|
|
25
|
+
import { getPathRoots, getRuntimePath } from '@vibesdotdev/paths';
|
|
26
|
+
import { checkProcessLiveness } from "./utils/liveness.js";
|
|
27
|
+
import { isProcessRunning } from "./utils/process-tree.js";
|
|
28
|
+
import { removeSocket } from "./utils/socket.js";
|
|
29
|
+
import { getVibesDir } from "./utils/vibes-home.js";
|
|
30
|
+
import { ConfigWatcher } from "./daemon/config-watcher.js";
|
|
31
|
+
import { OrphanScanner } from "./daemon/orphan-scanner.js";
|
|
32
|
+
import { HealthMonitor } from "./daemon/health-monitor.js";
|
|
33
|
+
import { ExecutableFreshnessReconciler } from "./daemon/executable-freshness-reconciler.js";
|
|
34
|
+
import { LivenessChecker } from "./daemon/liveness-checker.js";
|
|
35
|
+
import { LivenessProfiles } from "./services/liveness-state.js";
|
|
36
|
+
import { FleetAttachState } from "./daemon/fleet-attach-state.js";
|
|
37
|
+
import { mayRestart, readSupervision, restartDelayMs } from "./services/supervision-policy.js";
|
|
38
|
+
import { CapabilityError, CaughtFailureSchema, DefaultInvokePipeline, getRuntimeHostSignals, getRuntimeHostIdentity, isCapabilityError, valueFreeFailure } from '@vibesdotdev/kernel';
|
|
39
|
+
import { pmRpcResult } from "./daemon/rpc-result.js";
|
|
40
|
+
import { attempt, attemptSync, failureText } from "./utils/attempt.js";
|
|
41
|
+
import { hasErrnoCode } from "./utils/errno-failure.js";
|
|
42
|
+
import { listenUnix } from '@vibesdotdev/kernel-rpc/unix';
|
|
43
|
+
import { ResourceHealthMonitor } from "./daemon/resource-health-monitor.js";
|
|
44
|
+
import { CommandDispatcher } from "./daemon/command-handler.js";
|
|
45
|
+
import { readPMRole } from "./daemon/role.js";
|
|
46
|
+
import { createPMDaemonModuleContext } from "./daemon/daemon-module-context.js";
|
|
47
|
+
import { startRuntimeHostHotReload } from "./kinds/runtime-daemon-endpoint.js";
|
|
48
|
+
import { PM_COMMAND_IDS } from "./daemon/command-ids.js";
|
|
49
|
+
import { admittedWorkspaceIdentity } from "./admission.js";
|
|
50
|
+
// The PID file has ONE owner (`./utils/daemon-pid.ts`), so a surface that needs
|
|
51
|
+
// only the daemon's pid — `vibes update`'s roll census — can read it without
|
|
52
|
+
// importing this module's process manager, RPC transport and resource registry.
|
|
53
|
+
import { getDaemonPidPath, readDaemonPid } from "./utils/daemon-pid.js";
|
|
54
|
+
import { readRotationMaxAge, readRotationPolicy, rotateAppendedFile } from '@vibesdotdev/logging';
|
|
55
|
+
import { canConnectToPMSocket } from "./utils/daemon-reachability.js";
|
|
56
|
+
export { getDaemonPidPath, readDaemonPid } from "./utils/daemon-pid.js";
|
|
57
|
+
export { isDaemonReachable, isDaemonRunning, probeDaemon } from "./utils/daemon-reachability.js";
|
|
58
|
+
/**
|
|
59
|
+
* Statuses that record a finished run rather than assert a live process.
|
|
60
|
+
* Boot reconcile must leave these alone — see `reconcileState`.
|
|
61
|
+
*/
|
|
62
|
+
const TERMINAL_STATUSES = new Set([
|
|
63
|
+
'pass',
|
|
64
|
+
'fail',
|
|
65
|
+
'completed'
|
|
66
|
+
]);
|
|
67
|
+
async function rotateEach(runtime, entries, policy) {
|
|
68
|
+
const result = { rotated: [], failed: [] };
|
|
69
|
+
for (const { processId, path } of entries) {
|
|
70
|
+
const rotation = await attempt(() => rotateAppendedFile(runtime, path, policy));
|
|
71
|
+
if (!rotation.ok) {
|
|
72
|
+
result.failed.push({ processId, path, error: rotation.failure });
|
|
73
|
+
}
|
|
74
|
+
else if (rotation.value.rotated) {
|
|
75
|
+
result.rotated.push({ processId, path, previousSize: rotation.value.previousSize ?? 0 });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Process log rotation for LIVE writers: every running child's
|
|
82
|
+
* `<id>.stdout` / `<id>.stderr` and the daemon's own stdio logs, by the
|
|
83
|
+
* logging owner's `rotateAppendedFile` (copy+truncate, because each writer
|
|
84
|
+
* holds an O_APPEND fd) under the declared `pm.process-capture` policy.
|
|
85
|
+
* Start-time rotation uses the same call and policy, so the two can never
|
|
86
|
+
* drift apart on threshold or generation count (L1).
|
|
87
|
+
*/
|
|
88
|
+
export async function rotateOversizedProcessLogs(options) {
|
|
89
|
+
const runtimePath = await getRuntimePath(options.runtime);
|
|
90
|
+
const entries = [];
|
|
91
|
+
for (const processId of options.processIds) {
|
|
92
|
+
for (const stream of ['stdout', 'stderr']) {
|
|
93
|
+
entries.push({ processId, path: runtimePath.join(options.logDir, `${processId}.${stream}`) });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return rotateEach(options.runtime, entries, options.policy);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The daemon's own stdio logs, rotated in steady state (pm.md D17): the
|
|
100
|
+
* paths `getPMDaemon{Stdout,Stderr}LogPath` name under the daemon's roots,
|
|
101
|
+
* never its process log dir (which never held them). `pm-daemon.log` is the
|
|
102
|
+
* `pm-daemon` logging output and is rotated by its owner, not here.
|
|
103
|
+
*/
|
|
104
|
+
export async function rotateOversizedDaemonLogs(options) {
|
|
105
|
+
const pathOptions = { roots: options.roots, runtimePath: await getRuntimePath(options.runtime) };
|
|
106
|
+
return rotateEach(options.runtime, [
|
|
107
|
+
{ processId: 'pm-daemon', path: getPMDaemonStdoutLogPath(options.workspace, pathOptions) },
|
|
108
|
+
{ processId: 'pm-daemon', path: getPMDaemonStderrLogPath(options.workspace, pathOptions) }
|
|
109
|
+
], options.policy);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The version of THIS loaded module's package (its `package.json` beside
|
|
113
|
+
* the module's own directory), read once on first use. Genuinely module-scoped: it is
|
|
114
|
+
* an immutable fact of the module instance, identical for every runtime that
|
|
115
|
+
* loaded it, and a hot-reload generation loads a new module instance with its
|
|
116
|
+
* own. A later rewrite of the file on disk does not change the code running
|
|
117
|
+
* here, so the first read stays the true answer.
|
|
118
|
+
*/
|
|
119
|
+
let cachedVersion;
|
|
120
|
+
const FileTextSchema = z.string();
|
|
121
|
+
/** A file's content, or null when it does not exist (ENOENT); any other read failure propagates. */
|
|
122
|
+
async function readIfPresent(files, path) {
|
|
123
|
+
const read = await attempt(async () => FileTextSchema.parse(await files.readFile(path, 'utf-8')));
|
|
124
|
+
if (read.ok)
|
|
125
|
+
return read.value;
|
|
126
|
+
if (hasErrnoCode(read.failure) && read.failure.code === 'ENOENT')
|
|
127
|
+
return null;
|
|
128
|
+
throw read.failure;
|
|
129
|
+
}
|
|
130
|
+
/** The package manifest fields PM reads: its version. */
|
|
131
|
+
const PackageVersionSchema = z.object({ version: z.string().optional() });
|
|
132
|
+
async function getPMVersion(runtime) {
|
|
133
|
+
if (cachedVersion)
|
|
134
|
+
return cachedVersion;
|
|
135
|
+
// A compiled host carries no package.json beside the module (ENOENT): its
|
|
136
|
+
// version is reported as 0.0.0. Any other read or parse failure propagates.
|
|
137
|
+
const runtimePath = await getRuntimePath(runtime);
|
|
138
|
+
const packageJsonPath = runtimePath.fileURLToPath(new URL('../package.json', import.meta.url));
|
|
139
|
+
const content = await readIfPresent(await resolveFileSystemAdapter(runtime, { binding: false }), packageJsonPath);
|
|
140
|
+
if (content === null) {
|
|
141
|
+
cachedVersion = '0.0.0';
|
|
142
|
+
return cachedVersion;
|
|
143
|
+
}
|
|
144
|
+
cachedVersion = PackageVersionSchema.parse(JSON.parse(content)).version ?? '0.0.0';
|
|
145
|
+
return cachedVersion;
|
|
146
|
+
}
|
|
147
|
+
const RpcMethodNameSchema = z.string();
|
|
148
|
+
/**
|
|
149
|
+
* One connection's PM RPC root. Each command carries the connection's close
|
|
150
|
+
* signal, so an observation command (`await-exit`) whose caller left ends
|
|
151
|
+
* instead of waiting on (runtime-rpc rule 19).
|
|
152
|
+
*/
|
|
153
|
+
function createPMRpcRoot(dispatcher, connection) {
|
|
154
|
+
const target = {};
|
|
155
|
+
// A dynamic Proxy that catches any method name and routes it through the
|
|
156
|
+
// CommandDispatcher — we don't enumerate the 40+ commands here; the registry
|
|
157
|
+
// owns the method set.
|
|
158
|
+
return new Proxy(target, {
|
|
159
|
+
get(_target, prop) {
|
|
160
|
+
return async (params) => {
|
|
161
|
+
return pmRpcResult(async () => {
|
|
162
|
+
const result = await dispatcher.handleCommand({
|
|
163
|
+
type: 'pm-command',
|
|
164
|
+
command: prop,
|
|
165
|
+
...params
|
|
166
|
+
}, { signal: connection.signal });
|
|
167
|
+
return { success: true, ...result };
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
has(_target, prop) {
|
|
172
|
+
// Report all string properties as present so the socket listener doesn't
|
|
173
|
+
// throw "root has no method" for any registered command.
|
|
174
|
+
return RpcMethodNameSchema.safeParse(prop).success;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The PM daemon runs only on its own serve host: the host the CLI booted for
|
|
180
|
+
* `pm daemon serve`, which declared `qualifiers.serve = 'pm.daemon.serve'` and
|
|
181
|
+
* so answers `pm/role = 'daemon'`. That declaration is the recursion guard
|
|
182
|
+
* (D13): every in-process PM client of the host has `autoStartDaemon: false`,
|
|
183
|
+
* so nothing the daemon serves can launch another daemon. A host without it
|
|
184
|
+
* would hand the daemon's own commands clients that auto-start a daemon, so
|
|
185
|
+
* it is refused before the daemon touches anything.
|
|
186
|
+
*/
|
|
187
|
+
export async function assertPMDaemonServeHost(runtime) {
|
|
188
|
+
if ((await readPMRole(runtime)) === 'daemon')
|
|
189
|
+
return;
|
|
190
|
+
throw new CapabilityError("The PM daemon runs only on the host booted for 'pm daemon serve' " +
|
|
191
|
+
"(qualifiers.serve 'pm.daemon.serve'); this host's PM clients could auto-start a daemon.", 'INVALID_INPUT', {
|
|
192
|
+
reason: 'pm-daemon-host-undeclared',
|
|
193
|
+
recoveryHint: "Start it with 'vibes pm daemon start' or 'vibes pm daemon serve'."
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/** How long a managed child gets to exit on SIGTERM when the daemon stops, before SIGKILL. */
|
|
197
|
+
const MANAGED_STOP_GRACE_MS = 3000;
|
|
198
|
+
export class PMDaemon {
|
|
199
|
+
pm;
|
|
200
|
+
rm;
|
|
201
|
+
executor;
|
|
202
|
+
store;
|
|
203
|
+
liveness;
|
|
204
|
+
/** This daemon's attached fleet receivers (never a module singleton). */
|
|
205
|
+
fleet = new FleetAttachState();
|
|
206
|
+
rpcListener;
|
|
207
|
+
socketPath;
|
|
208
|
+
runtimePath;
|
|
209
|
+
/** The serve host runtime; replaced by hot reload's stable dispatch handle once armed. */
|
|
210
|
+
runtime;
|
|
211
|
+
/** `getPathRoots(runtime)` of the serve host, captured at construction. */
|
|
212
|
+
roots;
|
|
213
|
+
pidFile;
|
|
214
|
+
cleanupTimer;
|
|
215
|
+
healthCheckTimer;
|
|
216
|
+
livenessCheckTimer;
|
|
217
|
+
idleSweepIntervalMs;
|
|
218
|
+
healthCheckIntervalMs;
|
|
219
|
+
livenessCheckIntervalMs;
|
|
220
|
+
maxHealthCheckRetries;
|
|
221
|
+
initialBackoffDelay;
|
|
222
|
+
maxBackoffDelay;
|
|
223
|
+
minHealthFailuresBeforeKill = 3;
|
|
224
|
+
logger;
|
|
225
|
+
workspaceRoot;
|
|
226
|
+
// Where the 'global' ProcessManager writes `<id>.stdout` / `<id>.stderr`;
|
|
227
|
+
// the periodic sweep rotates live processes' logs here (see
|
|
228
|
+
// rotateOversizedProcessLogs). Same resolver ProcessManager('global') uses.
|
|
229
|
+
processLogDir;
|
|
230
|
+
// Track daemon start time for uptime calculation
|
|
231
|
+
startTime;
|
|
232
|
+
// Extracted modules
|
|
233
|
+
configWatcher;
|
|
234
|
+
orphanScanner;
|
|
235
|
+
healthMonitor;
|
|
236
|
+
livenessChecker;
|
|
237
|
+
executableFreshnessReconciler;
|
|
238
|
+
executableFreshnessTimer;
|
|
239
|
+
resourceHealthMonitor;
|
|
240
|
+
commandDispatcher;
|
|
241
|
+
hotReload;
|
|
242
|
+
/** Releases the generation-publication subscription (see start()). */
|
|
243
|
+
unsubscribeGeneration;
|
|
244
|
+
// Resource health check timer
|
|
245
|
+
resourceHealthCheckTimer;
|
|
246
|
+
orphanScanTimer;
|
|
247
|
+
resourceHealthCheckIntervalMs = 10000; // 10 seconds
|
|
248
|
+
// Pid-file heartbeat + supersession self-check (daemon-leak fix, work item
|
|
249
|
+
// c74e83a7-44bc-4281-8481-a76642ff5752). See start() for why both exist.
|
|
250
|
+
pidHeartbeatTimer;
|
|
251
|
+
supersessionTimer;
|
|
252
|
+
supersessionStrikes = 0;
|
|
253
|
+
pidHeartbeatIntervalMs = 60_000;
|
|
254
|
+
supersessionCheckIntervalMs = 15_000;
|
|
255
|
+
// Resolves start()'s keep-alive promise from stop() so programmatic
|
|
256
|
+
// callers of start() get control back instead of parking forever.
|
|
257
|
+
keepAliveResolve;
|
|
258
|
+
stopping;
|
|
259
|
+
stopFailed = false;
|
|
260
|
+
/**
|
|
261
|
+
* A supervisor tick owned by the serve host's lifecycle (RC07): disposed
|
|
262
|
+
* by `stop()` and by the runtime's disposal. The daemon host is not
|
|
263
|
+
* `finite`, so a lifecycle interval is admitted.
|
|
264
|
+
*/
|
|
265
|
+
tick(name, intervalMs, run) {
|
|
266
|
+
return this.runtime.lifecycle.interval(() => {
|
|
267
|
+
void this.runTick(name, run);
|
|
268
|
+
}, intervalMs);
|
|
269
|
+
}
|
|
270
|
+
/** One supervisor tick: a failure is reported, never thrown (nothing awaits a tick). */
|
|
271
|
+
async runTick(name, run) {
|
|
272
|
+
const ran = await attempt(run);
|
|
273
|
+
if (!ran.ok)
|
|
274
|
+
this.logger.error(`${name} failed`, { failure: valueFreeFailure(ran.failure) });
|
|
275
|
+
}
|
|
276
|
+
/** Remove a stale socket file during reconcile; a failure is reported and reconcile continues. */
|
|
277
|
+
/**
|
|
278
|
+
* Remove a dead process's socket through the runtime socket service. True
|
|
279
|
+
* only when the socket was there and is now removed; a refused removal (a
|
|
280
|
+
* listener still bound, a non-socket inode, an unreadable owner) is logged
|
|
281
|
+
* and reported false, never counted as removed.
|
|
282
|
+
*/
|
|
283
|
+
async removeStaleSocket(processId, socketPath) {
|
|
284
|
+
const socketService = await getRuntimeSocketService(this.runtime);
|
|
285
|
+
const removal = await attempt(async () => {
|
|
286
|
+
if (!(await socketService.inspectLocal(socketPath)).exists)
|
|
287
|
+
return false;
|
|
288
|
+
await socketService.removeLocal(socketPath);
|
|
289
|
+
return true;
|
|
290
|
+
});
|
|
291
|
+
if (!removal.ok) {
|
|
292
|
+
this.logger.warn('stale socket removal failed', { processId, socketPath, failure: valueFreeFailure(removal.failure) });
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
if (!removal.value)
|
|
296
|
+
return false;
|
|
297
|
+
return !(await socketService.inspectLocal(socketPath)).exists;
|
|
298
|
+
}
|
|
299
|
+
/** Dispose every supervisor tick. */
|
|
300
|
+
stopTicks() {
|
|
301
|
+
const failures = [];
|
|
302
|
+
for (const dispose of [
|
|
303
|
+
this.cleanupTimer,
|
|
304
|
+
this.healthCheckTimer,
|
|
305
|
+
this.livenessCheckTimer,
|
|
306
|
+
this.executableFreshnessTimer,
|
|
307
|
+
this.resourceHealthCheckTimer,
|
|
308
|
+
this.orphanScanTimer,
|
|
309
|
+
this.pidHeartbeatTimer,
|
|
310
|
+
this.supersessionTimer
|
|
311
|
+
]) {
|
|
312
|
+
const stopped = attemptSync(() => dispose?.());
|
|
313
|
+
if (!stopped.ok)
|
|
314
|
+
failures.push(stopped.failure);
|
|
315
|
+
}
|
|
316
|
+
this.cleanupTimer = undefined;
|
|
317
|
+
this.healthCheckTimer = undefined;
|
|
318
|
+
this.livenessCheckTimer = undefined;
|
|
319
|
+
this.executableFreshnessTimer = undefined;
|
|
320
|
+
this.resourceHealthCheckTimer = undefined;
|
|
321
|
+
this.orphanScanTimer = undefined;
|
|
322
|
+
this.pidHeartbeatTimer = undefined;
|
|
323
|
+
this.supersessionTimer = undefined;
|
|
324
|
+
if (failures.length === 1)
|
|
325
|
+
throw failures[0];
|
|
326
|
+
if (failures.length > 1)
|
|
327
|
+
throw new AggregateError(failures, 'PM supervisor timer disposal failed.');
|
|
328
|
+
}
|
|
329
|
+
waitForStop() {
|
|
330
|
+
return new Promise((resolve) => {
|
|
331
|
+
this.keepAliveResolve = resolve;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
// Agent-ops daemon modules — resolved at boot via runtime.query('pm/daemon-module')
|
|
335
|
+
// rather than hardcoded. Feature packages (e.g. @vibesdotdev/os) register tick/watch
|
|
336
|
+
// sources here; PM owns the surface, not the modules.
|
|
337
|
+
daemonModules = [];
|
|
338
|
+
// Track required modules that fail to start, with retry state
|
|
339
|
+
degradedModules = new Map();
|
|
340
|
+
// Reconcile runtime state with reality on boot
|
|
341
|
+
async reconcileState() {
|
|
342
|
+
const states = await this.store.getAll();
|
|
343
|
+
const summary = {
|
|
344
|
+
scanned: states.length,
|
|
345
|
+
updated: 0,
|
|
346
|
+
stopped: 0,
|
|
347
|
+
clearedSocketPath: 0,
|
|
348
|
+
removedSocketFiles: 0
|
|
349
|
+
};
|
|
350
|
+
for (const state of states) {
|
|
351
|
+
const sameObservation = (current) => current.status === state.status && current.pid === state.pid &&
|
|
352
|
+
current.startedAt?.getTime() === state.startedAt?.getTime();
|
|
353
|
+
// An owed terminal receipt is exact evidence, including its PID and time.
|
|
354
|
+
// Boot liveness reconciliation may not rewrite the admitted generation.
|
|
355
|
+
const generation = state.startedAt?.getTime();
|
|
356
|
+
if (generation !== undefined && processExitOf(state) && (await this.store.taskObligations(state.id)).some(entry => entry.startedAt === generation))
|
|
357
|
+
continue;
|
|
358
|
+
const config = await this.pm.getConfig(state.id);
|
|
359
|
+
const updates = {};
|
|
360
|
+
// A finite task's outcome is a RECORD, not a liveness claim. `pass`,
|
|
361
|
+
// `fail` and `completed` are terminal: the process is *supposed* to be
|
|
362
|
+
// gone. Reconciling them against "is the pid alive?" stomped every
|
|
363
|
+
// task result to `stopped` on each daemon boot, which silently broke
|
|
364
|
+
// `requiresPass` — an already-applied migration looked never-run, so
|
|
365
|
+
// its dependents refused to start until someone re-ran it by hand.
|
|
366
|
+
if (TERMINAL_STATUSES.has(state.status)) {
|
|
367
|
+
if (state.socketPath) {
|
|
368
|
+
if (await this.removeStaleSocket(state.id, state.socketPath))
|
|
369
|
+
summary.removedSocketFiles += 1;
|
|
370
|
+
updates.socketPath = undefined;
|
|
371
|
+
summary.clearedSocketPath += 1;
|
|
372
|
+
}
|
|
373
|
+
if (state.pid !== undefined && !(await isProcessRunning(this.runtime, state.pid))) {
|
|
374
|
+
updates.pid = undefined;
|
|
375
|
+
}
|
|
376
|
+
if (Object.keys(updates).length > 0) {
|
|
377
|
+
await this.store.withProcessAdmission(state.id, async () => {
|
|
378
|
+
if (generation !== undefined && (await this.store.taskObligations(state.id)).some(entry => entry.startedAt === generation))
|
|
379
|
+
return;
|
|
380
|
+
if (await this.store.updateWhen(state.id, updates, sameObservation))
|
|
381
|
+
summary.updated += 1;
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
// If config no longer declares a socket, clear any stale socketPath
|
|
387
|
+
if (!config?.socket && state.socketPath) {
|
|
388
|
+
updates.socketPath = undefined;
|
|
389
|
+
summary.clearedSocketPath += 1;
|
|
390
|
+
}
|
|
391
|
+
// Verify the process is really alive; if not, clean up and mark stopped
|
|
392
|
+
const livenessResult = await checkProcessLiveness(this.runtime, state);
|
|
393
|
+
const alive = livenessResult.alive;
|
|
394
|
+
if (!alive) {
|
|
395
|
+
// The liveness strategy for socket-backed processes requires BOTH
|
|
396
|
+
// PID and socket. A missing/unreachable socket flips `alive=false`
|
|
397
|
+
// even when the PID (and its entire subprocess tree) is still
|
|
398
|
+
// running. Killing the tree and deleting the socket on that false
|
|
399
|
+
// negative destroys a genuinely live process — e.g. an orphaned
|
|
400
|
+
// runtime daemon whose projection socket hasn't been (re)created
|
|
401
|
+
// yet. `checkProcessLiveness` already probed the pid directly
|
|
402
|
+
// (`isPIDAlive`), so reuse that verdict: only reap and clean up
|
|
403
|
+
// when the pid itself is confirmed dead. A live-but-socketless
|
|
404
|
+
// process is left alone here — repair (autostart, health
|
|
405
|
+
// monitor), never delete — instead of us destroying its state.
|
|
406
|
+
if (livenessResult.details.pidAlive === true) {
|
|
407
|
+
this.logger.warn('reconcile: liveness failed but pid is still alive (socket unreachable or missing) — leaving state and socket alone for repair, not killing', { processId: state.id, pid: state.pid, socketPath: state.socketPath });
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
if (state.socketPath && (await this.removeStaleSocket(state.id, state.socketPath))) {
|
|
411
|
+
summary.removedSocketFiles += 1;
|
|
412
|
+
}
|
|
413
|
+
updates.status = 'stopped';
|
|
414
|
+
updates.pid = undefined;
|
|
415
|
+
updates.stoppedAt = new Date();
|
|
416
|
+
updates.lastError = 'Reconciled: process not running';
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (Object.keys(updates).length > 0) {
|
|
420
|
+
if (await this.store.updateWhen(state.id, updates, sameObservation)) {
|
|
421
|
+
summary.updated += 1;
|
|
422
|
+
if (updates.status === 'stopped')
|
|
423
|
+
summary.stopped += 1;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return summary;
|
|
428
|
+
}
|
|
429
|
+
constructor(config) {
|
|
430
|
+
this.startTime = Date.now();
|
|
431
|
+
const workspaceIdentity = admittedWorkspaceIdentity(config.workspaceRoot);
|
|
432
|
+
this.workspaceRoot = workspaceIdentity.workspacePath;
|
|
433
|
+
const toolingId = workspaceIdentity.toolingId;
|
|
434
|
+
this.runtimePath = config.runtimePath;
|
|
435
|
+
this.runtime = config.runtime;
|
|
436
|
+
this.roots = getPathRoots(config.runtime);
|
|
437
|
+
this.socketPath =
|
|
438
|
+
config.socketPath ||
|
|
439
|
+
getPMSocketPath(toolingId, { roots: this.roots, runtimePath: config.runtimePath });
|
|
440
|
+
this.pidFile = config.pidFile || getDaemonPidPath(toolingId, { roots: this.roots, runtimePath: config.runtimePath });
|
|
441
|
+
this.idleSweepIntervalMs = config.idleSweepInterval || 60 * 1000;
|
|
442
|
+
this.healthCheckIntervalMs = config.healthCheckInterval || 30 * 1000;
|
|
443
|
+
this.livenessCheckIntervalMs = config.livenessCheckInterval || 10 * 1000;
|
|
444
|
+
this.maxHealthCheckRetries = config.maxHealthCheckRetries || 10;
|
|
445
|
+
this.initialBackoffDelay = config.initialBackoffDelay || 1000;
|
|
446
|
+
this.maxBackoffDelay = config.maxBackoffDelay || 30 * 1000;
|
|
447
|
+
// Initialize descriptor-driven daemon logger
|
|
448
|
+
this.logger = getPMDaemonLogger(this.runtime, 'global');
|
|
449
|
+
// Create shared store, partitioned by the daemon's ADMITTED workspace
|
|
450
|
+
// identity rather than ambient re-derivation — see
|
|
451
|
+
// store.impl.consumer.ts getBasePath / ProcessStoreOptions.workspaceToolingId.
|
|
452
|
+
this.store = new ProcessStore({ scope: 'global', roots: this.roots, workspaceToolingId: toolingId }, this.runtime);
|
|
453
|
+
// The admitted workspace's active liveness profiles, persisted in its
|
|
454
|
+
// pm-state.db; loaded in start() before the daemon serves (U-RC03-1).
|
|
455
|
+
this.liveness = new LivenessProfiles(this.store, () => this.runtime);
|
|
456
|
+
// Create resource manager
|
|
457
|
+
// Providers resolve from this daemon's runtime (`pm/resource-provider`:
|
|
458
|
+
// PM's builtins from the pm plugin, a workspace's or feature's own).
|
|
459
|
+
this.rm = new ResourceManager(this.store, new ResourceProviderRegistry(() => this.runtime), () => this.runtime);
|
|
460
|
+
// The scope this daemon declares (framework-M8): its admitted workspace
|
|
461
|
+
// and the host runtime's homes. It alone proves a port holder ours before
|
|
462
|
+
// PM signals anything; nothing reads this process's env or cwd for it.
|
|
463
|
+
const roots = this.roots;
|
|
464
|
+
const daemonScope = {
|
|
465
|
+
workspaceRoot: this.workspaceRoot,
|
|
466
|
+
vibesHome: roots.vibesHome,
|
|
467
|
+
userHome: roots.userHome
|
|
468
|
+
};
|
|
469
|
+
// Create process manager with resource manager
|
|
470
|
+
// Share the daemon's store so one run-end archive (below) sees the health
|
|
471
|
+
// monitor's and liveness checker's writes, not only lifecycle's.
|
|
472
|
+
this.pm = new ProcessManager('global', this.rm, {
|
|
473
|
+
getRuntime: () => this.runtime,
|
|
474
|
+
workspaceRoot: this.workspaceRoot,
|
|
475
|
+
store: this.store,
|
|
476
|
+
runtimePath: config.runtimePath,
|
|
477
|
+
daemonScope,
|
|
478
|
+
livenessProfile: (scopeKey) => this.liveness.get(scopeKey)
|
|
479
|
+
});
|
|
480
|
+
// The manager owns the (workspace-keyed) directory its processes write to.
|
|
481
|
+
this.processLogDir = this.pm.processLogDir;
|
|
482
|
+
// Lifecycle truncates `<id>.stdout`/`<id>.stderr` on every start; keep
|
|
483
|
+
// the run that just ended (its tail plus an exit banner) in `.1`.
|
|
484
|
+
this.store.onRunEnd(createProcessRunArchiver({
|
|
485
|
+
getRuntime: () => this.runtime,
|
|
486
|
+
logDir: this.processLogDir,
|
|
487
|
+
pendingInitiator: (processId) => this.pm.pendingRunEndInitiator(processId),
|
|
488
|
+
onArchived: (info) => this.logger.info('archived previous run logs', { ...info }),
|
|
489
|
+
onFailed: (info) => this.logger.warn('previous run log archive failed', {
|
|
490
|
+
processId: info.processId,
|
|
491
|
+
failed: info.failed.map((entry) => ({
|
|
492
|
+
path: entry.path,
|
|
493
|
+
failure: valueFreeFailure(entry.failure)
|
|
494
|
+
}))
|
|
495
|
+
})
|
|
496
|
+
}));
|
|
497
|
+
// Create preset executor
|
|
498
|
+
this.executor = new PresetExecutor(this.pm, this.rm, () => this.runtime);
|
|
499
|
+
// Create config watcher
|
|
500
|
+
this.configWatcher = new ConfigWatcher({
|
|
501
|
+
pm: this.pm,
|
|
502
|
+
rm: this.rm,
|
|
503
|
+
getCwd: () => this.workspaceRoot,
|
|
504
|
+
getRuntime: () => this.runtime,
|
|
505
|
+
getLivenessProfile: (scopeKey) => this.liveness.get(scopeKey),
|
|
506
|
+
getFleetProxy: (scope) => this.fleet.get(scope)
|
|
507
|
+
});
|
|
508
|
+
// Create orphan scanner
|
|
509
|
+
this.orphanScanner = new OrphanScanner({
|
|
510
|
+
getRuntime: () => this.runtime,
|
|
511
|
+
store: this.store,
|
|
512
|
+
pm: this.pm,
|
|
513
|
+
daemonScope
|
|
514
|
+
});
|
|
515
|
+
// Create health monitor
|
|
516
|
+
this.healthMonitor = new HealthMonitor({
|
|
517
|
+
getRuntime: () => this.runtime,
|
|
518
|
+
pm: this.pm,
|
|
519
|
+
store: this.store,
|
|
520
|
+
minHealthFailuresBeforeKill: this.minHealthFailuresBeforeKill
|
|
521
|
+
});
|
|
522
|
+
// Create liveness checker
|
|
523
|
+
this.livenessChecker = new LivenessChecker({
|
|
524
|
+
getRuntime: () => this.runtime,
|
|
525
|
+
pm: this.pm,
|
|
526
|
+
store: this.store
|
|
527
|
+
});
|
|
528
|
+
// Roll managed processes (and hand this daemon off) when the vibes
|
|
529
|
+
// executable on disk is replaced after they started — otherwise every
|
|
530
|
+
// daemon keeps executing a deleted inode until something kills it.
|
|
531
|
+
this.executableFreshnessReconciler = new ExecutableFreshnessReconciler({
|
|
532
|
+
getRuntime: () => this.runtime,
|
|
533
|
+
pm: this.pm,
|
|
534
|
+
selfStartedAtMs: this.startTime
|
|
535
|
+
});
|
|
536
|
+
// Create resource health monitor
|
|
537
|
+
this.resourceHealthMonitor = new ResourceHealthMonitor({
|
|
538
|
+
pm: this.pm,
|
|
539
|
+
rm: this.rm,
|
|
540
|
+
getRuntime: () => this.runtime
|
|
541
|
+
});
|
|
542
|
+
// Create command dispatcher
|
|
543
|
+
this.commandDispatcher = new CommandDispatcher({
|
|
544
|
+
liveness: this.liveness,
|
|
545
|
+
fleet: this.fleet,
|
|
546
|
+
pm: this.pm,
|
|
547
|
+
rm: this.rm,
|
|
548
|
+
executor: this.executor,
|
|
549
|
+
configWatcher: this.configWatcher,
|
|
550
|
+
getHealth: () => this.getHealth(),
|
|
551
|
+
reconcileState: () => this.reconcileState(),
|
|
552
|
+
requestHandoff: () => {
|
|
553
|
+
this.runtime.lifecycle.timeout(() => {
|
|
554
|
+
void this.requestStop('rpc-handoff', 'handoff');
|
|
555
|
+
}, 0);
|
|
556
|
+
},
|
|
557
|
+
requestShutdown: config.requestShutdown ??
|
|
558
|
+
(() => {
|
|
559
|
+
// Let runtime-rpc-unix finish the accepted response before
|
|
560
|
+
// PM drains children, persists state, and removes daemon
|
|
561
|
+
// artifacts. Do not bounce through a process signal here:
|
|
562
|
+
// compiled CLI hosts may still own a fast-exit signal
|
|
563
|
+
// handler that bypasses PM's asynchronous cleanup.
|
|
564
|
+
this.runtime.lifecycle.timeout(() => {
|
|
565
|
+
void this.requestStop('rpc');
|
|
566
|
+
}, 0);
|
|
567
|
+
})
|
|
568
|
+
}, config.runtime);
|
|
569
|
+
// Agent-ops daemon modules are NOT constructed here. They are resolved
|
|
570
|
+
// from the runtime in start() so PM stays decoupled from the feature
|
|
571
|
+
// packages that register them (RESOLVE, DON'T IMPORT).
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Start the daemon
|
|
575
|
+
*/
|
|
576
|
+
async start() {
|
|
577
|
+
const runtime = this.runtime;
|
|
578
|
+
await assertPMDaemonServeHost(runtime);
|
|
579
|
+
await this.hostPid();
|
|
580
|
+
const executable = (await getRuntimeHostIdentity(this.runtime)).captureExecutableIdentity();
|
|
581
|
+
const executablePath = executable === null ? null : z.object({ path: z.string().min(1) }).safeParse(executable);
|
|
582
|
+
if (executablePath !== null && !executablePath.success) {
|
|
583
|
+
throw new CapabilityError('The selected host supplied an invalid executable identity.', 'INVALID_INPUT', {
|
|
584
|
+
reason: 'host-identity-invalid', retryable: false
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
this.logger.info('starting');
|
|
588
|
+
// Liveness profiles are read synchronously by every spawn; load them
|
|
589
|
+
// before anything below (a generation reconcile included) can start a
|
|
590
|
+
// process or accept a command.
|
|
591
|
+
await this.liveness.load();
|
|
592
|
+
// Hot reload is armed on the serve host itself. Its `runtime` is a stable
|
|
593
|
+
// dispatch handle that follows every published generation, so the daemon
|
|
594
|
+
// holds it from here on.
|
|
595
|
+
// Optional: a runtime that composes no runtime daemon endpoint (or one
|
|
596
|
+
// without host hot reload) serves without it, and says so once.
|
|
597
|
+
const hot = await startRuntimeHostHotReload(runtime, { installedUpdates: true, log: this.logger });
|
|
598
|
+
if (!hot) {
|
|
599
|
+
this.logger.info('host hot reload not started: no runtime daemon endpoint with hot reload is registered');
|
|
600
|
+
}
|
|
601
|
+
else if (hot.enabled) {
|
|
602
|
+
this.hotReload = hot;
|
|
603
|
+
this.runtime = hot.runtime;
|
|
604
|
+
this.commandDispatcher.setRuntime(hot.runtime);
|
|
605
|
+
// Each published generation re-ran the kernel's discovery pass
|
|
606
|
+
// (rc02-rc03 §2.5); reconcile PM's registrations from it. PM runs
|
|
607
|
+
// no discovery of its own.
|
|
608
|
+
this.unsubscribeGeneration = hot.runtime.onGenerationChange(() => {
|
|
609
|
+
// A waiting observation must not pin the retired generation: it
|
|
610
|
+
// answers `interrupted` and its client re-issues on this one.
|
|
611
|
+
this.commandDispatcher.interruptObservations('generation');
|
|
612
|
+
return this.configWatcher.reconcileOnGeneration();
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
// Ensure directories exist and have sane perms before PID/socket
|
|
616
|
+
await this.ensurePathPermissions();
|
|
617
|
+
await this.cleanupStalePidIfNeeded();
|
|
618
|
+
await this.cleanupStaleSocketIfNeeded();
|
|
619
|
+
// A daemon signals only processes it started (SPEC hard rule; pm.md D3):
|
|
620
|
+
// other workspaces' daemons are never reaped here. Strays are reported by
|
|
621
|
+
// `vibes pm daemon reconcile` (daemon/stray-daemons.ts) and stopped through
|
|
622
|
+
// their own daemon's RPC.
|
|
623
|
+
await this.reconcileState();
|
|
624
|
+
// Scan for and cleanup orphaned sockets from previous daemon sessions
|
|
625
|
+
await this.orphanScanner.scanForOrphanedSockets();
|
|
626
|
+
// A reachable PM socket must already own the workspace's discovered
|
|
627
|
+
// process registry. Native consumers use typed RPC directly and cannot
|
|
628
|
+
// be required to replay CLI-only config registration before `start`.
|
|
629
|
+
//
|
|
630
|
+
// Resilient by design: one malformed descriptor (e.g. an app's
|
|
631
|
+
// *.pm.process.ts that omits `command`) must not take the whole daemon —
|
|
632
|
+
// and every other app — down with it. reconcileConfig already logs and
|
|
633
|
+
// skips each rejected config; startup proceeds with the ones that
|
|
634
|
+
// validated. Strict validation is `vibes pm validate`, not a startup crash.
|
|
635
|
+
const startupReconciliation = await this.configWatcher.reconcileConfig();
|
|
636
|
+
if (startupReconciliation.failed.length > 0) {
|
|
637
|
+
this.logger.warn('daemon started with rejected process configs (skipped)', {
|
|
638
|
+
rejected: startupReconciliation.failed
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
// The orphan scanner matches observed processes against registered
|
|
642
|
+
// configs (adoption, port ownership). Give it the registry now that
|
|
643
|
+
// startup reconciliation has populated it; every scan tick re-syncs.
|
|
644
|
+
await this.syncOrphanScannerConfigs();
|
|
645
|
+
// Required feature modules are part of startup truth. Their process
|
|
646
|
+
// admission must succeed before PM publishes a reachable RPC socket.
|
|
647
|
+
await this.startDaemonModules('required');
|
|
648
|
+
// Write PID file
|
|
649
|
+
await this.writePidFile();
|
|
650
|
+
// Wire the runtime-rpc-unix LISTEN side.
|
|
651
|
+
// The PM RPC root wraps every pm-command handler; arriving RpcInvoke frames
|
|
652
|
+
// are routed by method name to the CommandDispatcher (no named-command registry
|
|
653
|
+
// string; each method IS the command name).
|
|
654
|
+
const dispatcher = this.commandDispatcher;
|
|
655
|
+
const listening = await attempt(() => listenUnix(this.socketPath, {
|
|
656
|
+
connectionRoot: (connection) => createPMRpcRoot(dispatcher, connection),
|
|
657
|
+
// The PM root serves exactly its stable wire commands (the client's list).
|
|
658
|
+
rootMethods: PM_COMMAND_IDS,
|
|
659
|
+
pipeline: new DefaultInvokePipeline(),
|
|
660
|
+
classifyResult: () => ({ mode: 'inline' }),
|
|
661
|
+
bindChannel: () => null,
|
|
662
|
+
kindOf: () => 'pm/daemon'
|
|
663
|
+
}, { runtime: this.runtime }));
|
|
664
|
+
if (!listening.ok) {
|
|
665
|
+
// listenUnix throws when the socket path is already bound (EADDRINUSE).
|
|
666
|
+
// This is a fatal singleton violation — the socket check above should
|
|
667
|
+
// have caught it, but if it didn't, die loudly instead of silently.
|
|
668
|
+
const message = failureText(listening.failure);
|
|
669
|
+
this.logger.error('failed to bind daemon socket', {
|
|
670
|
+
socketPath: this.socketPath,
|
|
671
|
+
failure: valueFreeFailure(listening.failure)
|
|
672
|
+
});
|
|
673
|
+
// Clean up the PID file we just wrote so the next launcher doesn't
|
|
674
|
+
// think *this* process is the incumbent.
|
|
675
|
+
// The bind failure below stays the error; a failed pid cleanup is reported beside it.
|
|
676
|
+
const cleaned = await attempt(() => this.removePidFile());
|
|
677
|
+
if (!cleaned.ok) {
|
|
678
|
+
this.logger.warn('pid file cleanup after bind failure failed', { failure: valueFreeFailure(cleaned.failure) });
|
|
679
|
+
}
|
|
680
|
+
throw new CapabilityError(`Cannot bind PM daemon socket ${this.socketPath}: ${message}. ` +
|
|
681
|
+
`Another daemon may already be running. ` +
|
|
682
|
+
`Use 'vibes pm daemon restart' if you need to replace it.`, 'CONFLICT', { reason: 'pm-daemon-socket-bind-failed', details: { socketPath: this.socketPath }, cause: listening.failure });
|
|
683
|
+
}
|
|
684
|
+
this.rpcListener = listening.value;
|
|
685
|
+
// Set socket permissions (owner-only, same as before)
|
|
686
|
+
this.logger.info('listening (rpc-unix)', { socketPath: this.socketPath });
|
|
687
|
+
// Start idle process cleanup timer
|
|
688
|
+
this.cleanupTimer = this.tick('scheduled cleanup', this.idleSweepIntervalMs, () => this.runScheduledCleanup());
|
|
689
|
+
// Start health check timer (runs every 1s, but respects per-process intervals)
|
|
690
|
+
this.healthCheckTimer = this.tick('health check tick', 1000, () => this.healthMonitor.runHealthChecks());
|
|
691
|
+
this.logger.info('health check loop enabled', { tickIntervalMs: 1000 });
|
|
692
|
+
// Start liveness check timer
|
|
693
|
+
this.livenessCheckTimer = this.tick('liveness check', this.livenessCheckIntervalMs, () => this.livenessChecker.runLivenessChecks());
|
|
694
|
+
this.logger.info('liveness monitoring enabled', {
|
|
695
|
+
intervalMs: this.livenessCheckIntervalMs
|
|
696
|
+
});
|
|
697
|
+
// Executable freshness: one stale child rolled per tick, daemon handoff last.
|
|
698
|
+
const executableFreshnessIntervalMs = 30_000;
|
|
699
|
+
this.executableFreshnessTimer = this.tick('executable freshness tick', executableFreshnessIntervalMs, () => this.executableFreshnessReconciler.tick());
|
|
700
|
+
this.logger.info('executable freshness reconciler enabled', {
|
|
701
|
+
intervalMs: executableFreshnessIntervalMs,
|
|
702
|
+
executable: executablePath?.data.path ?? null,
|
|
703
|
+
optOut: 'VIBES_PM_EXECUTABLE_FRESHNESS=0'
|
|
704
|
+
});
|
|
705
|
+
// Pid-file heartbeat. The client's staleness heuristic
|
|
706
|
+
// (client.ts cleanupStaleDaemonArtifacts) treats a pid file older than
|
|
707
|
+
// 5 minutes as evidence the unreachable daemon is dead. The pid file
|
|
708
|
+
// used to be written once at startup, so after 5 minutes of UPTIME any
|
|
709
|
+
// daemon that missed a single 750ms reachability probe on a busy
|
|
710
|
+
// machine was culled-by-unlink and replaced — while the old process
|
|
711
|
+
// lived on. Refreshing mtime makes age measure LIVENESS, not uptime.
|
|
712
|
+
// A failed heartbeat is logged at error (not debug): a pid file that
|
|
713
|
+
// stops refreshing gets this daemon culled as dead.
|
|
714
|
+
this.pidHeartbeatTimer = this.tick('pid heartbeat', this.pidHeartbeatIntervalMs, () => this.heartbeatPidFile());
|
|
715
|
+
// Supersession self-check. If the pid file no longer names this process
|
|
716
|
+
// or the socket file is gone, another daemon has taken over (or an
|
|
717
|
+
// operator culled our artifacts). Exit instead of looping forever as an
|
|
718
|
+
// orphan — this is the backstop that makes daemon zombies structurally
|
|
719
|
+
// impossible regardless of who unlinks what (340 leaked daemons were
|
|
720
|
+
// found doing exactly that, all PID-1-parented with live timers).
|
|
721
|
+
this.supersessionTimer = this.tick('supersession check', this.supersessionCheckIntervalMs, async () => {
|
|
722
|
+
if (await this.tickSupersession())
|
|
723
|
+
await this.exitSuperseded();
|
|
724
|
+
});
|
|
725
|
+
// Start orphan scanner - runs every 30 seconds initially, then 60s during steady-state
|
|
726
|
+
// CRITICAL FIX (Issue 4.3): Reduce scan frequency after warmup to save CPU
|
|
727
|
+
const warmupOrphanScanInterval = 30000; // 30 seconds during first 5 minutes
|
|
728
|
+
const steadyStateOrphanScanInterval = 60000; // 60 seconds during steady-state
|
|
729
|
+
const currentOrphanScanInterval = warmupOrphanScanInterval;
|
|
730
|
+
this.orphanScanTimer = this.tick('orphan scan', warmupOrphanScanInterval, () => this.runOrphanScan());
|
|
731
|
+
// After the 5-minute warmup the warmup tick is replaced by the steady-state one.
|
|
732
|
+
const switchToSteadyState = this.runtime.lifecycle.timeout(() => {
|
|
733
|
+
this.orphanScanTimer?.();
|
|
734
|
+
this.orphanScanTimer = this.tick('orphan scan', steadyStateOrphanScanInterval, () => this.runOrphanScan());
|
|
735
|
+
this.logger.info('orphan scanner switched to steady-state interval', {
|
|
736
|
+
intervalMs: steadyStateOrphanScanInterval
|
|
737
|
+
});
|
|
738
|
+
}, 5 * 60 * 1000);
|
|
739
|
+
const warmupTick = this.orphanScanTimer;
|
|
740
|
+
this.orphanScanTimer = () => {
|
|
741
|
+
switchToSteadyState();
|
|
742
|
+
warmupTick();
|
|
743
|
+
};
|
|
744
|
+
this.logger.info('orphan scanner enabled', { intervalMs: currentOrphanScanInterval });
|
|
745
|
+
// Start resource health check timer
|
|
746
|
+
this.resourceHealthCheckTimer = this.tick('resource health check', this.resourceHealthCheckIntervalMs, () => this.resourceHealthMonitor.runResourceHealthChecks());
|
|
747
|
+
this.logger.info('resource health monitoring enabled', {
|
|
748
|
+
intervalMs: this.resourceHealthCheckIntervalMs
|
|
749
|
+
});
|
|
750
|
+
// PM watches no config file (pm.md D2): each published runtime generation
|
|
751
|
+
// reconciles the graph (`reconcileOnGeneration`, subscribed above).
|
|
752
|
+
// Resolve and start agent-ops daemon modules registered as
|
|
753
|
+
// `pm/daemon-module` descriptors (e.g. @vibesdotdev/os channel
|
|
754
|
+
// scheduler, surface watcher, platform channel sync). PM owns the
|
|
755
|
+
// surface; feature packages register the modules. Optional modules stay
|
|
756
|
+
// isolated from each other and from daemon availability.
|
|
757
|
+
await this.startDaemonModules('optional');
|
|
758
|
+
// Keep the daemon alive until stop() resolves this. main() never
|
|
759
|
+
// calls stop() (process exit is its terminator), but a programmatic
|
|
760
|
+
// caller of start() now gets control back on stop() instead of
|
|
761
|
+
// parking on a never-resolving promise.
|
|
762
|
+
await this.waitForStop();
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* Resolve every enabled `pm/daemon-module` from the runtime and start it.
|
|
766
|
+
* Tolerates an unbootstrapped runtime (tests, isolated construction) by
|
|
767
|
+
* starting zero modules — mirroring mountRegisteredEndpoints() in
|
|
768
|
+
* pm.daemon.serve.impl.ts. Modules are sorted by `priority` (higher first)
|
|
769
|
+
* so ordering-sensitive tick sources can declare a start order.
|
|
770
|
+
*
|
|
771
|
+
* Required modules that fail to start are added to degradedModules and
|
|
772
|
+
* restarted on the declared `supervision.daemonModule` policy (RC11 class:
|
|
773
|
+
* supervision of what the daemon owns; default 15s doubling to 5m, never
|
|
774
|
+
* giving up). The daemon continues starting; it does NOT throw for
|
|
775
|
+
* required module failures.
|
|
776
|
+
*/
|
|
777
|
+
async startDaemonModules(mode) {
|
|
778
|
+
const started = await attempt(() => this.startResolvedModules(mode));
|
|
779
|
+
if (started.ok)
|
|
780
|
+
return;
|
|
781
|
+
if (mode === 'required')
|
|
782
|
+
throw started.failure;
|
|
783
|
+
// Runtime not bootstrapped (e.g. direct PMDaemon construction in
|
|
784
|
+
// tests) — no modules to start.
|
|
785
|
+
this.logger.debug('daemon module resolution skipped', { failure: valueFreeFailure(started.failure) });
|
|
786
|
+
}
|
|
787
|
+
async startResolvedModules(mode) {
|
|
788
|
+
const runtime = this.runtime;
|
|
789
|
+
if (!runtime.hasKind('pm/daemon-module'))
|
|
790
|
+
return;
|
|
791
|
+
const descriptors = runtime
|
|
792
|
+
.query('pm/daemon-module')
|
|
793
|
+
.enabled()
|
|
794
|
+
.descriptors();
|
|
795
|
+
const sorted = [...descriptors]
|
|
796
|
+
.filter((descriptor) => Boolean(descriptor.required) === (mode === 'required'))
|
|
797
|
+
.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
798
|
+
for (const descriptor of sorted) {
|
|
799
|
+
const id = descriptor.id;
|
|
800
|
+
const started = await attempt(async () => {
|
|
801
|
+
const module = await runtime
|
|
802
|
+
.query('pm/daemon-module')
|
|
803
|
+
.withId(id)
|
|
804
|
+
.resolve();
|
|
805
|
+
// Built through the least-authority factory rather than inline: it
|
|
806
|
+
// narrows ProcessManager to its registered-process calls, so a daemon module
|
|
807
|
+
// can ensure its OWN registered process exists without gaining the
|
|
808
|
+
// authority to register commands or read unrelated configs.
|
|
809
|
+
const ctx = createPMDaemonModuleContext(this.pm, this.logger.child(`module:${id}`), this.runtime);
|
|
810
|
+
await module.start(ctx);
|
|
811
|
+
this.daemonModules.push({ id, module });
|
|
812
|
+
this.logger.info('daemon module started', { moduleId: id });
|
|
813
|
+
// If this module was previously degraded, remove it now that it started
|
|
814
|
+
const degraded = this.degradedModules.get(id);
|
|
815
|
+
if (degraded) {
|
|
816
|
+
degraded.retryTimer?.();
|
|
817
|
+
this.degradedModules.delete(id);
|
|
818
|
+
this.logger.info('degraded module recovered', { moduleId: id });
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
if (!started.ok) {
|
|
822
|
+
this.logger.error('daemon module failed to start', {
|
|
823
|
+
moduleId: id,
|
|
824
|
+
failure: valueFreeFailure(started.failure)
|
|
825
|
+
});
|
|
826
|
+
if (descriptor.required) {
|
|
827
|
+
const attempts = (this.degradedModules.get(id)?.attempts ?? 0) + 1;
|
|
828
|
+
await this.scheduleModuleRestart(descriptor, attempts, started.failure);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Retry starting a degraded required daemon module.
|
|
835
|
+
* Called by the retry timer scheduled in startDaemonModules.
|
|
836
|
+
*/
|
|
837
|
+
async retryDaemonModule(descriptor) {
|
|
838
|
+
const id = descriptor.id;
|
|
839
|
+
const degraded = this.degradedModules.get(id);
|
|
840
|
+
if (!degraded)
|
|
841
|
+
return; // Was already recovered or removed
|
|
842
|
+
const retried = await attempt(async () => {
|
|
843
|
+
const runtime = this.runtime;
|
|
844
|
+
if (!runtime.hasKind('pm/daemon-module'))
|
|
845
|
+
return;
|
|
846
|
+
const module = await runtime
|
|
847
|
+
.query('pm/daemon-module')
|
|
848
|
+
.withId(id)
|
|
849
|
+
.resolve();
|
|
850
|
+
// `.resolve()` returns the runtime's cached singleton for this id (asset
|
|
851
|
+
// kinds default to `cacheValue: true`), not a fresh instance — the SAME
|
|
852
|
+
// object as the failed attempt. If that attempt partially initialized
|
|
853
|
+
// internal state (a timer, a watcher, a listener) before throwing, calling
|
|
854
|
+
// `start()` again without an intervening `stop()` would run two live copies
|
|
855
|
+
// of whatever it allocated. Best-effort teardown first, exactly like
|
|
856
|
+
// `stopDaemonModules()` does for a normal shutdown.
|
|
857
|
+
const stopped = await attempt(async () => {
|
|
858
|
+
await module.stop?.();
|
|
859
|
+
});
|
|
860
|
+
if (!stopped.ok) {
|
|
861
|
+
this.logger.debug('degraded module pre-retry stop failed', {
|
|
862
|
+
moduleId: id,
|
|
863
|
+
failure: valueFreeFailure(stopped.failure)
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
const ctx = createPMDaemonModuleContext(this.pm, this.logger.child(`module:${id}`), this.runtime);
|
|
867
|
+
await module.start(ctx);
|
|
868
|
+
this.daemonModules.push({ id, module });
|
|
869
|
+
this.degradedModules.delete(id);
|
|
870
|
+
this.logger.info('degraded daemon module recovered on retry', { moduleId: id });
|
|
871
|
+
});
|
|
872
|
+
if (!retried.ok) {
|
|
873
|
+
this.logger.error('daemon module retry failed', {
|
|
874
|
+
moduleId: id,
|
|
875
|
+
failure: valueFreeFailure(retried.failure)
|
|
876
|
+
});
|
|
877
|
+
await this.scheduleModuleRestart(descriptor, degraded.attempts + 1, retried.failure);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Record a required module's failure and, within the declared
|
|
882
|
+
* `supervision.daemonModule` budget, schedule its restart on a lifecycle
|
|
883
|
+
* one-shot (disposed with the daemon's runtime). Past the budget it stays
|
|
884
|
+
* degraded, visible in the daemon's health, with no timer.
|
|
885
|
+
*/
|
|
886
|
+
async scheduleModuleRestart(descriptor, attempts, failure) {
|
|
887
|
+
const id = descriptor.id;
|
|
888
|
+
this.degradedModules.get(id)?.retryTimer?.();
|
|
889
|
+
const policy = (await readSupervision(this.runtime)).daemonModule;
|
|
890
|
+
// `attempts` is the attempt that just failed; the retry this would
|
|
891
|
+
// schedule is attempt `attempts + 1`, and the budget caps failed
|
|
892
|
+
// starts (`maxConsecutive`: consecutive failures before the
|
|
893
|
+
// supervisor gives up). A next attempt past the cap degrades the
|
|
894
|
+
// module for good, its record naming the attempt that was refused,
|
|
895
|
+
// with no timer armed.
|
|
896
|
+
if (!mayRestart(policy, attempts + 1)) {
|
|
897
|
+
const refusedAttempt = attempts + 1;
|
|
898
|
+
this.degradedModules.set(id, { id, error: failure, attempts: refusedAttempt, descriptor });
|
|
899
|
+
this.logger.error('required daemon module restart budget spent', {
|
|
900
|
+
moduleId: id,
|
|
901
|
+
attempts: refusedAttempt,
|
|
902
|
+
maxConsecutive: policy.maxConsecutive
|
|
903
|
+
});
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
const backoffMs = restartDelayMs(policy, attempts);
|
|
907
|
+
const nextRetryAt = new Date(Date.now() + backoffMs);
|
|
908
|
+
this.degradedModules.set(id, {
|
|
909
|
+
id,
|
|
910
|
+
error: failure,
|
|
911
|
+
attempts,
|
|
912
|
+
nextRetryAt,
|
|
913
|
+
descriptor,
|
|
914
|
+
retryTimer: this.runtime.lifecycle.timeout(() => {
|
|
915
|
+
void this.retryDaemonModule(descriptor);
|
|
916
|
+
}, backoffMs)
|
|
917
|
+
});
|
|
918
|
+
this.logger.info('required daemon module scheduled for restart', {
|
|
919
|
+
moduleId: id,
|
|
920
|
+
attempt: attempts,
|
|
921
|
+
nextRetryAt: nextRetryAt.toISOString(),
|
|
922
|
+
backoffMs
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Stop every started daemon module (graceful shutdown + supersession).
|
|
927
|
+
* Best-effort: one module's stop failure never blocks the rest.
|
|
928
|
+
*/
|
|
929
|
+
async stopDaemonModules() {
|
|
930
|
+
const modules = this.daemonModules;
|
|
931
|
+
this.daemonModules = [];
|
|
932
|
+
const outcomes = await Promise.all(modules.map(({ module }) => attempt(async () => { await module.stop?.(); })));
|
|
933
|
+
const failures = outcomes.flatMap((outcome) => outcome.ok ? [] : [outcome.failure]);
|
|
934
|
+
if (failures.length === 1)
|
|
935
|
+
throw failures[0];
|
|
936
|
+
if (failures.length > 1)
|
|
937
|
+
throw new AggregateError(failures, 'PM daemon module disposal failed.');
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Stop the daemon
|
|
941
|
+
* CRITICAL FIX: Kill all managed processes on shutdown to prevent orphans
|
|
942
|
+
*/
|
|
943
|
+
/**
|
|
944
|
+
* Stop once, whoever asks (shutdown, handoff, SIGTERM, SIGINT): a second
|
|
945
|
+
* request joins the first. A failed stop is logged once and recorded, so
|
|
946
|
+
* the serve host exits non-zero (`exitCode`).
|
|
947
|
+
*/
|
|
948
|
+
requestStop(reason, mode = 'shutdown') {
|
|
949
|
+
if (this.stopping) {
|
|
950
|
+
attemptSync(() => this.logger.warn('shutdown already in progress', { reason }));
|
|
951
|
+
return this.stopping;
|
|
952
|
+
}
|
|
953
|
+
attemptSync(() => this.logger.info('received daemon exit request', { reason, mode }));
|
|
954
|
+
this.stopping = this.stopReportingFailure(mode);
|
|
955
|
+
return this.stopping;
|
|
956
|
+
}
|
|
957
|
+
/** `stop()` for a requester with no caller to throw to: the failure is recorded (exit status) and reported once. */
|
|
958
|
+
async stopReportingFailure(mode) {
|
|
959
|
+
const stopped = await attempt(() => this.stop(mode));
|
|
960
|
+
if (!stopped.ok) {
|
|
961
|
+
this.stopFailed = true;
|
|
962
|
+
attemptSync(() => this.logger.error('error during shutdown', { failure: valueFreeFailure(stopped.failure) }));
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
/** The serve host's exit status once `start()` has returned: 1 when the stop failed. */
|
|
966
|
+
get exitCode() {
|
|
967
|
+
return this.stopFailed ? 1 : 0;
|
|
968
|
+
}
|
|
969
|
+
async stop(mode = 'shutdown') {
|
|
970
|
+
try {
|
|
971
|
+
if (mode === 'handoff') {
|
|
972
|
+
await this.teardownWithoutStoppingManagedProcesses({ persistState: true, releaseLockFiles: true });
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
await this.stopServingAndChildren();
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
catch (error) {
|
|
979
|
+
this.stopFailed = true;
|
|
980
|
+
throw error;
|
|
981
|
+
}
|
|
982
|
+
finally {
|
|
983
|
+
// The serve host exits only after the selected teardown completes.
|
|
984
|
+
// Shutdown drains children; handoff leaves their tracked runs live.
|
|
985
|
+
// Both release daemon identity before releasing start()'s keep-alive.
|
|
986
|
+
this.keepAliveResolve?.();
|
|
987
|
+
this.keepAliveResolve = undefined;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
async stopServingAndChildren() {
|
|
991
|
+
attemptSync(() => this.logger.info('stopping'));
|
|
992
|
+
const failures = [];
|
|
993
|
+
const release = async (run) => {
|
|
994
|
+
const released = await attempt(async () => { await run(); });
|
|
995
|
+
if (!released.ok)
|
|
996
|
+
failures.push(released.failure);
|
|
997
|
+
};
|
|
998
|
+
// Close the RPC admission boundary before taking any process snapshot.
|
|
999
|
+
// This is idempotent with the explicit shutdown command and also makes
|
|
1000
|
+
// signal/supersession teardown wait for already-accepted mutations.
|
|
1001
|
+
await release(() => this.commandDispatcher.closeAndDrain());
|
|
1002
|
+
await release(() => this.unsubscribeGeneration?.());
|
|
1003
|
+
this.unsubscribeGeneration = undefined;
|
|
1004
|
+
await release(() => this.rpcListener?.stop());
|
|
1005
|
+
this.rpcListener = undefined;
|
|
1006
|
+
// Stop the supervisor ticks (lifecycle disposers; idempotent).
|
|
1007
|
+
await release(() => this.stopTicks());
|
|
1008
|
+
// Clear all monitor tracking maps to prevent memory leaks
|
|
1009
|
+
await release(() => this.healthMonitor.clearTracking());
|
|
1010
|
+
await release(() => this.resourceHealthMonitor.clearTracking());
|
|
1011
|
+
await release(() => this.livenessChecker.clearTracking());
|
|
1012
|
+
// Stop config watcher and process file watchers
|
|
1013
|
+
await release(() => this.configWatcher.stop());
|
|
1014
|
+
await release(() => this.configWatcher.cleanupAllProcessWatchers());
|
|
1015
|
+
// Cancel any pending module retry timers
|
|
1016
|
+
for (const degraded of this.degradedModules.values()) {
|
|
1017
|
+
await release(() => degraded.retryTimer?.());
|
|
1018
|
+
}
|
|
1019
|
+
this.degradedModules.clear();
|
|
1020
|
+
// Stop daemon modules (channel scheduler, surface watcher, platform sync, …)
|
|
1021
|
+
await release(() => this.stopDaemonModules());
|
|
1022
|
+
// CRITICAL FIX: Stop all managed processes before shutting down
|
|
1023
|
+
// This prevents orphans when daemon crashes or is killed
|
|
1024
|
+
attemptSync(() => this.logger.info('stopping managed processes'));
|
|
1025
|
+
const snapshot = await attempt(() => this.store.getAll());
|
|
1026
|
+
if (!snapshot.ok)
|
|
1027
|
+
failures.push(snapshot.failure);
|
|
1028
|
+
const states = snapshot.ok ? snapshot.value : [];
|
|
1029
|
+
// Each child's own stop failure is the cause of the one typed refusal below.
|
|
1030
|
+
const childFailures = [];
|
|
1031
|
+
// Every child at once, so the daemon's stop fits its caller's grace
|
|
1032
|
+
// however many children it supervises.
|
|
1033
|
+
const outcomes = await Promise.all(states
|
|
1034
|
+
.filter((state) => state.status === 'running' || state.status === 'starting')
|
|
1035
|
+
.map(async (state) => {
|
|
1036
|
+
attemptSync(() => this.logger.debug('stopping managed process', { processId: state.id }));
|
|
1037
|
+
// Graceful first (SIGTERM to the tree, SIGKILL after the grace), so a
|
|
1038
|
+
// child can unlink its own sockets; then remove the socket PM declared
|
|
1039
|
+
// for it if the child left it behind.
|
|
1040
|
+
const stopped = await attempt(async () => {
|
|
1041
|
+
await this.pm.stop(state.id, { timeout: MANAGED_STOP_GRACE_MS });
|
|
1042
|
+
if (state.socketPath)
|
|
1043
|
+
await this.removeStaleSocket(state.id, state.socketPath);
|
|
1044
|
+
});
|
|
1045
|
+
if (!stopped.ok) {
|
|
1046
|
+
childFailures.push(stopped.failure);
|
|
1047
|
+
attemptSync(() => this.logger.error('failed to stop managed process', {
|
|
1048
|
+
processId: state.id,
|
|
1049
|
+
failure: valueFreeFailure(stopped.failure)
|
|
1050
|
+
}));
|
|
1051
|
+
}
|
|
1052
|
+
return { processId: state.id, stopped: stopped.ok };
|
|
1053
|
+
}));
|
|
1054
|
+
const stoppedCount = outcomes.filter((outcome) => outcome.stopped).length;
|
|
1055
|
+
const notStopped = outcomes.filter((outcome) => !outcome.stopped).map((outcome) => outcome.processId);
|
|
1056
|
+
if (stoppedCount > 0) {
|
|
1057
|
+
attemptSync(() => this.logger.info('managed processes stopped', { count: stoppedCount }));
|
|
1058
|
+
}
|
|
1059
|
+
// Remove PID file
|
|
1060
|
+
const identityReleased = await attempt(() => this.releaseIdentityFiles());
|
|
1061
|
+
if (!identityReleased.ok)
|
|
1062
|
+
failures.push(identityReleased.failure);
|
|
1063
|
+
// Hot reload last: `this.runtime` is its generation-following handle, and
|
|
1064
|
+
// stopping it disposes that handle. Stopped first, every child stop and
|
|
1065
|
+
// the identity-file release above failed "Cannot acquire a disposed
|
|
1066
|
+
// runtime generation", and the children outlived the daemon.
|
|
1067
|
+
const reloadStopped = await attempt(async () => { await this.hotReload?.stop(); });
|
|
1068
|
+
if (!reloadStopped.ok)
|
|
1069
|
+
failures.push(reloadStopped.failure);
|
|
1070
|
+
if (notStopped.length > 0) {
|
|
1071
|
+
// Partial success is a failure: the serve host exits non-zero.
|
|
1072
|
+
failures.push(new CapabilityError('The PM daemon stopped, but some managed processes did not.', 'INTERNAL', {
|
|
1073
|
+
reason: 'pm-daemon-children-not-stopped',
|
|
1074
|
+
details: { processIds: notStopped },
|
|
1075
|
+
cause: childFailures.length === 1 ? childFailures[0] : new AggregateError(childFailures, 'Managed process stops failed.')
|
|
1076
|
+
}));
|
|
1077
|
+
}
|
|
1078
|
+
if (failures.length === 1)
|
|
1079
|
+
throw failures[0];
|
|
1080
|
+
if (failures.length > 1)
|
|
1081
|
+
throw new AggregateError(failures, 'PM daemon shutdown failed.');
|
|
1082
|
+
attemptSync(() => this.logger.info('stopped'));
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Write PID file
|
|
1086
|
+
* Simple PID file creation - daemon lock enforcement happens via socket binding
|
|
1087
|
+
*/
|
|
1088
|
+
/**
|
|
1089
|
+
* Refresh the pid file's mtime so the client's 5-minute staleness window
|
|
1090
|
+
* measures liveness. Never resurrects or overwrites a pid file this daemon
|
|
1091
|
+
* no longer owns — if it's gone or names another pid, a takeover is in
|
|
1092
|
+
* progress and the supersession check owns the response.
|
|
1093
|
+
*/
|
|
1094
|
+
async heartbeatPidFile() {
|
|
1095
|
+
const pid = await this.hostPid();
|
|
1096
|
+
const files = await this.hostFiles();
|
|
1097
|
+
const current = await readIfPresent(files, this.pidFile);
|
|
1098
|
+
if (current === null || current.trim() !== pid.toString())
|
|
1099
|
+
return;
|
|
1100
|
+
await files.writeFile(this.pidFile, pid.toString(), { mode: 0o600 });
|
|
1101
|
+
}
|
|
1102
|
+
/** The supplied host's PID, admitted before PM uses it as ownership evidence. */
|
|
1103
|
+
async hostPid() {
|
|
1104
|
+
const pid = (await getRuntimeHostIdentity(this.runtime)).currentPid();
|
|
1105
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
1106
|
+
throw new CapabilityError('The selected host supplied an invalid process identity.', 'INVALID_INPUT', {
|
|
1107
|
+
reason: 'pm-host-pid-invalid', retryable: false
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
return pid;
|
|
1111
|
+
}
|
|
1112
|
+
/** The host filesystem the daemon's runtime resolves: the pid file and its directories are host facts at absolute paths. */
|
|
1113
|
+
hostFiles() {
|
|
1114
|
+
return resolveFileSystemAdapter(this.runtime, { binding: false });
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* One supersession check: do the pid file and listening endpoint still belong to
|
|
1118
|
+
* this process? Two consecutive failures are required before exiting so a
|
|
1119
|
+
* transient mid-rewrite read can't kill a healthy daemon.
|
|
1120
|
+
*
|
|
1121
|
+
* @returns true when the daemon should exit (superseded/culled).
|
|
1122
|
+
*/
|
|
1123
|
+
async tickSupersession() {
|
|
1124
|
+
const pid = await this.hostPid();
|
|
1125
|
+
// A removed pid file (ENOENT) is a cull: not owned.
|
|
1126
|
+
const probed = await attempt(async () => {
|
|
1127
|
+
const pidText = await readIfPresent(await this.hostFiles(), this.pidFile);
|
|
1128
|
+
return pidText?.trim() === pid.toString() && (await canConnectToPMSocket(this.runtime, this.socketPath, 500));
|
|
1129
|
+
});
|
|
1130
|
+
// An unreadable pid file or a failing socket probe counts as a strike,
|
|
1131
|
+
// and is reported: two in a row end this daemon as superseded.
|
|
1132
|
+
if (!probed.ok)
|
|
1133
|
+
this.logger.warn('daemon ownership probe failed', { failure: valueFreeFailure(probed.failure) });
|
|
1134
|
+
const owned = probed.ok && probed.value;
|
|
1135
|
+
if (owned) {
|
|
1136
|
+
this.supersessionStrikes = 0;
|
|
1137
|
+
return false;
|
|
1138
|
+
}
|
|
1139
|
+
this.supersessionStrikes += 1;
|
|
1140
|
+
this.logger.warn('daemon ownership check failed', {
|
|
1141
|
+
strikes: this.supersessionStrikes,
|
|
1142
|
+
pidFile: this.pidFile,
|
|
1143
|
+
socketPath: this.socketPath
|
|
1144
|
+
});
|
|
1145
|
+
return this.supersessionStrikes >= 2;
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Stop everything EXCEPT managed processes: timers, config watcher,
|
|
1149
|
+
* daemon modules, the RPC listener. Optionally persist store state and
|
|
1150
|
+
* release the pid file/socket. Shared by exitSuperseded() (never
|
|
1151
|
+
* persists or releases — the incumbent daemon owns that world) and
|
|
1152
|
+
* handleFatalError() (a genuine crash with no incumbent, so state and
|
|
1153
|
+
* the pid file/socket must be released or nothing else ever will).
|
|
1154
|
+
*/
|
|
1155
|
+
async teardownWithoutStoppingManagedProcesses(options) {
|
|
1156
|
+
const failures = [];
|
|
1157
|
+
// Supersession/fatal teardown releases infrastructure without stopping managed children.
|
|
1158
|
+
for (const release of [
|
|
1159
|
+
() => this.commandDispatcher.closeAndDrain(),
|
|
1160
|
+
async () => {
|
|
1161
|
+
await this.unsubscribeGeneration?.();
|
|
1162
|
+
this.unsubscribeGeneration = undefined;
|
|
1163
|
+
},
|
|
1164
|
+
() => this.stopTicks(),
|
|
1165
|
+
() => this.configWatcher.stop(),
|
|
1166
|
+
() => this.configWatcher.cleanupAllProcessWatchers(),
|
|
1167
|
+
() => this.stopDaemonModules(),
|
|
1168
|
+
() => this.rpcListener?.stop()
|
|
1169
|
+
]) {
|
|
1170
|
+
const released = await attempt(async () => { await release(); });
|
|
1171
|
+
if (!released.ok)
|
|
1172
|
+
failures.push(released.failure);
|
|
1173
|
+
}
|
|
1174
|
+
if (options.persistState) {
|
|
1175
|
+
// State is persisted immediately on every SQLite write; there is
|
|
1176
|
+
// no buffered snapshot left to flush here.
|
|
1177
|
+
attemptSync(() => this.logger.debug('state persistence is immediate (SQLite); nothing to flush'));
|
|
1178
|
+
}
|
|
1179
|
+
if (options.releaseLockFiles) {
|
|
1180
|
+
// Socket first: removeSocketFile()'s ownership check reads the pid
|
|
1181
|
+
// file and compares its contents to the supplied host PID — reversing this
|
|
1182
|
+
// order would have removePidFile() truncate the pid file first,
|
|
1183
|
+
// so the socket check would read an empty string, treat it as
|
|
1184
|
+
// "owned by another process", and leave the socket behind.
|
|
1185
|
+
const released = await attempt(() => this.releaseIdentityFiles());
|
|
1186
|
+
if (!released.ok)
|
|
1187
|
+
failures.push(released.failure);
|
|
1188
|
+
}
|
|
1189
|
+
if (failures.length === 1)
|
|
1190
|
+
throw failures[0];
|
|
1191
|
+
if (failures.length > 1)
|
|
1192
|
+
throw new AggregateError(failures, 'PM daemon infrastructure teardown failed.');
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Minimal teardown + exit for a superseded daemon. Deliberately NOT
|
|
1196
|
+
* `stop()`: the incumbent daemon now owns the managed processes (adopted
|
|
1197
|
+
* via the persisted store on its reconcileState), the pid file, and the
|
|
1198
|
+
* socket path. Killing children, saving state, or removing the pid file
|
|
1199
|
+
* here would corrupt the incumbent's world — the exact zombie-vs-incumbent
|
|
1200
|
+
* fight this check exists to end.
|
|
1201
|
+
*/
|
|
1202
|
+
async exitSuperseded() {
|
|
1203
|
+
const pid = await this.hostPid();
|
|
1204
|
+
attemptSync(() => this.logger.warn('superseded by another daemon (pid file / socket no longer ours) — exiting without touching managed processes', { pid, pidFile: this.pidFile, socketPath: this.socketPath }));
|
|
1205
|
+
try {
|
|
1206
|
+
await this.teardownWithoutStoppingManagedProcesses({ persistState: false, releaseLockFiles: false });
|
|
1207
|
+
}
|
|
1208
|
+
finally {
|
|
1209
|
+
this.keepAliveResolve?.();
|
|
1210
|
+
this.keepAliveResolve = undefined;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Handle an uncaughtException/unhandledRejection: log with the stack,
|
|
1215
|
+
* persist state, release the pid file/socket, and tear down WITHOUT
|
|
1216
|
+
* stopping managed processes. UNIT-013/#325 established that policy for
|
|
1217
|
+
* daemon supersession (exitSuperseded above); a fatal error in this
|
|
1218
|
+
* process is not a reason to take Drew's whole dev stack down with it —
|
|
1219
|
+
* that was the 2026-09-02 incident: an uncaught ENOENT from a preBuild
|
|
1220
|
+
* hook reached daemon.ts's uncaughtException handler, which called the
|
|
1221
|
+
* full `stop()` and killed every managed process. Unlike exitSuperseded,
|
|
1222
|
+
* there is no incumbent here, so state and the pid file/socket ARE
|
|
1223
|
+
* released — nothing else will. It does not end the process; the host
|
|
1224
|
+
* (its fatal-failure behaviour) owns that, so this stays testable.
|
|
1225
|
+
*/
|
|
1226
|
+
async handleFatalError(reason, error) {
|
|
1227
|
+
attemptSync(() => this.logger.error(`fatal error (${reason})`, { failure: valueFreeFailure(error) }));
|
|
1228
|
+
await this.teardownWithoutStoppingManagedProcesses({
|
|
1229
|
+
persistState: true,
|
|
1230
|
+
releaseLockFiles: true
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
async writePidFile() {
|
|
1234
|
+
const pid = await this.hostPid();
|
|
1235
|
+
const written = await attempt(async () => {
|
|
1236
|
+
// UNIT-020-C (root cause): a losing daemon start() must never clobber a
|
|
1237
|
+
// still-alive winner's pid file. cleanupStaleSocketIfNeeded() only guards
|
|
1238
|
+
// this early, before descriptor discovery, so a racing daemon can still
|
|
1239
|
+
// reach here after the winner already wrote and bound. Refuse to
|
|
1240
|
+
// overwrite a pid file naming a different, still-running pid; let
|
|
1241
|
+
// start() fail loudly instead of corrupting the incumbent's identity
|
|
1242
|
+
// (the failure this guards against: the loser used to overwrite the
|
|
1243
|
+
// winner's pid file here, then its own bind-failure cleanup truncated
|
|
1244
|
+
// that entry to empty, which the winner's tickSupersession read as
|
|
1245
|
+
// "superseded" and exited on).
|
|
1246
|
+
const files = await this.hostFiles();
|
|
1247
|
+
const existing = await readIfPresent(files, this.pidFile);
|
|
1248
|
+
if (existing !== null) {
|
|
1249
|
+
const existingPid = Number(existing.trim());
|
|
1250
|
+
if (Number.isInteger(existingPid) &&
|
|
1251
|
+
existingPid !== pid &&
|
|
1252
|
+
(await isProcessRunning(this.runtime, existingPid))) {
|
|
1253
|
+
throw new CapabilityError(`PID file ${this.pidFile} is owned by a live process (PID ${existingPid}); refusing to overwrite. ` +
|
|
1254
|
+
`Another daemon may already be running.`, 'CONFLICT', { reason: 'pm-daemon-pid-file-owned', details: { pidFile: this.pidFile, pid: existingPid } });
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
await files.writeFile(this.pidFile, pid.toString(), { mode: 0o600 });
|
|
1258
|
+
this.logger.debug('pid file written', { pidFile: this.pidFile });
|
|
1259
|
+
});
|
|
1260
|
+
if (!written.ok) {
|
|
1261
|
+
this.logger.error('failed to write pid file', {
|
|
1262
|
+
pidFile: this.pidFile,
|
|
1263
|
+
failure: valueFreeFailure(written.failure)
|
|
1264
|
+
});
|
|
1265
|
+
throw written.failure;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Remove PID file
|
|
1270
|
+
* Note: Web Locks API automatically releases lock when process exits
|
|
1271
|
+
*
|
|
1272
|
+
* UNIT-020-C: Only remove/truncate the pid file if it contains this process's pid.
|
|
1273
|
+
* When concurrent launchers race, the loser must not corrupt the winner's pid file.
|
|
1274
|
+
*/
|
|
1275
|
+
/**
|
|
1276
|
+
* Release the daemon's identity files in the only safe order: the socket
|
|
1277
|
+
* first, then the pid file. removeSocketFile()'s ownership check reads the
|
|
1278
|
+
* pid file, so removing the pid file first left the socket behind and the
|
|
1279
|
+
* next daemon failed to bind it ("Failed to listen at …"). Shared by stop()
|
|
1280
|
+
* and the managed-process-safe teardown.
|
|
1281
|
+
*/
|
|
1282
|
+
async releaseIdentityFiles() {
|
|
1283
|
+
// Both run even when the first fails; each failure is reported.
|
|
1284
|
+
const failures = [];
|
|
1285
|
+
for (const [name, release] of [
|
|
1286
|
+
['socket', () => this.removeSocketFile()],
|
|
1287
|
+
['pid file', () => this.removePidFile()]
|
|
1288
|
+
]) {
|
|
1289
|
+
const released = await attempt(release);
|
|
1290
|
+
if (!released.ok) {
|
|
1291
|
+
failures.push(released.failure);
|
|
1292
|
+
attemptSync(() => this.logger.warn(`daemon ${name} release failed`, { failure: valueFreeFailure(released.failure) }));
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
if (failures.length === 1)
|
|
1296
|
+
throw failures[0];
|
|
1297
|
+
if (failures.length > 1)
|
|
1298
|
+
throw new AggregateError(failures, 'Daemon identity release failed.');
|
|
1299
|
+
}
|
|
1300
|
+
/** Truncate this daemon's pid file (never another's). A write failure propagates to the caller. */
|
|
1301
|
+
async removePidFile() {
|
|
1302
|
+
const pid = await this.hostPid();
|
|
1303
|
+
const files = await this.hostFiles();
|
|
1304
|
+
const pidContent = await readIfPresent(files, this.pidFile);
|
|
1305
|
+
if (pidContent !== null && Number(pidContent.trim()) !== pid) {
|
|
1306
|
+
// Pid file is owned by another process; leave it untouched
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
// Truncate the PID file (lock auto-released on process exit)
|
|
1310
|
+
await files.writeFile(this.pidFile, '', { mode: 0o600 });
|
|
1311
|
+
attemptSync(() => this.logger.debug('pid file removed', { pidFile: this.pidFile }));
|
|
1312
|
+
}
|
|
1313
|
+
async removeSocketFile() {
|
|
1314
|
+
const pid = await this.hostPid();
|
|
1315
|
+
// No pid file: this daemon no longer owns the socket name.
|
|
1316
|
+
const pidContent = await readIfPresent(await this.hostFiles(), this.pidFile);
|
|
1317
|
+
if (pidContent === null)
|
|
1318
|
+
return;
|
|
1319
|
+
if (pidContent.trim() !== pid.toString())
|
|
1320
|
+
return;
|
|
1321
|
+
await removeSocket(this.runtime, this.socketPath);
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Ensure ~/.vibes paths exist and are user-writable
|
|
1325
|
+
*/
|
|
1326
|
+
async ensurePathPermissions() {
|
|
1327
|
+
const base = getVibesDir({ roots: this.roots });
|
|
1328
|
+
const sockDir = this.runtimePath.join(base, 'pm', 'sock');
|
|
1329
|
+
const logsDir = this.runtimePath.join(base, 'logs');
|
|
1330
|
+
const pmDir = this.runtimePath.join(base, 'pm');
|
|
1331
|
+
const runtimeSocketDir = getSocketBasePath({ roots: this.roots, runtimePath: this.runtimePath });
|
|
1332
|
+
const files = await this.hostFiles();
|
|
1333
|
+
// A directory the daemon cannot create fails its start here, by name. A
|
|
1334
|
+
// new directory is created owner-only, and one that already exists is
|
|
1335
|
+
// tightened to owner-only through the filesystem kind's `chmod` (a host
|
|
1336
|
+
// without POSIX modes, Windows, has none to pin).
|
|
1337
|
+
const pinsModes = this.runtime.localEnvironment.getPlatform?.() !== 'win32';
|
|
1338
|
+
for (const dir of [base, sockDir, logsDir, pmDir, runtimeSocketDir]) {
|
|
1339
|
+
await files.mkdir(dir, { recursive: true, mode: 0o700 });
|
|
1340
|
+
if (pinsModes)
|
|
1341
|
+
await chmodChecked(files, dir, 0o700);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Get daemon health information
|
|
1346
|
+
* Lightweight check for monitoring and status display
|
|
1347
|
+
*
|
|
1348
|
+
* CRITICAL FIX: If the store is throwing (e.g. SQLite disk I/O error),
|
|
1349
|
+
* return healthy:false so callers know the daemon is alive but sick.
|
|
1350
|
+
* A 200 response with healthy:false lets canConnectToPMSocket() decide
|
|
1351
|
+
* whether to treat the daemon as reachable.
|
|
1352
|
+
*/
|
|
1353
|
+
async getHealth() {
|
|
1354
|
+
const pid = await this.hostPid();
|
|
1355
|
+
const counted = await attempt(async () => {
|
|
1356
|
+
// `__`-prefixed rows are store bookkeeping (e.g. __lastStoreCleanup),
|
|
1357
|
+
// not processes. `pm status` / `pm list` already hide them; the
|
|
1358
|
+
// daemon's own count disagreed with those surfaces by exactly that
|
|
1359
|
+
// many (measured 2026-09-06: 45 here vs 44 there).
|
|
1360
|
+
const states = (await this.store.getAll()).filter((s) => isManagedProcessId(s.id));
|
|
1361
|
+
return { total: states.length, running: states.filter((s) => s.status === 'running').length };
|
|
1362
|
+
});
|
|
1363
|
+
const version = await getPMVersion(this.runtime);
|
|
1364
|
+
const { workspacePath, toolingId } = admittedWorkspaceIdentity(this.workspaceRoot);
|
|
1365
|
+
if (!counted.ok) {
|
|
1366
|
+
this.logger.error('health check failed: store unreachable', { failure: valueFreeFailure(counted.failure) });
|
|
1367
|
+
return {
|
|
1368
|
+
healthy: false,
|
|
1369
|
+
uptime: Date.now() - this.startTime,
|
|
1370
|
+
version,
|
|
1371
|
+
processCount: 0,
|
|
1372
|
+
runningCount: 0,
|
|
1373
|
+
timestamp: new Date(),
|
|
1374
|
+
pid,
|
|
1375
|
+
error: failureText(counted.failure)
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
const health = {
|
|
1379
|
+
healthy: true,
|
|
1380
|
+
uptime: Date.now() - this.startTime,
|
|
1381
|
+
version,
|
|
1382
|
+
processCount: counted.value.total,
|
|
1383
|
+
runningCount: counted.value.running,
|
|
1384
|
+
timestamp: new Date(),
|
|
1385
|
+
pid,
|
|
1386
|
+
commands: this.commandDispatcher.commandCounts(),
|
|
1387
|
+
taskSupervision: { version: 1, scope: PmTaskScopeSchema.parse({ workspacePath, toolingId }) }
|
|
1388
|
+
};
|
|
1389
|
+
if (this.degradedModules.size > 0) {
|
|
1390
|
+
health.degradedModules = Array.from(this.degradedModules.values()).map((d) => ({
|
|
1391
|
+
id: d.id,
|
|
1392
|
+
error: failureText(d.error),
|
|
1393
|
+
attempts: d.attempts,
|
|
1394
|
+
nextRetryAt: d.nextRetryAt
|
|
1395
|
+
}));
|
|
1396
|
+
}
|
|
1397
|
+
return health;
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* A PID file naming a live process stays; a stale or unparseable one is
|
|
1401
|
+
* removed. Liveness is the host process service's answer; a PID file that
|
|
1402
|
+
* cannot be read or removed, or a process table that cannot be read, fails
|
|
1403
|
+
* the start instead of being overwritten blind.
|
|
1404
|
+
*/
|
|
1405
|
+
async cleanupStalePidIfNeeded() {
|
|
1406
|
+
const files = await this.hostFiles();
|
|
1407
|
+
const content = await readIfPresent(files, this.pidFile);
|
|
1408
|
+
if (content === null)
|
|
1409
|
+
return;
|
|
1410
|
+
const pid = parseInt(content.trim(), 10);
|
|
1411
|
+
if (Number.isInteger(pid) && (await isProcessRunning(this.runtime, pid)))
|
|
1412
|
+
return;
|
|
1413
|
+
// Gone already (ENOENT) is the goal; any other removal failure fails the start.
|
|
1414
|
+
const removed = await attempt(() => files.remove(this.pidFile));
|
|
1415
|
+
if (!removed.ok && !(hasErrnoCode(removed.failure) && removed.failure.code === 'ENOENT'))
|
|
1416
|
+
throw removed.failure;
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Do NOT delete a socket that is actively bound by a running daemon: a
|
|
1420
|
+
* second launcher that races to the same socket must fail fast, not stomp
|
|
1421
|
+
* on the incumbent. The probe answers "no" only for confirmed absence or a
|
|
1422
|
+
* daemon that did not answer (and the socket service refuses to remove an
|
|
1423
|
+
* endpoint that is still listening); a non-socket file at the path, a
|
|
1424
|
+
* permission refusal, or a removal failure fails the start typed.
|
|
1425
|
+
*/
|
|
1426
|
+
async cleanupStaleSocketIfNeeded() {
|
|
1427
|
+
if (await canConnectToPMSocket(this.runtime, this.socketPath, 500)) {
|
|
1428
|
+
const incumbentPid = await readDaemonPid(this.runtime, this.pidFile);
|
|
1429
|
+
const detail = incumbentPid ? ` (PID ${incumbentPid})` : '';
|
|
1430
|
+
throw new CapabilityError(`PM daemon already running on socket ${this.socketPath}${detail}. ` +
|
|
1431
|
+
`Use 'vibes pm daemon restart' if you need to replace it.`, 'CONFLICT', { reason: 'pm-daemon-already-running', details: { socketPath: this.socketPath, pid: incumbentPid ?? null } });
|
|
1432
|
+
}
|
|
1433
|
+
await removeSocket(this.runtime, this.socketPath);
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Run scheduled cleanup of idle and ephemeral processes
|
|
1437
|
+
*/
|
|
1438
|
+
async runScheduledCleanup() {
|
|
1439
|
+
// Clean up idle processes (configured with idleTimeoutMs)
|
|
1440
|
+
const stopped = await this.pm.cleanupIdleProcesses();
|
|
1441
|
+
if (stopped.length > 0) {
|
|
1442
|
+
this.logger.info('idle cleanup removed processes', { processIds: stopped });
|
|
1443
|
+
}
|
|
1444
|
+
// Clean up ephemeral processes (ad-hoc processes not in vibes.pm.ts)
|
|
1445
|
+
const cleaned = await this.pm.cleanupEphemeralProcesses();
|
|
1446
|
+
if (cleaned.length > 0) {
|
|
1447
|
+
this.logger.info('ephemeral cleanup removed processes', { processIds: cleaned });
|
|
1448
|
+
}
|
|
1449
|
+
// CRITICAL FIX (Issue 3.2): Clean up old state entries (run once per day)
|
|
1450
|
+
// Track last cleanup time to avoid running too frequently. The
|
|
1451
|
+
// timestamp lives in the store's pm_kv table — it used to be a fake
|
|
1452
|
+
// `__lastStoreCleanup` process_states row, which every consumer had
|
|
1453
|
+
// to remember to filter out of counts and listings.
|
|
1454
|
+
const now = Date.now();
|
|
1455
|
+
const lastStoreCleanup = Number((await this.store.getMeta('lastStoreCleanup')) ?? 0) || 0;
|
|
1456
|
+
const oneDayMs = 24 * 60 * 60 * 1000;
|
|
1457
|
+
if (now - lastStoreCleanup > oneDayMs) {
|
|
1458
|
+
const swept = await attempt(async () => {
|
|
1459
|
+
const cleaned = await this.store.cleanupOldEntries(30); // 30 day retention
|
|
1460
|
+
if (cleaned.processes > 0 || cleaned.resources > 0) {
|
|
1461
|
+
this.logger.info('cleaned up old state entries', {
|
|
1462
|
+
processes: cleaned.processes,
|
|
1463
|
+
resources: cleaned.resources
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
// Update last cleanup timestamp
|
|
1467
|
+
await this.store.setMeta('lastStoreCleanup', String(now));
|
|
1468
|
+
// Retire the legacy fake-row sentinel from pre-kv databases so
|
|
1469
|
+
// it stops haunting counts.
|
|
1470
|
+
await this.store.delete('__lastStoreCleanup');
|
|
1471
|
+
});
|
|
1472
|
+
if (!swept.ok) {
|
|
1473
|
+
this.logger.error('failed to clean up old state entries', { failure: valueFreeFailure(swept.failure) });
|
|
1474
|
+
}
|
|
1475
|
+
// Process logs past the declared retention (`pm.process-capture` maxAge) age out:
|
|
1476
|
+
// archives whether or not a row exists, a current log only when none holds it.
|
|
1477
|
+
const aged = await attempt(async () => {
|
|
1478
|
+
const maxAgeMs = await readRotationMaxAge(this.runtime, PM_CAPTURE_ROTATION_POLICY);
|
|
1479
|
+
if (maxAgeMs === undefined)
|
|
1480
|
+
return;
|
|
1481
|
+
const expired = await this.pm.cleanupExpiredLogs(maxAgeMs);
|
|
1482
|
+
if (expired.cleaned.length > 0 || expired.errors.length > 0) {
|
|
1483
|
+
this.logger.info('aged out process logs', { removed: expired.cleaned.length, failed: expired.errors.map((error) => error.id) });
|
|
1484
|
+
}
|
|
1485
|
+
});
|
|
1486
|
+
if (!aged.ok) {
|
|
1487
|
+
this.logger.error('failed to age out process logs', { failure: valueFreeFailure(aged.failure) });
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
// Rotate oversized logs of live processes. LifecycleService only rotates
|
|
1491
|
+
// at start(), so without this a long-running child's log grew unbounded
|
|
1492
|
+
// until its next restart.
|
|
1493
|
+
const rotated = await attempt(() => this.rotateLiveProcessLogs());
|
|
1494
|
+
if (!rotated.ok) {
|
|
1495
|
+
this.logger.error('process log rotation sweep failed', { failure: valueFreeFailure(rotated.failure) });
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Rotate `<id>.stdout` / `<id>.stderr` of every running or starting
|
|
1500
|
+
* process that crossed the size threshold, and the daemon's own stdio
|
|
1501
|
+
* logs, through the logging owner under the declared policy (L1).
|
|
1502
|
+
*/
|
|
1503
|
+
/** The declared `pm.process-capture` rotation policy, read from the logging config on each sweep. */
|
|
1504
|
+
captureRotationPolicy() {
|
|
1505
|
+
return readRotationPolicy(this.runtime, PM_CAPTURE_ROTATION_POLICY);
|
|
1506
|
+
}
|
|
1507
|
+
async rotateLiveProcessLogs() {
|
|
1508
|
+
const states = await this.store.getAll();
|
|
1509
|
+
const liveIds = states
|
|
1510
|
+
.filter((state) => state.status === 'running' || state.status === 'starting')
|
|
1511
|
+
.map((state) => state.id);
|
|
1512
|
+
if (liveIds.length === 0)
|
|
1513
|
+
return;
|
|
1514
|
+
const policy = await this.captureRotationPolicy();
|
|
1515
|
+
const { rotated, failed } = await rotateOversizedProcessLogs({
|
|
1516
|
+
runtime: this.runtime,
|
|
1517
|
+
logDir: this.processLogDir,
|
|
1518
|
+
processIds: liveIds,
|
|
1519
|
+
policy
|
|
1520
|
+
});
|
|
1521
|
+
// The daemon's own stdio logs are not `<id>.stdout` files; rotate them at
|
|
1522
|
+
// their real paths under this daemon's roots (D17).
|
|
1523
|
+
const daemonRotation = await rotateOversizedDaemonLogs({ runtime: this.runtime, workspace: this.workspaceRoot, roots: this.roots, policy });
|
|
1524
|
+
rotated.push(...daemonRotation.rotated);
|
|
1525
|
+
failed.push(...daemonRotation.failed);
|
|
1526
|
+
for (const entry of rotated) {
|
|
1527
|
+
this.logger.info('rotated oversized process log', entry);
|
|
1528
|
+
}
|
|
1529
|
+
for (const entry of failed) {
|
|
1530
|
+
this.logger.warn('process log rotation failed', {
|
|
1531
|
+
processId: entry.processId,
|
|
1532
|
+
path: entry.path,
|
|
1533
|
+
failure: valueFreeFailure(entry.error)
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
/**
|
|
1538
|
+
* Hand the orphan scanner the current registry. `OrphanScannerDeps.configs`
|
|
1539
|
+
* is a plain Map behind a `setConfigs` setter (no live accessor), and the
|
|
1540
|
+
* daemon constructed the scanner without it and never called the setter —
|
|
1541
|
+
* so `enableAdoption: true` matched against an empty Map forever.
|
|
1542
|
+
*/
|
|
1543
|
+
async syncOrphanScannerConfigs() {
|
|
1544
|
+
const configs = await this.pm.getAllConfigs();
|
|
1545
|
+
this.orphanScanner.setConfigs(new Map(configs.map((config) => [config.id, config])));
|
|
1546
|
+
}
|
|
1547
|
+
/** One orphan-scan tick: refresh configs from the registry, then scan. */
|
|
1548
|
+
async runOrphanScan() {
|
|
1549
|
+
await this.syncOrphanScannerConfigs();
|
|
1550
|
+
await this.orphanScanner.scanAndKillOrphans();
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Check if daemon socket is connectable via HTTP health check.
|
|
1555
|
+
*
|
|
1556
|
+
* Validates the response body to ensure the daemon is not merely alive but
|
|
1557
|
+
* actually healthy (store is operational). A daemon with a corrupted SQLite
|
|
1558
|
+
* file will respond 200 but with { healthy: false }, so surface-level
|
|
1559
|
+
* `response.ok` is not enough.
|
|
1560
|
+
*/
|
|
1561
|
+
/**
|
|
1562
|
+
* Get daemon log file contents
|
|
1563
|
+
* Reads from the handed Runtime's output and preserves read failures.
|
|
1564
|
+
*/
|
|
1565
|
+
export async function getDaemonLogs(runtime, options = {}) {
|
|
1566
|
+
const lines = await readPMDaemonLogTail(runtime, options.lines ?? 50);
|
|
1567
|
+
if (lines.length === 0) {
|
|
1568
|
+
return 'No daemon logs available';
|
|
1569
|
+
}
|
|
1570
|
+
return lines.join('\n');
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Entry point for daemon. `workspaceRoot` is the admitted workspace the serve
|
|
1574
|
+
* body resolved (`pm/admitted-workspace`); the daemon supervises exactly it.
|
|
1575
|
+
*/
|
|
1576
|
+
async function main(options) {
|
|
1577
|
+
// The serve host the command was handed registered the host's
|
|
1578
|
+
// paths/runtime-path; resolve it from that runtime and hand both to the daemon.
|
|
1579
|
+
const daemon = new PMDaemon({
|
|
1580
|
+
runtime: options.runtime,
|
|
1581
|
+
runtimePath: await getRuntimePath(options.runtime),
|
|
1582
|
+
workspaceRoot: options.workspaceRoot
|
|
1583
|
+
});
|
|
1584
|
+
const logger = getPMDaemonLogger(options.runtime, 'global');
|
|
1585
|
+
// Report the inherited RLIMIT_NOFILE so low limits surface in one obvious
|
|
1586
|
+
// place instead of leaking out later as cryptic ENFILE errors from vite
|
|
1587
|
+
// or svelte-check. pm.daemon.start wraps this process with a raised
|
|
1588
|
+
// ulimit; if we still see a low number here, something stripped the wrap.
|
|
1589
|
+
// Null: the host has no descriptor limit to report (win32). A probe that
|
|
1590
|
+
// cannot run is reported as such and does not stop the daemon.
|
|
1591
|
+
let nofile = null;
|
|
1592
|
+
const limit = await attempt(() => readFileDescriptorLimit(options.runtime));
|
|
1593
|
+
if (limit.ok) {
|
|
1594
|
+
nofile = limit.value;
|
|
1595
|
+
}
|
|
1596
|
+
else if (isCapabilityError(limit.failure) && limit.failure.reason === 'process-table-unavailable') {
|
|
1597
|
+
logger.warn('file descriptor limit unreadable on this host', { reason: limit.failure.reason });
|
|
1598
|
+
}
|
|
1599
|
+
else {
|
|
1600
|
+
throw limit.failure;
|
|
1601
|
+
}
|
|
1602
|
+
if (nofile !== null && Number.isFinite(nofile)) {
|
|
1603
|
+
if (nofile < MIN_ACCEPTABLE_NOFILE) {
|
|
1604
|
+
logger.warn('file descriptor limit below threshold', {
|
|
1605
|
+
current: nofile,
|
|
1606
|
+
recommended: RECOMMENDED_NOFILE,
|
|
1607
|
+
remediation: fileDescriptorLimitRemediation(nofile)
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
else {
|
|
1611
|
+
logger.info('file descriptor limit', { current: nofile });
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
// Termination signals and fatal failures arrive through the serve host's
|
|
1615
|
+
// declared host signals (runtime/host signals), never process listeners;
|
|
1616
|
+
// the exit status returns to the `pm daemon serve` host, which owns exit.
|
|
1617
|
+
const signals = await getRuntimeHostSignals(options.runtime);
|
|
1618
|
+
const subscriptions = [
|
|
1619
|
+
signals.subscribe('SIGTERM', () => void daemon.requestStop('SIGTERM')),
|
|
1620
|
+
signals.subscribe('SIGINT', () => void daemon.requestStop('SIGINT'))
|
|
1621
|
+
];
|
|
1622
|
+
// Report-only (the host still prints and exits non-zero): a fatal error
|
|
1623
|
+
// persists state and releases the pid file/socket WITHOUT stopping managed
|
|
1624
|
+
// processes — a fatal error in this process is not a reason to take the
|
|
1625
|
+
// whole dev stack down with it (2026-09-02, see PMDaemon.handleFatalError).
|
|
1626
|
+
const fatal = signals.subscribeFatal?.((kind, error) => {
|
|
1627
|
+
void (async () => {
|
|
1628
|
+
const tornDown = await attempt(() => daemon.handleFatalError(kind, CaughtFailureSchema.parse(error)));
|
|
1629
|
+
if (!tornDown.ok)
|
|
1630
|
+
logger.error('fatal teardown failed', { failure: valueFreeFailure(tornDown.failure) });
|
|
1631
|
+
})();
|
|
1632
|
+
});
|
|
1633
|
+
if (fatal)
|
|
1634
|
+
subscriptions.push(fatal);
|
|
1635
|
+
else {
|
|
1636
|
+
// Typed absence: this host declares no fatal-failure reports, so a crash
|
|
1637
|
+
// still exits through the host's default, but PM cannot persist state or
|
|
1638
|
+
// release its pid file/socket first.
|
|
1639
|
+
logger.warn('host declares no fatal-failure reports; a crash will not release the pid file or socket', {
|
|
1640
|
+
reason: 'host-fatal-signals-unavailable'
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
const started = await attempt(() => daemon.start());
|
|
1644
|
+
for (const unsubscribe of subscriptions)
|
|
1645
|
+
unsubscribe();
|
|
1646
|
+
if (!started.ok) {
|
|
1647
|
+
logger.error('failed to start', { failure: valueFreeFailure(started.failure) });
|
|
1648
|
+
return 1;
|
|
1649
|
+
}
|
|
1650
|
+
logger.info('shutdown complete', { exitCode: daemon.exitCode });
|
|
1651
|
+
return daemon.exitCode;
|
|
1652
|
+
}
|
|
1653
|
+
export { main as startDaemon };
|
|
1654
|
+
//# sourceMappingURL=daemon.js.map
|