@bitkyc08/opencodex 2.15.1 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gui/dist/assets/{index-CMCDkQ7U.js → index-DOKr6RBR.js} +10 -10
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/adapters/base.ts +2 -0
- package/src/adapters/google-antigravity-replay.ts +9 -1
- package/src/adapters/kiro-thinking.ts +8 -0
- package/src/adapters/kiro.ts +45 -42
- package/src/adapters/openai-chat.ts +5 -2
- package/src/adapters/openai-responses.ts +5 -1
- package/src/cli/dispatch.ts +6 -3
- package/src/cli/export-command.ts +19 -7
- package/src/cli/help.ts +1 -1
- package/src/cli/index.ts +1 -0
- package/src/cli/registry.ts +2 -2
- package/src/clients/config-export.ts +165 -3
- package/src/generated/compatibility-version.json +59 -31
- package/src/integrations/config-io.ts +119 -1
- package/src/integrations/omp-yaml-source.ts +232 -99
- package/src/integrations/registry.ts +14 -0
- package/src/integrations/serialize.ts +80 -1
- package/src/integrations/state.ts +38 -6
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +152 -19
- package/src/lab/automation/orchestrator.ts +19 -0
- package/src/lib/lab-activation.ts +161 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/shadow-call.ts +6 -14
- package/src/lib/translator-budget.ts +34 -0
- package/src/providers/antigravity-models.ts +65 -10
- package/src/routing/compatibility/assemble.ts +21 -107
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/server/index.ts +8 -17
- package/src/server/lifecycle.ts +5 -3
- package/src/server/management/integration-routes.ts +21 -14
- package/src/server/management/routing-profile-routes.ts +9 -1
- package/src/server/management-api.ts +37 -6
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/responses/core.ts +20 -21
- package/src/types.ts +15 -5
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": "package.json",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "b8810736c02b3cf34dbd0119082924f56a48e435cd9a0768c68c428f8e128cda"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "scripts/model-metadata.source.json",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
"path": "src/adapters/base.ts",
|
|
45
|
-
"sha256": "
|
|
45
|
+
"sha256": "f20fdca89cd4bac4ec049ab46e200f2aa6435dae548c5994b7edf5b6d73f1bd5"
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
"path": "src/adapters/client-fingerprint.ts",
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
},
|
|
183
183
|
{
|
|
184
184
|
"path": "src/adapters/google-antigravity-replay.ts",
|
|
185
|
-
"sha256": "
|
|
185
|
+
"sha256": "52704bcd65eab346025e6faffe70d0c1d07e39651e4139f34bc67759fbaa4f08"
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
"path": "src/adapters/google-antigravity-wire.ts",
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
},
|
|
243
243
|
{
|
|
244
244
|
"path": "src/adapters/kiro-thinking.ts",
|
|
245
|
-
"sha256": "
|
|
245
|
+
"sha256": "c7093dd20dc16156aee4d6a37de0b71f6e646c09f2ba99be8f3c6a388703a981"
|
|
246
246
|
},
|
|
247
247
|
{
|
|
248
248
|
"path": "src/adapters/kiro-tool-fallback.ts",
|
|
@@ -262,7 +262,7 @@
|
|
|
262
262
|
},
|
|
263
263
|
{
|
|
264
264
|
"path": "src/adapters/kiro.ts",
|
|
265
|
-
"sha256": "
|
|
265
|
+
"sha256": "fe61e9e4f8d7eada8baab90e09e9b2b03641c114eabe7846f2947cb0667996f1"
|
|
266
266
|
},
|
|
267
267
|
{
|
|
268
268
|
"path": "src/adapters/mimo-free.ts",
|
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
},
|
|
275
275
|
{
|
|
276
276
|
"path": "src/adapters/openai-chat.ts",
|
|
277
|
-
"sha256": "
|
|
277
|
+
"sha256": "c87e922e32ccf8c224891e9a3a42e86139eb7db8d97b9c46613f01a132afc6fa"
|
|
278
278
|
},
|
|
279
279
|
{
|
|
280
280
|
"path": "src/adapters/openai-responses-url.ts",
|
|
@@ -282,7 +282,7 @@
|
|
|
282
282
|
},
|
|
283
283
|
{
|
|
284
284
|
"path": "src/adapters/openai-responses.ts",
|
|
285
|
-
"sha256": "
|
|
285
|
+
"sha256": "8d4809ac4228beea1fa08716cd43c9ab7a87fdeaed5f30f39336ee808375b98d"
|
|
286
286
|
},
|
|
287
287
|
{
|
|
288
288
|
"path": "src/adapters/run-turn-queue.ts",
|
|
@@ -446,7 +446,7 @@
|
|
|
446
446
|
},
|
|
447
447
|
{
|
|
448
448
|
"path": "src/cli/dispatch.ts",
|
|
449
|
-
"sha256": "
|
|
449
|
+
"sha256": "478bd9539c26322ec5365e80f44674d507c708ccff6d09605a6e7804abedee79"
|
|
450
450
|
},
|
|
451
451
|
{
|
|
452
452
|
"path": "src/cli/doctor.ts",
|
|
@@ -454,15 +454,15 @@
|
|
|
454
454
|
},
|
|
455
455
|
{
|
|
456
456
|
"path": "src/cli/export-command.ts",
|
|
457
|
-
"sha256": "
|
|
457
|
+
"sha256": "55489975589c8a411cab9d16835390f46a2059968c35344503aff9ffc4bc6e42"
|
|
458
458
|
},
|
|
459
459
|
{
|
|
460
460
|
"path": "src/cli/help.ts",
|
|
461
|
-
"sha256": "
|
|
461
|
+
"sha256": "91c302e213e4d40d5612aee041c5a938d74a06c9a55310eccd45d2ceb08bce4a"
|
|
462
462
|
},
|
|
463
463
|
{
|
|
464
464
|
"path": "src/cli/index.ts",
|
|
465
|
-
"sha256": "
|
|
465
|
+
"sha256": "63e8747afb606295340bd30598d7112b75efb2a89353234a874df42c5fc7e1a7"
|
|
466
466
|
},
|
|
467
467
|
{
|
|
468
468
|
"path": "src/cli/init.ts",
|
|
@@ -514,7 +514,7 @@
|
|
|
514
514
|
},
|
|
515
515
|
{
|
|
516
516
|
"path": "src/cli/registry.ts",
|
|
517
|
-
"sha256": "
|
|
517
|
+
"sha256": "1eb67cf2d3fb58a0b380d4a8cf71fee1ac3ac2123df6f52a4ee878da0e8a60db"
|
|
518
518
|
},
|
|
519
519
|
{
|
|
520
520
|
"path": "src/cli/root.ts",
|
|
@@ -558,7 +558,7 @@
|
|
|
558
558
|
},
|
|
559
559
|
{
|
|
560
560
|
"path": "src/clients/config-export.ts",
|
|
561
|
-
"sha256": "
|
|
561
|
+
"sha256": "4631957993e4d31bc41ecd56791ffed1e6356e3dd9d5107aca1bc9e4c5297de8"
|
|
562
562
|
},
|
|
563
563
|
{
|
|
564
564
|
"path": "src/codex/account-id.ts",
|
|
@@ -1038,7 +1038,7 @@
|
|
|
1038
1038
|
},
|
|
1039
1039
|
{
|
|
1040
1040
|
"path": "src/integrations/config-io.ts",
|
|
1041
|
-
"sha256": "
|
|
1041
|
+
"sha256": "5271736a6499bc4bcb68bde2ccefd8ef8ce7953bddf13e764fb1b9ee66433fe3"
|
|
1042
1042
|
},
|
|
1043
1043
|
{
|
|
1044
1044
|
"path": "src/integrations/journal.ts",
|
|
@@ -1054,7 +1054,7 @@
|
|
|
1054
1054
|
},
|
|
1055
1055
|
{
|
|
1056
1056
|
"path": "src/integrations/omp-yaml-source.ts",
|
|
1057
|
-
"sha256": "
|
|
1057
|
+
"sha256": "ba30982af0520ffe5c841b7254ab6d73e2a9fb53636f3c5096c9fa6ccfc41005"
|
|
1058
1058
|
},
|
|
1059
1059
|
{
|
|
1060
1060
|
"path": "src/integrations/ownership.ts",
|
|
@@ -1062,23 +1062,27 @@
|
|
|
1062
1062
|
},
|
|
1063
1063
|
{
|
|
1064
1064
|
"path": "src/integrations/registry.ts",
|
|
1065
|
-
"sha256": "
|
|
1065
|
+
"sha256": "299064969a383a4202e5c243d52d7b8f677a675db04a0661f66be01ae74e25d6"
|
|
1066
1066
|
},
|
|
1067
1067
|
{
|
|
1068
1068
|
"path": "src/integrations/serialize.ts",
|
|
1069
|
-
"sha256": "
|
|
1069
|
+
"sha256": "0560601276b25d82eaf6e5460c815e0a67ecb4cf1cf6e378952c60dedfb333e6"
|
|
1070
1070
|
},
|
|
1071
1071
|
{
|
|
1072
1072
|
"path": "src/integrations/state.ts",
|
|
1073
|
-
"sha256": "
|
|
1073
|
+
"sha256": "2b31611ea745ae22d4292719c2deb453efe6d5ea0cecba62d6d4352a30744e77"
|
|
1074
1074
|
},
|
|
1075
1075
|
{
|
|
1076
1076
|
"path": "src/integrations/store.ts",
|
|
1077
1077
|
"sha256": "195fe1af41fdaf567bfdaef5c457ee2452a77c43fc13475fccc7968676a2b199"
|
|
1078
1078
|
},
|
|
1079
|
+
{
|
|
1080
|
+
"path": "src/integrations/writer-lock.ts",
|
|
1081
|
+
"sha256": "4e133b69db94784460351a2ce947172fd6499235029fdf866fa3eff2afc477b5"
|
|
1082
|
+
},
|
|
1079
1083
|
{
|
|
1080
1084
|
"path": "src/integrations/writer.ts",
|
|
1081
|
-
"sha256": "
|
|
1085
|
+
"sha256": "788709e9e0505cc717f5c015110d8fa17246dc5b33185fafc99d8136236f1606"
|
|
1082
1086
|
},
|
|
1083
1087
|
{
|
|
1084
1088
|
"path": "src/lab/artifacts/sanitize.ts",
|
|
@@ -1118,7 +1122,7 @@
|
|
|
1118
1122
|
},
|
|
1119
1123
|
{
|
|
1120
1124
|
"path": "src/lab/automation/orchestrator.ts",
|
|
1121
|
-
"sha256": "
|
|
1125
|
+
"sha256": "5f10d45593ea6464f6ecd1db6ee922bc7627fc6578fe6f3f93b7a35c1b479df8"
|
|
1122
1126
|
},
|
|
1123
1127
|
{
|
|
1124
1128
|
"path": "src/lab/automation/persistence.ts",
|
|
@@ -1548,6 +1552,10 @@
|
|
|
1548
1552
|
"path": "src/lib/injection-debug-log.ts",
|
|
1549
1553
|
"sha256": "ab3b8e53c546c0ff43dc129d29c0b11c2d258f86e9d12475d87bf55510eb02c9"
|
|
1550
1554
|
},
|
|
1555
|
+
{
|
|
1556
|
+
"path": "src/lib/lab-activation.ts",
|
|
1557
|
+
"sha256": "7cdfb758543a789a75354ebfba730c516d264a4d6a10648456f57e2654034dec"
|
|
1558
|
+
},
|
|
1551
1559
|
{
|
|
1552
1560
|
"path": "src/lib/lab-live-execution-authority.ts",
|
|
1553
1561
|
"sha256": "7a4c488521b861ad70a87f560d85cb5c9f552e16493c5d44e19734947b4ac714"
|
|
@@ -1564,6 +1572,10 @@
|
|
|
1564
1572
|
"path": "src/lib/lab-live-route-production.ts",
|
|
1565
1573
|
"sha256": "fb890cceb6390cd2d846c86c97e0d490ea8b58783cd7410d032b6d8573a07f49"
|
|
1566
1574
|
},
|
|
1575
|
+
{
|
|
1576
|
+
"path": "src/lib/lab-passive-linker-registration.ts",
|
|
1577
|
+
"sha256": "5f88d3428f87f1773f944e43d812356b96e881dcb8bd13d34baf504ce509e54c"
|
|
1578
|
+
},
|
|
1567
1579
|
{
|
|
1568
1580
|
"path": "src/lib/local-management-attestation.ts",
|
|
1569
1581
|
"sha256": "1bccf8f85ecd89cb017224024ca3d199d97c8ce88f5ac936dbc1419845a77f6e"
|
|
@@ -1580,6 +1592,10 @@
|
|
|
1580
1592
|
"path": "src/lib/open-url.ts",
|
|
1581
1593
|
"sha256": "a6db7ec7181ccb4e95411b2c7499fdd00f3dd48bebcdaca099da086c0dae2e59"
|
|
1582
1594
|
},
|
|
1595
|
+
{
|
|
1596
|
+
"path": "src/lib/optional-shutdown-hooks.ts",
|
|
1597
|
+
"sha256": "ba1fb3f46ddd1ad7d1cf90e22ae8df5dd2969dbb99449beaf8fac3100425a908"
|
|
1598
|
+
},
|
|
1583
1599
|
{
|
|
1584
1600
|
"path": "src/lib/pinned-http.ts",
|
|
1585
1601
|
"sha256": "27a69c4eac63db31ef754c84d7f5f2e2949221b5fe27e066420f91b40fcc51d7"
|
|
@@ -1622,7 +1638,7 @@
|
|
|
1622
1638
|
},
|
|
1623
1639
|
{
|
|
1624
1640
|
"path": "src/lib/shadow-call.ts",
|
|
1625
|
-
"sha256": "
|
|
1641
|
+
"sha256": "2e55cf6e560b18337ac1911b38f20a27c1bd985a65e9496783f2a7cf85014bc6"
|
|
1626
1642
|
},
|
|
1627
1643
|
{
|
|
1628
1644
|
"path": "src/lib/sidecar-tracker.ts",
|
|
@@ -1658,7 +1674,7 @@
|
|
|
1658
1674
|
},
|
|
1659
1675
|
{
|
|
1660
1676
|
"path": "src/lib/translator-budget.ts",
|
|
1661
|
-
"sha256": "
|
|
1677
|
+
"sha256": "4d79fed2d10e23b87af2c67ea0a979ce580eb232ac35e1f6851b5f02ef5a07d7"
|
|
1662
1678
|
},
|
|
1663
1679
|
{
|
|
1664
1680
|
"path": "src/lib/upstream-reachability.ts",
|
|
@@ -1822,7 +1838,7 @@
|
|
|
1822
1838
|
},
|
|
1823
1839
|
{
|
|
1824
1840
|
"path": "src/providers/antigravity-models.ts",
|
|
1825
|
-
"sha256": "
|
|
1841
|
+
"sha256": "cbe65f34a127ad44fd8f6bd2214553b238449b4f10d948d5ed67f4b163964874"
|
|
1826
1842
|
},
|
|
1827
1843
|
{
|
|
1828
1844
|
"path": "src/providers/api-keys.ts",
|
|
@@ -1990,7 +2006,7 @@
|
|
|
1990
2006
|
},
|
|
1991
2007
|
{
|
|
1992
2008
|
"path": "src/routing/compatibility/assemble.ts",
|
|
1993
|
-
"sha256": "
|
|
2009
|
+
"sha256": "186010fe58a02823530819cf7bbf06cefdbb3224850ea8321736d1017f32783f"
|
|
1994
2010
|
},
|
|
1995
2011
|
{
|
|
1996
2012
|
"path": "src/routing/compatibility/behavior.ts",
|
|
@@ -2004,10 +2020,18 @@
|
|
|
2004
2020
|
"path": "src/routing/compatibility/endpoint.ts",
|
|
2005
2021
|
"sha256": "38578440e02ce712f8d84fa97ec2d1bc3396f31983be9b6e5b0010ef6edd146b"
|
|
2006
2022
|
},
|
|
2023
|
+
{
|
|
2024
|
+
"path": "src/routing/compatibility/lab-evidence-provider.ts",
|
|
2025
|
+
"sha256": "352a65b6d95c8e6eaa7e6f81fca49284b49a9ddf7bd1895be192b858784fd861"
|
|
2026
|
+
},
|
|
2007
2027
|
{
|
|
2008
2028
|
"path": "src/routing/compatibility/policy.ts",
|
|
2009
2029
|
"sha256": "d903d561ef2ae16c86d16c7ec157556ee0c78557aaa7e83dad46c1abc0e6530c"
|
|
2010
2030
|
},
|
|
2031
|
+
{
|
|
2032
|
+
"path": "src/routing/compatibility/provider-slot.ts",
|
|
2033
|
+
"sha256": "809c7b5dbe13b6e90d5abf51cadf33825f8d82b5fd1c7355d9ef25b736371bdc"
|
|
2034
|
+
},
|
|
2011
2035
|
{
|
|
2012
2036
|
"path": "src/routing/compatibility/reader.ts",
|
|
2013
2037
|
"sha256": "c48943c0b660609bbdf4d47896de6338cd46b2c9144f1c916646221fe437a678"
|
|
@@ -2114,11 +2138,11 @@
|
|
|
2114
2138
|
},
|
|
2115
2139
|
{
|
|
2116
2140
|
"path": "src/server/index.ts",
|
|
2117
|
-
"sha256": "
|
|
2141
|
+
"sha256": "cc6461e629f1f5e373d81ebee0720a9ba85c7deedded457bbd398ac962e0e404"
|
|
2118
2142
|
},
|
|
2119
2143
|
{
|
|
2120
2144
|
"path": "src/server/lifecycle.ts",
|
|
2121
|
-
"sha256": "
|
|
2145
|
+
"sha256": "02d0691de03c510419c971341a7015507491599b9a91bec369fd7144f85b05a3"
|
|
2122
2146
|
},
|
|
2123
2147
|
{
|
|
2124
2148
|
"path": "src/server/live.ts",
|
|
@@ -2134,7 +2158,7 @@
|
|
|
2134
2158
|
},
|
|
2135
2159
|
{
|
|
2136
2160
|
"path": "src/server/management-api.ts",
|
|
2137
|
-
"sha256": "
|
|
2161
|
+
"sha256": "0a513030e2b730393d86c87ad237f1e9f35e64586d8736c91c69fed6aaabb60d"
|
|
2138
2162
|
},
|
|
2139
2163
|
{
|
|
2140
2164
|
"path": "src/server/management-auth.ts",
|
|
@@ -2170,7 +2194,7 @@
|
|
|
2170
2194
|
},
|
|
2171
2195
|
{
|
|
2172
2196
|
"path": "src/server/management/integration-routes.ts",
|
|
2173
|
-
"sha256": "
|
|
2197
|
+
"sha256": "a049e2dd40f82793c33b7ac584f14ae6ead7e2524a5b1ee3a218caddc9a3bd86"
|
|
2174
2198
|
},
|
|
2175
2199
|
{
|
|
2176
2200
|
"path": "src/server/management/lab-automation-routes.ts",
|
|
@@ -2214,7 +2238,7 @@
|
|
|
2214
2238
|
},
|
|
2215
2239
|
{
|
|
2216
2240
|
"path": "src/server/management/routing-profile-routes.ts",
|
|
2217
|
-
"sha256": "
|
|
2241
|
+
"sha256": "08484dcc92a3672450122316dad9939707a2669eabf396084bfb93fa9dde35f9"
|
|
2218
2242
|
},
|
|
2219
2243
|
{
|
|
2220
2244
|
"path": "src/server/management/shared.ts",
|
|
@@ -2248,6 +2272,10 @@
|
|
|
2248
2272
|
"path": "src/server/memory-watchdog.ts",
|
|
2249
2273
|
"sha256": "d2f7f5cd03316cdfb0bd23abd77b4c28d87986a9a1cb9e0f53e3890695f07f4c"
|
|
2250
2274
|
},
|
|
2275
|
+
{
|
|
2276
|
+
"path": "src/server/passive-route-linker.ts",
|
|
2277
|
+
"sha256": "6a20d1e864efe80cd9d6c69df9616bc6092a6102cd8d339f0cb376f8821bed0b"
|
|
2278
|
+
},
|
|
2251
2279
|
{
|
|
2252
2280
|
"path": "src/server/port-reclaim.ts",
|
|
2253
2281
|
"sha256": "5b1a9e7e5e3d752ee7dd0dca1ea8737eeaf7945e2c9a4e3a0aed9805cc72d253"
|
|
@@ -2334,7 +2362,7 @@
|
|
|
2334
2362
|
},
|
|
2335
2363
|
{
|
|
2336
2364
|
"path": "src/server/responses/core.ts",
|
|
2337
|
-
"sha256": "
|
|
2365
|
+
"sha256": "b8e42c1e0be113256d7318ee6dc3dc4cb7d045867e9e5412ccdfd64fa07111cb"
|
|
2338
2366
|
},
|
|
2339
2367
|
{
|
|
2340
2368
|
"path": "src/server/responses/encrypted-payload.ts",
|
|
@@ -2482,7 +2510,7 @@
|
|
|
2482
2510
|
},
|
|
2483
2511
|
{
|
|
2484
2512
|
"path": "src/types.ts",
|
|
2485
|
-
"sha256": "
|
|
2513
|
+
"sha256": "b04403f46247c96634d0c8c6344c1ecc44979980b0456c28140e3aa1da4ab6ca"
|
|
2486
2514
|
},
|
|
2487
2515
|
{
|
|
2488
2516
|
"path": "src/update/badge.ts",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { mkdirSync, readFileSync, rmSync, statSync } from "node:fs";
|
|
11
11
|
import type { ConfigFormat } from "../clients/config-export";
|
|
12
|
+
import { MAX_JSON_NESTING } from "./serialize";
|
|
12
13
|
import { atomicWriteFile } from "../config";
|
|
13
14
|
import type { JournalEntry } from "./journal";
|
|
14
15
|
import type { OwnershipRecord } from "./ownership";
|
|
@@ -23,12 +24,129 @@ import type { IntegrationClientId } from "./registry";
|
|
|
23
24
|
*/
|
|
24
25
|
export const PARSE_FAILED = Symbol("parse-failed");
|
|
25
26
|
|
|
27
|
+
/**
|
|
28
|
+
* What `JSON.parse` has already discarded by the time we hold the parsed value,
|
|
29
|
+
* and a rewrite would therefore silently change. Both classes are invisible in
|
|
30
|
+
* the parsed object, which is why this scans the RAW text — same reasoning as
|
|
31
|
+
* the TOML inf/nan guard below.
|
|
32
|
+
*
|
|
33
|
+
* Numbers: `1e999` overflows to Infinity (a rewrite bakes in `null` — the merge
|
|
34
|
+
* layer's JSON clone does it even before the serializer could refuse), `1e-9999`
|
|
35
|
+
* underflows to `+0`, an integer literal may have been rounded (a rewrite then
|
|
36
|
+
* hands consumers that read JSON integers exactly — python, jq, BigInt revivers
|
|
37
|
+
* — a different value), and `-0` re-serializes as `0`. Only literals whose value
|
|
38
|
+
* actually changed are refused: `1e21`, `1e-320` or 2^54 round-trip exactly and
|
|
39
|
+
* stay usable.
|
|
40
|
+
*
|
|
41
|
+
* Duplicate members: `{"a":1,"a":2}` parses to a single `a`, so rewriting the
|
|
42
|
+
* document DELETES the earlier member. That is content loss, not the formatting
|
|
43
|
+
* normalization we promise, and this classifier is what makes the rewrite of a
|
|
44
|
+
* user-edited file reachable at all — so it fails closed here.
|
|
45
|
+
*
|
|
46
|
+
* Depth: the same pass counts container nesting against MAX_JSON_NESTING
|
|
47
|
+
* (shared with the serializer, see serialize.ts). JSON.parse handles hundreds
|
|
48
|
+
* of thousands of levels iteratively, but the downstream merge and
|
|
49
|
+
* JSON.stringify recurse — a 100KB file nested 50k deep sailed through parse
|
|
50
|
+
* and guard, then blew up serialization with a raw RangeError after a
|
|
51
|
+
* multi-GB allocation spike. A hand-written scan rather than a JSON.parse
|
|
52
|
+
* source-access reviver on purpose: the reviver walk recurses internally, so
|
|
53
|
+
* its depth limit would be an unpredictable stack size instead of this
|
|
54
|
+
* deterministic ceiling.
|
|
55
|
+
*/
|
|
56
|
+
function jsonTextSafeToRewrite(text: string): boolean {
|
|
57
|
+
/**
|
|
58
|
+
* One frame per open container; a Set of member names for objects, null for
|
|
59
|
+
* arrays. Its length is the current nesting depth.
|
|
60
|
+
*/
|
|
61
|
+
const containers: Array<Set<string> | null> = [];
|
|
62
|
+
/** The most recent string literal — the member name if a `:` follows. */
|
|
63
|
+
let lastString: string | null = null;
|
|
64
|
+
let inString = false;
|
|
65
|
+
let escaped = false;
|
|
66
|
+
let stringStart = 0;
|
|
67
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
68
|
+
const ch = text[i]!;
|
|
69
|
+
if (inString) {
|
|
70
|
+
if (escaped) escaped = false;
|
|
71
|
+
else if (ch === "\\") escaped = true;
|
|
72
|
+
else if (ch === "\"") {
|
|
73
|
+
inString = false;
|
|
74
|
+
lastString = text.slice(stringStart, i + 1);
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (ch === "\"") { inString = true; stringStart = i; continue; }
|
|
79
|
+
if (ch === "{" || ch === "[") {
|
|
80
|
+
containers.push(ch === "{" ? new Set<string>() : null);
|
|
81
|
+
if (containers.length > MAX_JSON_NESTING) return false;
|
|
82
|
+
lastString = null;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (ch === "}" || ch === "]") { containers.pop(); lastString = null; continue; }
|
|
86
|
+
if (ch === ":") {
|
|
87
|
+
const members = containers[containers.length - 1];
|
|
88
|
+
if (members && lastString !== null) {
|
|
89
|
+
/*
|
|
90
|
+
* Decoded, not raw: `"a"` and `"a"` are spellings of ONE member,
|
|
91
|
+
* and JSON.parse keeps only the last of them.
|
|
92
|
+
*/
|
|
93
|
+
let name: string;
|
|
94
|
+
try { name = JSON.parse(lastString) as string; } catch { return false; }
|
|
95
|
+
if (members.has(name)) return false;
|
|
96
|
+
members.add(name);
|
|
97
|
+
}
|
|
98
|
+
lastString = null;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (ch !== "-" && (ch < "0" || ch > "9")) continue;
|
|
102
|
+
let end = i + 1;
|
|
103
|
+
while (end < text.length && /[0-9+\-.eE]/.test(text[end]!)) end += 1;
|
|
104
|
+
const literal = text.slice(i, end);
|
|
105
|
+
i = end - 1;
|
|
106
|
+
const value = Number(literal);
|
|
107
|
+
if (!Number.isFinite(value)) return false;
|
|
108
|
+
if (value === 0) {
|
|
109
|
+
/*
|
|
110
|
+
* `-0` (re-serializes as `0`) and underflow: `1e-9999` is a nonzero
|
|
111
|
+
* value the parse already flattened to `+0`. The significand alone
|
|
112
|
+
* decides, so genuine zero spellings (`0`, `0.0`, `0e10`) stay usable.
|
|
113
|
+
*/
|
|
114
|
+
if (literal.startsWith("-") || /[1-9]/.test(literal.split(/[eE]/)[0]!)) return false;
|
|
115
|
+
}
|
|
116
|
+
/*
|
|
117
|
+
* Deliberately plain digit runs only. They are the one spelling real
|
|
118
|
+
* consumers read with exact integer semantics (python's json yields an
|
|
119
|
+
* arbitrary-precision int, jq preserves big integer literals), so baking
|
|
120
|
+
* in the rounded double changes what those consumers extract. Decimal or
|
|
121
|
+
* exponent spellings of the same value (`9007199254740993e0`, `…3.0`) are
|
|
122
|
+
* float semantics for every consumer — they round identically before and
|
|
123
|
+
* after a rewrite, and shortest-round-trip stringify preserves what any
|
|
124
|
+
* reader can observe, so refusing them would only manufacture dead ends
|
|
125
|
+
* (`1e308` is not exactly representable either, yet rewrites losslessly
|
|
126
|
+
* for every possible reader).
|
|
127
|
+
*/
|
|
128
|
+
const digits = literal[0] === "-" ? literal.slice(1) : literal;
|
|
129
|
+
if (/^[0-9]{16,}$/.test(digits) && BigInt(literal) !== BigInt(value)) return false;
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
|
|
26
134
|
/** Parse a client config, tolerating absence. PARSE_FAILED on garbage. */
|
|
27
135
|
export function parseConfig(text: string | null, format: ConfigFormat): unknown | typeof PARSE_FAILED {
|
|
28
136
|
if (text === null || text.trim().length === 0) return {};
|
|
29
137
|
try {
|
|
30
138
|
switch (format) {
|
|
31
|
-
case "json":
|
|
139
|
+
case "json": {
|
|
140
|
+
/*
|
|
141
|
+
* Scanned BEFORE parsing: the guard is text-only, and refusing first
|
|
142
|
+
* means a hostile document is never materialized — the depth ceiling
|
|
143
|
+
* would otherwise cap the rewrite only after JSON.parse had already
|
|
144
|
+
* built the 50k-deep object graph. The outcome is unchanged: invalid
|
|
145
|
+
* JSON still returns PARSE_FAILED, from the catch below.
|
|
146
|
+
*/
|
|
147
|
+
if (!jsonTextSafeToRewrite(text)) return PARSE_FAILED;
|
|
148
|
+
return JSON.parse(text);
|
|
149
|
+
}
|
|
32
150
|
case "json5": return Bun.JSON5.parse(text);
|
|
33
151
|
case "yaml": return Bun.YAML.parse(text);
|
|
34
152
|
case "toml": {
|