@wrongstack/cli 0.296.4 → 0.298.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/dist/{acp-A5OSIU2P.js → acp-S4LZQB66.js} +91 -23
- package/dist/{auth-CJWQJVRH.js → auth-NLLGEYQR.js} +3 -3
- package/dist/boot/dispatch-webui.d.ts +7 -0
- package/dist/boot/governance-evidence-candidate.d.ts +3 -0
- package/dist/boot/governance-shadow-bridge.d.ts +19 -0
- package/dist/boot/governance-trace-context.d.ts +64 -0
- package/dist/boot/launch-banner.d.ts +22 -0
- package/dist/boot/tui-session-resume.d.ts +10 -1
- package/dist/chimera-leader-wake.d.ts +57 -0
- package/dist/chimera-reviewer-policy.d.ts +89 -1
- package/dist/chimera-subagent-ladder.d.ts +72 -0
- package/dist/{chunk-AZESNNIC.js → chunk-4HH3YGG4.js} +3 -3
- package/dist/{chunk-IHBYBYGA.js → chunk-A6Q5KGLV.js} +51 -18
- package/dist/{chunk-ABXK4VVY.js → chunk-ARWGQUB3.js} +2 -1
- package/dist/{chunk-OI7GWJDS.js → chunk-C5GH4YBL.js} +1389 -184
- package/dist/{chunk-TADVX644.js → chunk-GO3TJICK.js} +11 -2
- package/dist/{chunk-JBTFWWKV.js → chunk-I2BM6FK6.js} +9 -4
- package/dist/{chunk-AXVZMEWG.js → chunk-I5MEUFDI.js} +2 -2
- package/dist/{chunk-WY7KKOUK.js → chunk-JW75HY4F.js} +31 -10
- package/dist/chunk-U3SS4NRH.js +10 -0
- package/dist/{chunk-Z7YGASQP.js → chunk-V3XH6XBJ.js} +30 -26
- package/dist/{chunk-BQCAJ7FI.js → chunk-XTIXVJXP.js} +16 -3
- package/dist/{cli-main-TOAWVJDY.js → cli-main-TJEU4OUY.js} +25912 -25134
- package/dist/cli-main-helpers.d.ts +42 -2
- package/dist/{execution-O7I5DYE6.js → execution-INOV5P7N.js} +1264 -650
- package/dist/execution-chimera-cascade.d.ts +7 -1
- package/dist/execution-chimera-review.d.ts +35 -0
- package/dist/fleet/host-types.d.ts +6 -1
- package/dist/fleet-statusline.d.ts +1 -0
- package/dist/goal-host.d.ts +1 -1
- package/dist/governance-V2Z42RBE.js +65 -0
- package/dist/governance-hq-telemetry.d.ts +17 -0
- package/dist/{hq-JUYKUNJX.js → hq-WO6CLUSI.js} +2 -2
- package/dist/hq-publisher.d.ts +3 -2
- package/dist/hq-server/auth.d.ts +33 -2
- package/dist/hq-server/login-attempt-store.d.ts +73 -0
- package/dist/hq-server/routes/auth-handlers.d.ts +73 -5
- package/dist/hq-server/routes.d.ts +5 -5
- package/dist/hq-server/types.d.ts +44 -2
- package/dist/hq-server/utils.d.ts +51 -6
- package/dist/hq-server/ws.d.ts +61 -2
- package/dist/{hq-server-6AQ3BXZA.js → hq-server-6TSAORAC.js} +2 -2
- package/dist/hq-server.d.ts +10 -0
- package/dist/index.js +337 -42
- package/dist/kanban-hq-sync.d.ts +13 -1
- package/dist/live-settings-input.d.ts +10 -1
- package/dist/{mailbox-serve-2UWHEN3M.js → mailbox-serve-DBOOOOWZ.js} +50 -8
- package/dist/{sdd-runtime-JG4EEKL6.js → sdd-runtime-AIJCJGWC.js} +2 -2
- package/dist/services/sdd/state.d.ts +3 -3
- package/dist/settings-menu.d.ts +1 -1
- package/dist/slash-commands/command-context.d.ts +2 -0
- package/dist/slash-commands/fallback.d.ts +2 -0
- package/dist/slash-commands/goal-refiner.d.ts +1 -1
- package/dist/slash-commands/goal.d.ts +1 -1
- package/dist/subcommands/handlers/acp-connection-gate.d.ts +20 -0
- package/dist/subcommands/handlers/governance.d.ts +8 -0
- package/dist/{update-YC4TYW2Y.js → update-MV6TUACD.js} +3 -3
- package/dist/utils/win32-cmd.d.ts +9 -6
- package/dist/{version-help-DROHZRW6.js → version-help-ASKQYXDJ.js} +2 -2
- package/dist/webui-server/kanban-host-adapter.d.ts +1 -1
- package/dist/webui-server/session-start-payload.d.ts +4 -0
- package/dist/{webui-server-ZF5KVGC5.js → webui-server-PCLSXX6L.js} +164 -134
- package/dist/webui-server-options.d.ts +7 -0
- package/dist/wiring/brain-and-orchestration.d.ts +2 -0
- package/dist/wiring/hq-telemetry.d.ts +4 -3
- package/dist/wiring/lifecycle-plugins.d.ts +5 -8
- package/dist/wiring/metrics.d.ts +1 -1
- package/dist/wiring/provider-runtime-setup.d.ts +2 -2
- package/package.json +23 -22
- package/dist/acp-A5OSIU2P.js.map +0 -7
- package/dist/acp-registry-cache.d.ts.map +0 -1
- package/dist/acp-server-agent.d.ts.map +0 -1
- package/dist/arg-parser.d.ts.map +0 -1
- package/dist/audit-2ZSFGNIF.js.map +0 -7
- package/dist/auth-CJWQJVRH.js.map +0 -7
- package/dist/auth-menu/add-provider.d.ts.map +0 -1
- package/dist/auth-menu/anthropic-oauth.d.ts.map +0 -1
- package/dist/auth-menu/auth-menu-audit.d.ts.map +0 -1
- package/dist/auth-menu/direct.d.ts.map +0 -1
- package/dist/auth-menu/github-copilot-oauth.d.ts.map +0 -1
- package/dist/auth-menu/helpers.d.ts.map +0 -1
- package/dist/auth-menu/index.d.ts.map +0 -1
- package/dist/auth-menu/local-presets.d.ts.map +0 -1
- package/dist/auth-menu/local.d.ts.map +0 -1
- package/dist/auth-menu/loopback-server.d.ts.map +0 -1
- package/dist/auth-menu/oauth-menu.d.ts.map +0 -1
- package/dist/auth-menu/openai-codex-oauth.d.ts.map +0 -1
- package/dist/auth-menu/panel-service.d.ts.map +0 -1
- package/dist/auth-menu/provider-menu.d.ts.map +0 -1
- package/dist/auth-menu/shared.d.ts.map +0 -1
- package/dist/auth-menu/top-menu.d.ts.map +0 -1
- package/dist/auth-menu/types.d.ts.map +0 -1
- package/dist/auth-menu.d.ts.map +0 -1
- package/dist/bench-7ZDWSNEF.js.map +0 -7
- package/dist/boot/auto-discover-providers.d.ts.map +0 -1
- package/dist/boot/brain-decision-log.d.ts.map +0 -1
- package/dist/boot/config-backup-recovery.d.ts.map +0 -1
- package/dist/boot/container-wiring.d.ts.map +0 -1
- package/dist/boot/dispatch-singleshot.d.ts.map +0 -1
- package/dist/boot/dispatch-tui.d.ts.map +0 -1
- package/dist/boot/dispatch-webui.d.ts.map +0 -1
- package/dist/boot/event-wiring.d.ts.map +0 -1
- package/dist/boot/execution-mode.d.ts.map +0 -1
- package/dist/boot/launch-menu.d.ts.map +0 -1
- package/dist/boot/short-circuit-desktop.d.ts.map +0 -1
- package/dist/boot/short-circuit-flags.d.ts.map +0 -1
- package/dist/boot/short-circuit-hq.d.ts.map +0 -1
- package/dist/boot/simpleui-full-auto.d.ts.map +0 -1
- package/dist/boot/system-prompt-builder.d.ts.map +0 -1
- package/dist/boot/system-prompt.d.ts.map +0 -1
- package/dist/boot/tool-registry.d.ts.map +0 -1
- package/dist/boot/tui-coordinator-callbacks.d.ts.map +0 -1
- package/dist/boot/tui-coordinator-setup.d.ts.map +0 -1
- package/dist/boot/tui-debug-stream.d.ts.map +0 -1
- package/dist/boot/tui-goal-wiring.d.ts.map +0 -1
- package/dist/boot/tui-live-sessions.d.ts.map +0 -1
- package/dist/boot/tui-project-picker-callback.d.ts.map +0 -1
- package/dist/boot/tui-project-spawn.d.ts.map +0 -1
- package/dist/boot/tui-project-switch.d.ts.map +0 -1
- package/dist/boot/tui-runtime-state.d.ts.map +0 -1
- package/dist/boot/tui-sdd-callback.d.ts.map +0 -1
- package/dist/boot/tui-session-resume.d.ts.map +0 -1
- package/dist/boot/tui-settings-adapter.d.ts.map +0 -1
- package/dist/boot-config.d.ts.map +0 -1
- package/dist/boot.d.ts.map +0 -1
- package/dist/brain-menu/panel-service.d.ts.map +0 -1
- package/dist/chimera-review-task.d.ts.map +0 -1
- package/dist/chimera-reviewer-policy.d.ts.map +0 -1
- package/dist/chronicle-QQEQFSSE.js.map +0 -7
- package/dist/chunk-5N34EWJR.js.map +0 -7
- package/dist/chunk-66T43Q4Y.js.map +0 -7
- package/dist/chunk-7OCVIDC7.js.map +0 -7
- package/dist/chunk-ABXK4VVY.js.map +0 -7
- package/dist/chunk-AXVZMEWG.js.map +0 -7
- package/dist/chunk-AZESNNIC.js.map +0 -7
- package/dist/chunk-BGFM3PD7.js.map +0 -7
- package/dist/chunk-BQCAJ7FI.js.map +0 -7
- package/dist/chunk-DPJZQCVP.js.map +0 -7
- package/dist/chunk-F4PEGAJZ.js.map +0 -7
- package/dist/chunk-IHBYBYGA.js.map +0 -7
- package/dist/chunk-JBSQ7ONN.js.map +0 -7
- package/dist/chunk-JBTFWWKV.js.map +0 -7
- package/dist/chunk-JUHRI6OV.js.map +0 -7
- package/dist/chunk-OI7GWJDS.js.map +0 -7
- package/dist/chunk-OP47B3IX.js.map +0 -7
- package/dist/chunk-PJHET45A.js.map +0 -7
- package/dist/chunk-Q5GTM25S.js.map +0 -7
- package/dist/chunk-QD544J2B.js.map +0 -7
- package/dist/chunk-QUNHS6O3.js.map +0 -7
- package/dist/chunk-TADVX644.js.map +0 -7
- package/dist/chunk-TGDHN4LM.js.map +0 -7
- package/dist/chunk-TYO2OVAD.js.map +0 -7
- package/dist/chunk-VCYZ3WZV.js.map +0 -7
- package/dist/chunk-VJUEZZYB.js +0 -29
- package/dist/chunk-VJUEZZYB.js.map +0 -7
- package/dist/chunk-WHOIR577.js.map +0 -7
- package/dist/chunk-WY7KKOUK.js.map +0 -7
- package/dist/chunk-XJXDOF63.js.map +0 -7
- package/dist/chunk-XWEGWYDU.js.map +0 -7
- package/dist/chunk-YWUPHRGB.js.map +0 -7
- package/dist/chunk-Z7YGASQP.js.map +0 -7
- package/dist/cli-bundled-prompts.d.ts.map +0 -1
- package/dist/cli-bundled-skills.d.ts.map +0 -1
- package/dist/cli-context.d.ts.map +0 -1
- package/dist/cli-entry-main.d.ts.map +0 -1
- package/dist/cli-entry-point.d.ts.map +0 -1
- package/dist/cli-eternal-flag.d.ts.map +0 -1
- package/dist/cli-main-TOAWVJDY.js.map +0 -7
- package/dist/cli-main-helpers.d.ts.map +0 -1
- package/dist/cli-main.d.ts.map +0 -1
- package/dist/cli-update-notice.d.ts.map +0 -1
- package/dist/config-doctor.d.ts.map +0 -1
- package/dist/config-history.d.ts.map +0 -1
- package/dist/context-limit.d.ts.map +0 -1
- package/dist/context-overflow-diagnostic.d.ts.map +0 -1
- package/dist/diag-doctor-OQ3AA63O.js.map +0 -7
- package/dist/diff-renderer.d.ts.map +0 -1
- package/dist/execute-deps.d.ts.map +0 -1
- package/dist/execution-O7I5DYE6.js.map +0 -7
- package/dist/execution-chimera-ask.d.ts.map +0 -1
- package/dist/execution-chimera-cascade.d.ts.map +0 -1
- package/dist/execution-cleanup.d.ts.map +0 -1
- package/dist/execution-kanban-dispatch.d.ts.map +0 -1
- package/dist/execution-repl-fleet-callbacks.d.ts.map +0 -1
- package/dist/execution-storage-observability.d.ts.map +0 -1
- package/dist/execution-tui-next-step-callbacks.d.ts.map +0 -1
- package/dist/execution.d.ts.map +0 -1
- package/dist/export-TPORYVRZ.js.map +0 -7
- package/dist/fleet/host-acp-runner-cache.d.ts.map +0 -1
- package/dist/fleet/host-acp.d.ts.map +0 -1
- package/dist/fleet/host-concurrency.d.ts.map +0 -1
- package/dist/fleet/host-context.d.ts.map +0 -1
- package/dist/fleet/host-director-builder.d.ts.map +0 -1
- package/dist/fleet/host-director-event-bridges.d.ts.map +0 -1
- package/dist/fleet/host-director-services.d.ts.map +0 -1
- package/dist/fleet/host-event-bridge.d.ts.map +0 -1
- package/dist/fleet/host-helpers.d.ts.map +0 -1
- package/dist/fleet/host-learning-tracker.d.ts.map +0 -1
- package/dist/fleet/host-learning.d.ts.map +0 -1
- package/dist/fleet/host-lifecycle-events.d.ts.map +0 -1
- package/dist/fleet/host-paths.d.ts.map +0 -1
- package/dist/fleet/host-provider.d.ts.map +0 -1
- package/dist/fleet/host-session-writer.d.ts.map +0 -1
- package/dist/fleet/host-shadow-pass.d.ts.map +0 -1
- package/dist/fleet/host-spawn-types.d.ts.map +0 -1
- package/dist/fleet/host-status.d.ts.map +0 -1
- package/dist/fleet/host-subagent-factory.d.ts.map +0 -1
- package/dist/fleet/host-supervisor.d.ts.map +0 -1
- package/dist/fleet/host-task-result-report.d.ts.map +0 -1
- package/dist/fleet/host-types.d.ts.map +0 -1
- package/dist/fleet/host.d.ts.map +0 -1
- package/dist/fleet/routing.d.ts.map +0 -1
- package/dist/fleet/status-broadcast.d.ts.map +0 -1
- package/dist/fleet/supervisor-registry.d.ts.map +0 -1
- package/dist/fleet-statusline.d.ts.map +0 -1
- package/dist/goal-host.d.ts.map +0 -1
- package/dist/hooks-wiring.d.ts.map +0 -1
- package/dist/hq-JUYKUNJX.js.map +0 -7
- package/dist/hq-command-controller.d.ts.map +0 -1
- package/dist/hq-publisher.d.ts.map +0 -1
- package/dist/hq-recovery-html.d.ts.map +0 -1
- package/dist/hq-server/audit-actor.d.ts.map +0 -1
- package/dist/hq-server/auth-state.d.ts.map +0 -1
- package/dist/hq-server/auth.d.ts.map +0 -1
- package/dist/hq-server/preflight.d.ts.map +0 -1
- package/dist/hq-server/project-root.d.ts.map +0 -1
- package/dist/hq-server/routes/auth-handlers.d.ts.map +0 -1
- package/dist/hq-server/routes/session-handlers.d.ts.map +0 -1
- package/dist/hq-server/routes/system-handlers.d.ts.map +0 -1
- package/dist/hq-server/routes.d.ts.map +0 -1
- package/dist/hq-server/snapshot.d.ts.map +0 -1
- package/dist/hq-server/startup.d.ts.map +0 -1
- package/dist/hq-server/trust-boundary.d.ts.map +0 -1
- package/dist/hq-server/types.d.ts.map +0 -1
- package/dist/hq-server/utils.d.ts.map +0 -1
- package/dist/hq-server/ws.d.ts.map +0 -1
- package/dist/hq-server-6AQ3BXZA.js.map +0 -7
- package/dist/hq-server.d.ts.map +0 -1
- package/dist/hq-static-serve.d.ts.map +0 -1
- package/dist/hq-ttl-U2FAYFAT.js.map +0 -7
- package/dist/hq-tunnel-RFKGC4HI.js.map +0 -7
- package/dist/hq-tunnel.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -7
- package/dist/init-E2NDDOHI.js.map +0 -7
- package/dist/input-reader.d.ts.map +0 -1
- package/dist/kanban-dispatch-route.d.ts.map +0 -1
- package/dist/kanban-hq-sync.d.ts.map +0 -1
- package/dist/kanban-run-mirror-EKVNGXWW.js.map +0 -7
- package/dist/launch-hints.d.ts.map +0 -1
- package/dist/live-settings-input.d.ts.map +0 -1
- package/dist/mailbox-bridge-bootstrap.d.ts.map +0 -1
- package/dist/mailbox-serve-2UWHEN3M.js.map +0 -7
- package/dist/mcp-CYLPUEHC.js.map +0 -7
- package/dist/mcp-serve.d.ts.map +0 -1
- package/dist/modeldiag-HENYJ4N7.js.map +0 -7
- package/dist/multi-agent.d.ts.map +0 -1
- package/dist/next-task-predictor.d.ts.map +0 -1
- package/dist/permission-prompt.d.ts.map +0 -1
- package/dist/permissions-FNYLZIL4.js.map +0 -7
- package/dist/picker-key-state.d.ts.map +0 -1
- package/dist/picker-model-picker.d.ts.map +0 -1
- package/dist/picker-ui.d.ts.map +0 -1
- package/dist/picker.d.ts.map +0 -1
- package/dist/plugin-api-factory.d.ts.map +0 -1
- package/dist/plugin-management.d.ts.map +0 -1
- package/dist/plugin-usage-OU6X6LM3.js.map +0 -7
- package/dist/plugins-4LJ5IUBI.js.map +0 -7
- package/dist/pre-launch/launch-prompts.d.ts.map +0 -1
- package/dist/pre-launch/project-check.d.ts.map +0 -1
- package/dist/pre-launch.d.ts.map +0 -1
- package/dist/preflight.d.ts.map +0 -1
- package/dist/profile-config-path.d.ts.map +0 -1
- package/dist/project-BLQ3ALVL.js.map +0 -7
- package/dist/project-manifest-GE25PW4S.js.map +0 -7
- package/dist/project-picker-BOCWHBXP.js.map +0 -7
- package/dist/project-picker.d.ts.map +0 -1
- package/dist/projects-XE76NFNZ.js.map +0 -7
- package/dist/provider-config-utils.d.ts.map +0 -1
- package/dist/provider-helpers.d.ts.map +0 -1
- package/dist/provider-id.d.ts.map +0 -1
- package/dist/providers-models-GDELBHZK.js.map +0 -7
- package/dist/quick-VIO2BEHS.js.map +0 -7
- package/dist/renderer.d.ts.map +0 -1
- package/dist/repl-auto-proceed.d.ts.map +0 -1
- package/dist/repl-client-registration.d.ts.map +0 -1
- package/dist/repl-input.d.ts.map +0 -1
- package/dist/repl-options.d.ts.map +0 -1
- package/dist/repl-rendering.d.ts.map +0 -1
- package/dist/repl-suggestions.d.ts.map +0 -1
- package/dist/repl.d.ts.map +0 -1
- package/dist/replay-KCTXNMZQ.js.map +0 -7
- package/dist/rewind-EJMVFVLS.js.map +0 -7
- package/dist/sdd-runtime-JG4EEKL6.js.map +0 -7
- package/dist/services/autonomy-mode.d.ts.map +0 -1
- package/dist/services/commit-message.d.ts.map +0 -1
- package/dist/services/dispatch-classifier.d.ts.map +0 -1
- package/dist/services/mcp-management.d.ts.map +0 -1
- package/dist/services/project-facts.d.ts.map +0 -1
- package/dist/services/project-manifest.d.ts.map +0 -1
- package/dist/services/sdd/project-context.d.ts.map +0 -1
- package/dist/services/sdd/spec-detection.d.ts.map +0 -1
- package/dist/services/sdd/state.d.ts.map +0 -1
- package/dist/services/sdd/task-manager.d.ts.map +0 -1
- package/dist/services/sdd-runtime.d.ts.map +0 -1
- package/dist/services/statusline-config.d.ts.map +0 -1
- package/dist/services/suggestion-store.d.ts.map +0 -1
- package/dist/session-event-wiring.d.ts.map +0 -1
- package/dist/session-stats.d.ts.map +0 -1
- package/dist/sessions-config-NLCMK3BY.js.map +0 -7
- package/dist/settings-menu.d.ts.map +0 -1
- package/dist/shutdown-cleanup.d.ts.map +0 -1
- package/dist/simpleui-dist-JIFGUJO7.js.map +0 -7
- package/dist/simpleui-dist.d.ts.map +0 -1
- package/dist/slash-commands/acp.d.ts.map +0 -1
- package/dist/slash-commands/agent-improve.d.ts.map +0 -1
- package/dist/slash-commands/agents.d.ts.map +0 -1
- package/dist/slash-commands/audit.d.ts.map +0 -1
- package/dist/slash-commands/auth.d.ts.map +0 -1
- package/dist/slash-commands/autonomy.d.ts.map +0 -1
- package/dist/slash-commands/brain.d.ts.map +0 -1
- package/dist/slash-commands/btw.d.ts.map +0 -1
- package/dist/slash-commands/clear.d.ts.map +0 -1
- package/dist/slash-commands/codebase-reindex.d.ts.map +0 -1
- package/dist/slash-commands/collab.d.ts.map +0 -1
- package/dist/slash-commands/command-context.d.ts.map +0 -1
- package/dist/slash-commands/commit-llm.d.ts.map +0 -1
- package/dist/slash-commands/compact.d.ts.map +0 -1
- package/dist/slash-commands/context.d.ts.map +0 -1
- package/dist/slash-commands/coordinator.d.ts.map +0 -1
- package/dist/slash-commands/delegate.d.ts.map +0 -1
- package/dist/slash-commands/design.d.ts.map +0 -1
- package/dist/slash-commands/dev.d.ts.map +0 -1
- package/dist/slash-commands/diag-stats.d.ts.map +0 -1
- package/dist/slash-commands/dispatch-llm.d.ts.map +0 -1
- package/dist/slash-commands/doctor.d.ts.map +0 -1
- package/dist/slash-commands/enhance.d.ts.map +0 -1
- package/dist/slash-commands/ensemble.d.ts.map +0 -1
- package/dist/slash-commands/f-keys.d.ts.map +0 -1
- package/dist/slash-commands/fallback.d.ts.map +0 -1
- package/dist/slash-commands/fix-classifier.d.ts.map +0 -1
- package/dist/slash-commands/fix.d.ts.map +0 -1
- package/dist/slash-commands/fleet.d.ts.map +0 -1
- package/dist/slash-commands/git.d.ts.map +0 -1
- package/dist/slash-commands/gitid.d.ts.map +0 -1
- package/dist/slash-commands/goal-refiner.d.ts.map +0 -1
- package/dist/slash-commands/goal.d.ts.map +0 -1
- package/dist/slash-commands/health.d.ts.map +0 -1
- package/dist/slash-commands/help.d.ts.map +0 -1
- package/dist/slash-commands/helpers.d.ts.map +0 -1
- package/dist/slash-commands/hq.d.ts.map +0 -1
- package/dist/slash-commands/index.d.ts.map +0 -1
- package/dist/slash-commands/init.d.ts.map +0 -1
- package/dist/slash-commands/interrupt.d.ts.map +0 -1
- package/dist/slash-commands/kanban-agent-helpers.d.ts.map +0 -1
- package/dist/slash-commands/kanban-format.d.ts.map +0 -1
- package/dist/slash-commands/kanban-help.d.ts.map +0 -1
- package/dist/slash-commands/kanban.d.ts.map +0 -1
- package/dist/slash-commands/mailbox-demo.d.ts.map +0 -1
- package/dist/slash-commands/mailbox-serve.d.ts.map +0 -1
- package/dist/slash-commands/mailbox.d.ts.map +0 -1
- package/dist/slash-commands/mcp-utils.d.ts.map +0 -1
- package/dist/slash-commands/mcp.d.ts.map +0 -1
- package/dist/slash-commands/memory-compact.d.ts.map +0 -1
- package/dist/slash-commands/memory-flags.d.ts.map +0 -1
- package/dist/slash-commands/memory-formatters.d.ts.map +0 -1
- package/dist/slash-commands/memory.d.ts.map +0 -1
- package/dist/slash-commands/metrics.d.ts.map +0 -1
- package/dist/slash-commands/mode.d.ts.map +0 -1
- package/dist/slash-commands/modelcaps.d.ts.map +0 -1
- package/dist/slash-commands/models.d.ts.map +0 -1
- package/dist/slash-commands/mouse.d.ts.map +0 -1
- package/dist/slash-commands/next.d.ts.map +0 -1
- package/dist/slash-commands/plan.d.ts.map +0 -1
- package/dist/slash-commands/plugin.d.ts.map +0 -1
- package/dist/slash-commands/profile.d.ts.map +0 -1
- package/dist/slash-commands/project-utils.d.ts.map +0 -1
- package/dist/slash-commands/project.d.ts.map +0 -1
- package/dist/slash-commands/provider-status.d.ts.map +0 -1
- package/dist/slash-commands/prune.d.ts.map +0 -1
- package/dist/slash-commands/refiner.d.ts.map +0 -1
- package/dist/slash-commands/review.d.ts.map +0 -1
- package/dist/slash-commands/sdd/rendering.d.ts.map +0 -1
- package/dist/slash-commands/sdd-command-helpers.d.ts.map +0 -1
- package/dist/slash-commands/sdd-format.d.ts.map +0 -1
- package/dist/slash-commands/sdd.d.ts.map +0 -1
- package/dist/slash-commands/security.d.ts.map +0 -1
- package/dist/slash-commands/session.d.ts.map +0 -1
- package/dist/slash-commands/setmodel.d.ts.map +0 -1
- package/dist/slash-commands/settings.d.ts.map +0 -1
- package/dist/slash-commands/shadow.d.ts.map +0 -1
- package/dist/slash-commands/slash-deep-help.d.ts.map +0 -1
- package/dist/slash-commands/spawn-agents.d.ts.map +0 -1
- package/dist/slash-commands/statusline.d.ts.map +0 -1
- package/dist/slash-commands/suggest.d.ts.map +0 -1
- package/dist/slash-commands/suggestion-store.d.ts.map +0 -1
- package/dist/slash-commands/supervisor.d.ts.map +0 -1
- package/dist/slash-commands/surfaces.d.ts.map +0 -1
- package/dist/slash-commands/tasks.d.ts.map +0 -1
- package/dist/slash-commands/techstack.d.ts.map +0 -1
- package/dist/slash-commands/telegram-pairing.d.ts.map +0 -1
- package/dist/slash-commands/telegram-settings.d.ts.map +0 -1
- package/dist/slash-commands/telegram-setup.d.ts.map +0 -1
- package/dist/slash-commands/todos.d.ts.map +0 -1
- package/dist/slash-commands/tool.d.ts.map +0 -1
- package/dist/slash-commands/tools.d.ts.map +0 -1
- package/dist/slash-commands/tuneup.d.ts.map +0 -1
- package/dist/slash-commands/working-dir.d.ts.map +0 -1
- package/dist/slash-commands/worktree.d.ts.map +0 -1
- package/dist/slash-commands/yolo.d.ts.map +0 -1
- package/dist/spinner.d.ts.map +0 -1
- package/dist/subcommands/contracts.d.ts.map +0 -1
- package/dist/subcommands/handlers/acp.d.ts.map +0 -1
- package/dist/subcommands/handlers/audit.d.ts.map +0 -1
- package/dist/subcommands/handlers/auth-local-help.d.ts.map +0 -1
- package/dist/subcommands/handlers/auth.d.ts.map +0 -1
- package/dist/subcommands/handlers/bench-run-help.d.ts.map +0 -1
- package/dist/subcommands/handlers/bench.d.ts.map +0 -1
- package/dist/subcommands/handlers/chronicle.d.ts.map +0 -1
- package/dist/subcommands/handlers/config-history.d.ts.map +0 -1
- package/dist/subcommands/handlers/diag-doctor.d.ts.map +0 -1
- package/dist/subcommands/handlers/export.d.ts.map +0 -1
- package/dist/subcommands/handlers/helpers.d.ts.map +0 -1
- package/dist/subcommands/handlers/hq.d.ts.map +0 -1
- package/dist/subcommands/handlers/init.d.ts.map +0 -1
- package/dist/subcommands/handlers/mailbox-serve.d.ts.map +0 -1
- package/dist/subcommands/handlers/mcp.d.ts.map +0 -1
- package/dist/subcommands/handlers/model-smoke-test.d.ts.map +0 -1
- package/dist/subcommands/handlers/modeldiag-profiles.d.ts.map +0 -1
- package/dist/subcommands/handlers/modeldiag.d.ts.map +0 -1
- package/dist/subcommands/handlers/models-add-help.d.ts.map +0 -1
- package/dist/subcommands/handlers/per-subcommand-deep-help-table.d.ts.map +0 -1
- package/dist/subcommands/handlers/per-subcommand-help-data.d.ts.map +0 -1
- package/dist/subcommands/handlers/per-subcommand-help-table.d.ts.map +0 -1
- package/dist/subcommands/handlers/per-subcommand-help-types.d.ts.map +0 -1
- package/dist/subcommands/handlers/per-subcommand-help.d.ts.map +0 -1
- package/dist/subcommands/handlers/permissions.d.ts.map +0 -1
- package/dist/subcommands/handlers/plugin-usage.d.ts.map +0 -1
- package/dist/subcommands/handlers/project.d.ts.map +0 -1
- package/dist/subcommands/handlers/projects.d.ts.map +0 -1
- package/dist/subcommands/handlers/providers-models.d.ts.map +0 -1
- package/dist/subcommands/handlers/quick.d.ts.map +0 -1
- package/dist/subcommands/handlers/replay.d.ts.map +0 -1
- package/dist/subcommands/handlers/rewind.d.ts.map +0 -1
- package/dist/subcommands/handlers/sessions-config.d.ts.map +0 -1
- package/dist/subcommands/handlers/sessions-fleet.d.ts.map +0 -1
- package/dist/subcommands/handlers/tools-skills.d.ts.map +0 -1
- package/dist/subcommands/handlers/update.d.ts.map +0 -1
- package/dist/subcommands/handlers/version-help.d.ts.map +0 -1
- package/dist/subcommands/index.d.ts.map +0 -1
- package/dist/theme.d.ts.map +0 -1
- package/dist/tools-skills-UNKLOB7M.js.map +0 -7
- package/dist/tui-thinking-word.d.ts.map +0 -1
- package/dist/tuneup.d.ts.map +0 -1
- package/dist/update-YC4TYW2Y.js.map +0 -7
- package/dist/update-check-UMYTOH7Z.js.map +0 -7
- package/dist/update-check.d.ts.map +0 -1
- package/dist/utils/delay-format.d.ts.map +0 -1
- package/dist/utils/hq-ttl.d.ts.map +0 -1
- package/dist/utils/win32-cmd.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
- package/dist/version-help-DROHZRW6.js.map +0 -7
- package/dist/version.d.ts.map +0 -1
- package/dist/webui-server/client-registration.d.ts.map +0 -1
- package/dist/webui-server/connection-handler.d.ts.map +0 -1
- package/dist/webui-server/context-breakdown.d.ts.map +0 -1
- package/dist/webui-server/contracts.d.ts.map +0 -1
- package/dist/webui-server/cost-helpers.d.ts.map +0 -1
- package/dist/webui-server/kanban-host-adapter.d.ts.map +0 -1
- package/dist/webui-server/kanban-run-mirror.d.ts.map +0 -1
- package/dist/webui-server/kanban-supervisor.d.ts.map +0 -1
- package/dist/webui-server/lifecycle.d.ts.map +0 -1
- package/dist/webui-server/listen-helpers.d.ts.map +0 -1
- package/dist/webui-server/logger-shim.d.ts.map +0 -1
- package/dist/webui-server/node-pty-loader.d.ts.map +0 -1
- package/dist/webui-server/prefs-seeding.d.ts.map +0 -1
- package/dist/webui-server/privileged-actions.d.ts.map +0 -1
- package/dist/webui-server/provider-config.d.ts.map +0 -1
- package/dist/webui-server/session-start-payload.d.ts.map +0 -1
- package/dist/webui-server/setup-events.d.ts.map +0 -1
- package/dist/webui-server/static-serve.d.ts.map +0 -1
- package/dist/webui-server/stream-coalescer.d.ts.map +0 -1
- package/dist/webui-server/terminal-log-view.d.ts.map +0 -1
- package/dist/webui-server-ZF5KVGC5.js.map +0 -7
- package/dist/webui-server-options.d.ts.map +0 -1
- package/dist/webui-server.d.ts.map +0 -1
- package/dist/wiring/brain-and-orchestration.d.ts.map +0 -1
- package/dist/wiring/codebase-index.d.ts.map +0 -1
- package/dist/wiring/command-host-adapters.d.ts.map +0 -1
- package/dist/wiring/command-host-state.d.ts.map +0 -1
- package/dist/wiring/controllers.d.ts.map +0 -1
- package/dist/wiring/dep-watcher-bridge.d.ts.map +0 -1
- package/dist/wiring/dep-watcher.d.ts.map +0 -1
- package/dist/wiring/design-studio.d.ts.map +0 -1
- package/dist/wiring/director-setup.d.ts.map +0 -1
- package/dist/wiring/eternal-command-handlers.d.ts.map +0 -1
- package/dist/wiring/fleet-command-handlers.d.ts.map +0 -1
- package/dist/wiring/hq-telemetry.d.ts.map +0 -1
- package/dist/wiring/lifecycle-plugins.d.ts.map +0 -1
- package/dist/wiring/mailbox-bridge-bootstrap.d.ts.map +0 -1
- package/dist/wiring/management-tools.d.ts.map +0 -1
- package/dist/wiring/metrics.d.ts.map +0 -1
- package/dist/wiring/pipeline.d.ts.map +0 -1
- package/dist/wiring/plugins.d.ts.map +0 -1
- package/dist/wiring/provider-runtime-setup.d.ts.map +0 -1
- package/dist/wiring/provider-runtime.d.ts.map +0 -1
- package/dist/wiring/provider-status.d.ts.map +0 -1
- package/dist/wiring/provider-utility-tools.d.ts.map +0 -1
- package/dist/wiring/provider.d.ts.map +0 -1
- package/dist/wiring/replay.d.ts.map +0 -1
- package/dist/wiring/runtime-controller-deps.d.ts.map +0 -1
- package/dist/wiring/runtime-dispatch-state.d.ts.map +0 -1
- package/dist/wiring/runtime-lifecycle-deps.d.ts.map +0 -1
- package/dist/wiring/runtime-picker-deps.d.ts.map +0 -1
- package/dist/wiring/sage.d.ts.map +0 -1
- package/dist/wiring/sdd-handlers.d.ts.map +0 -1
- package/dist/wiring/security-command.d.ts.map +0 -1
- package/dist/wiring/session-command-handlers.d.ts.map +0 -1
- package/dist/wiring/session-registry.d.ts.map +0 -1
- package/dist/wiring/session.d.ts.map +0 -1
- package/dist/wiring/slash-commands.d.ts.map +0 -1
- package/dist/wiring/to-execute-deps.d.ts.map +0 -1
- package/dist/wiring/tools.d.ts.map +0 -1
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/hq-command-controller.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * HQ command controller \u2014 the client-side dispatch surface for Phase 4 of the\n * HQ command center. A mutable holder (mirroring the established\n * `interruptController` pattern in cli-main.ts) that the `onCommand` handler\n * on the HQ publisher reads lazily, because several of its targets\n * (`director`, the rebound `interruptLeader`) are not yet defined at HQ-connect\n * time.\n *\n * The five command types route through the agent's own decision loop or the\n * project mailbox, so they inherit existing guardrails. `run-command` (raw\n * shell) is deliberately NOT wired here \u2014 it requires a separately-audited\n * escalation policy (operator flag + per-token `control.execute` + allowlist)\n * and is left as a stub that rejects until that policy exists.\n *\n * @module hq-command-controller\n */\nimport type { HqPublisherCommandResult } from '@wrongstack/core/hq';\nimport type { RemoteMailbox } from '@wrongstack/core/coordination';\nimport type { HqCommand } from '@wrongstack/core/hq';\n\n/**\n * Mutable holder for the command dispatch targets. Each field is populated\n * lazily as the corresponding subsystem comes online (director on\n * `onDirectorReady`, interruptLeader rebound by the REPL/TUI, \u2026). The\n * `onCommand` handler reads these at dispatch time, not at construction.\n */\nexport interface HqCommandController {\n /** Project mailbox used to deliver steer/broadcast messages. */\n steerMailbox?: RemoteMailbox | undefined;\n /** Abort the session leader's running Agent.run(). Returns true if a run was aborted. */\n interruptLeader: () => boolean;\n /** Terminate a specific subagent by id. Returns true if terminated. */\n terminateAgent?: (subagentId: string) => boolean | Promise<boolean>;\n /** Stop the entire fleet (all running/idle subagents). Returns kill count. */\n killFleet?: () => number | Promise<number>;\n /** Spawn a subagent of the given role. Returns the new subagentId. */\n spawnAgent?: (role: string, task?: string, maxIterations?: number) => Promise<string>;\n /** Derive the session-unique mailbox tag for addressing (e.g. `leader@<tag>`). */\n sessionTag: () => string;\n /** Whether raw shell execution is explicitly opted-in by the operator. */\n allowRunCommand: () => boolean;\n}\n\n/**\n * Build the `onCommand` handler for an HQ publisher. The handler validates\n * the command, dispatches through the controller, and returns an ack result\n * (or throws to produce a `failed` ack \u2014 the publisher's `handleCommandBatch`\n * wraps it). Best-effort: a dispatch failure never breaks the host.\n */\nexport function createHqCommandDispatcher(\n controller: HqCommandController,\n): (command: { commandId: string; type: string; payload: unknown }) => Promise<HqPublisherCommandResult> {\n return async (command) => {\n const cmd = command as { commandId: string; type: string; payload: Record<string, unknown> };\n try {\n const result = await dispatch(controller, cmd.commandId, cmd.type as HqCommand['type'], cmd.payload);\n return result;\n } catch (err) {\n return {\n commandId: command.commandId,\n status: 'failed',\n message: err instanceof Error ? err.message : String(err),\n };\n }\n };\n}\n\nasync function dispatch(\n controller: HqCommandController,\n commandId: string,\n type: HqCommand['type'],\n payload: Record<string, unknown>,\n): Promise<HqPublisherCommandResult> {\n switch (type) {\n case 'steer': {\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const to = typeof payload['to'] === 'string' ? payload['to'] : 'leader';\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ steer';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to, type: 'steer', subject, body, priority });\n return { commandId, status: 'accepted', message: `steered ${to}` };\n }\n\n case 'btw': {\n // Non-urgent FYI. Same targeting as steer, but delivered as a `btw`\n // mailbox message so the receiving agent absorbs it as context instead\n // of treating it as a course-correction. Lands in the mailbox file\n // regardless of whether a loop is currently running.\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const to = typeof payload['to'] === 'string' ? payload['to'] : 'leader';\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ note';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to, type: 'btw', subject, body, priority });\n return { commandId, status: 'accepted', message: `noted ${to}` };\n }\n\n case 'queue': {\n // Queue a prompt/note for the target. Delivered as a plain `note` the\n // agent picks up before its next step \u2014 used when the prompt should\n // wait its turn rather than steer the current operation. Like steer/btw,\n // this only writes to the mailbox; no live loop is required.\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const to = typeof payload['to'] === 'string' ? payload['to'] : 'leader';\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ prompt';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to, type: 'note', subject, body, priority });\n return { commandId, status: 'accepted', message: `queued for ${to}` };\n }\n\n case 'broadcast': {\n const mailbox = controller.steerMailbox;\n if (mailbox === undefined) {\n return { commandId, status: 'rejected', message: 'no mailbox available' };\n }\n const subject = typeof payload['subject'] === 'string' ? payload['subject'] : 'HQ broadcast';\n const body = typeof payload['body'] === 'string' ? payload['body'] : '';\n const priority = payload['priority'] === 'high' ? 'high' : payload['priority'] === 'low' ? 'low' : 'normal';\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({ from, to: 'all', type: 'broadcast', subject, body, priority });\n return { commandId, status: 'accepted', message: 'broadcast sent' };\n }\n\n case 'abort': {\n const target = typeof payload['target'] === 'string' ? payload['target'] : 'leader';\n if (target === 'leader') {\n const aborted = controller.interruptLeader();\n return {\n commandId,\n status: aborted ? 'completed' : 'accepted',\n message: aborted ? 'leader aborted' : 'no active leader run',\n };\n }\n if (target === 'fleet') {\n const killed = (await controller.killFleet?.()) ?? 0;\n return {\n commandId,\n status: 'completed',\n message: `fleet stopped (${killed} agents)`,\n };\n }\n // Specific subagent id.\n const terminated = (await controller.terminateAgent?.(target)) ?? false;\n return {\n commandId,\n status: terminated ? 'completed' : 'rejected',\n message: terminated ? `agent ${target} terminated` : `agent ${target} not found`,\n };\n }\n\n case 'spawn': {\n const role = typeof payload['role'] === 'string' ? payload['role'] : '';\n const task = typeof payload['task'] === 'string' ? payload['task'] : undefined;\n const maxIterations = typeof payload['maxIterations'] === 'number' ? payload['maxIterations'] : undefined;\n if (controller.spawnAgent === undefined) {\n return { commandId, status: 'rejected', message: 'no director active' };\n }\n const subagentId = await controller.spawnAgent(role, task, maxIterations);\n return { commandId, status: 'completed', message: `spawned ${subagentId}` };\n }\n\n case 'run-command': {\n // RCE gate: require explicit operator opt-in. Without it, reject every\n // run-command so a stolen client token can never gain shell access.\n if (!controller.allowRunCommand()) {\n return {\n commandId,\n status: 'rejected',\n message: 'run-command requires operator opt-in (--hq-allow-exec)',\n };\n }\n // Even with opt-in, we do NOT exec shell directly \u2014 we route through the\n // agent as a steer so the agent's own permission policy still applies.\n // A full direct-exec path is deferred until a separately-audited\n // escalation policy + allowlist exists.\n const mailbox = controller.steerMailbox;\n const command = typeof payload['command'] === 'string' ? payload['command'] : '';\n if (mailbox !== undefined && command.length > 0) {\n const from = `hq@${controller.sessionTag()}`;\n await mailbox.send({\n from,\n to: 'leader',\n type: 'steer',\n subject: 'Run command (HQ)',\n body: `Run the following shell command:\\n\\n\\`\\`\\`\\n${command}\\n\\`\\`\\``,\n priority: 'high',\n });\n return { commandId, status: 'accepted', message: 'run-command routed to leader as steer' };\n }\n return { commandId, status: 'rejected', message: 'cannot route run-command (no mailbox)' };\n }\n\n default:\n return { commandId, status: 'rejected', message: `unknown command type: ${type}` };\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/provider-config-utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { expectDefined } from '@wrongstack/core/utils';\nimport { FsError } from '@wrongstack/core/types';\n\nexport { expectDefined };\n\n/**\n * Pure helpers for ProviderConfig shape normalisation, key masking, and\n * timestamp generation \u2014 plus config file I/O (load/mutate providers).\n * Shared between auth-menu.ts, webui-server.ts, and any future code that\n * touches the config `providers` map.\n */\nimport * as fs from 'node:fs/promises';\nimport type { ProviderApiKey, ProviderConfig, SecretVault } from '@wrongstack/core/types';\nimport { atomicWrite, color } from '@wrongstack/core/utils';\nimport { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';\n/**\n * Normalize a ProviderConfig to the canonical `apiKeys[]` form.\n * Migrates the legacy single-key `apiKey` field on the fly so every\n * consumer sees a uniform shape. Does NOT mutate the input.\n */\nexport function normalizeKeys(cfg: ProviderConfig): ProviderApiKey[] {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n return cfg.apiKeys.map((k) => ({ ...k }));\n }\n if (typeof cfg.apiKey === 'string' && cfg.apiKey.length > 0) {\n return [{ label: 'default', apiKey: cfg.apiKey, createdAt: '' }];\n }\n return [];\n}\n\n/**\n * Write a normalized key list back into a ProviderConfig. Does NOT mirror\n * the plaintext key to the legacy `apiKey` field \u2014 that would leak the\n * secret on any accidental JSON.stringify of the config. Consumers that\n * need the real key must call {@link resolveActiveApiKey}.\n */\nexport function writeKeysBack(cfg: ProviderConfig, keys: ProviderApiKey[]): void {\n if (keys.length === 0) {\n delete cfg.apiKeys;\n delete cfg.apiKey;\n delete cfg.activeKey;\n return;\n }\n cfg.apiKeys = keys;\n const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);\n // Do NOT mirror plaintext to cfg.apiKey \u2014 the legacy field is cleared so\n // that accidental serialization (logging, error messages, WS payloads)\n // cannot leak the active key. Use resolveActiveApiKey() to read the real key.\n delete cfg.apiKey;\n if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {\n cfg.activeKey = active.label;\n }\n}\n\n/**\n * Extract the active (decrypted) API key from a ProviderConfig.\n *\n * Resolution order:\n * 1. `apiKeys[]` \u2014 pick the entry matching `activeKey`, or the first one\n * 2. Legacy `apiKey` field \u2014 only for configs not yet migrated to multi-key\n *\n * This is the **preferred** way to read the API key. Never read `cfg.apiKey`\n * directly in new code \u2014 after {@link writeKeysBack} it is cleared, and even\n * when present on a freshly-loaded config it may contain a masked value.\n */\nexport function resolveActiveApiKey(cfg: ProviderConfig): string | undefined {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n const active = cfg.activeKey\n ? cfg.apiKeys.find((k) => k.label === cfg.activeKey)\n : undefined;\n return (active ?? cfg.apiKeys[0])?.apiKey;\n }\n return cfg.apiKey && cfg.apiKey.length > 0 ? cfg.apiKey : undefined;\n}\n\nfunction isLoopbackBaseUrl(baseUrl: string | undefined): boolean {\n if (!baseUrl) return false;\n try {\n let host = new URL(baseUrl).hostname.toLowerCase();\n host = host.replace(/^\\[|\\]$/g, '');\n return host === 'localhost' || host === '::1' || host === '0.0.0.0' || /^127\\./.test(host);\n } catch {\n return false;\n }\n}\n\nfunction providerCanRunWithoutSavedKey(cfg: ProviderConfig): boolean {\n return isLoopbackBaseUrl(cfg.baseUrl) && (!cfg.envVars || cfg.envVars.length === 0);\n}\n\nfunction hasUsableSavedProvider(cfg: ProviderConfig): boolean {\n return resolveActiveApiKey(cfg) !== undefined || providerCanRunWithoutSavedKey(cfg);\n}\n\n/**\n * Clear top-level provider/model defaults when provider mutations make them\n * stale. This prevents a removed provider, deleted final key, or edited model\n * allowlist from being accepted on the next boot and crashing provider setup.\n */\nexport function clearStaleProviderDefaults(config: Record<string, unknown>): void {\n const providerId = typeof config['provider'] === 'string' ? config['provider'] : undefined;\n if (!providerId) return;\n const providers = config['providers'] as Record<string, ProviderConfig> | undefined;\n const provider = providers?.[providerId];\n if (!provider || !hasUsableSavedProvider(provider)) {\n delete config['provider'];\n delete config['model'];\n return;\n }\n const modelId = typeof config['model'] === 'string' ? config['model'] : undefined;\n if (modelId && Array.isArray(provider.models) && provider.models.length > 0 && !provider.models.includes(modelId)) {\n delete config['model'];\n }\n}\n\n/**\n * Return the label of the active key, or the first key's label if no\n * active is pinned. Returns `undefined` when there are no keys at all.\n */\nexport function activeLabel(cfg: ProviderConfig, keys: ProviderApiKey[]): string | undefined {\n if (cfg.activeKey && keys.some((k) => k.label === cfg.activeKey)) return cfg.activeKey;\n return keys[0]?.label;\n}\n\n/** Mask an API key for display: show first 4 + last 4 chars. */\nexport function maskedKey(key: string): string {\n if (!key) return color.dim('\u2014');\n if (key.length <= 8) return color.dim('\u2022'.repeat(key.length));\n const head = key.slice(0, 4);\n const tail = key.slice(-4);\n return `${color.dim(head + '\u2026')}${tail}`;\n}\n\n/** ISO-8601 timestamp for key `createdAt` fields. */\nexport function nowIso(): string {\n return new Date().toISOString();\n}\n\n/* ------------------------------------------------------------------ */\n/* Config file I/O \u2014 load / mutate `providers` atomically */\n/* ------------------------------------------------------------------ */\n\n/**\n * Read the on-disk config file and return its `providers` map, fully\n * decrypted. Returns `{}` on ENOENT or corrupt JSON (surfacing the error\n * via the optional `warn` callback when provided).\n */\nexport async function loadConfigProviders(\n configPath: string,\n vault: SecretVault,\n opts?: { warn?: (msg: string) => void; profileConfigPath?: string },\n): Promise<Record<string, ProviderConfig>> {\n const warn = opts?.warn;\n const targetPath = opts?.profileConfigPath ?? configPath;\n let raw: string;\n try {\n raw = await fs.readFile(targetPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n warn?.(`Could not read ${targetPath}: ${(err as Error).message}. Treating as empty.`);\n }\n return {};\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n warn?.(`Config at ${targetPath} is not valid JSON: ${(err as Error).message}`);\n return {};\n }\n const decrypted = decryptConfigSecrets(parsed, vault);\n return (decrypted as { providers?: Record<string, ProviderConfig> }).providers ?? {};\n}\n\n/**\n * Load \u2192 mutate \u2192 encrypt \u2192 atomic-write. Operates on the FULL config file\n * so non-provider keys are preserved. Refuses to overwrite a corrupt-but-\n * existing config (the user may still have salvageable data).\n */\nexport async function mutateConfigProviders(\n configPath: string,\n vault: SecretVault,\n mutator: (providers: Record<string, ProviderConfig>) => void,\n profileConfigPath?: string,\n): Promise<void> {\n const targetPath = profileConfigPath ?? configPath;\n let raw: string;\n let fileExists = true;\n try {\n raw = await fs.readFile(targetPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new FsError({\n message: `Refusing to mutate ${configPath}: ${(err as Error).message}`,\n code: 'FS_READ_FAILED',\n path: targetPath,\n context: { operation: 'mutateConfigProviders', phase: 'read' },\n cause: err,\n });\n }\n fileExists = false;\n raw = '{}';\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n if (fileExists) {\n throw new FsError({\n message:\n `Refusing to overwrite corrupt config at ${targetPath} ` +\n `(${(err as Error).message}). Fix or move the file aside before retrying.`,\n code: 'FS_READ_FAILED',\n path: targetPath,\n context: { operation: 'mutateConfigProviders', phase: 'parse' },\n cause: err,\n });\n }\n parsed = {};\n }\n const decrypted = decryptConfigSecrets(parsed, vault) as Record<string, unknown>;\n const providers = (decrypted.providers as Record<string, ProviderConfig>) ?? {};\n mutator(providers);\n decrypted.providers = providers;\n clearStaleProviderDefaults(decrypted);\n const encrypted = encryptConfigSecrets(decrypted, vault);\n await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/hq-server/audit-actor.ts"],
|
|
4
|
-
"sourcesContent": ["import * as os from 'node:os';\n\n/** Build the non-secret actor label used by HQ authentication audit entries. */\nexport function resolveAuditActor(): string {\n const user = (process.env.USERNAME ?? process.env.USER ?? '').toString();\n try {\n const host = os.hostname();\n return user ? `${user}@${host}` : `cli@${host}`;\n } catch {\n return user ? `${user}@unknown` : 'cli';\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;AAAA,YAAY,QAAQ;AAGb,SAAS,oBAA4B;AAC1C,QAAM,QAAQ,QAAQ,IAAI,YAAY,QAAQ,IAAI,QAAQ,IAAI,SAAS;AACvE,MAAI;AACF,UAAM,OAAU,YAAS;AACzB,WAAO,OAAO,GAAG,IAAI,IAAI,IAAI,KAAK,OAAO,IAAI;AAAA,EAC/C,QAAQ;AACN,WAAO,OAAO,GAAG,IAAI,aAAa;AAAA,EACpC;AACF;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/theme.ts"],
|
|
4
|
-
"sourcesContent": ["import { color } from '@wrongstack/core/utils';\n\nexport const theme = {\n primary: color.amber,\n accent: color.pink,\n muted: color.dim,\n success: color.green,\n warn: color.yellow,\n error: color.red,\n info: color.cyan,\n bold: color.bold,\n underline: color.underline,\n};\n"],
|
|
5
|
-
"mappings": ";;;AAAA,SAAS,aAAa;AAEf,IAAM,QAAQ;AAAA,EACnB,SAAS,MAAM;AAAA,EACf,QAAQ,MAAM;AAAA,EACd,OAAO,MAAM;AAAA,EACb,SAAS,MAAM;AAAA,EACf,MAAM,MAAM;AAAA,EACZ,OAAO,MAAM;AAAA,EACb,MAAM,MAAM;AAAA,EACZ,MAAM,MAAM;AAAA,EACZ,WAAW,MAAM;AACnB;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/wiring/plugins.ts", "../src/plugin-api-factory.ts"],
|
|
4
|
-
"sourcesContent": ["import { join } from 'node:path';\nimport type { AgentPipelines } from '@wrongstack/core/agent';\nimport type { Config, HealthRegistry, Logger, MetricsRuntimeStatus, MetricsSinkView, ModelsRegistry, Plugin, PromptLoader, SkillLoader } from '@wrongstack/core/types';\nimport type { ExtensionRegistry } from '@wrongstack/core/extension';\nimport type { PluginHostHandle } from '@wrongstack/core/plugin';\nimport type { ConfigStore, SessionWriter } from '@wrongstack/core/types';\nimport type { Container, EventBus } from '@wrongstack/core/kernel';\nimport type { ProviderRegistry, SlashCommandRegistry, ToolRegistry } from '@wrongstack/core/registry';\nimport { loadPlugins, resolvePluginConfig } from '@wrongstack/core/plugin';\nimport type { MCPRegistry } from '@wrongstack/mcp';\nimport { OFFICIAL_PLUGIN_FACTORIES } from '@wrongstack/plugins/factories';\nimport createApi from '../plugin-api-factory.js';\nimport { PLUGIN_AUDIT_ENTRIES } from '../plugin-management.js';\nimport { patchConfig } from '../utils.js';\n\n// ---------------------------------------------------------------------------\n// Deprecated plugin names \u2014 built-ins that have been merged into core\n// tools and no longer ship as separate plugins. We no longer auto-import\n// these factories, and if a user references one of these names in their\n// `config.plugins` we warn once and skip. Removal is split into two\n// phases:\n// 1. Remove the factory from BUILTIN_PLUGIN_FACTORIES (today).\n// 2. Drop the source files + subpath exports + tests from\n// @wrongstack/plugins in a follow-up commit.\n// Keeping the source files temporarily (phase 2) means user configs\n// that hard-code `@wrongstack/plugins/web-search` as a string spec\n// still resolve at runtime \u2014 the loader receives a no-op stub plugin\n// instead of an import error. Once the user removes the entry from\n// their config, the source can be safely deleted.\n// ---------------------------------------------------------------------------\nexport const DEPRECATED_PLUGIN_NAMES: Record<string, string> = {\n 'web-search': 'use the built-in `search` and `fetch` tools',\n 'json-path': 'use the built-in `json` tool with action: query | validate | transform | merge',\n};\n\n// Per-process dedupe so we don't spam the log if a user lists the\n// same deprecated name across multiple config entries (object form\n// + string form, etc.). Cleared on process restart by design \u2014\n// startup noise is fine, mid-session noise is not.\nconst deprecatedWarningsEmitted = new Set<string>();\n\nconst BUILTIN_PLUGIN_CONFIG_ALIASES: Record<string, string> = {\n lsp: '@wrongstack/plug-lsp',\n '@wrongstack/telegram': 'telegram',\n};\n\nexport const BUILTIN_PLUGIN_CONFIG_NAMES = new Set<string>([\n ...PLUGIN_AUDIT_ENTRIES.map((entry) => entry.name),\n ...PLUGIN_AUDIT_ENTRIES.map((entry) => `@wrongstack/plugins/${entry.name}`),\n ...Object.keys(BUILTIN_PLUGIN_CONFIG_ALIASES),\n]);\n\n/** Test helper: reset the dedupe set between test cases. */\nexport function _resetDeprecatedWarningsForTests(): void {\n deprecatedWarningsEmitted.clear();\n}\n\n/**\n * If `name` is in `DEPRECATED_PLUGIN_NAMES`, log a one-shot `warn`\n * describing the migration target and return true (caller should\n * skip the plugin). If the name is deprecated but already warned\n * about, return true WITHOUT logging again \u2014 the caller still needs\n * to know to skip the plugin. For unknown names, return false.\n */\nexport function warnIfDeprecatedPluginName(name: string, log: Logger): boolean {\n const replacement = DEPRECATED_PLUGIN_NAMES[name];\n if (!replacement) return false;\n if (deprecatedWarningsEmitted.has(name)) return true;\n deprecatedWarningsEmitted.add(name);\n log.warn(`[setupPlugins] plugin \"${name}\" is deprecated and no longer loaded \u2014 ${replacement}`);\n return true;\n}\n\n/**\n * Normalize a plugin spec (either a short name like `'web-search'` or a\n * fully-qualified import path like `'@wrongstack/plugins/web-search'`)\n * to its bare plugin name. Used to look the spec up in\n * `DEPRECATED_PLUGIN_NAMES` regardless of how the user spelled it.\n *\n * Returns null if the spec is not a string we can normalize (e.g.\n * relative paths, file URLs).\n */\nexport function pluginNameFromSpec(spec: string): string | null {\n if (spec.startsWith('.') || spec.startsWith('/') || spec.startsWith('file:')) {\n return null;\n }\n // `@scope/name/sub` \u2192 'name'; `@scope/name` \u2192 'name'; `name/sub` \u2192 'name'.\n const parts = spec.split('/');\n const last = parts[parts.length - 1];\n if (!last) return null;\n return last.split('?')[0] ?? null;\n}\n\nexport function builtinPluginNameFromSpec(spec: string): string | null {\n if (BUILTIN_PLUGIN_CONFIG_ALIASES[spec]) return BUILTIN_PLUGIN_CONFIG_ALIASES[spec];\n const bareName = pluginNameFromSpec(spec);\n if (BUILTIN_PLUGIN_CONFIG_NAMES.has(spec)) return bareName ?? spec;\n if (bareName && BUILTIN_PLUGIN_CONFIG_NAMES.has(bareName)) return bareName;\n return null;\n}\n\nexport interface PluginsWiringDeps {\n config: Config;\n container: Container;\n events: EventBus;\n pipelines: AgentPipelines;\n toolRegistry: ToolRegistry;\n providerRegistry: ProviderRegistry;\n slashCommandRegistry: SlashCommandRegistry;\n mcpRegistry: MCPRegistry;\n log: Logger;\n agent: { extensions?: ExtensionRegistry | undefined };\n /** Lifecycle hook registry \u2014 injected so plugins can register in-process hooks. */\n hookRegistry?: import('@wrongstack/core/hooks').HookRegistry | undefined;\n sessionWriter: SessionWriter;\n metricsSink?: MetricsSinkView | undefined;\n metricsStatus?: MetricsRuntimeStatus | undefined;\n /**\n * Models registry (models.dev-backed catalog of providers, models, and\n * per-token pricing). Forwarded to plugins that need model metadata\n * (cost-tracker, billing reports). Optional \u2014 minimal hosts may omit.\n */\n modelsRegistry?: ModelsRegistry | undefined;\n /**\n * Project-level mailbox (server-backed). Forwarded to plugins that\n * publish to other agents (todo-listener, session-recap). Optional \u2014\n * minimal hosts (tests, the LSP server) may omit.\n */\n mailbox?: import('@wrongstack/core/coordination').Mailbox | undefined;\n /**\n * Notification router \u2014 instantiated as a `NotifierImpl` by the host.\n * Plugins that deliver one-way notifications (Telegram, Slack, webhook)\n * register their `NotificationChannel` with this notifier during setup().\n * Optional \u2014 minimal hosts may omit.\n */\n notifier?: import('@wrongstack/core/notifications').Notifier | undefined;\n /**\n * LLM wiring for `api.llm` \u2014 the host session's live provider, its\n * default model, and a factory for named-provider overrides. Optional \u2014\n * minimal hosts omit it and plugins see `api.llm === undefined`.\n */\n llm?:\n | {\n provider: import('@wrongstack/core/types').Provider;\n model: string;\n getProvider?: (() => import('@wrongstack/core/types').Provider) | undefined;\n getModel?: (() => string) | undefined;\n createProvider?:\n | ((name: string, model?: string) => import('@wrongstack/core/types').Provider)\n | undefined;\n }\n | undefined;\n /** Health registry \u2014 injected so the observability built-in can run /health. */\n healthRegistry?: HealthRegistry | undefined;\n /** Skill loader \u2014 injected so the skills built-in can list/read skills. */\n skillLoader?: SkillLoader | undefined;\n /** Prompt loader \u2014 injected so the prompts built-in can list/search/save prompts. */\n promptLoader?: PromptLoader | undefined;\n configStore: ConfigStore;\n /** Secret vault \u2014 injected so sync plugin can encrypt the GitHub token. */\n vault?: { encrypt(plaintext: string): string; decrypt?(value: string): string };\n /** Resolved WstackPaths \u2014 injected so built-in plugins can init stores. */\n paths?: {\n globalRoot: string;\n globalConfig: string;\n globalSkills: string;\n globalPrompts: string;\n globalMemory: string;\n historyFile: string;\n syncConfig: string;\n /** ~/.wrongstack/profiles/<activeProfile> \u2014 used by sync plugin for its state path. */\n configDir: string;\n /**\n * Per-project root (`~/.wrongstack/projects/<slug>/`). Plugins that\n * need project-scoped state (todo-tracker, etc.) should put their\n * files here so they follow the same lifecycle as goals/SDD\n * boards/tasks.\n */\n projectDir?: string;\n /** Per-project goal.json path. Useful as a sibling anchor. */\n projectGoal?: string;\n };\n}\n\n/**\n * Built-in plugins loaded automatically for every WrongStack session.\n * Lazy (dynamic import) so they don't bloat consumers who never use them.\n *\n * Disable a built-in by adding `{ name: 'wstack-prompts', enabled: false }`\n * to config.plugins.\n *\n * Override for tests by mocking this module's `BUILTIN_PLUGIN_FACTORIES`.\n */\nexport const BUILTIN_PLUGIN_FACTORIES: (() => Promise<Plugin>)[] = [\n async () => {\n const { createPromptsPlugin } = await import('@wrongstack/core/plugin');\n return createPromptsPlugin();\n },\n async () => {\n const { createSyncPlugin } = await import('@wrongstack/core/plugin');\n return createSyncPlugin();\n },\n async () => {\n const { createChimeraPlugin } = await import('@wrongstack/core/plugin');\n return createChimeraPlugin();\n },\n async () => {\n const { createAutoReviewPlugin } = await import('@wrongstack/core/plugin');\n return createAutoReviewPlugin();\n },\n async () => {\n const { createSkillsPlugin } = await import('@wrongstack/core/plugin');\n return createSkillsPlugin();\n },\n // \u2500\u2500 Workspace plugins (@wrongstack/plugins subpath exports) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n ...OFFICIAL_PLUGIN_FACTORIES,\n // \u2500\u2500 LSP plugin \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async () => (await import('@wrongstack/plug-lsp')).default,\n // \u2500\u2500 Telegram plugin \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n async () => (await import('@wrongstack/telegram')).default,\n];\n\nexport async function setupPlugins(\n params: PluginsWiringDeps,\n): Promise<PluginHostHandle | undefined> {\n const {\n config,\n container,\n events,\n toolRegistry,\n providerRegistry,\n slashCommandRegistry,\n mcpRegistry,\n log,\n agent,\n sessionWriter,\n metricsSink,\n metricsStatus,\n modelsRegistry,\n mailbox,\n healthRegistry,\n skillLoader,\n promptLoader,\n configStore,\n vault,\n pipelines,\n paths,\n hookRegistry,\n } = params;\n\n // \u2500\u2500 1. Load built-in plugins (prompts, sync, git, \u2026) only when paths are\n // available \u2014 they need WstackPaths to initialise their stores.\n //\n // Built-ins are ENABLED BY DEFAULT. A user can opt a specific one out by\n // adding `{ name: 'wstack-git', enabled: false }` to `config.plugins`\n // (or disable all plugins with `config.features.plugins === false`).\n const builtinPlugins: Plugin[] = [];\n const disabledBuiltins = new Set(\n (config.plugins ?? [])\n .filter(\n (p): p is { name: string; enabled?: boolean | undefined } =>\n typeof p === 'object' && p.enabled === false,\n )\n .flatMap((p) => {\n const builtinName = builtinPluginNameFromSpec(p.name);\n return builtinName && builtinName !== p.name ? [p.name, builtinName] : [p.name];\n }),\n );\n if (paths && config.features?.plugins !== false) {\n for (const factory of BUILTIN_PLUGIN_FACTORIES) {\n try {\n const plugin = await factory();\n if (!plugin) continue;\n const auditEntry = PLUGIN_AUDIT_ENTRIES.find((entry) => entry.name === plugin.name);\n const explicitlyEnabled = (config.plugins ?? []).some((entry) => {\n const spec = typeof entry === 'string' ? entry : entry.name;\n if (typeof entry === 'object' && entry.enabled === false) return false;\n return (builtinPluginNameFromSpec(spec) ?? spec) === plugin.name;\n });\n if (auditEntry?.defaultState === 'inactive' && !explicitlyEnabled) {\n continue;\n }\n if (disabledBuiltins.has(plugin.name)) {\n log.info(`[setupPlugins] built-in plugin \"${plugin.name}\" disabled by config`);\n continue;\n }\n // Defensive: if a future PR leaves a deprecated factory in\n // BUILTIN_PLUGIN_FACTORIES, the loader-level deprecation policy\n // still skips it (and warns once per name). Today this branch\n // is unreachable because we removed those factories \u2014 but the\n // check stays so a sloppy re-add doesn't silently re-enable a\n // retired plugin.\n if (warnIfDeprecatedPluginName(plugin.name, log)) continue;\n builtinPlugins.push(plugin);\n } catch (err) {\n log.warn('[setupPlugins] builtin plugin failed to load:', err);\n }\n }\n }\n\n // \u2500\u2500 2. Load user plugins from config.plugins \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const userPlugins: Plugin[] = [];\n if (config.features?.plugins !== false) {\n for (const p of config.plugins ?? []) {\n if (typeof p === 'object' && p.enabled === false) continue;\n const spec = typeof p === 'string' ? p : p.name;\n // Deprecation policy: if the spec resolves to a deprecated plugin\n // name (either as `'web-search'` or `'@wrongstack/plugins/web-search'`),\n // warn once and skip the dynamic import. Today this means\n // web-search/json-path stub plugins silently load \u2014 after the\n // source files are deleted (phase 2), this branch becomes the\n // only line of defense.\n const bareName = pluginNameFromSpec(spec);\n if (bareName && warnIfDeprecatedPluginName(bareName, log)) {\n continue;\n }\n if (builtinPluginNameFromSpec(spec)) {\n continue;\n }\n try {\n const mod = (await import(spec)) as { default?: Plugin | undefined };\n if (mod.default) userPlugins.push(mod.default);\n } catch (err) {\n log.warn(`Plugin \"${spec}\" failed to load`, err);\n }\n }\n }\n\n // \u2500\u2500 3. Merge: builtins first (they set up infrastructure), then user plugins\n const allPlugins = [...builtinPlugins, ...userPlugins];\n if (allPlugins.length === 0) return;\n\n const pluginOptions = buildPluginOptions(config, allPlugins);\n\n // Workspace plugins that persist project-scoped state read ONLY their own\n // namespaced `config.extensions[name]` options \u2014 they never see the\n // top-level `paths` injected below. Bridge that gap for todo-tracker by\n // seeding a default `filePath` derived from `paths.projectDir` when the\n // user hasn't set one explicitly. This mirrors how goals/SDD boards/tasks\n // live under `~/.wrongstack/projects/<slug>/` and follows the intent\n // documented on `PluginsWiringDeps.paths.projectDir`.\n if (paths?.projectDir) {\n if (pluginOptions['todo-tracker'] === undefined) {\n pluginOptions['todo-tracker'] = {};\n }\n const todoTrackerOpts = pluginOptions['todo-tracker'];\n if (typeof todoTrackerOpts['filePath'] !== 'string' || todoTrackerOpts['filePath'] === '') {\n todoTrackerOpts['filePath'] = join(paths.projectDir, 'todo-tracker.json');\n }\n // context-pins persists pinned facts the same way \u2014 project-scoped,\n // next to goals/SDD boards/todo-tracker.\n const contextPinsOpts = pluginOptions['context-pins'] ?? {};\n pluginOptions['context-pins'] = contextPinsOpts;\n if (typeof contextPinsOpts['filePath'] !== 'string' || contextPinsOpts['filePath'] === '') {\n contextPinsOpts['filePath'] = join(paths.projectDir, 'context-pins.json');\n }\n }\n\n // Built-in plugins read their host dependencies off the TOP LEVEL of the\n // config object they receive (e.g. prompts/sync use `config.paths` /\n // `config.configStore`, observability uses `config.metricsSink` /\n // `config.healthRegistry`). Inject them here so each can wire up its store or\n // view without a circular import. User plugins never see these \u2014 they only\n // read their own namespaced `config.extensions[name]` options.\n const pluginConfig = patchConfig(config, {\n extensions: pluginOptions,\n paths,\n configStore,\n vault,\n metricsSink,\n metricsStatus,\n healthRegistry,\n skillLoader,\n promptLoader,\n } as Partial<Config>);\n\n const pluginHost = await loadPlugins(allPlugins, {\n log,\n pluginOptions,\n apiFactory: (plugin) =>\n createApi(plugin.name, {\n // First-party plugins come from BUILTIN_PLUGIN_FACTORIES \u2014 trust them\n // (\"official\") so they can claim bare slash command names (/prompts,\n // /sync) and override built-ins. User plugins stay namespaced.\n official: builtinPlugins.includes(plugin),\n container,\n events,\n pipelines: pipelines as never as Parameters<typeof createApi>[1]['pipelines'],\n toolRegistry,\n providerRegistry,\n slashCommandRegistry,\n mcpRegistry,\n config: pluginConfig,\n log,\n extensions: agent.extensions,\n hookRegistry,\n modelsRegistry,\n mailbox,\n notifier: params.notifier,\n llm: params.llm,\n sessionWriter: {\n transcriptPath: sessionWriter.transcriptPath,\n append: (e: Record<string, unknown> & { type: string; ts: string }) =>\n sessionWriter.append(e as Parameters<typeof sessionWriter.append>[0]),\n },\n metricsSink,\n configStore,\n }),\n });\n\n log.info(\n `[setupPlugins] loaded ${builtinPlugins.length} built-in, ${userPlugins.length} user plugin(s)`,\n );\n return pluginHost;\n}\n\nfunction buildPluginOptions(\n config: Config,\n plugins: readonly Plugin[],\n): Record<string, Record<string, unknown>> {\n const options: Record<string, Record<string, unknown>> = {};\n for (const [name, value] of Object.entries(config.extensions ?? {})) {\n options[name] = { ...value };\n }\n for (const plugin of plugins) {\n const resolved = resolvePluginConfig({\n name: plugin.name,\n aliases: plugin.configAliases,\n config,\n });\n if (resolved.configured) options[plugin.name] = resolved.options;\n }\n return options;\n}\n", "import { DefaultPluginAPI, type PluginAPI, type PluginAPIInit } from '@wrongstack/core/plugin';\n\nexport default function createApi(\n ownerName: string,\n base: Omit<PluginAPIInit, 'ownerName'>,\n): PluginAPI {\n return new DefaultPluginAPI({ ownerName, ...base });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/auth-menu/openai-codex-oauth.ts", "../src/auth-menu/loopback-server.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * OpenAI Codex \u2014 \"Sign in with ChatGPT\" OAuth (Authorization Code + PKCE).\n *\n * This is the ONLY login flow that actually works for using a ChatGPT\n * Plus/Pro/Team subscription programmatically. It mirrors the real Codex CLI:\n *\n * 1. Generate a PKCE verifier/challenge (S256) + CSRF state.\n * 2. Start a loopback HTTP server on http://localhost:1455/auth/callback.\n * 3. Open the browser to https://auth.openai.com/oauth/authorize.\n * 4. The browser redirects back to the loopback with `?code=...&state=...`.\n * 5. Exchange the code at https://auth.openai.com/oauth/token for an\n * access_token + refresh_token (and an id_token carrying the account id).\n * 6. Store the tokens in the vault as an `oauth` ProviderApiKey.\n *\n * The resulting access token is a JWT whose `https://api.openai.com/auth`\n * claim contains `chatgpt_account_id`. Requests then go to the ChatGPT\n * backend (`chatgpt.com/backend-api/codex/responses`) \u2014 NOT api.openai.com \u2014\n * which is what the `openai-codex` wire family handles. The standard\n * API-key flow (`family: openai` \u2192 api.openai.com/chat/completions) is left\n * completely untouched.\n *\n * NOTE: a ChatGPT web *session cookie* is NOT an API token. The old\n * device-code + cookie-scraping attempts could never produce a usable\n * credential; this module replaces them.\n */\n\nimport { createHash, randomBytes } from 'node:crypto';\nimport {\n type LoopbackServer,\n openBrowser,\n startLoopbackServer as startSharedLoopbackServer,\n} from './loopback-server.js';\nimport { CODEX_MODELS } from '@wrongstack/core/models';\nimport { color } from '@wrongstack/core/utils';\nimport { FetchError, ParseError, type ModelsRegistry, type ProviderApiKey, type ProviderConfig } from '@wrongstack/core/types';\nimport {\n mutateConfigProviders,\n normalizeKeys,\n nowIso,\n writeKeysBack,\n} from '../provider-config-utils.js';\nimport type { AuthMenuDeps } from './types.js';\n\n// \u2500\u2500 Codex OAuth constants (verified against the real Codex CLI) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';\nconst AUTH_BASE_URL = 'https://auth.openai.com';\nconst AUTHORIZE_URL = `${AUTH_BASE_URL}/oauth/authorize`;\nconst TOKEN_URL = `${AUTH_BASE_URL}/oauth/token`;\nconst REDIRECT_PORT = 1455;\nconst FALLBACK_REDIRECT_PORT = 1457;\nconst REDIRECT_HOST = '127.0.0.1';\nconst REDIRECT_PATH = '/auth/callback';\nconst SCOPE = 'openid profile email offline_access api.connectors.read api.connectors.invoke';\n/** JWT claim that carries the ChatGPT account id. */\nconst JWT_CLAIM_PATH = 'https://api.openai.com/auth';\n/** Telemetry/branding tag sent to authorize + as a request header. Free-form. */\nconst ORIGINATOR = 'wrongstack';\n/** Canonical provider id under which ChatGPT-login credentials are stored. */\nexport const CODEX_PROVIDER_ID = 'openai-codex';\n/** Default ChatGPT backend base. The wire family appends `/codex/responses`. */\nexport const CODEX_BASE_URL = 'https://chatgpt.com/backend-api';\n\n/**\n * Codex-specific compatibility wrapper retained for callers that imported the\n * helper from this module before the shared OAuth loopback server extraction.\n */\nexport function startLoopbackServer(\n expectedState: string,\n signal?: AbortSignal,\n): Promise<LoopbackServer> {\n return startSharedLoopbackServer(\n expectedState,\n [REDIRECT_PORT, FALLBACK_REDIRECT_PORT],\n signal,\n REDIRECT_PATH,\n REDIRECT_HOST,\n );\n}\n\n/**\n * Fallback model list used when BOTH the live backend AND the models.dev\n * catalog are unreachable. This should never happen in practice \u2014 the\n * catalog is cached locally and the only scenario where both fail is a\n * fresh install with no network on first login.\n *\n * The primary resolution order in `resolveCodexModels()` is:\n * 1. Live backend (`GET /models`)\n * 2. models.dev catalog (`family: gpt-codex*` under `openai` provider)\n * 3. This inline fallback\n */\n// \u2500\u2500 Token shapes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface CodexTokens {\n access: string;\n refresh: string;\n /** Absolute expiry in epoch milliseconds. */\n expires: number;\n idToken?: string | undefined;\n}\n\ninterface TokenEndpointResponse {\n access_token?: string;\n refresh_token?: string;\n expires_in?: number;\n id_token?: string;\n}\n\n// \u2500\u2500 PKCE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction base64url(buf: Buffer): string {\n return buf.toString('base64').replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nexport interface Pkce {\n verifier: string;\n challenge: string;\n}\n\n/** Generate a PKCE verifier + S256 challenge. */\nexport function generatePkce(): Pkce {\n const verifier = base64url(randomBytes(64));\n const challenge = base64url(createHash('sha256').update(verifier).digest());\n return { verifier, challenge };\n}\n\nfunction createState(): string {\n return base64url(randomBytes(32));\n}\n\nfunction redirectUri(port: number): string {\n return `http://localhost:${port}${REDIRECT_PATH}`;\n}\n\n/** Build the full authorize URL with all Codex-required query params. */\nexport function buildAuthorizeUrl(challenge: string, state: string, port = REDIRECT_PORT): string {\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set('response_type', 'code');\n url.searchParams.set('client_id', CLIENT_ID);\n url.searchParams.set('redirect_uri', redirectUri(port));\n url.searchParams.set('scope', SCOPE);\n url.searchParams.set('code_challenge', challenge);\n url.searchParams.set('code_challenge_method', 'S256');\n url.searchParams.set('state', state);\n url.searchParams.set('id_token_add_organizations', 'true');\n url.searchParams.set('codex_cli_simplified_flow', 'true');\n url.searchParams.set('originator', ORIGINATOR);\n return url.toString();\n}\n\n// \u2500\u2500 JWT account-id extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface JwtAuthClaim {\n chatgpt_account_id?: string;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n const json = Buffer.from(parts[1]!, 'base64url').toString('utf8');\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract `chatgpt_account_id` from an access/id token JWT. Returns null when\n * the token isn't a JWT or lacks the claim (the caller decides whether that\n * is fatal \u2014 for login it is; for a cached display value it isn't).\n */\nexport function extractAccountId(token: string): string | null {\n const payload = decodeJwtPayload(token);\n const auth = payload?.[JWT_CLAIM_PATH] as JwtAuthClaim | undefined;\n const id = auth?.chatgpt_account_id;\n return typeof id === 'string' && id.length > 0 ? id : null;\n}\n\n// \u2500\u2500 Model discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Recommended Codex models for ChatGPT sign-in. Live backend discovery\n * wins; these values are only used when the backend/catalog cannot\n * provide a list. Derived from `CODEX_MODELS` in core (the single source of\n * truth for Codex id/name/description) \u2014 used both by OAuth login\n * (resolveCodexModels \u2192 tier 3) and by the provider-boot synthesis\n * path (wiring/provider.ts when the catalog is unavailable).\n */\nexport const FALLBACK_CODEX_MODELS: ReadonlyArray<{ id: string; name: string }> = CODEX_MODELS.map(\n (m) => ({ id: m.id, name: m.name }),\n);\n\n/** Families in the models.dev catalog that indicate Codex / Responses API compatibility. */\nexport const CODEX_CATALOG_FAMILIES = new Set(['gpt-codex', 'gpt-codex-spark']);\n\nexport function fallbackCodexModelIds(): string[] {\n return FALLBACK_CODEX_MODELS.map((m) => m.id);\n}\n\nexport function fallbackCodexProviderModels(): Array<{ id: string; name: string }> {\n return FALLBACK_CODEX_MODELS.map((m) => ({ id: m.id, name: m.name }));\n}\n\n/**\n * Filter a list of available model ids down to the ones that are still\n * current for ChatGPT sign-in (i.e. present in FALLBACK_CODEX_MODELS).\n * Used by both OAuth login (to drop deprecated ids from the live /models\n * response) and by the provider-boot synthesis (to pick current ids out\n * of the models.dev catalog).\n */\nexport function filterCurrentCodexModelIds(ids: Iterable<string>): string[] {\n const available = new Set(ids);\n return FALLBACK_CODEX_MODELS.map((m) => m.id).filter((id) => available.has(id));\n}\n\nexport function isCodexCatalogModel(model: { family?: string | undefined }): boolean {\n return typeof model.family === 'string' && CODEX_CATALOG_FAMILIES.has(model.family);\n}\n\n/**\n * Resolve the list of available Codex models using a 3-tier fallback chain:\n *\n * 1. **Live backend** \u2014 `fetchCodexModels()` hits `GET <baseUrl>/models`\n * and keeps only current Codex model ids.\n * 2. **models.dev catalog** \u2014 queries the `openai` provider in the cached\n * models.dev registry and picks models whose `family` is `gpt-codex` or\n * `gpt-codex-spark` and whose ids are current for ChatGPT sign-in.\n * 3. **Inline fallback** \u2014 a minimal list of documented mainstream models\n * (`gpt-5.6-sol`, `gpt-5.5`, `gpt-5.6-terra`, `gpt-5.6-luna`,\n * `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.3-codex-spark`).\n *\n * The live/catalog tiers gate account availability, while the shared current\n * model list filters out deprecated ChatGPT sign-in ids before config is saved.\n */\nexport async function resolveCodexModels(\n modelsRegistry: ModelsRegistry,\n accessToken: Promise<string> | string,\n baseUrl?: string | undefined,\n signal?: AbortSignal,\n): Promise<string[]> {\n // Tier 1 \u2014 live backend\n const token = typeof accessToken === 'string' ? accessToken : await accessToken;\n const live = filterCurrentCodexModelIds(await fetchCodexModels(token, baseUrl, signal));\n if (live.length > 0) return live;\n\n // Tier 2 \u2014 models.dev catalog\n try {\n const openaiProvider = await modelsRegistry.getProvider('openai');\n if (openaiProvider) {\n const catalog = openaiProvider.models\n .filter(isCodexCatalogModel)\n .map((m) => m.id)\n .filter((id): id is string => typeof id === 'string' && id.length > 0);\n const currentCatalog = filterCurrentCodexModelIds(catalog);\n if (currentCatalog.length > 0) return currentCatalog;\n }\n } catch {\n // catalog unavailable \u2014 fall through to tier 3\n }\n\n // Tier 3 \u2014 inline fallback\n return fallbackCodexModelIds();\n}\n\n/**\n * Fetch the account's available Codex model ids live from the ChatGPT backend.\n *\n * Hits `GET <baseUrl>/models` \u2014 the standard OpenAI-compatible model listing\n * endpoint, which the Codex backend may expose. Best-effort: returns an empty\n * array on any failure so login still succeeds with the hardcoded fallback.\n */\nexport async function fetchCodexModels(\n accessToken: string,\n baseUrl?: string | undefined,\n signal?: AbortSignal,\n): Promise<string[]> {\n const url = `${(baseUrl ?? CODEX_BASE_URL).replace(/\\/+$/, '')}/models`;\n try {\n const res = await fetch(url, {\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n originator: 'wrongstack',\n 'OpenAI-Beta': 'responses=experimental',\n },\n signal: signal\n ? AbortSignal.any([signal, AbortSignal.timeout(8_000)])\n : AbortSignal.timeout(8_000),\n });\n if (!res.ok) return [];\n const json = (await res.json()) as\n | { data?: Array<{ id?: string }> }\n | { models?: Array<{ id?: string }> }\n | null;\n if (!json) return [];\n // Standard OpenAI-compatible: { data: [{ id: \"gpt-...\", ... }] }\n const rawList: unknown[] =\n 'data' in json && Array.isArray(json.data)\n ? (json.data as unknown[])\n : 'models' in json && Array.isArray(json.models)\n ? (json.models as unknown[])\n : [];\n const ids: string[] = [];\n for (const entry of rawList) {\n if (!entry || typeof entry !== 'object') continue;\n const id = (entry as Record<string, unknown>).id;\n if (typeof id === 'string' && id.length > 0) ids.push(id);\n }\n return ids;\n } catch {\n return [];\n }\n}\n\n// \u2500\u2500 Token endpoint calls \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function readTokens(res: Response, op: string, url: string): Promise<CodexTokens> {\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new FetchError({\n message: `Codex token ${op} failed (${res.status}): ${text || res.statusText}`,\n status: res.status,\n context: { provider: 'openai-codex', op, url },\n });\n }\n const json = (await res.json()) as TokenEndpointResponse | null;\n if (!json?.access_token || !json.refresh_token || typeof json.expires_in !== 'number') {\n throw new ParseError({\n message: `Codex token ${op} response missing fields`,\n source: 'openai-codex-token-response',\n context: { op },\n });\n }\n return {\n access: json.access_token,\n refresh: json.refresh_token,\n expires: Date.now() + json.expires_in * 1000,\n idToken: json.id_token,\n };\n}\n\n/** Exchange an authorization code (+ PKCE verifier) for tokens. */\nexport async function exchangeAuthorizationCode(\n code: string,\n verifier: string,\n signal?: AbortSignal,\n port = REDIRECT_PORT,\n): Promise<CodexTokens> {\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: CLIENT_ID,\n code,\n code_verifier: verifier,\n redirect_uri: redirectUri(port),\n }).toString(),\n signal: signal\n ? AbortSignal.any([signal, AbortSignal.timeout(30_000)])\n : AbortSignal.timeout(30_000),\n });\n return readTokens(res, 'exchange', TOKEN_URL);\n}\n\n/**\n * Refresh an expired access token using the stored refresh token. Exported for\n * the `openai-codex` provider, which calls it transparently before requests.\n */\nexport async function refreshCodexToken(\n refreshToken: string,\n signal?: AbortSignal,\n): Promise<CodexTokens> {\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n }).toString(),\n signal: signal\n ? AbortSignal.any([signal, AbortSignal.timeout(30_000)])\n : AbortSignal.timeout(30_000),\n });\n return readTokens(res, 'refresh', TOKEN_URL);\n}\n\n// \u2500\u2500 Loopback callback server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// Loopback server, browser opener, and callback HTML are now in\n// `./loopback-server.js` \u2014 imported at the top of this file.\n\n// \u2500\u2500 Manual paste fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Parse a pasted authorization code or full redirect URL into { code, state }. */\nexport function parseAuthorizationInput(input: string): {\n code?: string | undefined;\n state?: string | undefined;\n} {\n const value = input.trim();\n if (!value) return {};\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get('code') ?? undefined,\n state: url.searchParams.get('state') ?? undefined,\n };\n } catch {\n /* not a URL */\n }\n if (value.includes('code=')) {\n const params = new URLSearchParams(value);\n return {\n code: params.get('code') ?? undefined,\n state: params.get('state') ?? undefined,\n };\n }\n return { code: value };\n}\n\n// \u2500\u2500 Main login flow \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface CodexLoginOptions {\n /** Storage provider id. Defaults to the canonical `openai-codex`. */\n providerId?: string;\n /**\n * External cancellation signal (e.g. the TUI auth panel's Esc). When\n * provided, the flow does NOT install its own SIGINT handler \u2014 the\n * caller owns cancellation, and a raw `process.exit` from inside a\n * mounted Ink tree would corrupt the terminal.\n */\n signal?: AbortSignal | undefined;\n}\n\n/**\n * Run the \"Sign in with ChatGPT\" flow and persist the resulting OAuth tokens.\n * Returns 0 on success, 1 on cancel/error.\n */\nexport async function runCodexOAuthLogin(\n deps: AuthMenuDeps,\n opts: CodexLoginOptions = {},\n): Promise<number> {\n const providerId = opts.providerId ?? CODEX_PROVIDER_ID;\n const pkce = generatePkce();\n const state = createState();\n\n const ac = new AbortController();\n // First Ctrl+C cancels cleanly (aborts the controller, which unblocks the\n // loopback wait below); a second Ctrl+C is a hard escape hatch in case\n // anything downstream is still wedged. Skipped entirely when the caller\n // supplied an external signal (TUI) \u2014 the caller owns cancellation then.\n let sigintCount = 0;\n const onSig = () => {\n sigintCount += 1;\n if (sigintCount === 1) {\n deps.renderer.write(color.dim('\\n Cancelling sign-in\u2026 (press Ctrl+C again to force-quit)\\n'));\n ac.abort();\n } else {\n process.exit(130);\n }\n };\n const external = opts.signal;\n if (external) {\n if (external.aborted) ac.abort();\n else external.addEventListener('abort', () => ac.abort(), { once: true });\n } else {\n process.on('SIGINT', onSig);\n }\n\n const server = await startLoopbackServer(state, ac.signal);\n const authorizeUrl = buildAuthorizeUrl(pkce.challenge, state, server.port);\n // Wrap URL in OSC 8 terminal hyperlink sequences \u2014 makes it a clickable\n // link in modern terminals (Windows Terminal, iTerm2, Kitty, WezTerm, etc.).\n // The hyperlink is region-based: clicking any wrapped segment opens the URL.\n const osc8 = (url: string) => `\\x1b]8;;${url}\\x1b\\\\${url}\\x1b]8;;\\x1b\\\\`;\n\n deps.renderer.write(\n color.bold(`\\n Sign in with ChatGPT \u2014 ${color.cyan(providerId)}\\n`) +\n color.dim(' Uses your ChatGPT Plus/Pro/Team subscription (not an API key).\\n') +\n color.amber(' \u26A0 Using a subscription outside the official Codex client may violate\\n') +\n color.amber(' OpenAI\u2019s Terms \u2014 your account could be rate-limited or banned.\\n') +\n color.dim(' Sanctioned programmatic use = an API key: ') +\n color.bold('wstack auth openai') +\n color.dim('\\n\\n') +\n color.bold(` ${'\u2500'.repeat(56)}\\n`) +\n color.bold(' Open this URL in your browser to sign in:\\n') +\n color.cyan(` ${osc8(authorizeUrl)}\\n`) +\n color.bold(` ${'\u2500'.repeat(56)}\\n\\n`),\n );\n\n if (server.bound) {\n openBrowser(authorizeUrl);\n deps.renderer.write(\n color.dim(' A browser window should open. Waiting for you to finish signing in...\\n') +\n color.dim(` (Listening on ${redirectUri(server.port)} \u2014 press Ctrl+C to cancel.)\\n`),\n );\n } else {\n deps.renderer.write(\n color.amber(' \u26A0 Could not start the local callback listener (ports 1455 and 1457 in use).\\n') +\n color.dim(' After signing in, copy the full redirect URL from your browser\\n') +\n color.dim(' (it starts with http://localhost:1455/auth/callback or :1457) and paste it below.\\n'),\n );\n }\n\n let code: string | undefined;\n try {\n if (server.bound) {\n const callback = await server.waitForCode();\n // Ctrl+C while waiting on the loopback \u2192 cancel now rather than dropping\n // into the manual-paste prompt (which would block again).\n if (ac.signal.aborted) {\n deps.renderer.write(color.dim(' Cancelled.\\n'));\n return 1;\n }\n if (callback) code = callback.code;\n }\n\n // Manual paste fallback (port busy, or browser couldn't redirect back).\n if (!code) {\n const input = (\n await deps.reader.readLine(\n `\\n ${color.amber('?')} Paste the redirect URL or code ${color.dim('(or q to cancel)')}: `,\n )\n ).trim();\n if (input.toLowerCase() === 'q' || input === '') {\n deps.renderer.write(color.dim(' Cancelled.\\n'));\n return 1;\n }\n const parsed = parseAuthorizationInput(input);\n if (parsed.state && parsed.state !== state) {\n deps.renderer.writeError(' State mismatch \u2014 please restart the login flow.');\n return 1;\n }\n code = parsed.code;\n }\n\n if (!code) {\n deps.renderer.writeError(' No authorization code received.');\n return 1;\n }\n\n deps.renderer.write(color.dim('\\n Exchanging authorization code for tokens...\\n'));\n const tokens = await exchangeAuthorizationCode(code, pkce.verifier, ac.signal, server.port);\n const accountId = extractAccountId(tokens.access) ?? (tokens.idToken ? extractAccountId(tokens.idToken) : null);\n if (!accountId) {\n deps.renderer.writeError(\n ' Signed in, but the token has no ChatGPT account id.\\n' +\n ' This account may not have Codex/ChatGPT subscription access.',\n );\n return 1;\n }\n\n // Fetch available models from the Codex backend (best-effort).\n deps.renderer.write(color.dim(' Fetching available models...\\n'));\n const models = await resolveCodexModels(\n deps.modelsRegistry,\n tokens.access,\n CODEX_BASE_URL,\n ac.signal,\n );\n\n const saved = await saveCodexTokens(deps, providerId, tokens, accountId, models);\n if (!saved) return 1;\n\n const modelHint = models[0] ?? 'gpt-5.5';\n deps.renderer.write(color.green('\\n \u2713 Signed in with ChatGPT!\\n'));\n deps.renderer.writeInfo(\n ` Saved as provider ${color.bold(providerId)}${models.length > 0 ? ` (${models.length} models)` : ''}.\\n` +\n ` Use: ${color.bold(`wstack --provider ${providerId} --model ${modelHint}`)} \"<task>\"\\n` +\n color.dim(' Tokens refresh automatically before they expire.\\n'),\n );\n return 0;\n } catch (err) {\n const msg =\n err instanceof DOMException && err.name === 'AbortError'\n ? 'Login cancelled.'\n : (err as Error).message;\n deps.renderer.writeError(` Login failed: ${msg}`);\n return 1;\n } finally {\n server.close();\n if (!external) process.off('SIGINT', onSig);\n }\n}\n\n// \u2500\u2500 Persistence \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function saveCodexTokens(\n deps: AuthMenuDeps,\n providerId: string,\n tokens: CodexTokens,\n accountId: string,\n models: string[],\n): Promise<boolean> {\n const entry: ProviderApiKey = {\n label: 'oauth-default',\n apiKey: tokens.access,\n createdAt: nowIso(),\n authMethod: 'oauth',\n expiresAt: new Date(tokens.expires).toISOString(),\n refreshToken: tokens.refresh,\n tokenType: 'bearer',\n scope: SCOPE,\n accountId,\n };\n\n try {\n await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {\n const existing = all[providerId];\n const p: ProviderConfig = existing ? { ...existing } : { type: providerId };\n p.family = 'openai-codex';\n if (!p.baseUrl) p.baseUrl = CODEX_BASE_URL;\n // The caller populates `models` from the live backend or the fallback\n // constant. Always overwrite \u2014 the backend is authoritative.\n p.models = [...models];\n\n const keys = normalizeKeys(p).filter((k) => k.label !== entry.label);\n keys.push(entry);\n writeKeysBack(p, keys);\n p.activeKey = entry.label;\n all[providerId] = p;\n }, deps.profileConfigPath);\n return true;\n } catch (err) {\n deps.renderer.writeError(` Failed to save tokens: ${(err as Error).message}`);\n return false;\n }\n}\n", "/**\n * Shared loopback OAuth server \u2014 HTTP callback listener for OAuth flows.\n *\n * Both the Codex (\"Sign in with ChatGPT\") and Anthropic (\"Sign in with Claude\")\n * OAuth flows start a local HTTP server on a loopback port to receive the\n * authorization code redirect from the provider's browser flow. Before this\n * module existed, each flow duplicated:\n *\n * - `escapeHtml` / `callbackHtml` \u2014 render success/error HTML pages\n * - `openBrowser` \u2014 best-effort platform browser opener\n * - `startLoopbackServer` \u2014 HTTP server with port fallback, abort handling,\n * state validation, and callback URL parsing\n *\n * Usage:\n * ```ts\n * import { startLoopbackServer, callbackHtml, openBrowser } from './loopback-server.js';\n *\n * const server = await startLoopbackServer(state, [1455, 1457], signal);\n * const code = await server.waitForCode();\n * ```\n *\n * @module auth-menu/loopback-server\n */\n\nimport { spawn } from 'node:child_process';\nimport { createServer, type Server } from 'node:http';\n\n// \u2500\u2500 HTML rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ESCAPE_HTML: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n};\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, (ch) => ESCAPE_HTML[ch] ?? ch);\n}\n\n/**\n * Render a simple dark-themed HTML response for the browser callback page.\n * Shared by all loopback-based OAuth flows so the success/error page styling\n * is consistent and the HTML generation isn't duplicated.\n */\nexport function callbackHtml(ok: boolean, message: string): string {\n const heading = ok ? 'Authentication successful' : 'Authentication failed';\n return (\n `<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"/>` +\n `<title>${escapeHtml(heading)}</title><style>body{margin:0;min-height:100vh;display:flex;` +\n `align-items:center;justify-content:center;background:#09090b;color:#fafafa;` +\n `font-family:ui-sans-serif,system-ui,sans-serif;text-align:center}` +\n `h1{font-size:26px;margin:0 0 8px}p{color:#a1a1aa}</style></head><body><main>` +\n `<h1>${escapeHtml(heading)}</h1><p>${escapeHtml(message)}</p></main></body></html>`\n );\n}\n\n// \u2500\u2500 Platform browser opener (best-effort) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Open a URL in the user's default browser. Best-effort \u2014 never throws.\n *\n * - Windows: `cmd /c start \"\" <url>`\n * - macOS: `open <url>`\n * - Linux: `xdg-open <url>`\n */\nexport function openBrowser(url: string): void {\n try {\n const platform = process.platform;\n const { command, args } =\n platform === 'win32'\n ? { command: 'cmd', args: ['/c', 'start', '', url] }\n : platform === 'darwin'\n ? { command: 'open', args: [url] }\n : { command: 'xdg-open', args: [url] };\n const child = spawn(command, args, { stdio: 'ignore', windowsHide: true });\n child.on('error', () => {});\n child.unref();\n } catch {\n // Best-effort \u2014 the URL is always printed in the terminal.\n }\n}\n\n// \u2500\u2500 Loopback callback server \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Result of waiting for the OAuth callback. */\nexport interface LoopbackCallback {\n /** The authorization code from the provider. */\n code: string;\n /** The OAuth state parameter from the callback (validated against expected). */\n state: string;\n}\n\nexport interface LoopbackServer {\n /**\n * Wait for the browser to redirect back with the authorization code.\n * Resolves with the code and state, or `null` if cancelled/failed.\n */\n waitForCode(): Promise<LoopbackCallback | null>;\n /** Close the HTTP server and release the port. */\n close(): void;\n /** True when the server bound to a registered callback port. */\n readonly bound: boolean;\n /** The actual port the server is listening on (matches the authorize URL redirect_uri). */\n readonly port: number;\n}\n\n/**\n * Start a loopback HTTP server for OAuth authorization code callback.\n *\n * The server listens on the first available port from `ports`. If all ports\n * are busy, `bound` is `false` and the caller should fall back to a manual\n * paste prompt.\n *\n * When `signal` aborts (user pressed Ctrl+C or TUI Esc), the pending\n * `waitForCode()` promise resolves to `null` and the server is torn down\n * so the login flow can return promptly.\n *\n * @param expectedState - The OAuth `state` value to validate against the callback\n * @param ports - Ordered list of TCP ports to try (first available wins)\n * @param signal - Optional external cancellation signal\n * @param callbackPath - The URL path the provider redirects to (default `/auth/callback`)\n * @param redirectHost - The hostname to listen on (default `127.0.0.1`)\n */\nexport function startLoopbackServer(\n expectedState: string,\n ports: readonly number[],\n signal?: AbortSignal,\n callbackPath = '/auth/callback',\n redirectHost = '127.0.0.1',\n): Promise<LoopbackServer> {\n let resolveCode: (v: LoopbackCallback | null) => void = () => {};\n const codePromise = new Promise<LoopbackCallback | null>((resolve) => {\n let settled = false;\n resolveCode = (v) => {\n if (settled) return;\n settled = true;\n resolve(v);\n };\n });\n\n const server: Server = createServer((req, res) => {\n let url: URL;\n try {\n url = new URL(req.url ?? '', `http://${redirectHost}`);\n } catch {\n res.statusCode = 400;\n res.end();\n return;\n }\n if (url.pathname !== callbackPath) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/html; charset=utf-8');\n res.end(callbackHtml(false, 'Callback route not found.'));\n return;\n }\n res.setHeader('content-type', 'text/html; charset=utf-8');\n const err = url.searchParams.get('error');\n if (err) {\n res.statusCode = 400;\n res.end(callbackHtml(false, `Authorization error: ${err}`));\n resolveCode(null);\n return;\n }\n const state = url.searchParams.get('state') ?? '';\n if (state !== expectedState) {\n res.statusCode = 400;\n res.end(callbackHtml(false, 'State mismatch \u2014 please restart the login.'));\n resolveCode(null);\n return;\n }\n const code = url.searchParams.get('code');\n if (!code) {\n res.statusCode = 400;\n res.end(callbackHtml(false, 'Missing authorization code.'));\n return;\n }\n res.statusCode = 200;\n res.end(callbackHtml(true, 'You can close this window and return to the terminal.'));\n resolveCode({ code, state });\n });\n\n // Abort (Ctrl+C / TUI Esc) \u2192 unblock the pending wait and close the server.\n const onAbort = (): void => {\n resolveCode(null);\n try {\n server.close();\n } catch {\n /* ignore */\n }\n };\n if (signal) {\n if (signal.aborted) onAbort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n\n return new Promise<LoopbackServer>((resolve) => {\n const close = (): void => {\n resolveCode(null);\n try {\n server.close();\n } catch {\n /* ignore */\n }\n };\n\n const fail = (): void => {\n resolveCode(null);\n resolve({\n bound: false,\n port: ports[0] ?? 1455,\n waitForCode: () => Promise.resolve(null),\n close,\n });\n };\n\n let index = 0;\n server.on('error', () => {\n index += 1;\n const nextPort = ports[index];\n if (nextPort !== undefined) {\n server.listen(nextPort, redirectHost);\n return;\n }\n fail();\n });\n\n server.on('listening', () => {\n const address = server.address();\n const port = typeof address === 'object' && address ? address.port : ports[index] ?? 1455;\n resolve({\n bound: true,\n port,\n waitForCode: () => codePromise,\n close,\n });\n });\n\n server.listen(ports[0] ?? 1455, redirectHost);\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["startLoopbackServer", "startLoopbackServer"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/boot/auto-discover-providers.ts"],
|
|
4
|
-
"sourcesContent": ["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Config, Logger, ModelsDevProvider, ProviderConfig } from '@wrongstack/core/types';\nimport type { DefaultModelsRegistry } from '@wrongstack/core/models';\nimport { COMPATIBLE_PRESETS, discoverOpenAICompatibleModels } from '@wrongstack/providers';\n\ninterface DiscoverCacheEntry {\n fetchedAt: string;\n provider: ModelsDevProvider;\n}\ntype DiscoverCache = Record<string, DiscoverCacheEntry>;\n\n/** Active API key from a ProviderConfig (mirrors the provider factory's resolver). */\nfunction resolveKey(cfg: ProviderConfig): string | undefined {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n const active = cfg.activeKey\n ? cfg.apiKeys.find((k) => k.label === cfg.activeKey)\n : undefined;\n return (active ?? cfg.apiKeys[0])?.apiKey;\n }\n return cfg.apiKey && cfg.apiKey.length > 0 ? cfg.apiKey : undefined;\n}\n\n/** Providers eligible for `/v1/models` auto-discovery and their resolved base URL. */\nfunction eligibleProviders(\n config: Config,\n): Array<{ id: string; cfg: ProviderConfig; baseUrl: string; apiKey?: string | undefined }> {\n const out: Array<{\n id: string;\n cfg: ProviderConfig;\n baseUrl: string;\n apiKey?: string | undefined;\n }> = [];\n for (const [id, cfg] of Object.entries(config.providers ?? {})) {\n const preset = COMPATIBLE_PRESETS[id];\n const enabled = cfg.autoDiscoverModels ?? preset?.autoDiscover ?? false;\n if (!enabled) continue;\n const baseUrl = cfg.baseUrl ?? preset?.defaultBaseUrl;\n if (!baseUrl) continue;\n out.push({ id, cfg, baseUrl, apiKey: resolveKey(cfg) });\n }\n return out;\n}\n\nasync function readCache(file: string): Promise<DiscoverCache> {\n try {\n return JSON.parse(await fs.readFile(file, 'utf8')) as DiscoverCache;\n } catch {\n return {};\n }\n}\n\n/**\n * Fetch model lists for every auto-discovery provider in the config and merge\n * them into the catalog. Best-effort end to end: a down server or missing key\n * falls back to the last cached list (any age \u2014 a local proxy being offline at\n * boot shouldn't wipe its models), and any failure is a logged no-op so boot\n * never breaks.\n *\n * Caches the most recent successful fetch per provider+baseUrl so the models\n * survive a restart while the server is briefly unavailable.\n */\nexport async function discoverAndMergeProviders(opts: {\n config: Config;\n registry: DefaultModelsRegistry;\n cacheDir: string;\n logger?: Logger | undefined;\n fetchImpl?: typeof fetch | undefined;\n}): Promise<void> {\n const targets = eligibleProviders(opts.config);\n if (targets.length === 0) return;\n\n const cacheFile = path.join(opts.cacheDir, 'discovered-models-cache.json');\n const cache = await readCache(cacheFile);\n let cacheDirty = false;\n\n await Promise.all(\n targets.map(async ({ id, cfg, baseUrl, apiKey }) => {\n const cacheKey = `${id}\u0000${baseUrl}`;\n const provider = await discoverOpenAICompatibleModels(id, {\n baseUrl,\n apiKey,\n headers: cfg.headers,\n providerName: id,\n fetchImpl: opts.fetchImpl,\n });\n if (provider) {\n cache[cacheKey] = { fetchedAt: new Date().toISOString(), provider };\n cacheDirty = true;\n opts.registry.mergeOverlay({ [id]: provider });\n opts.logger?.info(\n `auto-discovered ${Object.keys(provider.models).length} models for \"${id}\" from ${baseUrl}`,\n );\n return;\n }\n // Fetch failed \u2014 fall back to the last cached list, if any.\n const cached = cache[cacheKey];\n if (cached) {\n opts.registry.mergeOverlay({ [id]: cached.provider });\n opts.logger?.warn(\n `auto-discovery for \"${id}\" failed; using ${\n Object.keys(cached.provider.models).length\n } cached models from ${cached.fetchedAt}`,\n );\n } else {\n opts.logger?.warn(\n `auto-discovery for \"${id}\" failed and no cache available (server at ${baseUrl} unreachable?)`,\n );\n }\n }),\n );\n\n if (cacheDirty) {\n try {\n await fs.writeFile(cacheFile, JSON.stringify(cache), 'utf8');\n } catch {\n // best-effort cache write\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAGtB,SAAS,oBAAoB,sCAAsC;AASnE,SAAS,WAAW,KAAyC;AAC3D,MAAI,MAAM,QAAQ,IAAI,OAAO,KAAK,IAAI,QAAQ,SAAS,GAAG;AACxD,UAAM,SAAS,IAAI,YACf,IAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,SAAS,IACjD;AACJ,YAAQ,UAAU,IAAI,QAAQ,CAAC,IAAI;AAAA,EACrC;AACA,SAAO,IAAI,UAAU,IAAI,OAAO,SAAS,IAAI,IAAI,SAAS;AAC5D;AAGA,SAAS,kBACP,QAC0F;AAC1F,QAAM,MAKD,CAAC;AACN,aAAW,CAAC,IAAI,GAAG,KAAK,OAAO,QAAQ,OAAO,aAAa,CAAC,CAAC,GAAG;AAC9D,UAAM,SAAS,mBAAmB,EAAE;AACpC,UAAM,UAAU,IAAI,sBAAsB,QAAQ,gBAAgB;AAClE,QAAI,CAAC,QAAS;AACd,UAAM,UAAU,IAAI,WAAW,QAAQ;AACvC,QAAI,CAAC,QAAS;AACd,QAAI,KAAK,EAAE,IAAI,KAAK,SAAS,QAAQ,WAAW,GAAG,EAAE,CAAC;AAAA,EACxD;AACA,SAAO;AACT;AAEA,eAAe,UAAU,MAAsC;AAC7D,MAAI;AACF,WAAO,KAAK,MAAM,MAAS,YAAS,MAAM,MAAM,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAYA,eAAsB,0BAA0B,MAM9B;AAChB,QAAM,UAAU,kBAAkB,KAAK,MAAM;AAC7C,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,YAAiB,UAAK,KAAK,UAAU,8BAA8B;AACzE,QAAM,QAAQ,MAAM,UAAU,SAAS;AACvC,MAAI,aAAa;AAEjB,QAAM,QAAQ;AAAA,IACZ,QAAQ,IAAI,OAAO,EAAE,IAAI,KAAK,SAAS,OAAO,MAAM;AAClD,YAAM,WAAW,GAAG,EAAE,KAAI,OAAO;AACjC,YAAM,WAAW,MAAM,+BAA+B,IAAI;AAAA,QACxD;AAAA,QACA;AAAA,QACA,SAAS,IAAI;AAAA,QACb,cAAc;AAAA,QACd,WAAW,KAAK;AAAA,MAClB,CAAC;AACD,UAAI,UAAU;AACZ,cAAM,QAAQ,IAAI,EAAE,YAAW,oBAAI,KAAK,GAAE,YAAY,GAAG,SAAS;AAClE,qBAAa;AACb,aAAK,SAAS,aAAa,EAAE,CAAC,EAAE,GAAG,SAAS,CAAC;AAC7C,aAAK,QAAQ;AAAA,UACX,mBAAmB,OAAO,KAAK,SAAS,MAAM,EAAE,MAAM,gBAAgB,EAAE,UAAU,OAAO;AAAA,QAC3F;AACA;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,QAAQ;AAC7B,UAAI,QAAQ;AACV,aAAK,SAAS,aAAa,EAAE,CAAC,EAAE,GAAG,OAAO,SAAS,CAAC;AACpD,aAAK,QAAQ;AAAA,UACX,uBAAuB,EAAE,mBACvB,OAAO,KAAK,OAAO,SAAS,MAAM,EAAE,MACtC,uBAAuB,OAAO,SAAS;AAAA,QACzC;AAAA,MACF,OAAO;AACL,aAAK,QAAQ;AAAA,UACX,uBAAuB,EAAE,8CAA8C,OAAO;AAAA,QAChF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,YAAY;AACd,QAAI;AACF,YAAS,aAAU,WAAW,KAAK,UAAU,KAAK,GAAG,MAAM;AAAA,IAC7D,QAAQ;AAAA,IAER;AAAA,EACF;AACF;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/utils.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Format a token count for human-readable display.\n * 999 \u2192 \"999\"\n * 1_200 \u2192 \"1.2k\"\n * 12_000 \u2192 \"12k\"\n * 1_500_000 \u2192 \"1.5M\"\n */\nexport function fmtTok(n: number): string {\n if (n < 1000) return String(n);\n if (n < 1_000_000) return `${(n / 1000).toFixed(n < 10_000 ? 1 : 0)}k`;\n return `${(n / 1_000_000).toFixed(1)}M`;\n}\n\n/**\n * Return a new frozen config object with the given patch applied.\n * Config objects are frozen by the config loader \u2014 direct mutation\n * silently fails at runtime. This helper spreads + re-freezes safely.\n */\nexport function patchConfig<T extends object>(base: T, patch: Partial<T>): T {\n return Object.freeze({ ...base, ...patch }) as T;\n}\n\n/**\n * Human-readable duration: 999 \u2192 \"999ms\", 12_500 \u2192 \"12.5s\",\n * 160_016 \u2192 \"2m40s\", 7_200_000 \u2192 \"2h0m\". Used by `/agents` and\n * `/fleet status` so users don't have to read \"160016ms\" and do the\n * conversion in their head.\n */\nexport function fmtDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n const s = ms / 1000;\n if (s < 60) return `${s.toFixed(s < 10 ? 1 : 0)}s`;\n const m = Math.floor(s / 60);\n const remSec = Math.round(s - m * 60);\n if (m < 60) return remSec === 0 ? `${m}m` : `${m}m${remSec}s`;\n const h = Math.floor(m / 60);\n const remMin = m - h * 60;\n return `${h}h${remMin}m`;\n}\n\n/**\n * Render a completed TaskResult into a single line for `/agents` and\n * `/fleet status`. Distinguishes all four terminal statuses with\n * separate icons + colors so users can tell a timeout from a real\n * failure at a glance, and surfaces both the failure kind (e.g.\n * `provider_rate_limit`, `tool_failed`) and a truncated error tail\n * (previously dropped on the floor).\n *\n * Accepts either the structured `SubagentError` envelope (current) or\n * a legacy string error \u2014 the field shape is widened to keep older\n * callers compiling while migrations roll through.\n *\n * The caller passes the color helper (it lives in @wrongstack/core)\n * to avoid a circular import from this utility module.\n */\nexport function fmtTaskResultLine(\n r: {\n status: 'success' | 'failed' | 'timeout' | 'stopped';\n error?:\n | string\n | {\n kind?: string | undefined;\n message?: string | undefined;\n retryable?: boolean | undefined;\n backoffMs?: number | undefined;\n }\n | undefined;\n iterations: number;\n toolCalls: number;\n durationMs: number;\n },\n color: {\n green(s: string): string;\n red(s: string): string;\n yellow(s: string): string;\n dim(s: string): string;\n },\n): { mark: string; stats: string; tail: string } {\n const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;\n // Error tails are unbounded provider strings \u2014 collapse whitespace and\n // truncate so a 2KB stack trace can't blow up the chat line. Lift the\n // structured `kind` chip in front of the tail so the user reads\n // `\u2717 failed [provider_rate_limit] \u2014 server overloaded` instead of\n // raw verbose body.\n const errMsg = typeof r.error === 'string' ? r.error : r.error?.message;\n const errKind = typeof r.error === 'object' ? r.error?.kind : undefined;\n const errTail = errMsg\n ? ` \u2014 ${errMsg.replace(/\\s+/g, ' ').slice(0, 80)}${errMsg.length > 80 ? '\u2026' : ''}`\n : '';\n const errKindChip = errKind ? color.dim(` [${errKind}]`) : '';\n const errSnip = errMsg || errKind ? `${errKindChip}${color.dim(errTail)}` : '';\n switch (r.status) {\n case 'success':\n return { mark: color.green('\u2713'), stats, tail: '' };\n case 'timeout':\n return {\n mark: color.yellow('\u23F1'),\n stats: `${color.yellow('timeout')} ${stats}`,\n tail: errSnip,\n };\n case 'stopped':\n return { mark: color.dim('\u2298'), stats: `${color.dim('stopped')} ${stats}`, tail: errSnip };\n case 'failed':\n return { mark: color.red('\u2717'), stats: `${color.red('failed')} ${stats}`, tail: errSnip };\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;AAOO,SAAS,OAAO,GAAmB;AACxC,MAAI,IAAI,IAAM,QAAO,OAAO,CAAC;AAC7B,MAAI,IAAI,IAAW,QAAO,IAAI,IAAI,KAAM,QAAQ,IAAI,MAAS,IAAI,CAAC,CAAC;AACnE,SAAO,IAAI,IAAI,KAAW,QAAQ,CAAC,CAAC;AACtC;AAOO,SAAS,YAA8B,MAAS,OAAsB;AAC3E,SAAO,OAAO,OAAO,EAAE,GAAG,MAAM,GAAG,MAAM,CAAC;AAC5C;AAQO,SAAS,YAAY,IAAoB;AAC9C,MAAI,KAAK,IAAM,QAAO,GAAG,EAAE;AAC3B,QAAM,IAAI,KAAK;AACf,MAAI,IAAI,GAAI,QAAO,GAAG,EAAE,QAAQ,IAAI,KAAK,IAAI,CAAC,CAAC;AAC/C,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,QAAM,SAAS,KAAK,MAAM,IAAI,IAAI,EAAE;AACpC,MAAI,IAAI,GAAI,QAAO,WAAW,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM;AAC1D,QAAM,IAAI,KAAK,MAAM,IAAI,EAAE;AAC3B,QAAM,SAAS,IAAI,IAAI;AACvB,SAAO,GAAG,CAAC,IAAI,MAAM;AACvB;AAiBO,SAAS,kBACd,GAeA,OAM+C;AAC/C,QAAM,QAAQ,GAAG,EAAE,UAAU,MAAM,EAAE,SAAS,MAAM,YAAY,EAAE,UAAU,CAAC;AAM7E,QAAM,SAAS,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ,EAAE,OAAO;AAChE,QAAM,UAAU,OAAO,EAAE,UAAU,WAAW,EAAE,OAAO,OAAO;AAC9D,QAAM,UAAU,SACZ,WAAM,OAAO,QAAQ,QAAQ,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,OAAO,SAAS,KAAK,WAAM,EAAE,KAC9E;AACJ,QAAM,cAAc,UAAU,MAAM,IAAI,KAAK,OAAO,GAAG,IAAI;AAC3D,QAAM,UAAU,UAAU,UAAU,GAAG,WAAW,GAAG,MAAM,IAAI,OAAO,CAAC,KAAK;AAC5E,UAAQ,EAAE,QAAQ;AAAA,IAChB,KAAK;AACH,aAAO,EAAE,MAAM,MAAM,MAAM,QAAG,GAAG,OAAO,MAAM,GAAG;AAAA,IACnD,KAAK;AACH,aAAO;AAAA,QACL,MAAM,MAAM,OAAO,QAAG;AAAA,QACtB,OAAO,GAAG,MAAM,OAAO,SAAS,CAAC,IAAI,KAAK;AAAA,QAC1C,MAAM;AAAA,MACR;AAAA,IACF,KAAK;AACH,aAAO,EAAE,MAAM,MAAM,IAAI,QAAG,GAAG,OAAO,GAAG,MAAM,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,MAAM,QAAQ;AAAA,IAC1F,KAAK;AACH,aAAO,EAAE,MAAM,MAAM,IAAI,QAAG,GAAG,OAAO,GAAG,MAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,MAAM,QAAQ;AAAA,EAC3F;AACF;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/webui-server/kanban-run-mirror.ts"],
|
|
4
|
-
"sourcesContent": ["export {\n buildTaskGraphFromGoalPhase,\n buildTaskGraphFromSddSnapshot,\n createKanbanRunMirror,\n type KanbanRunMirror,\n type KanbanRunMirrorDeps,\n} from '@wrongstack/webui-server';\n"],
|
|
5
|
-
"mappings": ";;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/dist/chunk-VJUEZZYB.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
// src/utils/win32-cmd.ts
|
|
3
|
-
var WIN32_CMD_META = /[&|<>"\r\n\0]/;
|
|
4
|
-
function buildWin32CmdShimInvocation(command, args = []) {
|
|
5
|
-
assertSafeWin32CmdArgs([command, ...args]);
|
|
6
|
-
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
7
|
-
return {
|
|
8
|
-
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
9
|
-
args: ["/d", "/c", line],
|
|
10
|
-
windowsVerbatimArguments: true
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
function assertSafeWin32CmdArgs(args) {
|
|
14
|
-
for (const arg of args) {
|
|
15
|
-
if (typeof arg === "string" && WIN32_CMD_META.test(arg)) {
|
|
16
|
-
throw new Error(
|
|
17
|
-
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function quoteWin32CmdArg(arg) {
|
|
23
|
-
return `"${arg}"`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export {
|
|
27
|
-
buildWin32CmdShimInvocation
|
|
28
|
-
};
|
|
29
|
-
//# sourceMappingURL=chunk-VJUEZZYB.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/utils/win32-cmd.ts"],
|
|
4
|
-
"sourcesContent": ["const WIN32_CMD_META = /[&|<>\"\\r\\n\\0]/;\n\nexport interface Win32CmdShimInvocation {\n command: string;\n args: string[];\n windowsVerbatimArguments: true;\n}\n\nexport function buildWin32CmdShimInvocation(\n command: string,\n args: readonly string[] = [],\n): Win32CmdShimInvocation {\n assertSafeWin32CmdArgs([command, ...args]);\n const line = ['call', quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(' ');\n return {\n command: process.env['COMSPEC'] ?? 'cmd.exe',\n args: ['/d', '/c', line],\n windowsVerbatimArguments: true,\n };\n}\n\nfunction assertSafeWin32CmdArgs(args: readonly unknown[]): void {\n for (const arg of args) {\n if (typeof arg === 'string' && WIN32_CMD_META.test(arg)) {\n throw new Error(\n 'win32 cmd shim spawn: argument contains a shell metacharacter ' +\n '(one of & | < > \", or a newline) that could enable command injection ' +\n 'through the .cmd/.bat wrapper - refusing to run. Offending argument: ' +\n JSON.stringify(arg),\n );\n }\n }\n}\n\nfunction quoteWin32CmdArg(arg: string): string {\n return `\"${arg}\"`;\n}\n"],
|
|
5
|
-
"mappings": ";;;AAAA,IAAM,iBAAiB;AAQhB,SAAS,4BACd,SACA,OAA0B,CAAC,GACH;AACxB,yBAAuB,CAAC,SAAS,GAAG,IAAI,CAAC;AACzC,QAAM,OAAO,CAAC,QAAQ,iBAAiB,OAAO,GAAG,GAAG,KAAK,IAAI,gBAAgB,CAAC,EAAE,KAAK,GAAG;AACxF,SAAO;AAAA,IACL,SAAS,QAAQ,IAAI,SAAS,KAAK;AAAA,IACnC,MAAM,CAAC,MAAM,MAAM,IAAI;AAAA,IACvB,0BAA0B;AAAA,EAC5B;AACF;AAEA,SAAS,uBAAuB,MAAgC;AAC9D,aAAW,OAAO,MAAM;AACtB,QAAI,OAAO,QAAQ,YAAY,eAAe,KAAK,GAAG,GAAG;AACvD,YAAM,IAAI;AAAA,QACR,6MAGE,KAAK,UAAU,GAAG;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,KAAqB;AAC7C,SAAO,IAAI,GAAG;AAChB;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/hq-publisher.ts", "../src/kanban-hq-sync.ts"],
|
|
4
|
-
"sourcesContent": ["import { createHqPublisherFromEnv, resolveHqConfig } from '@wrongstack/core/hq';\nimport type { CreateHqPublisherOptions } from '@wrongstack/core/hq';\nimport type { HqPublisher, HqSocketLike } from '@wrongstack/core/hq';\nimport { WebSocket } from 'ws';\nimport { createKanbanHqSync } from './kanban-hq-sync.js';\n\ntype CliHqPublisherOptions = Omit<CreateHqPublisherOptions, 'socketFactory'> & {\n socketFactory?: CreateHqPublisherOptions['socketFactory'];\n};\n\nexport interface CliHqConnection {\n getPublisher(): HqPublisher | undefined;\n stop(): void;\n}\n\nexport interface CliHqConnectionOptions extends CliHqPublisherOptions {\n onConnect?: ((publisher: HqPublisher) => void) | undefined;\n retryIntervalMs?: number | undefined;\n}\n\nfunction nodeWsSocketFactory(url: string): HqSocketLike {\n return new WebSocket(url) as unknown as HqSocketLike;\n}\n\nexport function createCliHqPublisher(options: CliHqPublisherOptions): HqPublisher | undefined {\n return createHqPublisherFromEnv({\n ...options,\n socketFactory: options.socketFactory ?? nodeWsSocketFactory,\n });\n}\n\nfunction hqExplicitlyDisabled(options: CliHqPublisherOptions): boolean {\n const envEnabled = process.env['WRONGSTACK_HQ_ENABLED']?.trim();\n if (envEnabled !== undefined && envEnabled.length > 0) return envEnabled === '0';\n if (options.config?.enabled !== undefined) return options.config.enabled === false;\n return options.appConfig?.hq?.enabled === false;\n}\n\nfunction resolvedHqConnectionKey(options: CliHqPublisherOptions): string | undefined {\n if (options.config !== undefined) {\n return options.config.enabled === false\n ? undefined\n : `${options.config.url}\\n${options.config.token ?? ''}`;\n }\n const config = resolveHqConfig({ config: options.appConfig?.hq });\n return config === undefined ? undefined : `${config.url}\\n${config.token ?? ''}`;\n}\n\nexport function startCliHqConnection(options: CliHqConnectionOptions): CliHqConnection {\n const shouldOwnKanbanSync = options.onKanbanSnapshot === undefined;\n let kanbanSync: ReturnType<typeof createKanbanHqSync> | undefined;\n const publisherOptions: CliHqConnectionOptions = shouldOwnKanbanSync\n ? {\n ...options,\n onKanbanSnapshot: (snapshot) => kanbanSync?.handleRemote(snapshot),\n }\n : options;\n let publisher: HqPublisher | undefined;\n let publisherKey: string | undefined;\n let timer: ReturnType<typeof setInterval> | undefined;\n\n const tryConnect = (): void => {\n const nextKey = resolvedHqConnectionKey(options);\n if (nextKey === undefined) return;\n if (publisher !== undefined && publisherKey === nextKey) return;\n\n publisher?.close();\n publisher = undefined;\n publisherKey = undefined;\n\n const next = createCliHqPublisher(publisherOptions);\n if (next === undefined) return;\n publisher = next;\n publisherKey = nextKey;\n if (shouldOwnKanbanSync) {\n kanbanSync?.stop();\n kanbanSync = createKanbanHqSync(options.projectRoot, next.project.projectId);\n }\n next.connect();\n if (kanbanSync !== undefined) {\n kanbanSync.attachPublisher(next).catch((error: unknown) => {\n process.emitWarning(\n `WrongStack kanban HQ sync attach failed (best-effort, retried on reconnect): ${\n error instanceof Error ? error.message : String(error)\n }`,\n { code: 'WRONGSTACK_HQ_KANBAN_SYNC_FAILED' },\n );\n });\n }\n options.onConnect?.(next);\n };\n\n tryConnect();\n if (!hqExplicitlyDisabled(options)) {\n timer = setInterval(tryConnect, options.retryIntervalMs ?? 2_500);\n timer.unref?.();\n }\n\n return {\n getPublisher: () => publisher,\n stop: () => {\n if (timer !== undefined) {\n clearInterval(timer);\n timer = undefined;\n }\n kanbanSync?.stop();\n publisher?.close();\n publisher = undefined;\n publisherKey = undefined;\n },\n };\n}\n", "import type {\n HqKanbanBoardRecord,\n HqKanbanSnapshotPayload,\n HqKanbanTombstone,\n HqPublisher,\n} from '@wrongstack/core/hq';\nimport { deriveHqProjectId } from '@wrongstack/core/hq';\nimport {\n bridgeKanbanSupervisor,\n deleteBoard,\n type KanbanBoard,\n listBoardIds,\n readBoard,\n readKanbanMetadata,\n writeBoard,\n writeKanbanMetadata,\n} from '@wrongstack/kanban';\n\ninterface LocalSyncState {\n boards: Record<string, { revision: number; updatedAt: string }>;\n tombstones: Record<string, HqKanbanTombstone>;\n}\n\nexport interface KanbanHqSync {\n attachPublisher(publisher: HqPublisher): Promise<void>;\n handleRemote(snapshot: HqKanbanSnapshotPayload): Promise<void>;\n /** Explicit refresh seam for hosts/tests; daemon events call the same path. */\n refresh(boardId?: string): void;\n stop(): void;\n}\n\nconst SYNC_STATE_KEY = 'hq-sync-state-v1';\n// The HQ WebSocket server deliberately caps inbound frames at 1 MiB. Keep\n// project-state payloads comfortably below that limit so the event envelope,\n// UTF-8 expansion, and future protocol metadata still have headroom.\nconst MAX_KANBAN_SNAPSHOT_PAYLOAD_BYTES = 512 * 1024;\nconst KANBAN_TOMBSTONE_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;\n\n// Cap the number of boards read per publish cycle so a large project doesn't\n// load hundreds of board payloads in a single burst. Remaining boards spill to\n// the next cycle.\nconst MAX_BOARDS_PER_PUBLISH = 50;\n\n// Kanban\u2194HQ sync is best-effort telemetry: every detached promise in this\n// module must land here instead of surfacing as an unhandled rejection (which\n// kills the host process on Node \u226515). Failed publishes self-heal \u2014 the state\n// fingerprint stays unwritten, so the next watcher event or reconnect\n// full-snapshot re-detects the same diff.\nfunction warnSyncFailure(error: unknown): void {\n process.emitWarning(\n `WrongStack kanban HQ sync failed (best-effort, will retry on next change): ${\n error instanceof Error ? error.message : String(error)\n }`,\n { code: 'WRONGSTACK_HQ_KANBAN_SYNC_FAILED' },\n );\n}\n\nexport function createKanbanHqSync(\n projectRoot: string,\n projectId = deriveHqProjectId(projectRoot),\n): KanbanHqSync {\n let publisher: HqPublisher | undefined;\n let unsubscribeDaemon: (() => void) | undefined;\n let daemonConnectionCount = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const pendingBoardIds = new Set<string>();\n let fullRescanPending = false;\n let applyingRemote = false;\n let stopped = false;\n let operationChain: Promise<void> = Promise.resolve();\n // Remote snapshots waiting to be applied, coalesced per boardId (latest\n // revision wins). Applying a snapshot does one IPC read/write per board;\n // when snapshots arrive faster than the owner can commit them, queueing each one\n // individually on `operationChain` retains every payload in memory \u2014 an\n // unbounded queue that has driven long fleet sessions into OOM. Coalescing\n // bounds pending memory to one record per distinct board.\n let pendingRemote: HqKanbanSnapshotPayload | null = null;\n let remoteApplyQueued = false;\n\n const runExclusive = <T>(operation: () => Promise<T>): Promise<T> => {\n let resolveResult!: (value: T | PromiseLike<T>) => void;\n let rejectResult!: (reason?: unknown) => void;\n const result = new Promise<T>((resolve, reject) => {\n resolveResult = resolve;\n rejectResult = reject;\n });\n operationChain = operationChain.then(async () => {\n try {\n resolveResult(await operation());\n } catch (error) {\n rejectResult(error);\n }\n });\n return result;\n };\n\n // Schedule the next publish cycle with a fixed debounce. The caller\n // (schedulePublish) already collapses rapid events into one batch, and\n // runExclusive serializes execution \u2014 no Date.now()-based interval is\n // needed because the 100ms debounce plus serialization chain already\n // prevents back-to-back publish bursts.\n const scheduleNext = (): void => {\n if (stopped || timer !== undefined || applyingRemote) return;\n timer = setTimeout(() => {\n timer = undefined;\n const rescan = fullRescanPending;\n const dirtyBoardIds = [...pendingBoardIds];\n fullRescanPending = false;\n pendingBoardIds.clear();\n runExclusive(() => publishLocal(false, rescan ? undefined : dirtyBoardIds)).catch(\n warnSyncFailure,\n );\n }, 100);\n timer.unref?.();\n };\n\n const schedulePublish = (boardId: string | null): void => {\n if (stopped || applyingRemote || publisher === undefined) return;\n if (boardId === null) fullRescanPending = true;\n else pendingBoardIds.add(boardId);\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n scheduleNext();\n };\n\n const publishLocal = async (\n fullSnapshot: boolean,\n dirtyBoardIds?: readonly string[],\n ): Promise<void> => {\n const target = publisher;\n if (target === undefined || stopped) return;\n const state = await readState(projectRoot);\n const prunedTombstones = pruneExpiredTombstones(state, Date.now());\n let stateChanged = fullSnapshot || prunedTombstones;\n const boards: HqKanbanBoardRecord[] = [];\n const tombstones: HqKanbanTombstone[] = [];\n const fullScan = fullSnapshot || dirtyBoardIds === undefined;\n const allBoardIds: readonly string[] = fullScan\n ? await listBoardIds(projectRoot)\n : dirtyBoardIds;\n let boardIds = allBoardIds;\n\n // Batch limit: only cap true delta publishes, never a full scan (initial\n // snapshot OR full rescan). When fullScan is true, ALL boards must be\n // loaded into `present` so the deletion-detection loop below does NOT\n // false-tombstone the boards this cycle didn't reach.\n if (!fullScan && boardIds.length > MAX_BOARDS_PER_PUBLISH) {\n for (const id of boardIds.slice(MAX_BOARDS_PER_PUBLISH)) {\n pendingBoardIds.add(id);\n }\n scheduleNext();\n boardIds = boardIds.slice(0, MAX_BOARDS_PER_PUBLISH);\n }\n\n const present = new Set<string>();\n const now = new Date().toISOString();\n for (const boardId of boardIds) {\n const board = await readBoard(projectRoot, boardId);\n if (board === null) {\n const known = state.boards[boardId];\n if (known !== undefined && state.tombstones[boardId] === undefined) {\n const tombstone = {\n boardId,\n revision: known.revision + 1,\n deletedAt: now,\n };\n state.tombstones[boardId] = tombstone;\n tombstones.push(tombstone);\n stateChanged = true;\n }\n continue;\n }\n present.add(boardId);\n const record = boardRecord(board);\n const known = state.boards[boardId];\n const hadTombstone = state.tombstones[boardId] !== undefined;\n if (\n fullSnapshot ||\n hadTombstone ||\n known === undefined ||\n compareVersions(known.revision, known.updatedAt, record.revision, record.updatedAt) !== 0\n ) {\n boards.push(record);\n }\n if (\n known === undefined ||\n known.revision !== record.revision ||\n known.updatedAt !== record.updatedAt ||\n hadTombstone\n ) {\n stateChanged = true;\n }\n state.boards[boardId] = { revision: record.revision, updatedAt: record.updatedAt };\n delete state.tombstones[boardId];\n }\n if (fullScan) {\n for (const [boardId, known] of Object.entries(state.boards)) {\n if (\n present.has(boardId) ||\n state.tombstones[boardId] !== undefined ||\n isExpiredVersion(known.updatedAt, Date.now())\n ) {\n continue;\n }\n const tombstone = {\n boardId,\n revision: known.revision + 1,\n deletedAt: now,\n };\n state.tombstones[boardId] = tombstone;\n tombstones.push(tombstone);\n stateChanged = true;\n }\n }\n if (stateChanged) await writeState(projectRoot, state);\n\n // A filesystem event caused by applying an HQ snapshot often arrives after\n // `applyingRemote` has been cleared. The persisted state fingerprint above\n // lets that event collapse to an empty delta instead of echoing the entire\n // project back to HQ and starting an N-client broadcast storm.\n if (!fullSnapshot && boards.length === 0 && tombstones.length === 0) return;\n\n for (const payload of chunkSnapshotPayload(\n projectId,\n now,\n boards,\n fullSnapshot ? Object.values(state.tombstones) : tombstones,\n )) {\n target.publishEvent({\n type: 'kanban.snapshot',\n payload,\n maxSummaryLength: 100_000,\n });\n }\n };\n\n const attachPublisher = (next: HqPublisher): Promise<void> => {\n publisher = next;\n return runExclusive(async () => {\n if (\n unsubscribeDaemon === undefined &&\n (process.env['NODE_ENV'] !== 'test' || process.env['WRONGSTACK_KANBAN_FORCE_IPC'] === '1')\n ) {\n unsubscribeDaemon = bridgeKanbanSupervisor(\n projectRoot,\n (event) => {\n const data = event.data as { boardId?: string } | undefined;\n // Non-board-scoped events conservatively request a full rescan.\n schedulePublish(data?.boardId ?? null);\n },\n {\n autoReconnect: true,\n reconnectDelayMs: 1_000,\n // Events emitted while the daemon was down cannot be replayed.\n // Reconcile the authoritative snapshot after every connection.\n onConnected: () => {\n daemonConnectionCount++;\n if (daemonConnectionCount > 1) schedulePublish(null);\n },\n },\n );\n }\n await publishLocal(true);\n });\n };\n\n const applyRemote = async (snapshot: HqKanbanSnapshotPayload): Promise<void> => {\n if (snapshot.projectId !== projectId || stopped) return;\n applyingRemote = true;\n try {\n const state = await readState(projectRoot);\n for (const remote of snapshot.boards) {\n const local = await readBoard(projectRoot, remote.boardId);\n if (\n local !== null &&\n compareVersions(\n local.revision ?? 0,\n local.updatedAt,\n remote.revision,\n remote.updatedAt,\n ) >= 0\n ) {\n continue;\n }\n await writeBoard(projectRoot, remote.board as unknown as KanbanBoard);\n state.boards[remote.boardId] = {\n revision: remote.revision,\n updatedAt: remote.updatedAt,\n };\n delete state.tombstones[remote.boardId];\n }\n for (const tombstone of snapshot.tombstones) {\n const local = await readBoard(projectRoot, tombstone.boardId);\n if (\n local !== null &&\n compareVersions(\n local.revision ?? 0,\n local.updatedAt,\n tombstone.revision,\n tombstone.deletedAt,\n ) >= 0\n ) {\n continue;\n }\n if (local !== null) await deleteBoard(projectRoot, tombstone.boardId);\n state.boards[tombstone.boardId] = {\n revision: Math.max(0, tombstone.revision - 1),\n updatedAt: tombstone.deletedAt,\n };\n state.tombstones[tombstone.boardId] = tombstone;\n }\n await writeState(projectRoot, state);\n } finally {\n applyingRemote = false;\n }\n };\n\n const handleRemote = (snapshot: HqKanbanSnapshotPayload): Promise<void> => {\n if (snapshot.projectId !== projectId || stopped) return Promise.resolve();\n pendingRemote =\n pendingRemote === null ? snapshot : coalesceRemoteSnapshots(pendingRemote, snapshot);\n // At most one apply pass is ever queued: it drains whatever has been\n // coalesced by the time it runs, so bursts collapse instead of chaining.\n if (remoteApplyQueued) return Promise.resolve();\n remoteApplyQueued = true;\n return runExclusive(async () => {\n remoteApplyQueued = false;\n const batch = pendingRemote;\n pendingRemote = null;\n if (batch !== null) await applyRemote(batch);\n }).catch(warnSyncFailure);\n };\n\n return {\n attachPublisher,\n handleRemote,\n refresh: (boardId?: string) => schedulePublish(boardId ?? null),\n stop: () => {\n stopped = true;\n if (timer !== undefined) clearTimeout(timer);\n pendingBoardIds.clear();\n fullRescanPending = false;\n pendingRemote = null;\n unsubscribeDaemon?.();\n unsubscribeDaemon = undefined;\n publisher = undefined;\n },\n };\n}\n\nfunction boardRecord(board: KanbanBoard): HqKanbanBoardRecord {\n return {\n boardId: board.id,\n revision: board.revision ?? 0,\n updatedAt: board.updatedAt,\n board: structuredClone(board) as unknown as Record<string, unknown>,\n };\n}\n\nfunction chunkSnapshotPayload(\n projectId: string,\n generatedAt: string,\n boards: HqKanbanBoardRecord[],\n tombstones: HqKanbanTombstone[],\n): HqKanbanSnapshotPayload[] {\n const chunks: HqKanbanSnapshotPayload[] = [];\n const emptyPayload = (): HqKanbanSnapshotPayload => ({\n projectId,\n generatedAt,\n boards: [],\n tombstones: [],\n });\n const emptyPayloadBytes = Buffer.byteLength(JSON.stringify(emptyPayload()), 'utf8');\n let currentBoards: HqKanbanBoardRecord[] = [];\n let currentTombstones: HqKanbanTombstone[] = [];\n let currentBytes = emptyPayloadBytes;\n\n const pushCurrent = (): void => {\n if (currentBoards.length === 0 && currentTombstones.length === 0) return;\n chunks.push({\n projectId,\n generatedAt,\n boards: currentBoards,\n tombstones: currentTombstones,\n });\n currentBoards = [];\n currentTombstones = [];\n currentBytes = emptyPayloadBytes;\n };\n\n const append = (\n kind: 'boards' | 'tombstones',\n item: HqKanbanBoardRecord | HqKanbanTombstone,\n ): void => {\n const itemBytes = Buffer.byteLength(JSON.stringify(item), 'utf8');\n const itemCount = kind === 'boards' ? currentBoards.length : currentTombstones.length;\n const additionalBytes = itemBytes + (itemCount > 0 ? 1 : 0);\n if (emptyPayloadBytes + itemBytes > MAX_KANBAN_SNAPSHOT_PAYLOAD_BYTES) {\n process.emitWarning(\n `Kanban ${kind === 'boards' ? 'board' : 'tombstone'} ${item.boardId} exceeds the ${MAX_KANBAN_SNAPSHOT_PAYLOAD_BYTES}-byte snapshot chunk target`,\n { code: 'WRONGSTACK_HQ_KANBAN_OVERSIZED_RECORD' },\n );\n }\n if (\n (currentBoards.length > 0 || currentTombstones.length > 0) &&\n currentBytes + additionalBytes > MAX_KANBAN_SNAPSHOT_PAYLOAD_BYTES\n ) {\n pushCurrent();\n }\n if (kind === 'boards') {\n currentBoards.push(item as HqKanbanBoardRecord);\n } else {\n currentTombstones.push(item as HqKanbanTombstone);\n }\n currentBytes +=\n itemBytes +\n (kind === 'boards'\n ? currentBoards.length > 1\n ? 1\n : 0\n : currentTombstones.length > 1\n ? 1\n : 0);\n };\n\n for (const board of boards) append('boards', board);\n for (const tombstone of tombstones) append('tombstones', tombstone);\n pushCurrent();\n\n // An empty snapshot is meaningful on first attach: it registers the project\n // state channel even when the project has no boards yet.\n return chunks.length > 0 ? chunks : [emptyPayload()];\n}\n\n/** Merge two pending remote snapshots into one, keeping \u2014 per boardId \u2014 the\n * record with the highest (revision, timestamp), whether board or tombstone.\n * Equivalent to applying both snapshots in arrival order when revisions are\n * monotonically increasing (which HQ guarantees in practice): the only\n * divergence is a lower-revision board arriving after a higher-revision\n * tombstone for the same boardId, where coalescing correctly keeps the\n * tombstone whereas naive sequential apply would resurrect the stale board. */\nfunction coalesceRemoteSnapshots(\n older: HqKanbanSnapshotPayload,\n newer: HqKanbanSnapshotPayload,\n): HqKanbanSnapshotPayload {\n type RemoteRecord =\n | { kind: 'board'; revision: number; time: string; record: HqKanbanBoardRecord }\n | { kind: 'tombstone'; revision: number; time: string; record: HqKanbanTombstone };\n const byBoardId = new Map<string, RemoteRecord>();\n const put = (candidate: RemoteRecord, boardId: string): void => {\n const existing = byBoardId.get(boardId);\n // On a full (revision, time) tie, prefer the newer-arriving record so a\n // same-timestamp content update in the second snapshot is not silently\n // discarded in favor of the older-arriving one.\n if (\n existing === undefined ||\n compareVersions(existing.revision, existing.time, candidate.revision, candidate.time) <= 0\n ) {\n byBoardId.set(boardId, candidate);\n }\n };\n for (const snapshot of [older, newer]) {\n for (const record of snapshot.boards) {\n put(\n { kind: 'board', revision: record.revision, time: record.updatedAt, record },\n record.boardId,\n );\n }\n for (const record of snapshot.tombstones) {\n put(\n { kind: 'tombstone', revision: record.revision, time: record.deletedAt, record },\n record.boardId,\n );\n }\n }\n const merged: HqKanbanSnapshotPayload = {\n projectId: newer.projectId,\n generatedAt: newer.generatedAt,\n boards: [],\n tombstones: [],\n };\n for (const entry of byBoardId.values()) {\n if (entry.kind === 'board') merged.boards.push(entry.record);\n else merged.tombstones.push(entry.record);\n }\n return merged;\n}\n\nfunction compareVersions(\n aRevision: number,\n aTime: string,\n bRevision: number,\n bTime: string,\n): number {\n if (aRevision !== bRevision) return aRevision - bRevision;\n return aTime.localeCompare(bTime);\n}\n\nfunction isExpiredVersion(timestamp: string, now: number): boolean {\n const parsed = Date.parse(timestamp);\n return !Number.isNaN(parsed) && parsed <= now - KANBAN_TOMBSTONE_RETENTION_MS;\n}\n\nfunction pruneExpiredTombstones(state: LocalSyncState, now: number): boolean {\n let changed = false;\n for (const [boardId, tombstone] of Object.entries(state.tombstones)) {\n if (!isExpiredVersion(tombstone.deletedAt, now)) continue;\n delete state.tombstones[boardId];\n delete state.boards[boardId];\n changed = true;\n }\n return changed;\n}\n\nasync function readState(projectRoot: string): Promise<LocalSyncState> {\n try {\n const raw = await readKanbanMetadata(projectRoot, SYNC_STATE_KEY);\n if (raw === null) return { boards: {}, tombstones: {} };\n const parsed = JSON.parse(raw) as Partial<LocalSyncState>;\n return { boards: parsed.boards ?? {}, tombstones: parsed.tombstones ?? {} };\n } catch {\n return { boards: {}, tombstones: {} };\n }\n}\n\nasync function writeState(projectRoot: string, state: LocalSyncState): Promise<void> {\n await writeKanbanMetadata(projectRoot, SYNC_STATE_KEY, JSON.stringify(state));\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["known"]
|
|
7
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["import { createRequire } from 'node:module';\n\nconst req = createRequire(import.meta.url);\n\nfunction readOwnVersion(): string {\n const candidates = ['../package.json', '../../package.json'];\n for (const rel of candidates) {\n try {\n const pkg = req(rel) as { version?: unknown | undefined };\n if (typeof pkg.version === 'string' && pkg.version.length > 0) return pkg.version;\n } catch {\n // try next\n }\n }\n return 'dev';\n}\n\nexport const CLI_VERSION = readOwnVersion();\n\nlet API_VERSION = '0.0.0';\ntry {\n const corePkg = req('@wrongstack/core/package.json') as {\n wrongstackApiVersion?: string | undefined;\n };\n if (corePkg.wrongstackApiVersion) API_VERSION = corePkg.wrongstackApiVersion;\n} catch {\n /* fallback */\n}\n\nexport { API_VERSION };\n"],
|
|
5
|
-
"mappings": ";;;AAAA,SAAS,qBAAqB;AAE9B,IAAM,MAAM,cAAc,YAAY,GAAG;AAEzC,SAAS,iBAAyB;AAChC,QAAM,aAAa,CAAC,mBAAmB,oBAAoB;AAC3D,aAAW,OAAO,YAAY;AAC5B,QAAI;AACF,YAAM,MAAM,IAAI,GAAG;AACnB,UAAI,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,SAAS,EAAG,QAAO,IAAI;AAAA,IAC5E,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,cAAc,eAAe;AAE1C,IAAI,cAAc;AAClB,IAAI;AACF,QAAM,UAAU,IAAI,+BAA+B;AAGnD,MAAI,QAAQ,qBAAsB,eAAc,QAAQ;AAC1D,QAAQ;AAER;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|