dsh-super-code 0.3.10 → 0.4.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 (926) hide show
  1. package/LICENSE +1 -1
  2. package/README.en.md +51 -19
  3. package/README.md +51 -19
  4. package/builtin/README.md +22 -0
  5. package/builtin/skills/mattpocock/LICENSE +21 -0
  6. package/builtin/skills/mattpocock/UPSTREAM.md +11 -0
  7. package/builtin/skills/mattpocock/distribution.json +352 -0
  8. package/builtin/skills/mattpocock/skills/ask-matt/PHASE-BOUNDARIES.md +55 -0
  9. package/builtin/skills/mattpocock/skills/ask-matt/SKILL.md +97 -0
  10. package/builtin/skills/mattpocock/skills/ask-matt/agents/openai.yaml +5 -0
  11. package/builtin/skills/mattpocock/skills/code-review/SKILL.md +89 -0
  12. package/builtin/skills/mattpocock/skills/code-review/agents/openai.yaml +3 -0
  13. package/builtin/skills/mattpocock/skills/codebase-design/DEEPENING.md +37 -0
  14. package/builtin/skills/mattpocock/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  15. package/builtin/skills/mattpocock/skills/codebase-design/SKILL.md +114 -0
  16. package/builtin/skills/mattpocock/skills/codebase-design/agents/openai.yaml +3 -0
  17. package/builtin/skills/mattpocock/skills/diagnosing-bugs/SKILL.md +138 -0
  18. package/builtin/skills/mattpocock/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  19. package/builtin/skills/mattpocock/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  20. package/builtin/skills/mattpocock/skills/domain-modeling/ADR-FORMAT.md +47 -0
  21. package/builtin/skills/mattpocock/skills/domain-modeling/GLOSSARY-FORMAT.md +60 -0
  22. package/builtin/skills/mattpocock/skills/domain-modeling/SKILL.md +74 -0
  23. package/builtin/skills/mattpocock/skills/domain-modeling/agents/openai.yaml +3 -0
  24. package/builtin/skills/mattpocock/skills/grill-me/SKILL.md +7 -0
  25. package/builtin/skills/mattpocock/skills/grill-me/agents/openai.yaml +5 -0
  26. package/builtin/skills/mattpocock/skills/grill-with-docs/SKILL.md +7 -0
  27. package/builtin/skills/mattpocock/skills/grill-with-docs/agents/openai.yaml +5 -0
  28. package/builtin/skills/mattpocock/skills/grilling/SKILL.md +30 -0
  29. package/builtin/skills/mattpocock/skills/grilling/agents/openai.yaml +3 -0
  30. package/builtin/skills/mattpocock/skills/handoff/SKILL.md +16 -0
  31. package/builtin/skills/mattpocock/skills/handoff/agents/openai.yaml +5 -0
  32. package/builtin/skills/mattpocock/skills/implement/SKILL.md +17 -0
  33. package/builtin/skills/mattpocock/skills/implement/agents/openai.yaml +5 -0
  34. package/builtin/skills/mattpocock/skills/implement-spec/SKILL.md +42 -0
  35. package/builtin/skills/mattpocock/skills/implement-spec/agents/openai.yaml +5 -0
  36. package/builtin/skills/mattpocock/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  37. package/builtin/skills/mattpocock/skills/improve-codebase-architecture/SKILL.md +71 -0
  38. package/builtin/skills/mattpocock/skills/improve-codebase-architecture/agents/openai.yaml +5 -0
  39. package/builtin/skills/mattpocock/skills/pr/CREDITS.md +3 -0
  40. package/builtin/skills/mattpocock/skills/pr/SKILL.md +170 -0
  41. package/builtin/skills/mattpocock/skills/pr/agents/openai.yaml +3 -0
  42. package/builtin/skills/mattpocock/skills/prototype/LOGIC.md +67 -0
  43. package/builtin/skills/mattpocock/skills/prototype/SKILL.md +26 -0
  44. package/builtin/skills/mattpocock/skills/prototype/UI.md +112 -0
  45. package/builtin/skills/mattpocock/skills/prototype/agents/openai.yaml +3 -0
  46. package/builtin/skills/mattpocock/skills/research/SKILL.md +12 -0
  47. package/builtin/skills/mattpocock/skills/research/agents/openai.yaml +3 -0
  48. package/builtin/skills/mattpocock/skills/retro/SKILL.md +44 -0
  49. package/builtin/skills/mattpocock/skills/retro/agents/openai.yaml +5 -0
  50. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/SKILL.md +120 -0
  51. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/agents/openai.yaml +5 -0
  52. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/domain.md +51 -0
  53. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/issue-tracker-github.md +50 -0
  54. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +46 -0
  55. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/issue-tracker-local.md +30 -0
  56. package/builtin/skills/mattpocock/skills/setup-matt-pocock-skills/triage-labels.md +15 -0
  57. package/builtin/skills/mattpocock/skills/tdd/SKILL.md +38 -0
  58. package/builtin/skills/mattpocock/skills/tdd/agents/openai.yaml +3 -0
  59. package/builtin/skills/mattpocock/skills/tdd/mocking.md +59 -0
  60. package/builtin/skills/mattpocock/skills/tdd/tests.md +77 -0
  61. package/builtin/skills/mattpocock/skills/teach/GLOSSARY-FORMAT.md +35 -0
  62. package/builtin/skills/mattpocock/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  63. package/builtin/skills/mattpocock/skills/teach/MISSION-FORMAT.md +31 -0
  64. package/builtin/skills/mattpocock/skills/teach/RESOURCES-FORMAT.md +32 -0
  65. package/builtin/skills/mattpocock/skills/teach/SKILL.md +140 -0
  66. package/builtin/skills/mattpocock/skills/teach/agents/openai.yaml +5 -0
  67. package/builtin/skills/mattpocock/skills/to-questionnaire/SKILL.md +54 -0
  68. package/builtin/skills/mattpocock/skills/to-questionnaire/agents/openai.yaml +5 -0
  69. package/builtin/skills/mattpocock/skills/to-spec/SKILL.md +75 -0
  70. package/builtin/skills/mattpocock/skills/to-spec/agents/openai.yaml +5 -0
  71. package/builtin/skills/mattpocock/skills/to-tickets/SKILL.md +105 -0
  72. package/builtin/skills/mattpocock/skills/to-tickets/agents/openai.yaml +5 -0
  73. package/builtin/skills/mattpocock/skills/triage/AGENT-BRIEF.md +207 -0
  74. package/builtin/skills/mattpocock/skills/triage/OUT-OF-SCOPE.md +105 -0
  75. package/builtin/skills/mattpocock/skills/triage/SKILL.md +112 -0
  76. package/builtin/skills/mattpocock/skills/triage/agents/openai.yaml +5 -0
  77. package/builtin/skills/mattpocock/skills/wait-what/SKILL.md +7 -0
  78. package/builtin/skills/mattpocock/skills/wait-what/agents/openai.yaml +5 -0
  79. package/builtin/skills/mattpocock/skills/wayfinder/SKILL.md +128 -0
  80. package/builtin/skills/mattpocock/skills/wayfinder/agents/openai.yaml +5 -0
  81. package/builtin/skills/mattpocock/skills/wizard/SKILL.md +44 -0
  82. package/builtin/skills/mattpocock/skills/wizard/agents/openai.yaml +3 -0
  83. package/builtin/skills/mattpocock/skills/wizard/template.sh +223 -0
  84. package/builtin/skills/mattpocock/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  85. package/builtin/skills/mattpocock/skills/writing-for-agents/SKILL.md +81 -0
  86. package/builtin/skills/mattpocock/skills/writing-for-agents/agents/openai.yaml +3 -0
  87. package/builtin/skills/oil-ui/LICENSE +21 -0
  88. package/builtin/skills/oil-ui/SKILL.md +163 -0
  89. package/builtin/skills/oil-ui/UPSTREAM.md +14 -0
  90. package/builtin/skills/oil-ui/assets/fonts/instrument-serif/InstrumentSerif-Regular.ttf +0 -0
  91. package/builtin/skills/oil-ui/assets/fonts/instrument-serif/OFL.txt +93 -0
  92. package/builtin/skills/oil-ui/assets/logo.png +0 -0
  93. package/builtin/skills/oil-ui/assets/style-explorer.html +433 -0
  94. package/builtin/skills/oil-ui/distribution.json +5 -0
  95. package/builtin/skills/oil-ui/references/design-direction.md +233 -0
  96. package/builtin/skills/oil-ui/references/direction-persuasion.md +25 -0
  97. package/builtin/skills/oil-ui/references/image-ideation.md +130 -0
  98. package/builtin/skills/oil-ui/references/layout-and-viewport.md +24 -0
  99. package/builtin/skills/oil-ui/references/media.md +158 -0
  100. package/builtin/skills/oil-ui/references/motion.md +123 -0
  101. package/builtin/skills/oil-ui/references/play.md +29 -0
  102. package/builtin/skills/oil-ui/references/reviewer-manual.md +73 -0
  103. package/builtin/skills/oil-ui/references/scroll-narrative.md +97 -0
  104. package/builtin/skills/oil-ui/references/style-explorer.md +48 -0
  105. package/builtin/skills/oil-ui/references/task-explore.md +28 -0
  106. package/builtin/skills/oil-ui/references/task-review.md +8 -0
  107. package/builtin/skills/oil-ui/references/tools.md +75 -0
  108. package/builtin/skills/oil-ui/references/ux-review.md +23 -0
  109. package/builtin/skills/oil-ui/references/ux-reviewer.md +10 -0
  110. package/builtin/skills/oil-ui/references/visual-language.md +103 -0
  111. package/builtin/skills/oil-ui/references/visual-review.md +35 -0
  112. package/builtin/skills/oil-ui/references/workdir.md +64 -0
  113. package/builtin/skills/oil-ui/scripts/build_explorer.py +958 -0
  114. package/builtin/skills/oil-ui/scripts/chrome.mjs +115 -0
  115. package/builtin/skills/oil-ui/scripts/curate-media.mjs +726 -0
  116. package/builtin/skills/oil-ui/scripts/measure_reference.py +543 -0
  117. package/builtin/skills/oil-ui/scripts/oiloil-image.mjs +388 -0
  118. package/builtin/skills/oil-ui/scripts/prep-image.mjs +287 -0
  119. package/builtin/skills/oil-ui/scripts/recommend_once.py +65 -0
  120. package/builtin/skills/oil-ui/scripts/shoot.mjs +2067 -0
  121. package/builtin/skills/openspec/LICENSE +22 -0
  122. package/builtin/skills/openspec/UPSTREAM.md +11 -0
  123. package/builtin/skills/openspec/distribution.json +73 -0
  124. package/builtin/skills/openspec/skills/README.md +19 -0
  125. package/builtin/skills/openspec/skills/openspec-apply-change/SKILL.md +205 -0
  126. package/builtin/skills/openspec/skills/openspec-archive-change/SKILL.md +220 -0
  127. package/builtin/skills/openspec/skills/openspec-bulk-archive-change/SKILL.md +376 -0
  128. package/builtin/skills/openspec/skills/openspec-continue-change/SKILL.md +137 -0
  129. package/builtin/skills/openspec/skills/openspec-explore/SKILL.md +355 -0
  130. package/builtin/skills/openspec/skills/openspec-ff-change/SKILL.md +128 -0
  131. package/builtin/skills/openspec/skills/openspec-new-change/SKILL.md +87 -0
  132. package/builtin/skills/openspec/skills/openspec-onboard/SKILL.md +574 -0
  133. package/builtin/skills/openspec/skills/openspec-propose/SKILL.md +174 -0
  134. package/builtin/skills/openspec/skills/openspec-sync-specs/SKILL.md +289 -0
  135. package/builtin/skills/openspec/skills/openspec-update-change/SKILL.md +108 -0
  136. package/builtin/skills/openspec/skills/openspec-verify-change/SKILL.md +222 -0
  137. package/builtin/skills/pstack/LICENSE +21 -0
  138. package/builtin/skills/pstack/UPSTREAM.md +17 -0
  139. package/builtin/skills/pstack/distribution.json +2299 -0
  140. package/builtin/skills/pstack/dsh/DSH.md +59 -0
  141. package/builtin/skills/pstack/dsh/LICENSE +21 -0
  142. package/builtin/skills/pstack/dsh/README.md +9 -0
  143. package/builtin/skills/pstack/dsh/adaptation.json +2930 -0
  144. package/builtin/skills/pstack/dsh/agents/comment-sicko.md +32 -0
  145. package/builtin/skills/pstack/dsh/agents/poteto-agent.md +5 -0
  146. package/builtin/skills/pstack/dsh/assets/logo.png +0 -0
  147. package/builtin/skills/pstack/dsh/authoring.md +7 -0
  148. package/builtin/skills/pstack/dsh/docs/guide/01-setup.md +68 -0
  149. package/builtin/skills/pstack/dsh/docs/guide/02-poteto-mode.md +141 -0
  150. package/builtin/skills/pstack/dsh/docs/guide/03-understand.md +81 -0
  151. package/builtin/skills/pstack/dsh/docs/guide/04-design.md +135 -0
  152. package/builtin/skills/pstack/dsh/docs/guide/05-build-and-clean.md +85 -0
  153. package/builtin/skills/pstack/dsh/docs/guide/06-verify-and-ship.md +164 -0
  154. package/builtin/skills/pstack/dsh/docs/guide/07-overnight.md +124 -0
  155. package/builtin/skills/pstack/dsh/docs/guide/08-principles.md +74 -0
  156. package/builtin/skills/pstack/dsh/docs/guide/09-make-it-yours.md +102 -0
  157. package/builtin/skills/pstack/dsh/docs/guide/10-recipes-and-pitfalls.md +184 -0
  158. package/builtin/skills/pstack/dsh/docs/guide/README.md +40 -0
  159. package/builtin/skills/pstack/dsh/docs/guide/images/design.jpg +0 -0
  160. package/builtin/skills/pstack/dsh/docs/guide/images/overnight.jpg +0 -0
  161. package/builtin/skills/pstack/dsh/docs/guide/images/recipes.jpg +0 -0
  162. package/builtin/skills/pstack/dsh/docs/guide/images/router.jpg +0 -0
  163. package/builtin/skills/pstack/dsh/docs/guide/images/understanding.jpg +0 -0
  164. package/builtin/skills/pstack/dsh/docs/guide/images/verification.jpg +0 -0
  165. package/builtin/skills/pstack/dsh/docs/harness/claude-code.md +69 -0
  166. package/builtin/skills/pstack/dsh/scripts/capture.mjs +80 -0
  167. package/builtin/skills/pstack/dsh/skills/architect/SKILL.md +82 -0
  168. package/builtin/skills/pstack/dsh/skills/architect/references/design-red-flags.md +57 -0
  169. package/builtin/skills/pstack/dsh/skills/architect/references/rationale-template.md +35 -0
  170. package/builtin/skills/pstack/dsh/skills/architect/references/runner-prompt.md +20 -0
  171. package/builtin/skills/pstack/dsh/skills/arena/SKILL.md +51 -0
  172. package/builtin/skills/pstack/dsh/skills/automate-me/SKILL.md +19 -0
  173. package/builtin/skills/pstack/dsh/skills/benchmark-checklist/SKILL.md +42 -0
  174. package/builtin/skills/pstack/dsh/skills/blast-radius/SKILL.md +53 -0
  175. package/builtin/skills/pstack/dsh/skills/bro/SKILL.md +10 -0
  176. package/builtin/skills/pstack/dsh/skills/correct/SKILL.md +35 -0
  177. package/builtin/skills/pstack/dsh/skills/create-formal-verification-skill/SKILL.md +46 -0
  178. package/builtin/skills/pstack/dsh/skills/create-verification-skill/SKILL.md +47 -0
  179. package/builtin/skills/pstack/dsh/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  180. package/builtin/skills/pstack/dsh/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  181. package/builtin/skills/pstack/dsh/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  182. package/builtin/skills/pstack/dsh/skills/figure-it-out/SKILL.md +55 -0
  183. package/builtin/skills/pstack/dsh/skills/how/SKILL.md +39 -0
  184. package/builtin/skills/pstack/dsh/skills/how/references/explainer-prompt.md +55 -0
  185. package/builtin/skills/pstack/dsh/skills/how/references/explorer-prompt.md +35 -0
  186. package/builtin/skills/pstack/dsh/skills/in-your-own-words/SKILL.md +10 -0
  187. package/builtin/skills/pstack/dsh/skills/interrogate/SKILL.md +34 -0
  188. package/builtin/skills/pstack/dsh/skills/ketchup/SKILL.md +46 -0
  189. package/builtin/skills/pstack/dsh/skills/ketchup-video/SKILL.md +32 -0
  190. package/builtin/skills/pstack/dsh/skills/maintain-formal-verification-skill/SKILL.md +61 -0
  191. package/builtin/skills/pstack/dsh/skills/maintain-verification-skill/SKILL.md +42 -0
  192. package/builtin/skills/pstack/dsh/skills/make-bot-ui/SKILL.md +22 -0
  193. package/builtin/skills/pstack/dsh/skills/make-bot-ui/references/submissions.md +44 -0
  194. package/builtin/skills/pstack/dsh/skills/make-bot-ui/scripts/submissions.mjs +86 -0
  195. package/builtin/skills/pstack/dsh/skills/no-comments/SKILL.md +27 -0
  196. package/builtin/skills/pstack/dsh/skills/poteto-help/SKILL.md +42 -0
  197. package/builtin/skills/pstack/dsh/skills/poteto-help/references/prompting.md +51 -0
  198. package/builtin/skills/pstack/dsh/skills/poteto-help/references/recipes.md +51 -0
  199. package/builtin/skills/pstack/dsh/skills/poteto-mode/SKILL.md +153 -0
  200. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/authoring-a-skill.md +8 -0
  201. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/autonomous-run.md +12 -0
  202. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/autopilot-full.md +25 -0
  203. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/autopilot-stack.md +8 -0
  204. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/babysit.md +23 -0
  205. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/bug-fix.md +15 -0
  206. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/eval.md +25 -0
  207. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/feature.md +21 -0
  208. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/hillclimb.md +21 -0
  209. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/investigation.md +14 -0
  210. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/multi-phase-plan.md +155 -0
  211. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/opening-a-pr.md +34 -0
  212. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/orchestrate.md +14 -0
  213. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/pause-safely.md +8 -0
  214. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/perf-issue.md +25 -0
  215. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/prototype.md +14 -0
  216. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/refactoring.md +16 -0
  217. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/runtime-forensics.md +11 -0
  218. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/session-pickup.md +9 -0
  219. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/shipping.md +12 -0
  220. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/trace-forensics.md +14 -0
  221. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/visual-parity.md +11 -0
  222. package/builtin/skills/pstack/dsh/skills/poteto-mode/playbooks/worktree-cleanup.md +9 -0
  223. package/builtin/skills/pstack/dsh/skills/poteto-mode/references/bugbot-triage.md +142 -0
  224. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/bootstrap.ts +62 -0
  225. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/bun.lock +67 -0
  226. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/check-plan.mjs +205 -0
  227. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/check-plan.test.ts +110 -0
  228. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/package.json +16 -0
  229. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/cli.test.ts +224 -0
  230. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/cli.ts +223 -0
  231. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/fakes.test-helper.ts +129 -0
  232. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/github.test.ts +498 -0
  233. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/github.ts +726 -0
  234. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/policy.test.ts +482 -0
  235. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/policy.ts +842 -0
  236. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/render.ts +169 -0
  237. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/tsconfig.json +13 -0
  238. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/types.compile.ts +93 -0
  239. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/types.ts +414 -0
  240. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/watch-pr/watch-pr +6 -0
  241. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/worktree-audit.mjs +52 -0
  242. package/builtin/skills/pstack/dsh/skills/poteto-mode/scripts/worktree-audit.sh +4 -0
  243. package/builtin/skills/pstack/dsh/skills/principle-attack-the-premise/SKILL.md +24 -0
  244. package/builtin/skills/pstack/dsh/skills/principle-boundary-discipline/SKILL.md +37 -0
  245. package/builtin/skills/pstack/dsh/skills/principle-build-the-lever/SKILL.md +26 -0
  246. package/builtin/skills/pstack/dsh/skills/principle-encode-lessons-in-structure/SKILL.md +14 -0
  247. package/builtin/skills/pstack/dsh/skills/principle-exhaust-the-design-space/SKILL.md +12 -0
  248. package/builtin/skills/pstack/dsh/skills/principle-experience-first/SKILL.md +22 -0
  249. package/builtin/skills/pstack/dsh/skills/principle-explain-the-number/SKILL.md +21 -0
  250. package/builtin/skills/pstack/dsh/skills/principle-fix-root-causes/SKILL.md +24 -0
  251. package/builtin/skills/pstack/dsh/skills/principle-foundational-thinking/SKILL.md +24 -0
  252. package/builtin/skills/pstack/dsh/skills/principle-guard-the-context-window/SKILL.md +15 -0
  253. package/builtin/skills/pstack/dsh/skills/principle-laziness-protocol/SKILL.md +13 -0
  254. package/builtin/skills/pstack/dsh/skills/principle-make-operations-idempotent/SKILL.md +25 -0
  255. package/builtin/skills/pstack/dsh/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +17 -0
  256. package/builtin/skills/pstack/dsh/skills/principle-minimize-reader-load/SKILL.md +21 -0
  257. package/builtin/skills/pstack/dsh/skills/principle-model-the-domain/SKILL.md +27 -0
  258. package/builtin/skills/pstack/dsh/skills/principle-never-block-on-the-human/SKILL.md +18 -0
  259. package/builtin/skills/pstack/dsh/skills/principle-outcome-oriented-execution/SKILL.md +24 -0
  260. package/builtin/skills/pstack/dsh/skills/principle-prove-it-works/SKILL.md +25 -0
  261. package/builtin/skills/pstack/dsh/skills/principle-redesign-from-first-principles/SKILL.md +19 -0
  262. package/builtin/skills/pstack/dsh/skills/principle-separate-before-serializing-shared-state/SKILL.md +19 -0
  263. package/builtin/skills/pstack/dsh/skills/principle-sequence-verifiable-units/SKILL.md +20 -0
  264. package/builtin/skills/pstack/dsh/skills/principle-subtract-before-you-add/SKILL.md +21 -0
  265. package/builtin/skills/pstack/dsh/skills/principle-test-behavior-not-implementation/SKILL.md +23 -0
  266. package/builtin/skills/pstack/dsh/skills/principle-type-system-discipline/SKILL.md +16 -0
  267. package/builtin/skills/pstack/dsh/skills/recall/SKILL.md +19 -0
  268. package/builtin/skills/pstack/dsh/skills/reflect/SKILL.md +19 -0
  269. package/builtin/skills/pstack/dsh/skills/reflect/references/divergent-reviewer.md +38 -0
  270. package/builtin/skills/pstack/dsh/skills/reflect/references/judgment-reviewer.md +37 -0
  271. package/builtin/skills/pstack/dsh/skills/reflect/references/synthesizer.md +56 -0
  272. package/builtin/skills/pstack/dsh/skills/reflect/references/tooling-reviewer.md +48 -0
  273. package/builtin/skills/pstack/dsh/skills/setup-pstack/SKILL.md +80 -0
  274. package/builtin/skills/pstack/dsh/skills/sharpen/SKILL.md +19 -0
  275. package/builtin/skills/pstack/dsh/skills/show-me-your-work/SKILL.md +85 -0
  276. package/builtin/skills/pstack/dsh/skills/show-me-your-work/references/decision-log-template.tsv +1 -0
  277. package/builtin/skills/pstack/dsh/skills/show-me-your-work/scripts/audit-log.mjs +43 -0
  278. package/builtin/skills/pstack/dsh/skills/show-me-your-work/scripts/log.sh +42 -0
  279. package/builtin/skills/pstack/dsh/skills/statechart/SKILL.md +85 -0
  280. package/builtin/skills/pstack/dsh/skills/statechart/references/render.md +93 -0
  281. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/cfg.mjs +31 -0
  282. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/cfg.ts +33 -0
  283. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/mermaid.mjs +223 -0
  284. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/mermaid.ts +201 -0
  285. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/plain-text.mjs +68 -0
  286. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/plain-text.ts +72 -0
  287. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/report.mjs +123 -0
  288. package/builtin/skills/pstack/dsh/skills/statechart/scripts/backends/report.ts +177 -0
  289. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/config.mjs +258 -0
  290. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/config.ts +276 -0
  291. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/dot.mjs +68 -0
  292. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/dot.ts +74 -0
  293. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/marks.mjs +102 -0
  294. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/marks.ts +93 -0
  295. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/messages.mjs +53 -0
  296. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/messages.ts +52 -0
  297. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/spec.mjs +89 -0
  298. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/spec.ts +114 -0
  299. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/trace.mjs +24 -0
  300. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/trace.ts +24 -0
  301. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/value.mjs +181 -0
  302. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/value.ts +166 -0
  303. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/verdict.mjs +38 -0
  304. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/verdict.ts +40 -0
  305. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/view.mjs +107 -0
  306. package/builtin/skills/pstack/dsh/skills/statechart/scripts/frontends/view.ts +119 -0
  307. package/builtin/skills/pstack/dsh/skills/statechart/scripts/ir.mjs +317 -0
  308. package/builtin/skills/pstack/dsh/skills/statechart/scripts/ir.ts +547 -0
  309. package/builtin/skills/pstack/dsh/skills/statechart/scripts/package.json +11 -0
  310. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/annotate.mjs +102 -0
  311. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/annotate.ts +128 -0
  312. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/label.mjs +217 -0
  313. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/label.ts +269 -0
  314. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/lift.mjs +89 -0
  315. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/lift.ts +85 -0
  316. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/loop-check.mjs +57 -0
  317. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/loop-check.ts +68 -0
  318. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/paths.mjs +50 -0
  319. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/paths.ts +60 -0
  320. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/reach.mjs +134 -0
  321. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/reach.ts +135 -0
  322. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/region-check.mjs +94 -0
  323. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/region-check.ts +97 -0
  324. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/regions.mjs +296 -0
  325. package/builtin/skills/pstack/dsh/skills/statechart/scripts/passes/regions.ts +295 -0
  326. package/builtin/skills/pstack/dsh/skills/statechart/scripts/pipeline.mjs +63 -0
  327. package/builtin/skills/pstack/dsh/skills/statechart/scripts/pipeline.ts +76 -0
  328. package/builtin/skills/pstack/dsh/skills/statechart/scripts/run.mjs +432 -0
  329. package/builtin/skills/pstack/dsh/skills/statechart/scripts/run.ts +481 -0
  330. package/builtin/skills/pstack/dsh/skills/statechart/scripts/statechart +29 -0
  331. package/builtin/skills/pstack/dsh/skills/statechart/scripts/statechart.mjs +149 -0
  332. package/builtin/skills/pstack/dsh/skills/statechart/scripts/statechart.ts +164 -0
  333. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/ConfigOracle.java +63 -0
  334. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/chart.test.ts +1210 -0
  335. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/charts/Braces.mmd +7 -0
  336. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/charts/Escapes.mmd +11 -0
  337. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/charts/Phases.mmd +29 -0
  338. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/cli.test.ts +1314 -0
  339. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/config-fuzz.test.ts +263 -0
  340. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/ChartRun.out +57 -0
  341. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/Counter.cfg +3 -0
  342. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/Counter.tla +10 -0
  343. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/chart.mmd +9 -0
  344. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/graph.dot +16 -0
  345. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/report.md +7 -0
  346. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/sany.out +2 -0
  347. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Counter/verdict-1.out +49 -0
  348. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/ChartRun.out +60 -0
  349. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.cfg +4 -0
  350. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/CounterAction.tla +22 -0
  351. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/chart.mmd +26 -0
  352. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/graph.dot +19 -0
  353. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/report.md +20 -0
  354. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/sany.out +2 -0
  355. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.exit +1 -0
  356. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/verdict-1.out +56 -0
  357. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.exit +1 -0
  358. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/verdict-2.out +82 -0
  359. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterAction/verdict-3.out +57 -0
  360. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/ChartRun.out +59 -0
  361. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.cfg +3 -0
  362. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/CounterDeadlock.tla +11 -0
  363. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/chart.mmd +22 -0
  364. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/graph.dot +16 -0
  365. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/report.md +17 -0
  366. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/sany.out +2 -0
  367. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.exit +1 -0
  368. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-1.out +56 -0
  369. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.exit +1 -0
  370. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterDeadlock/verdict-2.out +77 -0
  371. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/ChartRun.out +69 -0
  372. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.cfg +2 -0
  373. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/CounterFan.tla +11 -0
  374. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/chart.mmd +85 -0
  375. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/graph.dot +70 -0
  376. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/report.md +12 -0
  377. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/sany.out +2 -0
  378. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.exit +1 -0
  379. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/verdict-1.out +67 -0
  380. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterFan/verdict-2.out +57 -0
  381. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.exit +1 -0
  382. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/ChartRun.out +85 -0
  383. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.cfg +6 -0
  384. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/CounterGuard.tla +13 -0
  385. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/chart.mmd +5 -0
  386. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/graph.dot +10 -0
  387. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/report.md +31 -0
  388. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/sany.out +2 -0
  389. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.exit +1 -0
  390. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/verdict-1.out +64 -0
  391. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.exit +1 -0
  392. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterGuard/verdict-2.out +77 -0
  393. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/ChartRun.out +55 -0
  394. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.cfg +3 -0
  395. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/CounterInitPast.tla +10 -0
  396. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/chart.mmd +12 -0
  397. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/graph.dot +6 -0
  398. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/report.md +12 -0
  399. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/sany.out +2 -0
  400. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.exit +1 -0
  401. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-1.out +33 -0
  402. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPast/verdict-2.out +54 -0
  403. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/ChartRun.out +54 -0
  404. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.cfg +3 -0
  405. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/CounterInitPastHolds.tla +10 -0
  406. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/chart.mmd +1 -0
  407. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/graph.dot +6 -0
  408. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/report.md +7 -0
  409. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/sany.out +2 -0
  410. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInitPastHolds/verdict-1.out +46 -0
  411. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/ChartRun.out +59 -0
  412. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.cfg +2 -0
  413. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/CounterInstance.tla +10 -0
  414. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/CounterSteps.tla +6 -0
  415. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/chart.mmd +17 -0
  416. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/graph.dot +15 -0
  417. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/report.md +14 -0
  418. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/sany.out +3 -0
  419. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.exit +1 -0
  420. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterInstance/verdict-1.out +78 -0
  421. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/ChartRun.out +59 -0
  422. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.cfg +3 -0
  423. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/CounterJump.tla +19 -0
  424. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/chart.mmd +26 -0
  425. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/graph.dot +22 -0
  426. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/report.md +12 -0
  427. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/sany.out +2 -0
  428. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.exit +1 -0
  429. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/verdict-1.out +58 -0
  430. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterJump/verdict-2.out +57 -0
  431. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/ChartRun.out +57 -0
  432. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.cfg +2 -0
  433. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/CounterLoop.tla +11 -0
  434. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/chart.mmd +17 -0
  435. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/graph.dot +15 -0
  436. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/report.md +14 -0
  437. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/sany.out +2 -0
  438. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.exit +1 -0
  439. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterLoop/verdict-1.out +76 -0
  440. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/ChartRun.out +59 -0
  441. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.cfg +3 -0
  442. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/CounterOrder.tla +11 -0
  443. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/chart.mmd +19 -0
  444. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/graph.dot +10 -0
  445. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/report.md +15 -0
  446. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/sany.out +2 -0
  447. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.exit +1 -0
  448. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/verdict-1.out +56 -0
  449. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.exit +1 -0
  450. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterOrder/verdict-2.out +67 -0
  451. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/ChartRun.out +62 -0
  452. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.cfg +6 -0
  453. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/CounterRules.tla +24 -0
  454. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/Moves.tla +5 -0
  455. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/chart.mmd +22 -0
  456. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/graph.dot +10 -0
  457. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/report.md +23 -0
  458. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/sany.out +3 -0
  459. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.exit +1 -0
  460. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-1.out +58 -0
  461. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.exit +1 -0
  462. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-2.out +66 -0
  463. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.exit +1 -0
  464. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-3.out +74 -0
  465. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterRules/verdict-4.out +59 -0
  466. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/ChartRun.out +58 -0
  467. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.cfg +3 -0
  468. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/CounterStart.tla +15 -0
  469. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/chart.mmd +18 -0
  470. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/graph.dot +13 -0
  471. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/report.md +11 -0
  472. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/sany.out +2 -0
  473. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.exit +1 -0
  474. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/verdict-1.out +33 -0
  475. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStart/verdict-2.out +57 -0
  476. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/ChartRun.out +57 -0
  477. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.cfg +3 -0
  478. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/CounterStop.tla +15 -0
  479. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/chart.mmd +7 -0
  480. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/graph.dot +13 -0
  481. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/report.md +6 -0
  482. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/sany.out +2 -0
  483. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterStop/verdict-1.out +49 -0
  484. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/ChartRun.out +61 -0
  485. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.cfg +4 -0
  486. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/CounterTie.tla +14 -0
  487. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/chart.mmd +30 -0
  488. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/graph.dot +19 -0
  489. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/report.md +27 -0
  490. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/sany.out +2 -0
  491. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.exit +1 -0
  492. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-1.out +56 -0
  493. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.exit +1 -0
  494. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-2.out +64 -0
  495. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.exit +1 -0
  496. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-3.out +87 -0
  497. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTie/verdict-4.out +57 -0
  498. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/ChartRun.out +60 -0
  499. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.cfg +3 -0
  500. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/CounterTieInGraph.tla +12 -0
  501. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/chart.mmd +23 -0
  502. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/graph.dot +19 -0
  503. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/report.md +11 -0
  504. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/sany.out +2 -0
  505. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.exit +1 -0
  506. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-1.out +56 -0
  507. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterTieInGraph/verdict-2.out +57 -0
  508. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/ChartRun.out +61 -0
  509. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/CounterView.cfg +4 -0
  510. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/CounterView.tla +14 -0
  511. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/chart.mmd +23 -0
  512. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/graph.dot +19 -0
  513. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/report.md +27 -0
  514. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/sany.out +2 -0
  515. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-1.exit +1 -0
  516. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-1.out +56 -0
  517. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-2.exit +1 -0
  518. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-2.out +64 -0
  519. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-3.exit +1 -0
  520. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-3.out +87 -0
  521. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/verdict-4.out +57 -0
  522. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/CounterView/view.mjs +1 -0
  523. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/ChartRun.out +59 -0
  524. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/DieHard.cfg +4 -0
  525. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/DieHard.tla +38 -0
  526. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/chart.mmd +92 -0
  527. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/graph.dot +126 -0
  528. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/report.md +17 -0
  529. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/sany.out +2 -0
  530. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/verdict-1.exit +1 -0
  531. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/verdict-1.out +91 -0
  532. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/DieHard/verdict-2.out +57 -0
  533. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/ChartRun.out +61 -0
  534. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.cfg +6 -0
  535. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/FirstRule.tla +11 -0
  536. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/chart.mmd +22 -0
  537. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/graph.dot +16 -0
  538. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/report.md +25 -0
  539. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/sany.out +2 -0
  540. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.exit +1 -0
  541. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-1.out +56 -0
  542. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.exit +1 -0
  543. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-2.out +64 -0
  544. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.exit +1 -0
  545. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-3.out +64 -0
  546. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.exit +1 -0
  547. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/FirstRule/verdict-4.out +77 -0
  548. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/ChartRun.out +57 -0
  549. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.cfg +4 -0
  550. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/HiddenClock.tla +11 -0
  551. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/chart.mmd +13 -0
  552. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/graph.dot +12 -0
  553. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/report.md +11 -0
  554. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/sany.out +2 -0
  555. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.exit +1 -0
  556. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/HiddenClock/verdict-1.out +72 -0
  557. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/ChartRun.out +57 -0
  558. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/Login.cfg +3 -0
  559. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/Login.tla +62 -0
  560. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/chart.mmd +27 -0
  561. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/graph.dot +40 -0
  562. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/report.md +7 -0
  563. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/sany.out +1 -0
  564. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/verdict-1.out +47 -0
  565. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Login/view.mjs +1 -0
  566. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/ChartRun.out +57 -0
  567. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.cfg +2 -0
  568. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/LoginGuarded.tla +64 -0
  569. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/chart.mmd +28 -0
  570. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/graph.dot +37 -0
  571. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/report.md +8 -0
  572. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/sany.out +1 -0
  573. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/verdict-1.out +47 -0
  574. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginGuarded/view.mjs +1 -0
  575. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/ChartRun.out +60 -0
  576. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.cfg +3 -0
  577. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/LoginParallel.tla +64 -0
  578. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/chart.mmd +44 -0
  579. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/graph.dot +58 -0
  580. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/report.md +17 -0
  581. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/sany.out +1 -0
  582. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.exit +1 -0
  583. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/verdict-1.out +83 -0
  584. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/verdict-2.out +57 -0
  585. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/LoginParallel/view.mjs +1 -0
  586. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/ChartRun.out +60 -0
  587. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.cfg +3 -0
  588. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/MediaPlayer.tla +103 -0
  589. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/chart.mmd +43 -0
  590. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/graph.dot +93 -0
  591. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/report.md +14 -0
  592. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/sany.out +1 -0
  593. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.exit +1 -0
  594. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-1.out +59 -0
  595. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/verdict-2.out +72 -0
  596. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayer/view.mjs +3 -0
  597. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/ChartRun.out +57 -0
  598. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.cfg +2 -0
  599. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/MediaPlayerFixed.tla +100 -0
  600. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/chart.mmd +31 -0
  601. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/graph.dot +85 -0
  602. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/report.md +9 -0
  603. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/sany.out +1 -0
  604. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/verdict-1.out +47 -0
  605. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerFixed/view.mjs +3 -0
  606. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/ChartRun.out +59 -0
  607. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayer.tla +103 -0
  608. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.cfg +3 -0
  609. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/MediaPlayerProps.tla +6 -0
  610. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/chart.mmd +42 -0
  611. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/graph.dot +93 -0
  612. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/report.md +19 -0
  613. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/sany.out +2 -0
  614. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.exit +1 -0
  615. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-1.out +61 -0
  616. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-2.out +59 -0
  617. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-3.out +61 -0
  618. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.exit +1 -0
  619. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-4.out +66 -0
  620. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.exit +1 -0
  621. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-5.out +58 -0
  622. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/verdict-6.out +49 -0
  623. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/MediaPlayerProps/view.mjs +3 -0
  624. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/ChartRun.out +57 -0
  625. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.cfg +6 -0
  626. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/PickWorker.tla +11 -0
  627. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/chart.mmd +5 -0
  628. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/graph.dot +11 -0
  629. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/report.md +7 -0
  630. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/sany.out +5 -0
  631. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/PickWorker/verdict-1.out +70 -0
  632. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/ChartRun.out +61 -0
  633. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/Shadow.cfg +4 -0
  634. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/Shadow.tla +11 -0
  635. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/ShadowLib.tla +6 -0
  636. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/ShadowSub.tla +3 -0
  637. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/chart.mmd +9 -0
  638. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/graph.dot +16 -0
  639. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/report.md +8 -0
  640. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/sany.out +4 -0
  641. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/Shadow/verdict-1.out +65 -0
  642. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/ChartRun.out +59 -0
  643. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.cfg +2 -0
  644. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/SpacedNames.tla +9 -0
  645. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/chart.mmd +23 -0
  646. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/graph.dot +17 -0
  647. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/report.md +15 -0
  648. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/sany.out +1 -0
  649. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.exit +1 -0
  650. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/verdict-1.out +65 -0
  651. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.exit +1 -0
  652. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/SpacedNames/verdict-2.out +75 -0
  653. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/ChartRun.out +69 -0
  654. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.cfg +3 -0
  655. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/TwoPhase.tla +75 -0
  656. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/chart.mmd +60 -0
  657. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/graph.dot +297 -0
  658. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/report.md +20 -0
  659. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/sany.out +1 -0
  660. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.exit +1 -0
  661. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/verdict-1.out +95 -0
  662. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/verdict-2.out +57 -0
  663. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhase/view.mjs +1 -0
  664. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/ChartRun.out +57 -0
  665. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.cfg +3 -0
  666. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/TwoPhaseFixed.tla +75 -0
  667. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/chart.mmd +37 -0
  668. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/graph.dot +223 -0
  669. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/report.md +11 -0
  670. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/sany.out +1 -0
  671. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/verdict-1.out +47 -0
  672. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TwoPhaseFixed/view.mjs +1 -0
  673. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.exit +1 -0
  674. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/ChartRun.out +75 -0
  675. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.cfg +5 -0
  676. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/TypeGuard.tla +11 -0
  677. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/chart.mmd +18 -0
  678. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/graph.dot +14 -0
  679. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/report.md +29 -0
  680. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/sany.out +2 -0
  681. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.exit +1 -0
  682. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/verdict-1.out +64 -0
  683. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.exit +1 -0
  684. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/TypeGuard/verdict-2.out +75 -0
  685. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/ChartRun.out +58 -0
  686. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.cfg +2 -0
  687. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/UserNoDeadlock.tla +8 -0
  688. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/chart.mmd +22 -0
  689. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/graph.dot +16 -0
  690. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/report.md +15 -0
  691. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/sany.out +2 -0
  692. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.exit +1 -0
  693. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-1.out +56 -0
  694. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.exit +1 -0
  695. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus/UserNoDeadlock/verdict-2.out +77 -0
  696. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/corpus.test.ts +403 -0
  697. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/differential.test.ts +565 -0
  698. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/grid/Grid.cfg +2 -0
  699. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/grid/Grid.tla +9 -0
  700. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/grid/sany.out +2 -0
  701. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/java.ts +63 -0
  702. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/labels.ts +643 -0
  703. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/messages.test.ts +212 -0
  704. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/pipeline.test.ts +270 -0
  705. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/plain-tlc.test.ts +255 -0
  706. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/render.test.ts +81 -0
  707. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/tlc-out.test.ts +90 -0
  708. package/builtin/skills/pstack/dsh/skills/statechart/scripts/test/tlc.ts +158 -0
  709. package/builtin/skills/pstack/dsh/skills/statechart/scripts/tsconfig.json +11 -0
  710. package/builtin/skills/pstack/dsh/skills/statechart/scripts/worker.mjs +32 -0
  711. package/builtin/skills/pstack/dsh/skills/statechart/scripts/worker.ts +35 -0
  712. package/builtin/skills/pstack/dsh/skills/swarm/SKILL.md +44 -0
  713. package/builtin/skills/pstack/dsh/skills/tdd/SKILL.md +45 -0
  714. package/builtin/skills/pstack/dsh/skills/teach/SKILL.md +24 -0
  715. package/builtin/skills/pstack/dsh/skills/technical-writing/SKILL.md +109 -0
  716. package/builtin/skills/pstack/dsh/skills/typescript-best-practices/SKILL.md +34 -0
  717. package/builtin/skills/pstack/dsh/skills/typescript-best-practices/references/patterns.md +328 -0
  718. package/builtin/skills/pstack/dsh/skills/unslop/SKILL.md +65 -0
  719. package/builtin/skills/pstack/dsh/skills/why/SKILL.md +99 -0
  720. package/builtin/skills/pstack/dsh/skills/why/references/epistemics.md +71 -0
  721. package/builtin/skills/pstack/dsh/skills/why/references/investigator-prompt.md +84 -0
  722. package/builtin/skills/pstack/dsh/skills/why/references/source-playbook.md +17 -0
  723. package/builtin/skills/pstack/dsh/skills/why/references/sources/code-archaeology.md +51 -0
  724. package/builtin/skills/pstack/dsh/skills/why/references/sources/databricks.md +70 -0
  725. package/builtin/skills/pstack/dsh/skills/why/references/sources/datadog.md +97 -0
  726. package/builtin/skills/pstack/dsh/skills/why/references/sources/incident-postmortem.md +5 -0
  727. package/builtin/skills/pstack/dsh/skills/why/references/sources/linear.md +48 -0
  728. package/builtin/skills/pstack/dsh/skills/why/references/sources/notion.md +55 -0
  729. package/builtin/skills/pstack/dsh/skills/why/references/sources/sentry.md +66 -0
  730. package/builtin/skills/pstack/dsh/skills/why/references/sources/slack.md +17 -0
  731. package/builtin/skills/pstack/dsh/skills/why/references/synthesizer-prompt.md +129 -0
  732. package/client/index.js +453 -129
  733. package/cordis.patch.yml +5 -13
  734. package/docs/Acknowledgements.md +24 -12
  735. package/docs/Changelog.md +70 -0
  736. package/docs/Compatibility.md +78 -2
  737. package/docs/EvaluationResults.md +8 -6
  738. package/docs/UsageGuide.md +91 -15
  739. package/docs/en/Acknowledgements.md +24 -12
  740. package/docs/en/Changelog.md +70 -0
  741. package/docs/en/Compatibility.md +78 -2
  742. package/docs/en/EvaluationResults.md +8 -6
  743. package/docs/en/UsageGuide.md +91 -15
  744. package/docs/images/agent-tree-preview.png +0 -0
  745. package/docs/images/agent-tree.png +0 -0
  746. package/docs/images/install-tgz-preview.png +0 -0
  747. package/docs/images/install-tgz.png +0 -0
  748. package/docs/images/npm-downloads-dark.svg +22 -0
  749. package/docs/images/npm-downloads.svg +22 -0
  750. package/docs/images/preset-settings-preview.png +0 -0
  751. package/docs/images/star-history-dark.svg +22 -0
  752. package/docs/images/star-history.svg +22 -0
  753. package/docs/images/task-status-preview.png +0 -0
  754. package/docs/images/task-status.png +0 -0
  755. package/lib/connection/approvals.d.ts +4 -0
  756. package/lib/connection/approvals.d.ts.map +1 -1
  757. package/lib/connection/approvals.js.map +1 -1
  758. package/lib/connection/client.d.ts.map +1 -1
  759. package/lib/connection/client.js +20 -3
  760. package/lib/connection/client.js.map +1 -1
  761. package/lib/connection/directories.d.ts.map +1 -1
  762. package/lib/connection/directories.js +14 -5
  763. package/lib/connection/directories.js.map +1 -1
  764. package/lib/connection/git.d.ts.map +1 -1
  765. package/lib/connection/git.js +17 -12
  766. package/lib/connection/git.js.map +1 -1
  767. package/lib/connection/guidance.d.ts.map +1 -1
  768. package/lib/connection/guidance.js +7 -0
  769. package/lib/connection/guidance.js.map +1 -1
  770. package/lib/connection/http.d.ts.map +1 -1
  771. package/lib/connection/http.js +79 -31
  772. package/lib/connection/http.js.map +1 -1
  773. package/lib/connection/service.d.ts +6 -2
  774. package/lib/connection/service.d.ts.map +1 -1
  775. package/lib/connection/service.js +87 -33
  776. package/lib/connection/service.js.map +1 -1
  777. package/lib/connection/store.d.ts +3 -0
  778. package/lib/connection/store.d.ts.map +1 -1
  779. package/lib/connection/store.js +151 -37
  780. package/lib/connection/store.js.map +1 -1
  781. package/lib/connection/tasks.d.ts +10 -5
  782. package/lib/connection/tasks.d.ts.map +1 -1
  783. package/lib/connection/tasks.js +158 -81
  784. package/lib/connection/tasks.js.map +1 -1
  785. package/lib/connection/types.d.ts +2 -0
  786. package/lib/connection/types.d.ts.map +1 -1
  787. package/lib/connection/types.js.map +1 -1
  788. package/lib/core/batch-policy.js +2 -2
  789. package/lib/core/batch-policy.js.map +1 -1
  790. package/lib/core/delegation.d.ts +3 -0
  791. package/lib/core/delegation.d.ts.map +1 -1
  792. package/lib/core/delegation.js +2 -2
  793. package/lib/core/delegation.js.map +1 -1
  794. package/lib/core/deletion-command.d.ts.map +1 -1
  795. package/lib/core/deletion-command.js +271 -38
  796. package/lib/core/deletion-command.js.map +1 -1
  797. package/lib/core/tool-evidence.d.ts.map +1 -1
  798. package/lib/core/tool-evidence.js +9 -2
  799. package/lib/core/tool-evidence.js.map +1 -1
  800. package/lib/dsh/budget-settings.d.ts +11 -0
  801. package/lib/dsh/budget-settings.d.ts.map +1 -1
  802. package/lib/dsh/budget-settings.js +43 -9
  803. package/lib/dsh/budget-settings.js.map +1 -1
  804. package/lib/dsh/budgets.d.ts +5 -0
  805. package/lib/dsh/budgets.d.ts.map +1 -1
  806. package/lib/dsh/budgets.js +15 -0
  807. package/lib/dsh/budgets.js.map +1 -1
  808. package/lib/dsh/bundled-skills.d.ts +17 -0
  809. package/lib/dsh/bundled-skills.d.ts.map +1 -0
  810. package/lib/dsh/bundled-skills.js +94 -0
  811. package/lib/dsh/bundled-skills.js.map +1 -0
  812. package/lib/dsh/compaction.d.ts.map +1 -1
  813. package/lib/dsh/compaction.js +1 -0
  814. package/lib/dsh/compaction.js.map +1 -1
  815. package/lib/dsh/connection-approval.d.ts.map +1 -1
  816. package/lib/dsh/connection-approval.js +24 -2
  817. package/lib/dsh/connection-approval.js.map +1 -1
  818. package/lib/dsh/connection-history.d.ts +2 -1
  819. package/lib/dsh/connection-history.d.ts.map +1 -1
  820. package/lib/dsh/connection-history.js +25 -4
  821. package/lib/dsh/connection-history.js.map +1 -1
  822. package/lib/dsh/connection-host.d.ts +0 -1
  823. package/lib/dsh/connection-host.d.ts.map +1 -1
  824. package/lib/dsh/connection-host.js +59 -26
  825. package/lib/dsh/connection-host.js.map +1 -1
  826. package/lib/dsh/connection.d.ts.map +1 -1
  827. package/lib/dsh/connection.js +34 -8
  828. package/lib/dsh/connection.js.map +1 -1
  829. package/lib/dsh/deletion-protection.d.ts.map +1 -1
  830. package/lib/dsh/deletion-protection.js +18 -10
  831. package/lib/dsh/deletion-protection.js.map +1 -1
  832. package/lib/dsh/directory-metadata.d.ts +4 -0
  833. package/lib/dsh/directory-metadata.d.ts.map +1 -0
  834. package/lib/dsh/directory-metadata.js +4 -0
  835. package/lib/dsh/directory-metadata.js.map +1 -0
  836. package/lib/dsh/index.d.ts.map +1 -1
  837. package/lib/dsh/index.js +4 -0
  838. package/lib/dsh/index.js.map +1 -1
  839. package/lib/dsh/memory-library.d.ts.map +1 -1
  840. package/lib/dsh/memory-library.js +8 -4
  841. package/lib/dsh/memory-library.js.map +1 -1
  842. package/lib/dsh/official-budgets.d.ts.map +1 -1
  843. package/lib/dsh/official-budgets.js +16 -3
  844. package/lib/dsh/official-budgets.js.map +1 -1
  845. package/lib/dsh/openspec-shell.d.ts +3 -0
  846. package/lib/dsh/openspec-shell.d.ts.map +1 -0
  847. package/lib/dsh/openspec-shell.js +25 -0
  848. package/lib/dsh/openspec-shell.js.map +1 -0
  849. package/lib/dsh/preset-declaration.d.ts +6 -0
  850. package/lib/dsh/preset-declaration.d.ts.map +1 -1
  851. package/lib/dsh/preset-declaration.js +91 -65
  852. package/lib/dsh/preset-declaration.js.map +1 -1
  853. package/lib/dsh/preset-files.d.ts.map +1 -1
  854. package/lib/dsh/preset-files.js +16 -1
  855. package/lib/dsh/preset-files.js.map +1 -1
  856. package/lib/dsh/preset-installation.d.ts +11 -7
  857. package/lib/dsh/preset-installation.d.ts.map +1 -1
  858. package/lib/dsh/preset-installation.js +71 -33
  859. package/lib/dsh/preset-installation.js.map +1 -1
  860. package/lib/dsh/preset-metadata.d.ts.map +1 -1
  861. package/lib/dsh/preset-metadata.js +20 -7
  862. package/lib/dsh/preset-metadata.js.map +1 -1
  863. package/lib/dsh/preset-recovery-runtime.d.ts +76 -0
  864. package/lib/dsh/preset-recovery-runtime.d.ts.map +1 -0
  865. package/lib/dsh/preset-recovery-runtime.js +344 -0
  866. package/lib/dsh/preset-recovery-runtime.js.map +1 -0
  867. package/lib/dsh/preset-recovery.d.ts +14 -0
  868. package/lib/dsh/preset-recovery.d.ts.map +1 -0
  869. package/lib/dsh/preset-recovery.js +206 -0
  870. package/lib/dsh/preset-recovery.js.map +1 -0
  871. package/lib/dsh/preset-version.d.ts +1 -0
  872. package/lib/dsh/preset-version.d.ts.map +1 -1
  873. package/lib/dsh/preset-version.js +1 -1
  874. package/lib/dsh/preset-version.js.map +1 -1
  875. package/lib/dsh/ptc-budget.d.ts.map +1 -1
  876. package/lib/dsh/ptc-budget.js +24 -12
  877. package/lib/dsh/ptc-budget.js.map +1 -1
  878. package/lib/dsh/skill-directory.d.ts +45 -0
  879. package/lib/dsh/skill-directory.d.ts.map +1 -0
  880. package/lib/dsh/skill-directory.js +113 -0
  881. package/lib/dsh/skill-directory.js.map +1 -0
  882. package/lib/dsh/skill-installation.d.ts +8 -0
  883. package/lib/dsh/skill-installation.d.ts.map +1 -0
  884. package/lib/dsh/skill-installation.js +131 -0
  885. package/lib/dsh/skill-installation.js.map +1 -0
  886. package/lib/dsh/skill-packages.d.ts +6 -0
  887. package/lib/dsh/skill-packages.d.ts.map +1 -0
  888. package/lib/dsh/skill-packages.js +8 -0
  889. package/lib/dsh/skill-packages.js.map +1 -0
  890. package/lib/dsh/super-code.d.ts.map +1 -1
  891. package/lib/dsh/super-code.js +143 -166
  892. package/lib/dsh/super-code.js.map +1 -1
  893. package/lib/dsh/tool-contracts.d.ts +53 -0
  894. package/lib/dsh/tool-contracts.d.ts.map +1 -0
  895. package/lib/dsh/tool-contracts.js +129 -0
  896. package/lib/dsh/tool-contracts.js.map +1 -0
  897. package/lib/dsh/windows-shell.d.ts +2 -2
  898. package/lib/dsh/windows-shell.d.ts.map +1 -1
  899. package/lib/dsh/windows-shell.js +29 -5
  900. package/lib/dsh/windows-shell.js.map +1 -1
  901. package/lib/long-memory.d.ts +2 -2
  902. package/lib/long-memory.d.ts.map +1 -1
  903. package/lib/long-memory.js +19 -11
  904. package/lib/long-memory.js.map +1 -1
  905. package/lib/memory-usage-projection.d.ts.map +1 -1
  906. package/lib/memory-usage-projection.js +13 -9
  907. package/lib/memory-usage-projection.js.map +1 -1
  908. package/lib/super-agent-usage.d.ts +2 -0
  909. package/lib/super-agent-usage.d.ts.map +1 -1
  910. package/lib/super-agent-usage.js +16 -11
  911. package/lib/super-agent-usage.js.map +1 -1
  912. package/lib/task-feedback-projection.d.ts +12 -0
  913. package/lib/task-feedback-projection.d.ts.map +1 -1
  914. package/lib/task-feedback-projection.js +96 -27
  915. package/lib/task-feedback-projection.js.map +1 -1
  916. package/lib/task-memory-store.d.ts.map +1 -1
  917. package/lib/task-memory-store.js +7 -1
  918. package/lib/task-memory-store.js.map +1 -1
  919. package/package.json +24 -4
  920. package/presets/super-code/agent.cordis.yml +4 -6
  921. package/runtime/skills/openspec/bin/openspec +2 -0
  922. package/runtime/skills/openspec/bin/openspec.cmd +6 -0
  923. package/presets/super-code/skills/super-code-frontend/SKILL.md +0 -33
  924. package/presets/super-code/skills/super-code-frontend/references/browser-validation.md +0 -59
  925. package/presets/super-code/skills/super-code-frontend/references/interaction-states.md +0 -51
  926. package/presets/super-code/skills/super-code-frontend/references/visual-design.md +0 -43
