pim-agent 0.13.0 → 0.14.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/package.json +3 -3
- package/packages/core/src/attachments/AttachmentStore.ts +8 -13
- package/packages/core/src/attachments/Attachments.ts +2 -4
- package/packages/core/src/extensions/CoreExtensions.ts +1 -1
- package/packages/core/src/extensions/apply-patch/coordinator.ts +1 -1
- package/packages/core/src/extensions/apply-patch/executor.ts +21 -25
- package/packages/core/src/extensions/apply-patch/matcher.ts +1 -1
- package/packages/core/src/extensions/apply-patch/model.ts +2 -6
- package/packages/core/src/extensions/apply-patch/parser.ts +60 -162
- package/packages/core/src/extensions/apply-patch/schema.ts +0 -1
- package/packages/core/src/extensions/bash/MemoryCap.ts +5 -4
- package/packages/core/src/extensions/bash/capture.ts +16 -23
- package/packages/core/src/extensions/bash/format.ts +2 -2
- package/packages/core/src/extensions/bash/image.ts +4 -8
- package/packages/core/src/extensions/bash/index.ts +1 -1
- package/packages/core/src/extensions/bash/render.ts +1 -1
- package/packages/core/src/extensions/bash/run.ts +9 -15
- package/packages/core/src/extensions/bash/schema.ts +4 -4
- package/packages/core/src/extensions/edit/edit.ts +14 -33
- package/packages/core/src/extensions/glob/glob.ts +1 -3
- package/packages/core/src/extensions/glob/index.ts +7 -9
- package/packages/core/src/extensions/glob/render.ts +2 -4
- package/packages/core/src/extensions/glob/schema.ts +1 -1
- package/packages/core/src/extensions/grep/grep.ts +7 -7
- package/packages/core/src/extensions/grep/render.ts +5 -6
- package/packages/core/src/extensions/grep/schema.ts +3 -7
- package/packages/core/src/extensions/read/ImageMemory.ts +2 -8
- package/packages/core/src/extensions/read/image.ts +3 -3
- package/packages/core/src/extensions/read/index.ts +2 -14
- package/packages/core/src/extensions/read/read.ts +5 -6
- package/packages/core/src/extensions/read/render.ts +1 -1
- package/packages/core/src/extensions/read/schema.ts +2 -2
- package/packages/core/src/extensions/subagent/render.ts +2 -2
- package/packages/core/src/extensions/subagent/subagent.ts +10 -21
- package/packages/core/src/extensions/system-prompt/index.ts +1 -2
- package/packages/core/src/extensions/system-prompt/prompt.ts +2 -4
- package/packages/core/src/extensions/todo/render.ts +1 -4
- package/packages/core/src/extensions/todo/todo.ts +16 -23
- package/packages/core/src/extensions/web-fetch/JinaReaderClient.ts +3 -11
- package/packages/core/src/extensions/web-fetch/WebViewFetchClient.ts +1 -3
- package/packages/core/src/extensions/web-fetch/fetch.ts +4 -12
- package/packages/core/src/extensions/web-fetch/image.ts +3 -4
- package/packages/core/src/extensions/web-fetch/index.ts +2 -13
- package/packages/core/src/extensions/web-fetch/render.ts +3 -4
- package/packages/core/src/extensions/web-fetch/schema.ts +3 -4
- package/packages/core/src/extensions/web-search/ExaMcpClient.ts +23 -31
- package/packages/core/src/extensions/web-search/SearchBreaker.ts +1 -1
- package/packages/core/src/extensions/web-search/SearchChain.ts +6 -5
- package/packages/core/src/extensions/web-search/providers/DuckDuckGoProvider.ts +2 -2
- package/packages/core/src/extensions/web-search/providers/FirecrawlProvider.ts +1 -2
- package/packages/core/src/extensions/web-search/providers/SearchProvider.ts +3 -3
- package/packages/core/src/extensions/write/write.ts +1 -1
- package/packages/core/src/picker/InProcessFilePickerSuggestionEngine.ts +1 -3
- package/packages/core/src/picker/PickerItem.ts +1 -1
- package/packages/core/src/picker/PickerService.ts +3 -7
- package/packages/core/src/picker/RemoteFilePickerSuggestionEngine.ts +1 -2
- package/packages/core/src/picker/catalog.ts +7 -15
- package/packages/core/src/picker/filePickerWorker.ts +1 -3
- package/packages/core/src/picker/ranker.ts +1 -1
- package/packages/core/src/picker/token.ts +3 -4
- package/packages/core/src/session/AgentRuntime.ts +5 -8
- package/packages/core/src/session/EventLog.ts +6 -12
- package/packages/core/src/session/ReadCursors.ts +3 -4
- package/packages/core/src/session/SearchIndex.ts +49 -86
- package/packages/core/src/session/SearchTokens.ts +4 -7
- package/packages/core/src/session/SessionCache.ts +8 -6
- package/packages/core/src/session/SessionDigest.ts +10 -19
- package/packages/core/src/session/SessionHost.ts +53 -83
- package/packages/core/src/session/SessionLease.ts +12 -15
- package/packages/core/src/session/SessionMeta.ts +16 -32
- package/packages/core/src/session/SessionName.ts +3 -7
- package/packages/core/src/session/SessionRegistry.ts +13 -29
- package/packages/core/src/session/SessionUi.ts +12 -16
- package/packages/core/src/session/WriteMark.ts +7 -16
- package/packages/core/src/shared/Cli.ts +1 -1
- package/packages/core/src/shared/DaemonUnit.ts +1 -2
- package/packages/core/src/shared/DiffLines.ts +16 -34
- package/packages/core/src/shared/DiffRenderer.ts +8 -27
- package/packages/core/src/shared/Directories.ts +4 -4
- package/packages/core/src/shared/EditMatcher.ts +18 -50
- package/packages/core/src/shared/ExtensionToggles.ts +3 -6
- package/packages/core/src/shared/FileEnumerator.ts +73 -57
- package/packages/core/src/shared/FileScanner.ts +5 -13
- package/packages/core/src/shared/FileWatch.ts +13 -17
- package/packages/core/src/shared/Format.ts +2 -3
- package/packages/core/src/shared/FuzzyMatcher.ts +18 -19
- package/packages/core/src/shared/Git.ts +22 -47
- package/packages/core/src/shared/GitMonitor.ts +12 -23
- package/packages/core/src/shared/GlobExclusions.ts +0 -4
- package/packages/core/src/shared/Http.ts +1 -1
- package/packages/core/src/shared/ImageMime.ts +3 -5
- package/packages/core/src/shared/Images.ts +17 -27
- package/packages/core/src/shared/Languages.ts +2 -2
- package/packages/core/src/shared/Levenshtein.ts +1 -6
- package/packages/core/src/shared/Lines.ts +1 -1
- package/packages/core/src/shared/McpClient.ts +2 -2
- package/packages/core/src/shared/PatchSummary.ts +1 -1
- package/packages/core/src/shared/Paths.ts +4 -1
- package/packages/core/src/shared/PiExtensions.ts +5 -12
- package/packages/core/src/shared/PimSettings.ts +14 -15
- package/packages/core/src/shared/Proc.ts +2 -3
- package/packages/core/src/shared/RateLimiter.ts +1 -1
- package/packages/core/src/shared/Renderer.ts +1 -3
- package/packages/core/src/shared/RepoDiff.ts +24 -46
- package/packages/core/src/shared/SearchRender.ts +3 -4
- package/packages/core/src/shared/SpillCache.ts +2 -3
- package/packages/core/src/shared/SubagentLogs.ts +4 -6
- package/packages/core/src/shared/Supervisor.ts +19 -32
- package/packages/core/src/shared/Surface.ts +1 -1
- package/packages/core/src/shared/Sweeper.ts +1 -1
- package/packages/core/src/shared/Tools.ts +17 -30
- package/packages/core/src/shared/Updater.ts +15 -15
- package/packages/core/src/view/BodyRenderer.ts +1 -1
- package/packages/core/src/view/DiffBlocks.ts +0 -1
- package/packages/core/src/view/DiffExpand.ts +10 -25
- package/packages/core/src/view/DiffLayout.ts +2 -2
- package/packages/core/src/view/DiffPairs.ts +2 -2
- package/packages/core/src/view/MarkdownPainter.ts +2 -19
- package/packages/core/src/view/MovePath.ts +4 -17
- package/packages/core/src/view/Painting.ts +4 -4
- package/packages/core/src/view/ViewBlock.ts +11 -12
- package/packages/daemon/src/Daemon.ts +2 -7
- package/packages/daemon/src/DaemonInstall.ts +5 -12
- package/packages/daemon/src/Surfaces.ts +3 -12
- package/packages/daemon/src/TelegramSurface.ts +0 -1
- package/packages/daemon/src/index.ts +0 -1
- package/packages/protocol/src/Command.ts +33 -41
- package/packages/protocol/src/Diff.ts +0 -5
- package/packages/protocol/src/ImageRoute.ts +2 -5
- package/packages/protocol/src/ServerEvent.ts +68 -105
- package/packages/server/src/AttachmentEndpoint.ts +45 -19
- package/packages/server/src/ClientConnection.ts +11 -12
- package/packages/server/src/ImageEndpoint.ts +3 -4
- package/packages/server/src/ProbeClient.ts +26 -59
- package/packages/server/src/Reloader.ts +4 -7
- package/packages/server/src/SendFileTool.ts +1 -1
- package/packages/server/src/SessionCatalogue.ts +35 -47
- package/packages/server/src/SessionProjection.ts +7 -12
- package/packages/server/src/SessionStream.ts +33 -80
- package/packages/server/src/StaticClient.ts +7 -8
- package/packages/server/src/WebOptions.ts +2 -6
- package/packages/server/src/WsGateway.ts +35 -96
- package/packages/server/src/probe.ts +6 -18
- package/packages/telegram/src/Bot.ts +2 -2
- package/packages/telegram/src/Commands.ts +108 -65
- package/packages/telegram/src/Config.ts +1 -6
- package/packages/telegram/src/Markdown.ts +4 -13
- package/packages/telegram/src/Renderer.ts +1 -1
- package/packages/telegram/src/Session.ts +3 -10
- package/packages/telegram/src/TaskScheduler.ts +31 -10
- package/packages/telegram/src/TaskStore.ts +11 -1
- package/packages/telegram/src/TaskTool.ts +1 -1
- package/packages/telegram/src/UpdateConfirm.ts +2 -2
- package/packages/tui/src/extensions/_init/index.ts +2 -5
- package/packages/tui/src/extensions/file-picker/index.ts +2 -6
- package/packages/tui/src/extensions/footer/index.ts +0 -1
- package/packages/tui/src/extensions/footer/powerline.ts +16 -28
- package/packages/tui/src/extensions/pim/index.ts +1 -1
- package/packages/tui/src/extensions/session-lease/index.ts +5 -6
- package/packages/tui/src/extensions/working-indicator/index.ts +1 -2
- package/packages/tui/src/themes/themeCliArgs.ts +1 -1
- package/packages/web/dist/client/assets/{abnfDiagram-O67JEVCF-CZ7V84ot.js → abnfDiagram-O67JEVCF-WweOU5DK.js} +1 -1
- package/packages/web/dist/client/assets/{arc-DiHGkUvc.js → arc-O2PmZXWt.js} +1 -1
- package/packages/web/dist/client/assets/architecture-7GRP2DOG-COBxVilU.js +1 -0
- package/packages/web/dist/client/assets/{architectureDiagram-NJMV4G6O-XS5DhfJB.js → architectureDiagram-NJMV4G6O-DwYq1YaM.js} +1 -1
- package/packages/web/dist/client/assets/{blockDiagram-BEXU5L5S-BCsgLvy1.js → blockDiagram-BEXU5L5S-CVab041n.js} +1 -1
- package/packages/web/dist/client/assets/{c4Diagram-YGBWAQC7-Bj9LcWNm.js → c4Diagram-YGBWAQC7-BmotHez3.js} +1 -1
- package/packages/web/dist/client/assets/channel-BKV-IcTA.js +1 -0
- package/packages/web/dist/client/assets/{chunk-3FUC2YCW-BmDurFxp.js → chunk-3FUC2YCW-CWNS7-n4.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-5DYCD2WN-DAjG-pqn.js → chunk-5DYCD2WN-DflvXohu.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-742MDFTN-Bmxs5puY.js → chunk-742MDFTN-B_0t6_RE.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-7INBJB4K-Di7kIxrQ.js → chunk-7INBJB4K-wKj0Q3Kv.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-7M6MHVWA-CSc8sR0b.js → chunk-7M6MHVWA-BMvUghc8.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-7PRAP22T-C8kd5QvY.js → chunk-7PRAP22T-BY41wkcT.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-GTNCS2PH-DG2b2LYE.js → chunk-GTNCS2PH-PqY_YoS0.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-GWA4HPMP-DdLaLQCu.js → chunk-GWA4HPMP-fozSU5ty.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-MBY4JIJT-C1j0yQlk.js → chunk-MBY4JIJT-CrHrC3jw.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-NETBCI7D-Bfq9H74p.js → chunk-NETBCI7D-DWdAxieG.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-O7XYJQB3-ZHvBmBO-.js → chunk-O7XYJQB3-B6uOn9iS.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-UA2S7LBM-ku1JeHSK.js → chunk-UA2S7LBM-BxYSHqyy.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-WEXAMYUT-BP1iga_7.js → chunk-WEXAMYUT-CtwIaQDa.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-XXDRQBXY-BBeccPcX.js → chunk-XXDRQBXY-fgBFe-PX.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-Z7XXMR3K-SMHZugaR.js → chunk-Z7XXMR3K-CPonoV3p.js} +1 -1
- package/packages/web/dist/client/assets/{chunk-ZIGJFQKS-CFU_JLG4.js → chunk-ZIGJFQKS-Cdu87cTj.js} +1 -1
- package/packages/web/dist/client/assets/{classDiagram-v2-NBCMYWYE-CYviuQzJ.js → classDiagram-v2-NBCMYWYE-DSWsPaa7.js} +1 -1
- package/packages/web/dist/client/assets/{core-DyHsgs5k.js → core-CBoS7AST.js} +1 -1
- package/packages/web/dist/client/assets/{cose-bilkent-JH36ORCC-9v2ZkJzo.js → cose-bilkent-JH36ORCC-CTwlldtJ.js} +1 -1
- package/packages/web/dist/client/assets/{cynefin-OW5HDTMX-Bx5xRadi.js → cynefin-OW5HDTMX-CZQ4EPNJ.js} +1 -1
- package/packages/web/dist/client/assets/{cynefinDiagram-VND7K2PF-BRfGDKqa.js → cynefinDiagram-VND7K2PF-C2gp6H_Q.js} +1 -1
- package/packages/web/dist/client/assets/{dagre-6A5THRUB-C4l-2L2e.js → dagre-6A5THRUB-CDxTP47t.js} +1 -1
- package/packages/web/dist/client/assets/{diagram-22UHCM2B-d_hQ3kyi.js → diagram-22UHCM2B-BIohE1lI.js} +1 -1
- package/packages/web/dist/client/assets/{diagram-3UASUU5V-DrEeguPI.js → diagram-3UASUU5V-TwAUir-w.js} +1 -1
- package/packages/web/dist/client/assets/{diagram-ATOU4E4O-BmfQ22pD.js → diagram-ATOU4E4O-BM1JQrIu.js} +1 -1
- package/packages/web/dist/client/assets/{diagram-CDSNMT55-BjVWjuPF.js → diagram-CDSNMT55-BKIqhxSI.js} +1 -1
- package/packages/web/dist/client/assets/{diagram-MLGK6HIB-wDjk-O8i.js → diagram-MLGK6HIB-CVe3QDHr.js} +1 -1
- package/packages/web/dist/client/assets/{diagram-MPIPVDR6-DqXQFE1s.js → diagram-MPIPVDR6-Bj-MQIFI.js} +1 -1
- package/packages/web/dist/client/assets/{dist-BddGOpie.js → dist-DlZpcyc2.js} +1 -1
- package/packages/web/dist/client/assets/{ebnfDiagram-ZINNZB2B-UB8kOITM.js → ebnfDiagram-ZINNZB2B-C06mmvmz.js} +1 -1
- package/packages/web/dist/client/assets/{elk-276RUBZZ-D4miYQnD.js → elk-276RUBZZ-CizJSNEj.js} +1 -1
- package/packages/web/dist/client/assets/{erDiagram-OPXOYQCR--RXKv7KH.js → erDiagram-OPXOYQCR-M3FQkKI1.js} +1 -1
- package/packages/web/dist/client/assets/eventmodeling-NTZA5JFV-D_UXLpIu.js +1 -0
- package/packages/web/dist/client/assets/flowDiagram-KWPJA3E3-BT4eEEVm.js +1 -0
- package/packages/web/dist/client/assets/{ganttDiagram-FUAMR5RP-C0CFpE5x.js → ganttDiagram-FUAMR5RP-CojF9Q16.js} +1 -1
- package/packages/web/dist/client/assets/{gitGraph-4MIJSDKK-VPL7nv2c.js → gitGraph-4MIJSDKK-YvKqGEPk.js} +1 -1
- package/packages/web/dist/client/assets/{gitGraphDiagram-X574FWY7-CgxJA-T8.js → gitGraphDiagram-X574FWY7-XqNqIFo9.js} +1 -1
- package/packages/web/dist/client/assets/index--2CDtzvY.css +1 -0
- package/packages/web/dist/client/assets/{index-XTlTnQmx.js → index-bT6QPJZs.js} +7 -7
- package/packages/web/dist/client/assets/{info-A6RAGUB7-P0-o68pj.js → info-A6RAGUB7-B_1BCzM2.js} +1 -1
- package/packages/web/dist/client/assets/{infoDiagram-VRGFBTTK-DFJZNRUP.js → infoDiagram-VRGFBTTK-zFX8B-dP.js} +1 -1
- package/packages/web/dist/client/assets/{ishikawaDiagram-OU5B5YK6-ZkyhNd1T.js → ishikawaDiagram-OU5B5YK6-DLzQ_Uyf.js} +1 -1
- package/packages/web/dist/client/assets/{journeyDiagram-ZHPQQLJL-DFevH8my.js → journeyDiagram-ZHPQQLJL-S3WRMmoa.js} +1 -1
- package/packages/web/dist/client/assets/{kanban-definition-PNTS6WVX-l7e7ZZDC.js → kanban-definition-PNTS6WVX-B5Z8I-kM.js} +1 -1
- package/packages/web/dist/client/assets/{line-DO_s6Ujd.js → line-BGMH-i2X.js} +1 -1
- package/packages/web/dist/client/assets/{linear-C4xH5PPc.js → linear-KsrestXG.js} +1 -1
- package/packages/web/dist/client/assets/{mermaid-parser.core-nQaTP3VY.js → mermaid-parser.core-DNffyJJA.js} +3 -3
- package/packages/web/dist/client/assets/{mermaid.core-Cz05yTZh.js → mermaid.core-Cz3vJeQG.js} +4 -4
- package/packages/web/dist/client/assets/{mindmap-definition-NLK3R4M7-CHOEuHm2.js → mindmap-definition-NLK3R4M7-CzA61XUf.js} +1 -1
- package/packages/web/dist/client/assets/{packet-AYTQ26CC-BH3ehPMo.js → packet-AYTQ26CC-BO55e7cR.js} +1 -1
- package/packages/web/dist/client/assets/{pegDiagram-GJSIUBJH-CkWBLtad.js → pegDiagram-GJSIUBJH-DeRiXYNd.js} +1 -1
- package/packages/web/dist/client/assets/{pie-WAS4IAKB-nNVEq3dx.js → pie-WAS4IAKB-D9ibrQRe.js} +1 -1
- package/packages/web/dist/client/assets/{pieDiagram-5QR66LMP-DimUBAgN.js → pieDiagram-5QR66LMP-BaBpPP33.js} +1 -1
- package/packages/web/dist/client/assets/{quadrantDiagram-O4NWA36T-BR0XpRGQ.js → quadrantDiagram-O4NWA36T-DIfn4GjM.js} +1 -1
- package/packages/web/dist/client/assets/{radar-RG4KPBEZ-paA-H3mb.js → radar-RG4KPBEZ-Dmn5-nJq.js} +1 -1
- package/packages/web/dist/client/assets/{railroad-74A4TZTK-yEiKB3rz.js → railroad-74A4TZTK-ZCWNEd2Z.js} +1 -1
- package/packages/web/dist/client/assets/railroad-abnf-HS5TGJTU-_swqhy0y.js +1 -0
- package/packages/web/dist/client/assets/railroad-ebnf-LZEXJU2U-CytbazPx.js +1 -0
- package/packages/web/dist/client/assets/railroad-peg-WCYAUIDC-Bg8QW17T.js +1 -0
- package/packages/web/dist/client/assets/{railroadDiagram-XR7U4H2S--TXe6rdU.js → railroadDiagram-XR7U4H2S-CDPZ39sy.js} +1 -1
- package/packages/web/dist/client/assets/{requirementDiagram-PLB6GJNP-DyqH36Za.js → requirementDiagram-PLB6GJNP-CyCI8Yul.js} +1 -1
- package/packages/web/dist/client/assets/{sankeyDiagram-IPEJSGJF-Bg6e3BlM.js → sankeyDiagram-IPEJSGJF-p_XAPv72.js} +1 -1
- package/packages/web/dist/client/assets/{sequenceDiagram-PO4LG4MO-ClGf85My.js → sequenceDiagram-PO4LG4MO-DmR6IP_o.js} +1 -1
- package/packages/web/dist/client/assets/{src-DF7hQfMh.js → src-gnv7pJ1z.js} +1 -1
- package/packages/web/dist/client/assets/{stateDiagram-v2-GCMORJYK-BK8TpxNo.js → stateDiagram-v2-GCMORJYK-7ZTHl6ih.js} +1 -1
- package/packages/web/dist/client/assets/{swimlanes-2SLR337P-DDnTIT9M.js → swimlanes-2SLR337P-N6bj71pw.js} +1 -1
- package/packages/web/dist/client/assets/swimlanesDiagram-TC7HE7FX-BJQ2CBsp.js +8 -0
- package/packages/web/dist/client/assets/{timeline-definition-EJHVYXUP-mBBbH3bk.js → timeline-definition-EJHVYXUP-GNez0kW8.js} +1 -1
- package/packages/web/dist/client/assets/{treeView-Q6P3EWNA-CTK7tRwR.js → treeView-Q6P3EWNA-DyQZkboR.js} +1 -1
- package/packages/web/dist/client/assets/{treemap-WGGIJYW6-vOI-Ef_m.js → treemap-WGGIJYW6-_J8Pw2TM.js} +1 -1
- package/packages/web/dist/client/assets/{usecaseDiagram-POWQR4AR-COcii8x-.js → usecaseDiagram-POWQR4AR-Bg-CzKjl.js} +1 -1
- package/packages/web/dist/client/assets/{vennDiagram-UO4OBE2U-D6kmDGpM.js → vennDiagram-UO4OBE2U-DBQKHXhK.js} +1 -1
- package/packages/web/dist/client/assets/{wardley-WFR3VGLG-CtE2KI9r.js → wardley-WFR3VGLG-B5aAsQ3F.js} +1 -1
- package/packages/web/dist/client/assets/{wardleyDiagram-VNRHLVJA-ncxNGWnW.js → wardleyDiagram-VNRHLVJA-BKUQ1LK6.js} +1 -1
- package/packages/web/dist/client/assets/{xychartDiagram-PMCCYNJV-DUvd2Qze.js → xychartDiagram-PMCCYNJV-BI2sVbks.js} +1 -1
- package/packages/web/dist/client/index.html +2 -2
- package/packages/web/dist/client/assets/architecture-7GRP2DOG-HIzEIkwQ.js +0 -1
- package/packages/web/dist/client/assets/channel-BCA6qe9I.js +0 -1
- package/packages/web/dist/client/assets/eventmodeling-NTZA5JFV-l6SYFw1s.js +0 -1
- package/packages/web/dist/client/assets/flowDiagram-KWPJA3E3-CWW9qnqm.js +0 -1
- package/packages/web/dist/client/assets/index-D9_XJLSc.css +0 -1
- package/packages/web/dist/client/assets/railroad-abnf-HS5TGJTU-mVQx9aVM.js +0 -1
- package/packages/web/dist/client/assets/railroad-ebnf-LZEXJU2U-CllXx1OJ.js +0 -1
- package/packages/web/dist/client/assets/railroad-peg-WCYAUIDC-BBD2Q5W_.js +0 -1
- package/packages/web/dist/client/assets/swimlanesDiagram-TC7HE7FX-CM8UnP5t.js +0 -8
|
@@ -43,27 +43,26 @@ function prepare<T>(candidates: readonly FuzzyCandidate<T>[]): FuzzyIndex<T> {
|
|
|
43
43
|
return {
|
|
44
44
|
find: (query, options = {}) => {
|
|
45
45
|
const trimmed = query.trim();
|
|
46
|
-
const limit = options.limit ?? Infinity;
|
|
47
46
|
if (trimmed.length === 0) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
return limit === Infinity ? emptyHits : emptyHits.slice(0, limit);
|
|
47
|
+
emptyHits ??= [...candidates]
|
|
48
|
+
.sort((a, b) =>
|
|
49
|
+
(a.haystacks[0] ?? "").localeCompare(b.haystacks[0] ?? "")
|
|
50
|
+
)
|
|
51
|
+
.map((candidate) => ({
|
|
52
|
+
item: candidate.item,
|
|
53
|
+
score: 0,
|
|
54
|
+
positions: new Set<number>(),
|
|
55
|
+
}));
|
|
56
|
+
return emptyHits.slice(0, options.limit);
|
|
60
57
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
return fzf
|
|
59
|
+
.find(trimmed)
|
|
60
|
+
.slice(0, options.limit)
|
|
61
|
+
.map((result) => ({
|
|
62
|
+
item: result.item.item,
|
|
63
|
+
score: result.score,
|
|
64
|
+
positions: result.positions,
|
|
65
|
+
}));
|
|
67
66
|
},
|
|
68
67
|
};
|
|
69
68
|
}
|
|
@@ -6,32 +6,26 @@ import { Proc, type ProcOptions, type ProcResult } from "./Proc";
|
|
|
6
6
|
|
|
7
7
|
export type GitState = {
|
|
8
8
|
readonly branch: string | null;
|
|
9
|
-
/** Paths `git status` lists as changed; zero is a clean tree. */
|
|
10
9
|
readonly dirtyCount: number;
|
|
11
10
|
readonly ahead: number;
|
|
12
11
|
readonly behind: number;
|
|
13
|
-
/**
|
|
14
|
-
* Changes whenever the repository's content does: the commit at head, every
|
|
15
|
-
* path git calls changed, and what each of those paths now holds. A count
|
|
16
|
-
* cannot see an edit to a file already dirty; this can.
|
|
17
|
-
*/
|
|
12
|
+
/** Hash of HEAD, the changed paths and their stats; also moves when an already-dirty file is edited again. */
|
|
18
13
|
readonly revision: string;
|
|
19
14
|
};
|
|
20
15
|
|
|
21
|
-
/** One local branch, as `listBranches` ranks and labels it. */
|
|
22
16
|
export type GitBranch = {
|
|
23
17
|
readonly name: string;
|
|
24
18
|
readonly current: boolean;
|
|
25
|
-
/**
|
|
19
|
+
/** `origin/HEAD`'s target, else the first of `main`/`master`/`trunk` that exists. */
|
|
26
20
|
readonly isDefault: boolean;
|
|
27
|
-
/**
|
|
21
|
+
/** Last commit time, epoch seconds. */
|
|
28
22
|
readonly updatedAt: number;
|
|
29
23
|
readonly ahead: number;
|
|
30
24
|
readonly behind: number;
|
|
31
|
-
/**
|
|
25
|
+
/** Its upstream branch was deleted. */
|
|
32
26
|
readonly gone: boolean;
|
|
33
27
|
readonly merged: boolean;
|
|
34
|
-
/** Checked out in another worktree
|
|
28
|
+
/** Checked out in another worktree. */
|
|
35
29
|
readonly worktree: boolean;
|
|
36
30
|
};
|
|
37
31
|
|
|
@@ -41,7 +35,7 @@ export type GitOutcome =
|
|
|
41
35
|
|
|
42
36
|
export type CommitRequest = {
|
|
43
37
|
readonly message: string;
|
|
44
|
-
/** Exactly what is committed; a rename
|
|
38
|
+
/** Exactly what is committed; a rename lists both names. */
|
|
45
39
|
readonly paths: readonly string[];
|
|
46
40
|
};
|
|
47
41
|
|
|
@@ -81,7 +75,7 @@ const COMMIT_TIMEOUT_MS = 120_000;
|
|
|
81
75
|
|
|
82
76
|
const ERROR_LIMIT = 400;
|
|
83
77
|
|
|
84
|
-
/**
|
|
78
|
+
/** Fail instead of waiting on a credential prompt nobody can answer. */
|
|
85
79
|
const NETWORK_ENV: Readonly<Record<string, string | undefined>> = {
|
|
86
80
|
GIT_TERMINAL_PROMPT: "0",
|
|
87
81
|
GIT_ASKPASS: undefined,
|
|
@@ -90,7 +84,7 @@ const NETWORK_ENV: Readonly<Record<string, string | undefined>> = {
|
|
|
90
84
|
GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes",
|
|
91
85
|
};
|
|
92
86
|
|
|
93
|
-
/**
|
|
87
|
+
/** Hooks and signing must never open an editor. */
|
|
94
88
|
const COMMIT_OPTIONS: ProcOptions = {
|
|
95
89
|
env: { GIT_EDITOR: "true" },
|
|
96
90
|
timeoutMs: COMMIT_TIMEOUT_MS,
|
|
@@ -109,17 +103,13 @@ function git(
|
|
|
109
103
|
}
|
|
110
104
|
|
|
111
105
|
function network(cwd: string, args: readonly string[]): Promise<ProcResult> {
|
|
112
|
-
return
|
|
113
|
-
cwd,
|
|
114
|
-
env: NETWORK_ENV,
|
|
115
|
-
timeoutMs: NETWORK_TIMEOUT_MS,
|
|
116
|
-
});
|
|
106
|
+
return git(cwd, args, { env: NETWORK_ENV, timeoutMs: NETWORK_TIMEOUT_MS });
|
|
117
107
|
}
|
|
118
108
|
|
|
119
|
-
/**
|
|
109
|
+
/** Index of the path field in each porcelain-v2 entry type. */
|
|
120
110
|
const PATH_FIELD: Readonly<Record<string, number>> = { "1": 8, "2": 9, u: 10 };
|
|
121
111
|
|
|
122
|
-
/**
|
|
112
|
+
/** Only the first this-many changed paths are stat'd into the revision. */
|
|
123
113
|
const SAMPLE_LIMIT = 500;
|
|
124
114
|
|
|
125
115
|
function pathOf(line: string): string {
|
|
@@ -135,7 +125,6 @@ function pathOf(line: string): string {
|
|
|
135
125
|
return line.split(" ").slice(field).join(" ").split("\t")[0] ?? "";
|
|
136
126
|
}
|
|
137
127
|
|
|
138
|
-
/** What a changed path holds now, cheaply enough to read on every poll. */
|
|
139
128
|
function worktreeSample(cwd: string): (path: string) => string {
|
|
140
129
|
return (path) => {
|
|
141
130
|
const stats = statSync(join(cwd, path), { throwIfNoEntry: false });
|
|
@@ -205,7 +194,6 @@ function parseTrack(text: string): {
|
|
|
205
194
|
};
|
|
206
195
|
}
|
|
207
196
|
|
|
208
|
-
/** What one `for-each-ref` line says; `rank` adds the two facts that need the whole list. */
|
|
209
197
|
type Ref = Omit<GitBranch, "isDefault" | "merged">;
|
|
210
198
|
|
|
211
199
|
function parseRefs(text: string): readonly Ref[] {
|
|
@@ -228,7 +216,7 @@ function parseRefs(text: string): readonly Ref[] {
|
|
|
228
216
|
|
|
229
217
|
const MOVING = "checkout: moving from ";
|
|
230
218
|
|
|
231
|
-
/**
|
|
219
|
+
/** Last checkout time per branch, from the reflog. */
|
|
232
220
|
function parseVisits(text: string): ReadonlyMap<string, number> {
|
|
233
221
|
const visits = new Map<string, number>();
|
|
234
222
|
for (const line of Lines.split(text)) {
|
|
@@ -285,7 +273,7 @@ async function remoteOf(cwd: string): Promise<string | undefined> {
|
|
|
285
273
|
return remotes.length === 1 ? remotes[0] : undefined;
|
|
286
274
|
}
|
|
287
275
|
|
|
288
|
-
/**
|
|
276
|
+
/** The remote's default branch, if it names one. */
|
|
289
277
|
async function remoteHead(cwd: string): Promise<string | undefined> {
|
|
290
278
|
const remote = await remoteOf(cwd);
|
|
291
279
|
if (remote === undefined) {
|
|
@@ -315,7 +303,7 @@ async function mergedInto(
|
|
|
315
303
|
return new Set(code === 0 ? Lines.split(stdout) : []);
|
|
316
304
|
}
|
|
317
305
|
|
|
318
|
-
/**
|
|
306
|
+
/** Local branches: default first, then by last commit or checkout. */
|
|
319
307
|
async function listBranches(cwd: string): Promise<readonly GitBranch[]> {
|
|
320
308
|
const [refs, log, remote] = await Promise.all([
|
|
321
309
|
git(cwd, ["for-each-ref", "--format", BRANCH_FORMAT, "refs/heads/"]),
|
|
@@ -337,10 +325,7 @@ async function listBranches(cwd: string): Promise<readonly GitBranch[]> {
|
|
|
337
325
|
);
|
|
338
326
|
}
|
|
339
327
|
|
|
340
|
-
/**
|
|
341
|
-
* What a failed `git` said, in one line: its own words where it had any, the
|
|
342
|
-
* caller's fallback where it had none, and the timeout where it never answered.
|
|
343
|
-
*/
|
|
328
|
+
/** git's own error text, else `fallback`, or `timeout` when it timed out. */
|
|
344
329
|
function failure(
|
|
345
330
|
result: ProcResult,
|
|
346
331
|
fallback: string,
|
|
@@ -369,16 +354,12 @@ async function checkout(cwd: string, branch: string): Promise<GitOutcome> {
|
|
|
369
354
|
);
|
|
370
355
|
}
|
|
371
356
|
|
|
372
|
-
/**
|
|
357
|
+
/** True for an empty, absolute or `..` path. */
|
|
373
358
|
function escapes(path: string): boolean {
|
|
374
359
|
return path === "" || isAbsolute(path) || path.split(/[/\\]/).includes("..");
|
|
375
360
|
}
|
|
376
361
|
|
|
377
|
-
/**
|
|
378
|
-
* Commits exactly `paths` and nothing else: everything else changed stays
|
|
379
|
-
* dirty, and an unrelated path someone had staged stays staged. Untracked
|
|
380
|
-
* paths are added first, or a path-limited commit of one finds no such file.
|
|
381
|
-
*/
|
|
362
|
+
/** Commits exactly `paths`; other changes, staged or not, are left alone. */
|
|
382
363
|
async function commit(
|
|
383
364
|
cwd: string,
|
|
384
365
|
request: CommitRequest
|
|
@@ -397,13 +378,8 @@ async function commit(
|
|
|
397
378
|
error: `${outside === "" ? "an empty path" : outside} is not a path inside this repository`,
|
|
398
379
|
};
|
|
399
380
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
* rename's old name matches nothing: it is gone from both the worktree and
|
|
403
|
-
* the index. A deletion is the same. `git commit -- <paths>` reads those two
|
|
404
|
-
* off HEAD and the index by itself, so only the paths still on disk are
|
|
405
|
-
* worth adding, and a pick made entirely of them needs no `add` at all.
|
|
406
|
-
*/
|
|
381
|
+
// Add only paths on disk: `git add` rejects deleted paths and a rename's old
|
|
382
|
+
// name, and `git commit -- <paths>` handles those itself.
|
|
407
383
|
const onDisk = await Promise.all(
|
|
408
384
|
request.paths.map((path) => Bun.file(join(cwd, path)).exists())
|
|
409
385
|
);
|
|
@@ -457,7 +433,7 @@ async function pull(cwd: string): Promise<GitOutcome> {
|
|
|
457
433
|
);
|
|
458
434
|
}
|
|
459
435
|
|
|
460
|
-
/**
|
|
436
|
+
/** Undefined when the branch has no upstream or HEAD is detached. */
|
|
461
437
|
async function upstreamOf(cwd: string): Promise<string | undefined> {
|
|
462
438
|
const { code, stdout } = await git(cwd, [
|
|
463
439
|
"rev-parse",
|
|
@@ -469,7 +445,7 @@ async function upstreamOf(cwd: string): Promise<string | undefined> {
|
|
|
469
445
|
return code === 0 && name !== "" ? name : undefined;
|
|
470
446
|
}
|
|
471
447
|
|
|
472
|
-
/**
|
|
448
|
+
/** Sets the upstream on the first push. */
|
|
473
449
|
async function push(cwd: string): Promise<GitOutcome> {
|
|
474
450
|
const [head, upstream] = await Promise.all([
|
|
475
451
|
git(cwd, ["symbolic-ref", "--quiet", "--short", "HEAD"]),
|
|
@@ -500,7 +476,7 @@ async function push(cwd: string): Promise<GitOutcome> {
|
|
|
500
476
|
async function fetchStatus(cwd: string): Promise<GitState> {
|
|
501
477
|
try {
|
|
502
478
|
const { code, stdout } = await git(cwd, [
|
|
503
|
-
//
|
|
479
|
+
// Avoids taking `index.lock`, which would fail a concurrent checkout.
|
|
504
480
|
"--no-optional-locks",
|
|
505
481
|
"status",
|
|
506
482
|
"--porcelain=v2",
|
|
@@ -512,7 +488,6 @@ async function fetchStatus(cwd: string): Promise<GitState> {
|
|
|
512
488
|
}
|
|
513
489
|
}
|
|
514
490
|
|
|
515
|
-
/** The cwd's git state, for the TUI footer and the web's branch menu. */
|
|
516
491
|
export const Git = {
|
|
517
492
|
EMPTY,
|
|
518
493
|
parseStatus,
|
|
@@ -5,16 +5,13 @@ import { Git, type GitOutcome, type GitState } from "./Git";
|
|
|
5
5
|
|
|
6
6
|
export type GitListener = (state: GitState) => void;
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* What one operation under the lock says, and what it made where it made
|
|
10
|
-
* anything: a commit has a sha to hand back, a checkout has only its outcome.
|
|
11
|
-
*/
|
|
8
|
+
/** `value` carries an operation's result, e.g. a commit's sha. */
|
|
12
9
|
export type GitRun<T = never> = GitOutcome & { readonly value?: T };
|
|
13
10
|
|
|
14
11
|
export type GitMonitorDeps = {
|
|
15
|
-
/**
|
|
12
|
+
/** Minimum gap between fetches. Defaults to 30s. */
|
|
16
13
|
readonly fetchTtlMs?: number;
|
|
17
|
-
/**
|
|
14
|
+
/** Poll for worktree edits, which `.git` never sees. Defaults to 2s. */
|
|
18
15
|
readonly pollMs?: number;
|
|
19
16
|
readonly status?: (cwd: string) => Promise<GitState>;
|
|
20
17
|
readonly fetch?: (cwd: string) => Promise<GitOutcome>;
|
|
@@ -29,20 +26,18 @@ type Entry = {
|
|
|
29
26
|
pending: boolean;
|
|
30
27
|
fetchedAt: number;
|
|
31
28
|
locked: boolean;
|
|
32
|
-
/**
|
|
29
|
+
/** Duration and end time of the last read; the poll backs off by these. */
|
|
33
30
|
readMs: number;
|
|
34
31
|
readAt: number;
|
|
35
32
|
};
|
|
36
33
|
|
|
37
|
-
/** A checkout writes half the repository; one read has to stand for the burst. */
|
|
38
34
|
const DEBOUNCE_MS = 200;
|
|
39
35
|
|
|
40
36
|
const FETCH_TTL_MS = 30_000;
|
|
41
37
|
|
|
42
|
-
/** A worktree edit touches nothing under `.git`, so the watch alone would never see it. */
|
|
43
38
|
const POLL_MS = 2_000;
|
|
44
39
|
|
|
45
|
-
/** A repository
|
|
40
|
+
/** A slow repository is polled at most once per this many read durations. */
|
|
46
41
|
const BACKOFF = 4;
|
|
47
42
|
|
|
48
43
|
function same(a: GitState, b: GitState): boolean {
|
|
@@ -55,12 +50,7 @@ function same(a: GitState, b: GitState): boolean {
|
|
|
55
50
|
);
|
|
56
51
|
}
|
|
57
52
|
|
|
58
|
-
/**
|
|
59
|
-
* One reader of one repository, however many sessions share it: it watches
|
|
60
|
-
* `.git` so a commit anywhere reaches every surface, coalesces the burst a
|
|
61
|
-
* checkout makes into a single read, and serialises the operations that write,
|
|
62
|
-
* which cannot run two at a time over one index.
|
|
63
|
-
*/
|
|
53
|
+
/** One shared reader per repository: watches `.git`, debounces reads, and allows one writing operation at a time. */
|
|
64
54
|
export class GitMonitor {
|
|
65
55
|
private readonly entries = new Map<string, Entry>();
|
|
66
56
|
private readonly deps: GitMonitorDeps;
|
|
@@ -69,7 +59,7 @@ export class GitMonitor {
|
|
|
69
59
|
this.deps = deps;
|
|
70
60
|
}
|
|
71
61
|
|
|
72
|
-
/**
|
|
62
|
+
/** The listener hears only changes. */
|
|
73
63
|
public watch(cwd: string, listener: GitListener): () => void {
|
|
74
64
|
const entry = this.entryOf(cwd);
|
|
75
65
|
entry.listeners.add(listener);
|
|
@@ -84,12 +74,12 @@ export class GitMonitor {
|
|
|
84
74
|
};
|
|
85
75
|
}
|
|
86
76
|
|
|
87
|
-
/** The last state read
|
|
77
|
+
/** The last state read; never waits. */
|
|
88
78
|
public stateOf(cwd: string): GitState {
|
|
89
79
|
return this.entries.get(cwd)?.state ?? Git.EMPTY;
|
|
90
80
|
}
|
|
91
81
|
|
|
92
|
-
/**
|
|
82
|
+
/** `fetch` also fetches the remote first, at most once per TTL. */
|
|
93
83
|
public async refresh(
|
|
94
84
|
cwd: string,
|
|
95
85
|
options: { readonly fetch?: boolean } = {}
|
|
@@ -107,7 +97,7 @@ export class GitMonitor {
|
|
|
107
97
|
return await this.read(entry);
|
|
108
98
|
}
|
|
109
99
|
|
|
110
|
-
/**
|
|
100
|
+
/** Refuses while another operation runs on `cwd`; re-reads after. */
|
|
111
101
|
public async run<T = never>(
|
|
112
102
|
cwd: string,
|
|
113
103
|
operation: () => Promise<GitRun<T>>
|
|
@@ -165,8 +155,7 @@ export class GitMonitor {
|
|
|
165
155
|
}, DEBOUNCE_MS);
|
|
166
156
|
timer.unref?.();
|
|
167
157
|
});
|
|
168
|
-
// `false`: a
|
|
169
|
-
// status must never queue another behind itself.
|
|
158
|
+
// `false`: a tick must not queue a read behind a slow one.
|
|
170
159
|
const poll = setInterval(() => {
|
|
171
160
|
if (Date.now() - entry.readAt < entry.readMs * BACKOFF) {
|
|
172
161
|
return;
|
|
@@ -181,7 +170,7 @@ export class GitMonitor {
|
|
|
181
170
|
};
|
|
182
171
|
}
|
|
183
172
|
|
|
184
|
-
/** `restart` re-reads
|
|
173
|
+
/** `restart` re-reads after an in-flight read, which may predate the change. */
|
|
185
174
|
private read(entry: Entry, restart = true): Promise<GitState> {
|
|
186
175
|
if (entry.inFlight) {
|
|
187
176
|
entry.pending ||= restart;
|
|
@@ -3,10 +3,6 @@ function compile(exclude: readonly string[] | undefined): readonly Bun.Glob[] {
|
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
function ignores(globs: readonly Bun.Glob[], relativePath: string): boolean {
|
|
6
|
-
if (globs.length === 0) {
|
|
7
|
-
return false;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
6
|
return globs.some((glob) => glob.match(relativePath));
|
|
11
7
|
}
|
|
12
8
|
|
|
@@ -5,7 +5,7 @@ export type HttpFetch = (
|
|
|
5
5
|
init?: Parameters<typeof fetch>[1]
|
|
6
6
|
) => ReturnType<typeof fetch>;
|
|
7
7
|
|
|
8
|
-
/**
|
|
8
|
+
/** Retries off: ky's default honours `Retry-After` uncapped and can stall a tool for hours. */
|
|
9
9
|
export function createKy(custom?: HttpFetch): KyInstance {
|
|
10
10
|
return ky.create({
|
|
11
11
|
retry: 0,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** The formats every provider we target accepts. */
|
|
2
1
|
export type ImageMimeType =
|
|
3
2
|
| "image/png"
|
|
4
3
|
| "image/jpeg"
|
|
@@ -12,13 +11,12 @@ const EXTENSIONS = {
|
|
|
12
11
|
"image/webp": "webp",
|
|
13
12
|
} satisfies Record<ImageMimeType, string>;
|
|
14
13
|
|
|
15
|
-
/**
|
|
14
|
+
/** Includes both `jpg` and `jpeg`. */
|
|
16
15
|
const NAME_EXTENSIONS = new Set([
|
|
17
16
|
...Object.values(EXTENSIONS),
|
|
18
17
|
...Object.keys(EXTENSIONS).map((mimeType) => mimeType.slice("image/".length)),
|
|
19
18
|
]);
|
|
20
19
|
|
|
21
|
-
/** The format as a word, in the one spelling the notes, the UI and the cache filename all use. */
|
|
22
20
|
function extensionOf(mimeType: ImageMimeType): string {
|
|
23
21
|
return EXTENSIONS[mimeType];
|
|
24
22
|
}
|
|
@@ -27,10 +25,10 @@ function isSupported(mimeType: string): mimeType is ImageMimeType {
|
|
|
27
25
|
return Object.hasOwn(EXTENSIONS, mimeType);
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
/**
|
|
28
|
+
/** Takes a bare, lowercased extension. */
|
|
31
29
|
function namesExtension(extension: string): boolean {
|
|
32
30
|
return NAME_EXTENSIONS.has(extension);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
/**
|
|
33
|
+
/** Browser-safe: no Node imports. */
|
|
36
34
|
export const ImageMime = { extensionOf, isSupported, namesExtension };
|
|
@@ -10,33 +10,31 @@ import { SpillCache } from "./SpillCache";
|
|
|
10
10
|
|
|
11
11
|
export type { ImageMimeType };
|
|
12
12
|
|
|
13
|
-
/** What a tool needs off `ctx.model` to know whether a picture can be sent. */
|
|
14
13
|
export type VisionModel = {
|
|
15
14
|
readonly id: string;
|
|
16
15
|
readonly input: readonly string[];
|
|
17
16
|
};
|
|
18
17
|
|
|
19
|
-
/** An image the providers will take: within their formats, dimensions and byte budget. */
|
|
20
18
|
export type NormalisedImage = {
|
|
21
19
|
readonly base64: string;
|
|
22
20
|
readonly mimeType: ImageMimeType;
|
|
23
21
|
readonly width: number;
|
|
24
22
|
readonly height: number;
|
|
25
|
-
/** Encoded size after the resize
|
|
23
|
+
/** Encoded size after the resize. */
|
|
26
24
|
readonly bytes: number;
|
|
27
25
|
readonly originalWidth: number;
|
|
28
26
|
readonly originalHeight: number;
|
|
29
|
-
/**
|
|
27
|
+
/** May differ from `mimeType`: a resize can re-encode. */
|
|
30
28
|
readonly originalMimeType: ImageMimeType;
|
|
31
29
|
readonly resized: boolean;
|
|
32
|
-
/** Frames in the source
|
|
30
|
+
/** Frames in the source; the encoded copy keeps only the first. */
|
|
33
31
|
readonly frames: number;
|
|
34
32
|
readonly sha256: string;
|
|
35
33
|
/** `~/.pim/cache/img-<sha256>.<ext>`, or null when the cache write failed. */
|
|
36
34
|
readonly cachePath: string | null;
|
|
37
35
|
};
|
|
38
36
|
|
|
39
|
-
/**
|
|
37
|
+
/** No pixel data: `sha256` addresses the picture in the spill cache. */
|
|
40
38
|
export type ImageDetails = {
|
|
41
39
|
readonly sha256: string;
|
|
42
40
|
readonly mimeType: ImageMimeType;
|
|
@@ -49,12 +47,12 @@ export type ImageDetails = {
|
|
|
49
47
|
|
|
50
48
|
type ToolContent = AgentToolResult<unknown>["content"];
|
|
51
49
|
|
|
52
|
-
/**
|
|
50
|
+
/** Larger sources are rejected before decoding. */
|
|
53
51
|
const MAX_SOURCE_BYTES = 25 * 1024 * 1024;
|
|
54
52
|
const MAX_EDGE = 2000;
|
|
55
53
|
const MAX_ENCODED_BYTES = 3_932_160;
|
|
56
54
|
|
|
57
|
-
/**
|
|
55
|
+
/** Long enough for every signature, including WebP's `RIFF….WEBP`. */
|
|
58
56
|
const SNIFF_BYTES = 12;
|
|
59
57
|
|
|
60
58
|
const CACHE_PREFIX = "img-";
|
|
@@ -81,7 +79,7 @@ function startsWith(
|
|
|
81
79
|
return signature.every((byte, index) => bytes[offset + index] === byte);
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
/**
|
|
82
|
+
/** By magic bytes, never by extension. */
|
|
85
83
|
function sniff(bytes: Uint8Array): ImageMimeType | null {
|
|
86
84
|
if (startsWith(bytes, PNG)) {
|
|
87
85
|
return "image/png";
|
|
@@ -102,7 +100,7 @@ function view(bytes: Uint8Array): DataView {
|
|
|
102
100
|
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
/** RIFF chunks are padded to an even length
|
|
103
|
+
/** RIFF chunks are padded to an even length. */
|
|
106
104
|
function webpFrames(bytes: Uint8Array): number {
|
|
107
105
|
const reader = view(bytes);
|
|
108
106
|
let count = 0;
|
|
@@ -117,7 +115,7 @@ function webpFrames(bytes: Uint8Array): number {
|
|
|
117
115
|
return count;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
|
-
/** `acTL`
|
|
118
|
+
/** `acTL` holds the count and must come before the first `IDAT`. */
|
|
121
119
|
function apngFrames(bytes: Uint8Array): number {
|
|
122
120
|
const reader = view(bytes);
|
|
123
121
|
let at = 8;
|
|
@@ -173,32 +171,30 @@ const FRAME_READERS: Partial<
|
|
|
173
171
|
"image/gif": gifFrames,
|
|
174
172
|
};
|
|
175
173
|
|
|
176
|
-
/**
|
|
174
|
+
/** Read from the source, since the resize keeps only frame 1. */
|
|
177
175
|
function frames(bytes: Uint8Array, mimeType: ImageMimeType): number {
|
|
178
176
|
return Math.max(1, FRAME_READERS[mimeType]?.(bytes) ?? 1);
|
|
179
177
|
}
|
|
180
178
|
|
|
181
|
-
/** An unknown model is
|
|
179
|
+
/** An unknown model is assumed to see. */
|
|
182
180
|
function canSee(model: VisionModel | undefined): boolean {
|
|
183
181
|
return model === undefined || model.input.includes("image");
|
|
184
182
|
}
|
|
185
183
|
|
|
186
|
-
/** What a model without eyes is told in place of the picture it cannot be sent. */
|
|
187
184
|
function noVisionNote(tool: string, subject: string): string {
|
|
188
185
|
return `[${tool} tool: ${subject}; the current model has no vision input.]`;
|
|
189
186
|
}
|
|
190
187
|
|
|
191
|
-
/** A name that claims a picture — a claim the bytes still have to back. */
|
|
192
188
|
function looksLikeImageName(path: string): boolean {
|
|
193
189
|
return ImageMime.namesExtension(extname(path).slice(1).toLowerCase());
|
|
194
190
|
}
|
|
195
191
|
|
|
196
|
-
/**
|
|
192
|
+
/** The extension follows the encoded type, not the source path. */
|
|
197
193
|
function cacheName(sha256: string, mimeType: ImageMimeType): string {
|
|
198
194
|
return `${CACHE_PREFIX}${sha256}.${ImageMime.extensionOf(mimeType)}`;
|
|
199
195
|
}
|
|
200
196
|
|
|
201
|
-
/**
|
|
197
|
+
/** Meant for the stat size, so an oversized file is never read. */
|
|
202
198
|
function assertWithinSourceCap(byteLength: number, path: string): void {
|
|
203
199
|
if (byteLength > MAX_SOURCE_BYTES) {
|
|
204
200
|
throw new Error(
|
|
@@ -231,7 +227,7 @@ async function normalise(
|
|
|
231
227
|
);
|
|
232
228
|
}
|
|
233
229
|
|
|
234
|
-
//
|
|
230
|
+
// Unresized output is the input, so skip decoding the base64 back.
|
|
235
231
|
const data = resized.wasResized ? Buffer.from(resized.data, "base64") : bytes;
|
|
236
232
|
const mimeType = ImageMime.isSupported(resized.mimeType)
|
|
237
233
|
? resized.mimeType
|
|
@@ -256,7 +252,6 @@ async function normalise(
|
|
|
256
252
|
};
|
|
257
253
|
}
|
|
258
254
|
|
|
259
|
-
/** The record of the picture a tool hands its view, off the picture itself. */
|
|
260
255
|
function detailsOf(image: NormalisedImage): ImageDetails {
|
|
261
256
|
return {
|
|
262
257
|
sha256: image.sha256,
|
|
@@ -269,7 +264,7 @@ function detailsOf(image: NormalisedImage): ImageDetails {
|
|
|
269
264
|
};
|
|
270
265
|
}
|
|
271
266
|
|
|
272
|
-
/** Text first,
|
|
267
|
+
/** Text first, matching pi's read tool. */
|
|
273
268
|
function contentOf(image: NormalisedImage, note?: string): ToolContent {
|
|
274
269
|
const picture = {
|
|
275
270
|
type: "image" as const,
|
|
@@ -281,7 +276,6 @@ function contentOf(image: NormalisedImage, note?: string): ToolContent {
|
|
|
281
276
|
: [{ type: "text", text: note }, picture];
|
|
282
277
|
}
|
|
283
278
|
|
|
284
|
-
/** How the model maps coordinates it reads off the picture back onto the file. */
|
|
285
279
|
function resizeNote(image: NormalisedImage): string | undefined {
|
|
286
280
|
if (!image.resized) {
|
|
287
281
|
return undefined;
|
|
@@ -290,10 +284,7 @@ function resizeNote(image: NormalisedImage): string | undefined {
|
|
|
290
284
|
return `image resized from ${image.originalWidth}x${image.originalHeight} to ${image.width}x${image.height}; multiply coordinates by ${scale} to map to the original.`;
|
|
291
285
|
}
|
|
292
286
|
|
|
293
|
-
/**
|
|
294
|
-
* What the picture leaves out, which a still under every cap says nothing about:
|
|
295
|
-
* providers see one frame, so an unmentioned animation reads as an empty screen.
|
|
296
|
-
*/
|
|
287
|
+
/** Providers see only one frame, so say the image is animated. */
|
|
297
288
|
function animationNote(image: NormalisedImage): string | undefined {
|
|
298
289
|
if (image.frames < 2) {
|
|
299
290
|
return undefined;
|
|
@@ -301,7 +292,6 @@ function animationNote(image: NormalisedImage): string | undefined {
|
|
|
301
292
|
return `animated ${ImageMime.extensionOf(image.originalMimeType)}: ${image.frames} frames, ${image.originalWidth}x${image.originalHeight}; frame 1 shown.`;
|
|
302
293
|
}
|
|
303
294
|
|
|
304
|
-
/** Everything true of the picture that is not in the picture. */
|
|
305
295
|
function noteOf(image: NormalisedImage): string | undefined {
|
|
306
296
|
const notes = [resizeNote(image), animationNote(image)].filter(
|
|
307
297
|
(note) => note !== undefined
|
|
@@ -309,7 +299,7 @@ function noteOf(image: NormalisedImage): string | undefined {
|
|
|
309
299
|
return notes.length === 0 ? undefined : notes.join(" ");
|
|
310
300
|
}
|
|
311
301
|
|
|
312
|
-
/**
|
|
302
|
+
/** A human description of non-image bytes. */
|
|
313
303
|
function describe(bytes: Uint8Array): string {
|
|
314
304
|
if (bytes.length === 0) {
|
|
315
305
|
return "an empty file";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Values are highlight.js language ids
|
|
1
|
+
// Values are highlight.js language ids. Keep import-free: the web bundle uses it.
|
|
2
2
|
|
|
3
3
|
const ALIASES: Readonly<Record<string, string>> = {
|
|
4
4
|
ts: "typescript",
|
|
@@ -77,7 +77,7 @@ const ALIASES: Readonly<Record<string, string>> = {
|
|
|
77
77
|
|
|
78
78
|
const CANONICAL: ReadonlySet<string> = new Set(Object.values(ALIASES));
|
|
79
79
|
|
|
80
|
-
//
|
|
80
|
+
// Unknown names stay undefined: auto-detection paints prose as code.
|
|
81
81
|
function resolve(name: string | undefined): string | undefined {
|
|
82
82
|
if (name === undefined) {
|
|
83
83
|
return undefined;
|
|
@@ -27,12 +27,7 @@ function distance(left: string, right: string): number {
|
|
|
27
27
|
return previous[right.length] ?? 0;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* Damerau–Levenshtein, where a transposition is one edit rather than two, and
|
|
32
|
-
* a pair that cannot reach `max` answers `max + 1` without finishing the
|
|
33
|
-
* matrix — the shape a vocabulary scan wants, since almost every term it asks
|
|
34
|
-
* about is nowhere near.
|
|
35
|
-
*/
|
|
30
|
+
/** Damerau–Levenshtein (a transposition is one edit). Returns `max + 1` early once over `max`. */
|
|
36
31
|
function damerau(left: string, right: string, max: number): number {
|
|
37
32
|
const over = max + 1;
|
|
38
33
|
if (left === right) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const utf8Bom = "\uFEFF";
|
|
2
2
|
const utf8BomBytes = new Uint8Array([0xef, 0xbb, 0xbf]);
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/** A NUL within this many leading bytes marks a file as binary. */
|
|
5
5
|
const binarySniffBytes = 8192;
|
|
6
6
|
|
|
7
7
|
function normalize(content: string): string {
|
|
@@ -201,9 +201,9 @@ export class McpClient {
|
|
|
201
201
|
|
|
202
202
|
private async sendCancellation(
|
|
203
203
|
sessionId: string | undefined,
|
|
204
|
-
requestId: number
|
|
204
|
+
requestId: number
|
|
205
205
|
): Promise<void> {
|
|
206
|
-
if (sessionId === undefined
|
|
206
|
+
if (sessionId === undefined) {
|
|
207
207
|
return;
|
|
208
208
|
}
|
|
209
209
|
|
|
@@ -36,5 +36,5 @@ export function cleanPath(raw: string): string {
|
|
|
36
36
|
return path;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/**
|
|
39
|
+
/** Lenient scan of V4A patch text for renderers; unknown lines are ignored. */
|
|
40
40
|
export const PatchSummary = { firstPath };
|