@r1z4x/tezgah 1.9.2 → 1.11.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/CHANGELOG.md +83 -1
- package/MANIFEST +382 -144
- package/README.de.md +1 -1
- package/README.es.md +1 -1
- package/README.fr.md +1 -1
- package/README.md +1 -1
- package/README.tr.md +1 -1
- package/bin/codegen +5 -2
- package/bin/tezgah-design +288 -1
- package/bin/tezgah-docs +1 -1
- package/bin/tezgah-doctor +39 -2
- package/bin/tezgah-import-ai-research +26 -12
- package/bin/tezgah-ocr-review +296 -0
- package/bin/tezgah-research +216 -40
- package/bin/tezgah-review-quote +185 -0
- package/bin/tezgah-setup +136 -33
- package/bin/tezgah-skill +1 -1
- package/bin/tezgah-status +201 -3
- package/bin/tezgah-task +203 -3
- package/commands/adhd.md +2 -2
- package/commands/ponytail.md +4 -4
- package/docs/architecture.md +2 -2
- package/docs/citations-baseline.json +2 -2
- package/docs/clarity-baseline.json +2 -2
- package/docs/contract.md +87 -42
- package/docs/environment.md +2 -0
- package/docs/evidence.md +28 -9
- package/docs/feature-audit.md +2 -2
- package/docs/gate.md +54 -31
- package/docs/glossary.md +5 -2
- package/docs/hosts.md +17 -3
- package/docs/index.json +34 -8
- package/docs/judge.md +4 -2
- package/docs/layers.md +3 -3
- package/docs/models.md +31 -9
- package/docs/operations.md +126 -1
- package/docs/research.md +786 -5
- package/docs/skills.md +137 -13
- package/docs/status-line.md +115 -1
- package/hooks/hooks.json +1 -1
- package/hooks/lang/en.json +10 -0
- package/hooks/lang/tr.json +11 -1
- package/hooks/tezgah_agents.py +38 -22
- package/hooks/tezgah_apps.py +18 -0
- package/hooks/tezgah_components.py +4 -0
- package/hooks/tezgah_context.py +189 -50
- package/hooks/tezgah_extension.py +337 -0
- package/hooks/tezgah_gate.py +188 -56
- package/hooks/tezgah_integrity.py +652 -105
- package/hooks/tezgah_judge.py +6 -4
- package/hooks/tezgah_models.py +59 -19
- package/hooks/tezgah_orca.py +1 -1
- package/hooks/tezgah_paths.py +102 -6
- package/hooks/tezgah_policy.py +94 -45
- package/hooks/tezgah_rank.py +9 -6
- package/hooks/tezgah_replay.py +4 -4
- package/hooks/tezgah_research.py +1260 -65
- package/hooks/tezgah_research_capture.py +1544 -0
- package/hooks/tezgah_research_evidence.py +842 -0
- package/hooks/tezgah_research_stats.py +258 -0
- package/hooks/tezgah_skill_pick.py +408 -106
- package/hooks/tezgah_stopspec.py +8 -1
- package/hooks/tezgah_task.py +12 -4
- package/hooks/tezgah_taste_ledger.py +1 -1
- package/hosts/cursor/hook.py +29 -2
- package/hosts/opencode/plugins/tezgah.js +307 -46
- package/hosts/opencode/tui/cli/tui.tsx +100 -0
- package/hosts/opencode/tui/tezgah-tui.tsx +2 -1
- package/output-styles/tezgah.md +10 -10
- package/package.json +1 -1
- package/skills/ai-research/SKILL.md +21 -14
- package/skills/ai-research/SOURCE +7 -5
- package/skills/ai-research/index/1-frame.md +6 -6
- package/skills/ai-research/index/2-data.md +9 -9
- package/skills/ai-research/index/3-train.md +36 -36
- package/skills/ai-research/index/4-measure.md +13 -13
- package/skills/ai-research/index/5-run.md +11 -11
- package/skills/ai-research/index/6-write.md +23 -23
- package/skills/ai-research/library.json +104 -104
- package/skills/analyze-app/SKILL.md +17 -12
- package/skills/design-contract/SKILL.md +42 -7
- package/skills/design-contract/data-views.md +2 -2
- package/skills/design-library/EVALS.md +1 -1
- package/skills/design-library/INDEX.md +39 -39
- package/skills/design-library/SKILL.md +19 -13
- package/skills/design-library/SOURCE +45 -43
- package/skills/feature-audit/SKILL.md +20 -14
- package/skills/hallmark/LICENSE +21 -0
- package/skills/hallmark/SKILL.md +154 -0
- package/skills/hallmark/SOURCE +207 -0
- package/skills/hallmark/agents/openai.yaml +13 -0
- package/skills/hallmark/references/anatomy.md +71 -0
- package/skills/hallmark/references/brand-truth.md +40 -0
- package/skills/hallmark/references/comp.md +104 -0
- package/skills/hallmark/references/craft.md +116 -0
- package/skills/hallmark/references/dark-mode.md +49 -0
- package/skills/hallmark/references/data-viz.md +48 -0
- package/skills/hallmark/references/design-md.md +53 -0
- package/skills/hallmark/references/direction.md +52 -0
- package/skills/hallmark/references/export-formats.md +80 -0
- package/skills/hallmark/references/flow.md +131 -0
- package/skills/hallmark/references/fonts.md +58 -0
- package/skills/hallmark/references/gates.md +243 -0
- package/skills/hallmark/references/genres/atmospheric.md +24 -0
- package/skills/hallmark/references/genres/editorial.md +24 -0
- package/skills/hallmark/references/genres/modern-minimal.md +24 -0
- package/skills/hallmark/references/genres/playful.md +24 -0
- package/skills/hallmark/references/imagery.md +99 -0
- package/skills/hallmark/references/interaction-and-states.md +89 -0
- package/skills/hallmark/references/layout.md +104 -0
- package/skills/hallmark/references/macrostructures/01-bento-grid.md +21 -0
- package/skills/hallmark/references/macrostructures/02-long-document.md +35 -0
- package/skills/hallmark/references/macrostructures/03-marquee-hero.md +21 -0
- package/skills/hallmark/references/macrostructures/04-stat-led.md +21 -0
- package/skills/hallmark/references/macrostructures/05-workbench.md +21 -0
- package/skills/hallmark/references/macrostructures/06-conversational-faq.md +28 -0
- package/skills/hallmark/references/macrostructures/07-manifesto.md +28 -0
- package/skills/hallmark/references/macrostructures/08-photographic.md +21 -0
- package/skills/hallmark/references/macrostructures/09-quote-led.md +21 -0
- package/skills/hallmark/references/macrostructures/10-specimen.md +21 -0
- package/skills/hallmark/references/macrostructures/11-catalogue.md +21 -0
- package/skills/hallmark/references/macrostructures/12-letter.md +21 -0
- package/skills/hallmark/references/macrostructures/13-index-first.md +21 -0
- package/skills/hallmark/references/macrostructures/14-narrative-workflow.md +21 -0
- package/skills/hallmark/references/macrostructures/15-split-studio.md +21 -0
- package/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -0
- package/skills/hallmark/references/macrostructures/17-type-specimen.md +19 -0
- package/skills/hallmark/references/macrostructures/18-portfolio-grid.md +21 -0
- package/skills/hallmark/references/macrostructures/19-map-diagram.md +21 -0
- package/skills/hallmark/references/macrostructures/20-ecosystem-index.md +19 -0
- package/skills/hallmark/references/macrostructures/21-component-playground.md +21 -0
- package/skills/hallmark/references/macrostructures.md +119 -0
- package/skills/hallmark/references/microinteractions.md +80 -0
- package/skills/hallmark/references/patterns.md +202 -0
- package/skills/hallmark/references/redesign.md +88 -0
- package/skills/hallmark/references/responsive.md +46 -0
- package/skills/hallmark/references/review-finish.md +19 -0
- package/skills/hallmark/references/review-hero.md +20 -0
- package/skills/hallmark/references/scroll-choreography.md +110 -0
- package/skills/hallmark/references/texture.md +90 -0
- package/skills/hallmark/references/themes/README.md +58 -0
- package/skills/hallmark/references/themes/almanac.jpg +0 -0
- package/skills/hallmark/references/themes/almanac.md +103 -0
- package/skills/hallmark/references/themes/arcade.jpg +0 -0
- package/skills/hallmark/references/themes/arcade.md +102 -0
- package/skills/hallmark/references/themes/atelier.jpg +0 -0
- package/skills/hallmark/references/themes/atelier.md +98 -0
- package/skills/hallmark/references/themes/bloom.jpg +0 -0
- package/skills/hallmark/references/themes/bloom.md +102 -0
- package/skills/hallmark/references/themes/blueprint.jpg +0 -0
- package/skills/hallmark/references/themes/blueprint.md +103 -0
- package/skills/hallmark/references/themes/broadside.jpg +0 -0
- package/skills/hallmark/references/themes/broadside.md +108 -0
- package/skills/hallmark/references/themes/brutal.jpg +0 -0
- package/skills/hallmark/references/themes/brutal.md +95 -0
- package/skills/hallmark/references/themes/carnival.jpg +0 -0
- package/skills/hallmark/references/themes/carnival.md +104 -0
- package/skills/hallmark/references/themes/cobalt.jpg +0 -0
- package/skills/hallmark/references/themes/cobalt.md +101 -0
- package/skills/hallmark/references/themes/console.jpg +0 -0
- package/skills/hallmark/references/themes/console.md +99 -0
- package/skills/hallmark/references/themes/coral.jpg +0 -0
- package/skills/hallmark/references/themes/coral.md +102 -0
- package/skills/hallmark/references/themes/darkroom.jpg +0 -0
- package/skills/hallmark/references/themes/darkroom.md +99 -0
- package/skills/hallmark/references/themes/dose.jpg +0 -0
- package/skills/hallmark/references/themes/dose.md +98 -0
- package/skills/hallmark/references/themes/dusk.jpg +0 -0
- package/skills/hallmark/references/themes/dusk.md +105 -0
- package/skills/hallmark/references/themes/editorial.jpg +0 -0
- package/skills/hallmark/references/themes/editorial.md +97 -0
- package/skills/hallmark/references/themes/formwork.jpg +0 -0
- package/skills/hallmark/references/themes/formwork.md +107 -0
- package/skills/hallmark/references/themes/furrow.jpg +0 -0
- package/skills/hallmark/references/themes/furrow.md +98 -0
- package/skills/hallmark/references/themes/garden.jpg +0 -0
- package/skills/hallmark/references/themes/garden.md +97 -0
- package/skills/hallmark/references/themes/grid.jpg +0 -0
- package/skills/hallmark/references/themes/grid.md +101 -0
- package/skills/hallmark/references/themes/halftone.jpg +0 -0
- package/skills/hallmark/references/themes/halftone.md +106 -0
- package/skills/hallmark/references/themes/hedgerow.jpg +0 -0
- package/skills/hallmark/references/themes/hedgerow.md +104 -0
- package/skills/hallmark/references/themes/hum.jpg +0 -0
- package/skills/hallmark/references/themes/hum.md +99 -0
- package/skills/hallmark/references/themes/index.json +2191 -0
- package/skills/hallmark/references/themes/ink.jpg +0 -0
- package/skills/hallmark/references/themes/ink.md +106 -0
- package/skills/hallmark/references/themes/kiln.jpg +0 -0
- package/skills/hallmark/references/themes/kiln.md +108 -0
- package/skills/hallmark/references/themes/loom.jpg +0 -0
- package/skills/hallmark/references/themes/loom.md +106 -0
- package/skills/hallmark/references/themes/lumen.jpg +0 -0
- package/skills/hallmark/references/themes/lumen.md +103 -0
- package/skills/hallmark/references/themes/manifesto.jpg +0 -0
- package/skills/hallmark/references/themes/manifesto.md +101 -0
- package/skills/hallmark/references/themes/midnight.jpg +0 -0
- package/skills/hallmark/references/themes/midnight.md +97 -0
- package/skills/hallmark/references/themes/newsprint.jpg +0 -0
- package/skills/hallmark/references/themes/newsprint.md +102 -0
- package/skills/hallmark/references/themes/overprint.jpg +0 -0
- package/skills/hallmark/references/themes/overprint.md +101 -0
- package/skills/hallmark/references/themes/pasteup.jpg +0 -0
- package/skills/hallmark/references/themes/pasteup.md +100 -0
- package/skills/hallmark/references/themes/piste.jpg +0 -0
- package/skills/hallmark/references/themes/piste.md +99 -0
- package/skills/hallmark/references/themes/ribbon.jpg +0 -0
- package/skills/hallmark/references/themes/ribbon.md +106 -0
- package/skills/hallmark/references/themes/rim.jpg +0 -0
- package/skills/hallmark/references/themes/rim.md +96 -0
- package/skills/hallmark/references/themes/riso.jpg +0 -0
- package/skills/hallmark/references/themes/riso.md +98 -0
- package/skills/hallmark/references/themes/solstice.jpg +0 -0
- package/skills/hallmark/references/themes/solstice.md +104 -0
- package/skills/hallmark/references/themes/specimen.jpg +0 -0
- package/skills/hallmark/references/themes/specimen.md +100 -0
- package/skills/hallmark/references/themes/spore.jpg +0 -0
- package/skills/hallmark/references/themes/spore.md +104 -0
- package/skills/hallmark/references/themes/sport.jpg +0 -0
- package/skills/hallmark/references/themes/sport.md +101 -0
- package/skills/hallmark/references/themes/squeeze.jpg +0 -0
- package/skills/hallmark/references/themes/squeeze.md +99 -0
- package/skills/hallmark/references/themes/sticker.jpg +0 -0
- package/skills/hallmark/references/themes/sticker.md +106 -0
- package/skills/hallmark/references/themes/studio.jpg +0 -0
- package/skills/hallmark/references/themes/studio.md +99 -0
- package/skills/hallmark/references/themes/terminal.jpg +0 -0
- package/skills/hallmark/references/themes/terminal.md +96 -0
- package/skills/hallmark/references/themes/terrazzo.jpg +0 -0
- package/skills/hallmark/references/themes/terrazzo.md +106 -0
- package/skills/hallmark/references/themes/ultraviolet.jpg +0 -0
- package/skills/hallmark/references/themes/ultraviolet.md +106 -0
- package/skills/hallmark/references/themes/vellum.jpg +0 -0
- package/skills/hallmark/references/themes/vellum.md +105 -0
- package/skills/hallmark/references/themes/wayfind.jpg +0 -0
- package/skills/hallmark/references/themes/wayfind.md +105 -0
- package/skills/hallmark/references/themes/werkstatt.jpg +0 -0
- package/skills/hallmark/references/themes/werkstatt.md +105 -0
- package/skills/hallmark/scripts/capture.mjs +125 -0
- package/skills/hallmark/scripts/fixtures/exemplars/atmospheric.html +324 -0
- package/skills/hallmark/scripts/fixtures/exemplars/editorial.html +363 -0
- package/skills/hallmark/scripts/fixtures/exemplars/modern-minimal.html +527 -0
- package/skills/hallmark/scripts/fixtures/exemplars/playful.html +353 -0
- package/skills/hallmark/scripts/fixtures/eyebrow-fail/index.html +118 -0
- package/skills/hallmark/scripts/fixtures/eyebrow-pass/index.html +137 -0
- package/skills/hallmark/scripts/fixtures/kept/after.html +27 -0
- package/skills/hallmark/scripts/fixtures/kept/before.html +26 -0
- package/skills/hallmark/scripts/fixtures/slopped.html +145 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/Feature.vue +14 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/Hero.tsx +33 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/index.html +74 -0
- package/skills/hallmark/scripts/fixtures/tailwind-fail/style.css +6 -0
- package/skills/hallmark/scripts/fixtures/tailwind-pass/Hero.tsx +33 -0
- package/skills/hallmark/scripts/fixtures/tailwind-pass/index.html +57 -0
- package/skills/hallmark/scripts/fixtures/tailwind-pass/style.css +15 -0
- package/skills/hallmark/scripts/fixtures/waiver/index.html +54 -0
- package/skills/hallmark/scripts/imagegen.mjs +85 -0
- package/skills/hallmark/scripts/install-hook.mjs +70 -0
- package/skills/hallmark/scripts/install.mjs +141 -0
- package/skills/hallmark/scripts/lint-hook.mjs +49 -0
- package/skills/hallmark/scripts/photos.json +1 -0
- package/skills/hallmark/scripts/picture.mjs +71 -0
- package/skills/hallmark/scripts/refcheck.mjs +352 -0
- package/skills/hallmark/scripts/sloplint-render.mjs +1252 -0
- package/skills/hallmark/scripts/sloplint.mjs +4422 -0
- package/skills/hallmark/scripts/theme.mjs +650 -0
- package/skills/harness/SKILL.md +15 -8
- package/skills/i-have-adhd/SKILL.md +22 -11
- package/skills/no-ai-slop/SKILL.md +15 -1
- package/skills/plan-add/SKILL.md +33 -26
- package/skills/plan-status/SKILL.md +13 -7
- package/skills/plan-sync/SKILL.md +18 -12
- package/skills/pm-frameworks/SKILL.md +19 -10
- package/skills/pm-frameworks/SOURCE +7 -5
- package/skills/ponytail/SKILL.md +19 -14
- package/skills/product-analysis/SKILL.md +22 -18
- package/skills/product-flow/SKILL.md +14 -9
- package/skills/research/SKILL.md +75 -39
- package/skills/rl-env/SKILL.md +25 -13
- package/skills/rl-env/SOURCE +8 -6
- package/skills/tezgah-contract/SKILL.md +47 -42
- package/bin/tezgah-skill.py +0 -59
- /package/skills/ai-research/0-autoresearch-skill/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/litgpt/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/mamba/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/nanogpt/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/rwkv/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/01-model-architecture/torchtitan/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/02-tokenization/huggingface-tokenizers/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/02-tokenization/sentencepiece/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/axolotl/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/llama-factory/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/peft/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/03-fine-tuning/unsloth/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/nnsight/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/pyvene/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/saelens/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/04-mechanistic-interpretability/transformer-lens/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/05-data-processing/nemo-curator/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/05-data-processing/ray-data/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/grpo-rl-training/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/miles/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/openrlhf/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/simpo/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/slime/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/torchforge/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/trl-fine-tuning/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/06-post-training/verl/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/constitutional-ai/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/llamaguard/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/nemo-guardrails/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/07-safety-alignment/prompt-guard/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/accelerate/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/deepspeed/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/megatron-core/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/pytorch-fsdp2/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/pytorch-lightning/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/08-distributed-training/ray-train/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/09-infrastructure/lambda-labs/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/09-infrastructure/modal/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/09-infrastructure/skypilot/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/awq/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/bitsandbytes/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/flash-attention/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/gguf/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/gptq/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/hqq/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/10-optimization/ml-training-recipes/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/11-evaluation/bigcode-evaluation-harness/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/11-evaluation/lm-evaluation-harness/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/11-evaluation/nemo-evaluator/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/llama-cpp/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/sglang/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/tensorrt-llm/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/12-inference-serving/vllm/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/mlflow/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/swanlab/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/tensorboard/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/13-mlops/weights-and-biases/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/a-evolve/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/autogpt/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/crewai/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/langchain/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/14-agents/llamaindex/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/chroma/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/faiss/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/pinecone/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/qdrant/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/15-rag/sentence-transformers/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/dspy/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/guidance/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/instructor/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/16-prompt-engineering/outlines/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/17-observability/langsmith/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/17-observability/phoenix/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/audiocraft/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/blip-2/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/clip/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/cosmos-policy/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/llava/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/openpi/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/openvla-oft/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/segment-anything/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/stable-diffusion/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/18-multimodal/whisper/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/knowledge-distillation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/long-context/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/model-merging/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/model-pruning/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/moe-training/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/19-emerging-techniques/speculative-decoding/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/academic-plotting/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/ml-paper-writing/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/presenting-conference-talks/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/20-ml-paper-writing/systems-paper-writing/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/21-research-ideation/brainstorming-research-ideas/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/21-research-ideation/creative-thinking-for-research/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/22-agent-native-research-artifact/compiler/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/22-agent-native-research-artifact/research-manager/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/ai-research/22-agent-native-research-artifact/rigor-reviewer/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/colour-independence/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/flexible-typography/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/information-density/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/preference-audit/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/responsive-accessibility/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/responsive-review/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/simplified-views/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/specify/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/adaptive-interfaces/skills/user-preference-respect/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/adaptive-personalisation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/assess-load/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/cognitive-load-assessment/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/contextual-help-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/error-prevention-recovery/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/focus-attention-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/memory-load-reduction/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/plain-language-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/review/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/simplify/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/cognitive-accessibility/skills/wayfinding-navigation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/design-research/skills/behavioural-analytics/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/design-research/skills/qual-quant-triangulation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/audit/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/design-flow/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/feedback-and-status/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/gesture-alternatives/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/keyboard-navigation/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/keyboard-review/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/motion-sensitivity/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/multi-modal-input/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/touch-target-design/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/inclusive-interaction/skills/voice-interaction/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-affordance/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-brand-consistency/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-color/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-composition/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-information-density/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-typography/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/design-library/visual-critique/skills/critique-visual-hierarchy/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/pm-frameworks/intended-vs-implemented/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/pm-frameworks/opportunity-solution-tree/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-nemo-gym-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-openenv-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-ors-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/generate-verifiers-env/{SKILL.md → ENTRY.md} +0 -0
- /package/skills/rl-env/rl-env-from-description/{SKILL.md → ENTRY.md} +0 -0
package/bin/tezgah-research
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
"""tezgah-research - the research workspace CLI.
|
|
3
3
|
|
|
4
4
|
tezgah-research init <slug> --ask "<the user's words>" [--question "..."]
|
|
5
|
-
[--method qualitative|measured|exploratory] [--
|
|
6
|
-
[--out "<left alone>"]... [--allow-open "<why>"]
|
|
5
|
+
[--method qualitative|measured|exploratory] [--class R1..R12]
|
|
6
|
+
[--in "<covered>"]... [--out "<left alone>"]... [--allow-open "<why>"]
|
|
7
|
+
[--supersedes <slug>]
|
|
7
8
|
[--arena "<problem>" --budget "<budget>" [--evaluator <path> --metric "<m>"]]
|
|
8
9
|
scaffold a line
|
|
9
10
|
tezgah-research commit <slug> "<message>" commit the line in .tezgah's own repo
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
(the project's, when it tracks .tezgah)
|
|
12
|
+
tezgah-research check [<slug>] [--json] [--strict] [--orx] [--online] [--all-lines]
|
|
13
|
+
[-- <slug>] the discipline checks
|
|
12
14
|
tezgah-research status one line per research line
|
|
13
15
|
tezgah-research --all every checkout's lines (git worktrees)
|
|
14
16
|
tezgah-research claim <slug> record one claim from stdin
|
|
@@ -16,7 +18,9 @@
|
|
|
16
18
|
tezgah-research components [--json] what predicts what, per component
|
|
17
19
|
tezgah-research migrate <slug> [--dry-run] derive fields the rules require
|
|
18
20
|
tezgah-research source <slug> <hypothesis> --run <orxRunId> [--command "<cmd>"]
|
|
21
|
+
[--instrument <name>] [--arm <a>] [--item <i>] [--value <field>=<number>]...
|
|
19
22
|
[--scope real|fixture|derived] [--fixture "<what was generated>"]
|
|
23
|
+
[--ack "<the user's words>"]
|
|
20
24
|
tezgah-research compare <slug> <decision> record one variants x criteria cell from stdin
|
|
21
25
|
tezgah-research verdict <slug> <id> met|not-met|unanswerable --evidence "<ref>"
|
|
22
26
|
record one success criterion's verdict
|
|
@@ -37,6 +41,23 @@
|
|
|
37
41
|
tezgah-research dedup <slug> [--threshold <(0,1]>] [--json]
|
|
38
42
|
cluster the proposed ideas, write nothing
|
|
39
43
|
tezgah-research yield [--json] [--all-lines] how far ideas got, per operator and family
|
|
44
|
+
tezgah-research cite <slug> query four registries for each formal INDEX id
|
|
45
|
+
tezgah-research fetch <slug> <note> [--file <path> --ack "<the user's words>" | --orx]
|
|
46
|
+
capture a note's source text and its quotes
|
|
47
|
+
tezgah-research search <slug> --tag primary|snowball|counter|known [--item "<scope.in item>"]
|
|
48
|
+
-- <connector> <args...> capture one search on an allowlisted connector
|
|
49
|
+
tezgah-research instrument add <slug> <name> --kind measure|verdict --rung R1|R2|R3|R4
|
|
50
|
+
--construct "<text>" register an instrument
|
|
51
|
+
tezgah-research gold <slug> <instrument> --arm <a> --n N --seed S
|
|
52
|
+
draw an arm's seeded gold sample
|
|
53
|
+
tezgah-research label <slug> <instrument> --arm <a> (--human "<name>" --ack "<the user's words>"
|
|
54
|
+
| --provider openrouter --model <m>)
|
|
55
|
+
label an arm's gold sample
|
|
56
|
+
tezgah-research switch <slug> <instrument> (--to R1|R2|R3|R4|<method> | --narrow "<what the
|
|
57
|
+
claims now say>") --reason "<why>"
|
|
58
|
+
record a switch away from an instrument
|
|
59
|
+
tezgah-research release-check [--fixtures <dir>] score the known-truth cases, exit 1 past the bounds
|
|
60
|
+
tezgah-research calibration Brier score over resolved hypotheses
|
|
40
61
|
|
|
41
62
|
A research line lives at <repo>/.tezgah/research/<slug>/ and holds the state an
|
|
42
63
|
auditable investigation needs: the question, the decision log, the findings, the
|
|
@@ -47,7 +68,11 @@ and the review a concluded line reports. `check` exits 1 when a line breaks thos
|
|
|
47
68
|
rules, so a hook or a person can act on it. The project ignores `.tezgah/`; the
|
|
48
69
|
commits the order rule reads are made in `.tezgah`'s own private git repository,
|
|
49
70
|
which `init` creates and `commit` writes to, and a line the project itself
|
|
50
|
-
committed before the move keeps its order proof in the project's history.
|
|
71
|
+
committed before the move keeps its order proof in the project's history. A
|
|
72
|
+
folded `.tezgah` - one the project tracks, with no repository of its own - has
|
|
73
|
+
only the project's history, so `commit` commits the line there, after the
|
|
74
|
+
message passes the gate's own language and attribution readers (exit 2 and
|
|
75
|
+
the gate's refusal when it does not, nothing committed).
|
|
51
76
|
|
|
52
77
|
`check` with no slug reports the open lines in full; a line under `done/` is
|
|
53
78
|
verified by its order seal's hashes alone and named only when they fail, with
|
|
@@ -116,7 +141,8 @@ append. `board`, `dedup` and `yield` are reports: they write nothing and exit 0.
|
|
|
116
141
|
Exit codes: 0 clean, 1 problems found - a broken line for `check`, a refused
|
|
117
142
|
claim for `claim`, a refused row for `predict`, `idea`, `stage` or `match`, which
|
|
118
143
|
writes nothing and prints one reason per problem, or a new line refused for
|
|
119
|
-
`init` over unfinished ones - 2 misuse
|
|
144
|
+
`init` over unfinished ones - 2 misuse, or a folded `commit` whose message the
|
|
145
|
+
gate would refuse.
|
|
120
146
|
"""
|
|
121
147
|
import json
|
|
122
148
|
import os
|
|
@@ -158,9 +184,28 @@ def misuse(message):
|
|
|
158
184
|
return 2
|
|
159
185
|
|
|
160
186
|
|
|
187
|
+
INIT_USAGE = ('init <slug> --ask "<the user\'s words>" [--tier quick|study|program]'
|
|
188
|
+
' [--method qualitative|measured|exploratory] [--class R1..R12]'
|
|
189
|
+
' [--in "<covered>"]... [--out "<left alone>"]... [--question "..."]'
|
|
190
|
+
' [--allow-open "<reason>"] [--supersedes <slug>]'
|
|
191
|
+
' [--arena "<problem>" --budget "<budget>"'
|
|
192
|
+
' [--evaluator <path> --metric "<metric>"]]')
|
|
193
|
+
INIT_EXAMPLE = ('tezgah-research init cache-latency --ask "does the cache cut p95?" '
|
|
194
|
+
'--method measured --in "p95 of the read path" --out "write path"')
|
|
195
|
+
|
|
196
|
+
|
|
161
197
|
def cmd_init(args):
|
|
198
|
+
# R0 is refused before any other argument is read (spec 3.3): a factual or
|
|
199
|
+
# reference question gets its answer in the reply, never a line
|
|
200
|
+
if any(a == "--class" and b == "R0" for a, b in zip(args, args[1:])):
|
|
201
|
+
print("FAIL init: R0 gets no line: a factual or reference question is answered "
|
|
202
|
+
"in the reply with its evidence")
|
|
203
|
+
return 1
|
|
162
204
|
if not args:
|
|
163
205
|
return misuse("init needs a slug")
|
|
206
|
+
if args[0] in ("-h", "--help"):
|
|
207
|
+
print("usage: tezgah-research %s\nexample: %s" % (INIT_USAGE, INIT_EXAMPLE))
|
|
208
|
+
return 0
|
|
164
209
|
slug = args[0].strip().lower().replace(" ", "-")
|
|
165
210
|
if not tr.valid_slug(slug):
|
|
166
211
|
# A slug is the directory name the other commands list, so anything that
|
|
@@ -170,7 +215,7 @@ def cmd_init(args):
|
|
|
170
215
|
"and dashes" % args[0])
|
|
171
216
|
question, allow, supersedes = "", None, None
|
|
172
217
|
ask, tier, method, scope_in, scope_out = "", str(tr.DEFAULT_TIER), "", [], []
|
|
173
|
-
arena = {}
|
|
218
|
+
arena, question_class = {}, ""
|
|
174
219
|
rest = args[1:]
|
|
175
220
|
while rest:
|
|
176
221
|
flag = rest.pop(0)
|
|
@@ -184,6 +229,9 @@ def cmd_init(args):
|
|
|
184
229
|
method = rest.pop(0)
|
|
185
230
|
elif flag == "--in" and rest:
|
|
186
231
|
scope_in.append(rest.pop(0))
|
|
232
|
+
elif flag == "--class" and rest and rest[0] in tr.QUESTION_CLASSES[1:] \
|
|
233
|
+
and not question_class:
|
|
234
|
+
question_class = rest.pop(0)
|
|
187
235
|
elif flag == "--out" and rest:
|
|
188
236
|
scope_out.append(rest.pop(0))
|
|
189
237
|
elif flag == "--allow-open" and rest:
|
|
@@ -194,12 +242,7 @@ def cmd_init(args):
|
|
|
194
242
|
and flag not in arena:
|
|
195
243
|
arena[flag] = rest.pop(0)
|
|
196
244
|
else:
|
|
197
|
-
return misuse(
|
|
198
|
-
' [--method qualitative|measured|exploratory] [--in "<covered>"]...'
|
|
199
|
-
' [--out "<left alone>"]... [--question "..."]'
|
|
200
|
-
' [--allow-open "<reason>"] [--supersedes <slug>]'
|
|
201
|
-
' [--arena "<problem>" --budget "<budget>"'
|
|
202
|
-
' [--evaluator <path> --metric "<metric>"]]')
|
|
245
|
+
return misuse(INIT_USAGE)
|
|
203
246
|
if method == "exploratory":
|
|
204
247
|
# The arena is the lock an exploratory line commits before its first idea,
|
|
205
248
|
# so a line without one is a call that cannot work, not a line to repair.
|
|
@@ -222,6 +265,9 @@ def cmd_init(args):
|
|
|
222
265
|
if problems:
|
|
223
266
|
for problem in problems:
|
|
224
267
|
print("FAIL init: %s" % problem)
|
|
268
|
+
if not ask.strip():
|
|
269
|
+
print("usage: tezgah-research %s\nexample: %s" % (INIT_USAGE, INIT_EXAMPLE),
|
|
270
|
+
file=sys.stderr)
|
|
225
271
|
return 1
|
|
226
272
|
if allow is not None and not allow.strip():
|
|
227
273
|
return misuse("--allow-open needs the reason the new line is worth opening "
|
|
@@ -267,7 +313,8 @@ def cmd_init(args):
|
|
|
267
313
|
arena.get("--metric", "").strip())
|
|
268
314
|
made = tr.init(repo, slug, question=question, created=created,
|
|
269
315
|
supersedes=supersedes, ask=ask, tier=tier, method=method,
|
|
270
|
-
scope_in=scope_in, scope_out=scope_out, arena=record
|
|
316
|
+
scope_in=scope_in, scope_out=scope_out, arena=record,
|
|
317
|
+
question_class=question_class)
|
|
271
318
|
if allow is not None:
|
|
272
319
|
problem = tr.note_open(repo, slug, allow, created)
|
|
273
320
|
if problem:
|
|
@@ -278,12 +325,17 @@ def cmd_init(args):
|
|
|
278
325
|
print(" wrote %s" % path)
|
|
279
326
|
for problem in tr.scope_problems(tr.line_state(repo, slug)):
|
|
280
327
|
print(" owed: %s" % problem)
|
|
328
|
+
if question_class:
|
|
329
|
+
print("obligations: %s" % ", ".join(tr.obligations(question_class, method)))
|
|
330
|
+
print(tr.budget(slug, tr.line_dir(repo, slug), tr.line_state(repo, slug))[0])
|
|
331
|
+
for line, cid, status, sim in tr.overlaps(repo, question or ask, slug):
|
|
332
|
+
print("overlap: %s/%s %s %.2f" % (line, cid, status, sim))
|
|
281
333
|
if method == "exploratory":
|
|
282
|
-
print("\nnext: commit the arena now, before any idea -
|
|
334
|
+
print("\nnext: commit the arena now, before any idea - `~/.config/tezgah/bin/tezgah-research commit "
|
|
283
335
|
"%s \"arena\"`; an idea committed with it or before it is refused. Then "
|
|
284
|
-
"record ideas (
|
|
336
|
+
"record ideas (`~/.config/tezgah/bin/tezgah-research idea %s`, one JSON row on stdin, each "
|
|
285
337
|
"naming its operator, generator and kill result), commit them, and "
|
|
286
|
-
"follow
|
|
338
|
+
"follow `~/.config/tezgah/bin/tezgah-research board %s`: dedup, prior art, matches, pilots, a "
|
|
287
339
|
"full run, a confirmation on unseen data." % (slug, slug, slug))
|
|
288
340
|
elif method == "qualitative":
|
|
289
341
|
print("\nnext: read the primary sources for each state.json scope.in item "
|
|
@@ -293,7 +345,7 @@ def cmd_init(args):
|
|
|
293
345
|
else:
|
|
294
346
|
print("\nnext: write experiments/<hypothesis>/protocol.md - what the change "
|
|
295
347
|
"is, what it predicts, what result would falsify it, why - and COMMIT "
|
|
296
|
-
"it before the run:
|
|
348
|
+
"it before the run: `~/.config/tezgah/bin/tezgah-research commit %s \"protocol "
|
|
297
349
|
"<hypothesis>\"`. Then record the run in results.jsonl and commit it "
|
|
298
350
|
"the same way, in a later commit. The commits land in `.tezgah`'s own "
|
|
299
351
|
"git repository (the project ignores `.tezgah/`). Then analyse it in "
|
|
@@ -304,8 +356,10 @@ def cmd_init(args):
|
|
|
304
356
|
|
|
305
357
|
|
|
306
358
|
def cmd_commit(args):
|
|
307
|
-
"""Commit one line in the private `.tezgah` repository
|
|
308
|
-
rule reads. Only the line's
|
|
359
|
+
"""Commit one line in the private `.tezgah` repository, or in the project's
|
|
360
|
+
when `.tezgah` is folded - the commit the order rule reads. Only the line's
|
|
361
|
+
own paths are staged and committed: every layout location of the slug, so
|
|
362
|
+
the move `conclude` makes from `open/` to `done/` lands whole."""
|
|
309
363
|
if len(args) != 2 or not args[1].strip():
|
|
310
364
|
return misuse('commit <slug> "<message>"')
|
|
311
365
|
slug, message = args
|
|
@@ -313,21 +367,41 @@ def cmd_commit(args):
|
|
|
313
367
|
known = tr.slugs(repo)
|
|
314
368
|
if slug not in known:
|
|
315
369
|
return misuse("no such research line (have: %s)" % (", ".join(known) or "none"))
|
|
316
|
-
return commit_path(repo,
|
|
370
|
+
return commit_path(repo, [os.path.join(f, slug) for f in tr.layout_roots(repo)],
|
|
371
|
+
message)
|
|
372
|
+
|
|
317
373
|
|
|
374
|
+
def present(paths, base, ls_files):
|
|
375
|
+
"""The paths relative to `base` that exist on disk or that git still
|
|
376
|
+
tracks: a pathspec matching nothing would make `git add` fail."""
|
|
377
|
+
rels = [os.path.relpath(p, base) for p in paths]
|
|
378
|
+
tracked = ls_files(*rels).splitlines() if rels else []
|
|
379
|
+
return [r for r, p in zip(rels, paths) if os.path.lexists(p) or any(
|
|
380
|
+
t == r or t.startswith(r + "/") for t in tracked)]
|
|
318
381
|
|
|
319
|
-
|
|
320
|
-
|
|
382
|
+
|
|
383
|
+
def commit_path(repo, paths, message):
|
|
384
|
+
"""Stage and commit `paths` alone in the private repository of `repo`, or in
|
|
385
|
+
the project's own when `.tezgah` is folded - tracked by the project, with no
|
|
386
|
+
repository of its own (`tr.folded`)."""
|
|
321
387
|
ws = tp.ensure_workspace(repo)
|
|
388
|
+
if ws is None and tr.folded(repo):
|
|
389
|
+
return commit_project(repo, paths, message)
|
|
322
390
|
if ws is None:
|
|
323
391
|
print("commit refused: %s is not a git work tree (or .tezgah could not be "
|
|
324
392
|
"set up), so there is no private repository to commit into" % repo)
|
|
325
393
|
return 1
|
|
326
|
-
rel = os.path.relpath(path, ws)
|
|
327
394
|
try:
|
|
328
|
-
|
|
395
|
+
rels = present(paths, ws, lambda *r: tp.ws_git(repo, "ls-files", "--", *r).stdout)
|
|
396
|
+
done = tp.ws_git(repo, "add", "-A", "--", *rels)
|
|
397
|
+
if not done.returncode and not tp.ws_git(repo, "diff", "--cached", "--quiet",
|
|
398
|
+
"--", *rels).returncode:
|
|
399
|
+
# a writer that commits its own capture (`source`, `cite`) leaves nothing
|
|
400
|
+
# for the session's commit, which is not a failure (plan 128 K10)
|
|
401
|
+
print("nothing to commit: %s is already committed in %s" % (" ".join(rels), ws))
|
|
402
|
+
return 0
|
|
329
403
|
if not done.returncode:
|
|
330
|
-
done = tp.ws_git(repo, "commit", "-q", "-m", message, "--",
|
|
404
|
+
done = tp.ws_git(repo, "commit", "-q", "-m", message, "--", *rels)
|
|
331
405
|
except OSError as exc:
|
|
332
406
|
print("commit failed: %s" % exc)
|
|
333
407
|
return 1
|
|
@@ -335,7 +409,62 @@ def commit_path(repo, path, message):
|
|
|
335
409
|
print("commit failed: %s" % (done.stderr or done.stdout).strip())
|
|
336
410
|
return 1
|
|
337
411
|
sha = tp.ws_git(repo, "rev-parse", "HEAD").stdout.strip()
|
|
338
|
-
print("committed %s in %s at %s" % (
|
|
412
|
+
print("committed %s in %s at %s" % (" ".join(rels), ws, sha))
|
|
413
|
+
return 0
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def message_refusal(message):
|
|
417
|
+
"""The refusal the gate prints for `message` as a `git commit -m` value, or
|
|
418
|
+
None. A folded `commit` writes the project's own history, which the gate
|
|
419
|
+
never sees through this command, so the message meets the gate's own
|
|
420
|
+
readers here: the language reader `lang_reason` hands each subject to
|
|
421
|
+
(`tezgah_lang.refusal`), then the credit forms `attribution` matches
|
|
422
|
+
(`ATTRIB`), under the same switches."""
|
|
423
|
+
if tp.off("pretooluse-off"):
|
|
424
|
+
return None
|
|
425
|
+
import tezgah_gate as gate # deferred: only a folded commit pays the import
|
|
426
|
+
if gate.tezgah_lang is not None and not tp.off("lang-off"):
|
|
427
|
+
reason = gate.tezgah_lang.refusal("commit subject", message)
|
|
428
|
+
if reason:
|
|
429
|
+
return reason
|
|
430
|
+
return gate.ATTRIB_DENY if gate.ATTRIB.search(message) else None
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def commit_project(repo, paths, message):
|
|
434
|
+
"""Stage and commit `paths` alone in the project's repository: the history a
|
|
435
|
+
folded `.tezgah` lives in. Anything else the owner staged stays staged and
|
|
436
|
+
out of this commit (`commit -- <paths>`); the project's identity, signing and
|
|
437
|
+
hooks apply, since this is the project's own history. A message the gate
|
|
438
|
+
would refuse is refused first, exit 2, and nothing is staged."""
|
|
439
|
+
refused = message_refusal(message)
|
|
440
|
+
if refused:
|
|
441
|
+
print("commit refused: %s" % refused, file=sys.stderr)
|
|
442
|
+
return 2
|
|
443
|
+
git = ["git", "-C", repo]
|
|
444
|
+
try:
|
|
445
|
+
rels = present(paths, repo, lambda *r: subprocess.run(
|
|
446
|
+
git + ["ls-files", "--"] + list(r), capture_output=True, text=True).stdout)
|
|
447
|
+
done = subprocess.run(git + ["add", "-A", "--"] + rels, capture_output=True,
|
|
448
|
+
text=True)
|
|
449
|
+
if not done.returncode and not subprocess.run(
|
|
450
|
+
git + ["diff", "--cached", "--quiet", "--"] + rels).returncode:
|
|
451
|
+
print("nothing to commit: %s is already committed in the project repository %s"
|
|
452
|
+
% (" ".join(rels), repo))
|
|
453
|
+
return 0
|
|
454
|
+
if not done.returncode:
|
|
455
|
+
done = subprocess.run(git + ["commit", "-q", "-m", message, "--"] + rels,
|
|
456
|
+
capture_output=True, text=True)
|
|
457
|
+
except OSError as exc:
|
|
458
|
+
print("commit failed: %s" % exc)
|
|
459
|
+
return 1
|
|
460
|
+
if done.returncode:
|
|
461
|
+
print("commit failed: %s" % (done.stderr or done.stdout).strip())
|
|
462
|
+
return 1
|
|
463
|
+
sha = subprocess.run(git + ["rev-parse", "HEAD"], capture_output=True,
|
|
464
|
+
text=True).stdout.strip()
|
|
465
|
+
print("committed %s in the project repository %s at %s (.tezgah is tracked by "
|
|
466
|
+
"the project, so the project's history carries the line)"
|
|
467
|
+
% (" ".join(rels), repo, sha))
|
|
339
468
|
return 0
|
|
340
469
|
|
|
341
470
|
|
|
@@ -346,13 +475,14 @@ def cmd_check(args):
|
|
|
346
475
|
as_json = "--json" in flags
|
|
347
476
|
strict = "--strict" in flags
|
|
348
477
|
ask_orx = "--orx" in flags
|
|
478
|
+
online = "--online" in flags
|
|
349
479
|
all_lines = "--all-lines" in flags
|
|
350
480
|
rest = [a for a in flags
|
|
351
|
-
if a not in ("--json", "--strict", "--orx", "--all-lines")] + after
|
|
481
|
+
if a not in ("--json", "--strict", "--orx", "--online", "--all-lines")] + after
|
|
352
482
|
repo = repo_root(os.getcwd())
|
|
353
483
|
if len(rest) > 1:
|
|
354
|
-
return misuse("check [<slug>] [--json] [--strict] [--orx] [--
|
|
355
|
-
"[-- <slug>]")
|
|
484
|
+
return misuse("check [<slug>] [--json] [--strict] [--orx] [--online] "
|
|
485
|
+
"[--all-lines] [-- <slug>]")
|
|
356
486
|
known = tr.slugs(repo)
|
|
357
487
|
if rest and rest[0] not in known:
|
|
358
488
|
print("FAIL %s: no such research line (have: %s)"
|
|
@@ -362,13 +492,18 @@ def cmd_check(args):
|
|
|
362
492
|
report = {}
|
|
363
493
|
if known:
|
|
364
494
|
report = tr.check(repo, rest[0] if rest else None, strict=strict,
|
|
365
|
-
all_lines=all_lines, code=checkout_root(os.getcwd())
|
|
495
|
+
all_lines=all_lines, code=checkout_root(os.getcwd()),
|
|
496
|
+
flags={"online": online, "orx": ask_orx})
|
|
366
497
|
for slug, row in report.items():
|
|
367
498
|
for err in row["errors"]:
|
|
368
499
|
problems += 1
|
|
369
500
|
print("FAIL %s: %s" % (slug, err))
|
|
370
501
|
for warn in row["warnings"]:
|
|
371
502
|
print("warn %s: %s" % (slug, warn))
|
|
503
|
+
# rules 8's report lines (certainty, stats, effect, budget, ...): never
|
|
504
|
+
# problems, and inside the JSON row rather than before it
|
|
505
|
+
for line in [] if as_json else row.get("report", []):
|
|
506
|
+
print(line)
|
|
372
507
|
else:
|
|
373
508
|
print("no research line under %s" % tr.root(repo))
|
|
374
509
|
lines = len(report)
|
|
@@ -559,13 +694,21 @@ def cmd_migrate(args):
|
|
|
559
694
|
|
|
560
695
|
def cmd_source(args):
|
|
561
696
|
"""File one orx run's log as the receipt of an experiment."""
|
|
562
|
-
|
|
563
|
-
|
|
697
|
+
import re
|
|
698
|
+
import tezgah_research_capture as cap
|
|
699
|
+
reserved = ("source", "log", "run", "arm", "item", "instrument", "scope", "fixture",
|
|
700
|
+
"status", "command", "ack")
|
|
701
|
+
usage = ('source <slug> <hypothesis> --run <orxRunId> [--instrument <name>] [--arm <a>] '
|
|
702
|
+
'[--item <i>] [--value <field>=<number>]... [--command "<cmd>"] '
|
|
703
|
+
'[--scope real|fixture|derived] [--fixture "<what was generated>"] '
|
|
704
|
+
'[--ack "<the user\'s words>"]')
|
|
564
705
|
if len(args) < 2:
|
|
565
706
|
return misuse(usage)
|
|
566
707
|
slug, hypothesis = args[0], args[1]
|
|
567
|
-
run = command = scope = ""
|
|
708
|
+
run = command = scope = arm = item = ack = ""
|
|
709
|
+
instrument = None
|
|
568
710
|
fixture = None
|
|
711
|
+
values = []
|
|
569
712
|
rest = args[2:]
|
|
570
713
|
while rest:
|
|
571
714
|
flag = rest.pop(0)
|
|
@@ -577,6 +720,22 @@ def cmd_source(args):
|
|
|
577
720
|
scope = rest.pop(0)
|
|
578
721
|
elif flag == "--fixture" and rest:
|
|
579
722
|
fixture = rest.pop(0)
|
|
723
|
+
elif flag == "--instrument" and rest:
|
|
724
|
+
instrument = rest.pop(0)
|
|
725
|
+
elif flag == "--arm" and rest:
|
|
726
|
+
arm = rest.pop(0)
|
|
727
|
+
elif flag == "--item" and rest:
|
|
728
|
+
item = rest.pop(0)
|
|
729
|
+
elif flag == "--ack" and rest:
|
|
730
|
+
ack = rest.pop(0)
|
|
731
|
+
elif flag == "--value" and rest:
|
|
732
|
+
field, _eq, number = rest.pop(0).partition("=")
|
|
733
|
+
if field in reserved:
|
|
734
|
+
return misuse("--value %s: %s is a reserved row key" % (field, field))
|
|
735
|
+
if not re.fullmatch(r"[A-Za-z_][\w.-]*", field) or not re.fullmatch(
|
|
736
|
+
cap.VALUE_NUMBER, number):
|
|
737
|
+
return misuse("--value needs <field>=<number>, not %r" % (field + _eq + number))
|
|
738
|
+
values.append((field, number))
|
|
580
739
|
else:
|
|
581
740
|
return misuse(usage)
|
|
582
741
|
if "/" in hypothesis or "\\" in hypothesis or hypothesis.startswith("."):
|
|
@@ -588,6 +747,10 @@ def cmd_source(args):
|
|
|
588
747
|
return misuse("--scope %r is not one of %s" % (scope, ", ".join(tr.SCOPES)))
|
|
589
748
|
if fixture is not None and not fixture.strip():
|
|
590
749
|
return misuse("--fixture needs the text naming what was generated")
|
|
750
|
+
if instrument is not None and not instrument.strip():
|
|
751
|
+
return misuse("--instrument needs the instrument's name")
|
|
752
|
+
if ack and not ack.strip():
|
|
753
|
+
return misuse('--ack needs "<the user\'s words>" for a log above the bound')
|
|
591
754
|
repo = repo_root(os.getcwd())
|
|
592
755
|
known = tr.slugs(repo)
|
|
593
756
|
if slug not in known:
|
|
@@ -597,16 +760,15 @@ def cmd_source(args):
|
|
|
597
760
|
return misuse("orx is not installed, so no run log can be read; nothing "
|
|
598
761
|
"was written (TEZGAH_ORX_BIN overrides the lookup)")
|
|
599
762
|
path, problems = tr.source_run(repo, slug, hypothesis, run, orx, command, scope,
|
|
600
|
-
fixture or "")
|
|
763
|
+
fixture or "", arm, item, values, instrument or "", ack)
|
|
601
764
|
if problems:
|
|
602
765
|
for problem in problems:
|
|
603
766
|
print("FAIL %s: %s" % (slug, problem))
|
|
604
767
|
return 1
|
|
605
768
|
print("receipt %s" % path)
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
', "fixture": %s' % json.dumps(fixture) if fixture else ""))
|
|
769
|
+
rows = tr._row_objects(os.path.join(os.path.dirname(os.path.dirname(path)),
|
|
770
|
+
"results.jsonl"))
|
|
771
|
+
print("row %s" % json.dumps(rows[-1] if rows else {}))
|
|
610
772
|
if not scope:
|
|
611
773
|
print("note: the row declares no scope, so nothing says whether this run "
|
|
612
774
|
"measured the running system or an input you generated; re-file with "
|
|
@@ -1062,9 +1224,23 @@ def main(argv):
|
|
|
1062
1224
|
"board": cmd_board, "dedup": cmd_dedup, "yield": cmd_yield}
|
|
1063
1225
|
if cmd in campaign:
|
|
1064
1226
|
return campaign[cmd](rest)
|
|
1227
|
+
# rules 8's capture and evidence commands, imported only when asked for so a
|
|
1228
|
+
# missing optional module never breaks another command. Each handler takes
|
|
1229
|
+
# (repo, args), prints its own output and returns its exit code; `release-check`
|
|
1230
|
+
# and `calibration` need no line and run from any directory.
|
|
1231
|
+
import importlib
|
|
1232
|
+
for name in ("tezgah_research_capture", "tezgah_research_evidence"):
|
|
1233
|
+
try:
|
|
1234
|
+
commands = importlib.import_module(name).COMMANDS
|
|
1235
|
+
except (ImportError, AttributeError):
|
|
1236
|
+
continue
|
|
1237
|
+
if cmd in commands:
|
|
1238
|
+
return commands[cmd](repo_root(os.getcwd()), rest)
|
|
1065
1239
|
return misuse("unknown command %r (init, commit, check, status, --all, claim, predict, "
|
|
1066
1240
|
"components, migrate, source, compare, verdict, conclude, migrate-layout, "
|
|
1067
|
-
"close, seal, import, next, idea, stage, match, board, dedup, yield
|
|
1241
|
+
"close, seal, import, next, idea, stage, match, board, dedup, yield, cite, "
|
|
1242
|
+
"fetch, search, instrument, gold, label, switch, release-check, "
|
|
1243
|
+
"calibration)" % cmd)
|
|
1068
1244
|
|
|
1069
1245
|
|
|
1070
1246
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""tezgah-review-quote - place review findings on the diff by their quoted code.
|
|
3
|
+
|
|
4
|
+
tezgah-review-quote [--repo DIR] --from BASE [--to HEAD] FINDINGS_JSON
|
|
5
|
+
|
|
6
|
+
FINDINGS_JSON is a file (or `-` for stdin) holding a JSON list of objects with
|
|
7
|
+
at least `path` and `quote`. Prints that list with `status` added:
|
|
8
|
+
`located` (the quote is in its own file), `relocated` (it is nowhere in its own
|
|
9
|
+
file but exactly once in another changed file; `path` moves there) or
|
|
10
|
+
`unlocated`; a placed finding gets `start_line`/`end_line`, plus `side: "old"`
|
|
11
|
+
when the lines are pre-change. A quote found several times in its own file is
|
|
12
|
+
placed on the match covering the finding's own `start_line`, else it is
|
|
13
|
+
`unlocated` with `reason: "ambiguous: N matches"`.
|
|
14
|
+
|
|
15
|
+
A Python port of the deterministic comment positioning in
|
|
16
|
+
alibaba/open-code-review (internal/diff/resolver.go: ResolveComment,
|
|
17
|
+
RelocateAcrossFiles; Apache-2.0): each line is trimmed, one leading `+` then
|
|
18
|
+
`-` marker is stripped, blank quote lines are dropped, and the quote must match
|
|
19
|
+
consecutive lines - the hunks' new side, then their old side, then the whole
|
|
20
|
+
new file (where blank file lines are skipped too). Unlike OCR, which takes the
|
|
21
|
+
first match, every match is collected so a repeated quote is never placed on
|
|
22
|
+
the wrong copy; a cited line only chooses among the quote's matches.
|
|
23
|
+
"""
|
|
24
|
+
import argparse
|
|
25
|
+
import json
|
|
26
|
+
import subprocess
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def norm(line):
|
|
31
|
+
return line.strip().removeprefix("+").removeprefix("-").strip()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def quote_lines(text):
|
|
35
|
+
return [n for n in map(norm, text.split("\n")) if n]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def git(repo, *args):
|
|
39
|
+
return subprocess.run(["git", "-C", repo, *args], capture_output=True,
|
|
40
|
+
text=True, errors="replace")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def strip_prefix(path):
|
|
44
|
+
# ponytail: C-quoted paths (tabs, quotes in names) are not unquoted
|
|
45
|
+
if path == "/dev/null":
|
|
46
|
+
return None
|
|
47
|
+
return path[2:] if path[:2] in ("a/", "b/") else path
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def parse_diff(text):
|
|
51
|
+
"""One dict per changed file: old/new path and the hunks' two sides as
|
|
52
|
+
[(line_number, normalised_text, removed)] lists, one pair per hunk."""
|
|
53
|
+
files, cur, old_no, new_no = [], None, 0, 0
|
|
54
|
+
for line in text.split("\n"):
|
|
55
|
+
if line.startswith("diff --git "):
|
|
56
|
+
cur = {"old": None, "new": None, "hunks": []}
|
|
57
|
+
files.append(cur)
|
|
58
|
+
elif cur is None:
|
|
59
|
+
continue
|
|
60
|
+
elif line.startswith("--- ") and not cur["hunks"]:
|
|
61
|
+
cur["old"] = strip_prefix(line[4:].rstrip("\t"))
|
|
62
|
+
elif line.startswith("+++ ") and not cur["hunks"]:
|
|
63
|
+
cur["new"] = strip_prefix(line[4:].rstrip("\t"))
|
|
64
|
+
elif line.startswith("@@"):
|
|
65
|
+
spans = line.split("@@")[1].split()
|
|
66
|
+
old_no = int(spans[0][1:].split(",")[0])
|
|
67
|
+
new_no = int(spans[1][1:].split(",")[0])
|
|
68
|
+
cur["hunks"].append(([], []))
|
|
69
|
+
elif cur["hunks"] and not line.startswith("\\"):
|
|
70
|
+
new_side, old_side = cur["hunks"][-1]
|
|
71
|
+
mark, body = line[:1], norm(line[1:])
|
|
72
|
+
if mark in (" ", ""):
|
|
73
|
+
new_side.append((new_no, body, False))
|
|
74
|
+
old_side.append((old_no, body, False))
|
|
75
|
+
new_no += 1
|
|
76
|
+
old_no += 1
|
|
77
|
+
elif mark == "+":
|
|
78
|
+
new_side.append((new_no, body, False))
|
|
79
|
+
new_no += 1
|
|
80
|
+
elif mark == "-":
|
|
81
|
+
old_side.append((old_no, body, True))
|
|
82
|
+
old_no += 1
|
|
83
|
+
return files
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def matches(side, target):
|
|
87
|
+
"""Every consecutive run of `target` in `side`: (start, end, run)."""
|
|
88
|
+
n = len(target)
|
|
89
|
+
return [(side[i][0], side[i + n - 1][0], side[i:i + n])
|
|
90
|
+
for i in range(len(side) - n + 1)
|
|
91
|
+
if all(side[i + j][1] == target[j] for j in range(n))]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def resolve(f, target, content):
|
|
95
|
+
"""Every distinct (start, end, side) of `target` in one changed file: the
|
|
96
|
+
hunks' new side, their old side, then the whole new file."""
|
|
97
|
+
hits = [(s, e, "new") for hunk in f["hunks"] for s, e, _ in matches(hunk[0], target)]
|
|
98
|
+
# an old-side run of context lines only repeats a new-side one
|
|
99
|
+
hits += [(s, e, "old") for hunk in f["hunks"]
|
|
100
|
+
for s, e, run in matches(hunk[1], target) if any(p[2] for p in run)]
|
|
101
|
+
if content is not None:
|
|
102
|
+
lines = [(i, norm(t.rstrip("\r")))
|
|
103
|
+
for i, t in enumerate(content.split("\n"), 1)]
|
|
104
|
+
hits += [(s, e, "new") for s, e, _ in matches([p for p in lines if p[1]], target)]
|
|
105
|
+
return list(dict.fromkeys(hits))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def cited(finding):
|
|
109
|
+
try:
|
|
110
|
+
return int(finding.get("start_line"))
|
|
111
|
+
except (TypeError, ValueError):
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def place(finding, f, hit):
|
|
116
|
+
out = dict(finding, path=f["new"] or f["old"],
|
|
117
|
+
start_line=hit[0], end_line=hit[1])
|
|
118
|
+
out.pop("side", None)
|
|
119
|
+
if hit[2] == "old":
|
|
120
|
+
out["side"] = "old"
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def main(argv=None):
|
|
125
|
+
ap = argparse.ArgumentParser(prog="tezgah-review-quote")
|
|
126
|
+
ap.add_argument("--repo", default=".")
|
|
127
|
+
ap.add_argument("--from", dest="base", required=True)
|
|
128
|
+
ap.add_argument("--to", default="HEAD")
|
|
129
|
+
ap.add_argument("findings")
|
|
130
|
+
a = ap.parse_args(argv)
|
|
131
|
+
try:
|
|
132
|
+
src = sys.stdin if a.findings == "-" else open(a.findings, encoding="utf-8")
|
|
133
|
+
with src:
|
|
134
|
+
findings = json.load(src)
|
|
135
|
+
if not isinstance(findings, list) or not all(
|
|
136
|
+
isinstance(x, dict) and "path" in x and "quote" in x for x in findings):
|
|
137
|
+
raise ValueError("expected a JSON list of objects with path and quote")
|
|
138
|
+
except (OSError, ValueError) as e:
|
|
139
|
+
print(f"tezgah-review-quote: {a.findings}: {e}", file=sys.stderr)
|
|
140
|
+
return 2
|
|
141
|
+
diff = git(a.repo, "diff", "--no-ext-diff", "--no-textconv", "--no-color",
|
|
142
|
+
"--src-prefix=a/", "--dst-prefix=b/", "-U3", a.base, a.to)
|
|
143
|
+
if diff.returncode != 0:
|
|
144
|
+
print(f"tezgah-review-quote: git diff: {diff.stderr.strip()}", file=sys.stderr)
|
|
145
|
+
return 2
|
|
146
|
+
files, contents = parse_diff(diff.stdout), {}
|
|
147
|
+
|
|
148
|
+
def content(f):
|
|
149
|
+
if f["new"] and f["new"] not in contents:
|
|
150
|
+
r = git(a.repo, "show", f"{a.to}:{f['new']}")
|
|
151
|
+
contents[f["new"]] = r.stdout if r.returncode == 0 else None
|
|
152
|
+
return contents.get(f["new"])
|
|
153
|
+
|
|
154
|
+
out = []
|
|
155
|
+
for finding in findings:
|
|
156
|
+
target = quote_lines(str(finding["quote"] or ""))
|
|
157
|
+
own = [f for f in files if finding["path"] in (f["new"], f["old"])]
|
|
158
|
+
mine = resolve(own[0], target, content(own[0])) if target and own else []
|
|
159
|
+
line = cited(finding)
|
|
160
|
+
covering = [h for h in mine if line is not None and h[0] <= line <= h[1]]
|
|
161
|
+
# OCR's order: the new side wins over the old one, so a whitespace-only
|
|
162
|
+
# change matching on both sides is one new-side hit, not an ambiguity
|
|
163
|
+
new = [h for h in mine if h[2] == "new"]
|
|
164
|
+
pick = covering or (new if len(new) == 1 else []) or (mine if len(mine) == 1 else [])
|
|
165
|
+
if pick:
|
|
166
|
+
out.append(dict(place(finding, own[0], pick[0]), status="located"))
|
|
167
|
+
continue
|
|
168
|
+
if mine:
|
|
169
|
+
out.append(dict(finding, status="unlocated",
|
|
170
|
+
reason=f"ambiguous: {len(new) or len(mine)} matches"))
|
|
171
|
+
continue
|
|
172
|
+
hits = [] if not target else [
|
|
173
|
+
(f, h) for f in files if f not in own
|
|
174
|
+
for h in resolve(f, target, content(f))]
|
|
175
|
+
if len(hits) == 1:
|
|
176
|
+
out.append(dict(place(finding, *hits[0]), status="relocated"))
|
|
177
|
+
else:
|
|
178
|
+
out.append(dict(finding, status="unlocated"))
|
|
179
|
+
json.dump(out, sys.stdout, indent=2)
|
|
180
|
+
sys.stdout.write("\n")
|
|
181
|
+
return 0
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if __name__ == "__main__":
|
|
185
|
+
sys.exit(main())
|