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,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test license-check.sh — verifies CLI, project detection, and license scanning
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
LC="$SCRIPT_DIR/../license-check.sh"
|
|
7
|
+
|
|
8
|
+
FAILURES=0
|
|
9
|
+
TESTS=0
|
|
10
|
+
|
|
11
|
+
assert_eq() {
|
|
12
|
+
local desc="$1" expected="$2" actual="$3"
|
|
13
|
+
TESTS=$((TESTS + 1))
|
|
14
|
+
if [[ "$expected" != "$actual" ]]; then
|
|
15
|
+
echo "FAIL: $desc"
|
|
16
|
+
echo " expected: $expected"
|
|
17
|
+
echo " actual: $actual"
|
|
18
|
+
FAILURES=$((FAILURES + 1))
|
|
19
|
+
else
|
|
20
|
+
echo "PASS: $desc"
|
|
21
|
+
fi
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
assert_exit() {
|
|
25
|
+
local desc="$1" expected_exit="$2"
|
|
26
|
+
shift 2
|
|
27
|
+
local actual_exit=0
|
|
28
|
+
"$@" >/dev/null 2>&1 || actual_exit=$?
|
|
29
|
+
TESTS=$((TESTS + 1))
|
|
30
|
+
if [[ "$expected_exit" != "$actual_exit" ]]; then
|
|
31
|
+
echo "FAIL: $desc"
|
|
32
|
+
echo " expected exit: $expected_exit"
|
|
33
|
+
echo " actual exit: $actual_exit"
|
|
34
|
+
FAILURES=$((FAILURES + 1))
|
|
35
|
+
else
|
|
36
|
+
echo "PASS: $desc"
|
|
37
|
+
fi
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
assert_contains() {
|
|
41
|
+
local desc="$1" needle="$2" haystack="$3"
|
|
42
|
+
TESTS=$((TESTS + 1))
|
|
43
|
+
if echo "$haystack" | grep -qF "$needle"; then
|
|
44
|
+
echo "PASS: $desc"
|
|
45
|
+
else
|
|
46
|
+
echo "FAIL: $desc"
|
|
47
|
+
echo " expected to contain: $needle"
|
|
48
|
+
echo " in: $(echo "$haystack" | head -5)"
|
|
49
|
+
FAILURES=$((FAILURES + 1))
|
|
50
|
+
fi
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
WORK=$(mktemp -d)
|
|
54
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
55
|
+
|
|
56
|
+
# === CLI tests ===
|
|
57
|
+
|
|
58
|
+
assert_exit "--help exits 0" 0 bash "$LC" --help
|
|
59
|
+
assert_exit "unknown flag exits 1" 1 bash "$LC" --bogus
|
|
60
|
+
|
|
61
|
+
# === Help text ===
|
|
62
|
+
|
|
63
|
+
output=$(bash "$LC" --help 2>&1)
|
|
64
|
+
assert_contains "help mentions license" "license" "$output"
|
|
65
|
+
|
|
66
|
+
# === Sources common.sh ===
|
|
67
|
+
|
|
68
|
+
TESTS=$((TESTS + 1))
|
|
69
|
+
if grep -q 'source.*lib/common.sh' "$LC"; then
|
|
70
|
+
echo "PASS: license-check.sh sources lib/common.sh"
|
|
71
|
+
else
|
|
72
|
+
echo "FAIL: license-check.sh sources lib/common.sh"
|
|
73
|
+
FAILURES=$((FAILURES + 1))
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# === Unknown project type exits clean ===
|
|
77
|
+
|
|
78
|
+
mkdir -p "$WORK/empty-proj"
|
|
79
|
+
output=$(bash "$LC" --project-root "$WORK/empty-proj" 2>&1)
|
|
80
|
+
exit_code=$?
|
|
81
|
+
assert_eq "unknown project exits 0" "0" "$exit_code"
|
|
82
|
+
assert_contains "unknown project says CLEAN" "CLEAN" "$output"
|
|
83
|
+
assert_contains "shows License Check header" "License Check" "$output"
|
|
84
|
+
|
|
85
|
+
# === Python project without pip-licenses skips gracefully ===
|
|
86
|
+
|
|
87
|
+
mkdir -p "$WORK/py-proj"
|
|
88
|
+
touch "$WORK/py-proj/pyproject.toml"
|
|
89
|
+
output=$(bash "$LC" --project-root "$WORK/py-proj" 2>&1)
|
|
90
|
+
exit_code=$?
|
|
91
|
+
assert_eq "python without pip-licenses exits 0" "0" "$exit_code"
|
|
92
|
+
assert_contains "python skip message" "skipping" "$output"
|
|
93
|
+
|
|
94
|
+
# === Node project without npx skips gracefully ===
|
|
95
|
+
# (npx is likely available, so test the output structure instead)
|
|
96
|
+
|
|
97
|
+
mkdir -p "$WORK/node-proj"
|
|
98
|
+
echo '{"name":"test"}' > "$WORK/node-proj/package.json"
|
|
99
|
+
output=$(bash "$LC" --project-root "$WORK/node-proj" 2>&1) || true
|
|
100
|
+
assert_contains "node project checks deps" "Node dependencies" "$output"
|
|
101
|
+
|
|
102
|
+
# === Summary ===
|
|
103
|
+
echo ""
|
|
104
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
105
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
106
|
+
echo "FAILURES: $FAILURES"
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
echo "ALL PASSED"
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
# Save test script dir — sourcing mab-run.sh overwrites SCRIPT_DIR
|
|
6
|
+
TEST_DIR="$SCRIPT_DIR"
|
|
7
|
+
source "$SCRIPT_DIR/test-helpers.sh"
|
|
8
|
+
|
|
9
|
+
MAB_RUN="$TEST_DIR/../mab-run.sh"
|
|
10
|
+
|
|
11
|
+
# --- Test: --help exits 0 and mentions key concepts ---
|
|
12
|
+
help_output=$("$MAB_RUN" --help 2>&1) || true
|
|
13
|
+
assert_exit "--help exits 0" 0 "$MAB_RUN" --help
|
|
14
|
+
assert_contains "--help mentions worktree" "worktree" "$help_output"
|
|
15
|
+
assert_contains "--help mentions judge" "judge" "$help_output"
|
|
16
|
+
|
|
17
|
+
# --- Test: missing plan exits 1 ---
|
|
18
|
+
assert_exit "missing plan exits 1" 1 "$MAB_RUN" --plan /tmp/nonexistent-plan-$$.md --batch 1 --work-unit "test" --worktree /tmp
|
|
19
|
+
|
|
20
|
+
# --- Test: non-numeric batch exits 1 ---
|
|
21
|
+
TEST_TMPDIR=$(mktemp -d)
|
|
22
|
+
trap 'rm -rf "$TEST_TMPDIR"' EXIT
|
|
23
|
+
|
|
24
|
+
# Create a minimal plan file
|
|
25
|
+
cat > "$TEST_TMPDIR/plan.md" <<'MD'
|
|
26
|
+
# Test Plan
|
|
27
|
+
|
|
28
|
+
## Batch 1: Test batch
|
|
29
|
+
|
|
30
|
+
Do something.
|
|
31
|
+
MD
|
|
32
|
+
|
|
33
|
+
assert_exit "non-numeric batch exits 1" 1 "$MAB_RUN" --plan "$TEST_TMPDIR/plan.md" --batch abc --work-unit "test" --worktree "$TEST_TMPDIR"
|
|
34
|
+
|
|
35
|
+
# --- Test: --dry-run exits 0 with valid args ---
|
|
36
|
+
dry_output=$("$MAB_RUN" --plan "$TEST_TMPDIR/plan.md" --batch 1 --work-unit "test batch" --worktree "$TEST_TMPDIR" --dry-run 2>&1) || true
|
|
37
|
+
dry_exit=0
|
|
38
|
+
"$MAB_RUN" --plan "$TEST_TMPDIR/plan.md" --batch 1 --work-unit "test batch" --worktree "$TEST_TMPDIR" --dry-run > /dev/null 2>&1 || dry_exit=$?
|
|
39
|
+
assert_eq "--dry-run exits 0" "0" "$dry_exit"
|
|
40
|
+
assert_contains "--dry-run shows planned actions" "DRY RUN" "$dry_output"
|
|
41
|
+
|
|
42
|
+
# --- Test: --init-data creates valid JSON files ---
|
|
43
|
+
init_dir=$(mktemp -d)
|
|
44
|
+
trap 'rm -rf "$TEST_TMPDIR" "$init_dir"' EXIT
|
|
45
|
+
"$MAB_RUN" --init-data --worktree "$init_dir" > /dev/null 2>&1 || true
|
|
46
|
+
|
|
47
|
+
TESTS=$((TESTS + 1))
|
|
48
|
+
if [[ -f "$init_dir/logs/strategy-perf.json" ]] && jq . "$init_dir/logs/strategy-perf.json" > /dev/null 2>&1; then
|
|
49
|
+
echo "PASS: --init-data creates valid strategy-perf.json"
|
|
50
|
+
else
|
|
51
|
+
echo "FAIL: --init-data did not create valid strategy-perf.json"
|
|
52
|
+
FAILURES=$((FAILURES + 1))
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
TESTS=$((TESTS + 1))
|
|
56
|
+
if [[ -f "$init_dir/logs/mab-lessons.json" ]] && jq . "$init_dir/logs/mab-lessons.json" > /dev/null 2>&1; then
|
|
57
|
+
echo "PASS: --init-data creates valid mab-lessons.json"
|
|
58
|
+
else
|
|
59
|
+
echo "FAIL: --init-data did not create valid mab-lessons.json"
|
|
60
|
+
FAILURES=$((FAILURES + 1))
|
|
61
|
+
fi
|
|
62
|
+
rm -rf "$init_dir"
|
|
63
|
+
|
|
64
|
+
# --- Test: select_winner_with_gate_override ---
|
|
65
|
+
# Source mab-run functions for unit testing — fail loudly if sourcing breaks
|
|
66
|
+
source "$MAB_RUN" --source-only 2>/dev/null || true
|
|
67
|
+
|
|
68
|
+
TESTS=$((TESTS + 1))
|
|
69
|
+
if ! type select_winner_with_gate_override &>/dev/null; then
|
|
70
|
+
echo "FAIL: select_winner_with_gate_override not found after sourcing mab-run.sh"
|
|
71
|
+
FAILURES=$((FAILURES + 1))
|
|
72
|
+
else
|
|
73
|
+
echo "PASS: select_winner_with_gate_override available after --source-only"
|
|
74
|
+
|
|
75
|
+
# Only A passes → A wins
|
|
76
|
+
result=$(select_winner_with_gate_override 0 1 "agent-b")
|
|
77
|
+
assert_eq "only A passes → agent-a" "agent-a" "$result"
|
|
78
|
+
|
|
79
|
+
# Only B passes → B wins
|
|
80
|
+
result=$(select_winner_with_gate_override 1 0 "agent-a")
|
|
81
|
+
assert_eq "only B passes → agent-b" "agent-b" "$result"
|
|
82
|
+
|
|
83
|
+
# Neither passes → none
|
|
84
|
+
result=$(select_winner_with_gate_override 1 1 "agent-a")
|
|
85
|
+
assert_eq "neither passes → none" "none" "$result"
|
|
86
|
+
|
|
87
|
+
# Both pass → judge winner
|
|
88
|
+
result=$(select_winner_with_gate_override 0 0 "agent-b")
|
|
89
|
+
assert_eq "both pass → judge winner" "agent-b" "$result"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# --- Test: assemble_agent_prompt substitutes placeholders ---
|
|
93
|
+
TESTS=$((TESTS + 1))
|
|
94
|
+
if ! type assemble_agent_prompt &>/dev/null; then
|
|
95
|
+
echo "FAIL: assemble_agent_prompt not found after sourcing mab-run.sh"
|
|
96
|
+
FAILURES=$((FAILURES + 1))
|
|
97
|
+
else
|
|
98
|
+
echo "PASS: assemble_agent_prompt available after --source-only"
|
|
99
|
+
|
|
100
|
+
prompt_template="Work: {WORK_UNIT_DESCRIPTION}, PRD: {PRD_PATH}, Gate: {QUALITY_GATE_CMD}"
|
|
101
|
+
result=$(assemble_agent_prompt "$prompt_template" \
|
|
102
|
+
"implement feature X" \
|
|
103
|
+
"tasks/prd.json" \
|
|
104
|
+
"docs/ARCHITECTURE-MAP.json" \
|
|
105
|
+
"no lessons yet" \
|
|
106
|
+
"scripts/quality-gate.sh --project-root .")
|
|
107
|
+
|
|
108
|
+
assert_contains "substitutes WORK_UNIT_DESCRIPTION" "implement feature X" "$result"
|
|
109
|
+
assert_contains "substitutes PRD_PATH" "tasks/prd.json" "$result"
|
|
110
|
+
assert_contains "substitutes QUALITY_GATE_CMD" "scripts/quality-gate.sh --project-root ." "$result"
|
|
111
|
+
assert_not_contains "no remaining placeholders" "{WORK_UNIT_DESCRIPTION}" "$result"
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# --- Test: update_mab_data lesson deduplication ---
|
|
115
|
+
# Call update_mab_data twice with the same lesson — should have 1 entry with occurrences=2
|
|
116
|
+
TESTS=$((TESTS + 1))
|
|
117
|
+
if ! type update_mab_data &>/dev/null; then
|
|
118
|
+
echo "FAIL: update_mab_data not found after sourcing mab-run.sh"
|
|
119
|
+
FAILURES=$((FAILURES + 1))
|
|
120
|
+
else
|
|
121
|
+
echo "PASS: update_mab_data available after --source-only"
|
|
122
|
+
|
|
123
|
+
dedup_dir=$(mktemp -d)
|
|
124
|
+
MAB_WORKTREE="$dedup_dir"
|
|
125
|
+
mkdir -p "$dedup_dir/logs"
|
|
126
|
+
# init_strategy_perf is already available (sourced via mab-run.sh --source-only)
|
|
127
|
+
init_strategy_perf "$dedup_dir/logs/strategy-perf.json"
|
|
128
|
+
|
|
129
|
+
# First call — creates new lesson entry
|
|
130
|
+
update_mab_data "agent-a" "always check imports" "new-file"
|
|
131
|
+
|
|
132
|
+
TESTS=$((TESTS + 1))
|
|
133
|
+
count1=$(jq 'length' "$dedup_dir/logs/mab-lessons.json" 2>/dev/null || echo "0")
|
|
134
|
+
if [[ "$count1" == "1" ]]; then
|
|
135
|
+
echo "PASS: update_mab_data: first call creates 1 lesson entry"
|
|
136
|
+
else
|
|
137
|
+
echo "FAIL: update_mab_data: expected 1 entry after first call, got $count1"
|
|
138
|
+
FAILURES=$((FAILURES + 1))
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Second call with same lesson — should deduplicate (increment occurrences, not add)
|
|
142
|
+
update_mab_data "agent-b" "always check imports" "new-file"
|
|
143
|
+
|
|
144
|
+
TESTS=$((TESTS + 1))
|
|
145
|
+
count2=$(jq 'length' "$dedup_dir/logs/mab-lessons.json" 2>/dev/null || echo "0")
|
|
146
|
+
if [[ "$count2" == "1" ]]; then
|
|
147
|
+
echo "PASS: update_mab_data: second call deduplicates (still 1 entry)"
|
|
148
|
+
else
|
|
149
|
+
echo "FAIL: update_mab_data: expected 1 entry after dedup, got $count2"
|
|
150
|
+
FAILURES=$((FAILURES + 1))
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
occ=$(jq '.[0].occurrences' "$dedup_dir/logs/mab-lessons.json" 2>/dev/null || echo "0")
|
|
154
|
+
assert_eq "update_mab_data: occurrences incremented to 2" "2" "$occ"
|
|
155
|
+
|
|
156
|
+
rm -rf "$dedup_dir"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
# --- Test: --mab flag wiring (run-plan.sh → run-plan-headless.sh → mab-run.sh) ---
|
|
160
|
+
# run-plan.sh parses --mab and sets MAB=true
|
|
161
|
+
RP_MAIN="$TEST_DIR/../run-plan.sh"
|
|
162
|
+
RP_HEADLESS="$TEST_DIR/../lib/run-plan-headless.sh"
|
|
163
|
+
|
|
164
|
+
TESTS=$((TESTS + 1))
|
|
165
|
+
if grep -q '\-\-mab) MAB=true' "$RP_MAIN" 2>/dev/null; then
|
|
166
|
+
echo "PASS: run-plan.sh parses --mab flag and sets MAB=true"
|
|
167
|
+
else
|
|
168
|
+
echo "FAIL: run-plan.sh should parse --mab and set MAB=true"
|
|
169
|
+
FAILURES=$((FAILURES + 1))
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# run-plan-headless.sh checks MAB flag and invokes mab-run.sh
|
|
173
|
+
TESTS=$((TESTS + 1))
|
|
174
|
+
if grep -q 'MAB.*true' "$RP_HEADLESS" 2>/dev/null && \
|
|
175
|
+
grep -q 'mab-run.sh' "$RP_HEADLESS" 2>/dev/null; then
|
|
176
|
+
echo "PASS: run-plan-headless.sh checks MAB flag and invokes mab-run.sh"
|
|
177
|
+
else
|
|
178
|
+
echo "FAIL: run-plan-headless.sh should check MAB flag and invoke mab-run.sh"
|
|
179
|
+
FAILURES=$((FAILURES + 1))
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
report_results
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test scripts/lib/ollama.sh
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/test-helpers.sh"
|
|
7
|
+
|
|
8
|
+
OLLAMA_LIB="$SCRIPT_DIR/../lib/ollama.sh"
|
|
9
|
+
|
|
10
|
+
# === Test: Health check curl has timeout flags (#25) ===
|
|
11
|
+
# Read the source and verify --connect-timeout and --max-time are present on the health check line
|
|
12
|
+
health_line=$(grep -F 'OLLAMA_QUEUE_URL/health' "$OLLAMA_LIB")
|
|
13
|
+
# Use [[ ]] to check for substrings since grep chokes on --flag patterns
|
|
14
|
+
TESTS=$((TESTS + 1))
|
|
15
|
+
if [[ "$health_line" == *"--connect-timeout"* ]]; then
|
|
16
|
+
echo "PASS: health check: has --connect-timeout"
|
|
17
|
+
else
|
|
18
|
+
echo "FAIL: health check: has --connect-timeout"; FAILURES=$((FAILURES + 1))
|
|
19
|
+
fi
|
|
20
|
+
TESTS=$((TESTS + 1))
|
|
21
|
+
if [[ "$health_line" == *"--max-time"* ]]; then
|
|
22
|
+
echo "PASS: health check: has --max-time"
|
|
23
|
+
else
|
|
24
|
+
echo "FAIL: health check: has --max-time"; FAILURES=$((FAILURES + 1))
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# === Test: API call curl has --max-time ===
|
|
28
|
+
api_line=$(grep -F 'curl -s "$api_url"' "$OLLAMA_LIB")
|
|
29
|
+
TESTS=$((TESTS + 1))
|
|
30
|
+
if [[ "$api_line" == *"--max-time"* ]]; then
|
|
31
|
+
echo "PASS: api call: has --max-time"
|
|
32
|
+
else
|
|
33
|
+
echo "FAIL: api call: has --max-time"; FAILURES=$((FAILURES + 1))
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# === Test: ollama_build_payload produces valid JSON ===
|
|
37
|
+
# Source common.sh first (required dependency), then ollama.sh
|
|
38
|
+
COMMON_LIB="$SCRIPT_DIR/../lib/common.sh"
|
|
39
|
+
if [[ -f "$COMMON_LIB" ]]; then
|
|
40
|
+
source "$COMMON_LIB"
|
|
41
|
+
fi
|
|
42
|
+
source "$OLLAMA_LIB"
|
|
43
|
+
payload=$(ollama_build_payload "test-model" "test prompt")
|
|
44
|
+
model=$(echo "$payload" | jq -r '.model')
|
|
45
|
+
assert_eq "build_payload: model" "test-model" "$model"
|
|
46
|
+
prompt=$(echo "$payload" | jq -r '.prompt')
|
|
47
|
+
assert_eq "build_payload: prompt" "test prompt" "$prompt"
|
|
48
|
+
|
|
49
|
+
report_results
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test ollama.sh shared library functions
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/../lib/common.sh"
|
|
7
|
+
source "$SCRIPT_DIR/../lib/ollama.sh"
|
|
8
|
+
|
|
9
|
+
FAILURES=0
|
|
10
|
+
TESTS=0
|
|
11
|
+
|
|
12
|
+
assert_eq() {
|
|
13
|
+
local desc="$1" expected="$2" actual="$3"
|
|
14
|
+
TESTS=$((TESTS + 1))
|
|
15
|
+
if [[ "$expected" != "$actual" ]]; then
|
|
16
|
+
echo "FAIL: $desc"
|
|
17
|
+
echo " expected: $expected"
|
|
18
|
+
echo " actual: $actual"
|
|
19
|
+
FAILURES=$((FAILURES + 1))
|
|
20
|
+
else
|
|
21
|
+
echo "PASS: $desc"
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# === ollama_build_payload tests ===
|
|
26
|
+
|
|
27
|
+
val=$(ollama_build_payload "deepseek-r1:8b" "Hello world")
|
|
28
|
+
model=$(echo "$val" | jq -r '.model')
|
|
29
|
+
assert_eq "ollama_build_payload: model set" "deepseek-r1:8b" "$model"
|
|
30
|
+
|
|
31
|
+
stream=$(echo "$val" | jq -r '.stream')
|
|
32
|
+
assert_eq "ollama_build_payload: stream false" "false" "$stream"
|
|
33
|
+
|
|
34
|
+
# === ollama_parse_response tests ===
|
|
35
|
+
|
|
36
|
+
val=$(echo '{"response":"hello"}' | ollama_parse_response)
|
|
37
|
+
assert_eq "ollama_parse_response: extracts response" "hello" "$val"
|
|
38
|
+
|
|
39
|
+
val=$(echo '{}' | ollama_parse_response)
|
|
40
|
+
assert_eq "ollama_parse_response: empty on missing field" "" "$val"
|
|
41
|
+
|
|
42
|
+
# === ollama_extract_json tests ===
|
|
43
|
+
|
|
44
|
+
val=$(echo '```json
|
|
45
|
+
{"key":"value"}
|
|
46
|
+
```' | ollama_extract_json)
|
|
47
|
+
key=$(echo "$val" | jq -r '.key')
|
|
48
|
+
assert_eq "ollama_extract_json: strips fences and validates" "value" "$key"
|
|
49
|
+
|
|
50
|
+
val=$(echo 'not json at all' | ollama_extract_json 2>/dev/null)
|
|
51
|
+
assert_eq "ollama_extract_json: returns empty on invalid" "" "$val"
|
|
52
|
+
|
|
53
|
+
# === Summary ===
|
|
54
|
+
echo ""
|
|
55
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
56
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
57
|
+
echo "FAILURES: $FAILURES"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
echo "ALL PASSED"
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test pipeline-status.sh
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
STATUS_SCRIPT="$SCRIPT_DIR/../pipeline-status.sh"
|
|
7
|
+
|
|
8
|
+
FAILURES=0
|
|
9
|
+
TESTS=0
|
|
10
|
+
|
|
11
|
+
assert_exit() {
|
|
12
|
+
local desc="$1" expected_exit="$2"
|
|
13
|
+
shift 2
|
|
14
|
+
local actual_exit=0
|
|
15
|
+
"$@" >/dev/null 2>&1 || actual_exit=$?
|
|
16
|
+
TESTS=$((TESTS + 1))
|
|
17
|
+
if [[ "$expected_exit" != "$actual_exit" ]]; then
|
|
18
|
+
echo "FAIL: $desc"
|
|
19
|
+
echo " expected exit: $expected_exit"
|
|
20
|
+
echo " actual exit: $actual_exit"
|
|
21
|
+
FAILURES=$((FAILURES + 1))
|
|
22
|
+
else
|
|
23
|
+
echo "PASS: $desc"
|
|
24
|
+
fi
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert_contains() {
|
|
28
|
+
local desc="$1" needle="$2" haystack="$3"
|
|
29
|
+
TESTS=$((TESTS + 1))
|
|
30
|
+
if echo "$haystack" | grep -qF -- "$needle"; then
|
|
31
|
+
echo "PASS: $desc"
|
|
32
|
+
else
|
|
33
|
+
echo "FAIL: $desc"
|
|
34
|
+
echo " expected to contain: $needle"
|
|
35
|
+
echo " in: $(echo "$haystack" | head -5)"
|
|
36
|
+
FAILURES=$((FAILURES + 1))
|
|
37
|
+
fi
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
WORK=$(mktemp -d)
|
|
41
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
42
|
+
|
|
43
|
+
# --- Test: --help exits 0 ---
|
|
44
|
+
assert_exit "pipeline-status --help exits 0" 0 \
|
|
45
|
+
bash "$STATUS_SCRIPT" --help
|
|
46
|
+
|
|
47
|
+
# --- Test: runs on empty directory ---
|
|
48
|
+
mkdir -p "$WORK/empty-proj"
|
|
49
|
+
cd "$WORK/empty-proj" && git init --quiet
|
|
50
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/empty-proj" 2>&1) || true
|
|
51
|
+
assert_contains "shows Pipeline Status header" "Pipeline Status" "$output"
|
|
52
|
+
assert_contains "shows no active run-plan" "No active run-plan" "$output"
|
|
53
|
+
assert_contains "shows no PRD" "No PRD found" "$output"
|
|
54
|
+
|
|
55
|
+
# --- Test: shows run-plan state when present ---
|
|
56
|
+
mkdir -p "$WORK/proj-with-state"
|
|
57
|
+
cd "$WORK/proj-with-state" && git init --quiet
|
|
58
|
+
cat > "$WORK/proj-with-state/.run-plan-state.json" <<'JSON'
|
|
59
|
+
{
|
|
60
|
+
"plan_file": "docs/plans/test-plan.md",
|
|
61
|
+
"mode": "headless",
|
|
62
|
+
"current_batch": 2,
|
|
63
|
+
"completed_batches": [1],
|
|
64
|
+
"started_at": "2026-02-21T10:00:00Z",
|
|
65
|
+
"last_quality_gate": {"passed": true, "test_count": 42}
|
|
66
|
+
}
|
|
67
|
+
JSON
|
|
68
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-state" 2>&1) || true
|
|
69
|
+
assert_contains "shows plan file" "test-plan.md" "$output"
|
|
70
|
+
assert_contains "shows mode" "headless" "$output"
|
|
71
|
+
assert_contains "shows gate result" "passed=true" "$output"
|
|
72
|
+
|
|
73
|
+
# --- Test: shows PRD status when present ---
|
|
74
|
+
mkdir -p "$WORK/proj-with-state/tasks"
|
|
75
|
+
echo '[{"id":1,"passes":true},{"id":2,"passes":false},{"id":3,"passes":true}]' > "$WORK/proj-with-state/tasks/prd.json"
|
|
76
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-state" 2>&1) || true
|
|
77
|
+
assert_contains "shows PRD counts" "2/3 passing" "$output"
|
|
78
|
+
|
|
79
|
+
# --- Test: shows routing decisions when log exists ---
|
|
80
|
+
mkdir -p "$WORK/proj-with-state/logs"
|
|
81
|
+
echo "[14:30:01] MODE: headless mode selected" > "$WORK/proj-with-state/logs/routing-decisions.log"
|
|
82
|
+
echo "[14:30:02] MODEL: batch 1 routed to sonnet" >> "$WORK/proj-with-state/logs/routing-decisions.log"
|
|
83
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-state" 2>&1) || true
|
|
84
|
+
assert_contains "shows routing decisions header" "Routing Decisions" "$output"
|
|
85
|
+
assert_contains "shows routing log content" "headless mode selected" "$output"
|
|
86
|
+
|
|
87
|
+
# --- Test: no routing section when log missing ---
|
|
88
|
+
rm -f "$WORK/proj-with-state/logs/routing-decisions.log"
|
|
89
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-state" 2>&1) || true
|
|
90
|
+
TESTS=$((TESTS + 1))
|
|
91
|
+
if echo "$output" | grep -qF "Routing Decisions"; then
|
|
92
|
+
echo "FAIL: no routing section when log missing"
|
|
93
|
+
FAILURES=$((FAILURES + 1))
|
|
94
|
+
else
|
|
95
|
+
echo "PASS: no routing section when log missing"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# --- Test: shows total cost when costs present in state file ---
|
|
99
|
+
mkdir -p "$WORK/proj-with-costs"
|
|
100
|
+
cd "$WORK/proj-with-costs" && git init --quiet
|
|
101
|
+
cat > "$WORK/proj-with-costs/.run-plan-state.json" <<'JSON'
|
|
102
|
+
{
|
|
103
|
+
"plan_file": "docs/plans/test-plan.md",
|
|
104
|
+
"mode": "headless",
|
|
105
|
+
"current_batch": 3,
|
|
106
|
+
"completed_batches": [1, 2],
|
|
107
|
+
"started_at": "2026-02-21T10:00:00Z",
|
|
108
|
+
"last_quality_gate": {"passed": true, "test_count": 10},
|
|
109
|
+
"costs": {"1": "0.05", "2": "0.10"}
|
|
110
|
+
}
|
|
111
|
+
JSON
|
|
112
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-costs" 2>&1) || true
|
|
113
|
+
assert_contains "shows total cost line" "Total cost:" "$output"
|
|
114
|
+
|
|
115
|
+
# --- Test: --show-costs shows per-batch breakdown ---
|
|
116
|
+
output=$(bash "$STATUS_SCRIPT" --show-costs "$WORK/proj-with-costs" 2>&1) || true
|
|
117
|
+
assert_contains "--show-costs shows Cost Breakdown header" "Cost Breakdown" "$output"
|
|
118
|
+
assert_contains "--show-costs shows batch 1 cost" "Batch 1:" "$output"
|
|
119
|
+
assert_contains "--show-costs shows batch 2 cost" "Batch 2:" "$output"
|
|
120
|
+
|
|
121
|
+
# --- Test: --show-costs with non-numeric batch key does not crash (#42) ---
|
|
122
|
+
mkdir -p "$WORK/proj-with-final-key"
|
|
123
|
+
cd "$WORK/proj-with-final-key" && git init --quiet
|
|
124
|
+
cat > "$WORK/proj-with-final-key/.run-plan-state.json" <<'JSON'
|
|
125
|
+
{
|
|
126
|
+
"plan_file": "docs/plans/test-plan.md",
|
|
127
|
+
"mode": "headless",
|
|
128
|
+
"current_batch": 2,
|
|
129
|
+
"completed_batches": [1, "final"],
|
|
130
|
+
"started_at": "2026-02-21T10:00:00Z",
|
|
131
|
+
"last_quality_gate": {"passed": true, "test_count": 5},
|
|
132
|
+
"costs": {"1": "0.03", "final": "0.01"}
|
|
133
|
+
}
|
|
134
|
+
JSON
|
|
135
|
+
output=$(bash "$STATUS_SCRIPT" --show-costs "$WORK/proj-with-final-key" 2>&1) || true
|
|
136
|
+
assert_contains "--show-costs with 'final' key does not crash" "Cost Breakdown" "$output"
|
|
137
|
+
# Should show batch 1 (numeric) but not crash on "final"
|
|
138
|
+
assert_contains "--show-costs numeric key still shown" "Batch 1:" "$output"
|
|
139
|
+
|
|
140
|
+
# --- Test: --show-costs with no cost data shows informative message ---
|
|
141
|
+
mkdir -p "$WORK/proj-no-costs"
|
|
142
|
+
cd "$WORK/proj-no-costs" && git init --quiet
|
|
143
|
+
cat > "$WORK/proj-no-costs/.run-plan-state.json" <<'JSON'
|
|
144
|
+
{
|
|
145
|
+
"plan_file": "docs/plans/test-plan.md",
|
|
146
|
+
"mode": "headless",
|
|
147
|
+
"current_batch": 1,
|
|
148
|
+
"completed_batches": [],
|
|
149
|
+
"started_at": "2026-02-21T10:00:00Z",
|
|
150
|
+
"last_quality_gate": null
|
|
151
|
+
}
|
|
152
|
+
JSON
|
|
153
|
+
output=$(bash "$STATUS_SCRIPT" --show-costs "$WORK/proj-no-costs" 2>&1) || true
|
|
154
|
+
assert_contains "--show-costs with no costs shows informative message" "No cost data" "$output"
|
|
155
|
+
|
|
156
|
+
# --- Test: --help exits 0 and mentions --show-costs ---
|
|
157
|
+
output=$(bash "$STATUS_SCRIPT" --help 2>&1) || true
|
|
158
|
+
assert_contains "--help mentions --show-costs" "--show-costs" "$output"
|
|
159
|
+
|
|
160
|
+
# --- Test: MAB section shown when strategy-perf.json exists ---
|
|
161
|
+
mkdir -p "$WORK/proj-with-state/logs"
|
|
162
|
+
cat > "$WORK/proj-with-state/logs/strategy-perf.json" <<'JSON'
|
|
163
|
+
{
|
|
164
|
+
"new-file": {"superpowers": {"wins": 5, "losses": 2}, "ralph": {"wins": 3, "losses": 4}},
|
|
165
|
+
"refactoring": {"superpowers": {"wins": 0, "losses": 0}, "ralph": {"wins": 0, "losses": 0}},
|
|
166
|
+
"integration": {"superpowers": {"wins": 0, "losses": 0}, "ralph": {"wins": 0, "losses": 0}},
|
|
167
|
+
"test-only": {"superpowers": {"wins": 0, "losses": 0}, "ralph": {"wins": 0, "losses": 0}},
|
|
168
|
+
"calibration_count": 3,
|
|
169
|
+
"calibration_complete": false
|
|
170
|
+
}
|
|
171
|
+
JSON
|
|
172
|
+
echo '[{"pattern": "test pattern", "context": "new-file"}]' > "$WORK/proj-with-state/logs/mab-lessons.json"
|
|
173
|
+
|
|
174
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-state" 2>&1) || true
|
|
175
|
+
assert_contains "MAB section header shown" "MAB" "$output"
|
|
176
|
+
assert_contains "MAB calibration shown" "3/10" "$output"
|
|
177
|
+
assert_contains "MAB win rates shown" "superpowers=5W/2L" "$output"
|
|
178
|
+
assert_contains "MAB lesson count shown" "1 patterns recorded" "$output"
|
|
179
|
+
|
|
180
|
+
# --- Test: no MAB section when no perf file ---
|
|
181
|
+
rm -f "$WORK/proj-with-state/logs/strategy-perf.json" "$WORK/proj-with-state/logs/mab-lessons.json"
|
|
182
|
+
output=$(bash "$STATUS_SCRIPT" "$WORK/proj-with-state" 2>&1) || true
|
|
183
|
+
TESTS=$((TESTS + 1))
|
|
184
|
+
if echo "$output" | grep -qF "Multi-Armed Bandit"; then
|
|
185
|
+
echo "FAIL: MAB section should not appear without perf file"
|
|
186
|
+
FAILURES=$((FAILURES + 1))
|
|
187
|
+
else
|
|
188
|
+
echo "PASS: no MAB section when perf file absent"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# === Summary ===
|
|
192
|
+
echo ""
|
|
193
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
194
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
195
|
+
echo "FAILURES: $FAILURES"
|
|
196
|
+
exit 1
|
|
197
|
+
fi
|
|
198
|
+
echo "ALL PASSED"
|