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,424 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test run-plan-headless.sh extraction
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
RP="$SCRIPT_DIR/../run-plan.sh"
|
|
7
|
+
RPH="$SCRIPT_DIR/../lib/run-plan-headless.sh"
|
|
8
|
+
RPEB="$SCRIPT_DIR/../lib/run-plan-echo-back.sh"
|
|
9
|
+
RPS="$SCRIPT_DIR/../lib/run-plan-sampling.sh"
|
|
10
|
+
|
|
11
|
+
FAILURES=0
|
|
12
|
+
TESTS=0
|
|
13
|
+
|
|
14
|
+
assert_eq() {
|
|
15
|
+
local desc="$1" expected="$2" actual="$3"
|
|
16
|
+
TESTS=$((TESTS + 1))
|
|
17
|
+
if [[ "$expected" != "$actual" ]]; then
|
|
18
|
+
echo "FAIL: $desc"
|
|
19
|
+
echo " expected: $expected"
|
|
20
|
+
echo " actual: $actual"
|
|
21
|
+
FAILURES=$((FAILURES + 1))
|
|
22
|
+
else
|
|
23
|
+
echo "PASS: $desc"
|
|
24
|
+
fi
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# === Extracted file exists ===
|
|
28
|
+
|
|
29
|
+
TESTS=$((TESTS + 1))
|
|
30
|
+
if [[ -f "$RPH" ]]; then
|
|
31
|
+
echo "PASS: run-plan-headless.sh exists"
|
|
32
|
+
else
|
|
33
|
+
echo "FAIL: run-plan-headless.sh should exist at scripts/lib/"
|
|
34
|
+
FAILURES=$((FAILURES + 1))
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# === Extracted echo-back file exists ===
|
|
38
|
+
TESTS=$((TESTS + 1))
|
|
39
|
+
if [[ -f "$RPEB" ]]; then
|
|
40
|
+
echo "PASS: run-plan-echo-back.sh exists"
|
|
41
|
+
else
|
|
42
|
+
echo "FAIL: run-plan-echo-back.sh should exist at scripts/lib/"
|
|
43
|
+
FAILURES=$((FAILURES + 1))
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# === Extracted sampling file exists ===
|
|
47
|
+
TESTS=$((TESTS + 1))
|
|
48
|
+
if [[ -f "$RPS" ]]; then
|
|
49
|
+
echo "PASS: run-plan-sampling.sh exists"
|
|
50
|
+
else
|
|
51
|
+
echo "FAIL: run-plan-sampling.sh should exist at scripts/lib/"
|
|
52
|
+
FAILURES=$((FAILURES + 1))
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# === run-plan.sh sources it ===
|
|
56
|
+
|
|
57
|
+
TESTS=$((TESTS + 1))
|
|
58
|
+
if grep -q 'source.*lib/run-plan-headless.sh' "$RP"; then
|
|
59
|
+
echo "PASS: run-plan.sh sources lib/run-plan-headless.sh"
|
|
60
|
+
else
|
|
61
|
+
echo "FAIL: run-plan.sh should source lib/run-plan-headless.sh"
|
|
62
|
+
FAILURES=$((FAILURES + 1))
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# === run-plan.sh sources new modules ===
|
|
66
|
+
TESTS=$((TESTS + 1))
|
|
67
|
+
if grep -q 'source.*lib/run-plan-echo-back.sh' "$RP"; then
|
|
68
|
+
echo "PASS: run-plan.sh sources lib/run-plan-echo-back.sh"
|
|
69
|
+
else
|
|
70
|
+
echo "FAIL: run-plan.sh should source lib/run-plan-echo-back.sh"
|
|
71
|
+
FAILURES=$((FAILURES + 1))
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
TESTS=$((TESTS + 1))
|
|
75
|
+
if grep -q 'source.*lib/run-plan-sampling.sh' "$RP"; then
|
|
76
|
+
echo "PASS: run-plan.sh sources lib/run-plan-sampling.sh"
|
|
77
|
+
else
|
|
78
|
+
echo "FAIL: run-plan.sh should source lib/run-plan-sampling.sh"
|
|
79
|
+
FAILURES=$((FAILURES + 1))
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# === run-plan.sh no longer has inline run_mode_headless body ===
|
|
83
|
+
# The function definition should be in the extracted file, not in run-plan.sh
|
|
84
|
+
|
|
85
|
+
TESTS=$((TESTS + 1))
|
|
86
|
+
# Count lines of run_mode_headless in run-plan.sh — should be 0 (no function body)
|
|
87
|
+
if grep -q 'run_mode_headless()' "$RP"; then
|
|
88
|
+
echo "FAIL: run-plan.sh should not define run_mode_headless()"
|
|
89
|
+
FAILURES=$((FAILURES + 1))
|
|
90
|
+
else
|
|
91
|
+
echo "PASS: run_mode_headless() not defined in run-plan.sh"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# === Extracted file defines the function ===
|
|
95
|
+
|
|
96
|
+
TESTS=$((TESTS + 1))
|
|
97
|
+
if grep -q 'run_mode_headless()' "$RPH"; then
|
|
98
|
+
echo "PASS: run-plan-headless.sh defines run_mode_headless()"
|
|
99
|
+
else
|
|
100
|
+
echo "FAIL: run-plan-headless.sh should define run_mode_headless()"
|
|
101
|
+
FAILURES=$((FAILURES + 1))
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# === run-plan.sh is under 330 lines ===
|
|
105
|
+
|
|
106
|
+
line_count=$(wc -l < "$RP")
|
|
107
|
+
TESTS=$((TESTS + 1))
|
|
108
|
+
if [[ $line_count -le 330 ]]; then
|
|
109
|
+
echo "PASS: run-plan.sh is $line_count lines (<=330)"
|
|
110
|
+
else
|
|
111
|
+
echo "FAIL: run-plan.sh is $line_count lines (should be <=330)"
|
|
112
|
+
FAILURES=$((FAILURES + 1))
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# === Extracted file has the key logic markers ===
|
|
116
|
+
|
|
117
|
+
TESTS=$((TESTS + 1))
|
|
118
|
+
if grep -q 'mkdir -p.*logs' "$RPH"; then
|
|
119
|
+
echo "PASS: headless file creates logs directory"
|
|
120
|
+
else
|
|
121
|
+
echo "FAIL: headless file should create logs directory"
|
|
122
|
+
FAILURES=$((FAILURES + 1))
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
TESTS=$((TESTS + 1))
|
|
126
|
+
if grep -q 'claude -p' "$RPH"; then
|
|
127
|
+
echo "PASS: headless file calls claude -p"
|
|
128
|
+
else
|
|
129
|
+
echo "FAIL: headless file should call claude -p"
|
|
130
|
+
FAILURES=$((FAILURES + 1))
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# === Empty batch detection ===
|
|
134
|
+
# The parser should return empty text for empty batches, and headless mode should skip them.
|
|
135
|
+
# This test verifies the parser side (headless mode integration is tested separately).
|
|
136
|
+
|
|
137
|
+
WORK=$(mktemp -d)
|
|
138
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
139
|
+
|
|
140
|
+
source "$SCRIPT_DIR/../lib/run-plan-parser.sh"
|
|
141
|
+
|
|
142
|
+
# Create a plan with 2 real batches and 1 empty trailing match
|
|
143
|
+
cat > "$WORK/plan-empty.md" << 'PLAN'
|
|
144
|
+
## Batch 1: Real Batch
|
|
145
|
+
### Task 1: Do something
|
|
146
|
+
Write some code.
|
|
147
|
+
|
|
148
|
+
## Batch 2: Also Real
|
|
149
|
+
### Task 2: Do more
|
|
150
|
+
Write more code.
|
|
151
|
+
|
|
152
|
+
## Batch 3:
|
|
153
|
+
PLAN
|
|
154
|
+
|
|
155
|
+
# get_batch_text should return empty for batch 3
|
|
156
|
+
val=$(get_batch_text "$WORK/plan-empty.md" 3)
|
|
157
|
+
assert_eq "get_batch_text: empty batch returns empty" "" "$val"
|
|
158
|
+
|
|
159
|
+
# count_batches should count all 3 (parser counts headers)
|
|
160
|
+
val=$(count_batches "$WORK/plan-empty.md")
|
|
161
|
+
assert_eq "count_batches: counts all headers including empty" "3" "$val"
|
|
162
|
+
|
|
163
|
+
# === Bug #4: CLAUDE.md Run-Plan section removal uses awk not sed ===
|
|
164
|
+
# The sed range deletion pattern '/^## Run-Plan:/,/^## [^R]/' has no terminating
|
|
165
|
+
# anchor when Run-Plan is the last section, so it deletes from Run-Plan to EOF.
|
|
166
|
+
# The fix replaces it with awk which handles last-section correctly.
|
|
167
|
+
|
|
168
|
+
TESTS=$((TESTS + 1))
|
|
169
|
+
# awk should be used for section removal; the old sed range pattern should not be present
|
|
170
|
+
if grep -q "awk" "$RPH" && grep -q 'in_section' "$RPH"; then
|
|
171
|
+
echo "PASS: CLAUDE.md section removal uses awk (last-section safe, bug #4)"
|
|
172
|
+
else
|
|
173
|
+
echo "FAIL: CLAUDE.md section removal should use awk to handle last section correctly (bug #4)"
|
|
174
|
+
FAILURES=$((FAILURES + 1))
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
TESTS=$((TESTS + 1))
|
|
178
|
+
# The old broken sed range pattern must not be present
|
|
179
|
+
if grep -q "sed '/\^## Run-Plan:/,/\^## \[^R\]/" "$RPH" 2>/dev/null || \
|
|
180
|
+
grep -q "sed '/\^\#\# Run-Plan:/,/\^\#\# \[^R\]" "$RPH" 2>/dev/null; then
|
|
181
|
+
echo "FAIL: Old sed range deletion pattern still present (unbounded at last section, bug #4)"
|
|
182
|
+
FAILURES=$((FAILURES + 1))
|
|
183
|
+
else
|
|
184
|
+
echo "PASS: Old unbounded sed range deletion pattern removed"
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
# === Bug #16/#28: SAMPLE_COUNT resets at top of batch loop using SAMPLE_DEFAULT ===
|
|
188
|
+
|
|
189
|
+
# User's --sample value must be preserved into SAMPLE_DEFAULT before the loop
|
|
190
|
+
TESTS=$((TESTS + 1))
|
|
191
|
+
if grep -q 'SAMPLE_DEFAULT=.*SAMPLE_COUNT' "$RPH"; then
|
|
192
|
+
echo "PASS: SAMPLE_DEFAULT saves user's --sample value before batch loop"
|
|
193
|
+
else
|
|
194
|
+
echo "FAIL: SAMPLE_DEFAULT should save user's --sample value before batch loop (bug #16/#28)"
|
|
195
|
+
FAILURES=$((FAILURES + 1))
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# The reset inside the loop must use SAMPLE_DEFAULT, not hardcoded 0
|
|
199
|
+
TESTS=$((TESTS + 1))
|
|
200
|
+
batch_loop_region=$(sed -n '/for ((batch = START_BATCH/,/SAMPLE_ON_RETRY/p' "$RPH")
|
|
201
|
+
if echo "$batch_loop_region" | grep -q 'SAMPLE_COUNT=\$SAMPLE_DEFAULT'; then
|
|
202
|
+
echo "PASS: SAMPLE_COUNT resets to SAMPLE_DEFAULT at start of each batch iteration"
|
|
203
|
+
else
|
|
204
|
+
echo "FAIL: SAMPLE_COUNT should reset to SAMPLE_DEFAULT (not 0) at start of each batch iteration (bug #16/#28)"
|
|
205
|
+
FAILURES=$((FAILURES + 1))
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# === Bug #2/#27: Sampling block uses patch files instead of stash ===
|
|
209
|
+
# The fix replaced git stash/pop with git diff > patch + git apply to
|
|
210
|
+
# eliminate LIFO ordering issues. These tests verify the new approach.
|
|
211
|
+
|
|
212
|
+
# Baseline state must be saved as a patch file (not stash)
|
|
213
|
+
TESTS=$((TESTS + 1))
|
|
214
|
+
if grep -q '_baseline_patch' "$RPS"; then
|
|
215
|
+
echo "PASS: run-plan-sampling.sh saves baseline state as a patch file"
|
|
216
|
+
else
|
|
217
|
+
echo "FAIL: run-plan-sampling.sh should save baseline state as a patch file (bug #2/#27)"
|
|
218
|
+
FAILURES=$((FAILURES + 1))
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
# Winner state must be saved as a patch file (not stash)
|
|
222
|
+
TESTS=$((TESTS + 1))
|
|
223
|
+
if grep -q '_winner_patch\|run-plan-winner' "$RPS"; then
|
|
224
|
+
echo "PASS: run-plan-sampling.sh saves winner state as a patch file"
|
|
225
|
+
else
|
|
226
|
+
echo "FAIL: run-plan-sampling.sh should save winner state as a patch file (bug #2/#27)"
|
|
227
|
+
FAILURES=$((FAILURES + 1))
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
# No executable git stash usage remaining in sampling module (patch approach replaces it).
|
|
231
|
+
# Filter out comment lines (lines starting with optional whitespace + #).
|
|
232
|
+
TESTS=$((TESTS + 1))
|
|
233
|
+
sampling_block=$(sed -n '/^run_sampling_candidates()/,/^}/p' "$RPS")
|
|
234
|
+
# Strip comment-only lines before counting stash calls
|
|
235
|
+
stash_uses=$(echo "$sampling_block" | grep -v '^\s*#' | grep -c 'git stash' || true)
|
|
236
|
+
if [[ "$stash_uses" -eq 0 ]]; then
|
|
237
|
+
echo "PASS: No git stash calls in run_sampling_candidates (replaced by patch approach)"
|
|
238
|
+
else
|
|
239
|
+
echo "FAIL: Found $stash_uses git stash call(s) in run_sampling_candidates — should use patch files (bug #2/#27)"
|
|
240
|
+
FAILURES=$((FAILURES + 1))
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Restore of winner uses git apply (patch approach)
|
|
244
|
+
TESTS=$((TESTS + 1))
|
|
245
|
+
if echo "$sampling_block" | grep -q 'git apply'; then
|
|
246
|
+
echo "PASS: run_sampling_candidates uses git apply to restore winner state"
|
|
247
|
+
else
|
|
248
|
+
echo "FAIL: run_sampling_candidates should use git apply to restore winner state (bug #2/#27)"
|
|
249
|
+
FAILURES=$((FAILURES + 1))
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
# === Bug #30: Echo-back gate behavior ===
|
|
253
|
+
|
|
254
|
+
# run-plan.sh must accept --skip-echo-back without error
|
|
255
|
+
TESTS=$((TESTS + 1))
|
|
256
|
+
if grep -q '\-\-skip-echo-back' "$RP"; then
|
|
257
|
+
echo "PASS: run-plan.sh accepts --skip-echo-back flag"
|
|
258
|
+
else
|
|
259
|
+
echo "FAIL: run-plan.sh should define --skip-echo-back flag (bug #30)"
|
|
260
|
+
FAILURES=$((FAILURES + 1))
|
|
261
|
+
fi
|
|
262
|
+
|
|
263
|
+
# run-plan.sh must accept --strict-echo-back without error
|
|
264
|
+
TESTS=$((TESTS + 1))
|
|
265
|
+
if grep -q '\-\-strict-echo-back' "$RP"; then
|
|
266
|
+
echo "PASS: run-plan.sh accepts --strict-echo-back flag"
|
|
267
|
+
else
|
|
268
|
+
echo "FAIL: run-plan.sh should define --strict-echo-back flag (bug #30)"
|
|
269
|
+
FAILURES=$((FAILURES + 1))
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
# _echo_back_check function must exist in headless file
|
|
273
|
+
TESTS=$((TESTS + 1))
|
|
274
|
+
if grep -q '_echo_back_check()' "$RPEB"; then
|
|
275
|
+
echo "PASS: _echo_back_check() is defined in run-plan-echo-back.sh"
|
|
276
|
+
else
|
|
277
|
+
echo "FAIL: _echo_back_check() should be defined in run-plan-echo-back.sh (bug #30)"
|
|
278
|
+
FAILURES=$((FAILURES + 1))
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
# Echo-back gate must be non-blocking by default (no early return when STRICT_ECHO_BACK not set)
|
|
282
|
+
TESTS=$((TESTS + 1))
|
|
283
|
+
if grep -q 'STRICT_ECHO_BACK' "$RPEB"; then
|
|
284
|
+
echo "PASS: STRICT_ECHO_BACK controls blocking behavior in echo-back gate"
|
|
285
|
+
else
|
|
286
|
+
echo "FAIL: echo-back gate should check STRICT_ECHO_BACK for blocking mode (bug #30)"
|
|
287
|
+
FAILURES=$((FAILURES + 1))
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
# echo-back gate is documented as non-blocking by default
|
|
291
|
+
TESTS=$((TESTS + 1))
|
|
292
|
+
if grep -q 'NON-BLOCKING' "$RPEB"; then
|
|
293
|
+
echo "PASS: run-plan-echo-back.sh documents NON-BLOCKING default behavior"
|
|
294
|
+
else
|
|
295
|
+
echo "FAIL: run-plan-echo-back.sh should document NON-BLOCKING default (bug #30)"
|
|
296
|
+
FAILURES=$((FAILURES + 1))
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
# _echo_back_check: SKIP_ECHO_BACK=true must cause early return without error
|
|
300
|
+
TESTS=$((TESTS + 1))
|
|
301
|
+
(
|
|
302
|
+
source "$RPEB" 2>/dev/null || true
|
|
303
|
+
SKIP_ECHO_BACK=true
|
|
304
|
+
STRICT_ECHO_BACK=false
|
|
305
|
+
_echo_back_check "some batch text here" "/nonexistent/log" 2>/dev/null
|
|
306
|
+
) && echo "PASS: _echo_back_check returns 0 when SKIP_ECHO_BACK=true" \
|
|
307
|
+
|| {
|
|
308
|
+
echo "FAIL: _echo_back_check should return 0 when SKIP_ECHO_BACK=true (bug #30)"
|
|
309
|
+
FAILURES=$((FAILURES + 1))
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
# _echo_back_check: missing log file does not crash
|
|
313
|
+
TESTS=$((TESTS + 1))
|
|
314
|
+
(
|
|
315
|
+
source "$RPEB" 2>/dev/null || true
|
|
316
|
+
SKIP_ECHO_BACK=false
|
|
317
|
+
STRICT_ECHO_BACK=false
|
|
318
|
+
_echo_back_check "some batch text here" "/nonexistent/log" 2>/dev/null
|
|
319
|
+
) && echo "PASS: _echo_back_check handles missing log file gracefully" \
|
|
320
|
+
|| {
|
|
321
|
+
echo "FAIL: _echo_back_check should handle missing log file gracefully (bug #30)"
|
|
322
|
+
FAILURES=$((FAILURES + 1))
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
# _echo_back_check: empty batch text does not crash
|
|
326
|
+
TESTS=$((TESTS + 1))
|
|
327
|
+
tmplog=$(mktemp)
|
|
328
|
+
echo "some agent output here" > "$tmplog"
|
|
329
|
+
(
|
|
330
|
+
source "$RPEB" 2>/dev/null || true
|
|
331
|
+
SKIP_ECHO_BACK=false
|
|
332
|
+
STRICT_ECHO_BACK=false
|
|
333
|
+
_echo_back_check "" "$tmplog" 2>/dev/null
|
|
334
|
+
)
|
|
335
|
+
ec=$?
|
|
336
|
+
rm -f "$tmplog"
|
|
337
|
+
if [[ $ec -eq 0 ]]; then
|
|
338
|
+
echo "PASS: _echo_back_check handles empty batch text gracefully"
|
|
339
|
+
else
|
|
340
|
+
echo "FAIL: _echo_back_check should handle empty batch text without error (bug #30)"
|
|
341
|
+
FAILURES=$((FAILURES + 1))
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
# === Bug #4 BEHAVIORAL: awk removes Run-Plan even when it's the last section ===
|
|
345
|
+
# The old sed range pattern '/^## Run-Plan:/,/^## [^R]/' had no closing anchor
|
|
346
|
+
# when Run-Plan was the last section, eating the file from Run-Plan to EOF.
|
|
347
|
+
# This behavioral test exercises the actual awk code path with a CLAUDE.md
|
|
348
|
+
# where "## Run-Plan:" is the last section and verifies other sections survive.
|
|
349
|
+
|
|
350
|
+
WORK_AWK=$(mktemp -d)
|
|
351
|
+
# Create a CLAUDE.md where Run-Plan is the LAST section
|
|
352
|
+
cat > "$WORK_AWK/CLAUDE.md" << 'CLAUDE_EOF'
|
|
353
|
+
# Project Config
|
|
354
|
+
|
|
355
|
+
## Conventions
|
|
356
|
+
|
|
357
|
+
- Use pytest
|
|
358
|
+
- Stage specific files
|
|
359
|
+
|
|
360
|
+
## Run-Plan: Batch 3
|
|
361
|
+
|
|
362
|
+
### Recent Commits
|
|
363
|
+
abc1234 fix: something
|
|
364
|
+
|
|
365
|
+
### Progress Notes
|
|
366
|
+
Batch 2 done.
|
|
367
|
+
CLAUDE_EOF
|
|
368
|
+
|
|
369
|
+
# Run the same awk logic that run-plan-headless.sh uses inline
|
|
370
|
+
awk '
|
|
371
|
+
/^## Run-Plan:/ { in_section=1; next }
|
|
372
|
+
in_section && /^## / { in_section=0 }
|
|
373
|
+
!in_section { print }
|
|
374
|
+
' "$WORK_AWK/CLAUDE.md" > "$WORK_AWK/CLAUDE.md.tmp"
|
|
375
|
+
mv "$WORK_AWK/CLAUDE.md.tmp" "$WORK_AWK/CLAUDE.md"
|
|
376
|
+
|
|
377
|
+
# Verify: Run-Plan section is gone
|
|
378
|
+
TESTS=$((TESTS + 1))
|
|
379
|
+
if grep -q "## Run-Plan:" "$WORK_AWK/CLAUDE.md"; then
|
|
380
|
+
echo "FAIL: awk last-section: Run-Plan section should be removed"
|
|
381
|
+
FAILURES=$((FAILURES + 1))
|
|
382
|
+
else
|
|
383
|
+
echo "PASS: awk last-section: Run-Plan section removed"
|
|
384
|
+
fi
|
|
385
|
+
|
|
386
|
+
# Verify: Conventions section still exists (not eaten by unbounded deletion)
|
|
387
|
+
TESTS=$((TESTS + 1))
|
|
388
|
+
if grep -q "## Conventions" "$WORK_AWK/CLAUDE.md"; then
|
|
389
|
+
echo "PASS: awk last-section: Conventions section preserved"
|
|
390
|
+
else
|
|
391
|
+
echo "FAIL: awk last-section: Conventions section should survive Run-Plan removal"
|
|
392
|
+
FAILURES=$((FAILURES + 1))
|
|
393
|
+
fi
|
|
394
|
+
|
|
395
|
+
# Verify: content before Run-Plan is preserved
|
|
396
|
+
TESTS=$((TESTS + 1))
|
|
397
|
+
if grep -q "Use pytest" "$WORK_AWK/CLAUDE.md"; then
|
|
398
|
+
echo "PASS: awk last-section: content before Run-Plan preserved"
|
|
399
|
+
else
|
|
400
|
+
echo "FAIL: awk last-section: content before Run-Plan should be preserved"
|
|
401
|
+
FAILURES=$((FAILURES + 1))
|
|
402
|
+
fi
|
|
403
|
+
|
|
404
|
+
rm -rf "$WORK_AWK"
|
|
405
|
+
|
|
406
|
+
# === Bug #38: Empty claude output diagnostic ===
|
|
407
|
+
|
|
408
|
+
# Must check for empty log file after claude invocation
|
|
409
|
+
TESTS=$((TESTS + 1))
|
|
410
|
+
if grep -q 'claude produced no output' "$RPH"; then
|
|
411
|
+
echo "PASS: Empty claude output is diagnosed with a warning message (#38)"
|
|
412
|
+
else
|
|
413
|
+
echo "FAIL: Should diagnose empty claude output (crash/no output case) (bug #38)"
|
|
414
|
+
FAILURES=$((FAILURES + 1))
|
|
415
|
+
fi
|
|
416
|
+
|
|
417
|
+
# === Summary ===
|
|
418
|
+
echo ""
|
|
419
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
420
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
421
|
+
echo "FAILURES: $FAILURES"
|
|
422
|
+
exit 1
|
|
423
|
+
fi
|
|
424
|
+
echo "ALL PASSED"
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test notification format functions (no actual Telegram sending)
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/../lib/run-plan-notify.sh"
|
|
7
|
+
|
|
8
|
+
FAILURES=0
|
|
9
|
+
TESTS=0
|
|
10
|
+
|
|
11
|
+
assert_contains() {
|
|
12
|
+
local desc="$1" needle="$2" haystack="$3"
|
|
13
|
+
TESTS=$((TESTS + 1))
|
|
14
|
+
if [[ "$haystack" == *"$needle"* ]]; then
|
|
15
|
+
echo "PASS: $desc"
|
|
16
|
+
else
|
|
17
|
+
echo "FAIL: $desc"
|
|
18
|
+
echo " expected to contain: $needle"
|
|
19
|
+
echo " actual: $haystack"
|
|
20
|
+
FAILURES=$((FAILURES + 1))
|
|
21
|
+
fi
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
assert_eq() {
|
|
25
|
+
local desc="$1" expected="$2" actual="$3"
|
|
26
|
+
TESTS=$((TESTS + 1))
|
|
27
|
+
if [[ "$expected" == "$actual" ]]; then
|
|
28
|
+
echo "PASS: $desc"
|
|
29
|
+
else
|
|
30
|
+
echo "FAIL: $desc"
|
|
31
|
+
echo " expected: $expected"
|
|
32
|
+
echo " actual: $actual"
|
|
33
|
+
FAILURES=$((FAILURES + 1))
|
|
34
|
+
fi
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# --- Test: format_success_message includes plan name ---
|
|
38
|
+
msg=$(format_success_message "my-feature" 3 10 "Context Assembler" 2003 1953 "4m12s" "headless" "")
|
|
39
|
+
assert_contains "success includes plan name" "my-feature" "$msg"
|
|
40
|
+
|
|
41
|
+
# --- Test: format_success_message includes batch X/Y ---
|
|
42
|
+
assert_contains "success includes batch X/Y" "Batch 3/10" "$msg"
|
|
43
|
+
|
|
44
|
+
# --- Test: format_success_message includes batch title ---
|
|
45
|
+
assert_contains "success includes batch title" "Context Assembler" "$msg"
|
|
46
|
+
|
|
47
|
+
# --- Test: format_success_message includes check mark ---
|
|
48
|
+
assert_contains "success includes check mark" "✓" "$msg"
|
|
49
|
+
|
|
50
|
+
# --- Test: format_success_message includes test count ---
|
|
51
|
+
assert_contains "success includes test count" "2003" "$msg"
|
|
52
|
+
|
|
53
|
+
# --- Test: format_success_message includes delta with up arrow ---
|
|
54
|
+
assert_contains "success includes delta" "↑50" "$msg"
|
|
55
|
+
|
|
56
|
+
# --- Test: format_success_message delta calculation: 2003 - 1953 = 50 ---
|
|
57
|
+
TESTS=$((TESTS + 1))
|
|
58
|
+
if [[ "$msg" == *"↑50"* ]] && [[ "$msg" != *"↑500"* ]]; then
|
|
59
|
+
echo "PASS: delta is exactly 50"
|
|
60
|
+
else
|
|
61
|
+
echo "FAIL: delta should be exactly 50 (2003 - 1953)"
|
|
62
|
+
echo " message: $msg"
|
|
63
|
+
FAILURES=$((FAILURES + 1))
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# --- Test: format_success_message includes duration ---
|
|
67
|
+
assert_contains "success includes duration" "4m12s" "$msg"
|
|
68
|
+
|
|
69
|
+
# --- Test: format_success_message includes mode ---
|
|
70
|
+
assert_contains "success includes mode" "headless" "$msg"
|
|
71
|
+
|
|
72
|
+
# --- Test: format_success_message with summary ---
|
|
73
|
+
msg=$(format_success_message "my-feature" 1 5 "Quick Fixes" 100 90 "2m30s" "headless" "Added 3 tests, fixed parser")
|
|
74
|
+
assert_contains "success includes summary" "Added 3 tests, fixed parser" "$msg"
|
|
75
|
+
|
|
76
|
+
# --- Test: format_failure_message includes plan name ---
|
|
77
|
+
msg=$(format_failure_message "my-feature" 2 8 "ast-grep Rules" 45 3 "pytest failed" "Fix test_auth.py")
|
|
78
|
+
assert_contains "failure includes plan name" "my-feature" "$msg"
|
|
79
|
+
|
|
80
|
+
# --- Test: format_failure_message includes batch X/Y ---
|
|
81
|
+
assert_contains "failure includes batch X/Y" "Batch 2/8" "$msg"
|
|
82
|
+
|
|
83
|
+
# --- Test: format_failure_message includes batch title ---
|
|
84
|
+
assert_contains "failure includes batch title" "ast-grep Rules" "$msg"
|
|
85
|
+
|
|
86
|
+
# --- Test: format_failure_message includes cross mark ---
|
|
87
|
+
assert_contains "failure includes cross mark" "✗" "$msg"
|
|
88
|
+
|
|
89
|
+
# --- Test: format_failure_message includes test count ---
|
|
90
|
+
assert_contains "failure includes test count" "45" "$msg"
|
|
91
|
+
|
|
92
|
+
# --- Test: format_failure_message includes failing count ---
|
|
93
|
+
assert_contains "failure includes failing count" "3 failing" "$msg"
|
|
94
|
+
|
|
95
|
+
# --- Test: format_failure_message includes error as Issue ---
|
|
96
|
+
assert_contains "failure includes issue text" "pytest failed" "$msg"
|
|
97
|
+
|
|
98
|
+
# --- Test: format_failure_message includes action ---
|
|
99
|
+
assert_contains "failure includes action" "Fix test_auth.py" "$msg"
|
|
100
|
+
|
|
101
|
+
# --- Test: _load_telegram_env warns on missing file ---
|
|
102
|
+
WORK=$(mktemp -d)
|
|
103
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
104
|
+
|
|
105
|
+
msg=$(_load_telegram_env "$WORK/.env-nonexistent" 2>&1 || true)
|
|
106
|
+
assert_contains "warns on missing env file" "warn" "$(echo "$msg" | tr '[:upper:]' '[:lower:]')"
|
|
107
|
+
|
|
108
|
+
# --- Test: _send_telegram warns on missing token ---
|
|
109
|
+
unset TELEGRAM_BOT_TOKEN 2>/dev/null || true
|
|
110
|
+
unset TELEGRAM_CHAT_ID 2>/dev/null || true
|
|
111
|
+
msg=$(_send_telegram "test message" 2>&1 || true)
|
|
112
|
+
assert_contains "send warns on missing credentials" "warn" "$(echo "$msg" | tr '[:upper:]' '[:lower:]')"
|
|
113
|
+
|
|
114
|
+
# --- Test: format_success_message with zero delta ---
|
|
115
|
+
msg=$(format_success_message "zero-delta" 1 1 "Single Batch" 100 100 "1m00s" "team" "")
|
|
116
|
+
assert_contains "zero delta shows ↑0" "↑0" "$msg"
|
|
117
|
+
|
|
118
|
+
echo ""
|
|
119
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
120
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
121
|
+
echo "FAILURES: $FAILURES"
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
echo "ALL PASSED"
|