@ironbee-ai/cli 0.6.2 → 0.7.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/CHANGELOG.md +6 -0
- package/README.md +167 -39
- package/dist/analysis/code-changes.js.map +1 -1
- package/dist/analysis/cross-session.js.map +1 -1
- package/dist/analysis/fix-effectiveness.js.map +1 -1
- package/dist/analysis/time-analysis.js.map +1 -1
- package/dist/analysis/verdict-details.js.map +1 -1
- package/dist/analysis/verification-quality.js.map +1 -1
- package/dist/analytics/classifier.d.ts +99 -0
- package/dist/analytics/classifier.d.ts.map +1 -0
- package/dist/analytics/classifier.js +380 -0
- package/dist/analytics/classifier.js.map +1 -0
- package/dist/analytics/emit.d.ts +67 -0
- package/dist/analytics/emit.d.ts.map +1 -0
- package/dist/analytics/emit.js +901 -0
- package/dist/analytics/emit.js.map +1 -0
- package/dist/analytics/errors.d.ts +33 -0
- package/dist/analytics/errors.d.ts.map +1 -0
- package/dist/analytics/errors.js +93 -0
- package/dist/analytics/errors.js.map +1 -0
- package/dist/analytics/hook-trigger.d.ts +39 -0
- package/dist/analytics/hook-trigger.d.ts.map +1 -0
- package/dist/analytics/hook-trigger.js +127 -0
- package/dist/analytics/hook-trigger.js.map +1 -0
- package/dist/analytics/log.d.ts +44 -0
- package/dist/analytics/log.d.ts.map +1 -0
- package/dist/analytics/log.js +158 -0
- package/dist/analytics/log.js.map +1 -0
- package/dist/analytics/merge.d.ts +40 -0
- package/dist/analytics/merge.d.ts.map +1 -0
- package/dist/analytics/merge.js +527 -0
- package/dist/analytics/merge.js.map +1 -0
- package/dist/analytics/pricing.d.ts +149 -0
- package/dist/analytics/pricing.d.ts.map +1 -0
- package/dist/analytics/pricing.js +179 -0
- package/dist/analytics/pricing.js.map +1 -0
- package/dist/analytics/projection.d.ts +356 -0
- package/dist/analytics/projection.d.ts.map +1 -0
- package/dist/analytics/projection.js +2281 -0
- package/dist/analytics/projection.js.map +1 -0
- package/dist/analytics/spawn.d.ts +28 -0
- package/dist/analytics/spawn.d.ts.map +1 -0
- package/dist/analytics/spawn.js +57 -0
- package/dist/analytics/spawn.js.map +1 -0
- package/dist/analytics/state.d.ts +58 -0
- package/dist/analytics/state.d.ts.map +1 -0
- package/dist/analytics/state.js +329 -0
- package/dist/analytics/state.js.map +1 -0
- package/dist/analytics/transcript.d.ts +150 -0
- package/dist/analytics/transcript.d.ts.map +1 -0
- package/dist/analytics/transcript.js +276 -0
- package/dist/analytics/transcript.js.map +1 -0
- package/dist/analytics/types.d.ts +875 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics/types.js +31 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/clients/base.d.ts +21 -2
- package/dist/clients/base.d.ts.map +1 -1
- package/dist/clients/claude/commands/ironbee-verify.md +15 -7
- package/dist/clients/claude/fragments/command-verify.node.md +33 -0
- package/dist/clients/claude/fragments/rule.node.md +29 -0
- package/dist/clients/claude/fragments/skill.node.md +77 -0
- package/dist/clients/claude/hooks/activity-end.d.ts +13 -0
- package/dist/clients/claude/hooks/activity-end.d.ts.map +1 -0
- package/dist/clients/claude/hooks/activity-end.js +42 -0
- package/dist/clients/claude/hooks/activity-end.js.map +1 -0
- package/dist/clients/claude/hooks/require-verdict.d.ts +3 -2
- package/dist/clients/claude/hooks/require-verdict.d.ts.map +1 -1
- package/dist/clients/claude/hooks/require-verdict.js +6 -5
- package/dist/clients/claude/hooks/require-verdict.js.map +1 -1
- package/dist/clients/claude/hooks/require-verification.d.ts +7 -4
- package/dist/clients/claude/hooks/require-verification.d.ts.map +1 -1
- package/dist/clients/claude/hooks/require-verification.js +44 -22
- package/dist/clients/claude/hooks/require-verification.js.map +1 -1
- package/dist/clients/claude/hooks/session-end.d.ts.map +1 -1
- package/dist/clients/claude/hooks/session-end.js +17 -2
- package/dist/clients/claude/hooks/session-end.js.map +1 -1
- package/dist/clients/claude/hooks/session-start.d.ts.map +1 -1
- package/dist/clients/claude/hooks/session-start.js +2 -1
- package/dist/clients/claude/hooks/session-start.js.map +1 -1
- package/dist/clients/claude/hooks/track-action-monitor.d.ts +27 -0
- package/dist/clients/claude/hooks/track-action-monitor.d.ts.map +1 -0
- package/dist/clients/claude/hooks/track-action-monitor.js +126 -0
- package/dist/clients/claude/hooks/track-action-monitor.js.map +1 -0
- package/dist/clients/claude/hooks/track-action.d.ts.map +1 -1
- package/dist/clients/claude/hooks/track-action.js +29 -20
- package/dist/clients/claude/hooks/track-action.js.map +1 -1
- package/dist/clients/claude/hooks/verify-gate.d.ts.map +1 -1
- package/dist/clients/claude/hooks/verify-gate.js +18 -1
- package/dist/clients/claude/hooks/verify-gate.js.map +1 -1
- package/dist/clients/claude/index.d.ts +4 -1
- package/dist/clients/claude/index.d.ts.map +1 -1
- package/dist/clients/claude/index.js +171 -94
- package/dist/clients/claude/index.js.map +1 -1
- package/dist/clients/claude/rules/ironbee-verification.md +41 -33
- package/dist/clients/claude/skills/ironbee-verification.md +93 -76
- package/dist/clients/cursor/commands/ironbee-verify/SKILL.md +18 -10
- package/dist/clients/cursor/fragments/command-verify.node.md +33 -0
- package/dist/clients/cursor/fragments/rule.node.md +29 -0
- package/dist/clients/cursor/fragments/skill.node.md +77 -0
- package/dist/clients/cursor/hooks/activity-end.d.ts +14 -0
- package/dist/clients/cursor/hooks/activity-end.d.ts.map +1 -0
- package/dist/clients/cursor/hooks/activity-end.js +45 -0
- package/dist/clients/cursor/hooks/activity-end.js.map +1 -0
- package/dist/clients/cursor/hooks/require-verdict.d.ts +1 -1
- package/dist/clients/cursor/hooks/require-verdict.js +4 -4
- package/dist/clients/cursor/hooks/require-verification.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/require-verification.js +42 -16
- package/dist/clients/cursor/hooks/require-verification.js.map +1 -1
- package/dist/clients/cursor/hooks/session-end.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/session-end.js +18 -2
- package/dist/clients/cursor/hooks/session-end.js.map +1 -1
- package/dist/clients/cursor/hooks/session-start.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/session-start.js +2 -1
- package/dist/clients/cursor/hooks/session-start.js.map +1 -1
- package/dist/clients/cursor/hooks/track-action-monitor.d.ts +27 -0
- package/dist/clients/cursor/hooks/track-action-monitor.d.ts.map +1 -0
- package/dist/clients/cursor/hooks/track-action-monitor.js +133 -0
- package/dist/clients/cursor/hooks/track-action-monitor.js.map +1 -0
- package/dist/clients/cursor/hooks/track-action.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/track-action.js +51 -23
- package/dist/clients/cursor/hooks/track-action.js.map +1 -1
- package/dist/clients/cursor/hooks/verify-gate.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/verify-gate.js +14 -1
- package/dist/clients/cursor/hooks/verify-gate.js.map +1 -1
- package/dist/clients/cursor/index.d.ts +4 -1
- package/dist/clients/cursor/index.d.ts.map +1 -1
- package/dist/clients/cursor/index.js +117 -71
- package/dist/clients/cursor/index.js.map +1 -1
- package/dist/clients/cursor/rules/ironbee-verification.mdc +37 -29
- package/dist/clients/cursor/skills/ironbee-verification.md +93 -76
- package/dist/clients/registry.d.ts +14 -0
- package/dist/clients/registry.d.ts.map +1 -1
- package/dist/clients/registry.js +34 -0
- package/dist/clients/registry.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +40 -0
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/backend-toggle.d.ts +45 -0
- package/dist/commands/backend-toggle.d.ts.map +1 -0
- package/dist/commands/backend-toggle.js +192 -0
- package/dist/commands/backend-toggle.js.map +1 -0
- package/dist/commands/disable-backend.d.ts +14 -0
- package/dist/commands/disable-backend.d.ts.map +1 -0
- package/dist/commands/disable-backend.js +34 -0
- package/dist/commands/disable-backend.js.map +1 -0
- package/dist/commands/disable-verification.d.ts +16 -0
- package/dist/commands/disable-verification.d.ts.map +1 -0
- package/dist/commands/disable-verification.js +36 -0
- package/dist/commands/disable-verification.js.map +1 -0
- package/dist/commands/enable-backend.d.ts +15 -0
- package/dist/commands/enable-backend.d.ts.map +1 -0
- package/dist/commands/enable-backend.js +35 -0
- package/dist/commands/enable-backend.js.map +1 -0
- package/dist/commands/enable-verification.d.ts +14 -0
- package/dist/commands/enable-verification.d.ts.map +1 -0
- package/dist/commands/enable-verification.js +34 -0
- package/dist/commands/enable-verification.js.map +1 -0
- package/dist/commands/hook.d.ts.map +1 -1
- package/dist/commands/hook.js +60 -0
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/import.d.ts +39 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +369 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +15 -20
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/process-analytics.d.ts +18 -0
- package/dist/commands/process-analytics.d.ts.map +1 -0
- package/dist/commands/process-analytics.js +57 -0
- package/dist/commands/process-analytics.js.map +1 -0
- package/dist/commands/queue.d.ts +2 -3
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +2 -3
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +29 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/verification-toggle.d.ts +47 -0
- package/dist/commands/verification-toggle.d.ts.map +1 -0
- package/dist/commands/verification-toggle.js +113 -0
- package/dist/commands/verification-toggle.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +28 -0
- package/dist/commands/verify.js.map +1 -1
- package/dist/hooks/core/actions.d.ts +64 -67
- package/dist/hooks/core/actions.d.ts.map +1 -1
- package/dist/hooks/core/actions.js +39 -24
- package/dist/hooks/core/actions.js.map +1 -1
- package/dist/hooks/core/activity-end.d.ts +20 -0
- package/dist/hooks/core/activity-end.d.ts.map +1 -0
- package/dist/hooks/core/activity-end.js +23 -0
- package/dist/hooks/core/activity-end.js.map +1 -0
- package/dist/hooks/core/required-tools.d.ts +30 -0
- package/dist/hooks/core/required-tools.d.ts.map +1 -0
- package/dist/hooks/core/required-tools.js +70 -0
- package/dist/hooks/core/required-tools.js.map +1 -0
- package/dist/hooks/core/session-state.d.ts +12 -3
- package/dist/hooks/core/session-state.d.ts.map +1 -1
- package/dist/hooks/core/session-state.js +59 -0
- package/dist/hooks/core/session-state.js.map +1 -1
- package/dist/hooks/core/submit-verdict.d.ts.map +1 -1
- package/dist/hooks/core/submit-verdict.js +16 -12
- package/dist/hooks/core/submit-verdict.js.map +1 -1
- package/dist/hooks/core/verify-gate.d.ts +17 -3
- package/dist/hooks/core/verify-gate.d.ts.map +1 -1
- package/dist/hooks/core/verify-gate.js +312 -116
- package/dist/hooks/core/verify-gate.js.map +1 -1
- package/dist/import/claude/analytics-runner.d.ts +42 -0
- package/dist/import/claude/analytics-runner.d.ts.map +1 -0
- package/dist/import/claude/analytics-runner.js +213 -0
- package/dist/import/claude/analytics-runner.js.map +1 -0
- package/dist/import/claude/discovery.d.ts +22 -0
- package/dist/import/claude/discovery.d.ts.map +1 -0
- package/dist/import/claude/discovery.js +197 -0
- package/dist/import/claude/discovery.js.map +1 -0
- package/dist/import/claude/encoding.d.ts +50 -0
- package/dist/import/claude/encoding.d.ts.map +1 -0
- package/dist/import/claude/encoding.js +110 -0
- package/dist/import/claude/encoding.js.map +1 -0
- package/dist/import/claude/events/file-change.d.ts +28 -0
- package/dist/import/claude/events/file-change.d.ts.map +1 -0
- package/dist/import/claude/events/file-change.js +112 -0
- package/dist/import/claude/events/file-change.js.map +1 -0
- package/dist/import/claude/events/tool-call.d.ts +61 -0
- package/dist/import/claude/events/tool-call.d.ts.map +1 -0
- package/dist/import/claude/events/tool-call.js +119 -0
- package/dist/import/claude/events/tool-call.js.map +1 -0
- package/dist/import/claude/runner.d.ts +31 -0
- package/dist/import/claude/runner.d.ts.map +1 -0
- package/dist/import/claude/runner.js +280 -0
- package/dist/import/claude/runner.js.map +1 -0
- package/dist/import/claude/summary.d.ts +23 -0
- package/dist/import/claude/summary.d.ts.map +1 -0
- package/dist/import/claude/summary.js +186 -0
- package/dist/import/claude/summary.js.map +1 -0
- package/dist/import/claude/transcript-walk.d.ts +52 -0
- package/dist/import/claude/transcript-walk.d.ts.map +1 -0
- package/dist/import/claude/transcript-walk.js +187 -0
- package/dist/import/claude/transcript-walk.js.map +1 -0
- package/dist/import/concurrent-pool.d.ts +45 -0
- package/dist/import/concurrent-pool.d.ts.map +1 -0
- package/dist/import/concurrent-pool.js +95 -0
- package/dist/import/concurrent-pool.js.map +1 -0
- package/dist/import/emitter.d.ts +29 -0
- package/dist/import/emitter.d.ts.map +1 -0
- package/dist/import/emitter.js +66 -0
- package/dist/import/emitter.js.map +1 -0
- package/dist/import/events/activity.d.ts +23 -0
- package/dist/import/events/activity.d.ts.map +1 -0
- package/dist/import/events/activity.js +45 -0
- package/dist/import/events/activity.js.map +1 -0
- package/dist/import/events/session.d.ts +24 -0
- package/dist/import/events/session.d.ts.map +1 -0
- package/dist/import/events/session.js +47 -0
- package/dist/import/events/session.js.map +1 -0
- package/dist/import/filter.d.ts +47 -0
- package/dist/import/filter.d.ts.map +1 -0
- package/dist/import/filter.js +90 -0
- package/dist/import/filter.js.map +1 -0
- package/dist/import/ids.d.ts +56 -0
- package/dist/import/ids.d.ts.map +1 -0
- package/dist/import/ids.js +87 -0
- package/dist/import/ids.js.map +1 -0
- package/dist/import/index.d.ts +29 -0
- package/dist/import/index.d.ts.map +1 -0
- package/dist/import/index.js +52 -0
- package/dist/import/index.js.map +1 -0
- package/dist/import/marker.d.ts +20 -0
- package/dist/import/marker.d.ts.map +1 -0
- package/dist/import/marker.js +71 -0
- package/dist/import/marker.js.map +1 -0
- package/dist/import/pipeline.d.ts +41 -0
- package/dist/import/pipeline.d.ts.map +1 -0
- package/dist/import/pipeline.js +47 -0
- package/dist/import/pipeline.js.map +1 -0
- package/dist/import/progress.d.ts +20 -0
- package/dist/import/progress.d.ts.map +1 -0
- package/dist/import/progress.js +69 -0
- package/dist/import/progress.js.map +1 -0
- package/dist/import/skip.d.ts +13 -0
- package/dist/import/skip.d.ts.map +1 -0
- package/dist/import/skip.js +24 -0
- package/dist/import/skip.js.map +1 -0
- package/dist/import/types.d.ts +125 -0
- package/dist/import/types.d.ts.map +1 -0
- package/dist/import/types.js +28 -0
- package/dist/import/types.js.map +1 -0
- package/dist/index.js +21 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/collector.d.ts +29 -3
- package/dist/lib/collector.d.ts.map +1 -1
- package/dist/lib/collector.js +118 -8
- package/dist/lib/collector.js.map +1 -1
- package/dist/lib/config.d.ts +240 -83
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +482 -89
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/event.d.ts +72 -0
- package/dist/lib/event.d.ts.map +1 -0
- package/dist/lib/event.js +42 -0
- package/dist/lib/event.js.map +1 -0
- package/dist/lib/gitignore.d.ts +21 -0
- package/dist/lib/gitignore.d.ts.map +1 -0
- package/dist/lib/gitignore.js +54 -0
- package/dist/lib/gitignore.js.map +1 -0
- package/dist/lib/runtime-section.d.ts +118 -0
- package/dist/lib/runtime-section.d.ts.map +1 -0
- package/dist/lib/runtime-section.js +256 -0
- package/dist/lib/runtime-section.js.map +1 -0
- package/dist/lib/telemetry.d.ts +1 -1
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/telemetry.js +4 -1
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/queue/dead-letter.d.ts +5 -1
- package/dist/queue/dead-letter.d.ts.map +1 -1
- package/dist/queue/dead-letter.js +5 -1
- package/dist/queue/dead-letter.js.map +1 -1
- package/dist/queue/drain.d.ts +3 -2
- package/dist/queue/drain.d.ts.map +1 -1
- package/dist/queue/drain.js +3 -2
- package/dist/queue/drain.js.map +1 -1
- package/dist/queue/flush.d.ts +28 -12
- package/dist/queue/flush.d.ts.map +1 -1
- package/dist/queue/flush.js +43 -18
- package/dist/queue/flush.js.map +1 -1
- package/dist/queue/handlers/send-event.d.ts.map +1 -1
- package/dist/queue/handlers/send-event.js.map +1 -1
- package/dist/queue/index.d.ts +1 -2
- package/dist/queue/index.d.ts.map +1 -1
- package/dist/queue/index.js +2 -2
- package/dist/queue/index.js.map +1 -1
- package/dist/queue/paths.d.ts +4 -2
- package/dist/queue/paths.d.ts.map +1 -1
- package/dist/queue/paths.js +4 -2
- package/dist/queue/paths.js.map +1 -1
- package/dist/queue/process-file.d.ts +5 -1
- package/dist/queue/process-file.d.ts.map +1 -1
- package/dist/queue/process-file.js +5 -1
- package/dist/queue/process-file.js.map +1 -1
- package/dist/queue/snapshot.d.ts +4 -1
- package/dist/queue/snapshot.d.ts.map +1 -1
- package/dist/queue/snapshot.js +4 -1
- package/dist/queue/snapshot.js.map +1 -1
- package/dist/queue/spawn.d.ts +1 -3
- package/dist/queue/spawn.d.ts.map +1 -1
- package/dist/queue/spawn.js +1 -3
- package/dist/queue/spawn.js.map +1 -1
- package/dist/queue/submit.d.ts +6 -1
- package/dist/queue/submit.d.ts.map +1 -1
- package/dist/queue/submit.js +6 -1
- package/dist/queue/submit.js.map +1 -1
- package/dist/queue/types.d.ts +5 -1
- package/dist/queue/types.d.ts.map +1 -1
- package/dist/queue/types.js +5 -1
- package/dist/queue/types.js.map +1 -1
- package/dist/queue/worker-log.d.ts +3 -1
- package/dist/queue/worker-log.d.ts.map +1 -1
- package/dist/queue/worker-log.js +3 -1
- package/dist/queue/worker-log.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/config.js
CHANGED
|
@@ -6,20 +6,45 @@
|
|
|
6
6
|
* 1. Global: ~/.ironbee/config.json
|
|
7
7
|
* 2. Project: <projectDir>/.ironbee/config.json
|
|
8
8
|
*
|
|
9
|
-
* Project config overrides global config (
|
|
9
|
+
* Project config overrides global config (deep merge for nested sections,
|
|
10
|
+
* shallow for primitives — see deepMerge).
|
|
11
|
+
*
|
|
12
|
+
* The pre-split layout (top-level `verifyPatterns` / `additionalVerifyPatterns`)
|
|
13
|
+
* is no longer supported. Configs carrying those fields throw at load time —
|
|
14
|
+
* patterns must move under `browser.*` (or the appropriate runtime under
|
|
15
|
+
* `backend.<runtime>.*`).
|
|
10
16
|
*/
|
|
11
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.DEFAULT_BACKEND_NODE_EVIDENCE_PATHS = exports.DEFAULT_BACKEND_NODE_ALWAYS_REQUIRED = exports.DEFAULT_BROWSER_ALWAYS_REQUIRED = exports.DEFAULT_BROWSER_VERIFY_PATTERNS = exports.RUNTIME_TO_SERVER = exports.BACKEND_SERVERS = void 0;
|
|
12
19
|
exports.loadConfig = loadConfig;
|
|
20
|
+
exports.getActiveCycles = getActiveCycles;
|
|
13
21
|
exports.requiresVerification = requiresVerification;
|
|
22
|
+
exports.getRequiredToolsConfig = getRequiredToolsConfig;
|
|
14
23
|
exports.getMcpServerEntry = getMcpServerEntry;
|
|
24
|
+
exports.getNodeDevToolsMcpEntry = getNodeDevToolsMcpEntry;
|
|
15
25
|
exports.getMaxRetries = getMaxRetries;
|
|
26
|
+
exports.isCollectorConfigured = isCollectorConfigured;
|
|
16
27
|
exports.isJobQueueEnabled = isJobQueueEnabled;
|
|
17
28
|
exports.isRecordingEnabled = isRecordingEnabled;
|
|
29
|
+
exports.getVerificationEnabled = getVerificationEnabled;
|
|
30
|
+
exports.isAnalyticsEnabled = isAnalyticsEnabled;
|
|
31
|
+
exports.isAnalyticsEmitOnStopEnabled = isAnalyticsEmitOnStopEnabled;
|
|
32
|
+
exports.getAnalyticsEmitOnStopMinIntervalSeconds = getAnalyticsEmitOnStopMinIntervalSeconds;
|
|
33
|
+
exports.isAnalyticsTurnEventsEnabled = isAnalyticsTurnEventsEnabled;
|
|
34
|
+
exports.isAnalyticsStepEventsEnabled = isAnalyticsStepEventsEnabled;
|
|
35
|
+
exports.isAnalyticsApiRequestEventsEnabled = isAnalyticsApiRequestEventsEnabled;
|
|
18
36
|
const fs_1 = require("fs");
|
|
19
37
|
const path_1 = require("path");
|
|
20
38
|
const os_1 = require("os");
|
|
21
39
|
const logger_1 = require("./logger");
|
|
22
|
-
|
|
40
|
+
/** Backend MCP servers in the runtime registry. Code change to extend. */
|
|
41
|
+
exports.BACKEND_SERVERS = ["node-devtools"];
|
|
42
|
+
/** Map runtime key (`node`) → backend server name (`node-devtools`). */
|
|
43
|
+
exports.RUNTIME_TO_SERVER = {
|
|
44
|
+
node: "node-devtools",
|
|
45
|
+
};
|
|
46
|
+
/** Browser default verify patterns — preserves the pre-split list as-is. */
|
|
47
|
+
exports.DEFAULT_BROWSER_VERIFY_PATTERNS = [
|
|
23
48
|
"*.ts", "*.tsx",
|
|
24
49
|
"*.js", "*.jsx", "*.mjs", "*.cjs",
|
|
25
50
|
"*.vue", "*.svelte",
|
|
@@ -46,6 +71,36 @@ const DEFAULT_VERIFY_PATTERNS = [
|
|
|
46
71
|
"*.hbs", "*.ejs", "*.pug", "*.jade",
|
|
47
72
|
"*.astro",
|
|
48
73
|
];
|
|
74
|
+
/** Browser-cycle required tools — strict all-of, no alternative paths. */
|
|
75
|
+
exports.DEFAULT_BROWSER_ALWAYS_REQUIRED = [
|
|
76
|
+
"bdt_navigation_go-to",
|
|
77
|
+
"bdt_content_take-screenshot",
|
|
78
|
+
"bdt_a11y_take-aria-snapshot",
|
|
79
|
+
"bdt_o11y_get-console-messages",
|
|
80
|
+
];
|
|
81
|
+
/** Node-cycle required tools — connect always; then probe path or log path. */
|
|
82
|
+
exports.DEFAULT_BACKEND_NODE_ALWAYS_REQUIRED = [
|
|
83
|
+
"ndt_debug_connect",
|
|
84
|
+
];
|
|
85
|
+
exports.DEFAULT_BACKEND_NODE_EVIDENCE_PATHS = [
|
|
86
|
+
{
|
|
87
|
+
name: "probe",
|
|
88
|
+
allOf: [
|
|
89
|
+
{
|
|
90
|
+
anyOf: [
|
|
91
|
+
"ndt_debug_put-tracepoint",
|
|
92
|
+
"ndt_debug_put-logpoint",
|
|
93
|
+
"ndt_debug_put-exceptionpoint",
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
"ndt_debug_get-probe-snapshots",
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "log",
|
|
101
|
+
allOf: ["ndt_debug_get-logs"],
|
|
102
|
+
},
|
|
103
|
+
];
|
|
49
104
|
const DEFAULT_MAX_RETRIES = 3;
|
|
50
105
|
function loadJsonFile(filePath) {
|
|
51
106
|
if (!(0, fs_1.existsSync)(filePath)) {
|
|
@@ -59,116 +114,282 @@ function loadJsonFile(filePath) {
|
|
|
59
114
|
return {};
|
|
60
115
|
}
|
|
61
116
|
}
|
|
117
|
+
/** Detect pre-split flat config. Loud failure per design D6. */
|
|
118
|
+
function assertNoLegacyShape(config, sourcePath) {
|
|
119
|
+
const legacy = [];
|
|
120
|
+
if (Object.prototype.hasOwnProperty.call(config, "verifyPatterns")) {
|
|
121
|
+
legacy.push("'verifyPatterns'");
|
|
122
|
+
}
|
|
123
|
+
if (Object.prototype.hasOwnProperty.call(config, "additionalVerifyPatterns")) {
|
|
124
|
+
legacy.push("'additionalVerifyPatterns'");
|
|
125
|
+
}
|
|
126
|
+
if (legacy.length === 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`Legacy IronBee config detected in ${sourcePath}: ${legacy.join(", ")} at the top level is no longer supported. ` +
|
|
130
|
+
`Move them under 'browser.*' (or the appropriate runtime under 'backend.<runtime>.*').`);
|
|
131
|
+
}
|
|
132
|
+
function assertVerificationShape(config, sourcePath) {
|
|
133
|
+
if (!Object.prototype.hasOwnProperty.call(config, "verification")) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const v = config.verification;
|
|
137
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) {
|
|
138
|
+
throw new Error(`Invalid IronBee config in ${sourcePath}: 'verification' must be an object. ` +
|
|
139
|
+
`Expected shape: { "enable": boolean }.`);
|
|
140
|
+
}
|
|
141
|
+
const block = v;
|
|
142
|
+
if (Object.prototype.hasOwnProperty.call(block, "enable") && typeof block.enable !== "boolean") {
|
|
143
|
+
throw new Error(`Invalid IronBee config in ${sourcePath}: 'verification.enable' must be boolean. ` +
|
|
144
|
+
`Got ${typeof block.enable}.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Deep merge for the nested `browser` / `backend.<runtime>` blocks. */
|
|
148
|
+
function mergeCycleConfig(base, override) {
|
|
149
|
+
if (base === undefined && override === undefined) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
return { ...(base ?? {}), ...(override ?? {}) };
|
|
153
|
+
}
|
|
154
|
+
function mergeBackend(base, override) {
|
|
155
|
+
if (base === undefined && override === undefined) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
const merged = {};
|
|
159
|
+
const keys = new Set([
|
|
160
|
+
...Object.keys(base ?? {}),
|
|
161
|
+
...Object.keys(override ?? {}),
|
|
162
|
+
]);
|
|
163
|
+
for (const key of keys) {
|
|
164
|
+
merged[key] = mergeCycleConfig(base?.[key], override?.[key]);
|
|
165
|
+
}
|
|
166
|
+
return merged;
|
|
167
|
+
}
|
|
62
168
|
function loadConfig(projectDir) {
|
|
63
169
|
const globalPath = (0, path_1.join)((0, os_1.homedir)(), ".ironbee", "config.json");
|
|
64
170
|
const globalConfig = loadJsonFile(globalPath);
|
|
171
|
+
if ((0, fs_1.existsSync)(globalPath)) {
|
|
172
|
+
assertNoLegacyShape(globalConfig, globalPath);
|
|
173
|
+
assertVerificationShape(globalConfig, globalPath);
|
|
174
|
+
}
|
|
65
175
|
let projectConfig = {};
|
|
176
|
+
let projectPath = "";
|
|
66
177
|
if (projectDir) {
|
|
67
|
-
|
|
178
|
+
projectPath = (0, path_1.join)(projectDir, ".ironbee", "config.json");
|
|
68
179
|
projectConfig = loadJsonFile(projectPath);
|
|
180
|
+
if ((0, fs_1.existsSync)(projectPath)) {
|
|
181
|
+
assertNoLegacyShape(projectConfig, projectPath);
|
|
182
|
+
assertVerificationShape(projectConfig, projectPath);
|
|
183
|
+
}
|
|
69
184
|
}
|
|
70
|
-
// merge: defaults < global < project
|
|
71
185
|
const merged = {
|
|
72
186
|
...globalConfig,
|
|
73
187
|
...projectConfig,
|
|
74
188
|
};
|
|
189
|
+
merged.browser = mergeCycleConfig(globalConfig.browser, projectConfig.browser);
|
|
190
|
+
merged.backend = mergeBackend(globalConfig.backend, projectConfig.backend);
|
|
75
191
|
return merged;
|
|
76
192
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
* "*.ts" → matches "foo.ts"
|
|
82
|
-
* "src/components/**" → matches "src/components/Button/index.tsx"
|
|
83
|
-
* "*.test.*" → matches "foo.test.ts"
|
|
84
|
-
*/
|
|
193
|
+
// Glob → RegExp. Supports *, **, ** + slash (zero-or-more segments), ?, and
|
|
194
|
+
// brace expansion {a,b,c} → (a|b|c). The trailing-slash form of ** matches
|
|
195
|
+
// the empty path, so "server/**/*.ts" correctly matches both "server/api.ts"
|
|
196
|
+
// (depth 0) and "server/sub/api.ts" (depth 1+).
|
|
85
197
|
function globToRegExp(pattern) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
198
|
+
// 1. Brace expansion `{a,b,c}` → `(a|b|c)` before any escaping.
|
|
199
|
+
let p = pattern.replace(/\{([^}]+)\}/g, (_match, group) => {
|
|
200
|
+
return `(${group.split(",").map((s) => s.trim()).join("|")})`;
|
|
201
|
+
});
|
|
202
|
+
// 2. Tokenize globs to placeholders so the escape pass leaves them alone.
|
|
203
|
+
p = p.replace(/\*\*\//g, "\x00DSS\x00") // **/
|
|
204
|
+
.replace(/\*\*/g, "\x00DS\x00") // **
|
|
205
|
+
.replace(/\*/g, "\x00SS\x00") // *
|
|
206
|
+
.replace(/\?/g, "\x00QM\x00"); // ?
|
|
207
|
+
// 3. Escape regex specials (parens / pipe stay literal — they came from brace expansion).
|
|
208
|
+
p = p.replace(/[.+^$\\[\]]/g, "\\$&");
|
|
209
|
+
// 4. Restore globs as regex equivalents.
|
|
210
|
+
p = p.replace(/\x00DSS\x00/g, "(?:.*/)?")
|
|
211
|
+
.replace(/\x00DS\x00/g, ".*")
|
|
212
|
+
.replace(/\x00SS\x00/g, "[^/]*")
|
|
213
|
+
.replace(/\x00QM\x00/g, "[^/]");
|
|
214
|
+
return new RegExp(`(^|/)${p}$`);
|
|
100
215
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Tests if a file path matches any of the given glob patterns.
|
|
103
|
-
*/
|
|
104
216
|
function matchesAny(filePath, patterns) {
|
|
105
217
|
for (const pattern of patterns) {
|
|
106
|
-
|
|
107
|
-
if (regex.test(filePath)) {
|
|
218
|
+
if (globToRegExp(pattern).test(filePath)) {
|
|
108
219
|
return true;
|
|
109
220
|
}
|
|
110
221
|
}
|
|
111
222
|
return false;
|
|
112
223
|
}
|
|
224
|
+
/** Returns the effective pattern set for the browser cycle. */
|
|
225
|
+
function getBrowserPatterns(config) {
|
|
226
|
+
const block = config.browser;
|
|
227
|
+
const base = block?.verifyPatterns ?? exports.DEFAULT_BROWSER_VERIFY_PATTERNS;
|
|
228
|
+
const additional = block?.additionalVerifyPatterns ?? [];
|
|
229
|
+
return [...base, ...additional];
|
|
230
|
+
}
|
|
231
|
+
/** Returns the effective pattern set for `backend.<runtime>`. Empty by default. */
|
|
232
|
+
function getBackendRuntimePatterns(config, runtime) {
|
|
233
|
+
const block = config.backend?.[runtime];
|
|
234
|
+
const base = block?.verifyPatterns ?? [];
|
|
235
|
+
const additional = block?.additionalVerifyPatterns ?? [];
|
|
236
|
+
return [...base, ...additional];
|
|
237
|
+
}
|
|
113
238
|
/**
|
|
114
|
-
*
|
|
239
|
+
* Returns the names of cycles whose pattern set matches `filePath`.
|
|
240
|
+
* Used by verify-gate to determine which cycles are active for a Stop hook.
|
|
115
241
|
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* 2. verifyPatterns (+ additionalVerifyPatterns) → if matched, verify (return true)
|
|
119
|
-
* 3. No match → skip (return false)
|
|
242
|
+
* Order: browser first, then each registered backend runtime. `ignoredVerifyPatterns`
|
|
243
|
+
* applies globally — a file matched there activates no cycles.
|
|
120
244
|
*/
|
|
121
|
-
function
|
|
122
|
-
// 1. check ignored patterns first
|
|
245
|
+
function getActiveCycles(filePath, config) {
|
|
123
246
|
const ignored = config.ignoredVerifyPatterns ?? [];
|
|
124
247
|
if (ignored.length > 0 && matchesAny(filePath, ignored)) {
|
|
125
|
-
return
|
|
248
|
+
return [];
|
|
249
|
+
}
|
|
250
|
+
const active = [];
|
|
251
|
+
if (matchesAny(filePath, getBrowserPatterns(config))) {
|
|
252
|
+
active.push("browser");
|
|
126
253
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
254
|
+
for (const server of exports.BACKEND_SERVERS) {
|
|
255
|
+
const runtime = Object.keys(exports.RUNTIME_TO_SERVER).find((k) => exports.RUNTIME_TO_SERVER[k] === server);
|
|
256
|
+
if (runtime === undefined) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const patterns = getBackendRuntimePatterns(config, runtime);
|
|
260
|
+
if (patterns.length > 0 && matchesAny(filePath, patterns)) {
|
|
261
|
+
active.push(runtime);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return active;
|
|
132
265
|
}
|
|
133
|
-
|
|
266
|
+
/**
|
|
267
|
+
* Returns true if a file is under verification by *any* cycle. Used by
|
|
268
|
+
* `clear-verdict` and `require-verdict` hooks where the question is just
|
|
269
|
+
* "should this edit be tracked / gated?", regardless of which cycle.
|
|
270
|
+
*/
|
|
271
|
+
function requiresVerification(filePath, config) {
|
|
272
|
+
return getActiveCycles(filePath, config).length > 0;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Per-cycle resolved required-tools spec. Falls back to defaults at this layer
|
|
276
|
+
* so consumers always get a complete `{ alwaysRequired, evidencePaths }` shape.
|
|
277
|
+
*
|
|
278
|
+
* Validity rule: at least one of `alwaysRequired` or `evidencePaths` must be
|
|
279
|
+
* non-empty. Both empty → config error (caught here, surfaced to caller).
|
|
280
|
+
*/
|
|
281
|
+
function getRequiredToolsConfig(config, cycle) {
|
|
282
|
+
let alwaysRequired;
|
|
283
|
+
let evidencePaths;
|
|
284
|
+
if (cycle === "browser") {
|
|
285
|
+
alwaysRequired = config.browser?.alwaysRequired ?? exports.DEFAULT_BROWSER_ALWAYS_REQUIRED;
|
|
286
|
+
evidencePaths = config.browser?.evidencePaths ?? [];
|
|
287
|
+
}
|
|
288
|
+
else if (cycle === "node") {
|
|
289
|
+
alwaysRequired = config.backend?.node?.alwaysRequired ?? exports.DEFAULT_BACKEND_NODE_ALWAYS_REQUIRED;
|
|
290
|
+
evidencePaths = config.backend?.node?.evidencePaths ?? exports.DEFAULT_BACKEND_NODE_EVIDENCE_PATHS;
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
const block = config.backend?.[cycle];
|
|
294
|
+
alwaysRequired = block?.alwaysRequired ?? [];
|
|
295
|
+
evidencePaths = block?.evidencePaths ?? [];
|
|
296
|
+
}
|
|
297
|
+
if (alwaysRequired.length === 0 && evidencePaths.length === 0) {
|
|
298
|
+
throw new Error(`Invalid required-tools config for cycle '${cycle}': both 'alwaysRequired' and 'evidencePaths' are empty. ` +
|
|
299
|
+
`At least one must specify required tools.`);
|
|
300
|
+
}
|
|
301
|
+
return { alwaysRequired, evidencePaths };
|
|
302
|
+
}
|
|
303
|
+
const DEFAULT_MCP_COMMAND = "npx";
|
|
304
|
+
const DEFAULT_MCP_ARGS = ["-y", "browser-devtools-mcp"];
|
|
305
|
+
const BROWSER_IRONBEE_ENV = {
|
|
134
306
|
TOOL_NAME_PREFIX: "bdt_",
|
|
135
307
|
TOOL_INPUT_METADATA_ENABLE: "true",
|
|
136
308
|
};
|
|
137
|
-
const
|
|
309
|
+
const NODE_IRONBEE_ENV = {
|
|
310
|
+
PLATFORM: "node",
|
|
311
|
+
TOOL_NAME_PREFIX: "ndt_",
|
|
312
|
+
TOOL_INPUT_METADATA_ENABLE: "true",
|
|
313
|
+
};
|
|
314
|
+
const BROWSER_DEFAULT_MCP_ENV = {
|
|
138
315
|
BROWSER_DEVTOOLS_INSTALL_CHROMIUM: "true",
|
|
139
316
|
};
|
|
140
|
-
const
|
|
141
|
-
const DEFAULT_MCP_ARGS = ["-y", "browser-devtools-mcp"];
|
|
317
|
+
const NODE_DEFAULT_MCP_ENV = {};
|
|
142
318
|
/**
|
|
143
|
-
*
|
|
319
|
+
* Auto-derive OTEL exporter env for the devtools MCP server when the
|
|
320
|
+
* IronBee Collector is configured + enabled. Returns `{}` when the
|
|
321
|
+
* collector is absent / disabled / missing a URL — in that case the MCP
|
|
322
|
+
* server runs without telemetry, same as before.
|
|
144
323
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* - `browserDevTools.env` — env vars for the MCP server (used only when mcp is not provided)
|
|
324
|
+
* Precedence in the final env block (lowest → highest):
|
|
325
|
+
* default static env < auto-injected OTEL env < user override env < ironbee env
|
|
148
326
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
327
|
+
* So operators can still override individual keys via `browserDevTools.env`
|
|
328
|
+
* (e.g. point OTEL at a separate observability endpoint), or fully opt out
|
|
329
|
+
* by setting `OTEL_ENABLE: "false"` in their override.
|
|
152
330
|
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
331
|
+
* `runtime` toggles browser-only vars (USER_INTERACTION_EVENTS,
|
|
332
|
+
* BROWSER_HEADLESS_ENABLE) — node-devtools doesn't honor those.
|
|
155
333
|
*/
|
|
156
|
-
function
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
334
|
+
function buildOtelEnv(config, runtime) {
|
|
335
|
+
if (!isCollectorConfigured(config)) {
|
|
336
|
+
return {};
|
|
337
|
+
}
|
|
338
|
+
// Cast: `isCollectorConfigured` already guaranteed url + apiKey are
|
|
339
|
+
// non-empty strings.
|
|
340
|
+
const section = config.collector;
|
|
341
|
+
const env = {
|
|
342
|
+
OTEL_ENABLE: "true",
|
|
343
|
+
OTEL_EXPORTER_HTTP_URL: section.url,
|
|
344
|
+
OTEL_EXPORTER_HTTP_HEADERS: `X-API-Key=${section.apiKey}`,
|
|
345
|
+
OTEL_EXPORTER_TYPE: "otlp/http-protobuf",
|
|
346
|
+
};
|
|
347
|
+
if (runtime === "browser") {
|
|
348
|
+
env.OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS = "change,input,click";
|
|
349
|
+
env.BROWSER_HEADLESS_ENABLE = "true";
|
|
350
|
+
}
|
|
351
|
+
return env;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Builds an MCP server entry for the given runtime ("browser" or "node").
|
|
355
|
+
*
|
|
356
|
+
* Reads override config from `config.<runtime>DevTools`:
|
|
357
|
+
* - `<...>.mcp` — full MCP config (used as-is + ironbee env always wins)
|
|
358
|
+
* - `<...>.env` — env vars merged into the default (npx -y) config
|
|
359
|
+
*
|
|
360
|
+
* Env precedence (lowest → highest):
|
|
361
|
+
* 1. Static `defaultEnv` (e.g. `BROWSER_DEVTOOLS_INSTALL_CHROMIUM`)
|
|
362
|
+
* 2. Auto-injected OTEL exporter env (when `collector` is configured + enabled)
|
|
363
|
+
* 3. User override env from `<runtime>DevTools.env`
|
|
364
|
+
* 4. IronBee invariant env (`TOOL_NAME_PREFIX`, `TOOL_INPUT_METADATA_ENABLE`, `PLATFORM`)
|
|
365
|
+
*
|
|
366
|
+
* Operators can override individual OTEL vars or opt out entirely
|
|
367
|
+
* (`<runtime>DevTools.env.OTEL_ENABLE: "false"`). IronBee env always wins
|
|
368
|
+
* so the wire contract (tool-name prefix, metadata-injection toggle) cannot
|
|
369
|
+
* be broken from outside.
|
|
370
|
+
*/
|
|
371
|
+
function buildMcpEntry(config, overrideKey, ironbeeEnv, defaultEnv, runtime) {
|
|
372
|
+
const otelEnv = buildOtelEnv(config, runtime);
|
|
373
|
+
const override = config[overrideKey];
|
|
374
|
+
if (override && typeof override === "object" && !Array.isArray(override)) {
|
|
375
|
+
const block = override;
|
|
376
|
+
if (block.mcp && typeof block.mcp === "object" && !Array.isArray(block.mcp)) {
|
|
377
|
+
// Full-replacement MCP override. We still inject OTEL into the
|
|
378
|
+
// env (auto-derived from collector config) and let ironbee env
|
|
379
|
+
// win last. Operator's own `mcp.env` keys take precedence over
|
|
380
|
+
// OTEL but lose to ironbee env.
|
|
381
|
+
const mcp = { ...block.mcp };
|
|
382
|
+
const mcpEnv = {
|
|
383
|
+
...otelEnv,
|
|
384
|
+
...(mcp.env ?? {}),
|
|
385
|
+
...ironbeeEnv,
|
|
386
|
+
};
|
|
165
387
|
mcp.env = mcpEnv;
|
|
166
388
|
return mcp;
|
|
167
389
|
}
|
|
168
|
-
// no mcp provided — build default with browserDevTools.env merged
|
|
169
390
|
const userEnv = {};
|
|
170
|
-
if (
|
|
171
|
-
const envObj =
|
|
391
|
+
if (block.env && typeof block.env === "object" && !Array.isArray(block.env)) {
|
|
392
|
+
const envObj = block.env;
|
|
172
393
|
for (const key of Object.keys(envObj)) {
|
|
173
394
|
if (typeof envObj[key] === "string") {
|
|
174
395
|
userEnv[key] = envObj[key];
|
|
@@ -178,57 +399,229 @@ function getMcpServerEntry(projectDir) {
|
|
|
178
399
|
return {
|
|
179
400
|
command: DEFAULT_MCP_COMMAND,
|
|
180
401
|
args: [...DEFAULT_MCP_ARGS],
|
|
181
|
-
env: { ...
|
|
402
|
+
env: { ...defaultEnv, ...otelEnv, ...userEnv, ...ironbeeEnv },
|
|
182
403
|
};
|
|
183
404
|
}
|
|
184
|
-
// no browserDevTools config — full defaults
|
|
185
405
|
return {
|
|
186
406
|
command: DEFAULT_MCP_COMMAND,
|
|
187
407
|
args: [...DEFAULT_MCP_ARGS],
|
|
188
|
-
env: { ...
|
|
408
|
+
env: { ...defaultEnv, ...otelEnv, ...ironbeeEnv },
|
|
189
409
|
};
|
|
190
410
|
}
|
|
411
|
+
/** Returns the MCP server entry for `browser-devtools` (PLATFORM=browser, bdt_). */
|
|
412
|
+
function getMcpServerEntry(projectDir) {
|
|
413
|
+
const config = loadConfig(projectDir);
|
|
414
|
+
return buildMcpEntry(config, "browserDevTools", BROWSER_IRONBEE_ENV, BROWSER_DEFAULT_MCP_ENV, "browser");
|
|
415
|
+
}
|
|
416
|
+
/** Returns the MCP server entry for `node-devtools` (PLATFORM=node, ndt_). */
|
|
417
|
+
function getNodeDevToolsMcpEntry(projectDir) {
|
|
418
|
+
const config = loadConfig(projectDir);
|
|
419
|
+
return buildMcpEntry(config, "nodeDevTools", NODE_IRONBEE_ENV, NODE_DEFAULT_MCP_ENV, "node");
|
|
420
|
+
}
|
|
191
421
|
function getMaxRetries(config) {
|
|
192
422
|
return (typeof config.maxRetries === "number" && config.maxRetries > 0)
|
|
193
423
|
? config.maxRetries
|
|
194
424
|
: DEFAULT_MAX_RETRIES;
|
|
195
425
|
}
|
|
196
426
|
/**
|
|
197
|
-
* Returns true when the
|
|
427
|
+
* Returns true when the IronBee Collector is configured + active for this
|
|
428
|
+
* config — i.e. the collector section is present, `enable !== false`, the
|
|
429
|
+
* `url` is non-empty, and the `IRONBEE_COLLECTOR=false` env override isn't
|
|
430
|
+
* set. Pure check over an already-loaded `IronBeeConfig` so callers that
|
|
431
|
+
* have a config in hand don't pay an extra `loadConfig` round-trip.
|
|
198
432
|
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
433
|
+
* Used by the auto-enable behavior in `isJobQueueEnabled` /
|
|
434
|
+
* `isRecordingEnabled` / `isAnalyticsEnabled`: when the operator has
|
|
435
|
+
* configured a collector, we treat all three feature switches as
|
|
436
|
+
* implicitly opted in. Rationale: setting up a collector is a strong
|
|
437
|
+
* signal that the operator wants events to flow there, and these three
|
|
438
|
+
* sections are exactly what makes events flow (queue dispatch, recording
|
|
439
|
+
* enforcement, analytics derivation). Explicit `enable: false` on any of
|
|
440
|
+
* them still wins — the auto-enable only fires for "section absent".
|
|
441
|
+
*/
|
|
442
|
+
function isCollectorConfigured(config) {
|
|
443
|
+
if (process.env.IRONBEE_COLLECTOR === "false") {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
const section = config.collector;
|
|
447
|
+
if (!section) {
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
if (section.enable === false) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
if (typeof section.url !== "string" || section.url.length === 0) {
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
// apiKey is required — a collector running without auth is a developer
|
|
457
|
+
// convenience that ironbee no longer supports as the "configured" state.
|
|
458
|
+
// Production deployments always have an api key; for local testing,
|
|
459
|
+
// operators can either set a placeholder key or use IRONBEE_COLLECTOR=false
|
|
460
|
+
// to fully disable.
|
|
461
|
+
if (typeof section.apiKey !== "string" || section.apiKey.length === 0) {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Returns true when the job queue layer is enabled for this project.
|
|
204
468
|
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
469
|
+
* Resolution:
|
|
470
|
+
* 1. Section explicitly disabled (`enable: false`) → `false`.
|
|
471
|
+
* 2. Section present (any other shape) → `true` (presence-as-opt-in).
|
|
472
|
+
* 3. Collector configured + valid → `true` (auto-enable: a collector is
|
|
473
|
+
* pointless without a queue feeding it tool_call events).
|
|
474
|
+
* 4. Otherwise → `false`.
|
|
207
475
|
*/
|
|
208
476
|
function isJobQueueEnabled(projectDir) {
|
|
209
477
|
const config = loadConfig(projectDir);
|
|
210
|
-
return
|
|
478
|
+
return isFeatureEnabledWithCollectorAutoEnable(config, config.jobQueue);
|
|
211
479
|
}
|
|
212
480
|
/**
|
|
213
481
|
* Returns true when recording enforcement is enabled for this project.
|
|
214
|
-
* Same presence-as-opt-in
|
|
215
|
-
*
|
|
216
|
-
* `enable: false` explicitly to suspend without removing the section.
|
|
482
|
+
* Same resolution as `isJobQueueEnabled` (presence-as-opt-in + collector
|
|
483
|
+
* auto-enable + explicit-disable wins).
|
|
217
484
|
*/
|
|
218
485
|
function isRecordingEnabled(projectDir) {
|
|
219
486
|
const config = loadConfig(projectDir);
|
|
220
|
-
return
|
|
487
|
+
return isFeatureEnabledWithCollectorAutoEnable(config, config.recording);
|
|
221
488
|
}
|
|
222
489
|
/**
|
|
223
|
-
* Shared
|
|
224
|
-
*
|
|
225
|
-
* `
|
|
226
|
-
* (
|
|
490
|
+
* Shared resolution for sections that follow the "presence-as-opt-in +
|
|
491
|
+
* auto-enable when collector is configured" pattern. `jobQueue`, `recording`,
|
|
492
|
+
* `analytics` all use this. `collector` itself uses `isCollectorConfigured`
|
|
493
|
+
* directly (it's the one that drives the auto-enable, not subject to it).
|
|
227
494
|
*/
|
|
495
|
+
function isFeatureEnabledWithCollectorAutoEnable(config, section) {
|
|
496
|
+
// Explicit opt-out always wins, regardless of collector config.
|
|
497
|
+
if (section !== undefined && section !== null && typeof section === "object" && !Array.isArray(section)) {
|
|
498
|
+
if (section.enable === false) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
// Presence (with non-false `enable`) opts in.
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
// Section absent → fall back to collector-driven auto-enable.
|
|
505
|
+
return isCollectorConfigured(config);
|
|
506
|
+
}
|
|
228
507
|
function isPresenceEnabled(section) {
|
|
229
508
|
if (section === undefined || section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
230
509
|
return false;
|
|
231
510
|
}
|
|
232
511
|
return section.enable !== false;
|
|
233
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* Returns true when verification enforcement is enabled for this config.
|
|
515
|
+
*
|
|
516
|
+
* **Inverse semantics from `isJobQueueEnabled` / `isRecordingEnabled`**:
|
|
517
|
+
* verification is the core feature, opt-out by `enable: false`. Section absent,
|
|
518
|
+
* empty section, or `enable: true` all return true. Only `enable: false`
|
|
519
|
+
* returns false.
|
|
520
|
+
*/
|
|
521
|
+
function getVerificationEnabled(config) {
|
|
522
|
+
const section = config.verification;
|
|
523
|
+
if (section === undefined || section === null) {
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
if (typeof section !== "object" || Array.isArray(section)) {
|
|
527
|
+
return true;
|
|
528
|
+
}
|
|
529
|
+
return section.enable !== false;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Returns true when analytics collection is enabled for this project.
|
|
533
|
+
* Same resolution as `isJobQueueEnabled` / `isRecordingEnabled`:
|
|
534
|
+
* explicit-disable wins, presence opts in, and collector configured +
|
|
535
|
+
* section absent auto-enables.
|
|
536
|
+
*/
|
|
537
|
+
function isAnalyticsEnabled(projectDir) {
|
|
538
|
+
const config = loadConfig(projectDir);
|
|
539
|
+
return isFeatureEnabledWithCollectorAutoEnable(config, config.analytics);
|
|
540
|
+
}
|
|
541
|
+
/** Whether the Stop hook should project + emit analytics. Default `true` when analytics is enabled. */
|
|
542
|
+
function isAnalyticsEmitOnStopEnabled(projectDir) {
|
|
543
|
+
const config = loadConfig(projectDir);
|
|
544
|
+
const section = config.analytics;
|
|
545
|
+
if (section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
const v = section.emitOnStop;
|
|
549
|
+
return v !== false;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Throttle interval (seconds) for Stop-hook projection. Default 0 (disabled).
|
|
553
|
+
*
|
|
554
|
+
* The CLI used to default to 30s here as a "don't hammer the backend on
|
|
555
|
+
* hot Stop loops" guard. That was a CLI-side judgment about cadence — backends
|
|
556
|
+
* can rate-limit / dedupe / aggregate however they want, and a 30s default
|
|
557
|
+
* silently dropped per-Stop visibility (especially painful for verify-gate
|
|
558
|
+
* retry loops where each Stop carries fresh signal). Default is now 0;
|
|
559
|
+
* operators who DO want CLI-side throttling can set the config explicitly.
|
|
560
|
+
* `throttleState` in `hook-trigger.ts` returns null when interval ≤ 0, so
|
|
561
|
+
* 0 = no-op fast path.
|
|
562
|
+
*/
|
|
563
|
+
function getAnalyticsEmitOnStopMinIntervalSeconds(projectDir) {
|
|
564
|
+
const config = loadConfig(projectDir);
|
|
565
|
+
const section = config.analytics;
|
|
566
|
+
if (section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
567
|
+
return 0;
|
|
568
|
+
}
|
|
569
|
+
const v = section.emitOnStopMinIntervalSeconds;
|
|
570
|
+
return typeof v === "number" && v >= 0 ? v : 0;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Returns true when the per-turn `session_turn_analytics` wire records should
|
|
574
|
+
* be emitted alongside `session_analytics`. **Default `false` (opt-in)** —
|
|
575
|
+
* inverse of the `analytics` master switch's presence-as-opt-in.
|
|
576
|
+
*
|
|
577
|
+
* Rationale: turn-grain records are high-volume secondary signal; backends
|
|
578
|
+
* that only want session aggregates shouldn't pay for them by default. The
|
|
579
|
+
* base `session_analytics` record always ships when analytics is enabled.
|
|
580
|
+
*/
|
|
581
|
+
function isAnalyticsTurnEventsEnabled(projectDir) {
|
|
582
|
+
const config = loadConfig(projectDir);
|
|
583
|
+
const section = config.analytics;
|
|
584
|
+
if (section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
587
|
+
return section.emitTurnEvents === true;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Returns true when the per-step `session_turn_step_analytics` wire records
|
|
591
|
+
* should be emitted. **Default `false` (opt-in)** — same rationale as
|
|
592
|
+
* {@link isAnalyticsTurnEventsEnabled}, with one extra dimension: step-grain
|
|
593
|
+
* records are an order of magnitude higher volume than turn-grain.
|
|
594
|
+
*
|
|
595
|
+
* Independent of `emitTurnEvents`. Backend can reconstruct turn from steps,
|
|
596
|
+
* so step-only / turn-only / both / neither are all valid combinations.
|
|
597
|
+
*/
|
|
598
|
+
function isAnalyticsStepEventsEnabled(projectDir) {
|
|
599
|
+
const config = loadConfig(projectDir);
|
|
600
|
+
const section = config.analytics;
|
|
601
|
+
if (section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
return section.emitStepEvents === true;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Returns true when the per-API-request `api_request` wire records should be
|
|
608
|
+
* emitted. **Default `true` (opt-out)** — INVERSE of the turn / step event
|
|
609
|
+
* gating, mirroring the `verification.enable` opt-out semantics. Per-request
|
|
610
|
+
* audit (cost attribution, failure tracking, request-id timeline) is the
|
|
611
|
+
* primary value of the analytics pipeline for backend cost accounting, so
|
|
612
|
+
* it ships by default. Operators can opt out via `emitApiRequestEvents: false`
|
|
613
|
+
* if backend doesn't consume them.
|
|
614
|
+
*
|
|
615
|
+
* Independent of `emitTurnEvents` / `emitStepEvents`. The `analytics` master
|
|
616
|
+
* switch (section presence) still gates everything below it — without
|
|
617
|
+
* `analytics` in config, no api_request events ship regardless of this flag.
|
|
618
|
+
*/
|
|
619
|
+
function isAnalyticsApiRequestEventsEnabled(projectDir) {
|
|
620
|
+
const config = loadConfig(projectDir);
|
|
621
|
+
const section = config.analytics;
|
|
622
|
+
if (section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
return section.emitApiRequestEvents !== false;
|
|
626
|
+
}
|
|
234
627
|
//# sourceMappingURL=config.js.map
|