mixdog 0.9.1 → 0.9.3
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/package.json +9 -1
- package/scripts/_bench-cwc.json +20 -0
- package/scripts/agent-loop-policy-test.mjs +37 -0
- package/scripts/agent-parallel-smoke.mjs +54 -10
- package/scripts/anthropic-maxtokens-test.mjs +119 -0
- package/scripts/background-task-meta-smoke.mjs +1 -1
- package/scripts/bench-run.mjs +262 -0
- package/scripts/build-tui.mjs +13 -1
- package/scripts/compact-smoke.mjs +12 -0
- package/scripts/compact-trigger-migration-smoke.mjs +67 -1
- package/scripts/explore-bench.mjs +124 -0
- package/scripts/hook-bus-test.mjs +191 -0
- package/scripts/ingest-pure-conversation-smoke.mjs +148 -0
- package/scripts/internal-comms-bench.mjs +727 -0
- package/scripts/internal-comms-smoke.mjs +75 -0
- package/scripts/lead-workflow-smoke.mjs +4 -4
- package/scripts/live-worker-smoke.mjs +9 -9
- package/scripts/output-style-bench.mjs +285 -0
- package/scripts/output-style-smoke.mjs +13 -10
- package/scripts/patch-replay.mjs +90 -0
- package/scripts/path-suffix-test.mjs +57 -0
- package/scripts/provider-stream-stall-test.mjs +276 -0
- package/scripts/provider-toolcall-test.mjs +599 -1
- package/scripts/recall-bench.mjs +207 -0
- package/scripts/routing-corpus.mjs +281 -0
- package/scripts/session-bench.mjs +1526 -0
- package/scripts/session-diag.mjs +595 -0
- package/scripts/task-bench.mjs +207 -0
- package/scripts/tool-failures.mjs +6 -6
- package/scripts/tool-smoke.mjs +310 -67
- package/scripts/toolcall-args-test.mjs +81 -0
- package/src/agents/debugger/AGENT.md +4 -4
- package/src/agents/heavy-worker/AGENT.md +20 -9
- package/src/agents/reviewer/AGENT.md +4 -4
- package/src/agents/worker/AGENT.md +17 -9
- package/src/app.mjs +10 -6
- package/src/defaults/{hidden-roles.json → agents.json} +7 -7
- package/src/examples/schedules/SCHEDULE.example.md +32 -0
- package/src/examples/webhooks/WEBHOOK.example.md +40 -0
- package/src/headless-role.mjs +14 -14
- package/src/help.mjs +1 -0
- package/src/lib/rules-builder.cjs +32 -54
- package/src/mixdog-session-runtime.mjs +1040 -2036
- package/src/output-styles/default.md +12 -7
- package/src/output-styles/minimal.md +25 -0
- package/src/output-styles/oneline.md +21 -0
- package/src/output-styles/simple.md +10 -9
- package/src/repl.mjs +17 -7
- package/src/rules/agent/00-common.md +7 -5
- package/src/rules/agent/30-explorer.md +8 -12
- package/src/rules/lead/01-general.md +3 -1
- package/src/rules/lead/lead-tool.md +13 -2
- package/src/rules/shared/01-tool.md +23 -12
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +90 -32
- package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +32 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +18 -6
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +23 -20
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +48 -14
- package/src/runtime/agent/orchestrator/agent-trace.mjs +87 -12
- package/src/runtime/agent/orchestrator/config.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +182 -67
- package/src/runtime/agent/orchestrator/{internal-roles.mjs → internal-agents.mjs} +72 -72
- package/src/runtime/agent/orchestrator/internal-tools.mjs +13 -26
- package/src/runtime/agent/orchestrator/mcp/client.mjs +100 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +188 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +313 -84
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +104 -38
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +28 -33
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +184 -17
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +18 -8
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +227 -31
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +83 -6
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +229 -115
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +213 -33
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +49 -17
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +22 -17
- package/src/runtime/agent/orchestrator/session/compact.mjs +560 -51
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +250 -3
- package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +262 -0
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
- package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +49 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
- package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
- package/src/runtime/agent/orchestrator/session/loop.mjs +513 -1000
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +227 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +137 -0
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
- package/src/runtime/agent/orchestrator/session/manager.mjs +232 -1152
- package/src/runtime/agent/orchestrator/session/store.mjs +4 -4
- package/src/runtime/agent/orchestrator/session/tool-envelope.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +5 -0
- package/src/runtime/agent/orchestrator/stall-policy.mjs +63 -15
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +194 -24
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +143 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +34 -18
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.test.mjs +162 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/list-formatting.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-utils.mjs +15 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +9 -44
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +14 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +10 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +23 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +50 -39
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/builtin/tool-output-limit.mjs +10 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +70 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +497 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1192 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +39 -4189
- package/src/runtime/agent/orchestrator/tools/patch.mjs +119 -5
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
- package/src/runtime/channels/backends/discord.mjs +99 -9
- package/src/runtime/channels/backends/telegram.mjs +501 -0
- package/src/runtime/channels/index.mjs +437 -1439
- package/src/runtime/channels/lib/boot-profile.mjs +23 -0
- package/src/runtime/channels/lib/config.mjs +54 -2
- package/src/runtime/channels/lib/crash-log.mjs +106 -0
- package/src/runtime/channels/lib/format.mjs +4 -2
- package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
- package/src/runtime/channels/lib/output-forwarder.mjs +88 -67
- package/src/runtime/channels/lib/runtime-paths.mjs +29 -0
- package/src/runtime/channels/lib/scheduler.mjs +1 -1
- package/src/runtime/channels/lib/telegram-format.mjs +280 -0
- package/src/runtime/channels/lib/tool-format.mjs +1 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +19 -1
- package/src/runtime/channels/lib/webhook.mjs +59 -31
- package/src/runtime/channels/lib/whisper-language.mjs +42 -0
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +465 -345
- package/src/runtime/memory/lib/agent-ipc.mjs +2 -2
- package/src/runtime/memory/lib/core-memory-store.mjs +352 -2
- package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
- package/src/runtime/memory/lib/http-wire.mjs +57 -0
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle2.mjs +65 -9
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
- package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
- package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
- package/src/runtime/memory/lib/memory.mjs +121 -4
- package/src/runtime/memory/lib/pg/adapter.mjs +139 -15
- package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
- package/src/runtime/memory/lib/recall-format.mjs +183 -0
- package/src/runtime/memory/lib/session-ingest.mjs +107 -0
- package/src/runtime/memory/lib/trace-store.mjs +69 -22
- package/src/runtime/memory/tool-defs.mjs +10 -7
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/background-tasks.mjs +2 -3
- package/src/runtime/shared/buffered-appender.mjs +149 -0
- package/src/runtime/shared/channel-notification-routing.mjs +12 -0
- package/src/runtime/shared/channel-notification-routing.test.mjs +45 -0
- package/src/runtime/shared/config.mjs +9 -0
- package/src/runtime/shared/llm/http-agent.mjs +12 -5
- package/src/runtime/shared/schedules-store.mjs +21 -19
- package/src/runtime/shared/task-notification-envelope.mjs +98 -0
- package/src/runtime/shared/task-notification-envelope.test.mjs +107 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -2
- package/src/runtime/shared/tool-surface.mjs +98 -13
- package/src/runtime/shared/transcript-writer.mjs +156 -0
- package/src/runtime/shared/update-checker.mjs +214 -0
- package/src/session-runtime/config-helpers.mjs +209 -0
- package/src/session-runtime/effort.mjs +128 -0
- package/src/session-runtime/fs-utils.mjs +10 -0
- package/src/session-runtime/model-capabilities.mjs +130 -0
- package/src/session-runtime/output-styles.mjs +124 -0
- package/src/session-runtime/plugin-mcp.mjs +114 -0
- package/src/session-runtime/session-text.mjs +100 -0
- package/src/session-runtime/statusline-route.mjs +35 -0
- package/src/session-runtime/tool-catalog.mjs +720 -0
- package/src/session-runtime/workflow.mjs +358 -0
- package/src/standalone/agent-tool.mjs +302 -117
- package/src/standalone/channel-admin.mjs +133 -40
- package/src/standalone/channel-worker.mjs +10 -292
- package/src/standalone/explore-tool.mjs +12 -5
- package/src/standalone/hook-bus.mjs +165 -8
- package/src/standalone/memory-runtime-proxy.mjs +3 -1
- package/src/standalone/opencode-go-login.mjs +121 -0
- package/src/standalone/provider-admin.mjs +25 -3
- package/src/standalone/usage-dashboard.mjs +1 -1
- package/src/tui/App.jsx +2883 -778
- package/src/tui/components/ConfirmBar.jsx +47 -0
- package/src/tui/components/ContextPanel.jsx +5 -3
- package/src/tui/components/ItemRightHintOverprint.jsx +54 -0
- package/src/tui/components/Markdown.jsx +22 -98
- package/src/tui/components/Message.jsx +14 -35
- package/src/tui/components/Picker.jsx +87 -12
- package/src/tui/components/PromptInput.jsx +355 -22
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +8 -5
- package/src/tui/components/Spinner.jsx +7 -7
- package/src/tui/components/StatusLine.jsx +40 -21
- package/src/tui/components/TextEntryPanel.jsx +51 -7
- package/src/tui/components/ToolExecution.jsx +183 -101
- package/src/tui/components/TurnDone.jsx +4 -4
- package/src/tui/components/UsagePanel.jsx +1 -1
- package/src/tui/components/tool-output-format.mjs +161 -23
- package/src/tui/components/tool-output-format.test.mjs +87 -0
- package/src/tui/display-width.mjs +69 -0
- package/src/tui/display-width.test.mjs +35 -0
- package/src/tui/dist/index.mjs +6731 -2333
- package/src/tui/engine/agent-envelope.mjs +296 -0
- package/src/tui/engine/boot-profile.mjs +21 -0
- package/src/tui/engine/labels.mjs +67 -0
- package/src/tui/engine/notice-text.mjs +112 -0
- package/src/tui/engine/queue-helpers.mjs +161 -0
- package/src/tui/engine/session-stats.mjs +46 -0
- package/src/tui/engine/tool-call-fields.mjs +23 -0
- package/src/tui/engine/tool-result-text.mjs +126 -0
- package/src/tui/engine.mjs +569 -948
- package/src/tui/index.jsx +117 -7
- package/src/tui/input-editing.mjs +58 -8
- package/src/tui/input-editing.selection.test.mjs +75 -0
- package/src/tui/keyboard-protocol.mjs +42 -0
- package/src/tui/lib/voice-recorder.mjs +469 -0
- package/src/tui/markdown/format-token.mjs +128 -76
- package/src/tui/markdown/format-token.test.mjs +61 -19
- package/src/tui/markdown/measure-rendered-rows.mjs +85 -0
- package/src/tui/markdown/render-ansi.test.mjs +1 -1
- package/src/tui/markdown/streaming-markdown.mjs +167 -0
- package/src/tui/markdown/streaming-markdown.test.mjs +70 -0
- package/src/tui/markdown/table-layout.mjs +9 -9
- package/src/tui/paste-attachments.mjs +36 -9
- package/src/tui/paste-fix.test.mjs +119 -0
- package/src/tui/prompt-history-store.mjs +129 -0
- package/src/tui/prompt-history-store.test.mjs +52 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +3 -3
- package/src/tui/theme.mjs +41 -657
- package/src/tui/themes/base.mjs +86 -0
- package/src/tui/themes/basic.mjs +85 -0
- package/src/tui/themes/catppuccin.mjs +72 -0
- package/src/tui/themes/dracula.mjs +70 -0
- package/src/tui/themes/everforest.mjs +71 -0
- package/src/tui/themes/gruvbox.mjs +71 -0
- package/src/tui/themes/index.mjs +71 -0
- package/src/tui/themes/indigo.mjs +78 -0
- package/src/tui/themes/kanagawa.mjs +80 -0
- package/src/tui/themes/light.mjs +81 -0
- package/src/tui/themes/nord.mjs +72 -0
- package/src/tui/themes/onedark.mjs +16 -0
- package/src/tui/themes/rosepine.mjs +70 -0
- package/src/tui/themes/teal.mjs +80 -0
- package/src/tui/themes/tokyonight.mjs +79 -0
- package/src/tui/themes/utils.mjs +106 -0
- package/src/tui/themes/warm.mjs +79 -0
- package/src/tui/transcript-tool-failures.mjs +13 -2
- package/src/ui/markdown.mjs +1 -1
- package/src/ui/model-display.mjs +2 -2
- package/src/ui/statusline.mjs +75 -27
- package/src/vendor/statusline/bin/statusline-route.mjs +5 -12
- package/src/vendor/statusline/src/gateway/claude-current.mjs +3 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +30 -16
- package/src/workflows/default/WORKFLOW.md +46 -12
- package/src/workflows/sequential/WORKFLOW.md +51 -0
- package/src/workflows/solo/WORKFLOW.md +12 -1
- package/vendor/ink/build/display-width.js +62 -0
- package/vendor/ink/build/ink.js +100 -12
- package/vendor/ink/build/measure-text.js +4 -1
- package/vendor/ink/build/output.js +115 -9
- package/vendor/ink/build/render-node-to-output.js +4 -1
- package/vendor/ink/build/render.js +4 -0
- package/src/output-styles/extreme-simple.md +0 -20
- package/src/rules/lead/04-workflow.md +0 -51
- package/src/workflows/default/workflow.json +0 -13
- package/src/workflows/solo/workflow.json +0 -7
|
@@ -86,7 +86,7 @@ const PLAIN_STDOUT_CONTEXT_EVENTS = new Set([
|
|
|
86
86
|
'UserPromptExpansion',
|
|
87
87
|
]);
|
|
88
88
|
|
|
89
|
-
const SUPPORTED_HANDLER_TYPES = new Set(['command', 'http']);
|
|
89
|
+
const SUPPORTED_HANDLER_TYPES = new Set(['command', 'http', 'mcp_tool', 'prompt']);
|
|
90
90
|
|
|
91
91
|
function compactValue(value) {
|
|
92
92
|
if (value == null) return value;
|
|
@@ -349,6 +349,7 @@ function buildEventPayload(eventName, input = {}) {
|
|
|
349
349
|
'expansion_type',
|
|
350
350
|
'stop_reason',
|
|
351
351
|
'error_type',
|
|
352
|
+
'agent_type',
|
|
352
353
|
]) {
|
|
353
354
|
if (input[key] != null) payload[key] = input[key];
|
|
354
355
|
}
|
|
@@ -374,6 +375,7 @@ function handlerTimeoutS(handler, eventName) {
|
|
|
374
375
|
if (Number.isFinite(handler.timeout) && handler.timeout > 0) return handler.timeout;
|
|
375
376
|
if (handler.type === 'prompt') return DEFAULT_PROMPT_TIMEOUT_S;
|
|
376
377
|
if (handler.type === 'agent') return DEFAULT_AGENT_TIMEOUT_S;
|
|
378
|
+
if (handler.type === 'mcp_tool') return DEFAULT_COMMAND_TIMEOUT_S;
|
|
377
379
|
if (eventName === 'UserPromptSubmit') return USER_PROMPT_TIMEOUT_S;
|
|
378
380
|
if (eventName === 'MessageDisplay') return MESSAGE_DISPLAY_TIMEOUT_S;
|
|
379
381
|
return DEFAULT_COMMAND_TIMEOUT_S;
|
|
@@ -427,7 +429,7 @@ function hookEnv(projectDir, pluginData, payload, pluginRoot = null) {
|
|
|
427
429
|
return env;
|
|
428
430
|
}
|
|
429
431
|
|
|
430
|
-
function runCommandHandler(handler, payload, eventName, pluginData, onSpawnError = null) {
|
|
432
|
+
function runCommandHandler(handler, payload, eventName, pluginData, onSpawnError = null, onRewake = null) {
|
|
431
433
|
const projectDir = payload.cwd || process.cwd();
|
|
432
434
|
const effectivePluginData = handler._pluginData || pluginData || null;
|
|
433
435
|
const stdin = JSON.stringify(payload);
|
|
@@ -440,7 +442,58 @@ function runCommandHandler(handler, payload, eventName, pluginData, onSpawnError
|
|
|
440
442
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
441
443
|
};
|
|
442
444
|
|
|
443
|
-
if (handler.
|
|
445
|
+
if (handler.asyncRewake === true) {
|
|
446
|
+
try {
|
|
447
|
+
const child = spawn(spec.command, spec.args, {
|
|
448
|
+
...baseOpts,
|
|
449
|
+
});
|
|
450
|
+
let bgStdout = '';
|
|
451
|
+
let bgStderr = '';
|
|
452
|
+
let bgStdoutBytes = 0;
|
|
453
|
+
let bgStderrBytes = 0;
|
|
454
|
+
let killed = false;
|
|
455
|
+
child.stdout?.on('data', (chunk) => {
|
|
456
|
+
bgStdoutBytes += chunk.length;
|
|
457
|
+
if (bgStdoutBytes <= MAX_BUFFER_BYTES) bgStdout += chunk.toString('utf8');
|
|
458
|
+
});
|
|
459
|
+
child.stderr?.on('data', (chunk) => {
|
|
460
|
+
bgStderrBytes += chunk.length;
|
|
461
|
+
if (bgStderrBytes <= MAX_BUFFER_BYTES) bgStderr += chunk.toString('utf8');
|
|
462
|
+
});
|
|
463
|
+
const killTimer = setTimeout(() => {
|
|
464
|
+
killed = true;
|
|
465
|
+
try { child.stdout?.removeAllListeners('data'); } catch {}
|
|
466
|
+
try { child.stderr?.removeAllListeners('data'); } catch {}
|
|
467
|
+
try { child.kill('SIGTERM'); } catch {}
|
|
468
|
+
}, timeoutMs);
|
|
469
|
+
killTimer.unref?.();
|
|
470
|
+
child.on('error', (error) => {
|
|
471
|
+
clearTimeout(killTimer);
|
|
472
|
+
if (typeof onSpawnError === 'function') onSpawnError(error);
|
|
473
|
+
});
|
|
474
|
+
child.on('close', (code) => {
|
|
475
|
+
clearTimeout(killTimer);
|
|
476
|
+
try {
|
|
477
|
+
if (!killed && code === 2 && typeof onRewake === 'function') {
|
|
478
|
+
const text = (bgStderr || '').trim() || (bgStdout || '').trim();
|
|
479
|
+
onRewake({ eventName, payload, text });
|
|
480
|
+
}
|
|
481
|
+
} catch {}
|
|
482
|
+
});
|
|
483
|
+
child.stdin?.end(stdin);
|
|
484
|
+
return Promise.resolve({ exitCode: 0, stdout: '', stderr: '', async: true });
|
|
485
|
+
} catch (error) {
|
|
486
|
+
return Promise.resolve({
|
|
487
|
+
exitCode: -1,
|
|
488
|
+
stdout: '',
|
|
489
|
+
stderr: error?.message || String(error),
|
|
490
|
+
timedOut: false,
|
|
491
|
+
spawnError: error,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (handler.async === true) {
|
|
444
497
|
try {
|
|
445
498
|
const child = spawn(spec.command, spec.args, {
|
|
446
499
|
...baseOpts,
|
|
@@ -584,6 +637,78 @@ async function runHttpHandler(handler, payload, eventName) {
|
|
|
584
637
|
}
|
|
585
638
|
}
|
|
586
639
|
|
|
640
|
+
async function runMcpToolHandler(handler, payload, eventName, mcpToolRunner) {
|
|
641
|
+
const timeoutMs = Math.round(handlerTimeoutS(handler, eventName) * 1000);
|
|
642
|
+
let name = String(handler.tool || '').trim();
|
|
643
|
+
if (handler.server && !name.startsWith('mcp__')) {
|
|
644
|
+
name = `mcp__${String(handler.server).trim()}__${name}`;
|
|
645
|
+
}
|
|
646
|
+
if (!name) {
|
|
647
|
+
return { exitCode: -1, stdout: '', stderr: 'mcp_tool handler missing tool name', timedOut: false, spawnError: null };
|
|
648
|
+
}
|
|
649
|
+
let timer = null;
|
|
650
|
+
try {
|
|
651
|
+
const runPromise = Promise.resolve(mcpToolRunner({ name, args: payload }));
|
|
652
|
+
const text = await Promise.race([
|
|
653
|
+
runPromise,
|
|
654
|
+
new Promise((_r, reject) => {
|
|
655
|
+
timer = setTimeout(() => reject(new Error(`mcp_tool hook timed out: ${name}`)), timeoutMs);
|
|
656
|
+
// No unref: this timer must keep the event loop alive so the race can
|
|
657
|
+
// settle even when the runner promise never resolves. Cleared in finally.
|
|
658
|
+
}),
|
|
659
|
+
]);
|
|
660
|
+
return { exitCode: 0, stdout: limitText(String(text ?? '')), stderr: '', timedOut: false, spawnError: null };
|
|
661
|
+
} catch (error) {
|
|
662
|
+
const timedOut = /timed out/i.test(error?.message || '');
|
|
663
|
+
return { exitCode: -1, stdout: '', stderr: error?.message || String(error), timedOut, spawnError: null };
|
|
664
|
+
} finally {
|
|
665
|
+
if (timer) clearTimeout(timer);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
async function runPromptHandler(handler, payload, eventName, promptRunner) {
|
|
670
|
+
const timeoutMs = Math.round(handlerTimeoutS(handler, eventName) * 1000);
|
|
671
|
+
const prompt = String(handler.prompt || '');
|
|
672
|
+
if (!prompt) {
|
|
673
|
+
return { exitCode: -1, stdout: '', stderr: 'prompt handler missing prompt', timedOut: false, spawnError: null };
|
|
674
|
+
}
|
|
675
|
+
let timer = null;
|
|
676
|
+
try {
|
|
677
|
+
const runPromise = Promise.resolve(promptRunner({ prompt, payload, timeoutMs }));
|
|
678
|
+
const text = await Promise.race([
|
|
679
|
+
runPromise,
|
|
680
|
+
new Promise((_r, reject) => {
|
|
681
|
+
timer = setTimeout(() => reject(new Error(`prompt hook timed out: ${eventName}`)), timeoutMs);
|
|
682
|
+
// No unref: this timer must keep the event loop alive so the race can
|
|
683
|
+
// settle even when the runner promise never resolves. Cleared in finally.
|
|
684
|
+
}),
|
|
685
|
+
]);
|
|
686
|
+
const raw = String(text ?? '').trim();
|
|
687
|
+
const deny = (reason) => ({ exitCode: 2, stdout: '', stderr: reason, timedOut: false, spawnError: null });
|
|
688
|
+
const allow = () => ({ exitCode: 0, stdout: '', stderr: '', timedOut: false, spawnError: null });
|
|
689
|
+
let verdict = null;
|
|
690
|
+
try {
|
|
691
|
+
verdict = JSON.parse(raw);
|
|
692
|
+
} catch {
|
|
693
|
+
verdict = undefined;
|
|
694
|
+
}
|
|
695
|
+
if (verdict && typeof verdict === 'object') {
|
|
696
|
+
if (verdict.ok === false) return deny(String(verdict.reason || `blocked by ${eventName} prompt hook`));
|
|
697
|
+
return allow();
|
|
698
|
+
}
|
|
699
|
+
// plain-text response
|
|
700
|
+
const lowered = raw.toLowerCase();
|
|
701
|
+
if (!raw || ['yes', 'true', 'allow', 'ok'].includes(lowered)) return allow();
|
|
702
|
+
if (['no', 'false', 'deny', 'block'].includes(lowered)) return deny(raw || `blocked by ${eventName} prompt hook`);
|
|
703
|
+
return allow();
|
|
704
|
+
} catch (error) {
|
|
705
|
+
const timedOut = /timed out/i.test(error?.message || '');
|
|
706
|
+
return { exitCode: -1, stdout: '', stderr: error?.message || String(error), timedOut, spawnError: null };
|
|
707
|
+
} finally {
|
|
708
|
+
if (timer) clearTimeout(timer);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
587
712
|
function limitText(text) {
|
|
588
713
|
const value = String(text || '');
|
|
589
714
|
if (value.length <= MAX_OUTPUT_CHARS) return value;
|
|
@@ -727,10 +852,13 @@ function summarizeRule(rule, index) {
|
|
|
727
852
|
|
|
728
853
|
function handlerDedupeKey(handler) {
|
|
729
854
|
if (!handler || typeof handler !== 'object') return '';
|
|
855
|
+
const ifKey = handler.if != null ? `|if:${JSON.stringify(handler.if)}` : '';
|
|
730
856
|
if (handler.type === 'command') {
|
|
731
|
-
return `command:${handler._pluginRoot || ''}:${handler.command || ''}:${JSON.stringify(handler.args || null)}`;
|
|
857
|
+
return `command:${handler._pluginRoot || ''}:${handler.command || ''}:${JSON.stringify(handler.args || null)}${ifKey}`;
|
|
732
858
|
}
|
|
733
|
-
if (handler.type === 'http') return `http:${handler.url || ''}`;
|
|
859
|
+
if (handler.type === 'http') return `http:${handler.url || ''}${ifKey}`;
|
|
860
|
+
if (handler.type === 'mcp_tool') return `mcp_tool:${handler.server || ''}:${handler.tool || ''}${ifKey}`;
|
|
861
|
+
if (handler.type === 'prompt') return `prompt:${handler.prompt || ''}${ifKey}`;
|
|
734
862
|
return `${handler.type || 'unknown'}:${JSON.stringify(handler)}`;
|
|
735
863
|
}
|
|
736
864
|
|
|
@@ -742,11 +870,12 @@ function shellCountFor(handler) {
|
|
|
742
870
|
return handler?.type || 'unknown';
|
|
743
871
|
}
|
|
744
872
|
|
|
745
|
-
export function createStandaloneHookBus({ maxEvents = 80, dataDir = null } = {}) {
|
|
873
|
+
export function createStandaloneHookBus({ maxEvents = 80, dataDir = null, promptRunner = null, mcpToolRunner = null } = {}) {
|
|
746
874
|
const recent = [];
|
|
747
875
|
const counts = new Map(DEFAULT_EVENTS.map((name) => [name, 0]));
|
|
748
876
|
const rulesPath = hookRulesPath(dataDir);
|
|
749
877
|
const pluginData = dataDir || null;
|
|
878
|
+
let rewakeHandler = null;
|
|
750
879
|
let rulesCache = { mtimeMs: -1, rules: [] };
|
|
751
880
|
let configCache = {
|
|
752
881
|
key: '',
|
|
@@ -883,12 +1012,35 @@ export function createStandaloneHookBus({ maxEvents = 80, dataDir = null } = {})
|
|
|
883
1012
|
error: `hook spawn failed: ${error?.message || error}`,
|
|
884
1013
|
});
|
|
885
1014
|
};
|
|
886
|
-
|
|
1015
|
+
const reportRewake = ({ eventName: en, payload: pl, text }) => {
|
|
1016
|
+
try {
|
|
1017
|
+
if (typeof rewakeHandler === 'function') {
|
|
1018
|
+
rewakeHandler({ eventName: en, payload: pl, text });
|
|
1019
|
+
} else {
|
|
1020
|
+
emit('hook:rewake', { name: pl?.tool_name || en, text: text || null });
|
|
1021
|
+
}
|
|
1022
|
+
} catch {}
|
|
1023
|
+
};
|
|
1024
|
+
return await runCommandHandler(handler, payload, eventName, pluginData, reportSpawnError, reportRewake);
|
|
887
1025
|
}
|
|
888
1026
|
if (type === 'http') {
|
|
889
1027
|
if (!handler.url) return null;
|
|
890
1028
|
return await runHttpHandler(handler, payload, eventName);
|
|
891
1029
|
}
|
|
1030
|
+
if (type === 'mcp_tool') {
|
|
1031
|
+
if (typeof mcpToolRunner !== 'function') {
|
|
1032
|
+
emit('hook:error', { name: payload.tool_name || eventName, error: 'handler type mcp_tool not configured' });
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
1035
|
+
return await runMcpToolHandler(handler, payload, eventName, mcpToolRunner);
|
|
1036
|
+
}
|
|
1037
|
+
if (type === 'prompt') {
|
|
1038
|
+
if (typeof promptRunner !== 'function') {
|
|
1039
|
+
emit('hook:error', { name: payload.tool_name || eventName, error: 'handler type prompt not configured' });
|
|
1040
|
+
return null;
|
|
1041
|
+
}
|
|
1042
|
+
return await runPromptHandler(handler, payload, eventName, promptRunner);
|
|
1043
|
+
}
|
|
892
1044
|
return null;
|
|
893
1045
|
}
|
|
894
1046
|
|
|
@@ -1118,5 +1270,10 @@ export function createStandaloneHookBus({ maxEvents = 80, dataDir = null } = {})
|
|
|
1118
1270
|
};
|
|
1119
1271
|
}
|
|
1120
1272
|
|
|
1121
|
-
|
|
1273
|
+
function setRewakeHandler(fn) {
|
|
1274
|
+
rewakeHandler = typeof fn === 'function' ? fn : null;
|
|
1275
|
+
return rewakeHandler;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
return { addRule, beforeTool, deleteRule, dispatch, emit, listRules, setRewakeHandler, setRuleEnabled, status };
|
|
1122
1279
|
}
|
|
@@ -188,12 +188,14 @@ export function createStandaloneMemoryRuntime({
|
|
|
188
188
|
releaseOwnerIfSelf();
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
const daemonEnv = { ...process.env };
|
|
192
|
+
delete daemonEnv.MIXDOG_QUIET_MEMORY_LOG;
|
|
191
193
|
child = fork(entry, [], {
|
|
192
194
|
cwd,
|
|
193
195
|
stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
|
|
194
196
|
detached: true,
|
|
195
197
|
env: {
|
|
196
|
-
...
|
|
198
|
+
...daemonEnv,
|
|
197
199
|
MIXDOG_DATA_DIR: dataDir,
|
|
198
200
|
MIXDOG_WORKER_MODE: '1',
|
|
199
201
|
MIXDOG_STANDALONE: '1',
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
|
|
3
|
+
const COMMON_BROWSER_PATHS = (() => {
|
|
4
|
+
const platform = process.platform;
|
|
5
|
+
if (platform === 'win32') {
|
|
6
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
7
|
+
const programFiles = process.env.PROGRAMFILES || 'C:/Program Files';
|
|
8
|
+
const programFilesX86 = process.env['PROGRAMFILES(X86)'] || 'C:/Program Files (x86)';
|
|
9
|
+
return [
|
|
10
|
+
`${programFiles}/Google/Chrome/Application/chrome.exe`,
|
|
11
|
+
`${programFilesX86}/Google/Chrome/Application/chrome.exe`,
|
|
12
|
+
localAppData && `${localAppData}/Google/Chrome/Application/chrome.exe`,
|
|
13
|
+
`${programFiles}/Microsoft/Edge/Application/msedge.exe`,
|
|
14
|
+
`${programFilesX86}/Microsoft/Edge/Application/msedge.exe`,
|
|
15
|
+
localAppData && `${localAppData}/Microsoft/Edge/Application/msedge.exe`,
|
|
16
|
+
].filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
if (platform === 'linux') {
|
|
19
|
+
return [
|
|
20
|
+
'/usr/bin/google-chrome',
|
|
21
|
+
'/usr/bin/google-chrome-stable',
|
|
22
|
+
'/usr/bin/chromium',
|
|
23
|
+
'/usr/bin/chromium-browser',
|
|
24
|
+
'/snap/bin/chromium',
|
|
25
|
+
'/usr/bin/microsoft-edge',
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
return [
|
|
29
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
30
|
+
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
|
31
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
32
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
33
|
+
];
|
|
34
|
+
})();
|
|
35
|
+
|
|
36
|
+
function resolveExecutablePath() {
|
|
37
|
+
if (process.env.PUPPETEER_EXECUTABLE_PATH && fs.existsSync(process.env.PUPPETEER_EXECUTABLE_PATH)) {
|
|
38
|
+
return process.env.PUPPETEER_EXECUTABLE_PATH;
|
|
39
|
+
}
|
|
40
|
+
for (const executablePath of COMMON_BROWSER_PATHS) {
|
|
41
|
+
if (fs.existsSync(executablePath)) return executablePath;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let _inflight = null;
|
|
47
|
+
|
|
48
|
+
export async function loginOpenCodeGoConsoleWithBrowser({ timeoutMs = 300_000, onStatus } = {}) {
|
|
49
|
+
if (_inflight) return _inflight;
|
|
50
|
+
_inflight = _run({ timeoutMs, onStatus }).finally(() => { _inflight = null; });
|
|
51
|
+
return _inflight;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function _run({ timeoutMs, onStatus }) {
|
|
55
|
+
const status = (msg) => { try { if (typeof onStatus === 'function') onStatus(msg); } catch {} };
|
|
56
|
+
const executablePath = resolveExecutablePath();
|
|
57
|
+
if (!executablePath) {
|
|
58
|
+
throw new Error('No Chrome/Edge browser found. Set PUPPETEER_EXECUTABLE_PATH to a Chrome or Edge executable.');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const puppeteer = (await import('puppeteer-core')).default;
|
|
62
|
+
let browser = null;
|
|
63
|
+
let closed = false;
|
|
64
|
+
const closeBrowser = async () => {
|
|
65
|
+
if (closed) return;
|
|
66
|
+
closed = true;
|
|
67
|
+
try { if (browser) await browser.close(); } catch {}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
status('Launching browser…');
|
|
72
|
+
browser = await puppeteer.launch({
|
|
73
|
+
headless: false,
|
|
74
|
+
executablePath,
|
|
75
|
+
defaultViewport: null,
|
|
76
|
+
args: ['--disable-dev-shm-usage'],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
let disconnected = false;
|
|
80
|
+
browser.on('disconnected', () => { disconnected = true; });
|
|
81
|
+
|
|
82
|
+
const page = (await browser.pages())[0] || (await browser.newPage());
|
|
83
|
+
status('Opening opencode.ai/auth — please sign in…');
|
|
84
|
+
await page.goto('https://opencode.ai/auth', { waitUntil: 'domcontentloaded' }).catch(() => {});
|
|
85
|
+
|
|
86
|
+
const deadline = Date.now() + timeoutMs;
|
|
87
|
+
while (Date.now() < deadline) {
|
|
88
|
+
if (disconnected || page.isClosed()) {
|
|
89
|
+
throw new Error('Browser was closed before login completed.');
|
|
90
|
+
}
|
|
91
|
+
let cookies;
|
|
92
|
+
try {
|
|
93
|
+
cookies = await page.cookies('https://opencode.ai');
|
|
94
|
+
} catch {
|
|
95
|
+
throw new Error('Browser was closed before login completed.');
|
|
96
|
+
}
|
|
97
|
+
const auth = cookies.find(c => c.name === 'auth');
|
|
98
|
+
const url = page.url();
|
|
99
|
+
const wsMatch = url.match(/\/workspace\/(wrk_[a-zA-Z0-9]+)/);
|
|
100
|
+
// Only treat the login as complete on an authenticated console page.
|
|
101
|
+
// A pre-existing/stale auth cookie on a marketing or docs page must not
|
|
102
|
+
// short-circuit the flow with workspaceId:null.
|
|
103
|
+
const onWorkspace = (() => {
|
|
104
|
+
try {
|
|
105
|
+
const parsed = new URL(url);
|
|
106
|
+
return parsed.hostname.endsWith('opencode.ai') && /^\/(?:[a-z-]+\/)?workspace(\/|$)/.test(parsed.pathname);
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
})();
|
|
111
|
+
if (auth && auth.value && (wsMatch || onWorkspace)) {
|
|
112
|
+
status('Auth cookie captured.');
|
|
113
|
+
return { authCookie: auth.value, workspaceId: wsMatch?.[1] || null };
|
|
114
|
+
}
|
|
115
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
116
|
+
}
|
|
117
|
+
throw new Error(`Timed out after ${Math.round(timeoutMs / 1000)}s waiting for OpenCode Go login.`);
|
|
118
|
+
} finally {
|
|
119
|
+
await closeBrowser();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -52,6 +52,17 @@ const API_PROVIDER_IDS = new Set(API_PROVIDERS.map((p) => p.id));
|
|
|
52
52
|
const OAUTH_BY_ID = new Map(OAUTH_PROVIDERS.map((p) => [p.id, p]));
|
|
53
53
|
const LOCAL_BY_ID = new Map(LOCAL_PROVIDERS.map((p) => [p.id, p]));
|
|
54
54
|
|
|
55
|
+
const ALL_PROVIDER_IDS = new Set([
|
|
56
|
+
...API_PROVIDERS.map((p) => p.id),
|
|
57
|
+
...OAUTH_PROVIDERS.map((p) => p.id),
|
|
58
|
+
...LOCAL_PROVIDERS.map((p) => p.id),
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
export function isKnownProvider(provider) {
|
|
62
|
+
const id = String(provider || '').trim();
|
|
63
|
+
return id !== '' && ALL_PROVIDER_IDS.has(id);
|
|
64
|
+
}
|
|
65
|
+
|
|
55
66
|
async function detectLocalProvider(baseURL) {
|
|
56
67
|
const url = String(baseURL || '').replace(/\/+$/, '') + '/models';
|
|
57
68
|
const controller = new AbortController();
|
|
@@ -303,12 +314,23 @@ export function saveOpenCodeGoUsageAuth(cfgMod, { workspaceId, authCookie } = {}
|
|
|
303
314
|
if (!cookie) throw new Error('OpenCode auth cookie is required for usage lookup');
|
|
304
315
|
const authMatch = /(?:^|;\s*)auth=([^;]+)/.exec(cookie);
|
|
305
316
|
saveSecret(SECRET_ACCOUNTS.opencodeGoAuthCookie, authMatch ? authMatch[1] : cookie);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
// Usage auth is a console cookie, not a model API key. Only flip the model
|
|
318
|
+
// provider on when a key actually exists; otherwise cookie-only setups get
|
|
319
|
+
// routed to the provider with apiKey 'no-key' and fail with 401s.
|
|
320
|
+
const hasApiKey = Boolean(getAgentApiKey('opencode-go'));
|
|
321
|
+
updateConfigProvider(cfgMod, 'opencode-go', {
|
|
322
|
+
...(hasApiKey ? { enabled: true } : {}),
|
|
323
|
+
...(workspace ? { workspaceId: workspace } : {}),
|
|
324
|
+
});
|
|
309
325
|
return { provider: 'opencode-go', type: 'usage-auth', authenticated: true, workspaceId: workspace || null };
|
|
310
326
|
}
|
|
311
327
|
|
|
328
|
+
export async function loginOpenCodeGoUsage(cfgMod) {
|
|
329
|
+
const { loginOpenCodeGoConsoleWithBrowser } = await import('./opencode-go-login.mjs');
|
|
330
|
+
const { workspaceId, authCookie } = await loginOpenCodeGoConsoleWithBrowser();
|
|
331
|
+
return saveOpenCodeGoUsageAuth(cfgMod, { workspaceId, authCookie });
|
|
332
|
+
}
|
|
333
|
+
|
|
312
334
|
export function setLocalProvider(cfgMod, provider, { enabled, baseURL } = {}) {
|
|
313
335
|
const id = String(provider || '').trim();
|
|
314
336
|
const local = LOCAL_BY_ID.get(id);
|
|
@@ -29,7 +29,7 @@ function clean(value) {
|
|
|
29
29
|
|
|
30
30
|
function money(value) {
|
|
31
31
|
const n = Number(value);
|
|
32
|
-
if (!Number.isFinite(n)) return '
|
|
32
|
+
if (!Number.isFinite(n)) return 'N/A';
|
|
33
33
|
if (n === 0) return '$0';
|
|
34
34
|
if (n >= 10) return `$${n.toFixed(0)}`;
|
|
35
35
|
if (n >= 1) return `$${n.toFixed(2)}`;
|