muonroi-cli 1.7.2 → 1.8.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/LICENSE +21 -21
- package/README.md +122 -122
- package/dist/packages/agent-harness-core/src/event-filter.js +1 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +8 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +16 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +88 -10
- package/dist/packages/agent-harness-core/src/protocol.d.ts +15 -0
- package/dist/packages/agent-harness-core/src/selector.js +2 -2
- package/dist/packages/agent-harness-core/src/transports/sidechannel.js +1 -1
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +1 -1
- package/dist/packages/agent-harness-opentui/src/install.js +1 -1
- package/dist/src/__test-stubs__/vitest-setup.js +4 -0
- package/dist/src/agent-harness/__tests__/mock-model.spec.js +54 -0
- package/dist/src/agent-harness/mock-model.d.ts +1 -1
- package/dist/src/agent-harness/mock-model.js +32 -3
- package/dist/src/agent-harness/test-spawn.js +3 -1
- package/dist/src/chat/chat-keychain.js +9 -1
- package/dist/src/cli/cost-forensics.js +12 -12
- package/dist/src/cli/keys.d.ts +2 -2
- package/dist/src/cli/keys.js +107 -28
- package/dist/src/cli/usage-report.js +2 -2
- package/dist/src/council/__tests__/abort-threading.test.d.ts +1 -0
- package/dist/src/council/__tests__/abort-threading.test.js +193 -0
- package/dist/src/council/__tests__/clarification-prompt.test.js +21 -1
- package/dist/src/council/__tests__/council-turn-length-emit.test.d.ts +1 -0
- package/dist/src/council/__tests__/council-turn-length-emit.test.js +130 -0
- package/dist/src/council/__tests__/debate-round-budget.test.d.ts +1 -0
- package/dist/src/council/__tests__/debate-round-budget.test.js +45 -0
- package/dist/src/council/__tests__/evaluator-metrics.test.js +3 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.d.ts +1 -0
- package/dist/src/council/__tests__/post-debate-recommendation.test.js +58 -0
- package/dist/src/council/__tests__/research-tools.test.js +4 -0
- package/dist/src/council/__tests__/round-tools.test.js +6 -0
- package/dist/src/council/clarifier-question-cap.test.d.ts +12 -0
- package/dist/src/council/clarifier-question-cap.test.js +73 -0
- package/dist/src/council/clarifier.d.ts +29 -1
- package/dist/src/council/clarifier.js +64 -1
- package/dist/src/council/debate-planner.d.ts +2 -1
- package/dist/src/council/debate-planner.js +5 -3
- package/dist/src/council/debate.d.ts +9 -0
- package/dist/src/council/debate.js +88 -8
- package/dist/src/council/index.d.ts +46 -1
- package/dist/src/council/index.js +125 -19
- package/dist/src/council/llm.js +41 -13
- package/dist/src/council/prompts.js +56 -21
- package/dist/src/council/types.d.ts +14 -1
- package/dist/src/ee/__tests__/export-transcripts.test.js +1 -1
- package/dist/src/ee/bridge.d.ts +3 -1
- package/dist/src/ee/bridge.js +9 -3
- package/dist/src/ee/bridge.test.js +1 -2
- package/dist/src/ee/client.js +15 -2
- package/dist/src/ee/recall-ledger.d.ts +20 -0
- package/dist/src/ee/recall-ledger.js +40 -1
- package/dist/src/ee/search.d.ts +25 -0
- package/dist/src/ee/search.js +73 -0
- package/dist/src/ee/types.d.ts +15 -1
- package/dist/src/ee/who-am-i.d.ts +41 -0
- package/dist/src/ee/who-am-i.js +143 -0
- package/dist/src/ee/who-am-i.test.d.ts +1 -0
- package/dist/src/ee/who-am-i.test.js +101 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/headless/council-answers.js +1 -0
- package/dist/src/headless/output.d.ts +30 -1
- package/dist/src/headless/output.js +180 -0
- package/dist/src/headless/output.test.js +61 -1
- package/dist/src/hooks/index.js +48 -2
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +55 -60
- package/dist/src/lsp/client-normalize.test.d.ts +12 -0
- package/dist/src/lsp/client-normalize.test.js +34 -0
- package/dist/src/lsp/client.d.ts +1 -0
- package/dist/src/lsp/client.js +10 -2
- package/dist/src/lsp/manager.d.ts +1 -1
- package/dist/src/lsp/manager.js +2 -2
- package/dist/src/lsp/manager.test.js +2 -2
- package/dist/src/lsp/runtime.d.ts +1 -1
- package/dist/src/lsp/runtime.js +2 -2
- package/dist/src/maintain/__tests__/gh-create-pr.test.js +7 -3
- package/dist/src/maintain/__tests__/pr-builder.test.js +7 -3
- package/dist/src/mcp/__tests__/client-pool.spec.js +3 -3
- package/dist/src/mcp/__tests__/ee-tools.test.js +42 -14
- package/dist/src/mcp/__tests__/forensics-tools.test.js +3 -3
- package/dist/src/mcp/__tests__/lsp-tools.test.js +4 -4
- package/dist/src/mcp/client-pool.d.ts +1 -1
- package/dist/src/mcp/client-pool.js +25 -9
- package/dist/src/mcp/ee-tools.d.ts +10 -0
- package/dist/src/mcp/ee-tools.js +34 -0
- package/dist/src/mcp/oauth-callback.js +2 -2
- package/dist/src/mcp/parse-headers.test.js +14 -14
- package/dist/src/mcp/self-verify-jobs.js +1 -3
- package/dist/src/mcp/setup-guide-text.js +74 -74
- package/dist/src/mcp/smoke.test.js +43 -43
- package/dist/src/models/catalog-gemini.test.js +12 -10
- package/dist/src/models/catalog.json +106 -38
- package/dist/src/ops/doctor.js +7 -7
- package/dist/src/orchestrator/__tests__/auto-commit.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/auto-commit.test.js +142 -0
- package/dist/src/orchestrator/__tests__/batch-turn-runner.test.js +2 -0
- package/dist/src/orchestrator/__tests__/delegations.test.d.ts +1 -0
- package/dist/src/orchestrator/__tests__/delegations.test.js +96 -0
- package/dist/src/orchestrator/__tests__/message-processor.test.js +1 -0
- package/dist/src/orchestrator/__tests__/stream-runner.test.js +29 -0
- package/dist/src/orchestrator/agent.test.js +5 -2
- package/dist/src/orchestrator/auto-commit.d.ts +110 -0
- package/dist/src/orchestrator/auto-commit.js +364 -0
- package/dist/src/orchestrator/batch-turn-runner.d.ts +3 -2
- package/dist/src/orchestrator/batch-turn-runner.js +2 -1
- package/dist/src/orchestrator/compaction-proposer-prompt.d.ts +8 -0
- package/dist/src/orchestrator/compaction-proposer-prompt.js +43 -0
- package/dist/src/orchestrator/compaction.d.ts +22 -0
- package/dist/src/orchestrator/compaction.js +42 -0
- package/dist/src/orchestrator/delegations.d.ts +1 -0
- package/dist/src/orchestrator/delegations.js +41 -0
- package/dist/src/orchestrator/error-utils.js +27 -2
- package/dist/src/orchestrator/message-processor.d.ts +21 -5
- package/dist/src/orchestrator/message-processor.js +219 -2573
- package/dist/src/orchestrator/orchestrator.d.ts +8 -2
- package/dist/src/orchestrator/orchestrator.js +187 -34
- package/dist/src/orchestrator/preprocessor.d.ts +13 -0
- package/dist/src/orchestrator/preprocessor.js +145 -0
- package/dist/src/orchestrator/prompts.d.ts +8 -0
- package/dist/src/orchestrator/prompts.js +76 -60
- package/dist/src/orchestrator/safety-askcard.d.ts +66 -0
- package/dist/src/orchestrator/safety-askcard.js +74 -0
- package/dist/src/orchestrator/sandbox.test.js +8 -5
- package/dist/src/orchestrator/scope-ceiling.js +1 -1
- package/dist/src/orchestrator/stall-watchdog.d.ts +47 -0
- package/dist/src/orchestrator/stall-watchdog.js +23 -0
- package/dist/src/orchestrator/stall-watchdog.test.js +36 -1
- package/dist/src/orchestrator/stream-runner.js +52 -30
- package/dist/src/orchestrator/sub-agent-model-tier.js +1 -1
- package/dist/src/orchestrator/subagent-compactor.d.ts +14 -0
- package/dist/src/orchestrator/subagent-compactor.js +83 -10
- package/dist/src/orchestrator/subagent-compactor.spec.js +132 -0
- package/dist/src/orchestrator/text-tool-call-detector.d.ts +9 -5
- package/dist/src/orchestrator/text-tool-call-detector.js +16 -12
- package/dist/src/orchestrator/text-tool-call-detector.test.js +66 -8
- package/dist/src/orchestrator/tool-args-repair.js +1 -1
- package/dist/src/orchestrator/tool-engine.d.ts +151 -0
- package/dist/src/orchestrator/tool-engine.js +3079 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +1 -0
- package/dist/src/pil/__tests__/discovery-types.test.js +15 -4
- package/dist/src/pil/__tests__/discovery.test.js +89 -145
- package/dist/src/pil/__tests__/dual-run.test.js +2 -0
- package/dist/src/pil/__tests__/layer1-intent-trace.test.js +3 -0
- package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
- package/dist/src/pil/__tests__/layer16-clarity.test.js +35 -32
- package/dist/src/pil/__tests__/layer18-acceptance.test.js +1 -78
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.d.ts +1 -0
- package/dist/src/pil/__tests__/layer2_5-ponytail.test.js +53 -0
- package/dist/src/pil/__tests__/layer3-ee-injection.test.js +67 -4
- package/dist/src/pil/__tests__/layer3-injected-chunk.test.js +14 -2
- package/dist/src/pil/__tests__/layer4-gsd.test.js +30 -0
- package/dist/src/pil/__tests__/layer5-context.test.js +39 -1
- package/dist/src/pil/__tests__/layer6-output.test.js +30 -2
- package/dist/src/pil/__tests__/orchestrator-integration.test.js +3 -1
- package/dist/src/pil/__tests__/pipeline.test.js +11 -8
- package/dist/src/pil/__tests__/response-tools.test.js +52 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +5 -3
- package/dist/src/pil/agent-operating-contract.test.js +2 -2
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +1 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/config.d.ts +20 -0
- package/dist/src/pil/config.js +35 -0
- package/dist/src/pil/discovery-types.d.ts +32 -9
- package/dist/src/pil/discovery.d.ts +3 -3
- package/dist/src/pil/discovery.js +138 -244
- package/dist/src/pil/index.d.ts +1 -1
- package/dist/src/pil/index.js +1 -1
- package/dist/src/pil/layer1-intent.d.ts +9 -1
- package/dist/src/pil/layer1-intent.js +99 -44
- package/dist/src/pil/layer1-intent.test.js +112 -2
- package/dist/src/pil/layer15-context-scan.js +1 -1
- package/dist/src/pil/layer16-clarity.d.ts +21 -25
- package/dist/src/pil/layer16-clarity.js +52 -88
- package/dist/src/pil/layer18-acceptance.d.ts +13 -3
- package/dist/src/pil/layer18-acceptance.js +1 -75
- package/dist/src/pil/layer2-personality.js +7 -8
- package/dist/src/pil/layer2_5-ponytail.d.ts +2 -0
- package/dist/src/pil/layer2_5-ponytail.js +41 -0
- package/dist/src/pil/layer3-ee-injection.js +180 -14
- package/dist/src/pil/layer4-gsd.js +22 -8
- package/dist/src/pil/layer5-context.d.ts +1 -0
- package/dist/src/pil/layer5-context.js +26 -11
- package/dist/src/pil/layer6-output.js +23 -5
- package/dist/src/pil/llm-classify.js +3 -3
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +4 -3
- package/dist/src/pil/pipeline.js +15 -1
- package/dist/src/pil/response-tools.d.ts +16 -0
- package/dist/src/pil/response-tools.js +41 -0
- package/dist/src/pil/schema.d.ts +8 -0
- package/dist/src/pil/schema.js +24 -3
- package/dist/src/pil/task-tier-map.js +7 -7
- package/dist/src/pil/types.d.ts +9 -3
- package/dist/src/product-loop/__tests__/discovery-interview.test.js +103 -1
- package/dist/src/product-loop/__tests__/gather-selectable-alts.test.js +34 -0
- package/dist/src/product-loop/__tests__/sprint-self-verify.test.js +12 -12
- package/dist/src/product-loop/discovery-interview.d.ts +20 -0
- package/dist/src/product-loop/discovery-interview.js +121 -7
- package/dist/src/product-loop/done-gate.js +3 -3
- package/dist/src/product-loop/gather.js +19 -5
- package/dist/src/product-loop/loop-driver.js +20 -20
- package/dist/src/product-loop/progress-snapshot.js +4 -4
- package/dist/src/product-loop/sprint-self-verify.js +2 -2
- package/dist/src/providers/__tests__/reasoning-roundtrip.test.js +12 -0
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.d.ts +1 -5
- package/dist/src/providers/auth/__tests__/gemini-oauth.test.js +1 -5
- package/dist/src/providers/auth/gcloud.d.ts +28 -0
- package/dist/src/providers/auth/gcloud.js +102 -0
- package/dist/src/providers/auth/gemini-oauth.d.ts +46 -19
- package/dist/src/providers/auth/gemini-oauth.js +292 -105
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -1
- package/dist/src/providers/auth/grok-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +28 -6
- package/dist/src/providers/gemini.d.ts +1 -1
- package/dist/src/providers/gemini.js +10 -3
- package/dist/src/providers/keychain.d.ts +2 -2
- package/dist/src/providers/keychain.js +20 -2
- package/dist/src/providers/mcp-vision-bridge.js +48 -48
- package/dist/src/providers/openai.js +5 -1
- package/dist/src/providers/runtime.d.ts +1 -1
- package/dist/src/providers/runtime.js +11 -2
- package/dist/src/providers/siliconflow-sse-repair.js +1 -1
- package/dist/src/providers/strategies/google.strategy.d.ts +9 -2
- package/dist/src/providers/strategies/google.strategy.js +159 -9
- package/dist/src/providers/strategies/thinking-mode.js +19 -6
- package/dist/src/providers/types.d.ts +1 -1
- package/dist/src/reporter/index.js +1 -1
- package/dist/src/router/decide.test.js +40 -8
- package/dist/src/router/step-router.d.ts +20 -0
- package/dist/src/router/step-router.js +73 -0
- package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
- package/dist/src/scaffold/bb-quality-gate.js +5 -5
- package/dist/src/scaffold/continuation-prompt.js +60 -60
- package/dist/src/scaffold/init-new.js +453 -453
- package/dist/src/self-qa/__tests__/scenario-planner.test.js +3 -3
- package/dist/src/self-qa/agentic-loop.js +19 -19
- package/dist/src/self-qa/orchestrator.js +5 -5
- package/dist/src/self-qa/scenario-planner.js +1 -1
- package/dist/src/self-qa/spec-emitter.js +4 -4
- package/dist/src/storage/__tests__/migrations.test.js +2 -2
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.js +5 -5
- package/dist/src/storage/migrations.js +122 -122
- package/dist/src/storage/session-experience-store.js +4 -4
- package/dist/src/storage/sessions.js +43 -43
- package/dist/src/storage/transcript-view.js +7 -1
- package/dist/src/storage/transcript.d.ts +1 -0
- package/dist/src/storage/transcript.js +55 -0
- package/dist/src/storage/ui-interaction-log.d.ts +17 -0
- package/dist/src/storage/usage.js +14 -14
- package/dist/src/storage/workspaces.js +12 -12
- package/dist/src/tools/__tests__/native-tools.test.js +6 -0
- package/dist/src/tools/bash.d.ts +36 -23
- package/dist/src/tools/bash.js +59 -301
- package/dist/src/tools/bash.test.js +2 -257
- package/dist/src/tools/file-tracker.d.ts +5 -0
- package/dist/src/tools/file-tracker.js +14 -0
- package/dist/src/tools/file.js +2 -0
- package/dist/src/tools/git-safety.d.ts +38 -1
- package/dist/src/tools/git-safety.js +94 -4
- package/dist/src/tools/git-safety.test.js +45 -1
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +56 -0
- package/dist/src/tools/registry-bash-empty-command.test.js +4 -3
- package/dist/src/tools/registry-git-safety.test.js +17 -6
- package/dist/src/tools/registry.d.ts +5 -0
- package/dist/src/tools/registry.js +185 -11
- package/dist/src/types/index.d.ts +7 -1
- package/dist/src/ui/app.d.ts +1 -0
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/components/council-question-card.js +1 -0
- package/dist/src/ui/components/message-view.js +37 -3
- package/dist/src/ui/components/structured-response-view.js +7 -0
- package/dist/src/ui/components/task-list-panel.js +3 -12
- package/dist/src/ui/containers/chat-feed.d.ts +40 -0
- package/dist/src/ui/containers/chat-feed.js +66 -0
- package/dist/src/ui/containers/modals-layer.d.ts +87 -0
- package/dist/src/ui/containers/modals-layer.js +18 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/menu-parity.test.js +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.d.ts +1 -0
- package/dist/src/ui/slash/__tests__/ponytail.test.js +37 -0
- package/dist/src/ui/slash/council-inspect.js +4 -4
- package/dist/src/ui/slash/export.js +16 -1
- package/dist/src/ui/slash/menu-items.js +1 -0
- package/dist/src/ui/slash/ponytail.d.ts +2 -0
- package/dist/src/ui/slash/ponytail.js +19 -0
- package/dist/src/ui/status-bar/store.js +0 -1
- package/dist/src/ui/status-bar/store.test.js +2 -2
- package/dist/src/ui/use-app-logic.d.ts +26 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/relaunch.js +1 -1
- package/dist/src/ui/utils/text.d.ts +11 -0
- package/dist/src/ui/utils/text.js +21 -1
- package/dist/src/ui/utils/text.test.js +25 -1
- package/dist/src/ui/utils/tools.js +3 -1
- package/dist/src/usage/cost-log.js +2 -2
- package/dist/src/usage/estimator.d.ts +14 -0
- package/dist/src/usage/estimator.js +22 -0
- package/dist/src/utils/__tests__/compaction-caps.test.d.ts +21 -0
- package/dist/src/utils/__tests__/compaction-caps.test.js +187 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.d.ts +1 -0
- package/dist/src/utils/__tests__/llm-deadline-abort.test.js +33 -0
- package/dist/src/utils/clipboard-image.js +23 -23
- package/dist/src/utils/llm-deadline.d.ts +9 -1
- package/dist/src/utils/llm-deadline.js +31 -2
- package/dist/src/utils/permission-mode.d.ts +33 -0
- package/dist/src/utils/permission-mode.js +164 -3
- package/dist/src/utils/permission-mode.test.js +92 -1
- package/dist/src/utils/settings.d.ts +27 -31
- package/dist/src/utils/settings.js +100 -109
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/skills.js +3 -3
- package/dist/src/verify/__tests__/coverage-parsers.test.js +30 -30
- package/package.json +1 -1
|
@@ -36,32 +36,23 @@ function ItemRow({ item, t }) {
|
|
|
36
36
|
let glyph;
|
|
37
37
|
let glyphColor;
|
|
38
38
|
let textColor;
|
|
39
|
-
|
|
39
|
+
const label = item.status === "in_progress" ? (item.activeForm ?? item.subject) : item.subject;
|
|
40
40
|
if (item.status === "completed") {
|
|
41
41
|
glyph = "✓";
|
|
42
42
|
glyphColor = t.diffAddedFg;
|
|
43
43
|
textColor = t.textMuted;
|
|
44
|
-
// Strikethrough via U+0336 combining mark. OpenTUI doesn't expose CSS
|
|
45
|
-
// text-decoration so we synthesise it character-by-character — matches the
|
|
46
|
-
// visual goal in the spec.
|
|
47
|
-
label = item.subject
|
|
48
|
-
.split("")
|
|
49
|
-
.map((c) => `${c}̶`)
|
|
50
|
-
.join("");
|
|
51
44
|
}
|
|
52
45
|
else if (item.status === "in_progress") {
|
|
53
46
|
glyph = "◉";
|
|
54
47
|
glyphColor = t.accent;
|
|
55
48
|
textColor = t.text;
|
|
56
|
-
label = item.activeForm ?? item.subject;
|
|
57
49
|
}
|
|
58
50
|
else {
|
|
59
51
|
glyph = "○";
|
|
60
52
|
glyphColor = t.textMuted;
|
|
61
53
|
textColor = t.text;
|
|
62
|
-
label = item.subject;
|
|
63
54
|
}
|
|
64
|
-
return (_jsx(Semantic, { id: `task-${item.id}`, role: "listitem", name: label, state: item.status, children: _jsxs("text", { children: [_jsx("span", { style: { fg: glyphColor }, children: `${glyph} ` }),
|
|
55
|
+
return (_jsx(Semantic, { id: `task-${item.id}`, role: "listitem", name: label, state: item.status, children: _jsx("box", { width: "100%", children: _jsxs("text", { fg: textColor, children: [_jsx("span", { style: { fg: glyphColor }, children: `${glyph} ` }), trunc(label, 70)] }) }) }));
|
|
65
56
|
}
|
|
66
57
|
export function TaskListPanel({ snapshot, t, expanded }) {
|
|
67
58
|
if (snapshot.items.length === 0)
|
|
@@ -78,7 +69,7 @@ export function TaskListPanel({ snapshot, t, expanded }) {
|
|
|
78
69
|
if (pending > 0)
|
|
79
70
|
footerParts.push(`${pending} queued`);
|
|
80
71
|
const footer = footerParts.length > 0 ? footerParts.join(" · ") : "0 todos";
|
|
81
|
-
return (_jsx(Semantic, { id: "task-list", role: "listbox", name: "Todos", children: _jsxs("box", { border: true, borderColor: t.border, paddingLeft: 2, paddingRight: 2, paddingTop: 0, paddingBottom: 0, marginBottom: 1, flexDirection: "column", children: [_jsx("
|
|
72
|
+
return (_jsx(Semantic, { id: "task-list", role: "listbox", name: "Todos", children: _jsxs("box", { border: true, borderColor: t.border, paddingLeft: 2, paddingRight: 2, paddingTop: 0, paddingBottom: 0, marginBottom: 1, flexDirection: "column", children: [_jsx("box", { paddingBottom: 1, children: _jsx("text", { fg: t.textMuted, children: _jsx("b", { children: "Todos" }) }) }), _jsx("box", { flexDirection: "column", children: visible.map((it) => (_jsx(ItemRow, { item: it, t: t }, it.id))) }), overflow > 0 && (_jsx("box", { marginTop: 1, children: _jsx("text", { fg: t.textMuted, children: `… +${overflow} more (ctrl+e to expand)` }) })), _jsx("box", { marginTop: 1, paddingTop: 1, border: ["top"], borderColor: t.border, children: _jsx("text", { fg: t.textDim, children: footer }) })] }) }));
|
|
82
73
|
}
|
|
83
74
|
export const __TEST_ONLY__ = { sortItems, MAX_VISIBLE };
|
|
84
75
|
//# sourceMappingURL=task-list-panel.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface ChatFeedProps {
|
|
3
|
+
getSide: any;
|
|
4
|
+
getPartnerLast: any;
|
|
5
|
+
resolveStyle: any;
|
|
6
|
+
scrollRef: any;
|
|
7
|
+
messages: any;
|
|
8
|
+
expandedMessages: any;
|
|
9
|
+
liveTurnSourceLabel: any;
|
|
10
|
+
activeToolCalls: any;
|
|
11
|
+
streamContent: any;
|
|
12
|
+
isProcessing: any;
|
|
13
|
+
activeSubagent: any;
|
|
14
|
+
councilPhases: any;
|
|
15
|
+
productStatus: any;
|
|
16
|
+
councilStatuses: any;
|
|
17
|
+
councilInfoCards: any;
|
|
18
|
+
councilMessages: any;
|
|
19
|
+
councilPlaceholders: any;
|
|
20
|
+
reasoningActive: any;
|
|
21
|
+
lastReasoningElapsedMs: any;
|
|
22
|
+
streamReasoning: any;
|
|
23
|
+
showPlanPanel: any;
|
|
24
|
+
planQuestions: any;
|
|
25
|
+
pqs: any;
|
|
26
|
+
pendingPaymentApproval: any;
|
|
27
|
+
activeHaltCard: any;
|
|
28
|
+
haltSelectedIndex: any;
|
|
29
|
+
initNewForm: any;
|
|
30
|
+
pointToExistingForm: any;
|
|
31
|
+
councilProgress: any;
|
|
32
|
+
pendingCouncilQuestion: any;
|
|
33
|
+
councilCardState: any;
|
|
34
|
+
pendingCouncilPreflight: any;
|
|
35
|
+
preflightCardState: any;
|
|
36
|
+
t: any;
|
|
37
|
+
width: any;
|
|
38
|
+
modeInfo: any;
|
|
39
|
+
}
|
|
40
|
+
export declare function ChatFeed(props: ChatFeedProps): React.ReactNode;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { Semantic } from "@muonroi/agent-harness-opentui";
|
|
3
|
+
import { ProductStatusCard } from "../cards/product-status-card.js";
|
|
4
|
+
import { makePairKey } from "../components/bubble-layout.js";
|
|
5
|
+
import { CouncilInfoCardView } from "../components/council-info-card.js";
|
|
6
|
+
import { CouncilLeaderBubble } from "../components/council-leader-bubble.js";
|
|
7
|
+
import { CouncilMessageBubble } from "../components/council-message-bubble.js";
|
|
8
|
+
import { CouncilPhaseTimeline } from "../components/council-phase-timeline.js";
|
|
9
|
+
import { CouncilPlaceholderBubble } from "../components/council-placeholder-bubble.js";
|
|
10
|
+
import { CouncilQuestionCard } from "../components/council-question-card.js";
|
|
11
|
+
import { CouncilStatusList } from "../components/council-status-list.js";
|
|
12
|
+
import { CouncilSynthesisBanner } from "../components/council-synthesis-banner.js";
|
|
13
|
+
import { HaltRecoveryCard } from "../components/halt-recovery-card.js";
|
|
14
|
+
import { InitNewFormCard } from "../components/init-new-form-card.js";
|
|
15
|
+
import { computeMcpRunInfo, MessageView } from "../components/message-view.js";
|
|
16
|
+
import { PointToExistingFormCard } from "../components/point-to-existing-form-card.js";
|
|
17
|
+
import { DelegationTaskLine, InlineTool, ShimmerText, SubagentActivity, SubagentTaskLine, } from "../components/tool-result-views.js";
|
|
18
|
+
import { Markdown } from "../markdown.js";
|
|
19
|
+
import { PaymentApprovalPanel } from "../modals/wallet-picker-modal.js";
|
|
20
|
+
import { PlanQuestionsPanel } from "../plan.js";
|
|
21
|
+
import { buildPreflightQuestion } from "../utils/format.js";
|
|
22
|
+
import { toolArgs, toolLabel, tryParseArg } from "../utils/tools.js";
|
|
23
|
+
export function ChatFeed(props) {
|
|
24
|
+
const { modeInfo, getSide, getPartnerLast, resolveStyle, scrollRef, messages, expandedMessages, liveTurnSourceLabel, activeToolCalls, streamContent, isProcessing, activeSubagent, councilPhases, productStatus, councilStatuses, councilInfoCards, councilMessages, councilPlaceholders, reasoningActive, lastReasoningElapsedMs, streamReasoning, showPlanPanel, planQuestions, pqs, pendingPaymentApproval, activeHaltCard, haltSelectedIndex, initNewForm, pointToExistingForm, councilProgress, pendingCouncilQuestion, councilCardState, pendingCouncilPreflight, preflightCardState, t, width, } = props;
|
|
25
|
+
return (_jsx(Semantic, { id: "log", role: "log", props: { scrollTop: scrollRef.current?.scrollTop ?? 0 }, children: _jsxs("scrollbox", { ref: scrollRef, flexGrow: 1, stickyScroll: true, stickyStart: "bottom", children: [(() => {
|
|
26
|
+
const mcpRuns = computeMcpRunInfo(messages);
|
|
27
|
+
// Phase 5 F7 — index of the last assistant message so
|
|
28
|
+
// MessageView can skip auto-collapse on it (final answer
|
|
29
|
+
// should always be fully visible, not hidden behind
|
|
30
|
+
// "ctrl+e expand").
|
|
31
|
+
let _lastAssistantIdx = -1;
|
|
32
|
+
for (let _i = messages.length - 1; _i >= 0; _i--) {
|
|
33
|
+
if (messages[_i]?.type === "assistant") {
|
|
34
|
+
_lastAssistantIdx = _i;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return messages.map((msg, i) => (
|
|
39
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: append-only message log; index is part of the stable semantic id
|
|
40
|
+
_jsx(Semantic, { id: `msg-${i}`, role: "listitem", name: `${msg.type ?? "msg"}:${String(msg.content ?? "").slice(0, 40)}`, children: _jsx(MessageView, { entry: msg, index: i, t: t, modeColor: modeInfo.color, expandedMessages: expandedMessages, mcpRun: mcpRuns[i], isFinalAssistant: i === _lastAssistantIdx }, `${msg.timestamp?.getTime?.() ?? i}-${msg.type}-${msg.remoteKey ?? ""}-${String(msg.content ?? "").slice(0, 24)}`) }, `sem-${msg.timestamp?.getTime?.() ?? i}-${i}`)));
|
|
41
|
+
})(), liveTurnSourceLabel && (activeToolCalls.length > 0 || streamContent || isProcessing) && (_jsx("box", { paddingLeft: 3, marginTop: 1, flexShrink: 0, children: _jsx("text", { fg: t.textMuted, children: liveTurnSourceLabel }) })), activeToolCalls.map((tc) => tc.function.name === "task" ? (_jsx(SubagentTaskLine, { t: t, agent: tryParseArg(tc, "agent") || "sub-agent", label: toolArgs(tc) || "Working", pending: true }, tc.id)) : tc.function.name === "delegate" ? (_jsx(DelegationTaskLine, { t: t, label: toolArgs(tc) || "Background research", pending: true, id: undefined }, tc.id)) : (_jsx(InlineTool, { t: t, pending: true, children: toolLabel(tc) }, tc.id))), activeSubagent && _jsx(SubagentActivity, { t: t, status: activeSubagent }), councilPhases.length > 0 && (_jsx(Semantic, { id: "council-phases", role: "listbox", name: "Council Phases", children: _jsx(CouncilPhaseTimeline, { phases: councilPhases, theme: t }) })), productStatus && _jsx(ProductStatusCard, { data: productStatus, theme: t }), councilStatuses.length > 0 && (_jsx(Semantic, { id: "council-status", role: "listbox", name: "Council Status", children: _jsx(CouncilStatusList, { statuses: councilStatuses, theme: t }) })), councilInfoCards.map((card, idx) => (_jsx(Semantic, { id: `council-card-${idx}`, role: "listitem", name: card.title || `Council card ${idx}`, children: _jsx(CouncilInfoCardView, { card: card, terminalCols: width, theme: t }, `info-card-${idx}-${card.title}`) }, `sem-info-${idx}-${card.title}`))), councilMessages.map((cm, idx) => {
|
|
42
|
+
const side = cm.kind === "debate" && cm.partner
|
|
43
|
+
? getSide(makePairKey(cm.speaker.role, cm.partner.role), cm.speaker.role)
|
|
44
|
+
: "left";
|
|
45
|
+
const semName = `${cm.kind}:${cm.speaker?.role ?? "?"}`;
|
|
46
|
+
if (cm.kind === "leader") {
|
|
47
|
+
return (_jsx(Semantic, { id: `council-msg-${idx}`, role: "listitem", name: semName, value: cm.text, children: _jsx(CouncilLeaderBubble, { msg: cm, terminalCols: width }, idx) }, `sem-cm-${idx}`));
|
|
48
|
+
}
|
|
49
|
+
if (cm.kind === "synthesis") {
|
|
50
|
+
return (_jsx(Semantic, { id: `council-msg-${idx}`, role: "listitem", name: semName, value: cm.text, children: _jsx(CouncilSynthesisBanner, { msg: cm }, idx) }, `sem-cm-${idx}`));
|
|
51
|
+
}
|
|
52
|
+
const pairKey = cm.partner ? makePairKey(cm.speaker.role, cm.partner.role) : `solo::${cm.speaker.role}`;
|
|
53
|
+
const partnerLastText = cm.partner ? getPartnerLast(pairKey, cm.partner.role) : undefined;
|
|
54
|
+
return (_jsx(Semantic, { id: `council-msg-${idx}`, role: "listitem", name: semName, value: cm.text, children: _jsx(CouncilMessageBubble, { msg: cm, terminalCols: width, side: side, resolveStyle: resolveStyle, partnerLastText: partnerLastText, partnerRole: cm.partner?.role, theme: t }, idx) }, `sem-cm-${idx}`));
|
|
55
|
+
}), Array.from(councilPlaceholders.entries()).map(([id, p]) => (_jsx(CouncilPlaceholderBubble, { role: p.role, side: p.side, terminalCols: width, color: p.color, theme: t, variant: p.variant }, id))), (reasoningActive || lastReasoningElapsedMs > 0) && (_jsxs("box", { paddingLeft: 3, marginTop: 1, flexShrink: 0, flexDirection: "column", children: [_jsx("text", { fg: t.textMuted, children: reasoningActive ? "[Thought] Thinking..." : `[Thought] Thought for ${(lastReasoningElapsedMs / 1000).toFixed(1)}s` }), streamReasoning ? (_jsx("box", { border: ["left"], borderColor: t.textMuted, paddingLeft: 2, marginTop: 1, flexDirection: "column", children: reasoningActive ? (
|
|
56
|
+
// While actively streaming, render only the last 3
|
|
57
|
+
// non-empty lines as plain text to avoid Markdown
|
|
58
|
+
// re-parse overhead every 150ms.
|
|
59
|
+
_jsx("text", { fg: t.textMuted, children: streamReasoning
|
|
60
|
+
.split("\n")
|
|
61
|
+
.filter((l) => l.trim().length > 0)
|
|
62
|
+
.slice(-3)
|
|
63
|
+
.join(" · ") })) : (_jsx(Markdown, { content: streamReasoning, t: t })) })) : null] })), streamContent && (_jsx("box", { paddingLeft: 3, marginTop: 1, flexShrink: 0, children: _jsx(Markdown, { content: streamContent, t: t }) })), isProcessing && !streamContent && activeToolCalls.length === 0 && (_jsx(ShimmerText, { t: t, text: "Planning next moves" })), showPlanPanel && _jsx(PlanQuestionsPanel, { t: t, questions: planQuestions, state: pqs }), pendingPaymentApproval && _jsx(PaymentApprovalPanel, { t: t, payment: pendingPaymentApproval }), activeHaltCard && (_jsx(HaltRecoveryCard, { halt: activeHaltCard, selectedIndex: haltSelectedIndex, terminalCols: width, theme: t })), initNewForm && _jsx(InitNewFormCard, { state: initNewForm, terminalCols: width, theme: t }), pointToExistingForm && _jsx(PointToExistingFormCard, { state: pointToExistingForm, terminalCols: width, theme: t }), councilProgress && (_jsx(Semantic, { id: "continue-as-council-progress", role: "log", name: "Council brainstorm", children: _jsx("box", { flexDirection: "column", borderStyle: "single", borderColor: councilProgress.status === "error" ? t.initFormError : t.text, padding: 1, marginTop: 1, children: _jsxs("text", { fg: t.text, children: [councilProgress.status === "running" && "Council brainstorming — writing spec.md...", councilProgress.status === "done" &&
|
|
64
|
+
`Council brainstorm complete: ${councilProgress.specPath}${councilProgress.hasContent ? "" : " (no content — production council wiring deferred)"}`, councilProgress.status === "error" && `Council brainstorm failed: ${councilProgress.error}`] }) }) })), pendingCouncilQuestion && councilCardState && (_jsx(CouncilQuestionCard, { question: pendingCouncilQuestion, theme: t, state: councilCardState })), pendingCouncilPreflight && preflightCardState && (_jsx(CouncilQuestionCard, { question: buildPreflightQuestion(pendingCouncilPreflight), theme: t, state: preflightCardState }))] }) }));
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=chat-feed.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export interface ModalsLayerProps {
|
|
2
|
+
agentRows: any;
|
|
3
|
+
agentsEditorDraft: any;
|
|
4
|
+
agentsEditorError: any;
|
|
5
|
+
agentsEditorField: any;
|
|
6
|
+
agentsEditorModelIndex: any;
|
|
7
|
+
agentsEditorSyncKey: any;
|
|
8
|
+
agentsModalIndex: any;
|
|
9
|
+
agentsSearchQuery: any;
|
|
10
|
+
apiKeyError: any;
|
|
11
|
+
apiKeyInputRef: any;
|
|
12
|
+
apiKeyPrompt: any;
|
|
13
|
+
bwSync: any;
|
|
14
|
+
configuredProviders: any;
|
|
15
|
+
connectModalIndex: any;
|
|
16
|
+
defaultProvider: any;
|
|
17
|
+
disabledModels: any;
|
|
18
|
+
disabledProviders: any;
|
|
19
|
+
editingMcpId: any;
|
|
20
|
+
editingSubagent: any;
|
|
21
|
+
filteredModels: any;
|
|
22
|
+
height: any;
|
|
23
|
+
mcpArgsRef: any;
|
|
24
|
+
mcpCommandRef: any;
|
|
25
|
+
mcpCwdRef: any;
|
|
26
|
+
mcpEditorDraft: any;
|
|
27
|
+
mcpEditorError: any;
|
|
28
|
+
mcpEditorField: any;
|
|
29
|
+
mcpEditorSyncKey: any;
|
|
30
|
+
mcpEnvRef: any;
|
|
31
|
+
mcpHeadersRef: any;
|
|
32
|
+
mcpLabelRef: any;
|
|
33
|
+
mcpModalIndex: any;
|
|
34
|
+
mcpRows: any;
|
|
35
|
+
mcpSearchQuery: any;
|
|
36
|
+
mcpUrlRef: any;
|
|
37
|
+
model: any;
|
|
38
|
+
modelPickerFocus: any;
|
|
39
|
+
modelPickerIndex: any;
|
|
40
|
+
modelSearchQuery: any;
|
|
41
|
+
providerChipIndex: any;
|
|
42
|
+
providersWithKey: any;
|
|
43
|
+
reasoningEffortByModel: any;
|
|
44
|
+
sandboxMode: any;
|
|
45
|
+
sandboxSettings: any;
|
|
46
|
+
sandboxSettingsEditBuffer: any;
|
|
47
|
+
sandboxSettingsEditing: any;
|
|
48
|
+
sandboxSettingsFocusIndex: any;
|
|
49
|
+
scheduleModalIndex: any;
|
|
50
|
+
scheduleRows: any;
|
|
51
|
+
scheduleSearchQuery: any;
|
|
52
|
+
sessionPickerIndex: any;
|
|
53
|
+
sessionPickerList: any;
|
|
54
|
+
showAgentsEditor: any;
|
|
55
|
+
showAgentsModal: any;
|
|
56
|
+
showApiKeyModal: any;
|
|
57
|
+
showConnectModal: any;
|
|
58
|
+
showMcpEditor: any;
|
|
59
|
+
showMcpModal: any;
|
|
60
|
+
showModelPicker: any;
|
|
61
|
+
showSandboxPicker: any;
|
|
62
|
+
showScheduleModal: any;
|
|
63
|
+
showSessionPicker: any;
|
|
64
|
+
showTelegramPairModal: any;
|
|
65
|
+
showTelegramTokenModal: any;
|
|
66
|
+
showUpdateModal: any;
|
|
67
|
+
showWalletPicker: any;
|
|
68
|
+
startupConfig: any;
|
|
69
|
+
subagentInstructionRef: any;
|
|
70
|
+
subagentNameRef: any;
|
|
71
|
+
submitApiKey: any;
|
|
72
|
+
submitMcpEditor: any;
|
|
73
|
+
submitSubagentEditor: any;
|
|
74
|
+
submitTelegramPair: any;
|
|
75
|
+
submitTelegramToken: any;
|
|
76
|
+
t: any;
|
|
77
|
+
telegramPairError: any;
|
|
78
|
+
telegramPairInputRef: any;
|
|
79
|
+
telegramTokenError: any;
|
|
80
|
+
telegramTokenInputRef: any;
|
|
81
|
+
updateInfo: any;
|
|
82
|
+
walletDisplayInfo: any;
|
|
83
|
+
walletFocusIndex: any;
|
|
84
|
+
walletSettings: any;
|
|
85
|
+
width: any;
|
|
86
|
+
}
|
|
87
|
+
export declare function ModalsLayer(props: ModalsLayerProps): import("react").ReactNode;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@opentui/react/jsx-runtime";
|
|
2
|
+
import { formatSubagentName } from "../../utils/subagent-display.js";
|
|
3
|
+
import { SubagentEditorModal, SubagentsBrowserModal } from "../agents-modal.js";
|
|
4
|
+
import { CONNECT_CHANNELS } from "../constants.js";
|
|
5
|
+
import { McpBrowserModal, McpEditorModal } from "../mcp-modal.js";
|
|
6
|
+
import { ApiKeyModal } from "../modals/api-key-modal.js";
|
|
7
|
+
import { ConnectModal, TelegramPairModal, TelegramTokenModal } from "../modals/connect-modal.js";
|
|
8
|
+
import { ModelPickerModal } from "../modals/model-picker-modal.js";
|
|
9
|
+
import { SandboxPickerModal } from "../modals/sandbox-picker-modal.js";
|
|
10
|
+
import { SessionPickerModal } from "../modals/session-picker-modal.js";
|
|
11
|
+
import { UpdateModal } from "../modals/update-modal.js";
|
|
12
|
+
import { WalletPickerModal } from "../modals/wallet-picker-modal.js";
|
|
13
|
+
import { ScheduleBrowserModal } from "../schedule-modal.js";
|
|
14
|
+
export function ModalsLayer(props) {
|
|
15
|
+
const { agentRows, agentsEditorDraft, agentsEditorError, agentsEditorField, agentsEditorModelIndex, agentsEditorSyncKey, agentsModalIndex, agentsSearchQuery, apiKeyError, apiKeyInputRef, apiKeyPrompt, bwSync, configuredProviders, connectModalIndex, defaultProvider, disabledModels, disabledProviders, editingMcpId, editingSubagent, filteredModels, height, mcpArgsRef, mcpCommandRef, mcpCwdRef, mcpEditorDraft, mcpEditorError, mcpEditorField, mcpEditorSyncKey, mcpEnvRef, mcpHeadersRef, mcpLabelRef, mcpModalIndex, mcpRows, mcpSearchQuery, mcpUrlRef, model, modelPickerFocus, modelPickerIndex, modelSearchQuery, providerChipIndex, providersWithKey, reasoningEffortByModel, sandboxMode, sandboxSettings, sandboxSettingsEditBuffer, sandboxSettingsEditing, sandboxSettingsFocusIndex, scheduleModalIndex, scheduleRows, scheduleSearchQuery, sessionPickerIndex, sessionPickerList, showAgentsEditor, showAgentsModal, showApiKeyModal, showConnectModal, showMcpEditor, showMcpModal, showModelPicker, showSandboxPicker, showScheduleModal, showSessionPicker, showTelegramPairModal, showTelegramTokenModal, showUpdateModal, showWalletPicker, startupConfig, subagentInstructionRef, subagentNameRef, submitApiKey, submitMcpEditor, submitSubagentEditor, submitTelegramPair, submitTelegramToken, t, telegramPairError, telegramPairInputRef, telegramTokenError, telegramTokenInputRef, updateInfo, walletDisplayInfo, walletFocusIndex, walletSettings, width, } = props;
|
|
16
|
+
return (_jsxs(_Fragment, { children: [showApiKeyModal && (_jsx(ApiKeyModal, { t: t, width: width, height: height, inputRef: apiKeyInputRef, error: apiKeyError, onSubmit: submitApiKey })), showUpdateModal && updateInfo && (_jsx(UpdateModal, { t: t, width: width, height: height, currentVersion: startupConfig.version, latestVersion: updateInfo.latestVersion })), showMcpModal && !showMcpEditor && (_jsx(McpBrowserModal, { t: t, width: width, height: height, selectedIndex: mcpModalIndex, searchQuery: mcpSearchQuery, rows: mcpRows })), showMcpEditor && (_jsx(McpEditorModal, { t: t, width: width, height: height, draft: mcpEditorDraft, focusedField: mcpEditorField, syncKey: mcpEditorSyncKey, error: mcpEditorError, title: editingMcpId ? "Edit MCP Server" : "Add MCP Server", labelRef: mcpLabelRef, urlRef: mcpUrlRef, headersRef: mcpHeadersRef, commandRef: mcpCommandRef, argsRef: mcpArgsRef, cwdRef: mcpCwdRef, envRef: mcpEnvRef, onSubmit: submitMcpEditor })), showScheduleModal && (_jsx(ScheduleBrowserModal, { t: t, width: width, height: height, selectedIndex: scheduleModalIndex, searchQuery: scheduleSearchQuery, rows: scheduleRows })), showAgentsModal && !showAgentsEditor && (_jsx(SubagentsBrowserModal, { t: t, width: width, height: height, selectedIndex: agentsModalIndex, searchQuery: agentsSearchQuery, rows: agentRows })), showAgentsEditor && (_jsx(SubagentEditorModal, { t: t, width: width, height: height, draft: agentsEditorDraft, focusedField: agentsEditorField, modelIndex: agentsEditorModelIndex, error: agentsEditorError, title: editingSubagent ? `Edit sub-agent: ${formatSubagentName(editingSubagent.name)}` : "Add sub-agent", nameRef: subagentNameRef, instructionRef: subagentInstructionRef, onSubmit: submitSubagentEditor, showRemoveHint: !!editingSubagent }, `subagent-editor-${agentsEditorSyncKey}`)), showModelPicker && (_jsx(ModelPickerModal, { t: t, currentModel: model, selectedIndex: modelPickerIndex, width: width, height: height, searchQuery: modelSearchQuery, filteredModels: filteredModels, reasoningEffortByModel: reasoningEffortByModel, configuredProviders: configuredProviders, disabledProviders: disabledProviders, disabledModels: disabledModels, defaultProvider: defaultProvider, focus: modelPickerFocus, providerChipIndex: providerChipIndex, providersWithKey: providersWithKey, apiKeyPrompt: apiKeyPrompt, bwSync: bwSync })), showSessionPicker && (_jsx(SessionPickerModal, { t: t, sessions: sessionPickerList, focusIndex: sessionPickerIndex, width: width, height: height })), showWalletPicker && (_jsx(WalletPickerModal, { t: t, settings: walletSettings, walletInfo: walletDisplayInfo, focusIndex: walletFocusIndex, width: width, height: height })), showSandboxPicker && (_jsx(SandboxPickerModal, { t: t, currentMode: sandboxMode, settings: sandboxSettings, focusIndex: sandboxSettingsFocusIndex, editing: sandboxSettingsEditing, editBuffer: sandboxSettingsEditBuffer, width: width, height: height })), showConnectModal && (_jsx(ConnectModal, { t: t, width: width, height: height, selectedIndex: connectModalIndex, channels: CONNECT_CHANNELS })), showTelegramTokenModal && (_jsx(TelegramTokenModal, { t: t, width: width, height: height, inputRef: telegramTokenInputRef, error: telegramTokenError, onSubmit: submitTelegramToken })), showTelegramPairModal && (_jsx(TelegramPairModal, { t: t, width: width, height: height, inputRef: telegramPairInputRef, error: telegramPairError, onSubmit: () => void submitTelegramPair() }))] }));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=modals-layer.js.map
|
|
@@ -26,6 +26,7 @@ import "../council-inspect.js";
|
|
|
26
26
|
import "../ideal.js";
|
|
27
27
|
import "../route.js";
|
|
28
28
|
import "../status.js";
|
|
29
|
+
import "../ponytail.js";
|
|
29
30
|
describe("slash menu / registry parity", () => {
|
|
30
31
|
it("every registered slash command has a menu entry", () => {
|
|
31
32
|
const menuIds = new Set(SLASH_MENU_ITEMS.map((m) => m.id));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { handlePonytailSlash } from "../ponytail.js";
|
|
3
|
+
describe("handlePonytailSlash", () => {
|
|
4
|
+
const originalEnv = process.env.MUONROI_PONYTAIL_DISABLE;
|
|
5
|
+
const dummyCtx = {
|
|
6
|
+
cwd: "/",
|
|
7
|
+
tenantId: "test",
|
|
8
|
+
defaultProvider: "openai",
|
|
9
|
+
defaultModel: "gpt-4",
|
|
10
|
+
};
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
if (originalEnv === undefined) {
|
|
13
|
+
delete process.env.MUONROI_PONYTAIL_DISABLE;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
process.env.MUONROI_PONYTAIL_DISABLE = originalEnv;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
it("should enable ponytail mode and modify process.env", async () => {
|
|
20
|
+
process.env.MUONROI_PONYTAIL_DISABLE = "1";
|
|
21
|
+
const response = await handlePonytailSlash(["on"], dummyCtx);
|
|
22
|
+
expect(process.env.MUONROI_PONYTAIL_DISABLE).toBe("0");
|
|
23
|
+
expect(response).toContain("Ponytail Mode enabled");
|
|
24
|
+
});
|
|
25
|
+
it("should disable ponytail mode and modify process.env", async () => {
|
|
26
|
+
process.env.MUONROI_PONYTAIL_DISABLE = "0";
|
|
27
|
+
const response = await handlePonytailSlash(["off"], dummyCtx);
|
|
28
|
+
expect(process.env.MUONROI_PONYTAIL_DISABLE).toBe("1");
|
|
29
|
+
expect(response).toContain("Ponytail Mode disabled");
|
|
30
|
+
});
|
|
31
|
+
it("should return status when no args are provided", async () => {
|
|
32
|
+
process.env.MUONROI_PONYTAIL_DISABLE = "0";
|
|
33
|
+
const response = await handlePonytailSlash([], dummyCtx);
|
|
34
|
+
expect(response).toContain("ON (enabled)");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=ponytail.test.js.map
|
|
@@ -37,10 +37,10 @@ export const handleCouncilInspectSlash = async (args) => {
|
|
|
37
37
|
}
|
|
38
38
|
// Load all system messages for this session — parameterized query prevents SQL injection (T-17-04)
|
|
39
39
|
const rows = db
|
|
40
|
-
.prepare(`SELECT role, message_json, seq, created_at
|
|
41
|
-
FROM messages
|
|
42
|
-
WHERE session_id = ?
|
|
43
|
-
AND role = 'system'
|
|
40
|
+
.prepare(`SELECT role, message_json, seq, created_at
|
|
41
|
+
FROM messages
|
|
42
|
+
WHERE session_id = ?
|
|
43
|
+
AND role = 'system'
|
|
44
44
|
ORDER BY seq ASC`)
|
|
45
45
|
.all(sessionId);
|
|
46
46
|
if (rows.length === 0) {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import * as fs from "node:fs";
|
|
20
20
|
import * as path from "node:path";
|
|
21
|
+
import { appendCrashLog } from "../../index.js";
|
|
21
22
|
import { getDatabase } from "../../storage/db.js";
|
|
22
23
|
import { buildChatEntries } from "../../storage/transcript.js";
|
|
23
24
|
import { registerSlash } from "./registry.js";
|
|
@@ -251,7 +252,21 @@ export const handleExportSlash = async (_args, ctx) => {
|
|
|
251
252
|
if (!sessionId) {
|
|
252
253
|
return "No active session. Start a conversation first.";
|
|
253
254
|
}
|
|
254
|
-
|
|
255
|
+
let dbEntries = [];
|
|
256
|
+
try {
|
|
257
|
+
dbEntries = buildChatEntries(sessionId);
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
// A DB read failure here (SQLite busy/locked right after a council turn,
|
|
261
|
+
// schema drift, a corrupt page) used to throw out of this async handler.
|
|
262
|
+
// With no .catch on the dispatchSlash call site that became an
|
|
263
|
+
// unhandledRejection → process.exit(1) → the user kicked out of the TUI.
|
|
264
|
+
// Degrade instead: export the live TUI scrollback + interaction timeline.
|
|
265
|
+
// Logged to crash.log, NOT console (console.error corrupts the OpenTUI
|
|
266
|
+
// framebuffer while the renderer owns the terminal).
|
|
267
|
+
appendCrashLog("EXPORT", `buildChatEntries failed for session ${sessionId}: ${err instanceof Error ? err.stack || err.message : String(err)}`);
|
|
268
|
+
dbEntries = [];
|
|
269
|
+
}
|
|
255
270
|
const liveEntries = ctx.getLiveEntries?.() ?? [];
|
|
256
271
|
const timeline = selectInteractionTimeline(sessionId);
|
|
257
272
|
if (dbEntries.length === 0 && liveEntries.length === 0 && timeline.length === 0) {
|
|
@@ -87,6 +87,7 @@ export const SLASH_MENU_ITEMS = [
|
|
|
87
87
|
{ id: "ee-context-status", label: "ee-context status", description: "Show current BB-context setting", hidden: true },
|
|
88
88
|
{ id: "export", label: "export", description: "Export entire conversation to a .txt file", hidden: true },
|
|
89
89
|
{ id: "status", label: "status", description: "Show Agile sprint progress dashboard", hidden: true },
|
|
90
|
+
{ id: "ponytail", label: "ponytail", description: "Toggle Lazy Senior AI Mode (on/off/status)", hidden: false },
|
|
90
91
|
];
|
|
91
92
|
/** Items shown in the splash autocomplete + /help listing. */
|
|
92
93
|
export const VISIBLE_SLASH_MENU_ITEMS = SLASH_MENU_ITEMS.filter((m) => !m.hidden);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isPonytailModeEnabled } from "../../pil/config.js";
|
|
2
|
+
import { registerSlash } from "./registry.js";
|
|
3
|
+
export const handlePonytailSlash = async (args, _ctx) => {
|
|
4
|
+
const arg = args[0]?.toLowerCase();
|
|
5
|
+
if (arg === "on") {
|
|
6
|
+
process.env.MUONROI_PONYTAIL_DISABLE = "0";
|
|
7
|
+
return "✅ Ponytail Mode enabled (Lazy Senior mode). The agent will enforce YAGNI and prioritize standard libraries.";
|
|
8
|
+
}
|
|
9
|
+
if (arg === "off") {
|
|
10
|
+
process.env.MUONROI_PONYTAIL_DISABLE = "1";
|
|
11
|
+
return "❌ Ponytail Mode disabled. The agent is free to propose complex architectures and dependencies.";
|
|
12
|
+
}
|
|
13
|
+
// Status check
|
|
14
|
+
const status = isPonytailModeEnabled() ? "ON (enabled)" : "OFF (disabled)";
|
|
15
|
+
return `Ponytail Mode is currently: **${status}**\nUsage: \`/ponytail on\` or \`/ponytail off\``;
|
|
16
|
+
};
|
|
17
|
+
// Self-register on module import
|
|
18
|
+
registerSlash("ponytail", handlePonytailSlash);
|
|
19
|
+
//# sourceMappingURL=ponytail.js.map
|
|
@@ -87,7 +87,7 @@ describe("wireStatusBar", () => {
|
|
|
87
87
|
expect(s.model).toBe("claude-3-5-sonnet-latest");
|
|
88
88
|
off();
|
|
89
89
|
});
|
|
90
|
-
it("threshold event updates
|
|
90
|
+
it("threshold event updates month_usd (not session_usd)", () => {
|
|
91
91
|
const off = wireStatusBar();
|
|
92
92
|
thresholdCallback({
|
|
93
93
|
level: 80,
|
|
@@ -97,8 +97,8 @@ describe("wireStatusBar", () => {
|
|
|
97
97
|
atMs: 1,
|
|
98
98
|
});
|
|
99
99
|
const s = statusBarStore.getState();
|
|
100
|
-
expect(s.session_usd).toBe(12.5);
|
|
101
100
|
expect(s.month_usd).toBe(12.5);
|
|
101
|
+
expect(s.session_usd).toBe(0); // orchestrator owns session_usd, not thresholds
|
|
102
102
|
off();
|
|
103
103
|
});
|
|
104
104
|
it("downgrade event updates model", () => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "./slash/route.js";
|
|
2
|
+
import "./slash/optimize.js";
|
|
3
|
+
import "./slash/discuss.js";
|
|
4
|
+
import "./slash/plan.js";
|
|
5
|
+
import "./slash/execute.js";
|
|
6
|
+
import "./slash/compact.js";
|
|
7
|
+
import "./slash/expand.js";
|
|
8
|
+
import "./slash/clear.js";
|
|
9
|
+
import "./slash/pin.js";
|
|
10
|
+
import "./slash/cost.js";
|
|
11
|
+
import "./slash/ee.js";
|
|
12
|
+
import "./slash/debug.js";
|
|
13
|
+
import "./slash/council.js";
|
|
14
|
+
import "./slash/ideal.js";
|
|
15
|
+
import "./slash/export.js";
|
|
16
|
+
import "./slash/status.js";
|
|
17
|
+
import "./slash/ponytail.js";
|
|
18
|
+
export type { AppStartupConfig } from "./types.js";
|
|
19
|
+
export interface AppLogicProps {
|
|
20
|
+
agent: any;
|
|
21
|
+
startupConfig: any;
|
|
22
|
+
initialMessage?: any;
|
|
23
|
+
onExit: any;
|
|
24
|
+
onRelaunch: any;
|
|
25
|
+
}
|
|
26
|
+
export declare function useAppLogic(props: AppLogicProps): any;
|
|
Binary file
|
|
@@ -20,7 +20,7 @@ import { spawn } from "node:child_process";
|
|
|
20
20
|
* `process.argv[0]` itself. We sanitize the WHOLE args portion in one pass.
|
|
21
21
|
*/
|
|
22
22
|
export function sanitizeArgvForResume(args, sessionId) {
|
|
23
|
-
if (!sessionId
|
|
23
|
+
if (!sessionId?.trim()) {
|
|
24
24
|
throw new Error("sanitizeArgvForResume: sessionId is required");
|
|
25
25
|
}
|
|
26
26
|
const out = [];
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
export declare function formatTokenCount(tokens: number): string;
|
|
2
|
+
/**
|
|
3
|
+
* Strip invisible/control Unicode characters that leak into terminal output.
|
|
4
|
+
* Keeps \t \n \r (needed for rendering); removes everything else that most
|
|
5
|
+
* terminals cannot display safely: zero-width spaces, soft hyphens, BiDi
|
|
6
|
+
* overrides, C0/C1 controls, BOM, and other default-ignorable code points.
|
|
7
|
+
* Fast-pathed: returns the input unchanged when no match is found.
|
|
8
|
+
*
|
|
9
|
+
* Uses `new RegExp()` to avoid Biome's `noControlCharactersInRegex` lint
|
|
10
|
+
* (control-char escapes in a regex literal are blocked).
|
|
11
|
+
*/
|
|
12
|
+
export declare function stripInvisibleChars(text: string): string;
|
|
2
13
|
export declare function trunc(s: string, n: number): string;
|
|
3
14
|
export declare function truncateLine(s: string, n: number): string;
|
|
4
15
|
export declare function truncateBlock(text: string, maxLines: number): string;
|
|
@@ -5,6 +5,26 @@ export function formatTokenCount(tokens) {
|
|
|
5
5
|
return `${Math.round(tokens / 1_000)}K`;
|
|
6
6
|
return String(tokens);
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Strip invisible/control Unicode characters that leak into terminal output.
|
|
10
|
+
* Keeps \t \n \r (needed for rendering); removes everything else that most
|
|
11
|
+
* terminals cannot display safely: zero-width spaces, soft hyphens, BiDi
|
|
12
|
+
* overrides, C0/C1 controls, BOM, and other default-ignorable code points.
|
|
13
|
+
* Fast-pathed: returns the input unchanged when no match is found.
|
|
14
|
+
*
|
|
15
|
+
* Uses `new RegExp()` to avoid Biome's `noControlCharactersInRegex` lint
|
|
16
|
+
* (control-char escapes in a regex literal are blocked).
|
|
17
|
+
*/
|
|
18
|
+
export function stripInvisibleChars(text) {
|
|
19
|
+
if (!text)
|
|
20
|
+
return text;
|
|
21
|
+
// Constructed via new RegExp to bypass Biome lint for control-char patterns.
|
|
22
|
+
// U+034F (Combining Grapheme Joiner) is separated via alternation per
|
|
23
|
+
// Biome's noMisleadingCharacterClass rule.
|
|
24
|
+
const re = new RegExp("[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u00AD\u061C\u070F\u200B-\u200F\u2028-\u202F\u2060-\u2069\uFEFF\uFFF9-\uFFFB]|" +
|
|
25
|
+
"\u034F|\u{1BCA0}-\u{1BCA3}|\u{E0001}|\u{E0020}-\u{E007F}", "gu");
|
|
26
|
+
return re.test(text) ? text.replace(re, "") : text;
|
|
27
|
+
}
|
|
8
28
|
export function trunc(s, n) {
|
|
9
29
|
const str = String(s ?? "");
|
|
10
30
|
return str.length <= n ? str : `${str.slice(0, n)}…`;
|
|
@@ -37,7 +57,7 @@ export function sanitizeContent(raw) {
|
|
|
37
57
|
* answer (e.g. `\frac{a}{b}`) is untouched. Fast-pathed: no work when absent.
|
|
38
58
|
*/
|
|
39
59
|
export function stripStrayModelMacros(text) {
|
|
40
|
-
if (!text
|
|
60
|
+
if (!text?.includes("\\confidence"))
|
|
41
61
|
return text;
|
|
42
62
|
// Trailing form (most common) — also swallow the whitespace/newline before it.
|
|
43
63
|
let out = text.replace(/\s*\\confidence\s*\{[^}]*\}\s*$/i, "");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { stripStrayModelMacros } from "./text.js";
|
|
2
|
+
import { stripInvisibleChars, stripStrayModelMacros } from "./text.js";
|
|
3
3
|
describe("stripStrayModelMacros", () => {
|
|
4
4
|
it("strips a trailing \\confidence{NN} macro and the blank line before it", () => {
|
|
5
5
|
const input = "Root cause: parseInt radix.\n\nFix: use radix 10.\n\n\\confidence{85}";
|
|
@@ -20,4 +20,28 @@ describe("stripStrayModelMacros", () => {
|
|
|
20
20
|
expect(stripStrayModelMacros("")).toBe("");
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
|
+
describe("stripInvisibleChars", () => {
|
|
24
|
+
it("strips zero-width spaces (U+200B)", () => {
|
|
25
|
+
expect(stripInvisibleChars("hello\u200Bworld")).toBe("helloworld");
|
|
26
|
+
});
|
|
27
|
+
it("strips soft hyphen (U+00AD)", () => {
|
|
28
|
+
expect(stripInvisibleChars("hy\u00ADphen")).toBe("hyphen");
|
|
29
|
+
});
|
|
30
|
+
it("strips BOM (U+FEFF)", () => {
|
|
31
|
+
expect(stripInvisibleChars("\uFEFFHello")).toBe("Hello");
|
|
32
|
+
});
|
|
33
|
+
it("strips BiDi overrides (U+202E)", () => {
|
|
34
|
+
expect(stripInvisibleChars("abc\u202Edef")).toBe("abcdef");
|
|
35
|
+
});
|
|
36
|
+
it("strips C0 controls except \\t \\n \\r", () => {
|
|
37
|
+
expect(stripInvisibleChars("a\u0001b\rc\td")).toBe("ab\rc\td");
|
|
38
|
+
});
|
|
39
|
+
it("keeps normal text unchanged (fast path)", () => {
|
|
40
|
+
const normal = "Hello world, how are you?";
|
|
41
|
+
expect(stripInvisibleChars(normal)).toBe(normal);
|
|
42
|
+
});
|
|
43
|
+
it("handles empty string", () => {
|
|
44
|
+
expect(stripInvisibleChars("")).toBe("");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
23
47
|
//# sourceMappingURL=text.test.js.map
|
|
@@ -27,7 +27,9 @@ export function toolArgs(tc) {
|
|
|
27
27
|
try {
|
|
28
28
|
const a = JSON.parse(tc.function.arguments);
|
|
29
29
|
if (tc.function.name === "bash")
|
|
30
|
-
return String(a.command || "")
|
|
30
|
+
return String(a.command || "")
|
|
31
|
+
.replace(/\n/g, " ")
|
|
32
|
+
.trim();
|
|
31
33
|
if (tc.function.name === "read_file" || tc.function.name === "write_file" || tc.function.name === "edit_file")
|
|
32
34
|
return String(a.file_path || a.path || "");
|
|
33
35
|
if (describeMcpFsTool(tc.function.name)) {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { promises as fs } from "node:fs";
|
|
15
15
|
import * as os from "node:os";
|
|
16
16
|
import * as path from "node:path";
|
|
17
|
-
import { projectCostUSD } from "./estimator.js";
|
|
17
|
+
import { projectCostUSD, sanitizeInputTokens } from "./estimator.js";
|
|
18
18
|
function muonroiHome(homeOverride) {
|
|
19
19
|
return homeOverride ?? process.env.MUONROI_CLI_HOME ?? path.join(os.homedir(), ".muonroi-cli");
|
|
20
20
|
}
|
|
@@ -57,7 +57,7 @@ export async function meteredGenerate(args, fn) {
|
|
|
57
57
|
const startedAt = Date.now();
|
|
58
58
|
try {
|
|
59
59
|
const { result, actualInputTokens, actualOutputTokens, cachedInputTokens, stepCount } = await fn();
|
|
60
|
-
const inTok = actualInputTokens
|
|
60
|
+
const inTok = sanitizeInputTokens(actualInputTokens, estIn);
|
|
61
61
|
const outTok = actualOutputTokens ?? Math.max(1, Math.ceil(estOut / 4));
|
|
62
62
|
const usd = projectCostUSD(args.provider, args.model, inTok, outTok);
|
|
63
63
|
await appendCostLog({
|
|
@@ -10,6 +10,20 @@
|
|
|
10
10
|
* Acceptable for cap projection only -- not for billing reconciliation.
|
|
11
11
|
*/
|
|
12
12
|
export declare function estimateTokensFromChars(chars: number): number;
|
|
13
|
+
/**
|
|
14
|
+
* Sanitize an actual input-token count by comparing it to the estimated
|
|
15
|
+
* (chars/4) count. Some providers (SiliconFlow, possibly others) return
|
|
16
|
+
* implausibly low `prompt_tokens` (e.g. 10) regardless of actual prompt size,
|
|
17
|
+
* which under-reports cost and inflates apparent cache-hit ratios.
|
|
18
|
+
*
|
|
19
|
+
* Rules:
|
|
20
|
+
* - When `actual === undefined`: return `estimated` (no data = use estimate).
|
|
21
|
+
* - When `actual === 0`: return 0 (preserve mock / failed-call semantics).
|
|
22
|
+
* - When `estimated > 0` and `actual < estimated * 0.1`: the value is likely
|
|
23
|
+
* bogus — return `estimated` so cost projections stay accurate.
|
|
24
|
+
* - Otherwise: return `actual` as-is.
|
|
25
|
+
*/
|
|
26
|
+
export declare function sanitizeInputTokens(actual: number | undefined, estimated: number): number;
|
|
13
27
|
/**
|
|
14
28
|
* Project the USD cost of a request given token estimates and the static pricing table.
|
|
15
29
|
* Returns 0 for unknown provider/model -- caller decides how to handle (ledger treats as 0 risk).
|