aicodeman 1.47.0 → 1.49.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 +15 -3
- package/dist/cli-notify.d.ts +34 -0
- package/dist/cli-notify.d.ts.map +1 -0
- package/dist/cli-notify.js +100 -0
- package/dist/cli-notify.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/config/cli-registry/patterns.d.ts +1 -1
- package/dist/config/cli-registry/patterns.d.ts.map +1 -1
- package/dist/config/cli-registry/patterns.js +4 -0
- package/dist/config/cli-registry/patterns.js.map +1 -1
- package/dist/config/cli-registry/schema.d.ts +7 -0
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +67 -3
- package/dist/config/cli-registry/schema.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +114 -31
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +51 -21
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/config/foreign-tmux.d.ts +48 -0
- package/dist/config/foreign-tmux.d.ts.map +1 -0
- package/dist/config/foreign-tmux.js +48 -0
- package/dist/config/foreign-tmux.js.map +1 -0
- package/dist/config/path-probe.d.ts +6 -0
- package/dist/config/path-probe.d.ts.map +1 -1
- package/dist/config/path-probe.js +6 -0
- package/dist/config/path-probe.js.map +1 -1
- package/dist/config-backup.d.ts +1 -1
- package/dist/config-backup.d.ts.map +1 -1
- package/dist/config-backup.js +2 -0
- package/dist/config-backup.js.map +1 -1
- package/dist/custom-model-hosts.d.ts +32 -8
- package/dist/custom-model-hosts.d.ts.map +1 -1
- package/dist/custom-model-hosts.js +10 -0
- package/dist/custom-model-hosts.js.map +1 -1
- package/dist/custom-model-injection-apply.d.ts +21 -5
- package/dist/custom-model-injection-apply.d.ts.map +1 -1
- package/dist/custom-model-injection-apply.js +121 -27
- package/dist/custom-model-injection-apply.js.map +1 -1
- package/dist/custom-model-injection.d.ts +6 -0
- package/dist/custom-model-injection.d.ts.map +1 -1
- package/dist/custom-model-injection.js +92 -10
- package/dist/custom-model-injection.js.map +1 -1
- package/dist/discord-bridge.d.ts +338 -0
- package/dist/discord-bridge.d.ts.map +1 -0
- package/dist/discord-bridge.js +1256 -0
- package/dist/discord-bridge.js.map +1 -0
- package/dist/docker-hosts.d.ts +8 -1
- package/dist/docker-hosts.d.ts.map +1 -1
- package/dist/docker-hosts.js +5 -5
- package/dist/docker-hosts.js.map +1 -1
- package/dist/edit-history-local-source.d.ts +83 -0
- package/dist/edit-history-local-source.d.ts.map +1 -0
- package/dist/edit-history-local-source.js +198 -0
- package/dist/edit-history-local-source.js.map +1 -0
- package/dist/edit-history-parse.d.ts +114 -0
- package/dist/edit-history-parse.d.ts.map +1 -0
- package/dist/edit-history-parse.js +312 -0
- package/dist/edit-history-parse.js.map +1 -0
- package/dist/edit-history-store.d.ts +209 -0
- package/dist/edit-history-store.d.ts.map +1 -0
- package/dist/edit-history-store.js +599 -0
- package/dist/edit-history-store.js.map +1 -0
- package/dist/foreign-tmux-discovery.d.ts +140 -0
- package/dist/foreign-tmux-discovery.d.ts.map +1 -0
- package/dist/foreign-tmux-discovery.js +366 -0
- package/dist/foreign-tmux-discovery.js.map +1 -0
- package/dist/foreign-tmux.d.ts +381 -0
- package/dist/foreign-tmux.d.ts.map +1 -0
- package/dist/foreign-tmux.js +775 -0
- package/dist/foreign-tmux.js.map +1 -0
- package/dist/git-clone.d.ts +6 -1
- package/dist/git-clone.d.ts.map +1 -1
- package/dist/git-clone.js +79 -14
- package/dist/git-clone.js.map +1 -1
- package/dist/git-fetch-scheduler.d.ts +2 -0
- package/dist/git-fetch-scheduler.d.ts.map +1 -1
- package/dist/git-fetch-scheduler.js +1 -1
- package/dist/git-fetch-scheduler.js.map +1 -1
- package/dist/git-fetch.d.ts +1 -1
- package/dist/git-fetch.d.ts.map +1 -1
- package/dist/git-workspace-status.d.ts +2 -2
- package/dist/git-workspace-status.d.ts.map +1 -1
- package/dist/hooks-config.d.ts +2 -1
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +2 -1
- package/dist/hooks-config.js.map +1 -1
- package/dist/image-watcher.js +4 -4
- package/dist/image-watcher.js.map +1 -1
- package/dist/live-worktree.d.ts +53 -0
- package/dist/live-worktree.d.ts.map +1 -0
- package/dist/live-worktree.js +97 -0
- package/dist/live-worktree.js.map +1 -0
- package/dist/mux-interface.d.ts +22 -2
- package/dist/mux-interface.d.ts.map +1 -1
- package/dist/reboot-restore.d.ts +1 -1
- package/dist/reboot-restore.d.ts.map +1 -1
- package/dist/reboot-restore.js +9 -0
- package/dist/reboot-restore.js.map +1 -1
- package/dist/remote-files.d.ts +150 -5
- package/dist/remote-files.d.ts.map +1 -1
- package/dist/remote-files.js +505 -7
- package/dist/remote-files.js.map +1 -1
- package/dist/remote-hosts.d.ts +15 -9
- package/dist/remote-hosts.d.ts.map +1 -1
- package/dist/remote-hosts.js +42 -20
- package/dist/remote-hosts.js.map +1 -1
- package/dist/session-cli-registry-bridge.d.ts.map +1 -1
- package/dist/session-cli-registry-bridge.js +23 -8
- package/dist/session-cli-registry-bridge.js.map +1 -1
- package/dist/session-env-clamp.d.ts +1 -1
- package/dist/session-env-clamp.d.ts.map +1 -1
- package/dist/session-env-clamp.js +4 -3
- package/dist/session-env-clamp.js.map +1 -1
- package/dist/session.d.ts +161 -24
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +337 -37
- package/dist/session.js.map +1 -1
- package/dist/tmux-manager.d.ts +114 -12
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +318 -41
- package/dist/tmux-manager.js.map +1 -1
- package/dist/types/discord.d.ts +55 -0
- package/dist/types/discord.d.ts.map +1 -0
- package/dist/types/discord.js +18 -0
- package/dist/types/discord.js.map +1 -0
- package/dist/types/foreign-tmux.d.ts +101 -0
- package/dist/types/foreign-tmux.d.ts.map +1 -0
- package/dist/types/foreign-tmux.js +27 -0
- package/dist/types/foreign-tmux.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/session.d.ts +119 -2
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/types/update.d.ts +4 -1
- package/dist/types/update.d.ts.map +1 -1
- package/dist/web/case-path.d.ts +2 -0
- package/dist/web/case-path.d.ts.map +1 -1
- package/dist/web/case-path.js +3 -3
- package/dist/web/case-path.js.map +1 -1
- package/dist/web/edit-history-sync.d.ts +178 -0
- package/dist/web/edit-history-sync.d.ts.map +1 -0
- package/dist/web/edit-history-sync.js +461 -0
- package/dist/web/edit-history-sync.js.map +1 -0
- package/dist/web/launch-defaults.d.ts +1 -1
- package/dist/web/launch-defaults.js +2 -2
- package/dist/web/launch-defaults.js.map +1 -1
- package/dist/web/linked-cases-writer.d.ts +43 -0
- package/dist/web/linked-cases-writer.d.ts.map +1 -0
- package/dist/web/linked-cases-writer.js +107 -0
- package/dist/web/linked-cases-writer.js.map +1 -0
- package/dist/web/paste-image-gc.d.ts +10 -1
- package/dist/web/paste-image-gc.d.ts.map +1 -1
- package/dist/web/paste-image-gc.js +10 -2
- package/dist/web/paste-image-gc.js.map +1 -1
- package/dist/web/ports/session-port.d.ts +13 -0
- package/dist/web/ports/session-port.d.ts.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/{app.fe8a6b4c.js → app.9ea37070.js} +6 -6
- package/dist/web/public/app.9ea37070.js.br +0 -0
- package/dist/web/public/app.9ea37070.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.affcdde6.js → constants.782170e1.js} +114 -25
- package/dist/web/public/constants.782170e1.js.br +0 -0
- package/dist/web/public/constants.782170e1.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/edit-history-ui.js +643 -0
- package/dist/web/public/edit-history-ui.js.br +0 -0
- package/dist/web/public/edit-history-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/foreign-sessions.js +476 -0
- package/dist/web/public/foreign-sessions.js.br +0 -0
- package/dist/web/public/foreign-sessions.js.gz +0 -0
- package/dist/web/public/git-status-ui.js +5 -3
- package/dist/web/public/git-status-ui.js.br +0 -0
- package/dist/web/public/git-status-ui.js.gz +0 -0
- package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.a5e82c95.js +2 -0
- package/dist/web/public/i18n.a5e82c95.js.br +0 -0
- package/dist/web/public/i18n.a5e82c95.js.gz +0 -0
- package/dist/web/public/image-input.a5d0f8f3.js.gz +0 -0
- package/dist/web/public/index.html +183 -18
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
- package/dist/web/public/{keyboard-accessory.ff64fafc.js → keyboard-accessory.b941676c.js} +75 -2
- package/dist/web/public/keyboard-accessory.b941676c.js.br +0 -0
- package/dist/web/public/keyboard-accessory.b941676c.js.gz +0 -0
- package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
- package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
- package/dist/web/public/mobile-overview.js +10 -0
- package/dist/web/public/mobile-overview.js.br +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.67c8eb5b.css +1 -0
- package/dist/web/public/mobile.67c8eb5b.css.br +0 -0
- package/dist/web/public/mobile.67c8eb5b.css.gz +0 -0
- package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.4a56ee63.js → panels-ui.8bcd4473.js} +5 -5
- package/dist/web/public/panels-ui.8bcd4473.js.br +0 -0
- package/dist/web/public/panels-ui.8bcd4473.js.gz +0 -0
- package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
- package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/reboot-restore-ui.js.gz +0 -0
- package/dist/web/public/{respawn-ui.d7adcf6a.js → respawn-ui.304ba0d4.js} +1 -1
- package/dist/web/public/respawn-ui.304ba0d4.js.br +0 -0
- package/dist/web/public/respawn-ui.304ba0d4.js.gz +0 -0
- package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
- package/dist/web/public/security-notices.json +1 -21
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.426fb671.js → session-ui.a7c8c095.js} +30 -30
- package/dist/web/public/session-ui.a7c8c095.js.br +0 -0
- package/dist/web/public/session-ui.a7c8c095.js.gz +0 -0
- package/dist/web/public/settings-ui.18f92052.js +106 -0
- package/dist/web/public/settings-ui.18f92052.js.br +0 -0
- package/dist/web/public/settings-ui.18f92052.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
- package/dist/web/public/styles.6a718331.css +1 -0
- package/dist/web/public/styles.6a718331.css.br +0 -0
- package/dist/web/public/styles.6a718331.css.gz +0 -0
- package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
- package/dist/web/public/sw.js +2 -2
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.98843069.js.gz +0 -0
- package/dist/web/public/terminal-split.js.gz +0 -0
- package/dist/web/public/terminal-tile.js +2 -2
- package/dist/web/public/terminal-tile.js.br +0 -0
- package/dist/web/public/terminal-tile.js.gz +0 -0
- package/dist/web/public/terminal-ui.a7883640.js +4 -0
- package/dist/web/public/terminal-ui.a7883640.js.br +0 -0
- package/dist/web/public/terminal-ui.a7883640.js.gz +0 -0
- package/dist/web/public/tile-grid.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
- package/dist/web/public/vendor/fflate.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/public/whats-new.json +9 -8
- package/dist/web/routes/case-routes.d.ts.map +1 -1
- package/dist/web/routes/case-routes.js +165 -50
- package/dist/web/routes/case-routes.js.map +1 -1
- package/dist/web/routes/config-backup-routes.d.ts +5 -1
- package/dist/web/routes/config-backup-routes.d.ts.map +1 -1
- package/dist/web/routes/config-backup-routes.js +4 -1
- package/dist/web/routes/config-backup-routes.js.map +1 -1
- package/dist/web/routes/custom-model-routes.d.ts +7 -2
- package/dist/web/routes/custom-model-routes.d.ts.map +1 -1
- package/dist/web/routes/custom-model-routes.js +51 -6
- package/dist/web/routes/custom-model-routes.js.map +1 -1
- package/dist/web/routes/discord-routes.d.ts +25 -0
- package/dist/web/routes/discord-routes.d.ts.map +1 -0
- package/dist/web/routes/discord-routes.js +206 -0
- package/dist/web/routes/discord-routes.js.map +1 -0
- package/dist/web/routes/edit-history-routes.d.ts +43 -0
- package/dist/web/routes/edit-history-routes.d.ts.map +1 -0
- package/dist/web/routes/edit-history-routes.js +107 -0
- package/dist/web/routes/edit-history-routes.js.map +1 -0
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +273 -102
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/git-status-routes.d.ts.map +1 -1
- package/dist/web/routes/git-status-routes.js +7 -2
- package/dist/web/routes/git-status-routes.js.map +1 -1
- package/dist/web/routes/index.d.ts +2 -0
- package/dist/web/routes/index.d.ts.map +1 -1
- package/dist/web/routes/index.js +2 -0
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/mux-routes.d.ts +10 -3
- package/dist/web/routes/mux-routes.d.ts.map +1 -1
- package/dist/web/routes/mux-routes.js +59 -1
- package/dist/web/routes/mux-routes.js.map +1 -1
- package/dist/web/routes/ralph-routes.d.ts.map +1 -1
- package/dist/web/routes/ralph-routes.js +22 -0
- package/dist/web/routes/ralph-routes.js.map +1 -1
- package/dist/web/routes/readmymind-routes.d.ts.map +1 -1
- package/dist/web/routes/readmymind-routes.js +3 -2
- package/dist/web/routes/readmymind-routes.js.map +1 -1
- package/dist/web/routes/respawn-routes.d.ts.map +1 -1
- package/dist/web/routes/respawn-routes.js +24 -0
- package/dist/web/routes/respawn-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts +21 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +338 -55
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +4 -2
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +92 -2
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +111 -10
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/self-update.d.ts +9 -0
- package/dist/web/self-update.d.ts.map +1 -1
- package/dist/web/self-update.js +19 -3
- package/dist/web/self-update.js.map +1 -1
- package/dist/web/sensitive-path.d.ts.map +1 -1
- package/dist/web/sensitive-path.js +15 -0
- package/dist/web/sensitive-path.js.map +1 -1
- package/dist/web/server.d.ts +56 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +285 -17
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-wait-registry.d.ts +13 -0
- package/dist/web/session-wait-registry.d.ts.map +1 -1
- package/dist/web/session-wait-registry.js +16 -8
- package/dist/web/session-wait-registry.js.map +1 -1
- package/package.json +2 -2
- package/skills/codeman/SKILL.md +20 -4
- package/dist/web/public/app.fe8a6b4c.js.br +0 -0
- package/dist/web/public/app.fe8a6b4c.js.gz +0 -0
- package/dist/web/public/constants.affcdde6.js.br +0 -0
- package/dist/web/public/constants.affcdde6.js.gz +0 -0
- package/dist/web/public/i18n.a618ef4e.js +0 -2
- package/dist/web/public/i18n.a618ef4e.js.br +0 -0
- package/dist/web/public/i18n.a618ef4e.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.ff64fafc.js.br +0 -0
- package/dist/web/public/keyboard-accessory.ff64fafc.js.gz +0 -0
- package/dist/web/public/mobile.1bbd2d67.css +0 -1
- package/dist/web/public/mobile.1bbd2d67.css.br +0 -0
- package/dist/web/public/mobile.1bbd2d67.css.gz +0 -0
- package/dist/web/public/panels-ui.4a56ee63.js.br +0 -0
- package/dist/web/public/panels-ui.4a56ee63.js.gz +0 -0
- package/dist/web/public/respawn-ui.d7adcf6a.js.br +0 -0
- package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
- package/dist/web/public/session-ui.426fb671.js.br +0 -0
- package/dist/web/public/session-ui.426fb671.js.gz +0 -0
- package/dist/web/public/settings-ui.a191154e.js +0 -106
- package/dist/web/public/settings-ui.a191154e.js.br +0 -0
- package/dist/web/public/settings-ui.a191154e.js.gz +0 -0
- package/dist/web/public/styles.4f0c67a0.css +0 -1
- package/dist/web/public/styles.4f0c67a0.css.br +0 -0
- package/dist/web/public/styles.4f0c67a0.css.gz +0 -0
- package/dist/web/public/terminal-ui.7e787829.js +0 -4
- package/dist/web/public/terminal-ui.7e787829.js.br +0 -0
- package/dist/web/public/terminal-ui.7e787829.js.gz +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Reads a local claude session's transcripts for its edit history: the main
|
|
3
|
+
* transcript and its subagent transcripts, each from a byte offset.
|
|
4
|
+
*
|
|
5
|
+
* WHICH FILE (`resolveClaudeTranscript`). The transcript watcher's path, which the session's
|
|
6
|
+
* hooks report, so a session is read from wherever its claude really writes. Before the first
|
|
7
|
+
* hook after a server restart the watcher has none, and `findClaudeTranscript` looks for
|
|
8
|
+
* `<id>.jsonl` under the session's own `CLAUDE_CONFIG_DIR` override, else the server's
|
|
9
|
+
* (`claudeProjectsDir()`, as the relaunch pin does). A config dir set outside Codeman is not
|
|
10
|
+
* guessed; it is found with the next hook. Subagents live in
|
|
11
|
+
* `<main path without .jsonl>/subagents/agent-<id>.jsonl`.
|
|
12
|
+
*
|
|
13
|
+
* HOW MUCH. A requested file is read from its `offset` (clamped to its size), an unrequested
|
|
14
|
+
* (new) one from `budget` bytes before its end, and a new subagent's `.meta.json` (≤ 8 KB)
|
|
15
|
+
* comes along. `budgetBytes` is shared by all files, main first; once spent, files still
|
|
16
|
+
* report their size with an empty chunk. A request with `len` is a block that must end at
|
|
17
|
+
* `offset + len` (an "older" block ends at the floor): short of budget, its end is read.
|
|
18
|
+
* With `onlyRequested` ("older" reads) unrequested files are left out.
|
|
19
|
+
*
|
|
20
|
+
* Tests: `test/edit-history-local-source.test.ts`.
|
|
21
|
+
*
|
|
22
|
+
* @module edit-history-local-source
|
|
23
|
+
*/
|
|
24
|
+
import { open, readdir, realpath, stat } from 'node:fs/promises';
|
|
25
|
+
import { homedir } from 'node:os';
|
|
26
|
+
import { basename, isAbsolute, join } from 'node:path';
|
|
27
|
+
import { probePathKind } from './utils/bounded-path-probe.js';
|
|
28
|
+
import { claudeProjectsDir } from './utils/claude-transcript.js';
|
|
29
|
+
const ID_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
30
|
+
const REL_PATH_PATTERN = /^(main|subagents\/agent-[A-Za-z0-9_-]+\.jsonl)$/;
|
|
31
|
+
const AGENT_FILE_PATTERN = /^agent-([A-Za-z0-9_-]+)\.jsonl$/;
|
|
32
|
+
const META_MAX_BYTES = 8192;
|
|
33
|
+
async function readRange(path, offset, len) {
|
|
34
|
+
if (len <= 0)
|
|
35
|
+
return Buffer.alloc(0);
|
|
36
|
+
const fh = await open(path, 'r');
|
|
37
|
+
try {
|
|
38
|
+
const buf = Buffer.alloc(len);
|
|
39
|
+
const { bytesRead } = await fh.read(buf, 0, len, offset);
|
|
40
|
+
return buf.subarray(0, bytesRead);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return Buffer.alloc(0);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await fh.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function fileSize(path) {
|
|
50
|
+
try {
|
|
51
|
+
const s = await stat(path);
|
|
52
|
+
return s.isFile() ? s.size : null;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** The newest `<id>.jsonl` under any project dir, for the first id that has one; null when none does. */
|
|
59
|
+
export async function findClaudeTranscript(ids, projectsDir = claudeProjectsDir()) {
|
|
60
|
+
let dirs;
|
|
61
|
+
try {
|
|
62
|
+
dirs = await readdir(projectsDir);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
for (const id of new Set(ids)) {
|
|
68
|
+
if (!ID_PATTERN.test(id))
|
|
69
|
+
continue;
|
|
70
|
+
let best = null;
|
|
71
|
+
for (const dir of dirs) {
|
|
72
|
+
const path = join(projectsDir, dir, `${id}.jsonl`);
|
|
73
|
+
try {
|
|
74
|
+
const s = await stat(path);
|
|
75
|
+
if (s.isFile() && (!best || s.mtimeMs > best.mtime))
|
|
76
|
+
best = { path, mtime: s.mtimeMs };
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// not in this project dir
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (best)
|
|
83
|
+
return best.path;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The session's main transcript: the transcript watcher's (hook-reported) path when there is
|
|
89
|
+
* one, else the newest `<id>.jsonl` under `configDir` (the session's `CLAUDE_CONFIG_DIR`
|
|
90
|
+
* override; the server's config dir when unset). Null when neither finds one.
|
|
91
|
+
*/
|
|
92
|
+
export async function resolveClaudeTranscript(watcherPath, ids, configDir) {
|
|
93
|
+
return watcherPath || findClaudeTranscript(ids, claudeProjectsDir(configDir));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read the main transcript at `mainPath` and its subagent transcripts. Null when `mainPath`
|
|
97
|
+
* is not an absolute `<id>.jsonl` path or the file does not exist.
|
|
98
|
+
*/
|
|
99
|
+
export async function readClaudeEditSources(mainPath, requests, budgetBytes, opts = {}) {
|
|
100
|
+
if (!isAbsolute(mainPath) || !mainPath.endsWith('.jsonl'))
|
|
101
|
+
return null;
|
|
102
|
+
const transcriptId = basename(mainPath, '.jsonl');
|
|
103
|
+
if (!ID_PATTERN.test(transcriptId))
|
|
104
|
+
return null;
|
|
105
|
+
const byPath = new Map();
|
|
106
|
+
for (const r of requests) {
|
|
107
|
+
if (!REL_PATH_PATTERN.test(r.relPath) || byPath.has(r.relPath))
|
|
108
|
+
continue;
|
|
109
|
+
if (!Number.isSafeInteger(r.offset) || r.offset < 0)
|
|
110
|
+
continue;
|
|
111
|
+
if (r.len !== undefined && (!Number.isSafeInteger(r.len) || r.len < 0))
|
|
112
|
+
continue;
|
|
113
|
+
byPath.set(r.relPath, r);
|
|
114
|
+
}
|
|
115
|
+
const subDir = join(mainPath.slice(0, -'.jsonl'.length), 'subagents');
|
|
116
|
+
const sources = [{ relPath: 'main', path: mainPath }];
|
|
117
|
+
try {
|
|
118
|
+
for (const name of (await readdir(subDir)).sort()) {
|
|
119
|
+
const m = AGENT_FILE_PATTERN.exec(name);
|
|
120
|
+
if (m)
|
|
121
|
+
sources.push({ relPath: `subagents/${name}`, path: join(subDir, name), agentId: m[1] });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// no subagents yet
|
|
126
|
+
}
|
|
127
|
+
let remaining = Math.max(0, Math.floor(budgetBytes));
|
|
128
|
+
const files = [];
|
|
129
|
+
const metas = {};
|
|
130
|
+
for (const src of sources) {
|
|
131
|
+
const size = await fileSize(src.path);
|
|
132
|
+
if (size === null) {
|
|
133
|
+
if (src.relPath === 'main')
|
|
134
|
+
return null;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const req = byPath.get(src.relPath);
|
|
138
|
+
if (!req && opts.onlyRequested)
|
|
139
|
+
continue;
|
|
140
|
+
let start;
|
|
141
|
+
let len;
|
|
142
|
+
if (req?.len !== undefined) {
|
|
143
|
+
const blockStart = Math.min(req.offset, size);
|
|
144
|
+
const blockEnd = Math.min(req.offset + req.len, size);
|
|
145
|
+
len = Math.min(blockEnd - blockStart, remaining);
|
|
146
|
+
start = blockEnd - len;
|
|
147
|
+
}
|
|
148
|
+
else if (req) {
|
|
149
|
+
start = Math.min(req.offset, size);
|
|
150
|
+
len = Math.min(remaining, size - start);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
len = Math.min(size, remaining);
|
|
154
|
+
start = size - len;
|
|
155
|
+
}
|
|
156
|
+
const chunk = await readRange(src.path, start, len);
|
|
157
|
+
remaining -= chunk.length;
|
|
158
|
+
files.push({ relPath: src.relPath, size, startOffset: start, chunk });
|
|
159
|
+
if (!req && src.agentId) {
|
|
160
|
+
const metaPath = join(subDir, `agent-${src.agentId}.meta.json`);
|
|
161
|
+
const metaSize = await fileSize(metaPath);
|
|
162
|
+
if (metaSize !== null) {
|
|
163
|
+
metas[src.agentId] = (await readRange(metaPath, 0, Math.min(metaSize, META_MAX_BYTES))).toString('utf8');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { transcriptId, files, metas };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Per path its resolved path, kind, size and mtime, or null when it is not a regular file
|
|
171
|
+
* (missing, a directory, or on a filesystem that did not answer). `~/` means this user's home.
|
|
172
|
+
*
|
|
173
|
+
* The paths come from Bash output, so the agent chose them: each one first goes through the
|
|
174
|
+
* bounded probe (`probePathKind`, no `pastCap`, this is a bulk scan), and only a path it saw
|
|
175
|
+
* as a file is touched by `realpath` + `stat`. A path on a mount that stopped answering
|
|
176
|
+
* then costs one stalled stat at most, never a sync that cannot finish (#516 rule).
|
|
177
|
+
* Sequential, so one sync holds at most one threadpool worker.
|
|
178
|
+
*/
|
|
179
|
+
export async function probeLocalPaths(paths, home = homedir(), probeKind = probePathKind) {
|
|
180
|
+
const out = [];
|
|
181
|
+
for (const p of paths) {
|
|
182
|
+
const path = p.startsWith('~/') ? join(home, p.slice(2)) : p;
|
|
183
|
+
if (!isAbsolute(path) || (await probeKind(path)) !== 'file') {
|
|
184
|
+
out.push(null);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const real = await realpath(path);
|
|
189
|
+
const s = await stat(real);
|
|
190
|
+
out.push(s.isFile() ? { realPath: real, kind: 'file', size: s.size, mtimeMs: Math.floor(s.mtimeMs) } : null);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
out.push(null);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=edit-history-local-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-history-local-source.js","sourceRoot":"","sources":["../src/edit-history-local-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Edit history parser: claude JSONL transcript lines → the files the agent
|
|
3
|
+
* edited (with their diff) and the images its Bash calls may have produced.
|
|
4
|
+
*
|
|
5
|
+
* Every `Edit`/`Write` result line carries `toolUseResult.filePath` and a
|
|
6
|
+
* `structuredPatch` (hunks with ` `/`+`/`-` prefixed lines), so a per-edit diff needs no
|
|
7
|
+
* git. The whole-file fields next to it (`originalFile`, `content`) are never kept.
|
|
8
|
+
*
|
|
9
|
+
* Images rarely come from `Write`; they come from scripts run through Bash. A Bash call
|
|
10
|
+
* yields a CANDIDATE: the image-looking paths in its command and output, with the call's
|
|
11
|
+
* start and end time. Whether a candidate file was actually produced by the call (its
|
|
12
|
+
* mtime falls inside that window) is decided later by whoever can stat it, locally or on
|
|
13
|
+
* the remote host: this module does no IO.
|
|
14
|
+
*
|
|
15
|
+
* Chunked input: a transcript is read in byte ranges, so a Bash `tool_use` and its result
|
|
16
|
+
* can land in different chunks. Unanswered calls are handed back as `pending` and passed
|
|
17
|
+
* into the next call.
|
|
18
|
+
*
|
|
19
|
+
* Tests: `test/edit-history-parse.test.ts`.
|
|
20
|
+
*
|
|
21
|
+
* @module edit-history-parse
|
|
22
|
+
*/
|
|
23
|
+
/** Per-record budget for kept hunk lines; a larger patch is cut and marked `truncated`. */
|
|
24
|
+
export declare const MAX_HUNK_BYTES: number;
|
|
25
|
+
/** Image paths kept per Bash call. */
|
|
26
|
+
export declare const MAX_IMAGE_CANDIDATES = 20;
|
|
27
|
+
/** Unanswered Bash calls carried between chunks (an interrupted call never gets a result). */
|
|
28
|
+
export declare const MAX_PENDING_BASH = 200;
|
|
29
|
+
/**
|
|
30
|
+
* Command text kept per unanswered Bash call. Pending calls are persisted with the store, so
|
|
31
|
+
* this bounds it; an image path past this point of a command is still found in the output.
|
|
32
|
+
*/
|
|
33
|
+
export declare const MAX_PENDING_COMMAND_CHARS = 8192;
|
|
34
|
+
/** Longest id, cwd or agent id of an unanswered Bash call; a call with a longer one is not kept. */
|
|
35
|
+
export declare const MAX_PENDING_FIELD_CHARS = 4096;
|
|
36
|
+
export type EditKind = 'code' | 'image';
|
|
37
|
+
/** `edit` = a result with a path and a patch from a tool other than Edit/Write. */
|
|
38
|
+
export type EditTool = 'Edit' | 'Write' | 'edit';
|
|
39
|
+
export interface EditHunk {
|
|
40
|
+
oldStart: number;
|
|
41
|
+
oldLines: number;
|
|
42
|
+
newStart: number;
|
|
43
|
+
newLines: number;
|
|
44
|
+
lines: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface EditRecord {
|
|
47
|
+
/** The `tool_use_id` of the edit: unique per edit, used to deduplicate. */
|
|
48
|
+
id: string;
|
|
49
|
+
/** ms since epoch, from the result line's `timestamp` (0 when missing). */
|
|
50
|
+
ts: number;
|
|
51
|
+
path: string;
|
|
52
|
+
kind: EditKind;
|
|
53
|
+
tool: EditTool;
|
|
54
|
+
/** A `Write` that created the file. */
|
|
55
|
+
created: boolean;
|
|
56
|
+
/** Counted over the whole patch, also when `hunks` was cut. */
|
|
57
|
+
added: number;
|
|
58
|
+
removed: number;
|
|
59
|
+
hunks: EditHunk[];
|
|
60
|
+
truncated: boolean;
|
|
61
|
+
/** Set for lines of a subagent transcript. */
|
|
62
|
+
agentId?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface PendingBash {
|
|
65
|
+
id: string;
|
|
66
|
+
ts: number;
|
|
67
|
+
command: string;
|
|
68
|
+
cwd: string;
|
|
69
|
+
agentId?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface ImageCandidate {
|
|
72
|
+
toolUseId: string;
|
|
73
|
+
start: number;
|
|
74
|
+
end: number;
|
|
75
|
+
paths: string[];
|
|
76
|
+
agentId?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Files claude handed to the user (`SendUserFile`): shown on purpose, so no mtime window
|
|
79
|
+
* applies; the file must still exist, and a version already listed is not listed again.
|
|
80
|
+
*/
|
|
81
|
+
sent?: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface EditParseResult {
|
|
84
|
+
records: EditRecord[];
|
|
85
|
+
candidates: ImageCandidate[];
|
|
86
|
+
pending: PendingBash[];
|
|
87
|
+
}
|
|
88
|
+
/** `image` for the image extensions the panel can thumbnail, else `code`. */
|
|
89
|
+
export declare function classifyEditPath(path: string): EditKind;
|
|
90
|
+
/**
|
|
91
|
+
* Image-looking paths in a Bash call's command and output, in order of appearance,
|
|
92
|
+
* deduplicated and capped at {@link MAX_IMAGE_CANDIDATES}. Absolute paths are normalised,
|
|
93
|
+
* `~/` paths stay literal (the host that stats them expands `~`), relative ones are
|
|
94
|
+
* resolved against `cwd` and dropped when `cwd` is not absolute. URLs and globs are
|
|
95
|
+
* skipped.
|
|
96
|
+
*/
|
|
97
|
+
export declare function extractImagePathCandidates(command: string, stdout: string, stderr: string, cwd: string): string[];
|
|
98
|
+
/**
|
|
99
|
+
* The hunks of `patch` with their string lines, cut once the lines reach {@link MAX_HUNK_BYTES}
|
|
100
|
+
* (`truncated`). Also applied to hunks loaded from a store file.
|
|
101
|
+
*/
|
|
102
|
+
export declare function capHunks(patch: readonly unknown[]): {
|
|
103
|
+
hunks: EditHunk[];
|
|
104
|
+
truncated: boolean;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Parse transcript lines into edit records and Bash image candidates.
|
|
108
|
+
*
|
|
109
|
+
* @param text complete JSONL lines; a first line cut mid-record (a byte range starting
|
|
110
|
+
* inside it) and anything else that does not parse is skipped.
|
|
111
|
+
* @param pending unanswered Bash calls from the previous chunk.
|
|
112
|
+
*/
|
|
113
|
+
export declare function parseClaudeEditLines(text: string, pending?: readonly PendingBash[]): EditParseResult;
|
|
114
|
+
//# sourceMappingURL=edit-history-parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-history-parse.d.ts","sourceRoot":"","sources":["../src/edit-history-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,2FAA2F;AAC3F,eAAO,MAAM,cAAc,QAAY,CAAC;AACxC,sCAAsC;AACtC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,8FAA8F;AAC9F,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC;;;GAGG;AACH,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAC9C,oGAAoG;AACpG,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AACxC,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AA6BD,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBjH;AAMD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CA2B7F;AA2ED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,SAAS,WAAW,EAAO,GAAG,eAAe,CA8ExG"}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Edit history parser: claude JSONL transcript lines → the files the agent
|
|
3
|
+
* edited (with their diff) and the images its Bash calls may have produced.
|
|
4
|
+
*
|
|
5
|
+
* Every `Edit`/`Write` result line carries `toolUseResult.filePath` and a
|
|
6
|
+
* `structuredPatch` (hunks with ` `/`+`/`-` prefixed lines), so a per-edit diff needs no
|
|
7
|
+
* git. The whole-file fields next to it (`originalFile`, `content`) are never kept.
|
|
8
|
+
*
|
|
9
|
+
* Images rarely come from `Write`; they come from scripts run through Bash. A Bash call
|
|
10
|
+
* yields a CANDIDATE: the image-looking paths in its command and output, with the call's
|
|
11
|
+
* start and end time. Whether a candidate file was actually produced by the call (its
|
|
12
|
+
* mtime falls inside that window) is decided later by whoever can stat it, locally or on
|
|
13
|
+
* the remote host: this module does no IO.
|
|
14
|
+
*
|
|
15
|
+
* Chunked input: a transcript is read in byte ranges, so a Bash `tool_use` and its result
|
|
16
|
+
* can land in different chunks. Unanswered calls are handed back as `pending` and passed
|
|
17
|
+
* into the next call.
|
|
18
|
+
*
|
|
19
|
+
* Tests: `test/edit-history-parse.test.ts`.
|
|
20
|
+
*
|
|
21
|
+
* @module edit-history-parse
|
|
22
|
+
*/
|
|
23
|
+
import { posix } from 'node:path';
|
|
24
|
+
/** Per-record budget for kept hunk lines; a larger patch is cut and marked `truncated`. */
|
|
25
|
+
export const MAX_HUNK_BYTES = 64 * 1024;
|
|
26
|
+
/** Image paths kept per Bash call. */
|
|
27
|
+
export const MAX_IMAGE_CANDIDATES = 20;
|
|
28
|
+
/** Unanswered Bash calls carried between chunks (an interrupted call never gets a result). */
|
|
29
|
+
export const MAX_PENDING_BASH = 200;
|
|
30
|
+
/**
|
|
31
|
+
* Command text kept per unanswered Bash call. Pending calls are persisted with the store, so
|
|
32
|
+
* this bounds it; an image path past this point of a command is still found in the output.
|
|
33
|
+
*/
|
|
34
|
+
export const MAX_PENDING_COMMAND_CHARS = 8192;
|
|
35
|
+
/** Longest id, cwd or agent id of an unanswered Bash call; a call with a longer one is not kept. */
|
|
36
|
+
export const MAX_PENDING_FIELD_CHARS = 4096;
|
|
37
|
+
const IMAGE_EXT = '(?:png|jpe?g|gif|webp|avif|svg)';
|
|
38
|
+
const IMAGE_PATH_RE = new RegExp(`\\.${IMAGE_EXT}$`, 'i');
|
|
39
|
+
// After the extension: no further name character, and no `.ext` (a.png.bak).
|
|
40
|
+
const EXT_END = '(?![\\w-])(?!\\.\\w)';
|
|
41
|
+
// Characters that end an unquoted path token.
|
|
42
|
+
const TOKEN_CHAR = '[^\\s\'"`<>|;&()=,:*?]';
|
|
43
|
+
const PATH_TOKEN_RE = new RegExp([
|
|
44
|
+
// 1. file:// URL (Codex: `Saved to: file:///…`), which may contain spaces up to the extension.
|
|
45
|
+
// The lazy scan stops at the next `file://`: otherwise it runs to the line end from
|
|
46
|
+
// every `file://` of a line that repeats it (quadratic). `:` stays allowed, so a
|
|
47
|
+
// timestamped name (`plot-12:30.png`) is still found.
|
|
48
|
+
`file://(/(?:(?!file://)[^\\n])*?\\.${IMAGE_EXT})${EXT_END}`,
|
|
49
|
+
// 2./3. Quoted paths, spaces allowed.
|
|
50
|
+
`"([^"\\n]*\\.${IMAGE_EXT})"`,
|
|
51
|
+
`'([^'\\n]*\\.${IMAGE_EXT})'`,
|
|
52
|
+
// 4. Unquoted token. A match starts only at a token boundary (line start or a character
|
|
53
|
+
// that ends a token), never inside a URL (`:` is not a boundary), a glob or a longer
|
|
54
|
+
// name. Anchoring at boundaries keeps this linear: a lookbehind that only excluded
|
|
55
|
+
// some characters let a match start at every other character of a long token
|
|
56
|
+
// (`####…`, a base64 blob) and rescan the token from each, quadratic in the line
|
|
57
|
+
// length. The name before the extension must not be empty.
|
|
58
|
+
`(?<=^|[\\s'"\`<>|;&()=,*?])((?:${TOKEN_CHAR}*/)?[^\\s'"\`<>|;&()=,:*?/]+\\.${IMAGE_EXT})${EXT_END}`,
|
|
59
|
+
].join('|'), 'gi');
|
|
60
|
+
/** `image` for the image extensions the panel can thumbnail, else `code`. */
|
|
61
|
+
export function classifyEditPath(path) {
|
|
62
|
+
return IMAGE_PATH_RE.test(path) ? 'image' : 'code';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Image-looking paths in a Bash call's command and output, in order of appearance,
|
|
66
|
+
* deduplicated and capped at {@link MAX_IMAGE_CANDIDATES}. Absolute paths are normalised,
|
|
67
|
+
* `~/` paths stay literal (the host that stats them expands `~`), relative ones are
|
|
68
|
+
* resolved against `cwd` and dropped when `cwd` is not absolute. URLs and globs are
|
|
69
|
+
* skipped.
|
|
70
|
+
*/
|
|
71
|
+
export function extractImagePathCandidates(command, stdout, stderr, cwd) {
|
|
72
|
+
const text = [command, stdout, stderr].join('\n');
|
|
73
|
+
const out = [];
|
|
74
|
+
const seen = new Set();
|
|
75
|
+
for (const m of text.matchAll(PATH_TOKEN_RE)) {
|
|
76
|
+
const raw = m[1] ?? m[2] ?? m[3] ?? m[4];
|
|
77
|
+
if (!raw || raw.includes('://') || /[*?]/.test(raw))
|
|
78
|
+
continue;
|
|
79
|
+
let resolved;
|
|
80
|
+
if (raw.startsWith('/'))
|
|
81
|
+
resolved = posix.normalize(raw);
|
|
82
|
+
else if (raw.startsWith('~/'))
|
|
83
|
+
resolved = raw;
|
|
84
|
+
else if (cwd.startsWith('/'))
|
|
85
|
+
resolved = posix.resolve(cwd, raw);
|
|
86
|
+
else
|
|
87
|
+
continue;
|
|
88
|
+
if (seen.has(resolved))
|
|
89
|
+
continue;
|
|
90
|
+
seen.add(resolved);
|
|
91
|
+
out.push(resolved);
|
|
92
|
+
if (out.length >= MAX_IMAGE_CANDIDATES)
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
function isRecord(v) {
|
|
98
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The hunks of `patch` with their string lines, cut once the lines reach {@link MAX_HUNK_BYTES}
|
|
102
|
+
* (`truncated`). Also applied to hunks loaded from a store file.
|
|
103
|
+
*/
|
|
104
|
+
export function capHunks(patch) {
|
|
105
|
+
const hunks = [];
|
|
106
|
+
let budget = MAX_HUNK_BYTES;
|
|
107
|
+
let truncated = false;
|
|
108
|
+
for (const h of patch) {
|
|
109
|
+
if (!isRecord(h) || !Array.isArray(h.lines))
|
|
110
|
+
continue;
|
|
111
|
+
if (truncated)
|
|
112
|
+
break;
|
|
113
|
+
const kept = [];
|
|
114
|
+
for (const l of h.lines) {
|
|
115
|
+
if (typeof l !== 'string')
|
|
116
|
+
continue;
|
|
117
|
+
const cost = Buffer.byteLength(l) + 3;
|
|
118
|
+
if (cost > budget) {
|
|
119
|
+
truncated = true;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
budget -= cost;
|
|
123
|
+
kept.push(l);
|
|
124
|
+
}
|
|
125
|
+
hunks.push({
|
|
126
|
+
oldStart: Number(h.oldStart) || 0,
|
|
127
|
+
oldLines: Number(h.oldLines) || 0,
|
|
128
|
+
newStart: Number(h.newStart) || 0,
|
|
129
|
+
newLines: Number(h.newLines) || 0,
|
|
130
|
+
lines: kept,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return { hunks, truncated };
|
|
134
|
+
}
|
|
135
|
+
function toHunks(patch) {
|
|
136
|
+
let added = 0;
|
|
137
|
+
let removed = 0;
|
|
138
|
+
for (const h of patch) {
|
|
139
|
+
if (!isRecord(h) || !Array.isArray(h.lines))
|
|
140
|
+
continue;
|
|
141
|
+
for (const l of h.lines) {
|
|
142
|
+
if (typeof l !== 'string')
|
|
143
|
+
continue;
|
|
144
|
+
if (l.startsWith('+'))
|
|
145
|
+
added++;
|
|
146
|
+
else if (l.startsWith('-'))
|
|
147
|
+
removed++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return { ...capHunks(patch), added, removed };
|
|
151
|
+
}
|
|
152
|
+
/** A new file's content as one all-added hunk, in `structuredPatch` form. */
|
|
153
|
+
function createdFileHunk(content) {
|
|
154
|
+
const lines = content.split('\n');
|
|
155
|
+
if (lines.length > 0 && lines[lines.length - 1] === '')
|
|
156
|
+
lines.pop();
|
|
157
|
+
return { oldStart: 0, oldLines: 0, newStart: 1, newLines: lines.length, lines: lines.map((l) => `+${l}`) };
|
|
158
|
+
}
|
|
159
|
+
function toEditRecord(id, ts, result, agentId) {
|
|
160
|
+
if (!isRecord(result))
|
|
161
|
+
return null;
|
|
162
|
+
const { filePath, structuredPatch } = result;
|
|
163
|
+
if (typeof filePath !== 'string' || !filePath || !Array.isArray(structuredPatch))
|
|
164
|
+
return null;
|
|
165
|
+
const tool = typeof result.type === 'string' ? 'Write' : 'oldString' in result ? 'Edit' : 'edit';
|
|
166
|
+
const kind = classifyEditPath(filePath);
|
|
167
|
+
// A Write that created a file reports an empty patch; its diff is the whole content.
|
|
168
|
+
const patch = result.type === 'create' && structuredPatch.length === 0 && kind !== 'image' && typeof result.content === 'string'
|
|
169
|
+
? [createdFileHunk(result.content)]
|
|
170
|
+
: structuredPatch;
|
|
171
|
+
const { hunks, added, removed, truncated } = toHunks(patch);
|
|
172
|
+
const record = {
|
|
173
|
+
id,
|
|
174
|
+
ts,
|
|
175
|
+
path: filePath,
|
|
176
|
+
kind,
|
|
177
|
+
tool,
|
|
178
|
+
created: result.type === 'create',
|
|
179
|
+
added,
|
|
180
|
+
removed,
|
|
181
|
+
hunks,
|
|
182
|
+
truncated,
|
|
183
|
+
};
|
|
184
|
+
if (agentId)
|
|
185
|
+
record.agentId = agentId;
|
|
186
|
+
return record;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Image paths of a `SendUserFile` result (`{ caption, attachments: [{ path }] }`): the
|
|
190
|
+
* files claude delivered to the user, which is how a session shows generated images.
|
|
191
|
+
*/
|
|
192
|
+
function sentImagePaths(result) {
|
|
193
|
+
if (!isRecord(result) || !Array.isArray(result.attachments))
|
|
194
|
+
return [];
|
|
195
|
+
const out = [];
|
|
196
|
+
for (const a of result.attachments) {
|
|
197
|
+
if (!isRecord(a) || typeof a.path !== 'string' || !a.path.startsWith('/'))
|
|
198
|
+
continue;
|
|
199
|
+
if (IMAGE_PATH_RE.test(a.path) && !out.includes(a.path))
|
|
200
|
+
out.push(a.path);
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
204
|
+
/** The text of a `tool_result` block's content (a string or a list of text blocks). */
|
|
205
|
+
function blockText(content) {
|
|
206
|
+
if (typeof content === 'string')
|
|
207
|
+
return content;
|
|
208
|
+
if (!Array.isArray(content))
|
|
209
|
+
return '';
|
|
210
|
+
return content
|
|
211
|
+
.map((b) => (isRecord(b) && typeof b.text === 'string' ? b.text : ''))
|
|
212
|
+
.filter(Boolean)
|
|
213
|
+
.join('\n');
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Parse transcript lines into edit records and Bash image candidates.
|
|
217
|
+
*
|
|
218
|
+
* @param text complete JSONL lines; a first line cut mid-record (a byte range starting
|
|
219
|
+
* inside it) and anything else that does not parse is skipped.
|
|
220
|
+
* @param pending unanswered Bash calls from the previous chunk.
|
|
221
|
+
*/
|
|
222
|
+
export function parseClaudeEditLines(text, pending = []) {
|
|
223
|
+
const open = new Map(pending.map((p) => [p.id, p]));
|
|
224
|
+
const records = [];
|
|
225
|
+
const candidates = [];
|
|
226
|
+
for (const rawLine of text.split('\n')) {
|
|
227
|
+
const line = rawLine.trim();
|
|
228
|
+
if (!line)
|
|
229
|
+
continue;
|
|
230
|
+
let rec;
|
|
231
|
+
try {
|
|
232
|
+
rec = JSON.parse(line);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (!isRecord(rec))
|
|
238
|
+
continue;
|
|
239
|
+
const message = rec.message;
|
|
240
|
+
const content = isRecord(message) ? message.content : undefined;
|
|
241
|
+
if (!Array.isArray(content))
|
|
242
|
+
continue;
|
|
243
|
+
const parsedTs = typeof rec.timestamp === 'string' ? Date.parse(rec.timestamp) : NaN;
|
|
244
|
+
const ts = Number.isFinite(parsedTs) ? parsedTs : 0;
|
|
245
|
+
const agentId = typeof rec.agentId === 'string' && rec.agentId ? rec.agentId : undefined;
|
|
246
|
+
const cwd = typeof rec.cwd === 'string' ? rec.cwd : '';
|
|
247
|
+
if (rec.type === 'assistant') {
|
|
248
|
+
for (const block of content) {
|
|
249
|
+
if (!isRecord(block) || block.type !== 'tool_use' || block.name !== 'Bash')
|
|
250
|
+
continue;
|
|
251
|
+
if (typeof block.id !== 'string' || !isRecord(block.input))
|
|
252
|
+
continue;
|
|
253
|
+
const command = block.input.command;
|
|
254
|
+
if (typeof command !== 'string')
|
|
255
|
+
continue;
|
|
256
|
+
if ([block.id, cwd, agentId ?? ''].some((f) => f.length > MAX_PENDING_FIELD_CHARS))
|
|
257
|
+
continue;
|
|
258
|
+
const entry = { id: block.id, ts, command: command.slice(0, MAX_PENDING_COMMAND_CHARS), cwd };
|
|
259
|
+
if (agentId)
|
|
260
|
+
entry.agentId = agentId;
|
|
261
|
+
open.delete(block.id);
|
|
262
|
+
open.set(block.id, entry);
|
|
263
|
+
while (open.size > MAX_PENDING_BASH)
|
|
264
|
+
open.delete(open.keys().next().value);
|
|
265
|
+
}
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (rec.type !== 'user')
|
|
269
|
+
continue;
|
|
270
|
+
const results = content.filter((b) => isRecord(b) && b.type === 'tool_result' && typeof b.tool_use_id === 'string');
|
|
271
|
+
// `toolUseResult` describes the line's result; it is unambiguous only for one block.
|
|
272
|
+
const single = results.length === 1;
|
|
273
|
+
for (const block of results) {
|
|
274
|
+
const id = block.tool_use_id;
|
|
275
|
+
if (single) {
|
|
276
|
+
const edit = toEditRecord(id, ts, rec.toolUseResult, agentId);
|
|
277
|
+
if (edit)
|
|
278
|
+
records.push(edit);
|
|
279
|
+
}
|
|
280
|
+
const sent = single ? sentImagePaths(rec.toolUseResult) : [];
|
|
281
|
+
if (sent.length > 0) {
|
|
282
|
+
const candidate = { toolUseId: id, start: ts, end: ts, paths: sent, sent: true };
|
|
283
|
+
if (agentId)
|
|
284
|
+
candidate.agentId = agentId;
|
|
285
|
+
candidates.push(candidate);
|
|
286
|
+
}
|
|
287
|
+
const call = open.get(id);
|
|
288
|
+
if (!call)
|
|
289
|
+
continue;
|
|
290
|
+
open.delete(id);
|
|
291
|
+
const r = single ? rec.toolUseResult : undefined;
|
|
292
|
+
let stdout;
|
|
293
|
+
let stderr = '';
|
|
294
|
+
if (isRecord(r) && (typeof r.stdout === 'string' || typeof r.stderr === 'string')) {
|
|
295
|
+
stdout = typeof r.stdout === 'string' ? r.stdout : '';
|
|
296
|
+
stderr = typeof r.stderr === 'string' ? r.stderr : '';
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
stdout = blockText(block.content);
|
|
300
|
+
}
|
|
301
|
+
const paths = extractImagePathCandidates(call.command, stdout, stderr, call.cwd);
|
|
302
|
+
if (paths.length === 0)
|
|
303
|
+
continue;
|
|
304
|
+
const candidate = { toolUseId: id, start: call.ts, end: ts, paths };
|
|
305
|
+
if (call.agentId)
|
|
306
|
+
candidate.agentId = call.agentId;
|
|
307
|
+
candidates.push(candidate);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return { records, candidates, pending: [...open.values()] };
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=edit-history-parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-history-parse.js","sourceRoot":"","sources":["../src/edit-history-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,2FAA2F;AAC3F,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,CAAC;AACxC,sCAAsC;AACtC,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,8FAA8F;AAC9F,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAC9C,oGAAoG;AACpG,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AA4D5C,MAAM,SAAS,GAAG,iCAAiC,CAAC;AACpD,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1D,6EAA6E;AAC7E,MAAM,OAAO,GAAG,sBAAsB,CAAC;AACvC,8CAA8C;AAC9C,MAAM,UAAU,GAAG,wBAAwB,CAAC;AAC5C,MAAM,aAAa,GAAG,IAAI,MAAM,CAC9B;IACE,+FAA+F;IAC/F,uFAAuF;IACvF,oFAAoF;IACpF,yDAAyD;IACzD,sCAAsC,SAAS,IAAI,OAAO,EAAE;IAC5D,sCAAsC;IACtC,gBAAgB,SAAS,IAAI;IAC7B,gBAAgB,SAAS,IAAI;IAC7B,wFAAwF;IACxF,wFAAwF;IACxF,sFAAsF;IACtF,gFAAgF;IAChF,oFAAoF;IACpF,8DAA8D;IAC9D,kCAAkC,UAAU,kCAAkC,SAAS,IAAI,OAAO,EAAE;CACrG,CAAC,IAAI,CAAC,GAAG,CAAC,EACX,IAAI,CACL,CAAC;AAEF,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AACrD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAe,EAAE,MAAc,EAAE,MAAc,EAAE,GAAW;IACrG,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QAC9D,IAAI,QAAgB,CAAC;QACrB,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;aACpD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,QAAQ,GAAG,GAAG,CAAC;aACzC,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;;YAC5D,SAAS;QACd,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,SAAS;QACjC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnB,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnB,IAAI,GAAG,CAAC,MAAM,IAAI,oBAAoB;YAAE,MAAM;IAChD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAyB;IAChD,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,cAAc,CAAC;IAC5B,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,SAAS;QACtD,IAAI,SAAS;YAAE,MAAM;QACrB,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,SAAS;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,IAAI,GAAG,MAAM,EAAE,CAAC;gBAClB,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR,CAAC;YACD,MAAM,IAAI,IAAI,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACf,CAAC;QACD,KAAK,CAAC,IAAI,CAAC;YACT,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjC,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,OAAO,CAAC,KAAgB;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,SAAS;QACtD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACxB,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,SAAS;YACpC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,KAAK,EAAE,CAAC;iBAC1B,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,CAAC;QACxC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAChD,CAAC;AAED,6EAA6E;AAC7E,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE;QAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IACpE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7G,CAAC;AAED,SAAS,YAAY,CAAC,EAAU,EAAE,EAAU,EAAE,MAAe,EAAE,OAA2B;IACxF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAAC;IAC7C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9F,MAAM,IAAI,GAAa,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3G,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACxC,qFAAqF;IACrF,MAAM,KAAK,GACT,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;QAChH,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC,CAAC,eAAe,CAAC;IACtB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAe;QACzB,EAAE;QACF,EAAE;QACF,IAAI,EAAE,QAAQ;QACd,IAAI;QACJ,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,IAAI,KAAK,QAAQ;QACjC,KAAK;QACL,OAAO;QACP,KAAK;QACL,SAAS;KACV,CAAC;IACF,IAAI,OAAO;QAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,MAAe;IACrC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IACvE,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACpF,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,uFAAuF;AACvF,SAAS,SAAS,CAAC,OAAgB;IACjC,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACrE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,UAAkC,EAAE;IACrF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,UAAU,GAAqB,EAAE,CAAC;IAExC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,GAAY,CAAC;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC5B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACrF,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACzF,MAAM,GAAG,GAAG,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAEvD,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;oBAAE,SAAS;gBACrF,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC;oBAAE,SAAS;gBACrE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;gBACpC,IAAI,OAAO,OAAO,KAAK,QAAQ;oBAAE,SAAS;gBAC1C,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,uBAAuB,CAAC;oBAAE,SAAS;gBAC7F,MAAM,KAAK,GAAgB,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC,EAAE,GAAG,EAAE,CAAC;gBAC3G,IAAI,OAAO;oBAAE,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;gBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACtB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;gBAC1B,OAAO,IAAI,CAAC,IAAI,GAAG,gBAAgB;oBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;YACvF,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QAClC,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAgC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,CAClH,CAAC;QACF,qFAAqF;QACrF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;QACpC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,KAAK,CAAC,WAAqB,CAAC;YACvC,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;gBAC9D,IAAI,IAAI;oBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/B,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,MAAM,SAAS,GAAmB,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBACjG,IAAI,OAAO;oBAAE,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC;gBACzC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7B,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1B,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;YACjD,IAAI,MAAc,CAAC;YACnB,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAClF,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtD,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,KAAK,GAAG,0BAA0B,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;YACjF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACjC,MAAM,SAAS,GAAmB,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;YACpF,IAAI,IAAI,CAAC,OAAO;gBAAE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YACnD,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;AAC9D,CAAC"}
|