muonroi-cli 1.7.1 → 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 +143 -104
- 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.d.ts +6 -0
- package/dist/src/storage/sessions.js +49 -42
- 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 +2 -1
- 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/modals/session-picker-modal.js +14 -9
- package/dist/src/ui/modals/update-modal.js +2 -1
- 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/types.d.ts +7 -0
- 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.d.ts +17 -0
- package/dist/src/ui/utils/relaunch.js +28 -4
- package/dist/src/ui/utils/relaunch.test.js +50 -0
- 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
package/dist/src/lsp/runtime.js
CHANGED
|
@@ -10,9 +10,9 @@ export async function queryLsp(cwd, input) {
|
|
|
10
10
|
filePath: path.isAbsolute(input.filePath) ? input.filePath : path.resolve(cwd, input.filePath),
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
-
export async function syncFileWithLsp(cwd, filePath, content, save = true, waitForDiagnostics = true) {
|
|
13
|
+
export async function syncFileWithLsp(cwd, filePath, content, save = true, waitForDiagnostics = true, diagnosticsTimeoutMs) {
|
|
14
14
|
const manager = getOrCreateManager(cwd);
|
|
15
|
-
return manager.syncFile(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), content, save, waitForDiagnostics);
|
|
15
|
+
return manager.syncFile(path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath), content, save, waitForDiagnostics, diagnosticsTimeoutMs);
|
|
16
16
|
}
|
|
17
17
|
export function isLspToolEnabled(_cwd) {
|
|
18
18
|
const settings = getCurrentLspSettings();
|
|
@@ -12,9 +12,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
12
12
|
// ── Mocks ──────────────────────────────────────────────────────────────────
|
|
13
13
|
// vi.hoisted ensures the factory variable is available when vi.mock is hoisted.
|
|
14
14
|
const { mockExecFile } = vi.hoisted(() => ({ mockExecFile: vi.fn() }));
|
|
15
|
-
vi.mock("node:child_process", () =>
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
vi.mock("node:child_process", async () => {
|
|
16
|
+
const actual = await vi.importActual("node:child_process");
|
|
17
|
+
return {
|
|
18
|
+
...actual,
|
|
19
|
+
execFile: mockExecFile,
|
|
20
|
+
};
|
|
21
|
+
});
|
|
18
22
|
vi.mock("node:fs", async (importOriginal) => {
|
|
19
23
|
const actual = (await importOriginal());
|
|
20
24
|
return {
|
|
@@ -11,9 +11,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
11
11
|
// ── Mocks ──────────────────────────────────────────────────────────────────
|
|
12
12
|
// vi.hoisted ensures the factory variable is available when vi.mock is hoisted.
|
|
13
13
|
const { mockExecFile } = vi.hoisted(() => ({ mockExecFile: vi.fn() }));
|
|
14
|
-
vi.mock("node:child_process", () =>
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
vi.mock("node:child_process", async () => {
|
|
15
|
+
const actual = await vi.importActual("node:child_process");
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
execFile: mockExecFile,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
17
21
|
vi.mock("../../council/leader.js", () => ({
|
|
18
22
|
pickCouncilTaskModel: vi.fn((_task, leaderId) => leaderId),
|
|
19
23
|
}));
|
|
@@ -54,7 +54,7 @@ describe("acquireMcpTools — cross-turn client pool", () => {
|
|
|
54
54
|
client: { close: async () => { } },
|
|
55
55
|
}));
|
|
56
56
|
const b1 = await acquireMcpTools([srv("fs")]);
|
|
57
|
-
await expect(b1.tools
|
|
57
|
+
await expect(b1.tools.mcp_fs__boom.execute({}, {})).rejects.toThrow(/transport closed/);
|
|
58
58
|
// Initial connect + exactly ONE in-turn reconnect — the retry is not looped.
|
|
59
59
|
expect(connectOneServer).toHaveBeenCalledTimes(2);
|
|
60
60
|
});
|
|
@@ -77,7 +77,7 @@ describe("acquireMcpTools — cross-turn client pool", () => {
|
|
|
77
77
|
};
|
|
78
78
|
});
|
|
79
79
|
const b = await acquireMcpTools([srv("docs")]);
|
|
80
|
-
const result = await b.tools
|
|
80
|
+
const result = await b.tools.mcp_docs__ping.execute({}, {});
|
|
81
81
|
expect(result).toBe("pong"); // recovered within the SAME turn
|
|
82
82
|
expect(connectOneServer).toHaveBeenCalledTimes(2); // drop + one reconnect
|
|
83
83
|
});
|
|
@@ -104,7 +104,7 @@ describe("acquireMcpTools — cross-turn client pool", () => {
|
|
|
104
104
|
};
|
|
105
105
|
});
|
|
106
106
|
const b = await acquireMcpTools([srv("docs")]);
|
|
107
|
-
const tool = b.tools
|
|
107
|
+
const tool = b.tools.mcp_docs__ping;
|
|
108
108
|
const results = await Promise.all(Array.from({ length: 14 }, () => tool.execute({}, {})));
|
|
109
109
|
expect(results.every((r) => r === "pong")).toBe(true);
|
|
110
110
|
expect(connectOneServer).toHaveBeenCalledTimes(2); // 14 failures → exactly ONE shared reconnect
|
|
@@ -46,7 +46,7 @@ describe("ee-tools", () => {
|
|
|
46
46
|
}),
|
|
47
47
|
health: async () => ({ ok: true, status: 200 }),
|
|
48
48
|
}));
|
|
49
|
-
const out = rawTextOf(await handlers
|
|
49
|
+
const out = rawTextOf(await handlers.ee_query({ query: "redactor" }));
|
|
50
50
|
expect(out.isError).toBeFalsy();
|
|
51
51
|
expect(out.text).toContain("recall:redactor");
|
|
52
52
|
expect(out.text).toContain("[id:abc col:experience-behavioral]"); // handle preserved for exp-feedback
|
|
@@ -58,7 +58,7 @@ describe("ee-tools", () => {
|
|
|
58
58
|
recall: async () => ({ text: "x".repeat(50_000), entries: [], count: 42 }),
|
|
59
59
|
health: async () => ({ ok: true, status: 200 }),
|
|
60
60
|
}));
|
|
61
|
-
const out = rawTextOf(await handlers
|
|
61
|
+
const out = rawTextOf(await handlers.ee_query({ query: "wide", maxChars: 6000 }));
|
|
62
62
|
expect(out.isError).toBeFalsy();
|
|
63
63
|
expect(out.text.length).toBeLessThan(7000); // capped, not the full 50k dump
|
|
64
64
|
expect(out.text).toContain("truncated");
|
|
@@ -73,18 +73,18 @@ describe("ee-tools", () => {
|
|
|
73
73
|
},
|
|
74
74
|
health: async () => ({ ok: true, status: 200 }),
|
|
75
75
|
}));
|
|
76
|
-
await handlers
|
|
76
|
+
await handlers.ee_query({ query: "scope filter", project: "storyflow" });
|
|
77
77
|
expect(seenProject).toBe("storyflow");
|
|
78
78
|
});
|
|
79
79
|
it("ee_query returns ee_unavailable when recall yields null", async () => {
|
|
80
80
|
const handlers = collectTools((s) => registerEETools(s, { recall: async () => null, health: async () => ({ ok: false, status: 0 }) }));
|
|
81
|
-
const out = textOf(await handlers
|
|
81
|
+
const out = textOf(await handlers.ee_query({ query: "x" }));
|
|
82
82
|
expect(out.isError).toBe(true);
|
|
83
83
|
expect(out.json.error).toBe("ee_unavailable");
|
|
84
84
|
});
|
|
85
85
|
it("ee_health returns the injected status", async () => {
|
|
86
86
|
const handlers = collectTools((s) => registerEETools(s, { recall: async () => null, health: async () => ({ ok: true, status: 200 }) }));
|
|
87
|
-
const out = textOf(await handlers
|
|
87
|
+
const out = textOf(await handlers.ee_health({}));
|
|
88
88
|
expect(out.json).toEqual({ ok: true, status: 200 });
|
|
89
89
|
});
|
|
90
90
|
it("ee_health returns ee_unavailable when health throws", async () => {
|
|
@@ -94,7 +94,7 @@ describe("ee-tools", () => {
|
|
|
94
94
|
throw new Error("boom");
|
|
95
95
|
},
|
|
96
96
|
}));
|
|
97
|
-
const out = textOf(await handlers
|
|
97
|
+
const out = textOf(await handlers.ee_health({}));
|
|
98
98
|
expect(out.isError).toBe(true);
|
|
99
99
|
expect(out.json.error).toBe("ee_unavailable");
|
|
100
100
|
});
|
|
@@ -111,7 +111,7 @@ describe("ee-tools", () => {
|
|
|
111
111
|
return { ok: true, resolvedId: id, verdict: verdict === "followed" ? "FOLLOWED" : verdict };
|
|
112
112
|
},
|
|
113
113
|
}));
|
|
114
|
-
const out = textOf(await handlers
|
|
114
|
+
const out = textOf(await handlers.ee_feedback({ id: "abc", collection: "experience-behavioral", verdict: "followed" }));
|
|
115
115
|
expect(out.isError).toBeFalsy();
|
|
116
116
|
expect(seen).toEqual({ id: "abc", collection: "experience-behavioral", verdict: "followed", reason: undefined });
|
|
117
117
|
expect(out.json.ok).toBe(true);
|
|
@@ -120,7 +120,7 @@ describe("ee-tools", () => {
|
|
|
120
120
|
});
|
|
121
121
|
it("ee_feedback requires a reason for verdict=noise", async () => {
|
|
122
122
|
const handlers = collectTools((s) => registerEETools(s, { feedback: async () => ({ ok: true }) }));
|
|
123
|
-
const out = textOf(await handlers
|
|
123
|
+
const out = textOf(await handlers.ee_feedback({ id: "x", collection: "experience-selfqa", verdict: "noise" }));
|
|
124
124
|
expect(out.isError).toBe(true);
|
|
125
125
|
expect(out.json.error).toBe("reason_required");
|
|
126
126
|
});
|
|
@@ -128,7 +128,7 @@ describe("ee-tools", () => {
|
|
|
128
128
|
const ledger = createRecallLedger();
|
|
129
129
|
ledger.record([{ id: "abc", collection: "experience-behavioral" }], "q");
|
|
130
130
|
const handlers = collectTools((s) => registerEETools(s, { ledger, feedback: async () => ({ ok: false, error: "HTTP 500" }) }));
|
|
131
|
-
const out = textOf(await handlers
|
|
131
|
+
const out = textOf(await handlers.ee_feedback({ id: "abc", collection: "experience-behavioral", verdict: "ignored" }));
|
|
132
132
|
expect(out.isError).toBe(true);
|
|
133
133
|
expect(out.json.error).toBe("feedback_failed");
|
|
134
134
|
expect(ledger.pendingCount()).toBe(1); // NOT cleared on failure
|
|
@@ -145,11 +145,11 @@ describe("ee-tools", () => {
|
|
|
145
145
|
health: async () => ({ ok: true, status: 200 }),
|
|
146
146
|
}));
|
|
147
147
|
// First recall — no prior debt, so no gate prefix.
|
|
148
|
-
const first = rawTextOf(await handlers
|
|
148
|
+
const first = rawTextOf(await handlers.ee_query({ query: "first" }));
|
|
149
149
|
expect(first.text).not.toContain("still unrated");
|
|
150
150
|
expect(ledger.pendingCount()).toBe(1);
|
|
151
151
|
// Second recall — the prior id1 is still unrated → soft prefix, but recall still returned.
|
|
152
|
-
const second = rawTextOf(await handlers
|
|
152
|
+
const second = rawTextOf(await handlers.ee_query({ query: "second" }));
|
|
153
153
|
expect(second.isError).toBeFalsy();
|
|
154
154
|
expect(second.text).toContain("still unrated");
|
|
155
155
|
expect(second.text).toContain("id1");
|
|
@@ -172,7 +172,7 @@ describe("ee-tools", () => {
|
|
|
172
172
|
return { text: "should not run", entries: [], count: 0 };
|
|
173
173
|
},
|
|
174
174
|
}));
|
|
175
|
-
const out = textOf(await handlers
|
|
175
|
+
const out = textOf(await handlers.ee_query({ query: "blocked" }));
|
|
176
176
|
expect(out.isError).toBe(true);
|
|
177
177
|
expect(out.json.error).toBe("feedback_required");
|
|
178
178
|
expect(out.json.message).toContain("FEEDBACK GATE");
|
|
@@ -190,9 +190,37 @@ describe("ee-tools", () => {
|
|
|
190
190
|
}),
|
|
191
191
|
health: async () => ({ ok: true, status: 200 }),
|
|
192
192
|
}));
|
|
193
|
-
await handlers
|
|
194
|
-
await handlers
|
|
193
|
+
await handlers.ee_query({ query: "one" });
|
|
194
|
+
await handlers.ee_query({ query: "two" });
|
|
195
195
|
expect(ledger.pendingCount()).toBe(0); // nothing stamped when gate is off
|
|
196
196
|
});
|
|
197
|
+
// ─── ee_write (Layer 1 — agent records a new lesson) ───────────────────────
|
|
198
|
+
it("ee_write forwards the lesson to the write helper and returns the new id", async () => {
|
|
199
|
+
let seen = null;
|
|
200
|
+
const handlers = collectTools((s) => registerEETools(s, {
|
|
201
|
+
write: async (lesson, opts) => {
|
|
202
|
+
seen = { lesson, opts };
|
|
203
|
+
return { ok: true, id: "new-point-1" };
|
|
204
|
+
},
|
|
205
|
+
}));
|
|
206
|
+
const out = textOf(await handlers.ee_write({
|
|
207
|
+
lesson: "always call flushFrob() before reindex or reads go stale",
|
|
208
|
+
title: "reindex pitfall",
|
|
209
|
+
project: "experience-engine",
|
|
210
|
+
}));
|
|
211
|
+
expect(out.isError).toBeFalsy();
|
|
212
|
+
expect(out.json.ok).toBe(true);
|
|
213
|
+
expect(out.json.id).toBe("new-point-1");
|
|
214
|
+
expect(out.json.collection).toBe("experience-behavioral");
|
|
215
|
+
expect(seen.lesson).toContain("flushFrob");
|
|
216
|
+
expect(seen.opts.collection).toBe("experience-behavioral");
|
|
217
|
+
expect(seen.opts.projectSlug).toBe("experience-engine");
|
|
218
|
+
});
|
|
219
|
+
it("ee_write surfaces write_failed when the write helper fails", async () => {
|
|
220
|
+
const handlers = collectTools((s) => registerEETools(s, { write: async () => ({ ok: false, error: "import-memory HTTP 500" }) }));
|
|
221
|
+
const out = textOf(await handlers.ee_write({ lesson: "a sufficiently long lesson body here" }));
|
|
222
|
+
expect(out.isError).toBe(true);
|
|
223
|
+
expect(out.json.error).toBe("write_failed");
|
|
224
|
+
});
|
|
197
225
|
});
|
|
198
226
|
//# sourceMappingURL=ee-tools.test.js.map
|
|
@@ -32,20 +32,20 @@ const fakeSummary = (id) => ({
|
|
|
32
32
|
describe("forensics-tools", () => {
|
|
33
33
|
it("usage_forensics returns the summary for a unique prefix", async () => {
|
|
34
34
|
const handlers = collectTools((s) => registerForensicsTools(s, { resolve: () => ["sess123"], collect: (id) => fakeSummary(id) }));
|
|
35
|
-
const out = parse(await handlers
|
|
35
|
+
const out = parse(await handlers.usage_forensics({ prefix: "sess" }));
|
|
36
36
|
expect(out.isError).toBeFalsy();
|
|
37
37
|
expect(out.json.sessionId).toBe("sess123");
|
|
38
38
|
expect(out.json.peakSingleCallInput).toBe(100);
|
|
39
39
|
});
|
|
40
40
|
it("usage_forensics returns not_found for zero matches", async () => {
|
|
41
41
|
const handlers = collectTools((s) => registerForensicsTools(s, { resolve: () => [], collect: () => fakeSummary("x") }));
|
|
42
|
-
const out = parse(await handlers
|
|
42
|
+
const out = parse(await handlers.usage_forensics({ prefix: "nope" }));
|
|
43
43
|
expect(out.isError).toBe(true);
|
|
44
44
|
expect(out.json.error).toBe("not_found");
|
|
45
45
|
});
|
|
46
46
|
it("usage_forensics returns ambiguous for multiple matches", async () => {
|
|
47
47
|
const handlers = collectTools((s) => registerForensicsTools(s, { resolve: () => ["a1", "a2"], collect: () => fakeSummary("a1") }));
|
|
48
|
-
const out = parse(await handlers
|
|
48
|
+
const out = parse(await handlers.usage_forensics({ prefix: "a" }));
|
|
49
49
|
expect(out.isError).toBe(true);
|
|
50
50
|
expect(out.json.error).toBe("ambiguous");
|
|
51
51
|
expect(out.json.matches).toEqual(["a1", "a2"]);
|
|
@@ -18,13 +18,13 @@ describe("lsp-tools", () => {
|
|
|
18
18
|
it("lsp_query passes through the LspToolResponse when enabled", async () => {
|
|
19
19
|
const resp = { success: true, output: "def at file.ts:10" };
|
|
20
20
|
const handlers = collectTools((s) => registerLspTools(s, { enabled: () => true, query: async () => resp }));
|
|
21
|
-
const out = parse(await handlers
|
|
21
|
+
const out = parse(await handlers.lsp_query({ operation: "goToDefinition", filePath: "a.ts", line: 1, character: 2 }));
|
|
22
22
|
expect(out.isError).toBeFalsy();
|
|
23
23
|
expect(out.json).toEqual(resp);
|
|
24
24
|
});
|
|
25
25
|
it("lsp_query returns lsp_disabled when LSP is off", async () => {
|
|
26
26
|
const handlers = collectTools((s) => registerLspTools(s, { enabled: () => false, query: async () => ({ success: true, output: "x" }) }));
|
|
27
|
-
const out = parse(await handlers
|
|
27
|
+
const out = parse(await handlers.lsp_query({ operation: "hover", filePath: "a.ts", line: 0, character: 0 }));
|
|
28
28
|
expect(out.isError).toBe(true);
|
|
29
29
|
expect(out.json.error).toBe("lsp_disabled");
|
|
30
30
|
});
|
|
@@ -35,7 +35,7 @@ describe("lsp-tools", () => {
|
|
|
35
35
|
throw new Error("server launch failed");
|
|
36
36
|
},
|
|
37
37
|
}));
|
|
38
|
-
const out = parse(await handlers
|
|
38
|
+
const out = parse(await handlers.lsp_query({ operation: "findReferences", filePath: "a.ts", line: 3, character: 4 }));
|
|
39
39
|
expect(out.isError).toBe(true);
|
|
40
40
|
expect(out.json.error).toBe("lsp_error");
|
|
41
41
|
expect(out.json.message).toContain("server launch failed");
|
|
@@ -47,7 +47,7 @@ describe("lsp-tools", () => {
|
|
|
47
47
|
},
|
|
48
48
|
query: async () => ({ success: true, output: "x" }),
|
|
49
49
|
}));
|
|
50
|
-
const out = parse(await handlers
|
|
50
|
+
const out = parse(await handlers.lsp_query({ operation: "hover", filePath: "a.ts", line: 0, character: 0 }));
|
|
51
51
|
expect(out.isError).toBe(true);
|
|
52
52
|
expect(out.json.error).toBe("lsp_error");
|
|
53
53
|
expect(out.json.message).toContain("settings read failed");
|
|
@@ -44,7 +44,7 @@ export declare function acquireMcpTools(servers: McpServerConfig[], opts?: McpBu
|
|
|
44
44
|
* has connected. Idempotent (cached entries are reused); a failed connect is
|
|
45
45
|
* evicted by getOrConnect so a real turn retries.
|
|
46
46
|
*/
|
|
47
|
-
export declare function warmMcpClients(servers: McpServerConfig[]): void
|
|
47
|
+
export declare function warmMcpClients(servers: McpServerConfig[], syncAndLog?: boolean): Promise<void>;
|
|
48
48
|
/** Tear down every pooled client. Call on orchestrator/process shutdown. */
|
|
49
49
|
export declare function closeAllMcpClients(): Promise<void>;
|
|
50
50
|
/** Test-only: reset pool state between cases. */
|
|
@@ -236,15 +236,31 @@ export async function acquireMcpTools(servers, opts) {
|
|
|
236
236
|
* has connected. Idempotent (cached entries are reused); a failed connect is
|
|
237
237
|
* evicted by getOrConnect so a real turn retries.
|
|
238
238
|
*/
|
|
239
|
-
export function warmMcpClients(servers) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
239
|
+
export async function warmMcpClients(servers, syncAndLog = false) {
|
|
240
|
+
const validServers = servers.filter(s => s.enabled && validateMcpServerConfig(s).ok);
|
|
241
|
+
if (syncAndLog && validServers.length > 0) {
|
|
242
|
+
console.log(`[MCP] Warming up ${validServers.length} server(s)...`);
|
|
243
|
+
}
|
|
244
|
+
const promises = validServers.map(async (s) => {
|
|
245
|
+
try {
|
|
246
|
+
await getOrConnect(s);
|
|
247
|
+
if (syncAndLog) {
|
|
248
|
+
console.log(`[MCP] ✅ ${s.id}: healthy`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
if (syncAndLog) {
|
|
253
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
254
|
+
console.log(`[MCP] ❌ ${s.id}: failed - ${msg}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
if (syncAndLog) {
|
|
259
|
+
await Promise.all(promises);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
// Fire-and-forget for background warmup
|
|
263
|
+
void Promise.all(promises);
|
|
248
264
|
}
|
|
249
265
|
}
|
|
250
266
|
/** Tear down every pooled client. Call on orchestrator/process shutdown. */
|
|
@@ -30,6 +30,16 @@ export interface EEToolDeps {
|
|
|
30
30
|
status: number;
|
|
31
31
|
}>;
|
|
32
32
|
feedback?: (pointId: string, collection: string, verdict: FeedbackVerdict, reason?: NoiseReason) => Promise<FeedbackResult>;
|
|
33
|
+
write?: (lesson: string, opts: {
|
|
34
|
+
collection?: string;
|
|
35
|
+
title?: string;
|
|
36
|
+
projectSlug?: string;
|
|
37
|
+
confidence?: number;
|
|
38
|
+
}) => Promise<{
|
|
39
|
+
ok: boolean;
|
|
40
|
+
id?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}>;
|
|
33
43
|
/** Session pending-recall ledger. Defaults to the process singleton. */
|
|
34
44
|
ledger?: RecallLedger;
|
|
35
45
|
}
|
package/dist/src/mcp/ee-tools.js
CHANGED
|
@@ -155,5 +155,39 @@ export function registerEETools(server, deps = {}) {
|
|
|
155
155
|
return fail("ee_unavailable", e instanceof Error ? e.message : String(e));
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
|
+
server.registerTool("ee_write", {
|
|
159
|
+
description: "Save a NEW lesson to the Experience Engine brain so you and future sessions recall it. Call the MOMENT you " +
|
|
160
|
+
"hit a mistake / error / dead-end and find the working fix: record the pitfall AND the fix in one concise, " +
|
|
161
|
+
"generalizable lesson (1-3 sentences — what to do or avoid next time, NOT a play-by-play of this turn). The " +
|
|
162
|
+
"lesson is embedded immediately (via /api/import-memory: dense + sparse) and becomes recallable via ee_query " +
|
|
163
|
+
"in this and future sessions. Use ee_query first if unsure a lesson already exists. collection defaults to " +
|
|
164
|
+
"experience-behavioral (use experience-principles only for a broad, project-independent principle); project " +
|
|
165
|
+
"scopes the lesson.",
|
|
166
|
+
inputSchema: {
|
|
167
|
+
lesson: z.string().min(12).max(4000),
|
|
168
|
+
title: z.string().max(200).optional(),
|
|
169
|
+
collection: z.enum(["experience-behavioral", "experience-principles"]).optional(),
|
|
170
|
+
project: z.string().max(200).optional(),
|
|
171
|
+
},
|
|
172
|
+
}, async ({ lesson, title, collection, project }) => {
|
|
173
|
+
const trimmed = lesson.trim();
|
|
174
|
+
const text = trimmed.length > 1500 ? `${trimmed.slice(0, 1497)}...` : trimmed;
|
|
175
|
+
const targetCollection = collection ?? "experience-behavioral";
|
|
176
|
+
const write = deps.write ?? ((l, o) => import("../ee/search.js").then((m) => m.writeExperienceEE(l, o)));
|
|
177
|
+
try {
|
|
178
|
+
const result = await write(text, {
|
|
179
|
+
collection: targetCollection,
|
|
180
|
+
title,
|
|
181
|
+
projectSlug: project,
|
|
182
|
+
confidence: 0.65,
|
|
183
|
+
});
|
|
184
|
+
if (!result.ok)
|
|
185
|
+
return fail("write_failed", result.error ?? "import-memory POST failed");
|
|
186
|
+
return ok({ ok: true, id: result.id, collection: targetCollection, recallable: "now via ee_query" });
|
|
187
|
+
}
|
|
188
|
+
catch (e) {
|
|
189
|
+
return fail("write_failed", e instanceof Error ? e.message : String(e));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
158
192
|
}
|
|
159
193
|
//# sourceMappingURL=ee-tools.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import { URL } from "node:url";
|
|
3
|
-
const SUCCESS_HTML = `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
4
|
-
<h2>Authorization successful</h2><p>You can close this tab and return to the terminal.</p>
|
|
3
|
+
const SUCCESS_HTML = `<!DOCTYPE html><html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
4
|
+
<h2>Authorization successful</h2><p>You can close this tab and return to the terminal.</p>
|
|
5
5
|
</body></html>`;
|
|
6
6
|
export function startOAuthCallbackServer(opts) {
|
|
7
7
|
const callbackPath = opts.path ?? "/callback";
|
|
@@ -2,19 +2,19 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import { parseEnvLines, parseHeaderLines } from "./parse-headers.js";
|
|
3
3
|
describe("parseHeaderLines", () => {
|
|
4
4
|
it("parses colon-separated headers and trims whitespace", () => {
|
|
5
|
-
expect(parseHeaderLines(`
|
|
6
|
-
Authorization: Bearer token
|
|
7
|
-
X-Trace-Id: abc123
|
|
5
|
+
expect(parseHeaderLines(`
|
|
6
|
+
Authorization: Bearer token
|
|
7
|
+
X-Trace-Id: abc123
|
|
8
8
|
`)).toEqual({
|
|
9
9
|
Authorization: "Bearer token",
|
|
10
10
|
"X-Trace-Id": "abc123",
|
|
11
11
|
});
|
|
12
12
|
});
|
|
13
13
|
it("ignores blank and malformed lines while preserving later colons in values", () => {
|
|
14
|
-
expect(parseHeaderLines(`
|
|
15
|
-
invalid
|
|
16
|
-
: missing-name
|
|
17
|
-
Host: example.com:443
|
|
14
|
+
expect(parseHeaderLines(`
|
|
15
|
+
invalid
|
|
16
|
+
: missing-name
|
|
17
|
+
Host: example.com:443
|
|
18
18
|
`)).toEqual({
|
|
19
19
|
Host: "example.com:443",
|
|
20
20
|
});
|
|
@@ -22,19 +22,19 @@ describe("parseHeaderLines", () => {
|
|
|
22
22
|
});
|
|
23
23
|
describe("parseEnvLines", () => {
|
|
24
24
|
it("parses equals-separated env assignments and trims whitespace", () => {
|
|
25
|
-
expect(parseEnvLines(`
|
|
26
|
-
API_KEY = secret
|
|
27
|
-
MODE= production
|
|
25
|
+
expect(parseEnvLines(`
|
|
26
|
+
API_KEY = secret
|
|
27
|
+
MODE= production
|
|
28
28
|
`)).toEqual({
|
|
29
29
|
API_KEY: "secret",
|
|
30
30
|
MODE: "production",
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
it("ignores blank and malformed lines while preserving later equals in values", () => {
|
|
34
|
-
expect(parseEnvLines(`
|
|
35
|
-
missing
|
|
36
|
-
= no-name
|
|
37
|
-
URL=https://example.com?a=b
|
|
34
|
+
expect(parseEnvLines(`
|
|
35
|
+
missing
|
|
36
|
+
= no-name
|
|
37
|
+
URL=https://example.com?a=b
|
|
38
38
|
`)).toEqual({
|
|
39
39
|
URL: "https://example.com?a=b",
|
|
40
40
|
});
|
|
@@ -34,9 +34,7 @@ export class JobManager {
|
|
|
34
34
|
job.logBuffer.splice(0, job.logBuffer.length - LOG_CAP);
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
|
-
const run = opts.kind === "tier1"
|
|
38
|
-
? this.runner.tier1(opts, log, ctrl.signal)
|
|
39
|
-
: this.runner.agentic(opts, log, ctrl.signal);
|
|
37
|
+
const run = opts.kind === "tier1" ? this.runner.tier1(opts, log, ctrl.signal) : this.runner.agentic(opts, log, ctrl.signal);
|
|
40
38
|
run.then((report) => {
|
|
41
39
|
this.controllers.delete(runId); // I2: keep maps symmetric after natural completion
|
|
42
40
|
if (job.status === "cancelled")
|
|
@@ -6,79 +6,79 @@
|
|
|
6
6
|
* and the muonroi-tools MCP server (src/mcp/tools-server.ts, for external agents).
|
|
7
7
|
* Keeping it here avoids duplicating ~70 lines across the two.
|
|
8
8
|
*/
|
|
9
|
-
export const SETUP_GUIDE_TEXT = `# muonroi-cli Setup Guide
|
|
10
|
-
|
|
11
|
-
## Install (zero runtime deps — recommended)
|
|
12
|
-
Linux / macOS:
|
|
13
|
-
curl -fsSL https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.sh | bash
|
|
14
|
-
|
|
15
|
-
Windows PowerShell:
|
|
16
|
-
irm https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.ps1 | iex
|
|
17
|
-
|
|
18
|
-
Bun (requires Bun >= 1.3):
|
|
19
|
-
bun add -g muonroi-cli
|
|
20
|
-
# (npm install -g is NOT supported — TUI engine uses Bun-only ESM features)
|
|
21
|
-
|
|
22
|
-
The installers fetch a pre-compiled single binary from GitHub Releases.
|
|
23
|
-
|
|
24
|
-
## First run
|
|
25
|
-
- Wizard appears automatically.
|
|
26
|
-
- Lists supported providers (DeepSeek + SiliconFlow ready; others via BYOK).
|
|
27
|
-
- Four credential options: paste key, Bitwarden sync (B in /providers), keys export/import (encrypted bundle), or skip for later.
|
|
28
|
-
- Keys land in OS keychain (keytar). Settings written to ~/.muonroi-cli/user-settings.json.
|
|
29
|
-
- Role routing (leader/implement/verify/research) is configured for you.
|
|
30
|
-
|
|
31
|
-
After setup: run \`muonroi-cli doctor\` to validate.
|
|
32
|
-
|
|
33
|
-
## Essential commands
|
|
34
|
-
- Interactive TUI: \`muonroi-cli\` (or \`node dist/index.js\` after build)
|
|
35
|
-
- Headless one-shot: \`muonroi-cli --prompt "your task" --max-tool-rounds 8\`
|
|
36
|
-
- Health + MCP nudge: \`muonroi-cli doctor\`
|
|
37
|
-
- Update: \`muonroi-cli update\` (or set "autoUpdate": true in user-settings)
|
|
38
|
-
- Keys move between machines: \`muonroi-cli keys export file.json\` then import on target
|
|
39
|
-
- Native tools MCP (for external agents): \`muonroi-cli tools-mcp\` (stdio)
|
|
40
|
-
- Harness driver MCP: \`muonroi-cli mcp-driver\`
|
|
41
|
-
|
|
42
|
-
## MCP integration (for Claude Desktop, Cursor, other agents)
|
|
43
|
-
Add to your MCP client config:
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
"mcpServers": {
|
|
47
|
-
"muonroi-tools": {
|
|
48
|
-
"command": "bun",
|
|
49
|
-
"args": ["run", "/absolute/path/to/muonroi-cli/src/index.ts", "tools-mcp"]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
(Use absolute path. After \`bun run build\`: "node", "dist/index.js", "tools-mcp")
|
|
55
|
-
|
|
56
|
-
The CLI's OWN inner agent exposes these as NATIVE in-process tools (no MCP self-spawn):
|
|
57
|
-
- setup_guide (this document)
|
|
58
|
-
- ee_query / ee_health / ee_feedback — Experience Engine semantic recall + compaction checkpoints + feedback for learning
|
|
59
|
-
- usage_forensics <id-prefix> — per-session cost/token forensics (peak input, cache hits, anomalies)
|
|
60
|
-
- lsp_query — goToDefinition, findReferences, hover, symbols, call hierarchy etc.
|
|
61
|
-
- selfverify_* — Tier-1 heuristic + Tier-2 agentic self-QA harness runs (start/poll/result/cancel/list)
|
|
62
|
-
|
|
63
|
-
For BB/.NET template recipes and package docs, also connect an external "muonroi-docs" MCP server if available (provides docs_search + setup_guide for the templates).
|
|
64
|
-
|
|
65
|
-
## Development
|
|
66
|
-
git clone https://github.com/muonroi/muonroi-cli.git
|
|
67
|
-
cd muonroi-cli && bun install
|
|
68
|
-
|
|
69
|
-
bun run dev # run from source (TUI)
|
|
70
|
-
bun run typecheck # tsc --noEmit
|
|
71
|
-
bun run test # vitest (unit + headless)
|
|
72
|
-
bunx vitest -c vitest.harness.config.ts run tests/harness/ # TUI E2E (named-pipes on Win, fd3/4 on POSIX)
|
|
73
|
-
bun run build # or build:binary for standalone exe
|
|
74
|
-
|
|
75
|
-
See AGENTS.md (quick ref + rules), CLAUDE.md (harness verification), README.md.
|
|
76
|
-
|
|
77
|
-
## Verify
|
|
78
|
-
muonroi-cli doctor
|
|
79
|
-
# Checks runtimes, catalog load, keychain, MCP servers enabled, council research MCP nudge, EE reachability, recent error rate.
|
|
80
|
-
# Any "warn" entries tell you exactly what to enable (e.g. tavily for web research in council).
|
|
81
|
-
|
|
82
|
-
For BB-aware scaffolding (/ideal on a muonroi-building-block target): ensure dotnet SDK + the three Muonroi.*.Template packages are installed via NuGet; doctor surfaces missing feed/template cases.
|
|
9
|
+
export const SETUP_GUIDE_TEXT = `# muonroi-cli Setup Guide
|
|
10
|
+
|
|
11
|
+
## Install (zero runtime deps — recommended)
|
|
12
|
+
Linux / macOS:
|
|
13
|
+
curl -fsSL https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.sh | bash
|
|
14
|
+
|
|
15
|
+
Windows PowerShell:
|
|
16
|
+
irm https://raw.githubusercontent.com/muonroi/muonroi-cli/master/install.ps1 | iex
|
|
17
|
+
|
|
18
|
+
Bun (requires Bun >= 1.3):
|
|
19
|
+
bun add -g muonroi-cli
|
|
20
|
+
# (npm install -g is NOT supported — TUI engine uses Bun-only ESM features)
|
|
21
|
+
|
|
22
|
+
The installers fetch a pre-compiled single binary from GitHub Releases.
|
|
23
|
+
|
|
24
|
+
## First run
|
|
25
|
+
- Wizard appears automatically.
|
|
26
|
+
- Lists supported providers (DeepSeek + SiliconFlow ready; others via BYOK).
|
|
27
|
+
- Four credential options: paste key, Bitwarden sync (B in /providers), keys export/import (encrypted bundle), or skip for later.
|
|
28
|
+
- Keys land in OS keychain (keytar). Settings written to ~/.muonroi-cli/user-settings.json.
|
|
29
|
+
- Role routing (leader/implement/verify/research) is configured for you.
|
|
30
|
+
|
|
31
|
+
After setup: run \`muonroi-cli doctor\` to validate.
|
|
32
|
+
|
|
33
|
+
## Essential commands
|
|
34
|
+
- Interactive TUI: \`muonroi-cli\` (or \`node dist/index.js\` after build)
|
|
35
|
+
- Headless one-shot: \`muonroi-cli --prompt "your task" --max-tool-rounds 8\`
|
|
36
|
+
- Health + MCP nudge: \`muonroi-cli doctor\`
|
|
37
|
+
- Update: \`muonroi-cli update\` (or set "autoUpdate": true in user-settings)
|
|
38
|
+
- Keys move between machines: \`muonroi-cli keys export file.json\` then import on target
|
|
39
|
+
- Native tools MCP (for external agents): \`muonroi-cli tools-mcp\` (stdio)
|
|
40
|
+
- Harness driver MCP: \`muonroi-cli mcp-driver\`
|
|
41
|
+
|
|
42
|
+
## MCP integration (for Claude Desktop, Cursor, other agents)
|
|
43
|
+
Add to your MCP client config:
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
"mcpServers": {
|
|
47
|
+
"muonroi-tools": {
|
|
48
|
+
"command": "bun",
|
|
49
|
+
"args": ["run", "/absolute/path/to/muonroi-cli/src/index.ts", "tools-mcp"]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
(Use absolute path. After \`bun run build\`: "node", "dist/index.js", "tools-mcp")
|
|
55
|
+
|
|
56
|
+
The CLI's OWN inner agent exposes these as NATIVE in-process tools (no MCP self-spawn):
|
|
57
|
+
- setup_guide (this document)
|
|
58
|
+
- ee_query / ee_health / ee_feedback — Experience Engine semantic recall + compaction checkpoints + feedback for learning
|
|
59
|
+
- usage_forensics <id-prefix> — per-session cost/token forensics (peak input, cache hits, anomalies)
|
|
60
|
+
- lsp_query — goToDefinition, findReferences, hover, symbols, call hierarchy etc.
|
|
61
|
+
- selfverify_* — Tier-1 heuristic + Tier-2 agentic self-QA harness runs (start/poll/result/cancel/list)
|
|
62
|
+
|
|
63
|
+
For BB/.NET template recipes and package docs, also connect an external "muonroi-docs" MCP server if available (provides docs_search + setup_guide for the templates).
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
git clone https://github.com/muonroi/muonroi-cli.git
|
|
67
|
+
cd muonroi-cli && bun install
|
|
68
|
+
|
|
69
|
+
bun run dev # run from source (TUI)
|
|
70
|
+
bun run typecheck # tsc --noEmit
|
|
71
|
+
bun run test # vitest (unit + headless)
|
|
72
|
+
bunx vitest -c vitest.harness.config.ts run tests/harness/ # TUI E2E (named-pipes on Win, fd3/4 on POSIX)
|
|
73
|
+
bun run build # or build:binary for standalone exe
|
|
74
|
+
|
|
75
|
+
See AGENTS.md (quick ref + rules), CLAUDE.md (harness verification), README.md.
|
|
76
|
+
|
|
77
|
+
## Verify
|
|
78
|
+
muonroi-cli doctor
|
|
79
|
+
# Checks runtimes, catalog load, keychain, MCP servers enabled, council research MCP nudge, EE reachability, recent error rate.
|
|
80
|
+
# Any "warn" entries tell you exactly what to enable (e.g. tavily for web research in council).
|
|
81
|
+
|
|
82
|
+
For BB-aware scaffolding (/ideal on a muonroi-building-block target): ensure dotnet SDK + the three Muonroi.*.Template packages are installed via NuGet; doctor surfaces missing feed/template cases.
|
|
83
83
|
`;
|
|
84
84
|
//# sourceMappingURL=setup-guide-text.js.map
|