zorya-classifier 0.0.0-stage → 0.2.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.
Files changed (369) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +13 -0
  3. package/README.md +139 -2
  4. package/dist/app/cli-arguments.d.ts +40 -0
  5. package/dist/app/cli-arguments.js +67 -0
  6. package/dist/app/cli-route.d.ts +3 -0
  7. package/dist/app/cli-route.js +40 -0
  8. package/dist/app/create-classifier.d.ts +33 -0
  9. package/dist/app/create-classifier.js +312 -0
  10. package/dist/app/extraction-files.d.ts +9 -0
  11. package/dist/app/extraction-files.js +28 -0
  12. package/dist/cli.d.ts +2 -0
  13. package/dist/cli.js +77 -0
  14. package/dist/entities/boundary-view.d.ts +29 -0
  15. package/dist/entities/boundary-view.js +1 -0
  16. package/dist/entities/contracts.d.ts +471 -0
  17. package/dist/entities/contracts.js +97 -0
  18. package/dist/entities/cutout-raster.d.ts +7 -0
  19. package/dist/entities/cutout-raster.js +1 -0
  20. package/dist/entities/errors.d.ts +7 -0
  21. package/dist/entities/errors.js +16 -0
  22. package/dist/entities/object-proposals.d.ts +53 -0
  23. package/dist/entities/object-proposals.js +8 -0
  24. package/dist/entities/representation.d.ts +225 -0
  25. package/dist/entities/representation.js +33 -0
  26. package/dist/entities/segmentation-metadata.d.ts +11 -0
  27. package/dist/entities/segmentation-metadata.js +1 -0
  28. package/dist/entities/segmentation-verification.d.ts +30 -0
  29. package/dist/entities/segmentation-verification.js +1 -0
  30. package/dist/entities/segmentation.d.ts +159 -0
  31. package/dist/entities/segmentation.js +5 -0
  32. package/dist/entities/whole-object.d.ts +128 -0
  33. package/dist/entities/whole-object.js +7 -0
  34. package/dist/features/choice-beam-layout.d.ts +18 -0
  35. package/dist/features/choice-beam-layout.js +136 -0
  36. package/dist/features/choice.d.ts +4 -0
  37. package/dist/features/choice.js +83 -0
  38. package/dist/features/prompts.d.ts +8 -0
  39. package/dist/features/prompts.js +56 -0
  40. package/dist/features/segmentation/box-check.d.ts +10 -0
  41. package/dist/features/segmentation/box-check.js +299 -0
  42. package/dist/features/segmentation/mask.d.ts +6 -0
  43. package/dist/features/segmentation/mask.js +89 -0
  44. package/dist/features/segmentation/packed-mask.d.ts +5 -0
  45. package/dist/features/segmentation/packed-mask.js +53 -0
  46. package/dist/features/uniform-grid.d.ts +3 -0
  47. package/dist/features/uniform-grid.js +35 -0
  48. package/dist/index.d.ts +10 -0
  49. package/dist/index.js +2 -0
  50. package/dist/infrastructure/boundary-view.d.ts +2 -0
  51. package/dist/infrastructure/boundary-view.js +263 -0
  52. package/dist/infrastructure/openrouter-common.d.ts +130 -0
  53. package/dist/infrastructure/openrouter-common.js +317 -0
  54. package/dist/infrastructure/openrouter-vision.d.ts +11 -0
  55. package/dist/infrastructure/openrouter-vision.js +17 -0
  56. package/dist/infrastructure/openrouter.d.ts +19 -0
  57. package/dist/infrastructure/openrouter.js +207 -0
  58. package/dist/infrastructure/raster.d.ts +11 -0
  59. package/dist/infrastructure/raster.js +216 -0
  60. package/dist/infrastructure/segmentation/box-presentation.d.ts +2 -0
  61. package/dist/infrastructure/segmentation/box-presentation.js +136 -0
  62. package/dist/infrastructure/segmentation/cutout-raster.d.ts +3 -0
  63. package/dist/infrastructure/segmentation/cutout-raster.js +79 -0
  64. package/dist/infrastructure/segmentation/grabcut/index.d.ts +13 -0
  65. package/dist/infrastructure/segmentation/grabcut/index.js +118 -0
  66. package/dist/infrastructure/segmentation/grabcut/worker-inference.d.ts +47 -0
  67. package/dist/infrastructure/segmentation/grabcut/worker-inference.js +260 -0
  68. package/dist/infrastructure/segmentation/index.d.ts +2 -0
  69. package/dist/infrastructure/segmentation/index.js +2 -0
  70. package/dist/infrastructure/segmentation/mobile-sam/index.d.ts +58 -0
  71. package/dist/infrastructure/segmentation/mobile-sam/index.js +472 -0
  72. package/dist/infrastructure/segmentation/mobile-sam/worker-inference.d.ts +149 -0
  73. package/dist/infrastructure/segmentation/mobile-sam/worker-inference.js +845 -0
  74. package/dist/infrastructure/segmentation/native-child.d.ts +23 -0
  75. package/dist/infrastructure/segmentation/native-child.js +297 -0
  76. package/dist/infrastructure/segmentation/native-protocol.d.ts +923 -0
  77. package/dist/infrastructure/segmentation/native-protocol.js +242 -0
  78. package/dist/infrastructure/segmentation/native-worker.d.ts +1 -0
  79. package/dist/infrastructure/segmentation/native-worker.js +93 -0
  80. package/dist/infrastructure/segmentation/probe-backend.d.ts +1 -0
  81. package/dist/infrastructure/segmentation/probe-backend.js +31 -0
  82. package/dist/infrastructure/segmentation/proposal-presentation.d.ts +3 -0
  83. package/dist/infrastructure/segmentation/proposal-presentation.js +371 -0
  84. package/dist/infrastructure/segmentation/verify-asset.d.ts +4 -0
  85. package/dist/infrastructure/segmentation/verify-asset.js +32 -0
  86. package/dist/infrastructure/text-representation.d.ts +23 -0
  87. package/dist/infrastructure/text-representation.js +226 -0
  88. package/dist/infrastructure/vision-chat.d.ts +64 -0
  89. package/dist/infrastructure/vision-chat.js +318 -0
  90. package/dist/openai-compatible.d.ts +8 -0
  91. package/dist/openai-compatible.js +11 -0
  92. package/dist/openrouter.d.ts +4 -0
  93. package/dist/openrouter.js +2 -0
  94. package/dist/processes/boundary-state.d.ts +12 -0
  95. package/dist/processes/boundary-state.js +196 -0
  96. package/dist/processes/classify.d.ts +3 -0
  97. package/dist/processes/classify.js +39 -0
  98. package/dist/processes/extract-from-region.d.ts +19 -0
  99. package/dist/processes/extract-from-region.js +415 -0
  100. package/dist/processes/extract.d.ts +25 -0
  101. package/dist/processes/extract.js +223 -0
  102. package/dist/processes/locate.d.ts +3 -0
  103. package/dist/processes/locate.js +274 -0
  104. package/dist/processes/proposal-location.d.ts +19 -0
  105. package/dist/processes/proposal-location.js +396 -0
  106. package/dist/processes/whole-object.d.ts +7 -0
  107. package/dist/processes/whole-object.js +272 -0
  108. package/dist/segmentation.d.ts +10 -0
  109. package/dist/segmentation.js +4 -0
  110. package/dist/shared/choice-mass.d.ts +2 -0
  111. package/dist/shared/choice-mass.js +19 -0
  112. package/dist/shared/gate.d.ts +11 -0
  113. package/dist/shared/gate.js +52 -0
  114. package/dist/shared/input-budget.d.ts +7 -0
  115. package/dist/shared/input-budget.js +21 -0
  116. package/dist/shared/scope.d.ts +12 -0
  117. package/dist/shared/scope.js +29 -0
  118. package/docs/0.2.0-plan.md +190 -0
  119. package/docs/README.ru.md +258 -0
  120. package/docs/acceptance.md +144 -0
  121. package/docs/api.md +49 -0
  122. package/docs/architecture.md +45 -0
  123. package/docs/benchmarks.md +63 -0
  124. package/docs/categorical-presence-port.md +26 -0
  125. package/docs/evidence/current-linux-check.json +15 -0
  126. package/docs/evidence/decisions-completion-v1-manifest.json +96 -0
  127. package/docs/evidence/decisions-completion-v1-report.json +1205 -0
  128. package/docs/evidence/decisions-selection-v1-manifest.json +96 -0
  129. package/docs/evidence/decisions-selection-v1-report.json +1457 -0
  130. package/docs/evidence/jev-pricing-2026-10-18.json +69 -0
  131. package/docs/evidence/linux-check.json +20 -0
  132. package/docs/evidence/linux-check.txt +205 -0
  133. package/docs/evidence/live-release-smoke-manifest.json +82 -0
  134. package/docs/evidence/live-release-smoke-provenance.json +9 -0
  135. package/docs/evidence/live-release-smoke-report.json +2136 -0
  136. package/docs/evidence/live-v1-manifest.json +84 -0
  137. package/docs/evidence/live-v1-provenance.json +9 -0
  138. package/docs/evidence/live-v1-report.json +15555 -0
  139. package/docs/evidence/luna-decisions-fine-probe.json +19 -0
  140. package/docs/evidence/luna-decisions-locator-smoke-manifest.json +39 -0
  141. package/docs/evidence/luna-decisions-locator-smoke-report.json +149 -0
  142. package/docs/evidence/pack-check.json +26 -0
  143. package/docs/evidence/protocol-probes.json +61 -0
  144. package/docs/evidence/rejected-vision-selection-v1-qwen-photo-dev-01.json +42 -0
  145. package/docs/evidence/rejected-vision-selection-v1-qwen-photo-dev-17.json +42 -0
  146. package/docs/evidence/rejected-vision-selection-v1-qwen-photo-heldout-09.json +42 -0
  147. package/docs/evidence/rejected-vision-selection-v2-haiku-photo-dev-16.json +42 -0
  148. package/docs/evidence/rejected-vision-selection-v2-haiku-support-heldout-016.json +42 -0
  149. package/docs/evidence/v02/baseline.json +1043 -0
  150. package/docs/evidence/v02/boundary-variants.md +17 -0
  151. package/docs/evidence/v02/box-confirmation-dev40/README.md +15 -0
  152. package/docs/evidence/v02/box-confirmation-dev40/component-refinement.json +246 -0
  153. package/docs/evidence/v02/box-confirmation-dev40/evaluation.json +1663 -0
  154. package/docs/evidence/v02/box-confirmation-dev40/provenance.json +130 -0
  155. package/docs/evidence/v02/box-confirmation-dev40/report.json +127 -0
  156. package/docs/evidence/v02/box-confirmation-dev40-freeze-20261020-v1.json +230 -0
  157. package/docs/evidence/v02/box-confirmation-method-selection-20261020-v1.json +85 -0
  158. package/docs/evidence/v02/box-heldout-cancelled-before-dispatch-20261021-v1.json +32 -0
  159. package/docs/evidence/v02/box-heldout-combined-seal-20261021-v1.json +89 -0
  160. package/docs/evidence/v02/box-heldout-evaluator-truth-seal-20261021-v1.json +61 -0
  161. package/docs/evidence/v02/box-heldout-exclusion-audit-20261020-v1.json +81 -0
  162. package/docs/evidence/v02/box-heldout-map-seal-20261021-v1.json +48 -0
  163. package/docs/evidence/v02/box-heldout-photo-seal-20261020-v1.json +62 -0
  164. package/docs/evidence/v02/box-heldout-run-freeze-20261021-v1.json +61 -0
  165. package/docs/evidence/v02/box-heldout-source-review-20261020-v1.json +134 -0
  166. package/docs/evidence/v02/box-heldout-ui-seal-20261020-v1.json +44 -0
  167. package/docs/evidence/v02/calculator-proof-root-review-20261020-v1.json +63 -0
  168. package/docs/evidence/v02/categorical-dev40-freeze.json +94 -0
  169. package/docs/evidence/v02/categorical-dev40-preserve.json +460 -0
  170. package/docs/evidence/v02/categorical-dev40-target-only.json +460 -0
  171. package/docs/evidence/v02/categorical-heldout-admission-20261020-v3.json +215 -0
  172. package/docs/evidence/v02/categorical-heldout-admission-20261020-v4.json +270 -0
  173. package/docs/evidence/v02/categorical-heldout-dispatch-authorization-20261020-v4.json +79 -0
  174. package/docs/evidence/v02/categorical-heldout-predispatch-20261020-v3.json +57 -0
  175. package/docs/evidence/v02/categorical-heldout-producer-source-map-v4.json +262 -0
  176. package/docs/evidence/v02/categorical-heldout-producer-source-map.json +263 -0
  177. package/docs/evidence/v02/categorical-heldout-run-freeze-20261020-v3.json +35 -0
  178. package/docs/evidence/v02/categorical-heldout-run-freeze-20261020-v4.json +35 -0
  179. package/docs/evidence/v02/categorical-heldout-v4/README.md +35 -0
  180. package/docs/evidence/v02/categorical-heldout-v4/candidate-evaluation.json +2812 -0
  181. package/docs/evidence/v02/categorical-heldout-v4/candidate-physical-receipts.json +15261 -0
  182. package/docs/evidence/v02/categorical-heldout-v4/candidate-provenance.json +131 -0
  183. package/docs/evidence/v02/categorical-heldout-v4/control-evaluation.json +855 -0
  184. package/docs/evidence/v02/categorical-heldout-v4/control-physical-receipts.json +4402 -0
  185. package/docs/evidence/v02/categorical-heldout-v4/control-provenance.json +31 -0
  186. package/docs/evidence/v02/categorical-heldout-v4/mask-normalized-exploratory.json +682 -0
  187. package/docs/evidence/v02/categorical-heldout-v4/paired-qualification.json +21 -0
  188. package/docs/evidence/v02/categorical-heldout-v4/report.json +258 -0
  189. package/docs/evidence/v02/categorical-presence-dev6.json +144 -0
  190. package/docs/evidence/v02/categorical-presence-dev6.md +18 -0
  191. package/docs/evidence/v02/categorical-vision-method-selection.json +90 -0
  192. package/docs/evidence/v02/checked-region-component-v1/README.md +7 -0
  193. package/docs/evidence/v02/checked-region-component-v1/evidence.json +311 -0
  194. package/docs/evidence/v02/checked-region-resource-interrupted-2b0d09f.json +102 -0
  195. package/docs/evidence/v02/checked-region-segmentation-resource-4df544c-receipt.json +167 -0
  196. package/docs/evidence/v02/checked-region-segmentation-resource-4df544c-root-review.json +58 -0
  197. package/docs/evidence/v02/checked-region-segmentation-resource-987ac32-receipt.json +158 -0
  198. package/docs/evidence/v02/ci-012b935.json +17 -0
  199. package/docs/evidence/v02/ci-0c365cb.json +372 -0
  200. package/docs/evidence/v02/ci-185bde8.json +32 -0
  201. package/docs/evidence/v02/ci-24f849f.json +95 -0
  202. package/docs/evidence/v02/ci-25c19cd.json +375 -0
  203. package/docs/evidence/v02/ci-2922caf.json +375 -0
  204. package/docs/evidence/v02/ci-29357d7.json +29 -0
  205. package/docs/evidence/v02/ci-32aa90d.json +24 -0
  206. package/docs/evidence/v02/ci-35e3064.json +376 -0
  207. package/docs/evidence/v02/ci-4331b1b.json +384 -0
  208. package/docs/evidence/v02/ci-43b7426.json +376 -0
  209. package/docs/evidence/v02/ci-450439c.json +373 -0
  210. package/docs/evidence/v02/ci-46283fe.json +29 -0
  211. package/docs/evidence/v02/ci-4c9c09f.json +34 -0
  212. package/docs/evidence/v02/ci-5579646.json +27 -0
  213. package/docs/evidence/v02/ci-6f9cc15.json +127 -0
  214. package/docs/evidence/v02/ci-7c1051f.json +27 -0
  215. package/docs/evidence/v02/ci-9837888.json +34 -0
  216. package/docs/evidence/v02/ci-987ac32.json +29 -0
  217. package/docs/evidence/v02/ci-9d00fe5.json +25 -0
  218. package/docs/evidence/v02/ci-9f85acc.json +127 -0
  219. package/docs/evidence/v02/ci-be275a6.json +201 -0
  220. package/docs/evidence/v02/ci-c107ddf.json +372 -0
  221. package/docs/evidence/v02/ci-c35f67d.json +127 -0
  222. package/docs/evidence/v02/ci-c5eddd8.json +32 -0
  223. package/docs/evidence/v02/ci-d2042e0.json +372 -0
  224. package/docs/evidence/v02/ci-d684259.json +375 -0
  225. package/docs/evidence/v02/ci-e0c190b.json +127 -0
  226. package/docs/evidence/v02/ci-e551253.json +372 -0
  227. package/docs/evidence/v02/ci-f9d4633.json +29 -0
  228. package/docs/evidence/v02/dev1-proposal-evaluation.md +13 -0
  229. package/docs/evidence/v02/dev2-mobile-sam-proposal-oracle.md +21 -0
  230. package/docs/evidence/v02/dev2-proposal-evaluation.md +21 -0
  231. package/docs/evidence/v02/fresh-development.md +16 -0
  232. package/docs/evidence/v02/fresh-native-numeric/artifact-hashes.json +9 -0
  233. package/docs/evidence/v02/fresh-native-numeric/evaluation-root-v1.json +568 -0
  234. package/docs/evidence/v02/fresh-native-numeric/run-manifest.json +342 -0
  235. package/docs/evidence/v02/fresh-native-numeric/summary.json +5654 -0
  236. package/docs/evidence/v02/fresh-native-outline-axis/artifact-hashes.json +9 -0
  237. package/docs/evidence/v02/fresh-native-outline-axis/evaluation-root-v1.json +568 -0
  238. package/docs/evidence/v02/fresh-native-outline-axis/run-manifest.json +378 -0
  239. package/docs/evidence/v02/fresh-native-outline-axis/summary.json +5605 -0
  240. package/docs/evidence/v02/fresh-text/README.md +23 -0
  241. package/docs/evidence/v02/fresh-text/ascii-contours-v1/classify-followup-run-manifest.json +405 -0
  242. package/docs/evidence/v02/fresh-text/ascii-contours-v1/classify-followup-summary.json +1646 -0
  243. package/docs/evidence/v02/fresh-text/ascii-contours-v1/evaluation.json +568 -0
  244. package/docs/evidence/v02/fresh-text/ascii-contours-v1/original-run-manifest.json +404 -0
  245. package/docs/evidence/v02/fresh-text/ascii-contours-v1/original-summary.json +4416 -0
  246. package/docs/evidence/v02/fresh-text/ascii-luma-v1/classify-followup-run-manifest.json +405 -0
  247. package/docs/evidence/v02/fresh-text/ascii-luma-v1/classify-followup-summary.json +1646 -0
  248. package/docs/evidence/v02/fresh-text/ascii-luma-v1/evaluation.json +568 -0
  249. package/docs/evidence/v02/fresh-text/ascii-luma-v1/original-run-manifest.json +404 -0
  250. package/docs/evidence/v02/fresh-text/ascii-luma-v1/original-summary.json +4647 -0
  251. package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/classify-followup-run-manifest.json +405 -0
  252. package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/classify-followup-summary.json +846 -0
  253. package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/evaluation.json +568 -0
  254. package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/original-run-manifest.json +404 -0
  255. package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/original-summary.json +1789 -0
  256. package/docs/evidence/v02/fresh-text/no-image-control/evaluation.json +568 -0
  257. package/docs/evidence/v02/fresh-text/no-image-control/original-run-manifest.json +404 -0
  258. package/docs/evidence/v02/fresh-text/no-image-control/original-summary.json +3953 -0
  259. package/docs/evidence/v02/fresh-text/palette-grid-v1/classify-followup-run-manifest.json +405 -0
  260. package/docs/evidence/v02/fresh-text/palette-grid-v1/classify-followup-summary.json +1646 -0
  261. package/docs/evidence/v02/fresh-text/palette-grid-v1/evaluation.json +568 -0
  262. package/docs/evidence/v02/fresh-text/palette-grid-v1/original-run-manifest.json +404 -0
  263. package/docs/evidence/v02/fresh-text/palette-grid-v1/original-summary.json +3974 -0
  264. package/docs/evidence/v02/fresh-text/pixel-rle-v1/classify-followup-run-manifest.json +405 -0
  265. package/docs/evidence/v02/fresh-text/pixel-rle-v1/classify-followup-summary.json +1646 -0
  266. package/docs/evidence/v02/fresh-text/pixel-rle-v1/evaluation.json +568 -0
  267. package/docs/evidence/v02/fresh-text/pixel-rle-v1/original-run-manifest.json +404 -0
  268. package/docs/evidence/v02/fresh-text/pixel-rle-v1/original-summary.json +4945 -0
  269. package/docs/evidence/v02/fresh-text/report.json +284 -0
  270. package/docs/evidence/v02/fresh-text/svg-contours-v1/classify-followup-run-manifest.json +405 -0
  271. package/docs/evidence/v02/fresh-text/svg-contours-v1/classify-followup-summary.json +846 -0
  272. package/docs/evidence/v02/fresh-text/svg-contours-v1/evaluation.json +568 -0
  273. package/docs/evidence/v02/fresh-text/svg-contours-v1/original-run-manifest.json +404 -0
  274. package/docs/evidence/v02/fresh-text/svg-contours-v1/original-summary.json +2189 -0
  275. package/docs/evidence/v02/heldout-evaluation-20261020.md +37 -0
  276. package/docs/evidence/v02/heldout-input-derivation.md +18 -0
  277. package/docs/evidence/v02/integration-0c365cb.json +90 -0
  278. package/docs/evidence/v02/integration-25c19cd.json +52 -0
  279. package/docs/evidence/v02/integration-35e3064.json +41 -0
  280. package/docs/evidence/v02/integration-4331b1b.json +42 -0
  281. package/docs/evidence/v02/integration-4c9c09f.json +46 -0
  282. package/docs/evidence/v02/integration-8010aad.json +48 -0
  283. package/docs/evidence/v02/integration-c1aa640.json +41 -0
  284. package/docs/evidence/v02/integration-eea1790.json +46 -0
  285. package/docs/evidence/v02/integration-fa82e65.json +42 -0
  286. package/docs/evidence/v02/jpeg-transport-offline.json +268 -0
  287. package/docs/evidence/v02/jpeg-transport-offline.md +7 -0
  288. package/docs/evidence/v02/local-archive-cleanup.json +59 -0
  289. package/docs/evidence/v02/native-base64-after.json +30 -0
  290. package/docs/evidence/v02/native-base64-before.json +32 -0
  291. package/docs/evidence/v02/native-checked-region-windows-46283fe.json +248 -0
  292. package/docs/evidence/v02/native-checked-region-windows-987ac32.json +141 -0
  293. package/docs/evidence/v02/native-grabcut-windows-4c494a3-run2.json +148 -0
  294. package/docs/evidence/v02/native-grabcut-windows-4c494a3-run3.json +148 -0
  295. package/docs/evidence/v02/native-grabcut-windows-4c494a3.json +56 -0
  296. package/docs/evidence/v02/native-proposal-windows-0c365cb.json +148 -0
  297. package/docs/evidence/v02/native-proposal-windows-450439c.json +156 -0
  298. package/docs/evidence/v02/native-proposal-windows-4c9c09f-retry1.json +147 -0
  299. package/docs/evidence/v02/native-proposal-windows-4c9c09f.json +52 -0
  300. package/docs/evidence/v02/native-region-windows-efc9318.json +163 -0
  301. package/docs/evidence/v02/native-windows-eea1790-baseline.json +198 -0
  302. package/docs/evidence/v02/native-windows-eea1790.json +228 -0
  303. package/docs/evidence/v02/ordinary-luna-axis/run-manifest.json +99 -0
  304. package/docs/evidence/v02/ordinary-luna-axis/summary.json +811 -0
  305. package/docs/evidence/v02/owned-temp-cleanup-20261020-v1.json +28 -0
  306. package/docs/evidence/v02/presentation-paired-20261020.json +1438 -0
  307. package/docs/evidence/v02/proposal-resource-soak-261dc23.json +201 -0
  308. package/docs/evidence/v02/proposal-resource-soak-261dc23.md +15 -0
  309. package/docs/evidence/v02/proposal-resource-soak-450439c-receipt.md +13 -0
  310. package/docs/evidence/v02/reconstructed-c03-box.json +41 -0
  311. package/docs/evidence/v02/region-seeded-dev-v1/README.md +17 -0
  312. package/docs/evidence/v02/region-seeded-dev-v1/evaluation.json +260 -0
  313. package/docs/evidence/v02/region-seeded-dev-v2/README.md +15 -0
  314. package/docs/evidence/v02/region-seeded-dev-v2/evaluation.json +232 -0
  315. package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/README.md +9 -0
  316. package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/control-identity-failure.json +22 -0
  317. package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/evaluation.json +160 -0
  318. package/docs/evidence/v02/region-seeded-dev-v3-control-r2/README.md +9 -0
  319. package/docs/evidence/v02/region-seeded-dev-v3-control-r2/attempt-accounting.json +55 -0
  320. package/docs/evidence/v02/region-seeded-dev-v3-control-r2/evaluation.json +136 -0
  321. package/docs/evidence/v02/region-seeded-development-control-r2-freeze-20261021.json +132 -0
  322. package/docs/evidence/v02/region-seeded-development-freeze-20261021-v1.json +167 -0
  323. package/docs/evidence/v02/region-seeded-development-freeze-20261021-v2.json +186 -0
  324. package/docs/evidence/v02/region-seeded-development-freeze-20261021-v3.json +205 -0
  325. package/docs/evidence/v02/region-seeded-heldout-cancelled-before-dispatch-20261021-v2.json +20 -0
  326. package/docs/evidence/v02/region-seeded-heldout-dispatch-authorization-20261021-v3.json +47 -0
  327. package/docs/evidence/v02/region-seeded-heldout-readiness-audit-20261021-v3.json +125 -0
  328. package/docs/evidence/v02/region-seeded-heldout-run-freeze-20261021-v2.json +234 -0
  329. package/docs/evidence/v02/region-seeded-heldout-run-freeze-20261021-v3.json +357 -0
  330. package/docs/evidence/v02/region-seeded-heldout-v3/README.md +19 -0
  331. package/docs/evidence/v02/region-seeded-heldout-v3/evaluation-summary.json +445 -0
  332. package/docs/evidence/v02/region-seeded-method-selection-20261021-v2.json +66 -0
  333. package/docs/evidence/v02/region-seeded-method-selection-20261021-v3.json +120 -0
  334. package/docs/evidence/v02/region-segmentation-resource-0ba4c87-receipt.json +156 -0
  335. package/docs/evidence/v02/resource-soak-linux-8010aad.json +125 -0
  336. package/docs/evidence/v02/screen-v2-terminal-evaluation.md +22 -0
  337. package/docs/evidence/v02/seed-outline/run-manifest.json +59 -0
  338. package/docs/evidence/v02/seed-outline/summary.json +487 -0
  339. package/docs/evidence/v02/seed-unbounded/run-manifest.json +80 -0
  340. package/docs/evidence/v02/seed-unbounded/summary.json +730 -0
  341. package/docs/evidence/v02/segmentation/README.md +21 -0
  342. package/docs/evidence/v02/segmentation/component-comparison-summary.json +240 -0
  343. package/docs/evidence/v02/segmentation/provenance/MOBILE-SAM-LICENSE.txt +201 -0
  344. package/docs/evidence/v02/segmentation/provenance/OPENCV-LICENSE.txt +202 -0
  345. package/docs/evidence/v02/segmentation/provenance/mobile-sam-download-receipt.json +29 -0
  346. package/docs/evidence/v02/segmentation/provenance/mobile-sam-graph-audit.json +214 -0
  347. package/docs/evidence/v02/segmentation/provenance/mobile-sam-model-metadata.json +166 -0
  348. package/docs/evidence/v02/split-choice-noul-dev6.json +72 -0
  349. package/docs/evidence/v02/split-choice-noul-dev6.md +11 -0
  350. package/docs/evidence/v02/supported-vision-screen-20261020.md +65 -0
  351. package/docs/evidence/v02/wesnoth-1.16.11-minimap-projection-source-audit.md +56 -0
  352. package/docs/evidence/v02/wesnoth-proof-root-review-20261020-v1.json +76 -0
  353. package/docs/evidence/vision-cost-reconciliation.json +37 -0
  354. package/docs/evidence/vision-model-summary.json +562 -0
  355. package/docs/evidence/vision-selection-v1-manifest.json +95 -0
  356. package/docs/evidence/vision-selection-v1-report.json +4598 -0
  357. package/docs/evidence/vision-selection-v2-manifest.json +95 -0
  358. package/docs/evidence/vision-selection-v2-report.json +1139 -0
  359. package/docs/evidence/windows-native.json +73 -0
  360. package/docs/evidence/windows-secrets.json +46 -0
  361. package/docs/operations.md +21 -0
  362. package/docs/plan.md +27 -0
  363. package/docs/provenance.json +32 -0
  364. package/docs/publishing.md +30 -0
  365. package/docs/research/text-transport-audit.md +66 -0
  366. package/docs/results.md +69 -0
  367. package/docs/v02-usage.md +162 -0
  368. package/docs/vision-results.md +78 -0
  369. package/package.json +114 -4
