@opengsd/gsd-core 1.2.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ja-JP.md +870 -0
- package/README.ko-KR.md +861 -0
- package/README.md +301 -0
- package/README.pt-BR.md +492 -0
- package/README.zh-CN.md +842 -0
- package/agents/gsd-advisor-researcher.md +127 -0
- package/agents/gsd-ai-researcher.md +133 -0
- package/agents/gsd-assumptions-analyzer.md +105 -0
- package/agents/gsd-code-fixer.md +668 -0
- package/agents/gsd-code-reviewer.md +387 -0
- package/agents/gsd-codebase-mapper.md +853 -0
- package/agents/gsd-debug-session-manager.md +314 -0
- package/agents/gsd-debugger.md +1452 -0
- package/agents/gsd-doc-classifier.md +168 -0
- package/agents/gsd-doc-synthesizer.md +204 -0
- package/agents/gsd-doc-verifier.md +217 -0
- package/agents/gsd-doc-writer.md +615 -0
- package/agents/gsd-domain-researcher.md +153 -0
- package/agents/gsd-eval-auditor.md +191 -0
- package/agents/gsd-eval-planner.md +154 -0
- package/agents/gsd-executor.md +772 -0
- package/agents/gsd-framework-selector.md +160 -0
- package/agents/gsd-integration-checker.md +470 -0
- package/agents/gsd-intel-updater.md +342 -0
- package/agents/gsd-nyquist-auditor.md +203 -0
- package/agents/gsd-pattern-mapper.md +335 -0
- package/agents/gsd-phase-researcher.md +928 -0
- package/agents/gsd-plan-checker.md +978 -0
- package/agents/gsd-planner.md +1218 -0
- package/agents/gsd-project-researcher.md +677 -0
- package/agents/gsd-research-synthesizer.md +255 -0
- package/agents/gsd-roadmapper.md +688 -0
- package/agents/gsd-security-auditor.md +155 -0
- package/agents/gsd-ui-auditor.md +495 -0
- package/agents/gsd-ui-checker.md +309 -0
- package/agents/gsd-ui-researcher.md +380 -0
- package/agents/gsd-user-profiler.md +171 -0
- package/agents/gsd-verifier.md +917 -0
- package/bin/install.js +10936 -0
- package/bin/lib/ui-safety-gate.cjs +107 -0
- package/commands/gsd/add-tests.md +42 -0
- package/commands/gsd/ai-integration-phase.md +37 -0
- package/commands/gsd/audit-fix.md +34 -0
- package/commands/gsd/audit-milestone.md +37 -0
- package/commands/gsd/audit-uat.md +24 -0
- package/commands/gsd/autonomous.md +46 -0
- package/commands/gsd/capture.md +62 -0
- package/commands/gsd/cleanup.md +24 -0
- package/commands/gsd/code-review.md +59 -0
- package/commands/gsd/complete-milestone.md +143 -0
- package/commands/gsd/config.md +56 -0
- package/commands/gsd/debug.md +52 -0
- package/commands/gsd/discuss-phase.md +76 -0
- package/commands/gsd/docs-update.md +49 -0
- package/commands/gsd/eval-review.md +33 -0
- package/commands/gsd/execute-phase.md +64 -0
- package/commands/gsd/explore.md +27 -0
- package/commands/gsd/extract-learnings.md +23 -0
- package/commands/gsd/fast.md +31 -0
- package/commands/gsd/forensics.md +57 -0
- package/commands/gsd/graphify.md +199 -0
- package/commands/gsd/health.md +31 -0
- package/commands/gsd/help.md +28 -0
- package/commands/gsd/import.md +41 -0
- package/commands/gsd/inbox.md +39 -0
- package/commands/gsd/ingest-docs.md +42 -0
- package/commands/gsd/manager.md +45 -0
- package/commands/gsd/map-codebase.md +83 -0
- package/commands/gsd/milestone-summary.md +51 -0
- package/commands/gsd/mvp-phase.md +45 -0
- package/commands/gsd/new-milestone.md +45 -0
- package/commands/gsd/new-project.md +47 -0
- package/commands/gsd/ns-context.md +23 -0
- package/commands/gsd/ns-ideate.md +24 -0
- package/commands/gsd/ns-manage.md +29 -0
- package/commands/gsd/ns-project.md +22 -0
- package/commands/gsd/ns-review.md +26 -0
- package/commands/gsd/ns-workflow.md +28 -0
- package/commands/gsd/pause-work.md +43 -0
- package/commands/gsd/phase.md +56 -0
- package/commands/gsd/plan-phase.md +62 -0
- package/commands/gsd/plan-review-convergence.md +59 -0
- package/commands/gsd/pr-branch.md +26 -0
- package/commands/gsd/profile-user.md +46 -0
- package/commands/gsd/progress.md +47 -0
- package/commands/gsd/quick.md +174 -0
- package/commands/gsd/resume-work.md +30 -0
- package/commands/gsd/review-backlog.md +63 -0
- package/commands/gsd/review.md +41 -0
- package/commands/gsd/secure-phase.md +36 -0
- package/commands/gsd/settings.md +29 -0
- package/commands/gsd/ship.md +24 -0
- package/commands/gsd/sketch.md +60 -0
- package/commands/gsd/spec-phase.md +63 -0
- package/commands/gsd/spike.md +57 -0
- package/commands/gsd/stats.md +19 -0
- package/commands/gsd/surface.md +155 -0
- package/commands/gsd/thread.md +24 -0
- package/commands/gsd/ui-phase.md +35 -0
- package/commands/gsd/ui-review.md +33 -0
- package/commands/gsd/ultraplan-phase.md +34 -0
- package/commands/gsd/undo.md +35 -0
- package/commands/gsd/update.md +48 -0
- package/commands/gsd/validate-phase.md +36 -0
- package/commands/gsd/verify-work.md +39 -0
- package/commands/gsd/workspace.md +52 -0
- package/commands/gsd/workstreams.md +70 -0
- package/get-shit-done/bin/check-latest-version.cjs +106 -0
- package/get-shit-done/bin/gsd-tools.cjs +1676 -0
- package/get-shit-done/bin/lib/active-workstream-store.cjs +302 -0
- package/get-shit-done/bin/lib/adr-parser.cjs +394 -0
- package/get-shit-done/bin/lib/agent-command-router.cjs +65 -0
- package/get-shit-done/bin/lib/artifacts.cjs +53 -0
- package/get-shit-done/bin/lib/audit.cjs +755 -0
- package/get-shit-done/bin/lib/check-command-router.cjs +333 -0
- package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +118 -0
- package/get-shit-done/bin/lib/clock.cjs +96 -0
- package/get-shit-done/bin/lib/clusters.cjs +135 -0
- package/get-shit-done/bin/lib/code-review-flags.cjs +74 -0
- package/get-shit-done/bin/lib/command-aliases.cjs +815 -0
- package/get-shit-done/bin/lib/command-arg-projection.cjs +62 -0
- package/get-shit-done/bin/lib/command-routing-hub.cjs +388 -0
- package/get-shit-done/bin/lib/commands.cjs +1188 -0
- package/get-shit-done/bin/lib/config-schema.cjs +31 -0
- package/get-shit-done/bin/lib/config.cjs +728 -0
- package/get-shit-done/bin/lib/configuration.cjs +248 -0
- package/get-shit-done/bin/lib/context-utilization.cjs +47 -0
- package/get-shit-done/bin/lib/core.cjs +2121 -0
- package/get-shit-done/bin/lib/decisions.cjs +116 -0
- package/get-shit-done/bin/lib/docs.cjs +270 -0
- package/get-shit-done/bin/lib/drift.cjs +388 -0
- package/get-shit-done/bin/lib/fallow-runner.cjs +109 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +389 -0
- package/get-shit-done/bin/lib/gap-checker.cjs +205 -0
- package/get-shit-done/bin/lib/graphify.cjs +592 -0
- package/get-shit-done/bin/lib/gsd2-import.cjs +514 -0
- package/get-shit-done/bin/lib/init-command-router.cjs +58 -0
- package/get-shit-done/bin/lib/init.cjs +2112 -0
- package/get-shit-done/bin/lib/install-profiles.cjs +603 -0
- package/get-shit-done/bin/lib/installer-migration-authoring.cjs +117 -0
- package/get-shit-done/bin/lib/installer-migration-report.cjs +354 -0
- package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +220 -0
- package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +41 -0
- package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +80 -0
- package/get-shit-done/bin/lib/installer-migrations.cjs +778 -0
- package/get-shit-done/bin/lib/intel.cjs +708 -0
- package/get-shit-done/bin/lib/learnings.cjs +421 -0
- package/get-shit-done/bin/lib/milestone.cjs +314 -0
- package/get-shit-done/bin/lib/model-catalog.cjs +212 -0
- package/get-shit-done/bin/lib/model-profiles.cjs +31 -0
- package/get-shit-done/bin/lib/observability/event.cjs +82 -0
- package/get-shit-done/bin/lib/observability/logger.cjs +174 -0
- package/get-shit-done/bin/lib/observability/redaction.cjs +50 -0
- package/get-shit-done/bin/lib/package-identity.cjs +31 -0
- package/get-shit-done/bin/lib/phase-command-router.cjs +191 -0
- package/get-shit-done/bin/lib/phase-lifecycle.cjs +80 -0
- package/get-shit-done/bin/lib/phase.cjs +1607 -0
- package/get-shit-done/bin/lib/phases-command-router.cjs +39 -0
- package/get-shit-done/bin/lib/plan-scan.cjs +97 -0
- package/get-shit-done/bin/lib/planning-workspace.cjs +238 -0
- package/get-shit-done/bin/lib/profile-output.cjs +1141 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/project-root.cjs +112 -0
- package/get-shit-done/bin/lib/prompt-budget.cjs +399 -0
- package/get-shit-done/bin/lib/review-reviewer-selection.cjs +125 -0
- package/get-shit-done/bin/lib/roadmap-command-router.cjs +28 -0
- package/get-shit-done/bin/lib/roadmap.cjs +650 -0
- package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +301 -0
- package/get-shit-done/bin/lib/runtime-homes.cjs +222 -0
- package/get-shit-done/bin/lib/runtime-name-policy.cjs +83 -0
- package/get-shit-done/bin/lib/runtime-slash.cjs +112 -0
- package/get-shit-done/bin/lib/schema-detect.cjs +165 -0
- package/get-shit-done/bin/lib/secrets.cjs +32 -0
- package/get-shit-done/bin/lib/security.cjs +600 -0
- package/get-shit-done/bin/lib/semver-compare.cjs +35 -0
- package/get-shit-done/bin/lib/shell-command-projection.cjs +500 -0
- package/get-shit-done/bin/lib/state-command-router.cjs +252 -0
- package/get-shit-done/bin/lib/state-document.cjs +263 -0
- package/get-shit-done/bin/lib/state.cjs +2038 -0
- package/get-shit-done/bin/lib/surface.cjs +470 -0
- package/get-shit-done/bin/lib/task-command-router.cjs +81 -0
- package/get-shit-done/bin/lib/template.cjs +228 -0
- package/get-shit-done/bin/lib/uat.cjs +289 -0
- package/get-shit-done/bin/lib/update-context.cjs +209 -0
- package/get-shit-done/bin/lib/validate-command-router.cjs +83 -0
- package/get-shit-done/bin/lib/validate.cjs +92 -0
- package/get-shit-done/bin/lib/verify-command-router.cjs +40 -0
- package/get-shit-done/bin/lib/verify.cjs +1511 -0
- package/get-shit-done/bin/lib/workstream-inventory-builder.cjs +74 -0
- package/get-shit-done/bin/lib/workstream-inventory.cjs +146 -0
- package/get-shit-done/bin/lib/workstream-name-policy.cjs +94 -0
- package/get-shit-done/bin/lib/workstream.cjs +389 -0
- package/get-shit-done/bin/lib/worktree-safety.cjs +985 -0
- package/get-shit-done/bin/shared/config-defaults.manifest.json +97 -0
- package/get-shit-done/bin/shared/config-schema.manifest.json +175 -0
- package/get-shit-done/bin/shared/model-catalog.json +122 -0
- package/get-shit-done/bin/shared/runtime-aliases.manifest.json +75 -0
- package/get-shit-done/bin/verify-reapply-patches.cjs +352 -0
- package/get-shit-done/contexts/dev.md +21 -0
- package/get-shit-done/contexts/research.md +22 -0
- package/get-shit-done/contexts/review.md +23 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/ai-evals.md +156 -0
- package/get-shit-done/references/ai-frameworks.md +186 -0
- package/get-shit-done/references/artifact-types.md +131 -0
- package/get-shit-done/references/autonomous-smart-discuss.md +277 -0
- package/get-shit-done/references/checkpoints.md +814 -0
- package/get-shit-done/references/common-bug-patterns.md +114 -0
- package/get-shit-done/references/context-budget.md +85 -0
- package/get-shit-done/references/continuation-format.md +253 -0
- package/get-shit-done/references/debugger-philosophy.md +76 -0
- package/get-shit-done/references/decimal-phase-calculation.md +64 -0
- package/get-shit-done/references/doc-conflict-engine.md +91 -0
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/execute-mvp-tdd.md +81 -0
- package/get-shit-done/references/executor-examples.md +110 -0
- package/get-shit-done/references/few-shot-examples/plan-checker.md +73 -0
- package/get-shit-done/references/few-shot-examples/verifier.md +109 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/gates.md +70 -0
- package/get-shit-done/references/git-integration.md +298 -0
- package/get-shit-done/references/git-planning-commit.md +40 -0
- package/get-shit-done/references/ios-scaffold.md +123 -0
- package/get-shit-done/references/mandatory-initial-read.md +2 -0
- package/get-shit-done/references/model-profile-resolution.md +38 -0
- package/get-shit-done/references/model-profiles.md +245 -0
- package/get-shit-done/references/mvp-concepts.md +49 -0
- package/get-shit-done/references/phase-argument-parsing.md +61 -0
- package/get-shit-done/references/planner-antipatterns.md +89 -0
- package/get-shit-done/references/planner-chunked.md +49 -0
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-graphify-auto-update.md +67 -0
- package/get-shit-done/references/planner-human-verify-mode.md +57 -0
- package/get-shit-done/references/planner-interface-context.md +62 -0
- package/get-shit-done/references/planner-mvp-mode.md +53 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planner-source-audit.md +73 -0
- package/get-shit-done/references/planning-config.md +471 -0
- package/get-shit-done/references/project-skills-discovery.md +19 -0
- package/get-shit-done/references/questioning.md +162 -0
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/scout-codebase.md +51 -0
- package/get-shit-done/references/skeleton-template.md +48 -0
- package/get-shit-done/references/sketch-interactivity.md +41 -0
- package/get-shit-done/references/sketch-theme-system.md +94 -0
- package/get-shit-done/references/sketch-tooling.md +45 -0
- package/get-shit-done/references/sketch-variant-patterns.md +81 -0
- package/get-shit-done/references/spidr-splitting.md +69 -0
- package/get-shit-done/references/tdd.md +330 -0
- package/get-shit-done/references/thinking-models-debug.md +44 -0
- package/get-shit-done/references/thinking-models-execution.md +50 -0
- package/get-shit-done/references/thinking-models-planning.md +62 -0
- package/get-shit-done/references/thinking-models-research.md +50 -0
- package/get-shit-done/references/thinking-models-verification.md +55 -0
- package/get-shit-done/references/thinking-partner.md +96 -0
- package/get-shit-done/references/ui-brand.md +160 -0
- package/get-shit-done/references/universal-anti-patterns.md +63 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/user-story-template.md +58 -0
- package/get-shit-done/references/verification-overrides.md +227 -0
- package/get-shit-done/references/verification-patterns.md +612 -0
- package/get-shit-done/references/verify-mvp-mode.md +85 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/references/worktree-path-safety.md +89 -0
- package/get-shit-done/templates/AI-SPEC.md +246 -0
- package/get-shit-done/templates/DEBUG.md +169 -0
- package/get-shit-done/templates/README.md +77 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +265 -0
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +76 -0
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/codebase/architecture.md +255 -0
- package/get-shit-done/templates/codebase/concerns.md +310 -0
- package/get-shit-done/templates/codebase/conventions.md +307 -0
- package/get-shit-done/templates/codebase/integrations.md +280 -0
- package/get-shit-done/templates/codebase/stack.md +186 -0
- package/get-shit-done/templates/codebase/structure.md +285 -0
- package/get-shit-done/templates/codebase/testing.md +480 -0
- package/get-shit-done/templates/config.json +62 -0
- package/get-shit-done/templates/context.md +352 -0
- package/get-shit-done/templates/continue-here.md +78 -0
- package/get-shit-done/templates/copilot-instructions.md +7 -0
- package/get-shit-done/templates/debug-subagent-prompt.md +91 -0
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discovery.md +146 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/milestone-archive.md +123 -0
- package/get-shit-done/templates/milestone.md +115 -0
- package/get-shit-done/templates/phase-prompt.md +610 -0
- package/get-shit-done/templates/planner-subagent-prompt.md +117 -0
- package/get-shit-done/templates/project.md +186 -0
- package/get-shit-done/templates/requirements.md +231 -0
- package/get-shit-done/templates/research-project/ARCHITECTURE.md +204 -0
- package/get-shit-done/templates/research-project/FEATURES.md +147 -0
- package/get-shit-done/templates/research-project/PITFALLS.md +200 -0
- package/get-shit-done/templates/research-project/STACK.md +120 -0
- package/get-shit-done/templates/research-project/SUMMARY.md +170 -0
- package/get-shit-done/templates/research.md +592 -0
- package/get-shit-done/templates/retrospective.md +54 -0
- package/get-shit-done/templates/roadmap.md +202 -0
- package/get-shit-done/templates/spec.md +307 -0
- package/get-shit-done/templates/state.md +195 -0
- package/get-shit-done/templates/summary-complex.md +59 -0
- package/get-shit-done/templates/summary-minimal.md +41 -0
- package/get-shit-done/templates/summary-standard.md +48 -0
- package/get-shit-done/templates/summary.md +248 -0
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/templates/user-setup.md +311 -0
- package/get-shit-done/templates/verification-report.md +322 -0
- package/get-shit-done/workflows/_runtime-launcher.snippet.sh +1 -0
- package/get-shit-done/workflows/add-backlog.md +91 -0
- package/get-shit-done/workflows/add-phase.md +113 -0
- package/get-shit-done/workflows/add-tests.md +355 -0
- package/get-shit-done/workflows/add-todo.md +161 -0
- package/get-shit-done/workflows/ai-integration-phase.md +295 -0
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-fix.md +178 -0
- package/get-shit-done/workflows/audit-milestone.md +358 -0
- package/get-shit-done/workflows/audit-uat.md +110 -0
- package/get-shit-done/workflows/autonomous.md +795 -0
- package/get-shit-done/workflows/check-todos.md +180 -0
- package/get-shit-done/workflows/cleanup.md +155 -0
- package/get-shit-done/workflows/code-review-fix.md +502 -0
- package/get-shit-done/workflows/code-review.md +656 -0
- package/get-shit-done/workflows/complete-milestone.md +855 -0
- package/get-shit-done/workflows/debug.md +232 -0
- package/get-shit-done/workflows/diagnose-issues.md +241 -0
- package/get-shit-done/workflows/discovery-phase.md +291 -0
- package/get-shit-done/workflows/discuss-phase/modes/advisor.md +176 -0
- package/get-shit-done/workflows/discuss-phase/modes/all.md +28 -0
- package/get-shit-done/workflows/discuss-phase/modes/analyze.md +44 -0
- package/get-shit-done/workflows/discuss-phase/modes/auto.md +57 -0
- package/get-shit-done/workflows/discuss-phase/modes/batch.md +52 -0
- package/get-shit-done/workflows/discuss-phase/modes/chain.md +98 -0
- package/get-shit-done/workflows/discuss-phase/modes/default.md +141 -0
- package/get-shit-done/workflows/discuss-phase/modes/power.md +44 -0
- package/get-shit-done/workflows/discuss-phase/modes/text.md +55 -0
- package/get-shit-done/workflows/discuss-phase/templates/checkpoint.json +18 -0
- package/get-shit-done/workflows/discuss-phase/templates/context.md +136 -0
- package/get-shit-done/workflows/discuss-phase/templates/discussion-log.md +50 -0
- package/get-shit-done/workflows/discuss-phase-assumptions.md +675 -0
- package/get-shit-done/workflows/discuss-phase-power.md +291 -0
- package/get-shit-done/workflows/discuss-phase.md +499 -0
- package/get-shit-done/workflows/do.md +111 -0
- package/get-shit-done/workflows/docs-update.md +1162 -0
- package/get-shit-done/workflows/edit-phase.md +295 -0
- package/get-shit-done/workflows/eval-review.md +156 -0
- package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +82 -0
- package/get-shit-done/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
- package/get-shit-done/workflows/execute-phase/steps/post-merge-gate.md +117 -0
- package/get-shit-done/workflows/execute-phase.md +1709 -0
- package/get-shit-done/workflows/execute-plan.md +526 -0
- package/get-shit-done/workflows/explore.md +144 -0
- package/get-shit-done/workflows/extract-learnings.md +243 -0
- package/get-shit-done/workflows/fast.md +124 -0
- package/get-shit-done/workflows/forensics.md +279 -0
- package/get-shit-done/workflows/graduation.md +196 -0
- package/get-shit-done/workflows/health.md +224 -0
- package/get-shit-done/workflows/help/modes/brief.md +22 -0
- package/get-shit-done/workflows/help/modes/default.md +50 -0
- package/get-shit-done/workflows/help/modes/full.md +784 -0
- package/get-shit-done/workflows/help/modes/topic.md +74 -0
- package/get-shit-done/workflows/help.md +24 -0
- package/get-shit-done/workflows/import.md +254 -0
- package/get-shit-done/workflows/inbox.md +387 -0
- package/get-shit-done/workflows/ingest-docs.md +339 -0
- package/get-shit-done/workflows/insert-phase.md +152 -0
- package/get-shit-done/workflows/list-phase-assumptions.md +178 -0
- package/get-shit-done/workflows/list-workspaces.md +57 -0
- package/get-shit-done/workflows/manager.md +393 -0
- package/get-shit-done/workflows/map-codebase.md +444 -0
- package/get-shit-done/workflows/milestone-summary.md +224 -0
- package/get-shit-done/workflows/mvp-phase.md +222 -0
- package/get-shit-done/workflows/new-milestone.md +635 -0
- package/get-shit-done/workflows/new-project.md +1555 -0
- package/get-shit-done/workflows/new-workspace.md +240 -0
- package/get-shit-done/workflows/next.md +299 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +158 -0
- package/get-shit-done/workflows/pause-work.md +244 -0
- package/get-shit-done/workflows/plan-milestone-gaps.md +281 -0
- package/get-shit-done/workflows/plan-phase.md +1809 -0
- package/get-shit-done/workflows/plan-review-convergence.md +346 -0
- package/get-shit-done/workflows/plant-seed.md +230 -0
- package/get-shit-done/workflows/pr-branch.md +157 -0
- package/get-shit-done/workflows/profile-user.md +453 -0
- package/get-shit-done/workflows/progress.md +699 -0
- package/get-shit-done/workflows/quick.md +1039 -0
- package/get-shit-done/workflows/reapply-patches.md +426 -0
- package/get-shit-done/workflows/remove-phase.md +156 -0
- package/get-shit-done/workflows/remove-workspace.md +108 -0
- package/get-shit-done/workflows/resume-project.md +332 -0
- package/get-shit-done/workflows/review.md +623 -0
- package/get-shit-done/workflows/scan.md +105 -0
- package/get-shit-done/workflows/secure-phase.md +180 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/settings-advanced.md +620 -0
- package/get-shit-done/workflows/settings-integrations.md +312 -0
- package/get-shit-done/workflows/settings.md +552 -0
- package/get-shit-done/workflows/ship.md +356 -0
- package/get-shit-done/workflows/sketch-wrap-up.md +286 -0
- package/get-shit-done/workflows/sketch.md +361 -0
- package/get-shit-done/workflows/spec-phase.md +262 -0
- package/get-shit-done/workflows/spike-wrap-up.md +307 -0
- package/get-shit-done/workflows/spike.md +453 -0
- package/get-shit-done/workflows/stats.md +80 -0
- package/get-shit-done/workflows/sync-skills.md +182 -0
- package/get-shit-done/workflows/thread.md +222 -0
- package/get-shit-done/workflows/transition.md +694 -0
- package/get-shit-done/workflows/ui-phase.md +328 -0
- package/get-shit-done/workflows/ui-review.md +193 -0
- package/get-shit-done/workflows/ultraplan-phase.md +199 -0
- package/get-shit-done/workflows/undo.md +314 -0
- package/get-shit-done/workflows/update.md +443 -0
- package/get-shit-done/workflows/validate-phase.md +179 -0
- package/get-shit-done/workflows/verify-phase.md +544 -0
- package/get-shit-done/workflows/verify-work.md +781 -0
- package/hooks/dist/gsd-check-update-worker.js +95 -0
- package/hooks/dist/gsd-check-update.js +64 -0
- package/hooks/dist/gsd-context-monitor.js +195 -0
- package/hooks/dist/gsd-graphify-update.sh +158 -0
- package/hooks/dist/gsd-phase-boundary.sh +47 -0
- package/hooks/dist/gsd-prompt-guard.js +97 -0
- package/hooks/dist/gsd-read-guard.js +101 -0
- package/hooks/dist/gsd-read-injection-scanner.js +203 -0
- package/hooks/dist/gsd-session-state.sh +59 -0
- package/hooks/dist/gsd-statusline.js +548 -0
- package/hooks/dist/gsd-update-banner.js +134 -0
- package/hooks/dist/gsd-validate-commit.sh +57 -0
- package/hooks/dist/gsd-workflow-guard.js +166 -0
- package/hooks/dist/lib/git-cmd.js +150 -0
- package/hooks/dist/lib/gsd-graphify-rebuild.sh +65 -0
- package/hooks/gsd-check-update-worker.js +95 -0
- package/hooks/gsd-check-update.js +64 -0
- package/hooks/gsd-context-monitor.js +195 -0
- package/hooks/gsd-graphify-update.sh +158 -0
- package/hooks/gsd-phase-boundary.sh +47 -0
- package/hooks/gsd-prompt-guard.js +97 -0
- package/hooks/gsd-read-guard.js +101 -0
- package/hooks/gsd-read-injection-scanner.js +203 -0
- package/hooks/gsd-session-state.sh +59 -0
- package/hooks/gsd-statusline.js +548 -0
- package/hooks/gsd-update-banner.js +134 -0
- package/hooks/gsd-validate-commit.sh +57 -0
- package/hooks/gsd-workflow-guard.js +166 -0
- package/hooks/lib/git-cmd.js +150 -0
- package/hooks/lib/gsd-graphify-rebuild.sh +65 -0
- package/hooks/managed-hooks-registry.cjs +34 -0
- package/package.json +102 -0
- package/scripts/affected-tests-lib.cjs +541 -0
- package/scripts/audit-workflow-script-paths.cjs +73 -0
- package/scripts/base64-scan.sh +339 -0
- package/scripts/build-hooks.js +236 -0
- package/scripts/changeset/README.md +129 -0
- package/scripts/changeset/cli.cjs +392 -0
- package/scripts/changeset/github-release-notes.cjs +199 -0
- package/scripts/changeset/lint.cjs +110 -0
- package/scripts/changeset/new.cjs +137 -0
- package/scripts/changeset/parse.cjs +114 -0
- package/scripts/changeset/render.cjs +34 -0
- package/scripts/changeset/serialize.cjs +130 -0
- package/scripts/check-alias-drift.cjs +108 -0
- package/scripts/check-env.cjs +302 -0
- package/scripts/check-npm-integrity.cjs +209 -0
- package/scripts/ci-guard-runner.cjs +16 -0
- package/scripts/ci-prepare-test-scope.cjs +46 -0
- package/scripts/ci-rebase-check.cjs +85 -0
- package/scripts/ci-test-scope.cjs +302 -0
- package/scripts/command-contract-helpers.cjs +64 -0
- package/scripts/diff-touches-shipped-paths.cjs +147 -0
- package/scripts/fix-slash-commands.cjs +147 -0
- package/scripts/gen-inventory-manifest.cjs +109 -0
- package/scripts/generate-package-identity.cjs +104 -0
- package/scripts/lint-command-contract.cjs +108 -0
- package/scripts/lint-descriptions.cjs +83 -0
- package/scripts/lint-docs-required.cjs +222 -0
- package/scripts/lint-no-source-grep-extras.cjs +81 -0
- package/scripts/lint-no-source-grep.cjs +174 -0
- package/scripts/lint-package-identity-drift.cjs +141 -0
- package/scripts/lint-pr-check-project-dir.cjs +98 -0
- package/scripts/lint-shared-module-handsync.cjs +388 -0
- package/scripts/lint-shell-command-projection-drift.cjs +57 -0
- package/scripts/lint-skill-deps.cjs +180 -0
- package/scripts/lint-test-file-count.allowlist.json +36 -0
- package/scripts/lint-test-file-count.cjs +190 -0
- package/scripts/pr-template-policy.cjs +268 -0
- package/scripts/prompt-injection-scan.sh +203 -0
- package/scripts/release-tarball-smoke.cjs +627 -0
- package/scripts/run-affected-tests.cjs +6 -0
- package/scripts/run-cross-platform-tests.cjs +63 -0
- package/scripts/run-tests.cjs +282 -0
- package/scripts/secret-scan-lint.sh +231 -0
- package/scripts/secret-scan.sh +358 -0
- package/scripts/setup-branch-protection.sh +236 -0
- package/scripts/shared-module-handsync-allowlist.json +183 -0
- package/scripts/strip-prose-atrefs.cjs +106 -0
- package/scripts/sync-rulesets.sh +34 -0
- package/scripts/sync-runtime-launcher.cjs +402 -0
- package/scripts/test-failure-reasons.cjs +34 -0
- package/scripts/workflow-policy.cjs +450 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lint-descriptions.cjs
|
|
4
|
+
*
|
|
5
|
+
* Enforces the 100-char description budget for commands/gsd/*.md files.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node scripts/lint-descriptions.cjs [file.md ...]
|
|
9
|
+
*
|
|
10
|
+
* If no args are given, scans commands/gsd/ automatically.
|
|
11
|
+
* Exits 1 if any description exceeds 100 chars; exits 0 if all pass.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
'use strict';
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const MAX_LENGTH = 100;
|
|
20
|
+
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Parse the description field from frontmatter in a .md file.
|
|
24
|
+
* Returns null if no description is found.
|
|
25
|
+
*/
|
|
26
|
+
function parseDescription(content) {
|
|
27
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
28
|
+
if (!fmMatch) return null;
|
|
29
|
+
const fm = fmMatch[1];
|
|
30
|
+
|
|
31
|
+
const quoted = fm.match(/^description:\s+"((?:[^"\\]|\\.)*)"\s*$/m);
|
|
32
|
+
if (quoted) return quoted[1];
|
|
33
|
+
|
|
34
|
+
const plain = fm.match(/^description:\s+(.+)$/m);
|
|
35
|
+
if (plain) return plain[1].trim();
|
|
36
|
+
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getFiles() {
|
|
41
|
+
if (process.argv.length > 2) {
|
|
42
|
+
return process.argv.slice(2);
|
|
43
|
+
}
|
|
44
|
+
return fs.readdirSync(COMMANDS_DIR)
|
|
45
|
+
.filter(f => f.endsWith('.md'))
|
|
46
|
+
.map(f => path.join(COMMANDS_DIR, f));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const files = getFiles();
|
|
50
|
+
const violations = [];
|
|
51
|
+
|
|
52
|
+
for (const filePath of files) {
|
|
53
|
+
let content;
|
|
54
|
+
try {
|
|
55
|
+
content = fs.readFileSync(filePath, 'utf-8');
|
|
56
|
+
} catch (err) {
|
|
57
|
+
process.stderr.write(`ERROR: Cannot read file: ${filePath}\n ${err.message}\n`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const description = parseDescription(content);
|
|
62
|
+
if (description === null) continue;
|
|
63
|
+
|
|
64
|
+
if (description.length > MAX_LENGTH) {
|
|
65
|
+
violations.push({ filePath, length: description.length, description });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (violations.length === 0) {
|
|
70
|
+
const checked = files.length;
|
|
71
|
+
process.stdout.write(`ok lint-descriptions: ${checked} file(s) checked, 0 violations\n`);
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
process.stderr.write(`\nERROR lint-descriptions: ${violations.length} violation(s) found\n\n`);
|
|
76
|
+
for (const v of violations) {
|
|
77
|
+
const preview = v.description.length > 120 ? v.description.slice(0, 117) + '...' : v.description;
|
|
78
|
+
process.stderr.write(` ${v.filePath}\n`);
|
|
79
|
+
process.stderr.write(` Length : ${v.length} (max ${MAX_LENGTH})\n`);
|
|
80
|
+
process.stderr.write(` Desc : ${preview}\n\n`);
|
|
81
|
+
}
|
|
82
|
+
process.stderr.write(`Trim descriptions to <= ${MAX_LENGTH} chars. Flag docs belong in argument-hint:.\n\n`);
|
|
83
|
+
process.exit(1);
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Docs-required lint (#3213).
|
|
6
|
+
*
|
|
7
|
+
* Mirrors scripts/changeset/lint.cjs. Pure verdict function
|
|
8
|
+
* evaluateLint({ changedFiles, fragments, labels, malformed }) returns
|
|
9
|
+
* { ok, reason, triggering } using the LINT_REASON enum. The CLI wrapper
|
|
10
|
+
* reads the PR diff (`git diff --name-only origin/${base}...HEAD`), parses
|
|
11
|
+
* each touched `.changeset/*.md` fragment, then calls evaluateLint.
|
|
12
|
+
*
|
|
13
|
+
* Tests assert on the structured verdict, never on free text.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { parseFragment, FRAGMENT_ERROR } = require('./changeset/parse.cjs');
|
|
17
|
+
|
|
18
|
+
const LINT_REASON = Object.freeze({
|
|
19
|
+
OK_NO_TRIGGERING_FRAGMENTS: 'ok_no_triggering_fragments',
|
|
20
|
+
OK_DOCS_UPDATED: 'ok_docs_updated',
|
|
21
|
+
OK_OPT_OUT_LABEL: 'ok_opt_out_label',
|
|
22
|
+
OK_FRAGMENTS_EXEMPT: 'ok_fragments_exempt',
|
|
23
|
+
FAIL_DOCS_MISSING: 'fail_docs_missing',
|
|
24
|
+
FAIL_MALFORMED_FRAGMENT: 'fail_malformed_fragment',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const OPT_OUT_LABEL = 'no-docs';
|
|
28
|
+
|
|
29
|
+
// Fragment types that require a docs update. `Fixed` and `Security` are
|
|
30
|
+
// bug-class — they describe regressions or vulnerabilities, not new
|
|
31
|
+
// behavior to document.
|
|
32
|
+
const TRIGGERING_TYPES = new Set(['Added', 'Changed', 'Deprecated', 'Removed']);
|
|
33
|
+
|
|
34
|
+
const DOCS_PREFIX = 'docs/';
|
|
35
|
+
|
|
36
|
+
function isFragmentPath(file) {
|
|
37
|
+
return /^\.changeset\/[^/]+\.md$/.test(file) && !file.endsWith('/README.md');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isDocsFile(file) {
|
|
41
|
+
return file.startsWith(DOCS_PREFIX);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Per-fragment escape hatch: parse.cjs extracts `<!-- docs-exempt: <reason> -->`
|
|
45
|
+
// from the body into `fragment.docsExempt` (a non-empty reason string when the
|
|
46
|
+
// marker was present and well-formed; `null` otherwise). A non-empty audit
|
|
47
|
+
// trail is required — the lint defends in depth here too: even if a caller
|
|
48
|
+
// constructs a fragment with `docsExempt: ''`, that does not count as exempt.
|
|
49
|
+
function isExemptFragment(fragment) {
|
|
50
|
+
return typeof fragment.docsExempt === 'string' && fragment.docsExempt.trim().length > 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Pure verdict — no fs, no git.
|
|
55
|
+
*
|
|
56
|
+
* Malformed fragments fail closed: a triggering fragment with bad frontmatter
|
|
57
|
+
* cannot silently bypass docs enforcement. The changeset-required lint only
|
|
58
|
+
* checks fragment _presence_, not _validity_, so docs lint takes responsibility
|
|
59
|
+
* for any fragment it tries to consume.
|
|
60
|
+
*
|
|
61
|
+
* @param {object} args
|
|
62
|
+
* @param {string[]} args.changedFiles - file paths changed in the PR
|
|
63
|
+
* @param {Array<{ path: string, type: string, body: string, docsExempt: string|null }>} args.fragments
|
|
64
|
+
* - parsed records for well-formed `.changeset/*.md` files in `changedFiles`
|
|
65
|
+
* @param {Array<{ path: string, reason: string }>} [args.malformed]
|
|
66
|
+
* - records for `.changeset/*.md` files that failed `parseFragment`
|
|
67
|
+
* @param {string[]} args.labels - PR labels
|
|
68
|
+
* @returns {{ ok: boolean, reason: string, triggering: string[], malformed?: Array<{path:string,reason:string}> }}
|
|
69
|
+
*/
|
|
70
|
+
function evaluateLint({ changedFiles, fragments, labels, malformed = [] }) {
|
|
71
|
+
if (malformed.length > 0) {
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
reason: LINT_REASON.FAIL_MALFORMED_FRAGMENT,
|
|
75
|
+
triggering: [],
|
|
76
|
+
malformed,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const triggering = fragments.filter((f) => TRIGGERING_TYPES.has(f.type));
|
|
81
|
+
const triggeringPaths = triggering.map((f) => f.path);
|
|
82
|
+
|
|
83
|
+
if (triggering.length === 0) {
|
|
84
|
+
return { ok: true, reason: LINT_REASON.OK_NO_TRIGGERING_FRAGMENTS, triggering: [] };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Per-fragment exempt path: every triggering fragment must carry the marker.
|
|
88
|
+
// Partial exemption fails closed — one un-marked Added fragment still requires docs.
|
|
89
|
+
if (triggering.every(isExemptFragment)) {
|
|
90
|
+
return { ok: true, reason: LINT_REASON.OK_FRAGMENTS_EXEMPT, triggering: triggeringPaths };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (labels.includes(OPT_OUT_LABEL)) {
|
|
94
|
+
return { ok: true, reason: LINT_REASON.OK_OPT_OUT_LABEL, triggering: triggeringPaths };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (changedFiles.some(isDocsFile)) {
|
|
98
|
+
return { ok: true, reason: LINT_REASON.OK_DOCS_UPDATED, triggering: triggeringPaths };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { ok: false, reason: LINT_REASON.FAIL_DOCS_MISSING, triggering: triggeringPaths };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function readFragmentsFromDisk(changedFiles, rootDir) {
|
|
105
|
+
const fs = require('node:fs');
|
|
106
|
+
const path = require('node:path');
|
|
107
|
+
const fragments = [];
|
|
108
|
+
const malformed = [];
|
|
109
|
+
for (const rel of changedFiles) {
|
|
110
|
+
if (!isFragmentPath(rel)) continue;
|
|
111
|
+
const abs = path.join(rootDir, rel);
|
|
112
|
+
if (!fs.existsSync(abs)) continue; // fragment deleted in PR — skip
|
|
113
|
+
let src;
|
|
114
|
+
try {
|
|
115
|
+
src = fs.readFileSync(abs, 'utf8');
|
|
116
|
+
} catch (e) {
|
|
117
|
+
malformed.push({ path: rel, reason: 'read_error', detail: e.code || e.message });
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const parsed = parseFragment(src);
|
|
121
|
+
if (!parsed.ok) {
|
|
122
|
+
malformed.push({ path: rel, reason: parsed.reason, detail: parsed.detail || null });
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
fragments.push({
|
|
126
|
+
path: rel,
|
|
127
|
+
type: parsed.fragment.type,
|
|
128
|
+
body: parsed.fragment.body,
|
|
129
|
+
docsExempt: parsed.fragment.docsExempt,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return { fragments, malformed };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function main() {
|
|
136
|
+
const fs = require('node:fs');
|
|
137
|
+
const cp = require('node:child_process');
|
|
138
|
+
const path = require('node:path');
|
|
139
|
+
|
|
140
|
+
const rootDir = path.join(__dirname, '..');
|
|
141
|
+
|
|
142
|
+
const eventPath = process.env.GITHUB_EVENT_PATH;
|
|
143
|
+
let labels = [];
|
|
144
|
+
if (eventPath && fs.existsSync(eventPath)) {
|
|
145
|
+
try {
|
|
146
|
+
const event = JSON.parse(fs.readFileSync(eventPath, 'utf8'));
|
|
147
|
+
labels = (event.pull_request?.labels || []).map((l) => l.name);
|
|
148
|
+
} catch { /* fall through */ }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const base = process.env.GITHUB_BASE_REF || 'main';
|
|
152
|
+
let changedFiles = [];
|
|
153
|
+
try {
|
|
154
|
+
// execFileSync with argv — no shell, so a malicious GITHUB_BASE_REF
|
|
155
|
+
// cannot inject shell syntax. Git's own ref-name validator rejects
|
|
156
|
+
// any metacharacters it would otherwise interpret.
|
|
157
|
+
const out = cp.execFileSync(
|
|
158
|
+
'git',
|
|
159
|
+
['diff', '--name-only', `origin/${base}...HEAD`],
|
|
160
|
+
{ encoding: 'utf8', cwd: rootDir },
|
|
161
|
+
);
|
|
162
|
+
changedFiles = out.split('\n').filter(Boolean);
|
|
163
|
+
} catch (e) {
|
|
164
|
+
process.stderr.write(`could not compute diff: ${e.message}\n`);
|
|
165
|
+
process.exit(2);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const { fragments, malformed } = readFragmentsFromDisk(changedFiles, rootDir);
|
|
169
|
+
const verdict = evaluateLint({ changedFiles, fragments, labels, malformed });
|
|
170
|
+
|
|
171
|
+
if (process.argv.includes('--json')) {
|
|
172
|
+
process.stdout.write(
|
|
173
|
+
JSON.stringify({ ...verdict, changedFiles, fragments, malformed, labels }, null, 2) + '\n',
|
|
174
|
+
);
|
|
175
|
+
} else if (verdict.ok) {
|
|
176
|
+
process.stdout.write(`ok docs-lint: ${verdict.reason}\n`);
|
|
177
|
+
} else if (verdict.reason === LINT_REASON.FAIL_MALFORMED_FRAGMENT) {
|
|
178
|
+
process.stderr.write(`\nERROR docs-lint: ${verdict.reason}\n`);
|
|
179
|
+
process.stderr.write(
|
|
180
|
+
`${malformed.length} changeset fragment(s) failed to parse — docs lint cannot consume them:\n`,
|
|
181
|
+
);
|
|
182
|
+
for (const m of malformed) {
|
|
183
|
+
process.stderr.write(` ${m.path} (reason: ${m.reason}${m.detail ? `, detail: ${m.detail}` : ''})\n`);
|
|
184
|
+
}
|
|
185
|
+
process.stderr.write(
|
|
186
|
+
`\nFix the fragment frontmatter (\`type:\` + \`pr:\`) before this PR can pass.\n`,
|
|
187
|
+
);
|
|
188
|
+
} else {
|
|
189
|
+
process.stderr.write(`\nERROR docs-lint: ${verdict.reason}\n`);
|
|
190
|
+
process.stderr.write(
|
|
191
|
+
`${verdict.triggering.length} changeset fragment(s) require documentation updates:\n`,
|
|
192
|
+
);
|
|
193
|
+
for (const f of fragments.filter((f) => TRIGGERING_TYPES.has(f.type))) {
|
|
194
|
+
process.stderr.write(` ${f.path} (type: ${f.type})\n`);
|
|
195
|
+
}
|
|
196
|
+
process.stderr.write(`\nNo files under docs/ were modified in this PR.\n\n`);
|
|
197
|
+
process.stderr.write(
|
|
198
|
+
`Update the relevant docs/ file(s), or add the \`${OPT_OUT_LABEL}\` label if this change\n`,
|
|
199
|
+
);
|
|
200
|
+
process.stderr.write(
|
|
201
|
+
`is genuinely internal-only (infrastructure, refactor, test-only). Per-fragment\n`,
|
|
202
|
+
);
|
|
203
|
+
process.stderr.write(
|
|
204
|
+
`exemption via \`<!-- docs-exempt: <reason> -->\` inside the fragment body also works.\n`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
process.exit(verdict.ok ? 0 : 1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (require.main === module) main();
|
|
211
|
+
|
|
212
|
+
module.exports = {
|
|
213
|
+
evaluateLint,
|
|
214
|
+
readFragmentsFromDisk,
|
|
215
|
+
LINT_REASON,
|
|
216
|
+
OPT_OUT_LABEL,
|
|
217
|
+
TRIGGERING_TYPES,
|
|
218
|
+
FRAGMENT_ERROR,
|
|
219
|
+
isFragmentPath,
|
|
220
|
+
isDocsFile,
|
|
221
|
+
isExemptFragment,
|
|
222
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extended detector for the no-source-grep rule (#2982).
|
|
5
|
+
*
|
|
6
|
+
* The base lint (scripts/lint-no-source-grep.cjs) only catches the
|
|
7
|
+
* direct-chain form: readFileSync(...).includes(...). The much more common
|
|
8
|
+
* var-binding form escapes it:
|
|
9
|
+
*
|
|
10
|
+
* const src = fs.readFileSync(p, 'utf8');
|
|
11
|
+
* // ... 50 lines later ...
|
|
12
|
+
* assert.ok(src.includes('foo')); // ← still source-grep, lint missed it
|
|
13
|
+
*
|
|
14
|
+
* This module exposes pure detectors that scan source text and return
|
|
15
|
+
* structured violation records. The CLI wrapper (in the base lint) calls
|
|
16
|
+
* these for each test file.
|
|
17
|
+
*
|
|
18
|
+
* Tests assert on the typed VIOLATION enum codes, not on prose messages.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const VIOLATION = Object.freeze({
|
|
22
|
+
VAR_FROM_READFILE_USED_IN_TEXT_MATCH: 'var_from_readfile_used_in_text_match',
|
|
23
|
+
WRAPPED_ASSERT_OK_MATCH: 'wrapped_assert_ok_match',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const TEXT_MATCH_METHODS = ['includes', 'startsWith', 'endsWith', 'match', 'search'];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Single-pass scanner. Tracks variables bound from a readFileSync call,
|
|
30
|
+
* then flags any subsequent <var>.<method>( use where method is one of
|
|
31
|
+
* TEXT_MATCH_METHODS.
|
|
32
|
+
*/
|
|
33
|
+
function detectVarBindingViolations(src) {
|
|
34
|
+
// Pass 1: collect variables bound from readFileSync.
|
|
35
|
+
// Matches: const|let|var <name> = [fs.]readFileSync(
|
|
36
|
+
const bindRe = /(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:[A-Za-z_$][\w$.]*\.)?readFileSync\s*\(/g;
|
|
37
|
+
const boundVars = new Set();
|
|
38
|
+
let m;
|
|
39
|
+
while ((m = bindRe.exec(src)) !== null) {
|
|
40
|
+
boundVars.add(m[1]);
|
|
41
|
+
}
|
|
42
|
+
if (boundVars.size === 0) return [];
|
|
43
|
+
|
|
44
|
+
// Pass 2: find <var>.<method>( on any bound var.
|
|
45
|
+
const findings = [];
|
|
46
|
+
// Build a regex alternation from the bound var names.
|
|
47
|
+
const alt = [...boundVars].map((v) => v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
|
|
48
|
+
const useRe = new RegExp(
|
|
49
|
+
`\\b(${alt})\\s*\\.\\s*(${TEXT_MATCH_METHODS.join('|')})\\s*\\(`,
|
|
50
|
+
'g',
|
|
51
|
+
);
|
|
52
|
+
while ((m = useRe.exec(src)) !== null) {
|
|
53
|
+
findings.push({
|
|
54
|
+
kind: VIOLATION.VAR_FROM_READFILE_USED_IN_TEXT_MATCH,
|
|
55
|
+
variable: m[1],
|
|
56
|
+
method: m[2],
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return findings;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Detects assert.ok(<expr>.match(/.../)) and assert.ok(<expr>.match(<expr>))
|
|
64
|
+
* which is the same anti-pattern as assert.match but escapes the simpler
|
|
65
|
+
* regex used by the base lint.
|
|
66
|
+
*/
|
|
67
|
+
function detectWrappedAssertOkMatch(src) {
|
|
68
|
+
const re = /assert\.ok\s*\(\s*[A-Za-z_$][\w$.]*\.match\s*\(/g;
|
|
69
|
+
const findings = [];
|
|
70
|
+
let m;
|
|
71
|
+
while ((m = re.exec(src)) !== null) {
|
|
72
|
+
findings.push({ kind: VIOLATION.WRAPPED_ASSERT_OK_MATCH });
|
|
73
|
+
}
|
|
74
|
+
return findings;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function detectAll(src) {
|
|
78
|
+
return [...detectVarBindingViolations(src), ...detectWrappedAssertOkMatch(src)];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { detectVarBindingViolations, detectWrappedAssertOkMatch, detectAll, VIOLATION };
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lint-no-source-grep.cjs
|
|
4
|
+
*
|
|
5
|
+
* Enforces the "no source-grep tests" rule:
|
|
6
|
+
* Tests must NOT read source-code .cjs files with readFileSync to assert string
|
|
7
|
+
* presence. That pattern (source-grep theater) proves a literal exists in source,
|
|
8
|
+
* not that the runtime behavior is correct.
|
|
9
|
+
*
|
|
10
|
+
* ALLOWED:
|
|
11
|
+
* - require('../get-shit-done/bin/lib/foo.cjs') -- runs the module, not text inspection
|
|
12
|
+
* - readFileSync on .md / .json / .txt files -- product-content or config output
|
|
13
|
+
* - Files annotated: // allow-test-rule: <reason>
|
|
14
|
+
*
|
|
15
|
+
* DISALLOWED (without allow-test-rule):
|
|
16
|
+
* - readFileSync where the path argument ends in a .cjs filename literal
|
|
17
|
+
* - A path constant (e.g. CONFIG_PATH) assigned to a .cjs lib file, used in readFileSync
|
|
18
|
+
*
|
|
19
|
+
* Exit 0 = clean. Exit 1 = violations found (with diagnostics).
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
const TESTS_DIR = path.join(__dirname, '..', 'tests');
|
|
28
|
+
const ALLOW_ANNOTATION = /\/\/\s*allow-test-rule:\s*\S/;
|
|
29
|
+
|
|
30
|
+
// Matches constant definitions that hold a .cjs path in a SOURCE directory.
|
|
31
|
+
// Requires a source-dir indicator ('bin', 'lib', 'get-shit-done') to avoid
|
|
32
|
+
// flagging temp files like path.join(tmpDir, 'example.cjs').
|
|
33
|
+
// const CONFIG_PATH = path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib', 'config-schema.cjs');
|
|
34
|
+
const CJS_PATH_CONST_RE = /(?:const|let|var)\s+(\w+)\s*=\s*path\.join\s*\([^)]*(?:'bin'|"bin"|'lib'|"lib"|'get-shit-done'|"get-shit-done")[^)]*['"][^'"]*\.cjs['"]/gm;
|
|
35
|
+
|
|
36
|
+
// Matches readFileSync with a named variable as first arg
|
|
37
|
+
const READ_WITH_CONST_RE = /readFileSync\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,/gm;
|
|
38
|
+
|
|
39
|
+
// Matches readFileSync with an inline path.join(.cjs) as first arg
|
|
40
|
+
const READ_WITH_INLINE_CJS_RE = /readFileSync\s*\([^,)]*path\.join\s*\([^)]*(?:'bin'|"bin"|'lib'|"lib"|'get-shit-done'|"get-shit-done")[^)]*['"][^'"]*\.cjs['"]/;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* #2962-class violations: raw text matching against process output or file
|
|
44
|
+
* content. The rule from CONTRIBUTING.md "Prohibited: Raw Text Matching on
|
|
45
|
+
* Test Outputs": tests assert on typed structured fields, never on rendered
|
|
46
|
+
* text. Patterns below are the obvious anti-patterns; subtler hidden forms
|
|
47
|
+
* (e.g. wrapping the same logic in a parser function) are still forbidden
|
|
48
|
+
* by the prose rule but cannot be detected lexically without an AST.
|
|
49
|
+
*/
|
|
50
|
+
const RAW_MATCH_PATTERNS = [
|
|
51
|
+
{
|
|
52
|
+
re: /assert\.(?:match|doesNotMatch)\s*\(\s*[A-Za-z_$][A-Za-z0-9_$]*\.(?:stdout|stderr)\b/,
|
|
53
|
+
label: 'assert.match/doesNotMatch on .stdout/.stderr (emit --json from the SUT and assert on typed fields)',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
re: /\.(?:stdout|stderr)\.(?:includes|startsWith|endsWith)\s*\(/,
|
|
57
|
+
label: '.stdout/.stderr substring match (emit --json and assert on typed fields)',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
re: /readFileSync\s*\([^)]*\)\s*\.(?:includes|startsWith|endsWith)\s*\(/,
|
|
61
|
+
label: 'readFileSync(...).<includes|startsWith|endsWith> (expose an IR from production code; assert on its fields)',
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
function setFromMatches(content, re) {
|
|
66
|
+
const found = new Set();
|
|
67
|
+
let m;
|
|
68
|
+
const cloned = new RegExp(re.source, re.flags);
|
|
69
|
+
while ((m = cloned.exec(content)) !== null) found.add(m[1]);
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function check(filepath) {
|
|
74
|
+
const content = fs.readFileSync(filepath, 'utf-8');
|
|
75
|
+
const rel = path.relative(path.join(__dirname, '..'), filepath);
|
|
76
|
+
|
|
77
|
+
if (ALLOW_ANNOTATION.test(content)) return null;
|
|
78
|
+
|
|
79
|
+
const violations = [];
|
|
80
|
+
|
|
81
|
+
// Pattern A: readFileSync(path.join(..., 'foo.cjs'), ...)
|
|
82
|
+
if (READ_WITH_INLINE_CJS_RE.test(content)) {
|
|
83
|
+
violations.push({
|
|
84
|
+
reason: 'readFileSync with inline .cjs path literal',
|
|
85
|
+
fix: 'Replace with runGsdTools() behavioral test, or add // allow-test-rule: <reason>',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Pattern B: const FOO_PATH = path.join(..., 'foo.cjs') + readFileSync(FOO_PATH, ...)
|
|
90
|
+
const cjsConsts = setFromMatches(content, CJS_PATH_CONST_RE);
|
|
91
|
+
if (cjsConsts.size > 0) {
|
|
92
|
+
const readConsts = setFromMatches(content, READ_WITH_CONST_RE);
|
|
93
|
+
const overlap = [...cjsConsts].filter(c => readConsts.has(c));
|
|
94
|
+
if (overlap.length > 0) {
|
|
95
|
+
violations.push({
|
|
96
|
+
reason: `source .cjs path constant(s) used in readFileSync: ${overlap.join(', ')}`,
|
|
97
|
+
fix: 'Replace with runGsdTools() behavioral test, or add // allow-test-rule: <reason>',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Patterns C..E: raw text matching against process output or file content.
|
|
103
|
+
// See CONTRIBUTING.md "Prohibited: Raw Text Matching on Test Outputs".
|
|
104
|
+
for (const { re, label } of RAW_MATCH_PATTERNS) {
|
|
105
|
+
if (re.test(content)) {
|
|
106
|
+
violations.push({
|
|
107
|
+
reason: label,
|
|
108
|
+
fix: 'Expose typed IR from production code; assert on structured fields. Or add // allow-test-rule: <reason>',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Patterns F..G (#2982): var-binding readFileSync().<text-method>() and
|
|
114
|
+
// assert.ok(<expr>.match(...)). These escape the simpler patterns above
|
|
115
|
+
// because the bind and the use are on different lines or wrapped.
|
|
116
|
+
const extras = require('./lint-no-source-grep-extras.cjs');
|
|
117
|
+
const varBindFindings = extras.detectVarBindingViolations(content);
|
|
118
|
+
if (varBindFindings.length > 0) {
|
|
119
|
+
const samples = varBindFindings.slice(0, 3)
|
|
120
|
+
.map((f) => `${f.variable}.${f.method}()`)
|
|
121
|
+
.join(', ');
|
|
122
|
+
violations.push({
|
|
123
|
+
reason: `readFileSync-bound variable used in text-match method: ${samples}${varBindFindings.length > 3 ? `, …+${varBindFindings.length - 3} more` : ''}`,
|
|
124
|
+
fix: 'Expose typed IR; assert on structured fields. Or // allow-test-rule: <reason>',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const wrappedFindings = extras.detectWrappedAssertOkMatch(content);
|
|
128
|
+
if (wrappedFindings.length > 0) {
|
|
129
|
+
violations.push({
|
|
130
|
+
reason: `assert.ok(<expr>.match(...)) — escapes assert.match rule (${wrappedFindings.length} occurrence${wrappedFindings.length > 1 ? 's' : ''})`,
|
|
131
|
+
fix: 'Use assert.equal on a typed field, not regex match on text. Or // allow-test-rule: <reason>',
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (violations.length === 0) return null;
|
|
136
|
+
return { file: rel, violations };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function findTestFiles(dir) {
|
|
140
|
+
const results = [];
|
|
141
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
142
|
+
const full = path.join(dir, entry.name);
|
|
143
|
+
if (entry.isDirectory()) {
|
|
144
|
+
results.push(...findTestFiles(full));
|
|
145
|
+
} else if (entry.name.endsWith('.test.cjs')) {
|
|
146
|
+
results.push(full);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return results;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const testFiles = findTestFiles(TESTS_DIR);
|
|
153
|
+
|
|
154
|
+
const violations = testFiles.map(check).filter(Boolean);
|
|
155
|
+
|
|
156
|
+
if (violations.length === 0) {
|
|
157
|
+
console.log(`ok lint-no-source-grep: ${testFiles.length} test files checked, 0 violations`);
|
|
158
|
+
process.exit(0);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const totalIssues = violations.reduce((n, v) => n + v.violations.length, 0);
|
|
162
|
+
process.stderr.write(`\nERROR lint-no-source-grep: ${totalIssues} violation(s) across ${violations.length} file(s)\n\n`);
|
|
163
|
+
for (const f of violations) {
|
|
164
|
+
process.stderr.write(` ${f.file}\n`);
|
|
165
|
+
for (const v of f.violations) {
|
|
166
|
+
process.stderr.write(` Problem : ${v.reason}\n`);
|
|
167
|
+
process.stderr.write(` Fix : ${v.fix}\n`);
|
|
168
|
+
}
|
|
169
|
+
process.stderr.write('\n');
|
|
170
|
+
}
|
|
171
|
+
process.stderr.write('See CONTRIBUTING.md "Prohibited: Source-Grep Tests" and\n');
|
|
172
|
+
process.stderr.write('"Prohibited: Raw Text Matching on Test Outputs" for guidance.\n');
|
|
173
|
+
process.stderr.write('Structural tests that legitimately read source files: add // allow-test-rule: <reason>\n\n');
|
|
174
|
+
process.exit(1);
|