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,157 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
source "$SCRIPT_DIR/../lib/run-plan-parser.sh"
|
|
6
|
+
source "$SCRIPT_DIR/../lib/run-plan-routing.sh"
|
|
7
|
+
source "$SCRIPT_DIR/../lib/run-plan-team.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
|
+
WORK=$(mktemp -d)
|
|
26
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
27
|
+
|
|
28
|
+
# Plan with parallel structure: batch 1 is foundation, 2+3 are parallel, 4 depends on both
|
|
29
|
+
cat > "$WORK/parallel-plan.md" << 'PLAN'
|
|
30
|
+
## Batch 1: Foundation
|
|
31
|
+
|
|
32
|
+
**Files:**
|
|
33
|
+
- Create: `src/lib.sh`
|
|
34
|
+
|
|
35
|
+
### Task 1: Create lib
|
|
36
|
+
|
|
37
|
+
## Batch 2: Feature A
|
|
38
|
+
|
|
39
|
+
**Files:**
|
|
40
|
+
- Create: `src/feature-a.sh`
|
|
41
|
+
context_refs: src/lib.sh
|
|
42
|
+
|
|
43
|
+
### Task 2: Build feature A
|
|
44
|
+
|
|
45
|
+
## Batch 3: Feature B
|
|
46
|
+
|
|
47
|
+
**Files:**
|
|
48
|
+
- Create: `src/feature-b.sh`
|
|
49
|
+
context_refs: src/lib.sh
|
|
50
|
+
|
|
51
|
+
### Task 3: Build feature B
|
|
52
|
+
|
|
53
|
+
## Batch 4: Integration
|
|
54
|
+
|
|
55
|
+
**Files:**
|
|
56
|
+
- Modify: `src/feature-a.sh`
|
|
57
|
+
- Modify: `src/feature-b.sh`
|
|
58
|
+
context_refs: src/feature-a.sh, src/feature-b.sh
|
|
59
|
+
|
|
60
|
+
### Task 4: Wire together
|
|
61
|
+
PLAN
|
|
62
|
+
|
|
63
|
+
# Test compute_parallel_groups with parallel plan
|
|
64
|
+
dep_graph=$(build_dependency_graph "$WORK/parallel-plan.md")
|
|
65
|
+
groups=$(compute_parallel_groups "$dep_graph" 1 4)
|
|
66
|
+
|
|
67
|
+
# Should produce 3 groups: [1], [2,3], [4]
|
|
68
|
+
group_count=$(echo "$groups" | jq 'length')
|
|
69
|
+
assert_eq "parallel groups: 3 groups" "3" "$group_count"
|
|
70
|
+
|
|
71
|
+
# First group has batch 1
|
|
72
|
+
first_group=$(echo "$groups" | jq -c '.[0] | sort')
|
|
73
|
+
assert_eq "parallel groups: group 1 = [1]" '[1]' "$first_group"
|
|
74
|
+
|
|
75
|
+
# Second group has batches 2 and 3 (in some order)
|
|
76
|
+
second_group=$(echo "$groups" | jq -c '.[1] | sort')
|
|
77
|
+
assert_eq "parallel groups: group 2 = [2,3]" '[2,3]' "$second_group"
|
|
78
|
+
|
|
79
|
+
# Third group has batch 4
|
|
80
|
+
third_group=$(echo "$groups" | jq -c '.[2] | sort')
|
|
81
|
+
assert_eq "parallel groups: group 3 = [4]" '[4]' "$third_group"
|
|
82
|
+
|
|
83
|
+
# Sequential plan (each depends on previous)
|
|
84
|
+
cat > "$WORK/sequential-plan.md" << 'PLAN'
|
|
85
|
+
## Batch 1: Setup
|
|
86
|
+
|
|
87
|
+
**Files:**
|
|
88
|
+
- Create: `src/main.sh`
|
|
89
|
+
|
|
90
|
+
### Task 1: Setup
|
|
91
|
+
|
|
92
|
+
## Batch 2: Extend
|
|
93
|
+
|
|
94
|
+
**Files:**
|
|
95
|
+
- Modify: `src/main.sh`
|
|
96
|
+
context_refs: src/main.sh
|
|
97
|
+
|
|
98
|
+
### Task 2: Extend
|
|
99
|
+
|
|
100
|
+
## Batch 3: Finalize
|
|
101
|
+
|
|
102
|
+
**Files:**
|
|
103
|
+
- Modify: `src/main.sh`
|
|
104
|
+
context_refs: src/main.sh
|
|
105
|
+
|
|
106
|
+
### Task 3: Finalize
|
|
107
|
+
PLAN
|
|
108
|
+
|
|
109
|
+
dep_graph=$(build_dependency_graph "$WORK/sequential-plan.md")
|
|
110
|
+
groups=$(compute_parallel_groups "$dep_graph" 1 3)
|
|
111
|
+
|
|
112
|
+
# Sequential plan: each batch is its own group
|
|
113
|
+
group_count=$(echo "$groups" | jq 'length')
|
|
114
|
+
assert_eq "sequential groups: 3 groups (no parallelism)" "3" "$group_count"
|
|
115
|
+
|
|
116
|
+
# Each group has exactly one batch
|
|
117
|
+
for ((g = 0; g < 3; g++)); do
|
|
118
|
+
size=$(echo "$groups" | jq ".[$g] | length")
|
|
119
|
+
assert_eq "sequential groups: group $((g+1)) has 1 batch" "1" "$size"
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
# Test with subset range (start_batch=2, end_batch=3)
|
|
123
|
+
dep_graph=$(build_dependency_graph "$WORK/parallel-plan.md")
|
|
124
|
+
groups=$(compute_parallel_groups "$dep_graph" 2 3)
|
|
125
|
+
group_count=$(echo "$groups" | jq 'length')
|
|
126
|
+
# Batches 2 and 3 both depend on batch 1 which is outside our range
|
|
127
|
+
# Since batch 1 is not in range, its deps should be treated as satisfied
|
|
128
|
+
assert_eq "subset range: batches 2,3 form 1 group (deps outside range)" "1" "$group_count"
|
|
129
|
+
|
|
130
|
+
# === Bug #1: Team mode emits shared-worktree WARNING ===
|
|
131
|
+
|
|
132
|
+
TEAM_FILE="$SCRIPT_DIR/../lib/run-plan-team.sh"
|
|
133
|
+
|
|
134
|
+
TESTS=$((TESTS + 1))
|
|
135
|
+
if grep -q 'WARNING.*shared worktree\|WARNING.*Team mode.*shared\|WARNING: Team mode' "$TEAM_FILE"; then
|
|
136
|
+
echo "PASS: run_mode_team emits shared-worktree WARNING"
|
|
137
|
+
else
|
|
138
|
+
echo "FAIL: run_mode_team should emit a WARNING about shared worktree (bug #1)"
|
|
139
|
+
FAILURES=$((FAILURES + 1))
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# The warning should be emitted to stderr (>&2)
|
|
143
|
+
TESTS=$((TESTS + 1))
|
|
144
|
+
if grep -q 'WARNING.*>&2' "$TEAM_FILE"; then
|
|
145
|
+
echo "PASS: team mode WARNING goes to stderr"
|
|
146
|
+
else
|
|
147
|
+
echo "FAIL: team mode WARNING should be sent to stderr (>&2) (bug #1)"
|
|
148
|
+
FAILURES=$((FAILURES + 1))
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
echo ""
|
|
152
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
153
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
154
|
+
echo "FAILURES: $FAILURES"
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
echo "ALL PASSED"
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
source "$SCRIPT_DIR/test-helpers.sh"
|
|
6
|
+
|
|
7
|
+
INFER="$SCRIPT_DIR/../scope-infer.sh"
|
|
8
|
+
|
|
9
|
+
# --- Test: --help exits 0 ---
|
|
10
|
+
assert_exit "--help exits 0" 0 "$INFER" --help
|
|
11
|
+
|
|
12
|
+
# --- Test: --dry-run shows proposed scope without modifying files ---
|
|
13
|
+
WORK=$(mktemp -d)
|
|
14
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
15
|
+
|
|
16
|
+
# Create a lesson with no scope field, mentioning "HA" and "entity"
|
|
17
|
+
cat > "$WORK/0099-test-ha-lesson.md" <<'LESSON'
|
|
18
|
+
---
|
|
19
|
+
id: 99
|
|
20
|
+
title: "HA entity resolution fails on restart"
|
|
21
|
+
severity: should-fix
|
|
22
|
+
languages: [python]
|
|
23
|
+
category: data-model
|
|
24
|
+
pattern:
|
|
25
|
+
type: semantic
|
|
26
|
+
description: "HA entity lookup returns stale area"
|
|
27
|
+
fix: "Refresh entity registry on restart"
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Observation
|
|
31
|
+
Home Assistant entity area resolution uses a cached registry.
|
|
32
|
+
LESSON
|
|
33
|
+
|
|
34
|
+
dry_output=$("$INFER" --dir "$WORK" --dry-run 2>&1 || true)
|
|
35
|
+
assert_contains "--dry-run mentions ha-aria" "domain:ha-aria" "$dry_output"
|
|
36
|
+
|
|
37
|
+
# Verify file was NOT modified (dry run)
|
|
38
|
+
TESTS=$((TESTS + 1))
|
|
39
|
+
if grep -q '^scope:' "$WORK/0099-test-ha-lesson.md" 2>/dev/null; then
|
|
40
|
+
echo "FAIL: --dry-run should not modify lesson files"
|
|
41
|
+
FAILURES=$((FAILURES + 1))
|
|
42
|
+
else
|
|
43
|
+
echo "PASS: --dry-run does not modify lesson files"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# --- Test: --apply writes scope field to lesson ---
|
|
47
|
+
"$INFER" --dir "$WORK" --apply > /dev/null 2>&1 || true
|
|
48
|
+
|
|
49
|
+
TESTS=$((TESTS + 1))
|
|
50
|
+
if grep -q '^scope:' "$WORK/0099-test-ha-lesson.md" 2>/dev/null; then
|
|
51
|
+
echo "PASS: --apply writes scope field to lesson"
|
|
52
|
+
else
|
|
53
|
+
echo "FAIL: --apply should write scope field to lesson"
|
|
54
|
+
FAILURES=$((FAILURES + 1))
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# Verify inferred scope is correct
|
|
58
|
+
scope_line=$(grep '^scope:' "$WORK/0099-test-ha-lesson.md" 2>/dev/null || true)
|
|
59
|
+
assert_contains "--apply infers domain:ha-aria" "domain:ha-aria" "$scope_line"
|
|
60
|
+
|
|
61
|
+
# --- Test: Lesson with existing scope is not modified ---
|
|
62
|
+
cat > "$WORK/0098-already-scoped.md" <<'LESSON'
|
|
63
|
+
---
|
|
64
|
+
id: 98
|
|
65
|
+
title: "Already scoped lesson"
|
|
66
|
+
severity: should-fix
|
|
67
|
+
scope: [language:python]
|
|
68
|
+
languages: [python]
|
|
69
|
+
category: silent-failures
|
|
70
|
+
pattern:
|
|
71
|
+
type: semantic
|
|
72
|
+
description: "test"
|
|
73
|
+
fix: "test"
|
|
74
|
+
---
|
|
75
|
+
LESSON
|
|
76
|
+
|
|
77
|
+
apply_output=$("$INFER" --dir "$WORK" --apply 2>&1 || true)
|
|
78
|
+
scope_line=$(grep '^scope:' "$WORK/0098-already-scoped.md" 2>/dev/null || true)
|
|
79
|
+
assert_contains "existing scope preserved" "language:python" "$scope_line"
|
|
80
|
+
|
|
81
|
+
# --- Test: Python-only lesson with no domain signals → language:python ---
|
|
82
|
+
cat > "$WORK/0097-python-only.md" <<'LESSON'
|
|
83
|
+
---
|
|
84
|
+
id: 97
|
|
85
|
+
title: "Generic Python anti-pattern"
|
|
86
|
+
severity: should-fix
|
|
87
|
+
languages: [python]
|
|
88
|
+
category: async-traps
|
|
89
|
+
pattern:
|
|
90
|
+
type: syntactic
|
|
91
|
+
regex: "some_pattern"
|
|
92
|
+
description: "test"
|
|
93
|
+
fix: "test"
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Observation
|
|
97
|
+
This is a generic Python lesson with no domain signals.
|
|
98
|
+
LESSON
|
|
99
|
+
|
|
100
|
+
"$INFER" --dir "$WORK" --apply > /dev/null 2>&1 || true
|
|
101
|
+
scope_line=$(grep '^scope:' "$WORK/0097-python-only.md" 2>/dev/null || true)
|
|
102
|
+
assert_contains "python-only → language:python" "language:python" "$scope_line"
|
|
103
|
+
|
|
104
|
+
# --- Test: No signals → universal ---
|
|
105
|
+
cat > "$WORK/0096-universal.md" <<'LESSON'
|
|
106
|
+
---
|
|
107
|
+
id: 96
|
|
108
|
+
title: "Generic coding practice"
|
|
109
|
+
severity: nice-to-have
|
|
110
|
+
languages: [all]
|
|
111
|
+
category: test-anti-patterns
|
|
112
|
+
pattern:
|
|
113
|
+
type: syntactic
|
|
114
|
+
regex: "some_other_pattern"
|
|
115
|
+
description: "test"
|
|
116
|
+
fix: "test"
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Observation
|
|
120
|
+
This applies to all projects everywhere.
|
|
121
|
+
LESSON
|
|
122
|
+
|
|
123
|
+
"$INFER" --dir "$WORK" --apply > /dev/null 2>&1 || true
|
|
124
|
+
scope_line=$(grep '^scope:' "$WORK/0096-universal.md" 2>/dev/null || true)
|
|
125
|
+
assert_contains "no signals → universal" "universal" "$scope_line"
|
|
126
|
+
|
|
127
|
+
# --- Test: Summary output shows counts ---
|
|
128
|
+
WORK2=$(mktemp -d)
|
|
129
|
+
trap 'rm -rf "$WORK" "$WORK2"' EXIT
|
|
130
|
+
|
|
131
|
+
cat > "$WORK2/0001-test.md" <<'LESSON'
|
|
132
|
+
---
|
|
133
|
+
id: 1
|
|
134
|
+
title: "Test lesson"
|
|
135
|
+
severity: should-fix
|
|
136
|
+
languages: [python]
|
|
137
|
+
category: silent-failures
|
|
138
|
+
pattern:
|
|
139
|
+
type: syntactic
|
|
140
|
+
regex: "test"
|
|
141
|
+
description: "test"
|
|
142
|
+
fix: "test"
|
|
143
|
+
---
|
|
144
|
+
Generic content.
|
|
145
|
+
LESSON
|
|
146
|
+
|
|
147
|
+
summary_output=$("$INFER" --dir "$WORK2" --dry-run 2>&1 || true)
|
|
148
|
+
assert_contains "summary shows count" "Inferred scope for" "$summary_output"
|
|
149
|
+
|
|
150
|
+
report_results
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test setup-ralph-loop.sh
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/test-helpers.sh"
|
|
7
|
+
|
|
8
|
+
SETUP_SCRIPT="$SCRIPT_DIR/../setup-ralph-loop.sh"
|
|
9
|
+
WORK=$(mktemp -d)
|
|
10
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
11
|
+
|
|
12
|
+
# Run setup-ralph-loop in a temp dir so it writes .claude/ there
|
|
13
|
+
run_setup() {
|
|
14
|
+
(cd "$WORK" && bash "$SETUP_SCRIPT" "$@" 2>&1)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get_yaml_promise() {
|
|
18
|
+
sed -n 's/^completion_promise: *//p' "$WORK/.claude/ralph-loop.local.md"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# === Test: Basic prompt creates state file ===
|
|
22
|
+
rm -rf "$WORK/.claude"
|
|
23
|
+
output=$(run_setup "Hello world")
|
|
24
|
+
assert_contains "basic: creates state file" "Ralph loop activated" "$output"
|
|
25
|
+
assert_contains "basic: shows prompt" "Hello world" "$output"
|
|
26
|
+
|
|
27
|
+
# === Test: Completion promise with double quotes is safely quoted (#22) ===
|
|
28
|
+
rm -rf "$WORK/.claude"
|
|
29
|
+
output=$(run_setup 'Build it' --completion-promise 'say "hello" done')
|
|
30
|
+
yaml_val=$(get_yaml_promise)
|
|
31
|
+
# jq produces JSON-quoted string: "say \"hello\" done"
|
|
32
|
+
assert_contains "double quotes: safely quoted" '\"hello\"' "$yaml_val"
|
|
33
|
+
|
|
34
|
+
# === Test: Completion promise with backslashes is safely quoted (#22) ===
|
|
35
|
+
rm -rf "$WORK/.claude"
|
|
36
|
+
output=$(run_setup 'Build it' --completion-promise 'path\to\thing')
|
|
37
|
+
yaml_val=$(get_yaml_promise)
|
|
38
|
+
# jq produces: "path\\to\\thing"
|
|
39
|
+
assert_contains "backslash: safely quoted" '\\' "$yaml_val"
|
|
40
|
+
|
|
41
|
+
# === Test: Completion promise with single quotes is safely quoted (#22) ===
|
|
42
|
+
rm -rf "$WORK/.claude"
|
|
43
|
+
output=$(run_setup 'Build it' --completion-promise "it's done")
|
|
44
|
+
yaml_val=$(get_yaml_promise)
|
|
45
|
+
assert_contains "single quote: safely quoted" "it's done" "$yaml_val"
|
|
46
|
+
|
|
47
|
+
# === Test: Null completion promise stays null ===
|
|
48
|
+
rm -rf "$WORK/.claude"
|
|
49
|
+
output=$(run_setup "Build it")
|
|
50
|
+
yaml_val=$(get_yaml_promise)
|
|
51
|
+
assert_eq "null promise: stays null" "null" "$yaml_val"
|
|
52
|
+
|
|
53
|
+
# === Test: --help exits 0 ===
|
|
54
|
+
output=$(bash "$SETUP_SCRIPT" --help 2>&1 || echo "EXIT:$?")
|
|
55
|
+
assert_contains "--help: shows usage" "USAGE:" "$output"
|
|
56
|
+
assert_not_contains "--help: exit 0" "EXIT:" "$output"
|
|
57
|
+
|
|
58
|
+
# === Test: No prompt exits 1 ===
|
|
59
|
+
rm -rf "$WORK/.claude"
|
|
60
|
+
output=$(run_setup 2>&1 || echo "EXIT:$?")
|
|
61
|
+
assert_contains "no prompt: exits 1" "EXIT:1" "$output"
|
|
62
|
+
|
|
63
|
+
report_results
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test telegram.sh — ACT_ENV_FILE support
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
7
|
+
|
|
8
|
+
source "$SCRIPT_DIR/test-helpers.sh"
|
|
9
|
+
|
|
10
|
+
# --- Setup ---
|
|
11
|
+
WORK=$(mktemp -d)
|
|
12
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
13
|
+
|
|
14
|
+
# Create a fake .env
|
|
15
|
+
cat > "$WORK/test.env" <<'ENV'
|
|
16
|
+
TELEGRAM_BOT_TOKEN=test-token-123
|
|
17
|
+
TELEGRAM_CHAT_ID=test-chat-456
|
|
18
|
+
ENV
|
|
19
|
+
|
|
20
|
+
# --- Test 1: ACT_ENV_FILE overrides default ---
|
|
21
|
+
unset TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID 2>/dev/null || true
|
|
22
|
+
ACT_ENV_FILE="$WORK/test.env" source "$REPO_ROOT/scripts/lib/telegram.sh"
|
|
23
|
+
ACT_ENV_FILE="$WORK/test.env" _load_telegram_env
|
|
24
|
+
assert_eq "ACT_ENV_FILE loads token" "test-token-123" "$TELEGRAM_BOT_TOKEN"
|
|
25
|
+
assert_eq "ACT_ENV_FILE loads chat id" "test-chat-456" "$TELEGRAM_CHAT_ID"
|
|
26
|
+
|
|
27
|
+
# --- Test 2: Explicit argument still works ---
|
|
28
|
+
unset TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID 2>/dev/null || true
|
|
29
|
+
_load_telegram_env "$WORK/test.env"
|
|
30
|
+
assert_eq "Explicit arg loads token" "test-token-123" "$TELEGRAM_BOT_TOKEN"
|
|
31
|
+
|
|
32
|
+
# --- Test 3: Missing file returns error ---
|
|
33
|
+
unset TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID 2>/dev/null || true
|
|
34
|
+
exit_code=0
|
|
35
|
+
_load_telegram_env "$WORK/nonexistent.env" 2>/dev/null || exit_code=$?
|
|
36
|
+
assert_eq "Missing env file returns 1" "1" "$exit_code"
|
|
37
|
+
|
|
38
|
+
report_results
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test telegram.sh shared library
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/../lib/telegram.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
|
+
"$@" || 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
|
+
WORK=$(mktemp -d)
|
|
41
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
42
|
+
|
|
43
|
+
# === _load_telegram_env tests ===
|
|
44
|
+
|
|
45
|
+
# Missing file
|
|
46
|
+
assert_exit "_load_telegram_env: missing file returns 1" 1 \
|
|
47
|
+
_load_telegram_env "$WORK/nonexistent"
|
|
48
|
+
|
|
49
|
+
# File without keys
|
|
50
|
+
echo "SOME_OTHER_KEY=value" > "$WORK/empty.env"
|
|
51
|
+
assert_exit "_load_telegram_env: missing keys returns 1" 1 \
|
|
52
|
+
_load_telegram_env "$WORK/empty.env"
|
|
53
|
+
|
|
54
|
+
# File with both keys
|
|
55
|
+
cat > "$WORK/valid.env" << 'ENVFILE'
|
|
56
|
+
TELEGRAM_BOT_TOKEN=test-token-123
|
|
57
|
+
TELEGRAM_CHAT_ID=test-chat-456
|
|
58
|
+
ENVFILE
|
|
59
|
+
# File with export prefix
|
|
60
|
+
cat > "$WORK/export.env" << 'ENVFILE'
|
|
61
|
+
export TELEGRAM_BOT_TOKEN=export-token-789
|
|
62
|
+
export TELEGRAM_CHAT_ID=export-chat-012
|
|
63
|
+
ENVFILE
|
|
64
|
+
assert_exit "_load_telegram_env: export prefix returns 0" 0 \
|
|
65
|
+
_load_telegram_env "$WORK/export.env"
|
|
66
|
+
assert_eq "_load_telegram_env: export token parsed" "export-token-789" "$TELEGRAM_BOT_TOKEN"
|
|
67
|
+
assert_eq "_load_telegram_env: export chat_id parsed" "export-chat-012" "$TELEGRAM_CHAT_ID"
|
|
68
|
+
|
|
69
|
+
# File with both keys (no export)
|
|
70
|
+
assert_exit "_load_telegram_env: valid file returns 0" 0 \
|
|
71
|
+
_load_telegram_env "$WORK/valid.env"
|
|
72
|
+
assert_eq "_load_telegram_env: token loaded" "test-token-123" "$TELEGRAM_BOT_TOKEN"
|
|
73
|
+
assert_eq "_load_telegram_env: chat_id loaded" "test-chat-456" "$TELEGRAM_CHAT_ID"
|
|
74
|
+
|
|
75
|
+
# === Quote stripping (#7): values wrapped in double quotes ===
|
|
76
|
+
|
|
77
|
+
cat > "$WORK/quoted-double.env" << 'ENVFILE'
|
|
78
|
+
TELEGRAM_BOT_TOKEN="quoted-token-abc"
|
|
79
|
+
TELEGRAM_CHAT_ID="quoted-chat-def"
|
|
80
|
+
ENVFILE
|
|
81
|
+
assert_exit "_load_telegram_env: double-quoted values returns 0" 0 \
|
|
82
|
+
_load_telegram_env "$WORK/quoted-double.env"
|
|
83
|
+
assert_eq "_load_telegram_env: double-quoted token stripped" "quoted-token-abc" "$TELEGRAM_BOT_TOKEN"
|
|
84
|
+
assert_eq "_load_telegram_env: double-quoted chat_id stripped" "quoted-chat-def" "$TELEGRAM_CHAT_ID"
|
|
85
|
+
|
|
86
|
+
# === Quote stripping (#7): values wrapped in single quotes ===
|
|
87
|
+
|
|
88
|
+
cat > "$WORK/quoted-single.env" << 'ENVFILE'
|
|
89
|
+
TELEGRAM_BOT_TOKEN='single-token-ghi'
|
|
90
|
+
TELEGRAM_CHAT_ID='single-chat-jkl'
|
|
91
|
+
ENVFILE
|
|
92
|
+
assert_exit "_load_telegram_env: single-quoted values returns 0" 0 \
|
|
93
|
+
_load_telegram_env "$WORK/quoted-single.env"
|
|
94
|
+
assert_eq "_load_telegram_env: single-quoted token stripped" "single-token-ghi" "$TELEGRAM_BOT_TOKEN"
|
|
95
|
+
assert_eq "_load_telegram_env: single-quoted chat_id stripped" "single-chat-jkl" "$TELEGRAM_CHAT_ID"
|
|
96
|
+
|
|
97
|
+
# === Quote stripping (#7): export with double quotes ===
|
|
98
|
+
|
|
99
|
+
cat > "$WORK/export-quoted.env" << 'ENVFILE'
|
|
100
|
+
export TELEGRAM_BOT_TOKEN="export-quoted-mno"
|
|
101
|
+
export TELEGRAM_CHAT_ID="export-quoted-pqr"
|
|
102
|
+
ENVFILE
|
|
103
|
+
assert_exit "_load_telegram_env: export double-quoted returns 0" 0 \
|
|
104
|
+
_load_telegram_env "$WORK/export-quoted.env"
|
|
105
|
+
assert_eq "_load_telegram_env: export double-quoted token stripped" "export-quoted-mno" "$TELEGRAM_BOT_TOKEN"
|
|
106
|
+
assert_eq "_load_telegram_env: export double-quoted chat_id stripped" "export-quoted-pqr" "$TELEGRAM_CHAT_ID"
|
|
107
|
+
|
|
108
|
+
# === _send_telegram without credentials ===
|
|
109
|
+
|
|
110
|
+
unset TELEGRAM_BOT_TOKEN TELEGRAM_CHAT_ID
|
|
111
|
+
assert_exit "_send_telegram: no creds returns 0 (skip)" 0 \
|
|
112
|
+
_send_telegram "test message"
|
|
113
|
+
|
|
114
|
+
# === Summary ===
|
|
115
|
+
echo ""
|
|
116
|
+
echo "Results: $((TESTS - FAILURES))/$TESTS passed"
|
|
117
|
+
if [[ $FAILURES -gt 0 ]]; then
|
|
118
|
+
echo "FAILURES: $FAILURES"
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
121
|
+
echo "ALL PASSED"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Test scripts/telemetry.sh — telemetry capture, show, export, reset
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
7
|
+
TELEMETRY="$REPO_ROOT/scripts/telemetry.sh"
|
|
8
|
+
|
|
9
|
+
source "$SCRIPT_DIR/test-helpers.sh"
|
|
10
|
+
|
|
11
|
+
# --- Setup ---
|
|
12
|
+
WORK=$(mktemp -d)
|
|
13
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
14
|
+
mkdir -p "$WORK/logs"
|
|
15
|
+
|
|
16
|
+
# --- Test 1: record writes to telemetry.jsonl ---
|
|
17
|
+
bash "$TELEMETRY" record --project-root "$WORK" \
|
|
18
|
+
--batch-number 1 --passed true --strategy superpowers \
|
|
19
|
+
--duration 120 --cost 0.42 --test-delta 5 2>&1 || true
|
|
20
|
+
assert_eq "record creates telemetry.jsonl" "true" \
|
|
21
|
+
"$([ -f "$WORK/logs/telemetry.jsonl" ] && echo true || echo false)"
|
|
22
|
+
|
|
23
|
+
# --- Test 2: record appends valid JSON ---
|
|
24
|
+
line=$(head -1 "$WORK/logs/telemetry.jsonl")
|
|
25
|
+
jq_exit=0
|
|
26
|
+
echo "$line" | jq . >/dev/null 2>&1 || jq_exit=$?
|
|
27
|
+
assert_eq "record writes valid JSON" "0" "$jq_exit"
|
|
28
|
+
|
|
29
|
+
# --- Test 3: show produces dashboard output ---
|
|
30
|
+
output=$(bash "$TELEMETRY" show --project-root "$WORK" 2>&1 || true)
|
|
31
|
+
assert_contains "show displays header" "Telemetry Dashboard" "$output"
|
|
32
|
+
|
|
33
|
+
# --- Test 4: export produces anonymized output ---
|
|
34
|
+
bash "$TELEMETRY" export --project-root "$WORK" > "$WORK/export.json" 2>&1 || true
|
|
35
|
+
assert_eq "export creates output" "true" "$([ -s "$WORK/export.json" ] && echo true || echo false)"
|
|
36
|
+
|
|
37
|
+
# --- Test 5: reset clears telemetry ---
|
|
38
|
+
bash "$TELEMETRY" reset --project-root "$WORK" --yes 2>&1 || true
|
|
39
|
+
if [[ -f "$WORK/logs/telemetry.jsonl" ]]; then
|
|
40
|
+
line_count=$(wc -l < "$WORK/logs/telemetry.jsonl")
|
|
41
|
+
assert_eq "reset clears telemetry" "0" "$line_count"
|
|
42
|
+
else
|
|
43
|
+
pass "reset removes telemetry file"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
report_results
|