@herbertgao/pi-extensions 2026.9.19 → 2026.10.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/README.md +14 -16
- package/THIRD_PARTY_NOTICES.md +29 -3
- package/node_modules/@herbertgao/pi-bark/README.md +39 -3
- package/node_modules/@herbertgao/pi-bark/package.json +1 -1
- package/node_modules/@herbertgao/pi-bark/src/index.ts +275 -15
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +85 -68
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +79 -62
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/preview.webp +0 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +116 -34
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +370 -118
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +6 -36
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/index.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +31 -33
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +330 -360
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/index.ts +56 -108
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/session.ts +97 -15
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/reference/subagent.ts +80 -45
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/flush-docked-bash.ts +36 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer-layout.ts +229 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/footer.ts +521 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/mcp-chip.ts +136 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/startup-header.ts +92 -61
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/shell/working-message.ts +58 -38
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +19 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +1127 -231
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +267 -262
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +38 -48
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +8 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +2 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +287 -114
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +15 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +18 -72
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +61 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +303 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/ansi-utils.ts +25 -57
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-component.ts +125 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-edit-render.ts +227 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-header.ts +136 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-highlight.ts +151 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-inline.ts +324 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-layout.ts +762 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-limits.ts +152 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-palette.ts +410 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-parse.ts +535 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-presentation.ts +4 -4
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +21 -3219
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-text.ts +44 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-write-render.ts +568 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/index.ts +103 -48
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/line-width-safety.ts +8 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-execution.ts +2 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +171 -196
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/mcp-title.ts +39 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{message-display.ts → tool/message-display.ts} +27 -93
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/names.ts +429 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +259 -164
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{show-more-hint.ts → tool/show-more-hint.ts} +10 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +8 -26
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-color.ts +44 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/ansi-text.ts +77 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/component-tree.ts +34 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/format.ts +28 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +51 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/patch-keys.ts +124 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/sgr-mouse.ts +70 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +10 -8
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +1 -1
- package/node_modules/@herbertgao/pi-subagents/src/mention-clone.ts +3 -2
- package/node_modules/@herbertgao/sol-pi/CONTRIBUTING.md +22 -0
- package/node_modules/@herbertgao/sol-pi/README.md +36 -17
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +10 -6
- package/node_modules/@herbertgao/sol-pi/agents-install.md +15 -12
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +24 -8
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +2 -2
- package/node_modules/@herbertgao/sol-pi/docs/star-history.md +18 -0
- package/node_modules/@herbertgao/sol-pi/package.json +4 -2
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +23 -4
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +32 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +3 -2
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +27 -7
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +137 -41
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +1 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +2 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/projection.ts +58 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +28 -6
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +2 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +15 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@pi-plugins/fast-mode/README.md +7 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +7 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +5 -5
- package/node_modules/pi-antigravity/README.md +3 -0
- package/node_modules/pi-antigravity/package.json +8 -8
- package/node_modules/pi-antigravity/src/auth/oauth.ts +6 -3
- package/node_modules/pi-antigravity/src/index.ts +114 -110
- package/node_modules/pi-antigravity/src/stream/stream.ts +1 -1
- package/node_modules/pi-antigravity/src/utils/util.ts +18 -1
- package/node_modules/pi-multi-account/CHANGELOG.md +20 -0
- package/node_modules/pi-multi-account/README.md +46 -8
- package/node_modules/pi-multi-account/config-file-transaction.ts +42 -0
- package/node_modules/pi-multi-account/index.ts +255 -269
- package/node_modules/pi-multi-account/model-pins.ts +36 -0
- package/node_modules/pi-multi-account/package.json +9 -7
- package/node_modules/pi-multi-account/slot-proxy-auth.ts +12 -2
- package/node_modules/pi-multi-account/slot-proxy.ts +27 -5
- package/node_modules/pi-web-access/CHANGELOG.md +17 -0
- package/node_modules/pi-web-access/README.md +6 -3
- package/node_modules/pi-web-access/brave-rate-limit.ts +170 -0
- package/node_modules/pi-web-access/brave.ts +28 -11
- package/node_modules/pi-web-access/dist/index.js +202 -33
- package/node_modules/pi-web-access/gemini-search.ts +2 -5
- package/node_modules/pi-web-access/index.ts +13 -7
- package/node_modules/pi-web-access/openai-search.ts +24 -10
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/summary-review.ts +8 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/README.md +16 -12
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.d.ts +0 -5
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/adapter.js +2 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.d.ts +3 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/reader.js +27 -15
- package/node_modules/{@herbertgao/resume-from/dist/adapters/codex → resume-from/dist/adapters/claude-code}/redaction.js +16 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.d.ts +2 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/writer.js +1 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.d.ts +2 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.js +1 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/read.d.ts +16 -0
- package/node_modules/resume-from/dist/adapters/codex/read.js +723 -0
- package/node_modules/{@herbertgao/resume-from/dist/adapters/pi → resume-from/dist/adapters/codex}/redaction.js +16 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.d.ts +44 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/rollout.js +88 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/write.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.d.ts +5 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.js +10 -6
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from/dist/adapters/claude-code → resume-from/dist/adapters/pi}/redaction.js +16 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.d.ts +2 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/serialize.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.d.ts +1 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/render.js +4 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.js +31 -8
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.d.ts +1 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/wiring.js +1 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.d.ts +4 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/confirmation.js +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.d.ts +8 -6
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.d.ts +10 -5
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/finder.d.ts +2 -1
- package/node_modules/resume-from/dist/import/discovery/finder.js +269 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.d.ts +3 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.js +3 -3
- package/node_modules/resume-from/dist/import/pipeline.d.ts +28 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/pipeline.js +31 -11
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.d.ts +2 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/builder.js +9 -5
- package/node_modules/resume-from/dist/import/preview/warnings.d.ts +14 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/warnings.js +26 -20
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.js +12 -2
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.d.ts +9 -3
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.d.ts +4 -4
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/git.js +7 -4
- package/node_modules/resume-from/dist/platform/repo/reader.d.ts +3 -0
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/reader.js +60 -20
- package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.d.ts +8 -1
- package/node_modules/{@herbertgao/resume-from → resume-from}/package.json +19 -32
- package/node_modules/{@herbertgao/resume-from → resume-from}/shims/pi/extensions/resume-from.js +2 -2
- package/package.json +18 -22
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +0 -101
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.svg +0 -101
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/welcome.webp +0 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/render-utils.ts +0 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +0 -30
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +0 -12
- package/node_modules/@herbertgao/resume-from/dist/adapters/codex/read.js +0 -270
- package/node_modules/@herbertgao/resume-from/dist/import/discovery/finder.js +0 -129
- package/node_modules/@herbertgao/resume-from/dist/import/pipeline.d.ts +0 -17
- package/node_modules/@herbertgao/resume-from/dist/import/preview/warnings.d.ts +0 -11
- package/node_modules/@herbertgao/resume-from/dist/platform/repo/reader.d.ts +0 -8
- package/node_modules/pi-footer/CHANGELOG.md +0 -145
- package/node_modules/pi-footer/LICENSE +0 -21
- package/node_modules/pi-footer/README.md +0 -354
- package/node_modules/pi-footer/package.json +0 -68
- package/node_modules/pi-footer/src/cache.ts +0 -106
- package/node_modules/pi-footer/src/colors.ts +0 -237
- package/node_modules/pi-footer/src/config.ts +0 -202
- package/node_modules/pi-footer/src/event-widgets.ts +0 -41
- package/node_modules/pi-footer/src/extension-statuses.ts +0 -102
- package/node_modules/pi-footer/src/git.ts +0 -135
- package/node_modules/pi-footer/src/index.ts +0 -268
- package/node_modules/pi-footer/src/metrics.ts +0 -141
- package/node_modules/pi-footer/src/presets.ts +0 -383
- package/node_modules/pi-footer/src/render.ts +0 -114
- package/node_modules/pi-footer/src/separators.ts +0 -52
- package/node_modules/pi-footer/src/types.ts +0 -122
- package/node_modules/pi-footer/src/ui/color-level-confirm.ts +0 -22
- package/node_modules/pi-footer/src/ui/color-options.ts +0 -195
- package/node_modules/pi-footer/src/ui/config-lifecycle.ts +0 -61
- package/node_modules/pi-footer/src/ui/edit-colors.ts +0 -13
- package/node_modules/pi-footer/src/ui/events.ts +0 -35
- package/node_modules/pi-footer/src/ui/extension-status-picker.ts +0 -60
- package/node_modules/pi-footer/src/ui/extension-statuses.ts +0 -73
- package/node_modules/pi-footer/src/ui/fields.ts +0 -252
- package/node_modules/pi-footer/src/ui/global-menu.ts +0 -126
- package/node_modules/pi-footer/src/ui/helpers.ts +0 -44
- package/node_modules/pi-footer/src/ui/layout.ts +0 -17
- package/node_modules/pi-footer/src/ui/line-list.ts +0 -19
- package/node_modules/pi-footer/src/ui/model.ts +0 -64
- package/node_modules/pi-footer/src/ui/navigation.ts +0 -29
- package/node_modules/pi-footer/src/ui/option-edit.ts +0 -93
- package/node_modules/pi-footer/src/ui/overlay-render.ts +0 -103
- package/node_modules/pi-footer/src/ui/screen-context.ts +0 -18
- package/node_modules/pi-footer/src/ui/screen-controller.ts +0 -27
- package/node_modules/pi-footer/src/ui/screen-render.ts +0 -32
- package/node_modules/pi-footer/src/ui/screen-state.ts +0 -20
- package/node_modules/pi-footer/src/ui/screen.ts +0 -243
- package/node_modules/pi-footer/src/ui/screens/add-widget.ts +0 -92
- package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +0 -52
- package/node_modules/pi-footer/src/ui/screens/controller.ts +0 -12
- package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +0 -68
- package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +0 -115
- package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +0 -61
- package/node_modules/pi-footer/src/ui/screens/global.ts +0 -75
- package/node_modules/pi-footer/src/ui/screens/line-list.ts +0 -108
- package/node_modules/pi-footer/src/ui/screens/main.ts +0 -99
- package/node_modules/pi-footer/src/ui/screens/terminal.ts +0 -121
- package/node_modules/pi-footer/src/ui/screens/widget-list.ts +0 -154
- package/node_modules/pi-footer/src/ui/terminal-menu.ts +0 -32
- package/node_modules/pi-footer/src/ui/theme.ts +0 -48
- package/node_modules/pi-footer/src/ui/title-bar.ts +0 -100
- package/node_modules/pi-footer/src/ui/widget-actions.ts +0 -76
- package/node_modules/pi-footer/src/ui.ts +0 -66
- package/node_modules/pi-footer/src/widgets/context.ts +0 -28
- package/node_modules/pi-footer/src/widgets/core/active-tools.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/context-window.ts +0 -24
- package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +0 -19
- package/node_modules/pi-footer/src/widgets/core/cwd.ts +0 -108
- package/node_modules/pi-footer/src/widgets/core/event.ts +0 -34
- package/node_modules/pi-footer/src/widgets/core/external-status.ts +0 -102
- package/node_modules/pi-footer/src/widgets/core/model-provider.ts +0 -20
- package/node_modules/pi-footer/src/widgets/core/model.ts +0 -35
- package/node_modules/pi-footer/src/widgets/core/provider.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/session-name.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +0 -17
- package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/branch.ts +0 -81
- package/node_modules/pi-footer/src/widgets/git/clean.ts +0 -19
- package/node_modules/pi-footer/src/widgets/git/deletions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/diff.ts +0 -38
- package/node_modules/pi-footer/src/widgets/git/insertions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/remote.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/root.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/sha.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/staged.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/status.ts +0 -19
- package/node_modules/pi-footer/src/widgets/git/unstaged.ts +0 -17
- package/node_modules/pi-footer/src/widgets/git/untracked.ts +0 -17
- package/node_modules/pi-footer/src/widgets/instance.ts +0 -118
- package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +0 -18
- package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +0 -32
- package/node_modules/pi-footer/src/widgets/layout/separator.ts +0 -57
- package/node_modules/pi-footer/src/widgets/layout/spacer.ts +0 -31
- package/node_modules/pi-footer/src/widgets/options.ts +0 -122
- package/node_modules/pi-footer/src/widgets/project/runtime.ts +0 -361
- package/node_modules/pi-footer/src/widgets/registry.ts +0 -223
- package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/compactions.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/elapsed.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/last-activity.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/messages.ts +0 -19
- package/node_modules/pi-footer/src/widgets/session/session-id.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/session-start.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/tool-results.ts +0 -17
- package/node_modules/pi-footer/src/widgets/session/total-messages.ts +0 -19
- package/node_modules/pi-footer/src/widgets/session/total-time.ts +0 -18
- package/node_modules/pi-footer/src/widgets/session/user-messages.ts +0 -17
- package/node_modules/pi-footer/src/widgets/store.ts +0 -26
- package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +0 -55
- package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +0 -108
- package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +0 -26
- package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +0 -29
- package/node_modules/pi-footer/src/widgets/tokens/context.ts +0 -29
- package/node_modules/pi-footer/src/widgets/tokens/cost.ts +0 -51
- package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +0 -20
- package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +0 -25
- package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +0 -18
- package/node_modules/pi-footer/src/widgets/types.ts +0 -181
- package/node_modules/pi-footer/src/widgets/utils/colors.ts +0 -11
- package/node_modules/pi-footer/src/widgets/utils/context.ts +0 -112
- package/node_modules/pi-footer/src/widgets/utils/session.ts +0 -19
- package/node_modules/pi-footer/src/widgets/utils/token-format.ts +0 -78
- /package/node_modules/{@herbertgao/resume-from → resume-from}/LICENSE +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/entries.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/layout.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/readback.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/redaction.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/claude-code/validation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/readback.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/redaction.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/codex/validation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/adapter.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/format.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/parse.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/redaction.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/adapters/pi/validate.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/bin.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/agents.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/args.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/presentation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/cli/runner.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/entry.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/command.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/picker.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/presentation.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/register.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/pi-extension/ui.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/profile.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/host/registry.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/homes.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/discovery/ordering.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/handover.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/lander.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/landing/marker.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/format.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/preview/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/transfer/rules.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/import/wiring.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/defaults.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/errors.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/loader.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/paths.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/config/validate.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/repo/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/file-committer.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/store/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/contract.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/estimator.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.d.ts +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/platform/tokens/index.js +0 -0
- /package/node_modules/{@herbertgao/resume-from → resume-from}/dist/session/contract.js +0 -0
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The source role: a Codex home becomes a list of sessions, and one session becomes the
|
|
3
|
+
* canonical vocabulary. Every result body is dropped (FR-24) and every reasoning trace is
|
|
4
|
+
* ignored (FR-28, C-4).
|
|
5
|
+
*/
|
|
6
|
+
import { isAbsolute } from "node:path";
|
|
7
|
+
import { redactSensitiveArgumentsText, redactSensitiveText } from "./redaction.js";
|
|
8
|
+
import { CODEX_ENTRY_COMPACTED, CODEX_ENTRY_EVENT_MSG, CODEX_ENTRY_RESPONSE_ITEM, CODEX_EVENT_AGENT_MESSAGE, CODEX_EVENT_ITEM_COMPLETED, CODEX_EVENT_USER_MESSAGE, CODEX_EXTENSION_KIND_WEB_SEARCH, CODEX_ITEM_CUSTOM_TOOL_CALL, CODEX_ITEM_CUSTOM_TOOL_CALL_OUTPUT, CODEX_ITEM_FUNCTION_CALL, CODEX_ITEM_FUNCTION_CALL_OUTPUT, CODEX_THREAD_ITEM_AGENT_MESSAGE, CODEX_THREAD_ITEM_COLLAB_AGENT_TOOL_CALL, CODEX_THREAD_ITEM_COMMAND_EXECUTION, CODEX_THREAD_ITEM_CONTEXT_COMPACTION, CODEX_THREAD_ITEM_EXTENSION, CODEX_THREAD_ITEM_FILE_CHANGE, CODEX_THREAD_ITEM_IMAGE_VIEW, CODEX_THREAD_ITEM_MCP_TOOL_CALL, CODEX_THREAD_ITEM_REASONING, CODEX_THREAD_ITEM_SUB_AGENT_ACTIVITY, CODEX_THREAD_ITEM_USER_MESSAGE, isNotFoundError, KNOWN_ENTRY_TYPES, listRolloutFiles, payloadType, readSessionMeta, sessionsRoot, streamRolloutEntries, toIsoUtc, } from "./rollout.js";
|
|
9
|
+
const TITLE_LIMIT = 80;
|
|
10
|
+
const ARGUMENTS_PREVIEW_LIMIT = 60;
|
|
11
|
+
/** Tools whose name alone settles the question (FR-26). Everything else stays "unknown". */
|
|
12
|
+
const READ_ONLY_TOOLS = new Set([
|
|
13
|
+
"read_file",
|
|
14
|
+
"read",
|
|
15
|
+
"view_image",
|
|
16
|
+
"list_dir",
|
|
17
|
+
"grep",
|
|
18
|
+
"find",
|
|
19
|
+
"web_search",
|
|
20
|
+
]);
|
|
21
|
+
const MUTATING_TOOLS = new Set([
|
|
22
|
+
"apply_patch",
|
|
23
|
+
"write_file",
|
|
24
|
+
"edit_file",
|
|
25
|
+
"create_file",
|
|
26
|
+
"delete_file",
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* `Extension.kind` values that are reads by their own name. Any other kind is a call whose kind
|
|
30
|
+
* does not settle the question, so it stays "unknown" (FR-26).
|
|
31
|
+
*/
|
|
32
|
+
const READ_ONLY_EXTENSION_KINDS = new Set([CODEX_EXTENSION_KIND_WEB_SEARCH]);
|
|
33
|
+
export class CodexRolloutUnreadableError extends Error {
|
|
34
|
+
constructor(filePath) {
|
|
35
|
+
super(`Codex thread is unreadable: ${filePath} was cut mid-entry`);
|
|
36
|
+
this.name = "CodexRolloutUnreadableError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Lenient: a file cut mid-entry still yields whatever parsed, with `truncated` set. */
|
|
40
|
+
export async function scanRollout(filePath) {
|
|
41
|
+
// The same streamed reader the listing uses, so both call a line over the cap damage (C-13): one
|
|
42
|
+
// reader, one damage rule, and no whole file in memory. Reading stops at the first damage through
|
|
43
|
+
// `stop`, which lets the reader end the file on its own terms instead of being abandoned mid-read;
|
|
44
|
+
// `readRollout` refuses a damaged file anyway, so the rest of it cannot matter.
|
|
45
|
+
const state = { truncated: false, stop: false };
|
|
46
|
+
const entries = [];
|
|
47
|
+
for await (const entry of streamRolloutEntries(filePath, state)) {
|
|
48
|
+
if (state.truncated) {
|
|
49
|
+
state.stop = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
entries.push(entry);
|
|
53
|
+
}
|
|
54
|
+
let meta = null;
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
meta = readSessionMeta(entry);
|
|
57
|
+
if (meta !== null)
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
const { turns, skippedEntries, changedPaths } = toCanonicalTurns(entries);
|
|
61
|
+
const firstUserTurn = turns.find((turn) => turn.role === "user" && turn.kind === "message");
|
|
62
|
+
const lastStamp = [...entries].reverse().find((entry) => toIsoUtc(entry.timestamp) !== null);
|
|
63
|
+
return {
|
|
64
|
+
filePath,
|
|
65
|
+
meta,
|
|
66
|
+
turns,
|
|
67
|
+
skippedEntries,
|
|
68
|
+
startedAt: toIsoUtc(meta?.timestamp ?? entries[0]?.timestamp ?? null),
|
|
69
|
+
updatedAt: toIsoUtc(lastStamp?.timestamp ?? meta?.timestamp ?? null),
|
|
70
|
+
title: titleOf(firstUserTurn?.text ?? ""),
|
|
71
|
+
changedPaths,
|
|
72
|
+
truncated: state.truncated,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Strict: FR-51's "unreadable" answer. */
|
|
76
|
+
export async function readRollout(filePath) {
|
|
77
|
+
const rollout = await scanRollout(filePath);
|
|
78
|
+
if (rollout.truncated)
|
|
79
|
+
throw new CodexRolloutUnreadableError(filePath);
|
|
80
|
+
return rollout;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Sums up one rollout for the selection list in a single streamed pass (C-13): no turn is built,
|
|
84
|
+
* no argument is redacted, and neither the file nor its entries are held whole. Every field comes
|
|
85
|
+
* from the same classifier the loader uses, so a row cannot disagree with the session it opens.
|
|
86
|
+
*/
|
|
87
|
+
export async function summarizeRollout(filePath) {
|
|
88
|
+
// The listing never stops early: every entry decides the row (C-13).
|
|
89
|
+
const state = { truncated: false, stop: false };
|
|
90
|
+
let meta = null;
|
|
91
|
+
let firstEntryStamp = null;
|
|
92
|
+
let seenEntry = false;
|
|
93
|
+
let lastStamp = null;
|
|
94
|
+
let messages = 0;
|
|
95
|
+
let itemToolCalls = 0;
|
|
96
|
+
let summaryTurns = 0;
|
|
97
|
+
let itemSeen = false;
|
|
98
|
+
let legacyDialogueBeforeItems = false;
|
|
99
|
+
let legacyCallsBeforeItems = 0;
|
|
100
|
+
let legacyCallsAfterItems = 0;
|
|
101
|
+
let title = "";
|
|
102
|
+
for await (const entry of streamRolloutEntries(filePath, state)) {
|
|
103
|
+
if (meta === null)
|
|
104
|
+
meta = readSessionMeta(entry);
|
|
105
|
+
const stamp = toIsoUtc(entry.timestamp);
|
|
106
|
+
if (!seenEntry) {
|
|
107
|
+
seenEntry = true;
|
|
108
|
+
firstEntryStamp = stamp;
|
|
109
|
+
}
|
|
110
|
+
if (stamp !== null)
|
|
111
|
+
lastStamp = stamp;
|
|
112
|
+
const itemTurn = isItemCompletedTurn(entry);
|
|
113
|
+
if (itemTurn)
|
|
114
|
+
itemSeen = true;
|
|
115
|
+
const turn = classifyEntry(entry);
|
|
116
|
+
switch (turn.kind) {
|
|
117
|
+
case "summary":
|
|
118
|
+
summaryTurns += 1;
|
|
119
|
+
break;
|
|
120
|
+
case "message":
|
|
121
|
+
messages += 1;
|
|
122
|
+
if (!itemSeen && isLegacyMessageTurn(entry))
|
|
123
|
+
legacyDialogueBeforeItems = true;
|
|
124
|
+
if (turn.role === "user" && title === "")
|
|
125
|
+
title = turn.text;
|
|
126
|
+
break;
|
|
127
|
+
case "tool-call":
|
|
128
|
+
if (turn.schema === "item-completed")
|
|
129
|
+
itemToolCalls += 1;
|
|
130
|
+
else if (itemSeen)
|
|
131
|
+
legacyCallsAfterItems += 1;
|
|
132
|
+
else
|
|
133
|
+
legacyCallsBeforeItems += 1;
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
// "none" and "unknown" contribute no turn.
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const metaStamp = toIsoUtc(meta?.timestamp ?? null);
|
|
141
|
+
return {
|
|
142
|
+
filePath,
|
|
143
|
+
meta,
|
|
144
|
+
// The title reaches the target's metadata, so it is redacted as the turn text is (FR-28).
|
|
145
|
+
title: titleOf(redactSensitiveText(title)),
|
|
146
|
+
startedAt: metaStamp ?? firstEntryStamp,
|
|
147
|
+
updatedAt: lastStamp ?? metaStamp,
|
|
148
|
+
// The calls a mixed-era file made before its first item turn are kept; the rest are repeats or
|
|
149
|
+
// an item-era file's whole `response_item` stream, so they are not counted (C-12).
|
|
150
|
+
turnCount: summaryTurns +
|
|
151
|
+
messages +
|
|
152
|
+
itemToolCalls +
|
|
153
|
+
(itemSeen
|
|
154
|
+
? legacyDialogueBeforeItems
|
|
155
|
+
? legacyCallsBeforeItems
|
|
156
|
+
: 0
|
|
157
|
+
: legacyCallsBeforeItems + legacyCallsAfterItems),
|
|
158
|
+
truncated: state.truncated,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
export async function listCodexSessions(home) {
|
|
162
|
+
const descriptors = [];
|
|
163
|
+
let failed = 0;
|
|
164
|
+
let firstFailure = null;
|
|
165
|
+
for (const filePath of await listRolloutFiles(sessionsRoot(home))) {
|
|
166
|
+
let summary;
|
|
167
|
+
try {
|
|
168
|
+
summary = await summarizeRollout(filePath);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
if (isNotFoundError(error))
|
|
172
|
+
continue; // A rollout may disappear during a concurrent cleanup.
|
|
173
|
+
// One unreadable rollout must not hide the rest of the home (C-13). The home still reports a
|
|
174
|
+
// failure when nothing at all could be read, so a broken mount is never silent.
|
|
175
|
+
failed += 1;
|
|
176
|
+
firstFailure ??= error;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const meta = summary.meta;
|
|
180
|
+
if (meta === null)
|
|
181
|
+
continue;
|
|
182
|
+
const repoPaths = meta.cwd !== null && isAbsolute(meta.cwd) ? [meta.cwd] : [];
|
|
183
|
+
descriptors.push({
|
|
184
|
+
ref: { agent: "codex", home, id: meta.id },
|
|
185
|
+
title: summary.title,
|
|
186
|
+
startedAt: summary.startedAt ?? "",
|
|
187
|
+
updatedAt: summary.updatedAt ?? summary.startedAt ?? "",
|
|
188
|
+
turnCount: summary.turnCount,
|
|
189
|
+
repoPath: repoPaths[0] ?? null,
|
|
190
|
+
repoPaths,
|
|
191
|
+
startDirectory: repoPaths[0] ?? null,
|
|
192
|
+
filePath,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (descriptors.length === 0 && failed > 0) {
|
|
196
|
+
throw firstFailure instanceof Error ? firstFailure : new Error(String(firstFailure));
|
|
197
|
+
}
|
|
198
|
+
descriptors.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
199
|
+
return descriptors;
|
|
200
|
+
}
|
|
201
|
+
export async function loadCodexSession(descriptor) {
|
|
202
|
+
const rollout = await readRollout(descriptor.filePath);
|
|
203
|
+
return {
|
|
204
|
+
provenance: {
|
|
205
|
+
ref: descriptor.ref,
|
|
206
|
+
title: descriptor.title,
|
|
207
|
+
startedAt: descriptor.startedAt,
|
|
208
|
+
updatedAt: descriptor.updatedAt,
|
|
209
|
+
repo: {
|
|
210
|
+
commit: rollout.meta?.commit ?? null,
|
|
211
|
+
branch: rollout.meta?.branch ?? null,
|
|
212
|
+
changedPaths: rollout.changedPaths,
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
turns: rollout.turns,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function titleOf(text) {
|
|
219
|
+
const line = text
|
|
220
|
+
.split("\n")
|
|
221
|
+
.find((candidate) => candidate.trim() !== "")
|
|
222
|
+
?.trim() ?? "";
|
|
223
|
+
return line.length > TITLE_LIMIT ? `${line.slice(0, TITLE_LIMIT - 1)}…` : line;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Two dialogue schemas exist, and a rollout may even carry both (C-7, C-12):
|
|
227
|
+
*
|
|
228
|
+
* - the older one: messages from `event_msg` (`user_message`/`agent_message`) and tool calls from
|
|
229
|
+
* `response_item` (`function_call`/`custom_tool_call`);
|
|
230
|
+
* - the `item_completed` one: every turn — user text, agent text and every tool-like action — is a
|
|
231
|
+
* single `event_msg` whose `payload.item.type` says which. Its `response_item` stream repeats the
|
|
232
|
+
* same actions at a coarser granularity, so once a file speaks it, those repeats are not read as
|
|
233
|
+
* turns.
|
|
234
|
+
*
|
|
235
|
+
* Messages are never gated by schema: a legacy thread that was resumed by a newer client carries
|
|
236
|
+
* the dialogue of both eras, and each stays readable. The repeat rule therefore applies to tool
|
|
237
|
+
* calls only.
|
|
238
|
+
*
|
|
239
|
+
* Reasoning, in either shape, produces nothing at all (C-4, FR-28, NG-8). Which entries count is
|
|
240
|
+
* settled by `classifyEntry`, the same function the selection list counts with.
|
|
241
|
+
*/
|
|
242
|
+
function toCanonicalTurns(entries) {
|
|
243
|
+
const cut = entries.findIndex(isItemCompletedTurn);
|
|
244
|
+
const legacyCalls = legacyCallScope(entries, cut);
|
|
245
|
+
const outputs = legacyCalls === "none" ? new Map() : callOutputs(entries);
|
|
246
|
+
const turns = [];
|
|
247
|
+
const changed = new Set();
|
|
248
|
+
let skippedEntries = 0;
|
|
249
|
+
for (const [position, entry] of entries.entries()) {
|
|
250
|
+
const turn = classifyEntry(entry);
|
|
251
|
+
if (turn.kind === "unknown") {
|
|
252
|
+
skippedEntries += 1;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (turn.kind === "none")
|
|
256
|
+
continue;
|
|
257
|
+
if (turn.kind === "summary") {
|
|
258
|
+
turns.push({
|
|
259
|
+
index: turns.length,
|
|
260
|
+
role: "agent",
|
|
261
|
+
kind: "summary",
|
|
262
|
+
// FR-28, security: credentials in message text must not cross to a different vendor.
|
|
263
|
+
text: redactSensitiveText(turn.text),
|
|
264
|
+
toolCall: null,
|
|
265
|
+
timestamp: toIsoUtc(entry.timestamp),
|
|
266
|
+
});
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (turn.kind === "message") {
|
|
270
|
+
turns.push({
|
|
271
|
+
index: turns.length,
|
|
272
|
+
role: turn.role,
|
|
273
|
+
kind: "message",
|
|
274
|
+
// FR-28, security: credentials in message text must not cross to a different vendor.
|
|
275
|
+
text: redactSensitiveText(turn.text),
|
|
276
|
+
toolCall: null,
|
|
277
|
+
timestamp: toIsoUtc(entry.timestamp),
|
|
278
|
+
});
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
// The newer schema repeats its actions in `response_item`, so those repeats are not turns.
|
|
282
|
+
if (turn.schema === "legacy" && !readsLegacyCall(legacyCalls, position, cut))
|
|
283
|
+
continue;
|
|
284
|
+
const body = turn.schema === "item-completed" ? itemTurn(entry) : legacyCallTurn(entry, outputs);
|
|
285
|
+
if (body === null)
|
|
286
|
+
continue;
|
|
287
|
+
turns.push({
|
|
288
|
+
index: turns.length,
|
|
289
|
+
role: body.role,
|
|
290
|
+
kind: body.kind,
|
|
291
|
+
text: body.text,
|
|
292
|
+
toolCall: body.toolCall,
|
|
293
|
+
timestamp: toIsoUtc(entry.timestamp),
|
|
294
|
+
});
|
|
295
|
+
for (const path of body.changedPaths)
|
|
296
|
+
changed.add(path);
|
|
297
|
+
}
|
|
298
|
+
return { turns, skippedEntries, changedPaths: [...changed] };
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Classifies one entry without building anything: no record, no redaction, and no string work beyond
|
|
302
|
+
* the message text a title needs. A kind this module does not understand is reported, never guessed
|
|
303
|
+
* at (C-6); reasoning, compaction and activity markers are understood and carry no turn (C-4, C-12).
|
|
304
|
+
* An empty message carries no turn in either schema, so both eras agree on what a row counts.
|
|
305
|
+
*/
|
|
306
|
+
function classifyEntry(entry) {
|
|
307
|
+
if (!KNOWN_ENTRY_TYPES.has(entry.type))
|
|
308
|
+
return { kind: "unknown" };
|
|
309
|
+
if (entry.type === CODEX_ENTRY_COMPACTED) {
|
|
310
|
+
const message = entry.payload.message;
|
|
311
|
+
if (typeof message !== "string" || message.trim() === "")
|
|
312
|
+
return { kind: "none" };
|
|
313
|
+
return { kind: "summary", text: message };
|
|
314
|
+
}
|
|
315
|
+
if (entry.type === CODEX_ENTRY_EVENT_MSG) {
|
|
316
|
+
const type = payloadType(entry);
|
|
317
|
+
if (type === CODEX_EVENT_ITEM_COMPLETED)
|
|
318
|
+
return itemCompletedTurn(entry);
|
|
319
|
+
if (type !== CODEX_EVENT_USER_MESSAGE && type !== CODEX_EVENT_AGENT_MESSAGE)
|
|
320
|
+
return { kind: "none" };
|
|
321
|
+
const message = entry.payload.message;
|
|
322
|
+
if (typeof message !== "string" || message.trim() === "")
|
|
323
|
+
return { kind: "none" };
|
|
324
|
+
return {
|
|
325
|
+
kind: "message",
|
|
326
|
+
role: type === CODEX_EVENT_USER_MESSAGE ? "user" : "agent",
|
|
327
|
+
text: message,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (entry.type !== CODEX_ENTRY_RESPONSE_ITEM)
|
|
331
|
+
return { kind: "none" };
|
|
332
|
+
const type = payloadType(entry);
|
|
333
|
+
if (type !== CODEX_ITEM_FUNCTION_CALL && type !== CODEX_ITEM_CUSTOM_TOOL_CALL)
|
|
334
|
+
return { kind: "none" };
|
|
335
|
+
const toolName = entry.payload.name;
|
|
336
|
+
if (typeof toolName !== "string" || toolName === "")
|
|
337
|
+
return { kind: "none" };
|
|
338
|
+
return { kind: "tool-call", schema: "legacy" };
|
|
339
|
+
}
|
|
340
|
+
/** The class of one `item_completed` entry, from the same tables its builder reads (C-12). */
|
|
341
|
+
function itemCompletedTurn(entry) {
|
|
342
|
+
const item = itemCompletedItem(entry);
|
|
343
|
+
if (item === null)
|
|
344
|
+
return { kind: "none" };
|
|
345
|
+
const itemType = typeof item.type === "string" ? item.type : "";
|
|
346
|
+
const role = ITEM_MESSAGE_ROLES.get(itemType);
|
|
347
|
+
if (role !== undefined) {
|
|
348
|
+
const text = itemContentText(item);
|
|
349
|
+
// An item the model sent no text in — an image only, for one — carries no turn, exactly as the
|
|
350
|
+
// older schema's empty message does, so a row and the session it opens agree on the count. It
|
|
351
|
+
// does not mark the file as recording turns as items either: `isItemCompletedTurn` asks the same
|
|
352
|
+
// question this function answers.
|
|
353
|
+
if (text.trim() === "")
|
|
354
|
+
return { kind: "none" };
|
|
355
|
+
return { kind: "message", role, text };
|
|
356
|
+
}
|
|
357
|
+
if (ITEM_TOOL_TURN_BUILDERS.has(itemType))
|
|
358
|
+
return { kind: "tool-call", schema: "item-completed" };
|
|
359
|
+
return IGNORED_ITEM_TYPES.has(itemType) ? { kind: "none" } : { kind: "unknown" };
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* True when this entry records a turn as an `item_completed` item (C-12), whatever text a message
|
|
363
|
+
* carries. A file that records turns this way repeats them coarsely in `response_item`, so those
|
|
364
|
+
* repeats are not read as turns. An empty message or a kind that carries no turn marks nothing.
|
|
365
|
+
*/
|
|
366
|
+
function isItemCompletedTurn(entry) {
|
|
367
|
+
const turn = itemCompletedTurn(entry);
|
|
368
|
+
return turn.kind === "message" || turn.kind === "tool-call";
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Which older-schema calls a rollout still has to offer (C-12). `response_item` in a file that
|
|
372
|
+
* records turns as items holds the coarser repeat of those items, so those calls are not read — but
|
|
373
|
+
* a thread that a newer client resumed keeps the dialogue of both eras, and the calls it made
|
|
374
|
+
* before the first item turn are the only record of that work. Those are read; the ones after it
|
|
375
|
+
* are the repeats.
|
|
376
|
+
*/
|
|
377
|
+
function legacyCallScope(entries, cut) {
|
|
378
|
+
if (cut === -1)
|
|
379
|
+
return "all";
|
|
380
|
+
return entries.slice(0, cut).some(isLegacyMessageTurn) ? "before-items" : "none";
|
|
381
|
+
}
|
|
382
|
+
/** True when one older-schema call at this position is read under `scope` (C-12). */
|
|
383
|
+
function readsLegacyCall(scope, position, cut) {
|
|
384
|
+
if (scope === "all")
|
|
385
|
+
return true;
|
|
386
|
+
return scope === "before-items" && position < cut;
|
|
387
|
+
}
|
|
388
|
+
/** True when this entry is an older-schema dialogue message that carries text (C-7). */
|
|
389
|
+
function isLegacyMessageTurn(entry) {
|
|
390
|
+
if (entry.type !== CODEX_ENTRY_EVENT_MSG)
|
|
391
|
+
return false;
|
|
392
|
+
const type = payloadType(entry);
|
|
393
|
+
if (type !== CODEX_EVENT_USER_MESSAGE && type !== CODEX_EVENT_AGENT_MESSAGE)
|
|
394
|
+
return false;
|
|
395
|
+
const message = entry.payload.message;
|
|
396
|
+
return typeof message === "string" && message.trim() !== "";
|
|
397
|
+
}
|
|
398
|
+
/** The recorded answers of the older schema's calls, by call id (FR-25, FR-54). */
|
|
399
|
+
function callOutputs(entries) {
|
|
400
|
+
const outputs = new Map();
|
|
401
|
+
for (const entry of entries) {
|
|
402
|
+
if (entry.type !== CODEX_ENTRY_RESPONSE_ITEM)
|
|
403
|
+
continue;
|
|
404
|
+
const type = payloadType(entry);
|
|
405
|
+
if (type !== CODEX_ITEM_FUNCTION_CALL_OUTPUT && type !== CODEX_ITEM_CUSTOM_TOOL_CALL_OUTPUT)
|
|
406
|
+
continue;
|
|
407
|
+
const callId = entry.payload.call_id;
|
|
408
|
+
if (typeof callId !== "string")
|
|
409
|
+
continue;
|
|
410
|
+
outputs.set(callId, outputTextOf(entry.payload.output));
|
|
411
|
+
}
|
|
412
|
+
return outputs;
|
|
413
|
+
}
|
|
414
|
+
/** One older-schema `response_item` call becomes one tool-call turn (C-7). */
|
|
415
|
+
function legacyCallTurn(entry, outputs) {
|
|
416
|
+
const toolName = entry.payload.name;
|
|
417
|
+
if (typeof toolName !== "string" || toolName === "")
|
|
418
|
+
return null;
|
|
419
|
+
const rawArguments = payloadType(entry) === CODEX_ITEM_FUNCTION_CALL ? entry.payload.arguments : entry.payload.input;
|
|
420
|
+
const argumentsText = typeof rawArguments === "string" ? rawArguments : "";
|
|
421
|
+
const callId = entry.payload.call_id;
|
|
422
|
+
// FR-54: use has() not get() — outputs.get() can return "" for an empty result.
|
|
423
|
+
const resultRecorded = typeof callId === "string" && outputs.has(callId);
|
|
424
|
+
const output = typeof callId === "string" ? (outputs.get(callId) ?? null) : null;
|
|
425
|
+
const toolCall = toolCallRecord(toolName, argumentsText, output, resultRecorded);
|
|
426
|
+
return toolTurn(toolCall, toolCall.effect === "mutating" ? pathsOf(argumentsText) : []);
|
|
427
|
+
}
|
|
428
|
+
/** One `item_completed` entry becomes one tool-call turn, through the table that built it (C-12). */
|
|
429
|
+
function itemTurn(entry) {
|
|
430
|
+
const item = itemCompletedItem(entry);
|
|
431
|
+
return item === null ? null : turnFromItemCompleted(item);
|
|
432
|
+
}
|
|
433
|
+
/** The inner `item` of an `item_completed` entry, when the entry is one (C-12). */
|
|
434
|
+
function itemCompletedItem(entry) {
|
|
435
|
+
if (entry.type !== CODEX_ENTRY_EVENT_MSG)
|
|
436
|
+
return null;
|
|
437
|
+
if (payloadType(entry) !== CODEX_EVENT_ITEM_COMPLETED)
|
|
438
|
+
return null;
|
|
439
|
+
const item = entry.payload.item;
|
|
440
|
+
return typeof item === "object" && item !== null ? item : null;
|
|
441
|
+
}
|
|
442
|
+
/** Item kinds that are understood and deliberately carry no turn (C-4, C-12). */
|
|
443
|
+
const IGNORED_ITEM_TYPES = new Set([
|
|
444
|
+
CODEX_THREAD_ITEM_REASONING,
|
|
445
|
+
CODEX_THREAD_ITEM_CONTEXT_COMPACTION,
|
|
446
|
+
CODEX_THREAD_ITEM_SUB_AGENT_ACTIVITY,
|
|
447
|
+
]);
|
|
448
|
+
/** The role of a message item, by kind. A kind outside this table is not a message (C-12). */
|
|
449
|
+
const ITEM_MESSAGE_ROLES = new Map([
|
|
450
|
+
[CODEX_THREAD_ITEM_USER_MESSAGE, "user"],
|
|
451
|
+
[CODEX_THREAD_ITEM_AGENT_MESSAGE, "agent"],
|
|
452
|
+
]);
|
|
453
|
+
/**
|
|
454
|
+
* Every `item_completed` kind that carries a tool call, and how its record is built (C-12). The
|
|
455
|
+
* classifier and the builder read this one table, so no kind can be counted as a turn and then
|
|
456
|
+
* built as none, or the reverse.
|
|
457
|
+
*/
|
|
458
|
+
const ITEM_TOOL_TURN_BUILDERS = new Map([
|
|
459
|
+
[CODEX_THREAD_ITEM_COMMAND_EXECUTION, commandExecutionTurn],
|
|
460
|
+
[CODEX_THREAD_ITEM_FILE_CHANGE, fileChangeTurn],
|
|
461
|
+
[CODEX_THREAD_ITEM_EXTENSION, extensionTurn],
|
|
462
|
+
[CODEX_THREAD_ITEM_MCP_TOOL_CALL, mcpToolCallTurn],
|
|
463
|
+
[CODEX_THREAD_ITEM_COLLAB_AGENT_TOOL_CALL, collabAgentToolCallTurn],
|
|
464
|
+
[CODEX_THREAD_ITEM_IMAGE_VIEW, imageViewTurn],
|
|
465
|
+
]);
|
|
466
|
+
/**
|
|
467
|
+
* One `item_completed` item becomes one canonical turn. The kind of the call is settled by
|
|
468
|
+
* `item.type` itself, so the effect is read from that and never guessed from a tool name (FR-26).
|
|
469
|
+
* Returns null for a kind that carries no turn.
|
|
470
|
+
*/
|
|
471
|
+
function turnFromItemCompleted(item) {
|
|
472
|
+
const itemType = typeof item.type === "string" ? item.type : "";
|
|
473
|
+
const role = ITEM_MESSAGE_ROLES.get(itemType);
|
|
474
|
+
if (role !== undefined) {
|
|
475
|
+
return {
|
|
476
|
+
role,
|
|
477
|
+
kind: "message",
|
|
478
|
+
// FR-28, security: credentials in message text must not cross to a different vendor.
|
|
479
|
+
text: redactSensitiveText(itemContentText(item)),
|
|
480
|
+
toolCall: null,
|
|
481
|
+
changedPaths: [],
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
return ITEM_TOOL_TURN_BUILDERS.get(itemType)?.(item) ?? null;
|
|
485
|
+
}
|
|
486
|
+
/** The common shape of a turn a tool-like item produces. */
|
|
487
|
+
function toolTurn(toolCall, changedPaths = []) {
|
|
488
|
+
return { role: "agent", kind: "tool-call", text: "", toolCall, changedPaths };
|
|
489
|
+
}
|
|
490
|
+
/** `CommandExecution`: the shell line the model wrote, and the shape of its output (FR-23..FR-25). */
|
|
491
|
+
function commandExecutionTurn(item) {
|
|
492
|
+
const output = firstString(item.aggregated_output, item.formatted_output, item.stdout);
|
|
493
|
+
return toolTurn(toolCallRecord("exec", commandText(item.command), output, output !== null));
|
|
494
|
+
}
|
|
495
|
+
/** `FileChange`: the patch is the argument, and its paths are the files the call touched (FR-24, FR-36). */
|
|
496
|
+
function fileChangeTurn(item) {
|
|
497
|
+
const paths = objectKeys(item.changes);
|
|
498
|
+
return toolTurn(itemToolCallRecord("apply_patch", fileChangeArguments(item.changes), `${paths.length} file(s) changed`, "mutating", false), paths);
|
|
499
|
+
}
|
|
500
|
+
/** `Extension`: a tool action such as a web search, with its queries kept and its results dropped. */
|
|
501
|
+
function extensionTurn(item) {
|
|
502
|
+
const kind = firstNonEmptyString(item.kind) ?? "extension";
|
|
503
|
+
const results = Array.isArray(item.results) ? item.results.length : 0;
|
|
504
|
+
return toolTurn(itemToolCallRecord(kind, extensionArguments(item), `${results} result(s) dropped`, READ_ONLY_EXTENSION_KINDS.has(kind) ? "read-only" : "unknown", true));
|
|
505
|
+
}
|
|
506
|
+
/** `McpToolCall`: a server tool call, named by server and tool (FR-27). */
|
|
507
|
+
function mcpToolCallTurn(item) {
|
|
508
|
+
const call = mcpToolCall(item);
|
|
509
|
+
return toolTurn(itemToolCallRecord(call.toolName, call.argumentsText, mcpOutcome(item),
|
|
510
|
+
// A server's own `readOnlyHint` is a claim by another party, not the item kind (FR-26).
|
|
511
|
+
"unknown", item.result !== undefined && item.result !== null));
|
|
512
|
+
}
|
|
513
|
+
/** `CollabAgentToolCall`: an action on another agent of the same client. */
|
|
514
|
+
function collabAgentToolCallTurn(item) {
|
|
515
|
+
const call = collabAgentToolCall(item);
|
|
516
|
+
return toolTurn(itemToolCallRecord(call.toolName, call.argumentsText, call.outcome, "unknown", objectKeys(item.agents_states).length > 0));
|
|
517
|
+
}
|
|
518
|
+
/** `ImageView`: the path the model asked for; the image itself never crosses (FR-24). */
|
|
519
|
+
function imageViewTurn(item) {
|
|
520
|
+
return toolTurn(itemToolCallRecord("view_image", firstNonEmptyString(item.path) ?? "", "image not carried", "read-only", false));
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* The text of a message item. `content[].type` is `"text"` on a user message and `"Text"` on an
|
|
524
|
+
* agent message, so the text is taken from the part's own field and never by that casing.
|
|
525
|
+
*/
|
|
526
|
+
function itemContentText(item) {
|
|
527
|
+
const content = item.content;
|
|
528
|
+
if (!Array.isArray(content))
|
|
529
|
+
return "";
|
|
530
|
+
return content
|
|
531
|
+
.map((part) => typeof part === "object" && part !== null
|
|
532
|
+
? firstNonEmptyString(part.text)
|
|
533
|
+
: null)
|
|
534
|
+
.filter((part) => part !== null)
|
|
535
|
+
.join("\n");
|
|
536
|
+
}
|
|
537
|
+
/** A Codex command is an argv array; the shell line the model wrote is its joined form. */
|
|
538
|
+
function commandText(value) {
|
|
539
|
+
if (Array.isArray(value))
|
|
540
|
+
return value.filter((part) => typeof part === "string").join(" ");
|
|
541
|
+
return typeof value === "string" ? value : "";
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* FR-24 protects a result body, not a tool argument, and the legacy `apply_patch` call already
|
|
545
|
+
* carries the patch text it was given. A `FileChange` item is the same kind of argument, so the
|
|
546
|
+
* patch is rebuilt from it whole — path plus content — in `apply_patch`'s own shape.
|
|
547
|
+
*/
|
|
548
|
+
function fileChangeArguments(changes) {
|
|
549
|
+
if (typeof changes !== "object" || changes === null)
|
|
550
|
+
return "";
|
|
551
|
+
const parts = [];
|
|
552
|
+
for (const [path, change] of Object.entries(changes)) {
|
|
553
|
+
const record = typeof change === "object" && change !== null ? change : {};
|
|
554
|
+
const kind = firstNonEmptyString(record.type) ?? "update";
|
|
555
|
+
const verb = kind === "add" ? "Add" : kind === "delete" ? "Delete" : "Update";
|
|
556
|
+
const content = firstNonEmptyString(record.content);
|
|
557
|
+
parts.push(`*** ${verb} File: ${path}${content === null ? "" : `\n${content}`}`);
|
|
558
|
+
}
|
|
559
|
+
return parts.join("\n");
|
|
560
|
+
}
|
|
561
|
+
/** The queries an `Extension` item searched with, one per line. */
|
|
562
|
+
function extensionArguments(item) {
|
|
563
|
+
const action = item.action;
|
|
564
|
+
if (typeof action === "object" && action !== null) {
|
|
565
|
+
const queries = action.queries;
|
|
566
|
+
if (Array.isArray(queries)) {
|
|
567
|
+
const lines = queries.filter((query) => typeof query === "string" && query !== "");
|
|
568
|
+
if (lines.length > 0)
|
|
569
|
+
return lines.join("\n");
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return firstNonEmptyString(item.query) ?? "";
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* A server tool call names itself in `server` and `tool` and states its arguments as JSON. Both
|
|
576
|
+
* are kept: the name unchanged (FR-27) and the arguments redacted like any other call (FR-24).
|
|
577
|
+
*/
|
|
578
|
+
function mcpToolCall(item) {
|
|
579
|
+
const server = firstNonEmptyString(item.server);
|
|
580
|
+
const tool = firstNonEmptyString(item.tool);
|
|
581
|
+
const toolName = server !== null && tool !== null ? `${server}.${tool}` : (tool ?? server ?? "mcp");
|
|
582
|
+
return { toolName, argumentsText: jsonArguments(item.arguments) };
|
|
583
|
+
}
|
|
584
|
+
/** The recorded status of a server call, plus how many result items were dropped (FR-24, FR-25). */
|
|
585
|
+
function mcpOutcome(item) {
|
|
586
|
+
const result = item.result;
|
|
587
|
+
const record = typeof result === "object" && result !== null ? result : null;
|
|
588
|
+
const content = record === null ? null : record.content;
|
|
589
|
+
const results = Array.isArray(content) ? content.length : record === null ? 0 : 1;
|
|
590
|
+
const dropped = `${results} result(s) dropped`;
|
|
591
|
+
const status = firstNonEmptyString(item.status);
|
|
592
|
+
return status === null ? dropped : `${status}, ${dropped}`;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* An action on another agent. Its `tool` field names the action, and the agents it addresses are
|
|
596
|
+
* the argument; the per-agent states it records are that call's result and are dropped (FR-24).
|
|
597
|
+
*/
|
|
598
|
+
function collabAgentToolCall(item) {
|
|
599
|
+
const targets = [
|
|
600
|
+
...stringValues(item.receiver_agents),
|
|
601
|
+
...stringValues(item.receiver_thread_ids),
|
|
602
|
+
];
|
|
603
|
+
return {
|
|
604
|
+
toolName: firstNonEmptyString(item.tool) ?? "collab-agent",
|
|
605
|
+
argumentsText: targets.join("\n"),
|
|
606
|
+
outcome: firstNonEmptyString(item.status) ?? "no status recorded",
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
/** Tool arguments as the recorded JSON text, or as they already are when they are a string. */
|
|
610
|
+
function jsonArguments(value) {
|
|
611
|
+
if (typeof value === "string")
|
|
612
|
+
return value;
|
|
613
|
+
if (typeof value !== "object" || value === null)
|
|
614
|
+
return "";
|
|
615
|
+
return JSON.stringify(value);
|
|
616
|
+
}
|
|
617
|
+
/** The non-empty strings of an array field, in source order. */
|
|
618
|
+
function stringValues(value) {
|
|
619
|
+
if (!Array.isArray(value))
|
|
620
|
+
return [];
|
|
621
|
+
return value.filter((part) => typeof part === "string" && part !== "");
|
|
622
|
+
}
|
|
623
|
+
/** Non-empty string keys of an object, in source order — the paths a change touched. */
|
|
624
|
+
function objectKeys(value) {
|
|
625
|
+
if (typeof value !== "object" || value === null)
|
|
626
|
+
return [];
|
|
627
|
+
return Object.keys(value).filter((key) => key !== "");
|
|
628
|
+
}
|
|
629
|
+
/** The first value that is a string, empty string included: an empty result was still recorded. */
|
|
630
|
+
function firstString(...values) {
|
|
631
|
+
for (const value of values) {
|
|
632
|
+
if (typeof value === "string")
|
|
633
|
+
return value;
|
|
634
|
+
}
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
/** The first value that is a non-empty string, or null. `""` counts as absent here. */
|
|
638
|
+
function firstNonEmptyString(...values) {
|
|
639
|
+
for (const value of values) {
|
|
640
|
+
if (typeof value === "string" && value !== "")
|
|
641
|
+
return value;
|
|
642
|
+
}
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* A structured item states its own outcome, so this variant names it instead of measuring a dropped
|
|
647
|
+
* body. The arguments still cross redacted, exactly like the legacy tool-call path (FR-24, FR-28).
|
|
648
|
+
*/
|
|
649
|
+
function itemToolCallRecord(toolName, argumentsText, outcome, effect, bodyDropped) {
|
|
650
|
+
const safeArguments = redactSensitiveArgumentsText(argumentsText);
|
|
651
|
+
const head = `${toolName}(${singleLine(safeArguments, ARGUMENTS_PREVIEW_LIMIT)})`;
|
|
652
|
+
return {
|
|
653
|
+
toolName,
|
|
654
|
+
argumentsText: safeArguments,
|
|
655
|
+
outcomeLine: redactSensitiveText(`${head} → ${outcome}`),
|
|
656
|
+
effect,
|
|
657
|
+
bodyDropped,
|
|
658
|
+
resultRecorded: true,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
/** Only the shape of the output is measured. Not one fragment of it is carried (FR-24, FR-25). */
|
|
662
|
+
function toolCallRecord(toolName, argumentsText, output, resultRecorded) {
|
|
663
|
+
const safeArguments = redactSensitiveArgumentsText(argumentsText);
|
|
664
|
+
const head = `${toolName}(${singleLine(safeArguments, ARGUMENTS_PREVIEW_LIMIT)})`;
|
|
665
|
+
const outcomeLine = output === null
|
|
666
|
+
? `${head} → no output recorded`
|
|
667
|
+
: `${head} → ${output.split("\n").length} lines, body dropped`;
|
|
668
|
+
return {
|
|
669
|
+
toolName,
|
|
670
|
+
argumentsText: safeArguments,
|
|
671
|
+
outcomeLine: redactSensitiveText(outcomeLine),
|
|
672
|
+
effect: effectOf(toolName),
|
|
673
|
+
bodyDropped: output !== null,
|
|
674
|
+
// FR-54: false when no *_call_output entry existed for this call_id (broken tail signal).
|
|
675
|
+
resultRecorded,
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
function effectOf(toolName) {
|
|
679
|
+
if (MUTATING_TOOLS.has(toolName))
|
|
680
|
+
return "mutating";
|
|
681
|
+
if (READ_ONLY_TOOLS.has(toolName))
|
|
682
|
+
return "read-only";
|
|
683
|
+
return "unknown";
|
|
684
|
+
}
|
|
685
|
+
function outputTextOf(output) {
|
|
686
|
+
if (typeof output === "string")
|
|
687
|
+
return output;
|
|
688
|
+
if (Array.isArray(output)) {
|
|
689
|
+
return output
|
|
690
|
+
.map((part) => typeof part === "object" && part !== null
|
|
691
|
+
? String(part.text ?? "")
|
|
692
|
+
: "")
|
|
693
|
+
.join("\n");
|
|
694
|
+
}
|
|
695
|
+
return output === undefined || output === null ? "" : JSON.stringify(output);
|
|
696
|
+
}
|
|
697
|
+
function singleLine(text, limit) {
|
|
698
|
+
const flat = text.replaceAll(/\s+/g, " ").trim();
|
|
699
|
+
return flat.length > limit ? `${flat.slice(0, limit - 1)}…` : flat;
|
|
700
|
+
}
|
|
701
|
+
/** Files a mutating call touched, for RepoSnapshot.changedPaths (FR-36). */
|
|
702
|
+
function pathsOf(argumentsText) {
|
|
703
|
+
let text = argumentsText;
|
|
704
|
+
const direct = [];
|
|
705
|
+
try {
|
|
706
|
+
const parsed = JSON.parse(argumentsText);
|
|
707
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
708
|
+
const record = parsed;
|
|
709
|
+
const strings = Object.values(record).filter((value) => typeof value === "string");
|
|
710
|
+
text = strings.join("\n");
|
|
711
|
+
for (const key of ["path", "file_path", "filename"]) {
|
|
712
|
+
const value = record[key];
|
|
713
|
+
if (typeof value === "string" && value !== "")
|
|
714
|
+
direct.push(value);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
catch {
|
|
719
|
+
// Arguments that are not JSON are searched as they were recorded.
|
|
720
|
+
}
|
|
721
|
+
const patched = [...text.matchAll(/\*\*\* (?:Add|Update|Delete) File: (.+)/g)].map((match) => (match[1] ?? "").trim());
|
|
722
|
+
return [...direct, ...patched].filter((path) => path !== "");
|
|
723
|
+
}
|