dsh-aris-panel 0.1.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 (442) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/README_CN.md +87 -0
  4. package/dsh/checkout.patch.yml +38 -0
  5. package/dsh/client.js +634 -0
  6. package/dsh/cordis.patch.yml +44 -0
  7. package/dsh/index.mjs +76 -0
  8. package/dsh/run-status.mjs +182 -0
  9. package/dsh/scope-limits.mjs +50 -0
  10. package/dsh/workbench.mjs +291 -0
  11. package/mcp-servers/claude-review/README.md +93 -0
  12. package/mcp-servers/claude-review/run_with_claude_aws.sh +49 -0
  13. package/mcp-servers/claude-review/server.py +718 -0
  14. package/mcp-servers/codex-image2/README.md +65 -0
  15. package/mcp-servers/codex-image2/server.py +893 -0
  16. package/mcp-servers/feishu-bridge/requirements.txt +1 -0
  17. package/mcp-servers/feishu-bridge/server.py +240 -0
  18. package/mcp-servers/gemini-review/README.md +171 -0
  19. package/mcp-servers/gemini-review/server.py +1856 -0
  20. package/mcp-servers/llm-chat/requirements.txt +1 -0
  21. package/mcp-servers/llm-chat/server.py +664 -0
  22. package/mcp-servers/manual-review/README.md +133 -0
  23. package/mcp-servers/manual-review/server.py +910 -0
  24. package/mcp-servers/manual-review/ui.html +279 -0
  25. package/mcp-servers/minimax-chat/requirements.txt +1 -0
  26. package/mcp-servers/minimax-chat/server.py +381 -0
  27. package/package.json +51 -0
  28. package/skills/ablation-planner/SKILL.md +123 -0
  29. package/skills/alphaxiv/SKILL.md +196 -0
  30. package/skills/analyze-results/SKILL.md +46 -0
  31. package/skills/arxiv/SKILL.md +248 -0
  32. package/skills/auto-paper-improvement-loop/SKILL.md +651 -0
  33. package/skills/auto-review-loop/SKILL.md +1137 -0
  34. package/skills/auto-review-loop-llm/SKILL.md +259 -0
  35. package/skills/auto-review-loop-minimax/SKILL.md +302 -0
  36. package/skills/citation-audit/SKILL.md +502 -0
  37. package/skills/claims-drafting/SKILL.md +227 -0
  38. package/skills/comm-lit-review/SKILL.md +297 -0
  39. package/skills/deepxiv/SKILL.md +263 -0
  40. package/skills/dse-loop/SKILL.md +296 -0
  41. package/skills/embodiment-description/SKILL.md +129 -0
  42. package/skills/exa-search/SKILL.md +205 -0
  43. package/skills/experiment-audit/SKILL.md +311 -0
  44. package/skills/experiment-bridge/SKILL.md +376 -0
  45. package/skills/experiment-plan/SKILL.md +249 -0
  46. package/skills/experiment-queue/SKILL.md +431 -0
  47. package/skills/experiment-queue/scripts/build_manifest.py +142 -0
  48. package/skills/experiment-queue/scripts/queue_manager.py +433 -0
  49. package/skills/feishu-notify/SKILL.md +156 -0
  50. package/skills/figure-description/SKILL.md +138 -0
  51. package/skills/figure-spec/SKILL.md +262 -0
  52. package/skills/figure-spec/scripts/figure_renderer.py +799 -0
  53. package/skills/formula-derivation/SKILL.md +280 -0
  54. package/skills/gemini-search/SKILL.md +231 -0
  55. package/skills/grant-proposal/SKILL.md +698 -0
  56. package/skills/idea-creator/SKILL.md +542 -0
  57. package/skills/idea-discovery/SKILL.md +521 -0
  58. package/skills/idea-discovery-robot/SKILL.md +363 -0
  59. package/skills/integrity-forensics/SKILL.md +284 -0
  60. package/skills/interview-cheatsheet/SKILL.md +245 -0
  61. package/skills/invention-structuring/SKILL.md +188 -0
  62. package/skills/jurisdiction-format/SKILL.md +192 -0
  63. package/skills/kill-argument/SKILL.md +437 -0
  64. package/skills/mermaid-diagram/SKILL.md +419 -0
  65. package/skills/meta-apply/SKILL.md +141 -0
  66. package/skills/meta-optimize/SKILL.md +437 -0
  67. package/skills/monitor-experiment/SKILL.md +140 -0
  68. package/skills/novelty-check/SKILL.md +101 -0
  69. package/skills/openalex/SKILL.md +237 -0
  70. package/skills/overleaf-sync/SKILL.md +220 -0
  71. package/skills/paper-claim-audit/SKILL.md +348 -0
  72. package/skills/paper-compile/SKILL.md +266 -0
  73. package/skills/paper-figure/SKILL.md +312 -0
  74. package/skills/paper-illustration/SKILL.md +736 -0
  75. package/skills/paper-illustration-image2/SKILL.md +391 -0
  76. package/skills/paper-illustration-image2/scripts/paper_illustration_image2.py +255 -0
  77. package/skills/paper-plan/SKILL.md +386 -0
  78. package/skills/paper-poster/SKILL.md +19 -0
  79. package/skills/paper-poster-html/DESIGN_FINAL.md +176 -0
  80. package/skills/paper-poster-html/IMPLEMENTATION_CONVENTIONS.md +161 -0
  81. package/skills/paper-poster-html/LICENSES/posterly-MIT.txt +21 -0
  82. package/skills/paper-poster-html/NOTICE.md +57 -0
  83. package/skills/paper-poster-html/SKILL.md +323 -0
  84. package/skills/paper-poster-html/scripts/_posterly/__init__.py +0 -0
  85. package/skills/paper-poster-html/scripts/_posterly/canvas.py +200 -0
  86. package/skills/paper-poster-html/scripts/_posterly/measure.py +588 -0
  87. package/skills/paper-poster-html/scripts/_posterly/polish.py +498 -0
  88. package/skills/paper-poster-html/scripts/_posterly/preflight.py +489 -0
  89. package/skills/paper-poster-html/scripts/_posterly/render.py +215 -0
  90. package/skills/paper-poster-html/scripts/_posterly/textutil.py +16 -0
  91. package/skills/paper-poster-html/scripts/_posterly/verify_final.py +171 -0
  92. package/skills/paper-poster-html/scripts/asset_check.py +897 -0
  93. package/skills/paper-poster-html/scripts/extract_pdf_figures.py +666 -0
  94. package/skills/paper-poster-html/scripts/poster_check.py +251 -0
  95. package/skills/paper-poster-html/scripts/preprocess_figures.py +238 -0
  96. package/skills/paper-poster-html/scripts/render_preview.py +217 -0
  97. package/skills/paper-poster-html/scripts/run_gates.py +556 -0
  98. package/skills/paper-poster-html/scripts/style_check.py +1324 -0
  99. package/skills/paper-poster-html/templates/COMPONENTS.md +462 -0
  100. package/skills/paper-poster-html/templates/README.md +170 -0
  101. package/skills/paper-poster-html/templates/landscape_4col.html +1032 -0
  102. package/skills/paper-poster-html/templates/landscape_hero.html +1046 -0
  103. package/skills/paper-poster-html/templates/portrait_2col.html +947 -0
  104. package/skills/paper-poster-html/templates/tokens/acl.json +9 -0
  105. package/skills/paper-poster-html/templates/tokens/cvpr.json +9 -0
  106. package/skills/paper-poster-html/templates/tokens/generic.json +9 -0
  107. package/skills/paper-poster-html/templates/tokens/iclr.json +9 -0
  108. package/skills/paper-poster-html/templates/tokens/icml.json +9 -0
  109. package/skills/paper-poster-html/templates/tokens/neurips.json +9 -0
  110. package/skills/paper-slides/SKILL.md +635 -0
  111. package/skills/paper-talk/SKILL.md +381 -0
  112. package/skills/paper-write/SKILL.md +604 -0
  113. package/skills/paper-write/templates/IEEEtran.bst +2409 -0
  114. package/skills/paper-write/templates/IEEEtran.cls +6347 -0
  115. package/skills/paper-write/templates/iclr2026.tex +84 -0
  116. package/skills/paper-write/templates/icml2025.tex +87 -0
  117. package/skills/paper-write/templates/ieee_conference.tex +89 -0
  118. package/skills/paper-write/templates/ieee_journal.tex +93 -0
  119. package/skills/paper-write/templates/math_commands.tex +48 -0
  120. package/skills/paper-write/templates/neurips2025.tex +80 -0
  121. package/skills/paper-writing/SKILL.md +916 -0
  122. package/skills/patent-novelty-check/SKILL.md +153 -0
  123. package/skills/patent-pipeline/SKILL.md +344 -0
  124. package/skills/patent-review/SKILL.md +203 -0
  125. package/skills/pixel-art/SKILL.md +137 -0
  126. package/skills/prior-art-search/SKILL.md +146 -0
  127. package/skills/proof-checker/SKILL.md +866 -0
  128. package/skills/proof-orchestrator/NOTICE.md +24 -0
  129. package/skills/proof-orchestrator/SKILL.md +254 -0
  130. package/skills/proof-orchestrator/references/audit-output-contract.md +126 -0
  131. package/skills/proof-orchestrator/references/deepseek-routing.md +74 -0
  132. package/skills/proof-orchestrator/references/dispatch-prompts.md +227 -0
  133. package/skills/proof-orchestrator/references/notation-audit.md +135 -0
  134. package/skills/proof-orchestrator/references/proof-audit-rubric.md +70 -0
  135. package/skills/proof-orchestrator/references/stress-tests.md +38 -0
  136. package/skills/proof-writer/SKILL.md +223 -0
  137. package/skills/qzcli/SKILL.md +324 -0
  138. package/skills/rebuttal/SKILL.md +376 -0
  139. package/skills/render-html/SKILL.md +316 -0
  140. package/skills/render-html/scripts/render_html.py +1006 -0
  141. package/skills/render-html/scripts/templates/academic.html +703 -0
  142. package/skills/render-html/scripts/templates/dashboard.html +333 -0
  143. package/skills/research-lit/SKILL.md +756 -0
  144. package/skills/research-pipeline/SKILL.md +384 -0
  145. package/skills/research-refine/SKILL.md +770 -0
  146. package/skills/research-refine-pipeline/SKILL.md +186 -0
  147. package/skills/research-review/SKILL.md +198 -0
  148. package/skills/research-wiki/SKILL.md +461 -0
  149. package/skills/resubmit-pipeline/SKILL.md +447 -0
  150. package/skills/result-to-claim/SKILL.md +311 -0
  151. package/skills/run-experiment/SKILL.md +313 -0
  152. package/skills/semantic-scholar/SKILL.md +236 -0
  153. package/skills/serverless-modal/SKILL.md +335 -0
  154. package/skills/shared-references/acceptance-gate.md +324 -0
  155. package/skills/shared-references/assurance-contract.md +248 -0
  156. package/skills/shared-references/capture-antipatterns.md +78 -0
  157. package/skills/shared-references/citation-discipline.md +583 -0
  158. package/skills/shared-references/compute-env-contract.md +163 -0
  159. package/skills/shared-references/effort-contract.md +183 -0
  160. package/skills/shared-references/evidence-precheck.md +65 -0
  161. package/skills/shared-references/experiment-integrity.md +49 -0
  162. package/skills/shared-references/external-cadence.md +326 -0
  163. package/skills/shared-references/fan-out-pattern.md +366 -0
  164. package/skills/shared-references/injection-hygiene.md +127 -0
  165. package/skills/shared-references/integration-contract.md +461 -0
  166. package/skills/shared-references/output-composition.md +93 -0
  167. package/skills/shared-references/output-language.md +45 -0
  168. package/skills/shared-references/output-manifest.md +49 -0
  169. package/skills/shared-references/output-versioning.md +111 -0
  170. package/skills/shared-references/patent-format-cn.md +199 -0
  171. package/skills/shared-references/patent-format-ep.md +173 -0
  172. package/skills/shared-references/patent-format-us.md +161 -0
  173. package/skills/shared-references/patent-writing-principles.md +197 -0
  174. package/skills/shared-references/prior-art-databases.md +141 -0
  175. package/skills/shared-references/resumable-runs.md +109 -0
  176. package/skills/shared-references/review-scope-limits.md +81 -0
  177. package/skills/shared-references/review-tracing.md +391 -0
  178. package/skills/shared-references/reviewer-independence.md +79 -0
  179. package/skills/shared-references/reviewer-routing.md +852 -0
  180. package/skills/shared-references/skill-governance.md +104 -0
  181. package/skills/shared-references/taste-calibration.md +85 -0
  182. package/skills/shared-references/venue-checklists.md +114 -0
  183. package/skills/shared-references/wiki-helper-resolution.md +134 -0
  184. package/skills/shared-references/writing-principles.md +525 -0
  185. package/skills/skills-codex/README.md +102 -0
  186. package/skills/skills-codex/README_CN.md +100 -0
  187. package/skills/skills-codex/ablation-planner/SKILL.md +126 -0
  188. package/skills/skills-codex/alphaxiv/SKILL.md +186 -0
  189. package/skills/skills-codex/analyze-results/SKILL.md +45 -0
  190. package/skills/skills-codex/arxiv/SKILL.md +210 -0
  191. package/skills/skills-codex/auto-paper-improvement-loop/SKILL.md +574 -0
  192. package/skills/skills-codex/auto-review-loop/SKILL.md +500 -0
  193. package/skills/skills-codex/auto-review-loop-llm/SKILL.md +247 -0
  194. package/skills/skills-codex/auto-review-loop-minimax/SKILL.md +290 -0
  195. package/skills/skills-codex/citation-audit/SKILL.md +504 -0
  196. package/skills/skills-codex/claims-drafting/SKILL.md +239 -0
  197. package/skills/skills-codex/comm-lit-review/SKILL.md +299 -0
  198. package/skills/skills-codex/comm-lit-review/references/domain-taxonomy.md +57 -0
  199. package/skills/skills-codex/comm-lit-review/references/output-template.md +37 -0
  200. package/skills/skills-codex/comm-lit-review/references/source-policy.md +99 -0
  201. package/skills/skills-codex/comm-lit-review/references/venue-tiering.md +112 -0
  202. package/skills/skills-codex/deepxiv/SKILL.md +142 -0
  203. package/skills/skills-codex/dse-loop/SKILL.md +285 -0
  204. package/skills/skills-codex/embodiment-description/SKILL.md +129 -0
  205. package/skills/skills-codex/exa-search/SKILL.md +192 -0
  206. package/skills/skills-codex/experiment-audit/SKILL.md +286 -0
  207. package/skills/skills-codex/experiment-bridge/SKILL.md +356 -0
  208. package/skills/skills-codex/experiment-plan/SKILL.md +249 -0
  209. package/skills/skills-codex/experiment-queue/SKILL.md +401 -0
  210. package/skills/skills-codex/feishu-notify/SKILL.md +155 -0
  211. package/skills/skills-codex/figure-description/SKILL.md +138 -0
  212. package/skills/skills-codex/figure-spec/SKILL.md +252 -0
  213. package/skills/skills-codex/formula-derivation/SKILL.md +280 -0
  214. package/skills/skills-codex/gemini-search/SKILL.md +205 -0
  215. package/skills/skills-codex/grant-proposal/SKILL.md +626 -0
  216. package/skills/skills-codex/idea-creator/SKILL.md +405 -0
  217. package/skills/skills-codex/idea-discovery/SKILL.md +475 -0
  218. package/skills/skills-codex/idea-discovery-robot/SKILL.md +362 -0
  219. package/skills/skills-codex/integrity-forensics/SKILL.md +106 -0
  220. package/skills/skills-codex/interview-cheatsheet/SKILL.md +245 -0
  221. package/skills/skills-codex/invention-structuring/SKILL.md +188 -0
  222. package/skills/skills-codex/jurisdiction-format/SKILL.md +192 -0
  223. package/skills/skills-codex/kill-argument/SKILL.md +403 -0
  224. package/skills/skills-codex/mermaid-diagram/SKILL.md +379 -0
  225. package/skills/skills-codex/meta-apply/SKILL.md +154 -0
  226. package/skills/skills-codex/meta-optimize/SKILL.md +348 -0
  227. package/skills/skills-codex/monitor-experiment/SKILL.md +98 -0
  228. package/skills/skills-codex/novelty-check/SKILL.md +89 -0
  229. package/skills/skills-codex/openalex/SKILL.md +228 -0
  230. package/skills/skills-codex/overleaf-sync/SKILL.md +220 -0
  231. package/skills/skills-codex/paper-claim-audit/SKILL.md +350 -0
  232. package/skills/skills-codex/paper-compile/SKILL.md +253 -0
  233. package/skills/skills-codex/paper-figure/SKILL.md +311 -0
  234. package/skills/skills-codex/paper-illustration/SKILL.md +690 -0
  235. package/skills/skills-codex/paper-illustration-image2/SKILL.md +383 -0
  236. package/skills/skills-codex/paper-illustration-image2/scripts/paper_illustration_image2.py +255 -0
  237. package/skills/skills-codex/paper-plan/SKILL.md +278 -0
  238. package/skills/skills-codex/paper-poster/SKILL.md +19 -0
  239. package/skills/skills-codex/paper-poster-html/SKILL.md +377 -0
  240. package/skills/skills-codex/paper-slides/SKILL.md +571 -0
  241. package/skills/skills-codex/paper-talk/SKILL.md +381 -0
  242. package/skills/skills-codex/paper-write/SKILL.md +411 -0
  243. package/skills/skills-codex/paper-write/templates/IEEEtran.bst +2409 -0
  244. package/skills/skills-codex/paper-write/templates/IEEEtran.cls +6347 -0
  245. package/skills/skills-codex/paper-write/templates/aaai2026.bst +1493 -0
  246. package/skills/skills-codex/paper-write/templates/aaai2026.sty +315 -0
  247. package/skills/skills-codex/paper-write/templates/aaai2026.tex +952 -0
  248. package/skills/skills-codex/paper-write/templates/acl.sty +312 -0
  249. package/skills/skills-codex/paper-write/templates/acl2026.tex +377 -0
  250. package/skills/skills-codex/paper-write/templates/acl_natbib.bst +1940 -0
  251. package/skills/skills-codex/paper-write/templates/acm.bst +3081 -0
  252. package/skills/skills-codex/paper-write/templates/acm_mm2026.tex +204 -0
  253. package/skills/skills-codex/paper-write/templates/acmart.cls +3520 -0
  254. package/skills/skills-codex/paper-write/templates/cvpr.bst +1448 -0
  255. package/skills/skills-codex/paper-write/templates/cvpr.sty +508 -0
  256. package/skills/skills-codex/paper-write/templates/cvpr2026.tex +63 -0
  257. package/skills/skills-codex/paper-write/templates/iclr2026.tex +84 -0
  258. package/skills/skills-codex/paper-write/templates/iclr2026_conference.bst +1440 -0
  259. package/skills/skills-codex/paper-write/templates/iclr2026_conference.sty +246 -0
  260. package/skills/skills-codex/paper-write/templates/icml2026.sty +767 -0
  261. package/skills/skills-codex/paper-write/templates/icml2026.tex +662 -0
  262. package/skills/skills-codex/paper-write/templates/ieee_conference.tex +89 -0
  263. package/skills/skills-codex/paper-write/templates/ieee_journal.tex +93 -0
  264. package/skills/skills-codex/paper-write/templates/math_commands.tex +48 -0
  265. package/skills/skills-codex/paper-write/templates/neurips2026.tex +493 -0
  266. package/skills/skills-codex/paper-write/templates/neurips_2026.sty +437 -0
  267. package/skills/skills-codex/paper-writing/SKILL.md +731 -0
  268. package/skills/skills-codex/patent-novelty-check/SKILL.md +153 -0
  269. package/skills/skills-codex/patent-pipeline/SKILL.md +344 -0
  270. package/skills/skills-codex/patent-review/SKILL.md +202 -0
  271. package/skills/skills-codex/pixel-art/SKILL.md +139 -0
  272. package/skills/skills-codex/prior-art-search/SKILL.md +146 -0
  273. package/skills/skills-codex/proof-checker/SKILL.md +554 -0
  274. package/skills/skills-codex/proof-orchestrator/SKILL.md +260 -0
  275. package/skills/skills-codex/proof-orchestrator/references/audit-output-contract.md +126 -0
  276. package/skills/skills-codex/proof-orchestrator/references/deepseek-routing.md +76 -0
  277. package/skills/skills-codex/proof-orchestrator/references/dispatch-prompts.md +227 -0
  278. package/skills/skills-codex/proof-orchestrator/references/notation-audit.md +135 -0
  279. package/skills/skills-codex/proof-orchestrator/references/proof-audit-rubric.md +70 -0
  280. package/skills/skills-codex/proof-orchestrator/references/stress-tests.md +38 -0
  281. package/skills/skills-codex/proof-writer/SKILL.md +222 -0
  282. package/skills/skills-codex/qzcli/SKILL.md +324 -0
  283. package/skills/skills-codex/rebuttal/SKILL.md +305 -0
  284. package/skills/skills-codex/render-html/SKILL.md +305 -0
  285. package/skills/skills-codex/render-html/scripts/__pycache__/render_html.cpython-314.pyc +0 -0
  286. package/skills/skills-codex/render-html/scripts/render_html.py +909 -0
  287. package/skills/skills-codex/render-html/scripts/templates/academic.html +342 -0
  288. package/skills/skills-codex/render-html/scripts/templates/dashboard.html +333 -0
  289. package/skills/skills-codex/research-lit/SKILL.md +464 -0
  290. package/skills/skills-codex/research-pipeline/SKILL.md +340 -0
  291. package/skills/skills-codex/research-refine/SKILL.md +721 -0
  292. package/skills/skills-codex/research-refine-pipeline/SKILL.md +186 -0
  293. package/skills/skills-codex/research-review/SKILL.md +135 -0
  294. package/skills/skills-codex/research-wiki/SKILL.md +421 -0
  295. package/skills/skills-codex/resubmit-pipeline/SKILL.md +444 -0
  296. package/skills/skills-codex/result-to-claim/SKILL.md +246 -0
  297. package/skills/skills-codex/run-experiment/SKILL.md +236 -0
  298. package/skills/skills-codex/semantic-scholar/SKILL.md +219 -0
  299. package/skills/skills-codex/serverless-modal/SKILL.md +335 -0
  300. package/skills/skills-codex/shared-references/acceptance-gate.md +336 -0
  301. package/skills/skills-codex/shared-references/assurance-contract.md +139 -0
  302. package/skills/skills-codex/shared-references/capture-antipatterns.md +84 -0
  303. package/skills/skills-codex/shared-references/citation-discipline.md +452 -0
  304. package/skills/skills-codex/shared-references/compute-env-contract.md +163 -0
  305. package/skills/skills-codex/shared-references/effort-contract.md +143 -0
  306. package/skills/skills-codex/shared-references/evidence-precheck.md +73 -0
  307. package/skills/skills-codex/shared-references/experiment-integrity.md +49 -0
  308. package/skills/skills-codex/shared-references/external-cadence.md +334 -0
  309. package/skills/skills-codex/shared-references/fan-out-pattern.md +375 -0
  310. package/skills/skills-codex/shared-references/injection-hygiene.md +132 -0
  311. package/skills/skills-codex/shared-references/integration-contract.md +372 -0
  312. package/skills/skills-codex/shared-references/output-composition.md +98 -0
  313. package/skills/skills-codex/shared-references/output-language.md +45 -0
  314. package/skills/skills-codex/shared-references/output-manifest.md +40 -0
  315. package/skills/skills-codex/shared-references/output-versioning.md +111 -0
  316. package/skills/skills-codex/shared-references/patent-format-cn.md +199 -0
  317. package/skills/skills-codex/shared-references/patent-format-ep.md +173 -0
  318. package/skills/skills-codex/shared-references/patent-format-us.md +161 -0
  319. package/skills/skills-codex/shared-references/patent-writing-principles.md +197 -0
  320. package/skills/skills-codex/shared-references/prior-art-databases.md +141 -0
  321. package/skills/skills-codex/shared-references/resumable-runs.md +125 -0
  322. package/skills/skills-codex/shared-references/review-scope-limits.md +81 -0
  323. package/skills/skills-codex/shared-references/review-tracing.md +144 -0
  324. package/skills/skills-codex/shared-references/reviewer-independence.md +66 -0
  325. package/skills/skills-codex/shared-references/reviewer-routing.md +128 -0
  326. package/skills/skills-codex/shared-references/skill-governance.md +119 -0
  327. package/skills/skills-codex/shared-references/taste-calibration.md +90 -0
  328. package/skills/skills-codex/shared-references/venue-checklists.md +73 -0
  329. package/skills/skills-codex/shared-references/wiki-helper-resolution.md +69 -0
  330. package/skills/skills-codex/shared-references/writing-principles.md +525 -0
  331. package/skills/skills-codex/slides-polish/SKILL.md +563 -0
  332. package/skills/skills-codex/specification-writing/SKILL.md +211 -0
  333. package/skills/skills-codex/system-profile/SKILL.md +103 -0
  334. package/skills/skills-codex/training-check/SKILL.md +83 -0
  335. package/skills/skills-codex/vast-gpu/SKILL.md +394 -0
  336. package/skills/skills-codex/web-debug-search/SKILL.md +334 -0
  337. package/skills/skills-codex/wiki-enrich/SKILL.md +255 -0
  338. package/skills/skills-codex/writing-systems-papers/SKILL.md +184 -0
  339. package/skills/skills-codex-claude-review/README.md +79 -0
  340. package/skills/skills-codex-claude-review/README_CN.md +78 -0
  341. package/skills/skills-codex-claude-review/auto-paper-improvement-loop/SKILL.md +581 -0
  342. package/skills/skills-codex-claude-review/auto-review-loop/SKILL.md +510 -0
  343. package/skills/skills-codex-claude-review/novelty-check/SKILL.md +102 -0
  344. package/skills/skills-codex-claude-review/paper-figure/SKILL.md +319 -0
  345. package/skills/skills-codex-claude-review/paper-plan/SKILL.md +287 -0
  346. package/skills/skills-codex-claude-review/paper-write/SKILL.md +420 -0
  347. package/skills/skills-codex-claude-review/research-refine/SKILL.md +732 -0
  348. package/skills/skills-codex-claude-review/research-review/SKILL.md +149 -0
  349. package/skills/skills-codex-gemini-review/README.md +176 -0
  350. package/skills/skills-codex-gemini-review/README_CN.md +175 -0
  351. package/skills/skills-codex-gemini-review/auto-paper-improvement-loop/SKILL.md +331 -0
  352. package/skills/skills-codex-gemini-review/auto-review-loop/SKILL.md +304 -0
  353. package/skills/skills-codex-gemini-review/grant-proposal/SKILL.md +630 -0
  354. package/skills/skills-codex-gemini-review/idea-creator/SKILL.md +263 -0
  355. package/skills/skills-codex-gemini-review/idea-discovery/SKILL.md +275 -0
  356. package/skills/skills-codex-gemini-review/idea-discovery-robot/SKILL.md +365 -0
  357. package/skills/skills-codex-gemini-review/novelty-check/SKILL.md +92 -0
  358. package/skills/skills-codex-gemini-review/paper-figure/SKILL.md +289 -0
  359. package/skills/skills-codex-gemini-review/paper-plan/SKILL.md +265 -0
  360. package/skills/skills-codex-gemini-review/paper-poster-html/SKILL.md +102 -0
  361. package/skills/skills-codex-gemini-review/paper-slides/SKILL.md +582 -0
  362. package/skills/skills-codex-gemini-review/paper-write/SKILL.md +346 -0
  363. package/skills/skills-codex-gemini-review/paper-writing/SKILL.md +312 -0
  364. package/skills/skills-codex-gemini-review/research-refine/SKILL.md +674 -0
  365. package/skills/skills-codex-gemini-review/research-review/SKILL.md +112 -0
  366. package/skills/slides-polish/SKILL.md +565 -0
  367. package/skills/specification-writing/SKILL.md +211 -0
  368. package/skills/system-profile/SKILL.md +103 -0
  369. package/skills/training-check/SKILL.md +132 -0
  370. package/skills/vast-gpu/SKILL.md +394 -0
  371. package/skills/web-debug-search/SKILL.md +334 -0
  372. package/skills/wiki-enrich/SKILL.md +257 -0
  373. package/skills/writing-systems-papers/SKILL.md +184 -0
  374. package/templates/CLAUDE_MD_TEMPLATE.md +29 -0
  375. package/templates/EXPERIMENT_LOG_TEMPLATE.md +47 -0
  376. package/templates/EXPERIMENT_PLAN_TEMPLATE.md +51 -0
  377. package/templates/EXPERIMENT_PLAN_TEMPLATE_CN.md +53 -0
  378. package/templates/FINDINGS_TEMPLATE.md +52 -0
  379. package/templates/IDEA_CANDIDATES_TEMPLATE.md +47 -0
  380. package/templates/IDEA_CANDIDATES_TEMPLATE_CN.md +47 -0
  381. package/templates/INVENTION_BRIEF_TEMPLATE.md +87 -0
  382. package/templates/MANIFEST_TEMPLATE.md +7 -0
  383. package/templates/NARRATIVE_REPORT_TEMPLATE.md +49 -0
  384. package/templates/PAPER_PLAN_TEMPLATE.md +47 -0
  385. package/templates/PATENT_CLAIMS_TEMPLATE.md +78 -0
  386. package/templates/PATENT_SPECIFICATION_TEMPLATE.md +68 -0
  387. package/templates/README.md +57 -0
  388. package/templates/RESEARCH_BRIEF_TEMPLATE.md +35 -0
  389. package/templates/RESEARCH_BRIEF_TEMPLATE_CN.md +41 -0
  390. package/templates/RESEARCH_CONTRACT_TEMPLATE.md +60 -0
  391. package/templates/claude-hooks/corpus_write_guard.json +16 -0
  392. package/templates/claude-hooks/corpus_write_guard.py +85 -0
  393. package/templates/claude-hooks/meta_logging.json +74 -0
  394. package/templates/gitignore-trace.txt +3 -0
  395. package/tools/__pycache__/check_skills_inventory.cpython-314.pyc +0 -0
  396. package/tools/arxiv_fetch.py +311 -0
  397. package/tools/capture_filter.py +126 -0
  398. package/tools/check_skills_inventory.py +273 -0
  399. package/tools/convert_skills_to_llm_chat.py +282 -0
  400. package/tools/copilot_native_evidence.py +818 -0
  401. package/tools/deepxiv_fetch.py +213 -0
  402. package/tools/evidence_check.py +212 -0
  403. package/tools/exa_search.py +425 -0
  404. package/tools/experiment_queue/README.md +118 -0
  405. package/tools/experiment_queue/build_manifest.py +44 -0
  406. package/tools/experiment_queue/queue_manager.py +44 -0
  407. package/tools/extract_paper_style.py +560 -0
  408. package/tools/figure_renderer.py +69 -0
  409. package/tools/forensics_gate.py +669 -0
  410. package/tools/generate_codex_claude_review_overrides.py +299 -0
  411. package/tools/idea_discovery_gate.py +256 -0
  412. package/tools/install_aris.ps1 +1372 -0
  413. package/tools/install_aris.sh +1370 -0
  414. package/tools/install_aris_codex.sh +1023 -0
  415. package/tools/install_aris_copilot.sh +1052 -0
  416. package/tools/iteration_log.py +143 -0
  417. package/tools/lint_skills_helpers.sh +84 -0
  418. package/tools/meta_opt/check_ready.sh +80 -0
  419. package/tools/meta_opt/log_event.sh +91 -0
  420. package/tools/meta_opt/trigger_eval.py +280 -0
  421. package/tools/meta_opt/trigger_evals.sample.json +28 -0
  422. package/tools/openalex_fetch.py +326 -0
  423. package/tools/overleaf_audit.sh +104 -0
  424. package/tools/overleaf_setup.sh +150 -0
  425. package/tools/paper_illustration_image2.py +62 -0
  426. package/tools/provenance.py +294 -0
  427. package/tools/research_wiki.py +1720 -0
  428. package/tools/review_gate.py +502 -0
  429. package/tools/run_state.py +399 -0
  430. package/tools/save_trace.sh +477 -0
  431. package/tools/semantic_scholar_fetch.py +438 -0
  432. package/tools/skill-groups.tsv +116 -0
  433. package/tools/skill_picker.py +238 -0
  434. package/tools/smart_update.ps1 +521 -0
  435. package/tools/smart_update.sh +591 -0
  436. package/tools/smart_update_codex.sh +419 -0
  437. package/tools/smart_update_copilot.sh +605 -0
  438. package/tools/threat_scan.py +222 -0
  439. package/tools/verify_paper_audits.sh +487 -0
  440. package/tools/verify_papers.py +613 -0
  441. package/tools/verify_wiki_coverage.sh +176 -0
  442. package/tools/watchdog.py +485 -0
