@proflandrigan/shards 1.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/README.md +475 -0
- package/package.json +37 -0
- package/src/agents/academic.md +276 -0
- package/src/agents/ai-engineer.md +377 -0
- package/src/agents/analytics-engineer.md +364 -0
- package/src/agents/applied-ml-scientist.md +410 -0
- package/src/agents/backend-engineer.md +255 -0
- package/src/agents/bi-engineer.md +333 -0
- package/src/agents/data-analyst.md +343 -0
- package/src/agents/data-engineer.md +260 -0
- package/src/agents/data-modeller.md +386 -0
- package/src/agents/data-scientist.md +366 -0
- package/src/agents/deep-learning-engineer.md +389 -0
- package/src/agents/ml-engineer.md +424 -0
- package/src/agents/mlops-engineer.md +339 -0
- package/src/agents/researcher.md +187 -0
- package/src/agents/specific_instructions/academic/critical_review.md +263 -0
- package/src/agents/specific_instructions/academic/report.md +113 -0
- package/src/agents/specific_instructions/ai_engineer/advise.md +162 -0
- package/src/agents/specific_instructions/ai_engineer/bi_engineer_handoff.md +86 -0
- package/src/agents/specific_instructions/ai_engineer/experiment.md +471 -0
- package/src/agents/specific_instructions/ai_engineer/experiment_ui_mode.md +44 -0
- package/src/agents/specific_instructions/ai_engineer/phases/index.md +45 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-1.md +55 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-2.md +86 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-3.md +96 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-4.md +138 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-5.md +157 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-6.md +196 -0
- package/src/agents/specific_instructions/ai_engineer/phases/phase-7.md +313 -0
- package/src/agents/specific_instructions/ai_engineer/phases.md +1011 -0
- package/src/agents/specific_instructions/ai_engineer/prompt_lab.md +161 -0
- package/src/agents/specific_instructions/ai_engineer/prompt_lab_ui_mode.md +28 -0
- package/src/agents/specific_instructions/ai_engineer/research.md +393 -0
- package/src/agents/specific_instructions/ai_engineer/research_ui_mode.md +66 -0
- package/src/agents/specific_instructions/ai_engineer/review.md +159 -0
- package/src/agents/specific_instructions/ai_engineer/validation_checklist.md +182 -0
- package/src/agents/specific_instructions/analytics_engineer/advise.md +155 -0
- package/src/agents/specific_instructions/analytics_engineer/bi_engineer_handoff.md +91 -0
- package/src/agents/specific_instructions/analytics_engineer/data_analyst_handoff.md +84 -0
- package/src/agents/specific_instructions/analytics_engineer/deep_phases.md +818 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/index.md +24 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-1.md +77 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-2.md +106 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-3.md +93 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-4.md +79 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-5.md +61 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-6.md +45 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-7.md +235 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-8.md +221 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_quick/index.md +19 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_quick/phase-1.md +47 -0
- package/src/agents/specific_instructions/analytics_engineer/phases_quick/phase-2.md +78 -0
- package/src/agents/specific_instructions/analytics_engineer/quick_phases.md +112 -0
- package/src/agents/specific_instructions/analytics_engineer/review.md +167 -0
- package/src/agents/specific_instructions/analytics_engineer/service_mode.md +369 -0
- package/src/agents/specific_instructions/analytics_engineer/ui_mode.md +45 -0
- package/src/agents/specific_instructions/analytics_engineer/update.md +162 -0
- package/src/agents/specific_instructions/analytics_engineer/validation_checklist.md +121 -0
- package/src/agents/specific_instructions/applied_ml_scientist/advise.md +143 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases/index.md +21 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-1.md +51 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-2.md +66 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-3.md +113 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-4.md +104 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-5.md +156 -0
- package/src/agents/specific_instructions/applied_ml_scientist/phases.md +428 -0
- package/src/agents/specific_instructions/applied_ml_scientist/research.md +379 -0
- package/src/agents/specific_instructions/applied_ml_scientist/review.md +142 -0
- package/src/agents/specific_instructions/applied_ml_scientist/validation_checklist.md +136 -0
- package/src/agents/specific_instructions/backend_engineer/clean.md +149 -0
- package/src/agents/specific_instructions/backend_engineer/review.md +91 -0
- package/src/agents/specific_instructions/backend_engineer/review_checklist.md +54 -0
- package/src/agents/specific_instructions/backend_engineer/service_mode.md +67 -0
- package/src/agents/specific_instructions/bi_engineer/advise.md +137 -0
- package/src/agents/specific_instructions/bi_engineer/data_analyst_handoff.md +77 -0
- package/src/agents/specific_instructions/bi_engineer/incoming_handoff.md +45 -0
- package/src/agents/specific_instructions/bi_engineer/phases/index.md +20 -0
- package/src/agents/specific_instructions/bi_engineer/phases/phase-1.md +164 -0
- package/src/agents/specific_instructions/bi_engineer/phases/phase-2.md +92 -0
- package/src/agents/specific_instructions/bi_engineer/phases/phase-3.md +121 -0
- package/src/agents/specific_instructions/bi_engineer/phases/phase-4.md +106 -0
- package/src/agents/specific_instructions/bi_engineer/phases.md +451 -0
- package/src/agents/specific_instructions/bi_engineer/review.md +166 -0
- package/src/agents/specific_instructions/bi_engineer/update.md +147 -0
- package/src/agents/specific_instructions/bi_engineer/validation_checklist.md +124 -0
- package/src/agents/specific_instructions/data_analyst/advise.md +138 -0
- package/src/agents/specific_instructions/data_analyst/explain.md +221 -0
- package/src/agents/specific_instructions/data_analyst/incoming_handoff.md +40 -0
- package/src/agents/specific_instructions/data_analyst/phases/index.md +20 -0
- package/src/agents/specific_instructions/data_analyst/phases/phase-1.md +159 -0
- package/src/agents/specific_instructions/data_analyst/phases/phase-2.md +112 -0
- package/src/agents/specific_instructions/data_analyst/phases/phase-3.md +265 -0
- package/src/agents/specific_instructions/data_analyst/phases/phase-4.md +100 -0
- package/src/agents/specific_instructions/data_analyst/phases.md +501 -0
- package/src/agents/specific_instructions/data_analyst/review.md +138 -0
- package/src/agents/specific_instructions/data_analyst/ui_mode.md +26 -0
- package/src/agents/specific_instructions/data_analyst/update.md +144 -0
- package/src/agents/specific_instructions/data_analyst/validation_checklist.md +95 -0
- package/src/agents/specific_instructions/data_engineer/advise.md +137 -0
- package/src/agents/specific_instructions/data_engineer/phases.md +466 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/index.md +23 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-1.md +49 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-2.md +93 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-3.md +55 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-4.md +48 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-5.md +40 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-6.md +102 -0
- package/src/agents/specific_instructions/data_engineer/phases_deep/phase-7.md +87 -0
- package/src/agents/specific_instructions/data_engineer/phases_quick/index.md +19 -0
- package/src/agents/specific_instructions/data_engineer/phases_quick/phase-1.md +45 -0
- package/src/agents/specific_instructions/data_engineer/phases_quick/phase-2.md +54 -0
- package/src/agents/specific_instructions/data_engineer/review.md +135 -0
- package/src/agents/specific_instructions/data_engineer/validation_checklist.md +136 -0
- package/src/agents/specific_instructions/data_modeller/advise.md +137 -0
- package/src/agents/specific_instructions/data_modeller/phases.md +581 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/index.md +23 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-1.md +52 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-2.md +113 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-3.md +47 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-4.md +51 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-5.md +45 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-6.md +105 -0
- package/src/agents/specific_instructions/data_modeller/phases_deep/phase-7.md +136 -0
- package/src/agents/specific_instructions/data_modeller/phases_quick/index.md +19 -0
- package/src/agents/specific_instructions/data_modeller/phases_quick/phase-1.md +47 -0
- package/src/agents/specific_instructions/data_modeller/phases_quick/phase-2.md +65 -0
- package/src/agents/specific_instructions/data_modeller/review.md +141 -0
- package/src/agents/specific_instructions/data_modeller/service_mode.md +218 -0
- package/src/agents/specific_instructions/data_modeller/validation_checklist.md +125 -0
- package/src/agents/specific_instructions/data_scientist/advise.md +158 -0
- package/src/agents/specific_instructions/data_scientist/bi_engineer_handoff.md +63 -0
- package/src/agents/specific_instructions/data_scientist/experiment.md +482 -0
- package/src/agents/specific_instructions/data_scientist/experiment_ui_mode.md +44 -0
- package/src/agents/specific_instructions/data_scientist/explain.md +247 -0
- package/src/agents/specific_instructions/data_scientist/greenfield_data.md +35 -0
- package/src/agents/specific_instructions/data_scientist/ml_engineer_handoff.md +52 -0
- package/src/agents/specific_instructions/data_scientist/notebook_walkthrough.md +76 -0
- package/src/agents/specific_instructions/data_scientist/phases/index.md +24 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-1.md +45 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-2.md +67 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-3.md +89 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-4.md +143 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-5.md +71 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-6.md +239 -0
- package/src/agents/specific_instructions/data_scientist/phases/phase-7.md +207 -0
- package/src/agents/specific_instructions/data_scientist/phases.md +651 -0
- package/src/agents/specific_instructions/data_scientist/research.md +345 -0
- package/src/agents/specific_instructions/data_scientist/research_ui_mode.md +52 -0
- package/src/agents/specific_instructions/data_scientist/review.md +136 -0
- package/src/agents/specific_instructions/data_scientist/service_mode.md +247 -0
- package/src/agents/specific_instructions/data_scientist/validation_checklist.md +183 -0
- package/src/agents/specific_instructions/deep_learning_engineer/advise.md +145 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases/index.md +21 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-1.md +74 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-2.md +98 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-3.md +76 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-4.md +128 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-5.md +292 -0
- package/src/agents/specific_instructions/deep_learning_engineer/phases.md +567 -0
- package/src/agents/specific_instructions/deep_learning_engineer/research.md +389 -0
- package/src/agents/specific_instructions/deep_learning_engineer/review.md +155 -0
- package/src/agents/specific_instructions/deep_learning_engineer/validation_checklist.md +147 -0
- package/src/agents/specific_instructions/ml_engineer/advise.md +174 -0
- package/src/agents/specific_instructions/ml_engineer/bi_engineer_handoff.md +71 -0
- package/src/agents/specific_instructions/ml_engineer/experiment.md +474 -0
- package/src/agents/specific_instructions/ml_engineer/experiment_ui_mode.md +44 -0
- package/src/agents/specific_instructions/ml_engineer/notebook_walkthrough.md +75 -0
- package/src/agents/specific_instructions/ml_engineer/phases/index.md +25 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-1.md +49 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-2.md +75 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-3.md +124 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-4.md +279 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-5.md +160 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-6-5.md +170 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-6.md +295 -0
- package/src/agents/specific_instructions/ml_engineer/phases/phase-7.md +337 -0
- package/src/agents/specific_instructions/ml_engineer/phases.md +1068 -0
- package/src/agents/specific_instructions/ml_engineer/research.md +437 -0
- package/src/agents/specific_instructions/ml_engineer/research_ui_mode.md +71 -0
- package/src/agents/specific_instructions/ml_engineer/review.md +187 -0
- package/src/agents/specific_instructions/ml_engineer/service_mode.md +273 -0
- package/src/agents/specific_instructions/ml_engineer/validation_checklist.md +185 -0
- package/src/agents/specific_instructions/mlops_engineer/advise.md +139 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/index.md +23 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-1.md +52 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-2.md +86 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-3.md +105 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-4.md +128 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-5.md +106 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-6.md +128 -0
- package/src/agents/specific_instructions/mlops_engineer/phases/phase-7.md +144 -0
- package/src/agents/specific_instructions/mlops_engineer/phases.md +671 -0
- package/src/agents/specific_instructions/mlops_engineer/review.md +164 -0
- package/src/agents/specific_instructions/mlops_engineer/service_mode.md +81 -0
- package/src/agents/specific_instructions/mlops_engineer/validation_checklist.md +151 -0
- package/src/agents/specific_instructions/researcher/critical_review.md +292 -0
- package/src/agents/specific_instructions/researcher/review_checklist.md +67 -0
- package/src/agents/specific_instructions/researcher/service_mode.md +224 -0
- package/src/agents/specific_instructions/shared/auto_verify_mode.md +141 -0
- package/src/agents/specific_instructions/shared/autonomous_research.md +1289 -0
- package/src/agents/specific_instructions/shared/behavioral_rules.md +36 -0
- package/src/agents/specific_instructions/shared/diverge_protocol.md +387 -0
- package/src/agents/specific_instructions/shared/engineering_guidelines.md +136 -0
- package/src/agents/specific_instructions/shared/experiment_versioning.md +184 -0
- package/src/agents/specific_instructions/shared/goal_mode.md +187 -0
- package/src/agents/specific_instructions/shared/incremental_testing.md +139 -0
- package/src/agents/specific_instructions/shared/intent_discovery.md +223 -0
- package/src/agents/specific_instructions/shared/join_path_protocol.md +168 -0
- package/src/agents/specific_instructions/shared/knowledge_checkpoint.md +83 -0
- package/src/agents/specific_instructions/shared/knowledge_harvest.md +220 -0
- package/src/agents/specific_instructions/shared/knowledge_retrieval.md +100 -0
- package/src/agents/specific_instructions/shared/notebook_walkthrough_protocol.md +367 -0
- package/src/agents/specific_instructions/shared/reviewer_verdict_protocol.md +74 -0
- package/src/agents/specific_instructions/shared/swarm_protocol.md +97 -0
- package/src/agents/specific_instructions/shared/validation_protocol.md +139 -0
- package/src/agents/specific_instructions/syn/arbiter.md +140 -0
- package/src/agents/specific_instructions/syn/brainstorm.md +550 -0
- package/src/agents/specific_instructions/syn/code_review.md +232 -0
- package/src/agents/specific_instructions/syn/diff.md +239 -0
- package/src/agents/specific_instructions/syn/final_review.md +65 -0
- package/src/agents/specific_instructions/syn/fixer.md +240 -0
- package/src/agents/specific_instructions/syn/free_form.md +130 -0
- package/src/agents/specific_instructions/syn/knowledge.md +468 -0
- package/src/agents/specific_instructions/syn/notebook_walkthrough.md +78 -0
- package/src/agents/specific_instructions/syn/panel_review.md +634 -0
- package/src/agents/specific_instructions/syn/pm.md +453 -0
- package/src/agents/specific_instructions/syn/pr_review.md +255 -0
- package/src/agents/specific_instructions/syn/slides.md +417 -0
- package/src/agents/syn.md +729 -0
- package/src/commands/academic.md +41 -0
- package/src/commands/ai-engineer.md +45 -0
- package/src/commands/analytics-engineer.md +48 -0
- package/src/commands/applied-ml-scientist.md +45 -0
- package/src/commands/backend-engineer.md +35 -0
- package/src/commands/bi-engineer.md +40 -0
- package/src/commands/brainstorm.md +24 -0
- package/src/commands/data-analyst.md +38 -0
- package/src/commands/data-engineer.md +37 -0
- package/src/commands/data-modeller.md +38 -0
- package/src/commands/data-scientist.md +38 -0
- package/src/commands/deep-learning-engineer.md +47 -0
- package/src/commands/end.md +49 -0
- package/src/commands/knowledge.md +24 -0
- package/src/commands/ml-engineer.md +42 -0
- package/src/commands/mlops-engineer.md +47 -0
- package/src/commands/notebook-walkthrough.md +58 -0
- package/src/commands/researcher.md +40 -0
- package/src/commands/resume.md +57 -0
- package/src/commands/review-pr.md +26 -0
- package/src/commands/shards-guide.md +41 -0
- package/src/commands/shards-ui.md +32 -0
- package/src/commands/shards.md +41 -0
- package/src/docs/01-getting-started/concepts.md +109 -0
- package/src/docs/01-getting-started/first-session.md +79 -0
- package/src/docs/01-getting-started/install.md +61 -0
- package/src/docs/02-agents/academic.md +71 -0
- package/src/docs/02-agents/ai-engineer.md +78 -0
- package/src/docs/02-agents/analytics-engineer.md +58 -0
- package/src/docs/02-agents/applied-ml-scientist.md +59 -0
- package/src/docs/02-agents/backend-engineer.md +58 -0
- package/src/docs/02-agents/bi-engineer.md +65 -0
- package/src/docs/02-agents/data-analyst.md +67 -0
- package/src/docs/02-agents/data-engineer.md +57 -0
- package/src/docs/02-agents/data-modeller.md +51 -0
- package/src/docs/02-agents/data-scientist.md +78 -0
- package/src/docs/02-agents/deep-learning-engineer.md +64 -0
- package/src/docs/02-agents/ml-engineer.md +80 -0
- package/src/docs/02-agents/mlops-engineer.md +59 -0
- package/src/docs/02-agents/overview.md +62 -0
- package/src/docs/02-agents/researcher.md +73 -0
- package/src/docs/02-agents/syn.md +88 -0
- package/src/docs/03-protocols/auto-verify.md +82 -0
- package/src/docs/03-protocols/autonomous-research.md +59 -0
- package/src/docs/03-protocols/behavioral-rules.md +35 -0
- package/src/docs/03-protocols/diverge.md +50 -0
- package/src/docs/03-protocols/engineering-guidelines.md +56 -0
- package/src/docs/03-protocols/experiment-versioning.md +38 -0
- package/src/docs/03-protocols/gate-pattern.md +65 -0
- package/src/docs/03-protocols/incremental-testing.md +68 -0
- package/src/docs/03-protocols/join-path.md +46 -0
- package/src/docs/03-protocols/knowledge-ledger.md +70 -0
- package/src/docs/03-protocols/reviewer-verdicts.md +39 -0
- package/src/docs/03-protocols/swarm.md +40 -0
- package/src/docs/03-protocols/validation.md +174 -0
- package/src/docs/04-ui/activity-bar.md +70 -0
- package/src/docs/04-ui/chat-pane.md +80 -0
- package/src/docs/04-ui/code-intel.md +62 -0
- package/src/docs/04-ui/file-editing.md +61 -0
- package/src/docs/04-ui/git.md +54 -0
- package/src/docs/04-ui/keybindings.md +79 -0
- package/src/docs/04-ui/knowledge-map.md +76 -0
- package/src/docs/04-ui/overview.md +93 -0
- package/src/docs/04-ui/panels.md +49 -0
- package/src/docs/04-ui/pinboard-selection.md +66 -0
- package/src/docs/04-ui/quick-open-palette.md +56 -0
- package/src/docs/04-ui/sessions.md +81 -0
- package/src/docs/04-ui/settings-permissions.md +56 -0
- package/src/docs/05-commands/reference.md +59 -0
- package/src/docs/06-outputs/directory-map.md +116 -0
- package/src/docs/07-workflows/ai-eval-first.md +57 -0
- package/src/docs/07-workflows/deep-study-to-production.md +76 -0
- package/src/docs/07-workflows/diverge-exploration.md +77 -0
- package/src/docs/07-workflows/quick-analysis.md +45 -0
- package/src/docs/08-integrations/claude-code-auto-mode.md +191 -0
- package/src/docs/08-integrations/google-slides.md +175 -0
- package/src/docs/README.md +30 -0
- package/src/docs/manifest.json +108 -0
- package/src/templates/analysis-template.md +20 -0
- package/src/templates/branch-report.md +46 -0
- package/src/templates/diff-report.md +88 -0
- package/src/templates/knowledge-index.md +7 -0
- package/src/templates/model-card-schema.json +186 -0
- package/src/templates/model-card-schema.md +88 -0
- package/src/templates/model-card.md +124 -0
- package/src/templates/project-plan.md +47 -0
- package/src/templates/project-specs.md +81 -0
- package/src/templates/report-template.md +43 -0
- package/src/templates/study-template.md +25 -0
- package/src/ui/cc-readonly.js +181 -0
- package/src/ui/chat-session.js +466 -0
- package/src/ui/css/base.css +136 -0
- package/src/ui/css/brainstorm.css +525 -0
- package/src/ui/css/chat.css +1405 -0
- package/src/ui/css/editor.css +546 -0
- package/src/ui/css/eval-dashboard.css +157 -0
- package/src/ui/css/experiment.css +237 -0
- package/src/ui/css/guide.css +186 -0
- package/src/ui/css/knowledge-map.css +383 -0
- package/src/ui/css/layout.css +431 -0
- package/src/ui/css/model-card.css +161 -0
- package/src/ui/css/notebook-walkthrough.css +271 -0
- package/src/ui/css/pr-review.css +403 -0
- package/src/ui/css/prompt-lab.css +325 -0
- package/src/ui/css/sessions.css +258 -0
- package/src/ui/css/sidebar.css +661 -0
- package/src/ui/css/terminal.css +113 -0
- package/src/ui/css/theme-light.css +542 -0
- package/src/ui/index.html +389 -0
- package/src/ui/js/agents.js +32 -0
- package/src/ui/js/bookmarks.js +230 -0
- package/src/ui/js/chat.js +1776 -0
- package/src/ui/js/code-intel.js +328 -0
- package/src/ui/js/command-palette.js +142 -0
- package/src/ui/js/events.js +591 -0
- package/src/ui/js/explorer.js +317 -0
- package/src/ui/js/file-view.js +477 -0
- package/src/ui/js/git.js +536 -0
- package/src/ui/js/guide.js +198 -0
- package/src/ui/js/hud.js +75 -0
- package/src/ui/js/init.js +351 -0
- package/src/ui/js/knowledge-map.js +906 -0
- package/src/ui/js/markdown.js +114 -0
- package/src/ui/js/monaco.js +164 -0
- package/src/ui/js/notebook-walkthrough.js +272 -0
- package/src/ui/js/notebook.js +448 -0
- package/src/ui/js/panels.js +2681 -0
- package/src/ui/js/pinboard.js +186 -0
- package/src/ui/js/quick-open.js +164 -0
- package/src/ui/js/selection-context.js +131 -0
- package/src/ui/js/sessions.js +256 -0
- package/src/ui/js/settings.js +476 -0
- package/src/ui/js/split-view.js +82 -0
- package/src/ui/js/state.js +343 -0
- package/src/ui/js/table.js +161 -0
- package/src/ui/js/tabs.js +284 -0
- package/src/ui/js/tabular.js +125 -0
- package/src/ui/js/terminal.js +354 -0
- package/src/ui/js/timeline.js +137 -0
- package/src/ui/js/utils.js +293 -0
- package/src/ui/notebook-kernel.py +790 -0
- package/src/ui/open-browser.js +55 -0
- package/src/ui/permission-pattern.js +42 -0
- package/src/ui/relay.js +513 -0
- package/src/ui/server.js +3072 -0
- package/src/ui/session-index.js +225 -0
- package/src/ui/shards_icon.png +0 -0
- package/src/ui/spawn-server.js +41 -0
- package/src/ui/symbol-index.js +813 -0
- package/src/ui/ui-push.js +177 -0
- package/tools/gate-hook/VALIDATION_SPEC.md +273 -0
- package/tools/gate-hook/__tests__/auto-verify.test.js +343 -0
- package/tools/gate-hook/auto-allowlist.js +179 -0
- package/tools/gate-hook/auto-state.js +68 -0
- package/tools/gate-hook/classify.js +21 -0
- package/tools/gate-hook/log.js +57 -0
- package/tools/gate-hook/parser.js +205 -0
- package/tools/gate-hook/sql-guard.js +230 -0
- package/tools/gate-hook/state.js +170 -0
- package/tools/gate-hook/sweep.js +139 -0
- package/tools/gate-hook/transcript.js +45 -0
- package/tools/gate-hook/validation.js +321 -0
- package/tools/gate-hook.js +475 -0
- package/tools/install.js +914 -0
- package/tools/shards-gates.js +311 -0
- package/tools/shards-sessions.js +261 -0
- package/tools/shards-ui.js +377 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Gate enforcement hook for Shards — dispatches stop / pre-tool-use / user-prompt-submit
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
// Escape hatch: SHARDS_GATE_ENFORCE=0 disables all enforcement
|
|
6
|
+
if (process.env.SHARDS_GATE_ENFORCE === '0') process.exit(0);
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const HOOK_DIR = path.dirname(path.resolve(__filename));
|
|
12
|
+
const state = require(path.join(HOOK_DIR, 'gate-hook', 'state.js'));
|
|
13
|
+
const autoState = require(path.join(HOOK_DIR, 'gate-hook', 'auto-state.js'));
|
|
14
|
+
const { parseGates, checkViolation, parseAutoVerify, NON_ADVANCING_KINDS } = require(path.join(HOOK_DIR, 'gate-hook', 'parser.js'));
|
|
15
|
+
const { classify } = require(path.join(HOOK_DIR, 'gate-hook', 'classify.js'));
|
|
16
|
+
const { readLastAssistantMessage } = require(path.join(HOOK_DIR, 'gate-hook', 'transcript.js'));
|
|
17
|
+
const { appendViolation, appendHistory, appendAutoHistory } = require(path.join(HOOK_DIR, 'gate-hook', 'log.js'));
|
|
18
|
+
const { isAutoApprovable } = require(path.join(HOOK_DIR, 'gate-hook', 'auto-allowlist.js'));
|
|
19
|
+
const validation = require(path.join(HOOK_DIR, 'gate-hook', 'validation.js'));
|
|
20
|
+
const { isForceCloseBash, isStaleGate, sweepStaleSessions } = require(path.join(HOOK_DIR, 'gate-hook', 'sweep.js'));
|
|
21
|
+
|
|
22
|
+
// Opt-in validation enforcement. Default: off (parse-and-log only).
|
|
23
|
+
// Flip to 1 to have the hook block gates when validation is missing.
|
|
24
|
+
const VALIDATION_ENFORCE = process.env.SHARDS_VALIDATION_ENFORCE === '1';
|
|
25
|
+
|
|
26
|
+
// Checkpoint gates (kind=checkpoint) can be downgraded to advisory by setting
|
|
27
|
+
// SHARDS_CHECKPOINT_ENFORCE=0 — they are still logged but do not block tools.
|
|
28
|
+
// Phase and final gates are unaffected.
|
|
29
|
+
const CHECKPOINT_ENFORCE = process.env.SHARDS_CHECKPOINT_ENFORCE !== '0';
|
|
30
|
+
|
|
31
|
+
// Auto-verify mode: agents emit ::AUTO-VERIFY:: ... ::ENDAUTO:: markers to
|
|
32
|
+
// bracket bulk read-only verification work (grain checks, fan-out queries,
|
|
33
|
+
// dbt show, etc.). When the block is open, this hook auto-approves tool
|
|
34
|
+
// calls that match a hardcoded read-only allowlist. SHARDS_AUTO_VERIFY=0
|
|
35
|
+
// disables the entire branch.
|
|
36
|
+
const AUTO_VERIFY_ENFORCE = process.env.SHARDS_AUTO_VERIFY !== '0';
|
|
37
|
+
const AUTO_DEFAULT_TOOL_BUDGET = 20;
|
|
38
|
+
const AUTO_MAX_TOOL_BUDGET = 50;
|
|
39
|
+
const AUTO_DEFAULT_TTL_MINUTES = 10;
|
|
40
|
+
const AUTO_MAX_TTL_MINUTES = 30;
|
|
41
|
+
|
|
42
|
+
// Read tools that are allowed while a gate is open
|
|
43
|
+
const ALLOWED_TOOLS = new Set(['Read', 'Glob', 'Grep']);
|
|
44
|
+
|
|
45
|
+
function respond(obj) {
|
|
46
|
+
process.stdout.write(JSON.stringify(obj) + '\n');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── Auto-verify helpers ──────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
function clamp(n, lo, hi) { return Math.max(lo, Math.min(hi, n)); }
|
|
52
|
+
|
|
53
|
+
function openAutoVerify(open, current, sessionId) {
|
|
54
|
+
const attrs = open.attrs || {};
|
|
55
|
+
const requestedBudget = parseInt(attrs.tool_budget, 10);
|
|
56
|
+
const tool_budget = Number.isFinite(requestedBudget)
|
|
57
|
+
? clamp(requestedBudget, 1, AUTO_MAX_TOOL_BUDGET)
|
|
58
|
+
: AUTO_DEFAULT_TOOL_BUDGET;
|
|
59
|
+
const requestedTtl = parseInt(attrs.ttl_minutes, 10);
|
|
60
|
+
const ttl_minutes = Number.isFinite(requestedTtl)
|
|
61
|
+
? clamp(requestedTtl, 1, AUTO_MAX_TTL_MINUTES)
|
|
62
|
+
: AUTO_DEFAULT_TTL_MINUTES;
|
|
63
|
+
|
|
64
|
+
const opened_at = new Date();
|
|
65
|
+
const expires_at = new Date(opened_at.getTime() + ttl_minutes * 60 * 1000);
|
|
66
|
+
|
|
67
|
+
const id = `auto-${opened_at.getTime()}`;
|
|
68
|
+
const newState = {
|
|
69
|
+
open: true,
|
|
70
|
+
id,
|
|
71
|
+
agent: attrs.agent || null,
|
|
72
|
+
phase: attrs.phase || null,
|
|
73
|
+
opened_at: opened_at.toISOString(),
|
|
74
|
+
expires_at: expires_at.toISOString(),
|
|
75
|
+
tool_budget_initial: tool_budget,
|
|
76
|
+
tool_budget_remaining: tool_budget,
|
|
77
|
+
history: current.history || [],
|
|
78
|
+
};
|
|
79
|
+
autoState.write(newState);
|
|
80
|
+
appendAutoHistory({
|
|
81
|
+
event: 'opened', block_id: id, agent: attrs.agent || null,
|
|
82
|
+
phase: attrs.phase || null, tool_budget, ttl_minutes,
|
|
83
|
+
session_id: sessionId,
|
|
84
|
+
});
|
|
85
|
+
return newState;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function closeAutoVerify(current, sessionId, reason) {
|
|
89
|
+
const next = autoState.close(current, reason);
|
|
90
|
+
autoState.write(next);
|
|
91
|
+
appendAutoHistory({
|
|
92
|
+
event: 'closed', reason,
|
|
93
|
+
block_id: current.id, agent: current.agent, session_id: sessionId,
|
|
94
|
+
});
|
|
95
|
+
return next;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function processAutoVerifyMarkers(lastMsg, sessionId) {
|
|
99
|
+
if (!AUTO_VERIFY_ENFORCE) return;
|
|
100
|
+
const av = parseAutoVerify(lastMsg);
|
|
101
|
+
|
|
102
|
+
const closes = av.closes || (av.close ? [av.close] : []);
|
|
103
|
+
|
|
104
|
+
// No markers — nothing to do.
|
|
105
|
+
if (av.opens.length === 0 && closes.length === 0) return;
|
|
106
|
+
|
|
107
|
+
// Position-aware processing: apply markers in order so a message containing
|
|
108
|
+
// both open and close markers is handled correctly. All closes are
|
|
109
|
+
// processed (not just the first) — a message can legitimately open, close,
|
|
110
|
+
// re-open, and close again within one assistant turn.
|
|
111
|
+
const events = [];
|
|
112
|
+
for (const o of av.opens) events.push({ kind: 'open', index: o.index, marker: o });
|
|
113
|
+
for (const c of closes) events.push({ kind: 'close', index: c.index });
|
|
114
|
+
events.sort((a, b) => a.index - b.index);
|
|
115
|
+
|
|
116
|
+
let cur = autoState.read();
|
|
117
|
+
for (const ev of events) {
|
|
118
|
+
if (ev.kind === 'open') {
|
|
119
|
+
// If already open, treat as a re-open (close existing first so the audit
|
|
120
|
+
// log records the transition cleanly).
|
|
121
|
+
if (cur.open) cur = closeAutoVerify(cur, sessionId, 'reopened');
|
|
122
|
+
cur = openAutoVerify(ev.marker, cur, sessionId);
|
|
123
|
+
} else {
|
|
124
|
+
if (cur.open) cur = closeAutoVerify(cur, sessionId, 'endauto-marker');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ─── Stop handler ─────────────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
function handleStop(payload) {
|
|
132
|
+
const transcriptPath = payload.transcript_path;
|
|
133
|
+
const sessionId = payload.session_id || 'unknown';
|
|
134
|
+
|
|
135
|
+
// Stale-gate sweep — clear stale/abandoned slots before processing this Stop
|
|
136
|
+
// event so a stuck prior-session gate can't shadow a fresh open below. Only
|
|
137
|
+
// THIS session's gate (if stale) plus genuinely abandoned (>24h / malformed)
|
|
138
|
+
// gates from other sessions are swept; other sessions' fresh gates survive.
|
|
139
|
+
const existing = state.read();
|
|
140
|
+
if (isStaleGate(state.getGate(existing, sessionId)) ||
|
|
141
|
+
state.anyOpen(existing)) {
|
|
142
|
+
// sweepStaleSessions is a no-op when nothing is stale, so calling it
|
|
143
|
+
// whenever any gate is open is safe and keeps the abandoned-other-session
|
|
144
|
+
// cleanup running.
|
|
145
|
+
sweepStaleSessions(existing, sessionId);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const lastMsg = readLastAssistantMessage(transcriptPath);
|
|
149
|
+
if (!lastMsg) return;
|
|
150
|
+
|
|
151
|
+
// Parse gates first (cheap, side-effect-free) so a thrown exception inside
|
|
152
|
+
// processAutoVerifyMarkers cannot prevent the gate from being opened. Auto-
|
|
153
|
+
// verify and gate handling are isolated so each can fail independently and
|
|
154
|
+
// still surface in the audit log.
|
|
155
|
+
const gates = parseGates(lastMsg);
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
processAutoVerifyMarkers(lastMsg, sessionId);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
try {
|
|
161
|
+
appendViolation({
|
|
162
|
+
type: 'auto-verify-error',
|
|
163
|
+
reason: (err && err.message) || String(err),
|
|
164
|
+
session_id: sessionId,
|
|
165
|
+
});
|
|
166
|
+
} catch {}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (gates.length === 0) return;
|
|
170
|
+
|
|
171
|
+
// Use the last gate found in the message
|
|
172
|
+
const gate = gates[gates.length - 1];
|
|
173
|
+
const { id, phase, kind, agent } = gate.attrs;
|
|
174
|
+
|
|
175
|
+
if (!id) return;
|
|
176
|
+
|
|
177
|
+
// Check for violation: content after ::ENDGATE::
|
|
178
|
+
const violation = checkViolation(lastMsg);
|
|
179
|
+
if (violation) {
|
|
180
|
+
appendViolation({
|
|
181
|
+
type: 'post-fence-content',
|
|
182
|
+
gate_id: id,
|
|
183
|
+
reason: violation,
|
|
184
|
+
session_id: sessionId,
|
|
185
|
+
});
|
|
186
|
+
respond({
|
|
187
|
+
decision: 'block',
|
|
188
|
+
reason: 'Gate violation — content appeared after ::ENDGATE::. End your turn immediately.',
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Advisory mode for non-advancing kinds (checkpoint, confirm): if this gate
|
|
194
|
+
// is a mid-build/micro-confirmation seam and SHARDS_CHECKPOINT_ENFORCE=0,
|
|
195
|
+
// log the advisory and exit without opening state — downstream tool calls
|
|
196
|
+
// remain unblocked. Phase / final / execute / handoff gates always enforce.
|
|
197
|
+
const gateKind = kind || 'phase';
|
|
198
|
+
if (NON_ADVANCING_KINDS.has(gateKind) && !CHECKPOINT_ENFORCE) {
|
|
199
|
+
appendHistory({
|
|
200
|
+
event: 'advisory',
|
|
201
|
+
kind: gateKind,
|
|
202
|
+
gate_id: id,
|
|
203
|
+
phase: phase || null,
|
|
204
|
+
session_id: sessionId,
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Validation enforcement: if the gate declares `validates=<checklist>`, check
|
|
210
|
+
// the `## Validation` section in project-specs.md before opening.
|
|
211
|
+
// Non-advancing kinds (checkpoint, confirm) are build-time/micro punctuation
|
|
212
|
+
// and never carry a validates= field; validation evidence is a phase-gate
|
|
213
|
+
// concern.
|
|
214
|
+
const validates = NON_ADVANCING_KINDS.has(gateKind) ? null : gate.attrs.validates;
|
|
215
|
+
if (validates && validates !== 'none') {
|
|
216
|
+
const specs = validation.readSpecs();
|
|
217
|
+
const parsed = validation.parseValidationSection(specs);
|
|
218
|
+
const errors = validation.checkValidation(parsed);
|
|
219
|
+
if (errors.length > 0) {
|
|
220
|
+
appendViolation({
|
|
221
|
+
type: 'validation-missing',
|
|
222
|
+
gate_id: id,
|
|
223
|
+
checklist: validates,
|
|
224
|
+
errors,
|
|
225
|
+
session_id: sessionId,
|
|
226
|
+
});
|
|
227
|
+
if (VALIDATION_ENFORCE) {
|
|
228
|
+
respond({
|
|
229
|
+
decision: 'block',
|
|
230
|
+
reason: validation.formatValidationError(validates, gate.attrs, errors),
|
|
231
|
+
});
|
|
232
|
+
return; // do not open gate
|
|
233
|
+
}
|
|
234
|
+
// Soft-launch mode: log but do not block.
|
|
235
|
+
} else {
|
|
236
|
+
appendHistory({
|
|
237
|
+
event: 'validation-passed',
|
|
238
|
+
gate_id: id,
|
|
239
|
+
checklist: validates,
|
|
240
|
+
evidence_rows: parsed.evidenceRows.length,
|
|
241
|
+
track: parsed.track,
|
|
242
|
+
mode: parsed.mode || null,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Open the gate into THIS session's slot. Re-read so we compose against the
|
|
248
|
+
// freshest state (the sweep above may have written). setGate preserves the
|
|
249
|
+
// shared history and every other session's slot.
|
|
250
|
+
const current = state.read();
|
|
251
|
+
const gateObj = {
|
|
252
|
+
open: true,
|
|
253
|
+
id,
|
|
254
|
+
phase: phase || null,
|
|
255
|
+
kind: gateKind,
|
|
256
|
+
agent: agent || sessionId,
|
|
257
|
+
opened_at: new Date().toISOString(),
|
|
258
|
+
opened_in_turn: payload.turn_number || null,
|
|
259
|
+
transcript_ref: transcriptPath || null,
|
|
260
|
+
};
|
|
261
|
+
state.write(state.setGate(current, sessionId, gateObj));
|
|
262
|
+
appendHistory({ event: 'opened', gate_id: id, kind: gateKind, session_id: sessionId });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ─── PreToolUse handler ───────────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
function handlePreToolUse(payload) {
|
|
268
|
+
let s = state.read();
|
|
269
|
+
const toolName = payload.tool_name || '';
|
|
270
|
+
const sessionId = payload.session_id || 'unknown';
|
|
271
|
+
|
|
272
|
+
// Stale-gate sweep — clear malformed / abandoned gates before the block
|
|
273
|
+
// check. Catches the test-gate-leftover case where this session's slot was
|
|
274
|
+
// hand-written with no opened_at, plus genuinely abandoned gates older than
|
|
275
|
+
// 24h (any session). Other sessions' FRESH gates are left untouched.
|
|
276
|
+
if (state.anyOpen(s)) {
|
|
277
|
+
s = sweepStaleSessions(s, sessionId);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Block decision is scoped to THIS session's gate. A different session's
|
|
281
|
+
// open gate must NOT block this session's tool call.
|
|
282
|
+
const gate = state.getGate(s, sessionId);
|
|
283
|
+
|
|
284
|
+
// Branch 1: this session's gate is open. Existing block behavior — gates
|
|
285
|
+
// always win, except for the operator force-close escape hatch.
|
|
286
|
+
if (gate.open) {
|
|
287
|
+
if (ALLOWED_TOOLS.has(toolName)) return;
|
|
288
|
+
if (isForceCloseBash(toolName, payload.tool_input)) return;
|
|
289
|
+
|
|
290
|
+
const gateKind = gate.kind || 'phase';
|
|
291
|
+
const label = (
|
|
292
|
+
gateKind === 'checkpoint' ? 'Checkpoint gate — a component was just tested and awaits user confirmation before the next component can be written.' :
|
|
293
|
+
gateKind === 'confirm' ? 'Confirm gate — micro-confirmation checkpoint; await explicit user confirmation before continuing.' :
|
|
294
|
+
gateKind === 'execute' ? 'Execute gate — an experiment/AR iteration completed; await user confirmation before advancing.' :
|
|
295
|
+
gateKind === 'handoff' ? 'Handoff gate — specialist-to-specialist transition; await user confirmation before handing off.' :
|
|
296
|
+
gateKind === 'final' ? 'Final gate — last phase of this track; await user confirmation before closing out.' :
|
|
297
|
+
'Phase gate — await user confirmation before advancing.'
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const msg = [
|
|
301
|
+
`::GATE-BLOCK:: Gate '${gate.id}' (phase ${gate.phase}, kind ${gateKind}) is still open.`,
|
|
302
|
+
label,
|
|
303
|
+
`Opened at ${gate.opened_at}. User must confirm before you can proceed.`,
|
|
304
|
+
`If the user just confirmed, the UserPromptSubmit hook should have closed`,
|
|
305
|
+
`the gate — if it did not, the confirmation language was ambiguous. Ask`,
|
|
306
|
+
`the user for an explicit "confirmed" / "proceed".`,
|
|
307
|
+
].join('\n');
|
|
308
|
+
|
|
309
|
+
// Use the canonical PreToolUse hook contract (hookSpecificOutput.permission
|
|
310
|
+
// Decision) so the deny is recognized authoritatively across CC versions
|
|
311
|
+
// and matches the shape used by the auto-verify allow path below and by
|
|
312
|
+
// src/ui/relay.js. Legacy `decision: 'block'` is reserved for Stop hooks.
|
|
313
|
+
respond({
|
|
314
|
+
hookSpecificOutput: {
|
|
315
|
+
hookEventName: 'PreToolUse',
|
|
316
|
+
permissionDecision: 'deny',
|
|
317
|
+
permissionDecisionReason: msg,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Branch 2: no gate open — check auto-verify.
|
|
324
|
+
if (!AUTO_VERIFY_ENFORCE) return;
|
|
325
|
+
const a = autoState.read();
|
|
326
|
+
if (!a.open) return;
|
|
327
|
+
|
|
328
|
+
// Expired? Close and pass through.
|
|
329
|
+
if (autoState.isExpired(a)) {
|
|
330
|
+
const reason = (typeof a.tool_budget_remaining === 'number' && a.tool_budget_remaining <= 0)
|
|
331
|
+
? 'budget-exhausted' : 'ttl-expired';
|
|
332
|
+
autoState.write(autoState.close(a, reason));
|
|
333
|
+
appendAutoHistory({ event: 'closed', reason, block_id: a.id });
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Allowlist check.
|
|
338
|
+
if (!isAutoApprovable(toolName, payload.tool_input || {})) return;
|
|
339
|
+
|
|
340
|
+
// Decrement the budget atomically — read immediately before write to keep
|
|
341
|
+
// the race window tight, then verify the on-disk value to detect concurrent
|
|
342
|
+
// writers (two CC instances, parallel hook invocations). On drift, retry up
|
|
343
|
+
// to 3 times before giving up. If we can't safely decrement, fall through
|
|
344
|
+
// without emitting allow so CC's normal permission flow takes over.
|
|
345
|
+
let approvedState = null;
|
|
346
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
347
|
+
const fresh = autoState.read();
|
|
348
|
+
if (!fresh.open || fresh.id !== a.id) break; // block was closed or rotated
|
|
349
|
+
const remaining = (fresh.tool_budget_remaining || 0) - 1;
|
|
350
|
+
if (remaining < 0) break; // exhausted between branch entry and now
|
|
351
|
+
const candidate = { ...fresh, tool_budget_remaining: remaining };
|
|
352
|
+
autoState.write(candidate);
|
|
353
|
+
const after = autoState.read();
|
|
354
|
+
if (after.id === candidate.id && after.tool_budget_remaining === remaining) {
|
|
355
|
+
approvedState = candidate;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
// Drift detected — another writer overwrote us. Retry.
|
|
359
|
+
}
|
|
360
|
+
if (!approvedState) return;
|
|
361
|
+
|
|
362
|
+
appendAutoHistory({
|
|
363
|
+
event: 'auto-approved',
|
|
364
|
+
block_id: approvedState.id,
|
|
365
|
+
tool: toolName,
|
|
366
|
+
command: (payload.tool_input && payload.tool_input.command) || null,
|
|
367
|
+
budget_remaining: approvedState.tool_budget_remaining,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
respond({
|
|
371
|
+
hookSpecificOutput: {
|
|
372
|
+
hookEventName: 'PreToolUse',
|
|
373
|
+
permissionDecision: 'allow',
|
|
374
|
+
permissionDecisionReason: `auto-verify (block ${approvedState.id}, ${approvedState.tool_budget_remaining} approvals remaining)`,
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ─── UserPromptSubmit handler ─────────────────────────────────────────────────
|
|
380
|
+
|
|
381
|
+
// Patterns that should close any open auto-verify block immediately, even if
|
|
382
|
+
// no gate is open. These are stronger than the gate-classify "deny" patterns —
|
|
383
|
+
// we want to err on the side of closing the auto-verify block whenever the
|
|
384
|
+
// user expresses any concern or signals a stop.
|
|
385
|
+
const AUTO_HALT_RE = /\b(stop|halt|pause|cancel|abort|wait|hold(\s+on)?|no thanks|nope|don'?t)\b/i;
|
|
386
|
+
|
|
387
|
+
function maybeCloseAutoOnPrompt(prompt) {
|
|
388
|
+
if (!AUTO_VERIFY_ENFORCE) return;
|
|
389
|
+
const a = autoState.read();
|
|
390
|
+
if (!a.open) return;
|
|
391
|
+
if (!prompt || !AUTO_HALT_RE.test(prompt)) return;
|
|
392
|
+
autoState.write(autoState.close(a, 'user-halt'));
|
|
393
|
+
appendAutoHistory({ event: 'closed', reason: 'user-halt', block_id: a.id });
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function handleUserPromptSubmit(payload) {
|
|
397
|
+
const prompt = payload.prompt || '';
|
|
398
|
+
const sessionId = payload.session_id || 'unknown';
|
|
399
|
+
|
|
400
|
+
// Auto-verify halt on user dissent — independent of gate state.
|
|
401
|
+
maybeCloseAutoOnPrompt(prompt);
|
|
402
|
+
|
|
403
|
+
const s = state.read();
|
|
404
|
+
// Operate on THIS session's gate only — a confirm here must not close some
|
|
405
|
+
// other concurrent session's open gate.
|
|
406
|
+
const gate = state.getGate(s, sessionId);
|
|
407
|
+
if (!gate.open) return;
|
|
408
|
+
|
|
409
|
+
const result = classify(prompt);
|
|
410
|
+
|
|
411
|
+
if (result === 'confirm') {
|
|
412
|
+
const closed_at = new Date().toISOString();
|
|
413
|
+
const historyEntry = {
|
|
414
|
+
id: gate.id,
|
|
415
|
+
phase: gate.phase,
|
|
416
|
+
kind: gate.kind,
|
|
417
|
+
opened_at: gate.opened_at,
|
|
418
|
+
closed_at,
|
|
419
|
+
confirmed_by: 'user-prompt',
|
|
420
|
+
};
|
|
421
|
+
// Move this session's gate into shared history, then clear its slot.
|
|
422
|
+
const cleared = state.clearGate(s, sessionId);
|
|
423
|
+
state.write({
|
|
424
|
+
version: 2,
|
|
425
|
+
sessions: cleared.sessions,
|
|
426
|
+
history: [...cleared.history, historyEntry],
|
|
427
|
+
});
|
|
428
|
+
appendHistory({ event: 'closed', gate_id: gate.id, kind: gate.kind || 'phase', confirmed_by: 'user-prompt' });
|
|
429
|
+
} else if (result === 'deny') {
|
|
430
|
+
// Gate stays open — user is asking for a change
|
|
431
|
+
} else {
|
|
432
|
+
// Ambiguous — gate stays open, inject context reminder
|
|
433
|
+
respond({
|
|
434
|
+
additionalContext: `<system-reminder>\nGate '${gate.id}' is still open. The user's message did not contain an explicit confirmation. Do not advance to the next phase. Ask for explicit confirmation or address their message within the current phase.\n</system-reminder>`,
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
440
|
+
|
|
441
|
+
async function main() {
|
|
442
|
+
const event = process.argv[2];
|
|
443
|
+
let payload = {};
|
|
444
|
+
try {
|
|
445
|
+
const raw = fs.readFileSync(0, 'utf8');
|
|
446
|
+
if (raw && raw.trim()) payload = JSON.parse(raw);
|
|
447
|
+
} catch {
|
|
448
|
+
// Malformed or empty stdin — safe default
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
if (event === 'stop') return handleStop(payload);
|
|
453
|
+
if (event === 'pre-tool-use') return handlePreToolUse(payload);
|
|
454
|
+
if (event === 'user-prompt-submit') return handleUserPromptSubmit(payload);
|
|
455
|
+
} catch (err) {
|
|
456
|
+
// Never crash the hook — but DO record the failure so that "the gate hook
|
|
457
|
+
// silently did nothing" is debuggable. A swallowed exception here used to
|
|
458
|
+
// mean an open auto-verify block could be left in a stale state with no
|
|
459
|
+
// audit trail; now the violation log captures the symptom even when stdout
|
|
460
|
+
// stays empty. The append is best-effort: a second exception here is
|
|
461
|
+
// intentionally swallowed.
|
|
462
|
+
try {
|
|
463
|
+
appendViolation({
|
|
464
|
+
type: 'hook-exception',
|
|
465
|
+
event,
|
|
466
|
+
reason: (err && err.message) || String(err),
|
|
467
|
+
stack: (err && err.stack) ? String(err.stack).split('\n').slice(0, 5).join('\n') : null,
|
|
468
|
+
session_id: payload && payload.session_id || null,
|
|
469
|
+
});
|
|
470
|
+
} catch {}
|
|
471
|
+
}
|
|
472
|
+
process.exit(0);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
main().catch(() => process.exit(0));
|