@telora/daemon 0.12.33
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/.env.example +64 -0
- package/README.md +229 -0
- package/build-info.json +4 -0
- package/dist/activity-tracker.d.ts +13 -0
- package/dist/activity-tracker.d.ts.map +1 -0
- package/dist/activity-tracker.js +19 -0
- package/dist/activity-tracker.js.map +1 -0
- package/dist/agent-state.d.ts +45 -0
- package/dist/agent-state.d.ts.map +1 -0
- package/dist/agent-state.js +61 -0
- package/dist/agent-state.js.map +1 -0
- package/dist/audit-hooks.d.ts +12 -0
- package/dist/audit-hooks.d.ts.map +1 -0
- package/dist/audit-hooks.js +45 -0
- package/dist/audit-hooks.js.map +1 -0
- package/dist/auto-update.d.ts +42 -0
- package/dist/auto-update.d.ts.map +1 -0
- package/dist/auto-update.js +96 -0
- package/dist/auto-update.js.map +1 -0
- package/dist/branch-status.d.ts +40 -0
- package/dist/branch-status.d.ts.map +1 -0
- package/dist/branch-status.js +107 -0
- package/dist/branch-status.js.map +1 -0
- package/dist/completion-detector.d.ts +87 -0
- package/dist/completion-detector.d.ts.map +1 -0
- package/dist/completion-detector.js +160 -0
- package/dist/completion-detector.js.map +1 -0
- package/dist/completion-handler.d.ts +48 -0
- package/dist/completion-handler.d.ts.map +1 -0
- package/dist/completion-handler.js +200 -0
- package/dist/completion-handler.js.map +1 -0
- package/dist/condition-evaluators.d.ts +31 -0
- package/dist/condition-evaluators.d.ts.map +1 -0
- package/dist/condition-evaluators.js +416 -0
- package/dist/condition-evaluators.js.map +1 -0
- package/dist/config.d.ts +55 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +311 -0
- package/dist/config.js.map +1 -0
- package/dist/control-state.d.ts +41 -0
- package/dist/control-state.d.ts.map +1 -0
- package/dist/control-state.js +204 -0
- package/dist/control-state.js.map +1 -0
- package/dist/crash-recovery-cleanup.d.ts +21 -0
- package/dist/crash-recovery-cleanup.d.ts.map +1 -0
- package/dist/crash-recovery-cleanup.js +198 -0
- package/dist/crash-recovery-cleanup.js.map +1 -0
- package/dist/crash-recovery-scan.d.ts +19 -0
- package/dist/crash-recovery-scan.d.ts.map +1 -0
- package/dist/crash-recovery-scan.js +145 -0
- package/dist/crash-recovery-scan.js.map +1 -0
- package/dist/crash-recovery-types.d.ts +54 -0
- package/dist/crash-recovery-types.d.ts.map +1 -0
- package/dist/crash-recovery-types.js +13 -0
- package/dist/crash-recovery-types.js.map +1 -0
- package/dist/crash-recovery.d.ts +88 -0
- package/dist/crash-recovery.d.ts.map +1 -0
- package/dist/crash-recovery.js +448 -0
- package/dist/crash-recovery.js.map +1 -0
- package/dist/daemon-logs.d.ts +19 -0
- package/dist/daemon-logs.d.ts.map +1 -0
- package/dist/daemon-logs.js +81 -0
- package/dist/daemon-logs.js.map +1 -0
- package/dist/daemon-process.d.ts +154 -0
- package/dist/daemon-process.d.ts.map +1 -0
- package/dist/daemon-process.js +427 -0
- package/dist/daemon-process.js.map +1 -0
- package/dist/dag-validator.d.ts +52 -0
- package/dist/dag-validator.d.ts.map +1 -0
- package/dist/dag-validator.js +199 -0
- package/dist/dag-validator.js.map +1 -0
- package/dist/delivery-guards.d.ts +41 -0
- package/dist/delivery-guards.d.ts.map +1 -0
- package/dist/delivery-guards.js +195 -0
- package/dist/delivery-guards.js.map +1 -0
- package/dist/delivery-lifecycle.d.ts +110 -0
- package/dist/delivery-lifecycle.d.ts.map +1 -0
- package/dist/delivery-lifecycle.js +353 -0
- package/dist/delivery-lifecycle.js.map +1 -0
- package/dist/delivery-merge.d.ts +17 -0
- package/dist/delivery-merge.d.ts.map +1 -0
- package/dist/delivery-merge.js +89 -0
- package/dist/delivery-merge.js.map +1 -0
- package/dist/dependency-resolver.d.ts +77 -0
- package/dist/dependency-resolver.d.ts.map +1 -0
- package/dist/dependency-resolver.js +337 -0
- package/dist/dependency-resolver.js.map +1 -0
- package/dist/evaluation-context.d.ts +49 -0
- package/dist/evaluation-context.d.ts.map +1 -0
- package/dist/evaluation-context.js +98 -0
- package/dist/evaluation-context.js.map +1 -0
- package/dist/git-activity.d.ts +24 -0
- package/dist/git-activity.d.ts.map +1 -0
- package/dist/git-activity.js +97 -0
- package/dist/git-activity.js.map +1 -0
- package/dist/git-branch.d.ts +33 -0
- package/dist/git-branch.d.ts.map +1 -0
- package/dist/git-branch.js +88 -0
- package/dist/git-branch.js.map +1 -0
- package/dist/git-integration.d.ts +27 -0
- package/dist/git-integration.d.ts.map +1 -0
- package/dist/git-integration.js +82 -0
- package/dist/git-integration.js.map +1 -0
- package/dist/git-merge-helpers.d.ts +48 -0
- package/dist/git-merge-helpers.d.ts.map +1 -0
- package/dist/git-merge-helpers.js +105 -0
- package/dist/git-merge-helpers.js.map +1 -0
- package/dist/git-merge-lock.d.ts +67 -0
- package/dist/git-merge-lock.d.ts.map +1 -0
- package/dist/git-merge-lock.js +157 -0
- package/dist/git-merge-lock.js.map +1 -0
- package/dist/git-merge-strategies.d.ts +39 -0
- package/dist/git-merge-strategies.d.ts.map +1 -0
- package/dist/git-merge-strategies.js +127 -0
- package/dist/git-merge-strategies.js.map +1 -0
- package/dist/git-merge.d.ts +80 -0
- package/dist/git-merge.d.ts.map +1 -0
- package/dist/git-merge.js +373 -0
- package/dist/git-merge.js.map +1 -0
- package/dist/git-state-detector.d.ts +24 -0
- package/dist/git-state-detector.d.ts.map +1 -0
- package/dist/git-state-detector.js +122 -0
- package/dist/git-state-detector.js.map +1 -0
- package/dist/git-types.d.ts +40 -0
- package/dist/git-types.d.ts.map +1 -0
- package/dist/git-types.js +23 -0
- package/dist/git-types.js.map +1 -0
- package/dist/git-utils.d.ts +28 -0
- package/dist/git-utils.d.ts.map +1 -0
- package/dist/git-utils.js +57 -0
- package/dist/git-utils.js.map +1 -0
- package/dist/git.d.ts +24 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +64 -0
- package/dist/git.js.map +1 -0
- package/dist/guard-engine.d.ts +19 -0
- package/dist/guard-engine.d.ts.map +1 -0
- package/dist/guard-engine.js +21 -0
- package/dist/guard-engine.js.map +1 -0
- package/dist/guard-evaluator.d.ts +47 -0
- package/dist/guard-evaluator.d.ts.map +1 -0
- package/dist/guard-evaluator.js +193 -0
- package/dist/guard-evaluator.js.map +1 -0
- package/dist/heartbeat.d.ts +73 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +306 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +493 -0
- package/dist/index.js.map +1 -0
- package/dist/listener-auto-advance.d.ts +29 -0
- package/dist/listener-auto-advance.d.ts.map +1 -0
- package/dist/listener-auto-advance.js +172 -0
- package/dist/listener-auto-advance.js.map +1 -0
- package/dist/listener-review.d.ts +37 -0
- package/dist/listener-review.d.ts.map +1 -0
- package/dist/listener-review.js +217 -0
- package/dist/listener-review.js.map +1 -0
- package/dist/listener.d.ts +57 -0
- package/dist/listener.d.ts.map +1 -0
- package/dist/listener.js +361 -0
- package/dist/listener.js.map +1 -0
- package/dist/log-manager.d.ts +18 -0
- package/dist/log-manager.d.ts.map +1 -0
- package/dist/log-manager.js +18 -0
- package/dist/log-manager.js.map +1 -0
- package/dist/otlp-log-parser.d.ts +21 -0
- package/dist/otlp-log-parser.d.ts.map +1 -0
- package/dist/otlp-log-parser.js +143 -0
- package/dist/otlp-log-parser.js.map +1 -0
- package/dist/otlp-metric-parser.d.ts +20 -0
- package/dist/otlp-metric-parser.d.ts.map +1 -0
- package/dist/otlp-metric-parser.js +113 -0
- package/dist/otlp-metric-parser.js.map +1 -0
- package/dist/otlp-port-manager.d.ts +26 -0
- package/dist/otlp-port-manager.d.ts.map +1 -0
- package/dist/otlp-port-manager.js +130 -0
- package/dist/otlp-port-manager.js.map +1 -0
- package/dist/otlp-receiver.d.ts +51 -0
- package/dist/otlp-receiver.d.ts.map +1 -0
- package/dist/otlp-receiver.js +663 -0
- package/dist/otlp-receiver.js.map +1 -0
- package/dist/otlp-types.d.ts +92 -0
- package/dist/otlp-types.d.ts.map +1 -0
- package/dist/otlp-types.js +133 -0
- package/dist/otlp-types.js.map +1 -0
- package/dist/output-monitor.d.ts +33 -0
- package/dist/output-monitor.d.ts.map +1 -0
- package/dist/output-monitor.js +67 -0
- package/dist/output-monitor.js.map +1 -0
- package/dist/planning-prompt-builder.d.ts +67 -0
- package/dist/planning-prompt-builder.d.ts.map +1 -0
- package/dist/planning-prompt-builder.js +515 -0
- package/dist/planning-prompt-builder.js.map +1 -0
- package/dist/prompt-builder.d.ts +14 -0
- package/dist/prompt-builder.d.ts.map +1 -0
- package/dist/prompt-builder.js +174 -0
- package/dist/prompt-builder.js.map +1 -0
- package/dist/qa-crash-recovery.d.ts +77 -0
- package/dist/qa-crash-recovery.d.ts.map +1 -0
- package/dist/qa-crash-recovery.js +243 -0
- package/dist/qa-crash-recovery.js.map +1 -0
- package/dist/qa-dev-server.d.ts +73 -0
- package/dist/qa-dev-server.d.ts.map +1 -0
- package/dist/qa-dev-server.js +279 -0
- package/dist/qa-dev-server.js.map +1 -0
- package/dist/qa-orchestrator.d.ts +79 -0
- package/dist/qa-orchestrator.d.ts.map +1 -0
- package/dist/qa-orchestrator.js +349 -0
- package/dist/qa-orchestrator.js.map +1 -0
- package/dist/qa-port-allocator.d.ts +34 -0
- package/dist/qa-port-allocator.d.ts.map +1 -0
- package/dist/qa-port-allocator.js +75 -0
- package/dist/qa-port-allocator.js.map +1 -0
- package/dist/qa-provisioner.d.ts +33 -0
- package/dist/qa-provisioner.d.ts.map +1 -0
- package/dist/qa-provisioner.js +141 -0
- package/dist/qa-provisioner.js.map +1 -0
- package/dist/qa-state.d.ts +93 -0
- package/dist/qa-state.d.ts.map +1 -0
- package/dist/qa-state.js +74 -0
- package/dist/qa-state.js.map +1 -0
- package/dist/queries/control-state.d.ts +25 -0
- package/dist/queries/control-state.d.ts.map +1 -0
- package/dist/queries/control-state.js +34 -0
- package/dist/queries/control-state.js.map +1 -0
- package/dist/queries/daemon-connection.d.ts +25 -0
- package/dist/queries/daemon-connection.d.ts.map +1 -0
- package/dist/queries/daemon-connection.js +28 -0
- package/dist/queries/daemon-connection.js.map +1 -0
- package/dist/queries/deliveries.d.ts +100 -0
- package/dist/queries/deliveries.d.ts.map +1 -0
- package/dist/queries/deliveries.js +184 -0
- package/dist/queries/deliveries.js.map +1 -0
- package/dist/queries/git-activity.d.ts +20 -0
- package/dist/queries/git-activity.d.ts.map +1 -0
- package/dist/queries/git-activity.js +22 -0
- package/dist/queries/git-activity.js.map +1 -0
- package/dist/queries/guards.d.ts +47 -0
- package/dist/queries/guards.d.ts.map +1 -0
- package/dist/queries/guards.js +138 -0
- package/dist/queries/guards.js.map +1 -0
- package/dist/queries/index.d.ts +19 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +17 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/issues.d.ts +41 -0
- package/dist/queries/issues.d.ts.map +1 -0
- package/dist/queries/issues.js +67 -0
- package/dist/queries/issues.js.map +1 -0
- package/dist/queries/qa.d.ts +79 -0
- package/dist/queries/qa.d.ts.map +1 -0
- package/dist/queries/qa.js +85 -0
- package/dist/queries/qa.js.map +1 -0
- package/dist/queries/roles.d.ts +13 -0
- package/dist/queries/roles.d.ts.map +1 -0
- package/dist/queries/roles.js +39 -0
- package/dist/queries/roles.js.map +1 -0
- package/dist/queries/schemas.d.ts +777 -0
- package/dist/queries/schemas.d.ts.map +1 -0
- package/dist/queries/schemas.js +391 -0
- package/dist/queries/schemas.js.map +1 -0
- package/dist/queries/sessions.d.ts +64 -0
- package/dist/queries/sessions.d.ts.map +1 -0
- package/dist/queries/sessions.js +100 -0
- package/dist/queries/sessions.js.map +1 -0
- package/dist/queries/shared.d.ts +61 -0
- package/dist/queries/shared.d.ts.map +1 -0
- package/dist/queries/shared.js +187 -0
- package/dist/queries/shared.js.map +1 -0
- package/dist/queries/strategies.d.ts +69 -0
- package/dist/queries/strategies.d.ts.map +1 -0
- package/dist/queries/strategies.js +80 -0
- package/dist/queries/strategies.js.map +1 -0
- package/dist/queries/workflows.d.ts +17 -0
- package/dist/queries/workflows.d.ts.map +1 -0
- package/dist/queries/workflows.js +49 -0
- package/dist/queries/workflows.js.map +1 -0
- package/dist/queries/worktrees.d.ts +38 -0
- package/dist/queries/worktrees.d.ts.map +1 -0
- package/dist/queries/worktrees.js +37 -0
- package/dist/queries/worktrees.js.map +1 -0
- package/dist/self-update.d.ts +94 -0
- package/dist/self-update.d.ts.map +1 -0
- package/dist/self-update.js +438 -0
- package/dist/self-update.js.map +1 -0
- package/dist/session-lifecycle.d.ts +77 -0
- package/dist/session-lifecycle.d.ts.map +1 -0
- package/dist/session-lifecycle.js +379 -0
- package/dist/session-lifecycle.js.map +1 -0
- package/dist/shutdown-state.d.ts +17 -0
- package/dist/shutdown-state.d.ts.map +1 -0
- package/dist/shutdown-state.js +22 -0
- package/dist/shutdown-state.js.map +1 -0
- package/dist/spawn-cooldown.d.ts +14 -0
- package/dist/spawn-cooldown.d.ts.map +1 -0
- package/dist/spawn-cooldown.js +34 -0
- package/dist/spawn-cooldown.js.map +1 -0
- package/dist/spawn-environment.d.ts +35 -0
- package/dist/spawn-environment.d.ts.map +1 -0
- package/dist/spawn-environment.js +48 -0
- package/dist/spawn-environment.js.map +1 -0
- package/dist/spawner-liveness.d.ts +23 -0
- package/dist/spawner-liveness.d.ts.map +1 -0
- package/dist/spawner-liveness.js +99 -0
- package/dist/spawner-liveness.js.map +1 -0
- package/dist/spawner-resolution.d.ts +27 -0
- package/dist/spawner-resolution.d.ts.map +1 -0
- package/dist/spawner-resolution.js +99 -0
- package/dist/spawner-resolution.js.map +1 -0
- package/dist/spawner-timeout.d.ts +32 -0
- package/dist/spawner-timeout.d.ts.map +1 -0
- package/dist/spawner-timeout.js +124 -0
- package/dist/spawner-timeout.js.map +1 -0
- package/dist/spawner.d.ts +77 -0
- package/dist/spawner.d.ts.map +1 -0
- package/dist/spawner.js +734 -0
- package/dist/spawner.js.map +1 -0
- package/dist/strategy-completion.d.ts +110 -0
- package/dist/strategy-completion.d.ts.map +1 -0
- package/dist/strategy-completion.js +434 -0
- package/dist/strategy-completion.js.map +1 -0
- package/dist/strategy-engine.d.ts +47 -0
- package/dist/strategy-engine.d.ts.map +1 -0
- package/dist/strategy-engine.js +419 -0
- package/dist/strategy-engine.js.map +1 -0
- package/dist/strategy-executor.d.ts +93 -0
- package/dist/strategy-executor.d.ts.map +1 -0
- package/dist/strategy-executor.js +775 -0
- package/dist/strategy-executor.js.map +1 -0
- package/dist/strategy-lifecycle.d.ts +61 -0
- package/dist/strategy-lifecycle.d.ts.map +1 -0
- package/dist/strategy-lifecycle.js +516 -0
- package/dist/strategy-lifecycle.js.map +1 -0
- package/dist/strategy-merge.d.ts +72 -0
- package/dist/strategy-merge.d.ts.map +1 -0
- package/dist/strategy-merge.js +371 -0
- package/dist/strategy-merge.js.map +1 -0
- package/dist/strategy-prompt-builder.d.ts +62 -0
- package/dist/strategy-prompt-builder.d.ts.map +1 -0
- package/dist/strategy-prompt-builder.js +538 -0
- package/dist/strategy-prompt-builder.js.map +1 -0
- package/dist/strategy-provisioning.d.ts +16 -0
- package/dist/strategy-provisioning.d.ts.map +1 -0
- package/dist/strategy-provisioning.js +119 -0
- package/dist/strategy-provisioning.js.map +1 -0
- package/dist/strategy-team-state.d.ts +24 -0
- package/dist/strategy-team-state.d.ts.map +1 -0
- package/dist/strategy-team-state.js +43 -0
- package/dist/strategy-team-state.js.map +1 -0
- package/dist/strategy-teardown.d.ts +24 -0
- package/dist/strategy-teardown.d.ts.map +1 -0
- package/dist/strategy-teardown.js +158 -0
- package/dist/strategy-teardown.js.map +1 -0
- package/dist/strategy-worktree-state.d.ts +47 -0
- package/dist/strategy-worktree-state.d.ts.map +1 -0
- package/dist/strategy-worktree-state.js +104 -0
- package/dist/strategy-worktree-state.js.map +1 -0
- package/dist/supabase.d.ts +36 -0
- package/dist/supabase.d.ts.map +1 -0
- package/dist/supabase.js +50 -0
- package/dist/supabase.js.map +1 -0
- package/dist/task-converter.d.ts +61 -0
- package/dist/task-converter.d.ts.map +1 -0
- package/dist/task-converter.js +286 -0
- package/dist/task-converter.js.map +1 -0
- package/dist/task-dag-builder.d.ts +14 -0
- package/dist/task-dag-builder.d.ts.map +1 -0
- package/dist/task-dag-builder.js +17 -0
- package/dist/task-dag-builder.js.map +1 -0
- package/dist/team-prompt-base.d.ts +114 -0
- package/dist/team-prompt-base.d.ts.map +1 -0
- package/dist/team-prompt-base.js +531 -0
- package/dist/team-prompt-base.js.map +1 -0
- package/dist/team-prompt-variants.d.ts +27 -0
- package/dist/team-prompt-variants.d.ts.map +1 -0
- package/dist/team-prompt-variants.js +134 -0
- package/dist/team-prompt-variants.js.map +1 -0
- package/dist/team-spawner.d.ts +50 -0
- package/dist/team-spawner.d.ts.map +1 -0
- package/dist/team-spawner.js +410 -0
- package/dist/team-spawner.js.map +1 -0
- package/dist/telemetry-writer.d.ts +66 -0
- package/dist/telemetry-writer.d.ts.map +1 -0
- package/dist/telemetry-writer.js +96 -0
- package/dist/telemetry-writer.js.map +1 -0
- package/dist/trigger-executor.d.ts +56 -0
- package/dist/trigger-executor.d.ts.map +1 -0
- package/dist/trigger-executor.js +313 -0
- package/dist/trigger-executor.js.map +1 -0
- package/dist/types/config.d.ts +60 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/dag.d.ts +53 -0
- package/dist/types/dag.d.ts.map +1 -0
- package/dist/types/dag.js +5 -0
- package/dist/types/dag.js.map +1 -0
- package/dist/types/delivery.d.ts +71 -0
- package/dist/types/delivery.d.ts.map +1 -0
- package/dist/types/delivery.js +5 -0
- package/dist/types/delivery.js.map +1 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +15 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/issue.d.ts +22 -0
- package/dist/types/issue.d.ts.map +1 -0
- package/dist/types/issue.js +5 -0
- package/dist/types/issue.js.map +1 -0
- package/dist/types/merge.d.ts +28 -0
- package/dist/types/merge.d.ts.map +1 -0
- package/dist/types/merge.js +5 -0
- package/dist/types/merge.js.map +1 -0
- package/dist/types/session.d.ts +98 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +5 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/strategy.d.ts +175 -0
- package/dist/types/strategy.d.ts.map +1 -0
- package/dist/types/strategy.js +5 -0
- package/dist/types/strategy.js.map +1 -0
- package/dist/types/workflow.d.ts +34 -0
- package/dist/types/workflow.d.ts.map +1 -0
- package/dist/types/workflow.js +9 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/unified-init.d.ts +16 -0
- package/dist/unified-init.d.ts.map +1 -0
- package/dist/unified-init.js +183 -0
- package/dist/unified-init.js.map +1 -0
- package/dist/unified-shell-config.d.ts +34 -0
- package/dist/unified-shell-config.d.ts.map +1 -0
- package/dist/unified-shell-config.js +238 -0
- package/dist/unified-shell-config.js.map +1 -0
- package/dist/unified-shell-status.d.ts +15 -0
- package/dist/unified-shell-status.d.ts.map +1 -0
- package/dist/unified-shell-status.js +100 -0
- package/dist/unified-shell-status.js.map +1 -0
- package/dist/unified-shell.d.ts +50 -0
- package/dist/unified-shell.d.ts.map +1 -0
- package/dist/unified-shell.js +682 -0
- package/dist/unified-shell.js.map +1 -0
- package/dist/version-check.d.ts +19 -0
- package/dist/version-check.d.ts.map +1 -0
- package/dist/version-check.js +67 -0
- package/dist/version-check.js.map +1 -0
- package/dist/workflow-engine.d.ts +95 -0
- package/dist/workflow-engine.d.ts.map +1 -0
- package/dist/workflow-engine.js +165 -0
- package/dist/workflow-engine.js.map +1 -0
- package/dist/worktree-merge.d.ts +23 -0
- package/dist/worktree-merge.d.ts.map +1 -0
- package/dist/worktree-merge.js +57 -0
- package/dist/worktree-merge.js.map +1 -0
- package/dist/worktree-safety.d.ts +48 -0
- package/dist/worktree-safety.d.ts.map +1 -0
- package/dist/worktree-safety.js +113 -0
- package/dist/worktree-safety.js.map +1 -0
- package/dist/worktree-strategy.d.ts +69 -0
- package/dist/worktree-strategy.d.ts.map +1 -0
- package/dist/worktree-strategy.js +214 -0
- package/dist/worktree-strategy.js.map +1 -0
- package/dist/worktree.d.ts +159 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +512 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +76 -0
- package/scripts/telora-daemon-wrapper.sh +31 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon log viewing utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides tail-like functionality for the daemon log file,
|
|
5
|
+
* including follow mode (like `tail -f`).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Print the last N lines from a file.
|
|
9
|
+
*/
|
|
10
|
+
export declare function tailFile(filePath: string, lines: number): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Follow a log file, printing new lines as they appear.
|
|
13
|
+
* Returns a cleanup function that stops the follow.
|
|
14
|
+
*
|
|
15
|
+
* Uses fs.watchFile for polling-based watching (works across
|
|
16
|
+
* all platforms and with log rotation).
|
|
17
|
+
*/
|
|
18
|
+
export declare function followFile(filePath: string): () => void;
|
|
19
|
+
//# sourceMappingURL=daemon-logs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-logs.d.ts","sourceRoot":"","sources":["../src/daemon-logs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB7E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,IAAI,CAkDvD"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon log viewing utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides tail-like functionality for the daemon log file,
|
|
5
|
+
* including follow mode (like `tail -f`).
|
|
6
|
+
*/
|
|
7
|
+
import { createReadStream, existsSync, statSync, watchFile, unwatchFile } from 'node:fs';
|
|
8
|
+
import { createInterface } from 'node:readline';
|
|
9
|
+
/**
|
|
10
|
+
* Print the last N lines from a file.
|
|
11
|
+
*/
|
|
12
|
+
export async function tailFile(filePath, lines) {
|
|
13
|
+
if (!existsSync(filePath)) {
|
|
14
|
+
console.error(`Log file not found: ${filePath}`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Read the entire file and print the last N lines
|
|
18
|
+
const allLines = [];
|
|
19
|
+
const rl = createInterface({
|
|
20
|
+
input: createReadStream(filePath, { encoding: 'utf-8' }),
|
|
21
|
+
crlfDelay: Infinity,
|
|
22
|
+
});
|
|
23
|
+
for await (const line of rl) {
|
|
24
|
+
allLines.push(line);
|
|
25
|
+
}
|
|
26
|
+
const startIdx = Math.max(0, allLines.length - lines);
|
|
27
|
+
for (let i = startIdx; i < allLines.length; i++) {
|
|
28
|
+
console.log(allLines[i]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Follow a log file, printing new lines as they appear.
|
|
33
|
+
* Returns a cleanup function that stops the follow.
|
|
34
|
+
*
|
|
35
|
+
* Uses fs.watchFile for polling-based watching (works across
|
|
36
|
+
* all platforms and with log rotation).
|
|
37
|
+
*/
|
|
38
|
+
export function followFile(filePath) {
|
|
39
|
+
if (!existsSync(filePath)) {
|
|
40
|
+
console.error(`Log file not found: ${filePath}`);
|
|
41
|
+
console.error('Start the daemon first, then run logs --follow');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
let position = statSync(filePath).size;
|
|
45
|
+
let stopped = false;
|
|
46
|
+
const pollIntervalMs = 500;
|
|
47
|
+
watchFile(filePath, { interval: pollIntervalMs }, () => {
|
|
48
|
+
if (stopped)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
const currentSize = statSync(filePath).size;
|
|
52
|
+
if (currentSize < position) {
|
|
53
|
+
// File was truncated or rotated -- start from beginning
|
|
54
|
+
position = 0;
|
|
55
|
+
}
|
|
56
|
+
if (currentSize > position) {
|
|
57
|
+
const stream = createReadStream(filePath, {
|
|
58
|
+
start: position,
|
|
59
|
+
encoding: 'utf-8',
|
|
60
|
+
});
|
|
61
|
+
stream.on('data', (chunk) => {
|
|
62
|
+
process.stdout.write(chunk);
|
|
63
|
+
});
|
|
64
|
+
stream.on('end', () => {
|
|
65
|
+
position = currentSize;
|
|
66
|
+
});
|
|
67
|
+
stream.on('error', (err) => {
|
|
68
|
+
console.error(`Error reading log file: ${err.message}`);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// File may have been deleted during rotation
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return () => {
|
|
77
|
+
stopped = true;
|
|
78
|
+
unwatchFile(filePath);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=daemon-logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-logs.js","sourceRoot":"","sources":["../src/daemon-logs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB,EAAE,KAAa;IAC5D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,kDAAkD;IAClD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,EAAE,GAAG,eAAe,CAAC;QACzB,KAAK,EAAE,gBAAgB,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QACxD,SAAS,EAAE,QAAQ;KACpB,CAAC,CAAC;IAEH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IACtD,KAAK,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IACvC,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,cAAc,GAAG,GAAG,CAAC;IAE3B,SAAS,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE;QACrD,IAAI,OAAO;YAAE,OAAO;QAEpB,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;YAE5C,IAAI,WAAW,GAAG,QAAQ,EAAE,CAAC;gBAC3B,wDAAwD;gBACxD,QAAQ,GAAG,CAAC,CAAC;YACf,CAAC;YAED,IAAI,WAAW,GAAG,QAAQ,EAAE,CAAC;gBAC3B,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE;oBACxC,KAAK,EAAE,QAAQ;oBACf,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;oBAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACpB,QAAQ,GAAG,WAAW,CAAC;gBACzB,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBACzB,OAAO,CAAC,KAAK,CAAC,2BAA2B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC1D,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,EAAE;QACV,OAAO,GAAG,IAAI,CAAC;QACf,WAAW,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon process management utilities for CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for:
|
|
5
|
+
* - Reading PID files and checking daemon liveness
|
|
6
|
+
* - Sending signals (stop, status)
|
|
7
|
+
* - Spawning the daemon as a background process
|
|
8
|
+
* - Auto-rebuilding TypeScript before starting
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the global daemon state directory (~/.telora/).
|
|
12
|
+
*
|
|
13
|
+
* Process-level state (PID lock, metadata, canonical log) lives here
|
|
14
|
+
* because the daemon is a user-scoped singleton -- one process per user,
|
|
15
|
+
* potentially managing multiple product repositories.
|
|
16
|
+
*
|
|
17
|
+
* Per-product state (worktrees, session logs) remains in each repo's
|
|
18
|
+
* .telora/ directory, configured via configForProduct().
|
|
19
|
+
*
|
|
20
|
+
* Override with TELORA_STATE_DIR for testing.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveGlobalStateDir(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Ensure the global state directory (~/.telora/) exists.
|
|
25
|
+
* Called during daemon startup.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ensureGlobalStateDir(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve the PID file path in the global state directory (~/.telora/).
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolvePidFilePath(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Read the PID from the daemon PID file.
|
|
34
|
+
* Returns null if the file doesn't exist or contains invalid data.
|
|
35
|
+
*/
|
|
36
|
+
export declare function readDaemonPid(pidFilePath: string): number | null;
|
|
37
|
+
export interface DaemonStatus {
|
|
38
|
+
running: boolean;
|
|
39
|
+
pid: number | null;
|
|
40
|
+
pidFilePath: string;
|
|
41
|
+
logPath: string | null;
|
|
42
|
+
startedAt: string | null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Metadata written alongside the PID file for daemon discoverability.
|
|
46
|
+
*/
|
|
47
|
+
export interface DaemonMeta {
|
|
48
|
+
pid: number;
|
|
49
|
+
logPath: string;
|
|
50
|
+
startedAt: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if the daemon is currently running.
|
|
54
|
+
*/
|
|
55
|
+
export declare function getDaemonStatus(): DaemonStatus;
|
|
56
|
+
/**
|
|
57
|
+
* Send SIGTERM to the running daemon and wait for it to exit.
|
|
58
|
+
* Returns true if the daemon was stopped, false if it wasn't running.
|
|
59
|
+
* Throws if the daemon doesn't exit within the timeout.
|
|
60
|
+
*/
|
|
61
|
+
export declare function stopDaemon(timeoutMs?: number): Promise<boolean>;
|
|
62
|
+
/**
|
|
63
|
+
* Check if dist/ is stale relative to src/ files.
|
|
64
|
+
* Returns true if any src/ file is newer than the newest dist/ file,
|
|
65
|
+
* or if dist/ doesn't exist.
|
|
66
|
+
*/
|
|
67
|
+
export declare function needsRebuild(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Rebuild the daemon TypeScript project.
|
|
70
|
+
* Runs `npm run build` in the daemon package directory.
|
|
71
|
+
*/
|
|
72
|
+
export declare function rebuildDaemon(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Auto-rebuild if dist/ is stale. Used by start command.
|
|
75
|
+
*/
|
|
76
|
+
export declare function autoRebuildIfNeeded(): void;
|
|
77
|
+
export interface StartOptions {
|
|
78
|
+
/** Path to config file. */
|
|
79
|
+
config?: string;
|
|
80
|
+
/** Enable verbose logging. */
|
|
81
|
+
verbose?: boolean;
|
|
82
|
+
/** Engine filter (strategy or factory). */
|
|
83
|
+
engine?: string;
|
|
84
|
+
/** Skip crash recovery. */
|
|
85
|
+
skipRecovery?: boolean;
|
|
86
|
+
/** Disable auto-update. */
|
|
87
|
+
noAutoUpdate?: boolean;
|
|
88
|
+
/** Run in foreground (don't daemonize). */
|
|
89
|
+
foreground?: boolean;
|
|
90
|
+
/** Auto-rebuild before starting. */
|
|
91
|
+
rebuild?: boolean;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Resolve the path to the daemon log file in the global state directory.
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolveDaemonLogPath(): string;
|
|
97
|
+
/**
|
|
98
|
+
* Start the daemon as a background process.
|
|
99
|
+
*
|
|
100
|
+
* Spawns a detached child process that writes stdout/stderr to the
|
|
101
|
+
* daemon log file. The child process runs `telora-daemon run` with
|
|
102
|
+
* the provided options.
|
|
103
|
+
*
|
|
104
|
+
* Returns the PID of the spawned process.
|
|
105
|
+
*/
|
|
106
|
+
export declare function startDaemonBackground(opts: StartOptions): number;
|
|
107
|
+
/**
|
|
108
|
+
* Wait for the daemon to become healthy after background start.
|
|
109
|
+
* Checks that the PID file appears and the process is running.
|
|
110
|
+
* Returns true if healthy, false if the process died or timed out.
|
|
111
|
+
*/
|
|
112
|
+
export declare function waitForHealthy(timeoutMs?: number): Promise<boolean>;
|
|
113
|
+
/**
|
|
114
|
+
* Clean up stale PID file if the process isn't running.
|
|
115
|
+
* Returns true if a stale file was removed.
|
|
116
|
+
*/
|
|
117
|
+
export declare function cleanStalePidFile(): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the path to the daemon metadata file in the global state directory.
|
|
120
|
+
*/
|
|
121
|
+
export declare function resolveDaemonMetaPath(): string;
|
|
122
|
+
/**
|
|
123
|
+
* Write daemon metadata alongside the PID file.
|
|
124
|
+
* Called during daemon startup to record the log file path and start time.
|
|
125
|
+
*/
|
|
126
|
+
export declare function writeDaemonMeta(logPath?: string): void;
|
|
127
|
+
/**
|
|
128
|
+
* Read daemon metadata. Returns null if the file doesn't exist or is invalid.
|
|
129
|
+
*/
|
|
130
|
+
export declare function readDaemonMeta(): DaemonMeta | null;
|
|
131
|
+
/**
|
|
132
|
+
* Remove daemon metadata file. Called during shutdown alongside PID lock release.
|
|
133
|
+
*/
|
|
134
|
+
export declare function removeDaemonMeta(): void;
|
|
135
|
+
/**
|
|
136
|
+
* Rotate the canonical daemon log on startup.
|
|
137
|
+
*
|
|
138
|
+
* Renames the existing daemon.log to daemon.log.prev so each daemon run
|
|
139
|
+
* starts with a fresh log. Only one previous log is kept — this is enough
|
|
140
|
+
* for quick debugging without accumulating unbounded history.
|
|
141
|
+
*/
|
|
142
|
+
export declare function rotateDaemonLog(): void;
|
|
143
|
+
/**
|
|
144
|
+
* Set up canonical log file output for foreground mode.
|
|
145
|
+
*
|
|
146
|
+
* When the daemon runs in the foreground, stdout/stderr go to the terminal.
|
|
147
|
+
* This function additionally pipes both streams to the canonical log file
|
|
148
|
+
* so that `telora-daemon logs` always has something to read, regardless
|
|
149
|
+
* of how the daemon was started.
|
|
150
|
+
*
|
|
151
|
+
* Returns a cleanup function that closes the log stream.
|
|
152
|
+
*/
|
|
153
|
+
export declare function setupCanonicalLogTee(): () => void;
|
|
154
|
+
//# sourceMappingURL=daemon-process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-process.d.ts","sourceRoot":"","sources":["../src/daemon-process.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWhE;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,YAAY,CAiB9C;AAMD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,SAAS,SAAS,GACjB,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAoBtC;AAuBD;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAiBpC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAMD,MAAM,WAAW,YAAY;IAC3B,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2BAA2B;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAsDhE;AAMD;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,SAAS,SAAS,GACjB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAgB3C;AAMD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAUtD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CAYlD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CASvC;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAUtC;AAMD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,IAAI,CAwBjD"}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon process management utilities for CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Provides helpers for:
|
|
5
|
+
* - Reading PID files and checking daemon liveness
|
|
6
|
+
* - Sending signals (stop, status)
|
|
7
|
+
* - Spawning the daemon as a background process
|
|
8
|
+
* - Auto-rebuilding TypeScript before starting
|
|
9
|
+
*/
|
|
10
|
+
import { closeSync, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { resolve, dirname, join } from 'node:path';
|
|
12
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { homedir } from 'node:os';
|
|
15
|
+
/**
|
|
16
|
+
* Check if a process with the given PID is currently running.
|
|
17
|
+
* Uses kill(pid, 0) for existence check without delivering a signal.
|
|
18
|
+
*/
|
|
19
|
+
function isProcessRunning(pid) {
|
|
20
|
+
try {
|
|
21
|
+
process.kill(pid, 0);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Global state directory
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the global daemon state directory (~/.telora/).
|
|
33
|
+
*
|
|
34
|
+
* Process-level state (PID lock, metadata, canonical log) lives here
|
|
35
|
+
* because the daemon is a user-scoped singleton -- one process per user,
|
|
36
|
+
* potentially managing multiple product repositories.
|
|
37
|
+
*
|
|
38
|
+
* Per-product state (worktrees, session logs) remains in each repo's
|
|
39
|
+
* .telora/ directory, configured via configForProduct().
|
|
40
|
+
*
|
|
41
|
+
* Override with TELORA_STATE_DIR for testing.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveGlobalStateDir() {
|
|
44
|
+
return process.env.TELORA_STATE_DIR || resolve(homedir(), '.telora');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Ensure the global state directory (~/.telora/) exists.
|
|
48
|
+
* Called during daemon startup.
|
|
49
|
+
*/
|
|
50
|
+
export function ensureGlobalStateDir() {
|
|
51
|
+
const dir = resolveGlobalStateDir();
|
|
52
|
+
if (!existsSync(dir)) {
|
|
53
|
+
mkdirSync(dir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// PID file helpers
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the PID file path in the global state directory (~/.telora/).
|
|
61
|
+
*/
|
|
62
|
+
export function resolvePidFilePath() {
|
|
63
|
+
return resolve(resolveGlobalStateDir(), 'daemon.pid');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Read the PID from the daemon PID file.
|
|
67
|
+
* Returns null if the file doesn't exist or contains invalid data.
|
|
68
|
+
*/
|
|
69
|
+
export function readDaemonPid(pidFilePath) {
|
|
70
|
+
if (!existsSync(pidFilePath))
|
|
71
|
+
return null;
|
|
72
|
+
try {
|
|
73
|
+
const contents = readFileSync(pidFilePath, 'utf-8').trim();
|
|
74
|
+
const pid = parseInt(contents, 10);
|
|
75
|
+
if (isNaN(pid) || pid <= 0)
|
|
76
|
+
return null;
|
|
77
|
+
return pid;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if the daemon is currently running.
|
|
85
|
+
*/
|
|
86
|
+
export function getDaemonStatus() {
|
|
87
|
+
const pidFilePath = resolvePidFilePath();
|
|
88
|
+
const pid = readDaemonPid(pidFilePath);
|
|
89
|
+
if (pid === null) {
|
|
90
|
+
return { running: false, pid: null, pidFilePath, logPath: null, startedAt: null };
|
|
91
|
+
}
|
|
92
|
+
const running = isProcessRunning(pid);
|
|
93
|
+
const meta = readDaemonMeta();
|
|
94
|
+
return {
|
|
95
|
+
running,
|
|
96
|
+
pid: running ? pid : null,
|
|
97
|
+
pidFilePath,
|
|
98
|
+
logPath: meta?.logPath ?? null,
|
|
99
|
+
startedAt: meta?.startedAt ?? null,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Stop
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/**
|
|
106
|
+
* Send SIGTERM to the running daemon and wait for it to exit.
|
|
107
|
+
* Returns true if the daemon was stopped, false if it wasn't running.
|
|
108
|
+
* Throws if the daemon doesn't exit within the timeout.
|
|
109
|
+
*/
|
|
110
|
+
export async function stopDaemon(timeoutMs = 30_000) {
|
|
111
|
+
const status = getDaemonStatus();
|
|
112
|
+
if (!status.running || status.pid === null) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
// Send SIGTERM
|
|
116
|
+
try {
|
|
117
|
+
process.kill(status.pid, 'SIGTERM');
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Process already gone
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
// Wait for the process to exit
|
|
124
|
+
const startTime = Date.now();
|
|
125
|
+
const pollIntervalMs = 200;
|
|
126
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
127
|
+
if (!isProcessRunning(status.pid)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
131
|
+
}
|
|
132
|
+
throw new Error(`Daemon (PID ${status.pid}) did not exit within ${Math.round(timeoutMs / 1000)}s. ` +
|
|
133
|
+
`Use 'kill -9 ${status.pid}' to force kill.`);
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Auto-rebuild
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
/**
|
|
139
|
+
* Check if dist/ is stale relative to src/ files.
|
|
140
|
+
* Returns true if any src/ file is newer than the newest dist/ file,
|
|
141
|
+
* or if dist/ doesn't exist.
|
|
142
|
+
*/
|
|
143
|
+
export function needsRebuild() {
|
|
144
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
145
|
+
const pkgRoot = resolve(thisDir, '..');
|
|
146
|
+
const distDir = resolve(pkgRoot, 'dist');
|
|
147
|
+
const srcDir = resolve(pkgRoot, 'src');
|
|
148
|
+
// If dist doesn't exist, rebuild is needed
|
|
149
|
+
if (!existsSync(distDir))
|
|
150
|
+
return true;
|
|
151
|
+
// If running from source (tsx), no rebuild needed -- dev mode
|
|
152
|
+
if (import.meta.url.endsWith('.ts'))
|
|
153
|
+
return false;
|
|
154
|
+
// Find newest src file and newest dist file
|
|
155
|
+
const newestSrc = newestMtime(srcDir);
|
|
156
|
+
const newestDist = newestMtime(distDir);
|
|
157
|
+
if (newestSrc === 0)
|
|
158
|
+
return false; // No src files?
|
|
159
|
+
if (newestDist === 0)
|
|
160
|
+
return true; // Empty dist/
|
|
161
|
+
return newestSrc > newestDist;
|
|
162
|
+
}
|
|
163
|
+
function newestMtime(dir) {
|
|
164
|
+
let newest = 0;
|
|
165
|
+
try {
|
|
166
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
const fullPath = join(dir, entry.name);
|
|
169
|
+
if (entry.isDirectory()) {
|
|
170
|
+
if (entry.name === 'node_modules' || entry.name === '__tests__')
|
|
171
|
+
continue;
|
|
172
|
+
const sub = newestMtime(fullPath);
|
|
173
|
+
if (sub > newest)
|
|
174
|
+
newest = sub;
|
|
175
|
+
}
|
|
176
|
+
else if (entry.isFile()) {
|
|
177
|
+
const stat = statSync(fullPath);
|
|
178
|
+
if (stat.mtimeMs > newest)
|
|
179
|
+
newest = stat.mtimeMs;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Directory may not exist
|
|
185
|
+
}
|
|
186
|
+
return newest;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Rebuild the daemon TypeScript project.
|
|
190
|
+
* Runs `npm run build` in the daemon package directory.
|
|
191
|
+
*/
|
|
192
|
+
export function rebuildDaemon() {
|
|
193
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
194
|
+
const pkgRoot = resolve(thisDir, '..');
|
|
195
|
+
console.log('[cli] Rebuilding daemon...');
|
|
196
|
+
try {
|
|
197
|
+
execFileSync('npm', ['run', 'build'], {
|
|
198
|
+
cwd: pkgRoot,
|
|
199
|
+
stdio: 'inherit',
|
|
200
|
+
timeout: 60_000,
|
|
201
|
+
});
|
|
202
|
+
console.log('[cli] Rebuild complete');
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
throw new Error(`Failed to rebuild daemon: ${err instanceof Error ? err.message : String(err)}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Auto-rebuild if dist/ is stale. Used by start command.
|
|
210
|
+
*/
|
|
211
|
+
export function autoRebuildIfNeeded() {
|
|
212
|
+
if (needsRebuild()) {
|
|
213
|
+
console.log('[cli] dist/ is stale, rebuilding...');
|
|
214
|
+
rebuildDaemon();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Resolve the path to the daemon log file in the global state directory.
|
|
219
|
+
*/
|
|
220
|
+
export function resolveDaemonLogPath() {
|
|
221
|
+
return resolve(resolveGlobalStateDir(), 'daemon.log');
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Start the daemon as a background process.
|
|
225
|
+
*
|
|
226
|
+
* Spawns a detached child process that writes stdout/stderr to the
|
|
227
|
+
* daemon log file. The child process runs `telora-daemon run` with
|
|
228
|
+
* the provided options.
|
|
229
|
+
*
|
|
230
|
+
* Returns the PID of the spawned process.
|
|
231
|
+
*/
|
|
232
|
+
export function startDaemonBackground(opts) {
|
|
233
|
+
const repoPath = process.env.TELORA_REPO_PATH || process.cwd();
|
|
234
|
+
// Ensure global state directory exists
|
|
235
|
+
ensureGlobalStateDir();
|
|
236
|
+
const logPath = resolveDaemonLogPath();
|
|
237
|
+
// Rotate log BEFORE opening the fd so the child's stdout/stderr
|
|
238
|
+
// file descriptor points to the fresh daemon.log, not the rotated
|
|
239
|
+
// daemon.log.prev. The child will skip its own rotation when it
|
|
240
|
+
// detects stdout is not a TTY (background mode).
|
|
241
|
+
rotateDaemonLog();
|
|
242
|
+
// Build args for the child process
|
|
243
|
+
const args = ['run'];
|
|
244
|
+
if (opts.config) {
|
|
245
|
+
args.push('--config', opts.config);
|
|
246
|
+
}
|
|
247
|
+
if (opts.verbose) {
|
|
248
|
+
args.push('--verbose');
|
|
249
|
+
}
|
|
250
|
+
if (opts.engine) {
|
|
251
|
+
args.push('--engine', opts.engine);
|
|
252
|
+
}
|
|
253
|
+
if (opts.skipRecovery) {
|
|
254
|
+
args.push('--skip-recovery');
|
|
255
|
+
}
|
|
256
|
+
if (opts.noAutoUpdate) {
|
|
257
|
+
args.push('--no-auto-update');
|
|
258
|
+
}
|
|
259
|
+
// Resolve the daemon entry point
|
|
260
|
+
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
261
|
+
const entryPoint = resolve(thisDir, 'index.js');
|
|
262
|
+
// Open log file for appending
|
|
263
|
+
const logFd = openSync(logPath, 'a');
|
|
264
|
+
const child = spawn(process.execPath, [entryPoint, ...args], {
|
|
265
|
+
detached: true,
|
|
266
|
+
stdio: ['ignore', logFd, logFd],
|
|
267
|
+
cwd: repoPath,
|
|
268
|
+
env: { ...process.env },
|
|
269
|
+
});
|
|
270
|
+
// Let the child run independently
|
|
271
|
+
child.unref();
|
|
272
|
+
// Close our copy of the file descriptor
|
|
273
|
+
closeSync(logFd);
|
|
274
|
+
return child.pid ?? 0;
|
|
275
|
+
}
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
// Health confirmation
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
/**
|
|
280
|
+
* Wait for the daemon to become healthy after background start.
|
|
281
|
+
* Checks that the PID file appears and the process is running.
|
|
282
|
+
* Returns true if healthy, false if the process died or timed out.
|
|
283
|
+
*/
|
|
284
|
+
export async function waitForHealthy(timeoutMs = 10_000) {
|
|
285
|
+
const startTime = Date.now();
|
|
286
|
+
const pollIntervalMs = 500;
|
|
287
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
288
|
+
const status = getDaemonStatus();
|
|
289
|
+
if (status.running && status.pid !== null) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
293
|
+
}
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Clean up stale PID file if the process isn't running.
|
|
298
|
+
* Returns true if a stale file was removed.
|
|
299
|
+
*/
|
|
300
|
+
export function cleanStalePidFile() {
|
|
301
|
+
const pidFilePath = resolvePidFilePath();
|
|
302
|
+
const pid = readDaemonPid(pidFilePath);
|
|
303
|
+
if (pid === null)
|
|
304
|
+
return false;
|
|
305
|
+
if (!isProcessRunning(pid)) {
|
|
306
|
+
try {
|
|
307
|
+
unlinkSync(pidFilePath);
|
|
308
|
+
console.log(`[cli] Removed stale PID file (PID ${pid} is not running)`);
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
// Daemon metadata (log path, start time)
|
|
319
|
+
// ---------------------------------------------------------------------------
|
|
320
|
+
/**
|
|
321
|
+
* Resolve the path to the daemon metadata file in the global state directory.
|
|
322
|
+
*/
|
|
323
|
+
export function resolveDaemonMetaPath() {
|
|
324
|
+
return resolve(resolveGlobalStateDir(), 'daemon.meta.json');
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Write daemon metadata alongside the PID file.
|
|
328
|
+
* Called during daemon startup to record the log file path and start time.
|
|
329
|
+
*/
|
|
330
|
+
export function writeDaemonMeta(logPath) {
|
|
331
|
+
const metaPath = resolveDaemonMetaPath();
|
|
332
|
+
const meta = {
|
|
333
|
+
pid: process.pid,
|
|
334
|
+
logPath: logPath ?? resolveDaemonLogPath(),
|
|
335
|
+
startedAt: new Date().toISOString(),
|
|
336
|
+
};
|
|
337
|
+
ensureGlobalStateDir();
|
|
338
|
+
writeFileSync(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Read daemon metadata. Returns null if the file doesn't exist or is invalid.
|
|
342
|
+
*/
|
|
343
|
+
export function readDaemonMeta() {
|
|
344
|
+
const metaPath = resolveDaemonMetaPath();
|
|
345
|
+
if (!existsSync(metaPath))
|
|
346
|
+
return null;
|
|
347
|
+
try {
|
|
348
|
+
const contents = readFileSync(metaPath, 'utf-8');
|
|
349
|
+
const meta = JSON.parse(contents);
|
|
350
|
+
if (typeof meta.pid !== 'number' || typeof meta.logPath !== 'string')
|
|
351
|
+
return null;
|
|
352
|
+
return meta;
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Remove daemon metadata file. Called during shutdown alongside PID lock release.
|
|
360
|
+
*/
|
|
361
|
+
export function removeDaemonMeta() {
|
|
362
|
+
const metaPath = resolveDaemonMetaPath();
|
|
363
|
+
try {
|
|
364
|
+
if (existsSync(metaPath)) {
|
|
365
|
+
unlinkSync(metaPath);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// Best-effort cleanup
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// ---------------------------------------------------------------------------
|
|
373
|
+
// Log rotation
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
/**
|
|
376
|
+
* Rotate the canonical daemon log on startup.
|
|
377
|
+
*
|
|
378
|
+
* Renames the existing daemon.log to daemon.log.prev so each daemon run
|
|
379
|
+
* starts with a fresh log. Only one previous log is kept — this is enough
|
|
380
|
+
* for quick debugging without accumulating unbounded history.
|
|
381
|
+
*/
|
|
382
|
+
export function rotateDaemonLog() {
|
|
383
|
+
const logPath = resolveDaemonLogPath();
|
|
384
|
+
if (!existsSync(logPath))
|
|
385
|
+
return;
|
|
386
|
+
const prevPath = logPath + '.prev';
|
|
387
|
+
try {
|
|
388
|
+
renameSync(logPath, prevPath);
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
// Log file may be in use or inaccessible — not fatal
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// ---------------------------------------------------------------------------
|
|
395
|
+
// Canonical log tee (foreground mode)
|
|
396
|
+
// ---------------------------------------------------------------------------
|
|
397
|
+
/**
|
|
398
|
+
* Set up canonical log file output for foreground mode.
|
|
399
|
+
*
|
|
400
|
+
* When the daemon runs in the foreground, stdout/stderr go to the terminal.
|
|
401
|
+
* This function additionally pipes both streams to the canonical log file
|
|
402
|
+
* so that `telora-daemon logs` always has something to read, regardless
|
|
403
|
+
* of how the daemon was started.
|
|
404
|
+
*
|
|
405
|
+
* Returns a cleanup function that closes the log stream.
|
|
406
|
+
*/
|
|
407
|
+
export function setupCanonicalLogTee() {
|
|
408
|
+
ensureGlobalStateDir();
|
|
409
|
+
const logPath = resolveDaemonLogPath();
|
|
410
|
+
const logStream = createWriteStream(logPath, { flags: 'a' });
|
|
411
|
+
const origStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
412
|
+
const origStderrWrite = process.stderr.write.bind(process.stderr);
|
|
413
|
+
process.stdout.write = function (chunk, ...args) {
|
|
414
|
+
logStream.write(chunk);
|
|
415
|
+
return origStdoutWrite(chunk, ...args);
|
|
416
|
+
};
|
|
417
|
+
process.stderr.write = function (chunk, ...args) {
|
|
418
|
+
logStream.write(chunk);
|
|
419
|
+
return origStderrWrite(chunk, ...args);
|
|
420
|
+
};
|
|
421
|
+
return () => {
|
|
422
|
+
process.stdout.write = origStdoutWrite;
|
|
423
|
+
process.stderr.write = origStderrWrite;
|
|
424
|
+
logStream.end();
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=daemon-process.js.map
|