@@ -0,0 +1,726 @@
1
+ #!/usr/bin/env node
2
+ // Media discovery and local delivery for design agents. Node 22+, no npm dependencies.
3
+ import fs from 'node:fs/promises';
4
+ import { existsSync, realpathSync } from 'node:fs';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { createHash, randomUUID } from 'node:crypto';
9
+ import { promisify } from 'node:util';
10
+ import { execFile } from 'node:child_process';
11
+
12
+ const exec = promisify(execFile);
13
+ const UA = 'oil-ui-curate-media/2.1 (+https://github.com/oil-oil/oil-ui; Powered by Poly Haven)';
14
+ const KINDS = ['all', 'texture', 'design', 'photo', 'blueprint', 'map', 'plate', 'science', 'video'];
15
+ const PREFIX = { polyhaven: 'T', vam: 'V', loc: 'L', wellcome: 'W', nasa: 'N', commons: 'C', met: 'M', aic: 'A', cleveland: 'K', japan: 'J', rijks: 'R' };
16
+ const USES = { page: 0, check: 1, reference: 2 };
17
+ const EXAMPLE = 'node scripts/curate-media.mjs search "wood" --kind texture --limit 6';
18
+ const HELP = `常用命令:
19
+ ${EXAMPLE}
20
+ node scripts/curate-media.mjs search "<地名> | <当地语言的地名> | <物名> <年代>" --sheet --dir candidates
21
+ node scripts/curate-media.mjs search "bridge" --kind blueprint --sheet --dir candidates
22
+ node scripts/curate-media.mjs search "earth" --kind video --limit 4
23
+ node scripts/curate-media.mjs preview V1,T2 --sheet --dir candidates
24
+ node scripts/curate-media.mjs fetch C1,T2 --dir assets --sheet
25
+ node scripts/curate-media.mjs fetch V3 --dir <不上线的参考图目录>
26
+ node scripts/curate-media.mjs fetch T2 --maps all --resolution 1k --dir assets
27
+ node scripts/curate-media.mjs fetch "https://example.org/image.jpg" --out assets/image.jpg --note "来源说明"
28
+
29
+ 用法:node curate-media.mjs <search|preview|fetch> <关键词或编号/URL> [选项]
30
+ search "<关键词>" 搜索并返回 JSON;用 | 分隔可一次搜几组词
31
+ 先搜题材自己的地名、物名和专有名词(也试当地语言的叫法),每组一两个词,再加媒介或年代
32
+ 日本馆藏用日文汉字,简体搜不到时换繁体或日文写法
33
+ preview <编号,...> 从缓存制作候选联系表,也可传图片 URL
34
+ fetch <编号,...> 批量下载;也可传一个或多个 HTTP(S) URL(URL 含逗号时单独传入)
35
+
36
+ --kind <类别> ${KINDS.join('|')};默认 all
37
+ --limit <1..30> 总结果数,all 默认 12、其他默认 6;all 交错分配各信源
38
+ --use <范围> all|page;默认 all,page 只留可以放进页面的条目
39
+ --resolution <分辨率> 贴图 JPG:1k|2k|4k|8k,默认 1k,缺失时返回实际可用分辨率
40
+ --maps <名称,...> fetch 贴图:diffuse|roughness|normal|all;默认 diffuse
41
+ --dir <目录> 下载/联系表目录,默认 assets
42
+ --out <文件> 单文件下载路径,与 --dir 互斥;已有文件不会覆盖
43
+ --sheet search/preview 下载预览,出联系表 PNG 和 HTML,并给每项算 look;fetch 出本地联系表并完整解码检查
44
+ --cache <文件> 默认当前工作目录 .curate-cache.json;跨命令使用同一缓存
45
+ --refresh search 忽略 24 小时的 Poly Haven 目录缓存
46
+ --timeout <毫秒> 单个 API 请求超时,默认 12000
47
+ --download-timeout <毫秒> 每文件下载超时,默认 180000;可设 1000..900000
48
+ --max-mb <1..2048> 每文件下载上限,默认 256 MB
49
+ --video-size <版本> medium|small|preview|orig,默认 medium;失败时回退较小版本并记录原因
50
+ --note <说明> fetch 附加来源说明;URL 下载的权利状态记为未核实
51
+ --help, -h 打印帮助;参数可用 --名字=值 或 --名字 值
52
+
53
+ 信源与类别:texture=Poly Haven 无缝材质;design=Met、AIC、Cleveland、Rijksmuseum、V&A、Japan Search(日本国立博物馆、国会图书馆等)馆藏与 Poly Haven 3D 模型预览;
54
+ photo=Wikimedia Commons + LOC + NASA;blueprint=LOC hh/HABS-HAER 测绘图;map=LOC maps + Commons;
55
+ plate=Wellcome + Japan Search + Commons 版画;science=NASA + Wellcome;video=NASA;all 覆盖以上类别。
56
+ 标题和说明里一个关键词都不含的条目会被滤掉,数量记在 filtered。
57
+ 每项的 use 说明能怎么用:page=授权允许放进商业页面(CC BY/BY-SA 要署名);
58
+ check=权利没写清,先看来源页;reference=不能放进页面,可以下载到不上线的目录给生图当参考,
59
+ 只取题材、年代、构图和材质线索,不让生成结果复刻原图。结果按 page、check、reference 排序。
60
+ --sheet 时每项另有 look:tone 明暗、mono 是否近单色、edge 四边平均色、edgeFlat 四边是否平整、
61
+ paper 是否浅色平整纸底(可 multiply 贴到色块上)、calm 哪些区域干净可压字;
62
+ 联系表 PNG 按编号标注,Agent 直接读这张图挑选。
63
+ 贴图 imageUrl/textureUrl 是真实 Diffuse JPG;previewUrl 是渲染预览;
64
+ textureMaps 提供 Diffuse/Roughness/OpenGL Normal 直链、大小与 MD5。
65
+ 模型返回渲染预览及 glTF 文件/依赖清单,fetch 默认只下载模型预览图。
66
+ 编号持续累加,同一素材保留原编号;清除缓存后编号重新开始。
67
+ 标准输出是 JSON,进度/错误在标准错误。部分成功在 errors 中列出,仍保留有效结果;
68
+ 全部信源失败或下载有失败时返回码 1。正常零匹配返回码 0。
69
+ HTML 联系表打开后显示真实图片宽高和加载失败;远程预览不会下载视频。
70
+ 下载默认检查传输长度、签名、贴图 MD5;有 ffprobe 时检查实际宽高。
71
+ --sheet、look 及视频 poster 需要 ffmpeg/ffprobe;缺少时保留下载并明确报告未完成项。
72
+ 所有成功下载及视频首帧 poster 自动记入同目录 SOURCES.md。
73
+ 馆藏与 NASA 权利按记录/官方条款输出,不将整个信源标为可自由商用。`;
74
+
75
+ function usage(message) { throw new Error(`${message}\n示例:${EXAMPLE}\n批量下载:node scripts/curate-media.mjs fetch V1,T2 --dir assets --sheet\n全部选项:node scripts/curate-media.mjs --help`); }
76
+ export function parseArgs(argv) {
77
+ const [command, ...args] = argv;
78
+ if (!command || command === '--help' || command === '-h' || args.includes('--help') || args.includes('-h')) return { help: true };
79
+ if (!['search', 'fetch', 'preview'].includes(command)) usage(`未知命令 ${command}`);
80
+ const allowed = {
81
+ search: ['kind', 'limit', 'use', 'resolution', 'dir', 'sheet', 'cache', 'refresh', 'timeout'],
82
+ preview: ['dir', 'sheet', 'cache', 'timeout'],
83
+ fetch: ['dir', 'out', 'sheet', 'cache', 'maps', 'resolution', 'timeout', 'max-mb', 'note', 'video-size', 'download-timeout'],
84
+ }[command];
85
+ const flags = ['sheet', 'refresh'];
86
+ const opts = {}, positional = [];
87
+ for (let i = 0; i < args.length; i++) {
88
+ const arg = args[i];
89
+ if (!arg.startsWith('-')) { positional.push(arg); continue; }
90
+ const match = arg.match(/^--([^=]+)(?:=(.*))?$/);
91
+ if (!match || !allowed.includes(match[1])) usage(`不支持 ${arg};${command} 支持:${allowed.map(k => '--' + k).join(' ')}`);
92
+ const [, key, inline] = match;
93
+ if (key in opts) usage(`选项 --${key} 只能写一次`);
94
+ if (flags.includes(key)) {
95
+ if (inline !== undefined) usage(`--${key} 是不带值的开关`);
96
+ opts[key] = true;
97
+ } else {
98
+ const value = inline ?? args[++i];
99
+ if (!value || value.startsWith('--')) usage(`--${key} 缺少值`);
100
+ opts[key] = value;
101
+ }
102
+ }
103
+ if (!positional.length || !positional.join(' ').trim()) usage(`${command} 缺少关键词、编号或 URL`);
104
+ if (opts.out && opts.dir) usage('--out 与 --dir 不能同时使用');
105
+ opts.kind ??= 'all';
106
+ if (!KINDS.includes(opts.kind)) usage(`--kind 应为 ${KINDS.join('|')}`);
107
+ opts.use ??= 'all';
108
+ if (!['all', 'page'].includes(opts.use)) usage('--use 应为 all|page');
109
+ for (const [key, fallback, min, max] of [['limit', opts.kind === 'all' ? 12 : 6, 1, 30],['timeout', 12000, 1000, 120000], ['max-mb', 256, 1, 2048], ['download-timeout', 180000, 1000, 900000]]) {
110
+ opts[key] = Number(opts[key] ?? fallback);
111
+ if (!Number.isInteger(opts[key]) || opts[key] < min || opts[key] > max) usage(`--${key} 应为 ${min}..${max} 的整数`);
112
+ }
113
+ opts.resolution ??= '1k';
114
+ if (!['1k', '2k', '4k', '8k'].includes(opts.resolution)) usage('--resolution 应为 1k|2k|4k|8k');
115
+ opts['video-size'] ??= 'medium';
116
+ if (!['medium', 'small', 'preview', 'orig'].includes(opts['video-size'])) usage('--video-size 应为 medium|small|preview|orig');
117
+ opts.maps = (opts.maps ?? 'diffuse').split(',');
118
+ if (opts.maps.includes('all') && opts.maps.length === 1) opts.maps = ['diffuse', 'roughness', 'normal'];
119
+ if (opts.maps.some(k => !['diffuse', 'roughness', 'normal'].includes(k))) usage('--maps 应为 diffuse,roughness,normal 或 all');
120
+ opts.maps = [...new Set(opts.maps)];
121
+ opts.dir = path.resolve(opts.dir ?? (opts.out ? path.dirname(opts.out) : 'assets'));
122
+ const defaultCache = path.resolve('.curate-cache.json');
123
+ const fallbackCaches = [path.join(opts.dir, '.curate-cache.json'), path.join(path.dirname(opts.dir), '.curate-cache.json')];
124
+ opts.cache = opts.cache ? path.resolve(opts.cache) : (!existsSync(defaultCache) && fallbackCaches.find(c => existsSync(c))) || defaultCache;
125
+ return { command, positional, opts };
126
+ }
127
+
128
+ const https = value => String(value).replace(/^http:\/\//, 'https://').replace(/^\/\//, 'https://');
129
+ function httpUrl(value) {
130
+ const u = new URL(value);
131
+ if (!['http:', 'https:'].includes(u.protocol) || u.username || u.password) throw new Error('仅支持不带凭据的 HTTP(S) URL');
132
+ return u.href;
133
+ }
134
+ const apiUrl = (base, params) => { const u = new URL(base); for (const [k, v] of Object.entries(params)) u.searchParams.set(k, String(v)); return u.href; };
135
+ // AIC asks clients to identify themselves in its own header, for the API and IIIF alike.
136
+ const headersFor = url => ({ 'User-Agent': UA, ...(/^https:\/\/[^/]*artic\.edu\//.test(url) ? { 'AIC-User-Agent': UA } : {}) });
137
+ async function json(url, opts) {
138
+ const res = await fetch(httpUrl(url), { headers: { ...headersFor(url), Accept: 'application/json' }, signal: AbortSignal.timeout(opts.timeout) });
139
+ if (!res.ok) throw new Error(`HTTP ${res.status}: ${url}`);
140
+ return res.json();
141
+ }
142
+ async function pool(values, fn, concurrency = 3) {
143
+ const output = new Array(values.length); let cursor = 0;
144
+ await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, async () => {
145
+ while (cursor < values.length) { const i = cursor++; try { output[i] = { status: 'fulfilled', value: await fn(values[i], i) }; } catch (reason) { output[i] = { status: 'rejected', reason }; } }
146
+ }));
147
+ return output;
148
+ }
149
+ // Latin words of one or two letters are joiners (of, de, la, en); years, numbers and CJK words stay.
150
+ const JOINERS = new Set(['the', 'and', 'for', 'with', 'from', 'der', 'die', 'das', 'les', 'des', 'del', 'van', 'von']);
151
+ export const queryTerms = q => String(q).toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(w => w && (/\d|[^\p{Script=Latin}]/u.test(w) || (w.length > 2 && !JOINERS.has(w))));
152
+ // Whole words with plurals; long terms also match compounds. Substrings made "fig" match "configuration"; plate captions write "fig. 2".
153
+ export function matchCount(text, terms) {
154
+ const flat = String(text ?? '').normalize('NFKC').toLowerCase(), list = flat.replace(/<[^>]*>/g, ' ').replace(/\b(figs?|pl|no|vol)\.\s*\d+/g, ' ').split(/[^\p{L}\p{N}]+/u).filter(Boolean);
155
+ // Adjacent pairs joined, so "tea pot" in a title answers "teapot".
156
+ const words = new Set([...list, ...list.slice(1).map((w, i) => list[i] + w)]);
157
+ // CJK text has no spaces between words, so CJK terms match as substrings.
158
+ const has = t => /[^\p{Script=Latin}\p{N}]/u.test(t) ? flat.includes(t) : words.has(t) || words.has(t + 's') || words.has(t + 'es') || (t.length > 3 && t.endsWith('s') && words.has(t.slice(0, -1))) || (t.length >= 5 && [...words].some(w => w.startsWith(t)));
159
+ return terms.filter(has).length;
160
+ }
161
+ // page: the licence allows a commercial page; reference: it does not, but the picture can guide generation; check: unclear.
162
+ export function rightsUse(license = '', licenseUrl = '') {
163
+ const s = `${license} ${licenseUrl}`.toLowerCase();
164
+ if (/non-?commercial|by-nc|\bnc\b|no ?deriv|by-nd|\bnd\b|requires licensing/.test(s)) return 'reference';
165
+ if (/third-party rights|not verified|not specified|in copyright/.test(s)) return 'check';
166
+ if (/cc0|publicdomain|public domain|\bpdm?\b|no known restrictions|not subject to us copyright|creativecommons\.org\/licenses\/by(-sa)?\/|\bcc[ -]by(-sa)?\b|attribution( |-sharealike )\d/.test(s)) return 'page';
167
+ return 'check';
168
+ }
169
+ const emptyCache = () => ({ version: 1, items: {}, catalogues: {} });
170
+ async function readCache(file) {
171
+ try {
172
+ const data = JSON.parse(await fs.readFile(file, 'utf8'));
173
+ if (data.version !== 1 || !data.items || !data.catalogues) throw new Error('格式或版本不支持');
174
+ return data;
175
+ } catch (e) {
176
+ if (e.code === 'ENOENT') return emptyCache();
177
+ throw new Error(`缓存 ${file} 无法读取:${e.message};请用 --cache 指定新文件`);
178
+ }
179
+ }
180
+ async function replaceCache(temp, file) {
181
+ const deadline = Date.now() + 5000;
182
+ for (;;) {
183
+ try { await fs.rename(temp, file); return; }
184
+ catch (error) {
185
+ // Windows readers/virus scanners can briefly deny replacing an existing
186
+ // file. Keep the old cache intact and retry only sharing/permission errors.
187
+ if (!['EPERM', 'EACCES', 'EBUSY'].includes(error.code) || Date.now() >= deadline) throw error;
188
+ await new Promise(resolve => setTimeout(resolve, 60));
189
+ }
190
+ }
191
+ }
192
+ // Serialize read/modify/write across concurrent agent processes; network calls stay outside the lock.
193
+ async function updateCache(file, fn) {
194
+ await fs.mkdir(path.dirname(file), { recursive: true });
195
+ const lock = file + '.lock'; const deadline = Date.now() + 5000;
196
+ while (true) {
197
+ try { await fs.mkdir(lock); break; } catch (e) {
198
+ if (e.code !== 'EEXIST') throw e;
199
+ if (Date.now() > deadline) throw new Error(`缓存正在使用:${lock};若上次进程已退出,可移除锁目录后重试`);
200
+ await new Promise(resolve => setTimeout(resolve, 60));
201
+ }
202
+ }
203
+ const temp = file + '.' + randomUUID() + '.tmp';
204
+ try {
205
+ const data = await readCache(file); const result = await fn(data);
206
+ await fs.writeFile(temp, JSON.stringify(data)); await replaceCache(temp, file); return result;
207
+ } finally { await fs.rm(temp, { force: true }); await fs.rmdir(lock); }
208
+ }
209
+ async function catalogue(type, opts) {
210
+ const data = await readCache(opts.cache); const cached = data.catalogues[type];
211
+ if (!opts.refresh && cached && Date.now() - cached.time < 86400000) return cached.data;
212
+ const fresh = await json(`https://api.polyhaven.com/assets?t=${type}`, opts);
213
+ await updateCache(opts.cache, c => { c.catalogues[type] = { time: Date.now(), data: fresh }; });
214
+ return fresh;
215
+ }
216
+ export function selectMap(files, keys, resolution) {
217
+ for (const key of keys) {
218
+ const group = files[key]; if (!group) continue;
219
+ const available = Object.keys(group).filter(r => group[r]?.jpg?.url).sort((a, b) => parseInt(a) - parseInt(b));
220
+ const r = available.includes(resolution) ? resolution : available.filter(r => parseInt(r) <= parseInt(resolution)).at(-1) ?? available[0];
221
+ if (r) return { ...group[r].jpg, resolution: r, channel: key };
222
+ }
223
+ return null;
224
+ }
225
+ async function resolveTexture(item, opts) {
226
+ const files = await json(`https://api.polyhaven.com/files/${encodeURIComponent(item.sourceId)}`, opts);
227
+ const textureMaps = {
228
+ diffuse: selectMap(files, ['Diffuse', 'diff', 'Color', 'col'], opts.resolution),
229
+ roughness: selectMap(files, ['Rough', 'rough', 'Roughness'], opts.resolution),
230
+ normal: selectMap(files, ['nor_gl', 'Normal', 'normal'], opts.resolution),
231
+ };
232
+ if (!textureMaps.diffuse) throw new Error(`${item.sourceId} 没有可用 Diffuse JPG`);
233
+ return { ...item, textureMaps, textureUrl: textureMaps.diffuse.url, imageUrl: textureMaps.diffuse.url, normalConvention: 'OpenGL', tiling: '查看 previewUrl 并检查重复边缘;部分材质仅单轴重复' };
234
+ }
235
+ async function searchPoly(query, limit, opts, type = 'textures') {
236
+ const data = await catalogue(type, opts), terms = queryTerms(query);
237
+ const ranked = Object.entries(data).map(([slug, meta]) => {
238
+ const hay = [slug.replaceAll('_', ' '), meta.name, meta.description, meta.category, ...(meta.categories ?? []), ...(meta.tags ?? [])].join(' ');
239
+ return { slug, meta, score: matchCount(hay, terms) };
240
+ }).filter(x => x.score >= Math.max(1, Math.ceil(terms.length / 2))).sort((a, b) => b.score - a.score).slice(0, limit);
241
+ const out = await pool(ranked, async ({ slug, meta }) => {
242
+ const previewUrl = `https://cdn.polyhaven.com/asset_img/thumbs/${encodeURIComponent(slug)}.png?width=768`;
243
+ const item = { matched: ranked.find(x => x.slug === slug).score, provider: 'polyhaven', sourceId: slug, kind: type === 'textures' ? 'texture' : 'model', title: meta.name ?? slug, detail: (meta.categories ?? []).join(', '), license: 'CC0', licenseUrl: 'https://polyhaven.com/license', attribution: [Object.keys(meta.authors ?? {}).join(', '), 'Powered by Poly Haven'].filter(Boolean).join(' · '), pageUrl: `https://polyhaven.com/a/${encodeURIComponent(slug)}`, previewUrl, imageUrl: previewUrl };
244
+ if (type === 'textures') return resolveTexture(item, opts);
245
+ const files = await json(`https://api.polyhaven.com/files/${encodeURIComponent(slug)}`, opts);
246
+ const model = files.gltf?.[opts.resolution]?.gltf ?? Object.values(files.gltf ?? {})[0]?.gltf;
247
+ return { ...item, modelFile: model ?? null, previewType: 'rendered-image' };
248
+ });
249
+ const errors = out.flatMap((r, i) => r.status === 'rejected' ? [`${ranked[i].slug}: ${r.reason.message}`] : []);
250
+ return { items: out.filter(r => r.status === 'fulfilled').map(r => r.value), errors };
251
+ }
252
+ function iiifBase(value) { return value?.replace(/\/info\.json(?:\?.*)?$/, '').replace(/\/full\/.*$/, '').replace(/\/$/, ''); }
253
+ async function searchVam(query, limit, opts) {
254
+ const data = await json(apiUrl('https://api.vam.ac.uk/v2/objects/search', { q: query, images_exist: 1, page_size: limit }), opts);
255
+ return (data.records ?? []).flatMap(r => {
256
+ const base = iiifBase(r._images?._iiif_image_base_url ?? r._images?._primary_thumbnail ?? (r._primaryImageId ? `https://framemark.vam.ac.uk/collections/${r._primaryImageId}` : null));
257
+ if (!base) return [];
258
+ return [{ provider: 'vam', sourceId: r.systemNumber, kind: 'design', title: r._primaryTitle || r.objectType || r.systemNumber, detail: [r.objectType, r._primaryMaker?.name, r._primaryDate, r._primaryPlace].filter(Boolean).join(' · '), license: 'V&A terms: permitted non-commercial uses only; commercial/home-page/high-resolution publication requires licensing', licenseUrl: 'https://www.vam.ac.uk/info/va-websites-terms-conditions', attribution: `© Victoria and Albert Museum, London (${r.systemNumber})`, pageUrl: `https://collections.vam.ac.uk/item/${r.systemNumber}`, iiifInfoUrl: `${base}/info.json`, imageUrl: `${base}/full/!1600,1600/0/default.jpg`, previewUrl: `${base}/full/!400,400/0/default.jpg` }];
259
+ });
260
+ }
261
+ async function searchWellcome(query, limit, opts, kind = 'plate') {
262
+ const data = await json(apiUrl('https://api.wellcomecollection.org/catalogue/v2/images', { query, pageSize: limit, include: 'source.contributors' }), opts);
263
+ return (data.results ?? []).flatMap(r => {
264
+ const loc = r.locations?.find(x => x.locationType?.id === 'iiif-image') ?? r.thumbnail;
265
+ const base = iiifBase(loc?.url); if (!base) return [];
266
+ const people = (r.source?.contributors ?? []).map(c => c.agent?.label).filter(Boolean);
267
+ return [{ provider: 'wellcome', sourceId: r.id, kind, title: r.source?.title ?? r.id, detail: people.join(', '), license: loc.license?.label ?? 'Rights not specified; check item', licenseUrl: loc.license?.url ?? `https://wellcomecollection.org/works/${r.source?.id}`, attribution: [...people, loc.credit || 'Wellcome Collection'].join(' · '), pageUrl: `https://wellcomecollection.org/works/${r.source?.id}`, iiifInfoUrl: `${base}/info.json`, imageUrl: `${base}/full/!1600,1600/0/default.jpg`, previewUrl: `${base}/full/!400,400/0/default.jpg` }];
268
+ });
269
+ }
270
+ function locItem(row, kind, imageUrl, previewUrl, sourceId, pageUrl) {
271
+ const rights = row.item?.rights_advisory ?? row.item?.rights_information ?? row.rights ?? 'Rights not specified in search; check Rights & Access on item page';
272
+ return { provider: 'loc', sourceId, kind, title: row.title ?? 'Library of Congress', detail: [row.date, ...(row.contributor ?? row.contributors ?? [])].filter(Boolean).join(' · '), license: Array.isArray(rights) ? rights.join(' ') : rights, licenseUrl: pageUrl, attribution: row.item?.repository ?? 'Library of Congress', pageUrl, imageUrl: https(imageUrl), previewUrl: https(previewUrl ?? imageUrl) };
273
+ }
274
+ async function searchLoc(query, limit, opts, kind = 'photo') {
275
+ if (kind === 'blueprint') return searchBlueprint(query, limit, opts);
276
+ const data = await json(apiUrl(`https://www.loc.gov/${kind === 'map' ? 'maps' : 'photos'}/`, { q: query, fo: 'json', c: Math.min(limit * 2, 60) }), opts);
277
+ return (data.results ?? []).filter(r => !r.access_restricted).flatMap(r => {
278
+ const urls = (r.image_url ?? []).filter(u => /\.(jpe?g|png)(?:[?#]|$)/i.test(u));
279
+ if (!urls.length) return [];
280
+ const best = urls.at(-1).split('#')[0], page = https(r.url || r.id);
281
+ return [locItem(r, kind, best, (urls[1] ?? urls[0]).split('#')[0], r.id ?? page, page)];
282
+ }).slice(0, limit);
283
+ }
284
+ async function searchBlueprint(query, limit, opts) {
285
+ // hh includes photographs and surveys. Only /sheet/ images are measured drawings.
286
+ const data = await json(apiUrl('https://www.loc.gov/collections/historic-american-buildings-landscapes-and-engineering-records/', { q: `${query} drawings`, fo: 'json', at: 'results', c: Math.min(limit * 3, 60) }), opts);
287
+ return (data.results ?? []).flatMap(row => {
288
+ const resource = (row.resources ?? []).find(r => /\/sheet\//.test(r.image ?? ''));
289
+ const image = resource?.image ?? (row.image_url ?? []).find(u => /\/sheet\//.test(u));
290
+ if (!image) return [];
291
+ const preview = new URL(https(image), 'https://www.loc.gov').href.split('#')[0];
292
+ // LOC service derivative suffixes: _150px thumbnail, r medium, v large.
293
+ const full = preview.replace(/_150px\.jpg$/, 'v.jpg').replace(/r\.jpg$/, 'v.jpg');
294
+ const page = https(resource?.url ?? row.url ?? row.id);
295
+ return [locItem(row, 'blueprint', full, preview.replace(/_150px\.jpg$/, 'r.jpg'), page, page)];
296
+ }).slice(0, limit);
297
+ }
298
+ export function selectNasaFile(urls, type, videoSize = 'medium') {
299
+ const candidates = urls.filter(u => type === 'video' ? /\.(mp4|mov)(?:\?|$)/i.test(u) : /\.(jpe?g|png)(?:\?|$)/i.test(u));
300
+ const rank = type === 'video' ? [`~${videoSize}.`, ...['~medium.', '~small.', '~mobile.', '~preview.', '~orig.'].filter(x => x !== `~${videoSize}.`)] : ['~orig.', '~large.', '~medium.', '~small.', '~thumb.'];
301
+ return candidates.sort((a, b) => {
302
+ const score = u => { const i = rank.findIndex(t => u.includes(t)); return i < 0 ? 99 : i; };
303
+ return score(a) - score(b);
304
+ })[0];
305
+ }
306
+ async function resolveNasa(item, opts) {
307
+ const data = await json(item.manifestUrl, opts);
308
+ const urls = Array.isArray(data) ? data : (data.collection?.items ?? []).map(r => r.href);
309
+ const url = selectNasaFile(urls, item.mediaType, opts['video-size']);
310
+ if (!url) throw new Error(`${item.sourceId} 无可下载的 ${item.mediaType} 文件`);
311
+ const alternates = item.mediaType === 'video' ? ['preview', 'small', 'mobile'].map(size => urls.find(u => u.includes(`~${size}.`) && /\.mp4$/i.test(u))).filter(Boolean) : ['large', 'medium', 'small'].map(size => urls.find(u => u.includes(`~${size}.`) && /\.(jpe?g|png)$/i.test(u))).filter(Boolean);
312
+ return { ...item, downloadCandidates: [...new Set([url, ...alternates].map(https))], ...(item.mediaType === 'video' ? { videoUrl: https(url) } : { imageUrl: https(url) }) };
313
+ }
314
+ async function searchNasa(query, limit, opts, mediaType = 'image', kind = 'science') {
315
+ const data = await json(apiUrl('https://images-api.nasa.gov/search', { q: query, media_type: mediaType, page_size: mediaType === 'video' ? Math.min(limit * 3, 100) : limit }), opts);
316
+ return (data.collection?.items ?? []).flatMap(row => {
317
+ const r = row.data?.[0]; if (!r) return [];
318
+ const image = row.links?.find(l => l.render === 'image' && l.rel === 'preview')?.href ?? row.links?.find(l => l.render === 'image')?.href;
319
+ if (!image) return [];
320
+ if (mediaType === 'video' && /animation|visualization|simulation|computer.generated|rendering/i.test([r.title, ...(r.keywords ?? [])].join(' '))) return [];
321
+ const thirdParty = /copyright|©|all rights reserved/i.test([r.description, r.photographer, r.secondary_creator].join(' '));
322
+ return [{ provider: 'nasa', sourceId: r.nasa_id, kind, mediaType: r.media_type, title: r.title ?? r.nasa_id, detail: [r.center, r.date_created, r.description?.replace(/<[^>]*>/g, '').slice(0, 500)].filter(Boolean).join(' · '), license: thirdParty ? 'Third-party rights mentioned; check item credits' : 'NASA media usage guidelines; generally not subject to US copyright; verify third-party credits', licenseUrl: 'https://www.nasa.gov/nasa-brand-center/images-and-media/', attribution: ['NASA', r.center, r.photographer, r.secondary_creator].filter(Boolean).join(' · '), pageUrl: `https://images.nasa.gov/details/${encodeURIComponent(r.nasa_id)}`, imageUrl: https(image), previewUrl: https(image), manifestUrl: https(row.href ?? `https://images-api.nasa.gov/asset/${encodeURIComponent(r.nasa_id)}`) }];
323
+ }).slice(0, limit);
324
+ }
325
+ const plain = s => String(s ?? '').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/<[^>]*>/g, ' ').replace(/&amp;/g, '&').replace(/&quot;/g, '"').replace(/&#0?39;/g, "'").replace(/\s+/g, ' ').trim();
326
+ // Commons search matches anywhere on the file page; map and plate kinds keep only files whose title or description names the medium.
327
+ const MEDIUM = { map: /\b(map|maps|plan|chart|atlas|kaart|carte|karte|plattegrond)\b/i, plate: /\b(engraving|etching|lithograph|woodcut|plate|print|illustration|drawing|gravure)\b/i };
328
+ async function searchCommons(query, limit, opts, kind = 'photo') {
329
+ // Wikimedia only serves standard thumbnail widths; 500 and 1920 are among them.
330
+ const data = await json(apiUrl('https://commons.wikimedia.org/w/api.php', { action: 'query', format: 'json', formatversion: 2, generator: 'search', gsrsearch: `${query} filetype:bitmap`, gsrnamespace: 6, gsrlimit: Math.min(limit * 2, 40), prop: 'imageinfo', iiprop: 'url|size|mime|extmetadata', iiurlwidth: 1920, iiextmetadatafilter: 'LicenseShortName|License|LicenseUrl|Artist|DateTimeOriginal|ObjectName|ImageDescription|AttributionRequired' }), opts);
331
+ return (data.query?.pages ?? []).sort((a, b) => (a.index ?? 0) - (b.index ?? 0)).flatMap(p => {
332
+ const ii = p.imageinfo?.[0]; if (!ii?.url || !ii.width) return [];
333
+ const m = k => plain(ii.extmetadata?.[k]?.value);
334
+ const webSafe = /^image\/(jpeg|png|webp|gif)$/.test(ii.mime);
335
+ const imageUrl = ii.thumburl && (ii.width > 1920 || !webSafe) ? ii.thumburl : webSafe ? ii.url : null;
336
+ if (!imageUrl) return [];
337
+ const previewUrl = ii.thumburl && ii.width > 500 ? ii.thumburl.replace(/\/\d+px-/, '/500px-') : imageUrl;
338
+ const short = m('LicenseShortName') || m('License') || 'License on file page';
339
+ if (MEDIUM[kind] && !MEDIUM[kind].test(`${p.title} ${m('ObjectName')} ${m('ImageDescription')}`)) return [];
340
+ return [{ provider: 'commons', sourceId: String(p.pageid), kind, title: m('ObjectName') || p.title.replace(/^File:/, '').replace(/\.[a-z0-9]+$/i, ''), detail: [m('DateTimeOriginal'), m('Artist')].filter(Boolean).join(' · ').slice(0, 200), about: m('ImageDescription').slice(0, 300), license: short, licenseUrl: m('LicenseUrl') || ii.descriptionurl, attribution: [m('Artist') || 'Unknown', 'via Wikimedia Commons'].join(' · ').slice(0, 300), pageUrl: ii.descriptionurl, imageUrl: https(imageUrl), previewUrl: https(previewUrl), originalWidth: ii.width, originalHeight: ii.height }];
341
+ }).slice(0, limit * 2);
342
+ }
343
+ async function searchAic(query, limit, opts, kind = 'design') {
344
+ const data = await json(apiUrl('https://api.artic.edu/api/v1/artworks/search', { q: query, limit: Math.min(limit * 2, 40), fields: 'id,title,artist_display,date_display,image_id,is_public_domain,thumbnail,medium_display,artwork_type_title', 'query[term][is_public_domain]': 'true' }), opts);
345
+ const iiif = data.config?.iiif_url ?? 'https://www.artic.edu/iiif/2';
346
+ return (data.data ?? []).flatMap(r => {
347
+ if (!r.image_id || !r.is_public_domain) return [];
348
+ const width = r.thumbnail?.width, height = r.thumbnail?.height;
349
+ const base = `${iiif}/${r.image_id}/full`;
350
+ return [{ provider: 'aic', sourceId: String(r.id), kind, title: r.title ?? String(r.id), detail: [r.artwork_type_title, plain(r.artist_display), r.date_display].filter(Boolean).join(' · '), about: [r.medium_display, r.thumbnail?.alt_text].filter(Boolean).join(' · ').slice(0, 300), license: 'CC0 (public-domain artwork, Art Institute of Chicago)', licenseUrl: 'https://www.artic.edu/open-access/open-access-images', attribution: `Art Institute of Chicago (${r.id})`, pageUrl: `https://www.artic.edu/artworks/${r.id}`, imageUrl: `${base}/${width && width < 1686 ? width : 1686},/0/default.jpg`, previewUrl: `${base}/400,/0/default.jpg`, originalWidth: width, originalHeight: height }];
351
+ });
352
+ }
353
+ async function searchCleveland(query, limit, opts, kind = 'design') {
354
+ const data = await json(apiUrl('https://openaccess-api.clevelandart.org/api/artworks/', { q: query, has_image: 1, cc0: 1, limit: Math.min(limit * 2, 40) }), opts);
355
+ return (data.data ?? []).flatMap(r => {
356
+ const web = r.images?.web, print = r.images?.print, full = r.images?.full;
357
+ if (!web?.url) return [];
358
+ return [{ provider: 'cleveland', sourceId: String(r.id), kind, title: r.title ?? String(r.id), detail: [r.type, ...(r.creators ?? []).map(c => c.description), r.creation_date].filter(Boolean).join(' · '), about: plain(r.description ?? r.technique ?? '').slice(0, 300), license: 'CC0', licenseUrl: 'https://www.clevelandart.org/open-access', attribution: r.creditline ? `Cleveland Museum of Art · ${r.creditline}` : 'Cleveland Museum of Art', pageUrl: r.url, imageUrl: https((print ?? web).url), previewUrl: https(web.url), originalWidth: Number(full?.width ?? print?.width) || undefined, originalHeight: Number(full?.height ?? print?.height) || undefined }];
359
+ });
360
+ }
361
+ async function searchMet(query, limit, opts, kind = 'design') {
362
+ // v1 search was retired on 2026-10-01; v1.1 pages results, and each object needs its own request.
363
+ const data = await json(apiUrl('https://collectionapi.metmuseum.org/public/collection/v1.1/search', { q: query, hasImages: 'true', isPublicDomain: 'true', limit: Math.min(limit * 2, 12) }), opts);
364
+ const out = await pool(data.objectIDs ?? [], id => json(`https://collectionapi.metmuseum.org/public/collection/v1/objects/${id}`, opts), 4);
365
+ return out.flatMap(r => {
366
+ const o = r.status === 'fulfilled' ? r.value : null;
367
+ if (!o?.isPublicDomain || !o.primaryImage) return [];
368
+ return [{ provider: 'met', sourceId: String(o.objectID), kind, title: o.title || o.objectName || String(o.objectID), detail: [o.objectName, o.artistDisplayName, o.objectDate, o.culture].filter(Boolean).join(' · '), about: [o.medium, o.classification].filter(Boolean).join(' · ').slice(0, 300), license: 'CC0 (Met Open Access, public domain)', licenseUrl: 'https://www.metmuseum.org/policies/image-resources', attribution: `The Metropolitan Museum of Art (${o.objectID})`, pageUrl: o.objectURL, imageUrl: https(o.primaryImage), previewUrl: https(o.primaryImageSmall || o.primaryImage) }];
369
+ });
370
+ }
371
+ const JAPAN_RIGHTS = { cc0: 'CC0', pdm: 'Public Domain Mark', ccby: 'CC BY 4.0', ccbysa: 'CC BY-SA 4.0' };
372
+ async function searchJapan(query, limit, opts, kind = 'design') {
373
+ // Japan Search gathers ColBase (the national museums), the National Diet Library and regional collections; only openly licensed images are requested.
374
+ const u = new URL('https://jpsearch.go.jp/api/item/search/jps-cross');
375
+ u.searchParams.set('keyword', query); u.searchParams.set('f-contents', 'image'); u.searchParams.set('size', String(Math.min(limit * 3, 60)));
376
+ for (const r of Object.keys(JAPAN_RIGHTS)) u.searchParams.append('f-rights', '+' + r);
377
+ const data = await json(u.href, opts);
378
+ return (data.list ?? []).flatMap(x => {
379
+ const c = x.common ?? {}, raw = c.contentsUrl?.[0] ?? c.thumbnailUrl?.[0];
380
+ if (!raw || !JAPAN_RIGHTS[c.contentsRightsType]) return [];
381
+ // ColBase keeps a 3000px image at /slideshow/ beside the small /slideshow_s/; some items lack it, so the small one stays as fallback.
382
+ const original = https(raw), large = original.replace('/slideshow_s/', '/slideshow/');
383
+ const people = (c.contributor ?? []).filter(Boolean).slice(0, 2).join(' / ');
384
+ return [{ provider: 'japan', sourceId: c.id ?? x.id, kind, title: plain(c.title) || c.id, detail: [plain(c.titleEn), (c.temporal ?? []).at(-1), people].filter(Boolean).join(' · ').slice(0, 240), about: plain(c.description).slice(0, 300), license: JAPAN_RIGHTS[c.contentsRightsType], licenseUrl: 'https://jpsearch.go.jp/policy/available-rights-statements', attribution: c.database === 'cobas' ? `出典:ColBase(https://colbase.nich.go.jp/) · ${people}` : [people || c.provider, 'via Japan Search'].filter(Boolean).join(' · '), pageUrl: c.linkUrl ?? `https://jpsearch.go.jp/item/${c.id}`, imageUrl: large, previewUrl: https(c.thumbnailUrl?.[0] ?? raw), downloadCandidates: [...new Set([large, original])] }];
385
+ });
386
+ }
387
+ async function searchRijks(query, limit, opts, kind = 'design') {
388
+ // Linked Art: the search lists object ids; the image sits two hops away (object → visual item → digital object).
389
+ const data = await json(apiUrl('https://data.rijksmuseum.nl/search/collection', { description: query, imageAvailable: 'true' }), opts);
390
+ const out = await pool((data.orderedItems ?? []).slice(0, Math.min(limit * 2, 10)).map(x => x.id), async id => {
391
+ const o = await json(id, opts);
392
+ const visual = await json(o.shows[0].id, opts), digital = await json(visual.digitally_shown_by[0].id, opts);
393
+ const service = digital.access_point?.[0]?.id?.replace(/\/full\/.*$/, '');
394
+ if (!service) return null;
395
+ const names = (o.identified_by ?? []).filter(n => n.type === 'Name'), english = names.find(n => JSON.stringify(n.language ?? '').includes('300388277'));
396
+ const rights = JSON.stringify(o.subject_of ?? '').match(/https?:\/\/creativecommons\.org\/[a-z/]+\/[\d.]+\//)?.[0];
397
+ const number = (o.identified_by ?? []).find(n => n.type === 'Identifier')?.content;
398
+ return { provider: 'rijks', sourceId: id.split('/').pop(), kind, title: (english ?? names[0])?.content ?? number ?? id, detail: [names.find(n => n !== english)?.content, number].filter(Boolean).join(' · ').slice(0, 240), about: (o.referred_to_by ?? []).map(r => r.content).filter(Boolean).join(' · ').slice(0, 300), license: rights ? (rights.includes('/zero/') ? 'CC0' : rights.includes('/mark/') ? 'Public Domain Mark' : rights) : 'Rights not specified in record; check item page', licenseUrl: rights ?? id, attribution: `Rijksmuseum, Amsterdam${number ? ` (${number})` : ''}`, pageUrl: id, imageUrl: `${service}/full/!2400,2400/0/default.jpg`, previewUrl: `${service}/full/!500,500/0/default.jpg` };
399
+ }, 4);
400
+ return out.flatMap(r => r.status === 'fulfilled' && r.value ? [r.value] : []);
401
+ }
402
+ export function interleave(groups, limit) {
403
+ const out = [], seen = new Set();
404
+ for (let i = 0; groups.some(g => i < g.length) && out.length < limit; i++) {
405
+ for (const group of groups) {
406
+ const item = group[i]; if (!item) continue;
407
+ // Archives often list one work as several records; identical title and detail add nothing to compare.
408
+ const key = `${item.provider}:${item.sourceId}`, twin = `${item.provider}:${item.title}:${item.detail ?? ''}`.toLowerCase();
409
+ if (seen.has(key) || seen.has(twin)) continue; seen.add(key); seen.add(twin); out.push(item);
410
+ if (out.length === limit) break;
411
+ }
412
+ }
413
+ return out;
414
+ }
415
+ async function remember(items, opts) {
416
+ return updateCache(opts.cache, cache => items.map(item => {
417
+ const existing = Object.values(cache.items).find(x => x.provider === item.provider && x.sourceId === item.sourceId);
418
+ const prefix = PREFIX[item.provider];
419
+ const next = Math.max(0, ...Object.keys(cache.items).filter(k => k.startsWith(prefix)).map(k => Number(k.slice(1)) || 0)) + 1;
420
+ const ref = existing?.ref ?? prefix + next;
421
+ const result = { ...existing, ...item, ref, cachedAt: new Date().toISOString() }; cache.items[ref] = result; return result;
422
+ }));
423
+ }
424
+ function searchJobs(query, opts) {
425
+ const kinds = opts.kind === 'all' ? 15 : 1;
426
+ const per = Math.max(2, Math.ceil(opts.limit / kinds));
427
+ const jobs = {
428
+ texture: [['polyhaven/textures', () => searchPoly(query, per, opts)]],
429
+ design: [['met', () => searchMet(query, per, opts)], ['aic', () => searchAic(query, per, opts)], ['cleveland', () => searchCleveland(query, per, opts)], ['vam', () => searchVam(query, per, opts)], ['polyhaven/models', () => searchPoly(query, per, opts, 'models')], ['japan', () => searchJapan(query, per, opts)], ['rijks', () => searchRijks(query, per, opts)]],
430
+ photo: [['commons', () => searchCommons(query, per, opts)], ['loc/photos', () => searchLoc(query, per, opts)], ['nasa/images', () => searchNasa(query, per, opts, 'image', 'photo')]],
431
+ blueprint: [['loc/hh', () => searchLoc(query, per, opts, 'blueprint')]],
432
+ map: [['loc/maps', () => searchLoc(query, per, opts, 'map')], ['commons/maps', () => searchCommons(`${query} (map OR chart OR plan)`, per, opts, 'map')]],
433
+ plate: [['wellcome', () => searchWellcome(query, per, opts)], ['japan/plates', () => searchJapan(query, per, opts, 'plate')], ['commons/plates', () => searchCommons(`${query} engraving`, per, opts, 'plate')]],
434
+ science: [['nasa/science', () => searchNasa(query, per, opts)], ['wellcome/science', () => searchWellcome(query, per, opts, 'science')]],
435
+ video: [['nasa/video', () => searchNasa(query, per, opts, 'video', 'video')]],
436
+ };
437
+ if (opts.kind !== 'all') return jobs[opts.kind];
438
+ // One job per source, so a single slow or empty source cannot take the whole first round.
439
+ return [jobs.photo[0], jobs.design[5], jobs.texture[0], jobs.design[1], jobs.photo[1], jobs.design[6], jobs.design[2], jobs.plate[0], jobs.design[0], jobs.science[0], jobs.blueprint[0], jobs.map[0], jobs.design[3], jobs.video[0], jobs.design[4]];
440
+ }
441
+ async function runSearch(input, opts) {
442
+ const queries = input.split(/\s*\|\s*/).map(q => q.trim()).filter(Boolean);
443
+ if (!queries.length) usage('search 缺少关键词');
444
+ const selected = queries.flatMap(query => searchJobs(query, opts).map(([label, fn]) => [queries.length > 1 ? `${label} "${query}"` : label, fn, query]));
445
+ let filtered = 0;
446
+ const results = await Promise.allSettled(selected.map(async ([label, fn, query]) => {
447
+ const start = Date.now(); const value = await fn(); let items = Array.isArray(value) ? value : value.items;
448
+ const terms = queryTerms(query), before = items.length;
449
+ // Sources that search full records return items whose title and summary never mention the subject.
450
+ // full: the item names every query term. Full matches are picked across sources first, so a medium word alone ("engraving") cannot crowd out the subject.
451
+ // CJK queries reach records catalogued only in English, so a CJK miss ranks lower instead of being dropped.
452
+ items = items.map(item => { const score = item.matched ?? matchCount(`${item.title} ${item.detail} ${item.about ?? ''}`, terms); return { ...item, score, full: score >= terms.length }; });
453
+ if (terms.length && terms.every(t => /^[\p{Script=Latin}\p{N}]+$/u.test(t))) items = items.filter(item => item.score > 0);
454
+ filtered += before - items.length;
455
+ items = items.map(({ matched, score, ...item }) => ({ ...item, use: item.use ?? rightsUse(item.license, item.licenseUrl), query }));
456
+ if (opts.use === 'page') items = items.filter(item => item.use === 'page');
457
+ console.error(`[curate-media] ${label}: ${items.length} 项${before > items.length ? `(滤掉 ${before - items.length})` : ''} (${Date.now() - start}ms)`);
458
+ return { items, errors: value.errors ?? [] };
459
+ }));
460
+ const errors = results.flatMap((r, i) => r.status === 'rejected' ? [{ source: selected[i][0], message: r.reason.message }] : r.value.errors.map(message => ({ source: selected[i][0], message })));
461
+ const groups = results.filter(r => r.status === 'fulfilled').map(r => r.value.items);
462
+ const full = interleave(groups.map(g => g.filter(i => i.full)), opts.limit), taken = new Set(full.map(i => `${i.provider}:${i.sourceId}`));
463
+ const partial = interleave(groups.map(g => g.filter(i => !i.full && !taken.has(`${i.provider}:${i.sourceId}`))), opts.limit - full.length);
464
+ const picked = [...full, ...partial].map(({ full, ...item }) => item).sort((a, b) => USES[a.use] - USES[b.use]);
465
+ let items = await remember(picked, opts);
466
+ let sheet;
467
+ if (opts.sheet) ({ items, sheet } = await remoteSheet(items, opts));
468
+ const hint = items.length ? undefined : '零结果:每组只留一两个词,先搜地名或物名本身,或用 | 分开几种说法;--kind 换成 all';
469
+ return { query: input, ...(queries.length > 1 ? { queries } : {}), kind: opts.kind, count: items.length, ...(hint ? { hint } : {}), filtered, cache: opts.cache, items, errors, ...sheet, failed: results.every(r => r.status === 'rejected') || (!items.length && errors.length > 0) };
470
+ }
471
+ async function targets(positional, opts) {
472
+ const tokens = positional.flatMap(x => /^https?:\/\//i.test(x) ? [x] : x.split(/[,\s]+/)).filter(Boolean);
473
+ const cache = await readCache(opts.cache);
474
+ for (const extra of [path.join(opts.dir, '.curate-cache.json'), path.join(path.dirname(opts.dir), '.curate-cache.json')]) {
475
+ if (extra !== opts.cache && existsSync(extra)) {
476
+ try { const other = await readCache(extra); cache.items = { ...other.items, ...cache.items }; } catch {}
477
+ }
478
+ }
479
+ return [...new Set(tokens)].map(token => {
480
+ if (/^[A-Z]\d+$/i.test(token) && Object.values(PREFIX).includes(token[0].toUpperCase())) {
481
+ const item = cache.items[token.toUpperCase()];
482
+ if (!item) usage(`缓存中没有 ${token};先 search,或用 --cache 选择原缓存`);
483
+ return item;
484
+ }
485
+ try {
486
+ const url = httpUrl(token);
487
+ // A pasted result URL retains its source metadata whenever the workspace knows it.
488
+ const known = Object.values(cache.items).find(x => [x.imageUrl, x.videoUrl, ...Object.values(x.textureMaps ?? {}).map(m => m?.url)].includes(url));
489
+ return { ...known, directUrl: url, imageUrl: url, title: known?.title ?? path.basename(new URL(url).pathname), provider: known?.provider ?? 'url', use: known?.use ?? 'check', license: known?.license ?? 'Rights not verified (direct URL)', attribution: known?.attribution ?? 'Source supplied by user', pageUrl: known?.pageUrl ?? url, previewUrl: url };
490
+ } catch { usage(`无效编号或 URL:${token}`); }
491
+ });
492
+ }
493
+ const escapeHtml = s => String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
494
+ async function writeSheet(items, dir, remote) {
495
+ await fs.mkdir(dir, { recursive: true });
496
+ const cards = items.map(item => {
497
+ const src = remote ? item.previewUrl ?? item.imageUrl : item.poster ?? item.saved;
498
+ const href = remote ? src : src && path.relative(dir, src).split(path.sep).map(encodeURIComponent).join('/');
499
+ const image = href && !/\.(mp4|mov|webm)(?:\?|$)/i.test(href) ? `<img src="${escapeHtml(href)}" alt="${escapeHtml(item.title)}"><p class="size">加载中…</p>` : '<p>没有图片预览;请查看下载结果</p>';
500
+ return `<article>${image}<h2>${escapeHtml(item.ref ?? 'URL')} · ${escapeHtml(item.use ?? 'check')} · ${escapeHtml(item.map ?? item.kind)} · ${escapeHtml(item.title)}</h2><p>${escapeHtml(item.license)}</p><p>${escapeHtml(item.attribution)}</p><a href="${escapeHtml(item.pageUrl)}">来源记录</a>${item.integrity ? `<p>${escapeHtml(item.integrity)} · ${item.width ?? '?'} × ${item.height ?? '?'}</p>` : ''}</article>`;
501
+ }).join('\n');
502
+ const file = path.join(dir, remote ? 'candidates.html' : 'sheet.html');
503
+ const html = `<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>素材候选联系表</title><style>body{font:15px/1.5 system-ui;margin:24px;background:#eee;color:#222}main{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}article{background:white;padding:16px;overflow-wrap:anywhere}img{width:100%;height:240px;object-fit:contain}h2{font-size:17px;line-height:1.4}.error{color:#a00}</style><h1>素材候选 · ${items.length} 项</h1><p>${remote ? '远程预览:宽高为预览文件尺寸,原图尺寸在下载结果中。' : '本地素材:解码结果与真实宽高见各项说明。'}</p><main>${cards}</main><script>for(const img of document.images){const label=img.nextElementSibling;function check(){label.textContent=img.naturalWidth?img.naturalWidth+' × '+img.naturalHeight:'加载失败';if(!img.naturalWidth)label.className='error'}img.addEventListener('load',check);img.addEventListener('error',check);if(img.complete)check()}</script></html>`;
504
+ await fs.writeFile(file, html); return file;
505
+ }
506
+ async function hasTool(name) { try { await exec(name, ['-version'], { timeout: 5000, maxBuffer: 100000 }); return true; } catch { return false; } }
507
+ // Design facts from a 48×48 thumbnail: where text can sit, what the edges fuse with, whether ink sits on paper.
508
+ // Calm needs both low spread and low neighbour contrast; spread alone calls a fine-lined map calm. Thresholds come from real previews.
509
+ export function describePixels(buf, n = 48) {
510
+ const px = i => [buf[i * 3], buf[i * 3 + 1], buf[i * 3 + 2]];
511
+ const lum = i => { const [r, g, b] = px(i); return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; };
512
+ const region = (x0, y0, x1, y1) => {
513
+ let sum = 0, sq = 0, sat = 0, grad = 0, pairs = 0; const rgb = [0, 0, 0], count = (x1 - x0) * (y1 - y0);
514
+ for (let y = y0; y < y1; y++) for (let x = x0; x < x1; x++) {
515
+ const i = y * n + x, v = lum(i), c = px(i), max = Math.max(...c);
516
+ sum += v; sq += v * v; sat += max ? (max - Math.min(...c)) / max : 0; c.forEach((value, k) => { rgb[k] += value; });
517
+ if (x + 1 < x1) { grad += Math.abs(v - lum(i + 1)); pairs++; }
518
+ if (y + 1 < y1) { grad += Math.abs(v - lum(i + n)); pairs++; }
519
+ }
520
+ const mean = sum / count;
521
+ return { mean, sd: Math.sqrt(Math.max(0, sq / count - mean * mean)), sat: sat / count, grad: grad / pairs, rgb: rgb.map(v => v / count) };
522
+ };
523
+ const calmOf = r => r.sd < 0.09 && r.grad < 0.02;
524
+ const all = region(0, 0, n, n), t = Math.round(n / 3), e = 3;
525
+ const strips = [region(0, 0, n, e), region(0, n - e, n, n), region(0, 0, e, n), region(n - e, 0, n, n)];
526
+ const edgeFlat = strips.every(r => r.sd < 0.06 && r.grad < 0.02);
527
+ const ring = { mean: strips.reduce((v, r) => v + r.mean, 0) / 4, sat: strips.reduce((v, r) => v + r.sat, 0) / 4, rgb: [0, 1, 2].map(k => strips.reduce((v, r) => v + r.rgb[k], 0) / 4) };
528
+ const regions = { top: region(0, 0, n, t), bottom: region(0, n - t, n, n), left: region(0, 0, t, n), right: region(n - t, 0, n, n), centre: region(t, t, n - t, n - t) };
529
+ const hex = rgb => '#' + rgb.map(v => Math.round(v).toString(16).padStart(2, '0')).join('');
530
+ return { tone: all.mean < 0.33 ? 'dark' : all.mean > 0.66 ? 'light' : 'mid', mono: all.sat < 0.1, edge: hex(ring.rgb), edgeFlat, paper: edgeFlat && ring.mean > 0.75 && ring.sat < 0.2, calm: Object.keys(regions).filter(k => calmOf(regions[k])) };
531
+ }
532
+ async function lookAt(file, info) {
533
+ const { stdout } = await exec('ffmpeg', ['-nostdin', '-v', 'error', '-i', file, '-frames:v', '1', '-vf', 'scale=48:48:flags=area,format=rgb24', '-f', 'rawvideo', 'pipe:1'], { encoding: 'buffer', timeout: 20000, maxBuffer: 100000 });
534
+ if (stdout.length < 48 * 48 * 3) throw new Error('预览无法解码');
535
+ return { ...describePixels(stdout), ratio: +(info.width / info.height).toFixed(2) };
536
+ }
537
+ const FONTS = ['/System/Library/Fonts/Supplemental/Arial.ttf', '/System/Library/Fonts/Helvetica.ttc', '/Library/Fonts/Arial.ttf', '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', '/usr/share/fonts/dejavu/DejaVuSans.ttf', '/usr/share/fonts/TTF/DejaVuSans.ttf', '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf', 'C:/Windows/Fonts/arial.ttf', 'C:/Windows/Fonts/segoeui.ttf'];
538
+ const labelText = s => String(s ?? '').normalize('NFKD').replace(/[^A-Za-z0-9 ./#+()-]/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 46);
539
+ // One PNG an agent can read in a single look: each cell carries its ref, use and size.
540
+ async function contactSheet(cells, file) {
541
+ const cols = Math.min(4, cells.length), rows = Math.ceil(cells.length / cols), W = 360, H = 300, IW = W - 16, IH = H - 62;
542
+ const graph = [`color=c=0xEDEDED:s=${cols * W}x${rows * H}:d=1[b0]`];
543
+ cells.forEach((_, i) => {
544
+ const x = (i % cols) * W + 8, y = Math.floor(i / cols) * H + 8;
545
+ graph.push(`[${i}:v]scale=${IW}:${IH}:force_original_aspect_ratio=decrease[s${i}]`, `[b${i}][s${i}]overlay=x='${x}+(${IW}-w)/2':y='${y}+(${IH}-h)/2'[b${i + 1}]`);
546
+ });
547
+ const font = FONTS.find(f => existsSync(f));
548
+ const draw = (t, x, y, size, color) => `drawtext=${font ? `fontfile='${font.replace(/:/g, '\\:')}':` : ''}text='${labelText(t)}':x=${x}:y=${y}:fontsize=${size}:fontcolor=${color}`;
549
+ const labels = cells.flatMap((c, i) => { const x = (i % cols) * W + 10, y = Math.floor(i / cols) * H + H - 50; return [draw(c.top, x, y, 18, '0x111111'), draw(c.bottom, x, y + 25, 13, '0x555555')]; });
550
+ const run = withLabels => exec('ffmpeg', ['-nostdin', '-v', 'error', '-y', ...cells.flatMap(c => ['-i', c.src]), '-filter_complex', graph.join(';') + (withLabels ? `;[b${cells.length}]${labels.join(',')}[out]` : ''), '-map', withLabels ? '[out]' : `[b${cells.length}]`, '-frames:v', '1', '-update', '1', file], { timeout: 60000, maxBuffer: 1000000 });
551
+ try { await run(true); return { file, labelled: true }; }
552
+ catch { await run(false); return { file, labelled: false }; }
553
+ }
554
+ const sizeLabel = item => item.originalWidth && item.originalHeight ? `${item.originalWidth}x${item.originalHeight}` : item.width && item.height ? `${item.width}x${item.height}` : '';
555
+ async function remoteSheet(items, opts) {
556
+ const html = await writeSheet(items, opts.dir, true);
557
+ if (!(await hasTool('ffmpeg')) || !(await hasTool('ffprobe'))) return { items, sheet: { sheet: html, sheetWarnings: ['缺少 ffmpeg/ffprobe,没有联系表 PNG 和 look;打开 HTML 联系表挑选'] } };
558
+ const temp = await fs.mkdtemp(path.join(os.tmpdir(), 'oil-curate-'));
559
+ try {
560
+ const looked = await pool(items, async (item, i) => {
561
+ const file = path.join(temp, `${i}.part`);
562
+ await download(item.previewUrl ?? item.imageUrl, file, { ...opts, 'download-timeout': opts.timeout });
563
+ const size = await inspect(file, { ffprobe: true }, false);
564
+ return { file, size, look: await lookAt(file, size) };
565
+ }, 6);
566
+ const out = items.map((item, i) => looked[i].status !== 'fulfilled' ? { ...item, look: null, lookError: looked[i].reason.message } : { ...item, look: looked[i].value.look, ...(!item.originalWidth && item.previewUrl === item.imageUrl ? { originalWidth: looked[i].value.size.width, originalHeight: looked[i].value.size.height } : {}) });
567
+ const cells = out.flatMap((item, i) => looked[i].status === 'fulfilled' ? [{ src: looked[i].value.file, top: `${item.ref ?? 'URL'} ${item.use ?? ''} ${sizeLabel(item)}`, bottom: `${item.provider} - ${/[a-z]{3}/i.test(labelText(item.title)) ? item.title : item.detail}` }] : []);
568
+ const warnings = out.filter(x => x.lookError).map(x => `${x.ref ?? x.imageUrl}: 预览下载失败,未进 PNG:${x.lookError}`);
569
+ if (!cells.length) return { items: out, sheet: { sheet: html, sheetWarnings: warnings } };
570
+ const png = await contactSheet(cells, path.join(opts.dir, 'candidates.png'));
571
+ if (!png.labelled) warnings.push('ffmpeg 无法写字,PNG 没有编号;格子按 items 中有 look 的条目从左到右、从上到下排列');
572
+ console.error(`[curate-media] 联系表图片:${png.file}(直接读这张图挑选)`);
573
+ return { items: out, sheet: { sheet: html, sheetImage: png.file, ...(warnings.length ? { sheetWarnings: warnings } : {}) } };
574
+ } finally { await fs.rm(temp, { recursive: true, force: true }); }
575
+ }
576
+ export function sniff(buffer) {
577
+ if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) return { ext: '.jpg', video: false };
578
+ if (buffer.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) return { ext: '.png', video: false };
579
+ if (buffer.toString('ascii', 0, 6).match(/^GIF8[79]a$/)) return { ext: '.gif', video: false };
580
+ if (buffer.toString('ascii', 0, 4) === 'RIFF' && buffer.toString('ascii', 8, 12) === 'WEBP') return { ext: '.webp', video: false };
581
+ if (buffer.toString('ascii', 4, 8) === 'ftyp') return { ext: buffer.toString('ascii', 8, 12).startsWith('qt') ? '.mov' : '.mp4', video: true };
582
+ if (buffer.subarray(0, 4).equals(Buffer.from([0x1a, 0x45, 0xdf, 0xa3]))) return { ext: '.webm', video: true };
583
+ throw new Error('响应不是支持的图片或视频;可能是 HTML、JSON 错误页或损坏的文件');
584
+ }
585
+ async function download(url, temp, opts, expected) {
586
+ const res = await fetch(httpUrl(url), { headers: headersFor(url), signal: AbortSignal.timeout(opts['download-timeout']) });
587
+ if (!res.ok) throw new Error(`HTTP ${res.status}: ${url}`);
588
+ const max = opts['max-mb'] * 1024 * 1024, length = Number(res.headers.get('content-length'));
589
+ if (length > max) { await res.body?.cancel(); throw new Error(`文件超过 --max-mb ${opts['max-mb']}`); }
590
+ if (/text\/html|application\/json/.test(res.headers.get('content-type') ?? '')) { await res.body?.cancel(); throw new Error('响应是错误页或元数据,不是媒体文件'); }
591
+ const handle = await fs.open(temp, 'wx'); let bytes = 0, head = Buffer.alloc(0); const md5 = createHash('md5');
592
+ try {
593
+ for await (const chunk of res.body) {
594
+ bytes += chunk.length; if (bytes > max) throw new Error(`文件超过 --max-mb ${opts['max-mb']}`);
595
+ if (head.length < 32) head = Buffer.concat([head, Buffer.from(chunk)]).subarray(0, 32);
596
+ md5.update(chunk); await handle.writeFile(chunk);
597
+ }
598
+ } finally { await handle.close(); }
599
+ if (!bytes || (length && !res.headers.get('content-encoding') && bytes !== length)) throw new Error('文件为空或传输不完整');
600
+ if (expected?.size && bytes !== expected.size) throw new Error(`文件大小不符:${bytes},预期 ${expected.size}`);
601
+ const digest = md5.digest('hex'); if (expected?.md5 && digest !== expected.md5) throw new Error('MD5 校验失败');
602
+ return { bytes, md5: digest, ...sniff(head) };
603
+ }
604
+ async function inspect(file, tools, full) {
605
+ if (!tools.ffprobe) return { integrity: 'signature-and-length-only', warnings: ['缺少 ffprobe,尚未检查真实宽高'] };
606
+ const { stdout } = await exec('ffprobe', ['-v', 'error', '-select_streams', 'v:0', '-show_entries', 'stream=width,height,codec_name:format=duration', '-of', 'json', file], { timeout: 20000, maxBuffer: 100000 });
607
+ const data = JSON.parse(stdout), stream = data.streams?.[0];
608
+ if (!stream?.width || !stream?.height) throw new Error('没有可解码的图像/视频流');
609
+ if (full && tools.ffmpeg) await exec('ffmpeg', ['-nostdin', '-v', 'error', '-xerror', '-i', file, '-map', '0:v:0', '-f', 'null', '-'], { timeout: 120000, maxBuffer: 1000000 });
610
+ return { width: stream.width, height: stream.height, codec: stream.codec_name, duration: Number(data.format?.duration) || undefined, integrity: full && tools.ffmpeg ? 'full-decode' : 'probed', warnings: full && !tools.ffmpeg ? ['缺少 ffmpeg,尚未完整解码'] : [] };
611
+ }
612
+ const safeName = s => String(s ?? 'media').replace(/[^a-zA-Z0-9_-]+/g, '-').slice(0, 90) || 'media';
613
+ // Reserve the destination atomically; repeated downloads get suffixes instead of overwriting.
614
+ async function deliver(temp, wanted, explicit = false) {
615
+ for (let i = 0; i < 1000; i++) {
616
+ const p = path.parse(wanted), file = i ? path.join(p.dir, `${p.name}-${i}${p.ext}`) : wanted;
617
+ try { await fs.copyFile(temp, file, fs.constants.COPYFILE_EXCL); return file; } catch (e) { if (e.code !== 'EEXIST') throw e; if (explicit) throw new Error(`文件已存在:${file};请换一个 --out 文件名`); }
618
+ }
619
+ throw new Error('文件名冲突过多');
620
+ }
621
+ const mdText = s => String(s ?? '').replace(/[\r\n]+/g, ' ').replace(/[`\[\]<>]/g, '');
622
+ async function logSources(records, note) {
623
+ const groups = new Map();
624
+ for (const r of records) {
625
+ const dir = path.dirname(r.saved); if (!groups.has(dir)) groups.set(dir, []);
626
+ const line = `- \`${path.basename(r.saved)}\` — ${mdText(r.ref ?? r.provider)} · ${mdText(r.title)}${r.map ? ' · ' + r.map : ''}\n - Use: ${r.use === 'reference' ? 'reference only, not for the page' : r.use === 'page' ? 'page' : 'check rights on the source page'}\n - Source: ${r.pageUrl}\n - Download: ${r.url}\n - License: ${mdText(r.license)} (${r.licenseUrl ?? r.pageUrl})\n - Credit: ${mdText(r.attribution)}${note ? '\n - Note: ' + mdText(note) : ''}\n`;
627
+ groups.get(dir).push(line);
628
+ if (r.poster) groups.get(dir).push(`- \`${path.basename(r.poster)}\` — first-frame poster derived from \`${path.basename(r.saved)}\`; same license and credit as above.\n`);
629
+ }
630
+ for (const [dir, lines] of groups) await fs.appendFile(path.join(dir, 'SOURCES.md'), lines.join('\n') + '\n');
631
+ }
632
+ async function resolveIIIF(item, opts) {
633
+ const info = await json(item.iiifInfoUrl, opts);
634
+ if (!info.width || !info.height) throw new Error('IIIF 没有有效的原图尺寸');
635
+ const base = iiifBase(item.iiifInfoUrl);
636
+ const imageUrl = Math.max(info.width, info.height) <= 1600 ? `${base}/full/full/0/default.jpg` : `${base}/full/!1600,1600/0/default.jpg`;
637
+ return { ...item, imageUrl, originalWidth: info.width, originalHeight: info.height };
638
+ }
639
+ // Final picks get the same look fields and a PNG, measured on the files the page will use.
640
+ async function localSheet(records, dir) {
641
+ const cells = [];
642
+ for (const r of records) {
643
+ const src = r.poster ?? (r.video ? null : r.saved); if (!src) continue;
644
+ try { r.look = await lookAt(src, await inspect(src, { ffprobe: true }, false)); cells.push({ src, top: `${r.ref ?? 'URL'} ${r.use} ${r.width && r.height ? `${r.width}x${r.height}` : ''}`, bottom: path.basename(r.saved) }); }
645
+ catch (e) { r.warnings.push(`look 失败:${e.message}`); }
646
+ }
647
+ return cells.length ? (await contactSheet(cells, path.join(dir, 'sheet.png'))).file : undefined;
648
+ }
649
+ async function runFetch(items, opts) {
650
+ if (opts.out && (items.length !== 1 || (items[0].kind === 'texture' && !items[0].directUrl && opts.maps.length > 1))) usage('--out 只支持单文件;批量拉取用 --dir assets');
651
+ await fs.mkdir(opts.dir, { recursive: true });
652
+ const tools = { ffmpeg: await hasTool('ffmpeg'), ffprobe: await hasTool('ffprobe') };
653
+ const tasks = [], errors = [], records = [];
654
+ for (let item of items) {
655
+ try {
656
+ if (!item.directUrl && item.kind === 'texture') item = await resolveTexture(item, opts);
657
+ else if (!item.directUrl && item.provider === 'nasa') item = await resolveNasa(item, opts);
658
+ else if (!item.directUrl && item.iiifInfoUrl) item = await resolveIIIF(item, opts);
659
+ if (item.kind === 'texture' && !item.directUrl) {
660
+ for (const map of opts.maps) {
661
+ const file = item.textureMaps[map];
662
+ if (!file) { errors.push({ ref: item.ref, map, message: `没有可用 ${map} JPG` }); continue; }
663
+ tasks.push({ item, map, url: file.url, expected: file });
664
+ }
665
+ } else tasks.push({ item, url: item.directUrl ?? item.videoUrl ?? item.imageUrl });
666
+ } catch (e) { errors.push({ ref: item.ref, message: e.message }); }
667
+ }
668
+ const settled = await pool(tasks, async ({ item, map, url, expected }) => {
669
+ const temp = path.join(opts.dir, `.${randomUUID()}.part`); let result;
670
+ try {
671
+ let received; const recovery = [];
672
+ const candidates = item.directUrl ? [url] : item.downloadCandidates ?? [url];
673
+ for (const candidate of candidates.slice(0, 3)) {
674
+ try { received = await download(candidate, temp, opts, expected); url = candidate; break; }
675
+ catch (e) { recovery.push(`${candidate}: ${e.message}`); await fs.rm(temp, { force: true }); }
676
+ }
677
+ if (!received) throw new Error(recovery.join('; '));
678
+ const inspection = await inspect(temp, tools, opts.sheet);
679
+ const filename = `${safeName(item.ref ?? item.provider)}-${safeName(item.sourceId ?? item.title)}${map ? '-' + map + '-' + expected.resolution : ''}${received.ext}`;
680
+ const out = opts.out ? path.resolve(opts.out) : path.join(opts.dir, filename);
681
+ if (opts.out && ![received.ext, ...(received.ext === '.jpg' ? ['.jpeg'] : [])].includes(path.extname(out).toLowerCase())) throw new Error(`--out 后缀与实际文件格式不一致,应为 ${received.ext}`);
682
+ const saved = await deliver(temp, out, Boolean(opts.out));
683
+ result = { ref: item.ref, provider: item.provider, sourceId: item.sourceId, kind: item.kind, use: item.use ?? rightsUse(item.license, item.licenseUrl), title: item.title, map, resolution: expected?.resolution, url, saved, pageUrl: item.pageUrl, license: item.license, licenseUrl: item.licenseUrl, attribution: item.attribution, originalWidth: item.originalWidth, originalHeight: item.originalHeight, ...(map === 'normal' ? { normalConvention: item.normalConvention } : {}), ...received, ...inspection };
684
+ if (!received.video && Math.max(result.width ?? 9999, result.height ?? 9999) < 1000) result.warnings.push(`尺寸偏小(${result.width}x${result.height}),只适合小图位`);
685
+ if (result.use === 'reference') result.warnings.push('仅作生图参考:授权不允许放进页面,放在不上线的目录');
686
+ if (recovery.length) result.warnings.push(`已回退到可用版本;之前失败:${recovery.join('; ')}`);
687
+ if (received.video) {
688
+ if (!tools.ffmpeg) result.warnings.push('缺少 ffmpeg,poster 未生成');
689
+ else {
690
+ const posterTemp = path.join(opts.dir, `.${randomUUID()}.jpg`);
691
+ try {
692
+ await exec('ffmpeg', ['-nostdin', '-v', 'error', '-xerror', '-i', saved, '-frames:v', '1', '-q:v', '2', posterTemp], { timeout: 30000, maxBuffer: 100000 });
693
+ result.poster = await deliver(posterTemp, saved.replace(/\.[^.]+$/, '-poster.jpg'));
694
+ } catch (e) { result.warnings.push(`poster 失败:${e.message}`); }
695
+ finally { await fs.rm(posterTemp, { force: true }); }
696
+ }
697
+ }
698
+ console.error(`[curate-media] ${item.ref ?? 'URL'}${map ? '/' + map : ''}: ${received.bytes} bytes → ${saved}`);
699
+ return result;
700
+ } finally { await fs.rm(temp, { force: true }); }
701
+ });
702
+ settled.forEach((r, i) => { if (r.status === 'fulfilled') records.push(r.value); else errors.push({ ref: tasks[i].item.ref, url: tasks[i].url, message: r.reason.message }); });
703
+ await logSources(records, opts.note);
704
+ for (const r of records) if ((opts.sheet && r.integrity !== 'full-decode') || (r.video && !r.poster)) errors.push({ ref: r.ref, saved: r.saved, message: r.warnings.join('; ') || '检查或 poster 未完成' });
705
+ const sheet = opts.sheet ? await writeSheet(records, opts.dir, false) : undefined;
706
+ const sheetImage = opts.sheet && tools.ffmpeg && tools.ffprobe ? await localSheet(records, opts.dir) : undefined;
707
+ return { count: records.length, files: records, errors, ...(sheet ? { sheet } : {}), ...(sheetImage ? { sheetImage } : {}), ...(records.length === 1 ? { saved: records[0].saved, bytes: records[0].bytes } : {}), failed: errors.length > 0 };
708
+ }
709
+ export async function main(argv = process.argv.slice(2)) {
710
+ const parsed = parseArgs(argv); if (parsed.help) { console.log(HELP); return; }
711
+ const { command, positional, opts } = parsed; const start = Date.now(); let result;
712
+ if (command === 'search') result = await runSearch(positional.join(' ').trim(), opts);
713
+ else {
714
+ const items = await targets(positional, opts);
715
+ if (command === 'fetch') result = await runFetch(items, opts);
716
+ else { const { items: out, sheet } = await remoteSheet(items, opts); result = { count: out.length, items: out, ...sheet }; }
717
+ }
718
+ const { failed, ...output } = result;
719
+ console.log(JSON.stringify({ ...output, elapsedMs: Date.now() - start }, null, 2));
720
+ if (failed) process.exitCode = 1;
721
+ }
722
+ // Compare real paths: through a symlinked install or /tmp on macOS, the URL and argv differ and the script would exit silently.
723
+ const real = file => { try { return realpathSync(file); } catch { return path.resolve(file); } };
724
+ if (process.argv[1] && real(process.argv[1]) === real(fileURLToPath(import.meta.url))) {
725
+ main().catch(err => { console.error(`[curate-media] ${err.message}`); process.exitCode = 1; });
726
+ }