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