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
|
@@ -86,49 +86,49 @@ describe("MCP smoke test — buildMcpToolSet", () => {
|
|
|
86
86
|
it.skipIf(process.platform === "win32" || !!process.env.CI)("discovers tools from stdio MCP echo stub", async () => {
|
|
87
87
|
// Inline MCP echo server script — handles initialize, notifications/initialized,
|
|
88
88
|
// and tools/list using Content-Length framing per the MCP JSON-RPC spec.
|
|
89
|
-
const echoServerScript = `
|
|
90
|
-
const { stdin, stdout } = require('process');
|
|
91
|
-
let buf = '';
|
|
92
|
-
stdin.setEncoding('utf8');
|
|
93
|
-
stdin.on('data', (chunk) => {
|
|
94
|
-
buf += chunk;
|
|
95
|
-
while (true) {
|
|
96
|
-
const headerEnd = buf.indexOf('\\r\\n\\r\\n');
|
|
97
|
-
if (headerEnd === -1) break;
|
|
98
|
-
const header = buf.slice(0, headerEnd);
|
|
99
|
-
const match = header.match(/Content-Length:\\s*(\\d+)/i);
|
|
100
|
-
if (!match) { buf = buf.slice(headerEnd + 4); continue; }
|
|
101
|
-
const len = parseInt(match[1], 10);
|
|
102
|
-
const bodyStart = headerEnd + 4;
|
|
103
|
-
if (buf.length < bodyStart + len) break;
|
|
104
|
-
const body = buf.slice(bodyStart, bodyStart + len);
|
|
105
|
-
buf = buf.slice(bodyStart + len);
|
|
106
|
-
handleMessage(JSON.parse(body));
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
function send(obj) {
|
|
110
|
-
const s = JSON.stringify(obj);
|
|
111
|
-
stdout.write('Content-Length: ' + Buffer.byteLength(s) + '\\r\\n\\r\\n' + s);
|
|
112
|
-
}
|
|
113
|
-
function handleMessage(msg) {
|
|
114
|
-
if (msg.method === 'initialize') {
|
|
115
|
-
send({ jsonrpc: '2.0', id: msg.id, result: {
|
|
116
|
-
protocolVersion: '2024-11-05',
|
|
117
|
-
capabilities: { tools: { listChanged: false } },
|
|
118
|
-
serverInfo: { name: 'echo-stub', version: '1.0.0' }
|
|
119
|
-
}});
|
|
120
|
-
} else if (msg.method === 'notifications/initialized') {
|
|
121
|
-
// no response needed
|
|
122
|
-
} else if (msg.method === 'tools/list') {
|
|
123
|
-
send({ jsonrpc: '2.0', id: msg.id, result: {
|
|
124
|
-
tools: [{
|
|
125
|
-
name: 'echo',
|
|
126
|
-
description: 'Echoes input',
|
|
127
|
-
inputSchema: { type: 'object', properties: { message: { type: 'string' } }, required: ['message'] }
|
|
128
|
-
}]
|
|
129
|
-
}});
|
|
130
|
-
}
|
|
131
|
-
}
|
|
89
|
+
const echoServerScript = `
|
|
90
|
+
const { stdin, stdout } = require('process');
|
|
91
|
+
let buf = '';
|
|
92
|
+
stdin.setEncoding('utf8');
|
|
93
|
+
stdin.on('data', (chunk) => {
|
|
94
|
+
buf += chunk;
|
|
95
|
+
while (true) {
|
|
96
|
+
const headerEnd = buf.indexOf('\\r\\n\\r\\n');
|
|
97
|
+
if (headerEnd === -1) break;
|
|
98
|
+
const header = buf.slice(0, headerEnd);
|
|
99
|
+
const match = header.match(/Content-Length:\\s*(\\d+)/i);
|
|
100
|
+
if (!match) { buf = buf.slice(headerEnd + 4); continue; }
|
|
101
|
+
const len = parseInt(match[1], 10);
|
|
102
|
+
const bodyStart = headerEnd + 4;
|
|
103
|
+
if (buf.length < bodyStart + len) break;
|
|
104
|
+
const body = buf.slice(bodyStart, bodyStart + len);
|
|
105
|
+
buf = buf.slice(bodyStart + len);
|
|
106
|
+
handleMessage(JSON.parse(body));
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
function send(obj) {
|
|
110
|
+
const s = JSON.stringify(obj);
|
|
111
|
+
stdout.write('Content-Length: ' + Buffer.byteLength(s) + '\\r\\n\\r\\n' + s);
|
|
112
|
+
}
|
|
113
|
+
function handleMessage(msg) {
|
|
114
|
+
if (msg.method === 'initialize') {
|
|
115
|
+
send({ jsonrpc: '2.0', id: msg.id, result: {
|
|
116
|
+
protocolVersion: '2024-11-05',
|
|
117
|
+
capabilities: { tools: { listChanged: false } },
|
|
118
|
+
serverInfo: { name: 'echo-stub', version: '1.0.0' }
|
|
119
|
+
}});
|
|
120
|
+
} else if (msg.method === 'notifications/initialized') {
|
|
121
|
+
// no response needed
|
|
122
|
+
} else if (msg.method === 'tools/list') {
|
|
123
|
+
send({ jsonrpc: '2.0', id: msg.id, result: {
|
|
124
|
+
tools: [{
|
|
125
|
+
name: 'echo',
|
|
126
|
+
description: 'Echoes input',
|
|
127
|
+
inputSchema: { type: 'object', properties: { message: { type: 'string' } }, required: ['message'] }
|
|
128
|
+
}]
|
|
129
|
+
}});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
132
|
`;
|
|
133
133
|
const tmpDir = await mkdtemp(join(tmpdir(), "mcp-echo-stub-"));
|
|
134
134
|
const scriptPath = join(tmpDir, "echo-server.js");
|
|
@@ -2,17 +2,17 @@ import { beforeAll, describe, expect, it } from "vitest";
|
|
|
2
2
|
import { detectProviderForModel } from "../providers/runtime.js";
|
|
3
3
|
import { getModelInfo, loadCatalog } from "./registry.js";
|
|
4
4
|
/**
|
|
5
|
-
* Regression guard for the Gemini catalog entries
|
|
6
|
-
*
|
|
7
|
-
* catalog entry a model cannot be selected or routed (Zero-Hardcode Rule)
|
|
8
|
-
* these assertions lock in that Gemini is actually usable end-to-end.
|
|
5
|
+
* Regression guard for the Agy/Google Gemini catalog entries.
|
|
6
|
+
* These are the models Agy supports for the "google" provider (via agy.exe OAuth + cloudcode-pa).
|
|
7
|
+
* Without a catalog entry a model cannot be selected or routed (Zero-Hardcode Rule).
|
|
9
8
|
*/
|
|
10
9
|
const GEMINI_IDS = [
|
|
11
|
-
"gemini-
|
|
12
|
-
"gemini-
|
|
13
|
-
"gemini-3.5-flash",
|
|
14
|
-
"gemini-3.1-
|
|
15
|
-
"gemini-3.1-pro-
|
|
10
|
+
"gemini-3.5-flash-high",
|
|
11
|
+
"gemini-3.5-flash-medium",
|
|
12
|
+
"gemini-3.5-flash-low",
|
|
13
|
+
"gemini-3.1-pro-high",
|
|
14
|
+
"gemini-3.1-pro-low",
|
|
15
|
+
"gemini-3-flash",
|
|
16
16
|
];
|
|
17
17
|
describe("Gemini catalog entries", () => {
|
|
18
18
|
beforeAll(async () => {
|
|
@@ -26,8 +26,10 @@ describe("Gemini catalog entries", () => {
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
it("maps gemini ids to the google provider via runtime detection", () => {
|
|
29
|
-
|
|
29
|
+
// direct + alias (gemini-3.5-flash aliases to the high variant)
|
|
30
|
+
expect(detectProviderForModel("gemini-3.5-flash-high")).toBe("google");
|
|
30
31
|
expect(detectProviderForModel("gemini-3.5-flash")).toBe("google");
|
|
32
|
+
expect(detectProviderForModel("gemini-3.1-pro-high")).toBe("google");
|
|
31
33
|
});
|
|
32
34
|
it("marks all Gemini models multimodal (vision) and 1M context", () => {
|
|
33
35
|
for (const id of GEMINI_IDS) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "2.2",
|
|
3
3
|
"updated_at": "2026-06-04",
|
|
4
|
-
"description": "Local fallback catalog: deepseek + siliconflow + openai (ChatGPT OAuth) + google (
|
|
4
|
+
"description": "Local fallback catalog: deepseek + siliconflow + openai (ChatGPT OAuth) + google (Agy via agy.exe OAuth + cloudcode-pa). Agy supports: Gemini 3.5 Flash (High/Medium/Low), Gemini 3.1 Pro (High/Low), Gemini 3 Flash, Claude Sonnet 4.6 (Thinking), Claude Opus 4.6 (Thinking), GPT-OSS 120B (Medium+). Non-Gemini models under google provider use Agy token for proxied access. Other providers unchanged. Pricing APPROXIMATE.",
|
|
5
5
|
"models": [
|
|
6
6
|
{
|
|
7
7
|
"id": "deepseek-v4-flash",
|
|
@@ -227,42 +227,42 @@
|
|
|
227
227
|
"supports_vision": false
|
|
228
228
|
},
|
|
229
229
|
{
|
|
230
|
-
"id": "gemini-
|
|
231
|
-
"name": "Gemini
|
|
230
|
+
"id": "gemini-3.5-flash-high",
|
|
231
|
+
"name": "Gemini 3.5 Flash (High)",
|
|
232
232
|
"provider": "google",
|
|
233
|
-
"tier": "
|
|
233
|
+
"tier": "fast",
|
|
234
234
|
"context_window": 1048576,
|
|
235
235
|
"max_output_tokens": 65536,
|
|
236
|
-
"input_price_per_million": 0.
|
|
237
|
-
"output_price_per_million":
|
|
236
|
+
"input_price_per_million": 0.5,
|
|
237
|
+
"output_price_per_million": 3.0,
|
|
238
238
|
"reasoning": true,
|
|
239
239
|
"thinking_type": "enabled",
|
|
240
|
-
"supports_effort":
|
|
241
|
-
"default_reasoning_effort":
|
|
242
|
-
"description": "
|
|
243
|
-
"aliases": ["gemini-
|
|
240
|
+
"supports_effort": true,
|
|
241
|
+
"default_reasoning_effort": "high",
|
|
242
|
+
"description": "Agy-supported Gemini 3.5 Flash High via Agy OAuth (cloudcode-pa backend, not public Generative Language). Multimodal, 1M context. Matches official agy cli model list.",
|
|
243
|
+
"aliases": ["gemini-3.5-flash"],
|
|
244
244
|
"supports_vision": true
|
|
245
245
|
},
|
|
246
246
|
{
|
|
247
|
-
"id": "gemini-
|
|
248
|
-
"name": "Gemini
|
|
247
|
+
"id": "gemini-3.5-flash-medium",
|
|
248
|
+
"name": "Gemini 3.5 Flash (Medium)",
|
|
249
249
|
"provider": "google",
|
|
250
|
-
"tier": "
|
|
250
|
+
"tier": "balanced",
|
|
251
251
|
"context_window": 1048576,
|
|
252
252
|
"max_output_tokens": 65536,
|
|
253
|
-
"input_price_per_million":
|
|
254
|
-
"output_price_per_million":
|
|
253
|
+
"input_price_per_million": 0.5,
|
|
254
|
+
"output_price_per_million": 3.0,
|
|
255
255
|
"reasoning": true,
|
|
256
256
|
"thinking_type": "enabled",
|
|
257
|
-
"supports_effort":
|
|
258
|
-
"default_reasoning_effort":
|
|
259
|
-
"description": "
|
|
260
|
-
"aliases": ["gemini-
|
|
257
|
+
"supports_effort": true,
|
|
258
|
+
"default_reasoning_effort": "medium",
|
|
259
|
+
"description": "Agy-supported Gemini 3.5 Flash Medium via Agy OAuth (cloudcode-pa). Multimodal, 1M context. Matches official agy cli model list.",
|
|
260
|
+
"aliases": ["gemini-3.5-flash-med"],
|
|
261
261
|
"supports_vision": true
|
|
262
262
|
},
|
|
263
263
|
{
|
|
264
|
-
"id": "gemini-3.5-flash",
|
|
265
|
-
"name": "Gemini 3.5 Flash",
|
|
264
|
+
"id": "gemini-3.5-flash-low",
|
|
265
|
+
"name": "Gemini 3.5 Flash (Low)",
|
|
266
266
|
"provider": "google",
|
|
267
267
|
"tier": "fast",
|
|
268
268
|
"context_window": 1048576,
|
|
@@ -271,32 +271,32 @@
|
|
|
271
271
|
"output_price_per_million": 3.0,
|
|
272
272
|
"reasoning": true,
|
|
273
273
|
"thinking_type": "enabled",
|
|
274
|
-
"supports_effort":
|
|
275
|
-
"default_reasoning_effort":
|
|
276
|
-
"description": "
|
|
277
|
-
"aliases": ["gemini-
|
|
274
|
+
"supports_effort": true,
|
|
275
|
+
"default_reasoning_effort": "low",
|
|
276
|
+
"description": "Agy-supported Gemini 3.5 Flash Low via Agy OAuth (cloudcode-pa). Multimodal, 1M context. Matches official agy cli model list.",
|
|
277
|
+
"aliases": ["gemini-3.5-flash-low"],
|
|
278
278
|
"supports_vision": true
|
|
279
279
|
},
|
|
280
280
|
{
|
|
281
|
-
"id": "gemini-3.1-
|
|
282
|
-
"name": "Gemini 3.1
|
|
281
|
+
"id": "gemini-3.1-pro-high",
|
|
282
|
+
"name": "Gemini 3.1 Pro (High)",
|
|
283
283
|
"provider": "google",
|
|
284
|
-
"tier": "
|
|
284
|
+
"tier": "premium",
|
|
285
285
|
"context_window": 1048576,
|
|
286
286
|
"max_output_tokens": 65536,
|
|
287
|
-
"input_price_per_million": 0
|
|
288
|
-
"output_price_per_million": 0
|
|
287
|
+
"input_price_per_million": 2.0,
|
|
288
|
+
"output_price_per_million": 12.0,
|
|
289
289
|
"reasoning": true,
|
|
290
290
|
"thinking_type": "enabled",
|
|
291
|
-
"supports_effort":
|
|
292
|
-
"default_reasoning_effort":
|
|
293
|
-
"description": "
|
|
294
|
-
"aliases": ["gemini-
|
|
291
|
+
"supports_effort": true,
|
|
292
|
+
"default_reasoning_effort": "high",
|
|
293
|
+
"description": "Agy-supported Gemini 3.1 Pro High via Agy OAuth (cloudcode-pa backend). Strongest agentic Gemini. Matches official agy cli model list. Pricing approximate.",
|
|
294
|
+
"aliases": ["gemini-3.1-pro", "gemini-3.1-pro-preview"],
|
|
295
295
|
"supports_vision": true
|
|
296
296
|
},
|
|
297
297
|
{
|
|
298
|
-
"id": "gemini-3.1-pro-
|
|
299
|
-
"name": "Gemini 3.1 Pro
|
|
298
|
+
"id": "gemini-3.1-pro-low",
|
|
299
|
+
"name": "Gemini 3.1 Pro (Low)",
|
|
300
300
|
"provider": "google",
|
|
301
301
|
"tier": "premium",
|
|
302
302
|
"context_window": 1048576,
|
|
@@ -305,12 +305,80 @@
|
|
|
305
305
|
"output_price_per_million": 12.0,
|
|
306
306
|
"reasoning": true,
|
|
307
307
|
"thinking_type": "enabled",
|
|
308
|
+
"supports_effort": true,
|
|
309
|
+
"default_reasoning_effort": "low",
|
|
310
|
+
"description": "Agy-supported Gemini 3.1 Pro Low via Agy OAuth (cloudcode-pa). Matches official agy cli model list.",
|
|
311
|
+
"aliases": ["gemini-3.1-pro-low"],
|
|
312
|
+
"supports_vision": true
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"id": "gemini-3-flash",
|
|
316
|
+
"name": "Gemini 3 Flash",
|
|
317
|
+
"provider": "google",
|
|
318
|
+
"tier": "fast",
|
|
319
|
+
"context_window": 1048576,
|
|
320
|
+
"max_output_tokens": 65536,
|
|
321
|
+
"input_price_per_million": 0.3,
|
|
322
|
+
"output_price_per_million": 2.0,
|
|
323
|
+
"reasoning": true,
|
|
324
|
+
"thinking_type": "enabled",
|
|
308
325
|
"supports_effort": false,
|
|
309
326
|
"default_reasoning_effort": null,
|
|
310
|
-
"description": "
|
|
311
|
-
"aliases": ["gemini-
|
|
327
|
+
"description": "Agy-supported Gemini 3 Flash via Agy OAuth (cloudcode-pa). Multimodal. Matches official agy cli model list.",
|
|
328
|
+
"aliases": ["gemini-3-flash"],
|
|
329
|
+
"supports_vision": true
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"id": "claude-sonnet-4.6-thinking",
|
|
333
|
+
"name": "Claude Sonnet 4.6 (Thinking)",
|
|
334
|
+
"provider": "google",
|
|
335
|
+
"tier": "premium",
|
|
336
|
+
"context_window": 200000,
|
|
337
|
+
"max_output_tokens": 32000,
|
|
338
|
+
"input_price_per_million": 3.0,
|
|
339
|
+
"output_price_per_million": 15.0,
|
|
340
|
+
"reasoning": true,
|
|
341
|
+
"thinking_type": "enabled",
|
|
342
|
+
"supports_effort": true,
|
|
343
|
+
"default_reasoning_effort": "medium",
|
|
344
|
+
"description": "Agy-supported Claude Sonnet 4.6 Thinking via Agy OAuth (cloudcode-pa backend proxy). Matches official agy cli model list.",
|
|
345
|
+
"aliases": ["claude-sonnet-4-6-thinking", "claude-4.6-sonnet-thinking"],
|
|
346
|
+
"supports_vision": true
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"id": "claude-opus-4.6-thinking",
|
|
350
|
+
"name": "Claude Opus 4.6 (Thinking)",
|
|
351
|
+
"provider": "google",
|
|
352
|
+
"tier": "premium",
|
|
353
|
+
"context_window": 200000,
|
|
354
|
+
"max_output_tokens": 32000,
|
|
355
|
+
"input_price_per_million": 15.0,
|
|
356
|
+
"output_price_per_million": 75.0,
|
|
357
|
+
"reasoning": true,
|
|
358
|
+
"thinking_type": "enabled",
|
|
359
|
+
"supports_effort": true,
|
|
360
|
+
"default_reasoning_effort": "medium",
|
|
361
|
+
"description": "Agy-supported Claude Opus 4.6 Thinking via Agy OAuth (cloudcode-pa backend proxy). Matches official agy cli model list.",
|
|
362
|
+
"aliases": ["claude-opus-4-6-thinking", "claude-4.6-opus-thinking"],
|
|
312
363
|
"supports_vision": true
|
|
313
364
|
},
|
|
365
|
+
{
|
|
366
|
+
"id": "gpt-oss-120b-medium",
|
|
367
|
+
"name": "GPT-OSS 120B (Medium)",
|
|
368
|
+
"provider": "google",
|
|
369
|
+
"tier": "balanced",
|
|
370
|
+
"context_window": 128000,
|
|
371
|
+
"max_output_tokens": 32000,
|
|
372
|
+
"input_price_per_million": 0.2,
|
|
373
|
+
"output_price_per_million": 0.8,
|
|
374
|
+
"reasoning": true,
|
|
375
|
+
"thinking_type": "enabled",
|
|
376
|
+
"supports_effort": true,
|
|
377
|
+
"default_reasoning_effort": "medium",
|
|
378
|
+
"description": "Agy-supported GPT-OSS 120B Medium via Agy OAuth (cloudcode-pa). Matches official agy cli model list.",
|
|
379
|
+
"aliases": ["gpt-oss-120b", "gpt-oss-medium"],
|
|
380
|
+
"supports_vision": false
|
|
381
|
+
},
|
|
314
382
|
{
|
|
315
383
|
"id": "grok-4.3",
|
|
316
384
|
"name": "Grok 4.3 (xAI)",
|
package/dist/src/ops/doctor.js
CHANGED
|
@@ -169,9 +169,9 @@ async function checkBrainEmptiness() {
|
|
|
169
169
|
// Count ee_injection events with event_subtype='no_match' in last 30 days
|
|
170
170
|
const cutoff = new Date(Date.now() - 30 * 86_400_000).toISOString();
|
|
171
171
|
const row = db
|
|
172
|
-
.prepare(`SELECT COUNT(*) as cnt FROM interaction_logs
|
|
173
|
-
WHERE event_type = 'ee_injection'
|
|
174
|
-
AND event_subtype = 'no_match'
|
|
172
|
+
.prepare(`SELECT COUNT(*) as cnt FROM interaction_logs
|
|
173
|
+
WHERE event_type = 'ee_injection'
|
|
174
|
+
AND event_subtype = 'no_match'
|
|
175
175
|
AND created_at >= ?`)
|
|
176
176
|
.get(cutoff);
|
|
177
177
|
const noMatchCount = row?.cnt ?? 0;
|
|
@@ -293,10 +293,10 @@ async function checkCouncilMcpNudge() {
|
|
|
293
293
|
// 2. Query DB for [Council Memory] records with URL or research topics
|
|
294
294
|
const db = getDatabase();
|
|
295
295
|
const rows = db
|
|
296
|
-
.prepare(`SELECT message_json FROM messages
|
|
297
|
-
WHERE role = 'system'
|
|
298
|
-
AND message_json LIKE '%[Council Memory]%'
|
|
299
|
-
ORDER BY created_at DESC
|
|
296
|
+
.prepare(`SELECT message_json FROM messages
|
|
297
|
+
WHERE role = 'system'
|
|
298
|
+
AND message_json LIKE '%[Council Memory]%'
|
|
299
|
+
ORDER BY created_at DESC
|
|
300
300
|
LIMIT 50`)
|
|
301
301
|
.all();
|
|
302
302
|
let qualifyingCount = 0;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { blockingErrorsForFile, buildFileListSubject, isAutoCommitEnabled, isCliArtifactPath, isCommitGateEnabled, isExcludedPath, isSensitivePath, parsePorcelainPaths, pathsForCommitGate, splitCommitMessage, } from "../auto-commit.js";
|
|
7
|
+
function diag(severity) {
|
|
8
|
+
return {
|
|
9
|
+
message: "x",
|
|
10
|
+
severity,
|
|
11
|
+
range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function diagFile(filePath, severities) {
|
|
15
|
+
return { filePath, serverId: "ts", diagnostics: severities.map(diag) };
|
|
16
|
+
}
|
|
17
|
+
describe("auto-commit pure helpers", () => {
|
|
18
|
+
it("parses porcelain output incl. rename + quoted paths", () => {
|
|
19
|
+
const out = ' M src/a.ts\n?? new file.txt\nR old.ts -> src/b.ts\nA "with space.ts"\n';
|
|
20
|
+
const set = parsePorcelainPaths(out);
|
|
21
|
+
expect(set.has("src/a.ts")).toBe(true);
|
|
22
|
+
expect(set.has("new file.txt")).toBe(true);
|
|
23
|
+
// rename keeps ONLY the new path
|
|
24
|
+
expect(set.has("src/b.ts")).toBe(true);
|
|
25
|
+
expect(set.has("old.ts")).toBe(false);
|
|
26
|
+
// quoted path with a space is unquoted
|
|
27
|
+
expect(set.has("with space.ts")).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it("flags sensitive paths and lets normal source through", () => {
|
|
30
|
+
expect(isSensitivePath(".env")).toBe(true);
|
|
31
|
+
expect(isSensitivePath(".env.local")).toBe(true);
|
|
32
|
+
expect(isSensitivePath("config/app.key")).toBe(true);
|
|
33
|
+
expect(isSensitivePath("certs/server.pem")).toBe(true);
|
|
34
|
+
expect(isSensitivePath("src/db-secret.ts")).toBe(true);
|
|
35
|
+
// .muonroi-cli/ is categorized as a CLI artifact (excluded), not a "secret".
|
|
36
|
+
expect(isSensitivePath(".muonroi-cli/state.json")).toBe(false);
|
|
37
|
+
expect(isExcludedPath(".muonroi-cli/state.json")).toBe(true);
|
|
38
|
+
expect(isSensitivePath("src/index.ts")).toBe(false);
|
|
39
|
+
expect(isSensitivePath("README.md")).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
it("excludes CLI-generated artifacts + build junk (the 11-file-leak fix)", () => {
|
|
42
|
+
expect(isCliArtifactPath(".muonroi-flow/state.md")).toBe(true);
|
|
43
|
+
expect(isCliArtifactPath(".muonroi-flow/runs/abc/manifest.md")).toBe(true);
|
|
44
|
+
expect(isCliArtifactPath(".muonroi-cli/session.db")).toBe(true);
|
|
45
|
+
expect(isCliArtifactPath(".muonroi-harness-roots.json")).toBe(true);
|
|
46
|
+
expect(isCliArtifactPath("node_modules/x/index.js")).toBe(true);
|
|
47
|
+
expect(isCliArtifactPath("dist/bundle.js")).toBe(true);
|
|
48
|
+
expect(isCliArtifactPath("debug.log")).toBe(true);
|
|
49
|
+
expect(isCliArtifactPath("src/greeting.txt")).toBe(false);
|
|
50
|
+
// isExcludedPath unions secrets + artifacts
|
|
51
|
+
expect(isExcludedPath(".env")).toBe(true);
|
|
52
|
+
expect(isExcludedPath(".muonroi-flow/state.md")).toBe(true);
|
|
53
|
+
expect(isExcludedPath("greeting.txt")).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
it("backstop subject lists files + stays bounded (never the raw prompt)", () => {
|
|
56
|
+
expect(buildFileListSubject(["src/a.ts", "src/b.ts"])).toBe("chore: update 2 file(s) — a.ts, b.ts");
|
|
57
|
+
expect(buildFileListSubject(["a.ts", "b.ts", "c.ts", "d.ts", "e.ts"])).toContain("+2 more");
|
|
58
|
+
expect(buildFileListSubject(Array.from({ length: 20 }, (_, i) => `file${i}.ts`)).length).toBeLessThanOrEqual(72);
|
|
59
|
+
});
|
|
60
|
+
it("splits an agent-authored message: subject <=72, body kept, attribution deduped", () => {
|
|
61
|
+
expect(splitCommitMessage("feat: add X\r\n\r\nbody line")).toEqual({ subject: "feat: add X", body: "body line" });
|
|
62
|
+
expect(splitCommitMessage("x".repeat(200)).subject.length).toBeLessThanOrEqual(72);
|
|
63
|
+
// an attribution the agent already added is dropped (we append exactly one)
|
|
64
|
+
expect(splitCommitMessage("feat: y\nCoding by - Muonroi-CLI")).toEqual({ subject: "feat: y", body: "" });
|
|
65
|
+
});
|
|
66
|
+
it("is disabled under the unit-test runner so the suite never commits", () => {
|
|
67
|
+
// VITEST is set while this runs → must be false regardless of MUONROI_AUTO_COMMIT.
|
|
68
|
+
expect(isAutoCommitEnabled()).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe("G1 commit quality gate", () => {
|
|
72
|
+
it("commit gate is disabled under the unit-test runner (specs commit fixtures freely)", () => {
|
|
73
|
+
// Mirrors isAutoCommitEnabled — VITEST is set, so the gate must be off here.
|
|
74
|
+
expect(isCommitGateEnabled()).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
describe("blockingErrorsForFile — errors-only + per-file scope", () => {
|
|
77
|
+
it("returns severity-1 (error) diagnostics for the staged file", () => {
|
|
78
|
+
const abs = resolve("foo.ts");
|
|
79
|
+
const errs = blockingErrorsForFile([diagFile("foo.ts", [1, 1])], abs);
|
|
80
|
+
expect(errs).toHaveLength(2);
|
|
81
|
+
});
|
|
82
|
+
it("treats a missing severity as an error (LSP default is 1)", () => {
|
|
83
|
+
const abs = resolve("foo.ts");
|
|
84
|
+
expect(blockingErrorsForFile([diagFile("foo.ts", [undefined])], abs)).toHaveLength(1);
|
|
85
|
+
});
|
|
86
|
+
it("ignores warnings/infos (severity >= 2) — they never block a commit", () => {
|
|
87
|
+
const abs = resolve("foo.ts");
|
|
88
|
+
expect(blockingErrorsForFile([diagFile("foo.ts", [2, 3, 4])], abs)).toHaveLength(0);
|
|
89
|
+
});
|
|
90
|
+
it("ignores errors reported against a DIFFERENT file (cross-file breakage doesn't block)", () => {
|
|
91
|
+
const abs = resolve("foo.ts");
|
|
92
|
+
// An error on other.ts must not block a commit of foo.ts.
|
|
93
|
+
expect(blockingErrorsForFile([diagFile("other.ts", [1, 1])], abs)).toHaveLength(0);
|
|
94
|
+
});
|
|
95
|
+
it("mixes: keeps only this file's errors out of a multi-file, multi-severity set", () => {
|
|
96
|
+
const abs = resolve("foo.ts");
|
|
97
|
+
const errs = blockingErrorsForFile([diagFile("foo.ts", [1, 2, 3]), diagFile("bar.ts", [1, 1])], abs);
|
|
98
|
+
expect(errs).toHaveLength(1); // only foo.ts's single severity-1
|
|
99
|
+
});
|
|
100
|
+
it("empty diagnostics → no blockers (non-source / no-LSP-server files pass)", () => {
|
|
101
|
+
expect(blockingErrorsForFile([], resolve("README.md"))).toEqual([]);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe("pathsForCommitGate — bash `git commit` gate path set (real git)", () => {
|
|
106
|
+
let dir;
|
|
107
|
+
const g = (args) => execFileSync("git", args, { cwd: dir, stdio: "pipe" });
|
|
108
|
+
beforeEach(() => {
|
|
109
|
+
dir = mkdtempSync(join(tmpdir(), "commit-gate-"));
|
|
110
|
+
g(["init", "-q"]);
|
|
111
|
+
g(["config", "user.email", "t@t.t"]);
|
|
112
|
+
g(["config", "user.name", "t"]);
|
|
113
|
+
});
|
|
114
|
+
afterEach(() => rmSync(dir, { recursive: true, force: true }));
|
|
115
|
+
it("returns only the already-staged set for a plain `git commit`", async () => {
|
|
116
|
+
writeFileSync(join(dir, "a.ts"), "export const a = 1;\n");
|
|
117
|
+
writeFileSync(join(dir, "b.ts"), "export const b = 2;\n");
|
|
118
|
+
g(["add", "a.ts"]); // b.ts left untracked
|
|
119
|
+
const paths = await pathsForCommitGate(dir, { broadAdd: false, commitAll: false });
|
|
120
|
+
expect(paths).toEqual(["a.ts"]);
|
|
121
|
+
});
|
|
122
|
+
it("adds tracked modifications that `git commit -a` will auto-stage", async () => {
|
|
123
|
+
writeFileSync(join(dir, "a.ts"), "export const a = 1;\n");
|
|
124
|
+
g(["add", "a.ts"]);
|
|
125
|
+
g(["commit", "-qm", "init", "--no-verify"]); // temp fixture repo — hook-free by design
|
|
126
|
+
writeFileSync(join(dir, "a.ts"), "export const a = 99;\n"); // modify tracked, NOT re-staged
|
|
127
|
+
// plain commit sees nothing staged; commit -a includes the modification.
|
|
128
|
+
expect(await pathsForCommitGate(dir, { broadAdd: false, commitAll: false })).toEqual([]);
|
|
129
|
+
expect(await pathsForCommitGate(dir, { broadAdd: false, commitAll: true })).toContain("a.ts");
|
|
130
|
+
});
|
|
131
|
+
it("includes the whole working tree for a chained broad `git add -A` (add not yet run)", async () => {
|
|
132
|
+
writeFileSync(join(dir, "a.ts"), "export const a = 1;\n"); // untracked
|
|
133
|
+
writeFileSync(join(dir, "c.ts"), "export const c = 3;\n"); // untracked
|
|
134
|
+
// Nothing staged at pre-exec time → plain set is empty…
|
|
135
|
+
expect(await pathsForCommitGate(dir, { broadAdd: false, commitAll: false })).toEqual([]);
|
|
136
|
+
// …but `git add -A` would stage both, so the broad path enumerates them.
|
|
137
|
+
const broad = await pathsForCommitGate(dir, { broadAdd: true, commitAll: false });
|
|
138
|
+
expect(broad).toContain("a.ts");
|
|
139
|
+
expect(broad).toContain("c.ts");
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=auto-commit.test.js.map
|
|
@@ -56,6 +56,7 @@ function makeDeps(overrides = {}) {
|
|
|
56
56
|
runDelegation: async () => ({ success: true, output: "" }),
|
|
57
57
|
readDelegation: async () => ({ success: true, output: "" }),
|
|
58
58
|
listDelegations: async () => ({ success: true, output: "" }),
|
|
59
|
+
killDelegation: async () => ({ success: true, output: "" }),
|
|
59
60
|
executeBatchToolCall: async (_tools, _call) => ({
|
|
60
61
|
input: {},
|
|
61
62
|
result: { success: true, output: "" },
|
|
@@ -78,6 +79,7 @@ function makeArgs(signal, providerStub) {
|
|
|
78
79
|
const testProviders = getTestProviders();
|
|
79
80
|
return {
|
|
80
81
|
userModelMessage: { role: "user", content: "hello" },
|
|
82
|
+
userEnrichedMessage: { role: "user", content: "hello" },
|
|
81
83
|
observer: undefined,
|
|
82
84
|
provider: (providerStub ?? {}),
|
|
83
85
|
subagents: [],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { DelegationManager } from "../delegations.js";
|
|
7
|
+
function getProjectId(cwd) {
|
|
8
|
+
const base = path
|
|
9
|
+
.basename(cwd)
|
|
10
|
+
.replace(/[^a-zA-Z0-9._-]+/g, "-")
|
|
11
|
+
.replace(/^-+|-+$/g, "") || "project";
|
|
12
|
+
const hash = createHash("sha1").update(cwd).digest("hex").slice(0, 10);
|
|
13
|
+
return `${base}-${hash}`;
|
|
14
|
+
}
|
|
15
|
+
async function getDelegationsDir(cwd) {
|
|
16
|
+
const projectId = getProjectId(cwd);
|
|
17
|
+
return path.join(os.homedir(), ".muonroi-cli", "delegations", projectId);
|
|
18
|
+
}
|
|
19
|
+
describe("DelegationManager.kill", () => {
|
|
20
|
+
it("terminates a running delegation and updates its status to error", async () => {
|
|
21
|
+
const tempCwd = path.join(os.tmpdir(), "muonroi-test-" + Math.random().toString(36).slice(2));
|
|
22
|
+
const manager = new DelegationManager(() => tempCwd);
|
|
23
|
+
const dir = await getDelegationsDir(tempCwd);
|
|
24
|
+
await fs.mkdir(dir, { recursive: true });
|
|
25
|
+
const id = "test-amber-panda";
|
|
26
|
+
const jobPath = path.join(dir, `${id}.json`);
|
|
27
|
+
const outputPath = path.join(dir, `${id}.md`);
|
|
28
|
+
// Create a mock running delegation
|
|
29
|
+
const record = {
|
|
30
|
+
id,
|
|
31
|
+
agent: "explore",
|
|
32
|
+
description: "test delegation",
|
|
33
|
+
prompt: "noop",
|
|
34
|
+
cwd: tempCwd,
|
|
35
|
+
model: "grok-4",
|
|
36
|
+
sandboxMode: "off",
|
|
37
|
+
maxToolRounds: 10,
|
|
38
|
+
maxTokens: 4000,
|
|
39
|
+
status: "running",
|
|
40
|
+
startedAt: new Date().toISOString(),
|
|
41
|
+
outputPath,
|
|
42
|
+
pid: 99999, // dummy PID
|
|
43
|
+
};
|
|
44
|
+
await fs.writeFile(jobPath, JSON.stringify(record, null, 2), "utf8");
|
|
45
|
+
// Call cancel
|
|
46
|
+
const result = await manager.kill(id);
|
|
47
|
+
expect(result.success).toBe(true);
|
|
48
|
+
expect(result.output).toContain(`Delegation "${id}" (PID: 99999) has been terminated.`);
|
|
49
|
+
// Verify the record was updated
|
|
50
|
+
const updatedRaw = await fs.readFile(jobPath, "utf8");
|
|
51
|
+
const updated = JSON.parse(updatedRaw);
|
|
52
|
+
expect(updated.status).toBe("error");
|
|
53
|
+
expect(updated.error).toBe("Cancelled by user.");
|
|
54
|
+
// Cleanup
|
|
55
|
+
await fs.rm(jobPath, { force: true });
|
|
56
|
+
await fs.rm(outputPath, { force: true });
|
|
57
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
58
|
+
});
|
|
59
|
+
it("returns failure if the delegation ID is not found", async () => {
|
|
60
|
+
const tempCwd = path.join(os.tmpdir(), "muonroi-test-" + Math.random().toString(36).slice(2));
|
|
61
|
+
const manager = new DelegationManager(() => tempCwd);
|
|
62
|
+
const result = await manager.kill("non-existent-id");
|
|
63
|
+
expect(result.success).toBe(false);
|
|
64
|
+
expect(result.output).toContain('Delegation "non-existent-id" not found.');
|
|
65
|
+
});
|
|
66
|
+
it("returns failure if the delegation is already finished", async () => {
|
|
67
|
+
const tempCwd = path.join(os.tmpdir(), "muonroi-test-" + Math.random().toString(36).slice(2));
|
|
68
|
+
const manager = new DelegationManager(() => tempCwd);
|
|
69
|
+
const dir = await getDelegationsDir(tempCwd);
|
|
70
|
+
await fs.mkdir(dir, { recursive: true });
|
|
71
|
+
const id = "test-steady-owl";
|
|
72
|
+
const jobPath = path.join(dir, `${id}.json`);
|
|
73
|
+
const record = {
|
|
74
|
+
id,
|
|
75
|
+
agent: "explore",
|
|
76
|
+
description: "test delegation",
|
|
77
|
+
prompt: "noop",
|
|
78
|
+
cwd: tempCwd,
|
|
79
|
+
model: "grok-4",
|
|
80
|
+
sandboxMode: "off",
|
|
81
|
+
maxToolRounds: 10,
|
|
82
|
+
maxTokens: 4000,
|
|
83
|
+
status: "complete",
|
|
84
|
+
startedAt: new Date().toISOString(),
|
|
85
|
+
outputPath: path.join(dir, `${id}.md`),
|
|
86
|
+
};
|
|
87
|
+
await fs.writeFile(jobPath, JSON.stringify(record, null, 2), "utf8");
|
|
88
|
+
const result = await manager.kill(id);
|
|
89
|
+
expect(result.success).toBe(false);
|
|
90
|
+
expect(result.output).toContain(`Delegation "${id}" is not running (status: complete).`);
|
|
91
|
+
// Cleanup
|
|
92
|
+
await fs.rm(jobPath, { force: true });
|
|
93
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=delegations.test.js.map
|
|
@@ -99,6 +99,7 @@ function makeDeps(overrides = {}) {
|
|
|
99
99
|
runDelegation: async () => ({ success: true, output: "" }),
|
|
100
100
|
readDelegation: async () => ({ success: true, output: "" }),
|
|
101
101
|
listDelegations: async () => ({ success: true, output: "" }),
|
|
102
|
+
killDelegation: async () => ({ success: true, output: "" }),
|
|
102
103
|
appendCompletedTurn: () => { },
|
|
103
104
|
discardAbortedTurn: () => { },
|
|
104
105
|
recordUsage: () => { },
|