@@ -0,0 +1,312 @@
1
+ import { z } from 'zod';
2
+ import { classifySchema, locateSchema, parse } from '../entities/contracts.js';
3
+ import { ClassifierError } from '../entities/errors.js';
4
+ import { createSharpRaster } from '../infrastructure/raster.js';
5
+ import { classifyInput } from '../processes/classify.js';
6
+ import { locateInput } from '../processes/locate.js';
7
+ import { OperationGate } from '../shared/gate.js';
8
+ import { OperationScope } from '../shared/scope.js';
9
+ import { InputBudget } from '../shared/input-budget.js';
10
+ import { wholeObjectSchema } from '../entities/whole-object.js';
11
+ import { locateWholeObjectInput } from '../processes/whole-object.js';
12
+ import { preparedTextSchema, representationLimits } from '../entities/representation.js';
13
+ import { extractSchema } from '../entities/segmentation.js';
14
+ import { extractObject } from '../processes/extract.js';
15
+ import { extractFromRegion } from '../processes/extract-from-region.js';
16
+ import { createSharpCutoutRaster } from '../infrastructure/segmentation/cutout-raster.js';
17
+ import { locateFromProposals } from '../processes/proposal-location.js';
18
+ import { createSharpObjectProposalPresentation } from '../infrastructure/segmentation/proposal-presentation.js';
19
+ import { createSegmentationBoxCheck } from '../features/segmentation/box-check.js';
20
+ import { createSharpSegmentationBoxPresentation } from '../infrastructure/segmentation/box-presentation.js';
21
+ const configSchema = z.object({
22
+ timeoutMs: z.number().int().min(1).max(120000).default(45000),
23
+ concurrency: z.number().int().min(1).max(4).default(2),
24
+ maxQueue: z.number().int().min(0).max(32).default(16),
25
+ maxInputBytes: z
26
+ .number()
27
+ .int()
28
+ .min(1)
29
+ .max(256 * 1024 * 1024)
30
+ .default(64 * 1024 * 1024),
31
+ });
32
+ function signalOf(value) {
33
+ if (value === undefined)
34
+ return undefined;
35
+ if (!(value instanceof AbortSignal))
36
+ throw new ClassifierError('INVALID_INPUT', 'signal must be an AbortSignal');
37
+ return value;
38
+ }
39
+ export function createClassifier(options) {
40
+ return composeClassifier(options);
41
+ }
42
+ /** Internal benchmark composition. No research codec is exported by the npm entry points. */
43
+ export function createResearchClassifier(options, experimental, boundaryView, intervalPolicy) {
44
+ return composeClassifier(options, experimental, boundaryView, intervalPolicy);
45
+ }
46
+ function composeClassifier(options, experimental, boundaryView, intervalPolicy) {
47
+ if (!options || typeof options.decision?.decide !== 'function')
48
+ throw new ClassifierError('INVALID_INPUT', 'A DecisionPort is required');
49
+ const segmenter = options.segmentation;
50
+ const objectProposals = options.objectProposals;
51
+ if (segmenter !== undefined &&
52
+ (!segmenter ||
53
+ typeof segmenter.segment !== 'function' ||
54
+ (segmenter.expand !== undefined && typeof segmenter.expand !== 'function') ||
55
+ typeof segmenter.settle !== 'function' ||
56
+ typeof segmenter.dispose !== 'function'))
57
+ throw new ClassifierError('INVALID_INPUT', 'segmentation must implement SegmentationPort');
58
+ if (options.segmentationBoxCheck !== undefined &&
59
+ (!options.segmentationBoxCheck || typeof options.segmentationBoxCheck.check !== 'function'))
60
+ throw new ClassifierError('INVALID_INPUT', 'segmentationBoxCheck must implement its check port');
61
+ if (objectProposals !== undefined &&
62
+ (!objectProposals ||
63
+ typeof objectProposals.propose !== 'function' ||
64
+ typeof objectProposals.settle !== 'function' ||
65
+ typeof objectProposals.dispose !== 'function'))
66
+ throw new ClassifierError('INVALID_INPUT', 'objectProposals must implement ObjectProposalPort');
67
+ const config = parse(configSchema, {
68
+ timeoutMs: options.timeoutMs,
69
+ concurrency: options.concurrency,
70
+ maxQueue: options.maxQueue,
71
+ maxInputBytes: options.maxInputBytes,
72
+ });
73
+ const gate = new OperationGate(config.concurrency, config.maxQueue);
74
+ const inputBudget = new InputBudget(config.maxInputBytes);
75
+ const raster = createSharpRaster();
76
+ const cutoutRaster = createSharpCutoutRaster();
77
+ const boxCheck = segmenter
78
+ ? (options.segmentationBoxCheck ??
79
+ createSegmentationBoxCheck({
80
+ decision: options.decision,
81
+ presentation: createSharpSegmentationBoxPresentation(),
82
+ imageState: raster.imageState,
83
+ }))
84
+ : undefined;
85
+ const proposalDependencies = objectProposals
86
+ ? {
87
+ decision: options.decision,
88
+ raster,
89
+ image: cutoutRaster,
90
+ proposals: objectProposals,
91
+ presentation: createSharpObjectProposalPresentation(),
92
+ }
93
+ : undefined;
94
+ const owned = new Map();
95
+ let disposed = false;
96
+ const textRepresentation = experimental
97
+ ? {
98
+ async prepare(input) {
99
+ const result = parse(preparedTextSchema, await experimental.prepare(input), 'INVALID_RESPONSE');
100
+ const bytes = result.state.reduce((sum, part) => sum + Buffer.byteLength(part, 'utf8'), 0);
101
+ if (bytes > representationLimits.totalBytes || bytes !== result.metadata.bytes)
102
+ throw new ClassifierError('INVALID_RESPONSE', 'Representation byte accounting is inconsistent');
103
+ return {
104
+ state: result.state,
105
+ metadata: {
106
+ ...result.metadata,
107
+ views: result.metadata.views.map(({ content, ...view }) => ({
108
+ ...view,
109
+ ...(content === undefined ? {} : { content }),
110
+ })),
111
+ },
112
+ };
113
+ },
114
+ }
115
+ : undefined;
116
+ function representationFor(value) {
117
+ if (value?.type !== 'experimental-text')
118
+ return undefined;
119
+ if (!textRepresentation)
120
+ throw new ClassifierError('UNSUPPORTED', 'No text-image profile has passed release qualification yet');
121
+ return textRepresentation;
122
+ }
123
+ async function locateWhole(input, signal, representation) {
124
+ if (segmenter) {
125
+ const result = await extractRegion(input, signal, representation);
126
+ if (result.status === 'extracted')
127
+ return result.location;
128
+ if (result.status === 'unknown' && result.reason === 'segmentation-uncertain')
129
+ return {
130
+ status: 'unknown',
131
+ reason: 'segmentation-uncertain',
132
+ metadata: 'metadata' in result ? result.metadata : result.location.metadata,
133
+ ...(result.verification ? { verification: result.verification } : {}),
134
+ };
135
+ return result;
136
+ }
137
+ if (proposalDependencies) {
138
+ if (representation)
139
+ throw new ClassifierError('UNSUPPORTED', 'Mask proposal selection requires vision input');
140
+ return (await locateFromProposals(input, proposalDependencies, signal)).location;
141
+ }
142
+ return locateWholeObjectInput(input, options.decision, raster, signal, representation, boundaryView, intervalPolicy);
143
+ }
144
+ function extractRegion(input, signal, representation) {
145
+ if (!segmenter || !boxCheck)
146
+ throw new ClassifierError('UNSUPPORTED', 'Region extraction requires a SegmentationPort');
147
+ if (representation)
148
+ throw new ClassifierError('UNSUPPORTED', 'Checked segmentation requires vision input');
149
+ return extractFromRegion({ ...input, signal }, {
150
+ raster,
151
+ image: cutoutRaster,
152
+ segmenter,
153
+ boxCheck,
154
+ locateRegion: (source, { signal: operationSignal, ...request }) => locateInput({ ...request, image: source.bytes }, options.decision, raster, operationSignal, undefined, representation),
155
+ });
156
+ }
157
+ async function run(signal, task) {
158
+ if (disposed)
159
+ throw new ClassifierError('DISPOSED', 'Classifier has been disposed');
160
+ const scope = new OperationScope(config.timeoutMs, signal);
161
+ const job = (async () => {
162
+ let acquired = false;
163
+ try {
164
+ await gate.acquire(scope.signal);
165
+ acquired = true;
166
+ scope.guard();
167
+ const result = await task(scope.signal);
168
+ scope.guard();
169
+ return result;
170
+ }
171
+ catch (error) {
172
+ scope.guard();
173
+ throw error;
174
+ }
175
+ finally {
176
+ if (acquired)
177
+ gate.release();
178
+ scope.dispose();
179
+ owned.delete(scope);
180
+ }
181
+ })();
182
+ owned.set(scope, job);
183
+ return job;
184
+ }
185
+ async function locate(input) {
186
+ if (disposed)
187
+ throw new ClassifierError('DISPOSED', 'Classifier has been disposed');
188
+ gate.assertAvailable();
189
+ if (!input || typeof input !== 'object')
190
+ throw new ClassifierError('INVALID_INPUT', 'Expected locate input object');
191
+ const { signal, ...rest } = input;
192
+ const parent = signalOf(signal);
193
+ if (rest.mode === 'whole-object') {
194
+ const parsed = parse(wholeObjectSchema, rest);
195
+ const representation = representationFor(parsed.representation);
196
+ const release = inputBudget.reserve(parsed.image.byteLength);
197
+ try {
198
+ const snapshot = { ...parsed, image: new Uint8Array(parsed.image) };
199
+ return await run(parent, (s) => locateWhole(snapshot, s, representation));
200
+ }
201
+ finally {
202
+ release();
203
+ }
204
+ }
205
+ const parsed = parse(locateSchema, rest);
206
+ const representation = representationFor(parsed.representation);
207
+ const release = inputBudget.reserve(parsed.image.byteLength);
208
+ try {
209
+ const snapshot = { ...parsed, image: new Uint8Array(parsed.image) };
210
+ return await run(parent, (s) => locateInput(snapshot, options.decision, raster, s, options.refinement, representation));
211
+ }
212
+ finally {
213
+ release();
214
+ }
215
+ }
216
+ return {
217
+ async classify(input) {
218
+ if (disposed)
219
+ throw new ClassifierError('DISPOSED', 'Classifier has been disposed');
220
+ gate.assertAvailable();
221
+ if (!input || typeof input !== 'object')
222
+ throw new ClassifierError('INVALID_INPUT', 'Expected classify input object');
223
+ const { signal, ...rest } = input;
224
+ const parent = signalOf(signal);
225
+ const parsed = parse(classifySchema, rest);
226
+ const hasImage = typeof parsed.input !== 'string' && parsed.input.image !== undefined;
227
+ const representation = hasImage ? representationFor(parsed.representation) : undefined;
228
+ const byteCount = typeof parsed.input === 'string'
229
+ ? Buffer.byteLength(parsed.input)
230
+ : (parsed.input.image?.byteLength ?? 0) + Buffer.byteLength(parsed.input.text ?? '');
231
+ const release = inputBudget.reserve(byteCount);
232
+ try {
233
+ const media = typeof parsed.input === 'string'
234
+ ? parsed.input
235
+ : {
236
+ ...parsed.input,
237
+ ...(parsed.input.image === undefined
238
+ ? {}
239
+ : { image: new Uint8Array(parsed.input.image) }),
240
+ };
241
+ return await run(parent, (s) => classifyInput({ ...parsed, input: media }, options.decision, raster, s, representation));
242
+ }
243
+ finally {
244
+ release();
245
+ }
246
+ },
247
+ locate,
248
+ async extract(input) {
249
+ if (disposed)
250
+ throw new ClassifierError('DISPOSED', 'Classifier has been disposed');
251
+ gate.assertAvailable();
252
+ if (!input || typeof input !== 'object')
253
+ throw new ClassifierError('INVALID_INPUT', 'Expected extract input object');
254
+ const { signal, ...rest } = input;
255
+ const parent = signalOf(signal);
256
+ const parsed = parse(extractSchema, rest);
257
+ if (!segmenter && !proposalDependencies)
258
+ throw new ClassifierError('UNSUPPORTED', 'extract requires an explicit SegmentationPort or ObjectProposalPort');
259
+ const representation = representationFor(parsed.representation);
260
+ const release = inputBudget.reserve(parsed.image.byteLength);
261
+ try {
262
+ const snapshot = { ...parsed, image: new Uint8Array(parsed.image) };
263
+ return await run(parent, (s) => {
264
+ if (segmenter)
265
+ return extractRegion(snapshot, s, representation);
266
+ let prepared;
267
+ // Per-operation ownership: no global selected-mask cache or second native inference.
268
+ const selectedMask = {
269
+ async segment() {
270
+ if (!prepared?.mask || !prepared.segmentation)
271
+ throw new ClassifierError('INVALID_RESPONSE', 'Proposal selection omitted its mask');
272
+ return {
273
+ status: 'segmented',
274
+ mask: prepared.mask,
275
+ metadata: prepared.segmentation,
276
+ };
277
+ },
278
+ async settle() { },
279
+ async dispose() { },
280
+ };
281
+ return extractObject({ ...snapshot, mode: 'whole-object', signal: s }, {
282
+ raster,
283
+ image: cutoutRaster,
284
+ segmenter: selectedMask,
285
+ locateWhole: async (source, { signal: requestSignal, ...request }) => {
286
+ const wholeInput = {
287
+ ...request,
288
+ mode: 'whole-object',
289
+ image: source.bytes,
290
+ };
291
+ if (!proposalDependencies)
292
+ throw new ClassifierError('UNSUPPORTED', 'ObjectProposalPort is required');
293
+ if (representation)
294
+ throw new ClassifierError('UNSUPPORTED', 'Mask proposal selection requires vision input');
295
+ prepared = await locateFromProposals(wholeInput, proposalDependencies, requestSignal);
296
+ return prepared.location;
297
+ },
298
+ });
299
+ });
300
+ }
301
+ finally {
302
+ release();
303
+ }
304
+ },
305
+ async dispose() {
306
+ disposed = true;
307
+ for (const scope of owned.keys())
308
+ scope.abort();
309
+ await Promise.allSettled(owned.values());
310
+ },
311
+ };
312
+ }
@@ -0,0 +1,9 @@
1
+ import type { ExtractionResult } from '../entities/segmentation.js';
2
+ /** Reserve every destination exclusively before writing; never overwrite an existing artifact. */
3
+ export declare function writeExtractionFiles(prefix: string, result: Extract<ExtractionResult, {
4
+ status: 'extracted';
5
+ }>): Promise<{
6
+ png: string;
7
+ mask: string;
8
+ descriptor: string;
9
+ }>;
@@ -0,0 +1,28 @@
1
+ import { open, unlink } from 'node:fs/promises';
2
+ /** Reserve every destination exclusively before writing; never overwrite an existing artifact. */
3
+ export async function writeExtractionFiles(prefix, result) {
4
+ const files = { png: `${prefix}.png`, mask: `${prefix}.mask.u8`, descriptor: `${prefix}.json` };
5
+ const { png, mask, ...description } = result;
6
+ const descriptor = JSON.stringify({
7
+ ...description,
8
+ mask: { width: mask.width, height: mask.height, format: mask.format },
9
+ files,
10
+ }, null, 2);
11
+ const owned = [];
12
+ try {
13
+ for (const path of Object.values(files))
14
+ owned.push({ path, handle: await open(path, 'wx') });
15
+ for (const [index, bytes] of [png, mask.data, descriptor].entries())
16
+ await owned[index].handle.writeFile(bytes);
17
+ await Promise.all(owned.map(({ handle }) => handle.close()));
18
+ return files;
19
+ }
20
+ catch (error) {
21
+ const closed = await Promise.allSettled(owned.map(({ handle }) => handle.close()));
22
+ const removed = await Promise.allSettled(owned.map(({ path }) => unlink(path)));
23
+ const cleanupErrors = [...closed, ...removed].flatMap((outcome) => outcome.status === 'rejected' ? [outcome.reason] : []);
24
+ if (cleanupErrors.length)
25
+ throw new AggregateError([error, ...cleanupErrors], 'Extraction output and cleanup failed');
26
+ throw error;
27
+ }
28
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from 'node:fs/promises';
3
+ import { createClassifier } from './index.js';
4
+ import { createCliDecision } from './app/cli-route.js';
5
+ import { parseCliArguments } from './app/cli-arguments.js';
6
+ import { writeExtractionFiles } from './app/extraction-files.js';
7
+ import { createMobileSamSegmenter, createGrabCutSegmenter } from './segmentation.js';
8
+ async function main() {
9
+ const args = parseCliArguments(process.argv.slice(2));
10
+ if (args.command === 'help') {
11
+ console.log('zorya-classifier classify-text <text> <classes.json>\nzorya-classifier classify-image <image> <classes.json>\nzorya-classifier locate <image> <target> [--mode region|whole-object]\nzorya-classifier extract <image> <target> --output <prefix> --backend mobile-sam --encoder <path> --decoder <path> [--provider cpu|dml]\nzorya-classifier extract <image> <target> --output <prefix> --backend grabcut --opencv <path>\nSet ZORYA_MODEL. Default ZORYA_MODE=decisions; use chat for ordinary vision models/custom chat endpoints. OpenRouter: OPENROUTER_API_KEY + ZORYA_PROVIDER. Direct: ZORYA_ENDPOINT + optional ZORYA_API_KEY. Optional ZORYA_REASONING_EFFORT and ZORYA_RESPONSE_FORMAT. One classify request; up to three region or six whole-object requests. Extraction additionally runs the explicit local backend. Output files are never overwritten; native assets are never downloaded automatically.');
12
+ return;
13
+ }
14
+ const { command, value, target } = args;
15
+ const decision = createCliDecision(process.env);
16
+ const controller = new AbortController();
17
+ const abort = () => controller.abort();
18
+ process.once('SIGINT', abort);
19
+ process.once('SIGTERM', abort);
20
+ let segmenter;
21
+ let client;
22
+ try {
23
+ // Validate local data before creating a native worker or dispatching any model request.
24
+ const image = command === 'classify-text' ? undefined : await readFile(value);
25
+ let classes;
26
+ if (command === 'classify-text' || command === 'classify-image') {
27
+ const { z } = await import('zod');
28
+ const { classSchema, limits } = await import('./entities/contracts.js');
29
+ const unknownClasses = JSON.parse(await readFile(target, 'utf8'));
30
+ classes = z.array(classSchema).min(2).max(limits.maxClasses).parse(unknownClasses);
31
+ }
32
+ controller.signal.throwIfAborted();
33
+ if (command === 'extract')
34
+ segmenter =
35
+ args.backend === 'mobile-sam'
36
+ ? await createMobileSamSegmenter({
37
+ encoderPath: args.encoder,
38
+ decoderPath: args.decoder,
39
+ executionProvider: args.provider ?? 'cpu',
40
+ })
41
+ : await createGrabCutSegmenter({ assetPath: args.opencv });
42
+ client = createClassifier({ decision, ...(segmenter ? { segmentation: segmenter } : {}) });
43
+ controller.signal.throwIfAborted();
44
+ if (command === 'locate') {
45
+ console.log(JSON.stringify(await client.locate({
46
+ image: image,
47
+ target,
48
+ ...(args.mode ? { mode: args.mode } : {}),
49
+ signal: controller.signal,
50
+ }), null, 2));
51
+ }
52
+ else if (command === 'extract') {
53
+ const result = await client.extract({ image: image, target, signal: controller.signal });
54
+ console.log(JSON.stringify(result.status === 'extracted'
55
+ ? { status: result.status, files: await writeExtractionFiles(args.output, result) }
56
+ : result, null, 2));
57
+ }
58
+ else {
59
+ const input = command === 'classify-text' ? value : { image: image };
60
+ console.log(JSON.stringify(await client.classify({ input, classes: classes, signal: controller.signal }), null, 2));
61
+ }
62
+ }
63
+ finally {
64
+ process.removeListener('SIGINT', abort);
65
+ process.removeListener('SIGTERM', abort);
66
+ try {
67
+ await client?.dispose();
68
+ }
69
+ finally {
70
+ await segmenter?.dispose();
71
+ }
72
+ }
73
+ }
74
+ main().catch((error) => {
75
+ console.error(error instanceof Error ? error.message : 'Command failed');
76
+ process.exitCode = 1;
77
+ });
@@ -0,0 +1,29 @@
1
+ import type { PixelRect, RasterImage } from './contracts.js';
2
+ import type { BoundaryInterval } from './whole-object.js';
3
+ export type BoundaryAxis = 'left' | 'right' | 'top' | 'bottom';
4
+ export interface BoundaryCandidate {
5
+ /** Exact closed Choice key; display labels are mapped back to this ID by code. */
6
+ id: string;
7
+ display: string;
8
+ interval: BoundaryInterval;
9
+ }
10
+ export interface BoundaryViewInput {
11
+ source: RasterImage;
12
+ sourceRegion: PixelRect;
13
+ axis: BoundaryAxis;
14
+ candidates: readonly BoundaryCandidate[];
15
+ signal: AbortSignal;
16
+ }
17
+ export interface BoundaryView {
18
+ image: RasterImage;
19
+ sourceRegion: PixelRect;
20
+ /** Source pixels occupy this rectangle; rulers/gutters are outside it. */
21
+ content: PixelRect;
22
+ scaleX: number;
23
+ scaleY: number;
24
+ candidates: readonly BoundaryCandidate[];
25
+ }
26
+ /** Rendering only: never infers target facts or generates source coordinates. */
27
+ export interface BoundaryViewPort {
28
+ render(input: BoundaryViewInput): Promise<BoundaryView>;
29
+ }
@@ -0,0 +1 @@
1
+ export {};