@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,813 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync, execFileSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
// ─── Symbol Index Engine ─────────────────────────────────────────────────────
|
|
8
|
+
// Builds and maintains an in-memory symbol index using ctags (with regex fallback).
|
|
9
|
+
|
|
10
|
+
const SKIP_DIRS = new Set(['.git', 'node_modules', '__pycache__', '.shards', '.venv', 'venv', '.tox', '.mypy_cache', '.pytest_cache', 'dist', 'build']);
|
|
11
|
+
const SUPPORTED_EXTS = new Set(['.py', '.js', '.ts', '.tsx', '.jsx', '.go', '.rs', '.java', '.rb', '.c', '.cpp', '.h', '.hpp', '.cs', '.php', '.swift', '.kt', '.r', '.R', '.sql', '.sh', '.bash']);
|
|
12
|
+
|
|
13
|
+
let symbolsByName = new Map(); // name -> SymbolEntry[]
|
|
14
|
+
let symbolsByFile = new Map(); // relPath -> SymbolEntry[]
|
|
15
|
+
let ctagsAvailable = false;
|
|
16
|
+
let indexedAt = null;
|
|
17
|
+
let projectDir = null;
|
|
18
|
+
let watcher = null;
|
|
19
|
+
let watchDebounce = new Map(); // relPath -> timeout
|
|
20
|
+
|
|
21
|
+
// ─── Reference cache for hover enrichment ───────────────────────────────────
|
|
22
|
+
let referenceCache = new Map(); // name -> { refs: {count, byFile}, callers, callees, builtAt }
|
|
23
|
+
let fileToRefNames = new Map(); // file -> Set<name> — reverse map for cache invalidation
|
|
24
|
+
let cacheBuilding = false;
|
|
25
|
+
let cacheQueue = []; // names queued for background cache build
|
|
26
|
+
|
|
27
|
+
// ─── Ctags detection ─────────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
function detectCtags() {
|
|
30
|
+
try {
|
|
31
|
+
execSync('ctags --version', { timeout: 3000, stdio: 'pipe' });
|
|
32
|
+
ctagsAvailable = true;
|
|
33
|
+
} catch {
|
|
34
|
+
ctagsAvailable = false;
|
|
35
|
+
}
|
|
36
|
+
return ctagsAvailable;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── Ctags-based indexing ────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
function parseCtagsJson(output) {
|
|
42
|
+
const entries = [];
|
|
43
|
+
for (const line of output.split('\n')) {
|
|
44
|
+
if (!line.trim()) continue;
|
|
45
|
+
try {
|
|
46
|
+
const tag = JSON.parse(line);
|
|
47
|
+
if (!tag.name || !tag.path) continue;
|
|
48
|
+
entries.push({
|
|
49
|
+
name: tag.name,
|
|
50
|
+
kind: mapCtagsKind(tag.kind),
|
|
51
|
+
file: tag.path,
|
|
52
|
+
line: tag.line || 0,
|
|
53
|
+
pattern: tag.pattern || '',
|
|
54
|
+
scope: tag.scope || null,
|
|
55
|
+
scopeKind: tag.scopeKind || null,
|
|
56
|
+
signature: tag.signature || null,
|
|
57
|
+
});
|
|
58
|
+
} catch {
|
|
59
|
+
// skip malformed lines
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return entries;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function mapCtagsKind(kind) {
|
|
66
|
+
if (!kind) return 'symbol';
|
|
67
|
+
const map = {
|
|
68
|
+
f: 'function', F: 'function', function: 'function',
|
|
69
|
+
c: 'class', class: 'class',
|
|
70
|
+
m: 'method', method: 'method', member: 'method',
|
|
71
|
+
v: 'variable', variable: 'variable',
|
|
72
|
+
p: 'property', property: 'property',
|
|
73
|
+
i: 'interface', interface: 'interface',
|
|
74
|
+
e: 'enum', enum: 'enum',
|
|
75
|
+
t: 'type', typedef: 'type', type: 'type',
|
|
76
|
+
s: 'struct', struct: 'struct',
|
|
77
|
+
n: 'namespace', namespace: 'namespace', module: 'module',
|
|
78
|
+
d: 'macro', macro: 'macro', define: 'macro',
|
|
79
|
+
C: 'constant', constant: 'constant',
|
|
80
|
+
};
|
|
81
|
+
return map[kind] || kind;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function runCtagsOnProject(dir) {
|
|
85
|
+
try {
|
|
86
|
+
const args = [
|
|
87
|
+
'--output-format=json',
|
|
88
|
+
'--fields=+nKS',
|
|
89
|
+
'--extras=-{anonymous}',
|
|
90
|
+
'-R',
|
|
91
|
+
'--exclude=node_modules',
|
|
92
|
+
'--exclude=.git',
|
|
93
|
+
'--exclude=__pycache__',
|
|
94
|
+
'--exclude=.venv',
|
|
95
|
+
'--exclude=venv',
|
|
96
|
+
'--exclude=.shards',
|
|
97
|
+
'--exclude=dist',
|
|
98
|
+
'--exclude=build',
|
|
99
|
+
'--exclude=.tox',
|
|
100
|
+
'.',
|
|
101
|
+
];
|
|
102
|
+
const output = execFileSync('ctags', args, {
|
|
103
|
+
cwd: dir,
|
|
104
|
+
encoding: 'utf8',
|
|
105
|
+
timeout: 15000,
|
|
106
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
107
|
+
});
|
|
108
|
+
return parseCtagsJson(output);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function runCtagsOnFile(dir, relPath) {
|
|
115
|
+
try {
|
|
116
|
+
const absPath = path.join(dir, relPath);
|
|
117
|
+
if (!fs.existsSync(absPath)) return [];
|
|
118
|
+
const args = ['--output-format=json', '--fields=+nKS', '--extras=-{anonymous}', absPath];
|
|
119
|
+
const output = execFileSync('ctags', args, {
|
|
120
|
+
cwd: dir,
|
|
121
|
+
encoding: 'utf8',
|
|
122
|
+
timeout: 5000,
|
|
123
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
124
|
+
});
|
|
125
|
+
// ctags outputs absolute paths when given absolute input; normalize to relative
|
|
126
|
+
const entries = parseCtagsJson(output);
|
|
127
|
+
for (const e of entries) {
|
|
128
|
+
e.file = path.relative(dir, e.file);
|
|
129
|
+
}
|
|
130
|
+
return entries;
|
|
131
|
+
} catch {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ─── Regex-based fallback indexing ───────────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
const REGEX_PATTERNS = {
|
|
139
|
+
'.py': [
|
|
140
|
+
{ regex: /^(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)/gm, kind: 'function', sigGroup: 2 },
|
|
141
|
+
{ regex: /^class\s+(\w+)(?:\s*\(([^)]*)\))?/gm, kind: 'class', sigGroup: 2 },
|
|
142
|
+
{ regex: /^(\w+)\s*=\s*/gm, kind: 'variable' },
|
|
143
|
+
],
|
|
144
|
+
'.js': [
|
|
145
|
+
{ regex: /^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/gm, kind: 'function', sigGroup: 2 },
|
|
146
|
+
{ regex: /^(?:export\s+)?class\s+(\w+)/gm, kind: 'class' },
|
|
147
|
+
{ regex: /^(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=/gm, kind: 'variable' },
|
|
148
|
+
{ regex: /(\w+)\s*[:=]\s*(?:async\s+)?function\s*\(([^)]*)\)/gm, kind: 'function', sigGroup: 2 },
|
|
149
|
+
{ regex: /(\w+)\s*\(([^)]*)\)\s*\{/gm, kind: 'function', sigGroup: 2 },
|
|
150
|
+
],
|
|
151
|
+
'.ts': null, // same as .js
|
|
152
|
+
'.tsx': null,
|
|
153
|
+
'.jsx': null,
|
|
154
|
+
'.go': [
|
|
155
|
+
{ regex: /^func\s+(?:\(\w+\s+\*?\w+\)\s+)?(\w+)\s*\(([^)]*)\)/gm, kind: 'function', sigGroup: 2 },
|
|
156
|
+
{ regex: /^type\s+(\w+)\s+struct/gm, kind: 'struct' },
|
|
157
|
+
{ regex: /^type\s+(\w+)\s+interface/gm, kind: 'interface' },
|
|
158
|
+
],
|
|
159
|
+
'.rs': [
|
|
160
|
+
{ regex: /^(?:pub\s+)?(?:async\s+)?fn\s+(\w+)\s*(?:<[^>]*>)?\s*\(([^)]*)\)/gm, kind: 'function', sigGroup: 2 },
|
|
161
|
+
{ regex: /^(?:pub\s+)?struct\s+(\w+)/gm, kind: 'struct' },
|
|
162
|
+
{ regex: /^(?:pub\s+)?enum\s+(\w+)/gm, kind: 'enum' },
|
|
163
|
+
{ regex: /^(?:pub\s+)?trait\s+(\w+)/gm, kind: 'interface' },
|
|
164
|
+
],
|
|
165
|
+
'.java': [
|
|
166
|
+
{ regex: /(?:public|private|protected|static|\s)+[\w<>\[\]]+\s+(\w+)\s*\(([^)]*)\)/gm, kind: 'method', sigGroup: 2 },
|
|
167
|
+
{ regex: /(?:public\s+)?class\s+(\w+)/gm, kind: 'class' },
|
|
168
|
+
{ regex: /(?:public\s+)?interface\s+(\w+)/gm, kind: 'interface' },
|
|
169
|
+
],
|
|
170
|
+
'.rb': [
|
|
171
|
+
{ regex: /^\s*def\s+(\w+)(?:\(([^)]*)\))?/gm, kind: 'function', sigGroup: 2 },
|
|
172
|
+
{ regex: /^\s*class\s+(\w+)/gm, kind: 'class' },
|
|
173
|
+
{ regex: /^\s*module\s+(\w+)/gm, kind: 'module' },
|
|
174
|
+
],
|
|
175
|
+
'.sql': [
|
|
176
|
+
{ regex: /CREATE\s+(?:OR\s+REPLACE\s+)?(?:FUNCTION|PROCEDURE)\s+(\w+)\s*\(([^)]*)\)/gim, kind: 'function', sigGroup: 2 },
|
|
177
|
+
{ regex: /CREATE\s+(?:OR\s+REPLACE\s+)?(?:TABLE|VIEW)\s+(?:IF\s+NOT\s+EXISTS\s+)?(\w+)/gim, kind: 'class' },
|
|
178
|
+
],
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Alias entries
|
|
182
|
+
REGEX_PATTERNS['.ts'] = REGEX_PATTERNS['.js'];
|
|
183
|
+
REGEX_PATTERNS['.tsx'] = REGEX_PATTERNS['.js'];
|
|
184
|
+
REGEX_PATTERNS['.jsx'] = REGEX_PATTERNS['.js'];
|
|
185
|
+
|
|
186
|
+
function regexIndexFile(dir, relPath) {
|
|
187
|
+
const ext = path.extname(relPath).toLowerCase();
|
|
188
|
+
const patterns = REGEX_PATTERNS[ext];
|
|
189
|
+
if (!patterns) return [];
|
|
190
|
+
|
|
191
|
+
let content;
|
|
192
|
+
try {
|
|
193
|
+
const absPath = path.join(dir, relPath);
|
|
194
|
+
const stat = fs.statSync(absPath);
|
|
195
|
+
if (stat.size > 2 * 1024 * 1024) return []; // skip large files
|
|
196
|
+
content = fs.readFileSync(absPath, 'utf8');
|
|
197
|
+
} catch {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const entries = [];
|
|
202
|
+
const lines = content.split('\n');
|
|
203
|
+
|
|
204
|
+
for (const pat of patterns) {
|
|
205
|
+
pat.regex.lastIndex = 0;
|
|
206
|
+
let match;
|
|
207
|
+
while ((match = pat.regex.exec(content)) !== null) {
|
|
208
|
+
const name = match[1];
|
|
209
|
+
if (!name || name.length < 2) continue;
|
|
210
|
+
|
|
211
|
+
// Calculate line number
|
|
212
|
+
const offset = match.index;
|
|
213
|
+
let lineNum = 1;
|
|
214
|
+
for (let i = 0; i < offset && i < content.length; i++) {
|
|
215
|
+
if (content[i] === '\n') lineNum++;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const sig = pat.sigGroup ? (match[pat.sigGroup] || '') : null;
|
|
219
|
+
|
|
220
|
+
entries.push({
|
|
221
|
+
name,
|
|
222
|
+
kind: pat.kind,
|
|
223
|
+
file: relPath,
|
|
224
|
+
line: lineNum,
|
|
225
|
+
pattern: lines[lineNum - 1] || '',
|
|
226
|
+
scope: null,
|
|
227
|
+
scopeKind: null,
|
|
228
|
+
signature: sig ? `(${sig})` : null,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Deduplicate entries with same name+line (multiple patterns can match the same symbol)
|
|
234
|
+
const seen = new Set();
|
|
235
|
+
return entries.filter(e => {
|
|
236
|
+
const key = `${e.name}:${e.line}`;
|
|
237
|
+
if (seen.has(key)) return false;
|
|
238
|
+
seen.add(key);
|
|
239
|
+
return true;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function regexIndexProject(dir) {
|
|
244
|
+
const entries = [];
|
|
245
|
+
function walk(currentDir, relDir) {
|
|
246
|
+
let items;
|
|
247
|
+
try { items = fs.readdirSync(currentDir); } catch { return; }
|
|
248
|
+
for (const item of items) {
|
|
249
|
+
if (SKIP_DIRS.has(item)) continue;
|
|
250
|
+
const fullPath = path.join(currentDir, item);
|
|
251
|
+
const relPath = relDir ? `${relDir}/${item}` : item;
|
|
252
|
+
let stat;
|
|
253
|
+
try { stat = fs.statSync(fullPath); } catch { continue; }
|
|
254
|
+
if (stat.isDirectory()) {
|
|
255
|
+
walk(fullPath, relPath);
|
|
256
|
+
} else if (stat.isFile() && SUPPORTED_EXTS.has(path.extname(item).toLowerCase())) {
|
|
257
|
+
const fileEntries = regexIndexFile(dir, relPath);
|
|
258
|
+
entries.push(...fileEntries);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
walk(dir, '');
|
|
263
|
+
return entries;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ─── Index management ────────────────────────────────────────────────────────
|
|
267
|
+
|
|
268
|
+
function insertEntries(entries) {
|
|
269
|
+
for (const entry of entries) {
|
|
270
|
+
// By name
|
|
271
|
+
if (!symbolsByName.has(entry.name)) {
|
|
272
|
+
symbolsByName.set(entry.name, []);
|
|
273
|
+
}
|
|
274
|
+
symbolsByName.get(entry.name).push(entry);
|
|
275
|
+
|
|
276
|
+
// By file
|
|
277
|
+
if (!symbolsByFile.has(entry.file)) {
|
|
278
|
+
symbolsByFile.set(entry.file, []);
|
|
279
|
+
}
|
|
280
|
+
symbolsByFile.get(entry.file).push(entry);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function removeFileEntries(relPath) {
|
|
285
|
+
const entries = symbolsByFile.get(relPath);
|
|
286
|
+
if (!entries) return;
|
|
287
|
+
|
|
288
|
+
// Remove from symbolsByName
|
|
289
|
+
for (const entry of entries) {
|
|
290
|
+
const nameEntries = symbolsByName.get(entry.name);
|
|
291
|
+
if (nameEntries) {
|
|
292
|
+
const filtered = nameEntries.filter(e => e.file !== relPath);
|
|
293
|
+
if (filtered.length > 0) {
|
|
294
|
+
symbolsByName.set(entry.name, filtered);
|
|
295
|
+
} else {
|
|
296
|
+
symbolsByName.delete(entry.name);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
symbolsByFile.delete(relPath);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function buildIndex(dir, logFn) {
|
|
305
|
+
projectDir = dir;
|
|
306
|
+
const log = logFn || (() => {});
|
|
307
|
+
|
|
308
|
+
detectCtags();
|
|
309
|
+
symbolsByName = new Map();
|
|
310
|
+
symbolsByFile = new Map();
|
|
311
|
+
|
|
312
|
+
let entries;
|
|
313
|
+
if (ctagsAvailable) {
|
|
314
|
+
entries = runCtagsOnProject(dir);
|
|
315
|
+
if (!entries) {
|
|
316
|
+
// ctags failed, fall back
|
|
317
|
+
log('ctags execution failed, falling back to regex indexer');
|
|
318
|
+
entries = regexIndexProject(dir);
|
|
319
|
+
} else {
|
|
320
|
+
log(`ctags indexed ${entries.length} symbols`);
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
log('ctags not found — using regex fallback (install universal-ctags for full features)');
|
|
324
|
+
entries = regexIndexProject(dir);
|
|
325
|
+
log(`regex indexed ${entries.length} symbols`);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
insertEntries(entries);
|
|
329
|
+
indexedAt = new Date().toISOString();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function updateFileIndex(dir, relPath) {
|
|
333
|
+
if (!SUPPORTED_EXTS.has(path.extname(relPath).toLowerCase())) return;
|
|
334
|
+
|
|
335
|
+
// Invalidate reference cache entries affected by this file change
|
|
336
|
+
invalidateCacheForFile(relPath, dir);
|
|
337
|
+
|
|
338
|
+
removeFileEntries(relPath);
|
|
339
|
+
|
|
340
|
+
let entries;
|
|
341
|
+
if (ctagsAvailable) {
|
|
342
|
+
entries = runCtagsOnFile(dir, relPath);
|
|
343
|
+
if (!entries || entries.length === 0) {
|
|
344
|
+
entries = regexIndexFile(dir, relPath);
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
entries = regexIndexFile(dir, relPath);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
insertEntries(entries);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ─── Query functions ─────────────────────────────────────────────────────────
|
|
354
|
+
|
|
355
|
+
function getDefinitions(name, contextFile) {
|
|
356
|
+
const entries = symbolsByName.get(name) || [];
|
|
357
|
+
if (entries.length === 0) return [];
|
|
358
|
+
|
|
359
|
+
// Rank by proximity to context file
|
|
360
|
+
const contextDir = contextFile ? path.dirname(contextFile) : '';
|
|
361
|
+
const contextExt = contextFile ? path.extname(contextFile) : '';
|
|
362
|
+
|
|
363
|
+
// Prefer non-variable definitions, but fall back to variables if that's all we have
|
|
364
|
+
const nonVariables = entries.filter(e => e.kind !== 'variable');
|
|
365
|
+
const candidates = nonVariables.length > 0 ? nonVariables : entries;
|
|
366
|
+
|
|
367
|
+
return candidates
|
|
368
|
+
.sort((a, b) => {
|
|
369
|
+
// Same file first
|
|
370
|
+
const aFile = a.file === contextFile ? 0 : 1;
|
|
371
|
+
const bFile = b.file === contextFile ? 0 : 1;
|
|
372
|
+
if (aFile !== bFile) return aFile - bFile;
|
|
373
|
+
|
|
374
|
+
// Same directory
|
|
375
|
+
const aDir = path.dirname(a.file) === contextDir ? 0 : 1;
|
|
376
|
+
const bDir = path.dirname(b.file) === contextDir ? 0 : 1;
|
|
377
|
+
if (aDir !== bDir) return aDir - bDir;
|
|
378
|
+
|
|
379
|
+
// Same extension
|
|
380
|
+
const aExt = path.extname(a.file) === contextExt ? 0 : 1;
|
|
381
|
+
const bExt = path.extname(b.file) === contextExt ? 0 : 1;
|
|
382
|
+
if (aExt !== bExt) return aExt - bExt;
|
|
383
|
+
|
|
384
|
+
// Prefer functions/classes over variables
|
|
385
|
+
const kindRank = { 'function': 0, 'method': 0, 'class': 1, 'struct': 1, 'interface': 1, 'type': 2 };
|
|
386
|
+
const aKind = kindRank[a.kind] ?? 3;
|
|
387
|
+
const bKind = kindRank[b.kind] ?? 3;
|
|
388
|
+
return aKind - bKind;
|
|
389
|
+
})
|
|
390
|
+
.slice(0, 20);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function getReferences(name, dir) {
|
|
394
|
+
if (!name || name.length < 2) return [];
|
|
395
|
+
|
|
396
|
+
// Use grep for textual references
|
|
397
|
+
const includeFlags = [];
|
|
398
|
+
for (const ext of SUPPORTED_EXTS) {
|
|
399
|
+
includeFlags.push(`--include=*${ext}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
404
|
+
const args = ['-rn', ...includeFlags, '--max-count=200', `\\b${escapedName}\\b`, '.'];
|
|
405
|
+
const output = execFileSync('grep', args, {
|
|
406
|
+
cwd: dir, encoding: 'utf8', timeout: 5000, maxBuffer: 5 * 1024 * 1024, stdio: ['pipe', 'pipe', 'pipe'],
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const results = [];
|
|
410
|
+
for (const line of output.split('\n')) {
|
|
411
|
+
if (!line.trim()) continue;
|
|
412
|
+
const match = line.match(/^\.\/(.+?):(\d+):(.*)$/);
|
|
413
|
+
if (match) {
|
|
414
|
+
const [, file, lineNum, text] = match;
|
|
415
|
+
// Skip files in skip dirs
|
|
416
|
+
if (SKIP_DIRS.has(file.split('/')[0])) continue;
|
|
417
|
+
results.push({ file, line: parseInt(lineNum, 10), text: text.trim() });
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return results.slice(0, 200);
|
|
421
|
+
} catch {
|
|
422
|
+
// grep returns exit code 1 when no matches — that's fine
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function getCompletions(prefix, contextFile) {
|
|
428
|
+
if (!prefix || prefix.length < 1) return [];
|
|
429
|
+
|
|
430
|
+
const lowerPrefix = prefix.toLowerCase();
|
|
431
|
+
const results = [];
|
|
432
|
+
const contextDir = contextFile ? path.dirname(contextFile) : '';
|
|
433
|
+
|
|
434
|
+
for (const [name, entries] of symbolsByName) {
|
|
435
|
+
if (name.toLowerCase().startsWith(lowerPrefix)) {
|
|
436
|
+
// Pick the best entry for this name (slice to avoid mutating the index)
|
|
437
|
+
const best = entries.slice().sort((a, b) => {
|
|
438
|
+
if (a.file === contextFile && b.file !== contextFile) return -1;
|
|
439
|
+
if (b.file === contextFile && a.file !== contextFile) return 1;
|
|
440
|
+
if (path.dirname(a.file) === contextDir) return -1;
|
|
441
|
+
if (path.dirname(b.file) === contextDir) return 1;
|
|
442
|
+
return 0;
|
|
443
|
+
})[0];
|
|
444
|
+
|
|
445
|
+
results.push({
|
|
446
|
+
name: best.name,
|
|
447
|
+
kind: best.kind,
|
|
448
|
+
detail: best.signature || '',
|
|
449
|
+
file: best.file,
|
|
450
|
+
line: best.line,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Sort: exact prefix match first, then shorter names, then alphabetical
|
|
456
|
+
results.sort((a, b) => {
|
|
457
|
+
const aExact = a.name.startsWith(prefix) ? 0 : 1;
|
|
458
|
+
const bExact = b.name.startsWith(prefix) ? 0 : 1;
|
|
459
|
+
if (aExact !== bExact) return aExact - bExact;
|
|
460
|
+
if (a.name.length !== b.name.length) return a.name.length - b.name.length;
|
|
461
|
+
return a.name.localeCompare(b.name);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
return results.slice(0, 50);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function getHoverInfo(name, contextFile, line) {
|
|
468
|
+
const entries = symbolsByName.get(name);
|
|
469
|
+
if (!entries || entries.length === 0) return null;
|
|
470
|
+
|
|
471
|
+
// Best match: same file + closest line
|
|
472
|
+
let best = null;
|
|
473
|
+
let bestScore = Infinity;
|
|
474
|
+
|
|
475
|
+
for (const entry of entries) {
|
|
476
|
+
let score = 1000;
|
|
477
|
+
if (entry.file === contextFile) {
|
|
478
|
+
score = Math.abs(entry.line - (line || 0));
|
|
479
|
+
} else if (contextFile && path.dirname(entry.file) === path.dirname(contextFile)) {
|
|
480
|
+
score = 500;
|
|
481
|
+
}
|
|
482
|
+
if (score < bestScore) {
|
|
483
|
+
bestScore = score;
|
|
484
|
+
best = entry;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return best;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function getStatus() {
|
|
492
|
+
let symbolCount = 0;
|
|
493
|
+
for (const entries of symbolsByName.values()) {
|
|
494
|
+
symbolCount += entries.length;
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
indexed: indexedAt !== null,
|
|
498
|
+
symbolCount,
|
|
499
|
+
fileCount: symbolsByFile.size,
|
|
500
|
+
ctagsAvailable,
|
|
501
|
+
lastIndexed: indexedAt,
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// ─── File watcher ────────────────────────────────────────────────────────────
|
|
506
|
+
|
|
507
|
+
function startWatcher(dir, logFn) {
|
|
508
|
+
if (watcher) return;
|
|
509
|
+
const log = logFn || (() => {});
|
|
510
|
+
|
|
511
|
+
try {
|
|
512
|
+
watcher = fs.watch(dir, { recursive: true }, (eventType, filename) => {
|
|
513
|
+
if (!filename) return;
|
|
514
|
+
|
|
515
|
+
// Normalize path separators
|
|
516
|
+
const relPath = filename.replace(/\\/g, '/');
|
|
517
|
+
|
|
518
|
+
// Skip non-supported files and skip dirs
|
|
519
|
+
const parts = relPath.split('/');
|
|
520
|
+
for (const part of parts) {
|
|
521
|
+
if (SKIP_DIRS.has(part)) return;
|
|
522
|
+
}
|
|
523
|
+
if (!SUPPORTED_EXTS.has(path.extname(relPath).toLowerCase())) return;
|
|
524
|
+
|
|
525
|
+
// Debounce per file
|
|
526
|
+
if (watchDebounce.has(relPath)) {
|
|
527
|
+
clearTimeout(watchDebounce.get(relPath));
|
|
528
|
+
}
|
|
529
|
+
watchDebounce.set(relPath, setTimeout(() => {
|
|
530
|
+
watchDebounce.delete(relPath);
|
|
531
|
+
updateFileIndex(dir, relPath);
|
|
532
|
+
}, 500));
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
watcher.on('error', (err) => {
|
|
536
|
+
log(`File watcher error: ${err.message}`);
|
|
537
|
+
});
|
|
538
|
+
} catch (err) {
|
|
539
|
+
log(`Could not start file watcher: ${err.message}`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function stopWatcher() {
|
|
544
|
+
if (watcher) {
|
|
545
|
+
watcher.close();
|
|
546
|
+
watcher = null;
|
|
547
|
+
}
|
|
548
|
+
for (const timeout of watchDebounce.values()) {
|
|
549
|
+
clearTimeout(timeout);
|
|
550
|
+
}
|
|
551
|
+
watchDebounce.clear();
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// ─── Reference cache & lineage ───────────────────────────────────────────────
|
|
555
|
+
|
|
556
|
+
const CALLABLE_KINDS = new Set(['function', 'method', 'class', 'struct', 'interface', 'macro']);
|
|
557
|
+
|
|
558
|
+
function getCallersFromRefs(refs) {
|
|
559
|
+
// For each reference, find the enclosing function/method in that file
|
|
560
|
+
const callers = new Map(); // key -> caller entry (deduplicated)
|
|
561
|
+
for (const ref of refs) {
|
|
562
|
+
const fileSymbols = symbolsByFile.get(ref.file);
|
|
563
|
+
if (!fileSymbols) continue;
|
|
564
|
+
|
|
565
|
+
// Find the closest symbol defined before this reference line
|
|
566
|
+
let enclosing = null;
|
|
567
|
+
for (const sym of fileSymbols) {
|
|
568
|
+
if (!CALLABLE_KINDS.has(sym.kind)) continue;
|
|
569
|
+
if (sym.line <= ref.line) {
|
|
570
|
+
if (!enclosing || sym.line > enclosing.line) {
|
|
571
|
+
enclosing = sym;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (enclosing) {
|
|
576
|
+
const key = `${enclosing.name}:${enclosing.file}:${enclosing.line}`;
|
|
577
|
+
if (!callers.has(key)) {
|
|
578
|
+
callers.set(key, { name: enclosing.name, kind: enclosing.kind, file: enclosing.file, line: enclosing.line });
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return Array.from(callers.values());
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function getCalleesFromBody(entry) {
|
|
586
|
+
if (!projectDir) return [];
|
|
587
|
+
const fileSymbols = symbolsByFile.get(entry.file);
|
|
588
|
+
if (!fileSymbols) return [];
|
|
589
|
+
|
|
590
|
+
// Find the function body boundaries: from entry.line to next symbol's line in same file
|
|
591
|
+
const sortedSyms = fileSymbols.slice().sort((a, b) => a.line - b.line);
|
|
592
|
+
let bodyEnd = Infinity;
|
|
593
|
+
for (const sym of sortedSyms) {
|
|
594
|
+
if (sym.line > entry.line && sym !== entry) {
|
|
595
|
+
bodyEnd = sym.line - 1;
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Read the function body from disk
|
|
601
|
+
let bodyText;
|
|
602
|
+
try {
|
|
603
|
+
const absPath = path.join(projectDir, entry.file);
|
|
604
|
+
const content = fs.readFileSync(absPath, 'utf8');
|
|
605
|
+
const lines = content.split('\n');
|
|
606
|
+
const startLine = entry.line; // 1-indexed; skip the def line itself
|
|
607
|
+
const endLine = Math.min(bodyEnd, lines.length);
|
|
608
|
+
bodyText = lines.slice(startLine, endLine).join(' ');
|
|
609
|
+
} catch {
|
|
610
|
+
return [];
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (!bodyText) return [];
|
|
614
|
+
|
|
615
|
+
// Tokenize body into words and intersect with known symbols
|
|
616
|
+
const words = new Set(bodyText.match(/\b[a-zA-Z_]\w{2,}\b/g) || []);
|
|
617
|
+
const callees = [];
|
|
618
|
+
const seen = new Set();
|
|
619
|
+
|
|
620
|
+
for (const word of words) {
|
|
621
|
+
if (word === entry.name) continue; // skip self-references
|
|
622
|
+
if (seen.has(word)) continue;
|
|
623
|
+
|
|
624
|
+
const candidates = symbolsByName.get(word);
|
|
625
|
+
if (!candidates) continue;
|
|
626
|
+
|
|
627
|
+
// Only include callable kinds
|
|
628
|
+
const callable = candidates.find(c => CALLABLE_KINDS.has(c.kind));
|
|
629
|
+
if (callable) {
|
|
630
|
+
seen.add(word);
|
|
631
|
+
callees.push({ name: callable.name, kind: callable.kind, file: callable.file, line: callable.line });
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return callees.slice(0, 10);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
function buildRefEntry(name, dir) {
|
|
639
|
+
const refs = getReferences(name, dir);
|
|
640
|
+
|
|
641
|
+
// Summarize references by file
|
|
642
|
+
const byFileMap = new Map();
|
|
643
|
+
for (const ref of refs) {
|
|
644
|
+
if (!byFileMap.has(ref.file)) byFileMap.set(ref.file, []);
|
|
645
|
+
byFileMap.get(ref.file).push(ref.line);
|
|
646
|
+
}
|
|
647
|
+
const byFile = Array.from(byFileMap.entries())
|
|
648
|
+
.map(([file, lines]) => ({ file, lines }))
|
|
649
|
+
.sort((a, b) => b.lines.length - a.lines.length);
|
|
650
|
+
|
|
651
|
+
// Track reverse mapping for cache invalidation
|
|
652
|
+
for (const ref of refs) {
|
|
653
|
+
if (!fileToRefNames.has(ref.file)) fileToRefNames.set(ref.file, new Set());
|
|
654
|
+
fileToRefNames.get(ref.file).add(name);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Find callers from reference locations
|
|
658
|
+
const callers = getCallersFromRefs(refs);
|
|
659
|
+
|
|
660
|
+
// Find callees from function body
|
|
661
|
+
const entries = symbolsByName.get(name) || [];
|
|
662
|
+
const defEntry = entries.find(e => CALLABLE_KINDS.has(e.kind)) || entries[0];
|
|
663
|
+
const callees = defEntry ? getCalleesFromBody(defEntry) : [];
|
|
664
|
+
|
|
665
|
+
const cacheEntry = {
|
|
666
|
+
refs: {
|
|
667
|
+
count: refs.length,
|
|
668
|
+
byFile: byFile.slice(0, 5),
|
|
669
|
+
truncated: byFile.length > 5,
|
|
670
|
+
},
|
|
671
|
+
callers: callers.slice(0, 5),
|
|
672
|
+
callees: callees.slice(0, 5),
|
|
673
|
+
builtAt: Date.now(),
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
referenceCache.set(name, cacheEntry);
|
|
677
|
+
return cacheEntry;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function buildCacheAsync(dir, logFn) {
|
|
681
|
+
const log = logFn || (() => {});
|
|
682
|
+
if (cacheBuilding) return;
|
|
683
|
+
|
|
684
|
+
referenceCache.clear();
|
|
685
|
+
fileToRefNames.clear();
|
|
686
|
+
cacheBuilding = true;
|
|
687
|
+
|
|
688
|
+
// Queue all callable symbols for background cache build
|
|
689
|
+
cacheQueue = [];
|
|
690
|
+
for (const [name, entries] of symbolsByName) {
|
|
691
|
+
if (entries.some(e => CALLABLE_KINDS.has(e.kind))) {
|
|
692
|
+
cacheQueue.push(name);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
const total = cacheQueue.length;
|
|
697
|
+
log(`Building reference cache for ${total} symbols...`);
|
|
698
|
+
|
|
699
|
+
function processBatch() {
|
|
700
|
+
const batchSize = 10;
|
|
701
|
+
let processed = 0;
|
|
702
|
+
while (processed < batchSize && cacheQueue.length > 0) {
|
|
703
|
+
const name = cacheQueue.shift();
|
|
704
|
+
try {
|
|
705
|
+
buildRefEntry(name, dir);
|
|
706
|
+
} catch {
|
|
707
|
+
// skip failures
|
|
708
|
+
}
|
|
709
|
+
processed++;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if (cacheQueue.length > 0) {
|
|
713
|
+
setImmediate(processBatch);
|
|
714
|
+
} else {
|
|
715
|
+
cacheBuilding = false;
|
|
716
|
+
log(`Reference cache built: ${referenceCache.size} entries`);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
setImmediate(processBatch);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function invalidateCacheForFile(relPath, dir) {
|
|
724
|
+
// Invalidate symbols defined in this file
|
|
725
|
+
const fileSymbols = symbolsByFile.get(relPath) || [];
|
|
726
|
+
const toRebuild = new Set();
|
|
727
|
+
for (const sym of fileSymbols) {
|
|
728
|
+
if (referenceCache.has(sym.name)) {
|
|
729
|
+
referenceCache.delete(sym.name);
|
|
730
|
+
toRebuild.add(sym.name);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// Invalidate symbols that had references in this file
|
|
735
|
+
const refNames = fileToRefNames.get(relPath);
|
|
736
|
+
if (refNames) {
|
|
737
|
+
for (const name of refNames) {
|
|
738
|
+
if (referenceCache.has(name)) {
|
|
739
|
+
referenceCache.delete(name);
|
|
740
|
+
toRebuild.add(name);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
fileToRefNames.delete(relPath);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// Queue invalidated symbols for background rebuild
|
|
747
|
+
if (toRebuild.size > 0 && dir) {
|
|
748
|
+
for (const name of toRebuild) {
|
|
749
|
+
cacheQueue.push(name);
|
|
750
|
+
}
|
|
751
|
+
if (!cacheBuilding) {
|
|
752
|
+
cacheBuilding = true;
|
|
753
|
+
setImmediate(function rebuildBatch() {
|
|
754
|
+
let processed = 0;
|
|
755
|
+
while (processed < 10 && cacheQueue.length > 0) {
|
|
756
|
+
const name = cacheQueue.shift();
|
|
757
|
+
try { buildRefEntry(name, dir); } catch { /* skip */ }
|
|
758
|
+
processed++;
|
|
759
|
+
}
|
|
760
|
+
if (cacheQueue.length > 0) {
|
|
761
|
+
setImmediate(rebuildBatch);
|
|
762
|
+
} else {
|
|
763
|
+
cacheBuilding = false;
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
function getHoverEnriched(name, contextFile, line) {
|
|
771
|
+
const info = getHoverInfo(name, contextFile, line);
|
|
772
|
+
if (!info) return null;
|
|
773
|
+
|
|
774
|
+
let cached = referenceCache.get(name);
|
|
775
|
+
|
|
776
|
+
// Lazily build cache entry on first hover
|
|
777
|
+
if (!cached && projectDir) {
|
|
778
|
+
try {
|
|
779
|
+
cached = buildRefEntry(name, projectDir);
|
|
780
|
+
} catch {
|
|
781
|
+
// skip — will just return without enrichment
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
if (cached) {
|
|
786
|
+
return {
|
|
787
|
+
...info,
|
|
788
|
+
references: cached.refs,
|
|
789
|
+
callers: cached.callers,
|
|
790
|
+
callees: cached.callees,
|
|
791
|
+
enrichAvailable: true,
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return { ...info, enrichAvailable: false };
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// ─── Exports ─────────────────────────────────────────────────────────────────
|
|
799
|
+
|
|
800
|
+
module.exports = {
|
|
801
|
+
buildIndex,
|
|
802
|
+
updateFileIndex,
|
|
803
|
+
getDefinitions,
|
|
804
|
+
getReferences,
|
|
805
|
+
getCompletions,
|
|
806
|
+
getHoverInfo,
|
|
807
|
+
getHoverEnriched,
|
|
808
|
+
buildCacheAsync,
|
|
809
|
+
getStatus,
|
|
810
|
+
startWatcher,
|
|
811
|
+
stopWatcher,
|
|
812
|
+
detectCtags,
|
|
813
|
+
};
|