autonomous-coding-toolkit 1.0.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/.claude-plugin/marketplace.json +22 -0
- package/.claude-plugin/plugin.json +13 -0
- package/LICENSE +21 -0
- package/Makefile +21 -0
- package/README.md +140 -0
- package/SECURITY.md +28 -0
- package/agents/bash-expert.md +113 -0
- package/agents/dependency-auditor.md +138 -0
- package/agents/integration-tester.md +120 -0
- package/agents/lesson-scanner.md +149 -0
- package/agents/python-expert.md +179 -0
- package/agents/service-monitor.md +141 -0
- package/agents/shell-expert.md +147 -0
- package/benchmarks/runner.sh +147 -0
- package/benchmarks/tasks/01-rest-endpoint/rubric.sh +29 -0
- package/benchmarks/tasks/01-rest-endpoint/task.md +17 -0
- package/benchmarks/tasks/02-refactor-module/task.md +8 -0
- package/benchmarks/tasks/03-fix-integration-bug/task.md +8 -0
- package/benchmarks/tasks/04-add-test-coverage/task.md +8 -0
- package/benchmarks/tasks/05-multi-file-feature/task.md +8 -0
- package/bin/act.js +238 -0
- package/commands/autocode.md +6 -0
- package/commands/cancel-ralph.md +18 -0
- package/commands/code-factory.md +53 -0
- package/commands/create-prd.md +55 -0
- package/commands/ralph-loop.md +18 -0
- package/commands/run-plan.md +117 -0
- package/commands/submit-lesson.md +122 -0
- package/docs/ARCHITECTURE.md +630 -0
- package/docs/CONTRIBUTING.md +125 -0
- package/docs/lessons/0001-bare-exception-swallowing.md +34 -0
- package/docs/lessons/0002-async-def-without-await.md +28 -0
- package/docs/lessons/0003-create-task-without-callback.md +28 -0
- package/docs/lessons/0004-hardcoded-test-counts.md +28 -0
- package/docs/lessons/0005-sqlite-without-closing.md +33 -0
- package/docs/lessons/0006-venv-pip-path.md +27 -0
- package/docs/lessons/0007-runner-state-self-rejection.md +35 -0
- package/docs/lessons/0008-quality-gate-blind-spot.md +33 -0
- package/docs/lessons/0009-parser-overcount-empty-batches.md +36 -0
- package/docs/lessons/0010-local-outside-function-bash.md +33 -0
- package/docs/lessons/0011-batch-tests-for-unimplemented-code.md +36 -0
- package/docs/lessons/0012-api-markdown-unescaped-chars.md +33 -0
- package/docs/lessons/0013-export-prefix-env-parsing.md +33 -0
- package/docs/lessons/0014-decorator-registry-import-side-effect.md +43 -0
- package/docs/lessons/0015-frontend-backend-schema-drift.md +43 -0
- package/docs/lessons/0016-event-driven-cold-start-seeding.md +44 -0
- package/docs/lessons/0017-copy-paste-logic-diverges.md +43 -0
- package/docs/lessons/0018-layer-passes-pipeline-broken.md +45 -0
- package/docs/lessons/0019-systemd-envfile-ignores-export.md +41 -0
- package/docs/lessons/0020-persist-state-incrementally.md +44 -0
- package/docs/lessons/0021-dual-axis-testing.md +48 -0
- package/docs/lessons/0022-jsx-factory-shadowing.md +43 -0
- package/docs/lessons/0023-static-analysis-spiral.md +51 -0
- package/docs/lessons/0024-shared-pipeline-implementation.md +55 -0
- package/docs/lessons/0025-defense-in-depth-all-entry-points.md +65 -0
- package/docs/lessons/0026-linter-no-rules-false-enforcement.md +54 -0
- package/docs/lessons/0027-jsx-silent-prop-drop.md +64 -0
- package/docs/lessons/0028-no-infrastructure-in-client-code.md +49 -0
- package/docs/lessons/0029-never-write-secrets-to-files.md +61 -0
- package/docs/lessons/0030-cache-merge-not-replace.md +62 -0
- package/docs/lessons/0031-verify-units-at-boundaries.md +66 -0
- package/docs/lessons/0032-module-lifecycle-subscribe-unsubscribe.md +89 -0
- package/docs/lessons/0033-async-iteration-mutable-snapshot.md +72 -0
- package/docs/lessons/0034-caller-missing-await-silent-discard.md +65 -0
- package/docs/lessons/0035-duplicate-registration-silent-overwrite.md +85 -0
- package/docs/lessons/0036-websocket-dirty-disconnect.md +33 -0
- package/docs/lessons/0037-parallel-agents-worktree-corruption.md +31 -0
- package/docs/lessons/0038-subscribe-no-stored-ref.md +36 -0
- package/docs/lessons/0039-fallback-or-default-hides-bugs.md +34 -0
- package/docs/lessons/0040-event-firehose-filter-first.md +36 -0
- package/docs/lessons/0041-ambiguous-base-dir-path-nesting.md +32 -0
- package/docs/lessons/0042-spec-compliance-insufficient.md +36 -0
- package/docs/lessons/0043-exact-count-extensible-collections.md +32 -0
- package/docs/lessons/0044-relative-file-deps-worktree.md +39 -0
- package/docs/lessons/0045-iterative-design-improvement.md +33 -0
- package/docs/lessons/0046-plan-assertion-math-bugs.md +38 -0
- package/docs/lessons/0047-pytest-single-threaded-default.md +37 -0
- package/docs/lessons/0048-integration-wiring-batch.md +40 -0
- package/docs/lessons/0049-ab-verification.md +41 -0
- package/docs/lessons/0050-editing-sourced-files-during-execution.md +33 -0
- package/docs/lessons/0051-infrastructure-fixes-cant-self-heal.md +30 -0
- package/docs/lessons/0052-uncommitted-changes-poison-quality-gates.md +31 -0
- package/docs/lessons/0053-jq-compact-flag-inconsistency.md +31 -0
- package/docs/lessons/0054-parser-matches-inside-code-blocks.md +30 -0
- package/docs/lessons/0055-agents-compensate-for-garbled-prompts.md +31 -0
- package/docs/lessons/0056-grep-count-exit-code-on-zero.md +42 -0
- package/docs/lessons/0057-new-artifacts-break-git-clean-gates.md +42 -0
- package/docs/lessons/0058-dead-config-keys-never-consumed.md +49 -0
- package/docs/lessons/0059-contract-test-shared-structures.md +53 -0
- package/docs/lessons/0060-set-e-silent-death-in-runners.md +53 -0
- package/docs/lessons/0061-context-injection-dirty-state.md +50 -0
- package/docs/lessons/0062-sibling-bug-neighborhood-scan.md +29 -0
- package/docs/lessons/0063-one-flag-two-lifetimes.md +31 -0
- package/docs/lessons/0064-test-passes-wrong-reason.md +31 -0
- package/docs/lessons/0065-pipefail-grep-count-double-output.md +39 -0
- package/docs/lessons/0066-local-keyword-outside-function.md +37 -0
- package/docs/lessons/0067-stdin-hang-non-interactive-shell.md +36 -0
- package/docs/lessons/0068-agent-builds-wrong-thing-correctly.md +31 -0
- package/docs/lessons/0069-plan-quality-dominates-execution.md +30 -0
- package/docs/lessons/0070-spec-echo-back-prevents-drift.md +31 -0
- package/docs/lessons/0071-positive-instructions-outperform-negative.md +30 -0
- package/docs/lessons/0072-lost-in-the-middle-context-placement.md +30 -0
- package/docs/lessons/0073-unscoped-lessons-cause-false-positives.md +30 -0
- package/docs/lessons/0074-stale-context-injection-wrong-batch.md +32 -0
- package/docs/lessons/0075-research-artifacts-must-persist.md +32 -0
- package/docs/lessons/0076-wrong-decomposition-contaminates-downstream.md +30 -0
- package/docs/lessons/0077-cherry-pick-merges-need-manual-resolution.md +30 -0
- package/docs/lessons/0078-static-review-without-live-test.md +30 -0
- package/docs/lessons/0079-integration-wiring-batch-required.md +32 -0
- package/docs/lessons/FRAMEWORK.md +161 -0
- package/docs/lessons/SUMMARY.md +201 -0
- package/docs/lessons/TEMPLATE.md +85 -0
- package/docs/plans/2026-02-21-code-factory-v2-design.md +204 -0
- package/docs/plans/2026-02-21-code-factory-v2-implementation-plan.md +2189 -0
- package/docs/plans/2026-02-21-code-factory-v2-phase4-design.md +537 -0
- package/docs/plans/2026-02-21-code-factory-v2-phase4-implementation-plan.md +2012 -0
- package/docs/plans/2026-02-21-hardening-pass-design.md +108 -0
- package/docs/plans/2026-02-21-hardening-pass-plan.md +1378 -0
- package/docs/plans/2026-02-21-mab-research-report.md +406 -0
- package/docs/plans/2026-02-21-marketplace-restructure-design.md +240 -0
- package/docs/plans/2026-02-21-marketplace-restructure-plan.md +832 -0
- package/docs/plans/2026-02-21-phase4-completion-plan.md +697 -0
- package/docs/plans/2026-02-21-validator-suite-design.md +148 -0
- package/docs/plans/2026-02-21-validator-suite-plan.md +540 -0
- package/docs/plans/2026-02-22-mab-research-round2.md +556 -0
- package/docs/plans/2026-02-22-mab-run-design.md +462 -0
- package/docs/plans/2026-02-22-mab-run-plan.md +2046 -0
- package/docs/plans/2026-02-22-operations-design-methodology-research.md +681 -0
- package/docs/plans/2026-02-22-research-agent-failure-taxonomy.md +532 -0
- package/docs/plans/2026-02-22-research-code-guideline-policies.md +886 -0
- package/docs/plans/2026-02-22-research-codebase-audit-refactoring.md +908 -0
- package/docs/plans/2026-02-22-research-coding-standards-documentation.md +541 -0
- package/docs/plans/2026-02-22-research-competitive-landscape.md +687 -0
- package/docs/plans/2026-02-22-research-comprehensive-testing.md +1076 -0
- package/docs/plans/2026-02-22-research-context-utilization.md +459 -0
- package/docs/plans/2026-02-22-research-cost-quality-tradeoff.md +548 -0
- package/docs/plans/2026-02-22-research-lesson-transferability.md +508 -0
- package/docs/plans/2026-02-22-research-multi-agent-coordination.md +312 -0
- package/docs/plans/2026-02-22-research-phase-integration.md +602 -0
- package/docs/plans/2026-02-22-research-plan-quality.md +428 -0
- package/docs/plans/2026-02-22-research-prompt-engineering.md +558 -0
- package/docs/plans/2026-02-22-research-unconventional-perspectives.md +528 -0
- package/docs/plans/2026-02-22-research-user-adoption.md +638 -0
- package/docs/plans/2026-02-22-research-verification-effectiveness.md +433 -0
- package/docs/plans/2026-02-23-agent-suite-design.md +299 -0
- package/docs/plans/2026-02-23-agent-suite-plan.md +578 -0
- package/docs/plans/2026-02-23-phase3-cost-infrastructure-design.md +148 -0
- package/docs/plans/2026-02-23-phase3-cost-infrastructure-plan.md +1062 -0
- package/docs/plans/2026-02-23-research-bash-expert-agent.md +543 -0
- package/docs/plans/2026-02-23-research-dependency-auditor-agent.md +564 -0
- package/docs/plans/2026-02-23-research-improving-existing-agents.md +503 -0
- package/docs/plans/2026-02-23-research-integration-tester-agent.md +454 -0
- package/docs/plans/2026-02-23-research-python-expert-agent.md +429 -0
- package/docs/plans/2026-02-23-research-service-monitor-agent.md +425 -0
- package/docs/plans/2026-02-23-research-shell-expert-agent.md +533 -0
- package/docs/plans/2026-02-23-roadmap-to-completion.md +530 -0
- package/docs/plans/2026-02-24-headless-module-split-design.md +98 -0
- package/docs/plans/2026-02-24-headless-module-split.md +443 -0
- package/docs/plans/2026-02-24-lesson-scope-metadata-design.md +228 -0
- package/docs/plans/2026-02-24-lesson-scope-metadata-plan.md +968 -0
- package/docs/plans/2026-02-24-npm-packaging-design.md +841 -0
- package/docs/plans/2026-02-24-npm-packaging-plan.md +1965 -0
- package/docs/plans/audit-findings.md +186 -0
- package/docs/telegram-notification-format.md +98 -0
- package/examples/example-plan.md +51 -0
- package/examples/example-prd.json +72 -0
- package/examples/example-roadmap.md +33 -0
- package/examples/quickstart-plan.md +63 -0
- package/hooks/hooks.json +26 -0
- package/hooks/setup-symlinks.sh +48 -0
- package/hooks/stop-hook.sh +135 -0
- package/package.json +47 -0
- package/policies/bash.md +71 -0
- package/policies/python.md +71 -0
- package/policies/testing.md +61 -0
- package/policies/universal.md +60 -0
- package/scripts/analyze-report.sh +97 -0
- package/scripts/architecture-map.sh +145 -0
- package/scripts/auto-compound.sh +273 -0
- package/scripts/batch-audit.sh +42 -0
- package/scripts/batch-test.sh +101 -0
- package/scripts/entropy-audit.sh +221 -0
- package/scripts/failure-digest.sh +51 -0
- package/scripts/generate-ast-rules.sh +96 -0
- package/scripts/init.sh +112 -0
- package/scripts/lesson-check.sh +428 -0
- package/scripts/lib/common.sh +61 -0
- package/scripts/lib/cost-tracking.sh +153 -0
- package/scripts/lib/ollama.sh +60 -0
- package/scripts/lib/progress-writer.sh +128 -0
- package/scripts/lib/run-plan-context.sh +215 -0
- package/scripts/lib/run-plan-echo-back.sh +231 -0
- package/scripts/lib/run-plan-headless.sh +396 -0
- package/scripts/lib/run-plan-notify.sh +57 -0
- package/scripts/lib/run-plan-parser.sh +81 -0
- package/scripts/lib/run-plan-prompt.sh +215 -0
- package/scripts/lib/run-plan-quality-gate.sh +132 -0
- package/scripts/lib/run-plan-routing.sh +315 -0
- package/scripts/lib/run-plan-sampling.sh +170 -0
- package/scripts/lib/run-plan-scoring.sh +146 -0
- package/scripts/lib/run-plan-state.sh +142 -0
- package/scripts/lib/run-plan-team.sh +199 -0
- package/scripts/lib/telegram.sh +54 -0
- package/scripts/lib/thompson-sampling.sh +176 -0
- package/scripts/license-check.sh +74 -0
- package/scripts/mab-run.sh +575 -0
- package/scripts/module-size-check.sh +146 -0
- package/scripts/patterns/async-no-await.yml +5 -0
- package/scripts/patterns/bare-except.yml +6 -0
- package/scripts/patterns/empty-catch.yml +6 -0
- package/scripts/patterns/hardcoded-localhost.yml +9 -0
- package/scripts/patterns/retry-loop-no-backoff.yml +12 -0
- package/scripts/pipeline-status.sh +197 -0
- package/scripts/policy-check.sh +226 -0
- package/scripts/prior-art-search.sh +133 -0
- package/scripts/promote-mab-lessons.sh +126 -0
- package/scripts/prompts/agent-a-superpowers.md +29 -0
- package/scripts/prompts/agent-b-ralph.md +29 -0
- package/scripts/prompts/judge-agent.md +61 -0
- package/scripts/prompts/planner-agent.md +44 -0
- package/scripts/pull-community-lessons.sh +90 -0
- package/scripts/quality-gate.sh +266 -0
- package/scripts/research-gate.sh +90 -0
- package/scripts/run-plan.sh +329 -0
- package/scripts/scope-infer.sh +159 -0
- package/scripts/setup-ralph-loop.sh +155 -0
- package/scripts/telemetry.sh +230 -0
- package/scripts/tests/run-all-tests.sh +52 -0
- package/scripts/tests/test-act-cli.sh +46 -0
- package/scripts/tests/test-agents-md.sh +87 -0
- package/scripts/tests/test-analyze-report.sh +114 -0
- package/scripts/tests/test-architecture-map.sh +89 -0
- package/scripts/tests/test-auto-compound.sh +169 -0
- package/scripts/tests/test-batch-test.sh +65 -0
- package/scripts/tests/test-benchmark-runner.sh +25 -0
- package/scripts/tests/test-common.sh +168 -0
- package/scripts/tests/test-cost-tracking.sh +158 -0
- package/scripts/tests/test-echo-back.sh +180 -0
- package/scripts/tests/test-entropy-audit.sh +146 -0
- package/scripts/tests/test-failure-digest.sh +66 -0
- package/scripts/tests/test-generate-ast-rules.sh +145 -0
- package/scripts/tests/test-helpers.sh +82 -0
- package/scripts/tests/test-init.sh +47 -0
- package/scripts/tests/test-lesson-check.sh +278 -0
- package/scripts/tests/test-lesson-local.sh +55 -0
- package/scripts/tests/test-license-check.sh +109 -0
- package/scripts/tests/test-mab-run.sh +182 -0
- package/scripts/tests/test-ollama-lib.sh +49 -0
- package/scripts/tests/test-ollama.sh +60 -0
- package/scripts/tests/test-pipeline-status.sh +198 -0
- package/scripts/tests/test-policy-check.sh +124 -0
- package/scripts/tests/test-prior-art-search.sh +96 -0
- package/scripts/tests/test-progress-writer.sh +140 -0
- package/scripts/tests/test-promote-mab-lessons.sh +110 -0
- package/scripts/tests/test-pull-community-lessons.sh +149 -0
- package/scripts/tests/test-quality-gate.sh +241 -0
- package/scripts/tests/test-research-gate.sh +132 -0
- package/scripts/tests/test-run-plan-cli.sh +86 -0
- package/scripts/tests/test-run-plan-context.sh +305 -0
- package/scripts/tests/test-run-plan-e2e.sh +153 -0
- package/scripts/tests/test-run-plan-headless.sh +424 -0
- package/scripts/tests/test-run-plan-notify.sh +124 -0
- package/scripts/tests/test-run-plan-parser.sh +217 -0
- package/scripts/tests/test-run-plan-prompt.sh +254 -0
- package/scripts/tests/test-run-plan-quality-gate.sh +222 -0
- package/scripts/tests/test-run-plan-routing.sh +178 -0
- package/scripts/tests/test-run-plan-scoring.sh +148 -0
- package/scripts/tests/test-run-plan-state.sh +261 -0
- package/scripts/tests/test-run-plan-team.sh +157 -0
- package/scripts/tests/test-scope-infer.sh +150 -0
- package/scripts/tests/test-setup-ralph-loop.sh +63 -0
- package/scripts/tests/test-telegram-env.sh +38 -0
- package/scripts/tests/test-telegram.sh +121 -0
- package/scripts/tests/test-telemetry.sh +46 -0
- package/scripts/tests/test-thompson-sampling.sh +139 -0
- package/scripts/tests/test-validate-all.sh +60 -0
- package/scripts/tests/test-validate-commands.sh +89 -0
- package/scripts/tests/test-validate-hooks.sh +98 -0
- package/scripts/tests/test-validate-lessons.sh +150 -0
- package/scripts/tests/test-validate-plan-quality.sh +235 -0
- package/scripts/tests/test-validate-plans.sh +187 -0
- package/scripts/tests/test-validate-plugin.sh +106 -0
- package/scripts/tests/test-validate-prd.sh +184 -0
- package/scripts/tests/test-validate-skills.sh +134 -0
- package/scripts/validate-all.sh +57 -0
- package/scripts/validate-commands.sh +67 -0
- package/scripts/validate-hooks.sh +89 -0
- package/scripts/validate-lessons.sh +98 -0
- package/scripts/validate-plan-quality.sh +369 -0
- package/scripts/validate-plans.sh +120 -0
- package/scripts/validate-plugin.sh +86 -0
- package/scripts/validate-policies.sh +42 -0
- package/scripts/validate-prd.sh +118 -0
- package/scripts/validate-skills.sh +96 -0
- package/skills/autocode/SKILL.md +285 -0
- package/skills/autocode/ab-verification.md +51 -0
- package/skills/autocode/code-quality-standards.md +37 -0
- package/skills/autocode/competitive-mode.md +364 -0
- package/skills/brainstorming/SKILL.md +97 -0
- package/skills/capture-lesson/SKILL.md +187 -0
- package/skills/check-lessons/SKILL.md +116 -0
- package/skills/dispatching-parallel-agents/SKILL.md +110 -0
- package/skills/executing-plans/SKILL.md +85 -0
- package/skills/finishing-a-development-branch/SKILL.md +201 -0
- package/skills/receiving-code-review/SKILL.md +72 -0
- package/skills/requesting-code-review/SKILL.md +59 -0
- package/skills/requesting-code-review/code-reviewer.md +82 -0
- package/skills/research/SKILL.md +145 -0
- package/skills/roadmap/SKILL.md +115 -0
- package/skills/subagent-driven-development/SKILL.md +98 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +18 -0
- package/skills/subagent-driven-development/implementer-prompt.md +73 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +57 -0
- package/skills/systematic-debugging/SKILL.md +134 -0
- package/skills/systematic-debugging/condition-based-waiting.md +64 -0
- package/skills/systematic-debugging/defense-in-depth.md +32 -0
- package/skills/systematic-debugging/root-cause-tracing.md +55 -0
- package/skills/test-driven-development/SKILL.md +167 -0
- package/skills/using-git-worktrees/SKILL.md +219 -0
- package/skills/using-superpowers/SKILL.md +54 -0
- package/skills/verification-before-completion/SKILL.md +140 -0
- package/skills/verify/SKILL.md +82 -0
- package/skills/writing-plans/SKILL.md +128 -0
- package/skills/writing-skills/SKILL.md +93 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# module-size-check.sh — Enforce module size limits across the toolkit
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# module-size-check.sh [options] [path...]
|
|
6
|
+
#
|
|
7
|
+
# Options:
|
|
8
|
+
# --max-lines N Maximum allowed lines per file (default: 300)
|
|
9
|
+
# --exclude PATTERN Glob pattern to exclude (repeatable)
|
|
10
|
+
# --json Output as JSON (for quality-gate integration)
|
|
11
|
+
# --fix-suggestions Include suggested split strategies in output
|
|
12
|
+
# --warn-at N Warn (don't fail) for files between warn-at and max-lines
|
|
13
|
+
# --project-root DIR Project root (default: git root or cwd)
|
|
14
|
+
#
|
|
15
|
+
# If no paths given, scans scripts/**/*.sh (excluding tests/).
|
|
16
|
+
#
|
|
17
|
+
# Exit codes:
|
|
18
|
+
# 0 — all files within limit
|
|
19
|
+
# 1 — one or more files exceed limit
|
|
20
|
+
# 2 — usage error
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
MAX_LINES=300
|
|
24
|
+
WARN_AT=250
|
|
25
|
+
EXCLUDES=()
|
|
26
|
+
JSON=false
|
|
27
|
+
FIX_SUGGESTIONS=false
|
|
28
|
+
PROJECT_ROOT=""
|
|
29
|
+
PATHS=()
|
|
30
|
+
|
|
31
|
+
while [[ $# -gt 0 ]]; do
|
|
32
|
+
case "$1" in
|
|
33
|
+
--max-lines) MAX_LINES="$2"; shift 2 ;;
|
|
34
|
+
--exclude) EXCLUDES+=("$2"); shift 2 ;;
|
|
35
|
+
--json) JSON=true; shift ;;
|
|
36
|
+
--fix-suggestions) FIX_SUGGESTIONS=true; shift ;;
|
|
37
|
+
--warn-at) WARN_AT="$2"; shift 2 ;;
|
|
38
|
+
--project-root) PROJECT_ROOT="$2"; shift 2 ;;
|
|
39
|
+
--help|-h)
|
|
40
|
+
head -20 "$0" | tail -18
|
|
41
|
+
exit 0
|
|
42
|
+
;;
|
|
43
|
+
-*) echo "Unknown option: $1" >&2; exit 2 ;;
|
|
44
|
+
*) PATHS+=("$1"); shift ;;
|
|
45
|
+
esac
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
# Resolve project root
|
|
49
|
+
if [[ -z "$PROJECT_ROOT" ]]; then
|
|
50
|
+
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Default scan paths
|
|
54
|
+
if [[ ${#PATHS[@]} -eq 0 ]]; then
|
|
55
|
+
PATHS=("$PROJECT_ROOT/scripts")
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Collect files
|
|
59
|
+
files=()
|
|
60
|
+
for path in "${PATHS[@]}"; do
|
|
61
|
+
if [[ -f "$path" ]]; then
|
|
62
|
+
files+=("$path")
|
|
63
|
+
elif [[ -d "$path" ]]; then
|
|
64
|
+
while IFS= read -r f; do
|
|
65
|
+
files+=("$f")
|
|
66
|
+
done < <(find "$path" -name '*.sh' -not -path '*/tests/*' -not -path '*/.git/*' | sort)
|
|
67
|
+
fi
|
|
68
|
+
done
|
|
69
|
+
|
|
70
|
+
# Apply excludes
|
|
71
|
+
if [[ ${#EXCLUDES[@]} -gt 0 ]]; then
|
|
72
|
+
filtered=()
|
|
73
|
+
for f in "${files[@]}"; do
|
|
74
|
+
skip=false
|
|
75
|
+
for pattern in "${EXCLUDES[@]}"; do
|
|
76
|
+
if [[ "$f" == *"$pattern"* ]]; then
|
|
77
|
+
skip=true
|
|
78
|
+
break
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
[[ "$skip" == false ]] && filtered+=("$f")
|
|
82
|
+
done
|
|
83
|
+
files=("${filtered[@]}")
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Check each file
|
|
87
|
+
violations=0
|
|
88
|
+
warnings=0
|
|
89
|
+
json_entries=()
|
|
90
|
+
|
|
91
|
+
for file in "${files[@]}"; do
|
|
92
|
+
lines=$(wc -l < "$file")
|
|
93
|
+
rel_path="${file#"$PROJECT_ROOT/"}"
|
|
94
|
+
|
|
95
|
+
if [[ $lines -gt $MAX_LINES ]]; then
|
|
96
|
+
violations=$((violations + 1))
|
|
97
|
+
over=$((lines - MAX_LINES))
|
|
98
|
+
|
|
99
|
+
if [[ "$JSON" == true ]]; then
|
|
100
|
+
json_entries+=("{\"file\":\"$rel_path\",\"lines\":$lines,\"limit\":$MAX_LINES,\"over\":$over,\"severity\":\"error\"}")
|
|
101
|
+
else
|
|
102
|
+
echo "ERROR: $rel_path: $lines lines (limit: $MAX_LINES, over by $over)"
|
|
103
|
+
if [[ "$FIX_SUGGESTIONS" == true ]]; then
|
|
104
|
+
# Count functions as a rough split indicator
|
|
105
|
+
func_count=$(grep -cE '^[a-zA-Z_][a-zA-Z_0-9]*\(\)\s*\{' "$file" 2>/dev/null || echo "0")
|
|
106
|
+
if [[ $func_count -gt 1 ]]; then
|
|
107
|
+
echo " Suggestion: $func_count functions detected — extract into separate lib modules"
|
|
108
|
+
else
|
|
109
|
+
echo " Suggestion: look for inline blocks (loops, conditionals) that can become functions"
|
|
110
|
+
fi
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
elif [[ $lines -gt $WARN_AT ]]; then
|
|
114
|
+
warnings=$((warnings + 1))
|
|
115
|
+
if [[ "$JSON" == true ]]; then
|
|
116
|
+
json_entries+=("{\"file\":\"$rel_path\",\"lines\":$lines,\"limit\":$MAX_LINES,\"severity\":\"warning\"}")
|
|
117
|
+
else
|
|
118
|
+
echo "WARNING: $rel_path: $lines lines (approaching limit of $MAX_LINES)"
|
|
119
|
+
fi
|
|
120
|
+
fi
|
|
121
|
+
done
|
|
122
|
+
|
|
123
|
+
# Output
|
|
124
|
+
if [[ "$JSON" == true ]]; then
|
|
125
|
+
echo "["
|
|
126
|
+
for ((i = 0; i < ${#json_entries[@]}; i++)); do
|
|
127
|
+
if [[ $i -lt $((${#json_entries[@]} - 1)) ]]; then
|
|
128
|
+
echo " ${json_entries[$i]},"
|
|
129
|
+
else
|
|
130
|
+
echo " ${json_entries[$i]}"
|
|
131
|
+
fi
|
|
132
|
+
done
|
|
133
|
+
echo "]"
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Summary
|
|
137
|
+
total=${#files[@]}
|
|
138
|
+
if [[ "$JSON" != true ]]; then
|
|
139
|
+
echo ""
|
|
140
|
+
echo "Scanned $total files: $violations errors, $warnings warnings (limit: $MAX_LINES, warn: $WARN_AT)"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
if [[ $violations -gt 0 ]]; then
|
|
144
|
+
exit 1
|
|
145
|
+
fi
|
|
146
|
+
exit 0
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
id: hardcoded-localhost
|
|
2
|
+
message: "Hardcoded localhost URL — use environment variable or configuration for host/port"
|
|
3
|
+
severity: warning
|
|
4
|
+
language: python
|
|
5
|
+
rule:
|
|
6
|
+
any:
|
|
7
|
+
- pattern: '"http://localhost:$PORT$REST"'
|
|
8
|
+
- pattern: '"http://127.0.0.1:$PORT$REST"'
|
|
9
|
+
note: "Hardcoded URLs break in containers, CI, and multi-host deployments"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
id: retry-loop-no-backoff
|
|
2
|
+
message: "Retry loop without backoff — add exponential backoff or sleep between retries"
|
|
3
|
+
severity: warning
|
|
4
|
+
language: python
|
|
5
|
+
rule:
|
|
6
|
+
pattern: |
|
|
7
|
+
for $_ in range($RETRIES):
|
|
8
|
+
try:
|
|
9
|
+
$$$BODY
|
|
10
|
+
except $EXC:
|
|
11
|
+
$$$HANDLER
|
|
12
|
+
note: "Tight retry loops without backoff can DDoS external services and hide transient failures"
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# pipeline-status.sh — Single-command view of Code Factory pipeline status
|
|
3
|
+
#
|
|
4
|
+
# Usage: pipeline-status.sh [--help] [--show-costs] [project-root]
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
|
|
8
|
+
source "$SCRIPT_DIR/lib/common.sh"
|
|
9
|
+
|
|
10
|
+
SHOW_COSTS=false
|
|
11
|
+
PROJECT_ROOT=""
|
|
12
|
+
|
|
13
|
+
# Parse arguments
|
|
14
|
+
for arg in "$@"; do
|
|
15
|
+
case "$arg" in
|
|
16
|
+
--help|-h)
|
|
17
|
+
echo "pipeline-status.sh — Show Code Factory pipeline status"
|
|
18
|
+
echo "Usage: pipeline-status.sh [--show-costs] [project-root]"
|
|
19
|
+
echo ""
|
|
20
|
+
echo "Options:"
|
|
21
|
+
echo " --show-costs Show per-batch cost breakdown from state file"
|
|
22
|
+
exit 0
|
|
23
|
+
;;
|
|
24
|
+
--show-costs)
|
|
25
|
+
SHOW_COSTS=true
|
|
26
|
+
;;
|
|
27
|
+
*)
|
|
28
|
+
PROJECT_ROOT="$arg"
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
PROJECT_ROOT="${PROJECT_ROOT:-.}"
|
|
34
|
+
|
|
35
|
+
echo "═══════════════════════════════════════════════"
|
|
36
|
+
echo " Code Factory Pipeline Status"
|
|
37
|
+
echo "═══════════════════════════════════════════════"
|
|
38
|
+
echo "Project: $(basename "$(realpath "$PROJECT_ROOT")")"
|
|
39
|
+
echo "Type: $(detect_project_type "$PROJECT_ROOT")"
|
|
40
|
+
echo ""
|
|
41
|
+
|
|
42
|
+
# Run-plan state
|
|
43
|
+
STATE_FILE="$PROJECT_ROOT/.run-plan-state.json"
|
|
44
|
+
if [[ -f "$STATE_FILE" ]]; then
|
|
45
|
+
echo "--- Run Plan ---"
|
|
46
|
+
plan=$(jq -r '.plan_file // "unknown"' "$STATE_FILE")
|
|
47
|
+
mode=$(jq -r '.mode // "unknown"' "$STATE_FILE")
|
|
48
|
+
current=$(jq -r '.current_batch // 0' "$STATE_FILE")
|
|
49
|
+
completed=$(jq -r '.completed_batches | length' "$STATE_FILE")
|
|
50
|
+
started=$(jq -r '.started_at // "unknown"' "$STATE_FILE")
|
|
51
|
+
echo " Plan: $(basename "$plan")"
|
|
52
|
+
echo " Mode: $mode"
|
|
53
|
+
echo " Progress: $completed batches completed (current: $current)"
|
|
54
|
+
echo " Started: $started"
|
|
55
|
+
|
|
56
|
+
# Last quality gate
|
|
57
|
+
gate_passed=$(jq -r '.last_quality_gate.passed // "n/a"' "$STATE_FILE")
|
|
58
|
+
gate_tests=$(jq -r '.last_quality_gate.test_count // "n/a"' "$STATE_FILE")
|
|
59
|
+
echo " Last gate: passed=$gate_passed, tests=$gate_tests"
|
|
60
|
+
|
|
61
|
+
# Cost summary: total from state file costs map (if present)
|
|
62
|
+
# Fix #70: .costs values may be objects (from record_batch_cost) or plain numbers/strings (legacy).
|
|
63
|
+
# Try .estimated_cost_usd first, then tonumber for backward compat.
|
|
64
|
+
total_cost=$(jq -r '
|
|
65
|
+
if .costs then
|
|
66
|
+
(.costs | to_entries | map(
|
|
67
|
+
if .value | type == "object" then (.value.estimated_cost_usd // 0)
|
|
68
|
+
else (.value | tonumber? // 0) end
|
|
69
|
+
) | add // 0)
|
|
70
|
+
else 0 end
|
|
71
|
+
' "$STATE_FILE" 2>/dev/null || echo "0")
|
|
72
|
+
if [[ "$total_cost" != "0" && "$total_cost" != "null" && -n "$total_cost" ]]; then
|
|
73
|
+
echo " Total cost: \$$total_cost"
|
|
74
|
+
fi
|
|
75
|
+
echo ""
|
|
76
|
+
else
|
|
77
|
+
echo "--- Run Plan ---"
|
|
78
|
+
echo " No active run-plan state found"
|
|
79
|
+
echo ""
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# PRD status
|
|
83
|
+
if [[ -f "$PROJECT_ROOT/tasks/prd.json" ]]; then
|
|
84
|
+
echo "--- PRD ---"
|
|
85
|
+
total=$(jq 'length' "$PROJECT_ROOT/tasks/prd.json")
|
|
86
|
+
passing=$(jq '[.[] | select(.passes == true)] | length' "$PROJECT_ROOT/tasks/prd.json")
|
|
87
|
+
echo " Tasks: $passing/$total passing"
|
|
88
|
+
echo ""
|
|
89
|
+
else
|
|
90
|
+
echo "--- PRD ---"
|
|
91
|
+
echo " No PRD found (tasks/prd.json)"
|
|
92
|
+
echo ""
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# MAB status
|
|
96
|
+
PERF_FILE="$PROJECT_ROOT/logs/strategy-perf.json"
|
|
97
|
+
LESSONS_FILE="$PROJECT_ROOT/logs/mab-lessons.json"
|
|
98
|
+
if [[ -f "$PERF_FILE" ]]; then
|
|
99
|
+
echo "--- MAB (Multi-Armed Bandit) ---"
|
|
100
|
+
cal_count=$(jq -r '.calibration_count // 0' "$PERF_FILE" 2>/dev/null)
|
|
101
|
+
cal_complete=$(jq -r '.calibration_complete // false' "$PERF_FILE" 2>/dev/null)
|
|
102
|
+
echo " Calibration: $cal_count/10 (complete: $cal_complete)"
|
|
103
|
+
|
|
104
|
+
# Per-type win rates
|
|
105
|
+
for bt in "new-file" "refactoring" "integration" "test-only"; do
|
|
106
|
+
sp_w=$(jq -r --arg bt "$bt" '.[$bt].superpowers.wins // 0' "$PERF_FILE" 2>/dev/null)
|
|
107
|
+
sp_l=$(jq -r --arg bt "$bt" '.[$bt].superpowers.losses // 0' "$PERF_FILE" 2>/dev/null)
|
|
108
|
+
r_w=$(jq -r --arg bt "$bt" '.[$bt].ralph.wins // 0' "$PERF_FILE" 2>/dev/null)
|
|
109
|
+
r_l=$(jq -r --arg bt "$bt" '.[$bt].ralph.losses // 0' "$PERF_FILE" 2>/dev/null)
|
|
110
|
+
sp_total=$((sp_w + sp_l))
|
|
111
|
+
r_total=$((r_w + r_l))
|
|
112
|
+
if [[ $sp_total -gt 0 || $r_total -gt 0 ]]; then
|
|
113
|
+
echo " $bt: superpowers=${sp_w}W/${sp_l}L ralph=${r_w}W/${r_l}L"
|
|
114
|
+
fi
|
|
115
|
+
done
|
|
116
|
+
|
|
117
|
+
# Lesson count
|
|
118
|
+
if [[ -f "$LESSONS_FILE" ]]; then
|
|
119
|
+
lesson_count=$(jq 'length' "$LESSONS_FILE" 2>/dev/null || echo "0")
|
|
120
|
+
echo " Lessons: $lesson_count patterns recorded"
|
|
121
|
+
fi
|
|
122
|
+
echo ""
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Cost breakdown (--show-costs) (#42/#43)
|
|
126
|
+
# Filter to numeric-only batch keys before sort to avoid tonumber crash on "final" or other non-numeric keys.
|
|
127
|
+
if [[ "$SHOW_COSTS" == "true" && -f "$STATE_FILE" ]]; then
|
|
128
|
+
echo "--- Cost Breakdown ---"
|
|
129
|
+
has_costs=$(jq -r 'if .costs then "yes" else "no" end' "$STATE_FILE" 2>/dev/null || echo "no")
|
|
130
|
+
if [[ "$has_costs" == "yes" ]]; then
|
|
131
|
+
jq -r '
|
|
132
|
+
.costs // {} |
|
|
133
|
+
to_entries |
|
|
134
|
+
[.[] | select(.key | test("^[0-9]+$"))] |
|
|
135
|
+
sort_by(.key | tonumber) |
|
|
136
|
+
.[] |
|
|
137
|
+
" Batch \(.key): $\(if .value | type == "object" then .value.estimated_cost_usd // 0 else .value end)"
|
|
138
|
+
' "$STATE_FILE" 2>/dev/null || echo " (cost data unreadable)"
|
|
139
|
+
else
|
|
140
|
+
echo " No cost data in state file"
|
|
141
|
+
fi
|
|
142
|
+
echo ""
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Progress file
|
|
146
|
+
if [[ -f "$PROJECT_ROOT/progress.txt" ]]; then
|
|
147
|
+
echo "--- Progress ---"
|
|
148
|
+
tail -5 "$PROJECT_ROOT/progress.txt" | sed 's/^/ /'
|
|
149
|
+
echo ""
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Routing decisions
|
|
153
|
+
if [[ -f "$PROJECT_ROOT/logs/routing-decisions.log" ]]; then
|
|
154
|
+
echo "--- Routing Decisions ---"
|
|
155
|
+
tail -20 "$PROJECT_ROOT/logs/routing-decisions.log" | sed 's/^/ /'
|
|
156
|
+
echo ""
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# Git status
|
|
160
|
+
echo "--- Git ---"
|
|
161
|
+
branch=$(git -C "$PROJECT_ROOT" branch --show-current 2>/dev/null || echo "unknown")
|
|
162
|
+
uncommitted=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null | wc -l || echo 0)
|
|
163
|
+
echo " Branch: $branch"
|
|
164
|
+
echo " Uncommitted: $uncommitted files"
|
|
165
|
+
|
|
166
|
+
# Detailed cost breakdown (only with --show-costs)
|
|
167
|
+
if [[ "$SHOW_COSTS" == true && -f "$STATE_FILE" ]]; then
|
|
168
|
+
echo ""
|
|
169
|
+
echo "--- Cost Details ---"
|
|
170
|
+
jq -r '
|
|
171
|
+
.costs // {} | to_entries | sort_by(.key | tonumber) |
|
|
172
|
+
.[] | " Batch \(.key): $\(.value.estimated_cost_usd) | \(.value.input_tokens) in | \(.value.output_tokens) out | cache: \(.value.cache_read_tokens) read | \(.value.model // "unknown")"
|
|
173
|
+
' "$STATE_FILE" 2>/dev/null || echo " No cost data"
|
|
174
|
+
total=$(jq -r '.total_cost_usd // 0' "$STATE_FILE")
|
|
175
|
+
echo " Total: \$${total}"
|
|
176
|
+
echo ""
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Trust score (from telemetry)
|
|
180
|
+
if [[ -x "$SCRIPT_DIR/telemetry.sh" ]]; then
|
|
181
|
+
trust_json=$("$SCRIPT_DIR/telemetry.sh" trust --project-root "$PROJECT_ROOT" 2>/dev/null || echo '{}')
|
|
182
|
+
trust_score=$(echo "$trust_json" | jq -r '.score // "n/a"' 2>/dev/null || echo "n/a")
|
|
183
|
+
trust_level=$(echo "$trust_json" | jq -r '.level // "unknown"' 2>/dev/null || echo "unknown")
|
|
184
|
+
trust_runs=$(echo "$trust_json" | jq -r '.runs // 0' 2>/dev/null || echo "0")
|
|
185
|
+
trust_mode=$(echo "$trust_json" | jq -r '.default_mode // "unknown"' 2>/dev/null || echo "unknown")
|
|
186
|
+
|
|
187
|
+
if [[ "$trust_score" != "n/a" && "$trust_runs" != "0" ]]; then
|
|
188
|
+
echo ""
|
|
189
|
+
echo "--- Trust Score ---"
|
|
190
|
+
echo " Score: ${trust_score}/100 ($trust_runs runs)"
|
|
191
|
+
echo " Level: $trust_level"
|
|
192
|
+
echo " Default mode: $trust_mode"
|
|
193
|
+
fi
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
echo ""
|
|
197
|
+
echo "═══════════════════════════════════════════════"
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# policy-check.sh — Advisory policy checker
|
|
3
|
+
#
|
|
4
|
+
# Usage: policy-check.sh [--project-root <dir>] [--strict] [--scope <tags>]
|
|
5
|
+
#
|
|
6
|
+
# Reads policies/*.md and checks project files for violations.
|
|
7
|
+
# Advisory mode by default (always exits 0).
|
|
8
|
+
# --strict: exit 1 on any violation.
|
|
9
|
+
#
|
|
10
|
+
# Policy files are markdown with code blocks showing positive patterns.
|
|
11
|
+
# This script checks for the ABSENCE of positive patterns (anti-patterns).
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
|
|
16
|
+
TOOLKIT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
17
|
+
PROJECT_ROOT="."
|
|
18
|
+
STRICT=false
|
|
19
|
+
SCOPE_FILTER=""
|
|
20
|
+
VIOLATIONS=0
|
|
21
|
+
|
|
22
|
+
usage() {
|
|
23
|
+
cat <<'EOF'
|
|
24
|
+
policy-check.sh — Advisory policy checker
|
|
25
|
+
|
|
26
|
+
USAGE:
|
|
27
|
+
policy-check.sh [OPTIONS]
|
|
28
|
+
|
|
29
|
+
OPTIONS:
|
|
30
|
+
--project-root <dir> Project to check (default: current directory)
|
|
31
|
+
--strict Exit 1 on violations (default: advisory, always exit 0)
|
|
32
|
+
--scope <tags> Comma-separated scope tags to filter policies
|
|
33
|
+
-h, --help Show this help
|
|
34
|
+
|
|
35
|
+
POLICIES:
|
|
36
|
+
Reads from policies/ directory in the toolkit root.
|
|
37
|
+
Each .md file defines positive patterns for a language or domain.
|
|
38
|
+
|
|
39
|
+
EXIT CODES:
|
|
40
|
+
0 Advisory mode (default) — always exits 0, prints violations to stdout
|
|
41
|
+
0 Strict mode — no violations found
|
|
42
|
+
1 Strict mode — violations found
|
|
43
|
+
EOF
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# Parse args
|
|
47
|
+
while [[ $# -gt 0 ]]; do
|
|
48
|
+
case $1 in
|
|
49
|
+
--project-root) PROJECT_ROOT="$2"; shift 2 ;;
|
|
50
|
+
--strict) STRICT=true; shift ;;
|
|
51
|
+
--scope) SCOPE_FILTER="$2"; shift 2 ;;
|
|
52
|
+
-h|--help) usage; exit 0 ;;
|
|
53
|
+
-*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
54
|
+
*) PROJECT_ROOT="$1"; shift ;;
|
|
55
|
+
esac
|
|
56
|
+
done
|
|
57
|
+
|
|
58
|
+
if [[ ! -d "$PROJECT_ROOT" ]]; then
|
|
59
|
+
echo "Error: project directory not found: $PROJECT_ROOT" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
POLICY_DIR="$TOOLKIT_ROOT/policies"
|
|
64
|
+
if [[ ! -d "$POLICY_DIR" ]]; then
|
|
65
|
+
echo "Error: policies directory not found: $POLICY_DIR" >&2
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# Detect project language
|
|
70
|
+
detect_language() {
|
|
71
|
+
local dir="$1"
|
|
72
|
+
local langs=""
|
|
73
|
+
if [[ -f "$dir/setup.py" ]] || [[ -f "$dir/pyproject.toml" ]] || [[ -f "$dir/requirements.txt" ]]; then
|
|
74
|
+
langs+="python "
|
|
75
|
+
fi
|
|
76
|
+
if [[ -f "$dir/package.json" ]]; then
|
|
77
|
+
langs+="node "
|
|
78
|
+
fi
|
|
79
|
+
# Check for shell scripts
|
|
80
|
+
if find "$dir" -maxdepth 2 -name '*.sh' -print -quit 2>/dev/null | grep -q .; then
|
|
81
|
+
langs+="bash "
|
|
82
|
+
fi
|
|
83
|
+
if [[ -f "$dir/Makefile" ]]; then
|
|
84
|
+
langs+="make "
|
|
85
|
+
fi
|
|
86
|
+
echo "$langs"
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Check: bash scripts have strict mode
|
|
90
|
+
check_bash_strict_mode() {
|
|
91
|
+
local dir="$1"
|
|
92
|
+
local count=0
|
|
93
|
+
while IFS= read -r script; do
|
|
94
|
+
[[ -z "$script" ]] && continue
|
|
95
|
+
# Library files (sourced, not executed directly) inherit strict mode
|
|
96
|
+
if [[ "$(basename "$(dirname "$script")")" == "lib" ]]; then
|
|
97
|
+
continue
|
|
98
|
+
fi
|
|
99
|
+
if ! head -15 "$script" | grep -q 'set -.*e'; then
|
|
100
|
+
echo " POLICY: $script — missing strict mode (set -euo pipefail)"
|
|
101
|
+
count=$((count + 1))
|
|
102
|
+
fi
|
|
103
|
+
done < <(find "$dir" -name '*.sh' -not -path '*/.git/*' -not -path '*/node_modules/*' 2>/dev/null)
|
|
104
|
+
return $count
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Check: bash scripts quote variables in conditionals
|
|
108
|
+
check_bash_quoting() {
|
|
109
|
+
local dir="$1"
|
|
110
|
+
local count=0
|
|
111
|
+
while IFS= read -r script; do
|
|
112
|
+
[[ -z "$script" ]] && continue
|
|
113
|
+
# Look for unquoted $VAR in [[ ]] conditionals (simplified check)
|
|
114
|
+
if grep -En '\[\[.*\$[A-Za-z_]+[^"}\]]' "$script" 2>/dev/null | grep -v '#' | head -3 | grep -q .; then
|
|
115
|
+
echo " POLICY: $script — possible unquoted variable in conditional"
|
|
116
|
+
count=$((count + 1))
|
|
117
|
+
fi
|
|
118
|
+
done < <(find "$dir" -name '*.sh' -not -path '*/.git/*' -not -path '*/node_modules/*' 2>/dev/null)
|
|
119
|
+
return $count
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Check: python files use closing() for sqlite
|
|
123
|
+
check_python_sqlite_closing() {
|
|
124
|
+
local dir="$1"
|
|
125
|
+
local count=0
|
|
126
|
+
while IFS= read -r pyfile; do
|
|
127
|
+
[[ -z "$pyfile" ]] && continue
|
|
128
|
+
if grep -q 'sqlite3\.connect' "$pyfile" 2>/dev/null; then
|
|
129
|
+
if ! grep -q 'closing(' "$pyfile" 2>/dev/null; then
|
|
130
|
+
echo " POLICY: $pyfile — sqlite3.connect without closing() context manager"
|
|
131
|
+
count=$((count + 1))
|
|
132
|
+
fi
|
|
133
|
+
fi
|
|
134
|
+
done < <(find "$dir" -name '*.py' -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/.venv/*' 2>/dev/null)
|
|
135
|
+
return $count
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# Check: python async defs have await
|
|
139
|
+
check_python_async_await() {
|
|
140
|
+
local dir="$1"
|
|
141
|
+
local count=0
|
|
142
|
+
# This is a simplified heuristic — the lesson-scanner does deeper analysis
|
|
143
|
+
while IFS= read -r pyfile; do
|
|
144
|
+
[[ -z "$pyfile" ]] && continue
|
|
145
|
+
# Find async def functions and check if they contain await
|
|
146
|
+
if grep -q 'async def' "$pyfile" 2>/dev/null; then
|
|
147
|
+
# Very rough check: file has async def but no await at all
|
|
148
|
+
if ! grep -q 'await ' "$pyfile" 2>/dev/null; then
|
|
149
|
+
echo " POLICY: $pyfile — async def without any await (may be unnecessary async)"
|
|
150
|
+
count=$((count + 1))
|
|
151
|
+
fi
|
|
152
|
+
fi
|
|
153
|
+
done < <(find "$dir" -name '*.py' -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/.venv/*' 2>/dev/null)
|
|
154
|
+
return $count
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Check: test files don't have hardcoded counts
|
|
158
|
+
check_test_hardcoded_counts() {
|
|
159
|
+
local dir="$1"
|
|
160
|
+
local count=0
|
|
161
|
+
while IFS= read -r testfile; do
|
|
162
|
+
[[ -z "$testfile" ]] && continue
|
|
163
|
+
# Look for exact equality assertions on counts
|
|
164
|
+
if grep -En 'assert.*==[[:space:]]*[0-9]{2,}|assertEquals.*[0-9]{2,}|-eq[[:space:]]+[0-9]{2,}' "$testfile" 2>/dev/null | head -3 | grep -q .; then
|
|
165
|
+
echo " POLICY: $testfile — possible hardcoded test count assertion"
|
|
166
|
+
count=$((count + 1))
|
|
167
|
+
fi
|
|
168
|
+
done < <(find "$dir" \( -name 'test_*.py' -o -name '*_test.py' -o -name 'test-*.sh' -o -name '*.test.js' -o -name '*.test.ts' \) -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/.venv/*' 2>/dev/null)
|
|
169
|
+
return $count
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# Main
|
|
173
|
+
echo "POLICY CHECK: $PROJECT_ROOT"
|
|
174
|
+
echo ""
|
|
175
|
+
|
|
176
|
+
languages=$(detect_language "$PROJECT_ROOT")
|
|
177
|
+
echo "Detected languages: ${languages:-none}"
|
|
178
|
+
echo ""
|
|
179
|
+
|
|
180
|
+
# Run applicable checks
|
|
181
|
+
for policy_file in "$POLICY_DIR"/*.md; do
|
|
182
|
+
policy_name=$(basename "$policy_file" .md)
|
|
183
|
+
|
|
184
|
+
case "$policy_name" in
|
|
185
|
+
universal)
|
|
186
|
+
echo "Checking: universal policies"
|
|
187
|
+
# Universal checks are mostly process-level, hard to check statically
|
|
188
|
+
echo " (process-level policies — checked by skill, not script)"
|
|
189
|
+
echo ""
|
|
190
|
+
;;
|
|
191
|
+
bash)
|
|
192
|
+
if echo "$languages" | grep -q 'bash'; then
|
|
193
|
+
echo "Checking: bash policies"
|
|
194
|
+
violations_before=$VIOLATIONS
|
|
195
|
+
check_bash_strict_mode "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
|
|
196
|
+
echo ""
|
|
197
|
+
fi
|
|
198
|
+
;;
|
|
199
|
+
python)
|
|
200
|
+
if echo "$languages" | grep -q 'python'; then
|
|
201
|
+
echo "Checking: python policies"
|
|
202
|
+
check_python_sqlite_closing "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
|
|
203
|
+
check_python_async_await "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
|
|
204
|
+
echo ""
|
|
205
|
+
fi
|
|
206
|
+
;;
|
|
207
|
+
testing)
|
|
208
|
+
echo "Checking: testing policies"
|
|
209
|
+
check_test_hardcoded_counts "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
|
|
210
|
+
echo ""
|
|
211
|
+
;;
|
|
212
|
+
esac
|
|
213
|
+
done
|
|
214
|
+
|
|
215
|
+
# Summary
|
|
216
|
+
echo "─────────────────────────────────────"
|
|
217
|
+
if [[ $VIOLATIONS -gt 0 ]]; then
|
|
218
|
+
echo "POLICY CHECK: $VIOLATIONS violation(s) found"
|
|
219
|
+
if [[ "$STRICT" == "true" ]]; then
|
|
220
|
+
exit 1
|
|
221
|
+
fi
|
|
222
|
+
else
|
|
223
|
+
echo "POLICY CHECK: clean (no violations)"
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
exit 0
|