aicodeman 1.44.0 → 1.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -8
- package/dist/agent-codex-identity.d.ts +26 -0
- package/dist/agent-codex-identity.d.ts.map +1 -0
- package/dist/agent-codex-identity.js +253 -0
- package/dist/agent-codex-identity.js.map +1 -0
- package/dist/agent-inspection.d.ts +32 -0
- package/dist/agent-inspection.d.ts.map +1 -0
- package/dist/agent-inspection.js +196 -0
- package/dist/agent-inspection.js.map +1 -0
- package/dist/agent-staging.d.ts +130 -0
- package/dist/agent-staging.d.ts.map +1 -0
- package/dist/agent-staging.js +312 -0
- package/dist/agent-staging.js.map +1 -0
- package/dist/case-rename.d.ts +65 -0
- package/dist/case-rename.d.ts.map +1 -0
- package/dist/case-rename.js +198 -0
- package/dist/case-rename.js.map +1 -0
- package/dist/cli-agent.d.ts +91 -3
- package/dist/cli-agent.d.ts.map +1 -1
- package/dist/cli-agent.js +501 -44
- package/dist/cli-agent.js.map +1 -1
- package/dist/cli-history.d.ts +20 -0
- package/dist/cli-history.d.ts.map +1 -0
- package/dist/cli-history.js +61 -0
- package/dist/cli-history.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -1
- package/dist/cli.js.map +1 -1
- package/dist/codex-rollout-format.d.ts +66 -0
- package/dist/codex-rollout-format.d.ts.map +1 -0
- package/dist/codex-rollout-format.js +111 -0
- package/dist/codex-rollout-format.js.map +1 -0
- package/dist/codex-transcript.d.ts +3 -0
- package/dist/codex-transcript.d.ts.map +1 -1
- package/dist/codex-transcript.js +13 -41
- package/dist/codex-transcript.js.map +1 -1
- package/dist/config/auth-config.d.ts +16 -1
- package/dist/config/auth-config.d.ts.map +1 -1
- package/dist/config/auth-config.js +16 -1
- package/dist/config/auth-config.js.map +1 -1
- package/dist/config/cli-registry/schema.d.ts +12 -7
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +26 -0
- package/dist/config/cli-registry/schema.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +40 -1
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +57 -0
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/config/server-timing.d.ts +6 -0
- package/dist/config/server-timing.d.ts.map +1 -1
- package/dist/config/server-timing.js +9 -0
- package/dist/config/server-timing.js.map +1 -1
- package/dist/daemon-control.d.ts +1 -0
- package/dist/daemon-control.d.ts.map +1 -1
- package/dist/daemon-control.js +2 -0
- package/dist/daemon-control.js.map +1 -1
- package/dist/deepseek-transcript.d.ts +9 -7
- package/dist/deepseek-transcript.d.ts.map +1 -1
- package/dist/deepseek-transcript.js +9 -7
- package/dist/deepseek-transcript.js.map +1 -1
- package/dist/docker-hosts.d.ts +8 -0
- package/dist/docker-hosts.d.ts.map +1 -1
- package/dist/docker-hosts.js +29 -0
- package/dist/docker-hosts.js.map +1 -1
- package/dist/git-fetch-scheduler.d.ts +124 -0
- package/dist/git-fetch-scheduler.d.ts.map +1 -0
- package/dist/git-fetch-scheduler.js +249 -0
- package/dist/git-fetch-scheduler.js.map +1 -0
- package/dist/git-fetch.d.ts +241 -0
- package/dist/git-fetch.d.ts.map +1 -0
- package/dist/git-fetch.js +392 -0
- package/dist/git-fetch.js.map +1 -0
- package/dist/git-workspace-status.d.ts +36 -1
- package/dist/git-workspace-status.d.ts.map +1 -1
- package/dist/git-workspace-status.js +42 -5
- package/dist/git-workspace-status.js.map +1 -1
- package/dist/hooks-config.d.ts +14 -2
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +39 -3
- package/dist/hooks-config.js.map +1 -1
- package/dist/host-sensors.d.ts +115 -0
- package/dist/host-sensors.d.ts.map +1 -0
- package/dist/host-sensors.js +457 -0
- package/dist/host-sensors.js.map +1 -0
- package/dist/local-history.d.ts +71 -0
- package/dist/local-history.d.ts.map +1 -0
- package/dist/local-history.js +750 -0
- package/dist/local-history.js.map +1 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/mux-interface.d.ts +5 -2
- package/dist/mux-interface.d.ts.map +1 -1
- package/dist/prompt-cache-keepwarm.d.ts.map +1 -1
- package/dist/prompt-cache-keepwarm.js +5 -3
- package/dist/prompt-cache-keepwarm.js.map +1 -1
- package/dist/remote-hosts.d.ts +7 -0
- package/dist/remote-hosts.d.ts.map +1 -1
- package/dist/remote-hosts.js +17 -3
- package/dist/remote-hosts.js.map +1 -1
- package/dist/remote-pane-history.d.ts.map +1 -1
- package/dist/remote-pane-history.js +2 -2
- package/dist/remote-pane-history.js.map +1 -1
- package/dist/session.d.ts +113 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +354 -13
- package/dist/session.js.map +1 -1
- package/dist/terminal-input-classifier.d.ts +8 -0
- package/dist/terminal-input-classifier.d.ts.map +1 -0
- package/dist/terminal-input-classifier.js +60 -0
- package/dist/terminal-input-classifier.js.map +1 -0
- package/dist/tmux-manager.d.ts +30 -4
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +101 -21
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-prefix-table.d.ts +37 -5
- package/dist/tmux-prefix-table.d.ts.map +1 -1
- package/dist/tmux-prefix-table.js +40 -5
- package/dist/tmux-prefix-table.js.map +1 -1
- package/dist/tui/tui-app.d.ts +8 -1
- package/dist/tui/tui-app.d.ts.map +1 -1
- package/dist/tui/tui-app.js +49 -12
- package/dist/tui/tui-app.js.map +1 -1
- package/dist/tui/tui-client.d.ts +90 -3
- package/dist/tui/tui-client.d.ts.map +1 -1
- package/dist/tui/tui-client.js +195 -26
- package/dist/tui/tui-client.js.map +1 -1
- package/dist/types/session.d.ts +15 -0
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/web/agent-inbox-persistence.d.ts +52 -0
- package/dist/web/agent-inbox-persistence.d.ts.map +1 -0
- package/dist/web/agent-inbox-persistence.js +139 -0
- package/dist/web/agent-inbox-persistence.js.map +1 -0
- package/dist/web/agent-inbox.d.ts +140 -0
- package/dist/web/agent-inbox.d.ts.map +1 -0
- package/dist/web/agent-inbox.js +258 -0
- package/dist/web/agent-inbox.js.map +1 -0
- package/dist/web/middleware/auth.d.ts +2 -0
- package/dist/web/middleware/auth.d.ts.map +1 -1
- package/dist/web/middleware/auth.js +145 -52
- package/dist/web/middleware/auth.js.map +1 -1
- package/dist/web/network-auth-policy.d.ts +13 -3
- package/dist/web/network-auth-policy.d.ts.map +1 -1
- package/dist/web/network-auth-policy.js +15 -3
- package/dist/web/network-auth-policy.js.map +1 -1
- package/dist/web/ports/infra-port.d.ts +2 -0
- package/dist/web/ports/infra-port.d.ts.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.3093527f.js +43 -0
- package/dist/web/public/app.3093527f.js.br +0 -0
- package/dist/web/public/app.3093527f.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.4866ecc3.js → constants.affcdde6.js} +622 -12
- package/dist/web/public/constants.affcdde6.js.br +0 -0
- package/dist/web/public/constants.affcdde6.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/git-status-ui.js +88 -5
- package/dist/web/public/git-status-ui.js.br +0 -0
- package/dist/web/public/git-status-ui.js.gz +0 -0
- package/dist/web/public/header-divider.eb2d2463.js +1 -0
- package/dist/web/public/header-divider.eb2d2463.js.br +0 -0
- package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.70265257.js +2 -0
- package/dist/web/public/i18n.70265257.js.br +0 -0
- package/dist/web/public/i18n.70265257.js.gz +0 -0
- package/dist/web/public/image-input.941386e7.js.gz +0 -0
- package/dist/web/public/index.html +170 -16
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.4e8b20ac.js.gz +0 -0
- package/dist/web/public/{mobile-handlers.44adaa07.js → mobile-handlers.f7c3f692.js} +26 -2
- package/dist/web/public/mobile-handlers.f7c3f692.js.br +0 -0
- package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
- package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.1bbd2d67.css +1 -0
- package/dist/web/public/mobile.1bbd2d67.css.br +0 -0
- package/dist/web/public/mobile.1bbd2d67.css.gz +0 -0
- package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.cbb24ba1.js → panels-ui.4a56ee63.js} +76 -70
- package/dist/web/public/panels-ui.4a56ee63.js.br +0 -0
- package/dist/web/public/panels-ui.4a56ee63.js.gz +0 -0
- package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
- package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/reboot-restore-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
- package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/session-ui.186f9419.js +106 -0
- package/dist/web/public/session-ui.186f9419.js.br +0 -0
- package/dist/web/public/session-ui.186f9419.js.gz +0 -0
- package/dist/web/public/settings-ui.a191154e.js +106 -0
- package/dist/web/public/settings-ui.a191154e.js.br +0 -0
- package/dist/web/public/settings-ui.a191154e.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
- package/dist/web/public/styles.7238eae8.css +1 -0
- package/dist/web/public/styles.7238eae8.css.br +0 -0
- package/dist/web/public/styles.7238eae8.css.gz +0 -0
- package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
- package/dist/web/public/sw.js +2 -2
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
- package/dist/web/public/{tab-rail-resize.7157e0bd.js → tab-rail-resize.b5cdceaf.js} +1 -1
- package/dist/web/public/tab-rail-resize.b5cdceaf.js.br +0 -0
- package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
- package/dist/web/public/terminal-split.js.gz +0 -0
- package/dist/web/public/terminal-tile.js +10 -1
- package/dist/web/public/terminal-tile.js.br +0 -0
- package/dist/web/public/terminal-tile.js.gz +0 -0
- package/dist/web/public/terminal-ui.7e787829.js +4 -0
- package/dist/web/public/terminal-ui.7e787829.js.br +0 -0
- package/dist/web/public/terminal-ui.7e787829.js.gz +0 -0
- package/dist/web/public/tile-grid.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
- package/dist/web/public/vendor/fflate.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/{xterm-predictive-echo.ae5e3d5d.js → xterm-predictive-echo.276b11d9.js} +1 -1
- package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.br +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js +5 -0
- package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.br +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/public/whats-new.json +9 -9
- package/dist/web/route-helpers.d.ts +57 -6
- package/dist/web/route-helpers.d.ts.map +1 -1
- package/dist/web/route-helpers.js +72 -4
- package/dist/web/route-helpers.js.map +1 -1
- package/dist/web/routes/agent-session-routes.d.ts +20 -0
- package/dist/web/routes/agent-session-routes.d.ts.map +1 -0
- package/dist/web/routes/agent-session-routes.js +160 -0
- package/dist/web/routes/agent-session-routes.js.map +1 -0
- package/dist/web/routes/case-routes.d.ts.map +1 -1
- package/dist/web/routes/case-routes.js +203 -16
- package/dist/web/routes/case-routes.js.map +1 -1
- package/dist/web/routes/config-backup-routes.js +2 -2
- package/dist/web/routes/config-backup-routes.js.map +1 -1
- package/dist/web/routes/git-status-routes.d.ts +21 -7
- package/dist/web/routes/git-status-routes.d.ts.map +1 -1
- package/dist/web/routes/git-status-routes.js +78 -12
- package/dist/web/routes/git-status-routes.js.map +1 -1
- package/dist/web/routes/inbox-routes.d.ts +43 -0
- package/dist/web/routes/inbox-routes.d.ts.map +1 -0
- package/dist/web/routes/inbox-routes.js +148 -0
- package/dist/web/routes/inbox-routes.js.map +1 -0
- package/dist/web/routes/index.d.ts +2 -0
- package/dist/web/routes/index.d.ts.map +1 -1
- package/dist/web/routes/index.js +2 -0
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/ralph-routes.d.ts.map +1 -1
- package/dist/web/routes/ralph-routes.js +7 -16
- package/dist/web/routes/ralph-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +120 -74
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +107 -59
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/routes/ws-routes.d.ts +5 -0
- package/dist/web/routes/ws-routes.d.ts.map +1 -1
- package/dist/web/routes/ws-routes.js +84 -47
- package/dist/web/routes/ws-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +56 -7
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +88 -1
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/sensitive-path.d.ts.map +1 -1
- package/dist/web/sensitive-path.js +2 -0
- package/dist/web/sensitive-path.js.map +1 -1
- package/dist/web/server.d.ts +7 -2
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +144 -16
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-wait-registry.d.ts +48 -4
- package/dist/web/session-wait-registry.d.ts.map +1 -1
- package/dist/web/session-wait-registry.js +144 -6
- package/dist/web/session-wait-registry.js.map +1 -1
- package/dist/web/settings-writer.d.ts +47 -0
- package/dist/web/settings-writer.d.ts.map +1 -0
- package/dist/web/settings-writer.js +110 -0
- package/dist/web/settings-writer.js.map +1 -0
- package/dist/web/sse-events.d.ts +4 -1
- package/dist/web/sse-events.d.ts.map +1 -1
- package/dist/web/sse-events.js +4 -1
- package/dist/web/sse-events.js.map +1 -1
- package/package.json +1 -1
- package/skills/codeman/SKILL.md +30 -8
- package/skills/codeman/preamble.sh +3 -3
- package/skills/codeman/reference/endpoints.md +24 -3
- package/skills/codeman/reference/history.md +84 -0
- package/skills/codeman/reference/inspection-and-staging.md +152 -0
- package/skills/codeman/reference/messaging.md +1 -1
- package/skills/codeman/reference/verbs.md +65 -3
- package/dist/web/public/app.9314ee60.js +0 -43
- package/dist/web/public/app.9314ee60.js.br +0 -0
- package/dist/web/public/app.9314ee60.js.gz +0 -0
- package/dist/web/public/constants.4866ecc3.js.br +0 -0
- package/dist/web/public/constants.4866ecc3.js.gz +0 -0
- package/dist/web/public/i18n.22ca902b.js +0 -2
- package/dist/web/public/i18n.22ca902b.js.br +0 -0
- package/dist/web/public/i18n.22ca902b.js.gz +0 -0
- package/dist/web/public/mobile-handlers.44adaa07.js.br +0 -0
- package/dist/web/public/mobile-handlers.44adaa07.js.gz +0 -0
- package/dist/web/public/mobile.12fb18de.css +0 -1
- package/dist/web/public/mobile.12fb18de.css.br +0 -0
- package/dist/web/public/mobile.12fb18de.css.gz +0 -0
- package/dist/web/public/panels-ui.cbb24ba1.js.br +0 -0
- package/dist/web/public/panels-ui.cbb24ba1.js.gz +0 -0
- package/dist/web/public/session-ui.9c1f009b.js +0 -104
- package/dist/web/public/session-ui.9c1f009b.js.br +0 -0
- package/dist/web/public/session-ui.9c1f009b.js.gz +0 -0
- package/dist/web/public/settings-ui.fea9ddae.js +0 -106
- package/dist/web/public/settings-ui.fea9ddae.js.br +0 -0
- package/dist/web/public/settings-ui.fea9ddae.js.gz +0 -0
- package/dist/web/public/styles.e096fcd6.css +0 -1
- package/dist/web/public/styles.e096fcd6.css.br +0 -0
- package/dist/web/public/styles.e096fcd6.css.gz +0 -0
- package/dist/web/public/tab-rail-resize.7157e0bd.js.br +0 -0
- package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
- package/dist/web/public/terminal-ui.68dbd352.js +0 -2
- package/dist/web/public/terminal-ui.68dbd352.js.br +0 -0
- package/dist/web/public/terminal-ui.68dbd352.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.br +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js +0 -4
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.br +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
package/dist/web/server.js
CHANGED
|
@@ -44,6 +44,7 @@ import { looksLikeHostReboot, newestPersistedActivity, planRebootRestore } from
|
|
|
44
44
|
import { rebootRestoreRegistry } from './reboot-restore-registry.js';
|
|
45
45
|
import { dataPath, getDataDir, CODEMAN_INSTANCE } from '../config/instance.js';
|
|
46
46
|
import { WebhookNotifier, readWebhookConfig } from '../webhook-notify.js';
|
|
47
|
+
import { stopHostSensors } from '../host-sensors.js';
|
|
47
48
|
import { webviewFetch } from './webview-egress.js';
|
|
48
49
|
import { readRemoteHosts, rehydrateRemoteHostFields } from '../remote-hosts.js';
|
|
49
50
|
import { normalizeBasePath, stripBasePath, joinBasePath } from '../config/base-path.js';
|
|
@@ -77,7 +78,7 @@ import { createRequire } from 'node:module';
|
|
|
77
78
|
import { RunSummaryTracker } from '../run-summary.js';
|
|
78
79
|
import { OrchestratorLoop } from '../orchestrator-loop.js';
|
|
79
80
|
import { getLifecycleLog } from '../session-lifecycle-log.js';
|
|
80
|
-
import { applyWorkspaceHooks, pruneAgentSessionPreambles, readKeepWarmSettingsOrThrow, readPlanUsageTelemetryEnabled, removeAgentSessionPreamble, } from '../hooks-config.js';
|
|
81
|
+
import { applyWorkspaceHooks, pruneAgentSessionPreambles, readGitFetchSettings, readKeepWarmSettingsOrThrow, readPlanUsageTelemetryEnabled, removeAgentSessionPreamble, } from '../hooks-config.js';
|
|
81
82
|
import { PushSubscriptionStore } from '../push-store.js';
|
|
82
83
|
import webpush from 'web-push';
|
|
83
84
|
import { SseStreamManager } from './sse-stream-manager.js';
|
|
@@ -86,10 +87,16 @@ import { deriveWebviewSseHint } from './webview-sse.js';
|
|
|
86
87
|
import { createSessionListeners, attachSessionListeners, detachSessionListeners, } from './session-listener-wiring.js';
|
|
87
88
|
import { sessionWaits } from './session-wait-registry.js';
|
|
88
89
|
import { intentStore } from '../intent-store.js';
|
|
90
|
+
import { agentInbox } from './agent-inbox.js';
|
|
91
|
+
import { agentInboxPersistence } from './agent-inbox-persistence.js';
|
|
89
92
|
import { AI_CHECK_MODEL } from '../config/ai-defaults.js';
|
|
90
93
|
import { approvalInbox } from './approval-inbox.js';
|
|
91
94
|
import { SCREEN_BLOCKED_SOURCE } from './screen-blocked.js';
|
|
92
95
|
import { PromptCacheKeepWarmService } from '../prompt-cache-keepwarm.js';
|
|
96
|
+
import { fetchWorkspaceOnce } from '../git-fetch.js';
|
|
97
|
+
import { GitFetchScheduler } from '../git-fetch-scheduler.js';
|
|
98
|
+
import { probePathKind } from '../utils/bounded-path-probe.js';
|
|
99
|
+
import { defaultDockerWorkspaces } from './routes/git-status-routes.js';
|
|
93
100
|
import { composerIsEmpty, plainFrame } from '../session-submit-verifier.js';
|
|
94
101
|
import { detectUsageLimitPause } from '../usage-limit-patterns.js';
|
|
95
102
|
import { stopDeepSeekWeb } from '../deepseek-web-server.js';
|
|
@@ -117,6 +124,7 @@ import { MAX_PASTE_IMAGE_BYTES } from '../config/buffer-limits.js';
|
|
|
117
124
|
import { resolveTerminalHistoryConfig } from '../config/terminal-history.js';
|
|
118
125
|
import { SseEvent } from './sse-events.js';
|
|
119
126
|
import { MAX_ROUTE_PARAM_LENGTH } from './route-helpers.js';
|
|
127
|
+
import { mutateSettingsFile } from './settings-writer.js';
|
|
120
128
|
import { getLatestPlanUsage, setLatestCodexPlanUsage, setLatestCopilotPlanUsage } from './plan-usage-latest.js';
|
|
121
129
|
import { telemetrySignature } from '../usage-telemetry.js';
|
|
122
130
|
import { readCodexPlanUsage, resolveCodexBinaryPath } from '../utils/codex-cli-resolver.js';
|
|
@@ -127,9 +135,10 @@ import { isMultiUserMode } from '../config/multiuser.js';
|
|
|
127
135
|
import { bootstrapInitialAdmin, hasUsers, resolveClaudeModeForUsername } from '../user-store.js';
|
|
128
136
|
import { installRouteErrorHandler } from './route-error-handler.js';
|
|
129
137
|
import { isExplicitlyEnabled, isLoopbackBindHost, buildHostPolicy } from './network-auth-policy.js';
|
|
130
|
-
import { registerPushRoutes, registerTeamRoutes, registerMuxRoutes, registerFileRoutes, registerHtmlViewRoutes, registerScheduledRoutes, registerHookEventRoutes, registerApprovalRoutes, registerRebootRestoreRoutes, registerReadMyMindRoutes, registerGitStatusRoutes, registerStatusTelemetryRoutes, registerSystemRoutes, registerCaseRoutes, registerWorktreeRoutes, registerSessionRoutes, registerRespawnRoutes, registerRalphRoutes, registerPlanRoutes, registerClipboardRoutes, registerSearchRoutes, registerOrchestratorRoutes, registerCronRoutes, registerMeRoutes, registerAdminRoutes, registerWsRoutes, registerVoiceRoutes, registerWebviewRoutes, registerTabLayoutRoutes, registerMcpSyncRoutes, registerConfigBackupRoutes, runConfigBackup, registerWebhookRoutes, registerDoctorRoutes, registerCustomModelRoutes, refreshAllCustomModelHosts, readCustomModelEndpointsEnabled, closeAllLlamaSwapLogTails, detectCustomModelSwapDisplacements, pruneIdleLlamaSwapLogTails, tryWebviewRefererFallback, registerCliRegistryRoutes, } from './routes/index.js';
|
|
138
|
+
import { registerPushRoutes, registerTeamRoutes, registerMuxRoutes, registerFileRoutes, registerHtmlViewRoutes, registerScheduledRoutes, registerHookEventRoutes, registerApprovalRoutes, registerInboxRoutes, registerRebootRestoreRoutes, registerReadMyMindRoutes, registerGitStatusRoutes, registerStatusTelemetryRoutes, registerSystemRoutes, registerCaseRoutes, registerWorktreeRoutes, registerSessionRoutes, registerAgentSessionRoutes, registerRespawnRoutes, registerRalphRoutes, registerPlanRoutes, registerClipboardRoutes, registerSearchRoutes, registerOrchestratorRoutes, registerCronRoutes, registerMeRoutes, registerAdminRoutes, registerWsRoutes, registerVoiceRoutes, registerWebviewRoutes, registerTabLayoutRoutes, registerMcpSyncRoutes, registerConfigBackupRoutes, runConfigBackup, registerWebhookRoutes, registerDoctorRoutes, registerCustomModelRoutes, refreshAllCustomModelHosts, readCustomModelEndpointsEnabled, closeAllLlamaSwapLogTails, detectCustomModelSwapDisplacements, pruneIdleLlamaSwapLogTails, tryWebviewRefererFallback, registerCliRegistryRoutes, } from './routes/index.js';
|
|
131
139
|
import { isLostWebviewFrameNavigation } from './webview-proxy.js';
|
|
132
140
|
import { CronService } from '../cron/cron-service.js';
|
|
141
|
+
import { caseSessionSettled } from '../case-rename.js';
|
|
133
142
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
134
143
|
// Bounded, predictable shape for SSE client identifiers: alphanumerics, `_`, `-`.
|
|
135
144
|
// Length range covers crypto.randomUUID() (36 chars) plus any short stable IDs,
|
|
@@ -164,7 +173,7 @@ function escapeHtmlText(value) {
|
|
|
164
173
|
export function escapeScriptJson(json) {
|
|
165
174
|
return json.replace(/</g, '\\u003c');
|
|
166
175
|
}
|
|
167
|
-
import { SESSIONS_LIST_CACHE_TTL, SCHEDULED_CLEANUP_INTERVAL, SCHEDULED_RUN_MAX_AGE, SSE_HEARTBEAT_INTERVAL, SESSION_LIMIT_WAIT_MS, ITERATION_PAUSE_MS, STATS_COLLECTION_INTERVAL_MS, INACTIVITY_TIMEOUT_MS, CRON_TICK_INTERVAL, } from '../config/server-timing.js';
|
|
176
|
+
import { SESSIONS_LIST_CACHE_TTL, SCHEDULED_CLEANUP_INTERVAL, SCHEDULED_RUN_MAX_AGE, SSE_HEARTBEAT_INTERVAL, SESSION_LIMIT_WAIT_MS, ITERATION_PAUSE_MS, STATS_COLLECTION_INTERVAL_MS, INACTIVITY_TIMEOUT_MS, CRON_TICK_INTERVAL, GIT_FETCH_TICK_INTERVAL_MS, } from '../config/server-timing.js';
|
|
168
177
|
/**
|
|
169
178
|
* Get or generate a self-signed TLS certificate for HTTPS.
|
|
170
179
|
* Certs are stored in ~/.codeman/certs/ and reused across restarts.
|
|
@@ -250,6 +259,38 @@ export class WebServer extends EventEmitter {
|
|
|
250
259
|
},
|
|
251
260
|
log: (message) => console.log(message),
|
|
252
261
|
});
|
|
262
|
+
// Git fetch on an interval (git-fetch-scheduler.ts): the due-tracking lives in the service; the server
|
|
263
|
+
// lends it the facts a decision needs and stores what it reports on the session. A field initializer for
|
|
264
|
+
// the same reason as the keep-warm one above, and the scheduler reads the app setting FRESH on every tick:
|
|
265
|
+
// that is what makes a live toggle take effect on the next tick, and what makes turning it off actually
|
|
266
|
+
// stop the fetching. Default OFF, so an install that never enabled it spawns nothing at all.
|
|
267
|
+
gitFetchScheduler = new GitFetchScheduler({
|
|
268
|
+
sessionIds: () => this.sessions.keys(),
|
|
269
|
+
getSession: (id) => this.sessions.get(id),
|
|
270
|
+
readSettings: readGitFetchSettings,
|
|
271
|
+
// The same Docker list the panel's Fetch button uses: the rule has to be one rule. It rejects on a list
|
|
272
|
+
// that cannot be read, and the tick then fetches nothing (fail closed).
|
|
273
|
+
dockerWorkspaces: defaultDockerWorkspaces,
|
|
274
|
+
// Bounded probe, DEFAULT options (rule #516): a tick is a bulk scan, so it keeps the stall cap and must
|
|
275
|
+
// never be handed `pastCap`. A folder on a mount that stopped answering is skipped, not fetched.
|
|
276
|
+
probePath: (path) => probePathKind(path),
|
|
277
|
+
// Through the join, so the tick and the panel's Fetch button are the same run: a click on a folder the
|
|
278
|
+
// tick is already fetching joins it rather than starting a second `git fetch` in the same clone, and the
|
|
279
|
+
// run that gets published is the one that ran, with its own trigger.
|
|
280
|
+
fetch: (cwd, opts, trigger) => fetchWorkspaceOnce(cwd, opts, trigger),
|
|
281
|
+
publish: (id, status) => {
|
|
282
|
+
const session = this.sessions.get(id);
|
|
283
|
+
if (!session?.setGitFetchStatus(status))
|
|
284
|
+
return;
|
|
285
|
+
// No new SSE event: the status rides the session state the page already listens for, and the Git
|
|
286
|
+
// panel polls on its own clock. It is written to disk with the rest of the record, but the restore
|
|
287
|
+
// copies only the fields its own config lists and this is not one of them (src/types/session.ts), so
|
|
288
|
+
// what a run found is the panel's truth for the life of the session, not across a restart.
|
|
289
|
+
this.persistSessionState(session);
|
|
290
|
+
this.broadcast(SseEvent.SessionUpdated, this.getSessionStateWithRespawn(session));
|
|
291
|
+
},
|
|
292
|
+
log: (message) => console.log(message),
|
|
293
|
+
});
|
|
253
294
|
/**
|
|
254
295
|
* Wake-on-LAN registry, returned by `registerSessionRoutes`. Held for its LIFETIME
|
|
255
296
|
* only — `drop()` on session cleanup, `stop()` on shutdown. Waking from here would
|
|
@@ -305,6 +346,7 @@ export class WebServer extends EventEmitter {
|
|
|
305
346
|
qrAuthFailures = null;
|
|
306
347
|
hookSecretFailures = null;
|
|
307
348
|
userFailures = null;
|
|
349
|
+
userIpFailures = null;
|
|
308
350
|
pushStore = new PushSubscriptionStore();
|
|
309
351
|
/** ntfy / Slack / Discord / generic webhook for the push events; config in webhook.json (0600). */
|
|
310
352
|
webhookNotifier = new WebhookNotifier(() => readWebhookConfig(getDataDir()), webviewFetch);
|
|
@@ -314,12 +356,14 @@ export class WebServer extends EventEmitter {
|
|
|
314
356
|
windowTitle;
|
|
315
357
|
indexHtmlTemplate;
|
|
316
358
|
allowUnauthenticatedNetwork;
|
|
359
|
+
/** `--allow-unauthenticated-tunnel`; the tunnel guard reads it through the route context (#706). */
|
|
360
|
+
allowUnauthenticatedTunnel;
|
|
317
361
|
_pasteImageGcStop = null;
|
|
318
362
|
_eventLoopMonitor = null;
|
|
319
363
|
/** Opt-in hooks-only listener on the docker bridge gateway (CODEMAN_DOCKER_BRIDGE_HOOKS). */
|
|
320
364
|
_dockerBridgeServer = null;
|
|
321
365
|
teamWatcherHandlers = null;
|
|
322
|
-
constructor(port = 3000, https = false, testMode = false, host = '127.0.0.1', titleHostname, allowUnauthenticatedNetwork = false, basePath = '') {
|
|
366
|
+
constructor(port = 3000, https = false, testMode = false, host = '127.0.0.1', titleHostname, allowUnauthenticatedNetwork = false, basePath = '', allowUnauthenticatedTunnel = false) {
|
|
323
367
|
super();
|
|
324
368
|
this.setMaxListeners(0);
|
|
325
369
|
this.host = host;
|
|
@@ -330,6 +374,7 @@ export class WebServer extends EventEmitter {
|
|
|
330
374
|
this.testMode = testMode;
|
|
331
375
|
this.allowUnauthenticatedNetwork =
|
|
332
376
|
allowUnauthenticatedNetwork || isExplicitlyEnabled(process.env.CODEMAN_ALLOW_UNAUTHENTICATED_NETWORK);
|
|
377
|
+
this.allowUnauthenticatedTunnel = allowUnauthenticatedTunnel;
|
|
333
378
|
this.titleHostname = titleHostname || getHostname();
|
|
334
379
|
this.windowTitle = `codeman:${this.titleHostname}`;
|
|
335
380
|
this.indexHtmlTemplate = readFileSync(join(__dirname, 'public', 'index.html'), 'utf-8');
|
|
@@ -614,6 +659,8 @@ export class WebServer extends EventEmitter {
|
|
|
614
659
|
async registerSessionWithLayout(session, placement) {
|
|
615
660
|
return this.tabLayouts.sessionCreated(ownerLayoutKey(session.owner), session.id, placement, () => {
|
|
616
661
|
this.sessions.set(session.id, session);
|
|
662
|
+
// In the map now, so a case rename lists (and on request stops) it instead of refusing the move.
|
|
663
|
+
caseSessionSettled(session);
|
|
617
664
|
return () => {
|
|
618
665
|
if (this.sessions.get(session.id) === session)
|
|
619
666
|
this.sessions.delete(session.id);
|
|
@@ -685,6 +732,7 @@ export class WebServer extends EventEmitter {
|
|
|
685
732
|
scheduledRuns: this.scheduledRuns,
|
|
686
733
|
teamWatcher: this.teamWatcher,
|
|
687
734
|
tunnelManager: this.tunnelManager,
|
|
735
|
+
allowUnauthenticatedTunnel: this.allowUnauthenticatedTunnel,
|
|
688
736
|
pushStore: this.pushStore,
|
|
689
737
|
startScheduledRun: this.startScheduledRun.bind(this),
|
|
690
738
|
stopScheduledRun: this.stopScheduledRun.bind(this),
|
|
@@ -767,6 +815,7 @@ export class WebServer extends EventEmitter {
|
|
|
767
815
|
this.qrAuthFailures = authState.qrAuthFailures;
|
|
768
816
|
this.hookSecretFailures = authState.hookSecretFailures;
|
|
769
817
|
this.userFailures = authState.userFailures;
|
|
818
|
+
this.userIpFailures = authState.userIpFailures;
|
|
770
819
|
}
|
|
771
820
|
// WebSocket support (terminal I/O — low-latency bidirectional channel)
|
|
772
821
|
await this.app.register(fastifyWebsocket);
|
|
@@ -1030,9 +1079,21 @@ export class WebServer extends EventEmitter {
|
|
|
1030
1079
|
registerScheduledRoutes(this.app, ctx);
|
|
1031
1080
|
registerHookEventRoutes(this.app, ctx);
|
|
1032
1081
|
registerApprovalRoutes(this.app, ctx);
|
|
1082
|
+
registerInboxRoutes(this.app, ctx);
|
|
1033
1083
|
registerRebootRestoreRoutes(this.app, ctx);
|
|
1034
1084
|
registerReadMyMindRoutes(this.app, ctx);
|
|
1035
1085
|
registerGitStatusRoutes(this.app, ctx);
|
|
1086
|
+
// Git fetch on an interval: this is only the wake-up, the scheduler itself decides what is due. Off in
|
|
1087
|
+
// tests for the same reason as the polls below: a test drives `tick()` directly instead of waiting on
|
|
1088
|
+
// a timer the harness would have to keep alive. The setting is read FRESH inside `tick()`, so turning
|
|
1089
|
+
// it on takes effect on the next tick and turning it off actually stops the fetching.
|
|
1090
|
+
if (!this.testMode) {
|
|
1091
|
+
this.cleanup.setInterval(() => {
|
|
1092
|
+
this.gitFetchScheduler.tick().catch((err) => {
|
|
1093
|
+
console.error('[git fetch] interval tick failed:', getErrorMessage(err));
|
|
1094
|
+
});
|
|
1095
|
+
}, GIT_FETCH_TICK_INTERVAL_MS, { description: 'git fetch interval checker' });
|
|
1096
|
+
}
|
|
1036
1097
|
registerStatusTelemetryRoutes(this.app, ctx);
|
|
1037
1098
|
registerSystemRoutes(this.app, ctx);
|
|
1038
1099
|
registerCaseRoutes(this.app, ctx);
|
|
@@ -1040,6 +1101,7 @@ export class WebServer extends EventEmitter {
|
|
|
1040
1101
|
// The registry's lifetime is the server's: it drops per-session wake state on every
|
|
1041
1102
|
// cleanup path and resolves in-flight wakes on shutdown.
|
|
1042
1103
|
this.remoteWake = registerSessionRoutes(this.app, ctx);
|
|
1104
|
+
registerAgentSessionRoutes(this.app, ctx);
|
|
1043
1105
|
registerRespawnRoutes(this.app, ctx);
|
|
1044
1106
|
registerRalphRoutes(this.app, ctx);
|
|
1045
1107
|
registerPlanRoutes(this.app, ctx);
|
|
@@ -1263,6 +1325,9 @@ export class WebServer extends EventEmitter {
|
|
|
1263
1325
|
async _doCleanupSession(sessionId, killMux, reason, coordinateLayout = true) {
|
|
1264
1326
|
const session = this.sessions.get(sessionId);
|
|
1265
1327
|
this.keepWarmService.remove(sessionId);
|
|
1328
|
+
// A closed session takes its place in the fetch schedule with it: otherwise a detached-and-forgotten id
|
|
1329
|
+
// would still count as tracked, and its next run would land on a session that no longer exists.
|
|
1330
|
+
this.gitFetchScheduler.remove(sessionId);
|
|
1266
1331
|
const pinned = session?.pinned === true || this.store.getSession(sessionId)?.pinned === true;
|
|
1267
1332
|
if (coordinateLayout && session && killMux && !pinned) {
|
|
1268
1333
|
return this.tabLayouts.runSessionDeletion([{ id: sessionId, owner: session.owner }], () => this._doCleanupSession(sessionId, killMux, reason, false));
|
|
@@ -1438,6 +1503,12 @@ export class WebServer extends EventEmitter {
|
|
|
1438
1503
|
// The 'exit' here is NOT redundant with the PTY-exit listener: listeners are
|
|
1439
1504
|
// detached a few lines above, before `session.stop()`, so on a delete the
|
|
1440
1505
|
// session's own exit event never reaches the registry.
|
|
1506
|
+
// The agent inbox goes with a DELETED session only. killMux=false is shutdown or
|
|
1507
|
+
// detach: mail posted before that is still there when the session is re-attached
|
|
1508
|
+
// (while detached, the routes answer 404, so nothing new arrives). Before
|
|
1509
|
+
// cancelAll, so a reader released by it reads an empty inbox.
|
|
1510
|
+
if (killMux)
|
|
1511
|
+
agentInbox.drop(sessionId);
|
|
1441
1512
|
sessionWaits.notifySignal(sessionId, 'exit');
|
|
1442
1513
|
sessionWaits.cancelAll(sessionId);
|
|
1443
1514
|
approvalInbox.resolveForSession(sessionId, 'session_ended');
|
|
@@ -1630,6 +1701,13 @@ export class WebServer extends EventEmitter {
|
|
|
1630
1701
|
.filter((entry) => entry.capabilities.transcriptPageKeys === true)
|
|
1631
1702
|
.map((entry) => entry.id);
|
|
1632
1703
|
html = html.replace('</head>', () => `<script>window.__codemanTranscriptPageKeys=${JSON.stringify(pageKeyClis)};</script>\n</head>`);
|
|
1704
|
+
// Which run modes keep their PTY rows under a phone keyboard (inline renderers,
|
|
1705
|
+
// the `keyboardHold` capability; `_keyboardHoldEligible` in terminal-ui.js). Same
|
|
1706
|
+
// shape and reasoning as the page-key list above.
|
|
1707
|
+
const keyboardHoldClis = enabledClis()
|
|
1708
|
+
.filter((entry) => entry.capabilities.keyboardHold === 'inline')
|
|
1709
|
+
.map((entry) => entry.id);
|
|
1710
|
+
html = html.replace('</head>', () => `<script>window.__codemanKeyboardHoldModes=${JSON.stringify(keyboardHoldClis)};</script>\n</head>`);
|
|
1633
1711
|
if (!soloSessionId && process.env.CODEMAN_GESTURE === '1') {
|
|
1634
1712
|
html = html.replace('</head>', () => `<script>window.__codemanGestureAvailable=true;</script>\n</head>`);
|
|
1635
1713
|
if (settings.gestureControlEnabled === true) {
|
|
@@ -1913,6 +1991,12 @@ export class WebServer extends EventEmitter {
|
|
|
1913
1991
|
const settings = await this.readSettings();
|
|
1914
1992
|
return settings.agentSkillEnabled === true;
|
|
1915
1993
|
}
|
|
1994
|
+
// Whether pending agent-inbox mail is snapshotted to disk (synced
|
|
1995
|
+
// `agentInboxPersistEnabled` setting). Default OFF: an absent key writes nothing.
|
|
1996
|
+
async getAgentInboxPersistEnabled() {
|
|
1997
|
+
const settings = await this.readSettings();
|
|
1998
|
+
return settings.agentInboxPersistEnabled === true;
|
|
1999
|
+
}
|
|
1916
2000
|
// Whether a Claude session installs Codeman's hooks block into its workspace
|
|
1917
2001
|
// (synced `workspaceHooksEnabled` setting). Default ON — an absent key means a
|
|
1918
2002
|
// user who has never seen this setting, and OFF for them would mean no tab
|
|
@@ -2674,6 +2758,11 @@ export class WebServer extends EventEmitter {
|
|
|
2674
2758
|
// This prevents race conditions where clients connect before state is ready
|
|
2675
2759
|
// CRITICAL: Skip in test mode to prevent tests from picking up user sessions
|
|
2676
2760
|
if (!this.testMode) {
|
|
2761
|
+
// Pending agent mail first (opt-in snapshot), so it is in place before any
|
|
2762
|
+
// route can answer. Pruned against the restored sessions in finalizeRestoredState.
|
|
2763
|
+
const restoredMail = agentInboxPersistence.load(await this.getAgentInboxPersistEnabled());
|
|
2764
|
+
if (restoredMail > 0)
|
|
2765
|
+
console.log(`[AgentInbox] restored ${restoredMail} pending message(s)`);
|
|
2677
2766
|
const restored = await this.restoreMuxSessions();
|
|
2678
2767
|
await this.finalizeRestoredState(restored);
|
|
2679
2768
|
// Instance-scoped reaper: after restore, `docker rm -f` managed containers of
|
|
@@ -2891,17 +2980,13 @@ export class WebServer extends EventEmitter {
|
|
|
2891
2980
|
// Tunnel only starts when user clicks the toggle in the UI — never on boot.
|
|
2892
2981
|
// Reset persisted tunnelEnabled so the UI toggle reflects actual state.
|
|
2893
2982
|
if (await this.isTunnelEnabled()) {
|
|
2894
|
-
const settingsPath = dataPath('settings.json');
|
|
2895
2983
|
try {
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
settings.tunnelEnabled = false;
|
|
2899
|
-
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
2984
|
+
await mutateSettingsFile((settings) => ({ ...settings, tunnelEnabled: false }));
|
|
2985
|
+
console.log('Cloudflare tunnel setting reset (tunnel only starts on explicit UI toggle)');
|
|
2900
2986
|
}
|
|
2901
|
-
catch {
|
|
2902
|
-
|
|
2987
|
+
catch (err) {
|
|
2988
|
+
console.warn('Could not reset the Cloudflare tunnel setting:', getErrorMessage(err));
|
|
2903
2989
|
}
|
|
2904
|
-
console.log('Cloudflare tunnel setting reset (tunnel only starts on explicit UI toggle)');
|
|
2905
2990
|
}
|
|
2906
2991
|
// Start team watcher for agent team awareness (always on — lightweight polling)
|
|
2907
2992
|
this.teamWatcher.start();
|
|
@@ -3076,6 +3161,9 @@ export class WebServer extends EventEmitter {
|
|
|
3076
3161
|
if (saved.autoClearEnabled !== undefined || saved.autoClearThreshold !== undefined) {
|
|
3077
3162
|
session.setAutoClear(saved.autoClearEnabled ?? false, saved.autoClearThreshold);
|
|
3078
3163
|
}
|
|
3164
|
+
if (saved.gitFetchEnabled !== undefined || saved.gitFetchIntervalSeconds !== undefined) {
|
|
3165
|
+
session.setGitFetchSettings(saved.gitFetchEnabled, saved.gitFetchIntervalSeconds);
|
|
3166
|
+
}
|
|
3079
3167
|
if (saved.autoResumeEnabled) {
|
|
3080
3168
|
// The stamp is re-armed by default, because a Codeman restart leaves the
|
|
3081
3169
|
// limit footer un-reprinted and dropping it there would strand the pause.
|
|
@@ -3292,6 +3380,11 @@ export class WebServer extends EventEmitter {
|
|
|
3292
3380
|
// below, a future `expiresAt` re-arms the timer once the pane is attached.
|
|
3293
3381
|
lastRealPromptAt: savedState?.lastRealPromptAt,
|
|
3294
3382
|
keepWarmEnabled: savedState?.keepWarmEnabled,
|
|
3383
|
+
// The session's own fetch switch and interval, carried over rather than reset to the app default:
|
|
3384
|
+
// the choice is the user's and outlives the run that made it. The scheduler reads them fresh
|
|
3385
|
+
// on its next tick, so a restored session is back on its own schedule without a restart.
|
|
3386
|
+
gitFetchEnabled: savedState?.gitFetchEnabled,
|
|
3387
|
+
gitFetchIntervalSeconds: savedState?.gitFetchIntervalSeconds,
|
|
3295
3388
|
// Conversations this pane provably owned, oldest first. Its tail is
|
|
3296
3389
|
// the conversation the CLI was on when the server stopped, which is
|
|
3297
3390
|
// what a re-attach must point the viewer at instead of the launch id.
|
|
@@ -3466,6 +3559,7 @@ export class WebServer extends EventEmitter {
|
|
|
3466
3559
|
}
|
|
3467
3560
|
}
|
|
3468
3561
|
this.sessions.set(session.id, session);
|
|
3562
|
+
caseSessionSettled(session);
|
|
3469
3563
|
await this.setupSessionListeners(session);
|
|
3470
3564
|
// Auto-attach PTY to the surviving tmux session immediately.
|
|
3471
3565
|
// This ensures ALL sessions resume capturing output right away,
|
|
@@ -3538,6 +3632,21 @@ export class WebServer extends EventEmitter {
|
|
|
3538
3632
|
this.tabLayouts.markRestorationComplete();
|
|
3539
3633
|
await this.cleanupStaleSessions();
|
|
3540
3634
|
await this.tabLayouts.reconcileAfterRestoration();
|
|
3635
|
+
// Same gate as the tab layouts: only a restore that succeeded may decide which
|
|
3636
|
+
// inboxes are orphans. A failed one returns above and leaves every message alone.
|
|
3637
|
+
// Kept: live sessions plus every record state.json still holds (a session that
|
|
3638
|
+
// was not re-adopted this boot but is kept for recovery keeps its mail), plus the
|
|
3639
|
+
// sessions on the reboot-restore offer. `cleanupStaleSessions()` above has already
|
|
3640
|
+
// pruned their records, and a rebuild reuses the old id, so without them a restored
|
|
3641
|
+
// session would come back to an empty inbox. The 12 h TTL bounds what is never rebuilt.
|
|
3642
|
+
const keep = new Set([
|
|
3643
|
+
...this.sessions.keys(),
|
|
3644
|
+
...Object.keys(this.store.getSessions()),
|
|
3645
|
+
...rebootRestoreRegistry.list(() => true).map((entry) => entry.sessionId),
|
|
3646
|
+
]);
|
|
3647
|
+
const pruned = agentInbox.pruneExcept(keep);
|
|
3648
|
+
if (pruned > 0)
|
|
3649
|
+
console.log(`[AgentInbox] dropped ${pruned} inbox(es) of sessions that did not come back`);
|
|
3541
3650
|
}
|
|
3542
3651
|
/**
|
|
3543
3652
|
* Install Codeman's hooks into the workspaces of the sessions just recovered.
|
|
@@ -3692,6 +3801,8 @@ export class WebServer extends EventEmitter {
|
|
|
3692
3801
|
// port against the next start — the exact EADDRINUSE this feature already
|
|
3693
3802
|
// got wrong once.
|
|
3694
3803
|
void stopDeepSeekWeb();
|
|
3804
|
+
// The header's GPU / CPU clock sampler is a Windows child process under WSL, and its idle sweep a timer.
|
|
3805
|
+
stopHostSensors();
|
|
3695
3806
|
// Same teardown rule: the per-endpoint llama-swap log tails are otherwise closed
|
|
3696
3807
|
// only by the periodic idle sweep, whose interval is disposed just below.
|
|
3697
3808
|
closeAllLlamaSwapLogTails();
|
|
@@ -3705,8 +3816,14 @@ export class WebServer extends EventEmitter {
|
|
|
3705
3816
|
sessionWaits.cancelEverything();
|
|
3706
3817
|
approvalInbox.stop();
|
|
3707
3818
|
this.keepWarmService.stop();
|
|
3819
|
+
// Stops the fetch sweep from starting another run while the server is closing; a git process already
|
|
3820
|
+
// running is left to finish, which is what a fetch does to a repository nothing else is touching.
|
|
3821
|
+
this.gitFetchScheduler.stop();
|
|
3822
|
+
// A post within the debounce window before shutdown would otherwise not reach disk.
|
|
3823
|
+
// Flushed again after `app.close()` below, for a post that lands in between.
|
|
3824
|
+
agentInboxPersistence.flush();
|
|
3708
3825
|
// Same reason as `cancelEverything` above: an in-flight wake is awaited by a request,
|
|
3709
|
-
// and `app.close()` (the
|
|
3826
|
+
// and `app.close()` (at the end of this method) does not abort in-flight requests,
|
|
3710
3827
|
// so without this a restart during a wake waits out the readiness poll.
|
|
3711
3828
|
this.remoteWake?.stop();
|
|
3712
3829
|
this.lastRecordedTokens.clear();
|
|
@@ -3821,16 +3938,27 @@ export class WebServer extends EventEmitter {
|
|
|
3821
3938
|
this.userFailures.dispose();
|
|
3822
3939
|
this.userFailures = null;
|
|
3823
3940
|
}
|
|
3941
|
+
if (this.userIpFailures) {
|
|
3942
|
+
this.userIpFailures.dispose();
|
|
3943
|
+
this.userIpFailures = null;
|
|
3944
|
+
}
|
|
3824
3945
|
this.activePlanOrchestrators.clear();
|
|
3825
3946
|
this.cleaningUp.clear();
|
|
3826
3947
|
this.killingSessions.clear();
|
|
3827
3948
|
// Dispose push store (flush pending saves)
|
|
3828
3949
|
this.pushStore.dispose();
|
|
3829
|
-
|
|
3950
|
+
try {
|
|
3951
|
+
await this.app.close();
|
|
3952
|
+
}
|
|
3953
|
+
finally {
|
|
3954
|
+
// The routes answer until `app.close()` returns, so a post after the flush above
|
|
3955
|
+
// would otherwise sit in an unref'd debounce timer and never reach disk.
|
|
3956
|
+
agentInboxPersistence.flush();
|
|
3957
|
+
}
|
|
3830
3958
|
}
|
|
3831
3959
|
}
|
|
3832
|
-
export async function startWebServer(port = 3000, https = false, testMode = false, host = '127.0.0.1', titleHostname, allowUnauthenticatedNetwork = false, basePath = '') {
|
|
3833
|
-
const server = new WebServer(port, https, testMode, host, titleHostname, allowUnauthenticatedNetwork, basePath);
|
|
3960
|
+
export async function startWebServer(port = 3000, https = false, testMode = false, host = '127.0.0.1', titleHostname, allowUnauthenticatedNetwork = false, basePath = '', allowUnauthenticatedTunnel = false) {
|
|
3961
|
+
const server = new WebServer(port, https, testMode, host, titleHostname, allowUnauthenticatedNetwork, basePath, allowUnauthenticatedTunnel);
|
|
3834
3962
|
await server.start();
|
|
3835
3963
|
return server;
|
|
3836
3964
|
}
|