@vibecheckai/cli 3.5.0 → 3.5.1
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/bin/registry.js +174 -449
- package/bin/runners/cli-utils.js +33 -2
- package/bin/runners/context/generators/cursor.js +2 -49
- package/bin/runners/context/generators/mcp.js +13 -15
- package/bin/runners/context/proof-context.js +1 -248
- package/bin/runners/lib/analysis-core.js +180 -198
- package/bin/runners/lib/analyzers.js +241 -2212
- package/bin/runners/lib/cli-output.js +210 -242
- package/bin/runners/lib/detectors-v2.js +785 -547
- package/bin/runners/lib/entitlements-v2.js +431 -161
- package/bin/runners/lib/error-handler.js +9 -16
- package/bin/runners/lib/global-flags.js +0 -37
- package/bin/runners/lib/html-proof-report.js +700 -350
- package/bin/runners/lib/missions/plan.js +6 -46
- package/bin/runners/lib/missions/templates.js +0 -232
- package/bin/runners/lib/route-truth.js +322 -1167
- package/bin/runners/lib/scan-output.js +467 -493
- package/bin/runners/lib/ship-output.js +27 -280
- package/bin/runners/lib/terminal-ui.js +700 -310
- package/bin/runners/lib/truth.js +321 -1004
- package/bin/runners/lib/unified-output.js +158 -162
- package/bin/runners/lib/upsell.js +204 -104
- package/bin/runners/runAIAgent.js +10 -5
- package/bin/runners/runAllowlist.js +324 -0
- package/bin/runners/runAuth.js +94 -344
- package/bin/runners/runCheckpoint.js +45 -43
- package/bin/runners/runContext.js +24 -139
- package/bin/runners/runDoctor.js +101 -136
- package/bin/runners/runEvidencePack.js +219 -0
- package/bin/runners/runFix.js +71 -82
- package/bin/runners/runGuard.js +119 -606
- package/bin/runners/runInit.js +60 -22
- package/bin/runners/runInstall.js +281 -0
- package/bin/runners/runLabs.js +341 -0
- package/bin/runners/runMcp.js +62 -139
- package/bin/runners/runPolish.js +83 -282
- package/bin/runners/runPromptFirewall.js +12 -5
- package/bin/runners/runProve.js +58 -33
- package/bin/runners/runReality.js +58 -81
- package/bin/runners/runReport.js +7 -34
- package/bin/runners/runRuntime.js +8 -5
- package/bin/runners/runScan.js +844 -219
- package/bin/runners/runShip.js +59 -721
- package/bin/runners/runValidate.js +11 -24
- package/bin/runners/runWatch.js +76 -131
- package/bin/vibecheck.js +69 -295
- package/mcp-server/ARCHITECTURE.md +339 -0
- package/mcp-server/__tests__/cache.test.ts +313 -0
- package/mcp-server/__tests__/executor.test.ts +239 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.cache/webpack/cache.pack +1 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.next/server/chunk.js +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.turbo/cache.json +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/.venv/lib/env.py +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/dist/bundle.js +3 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/package.json +5 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/src/app.ts +5 -0
- package/mcp-server/__tests__/fixtures/exclusion-test/venv/lib/config.py +4 -0
- package/mcp-server/__tests__/ids.test.ts +345 -0
- package/mcp-server/__tests__/integration/tools.test.ts +410 -0
- package/mcp-server/__tests__/registry.test.ts +365 -0
- package/mcp-server/__tests__/sandbox.test.ts +323 -0
- package/mcp-server/__tests__/schemas.test.ts +372 -0
- package/mcp-server/benchmarks/run-benchmarks.ts +304 -0
- package/mcp-server/examples/doctor.request.json +14 -0
- package/mcp-server/examples/doctor.response.json +53 -0
- package/mcp-server/examples/error.response.json +15 -0
- package/mcp-server/examples/scan.request.json +14 -0
- package/mcp-server/examples/scan.response.json +108 -0
- package/mcp-server/handlers/tool-handler.ts +671 -0
- package/mcp-server/index-v1.js +698 -0
- package/mcp-server/index-v3.ts +293 -0
- package/mcp-server/index.js +1080 -1757
- package/mcp-server/index.old.js +4137 -0
- package/mcp-server/lib/cache.ts +341 -0
- package/mcp-server/lib/errors.ts +346 -0
- package/mcp-server/lib/executor.ts +792 -0
- package/mcp-server/lib/ids.ts +238 -0
- package/mcp-server/lib/logger.ts +368 -0
- package/mcp-server/lib/metrics.ts +365 -0
- package/mcp-server/lib/sandbox.ts +337 -0
- package/mcp-server/lib/validator.ts +229 -0
- package/mcp-server/package-lock.json +165 -0
- package/mcp-server/package.json +32 -7
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/registry/tools.json +476 -0
- package/mcp-server/schemas/error-envelope.schema.json +125 -0
- package/mcp-server/schemas/finding.schema.json +167 -0
- package/mcp-server/schemas/report-artifact.schema.json +88 -0
- package/mcp-server/schemas/run-request.schema.json +75 -0
- package/mcp-server/schemas/verdict.schema.json +168 -0
- package/mcp-server/tier-auth.d.ts +71 -0
- package/mcp-server/tier-auth.js +371 -183
- package/mcp-server/truth-context.js +90 -131
- package/mcp-server/truth-firewall-tools.js +1000 -1611
- package/mcp-server/tsconfig.json +34 -0
- package/mcp-server/vibecheck-tools.js +2 -2
- package/mcp-server/vitest.config.ts +16 -0
- package/package.json +3 -4
- package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +0 -474
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +0 -488
- package/bin/runners/lib/agent-firewall/change-packet/schema.json +0 -228
- package/bin/runners/lib/agent-firewall/change-packet/store.js +0 -200
- package/bin/runners/lib/agent-firewall/claims/claim-types.js +0 -21
- package/bin/runners/lib/agent-firewall/claims/extractor.js +0 -303
- package/bin/runners/lib/agent-firewall/claims/patterns.js +0 -24
- package/bin/runners/lib/agent-firewall/critic/index.js +0 -151
- package/bin/runners/lib/agent-firewall/critic/judge.js +0 -432
- package/bin/runners/lib/agent-firewall/critic/prompts.js +0 -305
- package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +0 -88
- package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +0 -75
- package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +0 -127
- package/bin/runners/lib/agent-firewall/evidence/resolver.js +0 -102
- package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +0 -213
- package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +0 -145
- package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +0 -19
- package/bin/runners/lib/agent-firewall/fs-hook/installer.js +0 -87
- package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +0 -184
- package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +0 -163
- package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +0 -107
- package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +0 -68
- package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +0 -66
- package/bin/runners/lib/agent-firewall/interceptor/base.js +0 -304
- package/bin/runners/lib/agent-firewall/interceptor/cursor.js +0 -35
- package/bin/runners/lib/agent-firewall/interceptor/vscode.js +0 -35
- package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +0 -34
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +0 -465
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +0 -604
- package/bin/runners/lib/agent-firewall/lawbook/index.js +0 -304
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +0 -514
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +0 -420
- package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
- package/bin/runners/lib/agent-firewall/logger.js +0 -141
- package/bin/runners/lib/agent-firewall/policy/default-policy.json +0 -90
- package/bin/runners/lib/agent-firewall/policy/engine.js +0 -103
- package/bin/runners/lib/agent-firewall/policy/loader.js +0 -451
- package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +0 -50
- package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +0 -50
- package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +0 -86
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +0 -162
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +0 -189
- package/bin/runners/lib/agent-firewall/policy/rules/scope.js +0 -93
- package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +0 -57
- package/bin/runners/lib/agent-firewall/policy/schema.json +0 -183
- package/bin/runners/lib/agent-firewall/policy/verdict.js +0 -54
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +0 -394
- package/bin/runners/lib/agent-firewall/proposal/index.js +0 -212
- package/bin/runners/lib/agent-firewall/proposal/schema.js +0 -251
- package/bin/runners/lib/agent-firewall/proposal/validator.js +0 -386
- package/bin/runners/lib/agent-firewall/reality/index.js +0 -332
- package/bin/runners/lib/agent-firewall/reality/state.js +0 -625
- package/bin/runners/lib/agent-firewall/reality/watcher.js +0 -322
- package/bin/runners/lib/agent-firewall/risk/index.js +0 -173
- package/bin/runners/lib/agent-firewall/risk/scorer.js +0 -328
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +0 -321
- package/bin/runners/lib/agent-firewall/risk/vectors.js +0 -421
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +0 -472
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +0 -346
- package/bin/runners/lib/agent-firewall/simulator/index.js +0 -181
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +0 -380
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +0 -661
- package/bin/runners/lib/agent-firewall/time-machine/index.js +0 -267
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +0 -436
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +0 -490
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +0 -530
- package/bin/runners/lib/agent-firewall/truthpack/index.js +0 -67
- package/bin/runners/lib/agent-firewall/truthpack/loader.js +0 -137
- package/bin/runners/lib/agent-firewall/unblock/planner.js +0 -337
- package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +0 -118
- package/bin/runners/lib/api-client.js +0 -269
- package/bin/runners/lib/audit-logger.js +0 -532
- package/bin/runners/lib/authority/authorities/architecture.js +0 -364
- package/bin/runners/lib/authority/authorities/compliance.js +0 -341
- package/bin/runners/lib/authority/authorities/human.js +0 -343
- package/bin/runners/lib/authority/authorities/quality.js +0 -420
- package/bin/runners/lib/authority/authorities/security.js +0 -228
- package/bin/runners/lib/authority/index.js +0 -293
- package/bin/runners/lib/authority-badge.js +0 -425
- package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
- package/bin/runners/lib/cli-charts.js +0 -368
- package/bin/runners/lib/cli-config-display.js +0 -405
- package/bin/runners/lib/cli-demo.js +0 -275
- package/bin/runners/lib/cli-errors.js +0 -438
- package/bin/runners/lib/cli-help-formatter.js +0 -439
- package/bin/runners/lib/cli-interactive-menu.js +0 -509
- package/bin/runners/lib/cli-prompts.js +0 -441
- package/bin/runners/lib/cli-scan-cards.js +0 -362
- package/bin/runners/lib/compliance-reporter.js +0 -710
- package/bin/runners/lib/conductor/index.js +0 -671
- package/bin/runners/lib/easy/README.md +0 -123
- package/bin/runners/lib/easy/index.js +0 -140
- package/bin/runners/lib/easy/interactive-wizard.js +0 -788
- package/bin/runners/lib/easy/one-click-firewall.js +0 -564
- package/bin/runners/lib/easy/zero-config-reality.js +0 -714
- package/bin/runners/lib/engines/accessibility-engine.js +0 -390
- package/bin/runners/lib/engines/api-consistency-engine.js +0 -467
- package/bin/runners/lib/engines/ast-cache.js +0 -99
- package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
- package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
- package/bin/runners/lib/engines/code-quality-engine.js +0 -255
- package/bin/runners/lib/engines/confidence-scoring.js +0 -276
- package/bin/runners/lib/engines/console-logs-engine.js +0 -115
- package/bin/runners/lib/engines/context-detection.js +0 -264
- package/bin/runners/lib/engines/cross-file-analysis-engine.js +0 -533
- package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
- package/bin/runners/lib/engines/dead-code-engine.js +0 -198
- package/bin/runners/lib/engines/deprecated-api-engine.js +0 -226
- package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
- package/bin/runners/lib/engines/empty-catch-engine.js +0 -260
- package/bin/runners/lib/engines/env-variables-engine.js +0 -458
- package/bin/runners/lib/engines/error-handling-engine.js +0 -437
- package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
- package/bin/runners/lib/engines/file-filter.js +0 -131
- package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
- package/bin/runners/lib/engines/framework-detection.js +0 -508
- package/bin/runners/lib/engines/hardcoded-secrets-engine.js +0 -251
- package/bin/runners/lib/engines/import-order-engine.js +0 -429
- package/bin/runners/lib/engines/mock-data-engine.js +0 -315
- package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
- package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
- package/bin/runners/lib/engines/orchestrator.js +0 -334
- package/bin/runners/lib/engines/parallel-processor.js +0 -71
- package/bin/runners/lib/engines/performance-issues-engine.js +0 -405
- package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
- package/bin/runners/lib/engines/security-vulnerabilities-engine.js +0 -571
- package/bin/runners/lib/engines/todo-fixme-engine.js +0 -115
- package/bin/runners/lib/engines/type-aware-engine.js +0 -376
- package/bin/runners/lib/engines/unsafe-regex-engine.js +0 -225
- package/bin/runners/lib/engines/vibecheck-engines/README.md +0 -53
- package/bin/runners/lib/engines/vibecheck-engines/index.js +0 -124
- package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
- package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +0 -439
- package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
- package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
- package/bin/runners/lib/engines/vibecheck-engines/package.json +0 -13
- package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
- package/bin/runners/lib/enhanced-features/index.js +0 -305
- package/bin/runners/lib/enhanced-output.js +0 -631
- package/bin/runners/lib/enterprise.js +0 -300
- package/bin/runners/lib/exit-codes.js +0 -275
- package/bin/runners/lib/fingerprint.js +0 -377
- package/bin/runners/lib/firewall/command-validator.js +0 -351
- package/bin/runners/lib/firewall/config.js +0 -341
- package/bin/runners/lib/firewall/content-validator.js +0 -519
- package/bin/runners/lib/firewall/index.js +0 -101
- package/bin/runners/lib/firewall/path-validator.js +0 -256
- package/bin/runners/lib/help-formatter.js +0 -413
- package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
- package/bin/runners/lib/logger.js +0 -38
- package/bin/runners/lib/mcp-utils.js +0 -425
- package/bin/runners/lib/output/index.js +0 -1022
- package/bin/runners/lib/policy-engine.js +0 -652
- package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
- package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
- package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
- package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
- package/bin/runners/lib/polish/autofix/index.js +0 -200
- package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
- package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
- package/bin/runners/lib/polish/backend-checks.js +0 -148
- package/bin/runners/lib/polish/documentation-checks.js +0 -111
- package/bin/runners/lib/polish/frontend-checks.js +0 -168
- package/bin/runners/lib/polish/index.js +0 -71
- package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
- package/bin/runners/lib/polish/library-detection.js +0 -175
- package/bin/runners/lib/polish/performance-checks.js +0 -100
- package/bin/runners/lib/polish/security-checks.js +0 -148
- package/bin/runners/lib/polish/utils.js +0 -203
- package/bin/runners/lib/prompt-builder.js +0 -540
- package/bin/runners/lib/proof-certificate.js +0 -634
- package/bin/runners/lib/reality/accessibility-audit.js +0 -946
- package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
- package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
- package/bin/runners/lib/reality/performance-tracker.js +0 -1077
- package/bin/runners/lib/reality/scenario-generator.js +0 -1404
- package/bin/runners/lib/reality/visual-regression.js +0 -852
- package/bin/runners/lib/reality-profiler.js +0 -717
- package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
- package/bin/runners/lib/review/ai-code-review.js +0 -832
- package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
- package/bin/runners/lib/sbom-generator.js +0 -641
- package/bin/runners/lib/scan-output-enhanced.js +0 -512
- package/bin/runners/lib/security/owasp-scanner.js +0 -939
- package/bin/runners/lib/ship-output-enterprise.js +0 -239
- package/bin/runners/lib/unified-cli-output.js +0 -777
- package/bin/runners/lib/validators/contract-validator.js +0 -283
- package/bin/runners/lib/validators/dead-export-detector.js +0 -279
- package/bin/runners/lib/validators/dep-audit.js +0 -245
- package/bin/runners/lib/validators/env-validator.js +0 -319
- package/bin/runners/lib/validators/index.js +0 -120
- package/bin/runners/lib/validators/license-checker.js +0 -252
- package/bin/runners/lib/validators/route-validator.js +0 -290
- package/bin/runners/runAgent.d.ts +0 -5
- package/bin/runners/runAgent.js +0 -164
- package/bin/runners/runApprove.js +0 -1233
- package/bin/runners/runAuthority.js +0 -528
- package/bin/runners/runClassify.js +0 -862
- package/bin/runners/runConductor.js +0 -772
- package/bin/runners/runContainer.js +0 -366
- package/bin/runners/runContext.d.ts +0 -4
- package/bin/runners/runEasy.js +0 -410
- package/bin/runners/runFirewall.d.ts +0 -5
- package/bin/runners/runFirewall.js +0 -137
- package/bin/runners/runFirewallHook.d.ts +0 -5
- package/bin/runners/runFirewallHook.js +0 -59
- package/bin/runners/runIaC.js +0 -372
- package/bin/runners/runPolish.d.ts +0 -4
- package/bin/runners/runProof.zip +0 -0
- package/bin/runners/runTruth.d.ts +0 -5
- package/bin/runners/runTruth.js +0 -104
- package/bin/runners/runVibe.js +0 -791
- package/mcp-server/HARDENING_SUMMARY.md +0 -299
- package/mcp-server/agent-firewall-interceptor.js +0 -500
- package/mcp-server/authority-tools.js +0 -569
- package/mcp-server/conductor/conflict-resolver.js +0 -588
- package/mcp-server/conductor/execution-planner.js +0 -544
- package/mcp-server/conductor/index.js +0 -377
- package/mcp-server/conductor/lock-manager.js +0 -615
- package/mcp-server/conductor/request-queue.js +0 -550
- package/mcp-server/conductor/session-manager.js +0 -500
- package/mcp-server/conductor/tools.js +0 -510
- package/mcp-server/lib/api-client.cjs +0 -13
- package/mcp-server/lib/logger.cjs +0 -30
- package/mcp-server/logger.js +0 -173
- package/mcp-server/tools-v3.js +0 -1039
- package/mcp-server/tools.js +0 -495
- package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Tool Handler
|
|
3
|
+
*
|
|
4
|
+
* Single entry point for all MCP tool calls.
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Schema validation
|
|
7
|
+
* - Tier checking
|
|
8
|
+
* - Execution routing
|
|
9
|
+
* - Response normalization
|
|
10
|
+
* - Error handling
|
|
11
|
+
*
|
|
12
|
+
* CRITICAL: Deterministic output. Stable IDs. Stable sorting.
|
|
13
|
+
* Agents must not thrash.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { readFileSync } from 'fs';
|
|
17
|
+
import { join, dirname } from 'path';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
|
|
20
|
+
import { validateToolInput, validateProjectPath } from '../lib/validator.js';
|
|
21
|
+
import { createErrorEnvelope, createSuccessEnvelope, Errors, ErrorCode } from '../lib/errors.js';
|
|
22
|
+
import { createSandbox } from '../lib/sandbox.js';
|
|
23
|
+
import { getGlobalCache } from '../lib/cache.js';
|
|
24
|
+
import { createRequestLogger } from '../lib/logger.js';
|
|
25
|
+
import { ToolExecutors, cancelExecution } from '../lib/executor.js';
|
|
26
|
+
import { checkFeatureAccess, TIERS } from '../tier-auth.js';
|
|
27
|
+
import { generateRequestId, generateFindingId, sortFindings } from '../lib/ids.js';
|
|
28
|
+
import { getMetricsCollector, recordFindings } from '../lib/metrics.js';
|
|
29
|
+
|
|
30
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load tool registry
|
|
34
|
+
*/
|
|
35
|
+
function loadRegistry() {
|
|
36
|
+
const registryPath = join(__dirname, '..', 'registry', 'tools.json');
|
|
37
|
+
return JSON.parse(readFileSync(registryPath, 'utf-8'));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Tool request
|
|
42
|
+
*/
|
|
43
|
+
export interface ToolRequest {
|
|
44
|
+
tool: string;
|
|
45
|
+
projectPath: string;
|
|
46
|
+
requestId?: string;
|
|
47
|
+
timeout?: number;
|
|
48
|
+
cache?: {
|
|
49
|
+
mode?: 'auto' | 'force' | 'skip';
|
|
50
|
+
maxAge?: number;
|
|
51
|
+
};
|
|
52
|
+
options?: Record<string, unknown>;
|
|
53
|
+
apiKey?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Tool response (success or error)
|
|
58
|
+
*/
|
|
59
|
+
export type ToolResponse =
|
|
60
|
+
| { ok: true; data: unknown; meta?: { cached?: boolean; durationMs?: number; requestId?: string }; timestamp: string }
|
|
61
|
+
| { ok: false; error: { code: string; message: string; retryable?: boolean; userAction?: string }; requestId: string; timestamp: string };
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Main tool handler
|
|
65
|
+
*/
|
|
66
|
+
export async function handleTool(request: ToolRequest): Promise<ToolResponse> {
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
const requestId = request.requestId ?? generateRequestId();
|
|
69
|
+
const logger = createRequestLogger(requestId);
|
|
70
|
+
const metrics = getMetricsCollector();
|
|
71
|
+
|
|
72
|
+
logger.info('Tool request received', { tool: request.tool, projectPath: request.projectPath });
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// 1. Load registry and find tool
|
|
76
|
+
const registry = loadRegistry();
|
|
77
|
+
const toolDef = registry.tools.find((t: { name: string }) => t.name === request.tool);
|
|
78
|
+
|
|
79
|
+
// Check aliases
|
|
80
|
+
if (!toolDef && registry.aliases[request.tool]) {
|
|
81
|
+
const aliasTarget = registry.aliases[request.tool];
|
|
82
|
+
logger.warn('Using deprecated alias', { alias: request.tool, target: aliasTarget });
|
|
83
|
+
request.tool = aliasTarget;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check deprecated
|
|
87
|
+
const deprecated = registry.deprecated?.find((d: { name: string }) =>
|
|
88
|
+
d.name === request.tool || request.tool.match(new RegExp(d.name.replace('*', '.*')))
|
|
89
|
+
);
|
|
90
|
+
if (deprecated) {
|
|
91
|
+
logger.warn('Deprecated tool called', {
|
|
92
|
+
tool: request.tool,
|
|
93
|
+
replacement: deprecated.replacement,
|
|
94
|
+
removeIn: deprecated.removeIn
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Tool not found
|
|
99
|
+
if (!toolDef && !registry.aliases[request.tool]) {
|
|
100
|
+
return createErrorEnvelope(
|
|
101
|
+
Errors.invalidInput(`Unknown tool: ${request.tool}. Available tools: ${registry.tools.map((t: { name: string }) => t.name).join(', ')}`),
|
|
102
|
+
requestId
|
|
103
|
+
) as ToolResponse;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const tool = toolDef ?? registry.tools.find((t: { name: string }) => t.name === registry.aliases[request.tool]);
|
|
107
|
+
|
|
108
|
+
// 2. Validate input schema
|
|
109
|
+
const validation = validateToolInput(tool.name, request.options ?? {});
|
|
110
|
+
if (!validation.valid) {
|
|
111
|
+
return createErrorEnvelope(
|
|
112
|
+
Errors.invalidInput(`Invalid input: ${validation.errors?.map(e => `${e.path}: ${e.message}`).join(', ')}`),
|
|
113
|
+
requestId
|
|
114
|
+
) as ToolResponse;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 3. Validate project path
|
|
118
|
+
const pathValidation = validateProjectPath(request.projectPath);
|
|
119
|
+
if (!pathValidation.valid) {
|
|
120
|
+
return createErrorEnvelope(
|
|
121
|
+
Errors.pathOutsideSandbox(request.projectPath, process.cwd()),
|
|
122
|
+
requestId
|
|
123
|
+
) as ToolResponse;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 4. Check tier access
|
|
127
|
+
const tierAccess = await checkFeatureAccess(tool.tier, request.apiKey);
|
|
128
|
+
if (!tierAccess.hasAccess) {
|
|
129
|
+
return createErrorEnvelope(
|
|
130
|
+
Errors.tierRequired(tool.name, tool.tier, tierAccess.tier),
|
|
131
|
+
requestId
|
|
132
|
+
) as ToolResponse;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check tier-gated options
|
|
136
|
+
if (tool.tierGated) {
|
|
137
|
+
for (const [option, requiredTier] of Object.entries(tool.tierGated)) {
|
|
138
|
+
if (request.options?.[option]) {
|
|
139
|
+
const optionAccess = await checkFeatureAccess(requiredTier as string, request.apiKey);
|
|
140
|
+
if (!optionAccess.hasAccess) {
|
|
141
|
+
return createErrorEnvelope(
|
|
142
|
+
Errors.tierRequired(`${tool.name} --${option}`, requiredTier as string, optionAccess.tier),
|
|
143
|
+
requestId
|
|
144
|
+
) as ToolResponse;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 5. Check cache
|
|
151
|
+
const cache = getGlobalCache();
|
|
152
|
+
const cacheMode = request.cache?.mode ?? 'auto';
|
|
153
|
+
|
|
154
|
+
if (tool.cacheable && cacheMode !== 'skip') {
|
|
155
|
+
const cacheKey = cache.generateKey(tool.name, request.projectPath, request.options);
|
|
156
|
+
const cached = cache.get(cacheKey);
|
|
157
|
+
|
|
158
|
+
if (cached.cached) {
|
|
159
|
+
const cacheMaxAge = request.cache?.maxAge ?? tool.cacheMaxAge ?? 300;
|
|
160
|
+
if (cached.age < cacheMaxAge * 1000) {
|
|
161
|
+
logger.info('Cache hit', { tool: tool.name, cacheAge: cached.age });
|
|
162
|
+
return createSuccessEnvelope(cached.data, {
|
|
163
|
+
cached: true,
|
|
164
|
+
cacheAge: cached.age,
|
|
165
|
+
durationMs: Date.now() - startTime,
|
|
166
|
+
requestId,
|
|
167
|
+
}) as ToolResponse;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 6. Execute tool
|
|
173
|
+
logger.info('Executing tool', { tool: tool.name, cli: tool.cli });
|
|
174
|
+
|
|
175
|
+
const result = await executeToolByName(tool.name, request.projectPath, request.options ?? {}, {
|
|
176
|
+
timeout: request.timeout ?? tool.timeout ?? 120000,
|
|
177
|
+
requestId,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// 7. Cache result if successful
|
|
181
|
+
if (result.ok && tool.cacheable && cacheMode !== 'skip') {
|
|
182
|
+
const cacheKey = cache.generateKey(tool.name, request.projectPath, request.options);
|
|
183
|
+
cache.set(cacheKey, result.data, { ttl: tool.cacheMaxAge ?? 300 });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 8. Post-process result for determinism
|
|
187
|
+
const durationMs = Date.now() - startTime;
|
|
188
|
+
logger.info('Tool completed', { tool: tool.name, durationMs, ok: result.ok });
|
|
189
|
+
|
|
190
|
+
if (result.ok) {
|
|
191
|
+
// Normalize findings with deterministic IDs and sorting
|
|
192
|
+
const normalizedData = normalizeOutput(result.data, tool.name);
|
|
193
|
+
|
|
194
|
+
// Record metrics
|
|
195
|
+
const findings = (normalizedData as { findings?: unknown[] })?.findings ?? [];
|
|
196
|
+
if (findings.length > 0) {
|
|
197
|
+
recordFindings(tool.name, findings as { severity?: string }[]);
|
|
198
|
+
}
|
|
199
|
+
metrics.recordToolExecution(tool.name, durationMs, true, false);
|
|
200
|
+
|
|
201
|
+
return createSuccessEnvelope(normalizedData, {
|
|
202
|
+
cached: false,
|
|
203
|
+
durationMs,
|
|
204
|
+
requestId,
|
|
205
|
+
}) as ToolResponse;
|
|
206
|
+
} else {
|
|
207
|
+
metrics.recordToolExecution(tool.name, durationMs, false, false);
|
|
208
|
+
return createErrorEnvelope(
|
|
209
|
+
Errors.cliError(result.error?.message ?? 'Unknown error', result.exitCode),
|
|
210
|
+
requestId
|
|
211
|
+
) as ToolResponse;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
} catch (error) {
|
|
215
|
+
const durationMs = Date.now() - startTime;
|
|
216
|
+
logger.error('Tool error', error instanceof Error ? error : new Error(String(error)));
|
|
217
|
+
|
|
218
|
+
return createErrorEnvelope(error, requestId) as ToolResponse;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Normalize output for determinism
|
|
224
|
+
*
|
|
225
|
+
* - Add stable IDs to findings
|
|
226
|
+
* - Sort findings deterministically
|
|
227
|
+
* - Ensure consistent field ordering
|
|
228
|
+
*/
|
|
229
|
+
function normalizeOutput(data: unknown, toolName: string): unknown {
|
|
230
|
+
if (!data || typeof data !== 'object') {
|
|
231
|
+
return data;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const obj = data as Record<string, unknown>;
|
|
235
|
+
|
|
236
|
+
// Process findings array if present
|
|
237
|
+
if (Array.isArray(obj.findings)) {
|
|
238
|
+
obj.findings = normalizeFindings(obj.findings);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Process blockers array if present
|
|
242
|
+
if (Array.isArray(obj.blockers)) {
|
|
243
|
+
obj.blockers = normalizeFindings(obj.blockers);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Process topIssues array if present
|
|
247
|
+
if (Array.isArray(obj.topIssues)) {
|
|
248
|
+
obj.topIssues = normalizeFindings(obj.topIssues);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return obj;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Normalize findings with stable IDs and sorting
|
|
256
|
+
*/
|
|
257
|
+
function normalizeFindings(findings: unknown[]): unknown[] {
|
|
258
|
+
const normalized = findings.map((finding, index) => {
|
|
259
|
+
if (!finding || typeof finding !== 'object') {
|
|
260
|
+
return finding;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const f = finding as Record<string, unknown>;
|
|
264
|
+
|
|
265
|
+
// Generate stable ID if missing or invalid
|
|
266
|
+
if (!f.id || typeof f.id !== 'string' || !f.id.match(/^[a-z_]+-[a-f0-9]{8}$/)) {
|
|
267
|
+
const category = (f.category as string) || (f.rule_id as string)?.split('.')[0] || 'unknown';
|
|
268
|
+
const evidence = Array.isArray(f.evidence) ? f.evidence[0] : {};
|
|
269
|
+
const evidenceObj = evidence as { file?: string; line?: number };
|
|
270
|
+
|
|
271
|
+
f.id = generateFindingId(
|
|
272
|
+
category,
|
|
273
|
+
{
|
|
274
|
+
path: evidenceObj?.file || `finding-${index}`,
|
|
275
|
+
lineStart: evidenceObj?.line || 0,
|
|
276
|
+
message: (f.title as string) || (f.message as string) || '',
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return f;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Sort deterministically
|
|
285
|
+
return sortFindings(normalized as Array<{
|
|
286
|
+
severity?: string;
|
|
287
|
+
rule_id?: string;
|
|
288
|
+
ruleId?: string;
|
|
289
|
+
evidence?: Array<{ file?: string; line?: number }>;
|
|
290
|
+
title?: string;
|
|
291
|
+
}>);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Execute tool by name
|
|
296
|
+
*/
|
|
297
|
+
async function executeToolByName(
|
|
298
|
+
toolName: string,
|
|
299
|
+
projectPath: string,
|
|
300
|
+
options: Record<string, unknown>,
|
|
301
|
+
execOptions: { timeout: number; requestId: string }
|
|
302
|
+
): Promise<{ ok: boolean; data?: unknown; error?: { message: string }; exitCode?: number }> {
|
|
303
|
+
const baseOptions = {
|
|
304
|
+
projectPath,
|
|
305
|
+
timeout: execOptions.timeout,
|
|
306
|
+
requestId: execOptions.requestId,
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
switch (toolName) {
|
|
310
|
+
case 'vibecheck.doctor':
|
|
311
|
+
return ToolExecutors.doctor(baseOptions);
|
|
312
|
+
|
|
313
|
+
case 'vibecheck.init':
|
|
314
|
+
return ToolExecutors.init({ ...baseOptions, force: options.force as boolean });
|
|
315
|
+
|
|
316
|
+
case 'vibecheck.scan':
|
|
317
|
+
return ToolExecutors.scan({
|
|
318
|
+
...baseOptions,
|
|
319
|
+
profile: options.profile as string,
|
|
320
|
+
since: options.since as string,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
case 'vibecheck.ship':
|
|
324
|
+
return ToolExecutors.ship({
|
|
325
|
+
...baseOptions,
|
|
326
|
+
strict: options.strict as boolean,
|
|
327
|
+
mockproof: options.mockproof as boolean,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
case 'vibecheck.prove':
|
|
331
|
+
return ToolExecutors.prove({
|
|
332
|
+
...baseOptions,
|
|
333
|
+
url: options.url as string,
|
|
334
|
+
auth: options.auth as string,
|
|
335
|
+
maxFixRounds: options.maxFixRounds as number,
|
|
336
|
+
skipReality: options.skipReality as boolean,
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
case 'vibecheck.reality':
|
|
340
|
+
return ToolExecutors.reality({
|
|
341
|
+
...baseOptions,
|
|
342
|
+
url: options.url as string,
|
|
343
|
+
auth: options.auth as string,
|
|
344
|
+
verifyAuth: options.verifyAuth as boolean,
|
|
345
|
+
maxPages: options.maxPages as number,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
case 'vibecheck.fix':
|
|
349
|
+
return ToolExecutors.fix({
|
|
350
|
+
...baseOptions,
|
|
351
|
+
apply: options.apply as boolean,
|
|
352
|
+
promptOnly: options.promptOnly as boolean,
|
|
353
|
+
autopilot: options.autopilot as boolean,
|
|
354
|
+
maxMissions: options.maxMissions as number,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
case 'vibecheck.guard':
|
|
358
|
+
return ToolExecutors.guard({
|
|
359
|
+
...baseOptions,
|
|
360
|
+
claims: options.claims as boolean,
|
|
361
|
+
hallucinations: options.hallucinations as boolean,
|
|
362
|
+
prompts: options.prompts as boolean,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
case 'vibecheck.ctx':
|
|
366
|
+
return ToolExecutors.ctx({
|
|
367
|
+
...baseOptions,
|
|
368
|
+
snapshot: options.snapshot as boolean,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
case 'vibecheck.report':
|
|
372
|
+
return ToolExecutors.report({
|
|
373
|
+
...baseOptions,
|
|
374
|
+
type: options.type as string,
|
|
375
|
+
format: options.format as string,
|
|
376
|
+
output: options.output as string,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
case 'vibecheck.polish':
|
|
380
|
+
return ToolExecutors.polish({
|
|
381
|
+
...baseOptions,
|
|
382
|
+
category: options.category as string,
|
|
383
|
+
fix: options.fix as boolean,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
case 'vibecheck.status':
|
|
387
|
+
return ToolExecutors.status(baseOptions);
|
|
388
|
+
|
|
389
|
+
case 'vibecheck.share':
|
|
390
|
+
return ToolExecutors.share({
|
|
391
|
+
...baseOptions,
|
|
392
|
+
missionDir: options.missionDir as string,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
case 'vibecheck.badge':
|
|
396
|
+
return ToolExecutors.badge({
|
|
397
|
+
...baseOptions,
|
|
398
|
+
format: options.format as string,
|
|
399
|
+
style: options.style as string,
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Query tools (non-CLI)
|
|
403
|
+
case 'vibecheck.get_truthpack':
|
|
404
|
+
return handleGetTruthpack(projectPath, options);
|
|
405
|
+
|
|
406
|
+
case 'vibecheck.validate_claim':
|
|
407
|
+
return handleValidateClaim(projectPath, options);
|
|
408
|
+
|
|
409
|
+
case 'vibecheck.search_evidence':
|
|
410
|
+
return handleSearchEvidence(projectPath, options);
|
|
411
|
+
|
|
412
|
+
case 'vibecheck.list_reports':
|
|
413
|
+
return handleListReports(projectPath, options);
|
|
414
|
+
|
|
415
|
+
case 'vibecheck.get_last_verdict':
|
|
416
|
+
return handleGetLastVerdict(projectPath);
|
|
417
|
+
|
|
418
|
+
case 'vibecheck.get_finding':
|
|
419
|
+
return handleGetFinding(projectPath, options);
|
|
420
|
+
|
|
421
|
+
default:
|
|
422
|
+
return { ok: false, error: { message: `No executor for tool: ${toolName}` } };
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Query tool handlers
|
|
428
|
+
*/
|
|
429
|
+
import { readFileSync as readSync, existsSync, readdirSync, statSync } from 'fs';
|
|
430
|
+
|
|
431
|
+
async function handleGetTruthpack(projectPath: string, options: Record<string, unknown>) {
|
|
432
|
+
const truthpackPaths = [
|
|
433
|
+
join(projectPath, '.vibecheck', 'truthpack.json'),
|
|
434
|
+
join(projectPath, '.vibecheck', 'truth', 'truthpack.json'),
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
for (const path of truthpackPaths) {
|
|
438
|
+
if (existsSync(path)) {
|
|
439
|
+
try {
|
|
440
|
+
const data = JSON.parse(readSync(path, 'utf-8'));
|
|
441
|
+
return { ok: true, data };
|
|
442
|
+
} catch {
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// If refresh requested or not found, run ctx
|
|
449
|
+
if (options.refresh) {
|
|
450
|
+
return ToolExecutors.ctx({ projectPath, timeout: 90000 });
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return { ok: false, error: { message: 'Truthpack not found. Run vibecheck.ctx first.' } };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function handleValidateClaim(projectPath: string, options: Record<string, unknown>) {
|
|
457
|
+
const claim = options.claim as string;
|
|
458
|
+
const type = options.type as string;
|
|
459
|
+
|
|
460
|
+
// Load truthpack
|
|
461
|
+
const truthpackResult = await handleGetTruthpack(projectPath, {});
|
|
462
|
+
if (!truthpackResult.ok) {
|
|
463
|
+
return { ok: false, error: { message: 'Cannot validate claim: truthpack not available' } };
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const truthpack = truthpackResult.data as Record<string, unknown>;
|
|
467
|
+
|
|
468
|
+
// Simple validation logic
|
|
469
|
+
if (type === 'route_exists') {
|
|
470
|
+
const routes = (truthpack.routes as { server?: Array<{ path: string }> })?.server ?? [];
|
|
471
|
+
const found = routes.some(r => r.path === claim || r.path.includes(claim));
|
|
472
|
+
return {
|
|
473
|
+
ok: true,
|
|
474
|
+
data: {
|
|
475
|
+
valid: found,
|
|
476
|
+
claim,
|
|
477
|
+
type,
|
|
478
|
+
evidence: found ? routes.filter(r => r.path.includes(claim)).slice(0, 3) : [],
|
|
479
|
+
},
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (type === 'env_var_used') {
|
|
484
|
+
const vars = (truthpack.env as { vars?: Array<{ name: string }> })?.vars ?? [];
|
|
485
|
+
const found = vars.some(v => v.name === claim);
|
|
486
|
+
return {
|
|
487
|
+
ok: true,
|
|
488
|
+
data: {
|
|
489
|
+
valid: found,
|
|
490
|
+
claim,
|
|
491
|
+
type,
|
|
492
|
+
evidence: found ? vars.filter(v => v.name === claim) : [],
|
|
493
|
+
},
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (type === 'file_exists') {
|
|
498
|
+
const exists = existsSync(join(projectPath, claim));
|
|
499
|
+
return {
|
|
500
|
+
ok: true,
|
|
501
|
+
data: {
|
|
502
|
+
valid: exists,
|
|
503
|
+
claim,
|
|
504
|
+
type,
|
|
505
|
+
evidence: exists ? [{ file: claim }] : [],
|
|
506
|
+
},
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return {
|
|
511
|
+
ok: true,
|
|
512
|
+
data: {
|
|
513
|
+
valid: 'unknown',
|
|
514
|
+
claim,
|
|
515
|
+
type,
|
|
516
|
+
reason: 'Claim type not supported',
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
async function handleSearchEvidence(projectPath: string, options: Record<string, unknown>) {
|
|
522
|
+
const query = options.query as string;
|
|
523
|
+
const type = options.type as string ?? 'any';
|
|
524
|
+
const limit = options.limit as number ?? 10;
|
|
525
|
+
|
|
526
|
+
// Load truthpack
|
|
527
|
+
const truthpackResult = await handleGetTruthpack(projectPath, {});
|
|
528
|
+
if (!truthpackResult.ok) {
|
|
529
|
+
return { ok: false, error: { message: 'Cannot search: truthpack not available' } };
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
const truthpack = truthpackResult.data as Record<string, unknown>;
|
|
533
|
+
const results: Array<{ type: string; match: unknown; confidence: number }> = [];
|
|
534
|
+
|
|
535
|
+
// Search routes
|
|
536
|
+
if (type === 'any' || type === 'route') {
|
|
537
|
+
const routes = (truthpack.routes as { server?: Array<{ path: string; file?: string }> })?.server ?? [];
|
|
538
|
+
for (const route of routes) {
|
|
539
|
+
if (route.path.includes(query)) {
|
|
540
|
+
results.push({ type: 'route', match: route, confidence: 0.9 });
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Search env vars
|
|
546
|
+
if (type === 'any' || type === 'env_var') {
|
|
547
|
+
const vars = (truthpack.env as { vars?: Array<{ name: string }> })?.vars ?? [];
|
|
548
|
+
for (const v of vars) {
|
|
549
|
+
if (v.name.includes(query)) {
|
|
550
|
+
results.push({ type: 'env_var', match: v, confidence: 0.95 });
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return {
|
|
556
|
+
ok: true,
|
|
557
|
+
data: {
|
|
558
|
+
query,
|
|
559
|
+
type,
|
|
560
|
+
results: results.slice(0, limit),
|
|
561
|
+
total: results.length,
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async function handleListReports(projectPath: string, options: Record<string, unknown>) {
|
|
567
|
+
const vibecheckDir = join(projectPath, '.vibecheck');
|
|
568
|
+
if (!existsSync(vibecheckDir)) {
|
|
569
|
+
return { ok: true, data: { reports: [] } };
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const reports: Array<{ type: string; path: string; created: number }> = [];
|
|
573
|
+
|
|
574
|
+
// Check common report locations
|
|
575
|
+
const reportFiles = [
|
|
576
|
+
{ type: 'verdict', path: 'last_ship.json' },
|
|
577
|
+
{ type: 'truthpack', path: 'truthpack.json' },
|
|
578
|
+
{ type: 'truthpack', path: 'truth/truthpack.json' },
|
|
579
|
+
{ type: 'summary', path: 'summary.json' },
|
|
580
|
+
{ type: 'sarif', path: 'results.sarif' },
|
|
581
|
+
{ type: 'html', path: 'report.html' },
|
|
582
|
+
];
|
|
583
|
+
|
|
584
|
+
for (const { type, path } of reportFiles) {
|
|
585
|
+
const fullPath = join(vibecheckDir, path);
|
|
586
|
+
if (existsSync(fullPath)) {
|
|
587
|
+
const stat = statSync(fullPath);
|
|
588
|
+
reports.push({ type, path: `.vibecheck/${path}`, created: stat.mtimeMs });
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Check missions directory
|
|
593
|
+
const missionsDir = join(vibecheckDir, 'missions');
|
|
594
|
+
if (existsSync(missionsDir)) {
|
|
595
|
+
const dirs = readdirSync(missionsDir).filter(d => /^\d+$/.test(d));
|
|
596
|
+
for (const dir of dirs.slice(-5)) {
|
|
597
|
+
reports.push({
|
|
598
|
+
type: 'mission',
|
|
599
|
+
path: `.vibecheck/missions/${dir}`,
|
|
600
|
+
created: parseInt(dir, 10),
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return {
|
|
606
|
+
ok: true,
|
|
607
|
+
data: {
|
|
608
|
+
reports: reports.sort((a, b) => b.created - a.created).slice(0, options.limit as number ?? 10),
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
async function handleGetLastVerdict(projectPath: string) {
|
|
614
|
+
const verdictPath = join(projectPath, '.vibecheck', 'last_ship.json');
|
|
615
|
+
|
|
616
|
+
if (!existsSync(verdictPath)) {
|
|
617
|
+
return { ok: false, error: { message: 'No verdict found. Run vibecheck.ship first.' } };
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
try {
|
|
621
|
+
const data = JSON.parse(readSync(verdictPath, 'utf-8'));
|
|
622
|
+
return { ok: true, data };
|
|
623
|
+
} catch {
|
|
624
|
+
return { ok: false, error: { message: 'Failed to read verdict file' } };
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
async function handleGetFinding(projectPath: string, options: Record<string, unknown>) {
|
|
629
|
+
const findingId = options.findingId as string;
|
|
630
|
+
|
|
631
|
+
// Load last ship report
|
|
632
|
+
const verdictResult = await handleGetLastVerdict(projectPath);
|
|
633
|
+
if (!verdictResult.ok) {
|
|
634
|
+
return verdictResult;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const verdict = verdictResult.data as { findings?: Array<{ id: string }> };
|
|
638
|
+
const finding = verdict.findings?.find(f => f.id === findingId);
|
|
639
|
+
|
|
640
|
+
if (!finding) {
|
|
641
|
+
return { ok: false, error: { message: `Finding not found: ${findingId}` } };
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
return { ok: true, data: finding };
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Cancel a running tool execution
|
|
649
|
+
*/
|
|
650
|
+
export function cancelTool(requestId: string): boolean {
|
|
651
|
+
return cancelExecution(requestId);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* List available tools
|
|
656
|
+
*/
|
|
657
|
+
export function listTools(): Array<{ name: string; description: string; tier: string; category: string }> {
|
|
658
|
+
const registry = loadRegistry();
|
|
659
|
+
return registry.tools.map((t: { name: string; description: string; tier: string; category: string }) => ({
|
|
660
|
+
name: t.name,
|
|
661
|
+
description: t.description,
|
|
662
|
+
tier: t.tier,
|
|
663
|
+
category: t.category,
|
|
664
|
+
}));
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
export default {
|
|
668
|
+
handleTool,
|
|
669
|
+
cancelTool,
|
|
670
|
+
listTools,
|
|
671
|
+
};
|