@ironbee-ai/cli 0.15.0 → 0.17.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 +8 -0
- package/dist/analytics/{emit.d.ts → claude/emit.d.ts} +1 -1
- package/dist/analytics/claude/emit.d.ts.map +1 -0
- package/dist/analytics/{emit.js → claude/emit.js} +34 -7
- package/dist/analytics/claude/emit.js.map +1 -0
- package/dist/analytics/{hook-trigger.d.ts → claude/hook-trigger.d.ts} +1 -1
- package/dist/analytics/claude/hook-trigger.d.ts.map +1 -0
- package/dist/analytics/{hook-trigger.js → claude/hook-trigger.js} +2 -2
- package/dist/analytics/claude/hook-trigger.js.map +1 -0
- package/dist/analytics/claude/log.d.ts.map +1 -0
- package/dist/analytics/{log.js → claude/log.js} +1 -1
- package/dist/analytics/claude/log.js.map +1 -0
- package/dist/analytics/{merge.d.ts → claude/merge.d.ts} +2 -1
- package/dist/analytics/claude/merge.d.ts.map +1 -0
- package/dist/analytics/{merge.js → claude/merge.js} +13 -1
- package/dist/analytics/claude/merge.js.map +1 -0
- package/dist/analytics/{pricing.d.ts → claude/pricing.d.ts} +1 -13
- package/dist/analytics/claude/pricing.d.ts.map +1 -0
- package/dist/analytics/{pricing.js → claude/pricing.js} +6 -14
- package/dist/analytics/claude/pricing.js.map +1 -0
- package/dist/analytics/{projection.d.ts → claude/projection.d.ts} +31 -7
- package/dist/analytics/claude/projection.d.ts.map +1 -0
- package/dist/analytics/{projection.js → claude/projection.js} +631 -327
- package/dist/analytics/claude/projection.js.map +1 -0
- package/dist/analytics/{spawn.d.ts → claude/spawn.d.ts} +4 -4
- package/dist/analytics/claude/spawn.d.ts.map +1 -0
- package/dist/analytics/{spawn.js → claude/spawn.js} +4 -3
- package/dist/analytics/claude/spawn.js.map +1 -0
- package/dist/analytics/{state.d.ts → claude/state.d.ts} +1 -1
- package/dist/analytics/claude/state.d.ts.map +1 -0
- package/dist/analytics/{state.js → claude/state.js} +2 -2
- package/dist/analytics/claude/state.js.map +1 -0
- package/dist/analytics/claude/transcript.d.ts.map +1 -0
- package/dist/analytics/{transcript.js → claude/transcript.js} +1 -1
- package/dist/analytics/claude/transcript.js.map +1 -0
- package/dist/analytics/codex/api-request.d.ts +108 -0
- package/dist/analytics/codex/api-request.d.ts.map +1 -0
- package/dist/analytics/codex/api-request.js +155 -0
- package/dist/analytics/codex/api-request.js.map +1 -0
- package/dist/analytics/codex/apply-patch.d.ts +21 -0
- package/dist/analytics/codex/apply-patch.d.ts.map +1 -0
- package/dist/analytics/codex/apply-patch.js +49 -0
- package/dist/analytics/codex/apply-patch.js.map +1 -0
- package/dist/analytics/codex/classifier.d.ts +28 -0
- package/dist/analytics/codex/classifier.d.ts.map +1 -0
- package/dist/analytics/codex/classifier.js +111 -0
- package/dist/analytics/codex/classifier.js.map +1 -0
- package/dist/analytics/codex/emit.d.ts +47 -0
- package/dist/analytics/codex/emit.d.ts.map +1 -0
- package/dist/analytics/codex/emit.js +158 -0
- package/dist/analytics/codex/emit.js.map +1 -0
- package/dist/analytics/codex/events-emit.d.ts +62 -0
- package/dist/analytics/codex/events-emit.d.ts.map +1 -0
- package/dist/analytics/codex/events-emit.js +555 -0
- package/dist/analytics/codex/events-emit.js.map +1 -0
- package/dist/analytics/codex/pricing.d.ts +57 -0
- package/dist/analytics/codex/pricing.d.ts.map +1 -0
- package/dist/analytics/codex/pricing.js +125 -0
- package/dist/analytics/codex/pricing.js.map +1 -0
- package/dist/analytics/codex/projection.d.ts +51 -0
- package/dist/analytics/codex/projection.d.ts.map +1 -0
- package/dist/analytics/codex/projection.js +1477 -0
- package/dist/analytics/codex/projection.js.map +1 -0
- package/dist/analytics/codex/spawn.d.ts +27 -0
- package/dist/analytics/codex/spawn.d.ts.map +1 -0
- package/dist/analytics/codex/spawn.js +64 -0
- package/dist/analytics/codex/spawn.js.map +1 -0
- package/dist/analytics/codex/status-snapshot.d.ts +80 -0
- package/dist/analytics/codex/status-snapshot.d.ts.map +1 -0
- package/dist/analytics/codex/status-snapshot.js +206 -0
- package/dist/analytics/codex/status-snapshot.js.map +1 -0
- package/dist/analytics/codex/transcript.d.ts +51 -0
- package/dist/analytics/codex/transcript.d.ts.map +1 -0
- package/dist/analytics/codex/transcript.js +134 -0
- package/dist/analytics/codex/transcript.js.map +1 -0
- package/dist/analytics/codex/types.d.ts +253 -0
- package/dist/analytics/codex/types.d.ts.map +1 -0
- package/dist/analytics/codex/types.js +29 -0
- package/dist/analytics/codex/types.js.map +1 -0
- package/dist/analytics/shared/classifier.d.ts.map +1 -0
- package/dist/analytics/{classifier.js → shared/classifier.js} +9 -0
- package/dist/analytics/shared/classifier.js.map +1 -0
- package/dist/analytics/shared/errors.d.ts.map +1 -0
- package/dist/analytics/shared/errors.js.map +1 -0
- package/dist/analytics/shared/tokens.d.ts +14 -0
- package/dist/analytics/shared/tokens.d.ts.map +1 -0
- package/dist/analytics/shared/tokens.js +17 -0
- package/dist/analytics/shared/tokens.js.map +1 -0
- package/dist/analytics/{types.d.ts → shared/types.d.ts} +42 -9
- package/dist/analytics/shared/types.d.ts.map +1 -0
- package/dist/analytics/shared/types.js.map +1 -0
- package/dist/clients/base.d.ts +26 -4
- package/dist/clients/base.d.ts.map +1 -1
- package/dist/clients/claude/hooks/activity-end.js +1 -1
- package/dist/clients/claude/hooks/activity-end.js.map +1 -1
- package/dist/clients/claude/hooks/activity-start.js +1 -1
- package/dist/clients/claude/hooks/activity-start.js.map +1 -1
- package/dist/clients/claude/hooks/clear-verdict.d.ts.map +1 -1
- package/dist/clients/claude/hooks/clear-verdict.js +20 -1
- package/dist/clients/claude/hooks/clear-verdict.js.map +1 -1
- package/dist/clients/claude/hooks/require-verdict.d.ts +8 -1
- package/dist/clients/claude/hooks/require-verdict.d.ts.map +1 -1
- package/dist/clients/claude/hooks/require-verdict.js +9 -2
- package/dist/clients/claude/hooks/require-verdict.js.map +1 -1
- package/dist/clients/claude/hooks/require-verification.d.ts +10 -1
- package/dist/clients/claude/hooks/require-verification.d.ts.map +1 -1
- package/dist/clients/claude/hooks/require-verification.js +34 -6
- 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 +7 -1
- 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 +7 -1
- package/dist/clients/claude/hooks/session-start.js.map +1 -1
- package/dist/clients/claude/hooks/session-status.d.ts.map +1 -1
- package/dist/clients/claude/hooks/session-status.js +13 -9
- package/dist/clients/claude/hooks/session-status.js.map +1 -1
- package/dist/clients/claude/hooks/track-action.d.ts.map +1 -1
- package/dist/clients/claude/hooks/track-action.js +26 -1
- 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 +8 -1
- package/dist/clients/claude/hooks/verify-gate.js.map +1 -1
- package/dist/clients/claude/index.d.ts +7 -2
- package/dist/clients/claude/index.d.ts.map +1 -1
- package/dist/clients/claude/index.js +72 -32
- package/dist/clients/claude/index.js.map +1 -1
- package/dist/clients/claude/util.d.ts.map +1 -1
- package/dist/clients/claude/util.js +55 -0
- package/dist/clients/claude/util.js.map +1 -1
- package/dist/clients/codex/commands/ironbee-verify/SKILL.md +58 -0
- package/dist/clients/codex/hooks/activity-end.d.ts +9 -0
- package/dist/clients/codex/hooks/activity-end.d.ts.map +1 -0
- package/dist/clients/codex/hooks/activity-end.js +65 -0
- package/dist/clients/codex/hooks/activity-end.js.map +1 -0
- package/dist/clients/codex/hooks/activity-start.d.ts +17 -0
- package/dist/clients/codex/hooks/activity-start.d.ts.map +1 -0
- package/dist/clients/codex/hooks/activity-start.js +38 -0
- package/dist/clients/codex/hooks/activity-start.js.map +1 -0
- package/dist/clients/codex/hooks/clear-verdict.d.ts +55 -0
- package/dist/clients/codex/hooks/clear-verdict.d.ts.map +1 -0
- package/dist/clients/codex/hooks/clear-verdict.js +303 -0
- package/dist/clients/codex/hooks/clear-verdict.js.map +1 -0
- package/dist/clients/codex/hooks/require-verdict.d.ts +36 -0
- package/dist/clients/codex/hooks/require-verdict.d.ts.map +1 -0
- package/dist/clients/codex/hooks/require-verdict.js +115 -0
- package/dist/clients/codex/hooks/require-verdict.js.map +1 -0
- package/dist/clients/codex/hooks/require-verification.d.ts +20 -0
- package/dist/clients/codex/hooks/require-verification.d.ts.map +1 -0
- package/dist/clients/codex/hooks/require-verification.js +156 -0
- package/dist/clients/codex/hooks/require-verification.js.map +1 -0
- package/dist/clients/codex/hooks/session-start.d.ts +10 -0
- package/dist/clients/codex/hooks/session-start.d.ts.map +1 -0
- package/dist/clients/codex/hooks/session-start.js +94 -0
- package/dist/clients/codex/hooks/session-start.js.map +1 -0
- package/dist/clients/codex/hooks/track-action-monitor.d.ts +10 -0
- package/dist/clients/codex/hooks/track-action-monitor.d.ts.map +1 -0
- package/dist/clients/codex/hooks/track-action-monitor.js +168 -0
- package/dist/clients/codex/hooks/track-action-monitor.js.map +1 -0
- package/dist/clients/codex/hooks/track-action-pre.d.ts +18 -0
- package/dist/clients/codex/hooks/track-action-pre.d.ts.map +1 -0
- package/dist/clients/codex/hooks/track-action-pre.js +35 -0
- package/dist/clients/codex/hooks/track-action-pre.js.map +1 -0
- package/dist/clients/codex/hooks/track-action.d.ts +22 -0
- package/dist/clients/codex/hooks/track-action.d.ts.map +1 -0
- package/dist/clients/codex/hooks/track-action.js +350 -0
- package/dist/clients/codex/hooks/track-action.js.map +1 -0
- package/dist/clients/codex/hooks/verify-gate.d.ts +15 -0
- package/dist/clients/codex/hooks/verify-gate.d.ts.map +1 -0
- package/dist/clients/codex/hooks/verify-gate.js +105 -0
- package/dist/clients/codex/hooks/verify-gate.js.map +1 -0
- package/dist/clients/codex/index.d.ts +52 -0
- package/dist/clients/codex/index.d.ts.map +1 -0
- package/dist/clients/codex/index.js +463 -0
- package/dist/clients/codex/index.js.map +1 -0
- package/dist/clients/codex/platforms/command-verify.backend.md +108 -0
- package/dist/clients/codex/platforms/command-verify.browser.md +108 -0
- package/dist/clients/codex/platforms/command-verify.node.md +61 -0
- package/dist/clients/codex/platforms/rule.backend.md +32 -0
- package/dist/clients/codex/platforms/rule.browser.md +17 -0
- package/dist/clients/codex/platforms/rule.node.md +28 -0
- package/dist/clients/codex/platforms/skill.backend.md +95 -0
- package/dist/clients/codex/platforms/skill.browser.md +28 -0
- package/dist/clients/codex/platforms/skill.node.md +62 -0
- package/dist/clients/codex/rules/ironbee-verification.md +48 -0
- package/dist/clients/codex/skills/ironbee-verification.md +80 -0
- package/dist/clients/codex/util.d.ts +193 -0
- package/dist/clients/codex/util.d.ts.map +1 -0
- package/dist/clients/codex/util.js +784 -0
- package/dist/clients/codex/util.js.map +1 -0
- package/dist/clients/cursor/hooks/activity-end.js +1 -1
- package/dist/clients/cursor/hooks/activity-end.js.map +1 -1
- package/dist/clients/cursor/hooks/clear-verdict.d.ts +5 -2
- package/dist/clients/cursor/hooks/clear-verdict.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/clear-verdict.js +16 -4
- package/dist/clients/cursor/hooks/clear-verdict.js.map +1 -1
- package/dist/clients/cursor/hooks/require-verdict.d.ts +7 -1
- package/dist/clients/cursor/hooks/require-verdict.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/require-verdict.js +8 -2
- package/dist/clients/cursor/hooks/require-verdict.js.map +1 -1
- package/dist/clients/cursor/hooks/require-verification.d.ts +8 -1
- package/dist/clients/cursor/hooks/require-verification.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/require-verification.js +27 -6
- package/dist/clients/cursor/hooks/require-verification.js.map +1 -1
- package/dist/clients/cursor/hooks/session-end.js +1 -1
- package/dist/clients/cursor/hooks/session-end.js.map +1 -1
- package/dist/clients/cursor/hooks/verify-gate.d.ts.map +1 -1
- package/dist/clients/cursor/hooks/verify-gate.js +6 -1
- package/dist/clients/cursor/hooks/verify-gate.js.map +1 -1
- package/dist/clients/cursor/index.d.ts +7 -2
- package/dist/clients/cursor/index.d.ts.map +1 -1
- package/dist/clients/cursor/index.js +69 -30
- package/dist/clients/cursor/index.js.map +1 -1
- package/dist/clients/registry.d.ts.map +1 -1
- package/dist/clients/registry.js +2 -1
- package/dist/clients/registry.js.map +1 -1
- package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
- package/dist/commands/claude/index.d.ts.map +1 -0
- package/dist/commands/{claude.js → claude/index.js} +12 -6
- package/dist/commands/claude/index.js.map +1 -0
- package/dist/commands/{otel.d.ts → claude/otel.d.ts} +5 -1
- package/dist/commands/claude/otel.d.ts.map +1 -0
- package/dist/commands/{otel.js → claude/otel.js} +9 -5
- package/dist/commands/claude/otel.js.map +1 -0
- package/dist/commands/claude/process-analytics.d.ts +19 -0
- package/dist/commands/claude/process-analytics.d.ts.map +1 -0
- package/dist/commands/{process-analytics.js → claude/process-analytics.js} +16 -15
- package/dist/commands/claude/process-analytics.js.map +1 -0
- package/dist/commands/{statusline-toggle.d.ts → claude/statusline-toggle.d.ts} +2 -2
- package/dist/commands/claude/statusline-toggle.d.ts.map +1 -0
- package/dist/commands/{statusline-toggle.js → claude/statusline-toggle.js} +8 -8
- package/dist/commands/claude/statusline-toggle.js.map +1 -0
- package/dist/commands/{statusline.d.ts → claude/statusline.d.ts} +1 -1
- package/dist/commands/claude/statusline.d.ts.map +1 -0
- package/dist/commands/{statusline.js → claude/statusline.js} +4 -4
- package/dist/commands/claude/statusline.js.map +1 -0
- package/dist/commands/codex/index.d.ts +11 -0
- package/dist/commands/codex/index.d.ts.map +1 -0
- package/dist/commands/codex/index.js +17 -0
- package/dist/commands/codex/index.js.map +1 -0
- package/dist/commands/codex/process-analytics.d.ts +14 -0
- package/dist/commands/codex/process-analytics.d.ts.map +1 -0
- package/dist/commands/codex/process-analytics.js +111 -0
- package/dist/commands/codex/process-analytics.js.map +1 -0
- package/dist/commands/hook.js +16 -2
- package/dist/commands/hook.js.map +1 -1
- package/dist/commands/import.js +3 -3
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/queue.js +3 -1
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/verification-toggle.d.ts +19 -0
- package/dist/commands/verification-toggle.d.ts.map +1 -1
- package/dist/commands/verification-toggle.js +88 -5
- package/dist/commands/verification-toggle.js.map +1 -1
- package/dist/commands/verification.d.ts +3 -0
- package/dist/commands/verification.d.ts.map +1 -1
- package/dist/commands/verification.js +34 -3
- package/dist/commands/verification.js.map +1 -1
- package/dist/hooks/core/actions.d.ts +17 -1
- package/dist/hooks/core/actions.d.ts.map +1 -1
- package/dist/hooks/core/actions.js +13 -0
- package/dist/hooks/core/actions.js.map +1 -1
- package/dist/hooks/core/activity-end.d.ts +8 -0
- package/dist/hooks/core/activity-end.d.ts.map +1 -1
- package/dist/hooks/core/activity-end.js +19 -0
- package/dist/hooks/core/activity-end.js.map +1 -1
- package/dist/hooks/core/session-state.d.ts +15 -1
- package/dist/hooks/core/session-state.d.ts.map +1 -1
- package/dist/hooks/core/session-state.js +102 -7
- 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 +29 -17
- package/dist/hooks/core/submit-verdict.js.map +1 -1
- package/dist/hooks/core/verification-lifecycle.d.ts +20 -0
- package/dist/hooks/core/verification-lifecycle.d.ts.map +1 -1
- package/dist/hooks/core/verification-lifecycle.js +41 -0
- package/dist/hooks/core/verification-lifecycle.js.map +1 -1
- package/dist/hooks/core/verify-gate.d.ts.map +1 -1
- package/dist/hooks/core/verify-gate.js +11 -5
- package/dist/hooks/core/verify-gate.js.map +1 -1
- package/dist/import/claude/analytics-runner.d.ts +1 -1
- package/dist/import/claude/analytics-runner.d.ts.map +1 -1
- package/dist/import/claude/analytics-runner.js +5 -5
- package/dist/import/claude/analytics-runner.js.map +1 -1
- package/dist/import/claude/auth-mode.d.ts +1 -1
- package/dist/import/claude/auth-mode.d.ts.map +1 -1
- package/dist/import/claude/discovery.js +1 -1
- package/dist/import/claude/discovery.js.map +1 -1
- package/dist/import/claude/encoding.js +1 -1
- package/dist/import/claude/encoding.js.map +1 -1
- package/dist/import/claude/events/file-change.d.ts +10 -1
- package/dist/import/claude/events/file-change.d.ts.map +1 -1
- package/dist/import/claude/events/file-change.js +79 -5
- package/dist/import/claude/events/file-change.js.map +1 -1
- package/dist/import/claude/events/tool-call.d.ts +16 -1
- package/dist/import/claude/events/tool-call.d.ts.map +1 -1
- package/dist/import/claude/events/tool-call.js +122 -15
- package/dist/import/claude/events/tool-call.js.map +1 -1
- package/dist/import/claude/runner.d.ts.map +1 -1
- package/dist/import/claude/runner.js +45 -3
- package/dist/import/claude/runner.js.map +1 -1
- package/dist/import/claude/summary.js +1 -1
- package/dist/import/claude/summary.js.map +1 -1
- package/dist/import/claude/transcript-walk.d.ts +1 -1
- package/dist/import/claude/transcript-walk.d.ts.map +1 -1
- package/dist/import/claude/transcript-walk.js +11 -4
- package/dist/import/claude/transcript-walk.js.map +1 -1
- package/dist/import/codex/analytics-runner.d.ts +46 -0
- package/dist/import/codex/analytics-runner.d.ts.map +1 -0
- package/dist/import/codex/analytics-runner.js +116 -0
- package/dist/import/codex/analytics-runner.js.map +1 -0
- package/dist/import/codex/discovery.d.ts +33 -0
- package/dist/import/codex/discovery.d.ts.map +1 -0
- package/dist/import/codex/discovery.js +202 -0
- package/dist/import/codex/discovery.js.map +1 -0
- package/dist/import/codex/events/file-change.d.ts +42 -0
- package/dist/import/codex/events/file-change.d.ts.map +1 -0
- package/dist/import/codex/events/file-change.js +125 -0
- package/dist/import/codex/events/file-change.js.map +1 -0
- package/dist/import/codex/events/tool-call.d.ts +49 -0
- package/dist/import/codex/events/tool-call.d.ts.map +1 -0
- package/dist/import/codex/events/tool-call.js +151 -0
- package/dist/import/codex/events/tool-call.js.map +1 -0
- package/dist/import/codex/runner.d.ts +34 -0
- package/dist/import/codex/runner.d.ts.map +1 -0
- package/dist/import/codex/runner.js +456 -0
- package/dist/import/codex/runner.js.map +1 -0
- package/dist/import/codex/summary.d.ts +20 -0
- package/dist/import/codex/summary.d.ts.map +1 -0
- package/dist/import/codex/summary.js +206 -0
- package/dist/import/codex/summary.js.map +1 -0
- package/dist/import/events/activity.d.ts.map +1 -1
- package/dist/import/events/activity.js +17 -2
- package/dist/import/events/activity.js.map +1 -1
- package/dist/import/events/session.d.ts +11 -1
- package/dist/import/events/session.d.ts.map +1 -1
- package/dist/import/events/session.js +19 -1
- package/dist/import/events/session.js.map +1 -1
- package/dist/import/ids.js +3 -3
- package/dist/import/ids.js.map +1 -1
- package/dist/import/pipeline.d.ts +22 -15
- package/dist/import/pipeline.d.ts.map +1 -1
- package/dist/import/pipeline.js +99 -18
- package/dist/import/pipeline.js.map +1 -1
- package/dist/import/types.d.ts +4 -0
- package/dist/import/types.d.ts.map +1 -1
- package/dist/import/types.js.map +1 -1
- package/dist/index.js +9 -11
- package/dist/index.js.map +1 -1
- package/dist/lib/collector.d.ts +2 -1
- package/dist/lib/collector.d.ts.map +1 -1
- package/dist/lib/collector.js +28 -3
- package/dist/lib/collector.js.map +1 -1
- package/dist/lib/config.d.ts +40 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +52 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/event.d.ts +18 -1
- package/dist/lib/event.d.ts.map +1 -1
- package/dist/lib/event.js +25 -1
- package/dist/lib/event.js.map +1 -1
- package/dist/lib/platform-section.d.ts.map +1 -1
- package/dist/lib/platform-section.js +8 -0
- package/dist/lib/platform-section.js.map +1 -1
- package/dist/otel/{context → claude/context}/build.d.ts +1 -1
- package/dist/otel/claude/context/build.d.ts.map +1 -0
- package/dist/otel/{context → claude/context}/build.js +3 -7
- package/dist/otel/claude/context/build.js.map +1 -0
- package/dist/otel/claude/context/classify.d.ts.map +1 -0
- package/dist/otel/claude/context/classify.js.map +1 -0
- package/dist/otel/{context → claude/context}/extract.d.ts +1 -1
- package/dist/otel/claude/context/extract.d.ts.map +1 -0
- package/dist/otel/claude/context/extract.js.map +1 -0
- package/dist/otel/claude/context/markers.d.ts.map +1 -0
- package/dist/otel/{context → claude/context}/markers.js +22 -3
- package/dist/otel/claude/context/markers.js.map +1 -0
- package/dist/otel/claude/context/util.d.ts.map +1 -0
- package/dist/otel/claude/context/util.js.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/ensure.d.ts +1 -1
- package/dist/otel/claude/daemon/ensure.d.ts.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/ensure.js +6 -6
- package/dist/otel/claude/daemon/ensure.js.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/forward.d.ts +1 -1
- package/dist/otel/claude/daemon/forward.d.ts.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/forward.js +0 -0
- package/dist/otel/claude/daemon/forward.js.map +1 -0
- package/dist/otel/claude/daemon/paths.d.ts.map +1 -0
- package/dist/otel/claude/daemon/paths.js.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/process.d.ts +1 -1
- package/dist/otel/claude/daemon/process.d.ts.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/process.js +1 -1
- package/dist/otel/claude/daemon/process.js.map +1 -0
- package/dist/otel/claude/daemon/reprocess.d.ts.map +1 -0
- package/dist/otel/{daemon → claude/daemon}/reprocess.js +2 -2
- package/dist/otel/claude/daemon/reprocess.js.map +1 -0
- package/dist/otel/claude/log-handler.d.ts.map +1 -0
- package/dist/otel/{log-handler.js → claude/log-handler.js} +1 -1
- package/dist/otel/claude/log-handler.js.map +1 -0
- package/dist/otel/collector.js +4 -4
- package/dist/otel/collector.js.map +1 -1
- package/dist/queue/flush.d.ts +23 -0
- package/dist/queue/flush.d.ts.map +1 -1
- package/dist/queue/flush.js +44 -0
- 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 +5 -4
- package/dist/queue/handlers/send-event.js.map +1 -1
- package/dist/queue/index.d.ts +2 -2
- package/dist/queue/index.d.ts.map +1 -1
- package/dist/queue/index.js +4 -1
- package/dist/queue/index.js.map +1 -1
- package/dist/queue/spawn.d.ts +20 -0
- package/dist/queue/spawn.d.ts.map +1 -1
- package/dist/queue/spawn.js +37 -0
- package/dist/queue/spawn.js.map +1 -1
- package/dist/tui/config/schema.d.ts.map +1 -1
- package/dist/tui/config/schema.js +8 -0
- package/dist/tui/config/schema.js.map +1 -1
- package/dist/tui/import/area.js +3 -3
- package/dist/tui/import/area.js.map +1 -1
- package/package.json +2 -1
- package/dist/analytics/classifier.d.ts.map +0 -1
- package/dist/analytics/classifier.js.map +0 -1
- package/dist/analytics/emit.d.ts.map +0 -1
- package/dist/analytics/emit.js.map +0 -1
- package/dist/analytics/errors.d.ts.map +0 -1
- package/dist/analytics/errors.js.map +0 -1
- package/dist/analytics/hook-trigger.d.ts.map +0 -1
- package/dist/analytics/hook-trigger.js.map +0 -1
- package/dist/analytics/log.d.ts.map +0 -1
- package/dist/analytics/log.js.map +0 -1
- package/dist/analytics/merge.d.ts.map +0 -1
- package/dist/analytics/merge.js.map +0 -1
- package/dist/analytics/pricing.d.ts.map +0 -1
- package/dist/analytics/pricing.js.map +0 -1
- package/dist/analytics/projection.d.ts.map +0 -1
- package/dist/analytics/projection.js.map +0 -1
- package/dist/analytics/spawn.d.ts.map +0 -1
- package/dist/analytics/spawn.js.map +0 -1
- package/dist/analytics/state.d.ts.map +0 -1
- package/dist/analytics/state.js.map +0 -1
- package/dist/analytics/transcript.d.ts.map +0 -1
- package/dist/analytics/transcript.js.map +0 -1
- package/dist/analytics/types.d.ts.map +0 -1
- package/dist/analytics/types.js.map +0 -1
- package/dist/commands/claude.d.ts.map +0 -1
- package/dist/commands/claude.js.map +0 -1
- package/dist/commands/otel.d.ts.map +0 -1
- package/dist/commands/otel.js.map +0 -1
- package/dist/commands/process-analytics.d.ts +0 -18
- package/dist/commands/process-analytics.d.ts.map +0 -1
- package/dist/commands/process-analytics.js.map +0 -1
- package/dist/commands/statusline-toggle.d.ts.map +0 -1
- package/dist/commands/statusline-toggle.js.map +0 -1
- package/dist/commands/statusline.d.ts.map +0 -1
- package/dist/commands/statusline.js.map +0 -1
- package/dist/otel/context/build.d.ts.map +0 -1
- package/dist/otel/context/build.js.map +0 -1
- package/dist/otel/context/classify.d.ts.map +0 -1
- package/dist/otel/context/classify.js.map +0 -1
- package/dist/otel/context/extract.d.ts.map +0 -1
- package/dist/otel/context/extract.js.map +0 -1
- package/dist/otel/context/markers.d.ts.map +0 -1
- package/dist/otel/context/markers.js.map +0 -1
- package/dist/otel/context/util.d.ts.map +0 -1
- package/dist/otel/context/util.js.map +0 -1
- package/dist/otel/daemon/ensure.d.ts.map +0 -1
- package/dist/otel/daemon/ensure.js.map +0 -1
- package/dist/otel/daemon/forward.d.ts.map +0 -1
- package/dist/otel/daemon/forward.js.map +0 -1
- package/dist/otel/daemon/paths.d.ts.map +0 -1
- package/dist/otel/daemon/paths.js.map +0 -1
- package/dist/otel/daemon/process.d.ts.map +0 -1
- package/dist/otel/daemon/process.js.map +0 -1
- package/dist/otel/daemon/reprocess.d.ts.map +0 -1
- package/dist/otel/daemon/reprocess.js.map +0 -1
- package/dist/otel/log-handler.d.ts.map +0 -1
- package/dist/otel/log-handler.js.map +0 -1
- /package/dist/analytics/{log.d.ts → claude/log.d.ts} +0 -0
- /package/dist/analytics/{transcript.d.ts → claude/transcript.d.ts} +0 -0
- /package/dist/analytics/{classifier.d.ts → shared/classifier.d.ts} +0 -0
- /package/dist/analytics/{errors.d.ts → shared/errors.d.ts} +0 -0
- /package/dist/analytics/{errors.js → shared/errors.js} +0 -0
- /package/dist/analytics/{types.js → shared/types.js} +0 -0
- /package/dist/otel/{context → claude/context}/classify.d.ts +0 -0
- /package/dist/otel/{context → claude/context}/classify.js +0 -0
- /package/dist/otel/{context → claude/context}/extract.js +0 -0
- /package/dist/otel/{context → claude/context}/markers.d.ts +0 -0
- /package/dist/otel/{context → claude/context}/util.d.ts +0 -0
- /package/dist/otel/{context → claude/context}/util.js +0 -0
- /package/dist/otel/{daemon → claude/daemon}/paths.d.ts +0 -0
- /package/dist/otel/{daemon → claude/daemon}/paths.js +0 -0
- /package/dist/otel/{daemon → claude/daemon}/reprocess.d.ts +0 -0
- /package/dist/otel/{log-handler.d.ts → claude/log-handler.d.ts} +0 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Codex CLI client utilities — stdin parsing, tool classification, TOML
|
|
4
|
+
* surgical editing, AGENTS.md block merge, auth detection.
|
|
5
|
+
*
|
|
6
|
+
* The TOML helpers are intentionally minimal: line-based surgical edits to
|
|
7
|
+
* known sections (`[features]`, `[mcp_servers.<name>]`). We don't need a
|
|
8
|
+
* full TOML parser/serializer because the only blocks we write/read have
|
|
9
|
+
* fixed shapes. User content outside our managed sections is preserved
|
|
10
|
+
* verbatim.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.AGENTS_MD_END_MARKER = exports.AGENTS_MD_START_MARKER = void 0;
|
|
14
|
+
exports.parseCodexHookStdin = parseCodexHookStdin;
|
|
15
|
+
exports.canonicalizeCodexServerName = canonicalizeCodexServerName;
|
|
16
|
+
exports.canonicalizeCodexToolName = canonicalizeCodexToolName;
|
|
17
|
+
exports.extractCodexMcpServer = extractCodexMcpServer;
|
|
18
|
+
exports.normalizeCodexToolName = normalizeCodexToolName;
|
|
19
|
+
exports.classifyCodexTool = classifyCodexTool;
|
|
20
|
+
exports.extractCodexToolInput = extractCodexToolInput;
|
|
21
|
+
exports.extractBashBinary = extractBashBinary;
|
|
22
|
+
exports.decodeJwtPayload = decodeJwtPayload;
|
|
23
|
+
exports.resolveCodexUsage = resolveCodexUsage;
|
|
24
|
+
exports.findTomlSection = findTomlSection;
|
|
25
|
+
exports.ensureFeaturesHooksTrue = ensureFeaturesHooksTrue;
|
|
26
|
+
exports.upsertMcpServer = upsertMcpServer;
|
|
27
|
+
exports.removeMcpServer = removeMcpServer;
|
|
28
|
+
exports.tomlBodyFromRecord = tomlBodyFromRecord;
|
|
29
|
+
exports.upsertAgentsMdBlock = upsertAgentsMdBlock;
|
|
30
|
+
exports.stripAgentsMdBlock = stripAgentsMdBlock;
|
|
31
|
+
exports.readCodexConfigToml = readCodexConfigToml;
|
|
32
|
+
exports.writeCodexConfigToml = writeCodexConfigToml;
|
|
33
|
+
exports.codexConfigTomlPath = codexConfigTomlPath;
|
|
34
|
+
exports.codexHooksJsonPath = codexHooksJsonPath;
|
|
35
|
+
const fs_1 = require("fs");
|
|
36
|
+
const os_1 = require("os");
|
|
37
|
+
const path_1 = require("path");
|
|
38
|
+
const logger_1 = require("../../lib/logger");
|
|
39
|
+
function parseCodexHookStdin(raw) {
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(raw);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
logger_1.logger.debug(`failed to parse Codex hook stdin: ${e}`);
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// ─── Tool classification ──────────────────────────────────────────────────
|
|
49
|
+
const MCP_PREFIX = "mcp__";
|
|
50
|
+
/**
|
|
51
|
+
* Codex flattens `-` to `_` in BOTH segments of `mcp__<server>__<tool>` when
|
|
52
|
+
* dispatching hooks — so `mcp__browser-devtools__bdt_content_take-screenshot`
|
|
53
|
+
* arrives on hook stdin as `mcp__browser_devtools__bdt_content_take_screenshot`.
|
|
54
|
+
*
|
|
55
|
+
* Two lossy mappings happen at once:
|
|
56
|
+
* 1. **server segment**: only three values matter; map them explicitly.
|
|
57
|
+
* 2. **tool action segment**: the canonical shape is
|
|
58
|
+
* `<prefix>_<domain>_<action-with-hyphens>` — first two underscores are
|
|
59
|
+
* structural separators, all later underscores were `-` originally.
|
|
60
|
+
* Live-verified examples (Codex 0.135.x):
|
|
61
|
+
* bdt_navigation_go_to → bdt_navigation_go-to
|
|
62
|
+
* bdt_content_take_screenshot → bdt_content_take-screenshot
|
|
63
|
+
* bdt_a11y_take_aria_snapshot → bdt_a11y_take-aria-snapshot
|
|
64
|
+
* bdt_o11y_get_console_messages → bdt_o11y_get-console-messages
|
|
65
|
+
* bdt_interaction_click → bdt_interaction_click (no hyphens in action)
|
|
66
|
+
*
|
|
67
|
+
* We denormalize BEFORE emitting any `tool_call` event so the wire format
|
|
68
|
+
* matches Claude/Cursor exactly and downstream consumers (verify-gate
|
|
69
|
+
* required-tools satisfier, evidence extractors, recording start/stop
|
|
70
|
+
* comparisons) work with one canonical name.
|
|
71
|
+
*/
|
|
72
|
+
const FLAT_SERVER_TO_CANONICAL = {
|
|
73
|
+
browser_devtools: "browser-devtools",
|
|
74
|
+
node_devtools: "node-devtools",
|
|
75
|
+
backend_devtools: "backend-devtools",
|
|
76
|
+
};
|
|
77
|
+
const DEVTOOLS_TOOL_PREFIXES = ["bdt_", "ndt_", "bedt_"];
|
|
78
|
+
/**
|
|
79
|
+
* Reverse Codex's `-`→`_` flattening on the server segment. Idempotent: an
|
|
80
|
+
* already-canonical (hyphenated) name passes through unchanged.
|
|
81
|
+
*/
|
|
82
|
+
function canonicalizeCodexServerName(serverSegment) {
|
|
83
|
+
return FLAT_SERVER_TO_CANONICAL[serverSegment] ?? serverSegment;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Reverse Codex's `-`→`_` flattening on a devtools tool action segment.
|
|
87
|
+
* Rule: keep the first two underscores (prefix + domain separators), turn
|
|
88
|
+
* every subsequent `_` into `-`. Only applies to known devtools prefixes
|
|
89
|
+
* (`bdt_` / `ndt_` / `bedt_`); other tool names pass through unchanged.
|
|
90
|
+
*
|
|
91
|
+
* Idempotent: input that already contains `-` only flattens further
|
|
92
|
+
* underscores past the third segment.
|
|
93
|
+
*/
|
|
94
|
+
function canonicalizeCodexToolName(bareToolName) {
|
|
95
|
+
if (!DEVTOOLS_TOOL_PREFIXES.some((p) => bareToolName.startsWith(p))) {
|
|
96
|
+
return bareToolName;
|
|
97
|
+
}
|
|
98
|
+
const parts = bareToolName.split("_");
|
|
99
|
+
if (parts.length <= 3) {
|
|
100
|
+
return bareToolName;
|
|
101
|
+
}
|
|
102
|
+
return `${parts[0]}_${parts[1]}_${parts.slice(2).join("-")}`;
|
|
103
|
+
}
|
|
104
|
+
/** Prefix → canonical devtools MCP server name. Single source of truth. */
|
|
105
|
+
const DEVTOOLS_PREFIX_TO_SERVER = [
|
|
106
|
+
["bdt_", "browser-devtools"],
|
|
107
|
+
["ndt_", "node-devtools"],
|
|
108
|
+
["bedt_", "backend-devtools"],
|
|
109
|
+
];
|
|
110
|
+
/**
|
|
111
|
+
* Returns the CANONICAL (hyphen-form) MCP server name for a Codex tool name.
|
|
112
|
+
*
|
|
113
|
+
* Codex tool names arrive in TWO shapes depending on the surface:
|
|
114
|
+
* 1. **Hook stdin** wraps the bare name in `mcp__<server>__<tool>` with the
|
|
115
|
+
* `-`→`_` flattening (e.g. `mcp__browser_devtools__bdt_content_start_recording`).
|
|
116
|
+
* 2. **Rollout JSONL** (`function_call.name`) carries the BARE tool name
|
|
117
|
+
* (e.g. `bdt_content_take_screenshot`) — no `mcp__` wrapper at all.
|
|
118
|
+
*
|
|
119
|
+
* Both are handled here so downstream comparisons against the registered
|
|
120
|
+
* server name (`browser-devtools` / `node-devtools` / `backend-devtools`)
|
|
121
|
+
* work regardless of surface.
|
|
122
|
+
*
|
|
123
|
+
* Returns null for non-MCP tools.
|
|
124
|
+
*/
|
|
125
|
+
function extractCodexMcpServer(toolName) {
|
|
126
|
+
if (!toolName) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (toolName.startsWith(MCP_PREFIX)) {
|
|
130
|
+
const rest = toolName.slice(MCP_PREFIX.length);
|
|
131
|
+
const sep = rest.indexOf("__");
|
|
132
|
+
if (sep < 0) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
return canonicalizeCodexServerName(rest.slice(0, sep));
|
|
136
|
+
}
|
|
137
|
+
for (const [prefix, server] of DEVTOOLS_PREFIX_TO_SERVER) {
|
|
138
|
+
if (toolName.startsWith(prefix)) {
|
|
139
|
+
return server;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Map a Codex / OpenAI tool name to the cross-client canonical (Claude) vocab,
|
|
146
|
+
* so `tool_call.tool_name` (live + import) AND `session_analytics.tools[*]`
|
|
147
|
+
* map keys (analytics projection) ALL agree on the same wire string for the
|
|
148
|
+
* same logical tool. Without this alignment, a backend join of
|
|
149
|
+
* `session_analytics.tools[k]` against `tool_call.tool_name` breaks on every
|
|
150
|
+
* Codex session for the affected tools:
|
|
151
|
+
*
|
|
152
|
+
* `apply_patch` → analytics keys `"Edit"`, live/import ship `"apply_patch"`
|
|
153
|
+
* `update_plan` → analytics keys `"TodoWrite"`, live/import ship `"update_plan"`
|
|
154
|
+
* `read_file` → analytics keys `"Read"`, live/import ship `"read_file"`
|
|
155
|
+
* `web_search` → analytics keys `"WebSearch"`, live/import ship `"web_search"`
|
|
156
|
+
* `web_fetch` → analytics keys `"WebFetch"`, live/import ship `"web_fetch"`
|
|
157
|
+
*
|
|
158
|
+
* Round 67 fix: extend the mapping (was `exec_command → Bash` only) to cover
|
|
159
|
+
* every alias the analytics projection's `claudeAlias` switch handles. The
|
|
160
|
+
* projection in `analytics/codex/projection.ts:670` continues to apply the
|
|
161
|
+
* same mapping for its `tools` map keys (kept there as a defense-in-depth /
|
|
162
|
+
* documentation aid — the two MUST stay in lockstep). Cross-client
|
|
163
|
+
* aggregations on `tools["Bash"]` / `tools["Read"]` / etc. now include both
|
|
164
|
+
* Claude and Codex sources for every alias, not just `Bash`.
|
|
165
|
+
*/
|
|
166
|
+
function normalizeCodexToolName(toolName) {
|
|
167
|
+
if (toolName === "exec_command") {
|
|
168
|
+
return "Bash";
|
|
169
|
+
}
|
|
170
|
+
if (toolName === "apply_patch") {
|
|
171
|
+
return "Edit";
|
|
172
|
+
}
|
|
173
|
+
if (toolName === "update_plan") {
|
|
174
|
+
return "TodoWrite";
|
|
175
|
+
}
|
|
176
|
+
if (toolName === "read_file") {
|
|
177
|
+
return "Read";
|
|
178
|
+
}
|
|
179
|
+
if (toolName === "web_search") {
|
|
180
|
+
return "WebSearch";
|
|
181
|
+
}
|
|
182
|
+
if (toolName === "web_fetch") {
|
|
183
|
+
return "WebFetch";
|
|
184
|
+
}
|
|
185
|
+
return toolName;
|
|
186
|
+
}
|
|
187
|
+
function classifyCodexTool(rawToolName) {
|
|
188
|
+
if (!rawToolName) {
|
|
189
|
+
return { tool_type: null, tool_name: "", mcp_server: null };
|
|
190
|
+
}
|
|
191
|
+
// Two shapes lead to MCP classification:
|
|
192
|
+
// 1. Hook stdin: `mcp__<server>__<tool>` (Codex wraps the bare name).
|
|
193
|
+
// 2. Rollout JSONL: bare `bdt_*` / `ndt_*` / `bedt_*` (no wrapper).
|
|
194
|
+
// Both routes through the same `extractCodexMcpServer` so import +
|
|
195
|
+
// analytics + live see identical (tool_type, mcp_server) — without this
|
|
196
|
+
// import-side devtools tool_call events ship with tool_type=null and
|
|
197
|
+
// mcp_server=null, and verify-gate cycle-attribution joins break.
|
|
198
|
+
if (rawToolName.startsWith(MCP_PREFIX)) {
|
|
199
|
+
const rest = rawToolName.slice(MCP_PREFIX.length);
|
|
200
|
+
const sep = rest.indexOf("__");
|
|
201
|
+
if (sep >= 0) {
|
|
202
|
+
const serverSegment = rest.slice(0, sep);
|
|
203
|
+
const canonicalServer = canonicalizeCodexServerName(serverSegment);
|
|
204
|
+
const bareToolName = rest.slice(sep + 2);
|
|
205
|
+
const canonicalTool = canonicalizeCodexToolName(bareToolName);
|
|
206
|
+
return { tool_type: "mcp", tool_name: canonicalTool, mcp_server: canonicalServer };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Bare-prefix rollout shape. extractCodexMcpServer already knows the
|
|
210
|
+
// canonical server name for each devtools prefix. Canonicalize the tool
|
|
211
|
+
// name too (underscore → hyphen past segment 3) so wire shape matches.
|
|
212
|
+
const bareServer = extractCodexMcpServer(rawToolName);
|
|
213
|
+
if (bareServer !== null && !rawToolName.startsWith(MCP_PREFIX)) {
|
|
214
|
+
return {
|
|
215
|
+
tool_type: "mcp",
|
|
216
|
+
tool_name: canonicalizeCodexToolName(rawToolName),
|
|
217
|
+
mcp_server: bareServer,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const normalized = normalizeCodexToolName(rawToolName);
|
|
221
|
+
// Codex's `multi_agent_v1` namespace exposes three sub-agent lifecycle
|
|
222
|
+
// tools: `spawn_agent` (dispatch — Claude-parity `Agent`/`Task`),
|
|
223
|
+
// `wait_agent` (sync on outstanding agents), `close_agent` (cancel /
|
|
224
|
+
// reap). Without explicit `tool_type: "sub_agent"` tagging, every
|
|
225
|
+
// Codex `tool_call` event for these ships with `tool_type` OMITTED
|
|
226
|
+
// (null branch), so backend dashboards filtering on `tool_type =
|
|
227
|
+
// 'sub_agent'` (cross-client sub-agent usage) silently miss every
|
|
228
|
+
// Codex multi-agent session. The Codex projection separately routes
|
|
229
|
+
// `spawn_agent.agent_type` into the `subAgents` map (see
|
|
230
|
+
// analytics/codex/projection.ts:715), so the session-level
|
|
231
|
+
// `uses_sub_agent` aggregate is unaffected — the per-event wire field
|
|
232
|
+
// is the bug. Keep `tool_name` as the literal tool name (each
|
|
233
|
+
// lifecycle phase is a distinct call); Claude's `tool_name` collapses
|
|
234
|
+
// to the agent_type because Claude has only ONE meta-tool for the
|
|
235
|
+
// whole lifecycle, while Codex has three. Cross-client semantic
|
|
236
|
+
// difference, not a parity-break.
|
|
237
|
+
if (rawToolName === "spawn_agent" || rawToolName === "wait_agent" || rawToolName === "close_agent") {
|
|
238
|
+
return { tool_type: "sub_agent", tool_name: normalized, mcp_server: null };
|
|
239
|
+
}
|
|
240
|
+
return { tool_type: null, tool_name: normalized, mcp_server: null };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Per-tool input whitelist (mirrors `extractClaudeToolInput` / `extractCursorToolInput`).
|
|
244
|
+
* Default Codex toolset: `Bash`/`exec_command`, `apply_patch`, `update_plan`, MCP tools.
|
|
245
|
+
* Returns undefined for unknown tools (so the wire shape stays opt-in).
|
|
246
|
+
*/
|
|
247
|
+
function extractCodexToolInput(toolName, toolInput) {
|
|
248
|
+
if (!toolName || toolInput === undefined) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
// apply_patch: hook stdin shape (live-tested 0.135.0) is
|
|
252
|
+
// `tool_input.command = "<patch text>"`. Fallback to .input (function_call
|
|
253
|
+
// shape) and raw string (defensive).
|
|
254
|
+
if (toolName === "apply_patch") {
|
|
255
|
+
if (typeof toolInput === "string") {
|
|
256
|
+
return { input_size: toolInput.length };
|
|
257
|
+
}
|
|
258
|
+
if (typeof toolInput === "object" && toolInput !== null) {
|
|
259
|
+
const rec = toolInput;
|
|
260
|
+
const body = rec.command ?? rec.input;
|
|
261
|
+
if (typeof body === "string") {
|
|
262
|
+
return { input_size: body.length };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return { input_size: undefined };
|
|
266
|
+
}
|
|
267
|
+
// From here, function_call tools — tool_input is a Record
|
|
268
|
+
if (typeof toolInput !== "object" || toolInput === null) {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
const obj = toolInput;
|
|
272
|
+
const normalized = normalizeCodexToolName(toolName);
|
|
273
|
+
if (normalized === "Bash") {
|
|
274
|
+
// Codex `exec_command` function args use `cmd` (verified 0.135.0
|
|
275
|
+
// against real rollouts: `~/.codex/sessions/.../*.jsonl` — every
|
|
276
|
+
// `{"name":"exec_command", "arguments":"{\"cmd\":...}"}` line uses
|
|
277
|
+
// `cmd`, never `command`). Earlier we only read `obj.command`, so
|
|
278
|
+
// `binary` was ALWAYS undefined for every Codex Bash tool_call —
|
|
279
|
+
// wire impact: `bash_binaries` map in Codex `session_analytics`
|
|
280
|
+
// was empty across the board, and per-event `tool_input.binary`
|
|
281
|
+
// was missing on the wire (cross-pipeline divergence with Claude's
|
|
282
|
+
// `extractCommandBinary` which correctly extracts the binary).
|
|
283
|
+
// Fall back to `command` defensively in case some Codex hook-stdin
|
|
284
|
+
// path or future shape uses the apply_patch-style remap.
|
|
285
|
+
const cmd = obj.cmd ?? obj.command;
|
|
286
|
+
const binary = typeof cmd === "string"
|
|
287
|
+
? extractBashBinary(cmd)
|
|
288
|
+
: undefined;
|
|
289
|
+
return {
|
|
290
|
+
workdir: obj.workdir,
|
|
291
|
+
binary,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
if (toolName === "update_plan") {
|
|
295
|
+
const explanation = obj.explanation;
|
|
296
|
+
const plan = obj.plan;
|
|
297
|
+
return {
|
|
298
|
+
explanation: typeof explanation === "string" ? explanation : undefined,
|
|
299
|
+
plan_step_count: Array.isArray(plan) ? plan.length : undefined,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
// Codex 0.135+ sub-agent orchestration tools (`multi_agent_v1` namespace).
|
|
303
|
+
// Real-rollout shape verified against `~/.codex/sessions/.../*.jsonl`:
|
|
304
|
+
// spawn_agent: {"agent_type":"explorer","message":"...","fork_context":true}
|
|
305
|
+
// wait_agent: {"targets":["<uuid>",...],"timeout_ms":30000}
|
|
306
|
+
// close_agent: {"target":"<uuid>"}
|
|
307
|
+
// Without per-tool branches, `extractCodexToolInput` falls through to the
|
|
308
|
+
// final `return undefined` and wire `tool_call.tool_input` is dropped —
|
|
309
|
+
// backend loses `agent_type` (the primary sub-agent telemetry signal),
|
|
310
|
+
// fan-out arity (`wait_agent.targets.length`), and close-agent target
|
|
311
|
+
// joins. The `message` field is agent-authored free text → length-only
|
|
312
|
+
// (mirrors `Bash.command` policy: keep the binary, drop the content).
|
|
313
|
+
if (toolName === "spawn_agent") {
|
|
314
|
+
const agentType = obj.agent_type;
|
|
315
|
+
const message = obj.message;
|
|
316
|
+
const forkContext = obj.fork_context;
|
|
317
|
+
return {
|
|
318
|
+
agent_type: typeof agentType === "string" ? agentType : undefined,
|
|
319
|
+
message_size: typeof message === "string" ? message.length : undefined,
|
|
320
|
+
fork_context: typeof forkContext === "boolean" ? forkContext : undefined,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
if (toolName === "wait_agent") {
|
|
324
|
+
const targets = obj.targets;
|
|
325
|
+
const timeoutMs = obj.timeout_ms;
|
|
326
|
+
return {
|
|
327
|
+
target_count: Array.isArray(targets) ? targets.length : undefined,
|
|
328
|
+
timeout_ms: typeof timeoutMs === "number" ? timeoutMs : undefined,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
if (toolName === "close_agent") {
|
|
332
|
+
const target = obj.target;
|
|
333
|
+
return {
|
|
334
|
+
target: typeof target === "string" ? target : undefined,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
// `view_image`: agent inspects a screenshot/image by file path. `path` is
|
|
338
|
+
// useful telemetry (groups verification screenshots by run), `detail` is
|
|
339
|
+
// OpenAI's tier flag. Mirrors Claude `Read.file_path` policy.
|
|
340
|
+
if (toolName === "view_image") {
|
|
341
|
+
const path = obj.path;
|
|
342
|
+
const detail = obj.detail;
|
|
343
|
+
return {
|
|
344
|
+
path: typeof path === "string" ? path : undefined,
|
|
345
|
+
detail: typeof detail === "string" ? detail : undefined,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
// `write_stdin`: writes characters into an exec_command's open stdin
|
|
349
|
+
// (session_id is the exec_command session, NOT the Codex session).
|
|
350
|
+
// `chars` is agent-authored free text → length-only (privacy fence,
|
|
351
|
+
// mirrors `Bash.command` content drop). Keep `session_id` for joining
|
|
352
|
+
// back to the originating exec_command and timing knobs for parity.
|
|
353
|
+
if (toolName === "write_stdin") {
|
|
354
|
+
const sessionId = obj.session_id;
|
|
355
|
+
const chars = obj.chars;
|
|
356
|
+
const yieldTimeMs = obj.yield_time_ms;
|
|
357
|
+
const maxOutputTokens = obj.max_output_tokens;
|
|
358
|
+
return {
|
|
359
|
+
session_id: typeof sessionId === "number" ? sessionId : undefined,
|
|
360
|
+
chars_size: typeof chars === "string" ? chars.length : undefined,
|
|
361
|
+
yield_time_ms: typeof yieldTimeMs === "number" ? yieldTimeMs : undefined,
|
|
362
|
+
max_output_tokens: typeof maxOutputTokens === "number" ? maxOutputTokens : undefined,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
// MCP devtools tools: pass through verbatim, BUT strip `_metadata` —
|
|
366
|
+
// require-verification.ts injects `_metadata` (containing internal
|
|
367
|
+
// correlation IDs AND `collectorApiKey` — a SECRET) into the
|
|
368
|
+
// tool_input via `updatedInput` for every devtools call. Live
|
|
369
|
+
// track-action strips it before recording (clients/codex/hooks/
|
|
370
|
+
// track-action.ts:167-170 `toolInputAsRecord`); import was missing
|
|
371
|
+
// the same strip → Codex import devtools `tool_call` events shipped
|
|
372
|
+
// `_metadata` (including `collectorApiKey`) onto the wire, while
|
|
373
|
+
// live shipped it stripped. Cross-pipeline divergence + secret
|
|
374
|
+
// leak on every re-import.
|
|
375
|
+
//
|
|
376
|
+
// BOTH shapes routed through `extractCodexMcpServer` so bare `bdt_*` /
|
|
377
|
+
// `ndt_*` / `bedt_*` from rollout JSONL gets the same passthrough as
|
|
378
|
+
// hook-stdin's `mcp__<server>__<tool>` shape. Without this, import-
|
|
379
|
+
// side devtools tool_call events ship with `tool_input: undefined`
|
|
380
|
+
// — backend dedup latest-wins → re-import erases the live tool_input
|
|
381
|
+
// payload.
|
|
382
|
+
if (toolName.startsWith(MCP_PREFIX) || extractCodexMcpServer(toolName) !== null) {
|
|
383
|
+
if ("_metadata" in obj) {
|
|
384
|
+
const { _metadata, ...rest } = obj;
|
|
385
|
+
void _metadata;
|
|
386
|
+
return rest;
|
|
387
|
+
}
|
|
388
|
+
return obj;
|
|
389
|
+
}
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
function extractBashBinary(command) {
|
|
393
|
+
const trimmed = command.trim();
|
|
394
|
+
if (!trimmed) {
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
// Skip leading env-var assignments (e.g. `KEY=val cmd …` → `cmd`).
|
|
398
|
+
// Cross-client parity with Claude's `extractCommandBinary` AND a
|
|
399
|
+
// secret-leak fence: real commands like `API_KEY=secret git push`
|
|
400
|
+
// used to land `binary="API_KEY=secret"` on the wire — both wrong
|
|
401
|
+
// (bash_binaries key polluted with secret-shaped tokens, and the
|
|
402
|
+
// secret value itself shipped as the analytics label).
|
|
403
|
+
const tokens = trimmed.split(/\s+/);
|
|
404
|
+
for (const t of tokens) {
|
|
405
|
+
// skip env-var assignments like FOO=bar / API_KEY=abc
|
|
406
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(t)) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
if (t.length > 0) {
|
|
410
|
+
// Strip path prefix so `/usr/bin/git` → `git`. Cross-client
|
|
411
|
+
// parity intentionally stops short of Claude's "keep full
|
|
412
|
+
// path" behavior — Codex's pre-existing semantics already
|
|
413
|
+
// stripped the path, and changing to match Claude would
|
|
414
|
+
// break any downstream consumer keyed on the existing
|
|
415
|
+
// Codex-side `bash_binaries` keys. Documented divergence.
|
|
416
|
+
return t.split(/[\\/]/).pop() ?? t;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return undefined;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Decode the *payload* of a JWT (`header.payload.signature`).
|
|
423
|
+
*
|
|
424
|
+
* We never verify the signature — the token was minted by Codex into the
|
|
425
|
+
* user's own `~/.codex/auth.json` and we just want to read the claims for
|
|
426
|
+
* event-tagging. Returns `null` on any malformedness (wrong segment count,
|
|
427
|
+
* bad base64url, non-JSON payload).
|
|
428
|
+
*/
|
|
429
|
+
function decodeJwtPayload(token) {
|
|
430
|
+
const parts = token.split(".");
|
|
431
|
+
if (parts.length !== 3) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const json = Buffer.from(parts[1], "base64url").toString("utf-8");
|
|
436
|
+
const parsed = JSON.parse(json);
|
|
437
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
438
|
+
return null;
|
|
439
|
+
}
|
|
440
|
+
return parsed;
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Extract `(email, chatgpt_plan_type)` from `tokens.id_token`. Handles both
|
|
448
|
+
* shapes Codex has shipped:
|
|
449
|
+
* - JWT string (current, live-verified) — claims live in the payload
|
|
450
|
+
* - `{ email, chatgpt_plan_type }` object (older / hypothetical) — direct
|
|
451
|
+
*/
|
|
452
|
+
function extractIdTokenFields(idToken) {
|
|
453
|
+
if (typeof idToken === "string") {
|
|
454
|
+
const payload = decodeJwtPayload(idToken);
|
|
455
|
+
if (!payload) {
|
|
456
|
+
return {};
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
email: payload.email,
|
|
460
|
+
planType: payload["https://api.openai.com/auth"]?.chatgpt_plan_type,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
if (typeof idToken === "object" && idToken !== null) {
|
|
464
|
+
const obj = idToken;
|
|
465
|
+
return { email: obj.email, planType: obj.chatgpt_plan_type };
|
|
466
|
+
}
|
|
467
|
+
return {};
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Read `~/.codex/auth.json` to derive `usage_type` / `usage_plan` /
|
|
471
|
+
* `user_email` for event base-fields population.
|
|
472
|
+
*
|
|
473
|
+
* `auth_mode` values seen in the wild:
|
|
474
|
+
* - `"chatgpt"` — ChatGPT browser-login / subscription (Plus / Pro / Team /
|
|
475
|
+
* Enterprise). Current default for `codex login`.
|
|
476
|
+
* - `"swic"` — older subscription mode alias; kept for back-compat.
|
|
477
|
+
* - `"api"` — OpenAI Platform API key.
|
|
478
|
+
*
|
|
479
|
+
* `authPath` is optional — defaults to `~/.codex/auth.json`. Tests pass an
|
|
480
|
+
* explicit path to avoid HOME-env-var caching issues across jest workers.
|
|
481
|
+
*/
|
|
482
|
+
function resolveCodexUsage(authPath) {
|
|
483
|
+
const p = authPath ?? (0, path_1.join)((0, os_1.homedir)(), ".codex", "auth.json");
|
|
484
|
+
if (!(0, fs_1.existsSync)(p)) {
|
|
485
|
+
return {};
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
const parsed = JSON.parse((0, fs_1.readFileSync)(p, "utf-8"));
|
|
489
|
+
const usageType = parsed.auth_mode === "chatgpt" || parsed.auth_mode === "swic"
|
|
490
|
+
? "subscription"
|
|
491
|
+
: parsed.auth_mode === "api"
|
|
492
|
+
? "api"
|
|
493
|
+
: undefined;
|
|
494
|
+
const { email, planType } = extractIdTokenFields(parsed.tokens?.id_token);
|
|
495
|
+
return {
|
|
496
|
+
usageType,
|
|
497
|
+
usagePlan: planType?.toLowerCase(),
|
|
498
|
+
userEmail: email,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
catch (e) {
|
|
502
|
+
logger_1.logger.debug(`failed to parse ${p}: ${e}`);
|
|
503
|
+
return {};
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
// ─── TOML surgical editor (~/.codex/config.toml) ──────────────────────────
|
|
507
|
+
/**
|
|
508
|
+
* Test if a line starts a TOML table header `[name]` (skipping arrays-of-tables `[[...]]`).
|
|
509
|
+
*/
|
|
510
|
+
function tableHeaderLineExact(line, sectionName) {
|
|
511
|
+
const trimmed = line.trim();
|
|
512
|
+
return trimmed === `[${sectionName}]`;
|
|
513
|
+
}
|
|
514
|
+
function isAnyTableHeader(line) {
|
|
515
|
+
const trimmed = line.trim();
|
|
516
|
+
return /^\[\[?[^\]]+\]\]?$/.test(trimmed);
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Find the line range [startIdx, endIdx) of a TOML table by exact header
|
|
520
|
+
* `[<sectionName>]`. Returns null if not found. `endIdx` is the line index
|
|
521
|
+
* of the next header (or content end). Header itself is included.
|
|
522
|
+
*/
|
|
523
|
+
function findTomlSection(lines, sectionName) {
|
|
524
|
+
let startIdx = -1;
|
|
525
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
526
|
+
if (tableHeaderLineExact(lines[i], sectionName)) {
|
|
527
|
+
startIdx = i;
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (startIdx < 0) {
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
let endIdx = lines.length;
|
|
535
|
+
for (let j = startIdx + 1; j < lines.length; j += 1) {
|
|
536
|
+
if (isAnyTableHeader(lines[j])) {
|
|
537
|
+
endIdx = j;
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
return { startIdx, endIdx };
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Strip trailing blank lines from a section body (kept just before the next
|
|
545
|
+
* header) so we don't accumulate them on repeated upsert.
|
|
546
|
+
*/
|
|
547
|
+
function trimTrailingBlanks(lines) {
|
|
548
|
+
const out = [...lines];
|
|
549
|
+
while (out.length > 0 && out[out.length - 1].trim() === "") {
|
|
550
|
+
out.pop();
|
|
551
|
+
}
|
|
552
|
+
return out;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Append `block` to `content` with a single blank-line separator. Normalizes
|
|
556
|
+
* trailing whitespace so the result always has exactly `\n\n` between the
|
|
557
|
+
* prior content and the new block, plus a single trailing `\n`.
|
|
558
|
+
*/
|
|
559
|
+
function appendBlockWithSeparator(content, block) {
|
|
560
|
+
if (content.length === 0) {
|
|
561
|
+
return block.join("\n") + "\n";
|
|
562
|
+
}
|
|
563
|
+
const trimmedTrailing = content.replace(/\n+$/, "");
|
|
564
|
+
return trimmedTrailing + "\n\n" + block.join("\n") + "\n";
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Ensure `[features]` table contains `hooks = true`. Idempotent — merges
|
|
568
|
+
* into an existing `[features]` table if present (without disturbing other
|
|
569
|
+
* keys), or appends a fresh table at the end of the file.
|
|
570
|
+
*/
|
|
571
|
+
function ensureFeaturesHooksTrue(content) {
|
|
572
|
+
const lines = content.split("\n");
|
|
573
|
+
const section = findTomlSection(lines, "features");
|
|
574
|
+
if (section === null) {
|
|
575
|
+
return appendBlockWithSeparator(content, ["[features]", "hooks = true"]);
|
|
576
|
+
}
|
|
577
|
+
// Existing [features] table — check if `hooks = ...` already present
|
|
578
|
+
const bodyLines = lines.slice(section.startIdx + 1, section.endIdx);
|
|
579
|
+
const hookKeyRegex = /^\s*hooks\s*=/;
|
|
580
|
+
let foundHookKey = false;
|
|
581
|
+
for (let k = 0; k < bodyLines.length; k += 1) {
|
|
582
|
+
if (hookKeyRegex.test(bodyLines[k])) {
|
|
583
|
+
bodyLines[k] = "hooks = true";
|
|
584
|
+
foundHookKey = true;
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (!foundHookKey) {
|
|
589
|
+
// Insert hooks=true at the top of the body (right after the header)
|
|
590
|
+
bodyLines.unshift("hooks = true");
|
|
591
|
+
}
|
|
592
|
+
const trimmed = trimTrailingBlanks(bodyLines);
|
|
593
|
+
const newLines = [
|
|
594
|
+
...lines.slice(0, section.startIdx),
|
|
595
|
+
lines[section.startIdx],
|
|
596
|
+
...trimmed,
|
|
597
|
+
...(section.endIdx < lines.length ? [""] : []),
|
|
598
|
+
...lines.slice(section.endIdx),
|
|
599
|
+
];
|
|
600
|
+
const out = newLines.join("\n");
|
|
601
|
+
// Always end with a single trailing newline for true idempotency.
|
|
602
|
+
return out.endsWith("\n") ? out : out + "\n";
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Insert or replace a `[mcp_servers.<name>]` block with the given body lines.
|
|
606
|
+
* Body lines should NOT include the header line. Idempotent.
|
|
607
|
+
*/
|
|
608
|
+
function upsertMcpServer(content, serverName, bodyLines) {
|
|
609
|
+
const sectionName = `mcp_servers.${serverName}`;
|
|
610
|
+
const lines = content.split("\n");
|
|
611
|
+
const section = findTomlSection(lines, sectionName);
|
|
612
|
+
const header = `[${sectionName}]`;
|
|
613
|
+
const block = [header, ...bodyLines];
|
|
614
|
+
if (section === null) {
|
|
615
|
+
return appendBlockWithSeparator(content, block);
|
|
616
|
+
}
|
|
617
|
+
// Replace existing block in place
|
|
618
|
+
const before = lines.slice(0, section.startIdx);
|
|
619
|
+
const after = lines.slice(section.endIdx);
|
|
620
|
+
const newLines = [
|
|
621
|
+
...before,
|
|
622
|
+
...block,
|
|
623
|
+
...(after.length > 0 ? [""] : []),
|
|
624
|
+
...after,
|
|
625
|
+
];
|
|
626
|
+
const out = newLines.join("\n");
|
|
627
|
+
return out.endsWith("\n") ? out : out + "\n";
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Remove a `[mcp_servers.<name>]` block entirely. Idempotent.
|
|
631
|
+
*
|
|
632
|
+
* Preserves the leading blank line that previously separated the removed
|
|
633
|
+
* block from the prior section — that blank stays as the separator between
|
|
634
|
+
* the prior section and whatever comes after. Collapses any consecutive
|
|
635
|
+
* blank lines that arise from the removal so we never end up with more
|
|
636
|
+
* than one blank line between sections.
|
|
637
|
+
*/
|
|
638
|
+
function removeMcpServer(content, serverName) {
|
|
639
|
+
const sectionName = `mcp_servers.${serverName}`;
|
|
640
|
+
const lines = content.split("\n");
|
|
641
|
+
const section = findTomlSection(lines, sectionName);
|
|
642
|
+
if (section === null) {
|
|
643
|
+
return content;
|
|
644
|
+
}
|
|
645
|
+
const newLines = [
|
|
646
|
+
...lines.slice(0, section.startIdx),
|
|
647
|
+
...lines.slice(section.endIdx),
|
|
648
|
+
];
|
|
649
|
+
// Collapse any 2+ consecutive blank lines (created by the removal) to one.
|
|
650
|
+
const collapsed = [];
|
|
651
|
+
let prevBlank = false;
|
|
652
|
+
for (const line of newLines) {
|
|
653
|
+
const isBlank = line.trim().length === 0;
|
|
654
|
+
if (isBlank && prevBlank) {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
collapsed.push(line);
|
|
658
|
+
prevBlank = isBlank;
|
|
659
|
+
}
|
|
660
|
+
const out = collapsed.join("\n");
|
|
661
|
+
return out.endsWith("\n") || out.length === 0 ? out : out + "\n";
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Render a body of inline TOML key=value lines from a record. Strings get
|
|
665
|
+
* quoted, arrays of strings get inline TOML array syntax, env nested table
|
|
666
|
+
* gets emitted as an inline table.
|
|
667
|
+
*/
|
|
668
|
+
function tomlBodyFromRecord(record) {
|
|
669
|
+
const out = [];
|
|
670
|
+
for (const [key, value] of Object.entries(record)) {
|
|
671
|
+
if (value === undefined || value === null) {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (typeof value === "string") {
|
|
675
|
+
out.push(`${key} = ${JSON.stringify(value)}`);
|
|
676
|
+
}
|
|
677
|
+
else if (typeof value === "number" || typeof value === "boolean") {
|
|
678
|
+
out.push(`${key} = ${value}`);
|
|
679
|
+
}
|
|
680
|
+
else if (Array.isArray(value)) {
|
|
681
|
+
const items = value.map((v) => {
|
|
682
|
+
if (typeof v === "string") {
|
|
683
|
+
return JSON.stringify(v);
|
|
684
|
+
}
|
|
685
|
+
if (typeof v === "number" || typeof v === "boolean") {
|
|
686
|
+
return String(v);
|
|
687
|
+
}
|
|
688
|
+
return JSON.stringify(v);
|
|
689
|
+
});
|
|
690
|
+
out.push(`${key} = [${items.join(", ")}]`);
|
|
691
|
+
}
|
|
692
|
+
else if (typeof value === "object") {
|
|
693
|
+
const inner = value;
|
|
694
|
+
const pairs = [];
|
|
695
|
+
for (const [k, v] of Object.entries(inner)) {
|
|
696
|
+
if (v === undefined || v === null) {
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
if (typeof v === "string") {
|
|
700
|
+
pairs.push(`${k} = ${JSON.stringify(v)}`);
|
|
701
|
+
}
|
|
702
|
+
else if (typeof v === "number" || typeof v === "boolean") {
|
|
703
|
+
pairs.push(`${k} = ${v}`);
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
pairs.push(`${k} = ${JSON.stringify(v)}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
out.push(`${key} = { ${pairs.join(", ")} }`);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return out;
|
|
713
|
+
}
|
|
714
|
+
// ─── AGENTS.md block merge ────────────────────────────────────────────────
|
|
715
|
+
exports.AGENTS_MD_START_MARKER = "<!-- ironbee:start -->";
|
|
716
|
+
exports.AGENTS_MD_END_MARKER = "<!-- ironbee:end -->";
|
|
717
|
+
/**
|
|
718
|
+
* Upsert the IronBee-managed block in an AGENTS.md file. The block is
|
|
719
|
+
* delimited by HTML comment markers; user content outside the markers is
|
|
720
|
+
* preserved verbatim. If markers don't exist, the block is appended.
|
|
721
|
+
*/
|
|
722
|
+
function upsertAgentsMdBlock(existing, blockContent) {
|
|
723
|
+
const wrapped = `${exports.AGENTS_MD_START_MARKER}\n${blockContent.trimEnd()}\n${exports.AGENTS_MD_END_MARKER}`;
|
|
724
|
+
const startIdx = existing.indexOf(exports.AGENTS_MD_START_MARKER);
|
|
725
|
+
const endIdx = existing.indexOf(exports.AGENTS_MD_END_MARKER);
|
|
726
|
+
if (startIdx >= 0 && endIdx > startIdx) {
|
|
727
|
+
const afterStart = existing.slice(0, startIdx);
|
|
728
|
+
const afterEnd = existing.slice(endIdx + exports.AGENTS_MD_END_MARKER.length);
|
|
729
|
+
return afterStart + wrapped + afterEnd;
|
|
730
|
+
}
|
|
731
|
+
if (existing.trim().length === 0) {
|
|
732
|
+
return wrapped + "\n";
|
|
733
|
+
}
|
|
734
|
+
return existing.trimEnd() + "\n\n" + wrapped + "\n";
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Strip the IronBee-managed block from AGENTS.md. Returns null when the
|
|
738
|
+
* resulting file would be empty (caller can delete the file). Preserves
|
|
739
|
+
* any user content outside the markers.
|
|
740
|
+
*/
|
|
741
|
+
function stripAgentsMdBlock(existing) {
|
|
742
|
+
const startIdx = existing.indexOf(exports.AGENTS_MD_START_MARKER);
|
|
743
|
+
const endIdx = existing.indexOf(exports.AGENTS_MD_END_MARKER);
|
|
744
|
+
if (startIdx < 0 || endIdx < startIdx) {
|
|
745
|
+
return existing.trim().length === 0 ? null : existing;
|
|
746
|
+
}
|
|
747
|
+
const before = existing.slice(0, startIdx).trimEnd();
|
|
748
|
+
const after = existing.slice(endIdx + exports.AGENTS_MD_END_MARKER.length).trimStart();
|
|
749
|
+
const combined = before + (before.length > 0 && after.length > 0 ? "\n\n" : "") + after;
|
|
750
|
+
if (combined.trim().length === 0) {
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
return combined.endsWith("\n") ? combined : combined + "\n";
|
|
754
|
+
}
|
|
755
|
+
// ─── Convenience for atomic Codex config write ────────────────────────────
|
|
756
|
+
function readCodexConfigToml() {
|
|
757
|
+
const p = codexConfigTomlPath();
|
|
758
|
+
if (!(0, fs_1.existsSync)(p)) {
|
|
759
|
+
return "";
|
|
760
|
+
}
|
|
761
|
+
try {
|
|
762
|
+
return (0, fs_1.readFileSync)(p, "utf-8");
|
|
763
|
+
}
|
|
764
|
+
catch (e) {
|
|
765
|
+
logger_1.logger.debug(`failed to read ${p}: ${e}`);
|
|
766
|
+
return "";
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
function writeCodexConfigToml(content) {
|
|
770
|
+
const p = codexConfigTomlPath();
|
|
771
|
+
try {
|
|
772
|
+
(0, fs_1.writeFileSync)(p, content);
|
|
773
|
+
}
|
|
774
|
+
catch (e) {
|
|
775
|
+
logger_1.logger.debug(`failed to write ${p}: ${e}`);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
function codexConfigTomlPath() {
|
|
779
|
+
return (0, path_1.join)((0, os_1.homedir)(), ".codex", "config.toml");
|
|
780
|
+
}
|
|
781
|
+
function codexHooksJsonPath() {
|
|
782
|
+
return (0, path_1.join)((0, os_1.homedir)(), ".codex", "hooks.json");
|
|
783
|
+
}
|
|
784
|
+
//# sourceMappingURL=util.js.map
|