@ironbee-ai/cli 0.15.0 → 0.16.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 +2 -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 +9 -0
- 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 +14 -0
- package/dist/clients/claude/hooks/clear-verdict.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 +1 -0
- package/dist/clients/claude/index.d.ts.map +1 -1
- package/dist/clients/claude/index.js +7 -0
- 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 +299 -0
- package/dist/clients/codex/hooks/clear-verdict.js.map +1 -0
- package/dist/clients/codex/hooks/require-verdict.d.ts +30 -0
- package/dist/clients/codex/hooks/require-verdict.d.ts.map +1 -0
- package/dist/clients/codex/hooks/require-verdict.js +109 -0
- package/dist/clients/codex/hooks/require-verdict.js.map +1 -0
- package/dist/clients/codex/hooks/require-verification.d.ts +12 -0
- package/dist/clients/codex/hooks/require-verification.d.ts.map +1 -0
- package/dist/clients/codex/hooks/require-verification.js +136 -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 +42 -0
- package/dist/clients/codex/index.d.ts.map +1 -0
- package/dist/clients/codex/index.js +427 -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 +12 -3
- package/dist/clients/cursor/hooks/clear-verdict.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 +1 -0
- package/dist/clients/cursor/index.d.ts.map +1 -1
- package/dist/clients/cursor/index.js +13 -0
- 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 +12 -0
- 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/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.map +1 -1
- package/dist/hooks/core/activity-end.js +4 -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/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.map +1 -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/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
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
* read-once-locally pattern.
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.formatHexAsUuid = void 0;
|
|
27
28
|
exports.deriveStepId = deriveStepId;
|
|
28
29
|
exports.deriveTurnId = deriveTurnId;
|
|
29
|
-
exports.formatHexAsUuid = formatHexAsUuid;
|
|
30
30
|
exports.deriveSessionAnalyticsEventId = deriveSessionAnalyticsEventId;
|
|
31
31
|
exports.deriveTurnEventId = deriveTurnEventId;
|
|
32
32
|
exports.deriveStepEventId = deriveStepEventId;
|
|
@@ -36,31 +36,40 @@ exports.projectDelta = projectDelta;
|
|
|
36
36
|
exports.projectDeltaInternal = projectDeltaInternal;
|
|
37
37
|
const node_crypto_1 = require("node:crypto");
|
|
38
38
|
const diff_1 = require("diff");
|
|
39
|
-
const
|
|
40
|
-
const
|
|
39
|
+
const event_1 = require("../../lib/event");
|
|
40
|
+
const logger_1 = require("../../lib/logger");
|
|
41
|
+
const types_1 = require("../shared/types");
|
|
41
42
|
const pricing_1 = require("./pricing");
|
|
42
|
-
const errors_1 = require("
|
|
43
|
-
const classifier_1 = require("
|
|
43
|
+
const errors_1 = require("../shared/errors");
|
|
44
|
+
const classifier_1 = require("../shared/classifier");
|
|
44
45
|
// ─────────────────────────────────────────────────────────────────────────
|
|
45
46
|
// Constants — keep in sync with /insights:332-349 + 651-677 + 651-677
|
|
46
47
|
// ─────────────────────────────────────────────────────────────────────────
|
|
48
|
+
// Kept in cross-client parity with Codex `languageFromPath`
|
|
49
|
+
// (`src/analytics/codex/projection.ts`). The two pipelines feed the same
|
|
50
|
+
// `code_changes.languages` map on the wire — a backend aggregating Claude +
|
|
51
|
+
// Codex sessions sees one key `"TypeScript"` regardless of source, NOT
|
|
52
|
+
// `"TypeScript"` (Codex side) + a silently dropped Claude `.kt` / `.swift`
|
|
53
|
+
// edit. Real corpus: Claude sessions editing `.php` / `.kt` / `.scala` /
|
|
54
|
+
// `.swift` etc. previously emitted zero `languages[...]` entries because the
|
|
55
|
+
// table didn't cover them — silent data loss vs the Codex side. Add new
|
|
56
|
+
// extensions to BOTH tables in lockstep.
|
|
47
57
|
const EXTENSION_TO_LANGUAGE = {
|
|
48
|
-
".ts": "TypeScript",
|
|
49
|
-
".
|
|
50
|
-
".
|
|
51
|
-
".
|
|
52
|
-
".
|
|
53
|
-
".
|
|
54
|
-
".
|
|
55
|
-
".
|
|
56
|
-
".
|
|
57
|
-
".md": "Markdown",
|
|
58
|
-
".json": "JSON",
|
|
59
|
-
".
|
|
60
|
-
".
|
|
61
|
-
".
|
|
62
|
-
".
|
|
63
|
-
".html": "HTML",
|
|
58
|
+
".ts": "TypeScript", ".tsx": "TypeScript",
|
|
59
|
+
".js": "JavaScript", ".jsx": "JavaScript", ".mjs": "JavaScript", ".cjs": "JavaScript",
|
|
60
|
+
".py": "Python", ".rb": "Ruby", ".go": "Go", ".rs": "Rust",
|
|
61
|
+
".java": "Java", ".kt": "Kotlin", ".scala": "Scala",
|
|
62
|
+
".swift": "Swift", ".m": "Objective-C", ".mm": "Objective-C",
|
|
63
|
+
".c": "C", ".h": "C", ".cpp": "C++", ".cc": "C++", ".hpp": "C++",
|
|
64
|
+
".cs": "C#", ".vb": "VB",
|
|
65
|
+
".php": "PHP", ".html": "HTML", ".htm": "HTML",
|
|
66
|
+
".css": "CSS", ".scss": "CSS", ".sass": "CSS", ".less": "CSS",
|
|
67
|
+
".md": "Markdown", ".mdx": "Markdown",
|
|
68
|
+
".json": "JSON", ".yaml": "YAML", ".yml": "YAML", ".toml": "TOML", ".xml": "XML",
|
|
69
|
+
".sh": "Shell", ".bash": "Shell", ".zsh": "Shell",
|
|
70
|
+
".sql": "SQL", ".graphql": "GraphQL", ".proto": "Protocol Buffer",
|
|
71
|
+
".ex": "Elixir", ".exs": "Elixir", ".erl": "Erlang",
|
|
72
|
+
".lua": "Lua", ".dart": "Dart", ".clj": "Clojure",
|
|
64
73
|
};
|
|
65
74
|
const INTERRUPT_MARKER = "[Request interrupted by user";
|
|
66
75
|
// Response-time clamp per /insights:633.
|
|
@@ -125,12 +134,33 @@ function extractBashSubcommand(cmd) {
|
|
|
125
134
|
if (stripped.length === 0) {
|
|
126
135
|
return undefined;
|
|
127
136
|
}
|
|
128
|
-
|
|
137
|
+
// Path-strip the binary token before the multi-subcommand set lookup —
|
|
138
|
+
// without this, `/usr/bin/git status` misses
|
|
139
|
+
// `KNOWN_MULTI_SUBCOMMAND_BINARIES.has("/usr/bin/git")` and drops to the
|
|
140
|
+
// single-binary fallback, losing the "status" / "install" verb. Same
|
|
141
|
+
// agent activity (`git status` vs `/usr/bin/git status`) would then ship
|
|
142
|
+
// two different wire shapes — cross-session aggregation breaks even
|
|
143
|
+
// within a single Claude project. Mirrors the Codex-side fix at
|
|
144
|
+
// analytics/codex/projection.ts:425. `extractBashBinary` deliberately
|
|
145
|
+
// keeps the full path (documented Claude-vs-Codex divergence on
|
|
146
|
+
// `bash_binaries`), but `bash_subcommands` has no such divergence —
|
|
147
|
+
// verb granularity is the load-bearing signal here.
|
|
148
|
+
const rawBinary = stripped[0];
|
|
149
|
+
const binary = rawBinary.split(/[\\/]/).pop() ?? rawBinary;
|
|
150
|
+
// Guard against empty/whitespace-only commands ("", " ", env-vars-only).
|
|
151
|
+
// `"".trim().split(/\s+/)` returns `[""]` (single empty-string element),
|
|
152
|
+
// not `[]` — the env-var skip doesn't filter the empty token, so
|
|
153
|
+
// `stripped = [""]` and `binary = ""`. The caller checks `sub !== undefined`,
|
|
154
|
+
// so the empty string would slip through and ship `bash_subcommands[""]: N`
|
|
155
|
+
// on the wire. Codex side filters via `if (sub)` (truthy check) but
|
|
156
|
+
// Claude's caller uses `!== undefined` — defending at the function level
|
|
157
|
+
// covers both call sites and any future caller.
|
|
158
|
+
if (binary.length === 0) {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
129
161
|
if (stripped.length === 1) {
|
|
130
162
|
return binary;
|
|
131
163
|
}
|
|
132
|
-
// Only include subcommand for known multi-subcommand CLIs AND when the
|
|
133
|
-
// second token has a safe identifier shape. Otherwise just emit the binary.
|
|
134
164
|
if (KNOWN_MULTI_SUBCOMMAND_BINARIES.has(binary)
|
|
135
165
|
&& SUBCOMMAND_TOKEN_RE.test(stripped[1])) {
|
|
136
166
|
return `${binary} ${stripped[1]}`;
|
|
@@ -478,15 +508,13 @@ function deriveTurnId(sessionId, turnIndex, startTime) {
|
|
|
478
508
|
.slice(0, 16);
|
|
479
509
|
}
|
|
480
510
|
/**
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
511
|
+
* Re-exported from `src/lib/event.ts` (single source of truth). Kept here
|
|
512
|
+
* for backwards compatibility with existing consumers (`src/import/ids.ts`,
|
|
513
|
+
* Codex `projection.ts`, status-snapshot etc.) that import the
|
|
514
|
+
* symbol from this module.
|
|
485
515
|
*/
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
+ `${hex32.slice(16, 20)}-${hex32.slice(20, 32)}`;
|
|
489
|
-
}
|
|
516
|
+
var event_2 = require("../../lib/event");
|
|
517
|
+
Object.defineProperty(exports, "formatHexAsUuid", { enumerable: true, get: function () { return event_2.formatHexAsUuid; } });
|
|
490
518
|
/**
|
|
491
519
|
* Deterministic Event.id for `session_analytics` wire records.
|
|
492
520
|
* `sha256("session_analytics:" + session_id)`, formatted as UUID. One id
|
|
@@ -506,7 +534,7 @@ function deriveSessionAnalyticsEventId(sessionId) {
|
|
|
506
534
|
const hex = (0, node_crypto_1.createHash)("sha256")
|
|
507
535
|
.update(`session_analytics:${sessionId}`)
|
|
508
536
|
.digest("hex");
|
|
509
|
-
return formatHexAsUuid(hex.slice(0, 32));
|
|
537
|
+
return (0, event_1.formatHexAsUuid)(hex.slice(0, 32));
|
|
510
538
|
}
|
|
511
539
|
/**
|
|
512
540
|
* Deterministic Event.id for `session_turn_analytics` wire records.
|
|
@@ -517,7 +545,7 @@ function deriveTurnEventId(sessionId, turnId) {
|
|
|
517
545
|
const hex = (0, node_crypto_1.createHash)("sha256")
|
|
518
546
|
.update(`session_turn_analytics:${sessionId}:${turnId}`)
|
|
519
547
|
.digest("hex");
|
|
520
|
-
return formatHexAsUuid(hex.slice(0, 32));
|
|
548
|
+
return (0, event_1.formatHexAsUuid)(hex.slice(0, 32));
|
|
521
549
|
}
|
|
522
550
|
/**
|
|
523
551
|
* Deterministic Event.id for `session_turn_step_analytics` wire records.
|
|
@@ -528,7 +556,7 @@ function deriveStepEventId(sessionId, stepId) {
|
|
|
528
556
|
const hex = (0, node_crypto_1.createHash)("sha256")
|
|
529
557
|
.update(`session_turn_step_analytics:${sessionId}:${stepId}`)
|
|
530
558
|
.digest("hex");
|
|
531
|
-
return formatHexAsUuid(hex.slice(0, 32));
|
|
559
|
+
return (0, event_1.formatHexAsUuid)(hex.slice(0, 32));
|
|
532
560
|
}
|
|
533
561
|
/**
|
|
534
562
|
* Open a fresh turn from the human-user prompt that started it. Computes
|
|
@@ -1095,6 +1123,20 @@ function projectDelta(input) {
|
|
|
1095
1123
|
// Reported back via DeltaInternal.seen_assistant_message_ids.
|
|
1096
1124
|
const seenAssistantMessageIds = new Set(input.priorSeenAssistantMessageIds ?? []);
|
|
1097
1125
|
const newAssistantMessageIdsThisSlice = [];
|
|
1126
|
+
// Anthropic API tool_use_id dedup. Claude Code 2.1+ transcript writer
|
|
1127
|
+
// splits a single API response's content blocks across multiple JSONL
|
|
1128
|
+
// lines (each carrying the SAME message.id but DIFFERENT tool_use
|
|
1129
|
+
// blocks per chunk — empirically verified against real transcripts:
|
|
1130
|
+
// 170 assistant lines / 84 distinct msg_ids on a 19-min session,
|
|
1131
|
+
// every multi-line msg_id had blocks of distinct types per chunk).
|
|
1132
|
+
// msg_id dedup alone would drop the streaming-split chunks entirely,
|
|
1133
|
+
// losing ~60% of tool_uses on real sessions. Instead, content-block
|
|
1134
|
+
// walks run on EVERY chunk and individual `tool_use` blocks are deduped
|
|
1135
|
+
// by their stable Anthropic-assigned `id`. This ALSO catches the
|
|
1136
|
+
// legacy "true duplicate re-emit" case (where the same block was
|
|
1137
|
+
// persisted multiple times verbatim — same id => skip).
|
|
1138
|
+
const seenToolUseIds = new Set(input.priorSeenToolUseIds ?? []);
|
|
1139
|
+
const newToolUseIdsThisSlice = [];
|
|
1098
1140
|
// Idle attribution: walking the timeline, the gap BEFORE a human-user
|
|
1099
1141
|
// message is "idle" (user typing/thinking/away). Every other gap is
|
|
1100
1142
|
// "active" (model + tools + agent loop). Seed `priorTsMs` from the prior
|
|
@@ -1158,218 +1200,347 @@ function projectDelta(input) {
|
|
|
1158
1200
|
priorTsMs = tsMillis;
|
|
1159
1201
|
}
|
|
1160
1202
|
if (line.type === "assistant" && line.message !== undefined) {
|
|
1161
|
-
// Anthropic msg_id dedup: skip
|
|
1162
|
-
//
|
|
1163
|
-
//
|
|
1164
|
-
//
|
|
1165
|
-
//
|
|
1203
|
+
// Anthropic msg_id dedup: skip PER-MESSAGE work (counters,
|
|
1204
|
+
// tokens, cost, model, context, EMITTER, step open, models[*]
|
|
1205
|
+
// map, context-tokens bucket, api_request emit, end-of-msg
|
|
1206
|
+
// classifier's cost accumulation) when this API response was
|
|
1207
|
+
// already counted via a prior line/slice. Claude Code 2.1+
|
|
1208
|
+
// splits ONE API response's content blocks across multiple
|
|
1209
|
+
// JSONL lines that share the same msg_id, so the per-message
|
|
1210
|
+
// counters MUST run once per msg_id. CONTENT BLOCKS
|
|
1211
|
+
// (tool_use, text, thinking) are walked on EVERY chunk
|
|
1212
|
+
// regardless and deduped at block level via `seenToolUseIds`
|
|
1213
|
+
// (see below) — the older "continue on msg_id seen" gate
|
|
1214
|
+
// would drop 60% of tool_uses on real transcripts.
|
|
1166
1215
|
const msgId = line.message.id;
|
|
1216
|
+
let isFirstChunkOfMsg = true;
|
|
1167
1217
|
if (typeof msgId === "string" && msgId.length > 0) {
|
|
1168
1218
|
if (seenAssistantMessageIds.has(msgId)) {
|
|
1169
|
-
|
|
1170
|
-
|
|
1219
|
+
isFirstChunkOfMsg = false;
|
|
1220
|
+
}
|
|
1221
|
+
else {
|
|
1222
|
+
seenAssistantMessageIds.add(msgId);
|
|
1223
|
+
newAssistantMessageIdsThisSlice.push(msgId);
|
|
1171
1224
|
}
|
|
1172
|
-
seenAssistantMessageIds.add(msgId);
|
|
1173
|
-
newAssistantMessageIdsThisSlice.push(msgId);
|
|
1174
|
-
}
|
|
1175
|
-
assistantResponseCount += 1;
|
|
1176
|
-
assistantTurnIndex += 1;
|
|
1177
|
-
// Track timestamp for response-time gap to the next user message.
|
|
1178
|
-
if (tsMillis !== null) {
|
|
1179
|
-
lastAssistantMs = tsMillis;
|
|
1180
1225
|
}
|
|
1181
|
-
//
|
|
1182
|
-
//
|
|
1183
|
-
//
|
|
1184
|
-
//
|
|
1185
|
-
//
|
|
1186
|
-
//
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1226
|
+
// msgCost + advisorCostThisMsg are computed inside the
|
|
1227
|
+
// per-message gate but consumed by the end-of-message
|
|
1228
|
+
// classifier which runs on every chunk (retry-detection
|
|
1229
|
+
// mutates msgBuckets-driven flags per chunk). Hoist to outer
|
|
1230
|
+
// scope so they retain their value across the gate; default
|
|
1231
|
+
// to 0 on subsequent chunks so `currentTurn.cost_usd += ...`
|
|
1232
|
+
// doesn't double-count.
|
|
1233
|
+
let msgCost = 0;
|
|
1234
|
+
let advisorCostThisMsg = 0;
|
|
1235
|
+
if (isFirstChunkOfMsg) {
|
|
1236
|
+
assistantResponseCount += 1;
|
|
1237
|
+
assistantTurnIndex += 1;
|
|
1238
|
+
// Track timestamp for response-time gap to the next user message.
|
|
1239
|
+
if (tsMillis !== null) {
|
|
1240
|
+
lastAssistantMs = tsMillis;
|
|
1191
1241
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1242
|
+
// Per-turn: bump assistant_messages + last_activity_time.
|
|
1243
|
+
// Per-step: every assistant message starts a new step. If a
|
|
1244
|
+
// prior step was open in this turn, close it (push to
|
|
1245
|
+
// completed_steps) before opening the new one. Step start_time
|
|
1246
|
+
// is this assistant's timestamp (or lastTimestamp fallback for
|
|
1247
|
+
// determinism when ts is missing — same rule as openTurn).
|
|
1248
|
+
if (currentTurn !== null) {
|
|
1249
|
+
currentTurn.assistant_messages += 1;
|
|
1250
|
+
if (typeof tsString === "string" && tsString.length > 0) {
|
|
1251
|
+
currentTurn.last_activity_time = tsString;
|
|
1252
|
+
}
|
|
1253
|
+
if (currentTurn.current_step !== undefined) {
|
|
1254
|
+
currentTurn.completed_steps.push(currentTurn.current_step);
|
|
1255
|
+
}
|
|
1256
|
+
const stepStart = typeof tsString === "string" && tsString.length > 0
|
|
1257
|
+
? tsString
|
|
1258
|
+
: lastTimestamp;
|
|
1259
|
+
currentTurn.current_step = openStep(currentTurn.next_step_index, stepStart);
|
|
1260
|
+
currentTurn.next_step_index += 1;
|
|
1194
1261
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1262
|
+
// Normalize bracketed runtime suffixes (e.g. `claude-opus-4-7[1m]`
|
|
1263
|
+
// → `claude-opus-4-7`) at the single capture site so every
|
|
1264
|
+
// downstream use ships a consistent canonical id: `api_request.model`,
|
|
1265
|
+
// `session_analytics.models[<key>]` map keys, `session_turn_analytics`
|
|
1266
|
+
// / `session_turn_step_analytics` per-turn / per-step `models`
|
|
1267
|
+
// map keys. Without this, `session_status.model` (already
|
|
1268
|
+
// normalized at clients/claude/hooks/session-status.ts:222
|
|
1269
|
+
// via `normalizeModelId`) emitted `claude-opus-4-7` while
|
|
1270
|
+
// `api_request.model` and `models[*]` keys shipped raw
|
|
1271
|
+
// `claude-opus-4-7[1m]` — backend dashboards joining
|
|
1272
|
+
// `api_request` ↔ `session_status` on `model` saw two
|
|
1273
|
+
// strings for one model, and `Σ session_analytics.models[*]`
|
|
1274
|
+
// didn't reconcile cross-event. The `[…]` suffix is
|
|
1275
|
+
// redundant on the wire — context-window size carries the
|
|
1276
|
+
// effective window through `session_status.context_window`.
|
|
1277
|
+
const rawModel = line.message.model;
|
|
1278
|
+
const model = rawModel === undefined
|
|
1279
|
+
? undefined
|
|
1280
|
+
: rawModel.replace(/\[[^\]]*\]/g, "").trim();
|
|
1281
|
+
const usage = line.message.usage;
|
|
1282
|
+
// Tokens — session-wide totals
|
|
1283
|
+
const msgInput = usage?.input_tokens ?? 0;
|
|
1284
|
+
const msgOutput = usage?.output_tokens ?? 0;
|
|
1285
|
+
const msgCacheCreation = usage?.cache_creation_input_tokens ?? 0;
|
|
1286
|
+
const msgCacheRead = usage?.cache_read_input_tokens ?? 0;
|
|
1287
|
+
// Cache-creation 5m / 1h split (Anthropic ephemeral tiers). When
|
|
1288
|
+
// present, used in cost calc to bill 1h tokens at the higher
|
|
1289
|
+
// rate; falls back to a single sum at 5m rate when absent.
|
|
1290
|
+
const msgCC5m = usage?.cache_creation?.ephemeral_5m_input_tokens ?? 0;
|
|
1291
|
+
const msgCC1h = usage?.cache_creation?.ephemeral_1h_input_tokens ?? 0;
|
|
1292
|
+
const hasCcSplit = (msgCC5m + msgCC1h) > 0;
|
|
1293
|
+
// Server tool use (web_search currently the only billable)
|
|
1294
|
+
const msgWebSearchReqs = usage?.server_tool_use?.web_search_requests ?? 0;
|
|
1295
|
+
// Fast mode tier (Opus 4.6 only — 6× regular rate)
|
|
1296
|
+
const msgSpeed = usage?.speed;
|
|
1297
|
+
inputTokens += msgInput;
|
|
1298
|
+
outputTokens += msgOutput;
|
|
1299
|
+
cacheCreationTokens += msgCacheCreation;
|
|
1300
|
+
cacheReadTokens += msgCacheRead;
|
|
1301
|
+
// Per-turn token totals — same additive rule as session-level.
|
|
1302
|
+
// Per-step: mirror onto the just-opened step.
|
|
1303
|
+
if (currentTurn !== null) {
|
|
1304
|
+
currentTurn.input_tokens += msgInput;
|
|
1305
|
+
currentTurn.output_tokens += msgOutput;
|
|
1306
|
+
currentTurn.cache_creation_tokens += msgCacheCreation;
|
|
1307
|
+
currentTurn.cache_read_tokens += msgCacheRead;
|
|
1308
|
+
if (currentTurn.current_step !== undefined) {
|
|
1309
|
+
currentTurn.current_step.input_tokens += msgInput;
|
|
1310
|
+
currentTurn.current_step.output_tokens += msgOutput;
|
|
1311
|
+
currentTurn.current_step.cache_creation_tokens += msgCacheCreation;
|
|
1312
|
+
currentTurn.current_step.cache_read_tokens += msgCacheRead;
|
|
1313
|
+
}
|
|
1234
1314
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
.
|
|
1299
|
-
.
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1315
|
+
// Per-message cost — looked up by model id (family fallback +
|
|
1316
|
+
// fast-mode tier when speed=="fast" on Opus 4.6). Unknown
|
|
1317
|
+
// family contributes 0. computeMessageCostUsd handles the
|
|
1318
|
+
// 5m/1h cache split + web_search add-on.
|
|
1319
|
+
const pricing = typeof model === "string" && model.length > 0
|
|
1320
|
+
? (0, pricing_1.lookupPricingForUsage)(model, msgSpeed)
|
|
1321
|
+
: null;
|
|
1322
|
+
// Assignment (not declaration) — msgCost was hoisted to outer
|
|
1323
|
+
// scope so the end-of-message classifier (which runs on every
|
|
1324
|
+
// chunk) can read it; on subsequent chunks the gate keeps
|
|
1325
|
+
// msgCost at 0 so cost isn't double-counted.
|
|
1326
|
+
msgCost = (0, pricing_1.computeMessageCostUsd)({
|
|
1327
|
+
input_tokens: msgInput,
|
|
1328
|
+
output_tokens: msgOutput,
|
|
1329
|
+
cache_creation_tokens: msgCacheCreation,
|
|
1330
|
+
cache_read_tokens: msgCacheRead,
|
|
1331
|
+
...(hasCcSplit ? {
|
|
1332
|
+
cache_creation_5m_tokens: msgCC5m,
|
|
1333
|
+
cache_creation_1h_tokens: msgCC1h,
|
|
1334
|
+
} : {}),
|
|
1335
|
+
web_search_requests: msgWebSearchReqs,
|
|
1336
|
+
}, pricing);
|
|
1337
|
+
costUsd += msgCost;
|
|
1338
|
+
// Per-API-request event emission. One record per non-duplicate
|
|
1339
|
+
// assistant line — covers both successful API responses and
|
|
1340
|
+
// terminal failure synthetic placeholders (`isApiErrorMessage`).
|
|
1341
|
+
// Body-only struct; emit wraps with the Event envelope.
|
|
1342
|
+
//
|
|
1343
|
+
// Field semantics verified against real transcripts:
|
|
1344
|
+
// - request_id: top-level `requestId` ONLY on success lines
|
|
1345
|
+
// (failure lines carry no join key → null).
|
|
1346
|
+
// - error: top-level `error` ONLY on failure lines.
|
|
1347
|
+
// - status_code: top-level `apiErrorStatus` rarely set even
|
|
1348
|
+
// on failures (~5% — only explicit HTTP errors like 429).
|
|
1349
|
+
// - speed: `usage.speed` typically "standard"; null on
|
|
1350
|
+
// synthetic-failure placeholder messages.
|
|
1351
|
+
// - duration: NOT in transcript at all → always null here
|
|
1352
|
+
// (transcript-derived). Server-side runtime emitters fill
|
|
1353
|
+
// this with real per-call latency.
|
|
1354
|
+
// - cost_usd: derived via pricing × tokens (= 0 on failures
|
|
1355
|
+
// since tokens are zero).
|
|
1356
|
+
const isApiErrorLine = line.isApiErrorMessage === true;
|
|
1357
|
+
const apiRequestId = typeof line.requestId === "string" && line.requestId.length > 0
|
|
1358
|
+
? line.requestId
|
|
1359
|
+
: null;
|
|
1360
|
+
const apiErrorStr = isApiErrorLine && typeof line.error === "string"
|
|
1361
|
+
? line.error
|
|
1362
|
+
: null;
|
|
1363
|
+
const apiStatusCode = isApiErrorLine && typeof line.apiErrorStatus === "number"
|
|
1364
|
+
? line.apiErrorStatus
|
|
1365
|
+
: null;
|
|
1366
|
+
const apiSpeed = typeof msgSpeed === "string" && msgSpeed.length > 0
|
|
1367
|
+
? msgSpeed
|
|
1368
|
+
: null;
|
|
1369
|
+
const apiTimestampMs = tsMillis ?? Date.now();
|
|
1370
|
+
// Event.id source: transcript line's top-level `uuid`. Verified
|
|
1371
|
+
// 100% presence on real transcripts (success + failure). Falls
|
|
1372
|
+
// back to a deterministic UUID-shaped id derived from
|
|
1373
|
+
// sha256(session_id|msg_id|timestamp) when uuid is missing
|
|
1374
|
+
// (defensive — never observed in production data; Cursor
|
|
1375
|
+
// transcripts have no uuid either way and don't reach this
|
|
1376
|
+
// path because they're skipped at emit-time).
|
|
1377
|
+
const apiEventId = typeof line.uuid === "string" && line.uuid.length > 0
|
|
1378
|
+
? line.uuid
|
|
1379
|
+
: (0, event_1.formatHexAsUuid)((0, node_crypto_1.createHash)("sha256")
|
|
1380
|
+
.update(`api_request:${input.sessionId}:${msgId ?? "anon"}:${apiTimestampMs}`)
|
|
1381
|
+
.digest("hex")
|
|
1382
|
+
.slice(0, 32));
|
|
1383
|
+
apiRequestEvents.push({
|
|
1384
|
+
id: apiEventId,
|
|
1385
|
+
timestamp_ms: apiTimestampMs,
|
|
1386
|
+
request_id: apiRequestId,
|
|
1387
|
+
success: !isApiErrorLine,
|
|
1388
|
+
error: apiErrorStr,
|
|
1389
|
+
status_code: apiStatusCode,
|
|
1390
|
+
model: typeof model === "string" && model.length > 0 ? model : "<unknown>",
|
|
1391
|
+
speed: apiSpeed,
|
|
1392
|
+
input_tokens: msgInput,
|
|
1393
|
+
output_tokens: msgOutput,
|
|
1394
|
+
cache_read_tokens: msgCacheRead,
|
|
1395
|
+
cache_creation_tokens: msgCacheCreation,
|
|
1396
|
+
cost_usd: msgCost,
|
|
1397
|
+
duration: null,
|
|
1398
|
+
});
|
|
1399
|
+
// Advisor sub-call recursion. `usage.iterations` may carry
|
|
1400
|
+
// entries typed `"advisor_message"` whose tokens are billed
|
|
1401
|
+
// separately — they're NOT included in the parent usage.
|
|
1402
|
+
// Each advisor sub-call goes to unattributed_cost (no per-tool
|
|
1403
|
+
// attribution; advisor is a server-side recursive call,
|
|
1404
|
+
// priced at its own model's rate). Other iteration types
|
|
1405
|
+
// (notably `"message"` which mirrors the parent) are skipped.
|
|
1406
|
+
// `advisorCostThisMsg` is declared in the outer scope (above
|
|
1407
|
+
// the isFirstChunkOfMsg gate) for the same reason as
|
|
1408
|
+
// msgCost — end-of-message classifier reads it on every
|
|
1409
|
+
// chunk; subsequent chunks see 0 (gate not entered).
|
|
1410
|
+
// Track advisor token totals across iterations so they can
|
|
1411
|
+
// be folded into session/turn/step usage AFTER the loop —
|
|
1412
|
+
// mirrors how `advisorCostThisMsg` gets folded into
|
|
1413
|
+
// `costUsd` at line ~1820. Without this fold, per-model
|
|
1414
|
+
// sums diverge from session totals (round 86a fixed cost
|
|
1415
|
+
// parity but left token parity broken):
|
|
1416
|
+
// Σ models[*].input_tokens > session.usage.input_tokens
|
|
1417
|
+
// by exactly `advisorInputThisMsg`, same for output/cache.
|
|
1418
|
+
// Backend dashboards reconciling "tokens by model" vs
|
|
1419
|
+
// "session usage" see the divergence.
|
|
1420
|
+
let advisorInputThisMsg = 0;
|
|
1421
|
+
let advisorOutputThisMsg = 0;
|
|
1422
|
+
let advisorCacheCreationThisMsg = 0;
|
|
1423
|
+
let advisorCacheReadThisMsg = 0;
|
|
1424
|
+
const iterations = usage?.iterations;
|
|
1425
|
+
if (Array.isArray(iterations)) {
|
|
1426
|
+
for (const it of iterations) {
|
|
1427
|
+
if (it.type !== "advisor_message") {
|
|
1428
|
+
continue;
|
|
1429
|
+
}
|
|
1430
|
+
const advModel = it.model;
|
|
1431
|
+
const advPricing = typeof advModel === "string" && advModel.length > 0
|
|
1432
|
+
? (0, pricing_1.lookupPricing)(advModel)
|
|
1433
|
+
: null;
|
|
1434
|
+
const advCC5m = it.cache_creation?.ephemeral_5m_input_tokens ?? 0;
|
|
1435
|
+
const advCC1h = it.cache_creation?.ephemeral_1h_input_tokens ?? 0;
|
|
1436
|
+
const advHasSplit = (advCC5m + advCC1h) > 0;
|
|
1437
|
+
const advInput = it.input_tokens ?? 0;
|
|
1438
|
+
const advOutput = it.output_tokens ?? 0;
|
|
1439
|
+
const advCacheCreation = it.cache_creation_input_tokens ?? 0;
|
|
1440
|
+
const advCacheRead = it.cache_read_input_tokens ?? 0;
|
|
1441
|
+
const advCost = (0, pricing_1.computeMessageCostUsd)({
|
|
1442
|
+
input_tokens: advInput,
|
|
1443
|
+
output_tokens: advOutput,
|
|
1444
|
+
cache_creation_tokens: advCacheCreation,
|
|
1445
|
+
cache_read_tokens: advCacheRead,
|
|
1446
|
+
...(advHasSplit ? {
|
|
1447
|
+
cache_creation_5m_tokens: advCC5m,
|
|
1448
|
+
cache_creation_1h_tokens: advCC1h,
|
|
1449
|
+
} : {}),
|
|
1450
|
+
}, advPricing);
|
|
1451
|
+
advisorCostThisMsg += advCost;
|
|
1452
|
+
advisorInputThisMsg += advInput;
|
|
1453
|
+
advisorOutputThisMsg += advOutput;
|
|
1454
|
+
advisorCacheCreationThisMsg += advCacheCreation;
|
|
1455
|
+
advisorCacheReadThisMsg += advCacheRead;
|
|
1456
|
+
// Route advisor cost + tokens into the advisor's
|
|
1457
|
+
// OWN per-model breakdown. Without this, session
|
|
1458
|
+
// `usage.cost_usd` includes advisor (line below)
|
|
1459
|
+
// but `Σ models[*].cost_usd` excludes it — backend
|
|
1460
|
+
// "cost by model" SQL would underreport by
|
|
1461
|
+
// exactly `advisorCostThisMsg` on every session
|
|
1462
|
+
// that triggered advisor sub-calls.
|
|
1463
|
+
if (typeof advModel === "string" && advModel.length > 0) {
|
|
1464
|
+
const advSlot = models[advModel] ?? {
|
|
1465
|
+
count: 0,
|
|
1466
|
+
input_tokens: 0,
|
|
1467
|
+
output_tokens: 0,
|
|
1468
|
+
cache_creation_tokens: 0,
|
|
1469
|
+
cache_read_tokens: 0,
|
|
1470
|
+
cost_usd: 0,
|
|
1471
|
+
};
|
|
1472
|
+
advSlot.count += 1;
|
|
1473
|
+
advSlot.input_tokens += advInput;
|
|
1474
|
+
advSlot.output_tokens += advOutput;
|
|
1475
|
+
advSlot.cache_creation_tokens += advCacheCreation;
|
|
1476
|
+
advSlot.cache_read_tokens += advCacheRead;
|
|
1477
|
+
advSlot.cost_usd += advCost;
|
|
1478
|
+
models[advModel] = advSlot;
|
|
1479
|
+
if (currentTurn !== null) {
|
|
1480
|
+
const advTurnSlot = currentTurn.models[advModel] ?? {
|
|
1481
|
+
count: 0,
|
|
1482
|
+
input_tokens: 0,
|
|
1483
|
+
output_tokens: 0,
|
|
1484
|
+
cache_creation_tokens: 0,
|
|
1485
|
+
cache_read_tokens: 0,
|
|
1486
|
+
cost_usd: 0,
|
|
1487
|
+
};
|
|
1488
|
+
advTurnSlot.count += 1;
|
|
1489
|
+
advTurnSlot.input_tokens += advInput;
|
|
1490
|
+
advTurnSlot.output_tokens += advOutput;
|
|
1491
|
+
advTurnSlot.cache_creation_tokens += advCacheCreation;
|
|
1492
|
+
advTurnSlot.cache_read_tokens += advCacheRead;
|
|
1493
|
+
advTurnSlot.cost_usd += advCost;
|
|
1494
|
+
currentTurn.models[advModel] = advTurnSlot;
|
|
1495
|
+
if (currentTurn.current_step !== undefined) {
|
|
1496
|
+
const advStepSlot = currentTurn.current_step.models[advModel] ?? {
|
|
1497
|
+
count: 0,
|
|
1498
|
+
input_tokens: 0,
|
|
1499
|
+
output_tokens: 0,
|
|
1500
|
+
cache_creation_tokens: 0,
|
|
1501
|
+
cache_read_tokens: 0,
|
|
1502
|
+
cost_usd: 0,
|
|
1503
|
+
};
|
|
1504
|
+
advStepSlot.count += 1;
|
|
1505
|
+
advStepSlot.input_tokens += advInput;
|
|
1506
|
+
advStepSlot.output_tokens += advOutput;
|
|
1507
|
+
advStepSlot.cache_creation_tokens += advCacheCreation;
|
|
1508
|
+
advStepSlot.cache_read_tokens += advCacheRead;
|
|
1509
|
+
advStepSlot.cost_usd += advCost;
|
|
1510
|
+
currentTurn.current_step.models[advModel] = advStepSlot;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1329
1514
|
}
|
|
1330
|
-
const advModel = it.model;
|
|
1331
|
-
const advPricing = typeof advModel === "string" && advModel.length > 0
|
|
1332
|
-
? (0, pricing_1.lookupPricing)(advModel)
|
|
1333
|
-
: null;
|
|
1334
|
-
const advCC5m = it.cache_creation?.ephemeral_5m_input_tokens ?? 0;
|
|
1335
|
-
const advCC1h = it.cache_creation?.ephemeral_1h_input_tokens ?? 0;
|
|
1336
|
-
const advHasSplit = (advCC5m + advCC1h) > 0;
|
|
1337
|
-
const advCost = (0, pricing_1.computeMessageCostUsd)({
|
|
1338
|
-
input_tokens: it.input_tokens ?? 0,
|
|
1339
|
-
output_tokens: it.output_tokens ?? 0,
|
|
1340
|
-
cache_creation_tokens: it.cache_creation_input_tokens ?? 0,
|
|
1341
|
-
cache_read_tokens: it.cache_read_input_tokens ?? 0,
|
|
1342
|
-
...(advHasSplit ? {
|
|
1343
|
-
cache_creation_5m_tokens: advCC5m,
|
|
1344
|
-
cache_creation_1h_tokens: advCC1h,
|
|
1345
|
-
} : {}),
|
|
1346
|
-
}, advPricing);
|
|
1347
|
-
advisorCostThisMsg += advCost;
|
|
1348
1515
|
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
cache_read_tokens: 0,
|
|
1361
|
-
cost_usd: 0,
|
|
1362
|
-
};
|
|
1363
|
-
slot.count += 1;
|
|
1364
|
-
slot.input_tokens += msgInput;
|
|
1365
|
-
slot.output_tokens += msgOutput;
|
|
1366
|
-
slot.cache_creation_tokens += msgCacheCreation;
|
|
1367
|
-
slot.cache_read_tokens += msgCacheRead;
|
|
1368
|
-
slot.cost_usd += msgCost;
|
|
1369
|
-
models[model] = slot;
|
|
1370
|
-
// Per-turn parallel — same additive rule. Per-step too.
|
|
1516
|
+
costUsd += advisorCostThisMsg;
|
|
1517
|
+
// Fold advisor TOKEN totals into session/turn/step usage
|
|
1518
|
+
// alongside the cost fold above. Without this, per-model
|
|
1519
|
+
// sums diverge from session totals: Σ models[*].input_tokens
|
|
1520
|
+
// > session.usage.input_tokens by exactly the advisor
|
|
1521
|
+
// tokens (round 86a fixed cost parity but missed the
|
|
1522
|
+
// matching token parity).
|
|
1523
|
+
inputTokens += advisorInputThisMsg;
|
|
1524
|
+
outputTokens += advisorOutputThisMsg;
|
|
1525
|
+
cacheCreationTokens += advisorCacheCreationThisMsg;
|
|
1526
|
+
cacheReadTokens += advisorCacheReadThisMsg;
|
|
1371
1527
|
if (currentTurn !== null) {
|
|
1372
|
-
|
|
1528
|
+
currentTurn.input_tokens += advisorInputThisMsg;
|
|
1529
|
+
currentTurn.output_tokens += advisorOutputThisMsg;
|
|
1530
|
+
currentTurn.cache_creation_tokens += advisorCacheCreationThisMsg;
|
|
1531
|
+
currentTurn.cache_read_tokens += advisorCacheReadThisMsg;
|
|
1532
|
+
if (currentTurn.current_step !== undefined) {
|
|
1533
|
+
currentTurn.current_step.input_tokens += advisorInputThisMsg;
|
|
1534
|
+
currentTurn.current_step.output_tokens += advisorOutputThisMsg;
|
|
1535
|
+
currentTurn.current_step.cache_creation_tokens += advisorCacheCreationThisMsg;
|
|
1536
|
+
currentTurn.current_step.cache_read_tokens += advisorCacheReadThisMsg;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
// Per-model usage breakdown — element-wise additive across deltas
|
|
1540
|
+
// in the merge step. Empty / missing model name skipped (no
|
|
1541
|
+
// attribution possible).
|
|
1542
|
+
if (typeof model === "string" && model.length > 0) {
|
|
1543
|
+
const slot = models[model] ?? {
|
|
1373
1544
|
count: 0,
|
|
1374
1545
|
input_tokens: 0,
|
|
1375
1546
|
output_tokens: 0,
|
|
@@ -1377,15 +1548,16 @@ function projectDelta(input) {
|
|
|
1377
1548
|
cache_read_tokens: 0,
|
|
1378
1549
|
cost_usd: 0,
|
|
1379
1550
|
};
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1551
|
+
slot.count += 1;
|
|
1552
|
+
slot.input_tokens += msgInput;
|
|
1553
|
+
slot.output_tokens += msgOutput;
|
|
1554
|
+
slot.cache_creation_tokens += msgCacheCreation;
|
|
1555
|
+
slot.cache_read_tokens += msgCacheRead;
|
|
1556
|
+
slot.cost_usd += msgCost;
|
|
1557
|
+
models[model] = slot;
|
|
1558
|
+
// Per-turn parallel — same additive rule. Per-step too.
|
|
1559
|
+
if (currentTurn !== null) {
|
|
1560
|
+
const turnSlot = currentTurn.models[model] ?? {
|
|
1389
1561
|
count: 0,
|
|
1390
1562
|
input_tokens: 0,
|
|
1391
1563
|
output_tokens: 0,
|
|
@@ -1393,70 +1565,96 @@ function projectDelta(input) {
|
|
|
1393
1565
|
cache_read_tokens: 0,
|
|
1394
1566
|
cost_usd: 0,
|
|
1395
1567
|
};
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
currentTurn.
|
|
1568
|
+
turnSlot.count += 1;
|
|
1569
|
+
turnSlot.input_tokens += msgInput;
|
|
1570
|
+
turnSlot.output_tokens += msgOutput;
|
|
1571
|
+
turnSlot.cache_creation_tokens += msgCacheCreation;
|
|
1572
|
+
turnSlot.cache_read_tokens += msgCacheRead;
|
|
1573
|
+
turnSlot.cost_usd += msgCost;
|
|
1574
|
+
currentTurn.models[model] = turnSlot;
|
|
1575
|
+
if (currentTurn.current_step !== undefined) {
|
|
1576
|
+
const stepSlot = currentTurn.current_step.models[model] ?? {
|
|
1577
|
+
count: 0,
|
|
1578
|
+
input_tokens: 0,
|
|
1579
|
+
output_tokens: 0,
|
|
1580
|
+
cache_creation_tokens: 0,
|
|
1581
|
+
cache_read_tokens: 0,
|
|
1582
|
+
cost_usd: 0,
|
|
1583
|
+
};
|
|
1584
|
+
stepSlot.count += 1;
|
|
1585
|
+
stepSlot.input_tokens += msgInput;
|
|
1586
|
+
stepSlot.output_tokens += msgOutput;
|
|
1587
|
+
stepSlot.cache_creation_tokens += msgCacheCreation;
|
|
1588
|
+
stepSlot.cache_read_tokens += msgCacheRead;
|
|
1589
|
+
stepSlot.cost_usd += msgCost;
|
|
1590
|
+
currentTurn.current_step.models[model] = stepSlot;
|
|
1591
|
+
}
|
|
1403
1592
|
}
|
|
1404
1593
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
contextTokensPeak = ctx;
|
|
1420
|
-
}
|
|
1421
|
-
// Per-turn samples — append in order; backend can
|
|
1422
|
-
// reconstruct session-level buckets by concatenating
|
|
1423
|
-
// every turn's samples in turn_index order.
|
|
1424
|
-
// Per-step: single scalar (one sample per step since a
|
|
1425
|
-
// step is bounded by exactly one assistant message).
|
|
1426
|
-
if (currentTurn !== null) {
|
|
1427
|
-
currentTurn.context_tokens_samples.push(ctx);
|
|
1428
|
-
currentTurn.context_tokens_latest = ctx;
|
|
1429
|
-
if (ctx > currentTurn.context_tokens_peak) {
|
|
1430
|
-
currentTurn.context_tokens_peak = ctx;
|
|
1594
|
+
// Context-tokens distribution (turn-bucketed)
|
|
1595
|
+
if (usage !== undefined) {
|
|
1596
|
+
const ctx = msgInput + msgCacheCreation + msgCacheRead;
|
|
1597
|
+
if (ctx > 0) {
|
|
1598
|
+
hasAssistantWithUsage = true;
|
|
1599
|
+
const bucket = turnBucket(assistantTurnIndex);
|
|
1600
|
+
const slot = contextTokensBuckets[bucket]
|
|
1601
|
+
?? { sum: 0, count: 0 };
|
|
1602
|
+
slot.sum += ctx;
|
|
1603
|
+
slot.count += 1;
|
|
1604
|
+
contextTokensBuckets[bucket] = slot;
|
|
1605
|
+
contextTokensLatest = ctx;
|
|
1606
|
+
if (ctx > contextTokensPeak) {
|
|
1607
|
+
contextTokensPeak = ctx;
|
|
1431
1608
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1609
|
+
// Per-turn samples — append in order; backend can
|
|
1610
|
+
// reconstruct session-level buckets by concatenating
|
|
1611
|
+
// every turn's samples in turn_index order.
|
|
1612
|
+
// Per-step: single scalar (one sample per step since a
|
|
1613
|
+
// step is bounded by exactly one assistant message).
|
|
1614
|
+
if (currentTurn !== null) {
|
|
1615
|
+
currentTurn.context_tokens_samples.push(ctx);
|
|
1616
|
+
currentTurn.context_tokens_latest = ctx;
|
|
1617
|
+
if (ctx > currentTurn.context_tokens_peak) {
|
|
1618
|
+
currentTurn.context_tokens_peak = ctx;
|
|
1619
|
+
}
|
|
1620
|
+
if (currentTurn.current_step !== undefined) {
|
|
1621
|
+
currentTurn.current_step.context_tokens = ctx;
|
|
1622
|
+
}
|
|
1434
1623
|
}
|
|
1435
1624
|
}
|
|
1436
1625
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1626
|
+
// ── Per-tool consumer: no-op ──────────────────────────────
|
|
1627
|
+
// Per-tool token / cost attribution does not exist. tool_result
|
|
1628
|
+
// bytes are recorded directly on `tools[T].output_size` at the
|
|
1629
|
+
// tool_result handler in the user-msg branch (no consumer
|
|
1630
|
+
// assistant N+1 attribution step needed). Anthropic-exact
|
|
1631
|
+
// tokens (msgInput, msgCacheCreation, msgCacheRead, msgOutput)
|
|
1632
|
+
// continue to flow into session/turn/step usage totals + per-
|
|
1633
|
+
// model cost. priorUserMsgTextBytes / hasCcSplit / msgCC5m /
|
|
1634
|
+
// msgCC1h / msgWebSearchReqs / advisorCostThisMsg references
|
|
1635
|
+
// exist for backward-compat with state shape but are unused
|
|
1636
|
+
// by per-tool attribution. msgWebSearchReqs cost still adds
|
|
1637
|
+
// to the session msgCost via computeMessageCostUsd above.
|
|
1638
|
+
void msgInput;
|
|
1639
|
+
void msgCacheCreation;
|
|
1640
|
+
void msgCacheRead;
|
|
1641
|
+
void hasCcSplit;
|
|
1642
|
+
void msgCC5m;
|
|
1643
|
+
void msgCC1h;
|
|
1644
|
+
void msgWebSearchReqs;
|
|
1645
|
+
void advisorCostThisMsg;
|
|
1646
|
+
void priorUserMsgTextBytes;
|
|
1647
|
+
resultedToolUseIds = [];
|
|
1648
|
+
} // end of `if (isFirstChunkOfMsg)` — per-message scalar work
|
|
1649
|
+
// Snapshot of `seenToolUseIds` taken at the start of this
|
|
1650
|
+
// chunk's content-block walks. Both Loop 1 (input_size
|
|
1651
|
+
// attribution) and Loop 2 (count + classifier flags) use
|
|
1652
|
+
// this snapshot to dedup — without it, Loop 1's add to the
|
|
1653
|
+
// running set would cause Loop 2 to skip the same id on
|
|
1654
|
+
// its own pass. New ids found in this chunk are committed
|
|
1655
|
+
// to the running set + `newToolUseIdsThisSlice` after both
|
|
1656
|
+
// loops finish.
|
|
1657
|
+
const seenToolUseIdsAtChunkStart = new Set(seenToolUseIds);
|
|
1460
1658
|
// Walk content blocks for tool_use entries.
|
|
1461
1659
|
// ── Per-tool emitter: byte counter ──────────────────────────
|
|
1462
1660
|
// Each tool_use bumps the corresponding tool/mcp_server/skill/
|
|
@@ -1483,6 +1681,12 @@ function projectDelta(input) {
|
|
|
1483
1681
|
|| block.id.length === 0) {
|
|
1484
1682
|
continue;
|
|
1485
1683
|
}
|
|
1684
|
+
// tool_use_id dedup — skip if this tool_use was
|
|
1685
|
+
// already counted in a prior chunk of this msg_id
|
|
1686
|
+
// (or in a prior slice persisted via state).
|
|
1687
|
+
if (seenToolUseIdsAtChunkStart.has(block.id)) {
|
|
1688
|
+
continue;
|
|
1689
|
+
}
|
|
1486
1690
|
const inputJsonBytes = Buffer.byteLength(JSON.stringify(block.input ?? {}), "utf-8");
|
|
1487
1691
|
// Sub-classification — same mutual-exclusion rules as before.
|
|
1488
1692
|
let bashBinary;
|
|
@@ -1527,7 +1731,9 @@ function projectDelta(input) {
|
|
|
1527
1731
|
pendingToolUses[block.id] = pending;
|
|
1528
1732
|
}
|
|
1529
1733
|
}
|
|
1530
|
-
|
|
1734
|
+
// Note: msgOutput is consumed inside the per-message gate
|
|
1735
|
+
// above (outputTokens accumulator). Its `void` no-op silencer
|
|
1736
|
+
// moved into the gate alongside the other locals.
|
|
1531
1737
|
// Per-message tool-bucket flag accumulator for the classifier
|
|
1532
1738
|
// retry state machine. Computed locally within this assistant
|
|
1533
1739
|
// message; merged into currentTurn at the end.
|
|
@@ -1539,6 +1745,17 @@ function projectDelta(input) {
|
|
|
1539
1745
|
}
|
|
1540
1746
|
const block = blk;
|
|
1541
1747
|
if (block.type === "tool_use" && typeof block.name === "string") {
|
|
1748
|
+
// tool_use_id dedup — skip if already counted in
|
|
1749
|
+
// a prior chunk of this msg_id (snapshot was taken
|
|
1750
|
+
// before Loop 1 ran so Loop 1's additions don't
|
|
1751
|
+
// pre-empt Loop 2's processing of the same id).
|
|
1752
|
+
// Empty/missing id falls through to count (current
|
|
1753
|
+
// behavior preserved: malformed ids still count).
|
|
1754
|
+
if (typeof block.id === "string"
|
|
1755
|
+
&& block.id.length > 0
|
|
1756
|
+
&& seenToolUseIdsAtChunkStart.has(block.id)) {
|
|
1757
|
+
continue;
|
|
1758
|
+
}
|
|
1542
1759
|
const toolName = block.name;
|
|
1543
1760
|
// Per-tool breakdown count — also update mcp_servers,
|
|
1544
1761
|
// bash_binaries, skills, sub_agents in the same step.
|
|
@@ -1667,15 +1884,27 @@ function projectDelta(input) {
|
|
|
1667
1884
|
(currentTurn.current_step.file_change_counts[filePath] ?? 0) + 1;
|
|
1668
1885
|
}
|
|
1669
1886
|
}
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1887
|
+
// Language counter is INSIDE the Edit/Write gate so it
|
|
1888
|
+
// tracks files actually MODIFIED (parity with Codex
|
|
1889
|
+
// `apply_patch` only-counts at projection.ts:863-870).
|
|
1890
|
+
// Without the gate, every `Read` (and any future
|
|
1891
|
+
// file_path-bearing tool) bumped `languages[lang]` —
|
|
1892
|
+
// same logical session shipped
|
|
1893
|
+
// `code_changes.{files_modified: 3, languages.TypeScript: 50}`
|
|
1894
|
+
// (47 Reads + 3 Edits) on Claude while Codex shipped
|
|
1895
|
+
// `{files_modified: 3, languages.TypeScript: 3}`.
|
|
1896
|
+
// Backend cross-client `Σ languages` joins broke and the
|
|
1897
|
+
// wire was internally inconsistent (50 ≠ 3 for the same
|
|
1898
|
+
// category aggregate).
|
|
1899
|
+
const lang = getLanguageFromPath(filePath);
|
|
1900
|
+
if (lang !== null) {
|
|
1901
|
+
languages[lang] = (languages[lang] ?? 0) + 1;
|
|
1902
|
+
if (currentTurn !== null) {
|
|
1903
|
+
currentTurn.languages[lang] = (currentTurn.languages[lang] ?? 0) + 1;
|
|
1904
|
+
if (currentTurn.current_step !== undefined) {
|
|
1905
|
+
currentTurn.current_step.languages[lang] =
|
|
1906
|
+
(currentTurn.current_step.languages[lang] ?? 0) + 1;
|
|
1907
|
+
}
|
|
1679
1908
|
}
|
|
1680
1909
|
}
|
|
1681
1910
|
}
|
|
@@ -1767,8 +1996,37 @@ function projectDelta(input) {
|
|
|
1767
1996
|
}
|
|
1768
1997
|
}
|
|
1769
1998
|
}
|
|
1999
|
+
// Commit tool_use_ids processed in this chunk to the
|
|
2000
|
+
// running set + slice output. Runs AFTER both Loop 1 and
|
|
2001
|
+
// Loop 2 so each loop saw the consistent pre-chunk snapshot.
|
|
2002
|
+
// Subsequent chunks of the same msg_id (and the next slice)
|
|
2003
|
+
// will then skip these ids via `seenToolUseIdsAtChunkStart`.
|
|
2004
|
+
if (Array.isArray(content)) {
|
|
2005
|
+
for (const blk of content) {
|
|
2006
|
+
if (blk === null || typeof blk !== "object") {
|
|
2007
|
+
continue;
|
|
2008
|
+
}
|
|
2009
|
+
const block = blk;
|
|
2010
|
+
if (block.type !== "tool_use"
|
|
2011
|
+
|| typeof block.id !== "string"
|
|
2012
|
+
|| block.id.length === 0) {
|
|
2013
|
+
continue;
|
|
2014
|
+
}
|
|
2015
|
+
if (!seenToolUseIds.has(block.id)) {
|
|
2016
|
+
seenToolUseIds.add(block.id);
|
|
2017
|
+
newToolUseIdsThisSlice.push(block.id);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
1770
2021
|
// End-of-message classifier update: retry detection +
|
|
1771
|
-
// per-turn cost accumulation.
|
|
2022
|
+
// per-turn cost accumulation. Retry detection runs on every
|
|
2023
|
+
// chunk (msgBuckets reflects this chunk's tool_uses); cost
|
|
2024
|
+
// accumulation is gated by `msgCost` being non-zero, which
|
|
2025
|
+
// only happens on the first chunk of a msg_id (subsequent
|
|
2026
|
+
// chunks keep msgCost at its outer-scope default of 0 since
|
|
2027
|
+
// the per-message gate is closed). Same effect as an explicit
|
|
2028
|
+
// `if (isFirstChunkOfMsg)` gate but without re-introducing
|
|
2029
|
+
// the dependency on the flag here.
|
|
1772
2030
|
if (currentTurn !== null) {
|
|
1773
2031
|
if (msgBuckets.edit) {
|
|
1774
2032
|
if (currentTurn.saw_bash_after_edit) {
|
|
@@ -1780,9 +2038,18 @@ function projectDelta(input) {
|
|
|
1780
2038
|
if (msgBuckets.bash && currentTurn.saw_edit_pending_bash) {
|
|
1781
2039
|
currentTurn.saw_bash_after_edit = true;
|
|
1782
2040
|
}
|
|
1783
|
-
|
|
2041
|
+
// Include advisor sub-call cost (`advisorCostThisMsg`,
|
|
2042
|
+
// computed above with the parent's msgCost). Session-level
|
|
2043
|
+
// `costUsd` adds it at line ~1747; turn-level must mirror
|
|
2044
|
+
// or backend's reconstruction invariant breaks:
|
|
2045
|
+
// `Σ SessionTurnAnalytics.usage.cost_usd` would be less
|
|
2046
|
+
// than `SessionAnalytics.usage.cost_usd` for any session
|
|
2047
|
+
// that triggered server-side advisor sub-calls. On
|
|
2048
|
+
// subsequent chunks msgCost = advisorCostThisMsg = 0
|
|
2049
|
+
// (per-message gate not entered), so this is a no-op.
|
|
2050
|
+
currentTurn.cost_usd += msgCost + advisorCostThisMsg;
|
|
1784
2051
|
if (currentTurn.current_step !== undefined) {
|
|
1785
|
-
currentTurn.current_step.cost_usd += msgCost;
|
|
2052
|
+
currentTurn.current_step.cost_usd += msgCost + advisorCostThisMsg;
|
|
1786
2053
|
}
|
|
1787
2054
|
}
|
|
1788
2055
|
}
|
|
@@ -2213,12 +2480,22 @@ function projectDeltaInternal(input) {
|
|
|
2213
2480
|
// (set if a turn straddled the prior slice boundary).
|
|
2214
2481
|
let nextTurnIndex = input.priorNextTurnIndex ?? 1;
|
|
2215
2482
|
let hasOpenTurn = input.priorCurrentTurn !== undefined;
|
|
2216
|
-
// Anthropic msg_id dedup —
|
|
2217
|
-
//
|
|
2218
|
-
//
|
|
2219
|
-
//
|
|
2483
|
+
// Anthropic msg_id dedup — mirrors projectDelta. Used to track WHICH
|
|
2484
|
+
// msg_ids are new in this slice for `new_assistant_message_ids`
|
|
2485
|
+
// emission (merge appends to state.internal.seen_assistant_message_ids).
|
|
2486
|
+
// Does NOT gate content-block processing — same streaming-split
|
|
2487
|
+
// semantic applies here: a single API response's content blocks may
|
|
2488
|
+
// be split across multiple JSONL lines sharing the same msg_id but
|
|
2489
|
+
// carrying DIFFERENT tool_use blocks per chunk. Per-block dedup uses
|
|
2490
|
+
// `seenToolUseIds` (below).
|
|
2220
2491
|
const seenAssistantMessageIds = new Set(input.priorSeenAssistantMessageIds ?? []);
|
|
2221
2492
|
const newAssistantMessageIdsThisSlice = [];
|
|
2493
|
+
// tool_use_id dedup — mirrors projectDelta. file_path counters
|
|
2494
|
+
// (file_path_change_counts, distinct_file_paths_seen) must not
|
|
2495
|
+
// double-count when a single Edit/Write tool_use re-appears across
|
|
2496
|
+
// streaming-split chunks or true-duplicate re-emits.
|
|
2497
|
+
const seenToolUseIds = new Set(input.priorSeenToolUseIds ?? []);
|
|
2498
|
+
const newToolUseIdsThisSlice = [];
|
|
2222
2499
|
for (const line of input.lines) {
|
|
2223
2500
|
const lineTsMs = tsMs(line.timestamp);
|
|
2224
2501
|
if (lineTsMs !== null) {
|
|
@@ -2250,21 +2527,26 @@ function projectDeltaInternal(input) {
|
|
|
2250
2527
|
if (line.type !== "assistant" || line.message === undefined) {
|
|
2251
2528
|
continue;
|
|
2252
2529
|
}
|
|
2253
|
-
//
|
|
2254
|
-
//
|
|
2255
|
-
//
|
|
2530
|
+
// msg_id tracking — record on first occurrence per slice so
|
|
2531
|
+
// `new_assistant_message_ids` is emitted in the return. Unlike
|
|
2532
|
+
// the pre-fix code (which `continue`'d here, dropping content
|
|
2533
|
+
// blocks of subsequent chunks), we now walk content blocks on
|
|
2534
|
+
// EVERY chunk and let `seenToolUseIds` handle block-level dedup.
|
|
2256
2535
|
const msgIdInternal = line.message.id;
|
|
2257
2536
|
if (typeof msgIdInternal === "string" && msgIdInternal.length > 0) {
|
|
2258
|
-
if (seenAssistantMessageIds.has(msgIdInternal)) {
|
|
2259
|
-
|
|
2537
|
+
if (!seenAssistantMessageIds.has(msgIdInternal)) {
|
|
2538
|
+
seenAssistantMessageIds.add(msgIdInternal);
|
|
2539
|
+
newAssistantMessageIdsThisSlice.push(msgIdInternal);
|
|
2260
2540
|
}
|
|
2261
|
-
seenAssistantMessageIds.add(msgIdInternal);
|
|
2262
|
-
newAssistantMessageIdsThisSlice.push(msgIdInternal);
|
|
2263
2541
|
}
|
|
2264
2542
|
const content = line.message.content;
|
|
2265
2543
|
if (!Array.isArray(content)) {
|
|
2266
2544
|
continue;
|
|
2267
2545
|
}
|
|
2546
|
+
// Snapshot seenToolUseIds so loop iterations within this chunk
|
|
2547
|
+
// can dedup against the pre-chunk state — symmetric with
|
|
2548
|
+
// projectDelta's `seenToolUseIdsAtChunkStart`.
|
|
2549
|
+
const seenToolUseIdsAtChunkStart = new Set(seenToolUseIds);
|
|
2268
2550
|
for (const blk of content) {
|
|
2269
2551
|
if (blk === null || typeof blk !== "object") {
|
|
2270
2552
|
continue;
|
|
@@ -2273,7 +2555,20 @@ function projectDeltaInternal(input) {
|
|
|
2273
2555
|
if (block.type !== "tool_use" || typeof block.name !== "string") {
|
|
2274
2556
|
continue;
|
|
2275
2557
|
}
|
|
2558
|
+
if (typeof block.id !== "string" || block.id.length === 0) {
|
|
2559
|
+
continue;
|
|
2560
|
+
}
|
|
2561
|
+
// tool_use_id dedup — skip if seen in a prior chunk or slice.
|
|
2562
|
+
if (seenToolUseIdsAtChunkStart.has(block.id)) {
|
|
2563
|
+
continue;
|
|
2564
|
+
}
|
|
2276
2565
|
if (block.name !== "Edit" && block.name !== "Write") {
|
|
2566
|
+
// Track the id even for non-file tool_uses so cross-slice
|
|
2567
|
+
// dedup catches them (symmetry with projectDelta).
|
|
2568
|
+
if (!seenToolUseIds.has(block.id)) {
|
|
2569
|
+
seenToolUseIds.add(block.id);
|
|
2570
|
+
newToolUseIdsThisSlice.push(block.id);
|
|
2571
|
+
}
|
|
2277
2572
|
continue;
|
|
2278
2573
|
}
|
|
2279
2574
|
const fp = block.input?.file_path;
|
|
@@ -2281,6 +2576,12 @@ function projectDeltaInternal(input) {
|
|
|
2281
2576
|
distinct.add(fp);
|
|
2282
2577
|
filePathChangeCounts[fp] = (filePathChangeCounts[fp] ?? 0) + 1;
|
|
2283
2578
|
}
|
|
2579
|
+
// Commit this Edit/Write tool_use_id to running set + slice
|
|
2580
|
+
// output so the next chunk/slice skips it.
|
|
2581
|
+
if (!seenToolUseIds.has(block.id)) {
|
|
2582
|
+
seenToolUseIds.add(block.id);
|
|
2583
|
+
newToolUseIdsThisSlice.push(block.id);
|
|
2584
|
+
}
|
|
2284
2585
|
}
|
|
2285
2586
|
}
|
|
2286
2587
|
return {
|
|
@@ -2292,6 +2593,9 @@ function projectDeltaInternal(input) {
|
|
|
2292
2593
|
...(newAssistantMessageIdsThisSlice.length > 0
|
|
2293
2594
|
? { new_assistant_message_ids: newAssistantMessageIdsThisSlice }
|
|
2294
2595
|
: {}),
|
|
2596
|
+
...(newToolUseIdsThisSlice.length > 0
|
|
2597
|
+
? { new_tool_use_ids: newToolUseIdsThisSlice }
|
|
2598
|
+
: {}),
|
|
2295
2599
|
};
|
|
2296
2600
|
}
|
|
2297
2601
|
//# sourceMappingURL=projection.js.map
|