borgmcp 1.1.15 → 2.0.1
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/CONTRIBUTING.md +15 -0
- package/LICENSE +201 -33
- package/NOTICE +2 -0
- package/README.md +85 -36
- package/SECURITY.md +7 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +63 -1
- package/dist/agent-runtime.js.map +1 -0
- package/dist/assimilate-cmd.d.ts +96 -17
- package/dist/assimilate-cmd.d.ts.map +1 -0
- package/dist/assimilate-cmd.js +1396 -48
- package/dist/assimilate-cmd.js.map +1 -0
- package/dist/assimilate-deps.d.ts.map +1 -0
- package/dist/assimilate-deps.js +384 -3
- package/dist/assimilate-deps.js.map +1 -0
- package/dist/assimilate-guard.d.ts +5 -7
- package/dist/assimilate-guard.d.ts.map +1 -0
- package/dist/assimilate-guard.js +60 -2
- package/dist/assimilate-guard.js.map +1 -0
- package/dist/assimilate-welcome.d.ts +1 -1
- package/dist/assimilate-welcome.d.ts.map +1 -0
- package/dist/assimilate-welcome.js +32 -2
- package/dist/assimilate-welcome.js.map +1 -0
- package/dist/auth-env.d.ts +7 -50
- package/dist/auth-env.d.ts.map +1 -0
- package/dist/auth-env.js +22 -1
- package/dist/auth-env.js.map +1 -0
- package/dist/backends/launch-all-pastelist.d.ts.map +1 -0
- package/dist/backends/launch-all-pastelist.js +11 -4
- package/dist/backends/launch-all-pastelist.js.map +1 -0
- package/dist/backends/launch-all-tmux.d.ts.map +1 -0
- package/dist/backends/launch-all-tmux.js +49 -1
- package/dist/backends/launch-all-tmux.js.map +1 -0
- package/dist/backends/launch-all-windows.d.ts.map +1 -0
- package/dist/backends/launch-all-windows.js +86 -12
- package/dist/backends/launch-all-windows.js.map +1 -0
- package/dist/bare-launch-menu.d.ts.map +1 -0
- package/dist/bare-launch-menu.js +83 -6
- package/dist/bare-launch-menu.js.map +1 -0
- package/dist/claude-launch-args.d.ts.map +1 -0
- package/dist/claude-launch-args.js +34 -1
- package/dist/claude-launch-args.js.map +1 -0
- package/dist/claude.d.ts.map +1 -0
- package/dist/claude.js +486 -14
- package/dist/claude.js.map +1 -0
- package/dist/cleanup-cmd.d.ts +5 -5
- package/dist/cleanup-cmd.d.ts.map +1 -0
- package/dist/cleanup-cmd.js +453 -14
- package/dist/cleanup-cmd.js.map +1 -0
- package/dist/clear-rewake-core.d.ts.map +1 -0
- package/dist/clear-rewake-core.js +23 -2
- package/dist/clear-rewake-core.js.map +1 -0
- package/dist/clear-rewake.d.ts.map +1 -0
- package/dist/clear-rewake.js +19 -1
- package/dist/clear-rewake.js.map +1 -0
- package/dist/cli-help.d.ts +5 -0
- package/dist/cli-help.d.ts.map +1 -0
- package/dist/cli-help.js +104 -56
- package/dist/cli-help.js.map +1 -0
- package/dist/cli-platform.d.ts.map +1 -0
- package/dist/cli-platform.js +106 -4
- package/dist/cli-platform.js.map +1 -0
- package/dist/cli-tool-approval.d.ts +84 -0
- package/dist/cli-tool-approval.d.ts.map +1 -0
- package/dist/cli-tool-approval.js +583 -0
- package/dist/cli-tool-approval.js.map +1 -0
- package/dist/codex-app-server.d.ts.map +1 -0
- package/dist/codex-app-server.js +228 -4
- package/dist/codex-app-server.js.map +1 -0
- package/dist/codex-app-wake.d.ts.map +1 -0
- package/dist/codex-app-wake.js +432 -2
- package/dist/codex-app-wake.js.map +1 -0
- package/dist/codex-launch.d.ts.map +1 -0
- package/dist/codex-launch.js +102 -2
- package/dist/codex-launch.js.map +1 -0
- package/dist/codex-remote.d.ts +6 -1
- package/dist/codex-remote.d.ts.map +1 -0
- package/dist/codex-remote.js +394 -1
- package/dist/codex-remote.js.map +1 -0
- package/dist/codex-wake-resolve.d.ts.map +1 -0
- package/dist/codex-wake-resolve.js +127 -1
- package/dist/codex-wake-resolve.js.map +1 -0
- package/dist/config-utils.d.ts +2 -2
- package/dist/config-utils.d.ts.map +1 -0
- package/dist/config-utils.js +766 -3
- package/dist/config-utils.js.map +1 -0
- package/dist/config.d.ts +98 -61
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +426 -1
- package/dist/config.js.map +1 -0
- package/dist/console-prefix.d.ts.map +1 -0
- package/dist/console-prefix.js +96 -1
- package/dist/console-prefix.js.map +1 -0
- package/dist/cube-name.d.ts.map +1 -0
- package/dist/cube-name.js +67 -1
- package/dist/cube-name.js.map +1 -0
- package/dist/cubes.d.ts +126 -18
- package/dist/cubes.d.ts.map +1 -0
- package/dist/cubes.js +412 -4
- package/dist/cubes.js.map +1 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +71 -1
- package/dist/debug.js.map +1 -0
- package/dist/direct-log.d.ts.map +1 -0
- package/dist/direct-log.js +11 -1
- package/dist/direct-log.js.map +1 -0
- package/dist/docs-sections.d.ts +11 -10
- package/dist/docs-sections.d.ts.map +1 -0
- package/dist/docs-sections.js +113 -3
- package/dist/docs-sections.js.map +1 -0
- package/dist/drone-lifecycle.d.ts +5 -21
- package/dist/drone-lifecycle.d.ts.map +1 -0
- package/dist/drone-lifecycle.js +57 -8
- package/dist/drone-lifecycle.js.map +1 -0
- package/dist/drone-management.d.ts +29 -0
- package/dist/drone-management.d.ts.map +1 -0
- package/dist/drone-management.js +109 -0
- package/dist/drone-management.js.map +1 -0
- package/dist/ensure-mcp-config.d.ts.map +1 -0
- package/dist/ensure-mcp-config.js +36 -1
- package/dist/ensure-mcp-config.js.map +1 -0
- package/dist/evict-drone.d.ts +10 -2
- package/dist/evict-drone.d.ts.map +1 -0
- package/dist/evict-drone.js +60 -1
- package/dist/evict-drone.js.map +1 -0
- package/dist/gc-orphan-inboxes.d.ts.map +1 -0
- package/dist/gc-orphan-inboxes.js +177 -1
- package/dist/gc-orphan-inboxes.js.map +1 -0
- package/dist/inbox-monitor.d.ts +1 -1
- package/dist/inbox-monitor.d.ts.map +1 -0
- package/dist/inbox-monitor.js +856 -3
- package/dist/inbox-monitor.js.map +1 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1034 -37
- package/dist/index.js.map +1 -0
- package/dist/launch-all-cmd.d.ts.map +1 -0
- package/dist/launch-all-cmd.js +377 -37
- package/dist/launch-all-cmd.js.map +1 -0
- package/dist/launch-all-command.d.ts.map +1 -0
- package/dist/launch-all-command.js +24 -1
- package/dist/launch-all-command.js.map +1 -0
- package/dist/launch-all-deps.d.ts +3 -8
- package/dist/launch-all-deps.d.ts.map +1 -0
- package/dist/launch-all-deps.js +99 -1
- package/dist/launch-all-deps.js.map +1 -0
- package/dist/launch-all-discovery.d.ts +1 -0
- package/dist/launch-all-discovery.d.ts.map +1 -0
- package/dist/launch-all-discovery.js +90 -4
- package/dist/launch-all-discovery.js.map +1 -0
- package/dist/launch-all-locks.d.ts.map +1 -0
- package/dist/launch-all-locks.js +54 -1
- package/dist/launch-all-locks.js.map +1 -0
- package/dist/launch-gate.d.ts +2 -2
- package/dist/launch-gate.d.ts.map +1 -0
- package/dist/launch-gate.js +73 -1
- package/dist/launch-gate.js.map +1 -0
- package/dist/lifecycle-log-guard.d.ts.map +1 -0
- package/dist/lifecycle-log-guard.js +93 -2
- package/dist/lifecycle-log-guard.js.map +1 -0
- package/dist/list-roles-render.d.ts.map +1 -0
- package/dist/list-roles-render.js +40 -6
- package/dist/list-roles-render.js.map +1 -0
- package/dist/local-log-routing.d.ts +19 -0
- package/dist/local-log-routing.d.ts.map +1 -0
- package/dist/local-log-routing.js +67 -0
- package/dist/local-log-routing.js.map +1 -0
- package/dist/local-manage-tool-result.d.ts +8 -0
- package/dist/local-manage-tool-result.d.ts.map +1 -0
- package/dist/local-manage-tool-result.js +10 -0
- package/dist/local-manage-tool-result.js.map +1 -0
- package/dist/local-server-cursor.d.ts +34 -0
- package/dist/local-server-cursor.d.ts.map +1 -0
- package/dist/local-server-cursor.js +151 -0
- package/dist/local-server-cursor.js.map +1 -0
- package/dist/log-audit.d.ts.map +1 -0
- package/dist/log-audit.js +194 -3
- package/dist/log-audit.js.map +1 -0
- package/dist/log-stream.d.ts +31 -18
- package/dist/log-stream.d.ts.map +1 -0
- package/dist/log-stream.js +1214 -12
- package/dist/log-stream.js.map +1 -0
- package/dist/model-presets.d.ts.map +1 -0
- package/dist/model-presets.js +19 -1
- package/dist/model-presets.js.map +1 -0
- package/dist/name-validator.d.ts.map +1 -0
- package/dist/name-validator.js +22 -1
- package/dist/name-validator.js.map +1 -0
- package/dist/opencode-drone.d.ts.map +1 -0
- package/dist/opencode-drone.js +438 -4
- package/dist/opencode-drone.js.map +1 -0
- package/dist/opencode-plugin.d.ts +1 -1
- package/dist/opencode-plugin.d.ts.map +1 -0
- package/dist/opencode-plugin.js +29 -4
- package/dist/opencode-plugin.js.map +1 -0
- package/dist/parse-assimilate-args.d.ts +1 -1
- package/dist/parse-assimilate-args.d.ts.map +1 -0
- package/dist/parse-assimilate-args.js +125 -1
- package/dist/parse-assimilate-args.js.map +1 -0
- package/dist/parse-launch-all-args.d.ts.map +1 -0
- package/dist/parse-launch-all-args.js +70 -1
- package/dist/parse-launch-all-args.js.map +1 -0
- package/dist/postinstall-banner.d.ts.map +1 -0
- package/dist/postinstall-banner.js +27 -2
- package/dist/postinstall-banner.js.map +1 -0
- package/dist/postinstall.d.ts.map +1 -0
- package/dist/postinstall.js +32 -5
- package/dist/postinstall.js.map +1 -0
- package/dist/readiness-probe.d.ts.map +1 -0
- package/dist/readiness-probe.js +9 -1
- package/dist/readiness-probe.js.map +1 -0
- package/dist/regen-format.d.ts.map +1 -0
- package/dist/regen-format.js +545 -13
- package/dist/regen-format.js.map +1 -0
- package/dist/regen.d.ts.map +1 -0
- package/dist/regen.js +141 -5
- package/dist/regen.js.map +1 -0
- package/dist/remote-client.d.ts +65 -175
- package/dist/remote-client.d.ts.map +1 -0
- package/dist/remote-client.js +942 -1
- package/dist/remote-client.js.map +1 -0
- package/dist/reset-local-seat-cmd.d.ts +50 -0
- package/dist/reset-local-seat-cmd.d.ts.map +1 -0
- package/dist/reset-local-seat-cmd.js +169 -0
- package/dist/reset-local-seat-cmd.js.map +1 -0
- package/dist/role-match.d.ts.map +1 -0
- package/dist/role-match.js +23 -1
- package/dist/role-match.js.map +1 -0
- package/dist/role-resolver.d.ts.map +1 -0
- package/dist/role-resolver.js +60 -1
- package/dist/role-resolver.js.map +1 -0
- package/dist/roster-render.d.ts.map +1 -0
- package/dist/roster-render.js +121 -3
- package/dist/roster-render.js.map +1 -0
- package/dist/seat-probe.d.ts +32 -13
- package/dist/seat-probe.d.ts.map +1 -0
- package/dist/seat-probe.js +78 -1
- package/dist/seat-probe.js.map +1 -0
- package/dist/seat-store.d.ts +76 -0
- package/dist/seat-store.d.ts.map +1 -0
- package/dist/seat-store.js +309 -0
- package/dist/seat-store.js.map +1 -0
- package/dist/seats.d.ts +303 -0
- package/dist/seats.d.ts.map +1 -0
- package/dist/seats.js +551 -0
- package/dist/seats.js.map +1 -0
- package/dist/self-path.d.ts +27 -0
- package/dist/self-path.d.ts.map +1 -0
- package/dist/self-path.js +43 -0
- package/dist/self-path.js.map +1 -0
- package/dist/server-endpoint.d.ts +9 -0
- package/dist/server-endpoint.d.ts.map +1 -0
- package/dist/server-endpoint.js +38 -0
- package/dist/server-endpoint.js.map +1 -0
- package/dist/server-errors.d.ts +50 -0
- package/dist/server-errors.d.ts.map +1 -0
- package/dist/server-errors.js +79 -0
- package/dist/server-errors.js.map +1 -0
- package/dist/server-handshake.d.ts +197 -0
- package/dist/server-handshake.d.ts.map +1 -0
- package/dist/server-handshake.js +505 -0
- package/dist/server-handshake.js.map +1 -0
- package/dist/server-response.d.ts +3 -0
- package/dist/server-response.d.ts.map +1 -0
- package/dist/server-response.js +67 -0
- package/dist/server-response.js.map +1 -0
- package/dist/server-trust.d.ts +14 -0
- package/dist/server-trust.d.ts.map +1 -0
- package/dist/server-trust.js +225 -0
- package/dist/server-trust.js.map +1 -0
- package/dist/setup-confirm.d.ts +3 -3
- package/dist/setup-confirm.d.ts.map +1 -0
- package/dist/setup-confirm.js +126 -2
- package/dist/setup-confirm.js.map +1 -0
- package/dist/setup.d.ts +5 -3
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +169 -46
- package/dist/setup.js.map +1 -0
- package/dist/shell-escape.d.ts.map +1 -0
- package/dist/shell-escape.js +22 -1
- package/dist/shell-escape.js.map +1 -0
- package/dist/spawn.d.ts +2 -2
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +29 -10
- package/dist/spawn.js.map +1 -0
- package/dist/startup-services.d.ts +0 -1
- package/dist/startup-services.d.ts.map +1 -0
- package/dist/startup-services.js +26 -1
- package/dist/startup-services.js.map +1 -0
- package/dist/stream-owner.d.ts +6 -2
- package/dist/stream-owner.d.ts.map +1 -0
- package/dist/stream-owner.js +547 -2
- package/dist/stream-owner.js.map +1 -0
- package/dist/stream-status.d.ts +1 -1
- package/dist/stream-status.d.ts.map +1 -0
- package/dist/stream-status.js +268 -3
- package/dist/stream-status.js.map +1 -0
- package/dist/sync-roles-render.d.ts.map +1 -0
- package/dist/sync-roles-render.js +118 -3
- package/dist/sync-roles-render.js.map +1 -0
- package/dist/sync.d.ts +1 -1
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +286 -22
- package/dist/sync.js.map +1 -0
- package/dist/terminal-title.d.ts.map +1 -0
- package/dist/terminal-title.js +68 -1
- package/dist/terminal-title.js.map +1 -0
- package/dist/token-store.d.ts +17 -111
- package/dist/token-store.d.ts.map +1 -0
- package/dist/token-store.js +81 -1
- package/dist/token-store.js.map +1 -0
- package/dist/tool-manifest.d.ts +4 -8
- package/dist/tool-manifest.d.ts.map +1 -0
- package/dist/tool-manifest.js +554 -1
- package/dist/tool-manifest.js.map +1 -0
- package/dist/tool-scope.d.ts +8 -12
- package/dist/tool-scope.d.ts.map +1 -0
- package/dist/tool-scope.js +97 -1
- package/dist/tool-scope.js.map +1 -0
- package/dist/types.d.ts +1 -5
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/unknown-subcommand.d.ts +1 -1
- package/dist/unknown-subcommand.d.ts.map +1 -0
- package/dist/unknown-subcommand.js +37 -1
- package/dist/unknown-subcommand.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +78 -2
- package/dist/version.js.map +1 -0
- package/dist/working-repo.d.ts.map +1 -0
- package/dist/working-repo.js +81 -1
- package/dist/working-repo.js.map +1 -0
- package/dist/worktree-lifecycle.d.ts.map +1 -0
- package/dist/worktree-lifecycle.js +205 -2
- package/dist/worktree-lifecycle.js.map +1 -0
- package/docs/EXTRACTION_PROVENANCE.md +40 -0
- package/docs/LOCAL_SERVER.md +103 -0
- package/docs/RELEASING.md +120 -0
- package/package.json +52 -34
- package/src/agent-runtime.ts +69 -0
- package/src/assimilate-cmd.ts +1864 -0
- package/src/assimilate-deps.ts +444 -0
- package/src/assimilate-guard.ts +84 -0
- package/src/assimilate-welcome.ts +39 -0
- package/src/auth-env.ts +21 -0
- package/src/backends/launch-all-pastelist.ts +18 -0
- package/src/backends/launch-all-tmux.ts +75 -0
- package/src/backends/launch-all-windows.ts +110 -0
- package/src/bare-launch-menu.ts +148 -0
- package/src/claude-launch-args.ts +35 -0
- package/src/claude.ts +561 -0
- package/src/cleanup-cmd.ts +581 -0
- package/src/clear-rewake-core.ts +34 -0
- package/src/clear-rewake.ts +18 -0
- package/src/cli-help.ts +116 -0
- package/src/cli-platform.ts +127 -0
- package/src/cli-tool-approval.ts +716 -0
- package/src/codex-app-server.ts +238 -0
- package/src/codex-app-wake.ts +512 -0
- package/src/codex-launch.ts +140 -0
- package/src/codex-remote.ts +500 -0
- package/src/codex-wake-resolve.ts +155 -0
- package/src/config-utils.ts +811 -0
- package/src/config.ts +595 -0
- package/src/console-prefix.ts +99 -0
- package/src/cube-name.ts +69 -0
- package/src/cubes.ts +583 -0
- package/src/debug.ts +73 -0
- package/src/direct-log.ts +9 -0
- package/src/docs-sections.ts +129 -0
- package/src/drone-lifecycle.ts +62 -0
- package/src/drone-management.ts +162 -0
- package/src/ensure-mcp-config.ts +54 -0
- package/src/evict-drone.ts +82 -0
- package/src/gc-orphan-inboxes.ts +229 -0
- package/src/inbox-monitor.ts +1005 -0
- package/src/index.ts +1201 -0
- package/src/launch-all-cmd.ts +450 -0
- package/src/launch-all-command.ts +30 -0
- package/src/launch-all-deps.ts +188 -0
- package/src/launch-all-discovery.ts +118 -0
- package/src/launch-all-locks.ts +74 -0
- package/src/launch-gate.ts +80 -0
- package/src/lifecycle-log-guard.ts +144 -0
- package/src/list-roles-render.ts +52 -0
- package/src/local-log-routing.ts +106 -0
- package/src/local-manage-tool-result.ts +10 -0
- package/src/local-server-cursor.ts +188 -0
- package/src/log-audit.ts +207 -0
- package/src/log-stream.ts +1505 -0
- package/src/model-presets.ts +22 -0
- package/src/name-validator.ts +23 -0
- package/src/opencode-drone.ts +528 -0
- package/src/opencode-plugin.ts +38 -0
- package/src/parse-assimilate-args.ts +125 -0
- package/src/parse-launch-all-args.ts +100 -0
- package/src/postinstall-banner.ts +37 -0
- package/src/postinstall.ts +36 -0
- package/src/readiness-probe.ts +12 -0
- package/src/regen-format.ts +651 -0
- package/src/regen.ts +150 -0
- package/src/remote-client.ts +1379 -0
- package/src/reset-local-seat-cmd.ts +227 -0
- package/src/role-match.ts +29 -0
- package/src/role-resolver.ts +93 -0
- package/src/roster-render.ts +196 -0
- package/src/seat-probe.ts +115 -0
- package/src/seat-store.ts +333 -0
- package/src/seats.ts +741 -0
- package/src/self-path.ts +51 -0
- package/src/server-endpoint.ts +38 -0
- package/src/server-errors.ts +93 -0
- package/src/server-handshake.ts +783 -0
- package/src/server-response.ts +76 -0
- package/src/server-trust.ts +245 -0
- package/src/setup-confirm.ts +171 -0
- package/src/setup.ts +186 -0
- package/src/shell-escape.ts +22 -0
- package/src/spawn.ts +31 -0
- package/src/startup-services.ts +36 -0
- package/src/stream-owner.ts +686 -0
- package/src/stream-status.ts +337 -0
- package/src/sync-roles-render.ts +163 -0
- package/src/sync.ts +363 -0
- package/src/terminal-title.ts +76 -0
- package/src/token-store.ts +102 -0
- package/src/tool-manifest.ts +610 -0
- package/src/tool-scope.ts +110 -0
- package/src/types.ts +5 -0
- package/src/unknown-subcommand.ts +35 -0
- package/src/version.ts +82 -0
- package/src/working-repo.ts +99 -0
- package/src/worktree-lifecycle.ts +254 -0
- package/dist/auth-recovery.d.ts +0 -33
- package/dist/auth-recovery.js +0 -1
- package/dist/auth.d.ts +0 -103
- package/dist/auth.js +0 -39
- package/dist/device-auth.d.ts +0 -75
- package/dist/device-auth.js +0 -1
- package/dist/drone-address.d.ts +0 -26
- package/dist/drone-address.js +0 -1
- package/dist/get-started.d.ts +0 -20
- package/dist/get-started.js +0 -2
- package/dist/health-beat.d.ts +0 -134
- package/dist/health-beat.js +0 -1
- package/dist/role-section.d.ts +0 -110
- package/dist/role-section.js +0 -8
- package/dist/setup-action.d.ts +0 -20
- package/dist/setup-action.js +0 -1
- package/dist/stale-version-check.d.ts +0 -40
- package/dist/stale-version-check.js +0 -1
- package/dist/subscription-retry.d.ts +0 -40
- package/dist/subscription-retry.js +0 -1
- package/dist/templates.d.ts +0 -107
- package/dist/templates.js +0 -359
- package/dist/token-crypto.d.ts +0 -50
- package/dist/token-crypto.js +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gh#793 — GC orphaned inbox files left by evicted/dead drones.
|
|
3
|
+
*
|
|
4
|
+
* The SSE cap-trim (`appendCappedInboxLine` → `trimInboxFileToRecentLines`)
|
|
5
|
+
* BOUNDS a live inbox file but never DELETES it, so an evicted/dead drone's
|
|
6
|
+
* `inboxes/<cube_id>/<drone_id>.log` (+ its worktree-runtime PID/heartbeat
|
|
7
|
+
* state) lingers forever. This GC removes those orphan artifacts,
|
|
8
|
+
* lazy-on-assimilate (no cron, no new command).
|
|
9
|
+
*
|
|
10
|
+
* THE INVIOLABLE RULE (CR live-safety gate): NEVER unlink an inbox with a live
|
|
11
|
+
* holder. Deleting a `.log` that a live #822 monitor is tailing leaves no inode
|
|
12
|
+
* to re-follow → HARD permanent deafness (a wrong delete is unrecoverable; a
|
|
13
|
+
* missed orphan is a harmless stale file). So we veto on ANY live signal and
|
|
14
|
+
* always err toward KEEPING.
|
|
15
|
+
*/
|
|
16
|
+
import { spawnSync } from 'node:child_process';
|
|
17
|
+
import { readFileSync, readdirSync, statSync, unlinkSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import {
|
|
20
|
+
pidfilePathFor,
|
|
21
|
+
heartbeatPathFor,
|
|
22
|
+
legacyPidfilePathFor,
|
|
23
|
+
legacyHeartbeatPathFor,
|
|
24
|
+
HEARTBEAT_STALE_MS,
|
|
25
|
+
} from './inbox-monitor.js';
|
|
26
|
+
|
|
27
|
+
/** §8.2 staleness threshold — ≥30 days; conservative, well beyond any plausible offline period. */
|
|
28
|
+
export const ORPHAN_INBOX_STALE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
29
|
+
|
|
30
|
+
/** Roster signal for a drone_id. `absent` is the safe default when no roster is available. */
|
|
31
|
+
export type DroneRosterState = 'present' | 'evicted' | 'absent';
|
|
32
|
+
|
|
33
|
+
export interface OrphanInboxEntry {
|
|
34
|
+
/** the drone_id parsed from the `<drone_id>.log` filename */
|
|
35
|
+
droneId: string;
|
|
36
|
+
/** absolute path to the `.log` */
|
|
37
|
+
inboxPath: string;
|
|
38
|
+
/** local mtime of the `.log`, in ms */
|
|
39
|
+
mtimeMs: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface SelectOrphanInboxesArgs {
|
|
43
|
+
entries: OrphanInboxEntry[];
|
|
44
|
+
/** §2 HARD gate: true if ANY live-holder signal fires (pgrep / fresh-heartbeat / live-pid). */
|
|
45
|
+
isLive: (inboxPath: string) => boolean;
|
|
46
|
+
/** roster bonus (when available): a `present` member is never reaped. */
|
|
47
|
+
droneState: (droneId: string) => DroneRosterState;
|
|
48
|
+
now: number;
|
|
49
|
+
staleMs: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Pure, FS-free selection (mirrors the `acquireInboxLock` dep-injection style so
|
|
54
|
+
* the live-safety + staleness logic is unit-pinned without touching the FS).
|
|
55
|
+
*
|
|
56
|
+
* An inbox is GC-eligible ONLY when ALL hold:
|
|
57
|
+
* §2 NO live holder — `isLive` false (the absolute gate; one live signal vetoes)
|
|
58
|
+
* §3 mtime stale past `staleMs` — the staleness belt (always required, even for evicted)
|
|
59
|
+
* §3.2 not a current roster member — `droneState` !== 'present' (roster bonus; 'absent' by default)
|
|
60
|
+
*/
|
|
61
|
+
export function selectOrphanInboxes(args: SelectOrphanInboxesArgs): OrphanInboxEntry[] {
|
|
62
|
+
const { entries, isLive, droneState, now, staleMs } = args;
|
|
63
|
+
return entries.filter((e) => {
|
|
64
|
+
if (isLive(e.inboxPath)) return false; // §2 INVIOLABLE — any live holder → KEEP
|
|
65
|
+
if (now - e.mtimeMs < staleMs) return false; // §3 staleness belt
|
|
66
|
+
return droneState(e.droneId) !== 'present'; // §3.2 never reap a current member
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface InboxLivenessDeps {
|
|
71
|
+
/** raw `pgrep -f <inboxPath>` match — true if a tail process is following the file (heartbeat-independent). */
|
|
72
|
+
pgrepTailMatch: (inboxPath: string) => boolean;
|
|
73
|
+
/** mtime (ms) of the heartbeat sidecar, or null if absent/unreadable. */
|
|
74
|
+
readHeartbeatMtimeMs: (heartbeatPath: string) => number | null;
|
|
75
|
+
/** parsed PID from the pidfile, or null if absent/unparseable. */
|
|
76
|
+
readPidfilePid: (pidfilePath: string) => number | null;
|
|
77
|
+
/** kill(pid, 0) liveness: true if the process exists. */
|
|
78
|
+
isAlive: (pid: number) => boolean;
|
|
79
|
+
now: number;
|
|
80
|
+
heartbeatStaleMs?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* §2 live-safety check — the HARD gate. LIVE if ANY of three INDEPENDENT signals
|
|
85
|
+
* fire (so a single positive vetoes the delete):
|
|
86
|
+
* 1. a raw `tail` pgrep match (a wedged-but-present tail still holds the inode → KEEP)
|
|
87
|
+
* 2. a heartbeat sidecar present AND fresh (within the stale threshold)
|
|
88
|
+
* 3. a pidfile whose PID is alive (kill-0)
|
|
89
|
+
*/
|
|
90
|
+
export function isInboxLive(
|
|
91
|
+
inboxPath: string,
|
|
92
|
+
deps: InboxLivenessDeps,
|
|
93
|
+
monitorStateRoot?: string | null
|
|
94
|
+
): boolean {
|
|
95
|
+
if (deps.pgrepTailMatch(inboxPath)) return true;
|
|
96
|
+
const staleMs = deps.heartbeatStaleMs ?? HEARTBEAT_STALE_MS;
|
|
97
|
+
const heartbeatPaths = [heartbeatPathFor(inboxPath, monitorStateRoot)];
|
|
98
|
+
const pidfilePaths = [pidfilePathFor(inboxPath, monitorStateRoot)];
|
|
99
|
+
if (monitorStateRoot) {
|
|
100
|
+
// Migration safety: an old inbox-adjacent holder is still a live veto.
|
|
101
|
+
heartbeatPaths.push(legacyHeartbeatPathFor(inboxPath));
|
|
102
|
+
pidfilePaths.push(legacyPidfilePathFor(inboxPath));
|
|
103
|
+
}
|
|
104
|
+
for (const heartbeatPath of new Set(heartbeatPaths)) {
|
|
105
|
+
const hbMs = deps.readHeartbeatMtimeMs(heartbeatPath);
|
|
106
|
+
if (hbMs !== null && deps.now - hbMs < staleMs) return true;
|
|
107
|
+
}
|
|
108
|
+
for (const pidfilePath of new Set(pidfilePaths)) {
|
|
109
|
+
const pid = deps.readPidfilePid(pidfilePath);
|
|
110
|
+
if (pid !== null && deps.isAlive(pid)) return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface OrphanGcDeps {
|
|
116
|
+
/** list the `<drone_id>.log` entries in the cube inbox dir (excludes sidecars). */
|
|
117
|
+
listInboxLogs: (cubeInboxDir: string) => OrphanInboxEntry[];
|
|
118
|
+
isLive: (inboxPath: string) => boolean;
|
|
119
|
+
droneState: (droneId: string) => DroneRosterState;
|
|
120
|
+
unlink: (path: string) => void;
|
|
121
|
+
now: number;
|
|
122
|
+
staleMs: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Wire the GC for one cube dir: select orphans (excluding the just-assimilated
|
|
127
|
+
* drone), then unlink each orphan's inbox plus its derived worktree-runtime
|
|
128
|
+
* PID/heartbeat state. Legacy inbox-adjacent artifacts are intentionally left
|
|
129
|
+
* for explicit operator cleanup: GC must never race an old binary that does
|
|
130
|
+
* not participate in modern state serialization. Best-effort — every unlink is
|
|
131
|
+
* swallowed per-file so a
|
|
132
|
+
* single failure never aborts the sweep or blocks assimilate. Returns the paths
|
|
133
|
+
* actually removed. Never rmdir's the cube dir (a live sibling may use it).
|
|
134
|
+
*/
|
|
135
|
+
export function gcOrphanInboxesForCube(args: {
|
|
136
|
+
cubeInboxDir: string;
|
|
137
|
+
selfDroneId: string;
|
|
138
|
+
/** Explicit current-worktree root; legacy sidecars remain untouched. */
|
|
139
|
+
monitorStateRoot?: string | null;
|
|
140
|
+
deps: OrphanGcDeps;
|
|
141
|
+
}): string[] {
|
|
142
|
+
const { cubeInboxDir, selfDroneId, monitorStateRoot, deps } = args;
|
|
143
|
+
const entries = deps.listInboxLogs(cubeInboxDir).filter((e) => e.droneId !== selfDroneId);
|
|
144
|
+
const orphans = selectOrphanInboxes({
|
|
145
|
+
entries,
|
|
146
|
+
isLive: deps.isLive,
|
|
147
|
+
droneState: deps.droneState,
|
|
148
|
+
now: deps.now,
|
|
149
|
+
staleMs: deps.staleMs,
|
|
150
|
+
});
|
|
151
|
+
const removed: string[] = [];
|
|
152
|
+
for (const o of orphans) {
|
|
153
|
+
const sidecars = [
|
|
154
|
+
pidfilePathFor(o.inboxPath, monitorStateRoot),
|
|
155
|
+
heartbeatPathFor(o.inboxPath, monitorStateRoot),
|
|
156
|
+
];
|
|
157
|
+
for (const p of new Set([o.inboxPath, ...sidecars])) {
|
|
158
|
+
try {
|
|
159
|
+
deps.unlink(p);
|
|
160
|
+
removed.push(p);
|
|
161
|
+
} catch {
|
|
162
|
+
/* best-effort: sidecar may be absent / unlink may race — never abort the sweep */
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return removed;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Real FS/process-backed deps, reusing the #795/#822 primitives. */
|
|
170
|
+
export function defaultInboxLivenessDeps(now: number = Date.now()): InboxLivenessDeps {
|
|
171
|
+
return {
|
|
172
|
+
pgrepTailMatch: (inboxPath) => {
|
|
173
|
+
try {
|
|
174
|
+
// raw presence: a tail following <inboxPath> (heartbeat-independent —
|
|
175
|
+
// a wedged tail still holds the inode, so its mere presence vetoes).
|
|
176
|
+
const res = spawnSync('pgrep', ['-f', inboxPath], { encoding: 'utf-8', timeout: 2_000 });
|
|
177
|
+
if (res.error) return false; // no pgrep (other platform) → defer to heartbeat/pid signals
|
|
178
|
+
return res.status === 0 && res.stdout.trim().length > 0;
|
|
179
|
+
} catch {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
readHeartbeatMtimeMs: (heartbeatPath) => {
|
|
184
|
+
try {
|
|
185
|
+
return statSync(heartbeatPath).mtimeMs;
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
readPidfilePid: (pidfilePath) => {
|
|
191
|
+
try {
|
|
192
|
+
const pid = Number.parseInt(readFileSync(pidfilePath, 'utf8').trim(), 10);
|
|
193
|
+
return Number.isNaN(pid) ? null : pid;
|
|
194
|
+
} catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
isAlive: (pid) => {
|
|
199
|
+
try {
|
|
200
|
+
process.kill(pid, 0);
|
|
201
|
+
return true;
|
|
202
|
+
} catch (err: any) {
|
|
203
|
+
return err?.code === 'EPERM'; // exists but unsignalable → still alive
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
now,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Real directory lister: `<drone_id>.log` files only (skips `.monitor.*` sidecars). */
|
|
211
|
+
export function defaultListInboxLogs(cubeInboxDir: string): OrphanInboxEntry[] {
|
|
212
|
+
let names: string[];
|
|
213
|
+
try {
|
|
214
|
+
names = readdirSync(cubeInboxDir);
|
|
215
|
+
} catch {
|
|
216
|
+
return []; // cube dir absent → nothing to GC
|
|
217
|
+
}
|
|
218
|
+
const out: OrphanInboxEntry[] = [];
|
|
219
|
+
for (const name of names) {
|
|
220
|
+
if (!name.endsWith('.log')) continue; // exclude .monitor.pid / .monitor.heartbeat
|
|
221
|
+
const inboxPath = join(cubeInboxDir, name);
|
|
222
|
+
try {
|
|
223
|
+
out.push({ droneId: name.slice(0, -'.log'.length), inboxPath, mtimeMs: statSync(inboxPath).mtimeMs });
|
|
224
|
+
} catch {
|
|
225
|
+
/* vanished mid-scan → skip */
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
229
|
+
}
|