@iowarp/clio-coder 0.4.7 → 0.4.9
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +111 -0
- package/CONTRIBUTING.md +83 -74
- package/README.md +69 -47
- package/dist/{acp-W3Y3TRHD.js → acp-ZWZCPS2A.js} +15 -15
- package/dist/{agents-J4ICNLQ3.js → agents-LYSOWZUE.js} +61 -59
- package/dist/assets/codewiki.json +1 -1
- package/dist/assets/web-notices/@hono__node-server-LICENSE +21 -0
- package/dist/assets/web-notices/hono-LICENSE +21 -0
- package/dist/{auth-X2UJUMOC.js → auth-WBQGKWQ5.js} +27 -27
- package/dist/background-BUMOBAQN.js +37 -0
- package/dist/{builtins-XLXWWSRF.js → builtins-ODRJOEDI.js} +7 -7
- package/dist/{chunk-C3G5PNUO.js → chunk-2DRRZ57Q.js} +36 -27
- package/dist/chunk-2JBZYUPY.js +105 -0
- package/dist/chunk-2KUBKL63.js +336 -0
- package/dist/chunk-2VBWFXYE.js +198 -0
- package/dist/{chunk-XZ6UFQ52.js → chunk-2X2R3UTH.js} +25 -15
- package/dist/{chunk-M6Z2V6YU.js → chunk-37LW32LZ.js} +5 -5
- package/dist/{chunk-6LRLOJHQ.js → chunk-3AND2EFU.js} +11 -62
- package/dist/{chunk-FQOOGXBH.js → chunk-3RDHGNU7.js} +101 -33
- package/dist/{chunk-D2T66PDV.js → chunk-3SUDBGEI.js} +41 -208
- package/dist/{chunk-5AJPUR72.js → chunk-3TQN67I2.js} +9 -9
- package/dist/{chunk-LBFQMYS3.js → chunk-3U4BL2EV.js} +5 -3
- package/dist/{chunk-UFYNOQK4.js → chunk-3UQADNG2.js} +7 -7
- package/dist/{chunk-V4ZKOKRB.js → chunk-434LRQ6Z.js} +61 -53
- package/dist/{chunk-NO7J45X6.js → chunk-4ATBOFRP.js} +713 -218
- package/dist/{chunk-ECOMVOHP.js → chunk-4DNL43EZ.js} +3 -3
- package/dist/{chunk-WT5TRMO4.js → chunk-4HFJKRGZ.js} +255 -82
- package/dist/{chunk-5A6XR3RJ.js → chunk-555E2WVV.js} +16 -2
- package/dist/{chunk-WURGVOZJ.js → chunk-5RTEFNBP.js} +18 -14
- package/dist/{config-YXARKGTX.js → chunk-64XJW7NT.js} +24 -268
- package/dist/{chunk-24S3DN22.js → chunk-6TKOFFGE.js} +4 -4
- package/dist/{chunk-YKRJTYNP.js → chunk-6UJ7RDI7.js} +4 -4
- package/dist/{chunk-MZNWZUJM.js → chunk-7FBCRWVT.js} +288 -288
- package/dist/{chunk-UA6W4XFJ.js → chunk-7JSOSVLP.js} +2 -2
- package/dist/chunk-7N3OLLSL.js +637 -0
- package/dist/{chunk-KKEYGFX4.js → chunk-7QQRPB2E.js} +11 -11
- package/dist/{chunk-N37QC5FV.js → chunk-A6DULIMH.js} +21 -9
- package/dist/{fleet-decisions-S3PTZV2D.js → chunk-AB3QXXBC.js} +5 -41
- package/dist/chunk-ACCECAH4.js +49 -0
- package/dist/{chunk-CP3HIR5H.js → chunk-AM6CEP2K.js} +20 -19
- package/dist/chunk-AUHVBIDW.js +19 -0
- package/dist/{chunk-BQQ5MXUC.js → chunk-AY4XE6GN.js} +19 -13
- package/dist/{chunk-ISNCCX42.js → chunk-BBA2TAWV.js} +10 -9
- package/dist/chunk-BFPHMSK7.js +169 -0
- package/dist/{chunk-LVFANMOH.js → chunk-BHJMMCXS.js} +4 -4
- package/dist/{chunk-DO7M3LSX.js → chunk-BMNVVKEW.js} +40 -93
- package/dist/{chunk-VTYHHQ57.js → chunk-CTGZCEI6.js} +2 -2
- package/dist/{chunk-RTLNFZMD.js → chunk-DIAJYJYG.js} +3 -3
- package/dist/chunk-EHZRAB4U.js +63 -0
- package/dist/{chunk-KS7ETA3P.js → chunk-EM2DIQAJ.js} +3 -3
- package/dist/{chunk-MNQN3X6Y.js → chunk-ETF4ROKH.js} +5 -5
- package/dist/{chunk-WN552PKN.js → chunk-F2YM3JY4.js} +744 -1134
- package/dist/{chunk-7EEGBKV4.js → chunk-FEBQWHJT.js} +24 -19
- package/dist/{chunk-4QKAITQT.js → chunk-FPS4R2RN.js} +74 -10
- package/dist/chunk-G5R53COU.js +68 -0
- package/dist/chunk-GHXGMFQ5.js +40 -0
- package/dist/{chunk-GFQ7P2UF.js → chunk-GJDRMBDI.js} +10 -10
- package/dist/{chunk-LZBMXNLP.js → chunk-GM4TY6VN.js} +43 -6
- package/dist/{chunk-NCCQ6DVS.js → chunk-GREYLTZ5.js} +8 -8
- package/dist/{chunk-HOX4YZ2K.js → chunk-H2WSCZZT.js} +19 -3
- package/dist/{chunk-3LXJOICS.js → chunk-H6IUCY6Q.js} +2 -2
- package/dist/{chunk-BO4XV5VX.js → chunk-H72DCH3E.js} +95 -206
- package/dist/{chunk-SEDI5K5B.js → chunk-H7TXJR23.js} +20 -20
- package/dist/chunk-HBJQQTKM.js +40 -0
- package/dist/chunk-HCVKSGNZ.js +990 -0
- package/dist/chunk-HVCAY2FH.js +67 -0
- package/dist/{chunk-34XHRVKG.js → chunk-I47EJPYL.js} +3 -3
- package/dist/{chunk-4N2RZ4TO.js → chunk-IALGWTLO.js} +3 -3
- package/dist/{chunk-IQCNVLO6.js → chunk-IALZJE37.js} +10 -7
- package/dist/{chunk-DLIYANB7.js → chunk-IC7JXLOM.js} +16 -11
- package/dist/{chunk-G4LGUTOE.js → chunk-IOSVTTCD.js} +5 -5
- package/dist/{chunk-DBREN25X.js → chunk-IPTPMLA6.js} +8 -3
- package/dist/{chunk-V552WL53.js → chunk-IZZI3SKQ.js} +3 -67
- package/dist/{chunk-TN5FW4XY.js → chunk-JIYWMQZ5.js} +12 -9
- package/dist/{chunk-T7QQBNLH.js → chunk-JKU34ACI.js} +10 -8
- package/dist/chunk-JOBN2YQQ.js +176 -0
- package/dist/chunk-JOL2QRLE.js +152 -0
- package/dist/{chunk-GXIWHXDB.js → chunk-JTR3VSV3.js} +3 -3
- package/dist/{chunk-T334FW2H.js → chunk-JU6MAMRJ.js} +7 -7
- package/dist/chunk-JURMQWVJ.js +15 -0
- package/dist/{chunk-CULVKYTK.js → chunk-K3XN4LZ4.js} +5 -5
- package/dist/{chunk-3T4DXWP6.js → chunk-KIVFXGBM.js} +27 -7
- package/dist/chunk-KKRXONXG.js +43 -0
- package/dist/{chunk-YPRSNUTC.js → chunk-KOAHT3N2.js} +2 -2
- package/dist/chunk-KP5BPXR3.js +73 -0
- package/dist/{chunk-UA3W4FGC.js → chunk-KRJQG47M.js} +6 -6
- package/dist/{chunk-GI5RRMAH.js → chunk-KW6OJ7IY.js} +19 -21
- package/dist/{chunk-A46ILRS2.js → chunk-L3NBWLSN.js} +4 -4
- package/dist/{chunk-MZHXENL7.js → chunk-L4RUTLRL.js} +8 -8
- package/dist/{chunk-P5SC4DLJ.js → chunk-LGTVWPRN.js} +2 -2
- package/dist/{chunk-65BGHOUR.js → chunk-LSQW6KZO.js} +5 -5
- package/dist/{chunk-TZHN5ITX.js → chunk-LWJYOHT3.js} +8 -8
- package/dist/{chunk-U3TPUXOQ.js → chunk-M6YLF66Z.js} +74 -40
- package/dist/chunk-MJ4QEJVT.js +185 -0
- package/dist/{chunk-T4TY5GG3.js → chunk-MO65K5CH.js} +5 -5
- package/dist/{chunk-TZ6UVP2H.js → chunk-MTOZEQHL.js} +8 -8
- package/dist/chunk-MZDPF35R.js +45 -0
- package/dist/{chunk-P4DL2LM5.js → chunk-MZKYVIWW.js} +8 -119
- package/dist/{chunk-KAFMW7WM.js → chunk-NBPA5QM6.js} +2 -2
- package/dist/{chunk-EUEXGXXR.js → chunk-NMBEW4PP.js} +5 -5
- package/dist/{chunk-SELG4SUR.js → chunk-NPLLK3HO.js} +72 -89
- package/dist/{chunk-VCRVEDUC.js → chunk-NSYGPIVW.js} +5 -5
- package/dist/{context-7HJEWTTP.js → chunk-NXTV5OI5.js} +36 -90
- package/dist/{chunk-IMOD2YPV.js → chunk-NYDG4QP4.js} +9 -19
- package/dist/{chunk-6CA2BHOR.js → chunk-OA2GDACN.js} +5 -5
- package/dist/{chunk-A67NR5AT.js → chunk-PJI57EC6.js} +14 -11
- package/dist/{chunk-IJMW64DX.js → chunk-PJJBUGMR.js} +50 -50
- package/dist/{chunk-CPXGJI2A.js → chunk-PNJE7JPS.js} +20 -5
- package/dist/chunk-PP23PZEV.js +1347 -0
- package/dist/chunk-PPIFDSBK.js +409 -0
- package/dist/{chunk-T52TPHYC.js → chunk-PTFISXQO.js} +8 -7
- package/dist/{chunk-C6GEXX4L.js → chunk-QB33Z5S7.js} +5 -5
- package/dist/{chunk-VMATUZB6.js → chunk-QGNII5VC.js} +10 -10
- package/dist/{chunk-TLTGZTXI.js → chunk-QI72X67S.js} +104 -27
- package/dist/chunk-QKHZZFKH.js +98 -0
- package/dist/{chunk-PFLOULP3.js → chunk-RDKX2PME.js} +4 -4
- package/dist/{chunk-B5ZTR6KZ.js → chunk-RL7LJYN4.js} +1 -1
- package/dist/chunk-RPMNIFRY.js +65 -0
- package/dist/{chunk-L3Z5ANCV.js → chunk-RQROVOV3.js} +13 -11
- package/dist/{chunk-6YHPAAZR.js → chunk-S34A7BSP.js} +3 -3
- package/dist/{chunk-5ZSZEYJK.js → chunk-SJETVJHX.js} +2 -2
- package/dist/{chunk-77CZRFTE.js → chunk-SJMNU4ZS.js} +2 -2
- package/dist/chunk-SLLG2G44.js +85 -0
- package/dist/{chunk-GVZFCJHE.js → chunk-SQAZN2V3.js} +48 -22
- package/dist/{chunk-2O2LVQQK.js → chunk-SQBT46OF.js} +2 -2
- package/dist/{chunk-ZGIGW4ZG.js → chunk-TCUOGIL2.js} +5 -5
- package/dist/{chunk-DACXIVVF.js → chunk-TIWPKCVO.js} +5 -5
- package/dist/{chunk-5CMARGPF.js → chunk-UIU7MGZ3.js} +11 -2
- package/dist/chunk-USBBEKHW.js +177 -0
- package/dist/{chunk-WLHX3MM5.js → chunk-V4XJWDHR.js} +21 -11
- package/dist/{chunk-MBJO5VNZ.js → chunk-VPWGADBG.js} +33 -33
- package/dist/{chunk-UUQ5G6EZ.js → chunk-VWFCAK34.js} +6 -6
- package/dist/{chunk-6CB2IL4N.js → chunk-W5RM7YAH.js} +1 -1
- package/dist/{chunk-4MFBBY2Z.js → chunk-W72LLZAV.js} +3 -3
- package/dist/{chunk-4UHVS5T7.js → chunk-WGRDABW7.js} +8 -8
- package/dist/{chunk-XR3XJN2M.js → chunk-WWRV5RJI.js} +4 -4
- package/dist/{chunk-24TOGHPO.js → chunk-X6FLVUM5.js} +4 -4
- package/dist/{chunk-6YA46L5A.js → chunk-XFLSL7BT.js} +2 -2
- package/dist/{chunk-QKWL7SYE.js → chunk-XJZEDCNT.js} +50 -39
- package/dist/{chunk-UWD3JD5X.js → chunk-XLLEL3K7.js} +10 -10
- package/dist/{chunk-2GPGAE5W.js → chunk-XNIZBOFV.js} +15 -1
- package/dist/chunk-XNZWWDC3.js +686 -0
- package/dist/{chunk-WBVKKTUT.js → chunk-XRECG65F.js} +2 -2
- package/dist/chunk-XTQ7MEJG.js +457 -0
- package/dist/{chunk-GEVQNST4.js → chunk-XZWSP67B.js} +2 -2
- package/dist/{chunk-WB7POC6M.js → chunk-Y3M2T5RO.js} +6 -6
- package/dist/{chunk-RXFPB32E.js → chunk-YJCCMYYT.js} +2 -2
- package/dist/{chunk-EUZRMP4Y.js → chunk-YPQOPFP7.js} +20 -20
- package/dist/{chunk-USZA7GWL.js → chunk-YQ3GFEUY.js} +2 -2
- package/dist/{chunk-BAU36233.js → chunk-YQYINEJI.js} +9 -9
- package/dist/{chunk-CE64C5K5.js → chunk-ZF6CV4WZ.js} +1356 -235
- package/dist/{chunk-3XE4NRLF.js → chunk-ZKJU55MX.js} +4 -2
- package/dist/{chunk-IZYTT3CD.js → chunk-ZKQ63XZ5.js} +16 -39
- package/dist/{chunk-6TAATXXH.js → chunk-ZKVMDNAN.js} +7 -7
- package/dist/chunk-ZST3FRCV.js +132 -0
- package/dist/cli/index.js +50 -38
- package/dist/{clio-L2P7S2R2.js → clio-JUDCLNHC.js} +11 -11
- package/dist/clio-context-tools-FT672MNZ.js +136 -0
- package/dist/{code-nav-B5LNX4KU.js → code-nav-7OVCTP2Z.js} +39 -37
- package/dist/{components-63MMQKUT.js → components-OZXZMDWU.js} +11 -11
- package/dist/config-P3ZQVF63.js +275 -0
- package/dist/config-graph-GKAOBAS5.js +160 -0
- package/dist/{configure-LMVQJ46J.js → configure-25LRYZJG.js} +56 -55
- package/dist/context-72VQV7JX.js +73 -0
- package/dist/{context-YG2LZDYZ.js → context-COWRWXP3.js} +89 -83
- package/dist/{context-XSZKKFBW.js → context-WB3D474G.js} +16 -16
- package/dist/{context-clear-AC5NXHM2.js → context-clear-Y4LYMWC6.js} +88 -82
- package/dist/{context-index-KKTPRV5G.js → context-index-W6A4V7OC.js} +4 -4
- package/dist/{context-map-T7ROR5D5.js → context-map-DKL3QT6D.js} +3 -3
- package/dist/{context-working-set-F4Q4J3NS.js → context-working-set-TMZYVC7A.js} +27 -25
- package/dist/data-tool-KMBWKKWR.js +2987 -0
- package/dist/{detail-H73BEF2N.js → detail-4GLROGY5.js} +89 -83
- package/dist/{dispatch-runner-3RY5FSJC.js → dispatch-runner-TR3LBP5P.js} +113 -107
- package/dist/docs-ZK777W2G.js +101 -0
- package/dist/{doctor-EQYJOGUG.js → doctor-WC4OV2OB.js} +76 -73
- package/dist/{eval-4P7O6CCE.js → eval-FUNWJNUJ.js} +88 -73
- package/dist/{eval-inventory-QOYZERXJ.js → eval-inventory-CX24K2JT.js} +5 -60
- package/dist/evals-L73EBHSU.js +104 -0
- package/dist/{evidence-O76QF7TZ.js → evidence-AVJ2RTHX.js} +99 -93
- package/dist/{evidence-D6GUSYJW.js → evidence-P4NZOAK7.js} +88 -82
- package/dist/evidence-Y55WKYHH.js +246 -0
- package/dist/{evolve-H47BCETS.js → evolve-MAWKRYWF.js} +93 -87
- package/dist/{extensions-NNL3ZOCU.js → extensions-PYQH3H47.js} +14 -13
- package/dist/fleet-M4H2QBWT.js +268 -0
- package/dist/{fleet-KMNS6NOM.js → fleet-ULBXXRDR.js} +146 -138
- package/dist/{fleet-commands-DOWSYCBX.js → fleet-commands-7NNC4JZU.js} +18 -17
- package/dist/fleet-decisions-EHEY7KPU.js +52 -0
- package/dist/{fleet-graph-F2DE2TME.js → fleet-graph-LQ2AHZT3.js} +24 -24
- package/dist/{fleet-inspect-EN2Q6IVB.js → fleet-inspect-5IGBIIYZ.js} +98 -258
- package/dist/{fleet-preflight-FRLETDD3.js → fleet-preflight-UTTNOKMG.js} +9 -4
- package/dist/{fleet-validate-B2XDLS57.js → fleet-validate-YGILJKA6.js} +29 -29
- package/dist/{fleet-verify-4JKUWGJ7.js → fleet-verify-AUWTCDKR.js} +88 -82
- package/dist/{fleet-view-BHJFW26B.js → fleet-view-TGUFCY5A.js} +90 -84
- package/dist/{init-XAT5N5YM.js → init-GFN2Z7NF.js} +111 -104
- package/dist/install-6PIF6F6W.js +19 -0
- package/dist/{interop-FVECHFKG.js → interop-EF5JUWWK.js} +29 -29
- package/dist/{inventory-7KFQGLCV.js → inventory-I6VJDDYF.js} +90 -84
- package/dist/library-3J5IO2OJ.js +75 -0
- package/dist/{library-QAPAO23R.js → library-IJTOFTDS.js} +20 -19
- package/dist/{library-NY2XOT75.js → library-Z3KZSHPE.js} +35 -35
- package/dist/{library-import-5Y6MAS3R.js → library-import-IMKFLDHX.js} +29 -29
- package/dist/{library-inventory-JT6HWITQ.js → library-inventory-CQP5D6GU.js} +21 -21
- package/dist/{library-validation-EQUH25DC.js → library-validation-33UTX7AI.js} +19 -19
- package/dist/mcp-5FWZKUS6.js +26 -0
- package/dist/{memory-DYVTTCP6.js → memory-36CWN67Y.js} +93 -87
- package/dist/{models-MASFJ6Y2.js → models-KQ6PQJJQ.js} +57 -56
- package/dist/{monitor-YMP4NXJJ.js → monitor-XX6ZD6KC.js} +98 -91
- package/dist/{orchestrator-AFQRRTEI.js → orchestrator-SK6HDAOP.js} +1537 -832
- package/dist/{panes-NICTHQCV.js → panes-L27QRXUH.js} +14 -14
- package/dist/{panes-D3Y2KFG5.js → panes-LXZIWNOZ.js} +4 -4
- package/dist/{paths-PSFAUIGO.js → paths-7DJDU4P4.js} +6 -6
- package/dist/{preload-5Q7VXRFJ.js → preload-K2TDYI4Y.js} +88 -82
- package/dist/{reset-7NKZK7JN.js → reset-73VU3XNT.js} +13 -13
- package/dist/{resources-NILSIZAT.js → resources-3BYJYVYL.js} +24 -24
- package/dist/{run-BPZGEBZV.js → run-AR7PY6GW.js} +144 -136
- package/dist/run-script-H2KUDIII.js +41 -0
- package/dist/settings-3VMBMWID.js +72 -0
- package/dist/{share-EZ6ERBMH.js → share-HVWH4FPF.js} +30 -30
- package/dist/{skills-BTVVNYVM.js → skills-5TYEY75Q.js} +30 -30
- package/dist/{skills-eval-UY34MNK7.js → skills-eval-CK3MD63Z.js} +114 -103
- package/dist/{skills-inventory-JDHSIA7I.js → skills-inventory-KSFYG3I6.js} +24 -24
- package/dist/{slash-commands-K4FNQ2AT.js → slash-commands-DMVHML7P.js} +60 -57
- package/dist/{steer-2B3EQGFH.js → steer-XCD6V3EW.js} +4 -4
- package/dist/{support-L2SOL3IE.js → support-JAZL6VBR.js} +7 -7
- package/dist/system-3TDQRMZZ.js +116 -0
- package/dist/{targets-44VKGFLN.js → targets-EZKHAYRN.js} +74 -72
- package/dist/{tasks-3KODKFU7.js → tasks-SNEFHWYW.js} +18 -18
- package/dist/{terminal-lease-LXA7MMPO.js → terminal-lease-BNLFA4OF.js} +8 -7
- package/dist/{tools-3UB7TEVR.js → tools-7IM6BDCE.js} +12 -12
- package/dist/{trace-TAMIU4OJ.js → trace-C3MBGD4S.js} +16 -65
- package/dist/{tui-primitives-A6MUW32V.js → tui-primitives-36BY2774.js} +2 -2
- package/dist/{uninstall-QYVRPEM4.js → uninstall-WWLOSZ42.js} +35 -10
- package/dist/{upgrade-7PMKM2JH.js → upgrade-ETK2JNSJ.js} +42 -51
- package/dist/{usage-6EQV7EQK.js → usage-S2HOB7BZ.js} +112 -102
- package/dist/{verifiers-JLITWSHU.js → verifiers-QDTEVH7R.js} +26 -24
- package/dist/{verify-T7NAEVIG.js → verify-SUKUK6XM.js} +16 -15
- package/dist/web/client/THIRD_PARTY_LICENSES.md +1809 -0
- package/dist/web/client/assets/abnfDiagram-VCTEODGH-BznNOe_I.js +1 -0
- package/dist/web/client/assets/arc-Pry-7G1_.js +1 -0
- package/dist/web/client/assets/architecture-7GRP2DOG-BQO9DL_y.js +1 -0
- package/dist/web/client/assets/architectureDiagram-5GKGNRK7-CKPbdvyx.js +36 -0
- package/dist/web/client/assets/array-BifhSqXX.js +1 -0
- package/dist/web/client/assets/atkinson-hyperlegible-next-latin-ext-wght-normal-C6vrW8VD.woff2 +0 -0
- package/dist/web/client/assets/atkinson-hyperlegible-next-latin-wght-normal-BcXVPD7q.woff2 +0 -0
- package/dist/web/client/assets/blockDiagram-I7D4REHJ-prINbpbM.js +129 -0
- package/dist/web/client/assets/c4Diagram-7LVT6UL2-DkVRKtyU.js +38 -0
- package/dist/web/client/assets/channel-c4EeUUqA.js +1 -0
- package/dist/web/client/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist/web/client/assets/chunk-4HAMMTFA-CV0Z1ApC.js +62 -0
- package/dist/web/client/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/dist/web/client/assets/chunk-75Z2AOVW-D34Nohxq.js +2 -0
- package/dist/web/client/assets/chunk-DU6HZSFF-Das_cS-O.js +125 -0
- package/dist/web/client/assets/chunk-F27PBJKO-CmRojxkG.js +1 -0
- package/dist/web/client/assets/chunk-FOHPRMQF-CoA4358r.js +161 -0
- package/dist/web/client/assets/chunk-GMAD6QVW-ClYZmc73.js +72 -0
- package/dist/web/client/assets/chunk-GVQU2GXP-B2BiHFt-.js +1 -0
- package/dist/web/client/assets/chunk-IMKFNOWR-BGApZ8nP.js +231 -0
- package/dist/web/client/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist/web/client/assets/chunk-L3NEJ4N5-DIzCgpkY.js +1 -0
- package/dist/web/client/assets/chunk-OSK3NFVY-BPT-yePv.js +10 -0
- package/dist/web/client/assets/chunk-P2QGCYS3-BC1WTc2t.js +1 -0
- package/dist/web/client/assets/chunk-POPQ4Y6H-BSjzBmZU.js +1 -0
- package/dist/web/client/assets/chunk-PWAF6VOD-BIjLs86Z.js +1 -0
- package/dist/web/client/assets/chunk-SHT3W25Y-CduDz2cm.js +168 -0
- package/dist/web/client/assets/chunk-SVP7TREG-XUn4pPAP.js +88 -0
- package/dist/web/client/assets/chunk-TICWLB2K-DcBy2DKy.js +206 -0
- package/dist/web/client/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
- package/dist/web/client/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist/web/client/assets/classDiagram-ZZMXUADV-C0HR7YKN.js +1 -0
- package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-C0HR7YKN.js +1 -0
- package/dist/web/client/assets/commit-mono-latin-400-normal-s0S3qwFW.woff +0 -0
- package/dist/web/client/assets/commit-mono-latin-400-normal-wzhe4RuD.woff2 +0 -0
- package/dist/web/client/assets/cose-bilkent-JH36ORCC-CVh1icwb.js +1 -0
- package/dist/web/client/assets/cynefin-OW5HDTMX-BecPbyM6.js +1 -0
- package/dist/web/client/assets/cynefinDiagram-5FMLGOSQ-BzMzFwyT.js +62 -0
- package/dist/web/client/assets/cytoscape.esm-c2aL46s-.js +321 -0
- package/dist/web/client/assets/dagre-C-rnJpZF.js +1 -0
- package/dist/web/client/assets/dagre-GXQ25YYZ-CAWJmRMG.js +4 -0
- package/dist/web/client/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/dist/web/client/assets/diagram-S7CK7UJ4--lp0ALmn.js +30 -0
- package/dist/web/client/assets/diagram-UQ7AKVKN-gKUnsjcj.js +41 -0
- package/dist/web/client/assets/diagram-VSXAHHWV-BoN5D1Gh.js +3 -0
- package/dist/web/client/assets/diagram-VX7I27RA-BMtuswQ6.js +24 -0
- package/dist/web/client/assets/diagram-Z3DM3KII-DtU8LXrA.js +24 -0
- package/dist/web/client/assets/dist-v5Q1xZ2K.js +1 -0
- package/dist/web/client/assets/ebnfDiagram-PWID7BFC-DDcnv9BH.js +1 -0
- package/dist/web/client/assets/erDiagram-RLTQ6QDP-DvRb4iDL.js +99 -0
- package/dist/web/client/assets/eventmodeling-NTZA5JFV-01h4SbTc.js +1 -0
- package/dist/web/client/assets/flowDiagram-HODETNUW-Bll_YZ6T.js +1 -0
- package/dist/web/client/assets/framework-YGoR34M4.js +9 -0
- package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-DdFZ9hvH.js +292 -0
- package/dist/web/client/assets/gitGraph-4MIJSDKK-DjD_AAMj.js +1 -0
- package/dist/web/client/assets/gitGraphDiagram-WWUBYQGX-CDyN9n2u.js +106 -0
- package/dist/web/client/assets/graphlib-DS17s2tU.js +1 -0
- package/dist/web/client/assets/index-CVcy0FAn.js +75 -0
- package/dist/web/client/assets/index-Dsi52apB.css +1 -0
- package/dist/web/client/assets/info-A6RAGUB7-C_XK8Hq0.js +1 -0
- package/dist/web/client/assets/infoDiagram-27XIBGKW-DIe4tJ1i.js +2 -0
- package/dist/web/client/assets/init-C-OQMol4.js +1 -0
- package/dist/web/client/assets/ishikawaDiagram-5VMMS53U-CVl5unKI.js +70 -0
- package/dist/web/client/assets/journeyDiagram-3NMN7TZE-CPEB1Vt8.js +139 -0
- package/dist/web/client/assets/kanban-definition-UXKFOSKX-j-9WXjYQ.js +89 -0
- package/dist/web/client/assets/katex-ZlcWpGUi.js +257 -0
- package/dist/web/client/assets/line-BIDAcEtX.js +1 -0
- package/dist/web/client/assets/linear-SzVmGSw4.js +1 -0
- package/dist/web/client/assets/mermaid-parser.core-Ux4vssh0.js +7 -0
- package/dist/web/client/assets/mermaid.core-CDuwVKeh.js +44 -0
- package/dist/web/client/assets/mindmap-definition-YA3MSWOX-5MlQEeQ6.js +96 -0
- package/dist/web/client/assets/newsreader-latin-ext-wght-normal-C-3rgBeH.woff2 +0 -0
- package/dist/web/client/assets/newsreader-latin-wght-normal-CCVVNp6i.woff2 +0 -0
- package/dist/web/client/assets/newsreader-vietnamese-wght-normal-Czsa-EzN.woff2 +0 -0
- package/dist/web/client/assets/ordinal-BDEzSJ7C.js +1 -0
- package/dist/web/client/assets/packet-AYTQ26CC-DRO66c9Q.js +1 -0
- package/dist/web/client/assets/path-fybaL0A-.js +1 -0
- package/dist/web/client/assets/pegDiagram-XKGWAZYB-BakZnSjM.js +1 -0
- package/dist/web/client/assets/pie-WAS4IAKB-BEzcmhz8.js +1 -0
- package/dist/web/client/assets/pieDiagram-E7YTZNPT-DpmqgoPt.js +39 -0
- package/dist/web/client/assets/prism-bash-D6zCJ74D.js +1 -0
- package/dist/web/client/assets/prism-c-04YixN25.js +1 -0
- package/dist/web/client/assets/prism-clike-DapgWyxx.js +1 -0
- package/dist/web/client/assets/prism-core-BtsZdCS6.js +1 -0
- package/dist/web/client/assets/prism-cpp-C-lJbC-6.js +1 -0
- package/dist/web/client/assets/prism-css-CPgOzxXp.js +1 -0
- package/dist/web/client/assets/prism-diff-BF8m0_mq.js +3 -0
- package/dist/web/client/assets/prism-docker-DkT6yOFj.js +1 -0
- package/dist/web/client/assets/prism-fortran-Be5x3y1V.js +1 -0
- package/dist/web/client/assets/prism-go-C_8qAH5n.js +1 -0
- package/dist/web/client/assets/prism-ini-BESK3y0r.js +1 -0
- package/dist/web/client/assets/prism-javascript-BnO-swvr.js +1 -0
- package/dist/web/client/assets/prism-json-Dp_-W-Hv.js +1 -0
- package/dist/web/client/assets/prism-jsx-D-D0NWtC.js +1 -0
- package/dist/web/client/assets/prism-julia-DIjOgiAV.js +1 -0
- package/dist/web/client/assets/prism-latex-DNMbqcH_.js +1 -0
- package/dist/web/client/assets/prism-makefile-CRKWLQ8l.js +1 -0
- package/dist/web/client/assets/prism-markdown-C0FPJ1Iz.js +1 -0
- package/dist/web/client/assets/prism-markup-Cp04rIa1.js +1 -0
- package/dist/web/client/assets/prism-matlab-D-nk08al.js +1 -0
- package/dist/web/client/assets/prism-python-CfiSVtM6.js +1 -0
- package/dist/web/client/assets/prism-r-QmNGR8LX.js +1 -0
- package/dist/web/client/assets/prism-rust-Bu9N8X3N.js +1 -0
- package/dist/web/client/assets/prism-shell-session-Be4UuYoM.js +1 -0
- package/dist/web/client/assets/prism-sql-CYhVDMEE.js +1 -0
- package/dist/web/client/assets/prism-toml-DKb54GAT.js +1 -0
- package/dist/web/client/assets/prism-tsx-p6J2Kc_4.js +1 -0
- package/dist/web/client/assets/prism-typescript-BMqONzxf.js +1 -0
- package/dist/web/client/assets/prism-yaml-C0JHu8gr.js +1 -0
- package/dist/web/client/assets/purify.es-ChwZkWde.js +3 -0
- package/dist/web/client/assets/quadrantDiagram-AXDQQJYC-DuMPwwV2.js +7 -0
- package/dist/web/client/assets/radar-RG4KPBEZ-Djm3oXl5.js +1 -0
- package/dist/web/client/assets/railroad-74A4TZTK-Cpvkwsao.js +1 -0
- package/dist/web/client/assets/railroad-abnf-HS5TGJTU-CpRQ3ruG.js +1 -0
- package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-1Rm5a5eJ.js +1 -0
- package/dist/web/client/assets/railroad-peg-WCYAUIDC-C8344cTh.js +1 -0
- package/dist/web/client/assets/railroadDiagram-O6MQD6OU-CgMS4B6R.js +1 -0
- package/dist/web/client/assets/requirementDiagram-BXWQKSXE-CX5eoNdN.js +84 -0
- package/dist/web/client/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/dist/web/client/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/dist/web/client/assets/sankeyDiagram-P5KCCOFB-CODBX2N3.js +40 -0
- package/dist/web/client/assets/sequenceDiagram-WJ2MYXX4-eUhhF8OR.js +162 -0
- package/dist/web/client/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
- package/dist/web/client/assets/src-B6xuSHsQ.js +1 -0
- package/dist/web/client/assets/stateDiagram-D77RDMKH-vR6l0NC2.js +1 -0
- package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-BYUm8jLY.js +1 -0
- package/dist/web/client/assets/swimlanes-42K2YHIH-v9Tw_zX7.js +1 -0
- package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-B2jdCvhD.js +8 -0
- package/dist/web/client/assets/timeline-definition-24CTP7MA-DxianbhU.js +120 -0
- package/dist/web/client/assets/treeView-Q6P3EWNA-DLxnZb9R.js +1 -0
- package/dist/web/client/assets/treemap-WGGIJYW6-I7UnZ6xJ.js +1 -0
- package/dist/web/client/assets/vennDiagram-4TSXK5OY-Ar7M8Mrj.js +34 -0
- package/dist/web/client/assets/wardley-WFR3VGLG-B8ZSHeDu.js +1 -0
- package/dist/web/client/assets/wardleyDiagram-VM6X3IG4-Qks2FmIn.js +78 -0
- package/dist/web/client/assets/xychartDiagram-S5SC5T6Z-BBBjRtiE.js +7 -0
- package/dist/web/client/clio-coder-logo.webp +0 -0
- package/dist/web/client/icon-192.png +0 -0
- package/dist/web/client/icon-512.png +0 -0
- package/dist/web/client/index.html +6 -0
- package/dist/web/client/manifest.webmanifest +15 -0
- package/dist/web/client/offline.css +55 -0
- package/dist/web/client/offline.html +5 -0
- package/dist/web/client/offline.js +27 -0
- package/dist/web/client/sw.js +34 -0
- package/dist/web/ops-worker.js +37 -0
- package/dist/web/reads-worker.js +1726 -0
- package/dist/web/server.js +8499 -0
- package/dist/web-EMGUGGEI.js +13 -0
- package/dist/{web-fetch-W4TNW4Q7.js → web-fetch-6BRRVQON.js} +22 -5
- package/dist/{wiki-generate-T2TJQJUA.js → wiki-generate-XHSJTDOP.js} +120 -113
- package/dist/{with-panes-CHFC7HGI.js → with-panes-Z6BTEHMZ.js} +12 -12
- package/dist/worker/entry.js +113 -99
- package/docs/README.md +28 -27
- package/docs/architecture/acp.md +5 -9
- package/docs/architecture/alcf-provider.md +0 -3
- package/docs/architecture/architecture.md +0 -3
- package/docs/architecture/artifact-placement.md +12 -4
- package/docs/architecture/artifact-versions.md +0 -3
- package/docs/architecture/capacity-and-scheduling.md +0 -3
- package/docs/architecture/context-engine.md +0 -3
- package/docs/architecture/context-working-set.md +0 -3
- package/docs/architecture/dispatch-architecture-rationale.md +0 -3
- package/docs/architecture/dispatch-typed-intent.md +0 -3
- package/docs/architecture/evidence-and-memory.md +0 -3
- package/docs/architecture/library.md +1 -3
- package/docs/architecture/middleware-and-components.md +0 -3
- package/docs/architecture/model-catalog.md +1 -4
- package/docs/architecture/observability.md +0 -3
- package/docs/architecture/pi-boundary.md +6 -9
- package/docs/architecture/prompt-envelope-and-tools.md +37 -30
- package/docs/architecture/provider-adapter-cookbook.md +1 -4
- package/docs/architecture/safety-model.md +19 -9
- package/docs/architecture/session-lifecycle.md +10 -7
- package/docs/architecture/time-conventions.md +0 -3
- package/docs/architecture/trace-store.md +28 -20
- package/docs/architecture/tui-design.md +38 -18
- package/docs/architecture/worker-context.md +1 -3
- package/docs/architecture/worker-dispatch-mechanics.md +1 -4
- package/docs/guide/authoring-plugins.md +1 -3
- package/docs/guide/built-in-agents.md +0 -3
- package/docs/guide/commands-and-modes.md +41 -25
- package/docs/guide/configuration-and-targets.md +204 -9
- package/docs/guide/configuration-reference.md +125 -17
- package/docs/guide/environment-variables.md +2 -8
- package/docs/guide/exit-codes-and-output.md +0 -3
- package/docs/guide/extensions-and-sharing.md +0 -3
- package/docs/guide/fleet-dispatch.md +3 -5
- package/docs/guide/glossary.md +1 -4
- package/docs/guide/harness-extensions.md +0 -2
- package/docs/guide/installation-and-lifecycle.md +3 -6
- package/docs/guide/interop.md +0 -2
- package/docs/guide/panes-and-files.md +0 -3
- package/docs/guide/plugins.md +0 -3
- package/docs/guide/proactive-memory.md +0 -3
- package/docs/guide/resource-library.md +1 -3
- package/docs/guide/skills-marketplace.md +0 -2
- package/docs/guide/tool-usage.md +166 -67
- package/docs/guide/troubleshooting.md +1 -4
- package/docs/history/config-knobs-audit.md +0 -3
- package/docs/history/release-cut-checklist.md +0 -3
- package/docs/process/development-pipeline.md +0 -3
- package/docs/process/documentation-coverage.md +3 -3
- package/docs/process/documentation-guide.md +16 -22
- package/docs/process/eval-runner.md +0 -3
- package/docs/process/evals-internal.md +0 -3
- package/docs/process/evolution.md +0 -3
- package/docs/process/fleet-demo-runbook.md +6 -9
- package/docs/process/git-commit-provenance.md +0 -3
- package/docs/process/performance-methodology.md +1 -4
- package/docs/process/release-cut-checklist.md +114 -221
- package/docs/process/scientific-validation.md +23 -6
- package/docs/process/tool-audit-v0.4.9.md +357 -0
- package/library/registry.yaml +2 -2
- package/library/skills/meta/clio-coder-test/SKILL.md +25 -15
- package/library/skills/meta/clio-coder-test/evals.md +16 -2
- package/library/skills/meta/clio-coder-test/plugin.json +1 -1
- package/library/skills/meta/clio-coder-test/references/test-map.md +19 -18
- package/library/skills/registry.yaml +2 -2
- package/library/skills/skill-marketplace.json +1 -1
- package/package.json +13 -11
- package/src/cli/argv.ts +31 -0
- package/src/cli/clio.ts +17 -13
- package/src/cli/config.ts +4 -0
- package/src/cli/docs.ts +65 -328
- package/src/cli/doctor-panes.ts +1 -1
- package/src/cli/doctor.ts +3 -1
- package/src/cli/index.ts +17 -2
- package/src/cli/mcp.ts +106 -0
- package/src/cli/skills-eval.ts +8 -2
- package/src/cli/trace.ts +4 -65
- package/src/cli/uninstall.ts +26 -0
- package/src/cli/upgrade.ts +34 -38
- package/src/cli/usage.ts +3 -0
- package/src/cli/verifiers.ts +1 -1
- package/src/cli/web.ts +79 -0
- package/src/core/bash-exec.ts +27 -4
- package/src/core/bus-events.ts +3 -4
- package/src/core/config.ts +73 -1
- package/src/core/defaults.ts +10 -1
- package/src/core/domain-loader.ts +37 -28
- package/src/core/event-bus.ts +1 -1
- package/src/core/run-records.ts +438 -0
- package/src/core/safe-exec.ts +506 -56
- package/src/core/skill-activation.ts +5 -3
- package/src/core/termination.ts +16 -12
- package/src/core/tool-names.ts +33 -12
- package/src/domains/agents/contract.ts +1 -1
- package/src/domains/agents/extension.ts +18 -10
- package/src/domains/config/extension.ts +5 -4
- package/src/domains/context/clio-md.ts +1 -1
- package/src/domains/context/worker/pressure.ts +6 -2
- package/src/domains/context/working-set/path-index.ts +7 -2
- package/src/domains/dispatch/code-step.ts +7 -2
- package/src/domains/dispatch/contract.ts +7 -0
- package/src/domains/dispatch/execution-role.ts +3 -3
- package/src/domains/dispatch/execution-scheduler.ts +204 -79
- package/src/domains/dispatch/extension.ts +206 -26
- package/src/domains/dispatch/fleet-preflight.ts +18 -3
- package/src/domains/dispatch/fleet-run.ts +1 -0
- package/src/domains/dispatch/gate-decisions.ts +3 -3
- package/src/domains/dispatch/heartbeat.ts +1 -1
- package/src/domains/dispatch/host-verification.ts +16 -14
- package/src/domains/dispatch/index.ts +1 -0
- package/src/domains/dispatch/orphan-recovery.ts +1 -0
- package/src/domains/dispatch/receipt-findings.ts +3 -4
- package/src/domains/dispatch/receipt-integrity.ts +3 -0
- package/src/domains/dispatch/reservation-store.ts +7 -9
- package/src/domains/dispatch/route-facts.ts +1 -1
- package/src/domains/dispatch/state.ts +4 -5
- package/src/domains/dispatch/types.ts +3 -1
- package/src/domains/eval/metrics/tracked.ts +22 -2
- package/src/domains/evidence/build.ts +35 -7
- package/src/domains/extensions/operator-runtime.ts +3 -1
- package/src/domains/gateway/mcp/client.ts +923 -0
- package/src/domains/gateway/mcp/config.ts +456 -0
- package/src/domains/gateway/mcp/index.ts +88 -0
- package/src/domains/gateway/mcp/protocol.ts +273 -0
- package/src/domains/gateway/mcp/trust.ts +263 -0
- package/src/domains/lifecycle/doctor.ts +17 -3
- package/src/domains/middleware/hooks.ts +2 -2
- package/src/domains/mux/contract.ts +5 -9
- package/src/domains/mux/detect.ts +1 -1
- package/src/domains/mux/extension.ts +1 -1
- package/src/domains/mux/protocol.ts +5 -7
- package/src/domains/mux/socket-client.ts +3 -3
- package/src/domains/observability/accountability.ts +2 -2
- package/src/domains/observability/background-memory-usage.ts +3 -0
- package/src/domains/observability/compaction-usage.ts +2 -0
- package/src/domains/observability/contract.ts +7 -3
- package/src/domains/observability/cost.ts +5 -0
- package/src/domains/observability/evidence-index.ts +2 -2
- package/src/domains/observability/extension.ts +1 -0
- package/src/domains/observability/out-of-turn-usage.ts +2 -0
- package/src/domains/observability/projection.ts +10 -0
- package/src/domains/observability/trace-store.ts +65 -5
- package/src/domains/prompts/compiler.ts +41 -23
- package/src/domains/prompts/extension.ts +4 -17
- package/src/domains/prompts/fragments/identity/docs-routing.md +2 -2
- package/src/domains/prompts/fragments/operating/skills.md +12 -10
- package/src/domains/providers/cache-deployment.ts +147 -0
- package/src/domains/providers/catalog.ts +12 -7
- package/src/domains/providers/extension.ts +27 -5
- package/src/domains/providers/index.ts +6 -1
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +42 -10
- package/src/domains/providers/plugins.ts +3 -13
- package/src/domains/providers/probe/http.ts +44 -59
- package/src/domains/providers/probe/reasoning.ts +2 -0
- package/src/domains/providers/runtimes/common/local-synth.ts +4 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +20 -31
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +9 -4
- package/src/domains/providers/types/target-descriptor.ts +17 -0
- package/src/domains/safety/action-classifier.ts +17 -1
- package/src/domains/safety/call-target.ts +14 -0
- package/src/domains/safety/contract.ts +1 -1
- package/src/domains/safety/finish-contract.ts +9 -3
- package/src/domains/safety/loop-detector.ts +1 -1
- package/src/domains/safety/policy-engine.ts +7 -0
- package/src/domains/safety/protected-artifacts.ts +3 -4
- package/src/domains/safety/rejection-feedback.ts +1 -1
- package/src/domains/safety/scope.ts +2 -3
- package/src/domains/safety/validation-contract.ts +3 -2
- package/src/domains/scheduling/budget.ts +5 -3
- package/src/domains/scheduling/contract.ts +2 -1
- package/src/domains/scheduling/extension.ts +3 -3
- package/src/domains/session/compaction/branch-summary.ts +1 -1
- package/src/domains/session/compaction/compact.ts +29 -3
- package/src/domains/session/compaction/cut-point.ts +1 -1
- package/src/domains/session/compaction/tokens.ts +5 -10
- package/src/domains/session/contract.ts +1 -1
- package/src/domains/session/cwd-fallback.ts +2 -2
- package/src/domains/session/entries.ts +1 -0
- package/src/domains/session/handoff.ts +5 -1
- package/src/domains/session/history.ts +6 -0
- package/src/domains/session/manager.ts +14 -7
- package/src/domains/session/retry.ts +2 -1
- package/src/domains/session/session-artifacts.ts +12 -7
- package/src/domains/session/task-board.ts +2 -3
- package/src/domains/session/usage.ts +6 -7
- package/src/engine/acp/server.ts +11 -0
- package/src/engine/ai.ts +2 -0
- package/src/engine/apis/openai-completions.ts +17 -4
- package/src/engine/loop-guard.ts +7 -0
- package/src/engine/prewarm.ts +232 -0
- package/src/engine/provider-diagnostics.ts +6 -1
- package/src/engine/provider-error-body.ts +65 -0
- package/src/engine/session.ts +118 -29
- package/src/engine/worker-runtime.ts +3 -0
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +38 -18
- package/src/interactive/chat-loop-messages.ts +3 -0
- package/src/interactive/chat-loop-policy.ts +1 -0
- package/src/interactive/chat-loop.ts +10 -12
- package/src/interactive/chat-panel.ts +23 -9
- package/src/interactive/chat-renderer.ts +33 -11
- package/src/interactive/clio-editor.ts +13 -5
- package/src/interactive/dispatch-board.ts +70 -30
- package/src/interactive/editor-submit.ts +30 -25
- package/src/interactive/footer/widgets.ts +12 -9
- package/src/interactive/interactive-presentation.ts +2 -3
- package/src/interactive/mux-bridge.ts +3 -7
- package/src/interactive/overlay-general-openers.ts +14 -7
- package/src/interactive/overlays/cwd-fallback.ts +1 -1
- package/src/interactive/overlays/library-model.ts +114 -35
- package/src/interactive/overlays/library.ts +52 -5
- package/src/interactive/overlays/list-overlay.ts +4 -1
- package/src/interactive/overlays/session-selector.ts +28 -23
- package/src/interactive/overlays/settings.ts +20 -1
- package/src/interactive/overlays/tree-selector.ts +47 -10
- package/src/interactive/panes-runtime.ts +1 -1
- package/src/interactive/prewarm.ts +11 -197
- package/src/interactive/renderers/compaction-summary.ts +1 -1
- package/src/interactive/renderers/provider-error.ts +118 -0
- package/src/interactive/renderers/retry-status.ts +59 -23
- package/src/interactive/renderers/tool-execution.ts +67 -7
- package/src/interactive/renderers/worker-answer.ts +198 -0
- package/src/interactive/renderers/worker-entry.ts +57 -163
- package/src/interactive/session-usage-reseed.ts +2 -0
- package/src/interactive/side-question.ts +2 -0
- package/src/interactive/slash-commands.ts +26 -1
- package/src/interactive/slash-spec.ts +2 -2
- package/src/interactive/theme/labels.ts +66 -30
- package/src/interactive/turn-context.ts +1 -0
- package/src/interactive/turn-persistence.ts +9 -1
- package/src/interactive/turn-prewarm.ts +126 -19
- package/src/interactive/turn-recovery.ts +2 -1
- package/src/interactive/turn-runtime.ts +36 -5
- package/src/interactive/view/artifacts.ts +3 -2
- package/src/interactive/view/view-overlay.ts +96 -20
- package/src/tools/agent-tools.ts +21 -7
- package/src/tools/artifact.ts +16 -8
- package/src/tools/bash.ts +90 -11
- package/src/tools/bootstrap.ts +42 -4
- package/src/tools/builtin-tool-catalog.ts +80 -11
- package/src/tools/context/index.ts +27 -31
- package/src/tools/context/library.ts +3 -1
- package/src/tools/context/surface.ts +12 -26
- package/src/tools/core-bootstrap.ts +72 -1
- package/src/tools/data/csv.ts +1189 -0
- package/src/tools/data/index.ts +308 -0
- package/src/tools/data/json.ts +1799 -0
- package/src/tools/data/jsonl.ts +561 -0
- package/src/tools/data/shared.ts +452 -0
- package/src/tools/edit-diff.ts +0 -7
- package/src/tools/edit.ts +115 -18
- package/src/tools/file-mutation-queue.ts +114 -4
- package/src/tools/find.ts +108 -29
- package/src/tools/gateway/caps.ts +11 -0
- package/src/tools/gateway/clio-context-surface.ts +41 -0
- package/src/tools/gateway/clio-context-tools.ts +77 -0
- package/src/tools/gateway/data-surface.ts +138 -0
- package/src/tools/gateway/data-tool.ts +201 -0
- package/src/tools/gateway/index.ts +342 -0
- package/src/tools/gateway/mcp-capabilities.ts +469 -0
- package/src/tools/grep.ts +88 -33
- package/src/tools/harness-extensions.ts +3 -0
- package/src/tools/ignore-policy.ts +7 -5
- package/src/tools/ls.ts +111 -20
- package/src/tools/policy.ts +35 -13
- package/src/tools/presentation.ts +6 -0
- package/src/tools/read.ts +634 -156
- package/src/tools/registry.ts +106 -8
- package/src/tools/run-script.ts +997 -0
- package/src/tools/spawn-hygiene.ts +157 -5
- package/src/tools/surface.ts +163 -0
- package/src/tools/verify/authoring.ts +8 -3
- package/src/tools/verify/catalog.ts +14 -1
- package/src/tools/verify/numeric.ts +367 -59
- package/src/tools/verify/perf.ts +171 -9
- package/src/tools/verify/scripts.ts +178 -26
- package/src/tools/web-fetch-surface.ts +22 -0
- package/src/tools/web-fetch.ts +26 -1
- package/src/tools/write.ts +45 -19
- package/src/worker/spec-contract.ts +27 -0
- package/dist/chunk-B6UM3OZC.js +0 -15
- package/dist/chunk-GJ24ODAX.js +0 -196
- package/dist/chunk-HRAKUPIH.js +0 -57
- package/dist/docs-BL7ROUFN.js +0 -292
|
@@ -0,0 +1,2987 @@
|
|
|
1
|
+
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
DATA_FORMATS,
|
|
4
|
+
DATA_OPS,
|
|
5
|
+
DATA_TOOL_NAME,
|
|
6
|
+
DataRefusalError,
|
|
7
|
+
MAX_NUMBER_LITERAL_CHARS,
|
|
8
|
+
capText,
|
|
9
|
+
classifyCell,
|
|
10
|
+
cutView,
|
|
11
|
+
dataToolSurface,
|
|
12
|
+
emptyCellHistogram,
|
|
13
|
+
exactView,
|
|
14
|
+
headerArg,
|
|
15
|
+
histogramRecord,
|
|
16
|
+
inferColumnType,
|
|
17
|
+
isDataFormat,
|
|
18
|
+
isDataRefusal,
|
|
19
|
+
numberLiteralPrecision,
|
|
20
|
+
prepareDataAdmissionArguments,
|
|
21
|
+
prepareDataArguments,
|
|
22
|
+
refusal,
|
|
23
|
+
refusalFromError,
|
|
24
|
+
resolveMaxRows,
|
|
25
|
+
sampledNotice,
|
|
26
|
+
sampledView,
|
|
27
|
+
statDataFile,
|
|
28
|
+
streamTextChunks,
|
|
29
|
+
throwIfAborted
|
|
30
|
+
} from "./chunk-PPIFDSBK.js";
|
|
31
|
+
import {
|
|
32
|
+
DATA_OBSERVATION_SELF_CAP_BYTES
|
|
33
|
+
} from "./chunk-JURMQWVJ.js";
|
|
34
|
+
import {
|
|
35
|
+
commitObservationReservation,
|
|
36
|
+
finalizeObservation,
|
|
37
|
+
observationBudgetExhausted,
|
|
38
|
+
releaseObservation,
|
|
39
|
+
reserveObservation
|
|
40
|
+
} from "./chunk-ZKQ63XZ5.js";
|
|
41
|
+
import "./chunk-IC7JXLOM.js";
|
|
42
|
+
import "./chunk-X6FLVUM5.js";
|
|
43
|
+
import "./chunk-GHXGMFQ5.js";
|
|
44
|
+
import "./chunk-KECNXMDE.js";
|
|
45
|
+
import "./chunk-WXA2CFJO.js";
|
|
46
|
+
import {
|
|
47
|
+
resolveToCwd
|
|
48
|
+
} from "./chunk-KP5BPXR3.js";
|
|
49
|
+
import "./chunk-5EQO5NWP.js";
|
|
50
|
+
import "./chunk-H2WSCZZT.js";
|
|
51
|
+
import "./chunk-SQBT46OF.js";
|
|
52
|
+
import "./chunk-KQ6IDQIB.js";
|
|
53
|
+
import "./chunk-H72DCH3E.js";
|
|
54
|
+
import "./chunk-2KUBKL63.js";
|
|
55
|
+
import "./chunk-MYI32N4R.js";
|
|
56
|
+
import "./chunk-R2P2U3ZS.js";
|
|
57
|
+
import "./chunk-NTTS3O53.js";
|
|
58
|
+
import "./chunk-M4KFUXS7.js";
|
|
59
|
+
import "./chunk-V4XJWDHR.js";
|
|
60
|
+
import "./chunk-C27U2TYG.js";
|
|
61
|
+
import "./chunk-B5GGDIHT.js";
|
|
62
|
+
import "./chunk-UIU7MGZ3.js";
|
|
63
|
+
import "./chunk-DXVMLM3Z.js";
|
|
64
|
+
import "./chunk-XTQ7MEJG.js";
|
|
65
|
+
import "./chunk-LTR5QCLS.js";
|
|
66
|
+
import "./chunk-6EXUUOSN.js";
|
|
67
|
+
import "./chunk-ZTNFYMIO.js";
|
|
68
|
+
import "./chunk-O3VV6IVK.js";
|
|
69
|
+
import "./chunk-DVJL77SO.js";
|
|
70
|
+
import "./chunk-GH5ZR6JP.js";
|
|
71
|
+
import "./chunk-TK2BMCBZ.js";
|
|
72
|
+
import "./chunk-CTTI7G3T.js";
|
|
73
|
+
import "./chunk-ZZFWWYLX.js";
|
|
74
|
+
import "./chunk-E3LEPLQ2.js";
|
|
75
|
+
import {
|
|
76
|
+
init_esm_shims
|
|
77
|
+
} from "./chunk-ECBHH7LU.js";
|
|
78
|
+
|
|
79
|
+
// src/tools/gateway/data-tool.ts
|
|
80
|
+
init_esm_shims();
|
|
81
|
+
import path from "node:path";
|
|
82
|
+
|
|
83
|
+
// src/tools/data/index.ts
|
|
84
|
+
init_esm_shims();
|
|
85
|
+
import { open } from "node:fs/promises";
|
|
86
|
+
import { extname } from "node:path";
|
|
87
|
+
|
|
88
|
+
// src/tools/data/csv.ts
|
|
89
|
+
init_esm_shims();
|
|
90
|
+
var CHAR_QUOTE = 34;
|
|
91
|
+
var CHAR_LF = 10;
|
|
92
|
+
var CHAR_CR = 13;
|
|
93
|
+
var CSV_MAX_FIELD_CHARS = 1048576;
|
|
94
|
+
var CSV_MAX_RECORD_CHARS = 16 * 1048576;
|
|
95
|
+
var CsvParser = class {
|
|
96
|
+
constructor(delimiter, callbacks) {
|
|
97
|
+
this.delimiter = delimiter;
|
|
98
|
+
this.callbacks = callbacks;
|
|
99
|
+
}
|
|
100
|
+
delimiter;
|
|
101
|
+
callbacks;
|
|
102
|
+
state = 0 /* FieldStart */;
|
|
103
|
+
fields = [];
|
|
104
|
+
current = "";
|
|
105
|
+
recordChars = 0;
|
|
106
|
+
hasContent = false;
|
|
107
|
+
skipLf = false;
|
|
108
|
+
line = 1;
|
|
109
|
+
recordLine = 1;
|
|
110
|
+
records = 0;
|
|
111
|
+
stopped = false;
|
|
112
|
+
issueThisRecord = null;
|
|
113
|
+
blankLines = 0;
|
|
114
|
+
crlf = 0;
|
|
115
|
+
lf = 0;
|
|
116
|
+
cr = 0;
|
|
117
|
+
get isStopped() {
|
|
118
|
+
return this.stopped;
|
|
119
|
+
}
|
|
120
|
+
get recordCount() {
|
|
121
|
+
return this.records;
|
|
122
|
+
}
|
|
123
|
+
/** Feed one chunk. Returns false once the record sink asked to stop. */
|
|
124
|
+
push(text) {
|
|
125
|
+
if (this.stopped) return false;
|
|
126
|
+
const length = text.length;
|
|
127
|
+
let runStart = this.state === 1 /* Unquoted */ || this.state === 2 /* Quoted */ ? 0 : -1;
|
|
128
|
+
for (let index = 0; index < length; index += 1) {
|
|
129
|
+
const code = text.charCodeAt(index);
|
|
130
|
+
if (this.skipLf) {
|
|
131
|
+
this.skipLf = false;
|
|
132
|
+
if (code === CHAR_LF) {
|
|
133
|
+
this.crlf += 1;
|
|
134
|
+
this.cr -= 1;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
switch (this.state) {
|
|
139
|
+
case 0 /* FieldStart */:
|
|
140
|
+
if (code === CHAR_QUOTE) {
|
|
141
|
+
this.state = 2 /* Quoted */;
|
|
142
|
+
this.hasContent = true;
|
|
143
|
+
runStart = index + 1;
|
|
144
|
+
} else if (code === this.delimiter) {
|
|
145
|
+
this.hasContent = true;
|
|
146
|
+
this.pushField("");
|
|
147
|
+
} else if (code === CHAR_LF || code === CHAR_CR) {
|
|
148
|
+
if (this.hasContent) this.pushField("");
|
|
149
|
+
this.newline(code);
|
|
150
|
+
this.endRecord();
|
|
151
|
+
} else {
|
|
152
|
+
this.state = 1 /* Unquoted */;
|
|
153
|
+
this.hasContent = true;
|
|
154
|
+
runStart = index;
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
case 1 /* Unquoted */:
|
|
158
|
+
if (code === this.delimiter) {
|
|
159
|
+
const fits = this.appendRun(text, runStart, index);
|
|
160
|
+
runStart = -1;
|
|
161
|
+
if (!fits) break;
|
|
162
|
+
this.pushField(this.current);
|
|
163
|
+
this.current = "";
|
|
164
|
+
if (this.state === 1 /* Unquoted */) this.state = 0 /* FieldStart */;
|
|
165
|
+
} else if (code === CHAR_LF || code === CHAR_CR) {
|
|
166
|
+
const fits = this.appendRun(text, runStart, index);
|
|
167
|
+
runStart = -1;
|
|
168
|
+
if (!fits) {
|
|
169
|
+
this.closeOverflow(code);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
this.pushField(this.current);
|
|
173
|
+
this.current = "";
|
|
174
|
+
this.state = 0 /* FieldStart */;
|
|
175
|
+
this.newline(code);
|
|
176
|
+
this.endRecord();
|
|
177
|
+
} else if (code === CHAR_QUOTE) {
|
|
178
|
+
this.issue("bare-quote", "a quote inside an unquoted field was read as literal text");
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case 2 /* Quoted */:
|
|
182
|
+
if (code === CHAR_QUOTE) {
|
|
183
|
+
const fits = this.appendRun(text, runStart, index);
|
|
184
|
+
runStart = -1;
|
|
185
|
+
if (fits) this.state = 3 /* QuoteInQuoted */;
|
|
186
|
+
} else if (code === CHAR_LF || code === CHAR_CR) {
|
|
187
|
+
const pending = index - runStart;
|
|
188
|
+
if (this.current.length + pending > CSV_MAX_FIELD_CHARS || this.recordChars + pending > CSV_MAX_RECORD_CHARS) {
|
|
189
|
+
this.appendRun(text, runStart, index);
|
|
190
|
+
runStart = -1;
|
|
191
|
+
this.closeOverflow(code);
|
|
192
|
+
} else if (code === CHAR_LF) {
|
|
193
|
+
this.line += 1;
|
|
194
|
+
this.lf += 1;
|
|
195
|
+
} else {
|
|
196
|
+
this.line += 1;
|
|
197
|
+
this.cr += 1;
|
|
198
|
+
this.skipLf = true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
case 3 /* QuoteInQuoted */:
|
|
203
|
+
if (code === CHAR_QUOTE) {
|
|
204
|
+
if (this.appendRun('"', 0, 1)) {
|
|
205
|
+
this.state = 2 /* Quoted */;
|
|
206
|
+
runStart = index + 1;
|
|
207
|
+
}
|
|
208
|
+
} else if (code === this.delimiter) {
|
|
209
|
+
this.pushField(this.current);
|
|
210
|
+
this.current = "";
|
|
211
|
+
if (this.state === 3 /* QuoteInQuoted */) this.state = 0 /* FieldStart */;
|
|
212
|
+
} else if (code === CHAR_LF || code === CHAR_CR) {
|
|
213
|
+
this.pushField(this.current);
|
|
214
|
+
this.current = "";
|
|
215
|
+
this.state = 0 /* FieldStart */;
|
|
216
|
+
this.newline(code);
|
|
217
|
+
this.endRecord();
|
|
218
|
+
} else {
|
|
219
|
+
this.issue("text-after-quote", "text after a closing quote was joined to the field");
|
|
220
|
+
this.state = 1 /* Unquoted */;
|
|
221
|
+
runStart = index;
|
|
222
|
+
}
|
|
223
|
+
break;
|
|
224
|
+
case 4 /* Overflow */:
|
|
225
|
+
if (code === CHAR_LF || code === CHAR_CR) this.closeOverflow(code);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
if (this.stopped) return false;
|
|
229
|
+
}
|
|
230
|
+
if (runStart >= 0 && (this.state === 1 /* Unquoted */ || this.state === 2 /* Quoted */)) {
|
|
231
|
+
this.appendRun(text, runStart, length);
|
|
232
|
+
}
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
end() {
|
|
236
|
+
if (this.stopped) return;
|
|
237
|
+
switch (this.state) {
|
|
238
|
+
case 2 /* Quoted */:
|
|
239
|
+
this.issue("unterminated-quote", "the file ended inside a quoted field");
|
|
240
|
+
this.fields.push(this.current);
|
|
241
|
+
this.endRecord();
|
|
242
|
+
break;
|
|
243
|
+
case 3 /* QuoteInQuoted */:
|
|
244
|
+
case 1 /* Unquoted */:
|
|
245
|
+
case 4 /* Overflow */:
|
|
246
|
+
this.fields.push(this.current);
|
|
247
|
+
this.endRecord();
|
|
248
|
+
break;
|
|
249
|
+
default:
|
|
250
|
+
if (this.hasContent) {
|
|
251
|
+
this.fields.push("");
|
|
252
|
+
this.endRecord();
|
|
253
|
+
}
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
this.current = "";
|
|
257
|
+
this.state = 0 /* FieldStart */;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Append text[from, to) to the current field within the caps. Returns false
|
|
261
|
+
* when a cap was hit: the field keeps what fit and the parser is in the
|
|
262
|
+
* Overflow state, dropping input until the record's next line break.
|
|
263
|
+
*/
|
|
264
|
+
appendRun(text, from, to) {
|
|
265
|
+
if (to <= from) return true;
|
|
266
|
+
const run = to - from;
|
|
267
|
+
const fieldRoom = CSV_MAX_FIELD_CHARS - this.current.length;
|
|
268
|
+
const recordRoom = CSV_MAX_RECORD_CHARS - this.recordChars;
|
|
269
|
+
const room = Math.min(fieldRoom, recordRoom);
|
|
270
|
+
if (run <= room) {
|
|
271
|
+
this.current += text.slice(from, to);
|
|
272
|
+
this.recordChars += run;
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
if (room > 0) {
|
|
276
|
+
this.current += text.slice(from, from + room);
|
|
277
|
+
this.recordChars += room;
|
|
278
|
+
}
|
|
279
|
+
this.overflow(fieldRoom <= recordRoom ? "field-too-large" : "record-too-large");
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
/** Complete a field; each field also costs one character of the record cap. */
|
|
283
|
+
pushField(value) {
|
|
284
|
+
this.fields.push(value);
|
|
285
|
+
this.recordChars += 1;
|
|
286
|
+
if (this.recordChars > CSV_MAX_RECORD_CHARS) this.overflow("record-too-large");
|
|
287
|
+
}
|
|
288
|
+
overflow(kind) {
|
|
289
|
+
const message = kind === "field-too-large" ? `a field exceeded ${CSV_MAX_FIELD_CHARS} characters${this.state === 2 /* Quoted */ ? " inside quotes, likely an unterminated quote" : ""}; it was cut at the cap and the record was closed at the next line break` : `a record exceeded ${CSV_MAX_RECORD_CHARS} characters; it was cut at the cap and closed at the next line break`;
|
|
290
|
+
this.issue(kind, message);
|
|
291
|
+
this.state = 4 /* Overflow */;
|
|
292
|
+
}
|
|
293
|
+
closeOverflow(code) {
|
|
294
|
+
this.fields.push(this.current);
|
|
295
|
+
this.current = "";
|
|
296
|
+
this.state = 0 /* FieldStart */;
|
|
297
|
+
this.newline(code);
|
|
298
|
+
this.endRecord();
|
|
299
|
+
}
|
|
300
|
+
newline(code) {
|
|
301
|
+
this.line += 1;
|
|
302
|
+
if (code === CHAR_CR) {
|
|
303
|
+
this.cr += 1;
|
|
304
|
+
this.skipLf = true;
|
|
305
|
+
} else {
|
|
306
|
+
this.lf += 1;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
endRecord() {
|
|
310
|
+
const startLine = this.recordLine;
|
|
311
|
+
this.recordLine = this.line;
|
|
312
|
+
this.recordChars = 0;
|
|
313
|
+
if (!this.hasContent && this.fields.length === 0) {
|
|
314
|
+
this.blankLines += 1;
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
this.records += 1;
|
|
318
|
+
const fields = this.fields;
|
|
319
|
+
this.fields = [];
|
|
320
|
+
this.hasContent = false;
|
|
321
|
+
this.issueThisRecord = null;
|
|
322
|
+
if (!this.callbacks.onRecord(fields, this.records, startLine)) this.stopped = true;
|
|
323
|
+
}
|
|
324
|
+
issue(kind, message) {
|
|
325
|
+
if (this.issueThisRecord === kind) return;
|
|
326
|
+
this.issueThisRecord = kind;
|
|
327
|
+
this.callbacks.onIssue({ kind, record: this.records + 1, line: this.recordLine, message });
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
var CSV_DELIMITER_CANDIDATES = [",", " ", ";", "|"];
|
|
331
|
+
var DELIMITER_SAMPLE_CHARS = 64 * 1024;
|
|
332
|
+
var DELIMITER_SAMPLE_RECORDS = 200;
|
|
333
|
+
function detectCsvDelimiter(sample, sampleComplete) {
|
|
334
|
+
let best = { delimiter: ",", confidence: 0, fieldCount: 1 };
|
|
335
|
+
for (const candidate of CSV_DELIMITER_CANDIDATES) {
|
|
336
|
+
const counts = [];
|
|
337
|
+
const parser = new CsvParser(candidate.charCodeAt(0), {
|
|
338
|
+
onRecord(fields) {
|
|
339
|
+
counts.push(fields.length);
|
|
340
|
+
return counts.length < DELIMITER_SAMPLE_RECORDS;
|
|
341
|
+
},
|
|
342
|
+
onIssue() {
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
parser.push(sample);
|
|
346
|
+
if (sampleComplete) parser.end();
|
|
347
|
+
const usable = sampleComplete || parser.isStopped ? counts : counts.slice(0, -1);
|
|
348
|
+
if (usable.length === 0) continue;
|
|
349
|
+
const tally = /* @__PURE__ */ new Map();
|
|
350
|
+
for (const count of usable) tally.set(count, (tally.get(count) ?? 0) + 1);
|
|
351
|
+
let modal = 1;
|
|
352
|
+
let modalHits = 0;
|
|
353
|
+
for (const [count, hits] of tally) {
|
|
354
|
+
if (hits > modalHits || hits === modalHits && count > modal) {
|
|
355
|
+
modal = count;
|
|
356
|
+
modalHits = hits;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (modal < 2) continue;
|
|
360
|
+
const confidence = modalHits / usable.length;
|
|
361
|
+
if (confidence > best.confidence) best = { delimiter: candidate, confidence, fieldCount: modal };
|
|
362
|
+
}
|
|
363
|
+
return best;
|
|
364
|
+
}
|
|
365
|
+
function headerLooksLikeNames(record) {
|
|
366
|
+
return record.length > 0 && record.every((cell) => cell.trim().length > 0 && classifyCell(cell.trim()) === "string");
|
|
367
|
+
}
|
|
368
|
+
function defaultColumnName(index) {
|
|
369
|
+
return `column_${index + 1}`;
|
|
370
|
+
}
|
|
371
|
+
var CSV_DEFAULT_SAMPLE_ROWS = 10;
|
|
372
|
+
var CSV_DEFAULT_MAX_ROWS = 1e5;
|
|
373
|
+
var COLUMN_TRACK_CAP = 1e4;
|
|
374
|
+
var FIRST_ISSUES_CAP = 10;
|
|
375
|
+
var SAMPLE_VALUES_CAP = 5;
|
|
376
|
+
function newColumn(index, name) {
|
|
377
|
+
return {
|
|
378
|
+
index,
|
|
379
|
+
name,
|
|
380
|
+
nonEmpty: 0,
|
|
381
|
+
empty: 0,
|
|
382
|
+
sentinels: /* @__PURE__ */ new Map(),
|
|
383
|
+
types: emptyCellHistogram(),
|
|
384
|
+
samples: [],
|
|
385
|
+
minLength: Number.POSITIVE_INFINITY,
|
|
386
|
+
maxLength: 0,
|
|
387
|
+
intMin: null,
|
|
388
|
+
intMax: null,
|
|
389
|
+
intMinText: "",
|
|
390
|
+
intMaxText: "",
|
|
391
|
+
floatMin: Number.POSITIVE_INFINITY,
|
|
392
|
+
floatMax: Number.NEGATIVE_INFINITY,
|
|
393
|
+
floatMinText: "",
|
|
394
|
+
floatMaxText: "",
|
|
395
|
+
floatApproximate: false,
|
|
396
|
+
precisionIssues: 0
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function accumulateCell(column, cell) {
|
|
400
|
+
const cls = classifyCell(cell);
|
|
401
|
+
column.types[cls] += 1;
|
|
402
|
+
if (cls === "empty") {
|
|
403
|
+
column.empty += 1;
|
|
404
|
+
column.minLength = 0;
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
column.nonEmpty += 1;
|
|
408
|
+
column.minLength = Math.min(column.minLength, cell.length);
|
|
409
|
+
column.maxLength = Math.max(column.maxLength, cell.length);
|
|
410
|
+
if (cls === "sentinel") {
|
|
411
|
+
column.sentinels.set(cell, (column.sentinels.get(cell) ?? 0) + 1);
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
if (column.samples.length < SAMPLE_VALUES_CAP && !column.samples.includes(cell)) column.samples.push(cell);
|
|
415
|
+
if (cls === "integer") {
|
|
416
|
+
const value = BigInt(cell);
|
|
417
|
+
if (column.intMin === null || value < column.intMin) {
|
|
418
|
+
column.intMin = value;
|
|
419
|
+
column.intMinText = cell;
|
|
420
|
+
}
|
|
421
|
+
if (column.intMax === null || value > column.intMax) {
|
|
422
|
+
column.intMax = value;
|
|
423
|
+
column.intMaxText = cell;
|
|
424
|
+
}
|
|
425
|
+
const precision = numberLiteralPrecision(cell);
|
|
426
|
+
if (precision !== null) column.precisionIssues += 1;
|
|
427
|
+
return precision;
|
|
428
|
+
}
|
|
429
|
+
if (cls === "float") {
|
|
430
|
+
const value = Number(cell);
|
|
431
|
+
const precision = numberLiteralPrecision(cell);
|
|
432
|
+
if (precision !== null) {
|
|
433
|
+
column.precisionIssues += 1;
|
|
434
|
+
column.floatApproximate = true;
|
|
435
|
+
}
|
|
436
|
+
if (Number.isFinite(value)) {
|
|
437
|
+
if (value < column.floatMin) {
|
|
438
|
+
column.floatMin = value;
|
|
439
|
+
column.floatMinText = cell;
|
|
440
|
+
}
|
|
441
|
+
if (value > column.floatMax) {
|
|
442
|
+
column.floatMax = value;
|
|
443
|
+
column.floatMaxText = cell;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return precision;
|
|
447
|
+
}
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
function numericRange(column) {
|
|
451
|
+
const hasInt = column.intMin !== null && column.intMax !== null;
|
|
452
|
+
const hasFloat = Number.isFinite(column.floatMin);
|
|
453
|
+
if (!hasInt && !hasFloat) return void 0;
|
|
454
|
+
if (hasInt && !hasFloat) return { min: column.intMinText, max: column.intMaxText, approximate: false };
|
|
455
|
+
if (!hasInt) return { min: column.floatMinText, max: column.floatMaxText, approximate: column.floatApproximate };
|
|
456
|
+
const intMinNumber = Number(column.intMin);
|
|
457
|
+
const intMaxNumber = Number(column.intMax);
|
|
458
|
+
const approximate = column.floatApproximate || !Number.isSafeInteger(intMinNumber) || !Number.isSafeInteger(intMaxNumber);
|
|
459
|
+
const min = intMinNumber <= column.floatMin ? column.intMinText : column.floatMinText;
|
|
460
|
+
const max = intMaxNumber >= column.floatMax ? column.intMaxText : column.floatMaxText;
|
|
461
|
+
return { min, max, approximate };
|
|
462
|
+
}
|
|
463
|
+
function columnReport(column) {
|
|
464
|
+
const range = numericRange(column);
|
|
465
|
+
return {
|
|
466
|
+
index: column.index,
|
|
467
|
+
name: column.name,
|
|
468
|
+
inferredType: inferColumnType(column.types),
|
|
469
|
+
nonEmpty: column.nonEmpty,
|
|
470
|
+
empty: column.empty,
|
|
471
|
+
sentinels: histogramRecord(column.sentinels),
|
|
472
|
+
types: { ...column.types },
|
|
473
|
+
sampleValues: column.samples.map((value) => capText(value).text),
|
|
474
|
+
minLength: Number.isFinite(column.minLength) ? column.minLength : 0,
|
|
475
|
+
maxLength: column.maxLength,
|
|
476
|
+
...range !== void 0 ? { numericRange: range } : {},
|
|
477
|
+
precisionIssues: column.precisionIssues
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
function lineEndingOf(parser) {
|
|
481
|
+
const kinds = [parser.lf > 0, parser.crlf > 0, parser.cr > 0].filter(Boolean).length;
|
|
482
|
+
if (kinds === 0) return "none";
|
|
483
|
+
if (kinds > 1) return "mixed";
|
|
484
|
+
if (parser.crlf > 0) return "crlf";
|
|
485
|
+
if (parser.cr > 0) return "cr";
|
|
486
|
+
return "lf";
|
|
487
|
+
}
|
|
488
|
+
function resolveDelimiter(explicit, format) {
|
|
489
|
+
if (explicit === void 0) return format === "tsv" ? " " : null;
|
|
490
|
+
if (explicit === "\\t") return " ";
|
|
491
|
+
if (explicit.length !== 1) return new Error("delimiter must be one character (or \\t)");
|
|
492
|
+
if (explicit === '"' || explicit === "\n" || explicit === "\r") {
|
|
493
|
+
return new Error("delimiter cannot be a quote or a line break");
|
|
494
|
+
}
|
|
495
|
+
return explicit;
|
|
496
|
+
}
|
|
497
|
+
async function scanCsv(path2, explicitDelimiter, signal, stats, callbacks) {
|
|
498
|
+
let parser = null;
|
|
499
|
+
let delimiter = explicitDelimiter;
|
|
500
|
+
let delimiterSource = delimiter === null ? "detected" : "explicit";
|
|
501
|
+
let sample = "";
|
|
502
|
+
for await (const chunk of streamTextChunks(path2, { signal, stats })) {
|
|
503
|
+
if (parser === null) {
|
|
504
|
+
if (delimiter === null) {
|
|
505
|
+
sample += chunk.text;
|
|
506
|
+
if (sample.length < DELIMITER_SAMPLE_CHARS) continue;
|
|
507
|
+
const detected = detectCsvDelimiter(sample.slice(0, DELIMITER_SAMPLE_CHARS), false);
|
|
508
|
+
delimiter = detected.delimiter;
|
|
509
|
+
if (detected.confidence === 0) delimiterSource = "default";
|
|
510
|
+
parser = new CsvParser(delimiter.charCodeAt(0), callbacks);
|
|
511
|
+
const keepGoing = parser.push(sample);
|
|
512
|
+
sample = "";
|
|
513
|
+
if (!keepGoing) break;
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
parser = new CsvParser(delimiter.charCodeAt(0), callbacks);
|
|
517
|
+
}
|
|
518
|
+
if (!parser.push(chunk.text)) break;
|
|
519
|
+
}
|
|
520
|
+
throwIfAborted(signal, path2);
|
|
521
|
+
if (parser === null) {
|
|
522
|
+
if (delimiter === null) {
|
|
523
|
+
const detected = detectCsvDelimiter(sample, true);
|
|
524
|
+
delimiter = detected.delimiter;
|
|
525
|
+
if (detected.confidence === 0) delimiterSource = "default";
|
|
526
|
+
}
|
|
527
|
+
parser = new CsvParser(delimiter.charCodeAt(0), callbacks);
|
|
528
|
+
parser.push(sample);
|
|
529
|
+
}
|
|
530
|
+
if (!parser.isStopped) parser.end();
|
|
531
|
+
return { parser, delimiter, delimiterSource };
|
|
532
|
+
}
|
|
533
|
+
var HeaderResolver = class {
|
|
534
|
+
constructor(option) {
|
|
535
|
+
this.option = option;
|
|
536
|
+
}
|
|
537
|
+
option;
|
|
538
|
+
header = null;
|
|
539
|
+
source = "none";
|
|
540
|
+
fieldCount = 0;
|
|
541
|
+
settled = false;
|
|
542
|
+
pending = null;
|
|
543
|
+
/** Returns the data rows this record releases, in order. */
|
|
544
|
+
feed(fields, line) {
|
|
545
|
+
if (this.settled) return [{ fields, line }];
|
|
546
|
+
if (this.option === true) {
|
|
547
|
+
this.settle(fields, "explicit", fields.length);
|
|
548
|
+
return [];
|
|
549
|
+
}
|
|
550
|
+
if (this.option === false) {
|
|
551
|
+
this.settle(null, "none", fields.length);
|
|
552
|
+
return [{ fields, line }];
|
|
553
|
+
}
|
|
554
|
+
if (this.pending === null) {
|
|
555
|
+
this.pending = { fields, line };
|
|
556
|
+
return [];
|
|
557
|
+
}
|
|
558
|
+
const first = this.pending;
|
|
559
|
+
this.pending = null;
|
|
560
|
+
if (headerLooksLikeNames(first.fields)) {
|
|
561
|
+
this.settle(first.fields, "detected", first.fields.length);
|
|
562
|
+
return [{ fields, line }];
|
|
563
|
+
}
|
|
564
|
+
this.settle(null, "none", first.fields.length);
|
|
565
|
+
return [first, { fields, line }];
|
|
566
|
+
}
|
|
567
|
+
/** End of input: a lone pending record is data. */
|
|
568
|
+
finish() {
|
|
569
|
+
if (this.settled) return [];
|
|
570
|
+
const first = this.pending;
|
|
571
|
+
this.pending = null;
|
|
572
|
+
if (first === null) {
|
|
573
|
+
this.settle(this.option === true ? [] : null, this.option === true ? "explicit" : "none", 0);
|
|
574
|
+
return [];
|
|
575
|
+
}
|
|
576
|
+
this.settle(null, "none", first.fields.length);
|
|
577
|
+
return [first];
|
|
578
|
+
}
|
|
579
|
+
settle(header, source, fieldCount) {
|
|
580
|
+
this.settled = true;
|
|
581
|
+
this.header = header;
|
|
582
|
+
this.source = source;
|
|
583
|
+
this.fieldCount = fieldCount;
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
async function inspectCsv(path2, options = {}) {
|
|
587
|
+
const stat = statDataFile(path2);
|
|
588
|
+
if ("ok" in stat) return stat;
|
|
589
|
+
const format = options.format ?? "csv";
|
|
590
|
+
const explicitDelimiter = resolveDelimiter(options.delimiter, format);
|
|
591
|
+
if (explicitDelimiter instanceof Error) return refusal("invalid-argument", explicitDelimiter.message, { path: path2 });
|
|
592
|
+
const sampleRows = Math.max(0, Math.min(1e3, Math.floor(options.sampleRows ?? CSV_DEFAULT_SAMPLE_ROWS)));
|
|
593
|
+
const maxRows = resolveMaxRows(options.maxRows, CSV_DEFAULT_MAX_ROWS);
|
|
594
|
+
const stats = { bytesRead: 0, bom: false };
|
|
595
|
+
const headers = new HeaderResolver(options.header ?? "auto");
|
|
596
|
+
const state = {
|
|
597
|
+
columns: [],
|
|
598
|
+
columnsTruncated: false,
|
|
599
|
+
columnsEstablished: false,
|
|
600
|
+
dataRows: 0,
|
|
601
|
+
stoppedAtRows: false,
|
|
602
|
+
raggedCount: 0,
|
|
603
|
+
raggedFirst: [],
|
|
604
|
+
issueCount: 0,
|
|
605
|
+
issueFirst: [],
|
|
606
|
+
precisionCount: 0,
|
|
607
|
+
precisionFirst: [],
|
|
608
|
+
sample: [],
|
|
609
|
+
sampleTruncatedCells: 0
|
|
610
|
+
};
|
|
611
|
+
const establishColumns = () => {
|
|
612
|
+
if (state.columnsEstablished) return;
|
|
613
|
+
state.columnsEstablished = true;
|
|
614
|
+
const names = headers.header ?? Array.from({ length: headers.fieldCount }, (_, index) => defaultColumnName(index));
|
|
615
|
+
for (const [index, name] of names.entries()) {
|
|
616
|
+
if (state.columns.length >= COLUMN_TRACK_CAP) {
|
|
617
|
+
state.columnsTruncated = true;
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
state.columns.push(newColumn(index, name));
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const consumeDataRow = (fields, line) => {
|
|
624
|
+
establishColumns();
|
|
625
|
+
if (state.dataRows >= maxRows) {
|
|
626
|
+
state.stoppedAtRows = true;
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
state.dataRows += 1;
|
|
630
|
+
if (fields.length !== headers.fieldCount) {
|
|
631
|
+
state.raggedCount += 1;
|
|
632
|
+
if (state.raggedFirst.length < FIRST_ISSUES_CAP) {
|
|
633
|
+
state.raggedFirst.push({ row: state.dataRows, line, fields: fields.length });
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
for (const [index, cell] of fields.entries()) {
|
|
637
|
+
let column = state.columns[index];
|
|
638
|
+
if (column === void 0) {
|
|
639
|
+
if (state.columns.length >= COLUMN_TRACK_CAP) {
|
|
640
|
+
state.columnsTruncated = true;
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
column = newColumn(index, defaultColumnName(index));
|
|
644
|
+
state.columns.push(column);
|
|
645
|
+
}
|
|
646
|
+
const precision = accumulateCell(column, cell);
|
|
647
|
+
if (precision !== null) {
|
|
648
|
+
state.precisionCount += 1;
|
|
649
|
+
if (state.precisionFirst.length < FIRST_ISSUES_CAP) {
|
|
650
|
+
state.precisionFirst.push({ kind: precision, literal: cell, row: state.dataRows, column: index });
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
if (state.sample.length < sampleRows) {
|
|
655
|
+
state.sample.push(
|
|
656
|
+
fields.map((cell) => {
|
|
657
|
+
const capped = capText(cell);
|
|
658
|
+
if (capped.truncated) state.sampleTruncatedCells += 1;
|
|
659
|
+
return capped.text;
|
|
660
|
+
})
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
return true;
|
|
664
|
+
};
|
|
665
|
+
const callbacks = {
|
|
666
|
+
onRecord(fields, _record, line) {
|
|
667
|
+
for (const row of headers.feed(fields, line)) {
|
|
668
|
+
if (!consumeDataRow(row.fields, row.line)) return false;
|
|
669
|
+
}
|
|
670
|
+
return true;
|
|
671
|
+
},
|
|
672
|
+
onIssue(issue) {
|
|
673
|
+
state.issueCount += 1;
|
|
674
|
+
if (state.issueFirst.length < FIRST_ISSUES_CAP) state.issueFirst.push(issue);
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
let scan;
|
|
678
|
+
try {
|
|
679
|
+
scan = await scanCsv(path2, explicitDelimiter, options.signal, stats, callbacks);
|
|
680
|
+
} catch (error) {
|
|
681
|
+
return refusalFromError(error, path2, options.signal);
|
|
682
|
+
}
|
|
683
|
+
if (!scan.parser.isStopped) {
|
|
684
|
+
for (const row of headers.finish()) consumeDataRow(row.fields, row.line);
|
|
685
|
+
establishColumns();
|
|
686
|
+
}
|
|
687
|
+
const sampled = state.stoppedAtRows;
|
|
688
|
+
const notes = [];
|
|
689
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
690
|
+
if (sampled) notes.push(sampledNotice(state.dataRows, "rows"));
|
|
691
|
+
if (scan.delimiterSource === "default") {
|
|
692
|
+
notes.push("no delimiter split the sample consistently; read as one column with the comma");
|
|
693
|
+
}
|
|
694
|
+
if (state.columnsTruncated) notes.push(`column tracking capped at ${COLUMN_TRACK_CAP} columns`);
|
|
695
|
+
if (state.raggedCount > 0) {
|
|
696
|
+
notes.push(`${state.raggedCount} row(s) have a field count other than ${headers.fieldCount}`);
|
|
697
|
+
}
|
|
698
|
+
if (state.issueCount > 0) notes.push(`${state.issueCount} quoting issue(s) were recovered leniently and are listed`);
|
|
699
|
+
if (state.precisionCount > 0) {
|
|
700
|
+
notes.push(`${state.precisionCount} numeric cell(s) would lose precision as doubles; cells stay source text`);
|
|
701
|
+
}
|
|
702
|
+
return {
|
|
703
|
+
ok: true,
|
|
704
|
+
format,
|
|
705
|
+
path: path2,
|
|
706
|
+
bytes: stat.size,
|
|
707
|
+
bytesScanned: stats.bytesRead,
|
|
708
|
+
view: sampled ? sampledView() : exactView(),
|
|
709
|
+
rowsScanned: state.dataRows,
|
|
710
|
+
rowCount: sampled ? null : state.dataRows,
|
|
711
|
+
delimiter: scan.delimiter,
|
|
712
|
+
delimiterSource: scan.delimiterSource,
|
|
713
|
+
header: headers.header,
|
|
714
|
+
headerSource: headers.source,
|
|
715
|
+
bom: stats.bom,
|
|
716
|
+
lineEnding: lineEndingOf(scan.parser),
|
|
717
|
+
fieldCount: headers.fieldCount,
|
|
718
|
+
columns: state.columns.map(columnReport),
|
|
719
|
+
columnsTruncated: state.columnsTruncated,
|
|
720
|
+
raggedRows: { count: state.raggedCount, first: state.raggedFirst },
|
|
721
|
+
quotingIssues: { count: state.issueCount, first: state.issueFirst },
|
|
722
|
+
precision: { count: state.precisionCount, first: state.precisionFirst },
|
|
723
|
+
blankLines: scan.parser.blankLines,
|
|
724
|
+
sample: state.sample,
|
|
725
|
+
sampleTruncatedCells: state.sampleTruncatedCells,
|
|
726
|
+
notes
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
var CSV_SELECT_DEFAULT_LIMIT = 50;
|
|
730
|
+
var CSV_SELECT_MAX_LIMIT = 1e3;
|
|
731
|
+
async function selectCsv(path2, options = {}) {
|
|
732
|
+
const stat = statDataFile(path2);
|
|
733
|
+
if ("ok" in stat) return stat;
|
|
734
|
+
const format = options.format ?? "csv";
|
|
735
|
+
const explicitDelimiter = resolveDelimiter(options.delimiter, format);
|
|
736
|
+
if (explicitDelimiter instanceof Error) return refusal("invalid-argument", explicitDelimiter.message, { path: path2 });
|
|
737
|
+
const offset = Math.max(0, Math.floor(options.offset ?? 0));
|
|
738
|
+
const limit = Math.max(1, Math.min(CSV_SELECT_MAX_LIMIT, Math.floor(options.limit ?? CSV_SELECT_DEFAULT_LIMIT)));
|
|
739
|
+
const stats = { bytesRead: 0, bom: false };
|
|
740
|
+
const headers = new HeaderResolver(options.header ?? "auto");
|
|
741
|
+
const state = {
|
|
742
|
+
projection: null,
|
|
743
|
+
projectionResolved: false,
|
|
744
|
+
projectionError: null,
|
|
745
|
+
dataRows: 0,
|
|
746
|
+
hasMore: false,
|
|
747
|
+
rows: []
|
|
748
|
+
};
|
|
749
|
+
const resolveProjection = () => {
|
|
750
|
+
if (state.projectionResolved) return state.projectionError === null;
|
|
751
|
+
state.projectionResolved = true;
|
|
752
|
+
if (options.columns === void 0) return true;
|
|
753
|
+
const names = headers.header;
|
|
754
|
+
const indexes2 = [];
|
|
755
|
+
for (const column of options.columns) {
|
|
756
|
+
if (typeof column === "number") {
|
|
757
|
+
if (!Number.isInteger(column) || column < 0) {
|
|
758
|
+
state.projectionError = refusal("invalid-argument", `column index ${column} is not a non-negative integer`, {
|
|
759
|
+
path: path2
|
|
760
|
+
});
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
indexes2.push(column);
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
const index = names?.indexOf(column) ?? -1;
|
|
767
|
+
if (index === -1) {
|
|
768
|
+
state.projectionError = refusal(
|
|
769
|
+
"unknown-column",
|
|
770
|
+
names === null ? `column "${column}" cannot be resolved: the file has no header; use a 0-based index` : `unknown column "${column}"; header columns are ${names.map((name) => JSON.stringify(name)).join(", ")}`,
|
|
771
|
+
{ path: path2 }
|
|
772
|
+
);
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
775
|
+
indexes2.push(index);
|
|
776
|
+
}
|
|
777
|
+
state.projection = indexes2;
|
|
778
|
+
return true;
|
|
779
|
+
};
|
|
780
|
+
const consumeDataRow = (fields) => {
|
|
781
|
+
if (!resolveProjection()) return false;
|
|
782
|
+
const index = state.dataRows;
|
|
783
|
+
state.dataRows += 1;
|
|
784
|
+
if (index < offset) return true;
|
|
785
|
+
if (state.rows.length >= limit) {
|
|
786
|
+
state.hasMore = true;
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
const projection2 = state.projection;
|
|
790
|
+
state.rows.push(projection2 === null ? fields : projection2.map((column) => fields[column] ?? null));
|
|
791
|
+
return true;
|
|
792
|
+
};
|
|
793
|
+
const callbacks = {
|
|
794
|
+
onRecord(fields, _record, line) {
|
|
795
|
+
for (const row of headers.feed(fields, line)) {
|
|
796
|
+
if (!consumeDataRow(row.fields)) return false;
|
|
797
|
+
}
|
|
798
|
+
if (headers.settled && !resolveProjection()) return false;
|
|
799
|
+
return true;
|
|
800
|
+
},
|
|
801
|
+
onIssue() {
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
let scan;
|
|
805
|
+
try {
|
|
806
|
+
scan = await scanCsv(path2, explicitDelimiter, options.signal, stats, callbacks);
|
|
807
|
+
} catch (error) {
|
|
808
|
+
return refusalFromError(error, path2, options.signal);
|
|
809
|
+
}
|
|
810
|
+
if (state.projectionError !== null) return state.projectionError;
|
|
811
|
+
if (!scan.parser.isStopped) {
|
|
812
|
+
for (const row of headers.finish()) consumeDataRow(row.fields);
|
|
813
|
+
if (!resolveProjection()) return state.projectionError ?? refusal("invalid-argument", "bad projection", { path: path2 });
|
|
814
|
+
}
|
|
815
|
+
const header = headers.header;
|
|
816
|
+
const projection = state.projection;
|
|
817
|
+
const indexes = projection ?? (header !== null ? header.map((_, index) => index) : Array.from({ length: state.rows.reduce((max, row) => Math.max(max, row.length), 0) }, (_, index) => index));
|
|
818
|
+
const notes = [];
|
|
819
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
820
|
+
if (scan.delimiterSource === "default") {
|
|
821
|
+
notes.push("no delimiter split the sample consistently; read as one column with the comma");
|
|
822
|
+
}
|
|
823
|
+
return {
|
|
824
|
+
ok: true,
|
|
825
|
+
format,
|
|
826
|
+
path: path2,
|
|
827
|
+
bytes: stat.size,
|
|
828
|
+
bytesScanned: stats.bytesRead,
|
|
829
|
+
view: exactView(),
|
|
830
|
+
delimiter: scan.delimiter,
|
|
831
|
+
header: header === null ? null : projection === null ? header : projection.map((column) => header[column] ?? defaultColumnName(column)),
|
|
832
|
+
columnIndexes: indexes,
|
|
833
|
+
offset,
|
|
834
|
+
limit,
|
|
835
|
+
returned: state.rows.length,
|
|
836
|
+
hasMore: state.hasMore,
|
|
837
|
+
rowsScanned: state.dataRows,
|
|
838
|
+
rows: state.rows,
|
|
839
|
+
notes
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
async function validateCsv(path2, options = {}) {
|
|
843
|
+
const stat = statDataFile(path2);
|
|
844
|
+
if ("ok" in stat) return stat;
|
|
845
|
+
const format = options.format ?? "csv";
|
|
846
|
+
const explicitDelimiter = resolveDelimiter(options.delimiter, format);
|
|
847
|
+
if (explicitDelimiter instanceof Error) return refusal("invalid-argument", explicitDelimiter.message, { path: path2 });
|
|
848
|
+
const maxRows = resolveMaxRows(options.maxRows, CSV_DEFAULT_MAX_ROWS);
|
|
849
|
+
const stats = { bytesRead: 0, bom: false };
|
|
850
|
+
const headers = new HeaderResolver(options.header ?? "auto");
|
|
851
|
+
const state = {
|
|
852
|
+
dataRows: 0,
|
|
853
|
+
stoppedAtRows: false,
|
|
854
|
+
raggedCount: 0,
|
|
855
|
+
raggedFirst: [],
|
|
856
|
+
issueCount: 0,
|
|
857
|
+
issueFirst: []
|
|
858
|
+
};
|
|
859
|
+
const consumeDataRow = (fields, line) => {
|
|
860
|
+
if (state.dataRows >= maxRows) {
|
|
861
|
+
state.stoppedAtRows = true;
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
state.dataRows += 1;
|
|
865
|
+
if (fields.length !== headers.fieldCount) {
|
|
866
|
+
state.raggedCount += 1;
|
|
867
|
+
if (state.raggedFirst.length < FIRST_ISSUES_CAP) {
|
|
868
|
+
state.raggedFirst.push({ row: state.dataRows, line, fields: fields.length });
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return true;
|
|
872
|
+
};
|
|
873
|
+
const callbacks = {
|
|
874
|
+
onRecord(fields, _record, line) {
|
|
875
|
+
for (const row of headers.feed(fields, line)) {
|
|
876
|
+
if (!consumeDataRow(row.fields, row.line)) return false;
|
|
877
|
+
}
|
|
878
|
+
return true;
|
|
879
|
+
},
|
|
880
|
+
onIssue(issue) {
|
|
881
|
+
state.issueCount += 1;
|
|
882
|
+
if (state.issueFirst.length < FIRST_ISSUES_CAP) state.issueFirst.push(issue);
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
let scan;
|
|
886
|
+
try {
|
|
887
|
+
scan = await scanCsv(path2, explicitDelimiter, options.signal, stats, callbacks);
|
|
888
|
+
} catch (error) {
|
|
889
|
+
return refusalFromError(error, path2, options.signal);
|
|
890
|
+
}
|
|
891
|
+
if (!scan.parser.isStopped) {
|
|
892
|
+
for (const row of headers.finish()) consumeDataRow(row.fields, row.line);
|
|
893
|
+
}
|
|
894
|
+
const complete = !state.stoppedAtRows;
|
|
895
|
+
const faults = state.raggedCount + state.issueCount;
|
|
896
|
+
const notes = [];
|
|
897
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
898
|
+
if (!complete) {
|
|
899
|
+
notes.push(
|
|
900
|
+
`validation incomplete: stopped after ${state.dataRows} rows; pass maxRows null to validate the whole file`
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
if (state.raggedCount > 0) {
|
|
904
|
+
notes.push(`${state.raggedCount} row(s) have a field count other than ${headers.fieldCount}`);
|
|
905
|
+
}
|
|
906
|
+
if (state.issueCount > 0) notes.push(`${state.issueCount} quoting issue(s)`);
|
|
907
|
+
return {
|
|
908
|
+
ok: true,
|
|
909
|
+
format,
|
|
910
|
+
path: path2,
|
|
911
|
+
bytes: stat.size,
|
|
912
|
+
bytesScanned: stats.bytesRead,
|
|
913
|
+
view: complete ? exactView() : sampledView(),
|
|
914
|
+
valid: faults > 0 ? false : complete ? true : null,
|
|
915
|
+
complete,
|
|
916
|
+
rowsScanned: state.dataRows,
|
|
917
|
+
rowCount: complete ? state.dataRows : null,
|
|
918
|
+
delimiter: scan.delimiter,
|
|
919
|
+
fieldCount: headers.fieldCount,
|
|
920
|
+
header: headers.header,
|
|
921
|
+
raggedRows: { count: state.raggedCount, first: state.raggedFirst },
|
|
922
|
+
quotingIssues: { count: state.issueCount, first: state.issueFirst },
|
|
923
|
+
blankLines: scan.parser.blankLines,
|
|
924
|
+
notes
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// src/tools/data/json.ts
|
|
929
|
+
init_esm_shims();
|
|
930
|
+
var JSON_MAX_DEPTH = 1024;
|
|
931
|
+
var KEY_CAPTURE_CAP = 1024;
|
|
932
|
+
var STRING_CAPTURE_CAP = 65536;
|
|
933
|
+
var CHAR_QUOTE2 = 34;
|
|
934
|
+
var CHAR_BACKSLASH = 92;
|
|
935
|
+
var CHAR_LF2 = 10;
|
|
936
|
+
function escapeChar(code) {
|
|
937
|
+
switch (code) {
|
|
938
|
+
case CHAR_QUOTE2:
|
|
939
|
+
return '"';
|
|
940
|
+
case CHAR_BACKSLASH:
|
|
941
|
+
return "\\";
|
|
942
|
+
case 47:
|
|
943
|
+
return "/";
|
|
944
|
+
case 98:
|
|
945
|
+
return "\b";
|
|
946
|
+
case 102:
|
|
947
|
+
return "\f";
|
|
948
|
+
case 110:
|
|
949
|
+
return "\n";
|
|
950
|
+
case 114:
|
|
951
|
+
return "\r";
|
|
952
|
+
case 116:
|
|
953
|
+
return " ";
|
|
954
|
+
default:
|
|
955
|
+
return null;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
function isWhitespace(code) {
|
|
959
|
+
return code === 32 || code === 9 || code === CHAR_LF2 || code === 13;
|
|
960
|
+
}
|
|
961
|
+
function isNumberChar(code) {
|
|
962
|
+
return code >= 48 && code <= 57 || code === 45 || code === 43 || code === 46 || code === 69 || code === 101;
|
|
963
|
+
}
|
|
964
|
+
var NUMBER_GRAMMAR = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/u;
|
|
965
|
+
var JsonStreamParser = class {
|
|
966
|
+
constructor(sink) {
|
|
967
|
+
this.sink = sink;
|
|
968
|
+
}
|
|
969
|
+
sink;
|
|
970
|
+
stack = [];
|
|
971
|
+
expect = 0 /* Value */;
|
|
972
|
+
tokenState = 0 /* None */;
|
|
973
|
+
token = "";
|
|
974
|
+
tokenTruncated = false;
|
|
975
|
+
stringCapture = false;
|
|
976
|
+
stringLength = 0;
|
|
977
|
+
stringIsKey = false;
|
|
978
|
+
escape = false;
|
|
979
|
+
unicodeHex = null;
|
|
980
|
+
line = 1;
|
|
981
|
+
column = 0;
|
|
982
|
+
chunkText = "";
|
|
983
|
+
chunkByteOffset = 0;
|
|
984
|
+
chunkIndex = 0;
|
|
985
|
+
stopped = false;
|
|
986
|
+
rootComplete = false;
|
|
987
|
+
/** Depth of the deepest container opened so far (root object or array is 0). */
|
|
988
|
+
maxDepth = 0;
|
|
989
|
+
get isStopped() {
|
|
990
|
+
return this.stopped;
|
|
991
|
+
}
|
|
992
|
+
get depth() {
|
|
993
|
+
return this.stack.length;
|
|
994
|
+
}
|
|
995
|
+
/** Feed one chunk. Returns false once a sink asked to stop; further pushes are ignored. */
|
|
996
|
+
push(text, byteOffset = 0) {
|
|
997
|
+
if (this.stopped) return false;
|
|
998
|
+
this.chunkText = text;
|
|
999
|
+
this.chunkByteOffset = byteOffset;
|
|
1000
|
+
const length = text.length;
|
|
1001
|
+
let index = 0;
|
|
1002
|
+
while (index < length) {
|
|
1003
|
+
this.chunkIndex = index;
|
|
1004
|
+
const code = text.charCodeAt(index);
|
|
1005
|
+
if (code === CHAR_LF2) {
|
|
1006
|
+
this.line += 1;
|
|
1007
|
+
this.column = 0;
|
|
1008
|
+
} else {
|
|
1009
|
+
this.column += 1;
|
|
1010
|
+
}
|
|
1011
|
+
switch (this.tokenState) {
|
|
1012
|
+
case 1 /* String */:
|
|
1013
|
+
index = this.scanString(text, index, length);
|
|
1014
|
+
break;
|
|
1015
|
+
case 2 /* Number */:
|
|
1016
|
+
if (isNumberChar(code)) {
|
|
1017
|
+
this.appendNumberChar(text[index]);
|
|
1018
|
+
index += 1;
|
|
1019
|
+
} else {
|
|
1020
|
+
this.column -= 1;
|
|
1021
|
+
if (code === CHAR_LF2) {
|
|
1022
|
+
this.line -= 1;
|
|
1023
|
+
this.column = 0;
|
|
1024
|
+
}
|
|
1025
|
+
this.completeNumber();
|
|
1026
|
+
this.tokenState = 0 /* None */;
|
|
1027
|
+
}
|
|
1028
|
+
break;
|
|
1029
|
+
case 3 /* Literal */:
|
|
1030
|
+
if (code >= 97 && code <= 122) {
|
|
1031
|
+
this.token += text[index];
|
|
1032
|
+
index += 1;
|
|
1033
|
+
if (this.token.length >= 5) this.completeLiteral();
|
|
1034
|
+
} else {
|
|
1035
|
+
this.column -= 1;
|
|
1036
|
+
if (code === CHAR_LF2) {
|
|
1037
|
+
this.line -= 1;
|
|
1038
|
+
this.column = 0;
|
|
1039
|
+
}
|
|
1040
|
+
this.completeLiteral();
|
|
1041
|
+
}
|
|
1042
|
+
break;
|
|
1043
|
+
default:
|
|
1044
|
+
index = this.scanStructural(text, index, code);
|
|
1045
|
+
break;
|
|
1046
|
+
}
|
|
1047
|
+
if (this.stopped) return false;
|
|
1048
|
+
}
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
end() {
|
|
1052
|
+
if (this.stopped) return;
|
|
1053
|
+
this.chunkIndex = this.chunkText.length;
|
|
1054
|
+
if (this.tokenState === 2 /* Number */) {
|
|
1055
|
+
this.completeNumber();
|
|
1056
|
+
this.tokenState = 0 /* None */;
|
|
1057
|
+
} else if (this.tokenState === 3 /* Literal */) {
|
|
1058
|
+
this.completeLiteral();
|
|
1059
|
+
} else if (this.tokenState === 1 /* String */) {
|
|
1060
|
+
throw this.error("unterminated string at end of input");
|
|
1061
|
+
}
|
|
1062
|
+
if (this.stopped) return;
|
|
1063
|
+
if (!this.rootComplete) {
|
|
1064
|
+
throw this.error(this.stack.length === 0 ? "unexpected end of input: no JSON value" : "unexpected end of input");
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
scanStructural(text, index, code) {
|
|
1068
|
+
if (isWhitespace(code)) return index + 1;
|
|
1069
|
+
if (this.expect === 6 /* End */) throw this.error("unexpected content after the JSON value");
|
|
1070
|
+
switch (code) {
|
|
1071
|
+
case CHAR_QUOTE2: {
|
|
1072
|
+
const isKey = this.expect === 2 /* Key */ || this.expect === 1 /* KeyOrEnd */;
|
|
1073
|
+
if (!isKey && this.expect !== 0 /* Value */ && this.expect !== 5 /* ValueOrEnd */) {
|
|
1074
|
+
throw this.error(this.describeExpectation());
|
|
1075
|
+
}
|
|
1076
|
+
this.tokenState = 1 /* String */;
|
|
1077
|
+
this.stringIsKey = isKey;
|
|
1078
|
+
this.stringCapture = isKey || this.sink.captureStrings(this.stack.length);
|
|
1079
|
+
this.token = "";
|
|
1080
|
+
this.tokenTruncated = false;
|
|
1081
|
+
this.stringLength = 0;
|
|
1082
|
+
this.escape = false;
|
|
1083
|
+
this.unicodeHex = null;
|
|
1084
|
+
return index + 1;
|
|
1085
|
+
}
|
|
1086
|
+
case 123:
|
|
1087
|
+
this.requireValueExpectation();
|
|
1088
|
+
this.openContainer("object");
|
|
1089
|
+
return index + 1;
|
|
1090
|
+
case 91:
|
|
1091
|
+
this.requireValueExpectation();
|
|
1092
|
+
this.openContainer("array");
|
|
1093
|
+
return index + 1;
|
|
1094
|
+
case 125:
|
|
1095
|
+
this.closeContainer("object");
|
|
1096
|
+
return index + 1;
|
|
1097
|
+
case 93:
|
|
1098
|
+
this.closeContainer("array");
|
|
1099
|
+
return index + 1;
|
|
1100
|
+
case 58:
|
|
1101
|
+
if (this.expect !== 3 /* Colon */) throw this.error(this.describeExpectation());
|
|
1102
|
+
this.expect = 0 /* Value */;
|
|
1103
|
+
return index + 1;
|
|
1104
|
+
case 44: {
|
|
1105
|
+
if (this.expect !== 4 /* CommaOrEnd */) throw this.error(this.describeExpectation());
|
|
1106
|
+
const top = this.stack[this.stack.length - 1];
|
|
1107
|
+
top.expect = top.kind === "object" ? 2 /* Key */ : 0 /* Value */;
|
|
1108
|
+
this.expect = top.expect;
|
|
1109
|
+
return index + 1;
|
|
1110
|
+
}
|
|
1111
|
+
default:
|
|
1112
|
+
this.requireValueExpectation();
|
|
1113
|
+
if (isNumberChar(code) && code !== 43 && code !== 46 && code !== 69 && code !== 101) {
|
|
1114
|
+
this.tokenState = 2 /* Number */;
|
|
1115
|
+
this.token = text[index];
|
|
1116
|
+
this.tokenTruncated = false;
|
|
1117
|
+
return index + 1;
|
|
1118
|
+
}
|
|
1119
|
+
if (code >= 97 && code <= 122) {
|
|
1120
|
+
this.tokenState = 3 /* Literal */;
|
|
1121
|
+
this.token = text[index];
|
|
1122
|
+
return index + 1;
|
|
1123
|
+
}
|
|
1124
|
+
throw this.error(`unexpected character ${JSON.stringify(text[index])}`);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
scanString(text, index, length) {
|
|
1128
|
+
if (!this.escape && this.unicodeHex === null) {
|
|
1129
|
+
let end = index;
|
|
1130
|
+
while (end < length) {
|
|
1131
|
+
const code2 = text.charCodeAt(end);
|
|
1132
|
+
if (code2 === CHAR_QUOTE2 || code2 === CHAR_BACKSLASH || code2 < 32) break;
|
|
1133
|
+
end += 1;
|
|
1134
|
+
}
|
|
1135
|
+
if (end > index) {
|
|
1136
|
+
const run = end - index;
|
|
1137
|
+
this.stringLength += run;
|
|
1138
|
+
if (this.stringCapture) this.captureString(text.slice(index, end));
|
|
1139
|
+
this.column += run - 1;
|
|
1140
|
+
if (end >= length) return end;
|
|
1141
|
+
index = end;
|
|
1142
|
+
this.chunkIndex = index;
|
|
1143
|
+
this.column += 1;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
const code = text.charCodeAt(index);
|
|
1147
|
+
if (this.unicodeHex !== null) {
|
|
1148
|
+
if (!(code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102)) {
|
|
1149
|
+
throw this.error("invalid \\u escape in string");
|
|
1150
|
+
}
|
|
1151
|
+
this.unicodeHex += text[index];
|
|
1152
|
+
if (this.unicodeHex.length === 4) {
|
|
1153
|
+
const decoded = String.fromCharCode(Number.parseInt(this.unicodeHex, 16));
|
|
1154
|
+
this.unicodeHex = null;
|
|
1155
|
+
this.stringLength += 1;
|
|
1156
|
+
if (this.stringCapture) this.captureString(decoded);
|
|
1157
|
+
}
|
|
1158
|
+
return index + 1;
|
|
1159
|
+
}
|
|
1160
|
+
if (this.escape) {
|
|
1161
|
+
this.escape = false;
|
|
1162
|
+
if (code === 117) {
|
|
1163
|
+
this.unicodeHex = "";
|
|
1164
|
+
return index + 1;
|
|
1165
|
+
}
|
|
1166
|
+
const decoded = escapeChar(code);
|
|
1167
|
+
if (decoded === null) throw this.error(`invalid escape \\${text[index]} in string`);
|
|
1168
|
+
this.stringLength += 1;
|
|
1169
|
+
if (this.stringCapture) this.captureString(decoded);
|
|
1170
|
+
return index + 1;
|
|
1171
|
+
}
|
|
1172
|
+
if (code === CHAR_QUOTE2) {
|
|
1173
|
+
this.completeString();
|
|
1174
|
+
return index + 1;
|
|
1175
|
+
}
|
|
1176
|
+
if (code === CHAR_BACKSLASH) {
|
|
1177
|
+
this.escape = true;
|
|
1178
|
+
return index + 1;
|
|
1179
|
+
}
|
|
1180
|
+
if (code < 32) throw this.error("unescaped control character in string");
|
|
1181
|
+
this.stringLength += 1;
|
|
1182
|
+
if (this.stringCapture) this.captureString(text[index]);
|
|
1183
|
+
return index + 1;
|
|
1184
|
+
}
|
|
1185
|
+
captureString(piece) {
|
|
1186
|
+
const cap = this.stringIsKey ? KEY_CAPTURE_CAP : STRING_CAPTURE_CAP;
|
|
1187
|
+
if (this.token.length >= cap) {
|
|
1188
|
+
this.tokenTruncated = true;
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
if (this.token.length + piece.length <= cap) {
|
|
1192
|
+
this.token += piece;
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
this.token += piece.slice(0, cap - this.token.length);
|
|
1196
|
+
this.tokenTruncated = true;
|
|
1197
|
+
}
|
|
1198
|
+
completeString() {
|
|
1199
|
+
this.tokenState = 0 /* None */;
|
|
1200
|
+
if (this.stringIsKey) {
|
|
1201
|
+
const top = this.stack[this.stack.length - 1];
|
|
1202
|
+
top.expect = 3 /* Colon */;
|
|
1203
|
+
this.expect = 3 /* Colon */;
|
|
1204
|
+
this.dispatch(this.sink.onKey(this.token, this.stack.length, this.tokenTruncated));
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
this.completeValue({
|
|
1208
|
+
type: "string",
|
|
1209
|
+
value: this.token,
|
|
1210
|
+
literal: null,
|
|
1211
|
+
captured: this.stringCapture,
|
|
1212
|
+
length: this.stringLength,
|
|
1213
|
+
truncated: this.tokenTruncated
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
appendNumberChar(char) {
|
|
1217
|
+
if (this.token.length >= MAX_NUMBER_LITERAL_CHARS) {
|
|
1218
|
+
this.tokenTruncated = true;
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
this.token += char;
|
|
1222
|
+
}
|
|
1223
|
+
completeNumber() {
|
|
1224
|
+
if (!this.tokenTruncated && !NUMBER_GRAMMAR.test(this.token)) {
|
|
1225
|
+
throw this.error(`invalid number literal ${JSON.stringify(this.token)}`);
|
|
1226
|
+
}
|
|
1227
|
+
const literal = this.tokenTruncated ? `${this.token}\u2026` : this.token;
|
|
1228
|
+
this.completeValue({
|
|
1229
|
+
type: "number",
|
|
1230
|
+
value: this.tokenTruncated ? Number.NaN : Number(this.token),
|
|
1231
|
+
literal,
|
|
1232
|
+
captured: true,
|
|
1233
|
+
length: 0,
|
|
1234
|
+
truncated: this.tokenTruncated
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
completeLiteral() {
|
|
1238
|
+
this.tokenState = 0 /* None */;
|
|
1239
|
+
const scalar = {
|
|
1240
|
+
type: "null",
|
|
1241
|
+
value: null,
|
|
1242
|
+
literal: null,
|
|
1243
|
+
captured: true,
|
|
1244
|
+
length: 0,
|
|
1245
|
+
truncated: false
|
|
1246
|
+
};
|
|
1247
|
+
if (this.token === "true") {
|
|
1248
|
+
scalar.type = "boolean";
|
|
1249
|
+
scalar.value = true;
|
|
1250
|
+
} else if (this.token === "false") {
|
|
1251
|
+
scalar.type = "boolean";
|
|
1252
|
+
scalar.value = false;
|
|
1253
|
+
} else if (this.token !== "null") {
|
|
1254
|
+
throw this.error(`unexpected literal ${JSON.stringify(this.token)}`);
|
|
1255
|
+
}
|
|
1256
|
+
this.completeValue(scalar);
|
|
1257
|
+
}
|
|
1258
|
+
requireValueExpectation() {
|
|
1259
|
+
if (this.expect !== 0 /* Value */ && this.expect !== 5 /* ValueOrEnd */) throw this.error(this.describeExpectation());
|
|
1260
|
+
}
|
|
1261
|
+
openContainer(kind) {
|
|
1262
|
+
if (this.stack.length >= JSON_MAX_DEPTH) {
|
|
1263
|
+
throw new DataRefusalError(
|
|
1264
|
+
refusal("nesting-too-deep", `JSON nesting exceeds ${JSON_MAX_DEPTH} levels at line ${this.line}`, {
|
|
1265
|
+
line: this.line,
|
|
1266
|
+
column: this.column,
|
|
1267
|
+
byteOffset: this.byteOffset()
|
|
1268
|
+
})
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
const depth = this.stack.length;
|
|
1272
|
+
if (depth > this.maxDepth) this.maxDepth = depth;
|
|
1273
|
+
const container = { kind, count: 0, expect: kind === "object" ? 1 /* KeyOrEnd */ : 5 /* ValueOrEnd */ };
|
|
1274
|
+
this.stack.push(container);
|
|
1275
|
+
this.expect = container.expect;
|
|
1276
|
+
this.dispatch(kind === "object" ? this.sink.onStartObject(depth) : this.sink.onStartArray(depth));
|
|
1277
|
+
}
|
|
1278
|
+
closeContainer(kind) {
|
|
1279
|
+
const top = this.stack[this.stack.length - 1];
|
|
1280
|
+
if (top === void 0 || top.kind !== kind) throw this.error(`unexpected ${kind === "object" ? "}" : "]"}`);
|
|
1281
|
+
const canClose = this.expect === 4 /* CommaOrEnd */ || kind === "object" && this.expect === 1 /* KeyOrEnd */ || kind === "array" && this.expect === 5 /* ValueOrEnd */;
|
|
1282
|
+
if (!canClose) throw this.error(this.describeExpectation());
|
|
1283
|
+
this.stack.pop();
|
|
1284
|
+
const depth = this.stack.length;
|
|
1285
|
+
this.dispatch(kind === "object" ? this.sink.onEndObject(depth, top.count) : this.sink.onEndArray(depth, top.count));
|
|
1286
|
+
if (this.stopped) return;
|
|
1287
|
+
this.afterValue();
|
|
1288
|
+
}
|
|
1289
|
+
completeValue(scalar) {
|
|
1290
|
+
this.dispatch(this.sink.onScalar(scalar, this.stack.length));
|
|
1291
|
+
if (this.stopped) return;
|
|
1292
|
+
this.afterValue();
|
|
1293
|
+
}
|
|
1294
|
+
afterValue() {
|
|
1295
|
+
const top = this.stack[this.stack.length - 1];
|
|
1296
|
+
if (top === void 0) {
|
|
1297
|
+
this.rootComplete = true;
|
|
1298
|
+
this.expect = 6 /* End */;
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
top.count += 1;
|
|
1302
|
+
top.expect = 4 /* CommaOrEnd */;
|
|
1303
|
+
this.expect = 4 /* CommaOrEnd */;
|
|
1304
|
+
}
|
|
1305
|
+
dispatch(verdict) {
|
|
1306
|
+
if (verdict === false) this.stopped = true;
|
|
1307
|
+
}
|
|
1308
|
+
describeExpectation() {
|
|
1309
|
+
switch (this.expect) {
|
|
1310
|
+
case 0 /* Value */:
|
|
1311
|
+
return "expected a JSON value";
|
|
1312
|
+
case 5 /* ValueOrEnd */:
|
|
1313
|
+
return "expected a JSON value or ']'";
|
|
1314
|
+
case 1 /* KeyOrEnd */:
|
|
1315
|
+
return "expected a string key or '}'";
|
|
1316
|
+
case 2 /* Key */:
|
|
1317
|
+
return "expected a string key";
|
|
1318
|
+
case 3 /* Colon */:
|
|
1319
|
+
return "expected ':' after object key";
|
|
1320
|
+
case 4 /* CommaOrEnd */:
|
|
1321
|
+
return `expected ',' or '${this.stack[this.stack.length - 1].kind === "object" ? "}" : "]"}'`;
|
|
1322
|
+
default:
|
|
1323
|
+
return "unexpected content after the JSON value";
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
byteOffset() {
|
|
1327
|
+
return this.chunkByteOffset + Buffer.byteLength(this.chunkText.slice(0, this.chunkIndex), "utf8");
|
|
1328
|
+
}
|
|
1329
|
+
error(message) {
|
|
1330
|
+
const byteOffset = this.byteOffset();
|
|
1331
|
+
return new DataRefusalError(
|
|
1332
|
+
refusal("invalid-json", `${message} at line ${this.line} column ${this.column} (byte offset ${byteOffset})`, {
|
|
1333
|
+
line: this.line,
|
|
1334
|
+
column: this.column,
|
|
1335
|
+
byteOffset
|
|
1336
|
+
})
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
var JsonValueBuilder = class {
|
|
1341
|
+
constructor(budgetChars, rootPointer) {
|
|
1342
|
+
this.budgetChars = budgetChars;
|
|
1343
|
+
this.rootPointer = rootPointer;
|
|
1344
|
+
}
|
|
1345
|
+
budgetChars;
|
|
1346
|
+
rootPointer;
|
|
1347
|
+
frames = [];
|
|
1348
|
+
spent = 0;
|
|
1349
|
+
exceeded = false;
|
|
1350
|
+
summaryType = "object";
|
|
1351
|
+
result;
|
|
1352
|
+
done = false;
|
|
1353
|
+
stringsCut = 0;
|
|
1354
|
+
issues = [];
|
|
1355
|
+
get complete() {
|
|
1356
|
+
return this.done;
|
|
1357
|
+
}
|
|
1358
|
+
/** The budget ran out; the value is (or contains) a $summary placeholder. */
|
|
1359
|
+
get overBudget() {
|
|
1360
|
+
return this.exceeded;
|
|
1361
|
+
}
|
|
1362
|
+
/** Strings cut at the capture cap, each left as a $truncated placeholder. */
|
|
1363
|
+
get cutStrings() {
|
|
1364
|
+
return this.stringsCut;
|
|
1365
|
+
}
|
|
1366
|
+
/** Anything in the value stands in for content that was not carried. */
|
|
1367
|
+
get truncated() {
|
|
1368
|
+
return this.exceeded || this.stringsCut > 0;
|
|
1369
|
+
}
|
|
1370
|
+
get value() {
|
|
1371
|
+
return this.result;
|
|
1372
|
+
}
|
|
1373
|
+
pointer() {
|
|
1374
|
+
let pointer = this.rootPointer;
|
|
1375
|
+
for (const frame of this.frames) {
|
|
1376
|
+
pointer += frame.kind === "object" ? `/${(frame.key ?? "").replace(/~/gu, "~0").replace(/\//gu, "~1")}` : `/${frame.value.length}`;
|
|
1377
|
+
}
|
|
1378
|
+
return pointer;
|
|
1379
|
+
}
|
|
1380
|
+
charge(chars) {
|
|
1381
|
+
if (this.exceeded) return false;
|
|
1382
|
+
this.spent += chars;
|
|
1383
|
+
if (this.spent > this.budgetChars) {
|
|
1384
|
+
this.exceeded = true;
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1387
|
+
return true;
|
|
1388
|
+
}
|
|
1389
|
+
place(value) {
|
|
1390
|
+
const frame = this.frames[this.frames.length - 1];
|
|
1391
|
+
if (frame === void 0) {
|
|
1392
|
+
this.result = value;
|
|
1393
|
+
this.done = true;
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
if (frame.kind === "array") frame.value.push(value);
|
|
1397
|
+
else frame.value[frame.key ?? ""] = value;
|
|
1398
|
+
frame.count += 1;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* The budget ran out somewhere inside the subtree. Everything built so far
|
|
1402
|
+
* is discarded and the whole subtree becomes one `$summary` placed when its
|
|
1403
|
+
* root closes, carrying the root's true member count from the parser.
|
|
1404
|
+
*/
|
|
1405
|
+
exhaust(rootKind) {
|
|
1406
|
+
this.exceeded = true;
|
|
1407
|
+
this.summaryType = this.frames[0]?.kind ?? rootKind;
|
|
1408
|
+
this.frames.length = 0;
|
|
1409
|
+
}
|
|
1410
|
+
startContainer(kind, _relativeDepth) {
|
|
1411
|
+
if (this.exceeded) return;
|
|
1412
|
+
if (!this.charge(2)) {
|
|
1413
|
+
this.exhaust(kind);
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
this.frames.push({ kind, value: kind === "object" ? {} : [], key: null, count: 0 });
|
|
1417
|
+
}
|
|
1418
|
+
key(name, _relativeDepth) {
|
|
1419
|
+
if (this.exceeded) return;
|
|
1420
|
+
const frame = this.frames[this.frames.length - 1];
|
|
1421
|
+
if (frame === void 0) return;
|
|
1422
|
+
if (!this.charge(name.length + 4)) {
|
|
1423
|
+
this.exhaust(frame.kind);
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
frame.key = name;
|
|
1427
|
+
}
|
|
1428
|
+
endContainer(kind, relativeDepth, count) {
|
|
1429
|
+
if (this.exceeded) {
|
|
1430
|
+
if (relativeDepth === 0) {
|
|
1431
|
+
this.result = {
|
|
1432
|
+
$summary: this.summaryType === "object" ? { type: "object", members: count, reason: "budget" } : { type: "array", length: count, reason: "budget" }
|
|
1433
|
+
};
|
|
1434
|
+
this.done = true;
|
|
1435
|
+
}
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
const frame = this.frames.pop();
|
|
1439
|
+
if (frame === void 0 || frame.kind !== kind) return;
|
|
1440
|
+
this.place(frame.value);
|
|
1441
|
+
}
|
|
1442
|
+
scalar(scalar, _relativeDepth) {
|
|
1443
|
+
if (this.exceeded) return;
|
|
1444
|
+
const cost = scalar.type === "string" ? scalar.length + 2 : scalar.literal?.length ?? 4;
|
|
1445
|
+
if (!this.charge(cost)) {
|
|
1446
|
+
const frame = this.frames[this.frames.length - 1];
|
|
1447
|
+
if (frame === void 0) {
|
|
1448
|
+
this.exceeded = false;
|
|
1449
|
+
this.spent = 0;
|
|
1450
|
+
} else {
|
|
1451
|
+
this.exhaust(frame.kind);
|
|
1452
|
+
return;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
if (scalar.type === "number") {
|
|
1456
|
+
const literal = scalar.literal ?? "";
|
|
1457
|
+
const precision = scalar.truncated ? "oversized-literal" : numberLiteralPrecision(literal);
|
|
1458
|
+
if (precision !== null) {
|
|
1459
|
+
this.issues.push({ kind: precision, literal, path: this.pointer() });
|
|
1460
|
+
this.place({ $literal: literal, precision });
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
this.place(scalar.value);
|
|
1464
|
+
return;
|
|
1465
|
+
}
|
|
1466
|
+
if (scalar.type === "string") {
|
|
1467
|
+
if (scalar.truncated) {
|
|
1468
|
+
this.stringsCut += 1;
|
|
1469
|
+
this.place({ $truncated: "string", length: scalar.length, text: scalar.value });
|
|
1470
|
+
} else this.place(scalar.value);
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
this.place(scalar.value);
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1476
|
+
function escapePointerSegment(segment) {
|
|
1477
|
+
return segment.replace(/~/gu, "~0").replace(/\//gu, "~1");
|
|
1478
|
+
}
|
|
1479
|
+
function parseJsonPointer(pointer) {
|
|
1480
|
+
if (pointer === "") return [];
|
|
1481
|
+
if (!pointer.startsWith("/")) return new Error("JSON pointer must start with '/' or be empty for the whole document");
|
|
1482
|
+
return pointer.slice(1).split("/").map((segment) => segment.replace(/~1/gu, "/").replace(/~0/gu, "~"));
|
|
1483
|
+
}
|
|
1484
|
+
var PathTracker = class {
|
|
1485
|
+
segments = [];
|
|
1486
|
+
kinds = [];
|
|
1487
|
+
indexes = [];
|
|
1488
|
+
startContainer(kind) {
|
|
1489
|
+
this.kinds.push(kind);
|
|
1490
|
+
this.indexes.push(0);
|
|
1491
|
+
this.segments.push(kind === "array" ? "0" : "");
|
|
1492
|
+
}
|
|
1493
|
+
key(name) {
|
|
1494
|
+
this.segments[this.segments.length - 1] = name;
|
|
1495
|
+
}
|
|
1496
|
+
endContainer() {
|
|
1497
|
+
this.kinds.pop();
|
|
1498
|
+
this.indexes.pop();
|
|
1499
|
+
this.segments.pop();
|
|
1500
|
+
}
|
|
1501
|
+
/** Advance after a value completes inside the current container. */
|
|
1502
|
+
advance() {
|
|
1503
|
+
const top = this.kinds.length - 1;
|
|
1504
|
+
if (top < 0) return;
|
|
1505
|
+
if (this.kinds[top] === "array") {
|
|
1506
|
+
const next = this.indexes[top] + 1;
|
|
1507
|
+
this.indexes[top] = next;
|
|
1508
|
+
this.segments[top] = String(next);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
pointer() {
|
|
1512
|
+
return this.segments.map((segment) => `/${escapePointerSegment(segment)}`).join("");
|
|
1513
|
+
}
|
|
1514
|
+
/** Pointer of the innermost open container. */
|
|
1515
|
+
containerPointer() {
|
|
1516
|
+
return this.segments.slice(0, -1).map((segment) => `/${escapePointerSegment(segment)}`).join("");
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
var DUPLICATE_KEY_TRACK_CAP = 1e4;
|
|
1520
|
+
var KEY_LIST_CAP = 200;
|
|
1521
|
+
var PRECISION_FIRST_CAP = 20;
|
|
1522
|
+
var SAMPLE_BUDGET_CHARS = 8192;
|
|
1523
|
+
var SELECT_BUDGET_CHARS = 1048576;
|
|
1524
|
+
var StructureScanner = class {
|
|
1525
|
+
constructor(pointerPrefix = "") {
|
|
1526
|
+
this.pointerPrefix = pointerPrefix;
|
|
1527
|
+
}
|
|
1528
|
+
pointerPrefix;
|
|
1529
|
+
path = new PathTracker();
|
|
1530
|
+
frames = [];
|
|
1531
|
+
duplicateCount = 0;
|
|
1532
|
+
duplicateFirst = null;
|
|
1533
|
+
duplicateCheckedFully = true;
|
|
1534
|
+
precisionCount = 0;
|
|
1535
|
+
precisionFirst = [];
|
|
1536
|
+
startContainer(kind) {
|
|
1537
|
+
this.path.startContainer(kind);
|
|
1538
|
+
this.frames.push({ seen: kind === "object" ? /* @__PURE__ */ new Set() : null, overCap: false });
|
|
1539
|
+
}
|
|
1540
|
+
key(name) {
|
|
1541
|
+
this.path.key(name);
|
|
1542
|
+
const frame = this.frames[this.frames.length - 1];
|
|
1543
|
+
if (frame?.seen === null || frame === void 0) return;
|
|
1544
|
+
if (frame.overCap) return;
|
|
1545
|
+
if (frame.seen.has(name)) {
|
|
1546
|
+
this.duplicateCount += 1;
|
|
1547
|
+
if (this.duplicateFirst === null) {
|
|
1548
|
+
this.duplicateFirst = { path: this.pointerPrefix + this.path.containerPointer(), key: name };
|
|
1549
|
+
}
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
if (frame.seen.size >= DUPLICATE_KEY_TRACK_CAP) {
|
|
1553
|
+
frame.overCap = true;
|
|
1554
|
+
frame.seen = null;
|
|
1555
|
+
this.duplicateCheckedFully = false;
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
frame.seen.add(name);
|
|
1559
|
+
}
|
|
1560
|
+
endContainer() {
|
|
1561
|
+
this.frames.pop();
|
|
1562
|
+
this.path.endContainer();
|
|
1563
|
+
this.path.advance();
|
|
1564
|
+
}
|
|
1565
|
+
scalar(scalar) {
|
|
1566
|
+
if (scalar.type === "number") {
|
|
1567
|
+
const literal = scalar.literal ?? "";
|
|
1568
|
+
const precision = scalar.truncated ? "oversized-literal" : numberLiteralPrecision(literal);
|
|
1569
|
+
if (precision !== null) {
|
|
1570
|
+
this.precisionCount += 1;
|
|
1571
|
+
if (this.precisionFirst.length < PRECISION_FIRST_CAP) {
|
|
1572
|
+
this.precisionFirst.push({ kind: precision, literal, path: this.pointerPrefix + this.path.pointer() });
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
this.path.advance();
|
|
1577
|
+
}
|
|
1578
|
+
duplicates() {
|
|
1579
|
+
return { count: this.duplicateCount, first: this.duplicateFirst, checkedFully: this.duplicateCheckedFully };
|
|
1580
|
+
}
|
|
1581
|
+
precision() {
|
|
1582
|
+
return { count: this.precisionCount, first: [...this.precisionFirst] };
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
var JSON_DEFAULT_SAMPLE_ROWS = 10;
|
|
1586
|
+
var JSON_DEFAULT_MAX_ROWS = 1e5;
|
|
1587
|
+
var InspectSink = class {
|
|
1588
|
+
constructor(sampleRows, maxRows) {
|
|
1589
|
+
this.sampleRows = sampleRows;
|
|
1590
|
+
this.maxRows = maxRows;
|
|
1591
|
+
}
|
|
1592
|
+
sampleRows;
|
|
1593
|
+
maxRows;
|
|
1594
|
+
scanner = new StructureScanner();
|
|
1595
|
+
root = null;
|
|
1596
|
+
rows = 0;
|
|
1597
|
+
rowCount = null;
|
|
1598
|
+
stoppedAtRows = false;
|
|
1599
|
+
keys = [];
|
|
1600
|
+
keysTruncated = false;
|
|
1601
|
+
types = /* @__PURE__ */ new Map();
|
|
1602
|
+
sample = [];
|
|
1603
|
+
/** Sample values that carry a $summary or $truncated placeholder; the counts stay exact. */
|
|
1604
|
+
sampleCuts = 0;
|
|
1605
|
+
rootValue;
|
|
1606
|
+
builder = null;
|
|
1607
|
+
builderDepth = 0;
|
|
1608
|
+
currentKey = "";
|
|
1609
|
+
sampleIssues = [];
|
|
1610
|
+
countType(type) {
|
|
1611
|
+
this.types.set(type, (this.types.get(type) ?? 0) + 1);
|
|
1612
|
+
}
|
|
1613
|
+
/** A depth-1 value begins: count it, decide whether it is sampled, or stop at the row bound. */
|
|
1614
|
+
beginRow(type) {
|
|
1615
|
+
if (this.rows >= this.maxRows) {
|
|
1616
|
+
this.stoppedAtRows = true;
|
|
1617
|
+
return false;
|
|
1618
|
+
}
|
|
1619
|
+
this.rows += 1;
|
|
1620
|
+
this.countType(type);
|
|
1621
|
+
if (this.sample.length < this.sampleRows) {
|
|
1622
|
+
const pointer = this.root === "array" ? `/${this.rows - 1}` : `/${escapePointerSegment(this.currentKey)}`;
|
|
1623
|
+
this.builder = new JsonValueBuilder(SAMPLE_BUDGET_CHARS, pointer);
|
|
1624
|
+
this.builderDepth = 1;
|
|
1625
|
+
}
|
|
1626
|
+
return true;
|
|
1627
|
+
}
|
|
1628
|
+
finishSampled() {
|
|
1629
|
+
const builder = this.builder;
|
|
1630
|
+
if (builder === null || !builder.complete) return;
|
|
1631
|
+
this.builder = null;
|
|
1632
|
+
if (builder.truncated) this.sampleCuts += 1;
|
|
1633
|
+
const value = builder.value;
|
|
1634
|
+
if (this.root === "array") this.sample.push(value);
|
|
1635
|
+
else this.sample.push({ key: this.currentKey, value });
|
|
1636
|
+
this.sampleIssues.push(...builder.issues);
|
|
1637
|
+
}
|
|
1638
|
+
onStartObject(depth) {
|
|
1639
|
+
if (depth === 0) {
|
|
1640
|
+
this.root = "object";
|
|
1641
|
+
this.scanner.startContainer("object");
|
|
1642
|
+
return void 0;
|
|
1643
|
+
}
|
|
1644
|
+
if (depth === 1 && !this.beginRow("object")) return false;
|
|
1645
|
+
this.scanner.startContainer("object");
|
|
1646
|
+
this.builder?.startContainer("object", depth - this.builderDepth);
|
|
1647
|
+
return void 0;
|
|
1648
|
+
}
|
|
1649
|
+
onStartArray(depth) {
|
|
1650
|
+
if (depth === 0) {
|
|
1651
|
+
this.root = "array";
|
|
1652
|
+
this.scanner.startContainer("array");
|
|
1653
|
+
return void 0;
|
|
1654
|
+
}
|
|
1655
|
+
if (depth === 1 && !this.beginRow("array")) return false;
|
|
1656
|
+
this.scanner.startContainer("array");
|
|
1657
|
+
this.builder?.startContainer("array", depth - this.builderDepth);
|
|
1658
|
+
return void 0;
|
|
1659
|
+
}
|
|
1660
|
+
onKey(key, depth, truncated) {
|
|
1661
|
+
this.scanner.key(key);
|
|
1662
|
+
if (depth === 1) {
|
|
1663
|
+
if (this.rows >= this.maxRows) {
|
|
1664
|
+
this.stoppedAtRows = true;
|
|
1665
|
+
return false;
|
|
1666
|
+
}
|
|
1667
|
+
this.currentKey = truncated ? `${key}\u2026` : key;
|
|
1668
|
+
if (this.keys.length < KEY_LIST_CAP) this.keys.push(this.currentKey);
|
|
1669
|
+
else this.keysTruncated = true;
|
|
1670
|
+
return void 0;
|
|
1671
|
+
}
|
|
1672
|
+
this.builder?.key(key, depth - this.builderDepth);
|
|
1673
|
+
return void 0;
|
|
1674
|
+
}
|
|
1675
|
+
onEndObject(depth, memberCount) {
|
|
1676
|
+
if (depth === 0) {
|
|
1677
|
+
this.rowCount = memberCount;
|
|
1678
|
+
return void 0;
|
|
1679
|
+
}
|
|
1680
|
+
this.scanner.endContainer();
|
|
1681
|
+
this.builder?.endContainer("object", depth - this.builderDepth, memberCount);
|
|
1682
|
+
if (depth === 1) this.finishSampled();
|
|
1683
|
+
return void 0;
|
|
1684
|
+
}
|
|
1685
|
+
onEndArray(depth, length) {
|
|
1686
|
+
if (depth === 0) {
|
|
1687
|
+
this.rowCount = length;
|
|
1688
|
+
return void 0;
|
|
1689
|
+
}
|
|
1690
|
+
this.scanner.endContainer();
|
|
1691
|
+
this.builder?.endContainer("array", depth - this.builderDepth, length);
|
|
1692
|
+
if (depth === 1) this.finishSampled();
|
|
1693
|
+
return void 0;
|
|
1694
|
+
}
|
|
1695
|
+
onScalar(scalar, depth) {
|
|
1696
|
+
if (depth === 0) {
|
|
1697
|
+
this.root = scalar.type;
|
|
1698
|
+
this.rows = 1;
|
|
1699
|
+
this.rowCount = 1;
|
|
1700
|
+
const builder = new JsonValueBuilder(SAMPLE_BUDGET_CHARS, "");
|
|
1701
|
+
builder.scalar(scalar, 0);
|
|
1702
|
+
this.rootValue = builder.value;
|
|
1703
|
+
this.sampleIssues.push(...builder.issues);
|
|
1704
|
+
this.scanner.scalar(scalar);
|
|
1705
|
+
return void 0;
|
|
1706
|
+
}
|
|
1707
|
+
if (depth === 1 && !this.beginRow(scalar.type)) return false;
|
|
1708
|
+
this.scanner.scalar(scalar);
|
|
1709
|
+
this.builder?.scalar(scalar, depth - this.builderDepth);
|
|
1710
|
+
if (depth === 1) this.finishSampled();
|
|
1711
|
+
return void 0;
|
|
1712
|
+
}
|
|
1713
|
+
captureStrings(depth) {
|
|
1714
|
+
if (depth === 0) return true;
|
|
1715
|
+
if (depth === 1) return this.rows < this.maxRows && this.sample.length < this.sampleRows;
|
|
1716
|
+
return this.builder !== null && !this.builder.overBudget;
|
|
1717
|
+
}
|
|
1718
|
+
/** Precision issues seen inside sampled values that the scanner already counted; used only for cross-checks. */
|
|
1719
|
+
get sampledIssues() {
|
|
1720
|
+
return this.sampleIssues;
|
|
1721
|
+
}
|
|
1722
|
+
};
|
|
1723
|
+
async function runParser(path2, sink, signal, stats) {
|
|
1724
|
+
const parser = new JsonStreamParser(sink);
|
|
1725
|
+
for await (const chunk of streamTextChunks(path2, { signal, stats })) {
|
|
1726
|
+
if (!parser.push(chunk.text, chunk.byteOffset)) return { parser, stopped: true };
|
|
1727
|
+
}
|
|
1728
|
+
parser.end();
|
|
1729
|
+
throwIfAborted(signal, path2);
|
|
1730
|
+
return { parser, stopped: parser.isStopped };
|
|
1731
|
+
}
|
|
1732
|
+
async function inspectJson(path2, options = {}) {
|
|
1733
|
+
const stat = statDataFile(path2);
|
|
1734
|
+
if ("ok" in stat) return stat;
|
|
1735
|
+
const sampleRows = Math.max(0, Math.min(1e3, Math.floor(options.sampleRows ?? JSON_DEFAULT_SAMPLE_ROWS)));
|
|
1736
|
+
const maxRows = resolveMaxRows(options.maxRows, JSON_DEFAULT_MAX_ROWS);
|
|
1737
|
+
const stats = { bytesRead: 0, bom: false };
|
|
1738
|
+
const sink = new InspectSink(sampleRows, maxRows);
|
|
1739
|
+
let parser;
|
|
1740
|
+
try {
|
|
1741
|
+
parser = (await runParser(path2, sink, options.signal, stats)).parser;
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
return refusalFromError(error, path2, options.signal);
|
|
1744
|
+
}
|
|
1745
|
+
const sampled = sink.stoppedAtRows;
|
|
1746
|
+
const notes = [];
|
|
1747
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
1748
|
+
if (sampled) notes.push(sampledNotice(sink.rows, sink.root === "object" ? "members" : "elements"));
|
|
1749
|
+
if (sink.sampleCuts > 0) {
|
|
1750
|
+
notes.push(
|
|
1751
|
+
`${sink.sampleCuts} sample value(s) were cut to the preview budget and carry $summary or $truncated placeholders; the counts are exact`
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
if (!sink.scanner.duplicateCheckedFully) {
|
|
1755
|
+
notes.push(
|
|
1756
|
+
`duplicate-key tracking stopped at ${DUPLICATE_KEY_TRACK_CAP} keys in one object; later duplicates there are unreported`
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
if (sink.keysTruncated) notes.push(`key list capped at ${KEY_LIST_CAP} names`);
|
|
1760
|
+
const root = sink.root ?? "null";
|
|
1761
|
+
const result = {
|
|
1762
|
+
ok: true,
|
|
1763
|
+
format: "json",
|
|
1764
|
+
path: path2,
|
|
1765
|
+
bytes: stat.size,
|
|
1766
|
+
bytesScanned: stats.bytesRead,
|
|
1767
|
+
view: sampled ? sampledView() : exactView(),
|
|
1768
|
+
rowsScanned: sink.rows,
|
|
1769
|
+
rowCount: sampled ? null : sink.rowCount,
|
|
1770
|
+
root,
|
|
1771
|
+
maxDepth: parser.maxDepth,
|
|
1772
|
+
duplicateKeys: sink.scanner.duplicates(),
|
|
1773
|
+
precision: sink.scanner.precision(),
|
|
1774
|
+
sample: sink.sample,
|
|
1775
|
+
notes
|
|
1776
|
+
};
|
|
1777
|
+
const types = {};
|
|
1778
|
+
for (const [type, count] of sink.types) types[type] = count;
|
|
1779
|
+
if (root === "array") result.elementTypes = types;
|
|
1780
|
+
else if (root === "object") {
|
|
1781
|
+
result.keys = { names: sink.keys, truncated: sink.keysTruncated };
|
|
1782
|
+
result.memberTypes = types;
|
|
1783
|
+
} else if (sink.rootValue !== void 0) result.value = sink.rootValue;
|
|
1784
|
+
return result;
|
|
1785
|
+
}
|
|
1786
|
+
var JSON_SELECT_DEFAULT_LIMIT = 50;
|
|
1787
|
+
var JSON_SELECT_MAX_LIMIT = 1e3;
|
|
1788
|
+
var SelectSink = class {
|
|
1789
|
+
constructor(segments, windowOffset, windowLimit) {
|
|
1790
|
+
this.segments = segments;
|
|
1791
|
+
this.windowOffset = windowOffset;
|
|
1792
|
+
this.windowLimit = windowLimit;
|
|
1793
|
+
}
|
|
1794
|
+
segments;
|
|
1795
|
+
windowOffset;
|
|
1796
|
+
windowLimit;
|
|
1797
|
+
path = new PathTracker();
|
|
1798
|
+
phase = "seeking";
|
|
1799
|
+
targetDepth = -1;
|
|
1800
|
+
found = false;
|
|
1801
|
+
targetType = null;
|
|
1802
|
+
builder = null;
|
|
1803
|
+
/** Array-window mode state. */
|
|
1804
|
+
windowed = false;
|
|
1805
|
+
elementIndex = 0;
|
|
1806
|
+
elements = [];
|
|
1807
|
+
hasMore = false;
|
|
1808
|
+
issues = [];
|
|
1809
|
+
tooLarge = false;
|
|
1810
|
+
cutStrings = 0;
|
|
1811
|
+
/** Deepest matched prefix length, for the not-found message. */
|
|
1812
|
+
deepestMatch = 0;
|
|
1813
|
+
/** Per-object key sets inside the captured value; null past the tracking cap. */
|
|
1814
|
+
keySets = [];
|
|
1815
|
+
duplicateCount = 0;
|
|
1816
|
+
duplicateFirst = null;
|
|
1817
|
+
duplicatesCheckedFully = true;
|
|
1818
|
+
trackObjectStart() {
|
|
1819
|
+
if (this.builder !== null) this.keySets.push(/* @__PURE__ */ new Set());
|
|
1820
|
+
}
|
|
1821
|
+
trackKey(key) {
|
|
1822
|
+
if (this.builder === null) return;
|
|
1823
|
+
const keys = this.keySets[this.keySets.length - 1];
|
|
1824
|
+
if (keys === null || keys === void 0) return;
|
|
1825
|
+
if (keys.has(key)) {
|
|
1826
|
+
this.duplicateCount += 1;
|
|
1827
|
+
if (this.duplicateFirst === null) this.duplicateFirst = { path: this.path.containerPointer(), key };
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
if (keys.size >= DUPLICATE_KEY_TRACK_CAP) {
|
|
1831
|
+
this.duplicatesCheckedFully = false;
|
|
1832
|
+
this.keySets[this.keySets.length - 1] = null;
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
keys.add(key);
|
|
1836
|
+
}
|
|
1837
|
+
trackObjectEnd() {
|
|
1838
|
+
if (this.builder !== null) this.keySets.pop();
|
|
1839
|
+
}
|
|
1840
|
+
pointerMatches() {
|
|
1841
|
+
const current = this.path.segments;
|
|
1842
|
+
if (current.length !== this.segments.length) return false;
|
|
1843
|
+
for (let index = 0; index < current.length; index += 1) {
|
|
1844
|
+
if (current[index] !== this.segments[index]) return false;
|
|
1845
|
+
}
|
|
1846
|
+
return true;
|
|
1847
|
+
}
|
|
1848
|
+
prefixMatches() {
|
|
1849
|
+
const current = this.path.segments;
|
|
1850
|
+
if (current.length > this.segments.length) return false;
|
|
1851
|
+
for (let index = 0; index < current.length; index += 1) {
|
|
1852
|
+
if (current[index] !== this.segments[index]) return false;
|
|
1853
|
+
}
|
|
1854
|
+
if (current.length > this.deepestMatch) this.deepestMatch = current.length;
|
|
1855
|
+
return true;
|
|
1856
|
+
}
|
|
1857
|
+
beginTarget(type, depth) {
|
|
1858
|
+
this.found = true;
|
|
1859
|
+
this.targetType = type;
|
|
1860
|
+
this.targetDepth = depth;
|
|
1861
|
+
this.phase = "capturing";
|
|
1862
|
+
if (type === "array" && this.windowOffset !== null) {
|
|
1863
|
+
this.windowed = true;
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
this.builder = new JsonValueBuilder(SELECT_BUDGET_CHARS, this.path.pointer());
|
|
1867
|
+
}
|
|
1868
|
+
finishBuilder() {
|
|
1869
|
+
const builder = this.builder;
|
|
1870
|
+
if (builder === null || !builder.complete) return void 0;
|
|
1871
|
+
this.builder = null;
|
|
1872
|
+
if (builder.overBudget) {
|
|
1873
|
+
this.tooLarge = true;
|
|
1874
|
+
return false;
|
|
1875
|
+
}
|
|
1876
|
+
this.cutStrings += builder.cutStrings;
|
|
1877
|
+
this.issues.push(...builder.issues);
|
|
1878
|
+
if (this.windowed) {
|
|
1879
|
+
this.elements.push(builder.value);
|
|
1880
|
+
if (this.elements.length >= this.windowLimit) {
|
|
1881
|
+
return void 0;
|
|
1882
|
+
}
|
|
1883
|
+
return void 0;
|
|
1884
|
+
}
|
|
1885
|
+
this.value = builder.value;
|
|
1886
|
+
this.phase = "done";
|
|
1887
|
+
return false;
|
|
1888
|
+
}
|
|
1889
|
+
value;
|
|
1890
|
+
beginElement(type, depth) {
|
|
1891
|
+
if (!this.windowed || depth !== this.targetDepth + 1) return void 0;
|
|
1892
|
+
const index = this.elementIndex;
|
|
1893
|
+
this.elementIndex += 1;
|
|
1894
|
+
const offset = this.windowOffset;
|
|
1895
|
+
if (index < offset) return void 0;
|
|
1896
|
+
if (this.elements.length >= this.windowLimit) {
|
|
1897
|
+
this.hasMore = true;
|
|
1898
|
+
this.phase = "done";
|
|
1899
|
+
return false;
|
|
1900
|
+
}
|
|
1901
|
+
this.builder = new JsonValueBuilder(SELECT_BUDGET_CHARS, `${this.path.pointer()}`);
|
|
1902
|
+
void type;
|
|
1903
|
+
return void 0;
|
|
1904
|
+
}
|
|
1905
|
+
onStartObject(depth) {
|
|
1906
|
+
if (this.phase === "seeking") {
|
|
1907
|
+
if (this.pointerMatches()) {
|
|
1908
|
+
this.beginTarget("object", depth);
|
|
1909
|
+
this.builder?.startContainer("object", 0);
|
|
1910
|
+
} else this.prefixMatches();
|
|
1911
|
+
} else if (this.phase === "capturing") {
|
|
1912
|
+
const stop = this.beginElement("object", depth);
|
|
1913
|
+
if (stop === false) return false;
|
|
1914
|
+
this.builder?.startContainer("object", depth - (this.windowed ? this.targetDepth + 1 : this.targetDepth));
|
|
1915
|
+
}
|
|
1916
|
+
this.trackObjectStart();
|
|
1917
|
+
this.path.startContainer("object");
|
|
1918
|
+
return void 0;
|
|
1919
|
+
}
|
|
1920
|
+
onStartArray(depth) {
|
|
1921
|
+
if (this.phase === "seeking") {
|
|
1922
|
+
if (this.pointerMatches()) {
|
|
1923
|
+
this.beginTarget("array", depth);
|
|
1924
|
+
this.builder?.startContainer("array", 0);
|
|
1925
|
+
} else this.prefixMatches();
|
|
1926
|
+
} else if (this.phase === "capturing") {
|
|
1927
|
+
const stop = this.beginElement("array", depth);
|
|
1928
|
+
if (stop === false) return false;
|
|
1929
|
+
this.builder?.startContainer("array", depth - (this.windowed ? this.targetDepth + 1 : this.targetDepth));
|
|
1930
|
+
}
|
|
1931
|
+
this.path.startContainer("array");
|
|
1932
|
+
return void 0;
|
|
1933
|
+
}
|
|
1934
|
+
onKey(key, depth) {
|
|
1935
|
+
this.path.key(key);
|
|
1936
|
+
if (this.phase === "seeking") this.prefixMatches();
|
|
1937
|
+
else if (this.phase === "capturing") {
|
|
1938
|
+
this.trackKey(key);
|
|
1939
|
+
this.builder?.key(key, depth - (this.windowed ? this.targetDepth + 1 : this.targetDepth));
|
|
1940
|
+
}
|
|
1941
|
+
return void 0;
|
|
1942
|
+
}
|
|
1943
|
+
onEndObject(depth, memberCount) {
|
|
1944
|
+
this.trackObjectEnd();
|
|
1945
|
+
this.path.endContainer();
|
|
1946
|
+
this.path.advance();
|
|
1947
|
+
if (this.phase !== "capturing") return void 0;
|
|
1948
|
+
if (this.windowed) {
|
|
1949
|
+
if (depth === this.targetDepth) {
|
|
1950
|
+
this.phase = "done";
|
|
1951
|
+
return false;
|
|
1952
|
+
}
|
|
1953
|
+
this.builder?.endContainer("object", depth - (this.targetDepth + 1), memberCount);
|
|
1954
|
+
if (depth === this.targetDepth + 1) return this.finishBuilder();
|
|
1955
|
+
return void 0;
|
|
1956
|
+
}
|
|
1957
|
+
this.builder?.endContainer("object", depth - this.targetDepth, memberCount);
|
|
1958
|
+
if (depth === this.targetDepth) return this.finishBuilder();
|
|
1959
|
+
return void 0;
|
|
1960
|
+
}
|
|
1961
|
+
onEndArray(depth, length) {
|
|
1962
|
+
this.path.endContainer();
|
|
1963
|
+
this.path.advance();
|
|
1964
|
+
if (this.phase !== "capturing") return void 0;
|
|
1965
|
+
if (this.windowed) {
|
|
1966
|
+
if (depth === this.targetDepth) {
|
|
1967
|
+
this.phase = "done";
|
|
1968
|
+
return false;
|
|
1969
|
+
}
|
|
1970
|
+
this.builder?.endContainer("array", depth - (this.targetDepth + 1), length);
|
|
1971
|
+
if (depth === this.targetDepth + 1) return this.finishBuilder();
|
|
1972
|
+
return void 0;
|
|
1973
|
+
}
|
|
1974
|
+
this.builder?.endContainer("array", depth - this.targetDepth, length);
|
|
1975
|
+
if (depth === this.targetDepth) return this.finishBuilder();
|
|
1976
|
+
return void 0;
|
|
1977
|
+
}
|
|
1978
|
+
onScalar(scalar, depth) {
|
|
1979
|
+
let verdict;
|
|
1980
|
+
if (this.phase === "seeking") {
|
|
1981
|
+
if (this.pointerMatches()) {
|
|
1982
|
+
this.beginTarget(scalar.type, depth);
|
|
1983
|
+
this.builder?.scalar(scalar, 0);
|
|
1984
|
+
verdict = this.finishBuilder();
|
|
1985
|
+
} else this.prefixMatches();
|
|
1986
|
+
} else if (this.phase === "capturing") {
|
|
1987
|
+
const stop = this.beginElement(scalar.type, depth);
|
|
1988
|
+
if (stop === false) return false;
|
|
1989
|
+
if (this.windowed) {
|
|
1990
|
+
this.builder?.scalar(scalar, depth - (this.targetDepth + 1));
|
|
1991
|
+
if (depth === this.targetDepth + 1) verdict = this.finishBuilder();
|
|
1992
|
+
} else {
|
|
1993
|
+
this.builder?.scalar(scalar, depth - this.targetDepth);
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
this.path.advance();
|
|
1997
|
+
return verdict;
|
|
1998
|
+
}
|
|
1999
|
+
captureStrings(depth) {
|
|
2000
|
+
if (this.phase === "seeking") return this.pointerMatches();
|
|
2001
|
+
if (this.phase !== "capturing") return false;
|
|
2002
|
+
if (this.windowed && depth === this.targetDepth + 1) {
|
|
2003
|
+
return this.elementIndex >= this.windowOffset && this.elements.length < this.windowLimit;
|
|
2004
|
+
}
|
|
2005
|
+
return this.builder !== null && !this.builder.overBudget;
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
async function selectJson(path2, options = {}) {
|
|
2009
|
+
const stat = statDataFile(path2);
|
|
2010
|
+
if ("ok" in stat) return stat;
|
|
2011
|
+
const pointer = options.pointer ?? "";
|
|
2012
|
+
const segments = parseJsonPointer(pointer);
|
|
2013
|
+
if (segments instanceof Error) return refusal("invalid-argument", segments.message, { path: path2 });
|
|
2014
|
+
const windowed = options.offset !== void 0 || options.limit !== void 0;
|
|
2015
|
+
const offset = windowed ? Math.max(0, Math.floor(options.offset ?? 0)) : null;
|
|
2016
|
+
const limit = Math.max(1, Math.min(JSON_SELECT_MAX_LIMIT, Math.floor(options.limit ?? JSON_SELECT_DEFAULT_LIMIT)));
|
|
2017
|
+
const stats = { bytesRead: 0, bom: false };
|
|
2018
|
+
const sink = new SelectSink(segments, offset, limit);
|
|
2019
|
+
let stopped = false;
|
|
2020
|
+
try {
|
|
2021
|
+
stopped = (await runParser(path2, sink, options.signal, stats)).stopped;
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
return refusalFromError(error, path2, options.signal);
|
|
2024
|
+
}
|
|
2025
|
+
if (sink.tooLarge) {
|
|
2026
|
+
const where = pointer || "the document root";
|
|
2027
|
+
return refusal(
|
|
2028
|
+
"selection-too-large",
|
|
2029
|
+
windowed ? `an element of the array at ${where} exceeds the ${SELECT_BUDGET_CHARS}-character selection budget; select a deeper pointer into that element, or a window of 1 to isolate it` : `the value at ${where} exceeds the ${SELECT_BUDGET_CHARS}-character selection budget; select a deeper pointer or an array window with offset and limit`,
|
|
2030
|
+
{ path: path2 }
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
2033
|
+
if (!sink.found) {
|
|
2034
|
+
const matched = segments.slice(0, sink.deepestMatch);
|
|
2035
|
+
const matchedPointer = matched.map((segment) => `/${escapePointerSegment(segment)}`).join("");
|
|
2036
|
+
return refusal(
|
|
2037
|
+
"pointer-not-found",
|
|
2038
|
+
`no value at ${pointer}; the deepest existing prefix is ${matchedPointer === "" ? "the document root" : matchedPointer}`,
|
|
2039
|
+
{ path: path2 }
|
|
2040
|
+
);
|
|
2041
|
+
}
|
|
2042
|
+
const notes = [];
|
|
2043
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
2044
|
+
if (stopped) {
|
|
2045
|
+
notes.push("reading stopped once the selection was complete; the rest of the document was not checked for syntax");
|
|
2046
|
+
}
|
|
2047
|
+
if (sink.cutStrings > 0) {
|
|
2048
|
+
notes.push(
|
|
2049
|
+
`${sink.cutStrings} string(s) longer than ${STRING_CAPTURE_CAP} characters were cut; each is a $truncated placeholder with its full length`
|
|
2050
|
+
);
|
|
2051
|
+
}
|
|
2052
|
+
if (sink.duplicateCount > 0) {
|
|
2053
|
+
notes.push(`${sink.duplicateCount} duplicate object key(s) inside the selection; the last value was kept`);
|
|
2054
|
+
}
|
|
2055
|
+
const precision = {
|
|
2056
|
+
count: sink.issues.length,
|
|
2057
|
+
first: sink.issues.slice(0, PRECISION_FIRST_CAP)
|
|
2058
|
+
};
|
|
2059
|
+
const base = {
|
|
2060
|
+
ok: true,
|
|
2061
|
+
format: "json",
|
|
2062
|
+
path: path2,
|
|
2063
|
+
bytes: stat.size,
|
|
2064
|
+
bytesScanned: stats.bytesRead,
|
|
2065
|
+
view: sink.cutStrings > 0 ? cutView() : exactView(),
|
|
2066
|
+
pointer,
|
|
2067
|
+
precision,
|
|
2068
|
+
duplicateKeys: {
|
|
2069
|
+
count: sink.duplicateCount,
|
|
2070
|
+
first: sink.duplicateFirst,
|
|
2071
|
+
checkedFully: sink.duplicatesCheckedFully
|
|
2072
|
+
},
|
|
2073
|
+
notes
|
|
2074
|
+
};
|
|
2075
|
+
if (windowed) {
|
|
2076
|
+
if (sink.targetType !== "array") {
|
|
2077
|
+
return refusal(
|
|
2078
|
+
"invalid-argument",
|
|
2079
|
+
`offset and limit apply to an array target; the value at ${pointer || "the document root"} is ${sink.targetType ?? "unknown"}`,
|
|
2080
|
+
{ path: path2 }
|
|
2081
|
+
);
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
...base,
|
|
2085
|
+
elements: sink.elements,
|
|
2086
|
+
offset,
|
|
2087
|
+
limit,
|
|
2088
|
+
returned: sink.elements.length,
|
|
2089
|
+
hasMore: sink.hasMore
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
return { ...base, value: sink.value ?? null };
|
|
2093
|
+
}
|
|
2094
|
+
var ValidateSink = class {
|
|
2095
|
+
constructor(maxRows) {
|
|
2096
|
+
this.maxRows = maxRows;
|
|
2097
|
+
}
|
|
2098
|
+
maxRows;
|
|
2099
|
+
scanner = new StructureScanner();
|
|
2100
|
+
root = null;
|
|
2101
|
+
rows = 0;
|
|
2102
|
+
rowCount = null;
|
|
2103
|
+
stoppedAtRows = false;
|
|
2104
|
+
beginRow() {
|
|
2105
|
+
if (this.rows >= this.maxRows) {
|
|
2106
|
+
this.stoppedAtRows = true;
|
|
2107
|
+
return false;
|
|
2108
|
+
}
|
|
2109
|
+
this.rows += 1;
|
|
2110
|
+
return true;
|
|
2111
|
+
}
|
|
2112
|
+
onStartObject(depth) {
|
|
2113
|
+
if (depth === 0) this.root = "object";
|
|
2114
|
+
else if (depth === 1 && !this.beginRow()) return false;
|
|
2115
|
+
this.scanner.startContainer("object");
|
|
2116
|
+
return void 0;
|
|
2117
|
+
}
|
|
2118
|
+
onStartArray(depth) {
|
|
2119
|
+
if (depth === 0) this.root = "array";
|
|
2120
|
+
else if (depth === 1 && !this.beginRow()) return false;
|
|
2121
|
+
this.scanner.startContainer("array");
|
|
2122
|
+
return void 0;
|
|
2123
|
+
}
|
|
2124
|
+
onKey(key, depth) {
|
|
2125
|
+
if (depth === 1 && this.rows >= this.maxRows) {
|
|
2126
|
+
this.stoppedAtRows = true;
|
|
2127
|
+
return false;
|
|
2128
|
+
}
|
|
2129
|
+
this.scanner.key(key);
|
|
2130
|
+
return void 0;
|
|
2131
|
+
}
|
|
2132
|
+
onEndObject(depth, memberCount) {
|
|
2133
|
+
if (depth === 0) this.rowCount = memberCount;
|
|
2134
|
+
this.scanner.endContainer();
|
|
2135
|
+
return void 0;
|
|
2136
|
+
}
|
|
2137
|
+
onEndArray(depth, length) {
|
|
2138
|
+
if (depth === 0) this.rowCount = length;
|
|
2139
|
+
this.scanner.endContainer();
|
|
2140
|
+
return void 0;
|
|
2141
|
+
}
|
|
2142
|
+
onScalar(scalar, depth) {
|
|
2143
|
+
if (depth === 0) {
|
|
2144
|
+
this.root = scalar.type;
|
|
2145
|
+
this.rows = 1;
|
|
2146
|
+
this.rowCount = 1;
|
|
2147
|
+
} else if (depth === 1 && !this.beginRow()) return false;
|
|
2148
|
+
this.scanner.scalar(scalar);
|
|
2149
|
+
return void 0;
|
|
2150
|
+
}
|
|
2151
|
+
captureStrings() {
|
|
2152
|
+
return false;
|
|
2153
|
+
}
|
|
2154
|
+
};
|
|
2155
|
+
async function validateJson(path2, options = {}) {
|
|
2156
|
+
const stat = statDataFile(path2);
|
|
2157
|
+
if ("ok" in stat) return stat;
|
|
2158
|
+
const maxRows = resolveMaxRows(options.maxRows, JSON_DEFAULT_MAX_ROWS);
|
|
2159
|
+
const stats = { bytesRead: 0, bom: false };
|
|
2160
|
+
const sink = new ValidateSink(maxRows);
|
|
2161
|
+
const parser = new JsonStreamParser(sink);
|
|
2162
|
+
let syntaxError;
|
|
2163
|
+
try {
|
|
2164
|
+
let stopped = false;
|
|
2165
|
+
for await (const chunk of streamTextChunks(path2, { signal: options.signal, stats })) {
|
|
2166
|
+
if (!parser.push(chunk.text, chunk.byteOffset)) {
|
|
2167
|
+
stopped = true;
|
|
2168
|
+
break;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
if (!stopped) parser.end();
|
|
2172
|
+
throwIfAborted(options.signal, path2);
|
|
2173
|
+
} catch (error) {
|
|
2174
|
+
if (error instanceof DataRefusalError && (error.refusal.reason === "invalid-json" || error.refusal.reason === "nesting-too-deep")) {
|
|
2175
|
+
syntaxError = {
|
|
2176
|
+
message: error.refusal.message,
|
|
2177
|
+
...error.refusal.line !== void 0 ? { line: error.refusal.line } : {},
|
|
2178
|
+
...error.refusal.column !== void 0 ? { column: error.refusal.column } : {},
|
|
2179
|
+
...error.refusal.byteOffset !== void 0 ? { byteOffset: error.refusal.byteOffset } : {}
|
|
2180
|
+
};
|
|
2181
|
+
} else {
|
|
2182
|
+
return refusalFromError(error, path2, options.signal);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
const complete = !sink.stoppedAtRows;
|
|
2186
|
+
const notes = [];
|
|
2187
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
2188
|
+
if (!complete) {
|
|
2189
|
+
notes.push(
|
|
2190
|
+
`validation incomplete: stopped after ${sink.rows} top-level rows; pass maxRows null to validate the whole document`
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
if (sink.scanner.duplicateCount > 0)
|
|
2194
|
+
notes.push(`${sink.scanner.duplicateCount} duplicate object key(s); JSON.parse would keep the last value`);
|
|
2195
|
+
return {
|
|
2196
|
+
ok: true,
|
|
2197
|
+
format: "json",
|
|
2198
|
+
path: path2,
|
|
2199
|
+
bytes: stat.size,
|
|
2200
|
+
bytesScanned: stats.bytesRead,
|
|
2201
|
+
view: complete ? exactView() : sampledView(),
|
|
2202
|
+
valid: syntaxError !== void 0 ? false : complete ? true : null,
|
|
2203
|
+
complete,
|
|
2204
|
+
rowsScanned: sink.rows,
|
|
2205
|
+
rowCount: complete && syntaxError === void 0 ? sink.rowCount : null,
|
|
2206
|
+
root: sink.root,
|
|
2207
|
+
maxDepth: parser.maxDepth,
|
|
2208
|
+
duplicateKeys: sink.scanner.duplicates(),
|
|
2209
|
+
precision: sink.scanner.precision(),
|
|
2210
|
+
...syntaxError !== void 0 ? { syntaxError } : {},
|
|
2211
|
+
notes
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
var TextScanSink = class {
|
|
2215
|
+
scanner;
|
|
2216
|
+
root = null;
|
|
2217
|
+
keys = [];
|
|
2218
|
+
memberTypes = /* @__PURE__ */ new Map();
|
|
2219
|
+
currentKey = "";
|
|
2220
|
+
builder;
|
|
2221
|
+
constructor(pointerPrefix, budgetChars) {
|
|
2222
|
+
this.scanner = new StructureScanner(pointerPrefix);
|
|
2223
|
+
this.builder = budgetChars === null ? null : new JsonValueBuilder(budgetChars, "");
|
|
2224
|
+
}
|
|
2225
|
+
get value() {
|
|
2226
|
+
return this.builder?.value;
|
|
2227
|
+
}
|
|
2228
|
+
get valueTruncated() {
|
|
2229
|
+
return this.builder?.truncated ?? false;
|
|
2230
|
+
}
|
|
2231
|
+
noteMember(type, depth) {
|
|
2232
|
+
if (depth !== 1) return;
|
|
2233
|
+
if (this.root === "object") {
|
|
2234
|
+
if (!this.memberTypes.has(this.currentKey)) this.memberTypes.set(this.currentKey, type);
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
onStartObject(depth) {
|
|
2238
|
+
if (depth === 0) this.root = "object";
|
|
2239
|
+
this.noteMember("object", depth);
|
|
2240
|
+
this.scanner.startContainer("object");
|
|
2241
|
+
this.builder?.startContainer("object", depth);
|
|
2242
|
+
return void 0;
|
|
2243
|
+
}
|
|
2244
|
+
onStartArray(depth) {
|
|
2245
|
+
if (depth === 0) this.root = "array";
|
|
2246
|
+
this.noteMember("array", depth);
|
|
2247
|
+
this.scanner.startContainer("array");
|
|
2248
|
+
this.builder?.startContainer("array", depth);
|
|
2249
|
+
return void 0;
|
|
2250
|
+
}
|
|
2251
|
+
onKey(key, depth) {
|
|
2252
|
+
this.scanner.key(key);
|
|
2253
|
+
if (depth === 1) {
|
|
2254
|
+
this.currentKey = key;
|
|
2255
|
+
this.keys.push(key);
|
|
2256
|
+
}
|
|
2257
|
+
this.builder?.key(key, depth);
|
|
2258
|
+
return void 0;
|
|
2259
|
+
}
|
|
2260
|
+
onEndObject(depth, memberCount) {
|
|
2261
|
+
this.scanner.endContainer();
|
|
2262
|
+
this.builder?.endContainer("object", depth, memberCount);
|
|
2263
|
+
return void 0;
|
|
2264
|
+
}
|
|
2265
|
+
onEndArray(depth, length) {
|
|
2266
|
+
this.scanner.endContainer();
|
|
2267
|
+
this.builder?.endContainer("array", depth, length);
|
|
2268
|
+
return void 0;
|
|
2269
|
+
}
|
|
2270
|
+
onScalar(scalar, depth) {
|
|
2271
|
+
if (depth === 0) this.root = scalar.type;
|
|
2272
|
+
this.noteMember(scalar.type, depth);
|
|
2273
|
+
this.scanner.scalar(scalar);
|
|
2274
|
+
this.builder?.scalar(scalar, depth);
|
|
2275
|
+
return void 0;
|
|
2276
|
+
}
|
|
2277
|
+
captureStrings() {
|
|
2278
|
+
return this.builder !== null && !this.builder.overBudget;
|
|
2279
|
+
}
|
|
2280
|
+
};
|
|
2281
|
+
function scanJsonText(text, options = {}) {
|
|
2282
|
+
const sink = new TextScanSink(options.pointerPrefix ?? "", options.materializeBudgetChars ?? null);
|
|
2283
|
+
const parser = new JsonStreamParser(sink);
|
|
2284
|
+
parser.push(text, 0);
|
|
2285
|
+
parser.end();
|
|
2286
|
+
return {
|
|
2287
|
+
root: sink.root ?? "null",
|
|
2288
|
+
keys: sink.keys,
|
|
2289
|
+
memberTypes: sink.memberTypes,
|
|
2290
|
+
maxDepth: parser.maxDepth,
|
|
2291
|
+
duplicateKeys: sink.scanner.duplicateCount,
|
|
2292
|
+
precision: [...sink.scanner.precisionFirst],
|
|
2293
|
+
value: sink.value,
|
|
2294
|
+
valueTruncated: sink.valueTruncated
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
// src/tools/data/jsonl.ts
|
|
2299
|
+
init_esm_shims();
|
|
2300
|
+
var JSONL_DEFAULT_SAMPLE_ROWS = 10;
|
|
2301
|
+
var JSONL_DEFAULT_MAX_ROWS = 1e5;
|
|
2302
|
+
var KEY_HISTOGRAM_CAP = 500;
|
|
2303
|
+
var INVALID_FIRST_CAP = 10;
|
|
2304
|
+
function oversizedMessage(chars) {
|
|
2305
|
+
return `line is ${chars} characters, over the ${JSONL_MAX_LINE_CHARS}-character limit for one JSONL record; skipped without being read (a whole JSON document saved as .jsonl looks like this: read it with format json)`;
|
|
2306
|
+
}
|
|
2307
|
+
var JSONL_MAX_LINE_CHARS = 1048576;
|
|
2308
|
+
async function forEachLine(path2, signal, stats, visitor) {
|
|
2309
|
+
let carry = "";
|
|
2310
|
+
let skipping = false;
|
|
2311
|
+
let skippedChars = 0;
|
|
2312
|
+
let line = 0;
|
|
2313
|
+
let stopped = false;
|
|
2314
|
+
const emit = (text) => {
|
|
2315
|
+
line += 1;
|
|
2316
|
+
const body = text.endsWith("\r") ? text.slice(0, -1) : text;
|
|
2317
|
+
if (body.trim().length === 0) {
|
|
2318
|
+
visitor.onBlank?.(line);
|
|
2319
|
+
return true;
|
|
2320
|
+
}
|
|
2321
|
+
return visitor.onLine(body, line);
|
|
2322
|
+
};
|
|
2323
|
+
const emitOversized = (chars) => {
|
|
2324
|
+
line += 1;
|
|
2325
|
+
return visitor.onOversized(line, chars);
|
|
2326
|
+
};
|
|
2327
|
+
outer: for await (const chunk of streamTextChunks(path2, { signal, stats })) {
|
|
2328
|
+
const text = chunk.text;
|
|
2329
|
+
let start = 0;
|
|
2330
|
+
for (; ; ) {
|
|
2331
|
+
const newline = text.indexOf("\n", start);
|
|
2332
|
+
if (newline === -1) break;
|
|
2333
|
+
const span = newline - start;
|
|
2334
|
+
if (skipping) {
|
|
2335
|
+
skipping = false;
|
|
2336
|
+
if (!emitOversized(skippedChars + span)) {
|
|
2337
|
+
stopped = true;
|
|
2338
|
+
break outer;
|
|
2339
|
+
}
|
|
2340
|
+
} else if (carry.length + span > JSONL_MAX_LINE_CHARS) {
|
|
2341
|
+
const chars = carry.length + span;
|
|
2342
|
+
carry = "";
|
|
2343
|
+
if (!emitOversized(chars)) {
|
|
2344
|
+
stopped = true;
|
|
2345
|
+
break outer;
|
|
2346
|
+
}
|
|
2347
|
+
} else {
|
|
2348
|
+
const lineText = carry.length === 0 ? text.slice(start, newline) : carry + text.slice(start, newline);
|
|
2349
|
+
carry = "";
|
|
2350
|
+
if (!emit(lineText)) {
|
|
2351
|
+
stopped = true;
|
|
2352
|
+
break outer;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
start = newline + 1;
|
|
2356
|
+
}
|
|
2357
|
+
const rest = text.length - start;
|
|
2358
|
+
if (rest === 0) continue;
|
|
2359
|
+
if (skipping) skippedChars += rest;
|
|
2360
|
+
else if (carry.length + rest > JSONL_MAX_LINE_CHARS) {
|
|
2361
|
+
skipping = true;
|
|
2362
|
+
skippedChars = carry.length + rest;
|
|
2363
|
+
carry = "";
|
|
2364
|
+
} else carry += text.slice(start);
|
|
2365
|
+
}
|
|
2366
|
+
throwIfAborted(signal, path2);
|
|
2367
|
+
if (!stopped) {
|
|
2368
|
+
if (skipping) emitOversized(skippedChars);
|
|
2369
|
+
else if (carry.length > 0 && !emit(carry)) stopped = true;
|
|
2370
|
+
}
|
|
2371
|
+
return { lines: line, stopped };
|
|
2372
|
+
}
|
|
2373
|
+
async function inspectJsonl(path2, options = {}) {
|
|
2374
|
+
const stat = statDataFile(path2);
|
|
2375
|
+
if ("ok" in stat) return stat;
|
|
2376
|
+
const sampleRows = Math.max(0, Math.min(1e3, Math.floor(options.sampleRows ?? JSONL_DEFAULT_SAMPLE_ROWS)));
|
|
2377
|
+
const maxRows = resolveMaxRows(options.maxRows, JSONL_DEFAULT_MAX_ROWS);
|
|
2378
|
+
const stats = { bytesRead: 0, bom: false };
|
|
2379
|
+
const state = {
|
|
2380
|
+
records: 0,
|
|
2381
|
+
blank: 0,
|
|
2382
|
+
stoppedAtRows: false,
|
|
2383
|
+
invalidCount: 0,
|
|
2384
|
+
invalidFirst: [],
|
|
2385
|
+
rootTypes: /* @__PURE__ */ new Map(),
|
|
2386
|
+
keys: /* @__PURE__ */ new Map(),
|
|
2387
|
+
keysTruncated: false,
|
|
2388
|
+
keyTypes: /* @__PURE__ */ new Map(),
|
|
2389
|
+
maxDepth: 0,
|
|
2390
|
+
duplicateCount: 0,
|
|
2391
|
+
duplicateFirstLine: null,
|
|
2392
|
+
precisionCount: 0,
|
|
2393
|
+
precisionFirst: [],
|
|
2394
|
+
sample: [],
|
|
2395
|
+
sampleCuts: 0
|
|
2396
|
+
};
|
|
2397
|
+
let scanOutcome;
|
|
2398
|
+
try {
|
|
2399
|
+
scanOutcome = await forEachLine(path2, options.signal, stats, {
|
|
2400
|
+
onBlank() {
|
|
2401
|
+
state.blank += 1;
|
|
2402
|
+
},
|
|
2403
|
+
onOversized(line, chars) {
|
|
2404
|
+
if (state.records >= maxRows) {
|
|
2405
|
+
state.stoppedAtRows = true;
|
|
2406
|
+
return false;
|
|
2407
|
+
}
|
|
2408
|
+
state.records += 1;
|
|
2409
|
+
state.invalidCount += 1;
|
|
2410
|
+
if (state.invalidFirst.length < INVALID_FIRST_CAP) {
|
|
2411
|
+
state.invalidFirst.push({ line, message: oversizedMessage(chars) });
|
|
2412
|
+
}
|
|
2413
|
+
return true;
|
|
2414
|
+
},
|
|
2415
|
+
onLine(text, line) {
|
|
2416
|
+
if (state.records >= maxRows) {
|
|
2417
|
+
state.stoppedAtRows = true;
|
|
2418
|
+
return false;
|
|
2419
|
+
}
|
|
2420
|
+
state.records += 1;
|
|
2421
|
+
const wantSample = state.sample.length < sampleRows;
|
|
2422
|
+
let scan;
|
|
2423
|
+
try {
|
|
2424
|
+
scan = scanJsonText(text, {
|
|
2425
|
+
pointerPrefix: "",
|
|
2426
|
+
materializeBudgetChars: wantSample ? SAMPLE_BUDGET_CHARS : null
|
|
2427
|
+
});
|
|
2428
|
+
} catch (error) {
|
|
2429
|
+
if (!(error instanceof DataRefusalError)) throw error;
|
|
2430
|
+
state.invalidCount += 1;
|
|
2431
|
+
if (state.invalidFirst.length < INVALID_FIRST_CAP) {
|
|
2432
|
+
state.invalidFirst.push({ line, message: error.refusal.message });
|
|
2433
|
+
}
|
|
2434
|
+
return true;
|
|
2435
|
+
}
|
|
2436
|
+
state.rootTypes.set(scan.root, (state.rootTypes.get(scan.root) ?? 0) + 1);
|
|
2437
|
+
if (scan.root === "object") {
|
|
2438
|
+
for (const key of new Set(scan.keys)) {
|
|
2439
|
+
const seen = state.keys.get(key);
|
|
2440
|
+
if (seen === void 0) {
|
|
2441
|
+
if (state.keys.size >= KEY_HISTOGRAM_CAP) {
|
|
2442
|
+
state.keysTruncated = true;
|
|
2443
|
+
continue;
|
|
2444
|
+
}
|
|
2445
|
+
state.keys.set(key, 1);
|
|
2446
|
+
} else state.keys.set(key, seen + 1);
|
|
2447
|
+
const type = scan.memberTypes.get(key);
|
|
2448
|
+
if (type === void 0) continue;
|
|
2449
|
+
let types = state.keyTypes.get(key);
|
|
2450
|
+
if (types === void 0) {
|
|
2451
|
+
types = /* @__PURE__ */ new Map();
|
|
2452
|
+
state.keyTypes.set(key, types);
|
|
2453
|
+
}
|
|
2454
|
+
types.set(type, (types.get(type) ?? 0) + 1);
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
if (scan.maxDepth > state.maxDepth) state.maxDepth = scan.maxDepth;
|
|
2458
|
+
if (scan.duplicateKeys > 0) {
|
|
2459
|
+
state.duplicateCount += scan.duplicateKeys;
|
|
2460
|
+
if (state.duplicateFirstLine === null) state.duplicateFirstLine = line;
|
|
2461
|
+
}
|
|
2462
|
+
for (const issue of scan.precision) {
|
|
2463
|
+
state.precisionCount += 1;
|
|
2464
|
+
if (state.precisionFirst.length < PRECISION_FIRST_CAP) state.precisionFirst.push({ ...issue, line });
|
|
2465
|
+
}
|
|
2466
|
+
if (wantSample && scan.value !== void 0) {
|
|
2467
|
+
state.sample.push({ line, value: scan.value });
|
|
2468
|
+
if (scan.valueTruncated) state.sampleCuts += 1;
|
|
2469
|
+
}
|
|
2470
|
+
return true;
|
|
2471
|
+
}
|
|
2472
|
+
});
|
|
2473
|
+
} catch (error) {
|
|
2474
|
+
return refusalFromError(error, path2, options.signal);
|
|
2475
|
+
}
|
|
2476
|
+
const sampled = state.stoppedAtRows;
|
|
2477
|
+
const notes = [];
|
|
2478
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
2479
|
+
if (sampled) notes.push(sampledNotice(state.records, "records"));
|
|
2480
|
+
if (state.invalidCount > 0)
|
|
2481
|
+
notes.push(`${state.invalidCount} line(s) are not valid JSON and are listed with their fault`);
|
|
2482
|
+
if (state.keysTruncated) notes.push(`key histogram capped at ${KEY_HISTOGRAM_CAP} distinct keys`);
|
|
2483
|
+
if (state.sampleCuts > 0) {
|
|
2484
|
+
notes.push(
|
|
2485
|
+
`${state.sampleCuts} sample record(s) were cut to the preview budget and carry $summary or $truncated placeholders; the counts are exact`
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
const keyTypes = {};
|
|
2489
|
+
for (const [key, types] of state.keyTypes) keyTypes[key] = histogramRecord(types);
|
|
2490
|
+
return {
|
|
2491
|
+
ok: true,
|
|
2492
|
+
format: "jsonl",
|
|
2493
|
+
path: path2,
|
|
2494
|
+
bytes: stat.size,
|
|
2495
|
+
bytesScanned: stats.bytesRead,
|
|
2496
|
+
view: sampled ? sampledView() : exactView(),
|
|
2497
|
+
rowsScanned: state.records,
|
|
2498
|
+
rowCount: sampled ? null : state.records,
|
|
2499
|
+
linesScanned: scanOutcome.lines,
|
|
2500
|
+
blankLines: state.blank,
|
|
2501
|
+
invalid: { count: state.invalidCount, first: state.invalidFirst },
|
|
2502
|
+
rootTypes: histogramRecord(state.rootTypes),
|
|
2503
|
+
keys: { histogram: histogramRecord(state.keys), truncated: state.keysTruncated },
|
|
2504
|
+
keyTypes,
|
|
2505
|
+
maxDepth: state.maxDepth,
|
|
2506
|
+
duplicateKeys: { count: state.duplicateCount, firstLine: state.duplicateFirstLine },
|
|
2507
|
+
precision: { count: state.precisionCount, first: state.precisionFirst },
|
|
2508
|
+
sample: state.sample,
|
|
2509
|
+
notes
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
var JSONL_SELECT_DEFAULT_LIMIT = 50;
|
|
2513
|
+
var JSONL_SELECT_MAX_LIMIT = 1e3;
|
|
2514
|
+
var SELECT_LINE_BUDGET_CHARS = 1048576;
|
|
2515
|
+
async function selectJsonl(path2, options = {}) {
|
|
2516
|
+
const stat = statDataFile(path2);
|
|
2517
|
+
if ("ok" in stat) return stat;
|
|
2518
|
+
const offset = Math.max(0, Math.floor(options.offset ?? 0));
|
|
2519
|
+
const limit = Math.max(1, Math.min(JSONL_SELECT_MAX_LIMIT, Math.floor(options.limit ?? JSONL_SELECT_DEFAULT_LIMIT)));
|
|
2520
|
+
const stats = { bytesRead: 0, bom: false };
|
|
2521
|
+
const state = {
|
|
2522
|
+
records: 0,
|
|
2523
|
+
hasMore: false,
|
|
2524
|
+
out: [],
|
|
2525
|
+
precisionCount: 0,
|
|
2526
|
+
precisionFirst: [],
|
|
2527
|
+
duplicateCount: 0,
|
|
2528
|
+
duplicateFirstLine: null
|
|
2529
|
+
};
|
|
2530
|
+
try {
|
|
2531
|
+
await forEachLine(path2, options.signal, stats, {
|
|
2532
|
+
onOversized(line, chars) {
|
|
2533
|
+
const index = state.records;
|
|
2534
|
+
state.records += 1;
|
|
2535
|
+
if (index < offset) return true;
|
|
2536
|
+
if (state.out.length >= limit) {
|
|
2537
|
+
state.hasMore = true;
|
|
2538
|
+
return false;
|
|
2539
|
+
}
|
|
2540
|
+
state.out.push({ line, error: oversizedMessage(chars) });
|
|
2541
|
+
return true;
|
|
2542
|
+
},
|
|
2543
|
+
onLine(text, line) {
|
|
2544
|
+
const index = state.records;
|
|
2545
|
+
state.records += 1;
|
|
2546
|
+
if (index < offset) return true;
|
|
2547
|
+
if (state.out.length >= limit) {
|
|
2548
|
+
state.hasMore = true;
|
|
2549
|
+
return false;
|
|
2550
|
+
}
|
|
2551
|
+
try {
|
|
2552
|
+
const scan = scanJsonText(text, { materializeBudgetChars: SELECT_LINE_BUDGET_CHARS });
|
|
2553
|
+
for (const issue of scan.precision) {
|
|
2554
|
+
state.precisionCount += 1;
|
|
2555
|
+
if (state.precisionFirst.length < PRECISION_FIRST_CAP) state.precisionFirst.push({ ...issue, line });
|
|
2556
|
+
}
|
|
2557
|
+
if (scan.duplicateKeys > 0) {
|
|
2558
|
+
state.duplicateCount += scan.duplicateKeys;
|
|
2559
|
+
if (state.duplicateFirstLine === null) state.duplicateFirstLine = line;
|
|
2560
|
+
}
|
|
2561
|
+
state.out.push({ line, value: scan.value ?? null, truncated: scan.valueTruncated });
|
|
2562
|
+
} catch (error) {
|
|
2563
|
+
if (!(error instanceof DataRefusalError)) throw error;
|
|
2564
|
+
state.out.push({ line, error: error.refusal.message });
|
|
2565
|
+
}
|
|
2566
|
+
return true;
|
|
2567
|
+
}
|
|
2568
|
+
});
|
|
2569
|
+
} catch (error) {
|
|
2570
|
+
return refusalFromError(error, path2, options.signal);
|
|
2571
|
+
}
|
|
2572
|
+
const notes = [];
|
|
2573
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
2574
|
+
const truncated = state.out.filter((record) => "truncated" in record && record.truncated).length;
|
|
2575
|
+
if (truncated > 0) {
|
|
2576
|
+
notes.push(
|
|
2577
|
+
`${truncated} record(s) were cut to the per-record budget or the string cap; $summary and $truncated placeholders mark the cuts`
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2580
|
+
if (state.duplicateCount > 0) {
|
|
2581
|
+
notes.push(`${state.duplicateCount} duplicate object key(s) in the returned records; the last value was kept`);
|
|
2582
|
+
}
|
|
2583
|
+
return {
|
|
2584
|
+
ok: true,
|
|
2585
|
+
format: "jsonl",
|
|
2586
|
+
path: path2,
|
|
2587
|
+
bytes: stat.size,
|
|
2588
|
+
bytesScanned: stats.bytesRead,
|
|
2589
|
+
view: truncated > 0 ? cutView() : exactView(),
|
|
2590
|
+
offset,
|
|
2591
|
+
limit,
|
|
2592
|
+
returned: state.out.length,
|
|
2593
|
+
hasMore: state.hasMore,
|
|
2594
|
+
rowsScanned: state.records,
|
|
2595
|
+
records: state.out,
|
|
2596
|
+
precision: { count: state.precisionCount, first: state.precisionFirst },
|
|
2597
|
+
duplicateKeys: { count: state.duplicateCount, firstLine: state.duplicateFirstLine },
|
|
2598
|
+
notes
|
|
2599
|
+
};
|
|
2600
|
+
}
|
|
2601
|
+
async function validateJsonl(path2, options = {}) {
|
|
2602
|
+
const stat = statDataFile(path2);
|
|
2603
|
+
if ("ok" in stat) return stat;
|
|
2604
|
+
const maxRows = resolveMaxRows(options.maxRows, JSONL_DEFAULT_MAX_ROWS);
|
|
2605
|
+
const stats = { bytesRead: 0, bom: false };
|
|
2606
|
+
const state = {
|
|
2607
|
+
records: 0,
|
|
2608
|
+
blank: 0,
|
|
2609
|
+
stoppedAtRows: false,
|
|
2610
|
+
invalidCount: 0,
|
|
2611
|
+
invalidFirst: [],
|
|
2612
|
+
duplicateCount: 0,
|
|
2613
|
+
duplicateFirstLine: null,
|
|
2614
|
+
precisionCount: 0,
|
|
2615
|
+
precisionFirst: []
|
|
2616
|
+
};
|
|
2617
|
+
let scanOutcome;
|
|
2618
|
+
try {
|
|
2619
|
+
scanOutcome = await forEachLine(path2, options.signal, stats, {
|
|
2620
|
+
onBlank() {
|
|
2621
|
+
state.blank += 1;
|
|
2622
|
+
},
|
|
2623
|
+
onOversized(line, chars) {
|
|
2624
|
+
if (state.records >= maxRows) {
|
|
2625
|
+
state.stoppedAtRows = true;
|
|
2626
|
+
return false;
|
|
2627
|
+
}
|
|
2628
|
+
state.records += 1;
|
|
2629
|
+
state.invalidCount += 1;
|
|
2630
|
+
if (state.invalidFirst.length < INVALID_FIRST_CAP) {
|
|
2631
|
+
state.invalidFirst.push({ line, message: oversizedMessage(chars) });
|
|
2632
|
+
}
|
|
2633
|
+
return true;
|
|
2634
|
+
},
|
|
2635
|
+
onLine(text, line) {
|
|
2636
|
+
if (state.records >= maxRows) {
|
|
2637
|
+
state.stoppedAtRows = true;
|
|
2638
|
+
return false;
|
|
2639
|
+
}
|
|
2640
|
+
state.records += 1;
|
|
2641
|
+
try {
|
|
2642
|
+
const scan = scanJsonText(text);
|
|
2643
|
+
if (scan.duplicateKeys > 0) {
|
|
2644
|
+
state.duplicateCount += scan.duplicateKeys;
|
|
2645
|
+
if (state.duplicateFirstLine === null) state.duplicateFirstLine = line;
|
|
2646
|
+
}
|
|
2647
|
+
for (const issue of scan.precision) {
|
|
2648
|
+
state.precisionCount += 1;
|
|
2649
|
+
if (state.precisionFirst.length < PRECISION_FIRST_CAP) state.precisionFirst.push({ ...issue, line });
|
|
2650
|
+
}
|
|
2651
|
+
} catch (error) {
|
|
2652
|
+
if (!(error instanceof DataRefusalError)) throw error;
|
|
2653
|
+
state.invalidCount += 1;
|
|
2654
|
+
if (state.invalidFirst.length < INVALID_FIRST_CAP) {
|
|
2655
|
+
state.invalidFirst.push({ line, message: error.refusal.message });
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
return true;
|
|
2659
|
+
}
|
|
2660
|
+
});
|
|
2661
|
+
} catch (error) {
|
|
2662
|
+
return refusalFromError(error, path2, options.signal);
|
|
2663
|
+
}
|
|
2664
|
+
const complete = !state.stoppedAtRows;
|
|
2665
|
+
const notes = [];
|
|
2666
|
+
if (stats.bom) notes.push("a UTF-8 byte-order mark was stripped");
|
|
2667
|
+
if (!complete) {
|
|
2668
|
+
notes.push(
|
|
2669
|
+
`validation incomplete: stopped after ${state.records} records; pass maxRows null to validate the whole file`
|
|
2670
|
+
);
|
|
2671
|
+
}
|
|
2672
|
+
if (state.invalidCount > 0) notes.push(`${state.invalidCount} line(s) are not valid JSON`);
|
|
2673
|
+
if (state.duplicateCount > 0)
|
|
2674
|
+
notes.push(`${state.duplicateCount} duplicate object key(s); JSON.parse would keep the last value`);
|
|
2675
|
+
return {
|
|
2676
|
+
ok: true,
|
|
2677
|
+
format: "jsonl",
|
|
2678
|
+
path: path2,
|
|
2679
|
+
bytes: stat.size,
|
|
2680
|
+
bytesScanned: stats.bytesRead,
|
|
2681
|
+
view: complete ? exactView() : sampledView(),
|
|
2682
|
+
valid: state.invalidCount > 0 ? false : complete ? true : null,
|
|
2683
|
+
complete,
|
|
2684
|
+
rowsScanned: state.records,
|
|
2685
|
+
rowCount: complete ? state.records : null,
|
|
2686
|
+
linesScanned: scanOutcome.lines,
|
|
2687
|
+
blankLines: state.blank,
|
|
2688
|
+
invalid: { count: state.invalidCount, first: state.invalidFirst },
|
|
2689
|
+
duplicateKeys: { count: state.duplicateCount, firstLine: state.duplicateFirstLine },
|
|
2690
|
+
precision: { count: state.precisionCount, first: state.precisionFirst },
|
|
2691
|
+
notes
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
// src/tools/data/index.ts
|
|
2696
|
+
var EXTENSION_FORMATS = {
|
|
2697
|
+
".csv": "csv",
|
|
2698
|
+
".tsv": "tsv",
|
|
2699
|
+
".tab": "tsv",
|
|
2700
|
+
".json": "json",
|
|
2701
|
+
".jsonl": "jsonl",
|
|
2702
|
+
".ndjson": "jsonl"
|
|
2703
|
+
};
|
|
2704
|
+
var SNIFF_BYTES = 4096;
|
|
2705
|
+
async function detectDataFormat(path2, explicit) {
|
|
2706
|
+
if (explicit !== void 0 && explicit !== null) {
|
|
2707
|
+
const normalized = explicit.trim().toLowerCase();
|
|
2708
|
+
return isDataFormat(normalized) ? normalized : null;
|
|
2709
|
+
}
|
|
2710
|
+
const byExtension = EXTENSION_FORMATS[extname(path2).toLowerCase()];
|
|
2711
|
+
if (byExtension !== void 0) return byExtension;
|
|
2712
|
+
let text;
|
|
2713
|
+
try {
|
|
2714
|
+
const handle = await open(path2, "r");
|
|
2715
|
+
try {
|
|
2716
|
+
const buffer = Buffer.alloc(SNIFF_BYTES);
|
|
2717
|
+
const { bytesRead } = await handle.read(buffer, 0, SNIFF_BYTES, 0);
|
|
2718
|
+
text = buffer.subarray(0, bytesRead).toString("utf8");
|
|
2719
|
+
} finally {
|
|
2720
|
+
await handle.close();
|
|
2721
|
+
}
|
|
2722
|
+
} catch {
|
|
2723
|
+
return null;
|
|
2724
|
+
}
|
|
2725
|
+
if (text.startsWith("\uFEFF")) text = text.slice(1);
|
|
2726
|
+
const trimmed = text.trimStart();
|
|
2727
|
+
if (trimmed.length === 0) return null;
|
|
2728
|
+
const first = trimmed[0];
|
|
2729
|
+
if (first === "[" || first === "{") {
|
|
2730
|
+
const lines = trimmed.split(/\r?\n/u).filter((line) => line.trim().length > 0);
|
|
2731
|
+
const second = lines[1]?.trimStart()[0];
|
|
2732
|
+
if (lines.length > 1 && (second === "{" || second === "[") && (lines[0] ?? "").trimEnd().endsWith("}")) {
|
|
2733
|
+
return "jsonl";
|
|
2734
|
+
}
|
|
2735
|
+
return "json";
|
|
2736
|
+
}
|
|
2737
|
+
const firstLine = trimmed.split(/\r?\n/u)[0] ?? "";
|
|
2738
|
+
if (firstLine.includes(" ")) return "tsv";
|
|
2739
|
+
if (firstLine.includes(",") || firstLine.includes(";") || firstLine.includes("|")) return "csv";
|
|
2740
|
+
return null;
|
|
2741
|
+
}
|
|
2742
|
+
function unsupported(path2, explicit) {
|
|
2743
|
+
const named = explicit === void 0 || explicit === null ? "" : ` (${JSON.stringify(explicit)})`;
|
|
2744
|
+
return refusal(
|
|
2745
|
+
"unsupported-format",
|
|
2746
|
+
`${path2} is not a supported structured-data format${named}; supported formats are ${DATA_FORMATS.join(", ")}. Pass format explicitly for a file with an unusual extension, or use run_script with a library for binary scientific formats.`,
|
|
2747
|
+
{ path: path2, supported: DATA_FORMATS }
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
async function inspectData(path2, options = {}) {
|
|
2751
|
+
const stat = statDataFile(path2);
|
|
2752
|
+
if ("ok" in stat) return stat;
|
|
2753
|
+
const format = await detectDataFormat(path2, options.format);
|
|
2754
|
+
if (format === null) return unsupported(path2, options.format);
|
|
2755
|
+
const shared = {
|
|
2756
|
+
...options.sampleRows !== void 0 ? { sampleRows: options.sampleRows } : {},
|
|
2757
|
+
...options.maxRows !== void 0 ? { maxRows: options.maxRows } : {},
|
|
2758
|
+
signal: options.signal
|
|
2759
|
+
};
|
|
2760
|
+
try {
|
|
2761
|
+
switch (format) {
|
|
2762
|
+
case "csv":
|
|
2763
|
+
case "tsv":
|
|
2764
|
+
return await inspectCsv(path2, {
|
|
2765
|
+
...shared,
|
|
2766
|
+
format,
|
|
2767
|
+
...options.delimiter !== void 0 ? { delimiter: options.delimiter } : {},
|
|
2768
|
+
...options.header !== void 0 ? { header: options.header } : {}
|
|
2769
|
+
});
|
|
2770
|
+
case "json":
|
|
2771
|
+
return await inspectJson(path2, shared);
|
|
2772
|
+
case "jsonl":
|
|
2773
|
+
return await inspectJsonl(path2, shared);
|
|
2774
|
+
}
|
|
2775
|
+
} catch (error) {
|
|
2776
|
+
return refusalFromError(error, path2, options.signal);
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
async function selectData(path2, options = {}) {
|
|
2780
|
+
const stat = statDataFile(path2);
|
|
2781
|
+
if ("ok" in stat) return stat;
|
|
2782
|
+
const format = await detectDataFormat(path2, options.format);
|
|
2783
|
+
if (format === null) return unsupported(path2, options.format);
|
|
2784
|
+
const window = {
|
|
2785
|
+
...options.offset !== void 0 ? { offset: options.offset } : {},
|
|
2786
|
+
...options.limit !== void 0 ? { limit: options.limit } : {},
|
|
2787
|
+
signal: options.signal
|
|
2788
|
+
};
|
|
2789
|
+
try {
|
|
2790
|
+
switch (format) {
|
|
2791
|
+
case "csv":
|
|
2792
|
+
case "tsv":
|
|
2793
|
+
return await selectCsv(path2, {
|
|
2794
|
+
...window,
|
|
2795
|
+
format,
|
|
2796
|
+
...options.delimiter !== void 0 ? { delimiter: options.delimiter } : {},
|
|
2797
|
+
...options.header !== void 0 ? { header: options.header } : {},
|
|
2798
|
+
...options.columns !== void 0 ? { columns: options.columns } : {}
|
|
2799
|
+
});
|
|
2800
|
+
case "json":
|
|
2801
|
+
if (options.columns !== void 0) {
|
|
2802
|
+
return refusal("invalid-argument", "columns applies to CSV/TSV; use pointer for a JSON document", { path: path2 });
|
|
2803
|
+
}
|
|
2804
|
+
return await selectJson(path2, {
|
|
2805
|
+
...window,
|
|
2806
|
+
...options.pointer !== void 0 ? { pointer: options.pointer } : {}
|
|
2807
|
+
});
|
|
2808
|
+
case "jsonl":
|
|
2809
|
+
if (options.pointer !== void 0) {
|
|
2810
|
+
return refusal(
|
|
2811
|
+
"invalid-argument",
|
|
2812
|
+
"pointer applies to a JSON document; JSONL selects records by offset and limit",
|
|
2813
|
+
{
|
|
2814
|
+
path: path2
|
|
2815
|
+
}
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
return await selectJsonl(path2, window);
|
|
2819
|
+
}
|
|
2820
|
+
} catch (error) {
|
|
2821
|
+
return refusalFromError(error, path2, options.signal);
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
async function validateData(path2, options = {}) {
|
|
2825
|
+
const stat = statDataFile(path2);
|
|
2826
|
+
if ("ok" in stat) return stat;
|
|
2827
|
+
const format = await detectDataFormat(path2, options.format);
|
|
2828
|
+
if (format === null) return unsupported(path2, options.format);
|
|
2829
|
+
const shared = {
|
|
2830
|
+
...options.maxRows !== void 0 ? { maxRows: options.maxRows } : {},
|
|
2831
|
+
signal: options.signal
|
|
2832
|
+
};
|
|
2833
|
+
try {
|
|
2834
|
+
switch (format) {
|
|
2835
|
+
case "csv":
|
|
2836
|
+
case "tsv":
|
|
2837
|
+
return await validateCsv(path2, {
|
|
2838
|
+
...shared,
|
|
2839
|
+
format,
|
|
2840
|
+
...options.delimiter !== void 0 ? { delimiter: options.delimiter } : {},
|
|
2841
|
+
...options.header !== void 0 ? { header: options.header } : {}
|
|
2842
|
+
});
|
|
2843
|
+
case "json":
|
|
2844
|
+
return await validateJson(path2, shared);
|
|
2845
|
+
case "jsonl":
|
|
2846
|
+
return await validateJsonl(path2, shared);
|
|
2847
|
+
}
|
|
2848
|
+
} catch (error) {
|
|
2849
|
+
return refusalFromError(error, path2, options.signal);
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
// src/tools/gateway/data-tool.ts
|
|
2854
|
+
function isDataOp(value) {
|
|
2855
|
+
return DATA_OPS.includes(value);
|
|
2856
|
+
}
|
|
2857
|
+
function countResult(op, payload) {
|
|
2858
|
+
if (op === "select") {
|
|
2859
|
+
const result = payload;
|
|
2860
|
+
const rows = result.rows ?? result.records ?? result.elements;
|
|
2861
|
+
const returned = typeof result.returned === "number" ? result.returned : Array.isArray(rows) ? rows.length : 1;
|
|
2862
|
+
const offset = typeof result.offset === "number" ? result.offset : 0;
|
|
2863
|
+
const limit = typeof result.limit === "number" ? result.limit : returned;
|
|
2864
|
+
const hasMore = result.hasMore === true;
|
|
2865
|
+
const total = typeof result.total === "number" ? result.total : hasMore ? null : offset + returned;
|
|
2866
|
+
return {
|
|
2867
|
+
unit: "entries",
|
|
2868
|
+
shownCount: returned,
|
|
2869
|
+
totalCount: total,
|
|
2870
|
+
truncated: hasMore,
|
|
2871
|
+
...hasMore ? { next: `offset=${offset + limit}` } : {}
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
return { unit: "results", shownCount: 1, totalCount: 1, truncated: false };
|
|
2875
|
+
}
|
|
2876
|
+
function describeDataView(view) {
|
|
2877
|
+
const flags = typeof view === "object" && view !== null ? view : {};
|
|
2878
|
+
if (flags.exact === true) return "exact";
|
|
2879
|
+
const parts = [...flags.sampled === true ? ["sampled"] : [], ...flags.converted === true ? ["converted"] : []];
|
|
2880
|
+
return parts.length > 0 ? parts.join(", ") : "value cut to budget";
|
|
2881
|
+
}
|
|
2882
|
+
function refusalResult(op, refusal2) {
|
|
2883
|
+
return {
|
|
2884
|
+
kind: "error",
|
|
2885
|
+
message: `data: ${op} refused (${refusal2.reason}): ${refusal2.message}`,
|
|
2886
|
+
details: { refusal: refusal2 }
|
|
2887
|
+
};
|
|
2888
|
+
}
|
|
2889
|
+
function createDataTool(deps = {}) {
|
|
2890
|
+
const getCwd = deps.getCwd ?? (() => process.cwd());
|
|
2891
|
+
return {
|
|
2892
|
+
...dataToolSurface,
|
|
2893
|
+
prepareAdmissionArguments: (args) => prepareDataAdmissionArguments(args, getCwd()),
|
|
2894
|
+
async run(rawArgs, options) {
|
|
2895
|
+
const args = prepareDataArguments(rawArgs);
|
|
2896
|
+
const op = typeof args.op === "string" ? args.op : "";
|
|
2897
|
+
if (!isDataOp(op)) {
|
|
2898
|
+
return { kind: "error", message: `data: op must be inspect, select, or validate; got '${op}'` };
|
|
2899
|
+
}
|
|
2900
|
+
if (typeof args.path !== "string" || args.path.trim().length === 0) {
|
|
2901
|
+
return { kind: "error", message: "data: path is required" };
|
|
2902
|
+
}
|
|
2903
|
+
const target = resolveToCwd(args.path.trim(), getCwd());
|
|
2904
|
+
const reservation = reserveObservation(DATA_OBSERVATION_SELF_CAP_BYTES, options);
|
|
2905
|
+
if (reservation.exhausted) {
|
|
2906
|
+
return observationBudgetExhausted({
|
|
2907
|
+
tool: DATA_TOOL_NAME,
|
|
2908
|
+
unit: op === "select" ? "entries" : "results",
|
|
2909
|
+
reservation,
|
|
2910
|
+
subject: `${op} ${path.relative(getCwd(), target) || target}`,
|
|
2911
|
+
hint: "Continue in a follow-up turn."
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
commitObservationReservation(reservation);
|
|
2915
|
+
try {
|
|
2916
|
+
const format = typeof args.format === "string" ? args.format : void 0;
|
|
2917
|
+
const delimiter = typeof args.delimiter === "string" ? args.delimiter : void 0;
|
|
2918
|
+
const header = headerArg(args.header);
|
|
2919
|
+
const signal = options?.signal;
|
|
2920
|
+
let result;
|
|
2921
|
+
if (op === "inspect") {
|
|
2922
|
+
const inspectOptions = {
|
|
2923
|
+
...format !== void 0 ? { format } : {},
|
|
2924
|
+
...delimiter !== void 0 ? { delimiter } : {},
|
|
2925
|
+
...header !== void 0 ? { header } : {},
|
|
2926
|
+
...typeof args.sample_rows === "number" ? { sampleRows: args.sample_rows } : {},
|
|
2927
|
+
...args.max_rows === null || typeof args.max_rows === "number" ? { maxRows: args.max_rows } : {},
|
|
2928
|
+
signal
|
|
2929
|
+
};
|
|
2930
|
+
result = await inspectData(target, inspectOptions);
|
|
2931
|
+
} else if (op === "select") {
|
|
2932
|
+
const selectOptions = {
|
|
2933
|
+
...format !== void 0 ? { format } : {},
|
|
2934
|
+
...delimiter !== void 0 ? { delimiter } : {},
|
|
2935
|
+
...header !== void 0 ? { header } : {},
|
|
2936
|
+
...typeof args.offset === "number" ? { offset: args.offset } : {},
|
|
2937
|
+
...typeof args.limit === "number" ? { limit: args.limit } : {},
|
|
2938
|
+
...Array.isArray(args.columns) ? { columns: args.columns } : {},
|
|
2939
|
+
...typeof args.pointer === "string" ? { pointer: args.pointer } : {},
|
|
2940
|
+
signal
|
|
2941
|
+
};
|
|
2942
|
+
result = await selectData(target, selectOptions);
|
|
2943
|
+
} else {
|
|
2944
|
+
const validateOptions = {
|
|
2945
|
+
...format !== void 0 ? { format } : {},
|
|
2946
|
+
...delimiter !== void 0 ? { delimiter } : {},
|
|
2947
|
+
...header !== void 0 ? { header } : {},
|
|
2948
|
+
...args.max_rows === null || typeof args.max_rows === "number" ? { maxRows: args.max_rows } : {},
|
|
2949
|
+
signal
|
|
2950
|
+
};
|
|
2951
|
+
result = await validateData(target, validateOptions);
|
|
2952
|
+
}
|
|
2953
|
+
if (isDataRefusal(result)) {
|
|
2954
|
+
releaseObservation(reservation);
|
|
2955
|
+
return refusalResult(op, result);
|
|
2956
|
+
}
|
|
2957
|
+
const counted = countResult(op, result);
|
|
2958
|
+
return finalizeObservation({
|
|
2959
|
+
tool: DATA_TOOL_NAME,
|
|
2960
|
+
unit: counted.unit,
|
|
2961
|
+
format: "json",
|
|
2962
|
+
output: JSON.stringify(result),
|
|
2963
|
+
shownCount: counted.shownCount,
|
|
2964
|
+
totalCount: counted.totalCount,
|
|
2965
|
+
truncated: counted.truncated,
|
|
2966
|
+
...counted.next !== void 0 ? { next: counted.next } : {},
|
|
2967
|
+
details: { op, path: target, format: result.format, view: result.view, viewLabel: describeDataView(result.view) },
|
|
2968
|
+
reservation,
|
|
2969
|
+
...options ? { options } : {}
|
|
2970
|
+
});
|
|
2971
|
+
} catch (error) {
|
|
2972
|
+
releaseObservation(reservation);
|
|
2973
|
+
return { kind: "error", message: `data: ${error instanceof Error ? error.message : String(error)}` };
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
var dataTool = createDataTool();
|
|
2979
|
+
export {
|
|
2980
|
+
DATA_OBSERVATION_SELF_CAP_BYTES,
|
|
2981
|
+
DATA_TOOL_NAME,
|
|
2982
|
+
createDataTool,
|
|
2983
|
+
dataTool,
|
|
2984
|
+
dataToolSurface,
|
|
2985
|
+
prepareDataArguments
|
|
2986
|
+
};
|
|
2987
|
+
//# sourceMappingURL=data-tool-KMBWKKWR.js.map
|