xtrm-tools 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -111
- package/cli/dist/index.cjs +142 -53
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/config/pi/extensions/beads.ts +24 -0
- package/hooks/beads-gate-core.mjs +6 -4
- package/hooks/beads-memory-gate.mjs +12 -5
- package/hooks/hooks.json +126 -0
- package/package.json +3 -1
- package/skills/test-planning/SKILL.md +208 -0
- package/skills/test-planning/evals/evals.json +23 -0
- package/skills/using-xtrm/SKILL.md +5 -27
- package/project-skills/tdd-guard/.claude/hooks/tdd-guard-pretool-bridge.cjs +0 -103
- package/project-skills/tdd-guard/.claude/settings.json +0 -38
- package/project-skills/tdd-guard/.claude/skills/using-tdd-guard/SKILL.md +0 -79
- package/project-skills/tdd-guard/CLAUDE.md +0 -98
- package/project-skills/tdd-guard/CONTRIBUTING.md +0 -38
- package/project-skills/tdd-guard/DEVELOPMENT.md +0 -127
- package/project-skills/tdd-guard/LICENSE +0 -21
- package/project-skills/tdd-guard/README.md +0 -398
- package/project-skills/tdd-guard/docs/adr/001-claude-session-subdirectory.md +0 -52
- package/project-skills/tdd-guard/docs/adr/002-secure-claude-binary-path.md +0 -56
- package/project-skills/tdd-guard/docs/adr/003-remove-configurable-data-directory.md +0 -56
- package/project-skills/tdd-guard/docs/adr/004-monorepo-architecture.md +0 -64
- package/project-skills/tdd-guard/docs/adr/005-claude-project-dir-support.md +0 -55
- package/project-skills/tdd-guard/docs/adr/006-phpunit-separate-repository.md +0 -93
- package/project-skills/tdd-guard/docs/adr/007-golangci-lint-path-support.md +0 -83
- package/project-skills/tdd-guard/docs/adr/008-storybook-reporter-design.md +0 -182
- package/project-skills/tdd-guard/docs/assets/tdd-guard-demo-screenshot.gif +0 -0
- package/project-skills/tdd-guard/docs/config-migration.md +0 -143
- package/project-skills/tdd-guard/docs/configuration.md +0 -137
- package/project-skills/tdd-guard/docs/custom-instructions.md +0 -43
- package/project-skills/tdd-guard/docs/enforcement.md +0 -46
- package/project-skills/tdd-guard/docs/ignore-patterns.md +0 -81
- package/project-skills/tdd-guard/docs/linting.md +0 -109
- package/project-skills/tdd-guard/docs/quick-commands.md +0 -52
- package/project-skills/tdd-guard/docs/session-management.md +0 -75
- package/project-skills/tdd-guard/docs/storybook-vitest-addon.md +0 -120
- package/project-skills/tdd-guard/docs/validation-model.md +0 -63
- package/project-skills/tdd-guard/eslint.config.mjs +0 -140
- package/project-skills/tdd-guard/package-lock.json +0 -16937
- package/project-skills/tdd-guard/package.json +0 -102
- package/project-skills/tdd-guard/reporters/go/README.md +0 -67
- package/project-skills/tdd-guard/reporters/go/cmd/tdd-guard-go/main.go +0 -127
- package/project-skills/tdd-guard/reporters/go/cmd/tdd-guard-go/main_test.go +0 -280
- package/project-skills/tdd-guard/reporters/go/go.mod +0 -3
- package/project-skills/tdd-guard/reporters/go/go.sum +0 -0
- package/project-skills/tdd-guard/reporters/go/internal/formatter/formatter.go +0 -126
- package/project-skills/tdd-guard/reporters/go/internal/formatter/formatter_test.go +0 -264
- package/project-skills/tdd-guard/reporters/go/internal/io/tee_reader.go +0 -26
- package/project-skills/tdd-guard/reporters/go/internal/io/tee_reader_test.go +0 -37
- package/project-skills/tdd-guard/reporters/go/internal/parser/mixed_reader.go +0 -94
- package/project-skills/tdd-guard/reporters/go/internal/parser/mixed_reader_test.go +0 -198
- package/project-skills/tdd-guard/reporters/go/internal/parser/parser.go +0 -245
- package/project-skills/tdd-guard/reporters/go/internal/parser/parser_test.go +0 -547
- package/project-skills/tdd-guard/reporters/go/internal/storage/storage.go +0 -35
- package/project-skills/tdd-guard/reporters/go/internal/storage/storage_test.go +0 -113
- package/project-skills/tdd-guard/reporters/go/internal/transformer/transformer.go +0 -103
- package/project-skills/tdd-guard/reporters/go/internal/transformer/transformer_test.go +0 -303
- package/project-skills/tdd-guard/reporters/jest/README.md +0 -102
- package/project-skills/tdd-guard/reporters/jest/package.json +0 -38
- package/project-skills/tdd-guard/reporters/jest/src/JestReporter.test-data.ts +0 -199
- package/project-skills/tdd-guard/reporters/jest/src/JestReporter.test.ts +0 -302
- package/project-skills/tdd-guard/reporters/jest/src/JestReporter.ts +0 -201
- package/project-skills/tdd-guard/reporters/jest/src/index.ts +0 -4
- package/project-skills/tdd-guard/reporters/jest/src/types.ts +0 -42
- package/project-skills/tdd-guard/reporters/jest/tsconfig.json +0 -11
- package/project-skills/tdd-guard/reporters/phpunit/.php-cs-fixer.php +0 -28
- package/project-skills/tdd-guard/reporters/phpunit/README.md +0 -97
- package/project-skills/tdd-guard/reporters/phpunit/SYNC_README.md +0 -29
- package/project-skills/tdd-guard/reporters/phpunit/composer.json +0 -55
- package/project-skills/tdd-guard/reporters/phpunit/phpunit.xml.dist +0 -19
- package/project-skills/tdd-guard/reporters/phpunit/psalm.xml +0 -44
- package/project-skills/tdd-guard/reporters/phpunit/src/Event/ErroredTestSubscriber.php +0 -28
- package/project-skills/tdd-guard/reporters/phpunit/src/Event/FailedTestSubscriber.php +0 -28
- package/project-skills/tdd-guard/reporters/phpunit/src/Event/IncompleteTestSubscriber.php +0 -28
- package/project-skills/tdd-guard/reporters/phpunit/src/Event/PassedTestSubscriber.php +0 -27
- package/project-skills/tdd-guard/reporters/phpunit/src/Event/SkippedTestSubscriber.php +0 -28
- package/project-skills/tdd-guard/reporters/phpunit/src/Event/TestRunnerFinishedSubscriber.php +0 -24
- package/project-skills/tdd-guard/reporters/phpunit/src/PathValidator.php +0 -88
- package/project-skills/tdd-guard/reporters/phpunit/src/Storage.php +0 -26
- package/project-skills/tdd-guard/reporters/phpunit/src/TddGuardExtension.php +0 -33
- package/project-skills/tdd-guard/reporters/phpunit/src/TddGuardListener.php +0 -158
- package/project-skills/tdd-guard/reporters/phpunit/src/TddGuardSubscriber.php +0 -35
- package/project-skills/tdd-guard/reporters/phpunit/src/TestResultCollector.php +0 -105
- package/project-skills/tdd-guard/reporters/phpunit/tests/PathValidatorTest.php +0 -74
- package/project-skills/tdd-guard/reporters/phpunit/tests/TddGuardExtensionFailedTest.php +0 -241
- package/project-skills/tdd-guard/reporters/phpunit/tests/TddGuardExtensionTest.php +0 -84
- package/project-skills/tdd-guard/reporters/phpunit/tests/TddGuardStorageLocationTest.php +0 -71
- package/project-skills/tdd-guard/reporters/pytest/README.md +0 -77
- package/project-skills/tdd-guard/reporters/pytest/pyproject.toml +0 -43
- package/project-skills/tdd-guard/reporters/pytest/pytest.ini.example +0 -7
- package/project-skills/tdd-guard/reporters/pytest/tdd_guard_pytest/__init__.py +0 -1
- package/project-skills/tdd-guard/reporters/pytest/tdd_guard_pytest/pytest_reporter.py +0 -134
- package/project-skills/tdd-guard/reporters/pytest/tests/__init__.py +0 -1
- package/project-skills/tdd-guard/reporters/pytest/tests/conftest.py +0 -3
- package/project-skills/tdd-guard/reporters/pytest/tests/helpers.py +0 -293
- package/project-skills/tdd-guard/reporters/pytest/tests/test_config_option.py +0 -38
- package/project-skills/tdd-guard/reporters/pytest/tests/test_path_validation.py +0 -59
- package/project-skills/tdd-guard/reporters/pytest/tests/test_plugin_config.py +0 -32
- package/project-skills/tdd-guard/reporters/pytest/tests/test_project_root.py +0 -296
- package/project-skills/tdd-guard/reporters/pytest/tests/test_pytest_reporter.py +0 -137
- package/project-skills/tdd-guard/reporters/rspec/Gemfile +0 -3
- package/project-skills/tdd-guard/reporters/rust/Cargo.lock +0 -458
- package/project-skills/tdd-guard/reporters/rust/Cargo.toml +0 -33
- package/project-skills/tdd-guard/reporters/rust/Makefile.example +0 -95
- package/project-skills/tdd-guard/reporters/rust/README.md +0 -88
- package/project-skills/tdd-guard/reporters/rust/src/error_parser.rs +0 -309
- package/project-skills/tdd-guard/reporters/rust/src/main.rs +0 -464
- package/project-skills/tdd-guard/reporters/rust/src/parser.rs +0 -225
- package/project-skills/tdd-guard/reporters/rust/src/transformer.rs +0 -409
- package/project-skills/tdd-guard/reporters/storybook/README.md +0 -108
- package/project-skills/tdd-guard/reporters/storybook/package-lock.json +0 -9482
- package/project-skills/tdd-guard/reporters/storybook/package.json +0 -43
- package/project-skills/tdd-guard/reporters/storybook/src/StorybookReporter.test-data.ts +0 -22
- package/project-skills/tdd-guard/reporters/storybook/src/StorybookReporter.test.ts +0 -190
- package/project-skills/tdd-guard/reporters/storybook/src/StorybookReporter.ts +0 -88
- package/project-skills/tdd-guard/reporters/storybook/src/index.ts +0 -12
- package/project-skills/tdd-guard/reporters/storybook/src/types.ts +0 -37
- package/project-skills/tdd-guard/reporters/storybook/tsconfig.json +0 -11
- package/project-skills/tdd-guard/reporters/test/artifacts/go/failing/go.mod +0 -3
- package/project-skills/tdd-guard/reporters/test/artifacts/go/failing/single_failing_test.go +0 -13
- package/project-skills/tdd-guard/reporters/test/artifacts/go/import/go.mod +0 -3
- package/project-skills/tdd-guard/reporters/test/artifacts/go/import/single_import_error_test.go +0 -17
- package/project-skills/tdd-guard/reporters/test/artifacts/go/passing/go.mod +0 -3
- package/project-skills/tdd-guard/reporters/test/artifacts/go/passing/single_passing_test.go +0 -13
- package/project-skills/tdd-guard/reporters/test/artifacts/jest/single-failing.test.js +0 -5
- package/project-skills/tdd-guard/reporters/test/artifacts/jest/single-import-error.test.js +0 -8
- package/project-skills/tdd-guard/reporters/test/artifacts/jest/single-passing.test.js +0 -5
- package/project-skills/tdd-guard/reporters/test/artifacts/phpunit/SingleFailingTest.php +0 -11
- package/project-skills/tdd-guard/reporters/test/artifacts/phpunit/SingleImportErrorTest.php +0 -14
- package/project-skills/tdd-guard/reporters/test/artifacts/phpunit/SinglePassingTest.php +0 -11
- package/project-skills/tdd-guard/reporters/test/artifacts/pytest/test_single_failing.py +0 -3
- package/project-skills/tdd-guard/reporters/test/artifacts/pytest/test_single_import_error.py +0 -6
- package/project-skills/tdd-guard/reporters/test/artifacts/pytest/test_single_passing.py +0 -3
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/failing/Cargo.lock +0 -7
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/failing/Cargo.toml +0 -4
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/failing/src/lib.rs +0 -14
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/import/Cargo.lock +0 -7
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/import/Cargo.toml +0 -4
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/import/src/lib.rs +0 -13
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/passing/Cargo.lock +0 -7
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/passing/Cargo.toml +0 -4
- package/project-skills/tdd-guard/reporters/test/artifacts/rust/passing/src/lib.rs +0 -14
- package/project-skills/tdd-guard/reporters/test/artifacts/storybook/Calculator.js +0 -4
- package/project-skills/tdd-guard/reporters/test/artifacts/storybook/single-failing.stories.js +0 -15
- package/project-skills/tdd-guard/reporters/test/artifacts/storybook/single-import-error.stories.js +0 -14
- package/project-skills/tdd-guard/reporters/test/artifacts/storybook/single-passing.stories.js +0 -15
- package/project-skills/tdd-guard/reporters/test/artifacts/vitest/single-failing.test.js +0 -7
- package/project-skills/tdd-guard/reporters/test/artifacts/vitest/single-import-error.test.js +0 -9
- package/project-skills/tdd-guard/reporters/test/artifacts/vitest/single-passing.test.js +0 -7
- package/project-skills/tdd-guard/reporters/test/factories/go.ts +0 -59
- package/project-skills/tdd-guard/reporters/test/factories/helpers.ts +0 -48
- package/project-skills/tdd-guard/reporters/test/factories/index.ts +0 -7
- package/project-skills/tdd-guard/reporters/test/factories/jest.ts +0 -51
- package/project-skills/tdd-guard/reporters/test/factories/phpunit.ts +0 -63
- package/project-skills/tdd-guard/reporters/test/factories/pytest.ts +0 -41
- package/project-skills/tdd-guard/reporters/test/factories/rust.ts +0 -158
- package/project-skills/tdd-guard/reporters/test/factories/storybook.ts +0 -198
- package/project-skills/tdd-guard/reporters/test/factories/vitest.ts +0 -51
- package/project-skills/tdd-guard/reporters/test/reporters.integration.test.ts +0 -735
- package/project-skills/tdd-guard/reporters/test/types.ts +0 -28
- package/project-skills/tdd-guard/reporters/vitest/README.md +0 -64
- package/project-skills/tdd-guard/reporters/vitest/package.json +0 -35
- package/project-skills/tdd-guard/reporters/vitest/src/VitestReporter.test-data.ts +0 -85
- package/project-skills/tdd-guard/reporters/vitest/src/VitestReporter.test.ts +0 -446
- package/project-skills/tdd-guard/reporters/vitest/src/VitestReporter.ts +0 -110
- package/project-skills/tdd-guard/reporters/vitest/src/index.ts +0 -4
- package/project-skills/tdd-guard/reporters/vitest/src/types.ts +0 -39
- package/project-skills/tdd-guard/reporters/vitest/tsconfig.json +0 -11
- package/project-skills/tdd-guard/src/cli/buildContext.test.ts +0 -200
- package/project-skills/tdd-guard/src/cli/buildContext.ts +0 -48
- package/project-skills/tdd-guard/src/cli/tdd-guard.test.ts +0 -159
- package/project-skills/tdd-guard/src/cli/tdd-guard.ts +0 -48
- package/project-skills/tdd-guard/src/config/Config.test.ts +0 -538
- package/project-skills/tdd-guard/src/config/Config.ts +0 -172
- package/project-skills/tdd-guard/src/contracts/schemas/guardSchemas.test.ts +0 -58
- package/project-skills/tdd-guard/src/contracts/schemas/guardSchemas.ts +0 -8
- package/project-skills/tdd-guard/src/contracts/schemas/lintSchemas.test.ts +0 -347
- package/project-skills/tdd-guard/src/contracts/schemas/lintSchemas.ts +0 -61
- package/project-skills/tdd-guard/src/contracts/schemas/pytestSchemas.test.ts +0 -24
- package/project-skills/tdd-guard/src/contracts/schemas/pytestSchemas.ts +0 -7
- package/project-skills/tdd-guard/src/contracts/schemas/reporterSchemas.test.ts +0 -377
- package/project-skills/tdd-guard/src/contracts/schemas/reporterSchemas.ts +0 -75
- package/project-skills/tdd-guard/src/contracts/schemas/toolSchemas.test.ts +0 -563
- package/project-skills/tdd-guard/src/contracts/schemas/toolSchemas.ts +0 -140
- package/project-skills/tdd-guard/src/contracts/types/ClientType.ts +0 -1
- package/project-skills/tdd-guard/src/contracts/types/ConfigOptions.ts +0 -12
- package/project-skills/tdd-guard/src/contracts/types/Context.ts +0 -16
- package/project-skills/tdd-guard/src/contracts/types/ModelClient.ts +0 -3
- package/project-skills/tdd-guard/src/contracts/types/ValidationResult.ts +0 -6
- package/project-skills/tdd-guard/src/guard/GuardManager.test.ts +0 -336
- package/project-skills/tdd-guard/src/guard/GuardManager.ts +0 -83
- package/project-skills/tdd-guard/src/hooks/HookEvents.test.ts +0 -107
- package/project-skills/tdd-guard/src/hooks/HookEvents.ts +0 -39
- package/project-skills/tdd-guard/src/hooks/fileTypeDetection.ts +0 -16
- package/project-skills/tdd-guard/src/hooks/postToolLint.test.ts +0 -327
- package/project-skills/tdd-guard/src/hooks/postToolLint.ts +0 -165
- package/project-skills/tdd-guard/src/hooks/processHookData.test.ts +0 -465
- package/project-skills/tdd-guard/src/hooks/processHookData.ts +0 -203
- package/project-skills/tdd-guard/src/hooks/sessionHandler.test.ts +0 -136
- package/project-skills/tdd-guard/src/hooks/sessionHandler.ts +0 -31
- package/project-skills/tdd-guard/src/hooks/userPromptHandler.test.ts +0 -131
- package/project-skills/tdd-guard/src/hooks/userPromptHandler.ts +0 -55
- package/project-skills/tdd-guard/src/index.ts +0 -19
- package/project-skills/tdd-guard/src/linters/Linter.ts +0 -5
- package/project-skills/tdd-guard/src/linters/eslint/ESLint.test.ts +0 -183
- package/project-skills/tdd-guard/src/linters/eslint/ESLint.ts +0 -82
- package/project-skills/tdd-guard/src/linters/golangci/GolangciLint.test.ts +0 -170
- package/project-skills/tdd-guard/src/linters/golangci/GolangciLint.ts +0 -148
- package/project-skills/tdd-guard/src/processors/index.ts +0 -1
- package/project-skills/tdd-guard/src/processors/lintProcessor.ts +0 -77
- package/project-skills/tdd-guard/src/processors/testResults/TestResultsProcessor.test.ts +0 -303
- package/project-skills/tdd-guard/src/processors/testResults/TestResultsProcessor.ts +0 -255
- package/project-skills/tdd-guard/src/providers/LinterProvider.test.ts +0 -43
- package/project-skills/tdd-guard/src/providers/LinterProvider.ts +0 -20
- package/project-skills/tdd-guard/src/providers/ModelClientProvider.test.ts +0 -68
- package/project-skills/tdd-guard/src/providers/ModelClientProvider.ts +0 -22
- package/project-skills/tdd-guard/src/storage/FileStorage.test.ts +0 -76
- package/project-skills/tdd-guard/src/storage/FileStorage.ts +0 -108
- package/project-skills/tdd-guard/src/storage/MemoryStorage.ts +0 -57
- package/project-skills/tdd-guard/src/storage/Storage.test.ts +0 -227
- package/project-skills/tdd-guard/src/storage/Storage.ts +0 -17
- package/project-skills/tdd-guard/src/validation/context/context.test.ts +0 -364
- package/project-skills/tdd-guard/src/validation/context/context.ts +0 -155
- package/project-skills/tdd-guard/src/validation/models/AnthropicApi.test.ts +0 -171
- package/project-skills/tdd-guard/src/validation/models/AnthropicApi.ts +0 -49
- package/project-skills/tdd-guard/src/validation/models/ClaudeAgentSdk.test.ts +0 -167
- package/project-skills/tdd-guard/src/validation/models/ClaudeAgentSdk.ts +0 -54
- package/project-skills/tdd-guard/src/validation/models/ClaudeCli.test.ts +0 -239
- package/project-skills/tdd-guard/src/validation/models/ClaudeCli.ts +0 -57
- package/project-skills/tdd-guard/src/validation/prompts/file-types.ts +0 -52
- package/project-skills/tdd-guard/src/validation/prompts/operations/edit.ts +0 -58
- package/project-skills/tdd-guard/src/validation/prompts/operations/multi-edit.ts +0 -54
- package/project-skills/tdd-guard/src/validation/prompts/operations/write.ts +0 -54
- package/project-skills/tdd-guard/src/validation/prompts/response.ts +0 -40
- package/project-skills/tdd-guard/src/validation/prompts/rules.ts +0 -51
- package/project-skills/tdd-guard/src/validation/prompts/system-prompt.ts +0 -10
- package/project-skills/tdd-guard/src/validation/prompts/tools/lint-results.ts +0 -15
- package/project-skills/tdd-guard/src/validation/prompts/tools/test-output.ts +0 -14
- package/project-skills/tdd-guard/src/validation/prompts/tools/todos.ts +0 -9
- package/project-skills/tdd-guard/src/validation/validator.test.ts +0 -268
- package/project-skills/tdd-guard/src/validation/validator.ts +0 -159
- package/project-skills/tdd-guard/test/artifacts/go/.golangci.yml +0 -6
- package/project-skills/tdd-guard/test/artifacts/go/with-issues/file-with-issues.go +0 -12
- package/project-skills/tdd-guard/test/artifacts/go/with-issues/go.mod +0 -3
- package/project-skills/tdd-guard/test/artifacts/go/without-issues/file-without-issues.go +0 -7
- package/project-skills/tdd-guard/test/artifacts/go/without-issues/go.mod +0 -3
- package/project-skills/tdd-guard/test/artifacts/javascript/eslint.config.js +0 -20
- package/project-skills/tdd-guard/test/artifacts/javascript/file-with-issues.js +0 -12
- package/project-skills/tdd-guard/test/artifacts/javascript/file-without-issues.js +0 -10
- package/project-skills/tdd-guard/test/hooks/fileTypeDetection.test.ts +0 -26
- package/project-skills/tdd-guard/test/hooks/processHookData.fileType.test.ts +0 -46
- package/project-skills/tdd-guard/test/hooks/processHookData.python.test.ts +0 -68
- package/project-skills/tdd-guard/test/integration/test-context.test.ts +0 -66
- package/project-skills/tdd-guard/test/integration/validator.core.test.ts +0 -96
- package/project-skills/tdd-guard/test/integration/validator.scenarios.test.ts +0 -497
- package/project-skills/tdd-guard/test/utils/assertions.ts +0 -29
- package/project-skills/tdd-guard/test/utils/factories/contextFactory.ts +0 -30
- package/project-skills/tdd-guard/test/utils/factories/editFactory.ts +0 -82
- package/project-skills/tdd-guard/test/utils/factories/helpers.test.ts +0 -46
- package/project-skills/tdd-guard/test/utils/factories/helpers.ts +0 -46
- package/project-skills/tdd-guard/test/utils/factories/lintFactory.ts +0 -352
- package/project-skills/tdd-guard/test/utils/factories/modelClientProviderFactory.ts +0 -21
- package/project-skills/tdd-guard/test/utils/factories/multiEditFactory.ts +0 -79
- package/project-skills/tdd-guard/test/utils/factories/operations.ts +0 -57
- package/project-skills/tdd-guard/test/utils/factories/reporterFactory.ts +0 -55
- package/project-skills/tdd-guard/test/utils/factories/scenarios/index.ts +0 -22
- package/project-skills/tdd-guard/test/utils/factories/scenarios/languages/python.ts +0 -745
- package/project-skills/tdd-guard/test/utils/factories/scenarios/languages/typescript.ts +0 -767
- package/project-skills/tdd-guard/test/utils/factories/scenarios/types.ts +0 -77
- package/project-skills/tdd-guard/test/utils/factories/scenarios/utils.ts +0 -15
- package/project-skills/tdd-guard/test/utils/factories/sessionStartFactory.ts +0 -36
- package/project-skills/tdd-guard/test/utils/factories/testDefaults.ts +0 -90
- package/project-skills/tdd-guard/test/utils/factories/testResultsFactory.ts +0 -234
- package/project-skills/tdd-guard/test/utils/factories/todoFactory.ts +0 -99
- package/project-skills/tdd-guard/test/utils/factories/userPromptSubmitFactory.ts +0 -39
- package/project-skills/tdd-guard/test/utils/factories/writeFactory.ts +0 -70
- package/project-skills/tdd-guard/test/utils/index.ts +0 -131
- package/project-skills/tdd-guard/tsconfig.build.json +0 -16
- package/project-skills/tdd-guard/tsconfig.eslint.json +0 -17
- package/project-skills/tdd-guard/tsconfig.json +0 -32
- package/project-skills/tdd-guard/tsconfig.node.json +0 -10
- package/project-skills/tdd-guard/vitest.config.ts +0 -85
package/cli/package.json
CHANGED
|
@@ -8,6 +8,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
8
8
|
const getCwd = (ctx: any) => ctx.cwd || process.cwd();
|
|
9
9
|
|
|
10
10
|
let cachedSessionId: string | null = null;
|
|
11
|
+
let memoryGateFired = false;
|
|
11
12
|
|
|
12
13
|
// Resolve a stable session ID across event types.
|
|
13
14
|
const getSessionId = (ctx: any): string => {
|
|
@@ -130,8 +131,31 @@ export default function (pi: ExtensionAPI) {
|
|
|
130
131
|
}
|
|
131
132
|
};
|
|
132
133
|
|
|
134
|
+
// Memory gate: if the session's claimed issue was closed, prompt for insights.
|
|
135
|
+
// Uses sendUserMessage to trigger a new agent turn (Pi has no blocking stop hook).
|
|
136
|
+
// memoryGateFired prevents re-triggering on the follow-up agent_end.
|
|
137
|
+
const triggerMemoryGateIfNeeded = async (ctx: any) => {
|
|
138
|
+
if (memoryGateFired) return;
|
|
139
|
+
const cwd = getCwd(ctx);
|
|
140
|
+
if (!EventAdapter.isBeadsProject(cwd)) return;
|
|
141
|
+
const sessionId = getSessionId(ctx);
|
|
142
|
+
const claimId = await getSessionClaim(sessionId, cwd);
|
|
143
|
+
if (!claimId) return;
|
|
144
|
+
|
|
145
|
+
const result = await SubprocessRunner.run("bd", ["list", "--status=closed"], { cwd });
|
|
146
|
+
if (result.code !== 0 || !result.stdout.includes(claimId)) return;
|
|
147
|
+
|
|
148
|
+
memoryGateFired = true;
|
|
149
|
+
pi.sendUserMessage(
|
|
150
|
+
`🧠 Memory gate: claim \`${claimId}\` was closed this session.\n` +
|
|
151
|
+
`For each closed issue, worth persisting?\n` +
|
|
152
|
+
` YES → \`bd remember "<insight>"\` NO → note "nothing to persist"`,
|
|
153
|
+
);
|
|
154
|
+
};
|
|
155
|
+
|
|
133
156
|
pi.on("agent_end", async (_event, ctx) => {
|
|
134
157
|
await notifySessionEnd(ctx);
|
|
158
|
+
await triggerMemoryGateIfNeeded(ctx);
|
|
135
159
|
return undefined;
|
|
136
160
|
});
|
|
137
161
|
|
|
@@ -154,14 +154,16 @@ export function decideCommitGate(ctx, state) {
|
|
|
154
154
|
return { allow: true };
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
// Has claim but
|
|
158
|
-
|
|
157
|
+
// Has claim but no in_progress issues → allow (stale/already-closed claim)
|
|
158
|
+
if (!state.inProgress || state.inProgress.count === 0) {
|
|
159
|
+
return { allow: true };
|
|
160
|
+
}
|
|
159
161
|
|
|
160
|
-
//
|
|
162
|
+
// Has claim + in_progress issues → block (need to close first)
|
|
161
163
|
return {
|
|
162
164
|
allow: false,
|
|
163
165
|
reason: 'unclosed_claim',
|
|
164
|
-
summary,
|
|
166
|
+
summary: state.inProgress.summary,
|
|
165
167
|
claimed: state.claimId,
|
|
166
168
|
};
|
|
167
169
|
}
|
|
@@ -11,7 +11,7 @@ import { execSync } from 'node:child_process';
|
|
|
11
11
|
import { existsSync, unlinkSync } from 'node:fs';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
13
|
import { readHookInput } from './beads-gate-core.mjs';
|
|
14
|
-
import { resolveCwd, isBeadsProject } from './beads-gate-utils.mjs';
|
|
14
|
+
import { resolveCwd, isBeadsProject, getSessionClaim } from './beads-gate-utils.mjs';
|
|
15
15
|
import { memoryPromptMessage } from './beads-gate-messages.mjs';
|
|
16
16
|
|
|
17
17
|
const input = readHookInput();
|
|
@@ -27,8 +27,15 @@ if (existsSync(marker)) {
|
|
|
27
27
|
process.exit(0);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
// Only
|
|
31
|
-
|
|
30
|
+
// Only fire if this session had an active claim that is now closed
|
|
31
|
+
const sessionId = input.session_id ?? null;
|
|
32
|
+
if (!sessionId) process.exit(0);
|
|
33
|
+
|
|
34
|
+
const claimId = getSessionClaim(sessionId, cwd);
|
|
35
|
+
if (!claimId) process.exit(0); // no claim this session → no work to persist
|
|
36
|
+
|
|
37
|
+
// Check if the claimed issue was closed this session
|
|
38
|
+
let claimClosed = false;
|
|
32
39
|
try {
|
|
33
40
|
const out = execSync('bd list --status=closed', {
|
|
34
41
|
encoding: 'utf8',
|
|
@@ -36,12 +43,12 @@ try {
|
|
|
36
43
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
44
|
timeout: 8000,
|
|
38
45
|
});
|
|
39
|
-
|
|
46
|
+
claimClosed = out.includes(claimId);
|
|
40
47
|
} catch {
|
|
41
48
|
process.exit(0); // fail open
|
|
42
49
|
}
|
|
43
50
|
|
|
44
|
-
if (!
|
|
51
|
+
if (!claimClosed) process.exit(0);
|
|
45
52
|
|
|
46
53
|
process.stderr.write(memoryPromptMessage());
|
|
47
54
|
process.exit(2);
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Write|Edit|MultiEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/main-guard.mjs",
|
|
10
|
+
"timeout": 5000
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"matcher": "Bash",
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/main-guard.mjs",
|
|
20
|
+
"timeout": 5000
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"type": "command",
|
|
24
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-commit-gate.mjs",
|
|
25
|
+
"timeout": 5000
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
|
|
31
|
+
"hooks": [
|
|
32
|
+
{
|
|
33
|
+
"type": "command",
|
|
34
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-edit-gate.mjs",
|
|
35
|
+
"timeout": 5000
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"PostToolUse": [
|
|
41
|
+
{
|
|
42
|
+
"matcher": "Bash",
|
|
43
|
+
"hooks": [
|
|
44
|
+
{
|
|
45
|
+
"type": "command",
|
|
46
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/main-guard-post-push.mjs",
|
|
47
|
+
"timeout": 5000
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"matcher": "Bash|execute_shell_command|bash",
|
|
53
|
+
"hooks": [
|
|
54
|
+
{
|
|
55
|
+
"type": "command",
|
|
56
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-claim-sync.mjs",
|
|
57
|
+
"timeout": 5000
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"matcher": "Bash|mcp__serena__find_symbol|mcp__serena__get_symbols_overview|mcp__serena__search_for_pattern|mcp__serena__find_referencing_symbols|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|mcp__serena__rename_symbol",
|
|
63
|
+
"hooks": [
|
|
64
|
+
{
|
|
65
|
+
"type": "command",
|
|
66
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/gitnexus/gitnexus-hook.cjs",
|
|
67
|
+
"timeout": 10000
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"SessionStart": [
|
|
73
|
+
{
|
|
74
|
+
"hooks": [
|
|
75
|
+
{
|
|
76
|
+
"type": "command",
|
|
77
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-compact-restore.mjs",
|
|
78
|
+
"timeout": 5000
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "command",
|
|
82
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/serena-workflow-reminder.py"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"Stop": [
|
|
88
|
+
{
|
|
89
|
+
"hooks": [
|
|
90
|
+
{
|
|
91
|
+
"type": "command",
|
|
92
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-stop-gate.mjs",
|
|
93
|
+
"timeout": 5000
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"type": "command",
|
|
97
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-memory-gate.mjs",
|
|
98
|
+
"timeout": 8000
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"PreCompact": [
|
|
104
|
+
{
|
|
105
|
+
"hooks": [
|
|
106
|
+
{
|
|
107
|
+
"type": "command",
|
|
108
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-compact-save.mjs",
|
|
109
|
+
"timeout": 5000
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"UserPromptSubmit": [
|
|
115
|
+
{
|
|
116
|
+
"hooks": [
|
|
117
|
+
{
|
|
118
|
+
"type": "command",
|
|
119
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/branch-state.mjs",
|
|
120
|
+
"timeout": 3000
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xtrm-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Claude Code tools installer (skills, hooks, MCP servers)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"sync:cli-version": "node scripts/sync-cli-version.mjs",
|
|
40
|
+
"compile-policies": "node scripts/compile-policies.mjs",
|
|
41
|
+
"check-policies": "node scripts/compile-policies.mjs --check",
|
|
40
42
|
"prebuild": "npm run sync:cli-version",
|
|
41
43
|
"build": "npm run build --workspace cli",
|
|
42
44
|
"typecheck": "npm run typecheck --workspace cli",
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-planning
|
|
3
|
+
description: "Plans and creates test issues alongside implementation work using bd issue tracker. Activates at two points: (1) when creating an issue board from a spec/plan — classifies each issue by code layer and attaches the right testing strategy as a companion issue or AC gate, and (2) when closing an implementation issue — checks whether adequate test coverage was planned, improves existing test issues if needed. Use this skill PROACTIVELY whenever you see implementation issues being created without test coverage, when an epic is being broken into tasks, when closing/reviewing implementation work, or when the user asks about testing strategy for a set of issues. Also activate when you see bd create, bd children, bd close in a planning context."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test Planning
|
|
7
|
+
|
|
8
|
+
This skill ensures every implementation issue has appropriate test coverage planned — not as an afterthought, but wired into the issue board from the start. It does NOT write test code; it classifies what needs testing, picks the right strategy, and creates bd issues that another agent (or human) will implement.
|
|
9
|
+
|
|
10
|
+
## When This Fires
|
|
11
|
+
|
|
12
|
+
### Trigger 1: Planning phase (issue board creation)
|
|
13
|
+
|
|
14
|
+
When breaking a spec or plan into bd issues — typically during epic decomposition or `bd create --parent` sequences — scan each implementation issue and create companion test issues.
|
|
15
|
+
|
|
16
|
+
### Trigger 2: Closure gate (implementation complete)
|
|
17
|
+
|
|
18
|
+
When an implementation issue is being closed (`bd close`), check whether:
|
|
19
|
+
- A test issue already exists for it (created in Trigger 1)
|
|
20
|
+
- The test issue needs updating based on what was actually built (scope may have shifted)
|
|
21
|
+
- Test coverage gaps appeared during implementation (new edge cases, API quirks discovered)
|
|
22
|
+
|
|
23
|
+
If a test issue exists, review and improve it. If none exists, create one before or alongside closure.
|
|
24
|
+
|
|
25
|
+
## Layer Detection
|
|
26
|
+
|
|
27
|
+
Read the issue title, description, and any code paths mentioned to classify which architectural layer the work touches. This determines the testing strategy.
|
|
28
|
+
|
|
29
|
+
### Core layer — pure domain logic
|
|
30
|
+
Code that transforms data, computes values, manages state, with no I/O. Examples:
|
|
31
|
+
- Config parsing/merging
|
|
32
|
+
- Data formatting (output renderers, serializers)
|
|
33
|
+
- Computation (implied rates from prices, spread calculations)
|
|
34
|
+
- State machines (session tracking, log rotation)
|
|
35
|
+
- Validators, parsers, transformers
|
|
36
|
+
|
|
37
|
+
**Signals**: "implement", "compute", "format", "parse", "validate", functions that take data and return data, no HTTP/DB/filesystem in the description.
|
|
38
|
+
|
|
39
|
+
### Boundary layer — I/O interfaces and service contracts
|
|
40
|
+
Code that crosses a system boundary: HTTP clients, API routes, database queries, file I/O, message queues. Examples:
|
|
41
|
+
- API client methods (async_client, REST wrappers)
|
|
42
|
+
- API route handlers
|
|
43
|
+
- Database query functions
|
|
44
|
+
- File readers/writers
|
|
45
|
+
- External service integrations
|
|
46
|
+
|
|
47
|
+
**Signals**: "endpoint", "API", "client", "route", "fetch", "query", URLs, ports, service names, request/response shapes mentioned.
|
|
48
|
+
|
|
49
|
+
### Shell layer — orchestration and wiring
|
|
50
|
+
Code that glues core + boundary together into user-facing features. Examples:
|
|
51
|
+
- CLI commands that call a client, transform data, then output
|
|
52
|
+
- Pipeline orchestrators
|
|
53
|
+
- Command handlers
|
|
54
|
+
- Workflow coordinators
|
|
55
|
+
|
|
56
|
+
**Signals**: "command", "CLI", "subcommand", "mercury <verb>", user-facing behavior described, combines multiple components.
|
|
57
|
+
|
|
58
|
+
## Testing Strategy Selection
|
|
59
|
+
|
|
60
|
+
### By layer
|
|
61
|
+
|
|
62
|
+
| Layer | Primary strategy | What to assert | Mock policy |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| Core | Unit + property tests | Input/output correctness, edge cases, invariants | No mocking needed — pure functions |
|
|
65
|
+
| Boundary | Contract tests (live preferred) | Response schemas, field presence/types, status codes, param behavior | Live > contract > mock (see preference order below) |
|
|
66
|
+
| Shell | Integration tests | Exit codes, output format validity, end-to-end wiring, error messages | Test the real thing via subprocess or function call |
|
|
67
|
+
|
|
68
|
+
### By situation (override layer default when applicable)
|
|
69
|
+
|
|
70
|
+
| Situation | Strategy | When to pick it |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| Interface unclear/evolving | TDD | Spec is vague, requirements shifting — tests define the contract |
|
|
73
|
+
| Contract known up front | Spec-first | API routes documented, response shapes defined — write schema assertions |
|
|
74
|
+
| Parsers/transforms/invariants | Property-based | The function should hold for any valid input, not just examples |
|
|
75
|
+
| Service/API boundaries | Contract testing | Testing the seam between systems — assert schemas, not implementations |
|
|
76
|
+
| Legacy code being wrapped | Characterization tests | Capture current behavior before changing it |
|
|
77
|
+
| Simple CRUD paths | Example-based | Straightforward input→output, a few examples suffice |
|
|
78
|
+
|
|
79
|
+
### Live-first preference
|
|
80
|
+
|
|
81
|
+
When services are accessible, prefer this order:
|
|
82
|
+
|
|
83
|
+
1. **Live tests** — hit real services, assert real responses. No mocking. This catches actual bugs: wrong URLs, changed schemas, auth issues, network edge cases. Mark with `@pytest.mark.live`.
|
|
84
|
+
2. **Contract tests with recorded fixtures** — if live access is intermittent, record responses once and replay. Still validates schema, but won't catch drift.
|
|
85
|
+
3. **Mocked tests** — last resort, only when no service access exists or for pure unit logic that has no I/O.
|
|
86
|
+
|
|
87
|
+
The rationale: mocks encode your assumptions about the system. If your assumptions were correct, you wouldn't need tests. Live tests validate reality.
|
|
88
|
+
|
|
89
|
+
## Creating Test Issues
|
|
90
|
+
|
|
91
|
+
### Naming convention
|
|
92
|
+
|
|
93
|
+
Test issues are children of the same parent epic as the implementation issue. Name pattern:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Test: <what's being tested> — <strategy>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Examples:
|
|
100
|
+
- "Test: rates/candles/stir/curve commands — CLI integration + contract tests"
|
|
101
|
+
- "Test: config system — unit tests for load/save/override/env precedence"
|
|
102
|
+
- "Test: async_client URL routing — live contract tests against all services"
|
|
103
|
+
|
|
104
|
+
### Issue structure
|
|
105
|
+
|
|
106
|
+
When creating a test issue with `bd create`:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
bd create "Test: <description>" \
|
|
110
|
+
-t task -p <same or +1 from impl issue> \
|
|
111
|
+
--parent <same parent epic> \
|
|
112
|
+
-l testing,<layer>,<phase> \
|
|
113
|
+
--deps "blocks:<next-phase-issue-id>" \
|
|
114
|
+
-d "<structured description>"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The description should contain:
|
|
118
|
+
|
|
119
|
+
1. **What implementation it covers** — reference the impl issue ID(s)
|
|
120
|
+
2. **Layer classification** — which layer and why
|
|
121
|
+
3. **Strategy chosen** — which testing approach and why
|
|
122
|
+
4. **Test file structure** — where tests go in the project
|
|
123
|
+
5. **What to assert** — specific assertions, not vague "test that it works"
|
|
124
|
+
6. **AC** — when is this test issue done
|
|
125
|
+
|
|
126
|
+
### Batching
|
|
127
|
+
|
|
128
|
+
Don't create one test issue per implementation issue — that's overhead. Batch by layer and phase:
|
|
129
|
+
|
|
130
|
+
- Group all core-layer issues from the same phase into one test issue
|
|
131
|
+
- Group all boundary-layer issues into one contract test issue
|
|
132
|
+
- Group all shell-layer issues into one integration test issue
|
|
133
|
+
|
|
134
|
+
Example: if a phase ships 4 CLI commands + 1 client change + 1 config change:
|
|
135
|
+
- 1 test issue for core (config unit tests)
|
|
136
|
+
- 1 test issue for boundary (client contract tests)
|
|
137
|
+
- 1 test issue for shell (CLI integration tests for all 4 commands)
|
|
138
|
+
|
|
139
|
+
### Gating
|
|
140
|
+
|
|
141
|
+
Test issues should gate the next phase of work. Use bd dependencies or document in the issue description:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
This issue gates: .17 (analyze runner), .18 (spread), .19 (charts)
|
|
145
|
+
Do not start Phase 3 until these tests pass.
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Closure Gate Behavior
|
|
149
|
+
|
|
150
|
+
When an implementation issue is closed, check:
|
|
151
|
+
|
|
152
|
+
1. **Does a test issue exist?** Run `bd children <parent>` and look for test issues that reference this impl issue.
|
|
153
|
+
|
|
154
|
+
2. **Is the test issue still accurate?** Implementation often diverges from plan. Compare what was built (read the commit, check the code) against what the test issue specifies. Common drift:
|
|
155
|
+
- New subcommands added that aren't in the test plan
|
|
156
|
+
- API response shape different from what was expected
|
|
157
|
+
- Edge cases discovered during implementation
|
|
158
|
+
- Dependencies changed (a service turned out to be local-only)
|
|
159
|
+
|
|
160
|
+
3. **Update if needed.** Use `bd update <test-issue-id>` or `bd comments add <test-issue-id>` to add new assertions, remove obsolete ones, or note discovered quirks.
|
|
161
|
+
|
|
162
|
+
4. **If no test issue exists**, create one. Classify the layer, pick the strategy, write the assertions. This is the safety net for work that was done without planning tests upfront.
|
|
163
|
+
|
|
164
|
+
## Examples
|
|
165
|
+
|
|
166
|
+
### Planning phase — epic decomposition
|
|
167
|
+
|
|
168
|
+
Given an epic with these children:
|
|
169
|
+
```
|
|
170
|
+
.10 Scaffold CLI project structure
|
|
171
|
+
.11 Implement logging system
|
|
172
|
+
.12 Implement config system
|
|
173
|
+
.13 Implement output formatting
|
|
174
|
+
.14 Implement async HTTP client
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Create:
|
|
178
|
+
```
|
|
179
|
+
bd create "Test: P1 core — unit tests for config, log, session, output" \
|
|
180
|
+
-t task -p 1 --parent <epic> -l testing,core,phase-1 \
|
|
181
|
+
-d "Unit + property tests for pure domain logic...
|
|
182
|
+
Covers: .11, .12, .13
|
|
183
|
+
Strategy: unit tests (core layer, pure logic, no I/O)
|
|
184
|
+
..."
|
|
185
|
+
|
|
186
|
+
bd create "Test: P1 boundary — live contract tests for async client" \
|
|
187
|
+
-t task -p 1 --parent <epic> -l testing,boundary,phase-1 \
|
|
188
|
+
-d "Contract tests against live services...
|
|
189
|
+
Covers: .14
|
|
190
|
+
Strategy: contract tests, live-first (boundary layer, HTTP I/O)
|
|
191
|
+
..."
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Closure gate — implementation done, test issue exists
|
|
195
|
+
|
|
196
|
+
Agent closes `.15` (data commands: rates, candles, stir, curve). Finds existing test issue `.26`. Reads `.26` description, compares against what `.15` actually built:
|
|
197
|
+
|
|
198
|
+
- `.15` added `rates iorb` subcommand not in original test plan → update `.26` to include IORB assertion
|
|
199
|
+
- `.15` discovered STIR implied rates are client-side computation → add property test: `implied_rate == 100 - price` for any valid price
|
|
200
|
+
- Update `.26` with `bd update` or add a comment
|
|
201
|
+
|
|
202
|
+
### Closure gate — no test issue exists
|
|
203
|
+
|
|
204
|
+
Agent closes a feature issue that was done ad-hoc. No test issue found. Agent:
|
|
205
|
+
1. Reads the implementation to classify the layer
|
|
206
|
+
2. Picks strategy
|
|
207
|
+
3. Creates test issue as child of same parent
|
|
208
|
+
4. Documents what to assert based on the actual code
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill_name": "test-planning",
|
|
3
|
+
"evals": [
|
|
4
|
+
{
|
|
5
|
+
"id": 1,
|
|
6
|
+
"prompt": "I've got an epic for a new notification service (notif-3a). I just created 8 child issues: .1 is the Postgres schema migration, .2 is the async message consumer (reads from RabbitMQ), .3 is the template renderer (Jinja2, pure python), .4 is the delivery client (calls Twilio/SendGrid APIs), .5 is the REST API for managing preferences, .6 is the CLI tool for ops to send test notifications, .7 is the retry/dead-letter handler, .8 is the rate limiter. Break down what testing each of these needs and create the bd issues.",
|
|
7
|
+
"expected_output": "Should detect layers: .1 (boundary/DB), .2 (boundary/MQ), .3 (core/pure), .4 (boundary/external API), .5 (boundary/API), .6 (shell/CLI), .7 (core/state machine), .8 (core/algorithm). Should batch into ~3 test issues: core tests (.3, .7, .8), boundary/contract tests (.1, .2, .4, .5), shell integration (.6). Should use property-based for rate limiter, contract tests for external APIs, characterization or spec-first for DB schema.",
|
|
8
|
+
"files": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": 2,
|
|
12
|
+
"prompt": "I just finished implementing the data ingestion pipeline (issue data-pipe-9f.4) — it reads CSVs from S3, validates schemas, transforms column types, and writes to Postgres. The parent epic is data-pipe-9f. Can you close it for me? bd close data-pipe-9f.4 --reason 'pipeline implemented and deployed'",
|
|
13
|
+
"expected_output": "Should trigger closure gate behavior: check bd children data-pipe-9f for existing test issues. Since none exist, should create a test issue covering all layers: unit tests for schema validation and column transforms (core), contract tests for S3 reads and Postgres writes (boundary), integration test for end-to-end pipeline (shell). Should NOT just close the issue without checking for test coverage.",
|
|
14
|
+
"files": []
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": 3,
|
|
18
|
+
"prompt": "We have an epic tracker-7b with 5 implementation issues done and 1 test issue (tracker-7b.6) that was created during planning. But during implementation of .3 (the websocket price feed handler), we discovered the feed sometimes sends malformed JSON that the parser needs to handle gracefully, and .5 (the position calculator) ended up also doing margin calculations which weren't in the original plan. Can you review tracker-7b.6 and update it?",
|
|
19
|
+
"expected_output": "Should read tracker-7b.6, identify drift: (1) malformed JSON handling in websocket parser is a new edge case — add property-based tests for parser robustness, (2) margin calculations in position calculator are new core logic — add unit tests. Should update the existing test issue via bd update or bd comments, not create a new one. Should note that the parser needs characterization tests if there's existing behavior to preserve.",
|
|
20
|
+
"files": []
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -4,7 +4,7 @@ description: >
|
|
|
4
4
|
Operating manual for an xtrm-equipped Claude Code session. Activates automatically at
|
|
5
5
|
session start to orient the agent on how to work within the xtrm stack: when to apply
|
|
6
6
|
prompt improvement, how the beads issue-tracking gate works, which hooks enforce workflows,
|
|
7
|
-
and how to compose the full toolset (gitnexus, Serena,
|
|
7
|
+
and how to compose the full toolset (gitnexus, Serena, quality gates, delegation).
|
|
8
8
|
Use this skill whenever a new session begins in an xtrm-tools-installed environment, or
|
|
9
9
|
when the user asks how to work with the xtrm stack, what tools are available, or how any
|
|
10
10
|
xtrm workflow operates.
|
|
@@ -24,7 +24,7 @@ within this stack. Read it at session start and refer back when uncertain about
|
|
|
24
24
|
|---|---|
|
|
25
25
|
| **Skills** | Domain expertise loaded on demand |
|
|
26
26
|
| **Hooks** | Automated lifecycle enforcement (gates, suggestions, reminders) |
|
|
27
|
-
| **Project Skills** | Per-project quality enforcement (
|
|
27
|
+
| **Project Skills** | Per-project quality enforcement (quality-gates, service-skills-set) |
|
|
28
28
|
| **MCP Servers** | Semantic tools: Serena (code), gitnexus (graph), context7 (docs), deepwiki |
|
|
29
29
|
| **CLI** | `xtrm install / status / reset / help` — sync and install tooling |
|
|
30
30
|
| **beads (bd)** | Git-backed issue tracker with session gate enforcement |
|
|
@@ -151,27 +151,6 @@ If index is stale: `npx gitnexus analyze` before using MCP tools.
|
|
|
151
151
|
|
|
152
152
|
---
|
|
153
153
|
|
|
154
|
-
## TDD Guard — Test-First Enforcement
|
|
155
|
-
|
|
156
|
-
This project enforces TDD via `tdd-guard`. It **blocks implementation** until a failing test exists.
|
|
157
|
-
|
|
158
|
-
**The cycle:**
|
|
159
|
-
1. Write a failing test first — use `sed` or `Bash` to append (not `Write`/`Edit`, which the guard intercepts)
|
|
160
|
-
2. Run `npx vitest run <test-file>` to register the failure in `.claude/tdd-guard/data/test.json`
|
|
161
|
-
3. Implement the minimum code to make it pass
|
|
162
|
-
4. Run tests again — guard clears when tests pass
|
|
163
|
-
|
|
164
|
-
Never skip the failing test step. Over-implementation is also flagged — write a stub first, then build up.
|
|
165
|
-
|
|
166
|
-
> **Needs configuration**: tdd-guard is a project skill installed per-project:
|
|
167
|
-
> ```bash
|
|
168
|
-
> xtrm install project tdd-guard
|
|
169
|
-
> ```
|
|
170
|
-
> Requires vitest in the project. After install, verify `.claude/settings.json` includes the
|
|
171
|
-
> PreToolUse and UserPromptSubmit hook entries for tdd-guard.
|
|
172
|
-
|
|
173
|
-
---
|
|
174
|
-
|
|
175
154
|
## Quality Gates — Automatic on Every Edit
|
|
176
155
|
|
|
177
156
|
After each file edit, quality-gates hooks run automatically:
|
|
@@ -204,7 +183,7 @@ unless there is a genuine reason.
|
|
|
204
183
|
| Changing a function | `gitnexus-impact-analysis` first, then Serena edit |
|
|
205
184
|
| Safe rename/refactor | `gitnexus-refactoring` |
|
|
206
185
|
| Docker service project | `using-service-skills` → activate expert persona |
|
|
207
|
-
| Writing new feature |
|
|
186
|
+
| Writing new feature | Write tests alongside, quality gates auto-run after |
|
|
208
187
|
| Maintaining docs | `/documenting` (Serena SSOT drift detection) |
|
|
209
188
|
| Building/improving a skill | `skill-creator` |
|
|
210
189
|
|
|
@@ -227,7 +206,7 @@ unless there is a genuine reason.
|
|
|
227
206
|
`obsidian-cli`, `hook-development`, `claude-api`
|
|
228
207
|
|
|
229
208
|
**Project Skills** (install per-project with `xtrm install project <name>`):
|
|
230
|
-
`
|
|
209
|
+
`quality-gates`, `service-skills-set`
|
|
231
210
|
|
|
232
211
|
---
|
|
233
212
|
|
|
@@ -244,7 +223,6 @@ These hooks run automatically — you cannot disable them mid-session:
|
|
|
244
223
|
| `gitnexus-impact-reminder.py` | UserPromptSubmit (edit-intent keywords) | Injects impact analysis reminder |
|
|
245
224
|
| `serena-workflow-reminder.py` | SessionStart + PreToolUse (Edit) | Enforces Serena LSP over raw Edit |
|
|
246
225
|
| `skill-suggestion.py` | UserPromptSubmit | Suggests relevant skill if detected |
|
|
247
|
-
| `tdd-guard` hooks | PreToolUse (Edit/Write) | Blocks implementation without failing test |
|
|
248
226
|
| `quality-gates` hooks | PostToolUse (Edit/Write) | Runs lint + type checks automatically |
|
|
249
227
|
|
|
250
228
|
---
|
|
@@ -255,7 +233,7 @@ These hooks run automatically — you cannot disable them mid-session:
|
|
|
255
233
|
|---|---|---|
|
|
256
234
|
| `serena` | Semantic code reading/editing | Auto-detected; activate project per session |
|
|
257
235
|
| `gitnexus` | Knowledge graph, impact analysis | `npm install -g gitnexus` + `npx gitnexus analyze` per project |
|
|
258
|
-
| `context7` | Library documentation lookup |
|
|
236
|
+
| `context7` | Library documentation lookup | No setup needed (free stdio transport) |
|
|
259
237
|
| `deepwiki` | Technical docs for GitHub repos | No setup needed |
|
|
260
238
|
| `github-grep` | Code search across GitHub | No setup needed |
|
|
261
239
|
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { readFileSync } = require('node:fs');
|
|
3
|
-
const { spawnSync } = require('node:child_process');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
|
|
6
|
-
const CODE_EXTENSIONS = new Set([
|
|
7
|
-
'.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
|
|
8
|
-
'.py', '.php', '.go', '.rs', '.java', '.kt', '.kts',
|
|
9
|
-
'.c', '.cc', '.cpp', '.cxx', '.h', '.hh', '.hpp',
|
|
10
|
-
'.cs', '.rb', '.swift', '.scala', '.lua', '.sh', '.zsh', '.bash',
|
|
11
|
-
]);
|
|
12
|
-
|
|
13
|
-
const SERENA_EDIT_TOOLS = new Set([
|
|
14
|
-
'mcp__serena__rename_symbol',
|
|
15
|
-
'mcp__serena__replace_symbol_body',
|
|
16
|
-
'mcp__serena__insert_after_symbol',
|
|
17
|
-
'mcp__serena__insert_before_symbol',
|
|
18
|
-
]);
|
|
19
|
-
|
|
20
|
-
function isEditLikeTool(toolName) {
|
|
21
|
-
if (!toolName) return false;
|
|
22
|
-
if (toolName === 'Edit' || toolName === 'Write' || toolName === 'MultiEdit' || toolName === 'TodoWrite') {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
return SERENA_EDIT_TOOLS.has(toolName);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function pickFilePath(toolInput) {
|
|
29
|
-
if (!toolInput || typeof toolInput !== 'object') return null;
|
|
30
|
-
|
|
31
|
-
const direct = toolInput.file_path || toolInput.filePath || toolInput.path ||
|
|
32
|
-
toolInput.relative_path || toolInput.relativePath;
|
|
33
|
-
if (typeof direct === 'string' && direct.trim()) return direct;
|
|
34
|
-
|
|
35
|
-
if (Array.isArray(toolInput.edits)) {
|
|
36
|
-
for (const edit of toolInput.edits) {
|
|
37
|
-
const p = edit?.file_path || edit?.filePath || edit?.path || edit?.relative_path || edit?.relativePath;
|
|
38
|
-
if (typeof p === 'string' && p.trim()) return p;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function isCodeFile(filePath) {
|
|
46
|
-
if (!filePath) return true; // fail-open when no path is available
|
|
47
|
-
return CODE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let payloadText = '';
|
|
51
|
-
try {
|
|
52
|
-
payloadText = readFileSync(0, 'utf8');
|
|
53
|
-
} catch {
|
|
54
|
-
process.exit(0);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let payload;
|
|
58
|
-
try {
|
|
59
|
-
payload = JSON.parse(payloadText);
|
|
60
|
-
} catch {
|
|
61
|
-
process.exit(0);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const toolName = payload.tool_name || '';
|
|
65
|
-
if (!isEditLikeTool(toolName)) {
|
|
66
|
-
process.exit(0);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const filePath = pickFilePath(payload.tool_input);
|
|
70
|
-
if (!isCodeFile(filePath)) {
|
|
71
|
-
process.exit(0);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const hookEnv = { ...process.env, VALIDATION_CLIENT: 'sdk' };
|
|
75
|
-
delete hookEnv.MODEL_TYPE;
|
|
76
|
-
delete hookEnv.TDD_GUARD_ANTHROPIC_API_KEY;
|
|
77
|
-
delete hookEnv.ANTHROPIC_API_KEY;
|
|
78
|
-
delete hookEnv.ANTHROPIC_BASE_URL;
|
|
79
|
-
|
|
80
|
-
const result = spawnSync('tdd-guard', {
|
|
81
|
-
input: payloadText,
|
|
82
|
-
encoding: 'utf8',
|
|
83
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
84
|
-
env: hookEnv,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
if (result.stdout) process.stdout.write(result.stdout);
|
|
88
|
-
|
|
89
|
-
if (result.error) {
|
|
90
|
-
process.exit(0);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const combinedOutput = `${result.stdout || ''}\n${result.stderr || ''}`;
|
|
94
|
-
if (
|
|
95
|
-
combinedOutput.includes('Error during validation:') &&
|
|
96
|
-
combinedOutput.includes('API Error:') &&
|
|
97
|
-
combinedOutput.includes('not valid JSON')
|
|
98
|
-
) {
|
|
99
|
-
// Validation backend/parsing failure: do not hard-block edits.
|
|
100
|
-
process.exit(0);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
process.exit(result.status ?? 0);
|