@@ -0,0 +1,1023 @@
1
+ #!/usr/bin/env bash
2
+ # install_aris_codex.sh -- Project-local ARIS Codex skill installation.
3
+ #
4
+ # This installer manages a flat Codex project layout:
5
+ # <project>/.agents/skills/<skill-name> -> <aris-repo>/skills/<package>/<skill-name>
6
+ #
7
+ # Managed entries are tracked in:
8
+ # <project>/.aris/installed-skills-codex.txt
9
+ #
10
+ # Default package set:
11
+ # - skills/skills-codex
12
+ #
13
+ # Optional overlays:
14
+ # --with-claude-review-overlay
15
+ # --with-gemini-review-overlay
16
+ #
17
+ # Usage:
18
+ # bash tools/install_aris_codex.sh [project_path] [options]
19
+ #
20
+ # Actions (mutually exclusive, default: auto):
21
+ # default install if no manifest, else reconcile
22
+ # --reconcile explicit reconcile; refuse if no manifest
23
+ # --uninstall remove only entries in manifest; delete manifest
24
+ #
25
+ # Selection (catalog: tools/skill-groups.tsv in the aris-repo):
26
+ # --groups A,B install only these skill groups (see --list-groups)
27
+ # --skills X,Y additionally install these skills (clears declined mark)
28
+ # --exclude X,Y never install these skills (recorded as declined)
29
+ # --all install every upstream skill (legacy default)
30
+ # --add-new reconcile: accept all upstream skills not yet installed
31
+ # --skip-new reconcile: skip new upstream skills without prompting
32
+ # --list-groups print the group catalog and exit
33
+ # With no selection flags: fresh install on a TTY opens a full-screen
34
+ # checkbox picker (Space toggles a skill / a whole group, Enter confirms;
35
+ # ARIS_NO_PICKER=1 or missing python3/curses falls back to per-group
36
+ # Y/n/e prompts); fresh install with --quiet/no TTY installs everything (old behavior).
37
+ # Reconcile keeps exactly what the manifest says is installed; NEW upstream
38
+ # skills need per-skill confirmation (declined ones are remembered in
39
+ # .aris/skills-declined-codex.txt and never re-asked).
40
+ #
41
+ # Options:
42
+ # --aris-repo PATH override repo discovery
43
+ # --with-claude-review-overlay install skills-codex-claude-review on top
44
+ # --with-gemini-review-overlay install skills-codex-gemini-review on top
45
+ # --dry-run show plan, no writes
46
+ # --quiet no prompts
47
+ # --no-doc skip AGENTS.md managed block update
48
+ # --replace-link NAME replace a conflicting symlink for NAME
49
+ # --clear-stale-lock clear a stale installer lock
50
+
51
+ set -euo pipefail
52
+
53
+ MANIFEST_VERSION="1"
54
+ MANIFEST_NAME="installed-skills-codex.txt"
55
+ MANIFEST_PREV_NAME="installed-skills-codex.txt.prev"
56
+ DECLINED_NAME="skills-declined-codex.txt"
57
+ CATALOG_REL="tools/skill-groups.tsv"
58
+ GLOBAL_POINTER="$HOME/.aris/repo"
59
+ ARIS_DIR_NAME=".aris"
60
+ LOCK_DIR_NAME=".install-codex.lock.d"
61
+ SKILLS_REL=".agents/skills"
62
+ DOC_FILE_NAME="AGENTS.md"
63
+ BLOCK_BEGIN="<!-- ARIS-CODEX:BEGIN -->"
64
+ BLOCK_END="<!-- ARIS-CODEX:END -->"
65
+ SAFE_NAME_REGEX='^[A-Za-z0-9][A-Za-z0-9._-]*$'
66
+ BASE_PACKAGE="skills-codex"
67
+
68
+ PROJECT_PATH=""
69
+ ARIS_REPO_OVERRIDE=""
70
+ ACTION="auto"
71
+ DRY_RUN=false
72
+ QUIET=false
73
+ NO_DOC=false
74
+ CLEAR_STALE_LOCK=false
75
+ WITH_CLAUDE_OVERLAY=false
76
+ WITH_GEMINI_OVERLAY=false
77
+ REPLACE_LINK_NAMES=()
78
+ SELECT_GROUPS="" # comma list from --groups
79
+ SELECT_SKILLS="" # comma list from --skills
80
+ EXCLUDE_SKILLS="" # comma list from --exclude
81
+ SELECT_ALL=false
82
+ NEW_POLICY="" # "" (prompt) | add | skip
83
+ LIST_GROUPS=false
84
+
85
+ usage() { sed -n '2,49p' "$0" | sed 's/^# \?//'; }
86
+
87
+ while [[ $# -gt 0 ]]; do
88
+ case "$1" in
89
+ --reconcile) ACTION="reconcile"; shift ;;
90
+ --uninstall) ACTION="uninstall"; shift ;;
91
+ --aris-repo) ARIS_REPO_OVERRIDE="${2:?--aris-repo requires path}"; shift 2 ;;
92
+ --with-claude-review-overlay) WITH_CLAUDE_OVERLAY=true; shift ;;
93
+ --with-gemini-review-overlay) WITH_GEMINI_OVERLAY=true; shift ;;
94
+ --dry-run) DRY_RUN=true; shift ;;
95
+ --quiet) QUIET=true; shift ;;
96
+ --no-doc) NO_DOC=true; shift ;;
97
+ --replace-link) REPLACE_LINK_NAMES+=("${2:?--replace-link requires NAME}"); shift 2 ;;
98
+ --clear-stale-lock) CLEAR_STALE_LOCK=true; shift ;;
99
+ --groups) SELECT_GROUPS="${SELECT_GROUPS:+$SELECT_GROUPS,}${2:?--groups requires A,B,...}"; shift 2 ;;
100
+ --skills) SELECT_SKILLS="${SELECT_SKILLS:+$SELECT_SKILLS,}${2:?--skills requires X,Y,...}"; shift 2 ;;
101
+ --exclude) EXCLUDE_SKILLS="${EXCLUDE_SKILLS:+$EXCLUDE_SKILLS,}${2:?--exclude requires X,Y,...}"; shift 2 ;;
102
+ --all) SELECT_ALL=true; shift ;;
103
+ --add-new) NEW_POLICY="add"; shift ;;
104
+ --skip-new) NEW_POLICY="skip"; shift ;;
105
+ --list-groups) LIST_GROUPS=true; shift ;;
106
+ -h|--help) usage; exit 0 ;;
107
+ --*) echo "Unknown option: $1" >&2; exit 2 ;;
108
+ *)
109
+ if [[ -z "$PROJECT_PATH" ]]; then
110
+ PROJECT_PATH="$1"
111
+ else
112
+ echo "Error: unexpected positional argument: $1" >&2
113
+ exit 2
114
+ fi
115
+ shift
116
+ ;;
117
+ esac
118
+ done
119
+
120
+ if $SELECT_ALL && [[ -n "$SELECT_GROUPS$SELECT_SKILLS" ]]; then
121
+ echo "Error: --all cannot be combined with --groups/--skills (only --exclude)" >&2; exit 2
122
+ fi
123
+
124
+ log() { $QUIET && return 0; echo "$@"; }
125
+ warn() { echo "warning: $*" >&2; }
126
+ die() { echo "error: $*" >&2; exit 1; }
127
+ prompt() { $QUIET && return 0; printf "%s " "$1" >&2; read -r REPLY; [[ "$REPLY" =~ ^[Yy]$ ]]; }
128
+ abs_path() { ( cd "$1" 2>/dev/null && pwd ) || return 1; }
129
+ is_safe_name() { [[ "$1" =~ $SAFE_NAME_REGEX ]]; }
130
+ is_symlink() { [[ -L "$1" ]]; }
131
+ name_in_replace_allowlist() {
132
+ local needle="$1"
133
+ local item
134
+ # bash 3.2: empty-array "${ARR[@]}" trips `set -u`; no --replace-link = empty allowlist
135
+ [[ ${#REPLACE_LINK_NAMES[@]} -gt 0 ]] || return 1
136
+ for item in "${REPLACE_LINK_NAMES[@]}"; do
137
+ [[ "$item" == "$needle" ]] && return 0
138
+ done
139
+ return 1
140
+ }
141
+
142
+ read_link_target() {
143
+ if command -v greadlink >/dev/null 2>&1; then greadlink "$1"
144
+ else readlink "$1"; fi
145
+ }
146
+
147
+ canonicalize() {
148
+ if command -v greadlink >/dev/null 2>&1; then greadlink -f "$1" 2>/dev/null || true
149
+ elif readlink -f "$1" 2>/dev/null; then :
150
+ else
151
+ local d f
152
+ if [[ -d "$1" ]]; then
153
+ ( cd "$1" && pwd )
154
+ else
155
+ d="$(dirname "$1")"
156
+ f="$(basename "$1")"
157
+ ( cd "$d" 2>/dev/null && echo "$(pwd)/$f" )
158
+ fi
159
+ fi
160
+ }
161
+
162
+ resolve_aris_repo() {
163
+ local p
164
+ if [[ -n "$ARIS_REPO_OVERRIDE" ]]; then
165
+ p="$(abs_path "$ARIS_REPO_OVERRIDE")" || die "--aris-repo path not found: $ARIS_REPO_OVERRIDE"
166
+ else
167
+ local script_dir parent guess
168
+ script_dir="$(cd "$(dirname "$0")" && pwd)"
169
+ parent="$(cd "$script_dir/.." && pwd)"
170
+ if [[ -d "$parent/skills/$BASE_PACKAGE" ]]; then
171
+ p="$parent"
172
+ elif [[ -n "${ARIS_REPO:-}" && -d "$ARIS_REPO/skills/$BASE_PACKAGE" ]]; then
173
+ p="$(abs_path "$ARIS_REPO")"
174
+ else
175
+ for guess in \
176
+ "$HOME/Desktop/Auto-claude-code-research-in-sleep" \
177
+ "$HOME/Auto-claude-code-research-in-sleep" \
178
+ "$HOME/aris_repo" \
179
+ "$HOME/.codex/Auto-claude-code-research-in-sleep"; do
180
+ if [[ -d "$guess/skills/$BASE_PACKAGE" ]]; then
181
+ p="$(abs_path "$guess")"
182
+ break
183
+ fi
184
+ done
185
+ fi
186
+ fi
187
+ [[ -n "${p:-}" ]] || die "cannot find ARIS repo with skills/$BASE_PACKAGE. Use --aris-repo PATH."
188
+ [[ -d "$p/skills/$BASE_PACKAGE" ]] || die "repo missing skills/$BASE_PACKAGE: $p"
189
+ echo "$p"
190
+ }
191
+
192
+ selected_packages() {
193
+ local packages=("$BASE_PACKAGE")
194
+ $WITH_CLAUDE_OVERLAY && packages+=("skills-codex-claude-review")
195
+ $WITH_GEMINI_OVERLAY && packages+=("skills-codex-gemini-review")
196
+ printf "%s\n" "${packages[@]}"
197
+ }
198
+
199
+ build_upstream_inventory() {
200
+ local repo="$1" out="$2"
201
+ local package package_dir d name kind source_rel tmp
202
+ tmp="$(mktemp -t aris-codex-upstream-raw.XXXX)"
203
+ : > "$out"
204
+ : > "$tmp"
205
+
206
+ while IFS= read -r package; do
207
+ [[ -z "$package" ]] && continue
208
+ package_dir="$repo/skills/$package"
209
+ [[ -d "$package_dir" ]] || die "selected package missing: $package_dir"
210
+ for d in "$package_dir"/*; do
211
+ [[ -d "$d" ]] || continue
212
+ name="$(basename "$d")"
213
+ is_safe_name "$name" || { warn "skipping unsafe upstream name: $name"; continue; }
214
+ if [[ "$name" == "shared-references" ]]; then
215
+ kind="support"
216
+ elif [[ -f "$d/SKILL.md" ]]; then
217
+ kind="skill"
218
+ else
219
+ continue
220
+ fi
221
+ source_rel="skills/$package/$name"
222
+ printf "%s|%s|%s\n" "$kind" "$name" "$source_rel" >> "$tmp"
223
+ done
224
+ done < <(selected_packages)
225
+
226
+ if [[ ! -s "$tmp" ]]; then
227
+ rm -f "$tmp"
228
+ die "upstream inventory empty"
229
+ fi
230
+
231
+ # Keep the last entry for duplicate names so overlays override the base
232
+ # package, then sort by skill/support name for deterministic plans.
233
+ awk -F'|' '{row[$2]=$0} END {for (name in row) print row[name]}' "$tmp" | sort -t'|' -k2,2 > "$out"
234
+ rm -f "$tmp"
235
+ }
236
+
237
+ # --- Selective install (#366, ported from install_aris.sh) ---
238
+ # Upstream rows here are 3-field (kind|name|source_rel) because a name may be
239
+ # sourced from the base package or an overlay; catalog skill names match the
240
+ # mainline skill names 1:1 (mirror directories share names with skills/<name>).
241
+
242
+ catalog_ok() { [[ -n "${CATALOG_PATH:-}" && -f "$CATALOG_PATH" ]]; }
243
+ catalog_groups() { awk -F'\t' '$1=="group"{print $2 "\t" $3 "\t" $4}' "$CATALOG_PATH"; }
244
+ catalog_group_of() { awk -F'\t' -v s="$1" '$1=="skill" && $2==s {print $3; exit}' "$CATALOG_PATH"; }
245
+ catalog_desc_of() { awk -F'\t' -v s="$1" '$1=="skill" && $2==s {print (NF>=5?$5:""); exit}' "$CATALOG_PATH"; }
246
+ catalog_requires() { awk -F'\t' -v s="$1" '$1=="skill" && $2==s && $4!="-" {print $4; exit}' "$CATALOG_PATH" | tr ',' '\n'; }
247
+ catalog_skills_in_group() { awk -F'\t' -v g="$1" '$1=="skill" && $3==g {print $2}' "$CATALOG_PATH"; }
248
+ catalog_has_skill() { awk -F'\t' -v s="$1" '$1=="skill" && $2==s {found=1; exit} END{exit !found}' "$CATALOG_PATH"; }
249
+
250
+ in_file() { grep -qxF "$1" "$2" 2>/dev/null; }
251
+ upstream_has_skill() { grep -q "^skill|$1|" "$2"; }
252
+
253
+ print_group_catalog() {
254
+ catalog_ok || die "skill catalog not found: ${CATALOG_PATH:-<unset>}"
255
+ echo "Skill groups (from $CATALOG_PATH):"
256
+ local gid display desc n
257
+ while IFS=$'\t' read -r gid display desc; do
258
+ n=$(catalog_skills_in_group "$gid" | wc -l | tr -d ' ')
259
+ printf "\n %-14s %s — %s [%s skills]\n" "$gid" "$display" "$desc" "$n"
260
+ catalog_skills_in_group "$gid" | sed 's/^/ /'
261
+ done < <(catalog_groups)
262
+ }
263
+
264
+ load_declined() { # $1 = out file
265
+ : > "$1"
266
+ [[ -f "$DECLINED_PATH" ]] || return 0
267
+ grep -v '^[[:space:]]*$' "$DECLINED_PATH" >> "$1" || true
268
+ }
269
+
270
+ save_declined() { # $1 = candidates file, $2 = selected file
271
+ $DRY_RUN && return 0
272
+ mkdir -p "$PROJECT_ARIS_DIR"
273
+ local tmp="$DECLINED_PATH.tmp.$$"
274
+ sort -u "$1" | grep -v '^$' | grep -vxF -f "$2" > "$tmp" || true
275
+ if [[ -s "$tmp" || -f "$DECLINED_PATH" ]]; then
276
+ mv -f "$tmp" "$DECLINED_PATH"
277
+ else
278
+ rm -f "$tmp"
279
+ fi
280
+ }
281
+
282
+ # Auto-include hard pipeline deps (catalog `requires` column, transitively).
283
+ expand_deps() { # $1 = selected file, $2 = excludes file, $3 = upstream file
284
+ catalog_ok || return 0
285
+ local changed=1 name dep
286
+ while (( changed )); do
287
+ changed=0
288
+ for name in $(cat "$1"); do
289
+ for dep in $(catalog_requires "$name"); do
290
+ in_file "$dep" "$1" && continue
291
+ if in_file "$dep" "$2"; then
292
+ warn "'$name' requires '$dep' but it is excluded — that pipeline phase will break"
293
+ continue
294
+ fi
295
+ upstream_has_skill "$dep" "$3" || continue
296
+ echo "$dep" >> "$1"
297
+ log " ↳ auto-including '$dep' (required by '$name')"
298
+ changed=1
299
+ done
300
+ done
301
+ done
302
+ }
303
+
304
+ # Interactive selection (fresh install on a TTY, no selection flags).
305
+ # Preferred UI: full-screen checkbox picker (tools/skill_picker.py, curses) —
306
+ # Space toggles a skill / a whole group, Enter confirms, q aborts. Falls back
307
+ # to the classic per-group Y/n/e prompts when python3/curses/tty are
308
+ # unavailable or ARIS_NO_PICKER=1 is set.
309
+ interactive_select() { # $1 = upstream file, $2 = out (selected) file
310
+ if [[ "${ARIS_NO_PICKER:-0}" != "1" ]] && command -v python3 >/dev/null 2>&1 \
311
+ && [[ -f "$ARIS_REPO/tools/skill_picker.py" ]]; then
312
+ local avail_f rc=0
313
+ avail_f="$(mktemp -t aris-avail.XXXX)"
314
+ grep '^skill|' "$1" | cut -d'|' -f2 > "$avail_f" || true
315
+ python3 "$ARIS_REPO/tools/skill_picker.py" \
316
+ --catalog "$CATALOG_PATH" --available "$avail_f" --out "$2" \
317
+ </dev/tty >/dev/tty || rc=$?
318
+ rm -f "$avail_f"
319
+ if [[ $rc -eq 0 ]]; then return 0
320
+ elif [[ $rc -eq 1 ]]; then die "interactive selection aborted"
321
+ fi
322
+ # rc=2 (or unexpected): picker unusable — fall through to prompts.
323
+ warn "checkbox picker unavailable — using per-group prompts"
324
+ fi
325
+ log ""
326
+ log "Interactive skill selection — per group: Y=install all, n=skip, e=pick per skill."
327
+ local gid display desc n reply r2 name glist
328
+ glist="$(mktemp -t aris-codex-glist.XXXX)"
329
+ while IFS=$'\t' read -r gid display desc; do
330
+ catalog_skills_in_group "$gid" | while read -r name; do
331
+ upstream_has_skill "$name" "$1" && echo "$name"
332
+ done > "$glist" || true
333
+ n=$(wc -l < "$glist" | tr -d ' ')
334
+ (( n == 0 )) && continue
335
+ printf "\n%s (%s) — %s\n" "$display" "$gid" "$desc" >&2
336
+ sed 's/^/ /' "$glist" >&2
337
+ printf "Install group '%s' (%s skills)? [Y/n/e] " "$gid" "$n" >&2
338
+ read -r reply </dev/tty
339
+ case "$reply" in
340
+ [nN]*) : ;;
341
+ [eE]*)
342
+ while read -r name; do
343
+ printf " install %-30s [Y/n] " "$name" >&2
344
+ read -r r2 </dev/tty
345
+ [[ "$r2" =~ ^[nN] ]] || echo "$name" >> "$2"
346
+ done < "$glist"
347
+ ;;
348
+ *) cat "$glist" >> "$2" ;;
349
+ esac
350
+ done < <(catalog_groups)
351
+ # Upstream skills the catalog doesn't know yet (catalog drift): never drop silently.
352
+ local ungrouped; ungrouped="$(mktemp -t aris-codex-ungrouped.XXXX)"
353
+ grep '^skill|' "$1" | cut -d'|' -f2 | while read -r name; do
354
+ catalog_has_skill "$name" || echo "$name"
355
+ done > "$ungrouped" || true
356
+ if [[ -s "$ungrouped" ]]; then
357
+ printf "\nSkills not in the catalog yet:\n" >&2
358
+ sed 's/^/ /' "$ungrouped" >&2
359
+ while read -r name; do
360
+ printf " install %-30s [Y/n] " "$name" >&2
361
+ read -r r2 </dev/tty
362
+ [[ "$r2" =~ ^[nN] ]] || echo "$name" >> "$2"
363
+ done < "$ungrouped"
364
+ fi
365
+ rm -f "$glist" "$ungrouped"
366
+ }
367
+
368
+ # Validate --groups/--skills names against catalog + upstream.
369
+ validate_selection_flags() { # $1 = upstream file
370
+ local g s
371
+ if [[ -n "$SELECT_GROUPS" ]]; then
372
+ catalog_ok || die "--groups needs the catalog at $CATALOG_PATH (update your aris-repo clone)"
373
+ for g in $(echo "$SELECT_GROUPS" | tr ',' ' '); do
374
+ catalog_groups | cut -f1 | grep -qxF "$g" \
375
+ || die "unknown group '$g' — run with --list-groups to see valid ids"
376
+ done
377
+ fi
378
+ for s in $(echo "$SELECT_SKILLS" | tr ',' ' '); do
379
+ upstream_has_skill "$s" "$1" || die "unknown skill '$s' (not an upstream skill)"
380
+ done
381
+ }
382
+
383
+ # Build the selected-skill set (one name per line in $3).
384
+ build_selection() { # $1 = upstream file, $2 = declined-candidates out file, $3 = selected out file
385
+ local upstream="$1" declined_out="$2" out="$3"
386
+ : > "$out"
387
+ load_declined "$declined_out"
388
+
389
+ local excl; excl="$(mktemp -t aris-codex-excl.XXXX)"
390
+ echo "$EXCLUDE_SKILLS" | tr ',' '\n' | grep -v '^$' > "$excl" || true
391
+ cat "$excl" >> "$declined_out"
392
+
393
+ validate_selection_flags "$upstream"
394
+
395
+ local has_selection_flags=false
396
+ [[ -n "$SELECT_GROUPS$SELECT_SKILLS" ]] && has_selection_flags=true
397
+ local fresh=true
398
+ [[ -f "$MANIFEST_PATH" ]] && fresh=false
399
+
400
+ local name g subset_choice=false
401
+ if $fresh; then
402
+ if $SELECT_ALL || { ! $has_selection_flags && { $QUIET || [[ ! -t 0 ]]; }; }; then
403
+ grep '^skill|' "$upstream" | cut -d'|' -f2 > "$out"
404
+ elif $has_selection_flags; then
405
+ subset_choice=true
406
+ for g in $(echo "$SELECT_GROUPS" | tr ',' ' '); do
407
+ catalog_skills_in_group "$g" | while read -r name; do
408
+ upstream_has_skill "$name" "$upstream" && echo "$name"
409
+ done >> "$out" || true
410
+ done
411
+ echo "$SELECT_SKILLS" | tr ',' '\n' | grep -v '^$' >> "$out" || true
412
+ elif catalog_ok; then
413
+ subset_choice=true
414
+ interactive_select "$upstream" "$out"
415
+ else
416
+ warn "catalog missing at $CATALOG_PATH — falling back to full install"
417
+ grep '^skill|' "$upstream" | cut -d'|' -f2 > "$out"
418
+ fi
419
+ # Explicit subset choice ⇒ remember the rest as declined (won't re-ask).
420
+ if $subset_choice; then
421
+ grep '^skill|' "$upstream" | cut -d'|' -f2 | grep -vxF -f "$out" >> "$declined_out" 2>/dev/null || true
422
+ fi
423
+ else
424
+ # Reconcile: installed set = manifest ∩ upstream (auto-detected).
425
+ manifest_names "$MANIFEST_DATA" | while read -r name; do
426
+ [[ "$(manifest_kind_of "$MANIFEST_DATA" "$name")" == "skill" ]] || continue
427
+ upstream_has_skill "$name" "$upstream" && echo "$name"
428
+ done >> "$out" || true
429
+ # Flag-based additions re-enable previously declined skills.
430
+ for g in $(echo "$SELECT_GROUPS" | tr ',' ' '); do
431
+ catalog_skills_in_group "$g" | while read -r name; do
432
+ upstream_has_skill "$name" "$upstream" && echo "$name"
433
+ done >> "$out" || true
434
+ done
435
+ echo "$SELECT_SKILLS" | tr ',' '\n' | grep -v '^$' >> "$out" || true
436
+ # NEW upstream skills: not installed, not declined, not just selected.
437
+ local new_file; new_file="$(mktemp -t aris-codex-new.XXXX)"
438
+ grep '^skill|' "$upstream" | cut -d'|' -f2 | while read -r name; do
439
+ in_file "$name" "$out" && continue
440
+ in_file "$name" "$declined_out" && continue
441
+ echo "$name"
442
+ done > "$new_file" || true
443
+ if [[ -s "$new_file" ]]; then
444
+ if $SELECT_ALL || [[ "$NEW_POLICY" == "add" ]]; then
445
+ cat "$new_file" >> "$out"
446
+ log "→ adding $(wc -l < "$new_file" | tr -d ' ') new upstream skill(s) (--all/--add-new)"
447
+ elif [[ "$NEW_POLICY" == "skip" ]] || $QUIET || [[ ! -t 0 ]]; then
448
+ log ""
449
+ log "New upstream skills NOT installed (rerun without --skip-new/--quiet to be asked,"
450
+ log "or pass --add-new / --skills NAME):"
451
+ sed 's/^/ /' "$new_file" | while read -r l; do log "$l"; done
452
+ else
453
+ log ""
454
+ log "New skills appeared upstream since your last install:"
455
+ local reply grp sdesc
456
+ while read -r name; do
457
+ grp="$(catalog_group_of "$name")"
458
+ sdesc="$(catalog_desc_of "$name")"
459
+ printf " install new skill %-30s (group: %s)%s [y/N] " "$name" "${grp:-?}" "${sdesc:+ — $sdesc}" >&2
460
+ read -r reply </dev/tty
461
+ if [[ "$reply" =~ ^[yY] ]]; then echo "$name" >> "$out"
462
+ else echo "$name" >> "$declined_out"
463
+ fi
464
+ done < "$new_file"
465
+ fi
466
+ fi
467
+ rm -f "$new_file"
468
+ fi
469
+
470
+ # Excludes beat every other source (manifest, groups, deps, new skills).
471
+ local pruned
472
+ if [[ -s "$excl" ]]; then
473
+ pruned="$(mktemp -t aris-codex-pruned.XXXX)"
474
+ grep -vxF -f "$excl" "$out" > "$pruned" || true
475
+ mv -f "$pruned" "$out"
476
+ fi
477
+ expand_deps "$out" "$excl" "$upstream"
478
+ sort -u -o "$out" "$out"
479
+ rm -f "$excl"
480
+ [[ -s "$out" ]] || die "selection is empty — nothing to install (use --all or --groups/--skills)"
481
+ }
482
+
483
+ # Keep support entries + selected skills only (upstream rows stay 3-field).
484
+ filter_upstream_by_selection() { # $1 = upstream file, $2 = selected file, $3 = out
485
+ awk -F'|' -v sel="$2" '
486
+ BEGIN { while ((getline line < sel) > 0) picked[line]=1 }
487
+ $1=="support" { print; next }
488
+ $1=="skill" && picked[$2] { print }
489
+ ' "$1" > "$3"
490
+ }
491
+
492
+ # Layer-4 helper resolution (#366): a global pointer file lets globally/copy-
493
+ # installed skills find $ARIS_REPO/tools without a per-project install.
494
+ ensure_global_pointer() {
495
+ $DRY_RUN && return 0
496
+ mkdir -p "$(dirname "$GLOBAL_POINTER")" 2>/dev/null || { warn "cannot create $(dirname "$GLOBAL_POINTER") — skipping global pointer"; return 0; }
497
+ local cur=""
498
+ [[ -f "$GLOBAL_POINTER" ]] && cur="$(cat "$GLOBAL_POINTER" 2>/dev/null || true)"
499
+ [[ "$cur" == "$ARIS_REPO" ]] && return 0
500
+ printf '%s\n' "$ARIS_REPO" > "$GLOBAL_POINTER.tmp.$$" && mv -f "$GLOBAL_POINTER.tmp.$$" "$GLOBAL_POINTER"
501
+ log " + global pointer $GLOBAL_POINTER -> $ARIS_REPO"
502
+ }
503
+
504
+ load_manifest() {
505
+ local path="$1" out="$2"
506
+ : > "$out"
507
+ [[ -f "$path" ]] || return 0
508
+ local ver
509
+ ver="$(awk -F'\t' '$1=="version"{print $2}' "$path" | head -1)"
510
+ [[ "$ver" == "$MANIFEST_VERSION" ]] || die "manifest version mismatch (got: ${ver:-none}, expected: $MANIFEST_VERSION)"
511
+ awk -F'\t' '
512
+ BEGIN { in_body=0 }
513
+ /^kind\tname\tsource_rel\ttarget_rel\tmode$/ { in_body=1; next }
514
+ in_body && NF==5 { print }
515
+ ' "$path" > "$out"
516
+ }
517
+
518
+ manifest_lookup_target() { awk -F'\t' -v n="$2" '$2==n {print $4; exit}' "$1"; }
519
+ manifest_lookup_source() { awk -F'\t' -v n="$2" '$2==n {print $3; exit}' "$1"; }
520
+ manifest_repo_root() { awk -F'\t' '$1=="repo_root" {print $2; exit}' "$1"; }
521
+ manifest_names() { awk -F'\t' '{print $2}' "$1"; }
522
+ manifest_kind_of() { awk -F'\t' -v n="$2" '$2==n {print $1; exit}' "$1"; }
523
+
524
+ PROJECT_PATH="${PROJECT_PATH:-$(pwd)}"
525
+ [[ -d "$PROJECT_PATH" ]] || die "project path does not exist: $PROJECT_PATH"
526
+ PROJECT_PATH="$(abs_path "$PROJECT_PATH")"
527
+ ARIS_REPO="$(resolve_aris_repo)"
528
+ PROJECT_SKILLS_DIR="$PROJECT_PATH/$SKILLS_REL"
529
+ PROJECT_ARIS_DIR="$PROJECT_PATH/$ARIS_DIR_NAME"
530
+ MANIFEST_PATH="$PROJECT_ARIS_DIR/$MANIFEST_NAME"
531
+ MANIFEST_PREV="$PROJECT_ARIS_DIR/$MANIFEST_PREV_NAME"
532
+ LOCK_DIR="$PROJECT_ARIS_DIR/$LOCK_DIR_NAME"
533
+ DOC_FILE="$PROJECT_PATH/$DOC_FILE_NAME"
534
+ LEGACY_NESTED="$PROJECT_PATH/.agents/skills/aris"
535
+ CATALOG_PATH="$ARIS_REPO/$CATALOG_REL"
536
+ DECLINED_PATH="$PROJECT_ARIS_DIR/$DECLINED_NAME"
537
+
538
+ if $LIST_GROUPS; then
539
+ print_group_catalog
540
+ exit 0
541
+ fi
542
+
543
+ check_no_symlinked_parents() {
544
+ local p
545
+ for p in "$PROJECT_ARIS_DIR" "$PROJECT_PATH/.agents" "$PROJECT_SKILLS_DIR"; do
546
+ if is_symlink "$p"; then
547
+ die "$p is a symlink; refusing to mutate symlinked parent directories"
548
+ fi
549
+ done
550
+ }
551
+
552
+ check_legacy_nested_install() {
553
+ if [[ -e "$LEGACY_NESTED" || -L "$LEGACY_NESTED" ]]; then
554
+ die "legacy nested Codex install detected at $LEGACY_NESTED. Remove or migrate it before using the flat .agents/skills/<name> layout."
555
+ fi
556
+ }
557
+
558
+ write_lock_metadata() {
559
+ cat > "$LOCK_DIR/owner.json" <<EOF
560
+ {"host":"$(hostname)","pid":$$,"started_at":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","tool":"install_aris_codex.sh"}
561
+ EOF
562
+ echo "$$" > "$LOCK_DIR/owner.pid"
563
+ echo "$(hostname)" > "$LOCK_DIR/owner.host"
564
+ }
565
+
566
+ release_lock() {
567
+ [[ -d "$LOCK_DIR" ]] || return 0
568
+ if [[ -f "$LOCK_DIR/owner.pid" && -f "$LOCK_DIR/owner.host" ]]; then
569
+ local pid host
570
+ pid="$(cat "$LOCK_DIR/owner.pid" 2>/dev/null || echo "")"
571
+ host="$(cat "$LOCK_DIR/owner.host" 2>/dev/null || echo "")"
572
+ if [[ "$pid" == "$$" && "$host" == "$(hostname)" ]]; then
573
+ rm -rf "$LOCK_DIR"
574
+ fi
575
+ fi
576
+ }
577
+
578
+ acquire_lock() {
579
+ mkdir -p "$PROJECT_ARIS_DIR"
580
+ if mkdir "$LOCK_DIR" 2>/dev/null; then
581
+ write_lock_metadata
582
+ trap release_lock EXIT INT TERM
583
+ return 0
584
+ fi
585
+ if $CLEAR_STALE_LOCK; then
586
+ warn "removing stale lock: $LOCK_DIR"
587
+ rm -rf "$LOCK_DIR"
588
+ mkdir "$LOCK_DIR" || die "cannot acquire lock after stale clear"
589
+ write_lock_metadata
590
+ trap release_lock EXIT INT TERM
591
+ return 0
592
+ fi
593
+ local owner=""
594
+ [[ -f "$LOCK_DIR/owner.json" ]] && owner="$(cat "$LOCK_DIR/owner.json")"
595
+ die "another install_aris_codex.sh appears to be running (lock: $LOCK_DIR, owner: $owner)"
596
+ }
597
+
598
+ compute_plan() {
599
+ local upstream_file="$1" manifest_data="$2" out="$3"
600
+ local kind name source_rel target_path expected_target current_target in_manifest
601
+ : > "$out"
602
+
603
+ while IFS='|' read -r kind name source_rel; do
604
+ [[ -z "$name" ]] && continue
605
+ target_path="$PROJECT_SKILLS_DIR/$name"
606
+ expected_target="$ARIS_REPO/$source_rel"
607
+ in_manifest=false
608
+ [[ -n "$(manifest_lookup_target "$manifest_data" "$name")" ]] && in_manifest=true
609
+
610
+ if [[ -L "$target_path" ]]; then
611
+ current_target="$(read_link_target "$target_path")"
612
+ [[ "$current_target" != /* ]] && current_target="$(canonicalize "$(dirname "$target_path")/$current_target")"
613
+ if [[ "$current_target" == "$expected_target" ]]; then
614
+ if $in_manifest; then
615
+ printf "REUSE|%s|%s|%s|\n" "$kind" "$name" "$source_rel" >> "$out"
616
+ else
617
+ printf "ADOPT|%s|%s|%s|\n" "$kind" "$name" "$source_rel" >> "$out"
618
+ fi
619
+ elif $in_manifest || name_in_replace_allowlist "$name"; then
620
+ printf "UPDATE_TARGET|%s|%s|%s|%s\n" "$kind" "$name" "$source_rel" "$current_target" >> "$out"
621
+ else
622
+ printf "CONFLICT|%s|%s|%s|symlink_to:%s\n" "$kind" "$name" "$source_rel" "$current_target" >> "$out"
623
+ fi
624
+ elif [[ -e "$target_path" ]]; then
625
+ printf "CONFLICT|%s|%s|%s|real_path\n" "$kind" "$name" "$source_rel" >> "$out"
626
+ else
627
+ printf "CREATE|%s|%s|%s|\n" "$kind" "$name" "$source_rel" >> "$out"
628
+ fi
629
+ done < "$upstream_file"
630
+
631
+ local recorded_repo_root
632
+ recorded_repo_root="$(manifest_repo_root "$MANIFEST_PATH" 2>/dev/null || true)"
633
+ local mkind mname msource mtarget mmode
634
+ while IFS=$'\t' read -r mkind mname msource mtarget mmode; do
635
+ [[ -z "$mname" ]] && continue
636
+ if awk -F'|' -v n="$mname" '$2==n {found=1} END{exit found?0:1}' "$upstream_file"; then
637
+ continue
638
+ fi
639
+ [[ -n "$recorded_repo_root" ]] || die "manifest missing repo_root: $MANIFEST_PATH"
640
+ printf "REMOVE|%s|%s|%s|%s/%s\n" "$mkind" "$mname" "$msource" "$recorded_repo_root" "$msource" >> "$out"
641
+ done < "$manifest_data"
642
+ }
643
+
644
+ print_plan() {
645
+ local plan="$1"
646
+ local action
647
+ log ""
648
+ log "Plan summary:"
649
+ for action in CREATE ADOPT UPDATE_TARGET REUSE REMOVE CONFLICT; do
650
+ log " $action: $(grep -c "^$action|" "$plan" || true)"
651
+ done
652
+ if grep -q '^CONFLICT|' "$plan"; then
653
+ log ""
654
+ log "Conflicts:"
655
+ while IFS='|' read -r _ kind name _source extra; do
656
+ log " - $name ($kind): $extra"
657
+ done < <(grep '^CONFLICT|' "$plan")
658
+ fi
659
+ }
660
+
661
+ write_manifest_tmp() {
662
+ local plan="$1" out="$2"
663
+ {
664
+ printf "version\t%s\n" "$MANIFEST_VERSION"
665
+ printf "repo_root\t%s\n" "$ARIS_REPO"
666
+ printf "project_root\t%s\n" "$PROJECT_PATH"
667
+ printf "generated\t%s\n" "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
668
+ printf "packages\t%s\n" "$(selected_packages | paste -sd, -)"
669
+ printf "kind\tname\tsource_rel\ttarget_rel\tmode\n"
670
+ awk -F'|' '$1=="REUSE"||$1=="ADOPT"||$1=="CREATE"||$1=="UPDATE_TARGET"{print}' "$plan" \
671
+ | while IFS='|' read -r _ kind name source_rel _extra; do
672
+ printf "%s\t%s\t%s\t%s/%s\tsymlink\n" "$kind" "$name" "$source_rel" "$SKILLS_REL" "$name"
673
+ done
674
+ } > "$out"
675
+ }
676
+
677
+ apply_plan() {
678
+ local plan="$1"
679
+ local action kind name source_rel extra target_path expected_target current_target
680
+ mkdir -p "$PROJECT_SKILLS_DIR"
681
+ while IFS='|' read -r action kind name source_rel extra; do
682
+ [[ -z "$name" ]] && continue
683
+ target_path="$PROJECT_SKILLS_DIR/$name"
684
+ expected_target="$ARIS_REPO/$source_rel"
685
+ case "$action" in
686
+ REUSE|ADOPT)
687
+ :
688
+ ;;
689
+ CREATE)
690
+ if [[ -e "$target_path" || -L "$target_path" ]]; then
691
+ die "path appeared during install: $target_path"
692
+ fi
693
+ if $DRY_RUN; then
694
+ log " (dry-run) ln -s $expected_target $target_path"
695
+ else
696
+ ln -s "$expected_target" "$target_path"
697
+ log " + $name"
698
+ fi
699
+ ;;
700
+ UPDATE_TARGET)
701
+ if [[ -L "$target_path" ]]; then
702
+ current_target="$(read_link_target "$target_path")"
703
+ [[ "$current_target" != /* ]] && current_target="$(canonicalize "$(dirname "$target_path")/$current_target")"
704
+ else
705
+ current_target=""
706
+ fi
707
+ if [[ "$current_target" != "$extra" ]]; then
708
+ die "symlink target changed during install for $name (expected: $extra, got: ${current_target:-missing})"
709
+ fi
710
+ if $DRY_RUN; then
711
+ log " (dry-run) relink $target_path -> $expected_target"
712
+ else
713
+ rm -f "$target_path"
714
+ ln -s "$expected_target" "$target_path"
715
+ log " ↻ $name"
716
+ fi
717
+ ;;
718
+ REMOVE)
719
+ [[ -n "$extra" ]] || die "remove action missing recorded target for $name"
720
+ if [[ -L "$target_path" ]]; then
721
+ current_target="$(read_link_target "$target_path")"
722
+ [[ "$current_target" != /* ]] && current_target="$(canonicalize "$(dirname "$target_path")/$current_target")"
723
+ if [[ "$current_target" == "$extra" ]]; then
724
+ if $DRY_RUN; then
725
+ log " (dry-run) rm $target_path"
726
+ else
727
+ rm -f "$target_path"
728
+ log " - $name"
729
+ fi
730
+ else
731
+ die "refusing to remove $name; target changed during reconcile (expected: $extra, got: $current_target)"
732
+ fi
733
+ elif [[ -e "$target_path" ]]; then
734
+ die "refusing to remove $name; target path is no longer a symlink"
735
+ else
736
+ log " - $name (already removed)"
737
+ fi
738
+ ;;
739
+ CONFLICT)
740
+ die "conflict reached apply phase for $name"
741
+ ;;
742
+ esac
743
+ done < "$plan"
744
+ }
745
+
746
+ commit_manifest() {
747
+ local manifest_tmp="$1"
748
+ if $DRY_RUN; then
749
+ log " (dry-run) would commit manifest"
750
+ return 0
751
+ fi
752
+ mkdir -p "$PROJECT_ARIS_DIR"
753
+ if [[ -f "$MANIFEST_PATH" ]]; then
754
+ cp -p "$MANIFEST_PATH" "$MANIFEST_PREV.tmp"
755
+ mv -f "$MANIFEST_PREV.tmp" "$MANIFEST_PREV"
756
+ fi
757
+ mv -f "$manifest_tmp" "$MANIFEST_PATH"
758
+ }
759
+
760
+ update_agents_doc() {
761
+ local installed_names_file="$1"
762
+ $NO_DOC && return 0
763
+ local original=""
764
+ [[ -f "$DOC_FILE" ]] && original="$(cat "$DOC_FILE")"
765
+ local count packages_csv new_block new_content tmp current
766
+ count="$(wc -l < "$installed_names_file" | tr -d ' ')"
767
+ packages_csv="$(selected_packages | paste -sd, -)"
768
+ local repo_lookup_cmd
769
+ repo_lookup_cmd="ARIS_REPO=\$(awk -F'\\t' '\$1==\"repo_root\"{print \$2; exit}' \"$PROJECT_PATH/$ARIS_DIR_NAME/$MANIFEST_NAME\")"
770
+ new_block="$BLOCK_BEGIN
771
+ ## ARIS Codex Skill Scope
772
+ ARIS Codex packages installed in this project: $packages_csv
773
+ Managed entries: $count
774
+ Manifest: \`$ARIS_DIR_NAME/$MANIFEST_NAME\`
775
+ ARIS repo root: \`$ARIS_REPO\`
776
+ Project skill path: \`$SKILLS_REL/<skill-name>\`
777
+ For ARIS Codex workflows, prefer the project-local skills under \`$SKILLS_REL/\`.
778
+ When a skill needs ARIS helper scripts, resolve the repo root from the manifest or set it explicitly:
779
+ \`$repo_lookup_cmd\`
780
+ Do not edit or delete symlinked skills in place; update upstream or rerun:
781
+ \`bash $ARIS_REPO/tools/install_aris_codex.sh \"$PROJECT_PATH\" --reconcile\`
782
+ For copied Codex installs, use:
783
+ \`bash $ARIS_REPO/tools/smart_update_codex.sh --project \"$PROJECT_PATH\"\`
784
+ $BLOCK_END"
785
+
786
+ if printf '%s' "$original" | grep -qF "$BLOCK_BEGIN"; then
787
+ new_content="$(python3 - "$DOC_FILE" "$BLOCK_BEGIN" "$BLOCK_END" "$new_block" <<'PYEOF'
788
+ import pathlib
789
+ import re
790
+ import sys
791
+
792
+ path, begin, end, body = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
793
+ text = pathlib.Path(path).read_text() if pathlib.Path(path).exists() else ""
794
+ pattern = re.compile(re.escape(begin) + r".*?" + re.escape(end), re.DOTALL)
795
+ matches = pattern.findall(text)
796
+ if len(matches) > 1:
797
+ sys.stderr.write("ARIS-CODEX:WARN multiple managed blocks found; skipping update\n")
798
+ sys.stdout.write(text)
799
+ else:
800
+ sys.stdout.write(pattern.sub(body, text))
801
+ PYEOF
802
+ )" || { warn "AGENTS.md update failed; continuing"; return 0; }
803
+ else
804
+ new_content="$original"
805
+ [[ -n "$new_content" && "${new_content: -1}" != $'\n' ]] && new_content="${new_content}"$'\n'
806
+ new_content="${new_content}${new_block}"$'\n'
807
+ fi
808
+
809
+ if $DRY_RUN; then
810
+ log " (dry-run) would update AGENTS.md managed block"
811
+ return 0
812
+ fi
813
+
814
+ tmp="$DOC_FILE.aris-codex-tmp.$$"
815
+ printf '%s' "$new_content" > "$tmp"
816
+ current=""
817
+ [[ -f "$DOC_FILE" ]] && current="$(cat "$DOC_FILE")"
818
+ if [[ "$current" != "$original" ]]; then
819
+ rm -f "$tmp"
820
+ warn "AGENTS.md changed during install; skipping managed block update"
821
+ return 0
822
+ fi
823
+ mv -f "$tmp" "$DOC_FILE"
824
+ log " ✓ updated AGENTS.md"
825
+ }
826
+
827
+ remove_agents_doc_block() {
828
+ $NO_DOC && return 0
829
+ [[ -f "$DOC_FILE" ]] || return 0
830
+
831
+ local original new_content tmp current
832
+ original="$(cat "$DOC_FILE")"
833
+ if ! printf '%s' "$original" | grep -qF "$BLOCK_BEGIN"; then
834
+ return 0
835
+ fi
836
+
837
+ new_content="$(python3 - "$DOC_FILE" "$BLOCK_BEGIN" "$BLOCK_END" <<'PYEOF'
838
+ import pathlib
839
+ import re
840
+ import sys
841
+
842
+ path, begin, end = sys.argv[1], sys.argv[2], sys.argv[3]
843
+ text = pathlib.Path(path).read_text()
844
+ pattern = re.compile(r"\n?" + re.escape(begin) + r".*?" + re.escape(end) + r"\n?", re.DOTALL)
845
+ matches = pattern.findall(text)
846
+ if len(matches) > 1:
847
+ sys.stderr.write("ARIS-CODEX:WARN multiple managed blocks found; skipping removal\n")
848
+ sys.stdout.write(text)
849
+ else:
850
+ updated = pattern.sub("\n", text)
851
+ sys.stdout.write(updated.lstrip("\n"))
852
+ PYEOF
853
+ )" || { warn "AGENTS.md managed block removal failed; continuing"; return 0; }
854
+
855
+ if $DRY_RUN; then
856
+ log " (dry-run) would remove AGENTS.md managed block"
857
+ return 0
858
+ fi
859
+
860
+ tmp="$DOC_FILE.aris-codex-tmp.$$"
861
+ printf '%s' "$new_content" > "$tmp"
862
+ current="$(cat "$DOC_FILE")"
863
+ if [[ "$current" != "$original" ]]; then
864
+ rm -f "$tmp"
865
+ warn "AGENTS.md changed during uninstall; skipping managed block removal"
866
+ return 0
867
+ fi
868
+ mv -f "$tmp" "$DOC_FILE"
869
+ log " ✓ removed AGENTS.md managed block"
870
+ }
871
+
872
+ do_uninstall() {
873
+ [[ -f "$MANIFEST_PATH" ]] || die "no manifest at $MANIFEST_PATH; nothing to uninstall"
874
+ local manifest_data
875
+ manifest_data="$(mktemp -t aris-codex-manifest.XXXX)"
876
+ load_manifest "$MANIFEST_PATH" "$manifest_data"
877
+ log ""
878
+ log "Uninstall plan:"
879
+ while IFS=$'\t' read -r kind name _source _target _mode; do
880
+ [[ -z "$name" ]] && continue
881
+ log " - $name ($kind)"
882
+ done < "$manifest_data"
883
+ if ! $DRY_RUN; then
884
+ prompt "Proceed?" || { log "aborted"; exit 0; }
885
+ fi
886
+ local kind name source_rel target_rel mode target_path expected_target current_target
887
+ local recorded_repo_root
888
+ recorded_repo_root="$(manifest_repo_root "$MANIFEST_PATH")"
889
+ [[ -n "$recorded_repo_root" ]] || die "manifest missing repo_root: $MANIFEST_PATH"
890
+ while IFS=$'\t' read -r kind name source_rel target_rel mode; do
891
+ [[ -z "$name" ]] && continue
892
+ target_path="$PROJECT_PATH/$target_rel"
893
+ expected_target="$recorded_repo_root/$source_rel"
894
+ if [[ -L "$target_path" ]]; then
895
+ current_target="$(read_link_target "$target_path")"
896
+ [[ "$current_target" != /* ]] && current_target="$(canonicalize "$(dirname "$target_path")/$current_target")"
897
+ if [[ "$current_target" == "$expected_target" ]]; then
898
+ if $DRY_RUN; then
899
+ log " (dry-run) rm $target_path"
900
+ else
901
+ rm -f "$target_path"
902
+ log " - removed $name"
903
+ fi
904
+ else
905
+ warn "skipping $name during uninstall; target changed to $current_target"
906
+ fi
907
+ else
908
+ warn "skipping $name during uninstall; not a symlink"
909
+ fi
910
+ done < "$manifest_data"
911
+ rm -f "$manifest_data"
912
+ if ! $DRY_RUN; then
913
+ mv -f "$MANIFEST_PATH" "$MANIFEST_PREV"
914
+ log " ✓ uninstalled (manifest preserved as $MANIFEST_PREV)"
915
+ fi
916
+ remove_agents_doc_block
917
+ }
918
+
919
+ log ""
920
+ log "ARIS Codex Project Install"
921
+ log " Project: $PROJECT_PATH"
922
+ log " Repo: $ARIS_REPO"
923
+ log " Packages: $(selected_packages | paste -sd, -)"
924
+ log " Action: $ACTION$($DRY_RUN && echo ' (dry-run)')"
925
+ log ""
926
+
927
+ check_no_symlinked_parents
928
+ check_legacy_nested_install
929
+ if ! $DRY_RUN; then
930
+ acquire_lock
931
+ fi
932
+
933
+ if [[ "$ACTION" == "uninstall" ]]; then
934
+ do_uninstall
935
+ exit 0
936
+ fi
937
+
938
+ if [[ "$ACTION" == "reconcile" && ! -f "$MANIFEST_PATH" ]]; then
939
+ die "--reconcile requires existing manifest; none found at $MANIFEST_PATH"
940
+ fi
941
+
942
+ UPSTREAM_FILE="$(mktemp -t aris-codex-upstream.XXXX)"
943
+ build_upstream_inventory "$ARIS_REPO" "$UPSTREAM_FILE"
944
+
945
+ MANIFEST_DATA="$(mktemp -t aris-codex-manifest.XXXX)"
946
+ load_manifest "$MANIFEST_PATH" "$MANIFEST_DATA"
947
+
948
+ # Selective install (#366): build the selected set, then plan against it.
949
+ SELECTED_FILE="$(mktemp -t aris-codex-selected.XXXX)"
950
+ DECLINED_CANDIDATES="$(mktemp -t aris-codex-declined.XXXX)"
951
+ build_selection "$UPSTREAM_FILE" "$DECLINED_CANDIDATES" "$SELECTED_FILE"
952
+ SELECTED_UPSTREAM="$(mktemp -t aris-codex-upstream-sel.XXXX)"
953
+ filter_upstream_by_selection "$UPSTREAM_FILE" "$SELECTED_FILE" "$SELECTED_UPSTREAM"
954
+ N_SELECTED=$(grep -c '^skill|' "$SELECTED_UPSTREAM" || true)
955
+ N_UPSTREAM=$(grep -c '^skill|' "$UPSTREAM_FILE" || true)
956
+ log ""
957
+ log "Selection: $N_SELECTED of $N_UPSTREAM upstream skills"
958
+
959
+ PLAN_FILE="$(mktemp -t aris-codex-plan.XXXX)"
960
+ compute_plan "$SELECTED_UPSTREAM" "$MANIFEST_DATA" "$PLAN_FILE"
961
+ print_plan "$PLAN_FILE"
962
+
963
+ if grep -q '^CONFLICT|' "$PLAN_FILE"; then
964
+ log ""
965
+ log "Aborting due to unresolved conflicts."
966
+ log "Use --replace-link NAME for a symlink you intentionally want to replace."
967
+ exit 1
968
+ fi
969
+
970
+ if $DRY_RUN; then
971
+ log ""
972
+ log "(dry-run) no changes made"
973
+ rm -f "$UPSTREAM_FILE" "$MANIFEST_DATA" "$PLAN_FILE" "$SELECTED_FILE" "$SELECTED_UPSTREAM" "$DECLINED_CANDIDATES"
974
+ exit 0
975
+ fi
976
+
977
+ N_CHANGES="$(awk -F'|' '$1=="CREATE"||$1=="UPDATE_TARGET"||$1=="REMOVE"{n++} END{print n+0}' "$PLAN_FILE")"
978
+ if (( N_CHANGES > 0 )); then
979
+ prompt "Apply these $N_CHANGES changes?" || { log "aborted"; exit 0; }
980
+ fi
981
+
982
+ MANIFEST_TMP="$MANIFEST_PATH.tmp.$$"
983
+ write_manifest_tmp "$PLAN_FILE" "$MANIFEST_TMP"
984
+ log ""
985
+ log "Applying:"
986
+ apply_plan "$PLAN_FILE"
987
+ commit_manifest "$MANIFEST_TMP"
988
+
989
+ # #366: persist declined skills + global repo pointer (best-effort, after
990
+ # manifest commit for the same reason as install_aris.sh).
991
+ save_declined "$DECLINED_CANDIDATES" "$SELECTED_FILE"
992
+ ensure_global_pointer
993
+
994
+ INSTALLED_NAMES="$(mktemp -t aris-codex-names.XXXX)"
995
+ awk -F'|' '$1=="REUSE"||$1=="ADOPT"||$1=="CREATE"||$1=="UPDATE_TARGET"{print $3}' "$PLAN_FILE" > "$INSTALLED_NAMES"
996
+ update_agents_doc "$INSTALLED_NAMES"
997
+
998
+ if ! $DRY_RUN; then
999
+ local_bad=0
1000
+ while IFS=$'\t' read -r kind name source_rel target_rel mode; do
1001
+ [[ -z "$name" ]] && continue
1002
+ target_path="$PROJECT_PATH/$target_rel"
1003
+ expected_target="$ARIS_REPO/$source_rel"
1004
+ if [[ ! -L "$target_path" ]]; then
1005
+ warn "verify: missing symlink $target_path"
1006
+ local_bad=$((local_bad + 1))
1007
+ continue
1008
+ fi
1009
+ current_target="$(read_link_target "$target_path")"
1010
+ [[ "$current_target" != /* ]] && current_target="$(canonicalize "$(dirname "$target_path")/$current_target")"
1011
+ if [[ "$current_target" != "$expected_target" ]]; then
1012
+ warn "verify: wrong target for $target_path -> $current_target"
1013
+ local_bad=$((local_bad + 1))
1014
+ fi
1015
+ done < <(awk -F'\t' '
1016
+ BEGIN { in_body=0 }
1017
+ /^kind\tname\tsource_rel\ttarget_rel\tmode$/ { in_body=1; next }
1018
+ in_body && NF==5 { print }
1019
+ ' "$MANIFEST_PATH")
1020
+ (( local_bad == 0 )) && log "" && log "✓ Codex install complete. $N_CHANGES changes applied."
1021
+ fi
1022
+
1023
+ rm -f "$UPSTREAM_FILE" "$MANIFEST_DATA" "$PLAN_FILE" "$INSTALLED_NAMES" "$SELECTED_FILE" "$SELECTED_UPSTREAM" "$DECLINED_CANDIDATES"