cli-jaw 2.2.16 → 2.2.17
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 +10 -1
- package/dist/bin/commands/_shared/dashboard-client.js +42 -0
- package/dist/bin/commands/_shared/dashboard-client.js.map +1 -0
- package/dist/bin/commands/_shared/search-format.js +40 -0
- package/dist/bin/commands/_shared/search-format.js.map +1 -0
- package/dist/bin/commands/chat-search.js +5 -3
- package/dist/bin/commands/chat-search.js.map +1 -1
- package/dist/bin/commands/dashboard-chat.js +14 -31
- package/dist/bin/commands/dashboard-chat.js.map +1 -1
- package/dist/bin/commands/dashboard-memory.js +12 -49
- package/dist/bin/commands/dashboard-memory.js.map +1 -1
- package/dist/bin/commands/doctor.js +33 -10
- package/dist/bin/commands/doctor.js.map +1 -1
- package/dist/bin/commands/init.js +13 -1
- package/dist/bin/commands/init.js.map +1 -1
- package/dist/bin/commands/memory.js +5 -1
- package/dist/bin/commands/memory.js.map +1 -1
- package/dist/bin/commands/slack.js +57 -3
- package/dist/bin/commands/slack.js.map +1 -1
- package/dist/bin/commands/tui/input-handler.js +1 -1
- package/dist/bin/commands/tui/input-handler.js.map +1 -1
- package/dist/bin/commands/tui/slash-command-runner.js +4 -5
- package/dist/bin/commands/tui/slash-command-runner.js.map +1 -1
- package/dist/bin/postinstall.js +16 -18
- package/dist/bin/postinstall.js.map +1 -1
- package/dist/lib/media-kind.js +28 -0
- package/dist/lib/media-kind.js.map +1 -0
- package/dist/lib/upload.js +27 -10
- package/dist/lib/upload.js.map +1 -1
- package/dist/server.js +35 -51
- package/dist/server.js.map +1 -1
- package/dist/src/agent/args.js +34 -0
- package/dist/src/agent/args.js.map +1 -1
- package/dist/src/agent/codex-app-client.js +1016 -135
- package/dist/src/agent/codex-app-client.js.map +1 -1
- package/dist/src/agent/codex-app-events.js +72 -1
- package/dist/src/agent/codex-app-events.js.map +1 -1
- package/dist/src/agent/codex-host-pool.js +617 -0
- package/dist/src/agent/codex-host-pool.js.map +1 -0
- package/dist/src/agent/jwc-runtime.js +12 -4
- package/dist/src/agent/jwc-runtime.js.map +1 -1
- package/dist/src/agent/kiro-auth.js +10 -4
- package/dist/src/agent/kiro-auth.js.map +1 -1
- package/dist/src/agent/kiro-runtime.js +45 -8
- package/dist/src/agent/kiro-runtime.js.map +1 -1
- package/dist/src/agent/lifecycle-handler.js +75 -52
- package/dist/src/agent/lifecycle-handler.js.map +1 -1
- package/dist/src/agent/memory-flush-controller.js +241 -33
- package/dist/src/agent/memory-flush-controller.js.map +1 -1
- package/dist/src/agent/prompt-context.js +4 -0
- package/dist/src/agent/prompt-context.js.map +1 -1
- package/dist/src/agent/runtime-pool.js +64 -34
- package/dist/src/agent/runtime-pool.js.map +1 -1
- package/dist/src/agent/session-persistence.js +71 -15
- package/dist/src/agent/session-persistence.js.map +1 -1
- package/dist/src/agent/spawn/queue.js +319 -162
- package/dist/src/agent/spawn/queue.js.map +1 -1
- package/dist/src/agent/spawn.js +581 -268
- package/dist/src/agent/spawn.js.map +1 -1
- package/dist/src/bgtask/types.js +1 -1
- package/dist/src/bgtask/types.js.map +1 -1
- package/dist/src/browser/adaptive-fetch/safety.js +25 -0
- package/dist/src/browser/adaptive-fetch/safety.js.map +1 -1
- package/dist/src/browser/connection.js +2 -8
- package/dist/src/browser/connection.js.map +1 -1
- package/dist/src/cli/capability-probe-worker.js +172 -0
- package/dist/src/cli/capability-probe-worker.js.map +1 -0
- package/dist/src/cli/capability-probe.js +83 -0
- package/dist/src/cli/capability-probe.js.map +1 -0
- package/dist/src/cli/claude-models.js +2 -2
- package/dist/src/cli/claude-models.js.map +1 -1
- package/dist/src/cli/cli-status-worker.js +296 -0
- package/dist/src/cli/cli-status-worker.js.map +1 -0
- package/dist/src/cli/cli-status.js +81 -0
- package/dist/src/cli/cli-status.js.map +1 -0
- package/dist/src/cli/command-context.js +17 -5
- package/dist/src/cli/command-context.js.map +1 -1
- package/dist/src/cli/compact.js +56 -19
- package/dist/src/cli/compact.js.map +1 -1
- package/dist/src/cli/handlers-runtime.js +6 -4
- package/dist/src/cli/handlers-runtime.js.map +1 -1
- package/dist/src/cli/handlers.js +7 -2
- package/dist/src/cli/handlers.js.map +1 -1
- package/dist/src/cli/opencodex-models.js +5 -32
- package/dist/src/cli/opencodex-models.js.map +1 -1
- package/dist/src/cli/opencodex-runtime.js +82 -0
- package/dist/src/cli/opencodex-runtime.js.map +1 -0
- package/dist/src/cli/readiness.js +35 -18
- package/dist/src/cli/readiness.js.map +1 -1
- package/dist/src/cli/registry-live.js +8 -2
- package/dist/src/cli/registry-live.js.map +1 -1
- package/dist/src/cli/registry.js +1 -1
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/core/browser-open-default.js +6 -4
- package/dist/src/core/browser-open-default.js.map +1 -1
- package/dist/src/core/browser-open.js +11 -15
- package/dist/src/core/browser-open.js.map +1 -1
- package/dist/src/core/bus.js +7 -1
- package/dist/src/core/bus.js.map +1 -1
- package/dist/src/core/chat-sessions.js +121 -12
- package/dist/src/core/chat-sessions.js.map +1 -1
- package/dist/src/core/cli-detect.js +148 -4
- package/dist/src/core/cli-detect.js.map +1 -1
- package/dist/src/core/codex-config.js +21 -0
- package/dist/src/core/codex-config.js.map +1 -1
- package/dist/src/core/compact.js +73 -21
- package/dist/src/core/compact.js.map +1 -1
- package/dist/src/core/config.js +449 -20
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/db.js +225 -0
- package/dist/src/core/db.js.map +1 -1
- package/dist/src/core/event-bus.js +49 -4
- package/dist/src/core/event-bus.js.map +1 -1
- package/dist/src/core/event-scope.js +100 -0
- package/dist/src/core/event-scope.js.map +1 -0
- package/dist/src/core/main-session.js +64 -21
- package/dist/src/core/main-session.js.map +1 -1
- package/dist/src/core/message-summary.js +12 -2
- package/dist/src/core/message-summary.js.map +1 -1
- package/dist/src/core/platform-kind.js +139 -0
- package/dist/src/core/platform-kind.js.map +1 -0
- package/dist/src/core/rate-limit.js +156 -0
- package/dist/src/core/rate-limit.js.map +1 -0
- package/dist/src/core/runtime-settings.js +165 -17
- package/dist/src/core/runtime-settings.js.map +1 -1
- package/dist/src/core/session-context.js +7 -0
- package/dist/src/core/session-context.js.map +1 -0
- package/dist/src/core/session-ops.js +53 -9
- package/dist/src/core/session-ops.js.map +1 -1
- package/dist/src/core/settings-merge.js +105 -3
- package/dist/src/core/settings-merge.js.map +1 -1
- package/dist/src/core/settings-watch.js +29 -5
- package/dist/src/core/settings-watch.js.map +1 -1
- package/dist/src/core/widget-watcher.js +15 -2
- package/dist/src/core/widget-watcher.js.map +1 -1
- package/dist/src/discord/bot.js +5 -2
- package/dist/src/discord/bot.js.map +1 -1
- package/dist/src/discord/commands.js +4 -4
- package/dist/src/discord/commands.js.map +1 -1
- package/dist/src/goal/heartbeat.js +1 -1
- package/dist/src/goal/heartbeat.js.map +1 -1
- package/dist/src/goal/runtime.js +1 -1
- package/dist/src/goal/runtime.js.map +1 -1
- package/dist/src/goal-run/controller.js +2 -2
- package/dist/src/goal-run/controller.js.map +1 -1
- package/dist/src/manager/internal-fetch.js +15 -0
- package/dist/src/manager/internal-fetch.js.map +1 -0
- package/dist/src/manager/logs.js +2 -1
- package/dist/src/manager/logs.js.map +1 -1
- package/dist/src/manager/memory/chat-federation.js +104 -11
- package/dist/src/manager/memory/chat-federation.js.map +1 -1
- package/dist/src/manager/memory/federation.js +100 -0
- package/dist/src/manager/memory/federation.js.map +1 -1
- package/dist/src/manager/metadata.js +4 -1
- package/dist/src/manager/metadata.js.map +1 -1
- package/dist/src/manager/notes/assets.js +1 -1
- package/dist/src/manager/notes/assets.js.map +1 -1
- package/dist/src/manager/notes/frontmatter.js +5 -49
- package/dist/src/manager/notes/frontmatter.js.map +1 -1
- package/dist/src/manager/notes/link-resolver.js +2 -2
- package/dist/src/manager/notes/link-resolver.js.map +1 -1
- package/dist/src/manager/notes/remote-assets.js +1 -1
- package/dist/src/manager/notes/remote-assets.js.map +1 -1
- package/dist/src/manager/notes/routes.js +2 -2
- package/dist/src/manager/notes/routes.js.map +1 -1
- package/dist/src/manager/notes/store.js +2 -2
- package/dist/src/manager/notes/store.js.map +1 -1
- package/dist/src/manager/notes/trash.js +1 -1
- package/dist/src/manager/notes/trash.js.map +1 -1
- package/dist/src/manager/notes/vault-index.js +2 -2
- package/dist/src/manager/notes/vault-index.js.map +1 -1
- package/dist/src/manager/notes/wiki-links.js +1 -1
- package/dist/src/manager/notes/wiki-links.js.map +1 -1
- package/dist/src/manager/notes/wiki-routes.js +84 -0
- package/dist/src/manager/notes/wiki-routes.js.map +1 -0
- package/dist/src/manager/proxy.js +1 -0
- package/dist/src/manager/proxy.js.map +1 -1
- package/dist/src/manager/routes/dashboard-memory.js +24 -1
- package/dist/src/manager/routes/dashboard-memory.js.map +1 -1
- package/dist/src/manager/routes/runtime-monitor.js +1 -1
- package/dist/src/manager/routes/runtime-monitor.js.map +1 -1
- package/dist/src/manager/scan.js +5 -3
- package/dist/src/manager/scan.js.map +1 -1
- package/dist/src/manager/server.js +20 -6
- package/dist/src/manager/server.js.map +1 -1
- package/dist/src/manager/telegram-hub/hub-bot.js +4 -3
- package/dist/src/manager/telegram-hub/hub-bot.js.map +1 -1
- package/dist/src/manager/worker-events.js +2 -1
- package/dist/src/manager/worker-events.js.map +1 -1
- package/dist/src/memory/heartbeat.js +6 -5
- package/dist/src/memory/heartbeat.js.map +1 -1
- package/dist/src/memory/indexing.js +162 -45
- package/dist/src/memory/indexing.js.map +1 -1
- package/dist/src/messaging/channel-validate.js +14 -1
- package/dist/src/messaging/channel-validate.js.map +1 -1
- package/dist/src/messaging/redact.js +2 -1
- package/dist/src/messaging/redact.js.map +1 -1
- package/dist/src/messaging/session-key.js +21 -2
- package/dist/src/messaging/session-key.js.map +1 -1
- package/dist/src/notes/constants.js.map +1 -0
- package/dist/src/notes/frontmatter.js +59 -0
- package/dist/src/notes/frontmatter.js.map +1 -0
- package/dist/src/notes/path-guards.js.map +1 -0
- package/dist/src/notes/search.js.map +1 -0
- package/dist/src/orchestrator/attestation.js +1 -1
- package/dist/src/orchestrator/attestation.js.map +1 -1
- package/dist/src/orchestrator/gateway.js +135 -31
- package/dist/src/orchestrator/gateway.js.map +1 -1
- package/dist/src/orchestrator/pipeline.js +53 -21
- package/dist/src/orchestrator/pipeline.js.map +1 -1
- package/dist/src/orchestrator/scope.js +36 -2
- package/dist/src/orchestrator/scope.js.map +1 -1
- package/dist/src/orchestrator/session-lanes.js +87 -0
- package/dist/src/orchestrator/session-lanes.js.map +1 -0
- package/dist/src/orchestrator/session-work.js +25 -0
- package/dist/src/orchestrator/session-work.js.map +1 -0
- package/dist/src/orchestrator/state-machine.js +1 -5
- package/dist/src/orchestrator/state-machine.js.map +1 -1
- package/dist/src/orchestrator/worker-registry.js +20 -10
- package/dist/src/orchestrator/worker-registry.js.map +1 -1
- package/dist/src/prompt/builder.js +40 -2
- package/dist/src/prompt/builder.js.map +1 -1
- package/dist/src/prompt/templates/a1-system.md +8 -1
- package/dist/src/routes/agent-control.js +44 -8
- package/dist/src/routes/agent-control.js.map +1 -1
- package/dist/src/routes/chat-sessions.js +34 -6
- package/dist/src/routes/chat-sessions.js.map +1 -1
- package/dist/src/routes/command.js +63 -8
- package/dist/src/routes/command.js.map +1 -1
- package/dist/src/routes/events.js +11 -2
- package/dist/src/routes/events.js.map +1 -1
- package/dist/src/routes/link-preview.js +1 -27
- package/dist/src/routes/link-preview.js.map +1 -1
- package/dist/src/routes/messages.js +6 -5
- package/dist/src/routes/messages.js.map +1 -1
- package/dist/src/routes/messaging.js +45 -1
- package/dist/src/routes/messaging.js.map +1 -1
- package/dist/src/routes/orchestrate.js +53 -33
- package/dist/src/routes/orchestrate.js.map +1 -1
- package/dist/src/routes/search.js +84 -0
- package/dist/src/routes/search.js.map +1 -0
- package/dist/src/routes/session-request.js +29 -0
- package/dist/src/routes/session-request.js.map +1 -0
- package/dist/src/routes/settings.js +110 -3
- package/dist/src/routes/settings.js.map +1 -1
- package/dist/src/routes/static.js +30 -8
- package/dist/src/routes/static.js.map +1 -1
- package/dist/src/routes/system.js +1 -1
- package/dist/src/routes/system.js.map +1 -1
- package/dist/src/routes/wiki.js +122 -0
- package/dist/src/routes/wiki.js.map +1 -0
- package/dist/src/search/contract.js +2 -0
- package/dist/src/search/contract.js.map +1 -0
- package/dist/src/search/coordinator.js +153 -0
- package/dist/src/search/coordinator.js.map +1 -0
- package/dist/src/search/provider.js +40 -0
- package/dist/src/search/provider.js.map +1 -0
- package/dist/src/search/providers/chat.js +115 -0
- package/dist/src/search/providers/chat.js.map +1 -0
- package/dist/src/search/providers/memory.js +53 -0
- package/dist/src/search/providers/memory.js.map +1 -0
- package/dist/src/search/providers/wiki.js +80 -0
- package/dist/src/search/providers/wiki.js.map +1 -0
- package/dist/src/slack/api.js +10 -1
- package/dist/src/slack/api.js.map +1 -1
- package/dist/src/slack/attachment-recovery.js +42 -0
- package/dist/src/slack/attachment-recovery.js.map +1 -0
- package/dist/src/slack/bot.js +120 -41
- package/dist/src/slack/bot.js.map +1 -1
- package/dist/src/slack/commands.js +24 -8
- package/dist/src/slack/commands.js.map +1 -1
- package/dist/src/slack/events.js +12 -1
- package/dist/src/slack/events.js.map +1 -1
- package/dist/src/slack/history.js +108 -0
- package/dist/src/slack/history.js.map +1 -0
- package/dist/src/slack/inbound-file.js +242 -0
- package/dist/src/slack/inbound-file.js.map +1 -0
- package/dist/src/slack/inbound-url.js +39 -0
- package/dist/src/slack/inbound-url.js.map +1 -0
- package/dist/src/slack/ingress.js +140 -0
- package/dist/src/slack/ingress.js.map +1 -0
- package/dist/src/slack/manifest.js +3 -0
- package/dist/src/slack/manifest.js.map +1 -1
- package/dist/src/slack/socket.js +1 -1
- package/dist/src/slack/socket.js.map +1 -1
- package/dist/src/slack/thread-tracker.js +86 -0
- package/dist/src/slack/thread-tracker.js.map +1 -0
- package/dist/src/telegram/bot.js +21 -11
- package/dist/src/telegram/bot.js.map +1 -1
- package/dist/src/wiki/config.js +193 -0
- package/dist/src/wiki/config.js.map +1 -0
- package/dist/src/wiki/entities.js +61 -0
- package/dist/src/wiki/entities.js.map +1 -0
- package/dist/src/wiki/ontology.js +72 -0
- package/dist/src/wiki/ontology.js.map +1 -0
- package/dist/src/wiki/prompt.js +172 -0
- package/dist/src/wiki/prompt.js.map +1 -0
- package/dist/src/wiki/safe-traversal.js +198 -0
- package/dist/src/wiki/safe-traversal.js.map +1 -0
- package/dist/src/wiki/scaffold.js +77 -0
- package/dist/src/wiki/scaffold.js.map +1 -0
- package/package.json +1 -1
- package/public/css/session-hub.css +266 -0
- package/public/dist/assets/AdvancedExport-DYGcCAUq.js +1 -0
- package/public/dist/assets/Agent-CNNQ7KkJ.js +1 -0
- package/public/dist/assets/{DesignPanel-BGMPhZSx.js → DesignPanel-DcL369nB.js} +1 -1
- package/public/dist/assets/{DocPanel-Dz-J_l5M.js → DocPanel-K8A2pm_1.js} +1 -1
- package/public/dist/assets/{FolderPanel-DbPhzzvi.js → FolderPanel-CV52EzwG.js} +1 -1
- package/public/dist/assets/{MilkdownWysiwygEditor-Em7iC6y9.js → MilkdownWysiwygEditor-BKOCDI4Z.js} +1 -1
- package/public/dist/assets/api-B25zNNFJ.js +1 -0
- package/public/dist/assets/{app-DX4e6isX.css → app-DjgGeXhJ.css} +1 -1
- package/public/dist/assets/app-Dsgp4xpU.js +55 -0
- package/public/dist/assets/bgtask-badge-C6h5C-o4.js +1 -0
- package/public/dist/assets/{bgtask-badge-qMkKOZx0.js → bgtask-badge-CpavV0Jc.js} +4 -4
- package/public/dist/assets/{employees-BnobWM_2.js → employees-BJyEgim7.js} +4 -4
- package/public/dist/assets/idb-cache-B5PX63p7.js +1 -0
- package/public/dist/assets/{idb-cache-BzzftUET.js → idb-cache-lOntwU3S.js} +1 -1
- package/public/dist/assets/{iframe-renderer-C5vRbbl9.js → iframe-renderer-B8k3AvTv.js} +12 -12
- package/public/dist/assets/iframe-renderer-BO_GgCTR.js +1 -0
- package/public/dist/assets/manager-LkGs6qEJ.css +1 -0
- package/public/dist/assets/manager-kXYQyMhR.js +13 -0
- package/public/dist/assets/{memory-DF4kPwwC.js → memory-D2RbBVO-.js} +11 -11
- package/public/dist/assets/memory-amsvg4Ey.js +1 -0
- package/public/dist/assets/message-history-BGHZxvgV.js +1 -0
- package/public/dist/assets/message-history-Bw2E_b8L.js +1 -0
- package/public/dist/assets/pi-settings-5HVg1sXJ.js +1 -0
- package/public/dist/assets/render-BkGcpH7z.js +157 -0
- package/public/dist/assets/settings-B1FPORO2.js +56 -0
- package/public/dist/assets/settings-CMN-zN4Q.js +1 -0
- package/public/dist/assets/settings-core-B_OjGYVN.js +1 -0
- package/public/dist/assets/settings-core-CxRwqx86.js +144 -0
- package/public/dist/assets/sidebar-DW78DANx.js +49 -0
- package/public/dist/assets/skills-Dz-9Yrxr.js +1 -0
- package/public/dist/assets/{skills-IGquen_j.js → skills-lWi0ZFiV.js} +6 -6
- package/public/dist/assets/{slash-commands-ZRDOL99E.js → slash-commands-DYOI6nKj.js} +1 -1
- package/public/dist/assets/slash-commands-xJFCdTTM.js +1 -0
- package/public/dist/assets/{trace-drawer-D8To8fYt.js → trace-drawer-DBX9xzmt.js} +1 -1
- package/public/dist/assets/{ui-Hx_mNoDf.js → ui-Bx7eqnXt.js} +1 -1
- package/public/dist/assets/ui-JOcrYeG-.js +1 -0
- package/public/dist/assets/{wiki-link-suggestions-DZQc78gj.js → wiki-link-suggestions-Dp6kBQVu.js} +1 -1
- package/public/dist/index.html +4 -4
- package/public/dist/manager/index.html +2 -2
- package/public/index.html +3 -2
- package/public/js/event-channel.ts +25 -0
- package/public/js/features/channel-onboarding-flow.ts +16 -1
- package/public/js/features/channel-onboarding.ts +20 -2
- package/public/js/features/chat-messages.ts +3 -1
- package/public/js/features/chat-search.ts +2 -1
- package/public/js/features/chat.ts +56 -18
- package/public/js/features/elicitation.ts +15 -0
- package/public/js/features/idb-cache.ts +34 -0
- package/public/js/features/message-history.ts +2 -1
- package/public/js/features/session-hub.ts +334 -0
- package/public/js/features/settings-cli-status-render.ts +1 -1
- package/public/js/features/settings-cli-status.ts +25 -11
- package/public/js/features/settings-core.ts +72 -3
- package/public/js/features/settings-types.ts +32 -0
- package/public/js/features/ui-status.ts +2 -1
- package/public/js/main.ts +20 -0
- package/public/js/render/compose-block.ts +7 -0
- package/public/js/ws.ts +22 -2
- package/public/locales/en.json +46 -4
- package/public/locales/ja.json +46 -4
- package/public/locales/ko.json +46 -4
- package/public/locales/zh.json +46 -4
- package/public/manager/src/App.tsx +1 -1
- package/public/manager/src/InstancePreview.tsx +5 -1
- package/public/manager/src/api.ts +2 -1
- package/public/manager/src/components/InstanceGroups.tsx +10 -0
- package/public/manager/src/components/InstanceListContent.tsx +24 -1
- package/public/manager/src/components/InstanceRow.tsx +33 -3
- package/public/manager/src/components/InstanceSessionList.tsx +132 -0
- package/public/manager/src/hooks/useActiveSessionDisclosure.ts +45 -0
- package/public/manager/src/lib/resilient-fetch.ts +93 -0
- package/public/manager/src/lib/session-store.ts +216 -0
- package/public/manager/src/manager-components.css +97 -0
- package/public/manager/src/settings/pages/AdvancedExport.tsx +12 -2
- package/public/manager/src/settings/pages/Agent.tsx +113 -1
- package/public/manager/src/settings/pages/components/agent/agent-meta.ts +1 -1
- package/scripts/burst-scenario.mjs +72 -0
- package/scripts/check-redaction-sinks.mjs +1 -0
- package/scripts/check-strict-baseline.mjs +1 -1
- package/dist/src/manager/notes/constants.js.map +0 -1
- package/dist/src/manager/notes/path-guards.js.map +0 -1
- package/dist/src/manager/notes/search.js.map +0 -1
- package/public/dist/assets/AdvancedExport-DsDpqXoH.js +0 -1
- package/public/dist/assets/Agent-BjbZVZ9p.js +0 -1
- package/public/dist/assets/api-C9dOxby7.js +0 -1
- package/public/dist/assets/app-BzD_ZLvt.js +0 -55
- package/public/dist/assets/bgtask-badge-Dqbp-Y4e.js +0 -1
- package/public/dist/assets/idb-cache-ZH6lOebk.js +0 -1
- package/public/dist/assets/iframe-renderer-Df4KIVyx.js +0 -1
- package/public/dist/assets/manager-C4eNDNFt.css +0 -1
- package/public/dist/assets/manager-DaN201mN.js +0 -13
- package/public/dist/assets/memory-D-bULTHl.js +0 -1
- package/public/dist/assets/message-history-C4WOisGx.js +0 -1
- package/public/dist/assets/message-history-ZBoza6ew.js +0 -1
- package/public/dist/assets/pi-settings-CBUGDAuT.js +0 -1
- package/public/dist/assets/render-DYX6GRQ0.js +0 -122
- package/public/dist/assets/settings-DbJpGoaX.js +0 -55
- package/public/dist/assets/settings-SreihUje.js +0 -1
- package/public/dist/assets/settings-core-B1Y5Nb4Z.js +0 -1
- package/public/dist/assets/settings-core-DobZWIZ7.js +0 -140
- package/public/dist/assets/sidebar-Cp22g0Gv.js +0 -49
- package/public/dist/assets/skills-DwPIP08e.js +0 -1
- package/public/dist/assets/slash-commands-BBVfwcnW.js +0 -1
- package/public/dist/assets/ui-CAicpUZc.js +0 -1
- /package/dist/src/{manager/notes → notes}/constants.js +0 -0
- /package/dist/src/{manager/notes → notes}/path-guards.js +0 -0
- /package/dist/src/{manager/notes → notes}/search.js +0 -0
- /package/public/dist/assets/{pi-settings-Dh5lgb87.js → pi-settings-DEuKgvIj.js} +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// ─── Scoped SSE delivery rule (072 §1.3a) ────────────
|
|
2
|
+
// A browser tab bound to one chat session connects with `?scope=`, and the route
|
|
3
|
+
// filters on strict equality against `data.scope`. That filter alone is not enough,
|
|
4
|
+
// because `broadcast()` stamps the ambient session scope onto EVERY event published
|
|
5
|
+
// inside a session's async context (core/bus.ts). Instance-wide events published
|
|
6
|
+
// during an agent turn — a heartbeat, a settings reload — therefore carry that
|
|
7
|
+
// session's scope and would vanish from every other tab.
|
|
8
|
+
//
|
|
9
|
+
// So delivery asks two questions in order: is this event instance-wide (deliver to
|
|
10
|
+
// everyone regardless of the scope it happens to carry), and otherwise does its scope
|
|
11
|
+
// match the connection. The judgement is "does one session own this event", not "is it
|
|
12
|
+
// topology". An event wrongly marked instance-wide is just noise in a tab; an event
|
|
13
|
+
// wrongly marked session-owned disappears.
|
|
14
|
+
import { DELIVERY_KEY_GLOBAL, DELIVERY_KEY_NONE, isPublicSseTopic } from './event-bus.js';
|
|
15
|
+
// Instance-wide events. Every tab needs these regardless of which session's async
|
|
16
|
+
// context happened to publish them.
|
|
17
|
+
export const INSTANCE_WIDE_EVENTS = new Set([
|
|
18
|
+
// The session list itself — a tab must see sessions appear and disappear.
|
|
19
|
+
'session_created',
|
|
20
|
+
'session_list',
|
|
21
|
+
// Instance configuration and inventory.
|
|
22
|
+
'settings_change',
|
|
23
|
+
'agent_added',
|
|
24
|
+
'agent_updated',
|
|
25
|
+
'agent_deleted',
|
|
26
|
+
// Instance-wide subsystems with no session dimension.
|
|
27
|
+
'memory_status',
|
|
28
|
+
'heartbeat_pending',
|
|
29
|
+
'bgtask_update',
|
|
30
|
+
'alert_escalation',
|
|
31
|
+
'schedule_wakeup',
|
|
32
|
+
'schedule_wakeup_failed',
|
|
33
|
+
// A global switch is published outside any session context, so it carries no scope
|
|
34
|
+
// and a strict filter would drop it from every scoped tab — leaving each of them
|
|
35
|
+
// showing a stale idea of which session is active.
|
|
36
|
+
'session_switched',
|
|
37
|
+
]);
|
|
38
|
+
// `system_notice` is a mixed bag: some notices describe one session's turn and some
|
|
39
|
+
// describe the instance. Classifying the whole type either way is wrong, so the code
|
|
40
|
+
// decides. An unrecognised code is treated as instance-wide, which is the safe error:
|
|
41
|
+
// an extra notice is noise, a missing one is invisible.
|
|
42
|
+
//
|
|
43
|
+
// The code is not sufficient on its own. `auto_compact_refresh` is published both by a
|
|
44
|
+
// session's own turn AND by the instance-wide reset in session-ops, and only the first
|
|
45
|
+
// carries a scope. A notice with no scope has no session to belong to, so it is
|
|
46
|
+
// delivered everywhere rather than nowhere.
|
|
47
|
+
const SESSION_OWNED_NOTICE_CODES = new Set([
|
|
48
|
+
'compact_suggest',
|
|
49
|
+
'auto_compact_refresh',
|
|
50
|
+
]);
|
|
51
|
+
function isSessionOwnedNotice(data) {
|
|
52
|
+
const code = data["code"];
|
|
53
|
+
return typeof code === 'string'
|
|
54
|
+
&& SESSION_OWNED_NOTICE_CODES.has(code)
|
|
55
|
+
&& typeof data["scope"] === 'string';
|
|
56
|
+
}
|
|
57
|
+
// Goal state is a single instance-wide file with no session field (goal/store.ts).
|
|
58
|
+
// A goal finished in one tab must clear the cockpit in every tab, so goal events are
|
|
59
|
+
// delivered everywhere even though a turn in one session produced them.
|
|
60
|
+
export function isInstanceWideEvent(event) {
|
|
61
|
+
return INSTANCE_WIDE_EVENTS.has(event) || event.startsWith('goal_');
|
|
62
|
+
}
|
|
63
|
+
export function shouldDeliverToScope(entry, scopeFilter) {
|
|
64
|
+
// No filter means "everything", which is what manager and worker connections rely on.
|
|
65
|
+
if (!scopeFilter)
|
|
66
|
+
return true;
|
|
67
|
+
if (entry.event === 'system_notice') {
|
|
68
|
+
return isSessionOwnedNotice(entry.data)
|
|
69
|
+
? entry.data["scope"] === scopeFilter
|
|
70
|
+
: true;
|
|
71
|
+
}
|
|
72
|
+
if (isInstanceWideEvent(entry.event))
|
|
73
|
+
return true;
|
|
74
|
+
return entry.data["scope"] === scopeFilter;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The delivery class of an event, for the replay-gap watermarks in the bus.
|
|
78
|
+
*
|
|
79
|
+
* It answers the same questions as delivery, in the same order, because a gap check that
|
|
80
|
+
* classified events differently from the filter would report losses that never happened
|
|
81
|
+
* and miss ones that did. The route drops non-public topics before it looks at scope, so
|
|
82
|
+
* that comes first here too: an event no subscriber can see costs nobody anything when it
|
|
83
|
+
* ages out.
|
|
84
|
+
*/
|
|
85
|
+
export function deliveryKeyForEntry(entry) {
|
|
86
|
+
if (!isPublicSseTopic(entry.topic))
|
|
87
|
+
return DELIVERY_KEY_NONE;
|
|
88
|
+
if (entry.event === 'system_notice') {
|
|
89
|
+
// A compact suggestion belongs to the session that raised it; every other notice
|
|
90
|
+
// is for the whole instance.
|
|
91
|
+
return isSessionOwnedNotice(entry.data)
|
|
92
|
+
? String(entry.data["scope"])
|
|
93
|
+
: DELIVERY_KEY_GLOBAL;
|
|
94
|
+
}
|
|
95
|
+
if (isInstanceWideEvent(entry.event))
|
|
96
|
+
return DELIVERY_KEY_GLOBAL;
|
|
97
|
+
const scope = entry.data["scope"];
|
|
98
|
+
return typeof scope === 'string' && scope ? scope : DELIVERY_KEY_GLOBAL;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=event-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-scope.js","sourceRoot":"","sources":["../../../src/core/event-scope.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,8 @@ import { broadcast } from './bus.js';
|
|
|
2
2
|
import { DEFAULT_CLI } from '../cli/registry.js';
|
|
3
3
|
import { settings } from './config.js';
|
|
4
4
|
import { db, clearMessages, clearMessagesScoped, getSession, updateSession } from './db.js';
|
|
5
|
-
import { getActiveChatSession } from './chat-sessions.js';
|
|
5
|
+
import { getActiveChatSession, getChatSessionRemoteKey } from './chat-sessions.js';
|
|
6
|
+
import { scopeForChatSession } from '../orchestrator/scope.js';
|
|
6
7
|
export function getCliModelAndEffort(cli, currentSettings = settings) {
|
|
7
8
|
const ao = currentSettings["activeOverrides"]?.[cli] || {};
|
|
8
9
|
const pc = currentSettings["perCli"]?.[cli] || {};
|
|
@@ -42,9 +43,26 @@ export function buildClearedSessionRow(currentSettings = settings, session = nul
|
|
|
42
43
|
effort,
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The `session` row is a single row for the whole instance, and the instance web owns
|
|
48
|
+
* what it holds (074). Callers that speak for the instance — a settings change, a CLI
|
|
49
|
+
* switch — write it unconditionally. Callers acting for one session pass false when
|
|
50
|
+
* that session is not the default one, so clearing a Slack thread cannot rewrite the
|
|
51
|
+
* CLI and model every other session reads.
|
|
52
|
+
*
|
|
53
|
+
* The decision is the caller's rather than this function's: it is also on the path of
|
|
54
|
+
* instance-wide writes, and refusing there would stop a second browser tab from
|
|
55
|
+
* updating the mirror after a legitimate change.
|
|
56
|
+
*/
|
|
57
|
+
export function writeMainSessionRow(row, ownsSingletonRow = true) {
|
|
58
|
+
if (!ownsSingletonRow)
|
|
59
|
+
return;
|
|
46
60
|
updateSession.run(row.cli, row.sessionId, row.model, row.permissions, row.workingDir, row.effort);
|
|
47
61
|
}
|
|
62
|
+
/** True when the caller's session is the one that owns the shared row. */
|
|
63
|
+
function currentSessionOwnsSingletonRow() {
|
|
64
|
+
return getActiveChatSession() === 'default';
|
|
65
|
+
}
|
|
48
66
|
export function syncMainSessionToSettings(prevCli = null) {
|
|
49
67
|
const session = getSession();
|
|
50
68
|
const row = buildSelectedSessionRow(settings, session, prevCli);
|
|
@@ -55,20 +73,29 @@ export function syncMainSessionToSettings(prevCli = null) {
|
|
|
55
73
|
return row;
|
|
56
74
|
}
|
|
57
75
|
// Atomic: delete messages + update session in one transaction
|
|
58
|
-
const clearMainTx = db.transaction((row) => {
|
|
76
|
+
const clearMainTx = db.transaction((row, ownsSingletonRow) => {
|
|
59
77
|
if (row.workingDir && row.workingDir !== '~') {
|
|
60
78
|
clearMessagesScoped.run(row.workingDir, getActiveChatSession());
|
|
61
79
|
}
|
|
62
80
|
else {
|
|
63
81
|
clearMessages.run(getActiveChatSession());
|
|
64
82
|
}
|
|
65
|
-
writeMainSessionRow(row);
|
|
83
|
+
writeMainSessionRow(row, ownsSingletonRow);
|
|
66
84
|
});
|
|
67
85
|
export function clearMainSessionState() {
|
|
68
86
|
const session = getSession();
|
|
69
87
|
const row = buildClearedSessionRow(settings, session);
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
// History is this session's to delete; the shared runtime selection is not.
|
|
89
|
+
const ownsSingletonRow = currentSessionOwnsSingletonRow();
|
|
90
|
+
// Capture the session BEFORE the transaction so the notice names exactly the history
|
|
91
|
+
// that was deleted. Without a scope on it, a scoped tab drops the event and keeps
|
|
92
|
+
// showing messages that no longer exist — including the tab whose history this was.
|
|
93
|
+
const clearedSessionId = getActiveChatSession();
|
|
94
|
+
clearMainTx(row, ownsSingletonRow);
|
|
95
|
+
broadcast('clear', {
|
|
96
|
+
scope: scopeForChatSession(clearedSessionId, getChatSessionRemoteKey(clearedSessionId) ?? undefined),
|
|
97
|
+
sessionId: clearedSessionId,
|
|
98
|
+
});
|
|
72
99
|
return row;
|
|
73
100
|
}
|
|
74
101
|
/** Reset boss session ID (prevents stale --resume) but preserves message history. */
|
|
@@ -82,8 +109,14 @@ export function clearBossSessionOnly() {
|
|
|
82
109
|
export function resetSessionPreservingHistory() {
|
|
83
110
|
const session = getSession();
|
|
84
111
|
const row = buildClearedSessionRow(settings, session);
|
|
85
|
-
writeMainSessionRow(row);
|
|
86
|
-
|
|
112
|
+
writeMainSessionRow(row, currentSessionOwnsSingletonRow());
|
|
113
|
+
const resetSessionId = getActiveChatSession();
|
|
114
|
+
broadcast('session_reset', {
|
|
115
|
+
cli: row.cli,
|
|
116
|
+
model: row.model,
|
|
117
|
+
scope: scopeForChatSession(resetSessionId, getChatSessionRemoteKey(resetSessionId) ?? undefined),
|
|
118
|
+
sessionId: resetSessionId,
|
|
119
|
+
});
|
|
87
120
|
return row;
|
|
88
121
|
}
|
|
89
122
|
// ─── Pending bootstrap prompt (1-shot consumption, DB-backed) ───
|
|
@@ -96,10 +129,18 @@ import { getMemory, upsertMemory, deleteMemory } from './db.js';
|
|
|
96
129
|
import { log } from './logger.js';
|
|
97
130
|
const BOOTSTRAP_KEY = '__bootstrap_prompt';
|
|
98
131
|
const BOOTSTRAP_SOURCE = '__system_bootstrap';
|
|
99
|
-
|
|
132
|
+
// A compact summary belongs to the conversation that produced it. While one main
|
|
133
|
+
// run existed at a time a single row was enough; with several scopes in flight the
|
|
134
|
+
// first spawn to look would take someone else's handoff. Scoped rows get their own
|
|
135
|
+
// key and the bare key stays the default scope's, which is what existing rows are.
|
|
136
|
+
function bootstrapKeyFor(scopeKey) {
|
|
137
|
+
return !scopeKey || scopeKey === 'default' ? BOOTSTRAP_KEY : `${BOOTSTRAP_KEY}:${scopeKey}`;
|
|
138
|
+
}
|
|
139
|
+
function readBootstrapRow(scopeKey) {
|
|
100
140
|
try {
|
|
141
|
+
const key = bootstrapKeyFor(scopeKey);
|
|
101
142
|
const rows = getMemory.all();
|
|
102
|
-
const row = rows.find(r => r.key ===
|
|
143
|
+
const row = rows.find(r => r.key === key && r.source === BOOTSTRAP_SOURCE);
|
|
103
144
|
return row?.value && row.value.trim() ? row.value : null;
|
|
104
145
|
}
|
|
105
146
|
catch (e) {
|
|
@@ -107,13 +148,14 @@ function readBootstrapRow() {
|
|
|
107
148
|
return null;
|
|
108
149
|
}
|
|
109
150
|
}
|
|
110
|
-
export function setPendingBootstrapPrompt(text) {
|
|
151
|
+
export function setPendingBootstrapPrompt(text, scopeKey) {
|
|
111
152
|
try {
|
|
153
|
+
const key = bootstrapKeyFor(scopeKey);
|
|
112
154
|
if (text && text.trim()) {
|
|
113
|
-
upsertMemory.run(
|
|
155
|
+
upsertMemory.run(key, text, BOOTSTRAP_SOURCE);
|
|
114
156
|
}
|
|
115
157
|
else {
|
|
116
|
-
deleteMemory.run(
|
|
158
|
+
deleteMemory.run(key);
|
|
117
159
|
}
|
|
118
160
|
}
|
|
119
161
|
catch (e) {
|
|
@@ -122,19 +164,20 @@ export function setPendingBootstrapPrompt(text) {
|
|
|
122
164
|
}
|
|
123
165
|
// Strict variant: throws on DB failure. Use inside transactions where the caller
|
|
124
166
|
// must know about persistence loss so the surrounding tx can roll back.
|
|
125
|
-
export function setPendingBootstrapPromptStrict(text) {
|
|
167
|
+
export function setPendingBootstrapPromptStrict(text, scopeKey) {
|
|
168
|
+
const key = bootstrapKeyFor(scopeKey);
|
|
126
169
|
if (text && text.trim()) {
|
|
127
|
-
upsertMemory.run(
|
|
170
|
+
upsertMemory.run(key, text, BOOTSTRAP_SOURCE);
|
|
128
171
|
}
|
|
129
172
|
else {
|
|
130
|
-
deleteMemory.run(
|
|
173
|
+
deleteMemory.run(key);
|
|
131
174
|
}
|
|
132
175
|
}
|
|
133
|
-
export function consumePendingBootstrapPrompt() {
|
|
134
|
-
const out = readBootstrapRow();
|
|
176
|
+
export function consumePendingBootstrapPrompt(scopeKey) {
|
|
177
|
+
const out = readBootstrapRow(scopeKey);
|
|
135
178
|
if (out) {
|
|
136
179
|
try {
|
|
137
|
-
deleteMemory.run(
|
|
180
|
+
deleteMemory.run(bootstrapKeyFor(scopeKey));
|
|
138
181
|
}
|
|
139
182
|
catch (e) {
|
|
140
183
|
console.warn('[jaw:bootstrap] consume delete failed:', e.message);
|
|
@@ -142,7 +185,7 @@ export function consumePendingBootstrapPrompt() {
|
|
|
142
185
|
}
|
|
143
186
|
return out;
|
|
144
187
|
}
|
|
145
|
-
export function peekPendingBootstrapPrompt() {
|
|
146
|
-
return readBootstrapRow();
|
|
188
|
+
export function peekPendingBootstrapPrompt(scopeKey) {
|
|
189
|
+
return readBootstrapRow(scopeKey);
|
|
147
190
|
}
|
|
148
191
|
//# sourceMappingURL=main-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-session.js","sourceRoot":"","sources":["../../../src/core/main-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,aAAa,EAAE,mBAAmB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"main-session.js","sourceRoot":"","sources":["../../../src/core/main-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
const TITLE_MAX_CHARS = 64;
|
|
2
|
+
/**
|
|
3
|
+
* 첨부 프롬프트의 머리 블록. 파일/이미지/동영상 세 변형과 다중 헤더를 모두
|
|
4
|
+
* 덮는다. 한 가지만 알면 나머지 변형에서 업로드 절대경로가 활동 제목으로
|
|
5
|
+
* 새어나간다 (devlog 260806_slack_multifile_ingest/010 D-5).
|
|
6
|
+
*/
|
|
7
|
+
// 조사가 다르다: 파일"을" / 이미지"를" / 동영상"을".
|
|
8
|
+
const SENT_PREFIX = /^\[(?:사용자가 (?:파일을|이미지를|동영상을) 보냈습니다:[^\]]+|사용자가 파일 \d+개를 보냈습니다)\]\s*/u;
|
|
9
|
+
/** 다중 목록의 번호 줄(`1. [이미지] /path`)도 제목이 되면 안 된다. */
|
|
10
|
+
const NUMBERED_ENTRY = /^\d+\.\s+\[(?:이미지|동영상|파일)\]\s/u;
|
|
2
11
|
function stripKnownPrefixes(line) {
|
|
3
12
|
return line
|
|
4
|
-
.replace(
|
|
13
|
+
.replace(SENT_PREFIX, '')
|
|
5
14
|
.replace(/^사용자 메시지:\s*/u, '')
|
|
6
15
|
.replace(/^user message:\s*/iu, '')
|
|
7
16
|
.replace(/^assistant:\s*/iu, '')
|
|
@@ -30,7 +39,8 @@ export function cleanDashboardActivityTitle(input) {
|
|
|
30
39
|
.split('\n')
|
|
31
40
|
.map(line => stripMarkdown(stripKnownPrefixes(line)).replace(/\s+/g, ' ').trim())
|
|
32
41
|
.filter(Boolean)
|
|
33
|
-
.filter(line => !
|
|
42
|
+
.filter(line => !SENT_PREFIX.test(line))
|
|
43
|
+
.filter(line => !NUMBERED_ENTRY.test(line))
|
|
34
44
|
.filter(line => !/^```/.test(line));
|
|
35
45
|
return lines[0] ? clipTitle(lines[0]) : '';
|
|
36
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-summary.js","sourceRoot":"","sources":["../../../src/core/message-summary.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,SAAS,kBAAkB,CAAC,IAAY;IACpC,OAAO,IAAI;SACN,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"message-summary.js","sourceRoot":"","sources":["../../../src/core/message-summary.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B;;;;GAIG;AACH,oCAAoC;AACpC,MAAM,WAAW,GAAG,sEAAsE,CAAC;AAC3F,kDAAkD;AAClD,MAAM,cAAc,GAAG,gCAAgC,CAAC;AAExD,SAAS,kBAAkB,CAAC,IAAY;IACpC,OAAO,IAAI;SACN,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC;SAClC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;SAC1B,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IAC/B,OAAO,IAAI;SACN,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;SACpB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;SACtB,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC;SACjC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC;SACvC,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC5B,IAAI,KAAK,CAAC,MAAM,IAAI,eAAe;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAAa;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SAC5B,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;SAClB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;SAChF,MAAM,CAAC,OAAO,CAAC;SACf,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACvC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC1C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,iCAAiC,CAAC,KAAoB;IAClE,MAAM,KAAK,GAAG,2BAA2B,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACvD,OAAO,KAAK,IAAI,IAAI,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical platform classification for cli-jaw.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for "am I on native Windows / in WSL / on plain
|
|
5
|
+
* Linux". Every rule takes its inputs as parameters so the whole matrix is
|
|
6
|
+
* testable on one CI OS.
|
|
7
|
+
*
|
|
8
|
+
* Design rationale and primary sources:
|
|
9
|
+
* devlog/_plan/260805_windows_native_detection/001_platform_signal_research.md
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import os from 'node:os';
|
|
13
|
+
export const defaultPlatformProbes = {
|
|
14
|
+
readText(path) {
|
|
15
|
+
try {
|
|
16
|
+
return fs.readFileSync(path, 'utf8');
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
exists(path) {
|
|
23
|
+
try {
|
|
24
|
+
return fs.existsSync(path);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
release() {
|
|
31
|
+
try {
|
|
32
|
+
return os.release();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* WSL markers that only ever exist inside a WSL *Linux* process.
|
|
41
|
+
*
|
|
42
|
+
* WSLENV is deliberately absent: Microsoft documents it as shared with the
|
|
43
|
+
* Windows host (it is what configures env-var translation across the
|
|
44
|
+
* boundary), so testing it misclassifies native Windows as WSL.
|
|
45
|
+
*/
|
|
46
|
+
const WSL_ENV_KEYS = ['WSL_DISTRO_NAME', 'WSL_INTEROP'];
|
|
47
|
+
const WSL_PATH_MARKERS = ['/run/WSL', '/proc/sys/fs/binfmt_misc/WSLInterop'];
|
|
48
|
+
function hasWslEnvMarker(env) {
|
|
49
|
+
return WSL_ENV_KEYS.some((key) => !!env[key]);
|
|
50
|
+
}
|
|
51
|
+
function hasWslPathMarker(probes) {
|
|
52
|
+
return WSL_PATH_MARKERS.some((markerPath) => probes.exists(markerPath));
|
|
53
|
+
}
|
|
54
|
+
function hasWslKernelMarker(probes) {
|
|
55
|
+
// `||` not `??`: an unreadable probe returns null, but a mounted-but-empty
|
|
56
|
+
// /proc under a restricted container returns '', and both must fall
|
|
57
|
+
// through to os.release().
|
|
58
|
+
const osrelease = probes.readText('/proc/sys/kernel/osrelease')?.trim() || probes.release();
|
|
59
|
+
if (osrelease.toLowerCase().includes('microsoft'))
|
|
60
|
+
return true;
|
|
61
|
+
const version = probes.readText('/proc/version');
|
|
62
|
+
return !!version && version.toLowerCase().includes('microsoft');
|
|
63
|
+
}
|
|
64
|
+
export function resolvePlatformKind(platform = process.platform, env = process.env, probes = defaultPlatformProbes) {
|
|
65
|
+
// STRICT: a win32 process is a Win32 binary. WSL env vars leaking in from
|
|
66
|
+
// the host (WSLENV, or anything a user exported) can never change this.
|
|
67
|
+
if (platform === 'win32')
|
|
68
|
+
return 'windows-native';
|
|
69
|
+
if (platform === 'darwin')
|
|
70
|
+
return 'darwin';
|
|
71
|
+
if (platform !== 'linux')
|
|
72
|
+
return 'other';
|
|
73
|
+
if (hasWslEnvMarker(env) || hasWslPathMarker(probes) || hasWslKernelMarker(probes)) {
|
|
74
|
+
return 'wsl';
|
|
75
|
+
}
|
|
76
|
+
return 'linux';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Takes only `platform` on purpose: adding env inputs would reintroduce the
|
|
80
|
+
* exact class of bug this module exists to prevent.
|
|
81
|
+
*/
|
|
82
|
+
export function isWindowsNative(platform = process.platform) {
|
|
83
|
+
return platform === 'win32';
|
|
84
|
+
}
|
|
85
|
+
export function isWsl(platform = process.platform, env = process.env, probes = defaultPlatformProbes) {
|
|
86
|
+
return resolvePlatformKind(platform, env, probes) === 'wsl';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* True when a Win32 process appears to have been launched from a WSL shell,
|
|
90
|
+
* i.e. Windows Node running against a WSL working directory. Global npm
|
|
91
|
+
* installs then land on the Windows side rather than in the distro.
|
|
92
|
+
*
|
|
93
|
+
* Keyed on the working directory, not the environment. A Win32 process started
|
|
94
|
+
* from inside a distro has its cwd on the WSL filesystem, which Windows spells
|
|
95
|
+
* as the UNC prefix `\\wsl$\<distro>` or `\\wsl.localhost\<distro>`. Every
|
|
96
|
+
* environment variable is ambiguous here: native Windows with interop
|
|
97
|
+
* configured and Windows-Node-from-WSL both carry WSLENV.
|
|
98
|
+
*
|
|
99
|
+
* Both parameters are required. There is no useful default: inside an npm
|
|
100
|
+
* lifecycle script `process.cwd()` is the installed package root, not where
|
|
101
|
+
* the user ran npm. Use `resolveInvocationCwd()` to obtain the right value.
|
|
102
|
+
*
|
|
103
|
+
* This is a HEURISTIC, and weaker than resolvePlatformKind's taxonomy. Two
|
|
104
|
+
* known holes, both inherent to a cwd-based signal:
|
|
105
|
+
* - false negative: the user cd's to a Windows path (e.g. /mnt/c/src) inside
|
|
106
|
+
* a WSL shell before invoking npm, so the cwd is an ordinary drive path;
|
|
107
|
+
* - false positive: a native PowerShell session whose cwd is a \\wsl$ share.
|
|
108
|
+
*
|
|
109
|
+
* Do not describe this function as strict. The strictness guarantee belongs to
|
|
110
|
+
* resolvePlatformKind, which can never confuse windows-native with wsl; this
|
|
111
|
+
* only decides whether to print an advisory warning.
|
|
112
|
+
*/
|
|
113
|
+
export function isWindowsNodeLaunchedFromWsl(platform, cwd) {
|
|
114
|
+
if (platform !== 'win32')
|
|
115
|
+
return false;
|
|
116
|
+
if (!cwd)
|
|
117
|
+
return false;
|
|
118
|
+
const normalized = cwd.replace(/\//g, '\\').toLowerCase();
|
|
119
|
+
return normalized.startsWith('\\\\wsl$\\') || normalized.startsWith('\\\\wsl.localhost\\');
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The directory the user actually invoked the command from.
|
|
123
|
+
*
|
|
124
|
+
* npm sets INIT_CWD to the directory where `npm` was originally run, while the
|
|
125
|
+
* lifecycle script itself executes from the package root. Outside an npm
|
|
126
|
+
* lifecycle INIT_CWD is absent and process.cwd() is already correct.
|
|
127
|
+
*/
|
|
128
|
+
export function resolveInvocationCwd(env = process.env) {
|
|
129
|
+
const initCwd = env['INIT_CWD'];
|
|
130
|
+
if (initCwd && initCwd.trim())
|
|
131
|
+
return initCwd;
|
|
132
|
+
try {
|
|
133
|
+
return process.cwd();
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return '';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=platform-kind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-kind.js","sourceRoot":"","sources":["../../../src/core/platform-kind.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AAazB,MAAM,CAAC,MAAM,qBAAqB,GAAmB;IACjD,QAAQ,CAAC,IAAI;QACT,IAAI,CAAC;YAAC,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;IACxE,CAAC;IACD,MAAM,CAAC,IAAI;QACP,IAAI,CAAC;YAAC,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,KAAK,CAAC;QAAC,CAAC;IAC/D,CAAC;IACD,OAAO;QACH,IAAI,CAAC;YAAC,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC;IACrD,CAAC;CACJ,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,CAAC,iBAAiB,EAAE,aAAa,CAAU,CAAC;AACjE,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,qCAAqC,CAAU,CAAC;AAEtF,SAAS,eAAe,CAAC,GAAsB;IAC3C,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAsB;IAC5C,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAsB;IAC9C,2EAA2E;IAC3E,oEAAoE;IACpE,2BAA2B;IAC3B,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;IAC5F,IAAI,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACjD,OAAO,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAC/B,WAA4B,OAAO,CAAC,QAAQ,EAC5C,MAAyB,OAAO,CAAC,GAAG,EACpC,SAAyB,qBAAqB;IAE9C,0EAA0E;IAC1E,wEAAwE;IACxE,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,gBAAgB,CAAC;IAClD,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC3C,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAEzC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;QACjF,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC3B,WAA4B,OAAO,CAAC,QAAQ;IAE5C,OAAO,QAAQ,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,KAAK,CACjB,WAA4B,OAAO,CAAC,QAAQ,EAC5C,MAAyB,OAAO,CAAC,GAAG,EACpC,SAAyB,qBAAqB;IAE9C,OAAO,mBAAmB,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,KAAK,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,4BAA4B,CACxC,QAAyB,EACzB,GAAW;IAEX,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IACvB,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1D,OAAO,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAC/F,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACrE,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE;QAAE,OAAO,OAAO,CAAC;IAC9C,IAAI,CAAC;QAAC,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
const DEFAULT_CONFIG = {
|
|
2
|
+
windowMs: 60_000,
|
|
3
|
+
budgets: {
|
|
4
|
+
cli: { poll: 600, mutate: 240, general: 600 },
|
|
5
|
+
manager: { poll: 600, mutate: 240, general: 600 },
|
|
6
|
+
browser: { poll: 300, mutate: 120, general: 300 },
|
|
7
|
+
lan: { poll: 120, mutate: 120, general: 120 },
|
|
8
|
+
remote: { poll: 60, mutate: 30, general: 120 },
|
|
9
|
+
},
|
|
10
|
+
nonLoopbackTotalLimit: 120,
|
|
11
|
+
};
|
|
12
|
+
const EXEMPT_PATH_PREFIXES = [
|
|
13
|
+
'/api/orchestrate/worker-runs',
|
|
14
|
+
'/api/orchestrate/worker/',
|
|
15
|
+
'/api/orchestrate/worker-progress',
|
|
16
|
+
];
|
|
17
|
+
function isLoopback(ip) {
|
|
18
|
+
return ip === '127.0.0.1' || ip === '::1' || ip === '::ffff:127.0.0.1';
|
|
19
|
+
}
|
|
20
|
+
export function classifyClient(opts) {
|
|
21
|
+
// Network position is authoritative: remote headers cannot buy a loopback budget.
|
|
22
|
+
if (!isLoopback(opts.ip)) {
|
|
23
|
+
if (opts.lanAllowed && opts.isPrivateIp(opts.ip))
|
|
24
|
+
return 'lan';
|
|
25
|
+
return 'remote';
|
|
26
|
+
}
|
|
27
|
+
if (opts.authHeader === `Bearer ${opts.authToken}`)
|
|
28
|
+
return 'cli';
|
|
29
|
+
if (opts.internalHeader !== undefined)
|
|
30
|
+
return 'manager';
|
|
31
|
+
return 'browser';
|
|
32
|
+
}
|
|
33
|
+
export function classifyPath(method, path) {
|
|
34
|
+
const normalizedMethod = method.toUpperCase();
|
|
35
|
+
if (normalizedMethod !== 'GET' && normalizedMethod !== 'HEAD')
|
|
36
|
+
return 'mutate';
|
|
37
|
+
if (path === '/api/status'
|
|
38
|
+
|| path === '/api/health'
|
|
39
|
+
|| path === '/api/messages/latest'
|
|
40
|
+
|| path === '/api/goal')
|
|
41
|
+
return 'poll';
|
|
42
|
+
return 'general';
|
|
43
|
+
}
|
|
44
|
+
function viewBucket(bucket, now, windowMs) {
|
|
45
|
+
let { windowStart, count, prevCount } = bucket;
|
|
46
|
+
const age = Math.max(0, now - windowStart);
|
|
47
|
+
if (age >= 2 * windowMs) {
|
|
48
|
+
windowStart += windowMs * Math.floor(age / windowMs);
|
|
49
|
+
count = 0;
|
|
50
|
+
prevCount = 0;
|
|
51
|
+
}
|
|
52
|
+
else if (age >= windowMs) {
|
|
53
|
+
windowStart += windowMs * Math.floor(age / windowMs);
|
|
54
|
+
prevCount = count;
|
|
55
|
+
count = 0;
|
|
56
|
+
}
|
|
57
|
+
const elapsed = Math.max(0, now - windowStart);
|
|
58
|
+
const previousWeight = Math.max(0, Math.min(1, 1 - elapsed / windowMs));
|
|
59
|
+
return { windowStart, count, prevCount, effective: count + prevCount * previousWeight };
|
|
60
|
+
}
|
|
61
|
+
function retryAfterSec(bucket, limit, now, windowMs) {
|
|
62
|
+
const maxSeconds = Math.ceil(2 * windowMs / 1_000) + 1;
|
|
63
|
+
for (let seconds = 1; seconds <= maxSeconds; seconds++) {
|
|
64
|
+
if (viewBucket(bucket, now + seconds * 1_000, windowMs).effective < limit)
|
|
65
|
+
return seconds;
|
|
66
|
+
}
|
|
67
|
+
return maxSeconds;
|
|
68
|
+
}
|
|
69
|
+
export function createRateLimiter(config = {}) {
|
|
70
|
+
const resolved = { ...DEFAULT_CONFIG, ...config };
|
|
71
|
+
const buckets = new Map();
|
|
72
|
+
const loggedWindows = new Map();
|
|
73
|
+
function check(key, cls, pathClass, now = Date.now()) {
|
|
74
|
+
const pathKey = `${cls}:${key}:${pathClass}`;
|
|
75
|
+
const specs = [{ key: pathKey, limit: resolved.budgets[cls][pathClass] }];
|
|
76
|
+
if (cls === 'lan' || cls === 'remote') {
|
|
77
|
+
specs.push({ key: `${cls}:${key}:total`, limit: resolved.nonLoopbackTotalLimit });
|
|
78
|
+
}
|
|
79
|
+
// Peek every participating bucket before committing so a rejection consumes no quota.
|
|
80
|
+
const views = specs.map(spec => {
|
|
81
|
+
const bucket = buckets.get(spec.key) ?? { windowStart: now, count: 0, prevCount: 0 };
|
|
82
|
+
return { ...spec, bucket, view: viewBucket(bucket, now, resolved.windowMs) };
|
|
83
|
+
});
|
|
84
|
+
const violated = views.filter(item => item.view.effective >= item.limit);
|
|
85
|
+
if (violated.length > 0) {
|
|
86
|
+
let retry = 0;
|
|
87
|
+
let limit = violated[0].limit;
|
|
88
|
+
let shouldLog = false;
|
|
89
|
+
for (const item of violated) {
|
|
90
|
+
const needed = retryAfterSec(item.bucket, item.limit, now, resolved.windowMs);
|
|
91
|
+
if (needed > retry) {
|
|
92
|
+
retry = needed;
|
|
93
|
+
limit = item.limit;
|
|
94
|
+
}
|
|
95
|
+
if (loggedWindows.get(item.key) !== item.view.windowStart) {
|
|
96
|
+
shouldLog = true;
|
|
97
|
+
loggedWindows.set(item.key, item.view.windowStart);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { allowed: false, retryAfterSec: retry, limit, remaining: 0, shouldLog };
|
|
101
|
+
}
|
|
102
|
+
for (const item of views) {
|
|
103
|
+
buckets.set(item.key, {
|
|
104
|
+
windowStart: item.view.windowStart,
|
|
105
|
+
count: item.view.count + 1,
|
|
106
|
+
prevCount: item.view.prevCount,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return { allowed: true };
|
|
110
|
+
}
|
|
111
|
+
function sweep(now = Date.now()) {
|
|
112
|
+
for (const [key, bucket] of buckets) {
|
|
113
|
+
if (now - bucket.windowStart >= 2 * resolved.windowMs) {
|
|
114
|
+
buckets.delete(key);
|
|
115
|
+
loggedWindows.delete(key);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { check, sweep };
|
|
120
|
+
}
|
|
121
|
+
export function createRateLimitMiddleware(opts) {
|
|
122
|
+
const limiter = opts.limiter ?? createRateLimiter();
|
|
123
|
+
return (req, res, next) => {
|
|
124
|
+
if (!req.path.startsWith('/api/'))
|
|
125
|
+
return next();
|
|
126
|
+
if (req.path === '/api/events')
|
|
127
|
+
return next();
|
|
128
|
+
if (EXEMPT_PATH_PREFIXES.some(prefix => req.path.startsWith(prefix)))
|
|
129
|
+
return next();
|
|
130
|
+
const ip = req.ip || req.socket?.remoteAddress || '';
|
|
131
|
+
const internalHeader = req.headers['x-jaw-internal'];
|
|
132
|
+
const cls = classifyClient({
|
|
133
|
+
ip,
|
|
134
|
+
...(req.headers.authorization === undefined
|
|
135
|
+
? {}
|
|
136
|
+
: { authHeader: req.headers.authorization }),
|
|
137
|
+
...(internalHeader === undefined
|
|
138
|
+
? {}
|
|
139
|
+
: { internalHeader: Array.isArray(internalHeader) ? internalHeader.join(', ') : internalHeader }),
|
|
140
|
+
authToken: opts.authToken,
|
|
141
|
+
lanAllowed: opts.lanAllowed(),
|
|
142
|
+
isPrivateIp: opts.isPrivateIp,
|
|
143
|
+
});
|
|
144
|
+
const decision = limiter.check(ip, cls, classifyPath(req.method, req.path));
|
|
145
|
+
if (decision.allowed)
|
|
146
|
+
return next();
|
|
147
|
+
res.setHeader('Retry-After', String(decision.retryAfterSec));
|
|
148
|
+
res.setHeader('RateLimit', `limit=${decision.limit}, remaining=${decision.remaining}, reset=${decision.retryAfterSec}`);
|
|
149
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
150
|
+
if (decision.shouldLog) {
|
|
151
|
+
console.warn(`[rate-limit] ${ip} (${cls}) exceeded (first blocked: ${req.method} ${req.path})`);
|
|
152
|
+
}
|
|
153
|
+
return res.status(429).json({ error: 'rate_limit', retryAfterSec: decision.retryAfterSec });
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=rate-limit.js.map
|