specfact-cli 0.27.0__tar.gz → 0.30.1__tar.gz
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.
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/.gitignore +4 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/PKG-INFO +51 -4
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/README.md +50 -3
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/pyproject.toml +6 -3
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/__init__.py +1 -1
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/ado.py +10 -2
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/graph_analyzer.py +6 -6
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/cli.py +50 -1
- specfact_cli-0.30.1/src/specfact_cli/commands/analyze.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/auth.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/backlog_commands.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/contract_cmd.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/drift.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/enforce.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/generate.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/import_cmd.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/init.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/migrate.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/plan.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/project_cmd.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/repro.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/sdd.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/spec.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/sync.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/update.py +6 -0
- specfact_cli-0.30.1/src/specfact_cli/commands/validate.py +6 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/common/logger_setup.py +9 -2
- specfact_cli-0.30.1/src/specfact_cli/contracts/__init__.py +29 -0
- specfact_cli-0.30.1/src/specfact_cli/contracts/module_interface.py +30 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/persona_exporter.py +1 -1
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/importers/speckit_converter.py +14 -5
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/merge/resolver.py +1 -1
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/bridge.py +8 -16
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/change.py +13 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/dor_config.py +2 -6
- specfact_cli-0.30.1/src/specfact_cli/models/module_package.py +73 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/plan.py +26 -2
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/project.py +33 -4
- specfact_cli-0.30.1/src/specfact_cli/models/validation.py +31 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/analyze/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/analyze/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/analyze/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/analyze.py → specfact_cli-0.30.1/src/specfact_cli/modules/analyze/src/commands.py +7 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/auth/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/auth/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/auth/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/auth.py → specfact_cli-0.30.1/src/specfact_cli/modules/auth/src/commands.py +19 -1
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/module-package.yaml +24 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/adapters/__init__.py +9 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/adapters/ado.py +20 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/adapters/base.py +93 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/adapters/github.py +20 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/adapters/jira.py +20 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/adapters/linear.py +20 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/backlog_commands.py → specfact_cli-0.30.1/src/specfact_cli/modules/backlog/src/commands.py +70 -2
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/contract/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/contract/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/contract/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/contract_cmd.py → specfact_cli-0.30.1/src/specfact_cli/modules/contract/src/commands.py +13 -3
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/drift/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/drift/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/drift/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/drift.py → specfact_cli-0.30.1/src/specfact_cli/modules/drift/src/commands.py +7 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/enforce/module-package.yaml +3 -1
- specfact_cli-0.30.1/src/specfact_cli/modules/enforce/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/enforce/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/enforce.py → specfact_cli-0.30.1/src/specfact_cli/modules/enforce/src/commands.py +71 -3
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/generate/module-package.yaml +3 -1
- specfact_cli-0.30.1/src/specfact_cli/modules/generate/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/generate/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/generate.py → specfact_cli-0.30.1/src/specfact_cli/modules/generate/src/commands.py +69 -2
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/import_cmd/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/import_cmd/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/import_cmd/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/import_cmd.py → specfact_cli-0.30.1/src/specfact_cli/modules/import_cmd/src/commands.py +19 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/init/module-package.yaml +2 -1
- specfact_cli-0.30.1/src/specfact_cli/modules/init/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/init/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/init.py → specfact_cli-0.30.1/src/specfact_cli/modules/init/src/commands.py +457 -28
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/migrate/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/migrate/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/migrate/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/migrate.py → specfact_cli-0.30.1/src/specfact_cli/modules/migrate/src/commands.py +5 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/module_io_shim.py +77 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/plan/module-package.yaml +3 -1
- specfact_cli-0.30.1/src/specfact_cli/modules/plan/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/plan/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/plan.py → specfact_cli-0.30.1/src/specfact_cli/modules/plan/src/commands.py +99 -64
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/project/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/project/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/project/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/project_cmd.py → specfact_cli-0.30.1/src/specfact_cli/modules/project/src/commands.py +49 -15
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/repro/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/repro/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/repro/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/repro.py → specfact_cli-0.30.1/src/specfact_cli/modules/repro/src/commands.py +25 -3
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/sdd/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/sdd/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/sdd/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/sdd.py → specfact_cli-0.30.1/src/specfact_cli/modules/sdd/src/commands.py +10 -26
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/spec/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/spec/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/spec/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/spec.py → specfact_cli-0.30.1/src/specfact_cli/modules/spec/src/commands.py +5 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/sync/module-package.yaml +4 -1
- specfact_cli-0.30.1/src/specfact_cli/modules/sync/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/sync/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/sync.py → specfact_cli-0.30.1/src/specfact_cli/modules/sync/src/commands.py +161 -18
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/upgrade/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/upgrade/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/upgrade/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/update.py → specfact_cli-0.30.1/src/specfact_cli/modules/upgrade/src/commands.py +9 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/validate/module-package.yaml +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/validate/src/__init__.py +1 -0
- specfact_cli-0.30.1/src/specfact_cli/modules/validate/src/app.py +6 -0
- specfact_cli-0.27.0/src/specfact_cli/commands/validate.py → specfact_cli-0.30.1/src/specfact_cli/modules/validate/src/commands.py +7 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/parsers/persona_importer.py +28 -15
- specfact_cli-0.30.1/src/specfact_cli/registry/bridge_registry.py +75 -0
- specfact_cli-0.30.1/src/specfact_cli/registry/module_packages.py +697 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/registry/module_state.py +32 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/registry/registry.py +17 -3
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/runtime.py +42 -28
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/bridge_probe.py +28 -13
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/telemetry.py +74 -6
- specfact_cli-0.30.1/src/specfact_cli/utils/bundle_converters.py +67 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/git.py +3 -3
- specfact_cli-0.30.1/src/specfact_cli/utils/persona_ownership.py +34 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/source_scanner.py +14 -11
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/repro_checker.py +83 -9
- specfact_cli-0.27.0/src/specfact_cli/contracts/__init__.py +0 -3
- specfact_cli-0.27.0/src/specfact_cli/modules/analyze/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/auth/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/backlog/module-package.yaml +0 -10
- specfact_cli-0.27.0/src/specfact_cli/modules/backlog/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/contract/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/drift/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/enforce/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/generate/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/import_cmd/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/init/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/migrate/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/plan/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/project/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/repro/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/sdd/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/spec/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/sync/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/upgrade/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/modules/validate/src/app.py +0 -6
- specfact_cli-0.27.0/src/specfact_cli/registry/module_packages.py +0 -232
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/LICENSE.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/shared/cli-enforcement.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.01-import.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.02-plan.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.03-review.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.04-sdd.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.05-enforce.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.06-sync.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.07-contracts.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.backlog-daily.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.backlog-refine.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.compare.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.sync-backlog.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/prompts/specfact.validate.md +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/defaults/defect_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/defaults/enabler_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/defaults/spike_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/defaults/user_story_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/field_mappings/ado_agile.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/field_mappings/ado_default.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/field_mappings/ado_kanban.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/field_mappings/ado_safe.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/field_mappings/ado_scrum.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/frameworks/safe/safe_feature_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/frameworks/scrum/user_story_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/personas/developer/developer_task_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/personas/product-owner/user_story_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/backlog/providers/ado/work_item_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/persona/architect.md.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/persona/developer.md.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/persona/product-owner.md.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/__main__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/backlog_base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/github.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/openspec.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/openspec_parser.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/registry.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/adapters/speckit.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/adapters/base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/ai_refiner.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/converter.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/filters.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/format_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/formats/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/formats/base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/formats/markdown_format.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/formats/structured_format.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/mappers/base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/backlog/template_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/contracts/crosshair_props.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/contract_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/openapi_extractor.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/task_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/test_to_openapi.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/integrations/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/integrations/specmatic.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/merge/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/backlog_item.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/capabilities.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/contract.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/deviation.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/persona_template.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/quality.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/sdd.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/source_tracking.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/models/task.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/modules/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/parsers/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/registry/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/registry/bootstrap.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/registry/help_cache.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/registry/metadata.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/bridge_sync.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/bridge_watch.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/change_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/code_to_spec.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/drift_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/spec_to_code.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/spec_to_tests.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/bridge_templates.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/registry.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/templates/specification_templates.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/auth_tokens.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/bundle_loader.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/code_change_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/content_sanitizer.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/context_detection.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/enrichment_context.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/env_manager.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/ide_setup.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/incremental_check.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/metadata.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/optional_deps.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/performance.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/progress.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/sdd_discovery.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/startup_checks.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/structure.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/structured_io.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/suggestions.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/terminal.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/agile_validation.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/cli_first_validator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/contract_validator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/schema.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/models.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/versioning/__init__.py +0 -0
- {specfact_cli-0.27.0 → specfact_cli-0.30.1}/src/specfact_cli/versioning/analyzer.py +0 -0
|
@@ -107,6 +107,10 @@ docs/internal/
|
|
|
107
107
|
.github/prompts/specfact.*.md
|
|
108
108
|
.github/prompts/opsx-*.md
|
|
109
109
|
|
|
110
|
+
.claude/commands/opsx/
|
|
111
|
+
.claude/skills/openspec-*/
|
|
112
|
+
!.claude/skills/openspec-workflows/
|
|
113
|
+
|
|
110
114
|
# Semgrep rules (generated from tools/semgrep/ - source rules are versioned)
|
|
111
115
|
.semgrep/
|
|
112
116
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specfact-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.1
|
|
4
4
|
Summary: The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases.
|
|
5
5
|
Project-URL: Homepage, https://github.com/nold-ai/specfact-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/nold-ai/specfact-cli.git
|
|
@@ -309,12 +309,16 @@ uvx specfact-cli@latest
|
|
|
309
309
|
pip install -U specfact-cli
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
-
###
|
|
312
|
+
### Bootstrap and IDE Setup
|
|
313
313
|
|
|
314
314
|
```bash
|
|
315
|
+
# Bootstrap module registry and local config (~/.specfact)
|
|
315
316
|
specfact init
|
|
316
|
-
|
|
317
|
-
|
|
317
|
+
|
|
318
|
+
# Configure IDE prompts/templates (interactive selector by default)
|
|
319
|
+
specfact init ide
|
|
320
|
+
specfact init ide --ide cursor
|
|
321
|
+
specfact init ide --ide vscode
|
|
318
322
|
```
|
|
319
323
|
|
|
320
324
|
### Run Your First Flow
|
|
@@ -412,6 +416,49 @@ Most tools help **either** coders **or** agile teams. SpecFact does both:
|
|
|
412
416
|
- **Backlogs**: GitHub Issues, Azure DevOps, Jira, Linear
|
|
413
417
|
- **Contracts**: Specmatic, OpenAPI
|
|
414
418
|
|
|
419
|
+
### Module Lifecycle Baseline
|
|
420
|
+
|
|
421
|
+
SpecFact now has a lifecycle-managed module system:
|
|
422
|
+
|
|
423
|
+
- `specfact init` is bootstrap-first: initializes local CLI state, discovers installed modules, and reports prompt status.
|
|
424
|
+
- `specfact init ide` handles IDE prompt/template sync and IDE settings updates.
|
|
425
|
+
- `specfact init --list-modules` shows effective enabled/disabled state.
|
|
426
|
+
- `specfact init --enable-module` / `--disable-module` support:
|
|
427
|
+
- interactive selection in interactive terminals when no module id is provided
|
|
428
|
+
- explicit ids in non-interactive mode (for automation)
|
|
429
|
+
- dependency-aware safety checks with `--force` cascading enable/disable behavior
|
|
430
|
+
- Module manifests support dependency and core-version compatibility enforcement at registration time.
|
|
431
|
+
|
|
432
|
+
This lifecycle model is the baseline for future granular module updates and enhancements. Module installation from third-party or open-source community providers is planned, but not implemented yet.
|
|
433
|
+
|
|
434
|
+
Contract-first module architecture highlights:
|
|
435
|
+
|
|
436
|
+
- `ModuleIOContract` formalizes module IO operations (`import`, `export`, `sync`, `validate`) on `ProjectBundle`.
|
|
437
|
+
- Core-module isolation is enforced by static analysis (`core` never imports `specfact_cli.modules.*` directly).
|
|
438
|
+
- Registration tracks protocol operation coverage and schema compatibility metadata.
|
|
439
|
+
- Bridge registry support allows module manifests to declare `service_bridges` converters (for example ADO/Jira/Linear/GitHub) loaded at lifecycle startup without direct core-to-module imports.
|
|
440
|
+
- Protocol reporting classifies modules from effective runtime interfaces with a single aggregate summary (`Full/Partial/Legacy`).
|
|
441
|
+
|
|
442
|
+
Why this matters:
|
|
443
|
+
|
|
444
|
+
- Feature areas can evolve independently without repeatedly modifying core CLI wiring.
|
|
445
|
+
- Module teams can ship at different speeds while preserving stable core behavior.
|
|
446
|
+
- Clear IO contracts reduce coupling and make future migrations (e.g., new adapters/modules) lower risk.
|
|
447
|
+
- Core remains focused on lifecycle, registry, and validation orchestration rather than tool-specific command logic.
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
## Developer Note: Command Layout
|
|
452
|
+
|
|
453
|
+
- Primary command implementations live in `src/specfact_cli/modules/<module>/src/commands.py`.
|
|
454
|
+
- Legacy imports from `src/specfact_cli/commands/*.py` are compatibility shims and only guarantee `app` re-exports.
|
|
455
|
+
- Preferred imports for module code:
|
|
456
|
+
- `from specfact_cli.modules.<module>.src.commands import app`
|
|
457
|
+
- `from specfact_cli.modules.<module>.src.commands import <symbol>`
|
|
458
|
+
- Shim deprecation timeline:
|
|
459
|
+
- Legacy shim usage is deprecated for non-`app` symbols now.
|
|
460
|
+
- Shim removal is planned no earlier than `v0.30` (or the next major migration window).
|
|
461
|
+
|
|
415
462
|
---
|
|
416
463
|
|
|
417
464
|
## Where SpecFact Fits
|
|
@@ -31,12 +31,16 @@ uvx specfact-cli@latest
|
|
|
31
31
|
pip install -U specfact-cli
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
###
|
|
34
|
+
### Bootstrap and IDE Setup
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
+
# Bootstrap module registry and local config (~/.specfact)
|
|
37
38
|
specfact init
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
# Configure IDE prompts/templates (interactive selector by default)
|
|
41
|
+
specfact init ide
|
|
42
|
+
specfact init ide --ide cursor
|
|
43
|
+
specfact init ide --ide vscode
|
|
40
44
|
```
|
|
41
45
|
|
|
42
46
|
### Run Your First Flow
|
|
@@ -134,6 +138,49 @@ Most tools help **either** coders **or** agile teams. SpecFact does both:
|
|
|
134
138
|
- **Backlogs**: GitHub Issues, Azure DevOps, Jira, Linear
|
|
135
139
|
- **Contracts**: Specmatic, OpenAPI
|
|
136
140
|
|
|
141
|
+
### Module Lifecycle Baseline
|
|
142
|
+
|
|
143
|
+
SpecFact now has a lifecycle-managed module system:
|
|
144
|
+
|
|
145
|
+
- `specfact init` is bootstrap-first: initializes local CLI state, discovers installed modules, and reports prompt status.
|
|
146
|
+
- `specfact init ide` handles IDE prompt/template sync and IDE settings updates.
|
|
147
|
+
- `specfact init --list-modules` shows effective enabled/disabled state.
|
|
148
|
+
- `specfact init --enable-module` / `--disable-module` support:
|
|
149
|
+
- interactive selection in interactive terminals when no module id is provided
|
|
150
|
+
- explicit ids in non-interactive mode (for automation)
|
|
151
|
+
- dependency-aware safety checks with `--force` cascading enable/disable behavior
|
|
152
|
+
- Module manifests support dependency and core-version compatibility enforcement at registration time.
|
|
153
|
+
|
|
154
|
+
This lifecycle model is the baseline for future granular module updates and enhancements. Module installation from third-party or open-source community providers is planned, but not implemented yet.
|
|
155
|
+
|
|
156
|
+
Contract-first module architecture highlights:
|
|
157
|
+
|
|
158
|
+
- `ModuleIOContract` formalizes module IO operations (`import`, `export`, `sync`, `validate`) on `ProjectBundle`.
|
|
159
|
+
- Core-module isolation is enforced by static analysis (`core` never imports `specfact_cli.modules.*` directly).
|
|
160
|
+
- Registration tracks protocol operation coverage and schema compatibility metadata.
|
|
161
|
+
- Bridge registry support allows module manifests to declare `service_bridges` converters (for example ADO/Jira/Linear/GitHub) loaded at lifecycle startup without direct core-to-module imports.
|
|
162
|
+
- Protocol reporting classifies modules from effective runtime interfaces with a single aggregate summary (`Full/Partial/Legacy`).
|
|
163
|
+
|
|
164
|
+
Why this matters:
|
|
165
|
+
|
|
166
|
+
- Feature areas can evolve independently without repeatedly modifying core CLI wiring.
|
|
167
|
+
- Module teams can ship at different speeds while preserving stable core behavior.
|
|
168
|
+
- Clear IO contracts reduce coupling and make future migrations (e.g., new adapters/modules) lower risk.
|
|
169
|
+
- Core remains focused on lifecycle, registry, and validation orchestration rather than tool-specific command logic.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Developer Note: Command Layout
|
|
174
|
+
|
|
175
|
+
- Primary command implementations live in `src/specfact_cli/modules/<module>/src/commands.py`.
|
|
176
|
+
- Legacy imports from `src/specfact_cli/commands/*.py` are compatibility shims and only guarantee `app` re-exports.
|
|
177
|
+
- Preferred imports for module code:
|
|
178
|
+
- `from specfact_cli.modules.<module>.src.commands import app`
|
|
179
|
+
- `from specfact_cli.modules.<module>.src.commands import <symbol>`
|
|
180
|
+
- Shim deprecation timeline:
|
|
181
|
+
- Legacy shim usage is deprecated for non-`app` symbols now.
|
|
182
|
+
- Shim removal is planned no earlier than `v0.30` (or the next major migration window).
|
|
183
|
+
|
|
137
184
|
---
|
|
138
185
|
|
|
139
186
|
## Where SpecFact Fits
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specfact-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.30.1"
|
|
8
8
|
description = "The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -193,8 +193,8 @@ validate-prompts = "python tools/validate_prompts.py"
|
|
|
193
193
|
# Development scripts
|
|
194
194
|
test = "pytest {args}"
|
|
195
195
|
test-cov = "pytest --cov=src --cov-report=term-missing {args}"
|
|
196
|
-
type-check = "basedpyright {args}"
|
|
197
|
-
lint = "ruff format . --check && basedpyright && ruff check . && pylint src tests tools"
|
|
196
|
+
type-check = "basedpyright --pythonpath $(python -c 'import sys; print(sys.executable)') {args}"
|
|
197
|
+
lint = "ruff format . --check && basedpyright --pythonpath $(python -c 'import sys; print(sys.executable)') && ruff check . && pylint src tests tools"
|
|
198
198
|
governance = "pylint src tests tools --reports=y --output-format=parseable"
|
|
199
199
|
format = "ruff check . --fix && ruff format ."
|
|
200
200
|
|
|
@@ -705,6 +705,9 @@ ignore = [
|
|
|
705
705
|
"src/specfact_cli/commands/**/*" = [
|
|
706
706
|
"B008", # typer.Option/Argument in defaults (common Typer pattern)
|
|
707
707
|
]
|
|
708
|
+
"src/specfact_cli/modules/**/src/commands.py" = [
|
|
709
|
+
"B008", # typer.Option/Argument in defaults (common Typer pattern)
|
|
710
|
+
]
|
|
708
711
|
|
|
709
712
|
[tool.ruff.lint.isort]
|
|
710
713
|
# Match isort ruff profile configuration
|
|
@@ -14,7 +14,7 @@ import os
|
|
|
14
14
|
import re
|
|
15
15
|
from datetime import UTC, datetime
|
|
16
16
|
from pathlib import Path
|
|
17
|
-
from typing import Any
|
|
17
|
+
from typing import Any, cast
|
|
18
18
|
from urllib.parse import urlparse
|
|
19
19
|
|
|
20
20
|
import requests
|
|
@@ -549,7 +549,15 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
|
|
|
549
549
|
assigned_to = fields.get("System.AssignedTo")
|
|
550
550
|
if assigned_to:
|
|
551
551
|
if isinstance(assigned_to, dict):
|
|
552
|
-
|
|
552
|
+
assignee_dict = cast(dict[str, Any], assigned_to)
|
|
553
|
+
display_name = assignee_dict.get("displayName")
|
|
554
|
+
unique_name = assignee_dict.get("uniqueName")
|
|
555
|
+
if isinstance(display_name, str) and display_name.strip():
|
|
556
|
+
assignee_name = display_name.strip()
|
|
557
|
+
elif isinstance(unique_name, str):
|
|
558
|
+
assignee_name = unique_name
|
|
559
|
+
else:
|
|
560
|
+
assignee_name = ""
|
|
553
561
|
else:
|
|
554
562
|
assignee_name = str(assigned_to)
|
|
555
563
|
if assignee_name and not owner:
|
|
@@ -370,11 +370,11 @@ class GraphAnalyzer:
|
|
|
370
370
|
|
|
371
371
|
Tries multiple strategies:
|
|
372
372
|
1. Exact match
|
|
373
|
-
2. Last part match (e.g., "import_cmd" matches "src.specfact_cli.
|
|
374
|
-
3. Partial path match (e.g., "specfact_cli.commands" matches "src.specfact_cli.
|
|
373
|
+
2. Last part match (e.g., "import_cmd" matches "src.specfact_cli.modules.import_cmd.src.commands")
|
|
374
|
+
3. Partial path match (e.g., "specfact_cli.commands" matches "src.specfact_cli.modules.import_cmd.src.commands")
|
|
375
375
|
|
|
376
376
|
Args:
|
|
377
|
-
imported: Imported module name (e.g., "specfact_cli.
|
|
377
|
+
imported: Imported module name (e.g., "specfact_cli.modules.import_cmd.src.commands")
|
|
378
378
|
known_modules: List of known module names in the graph
|
|
379
379
|
|
|
380
380
|
Returns:
|
|
@@ -385,14 +385,14 @@ class GraphAnalyzer:
|
|
|
385
385
|
return imported
|
|
386
386
|
|
|
387
387
|
# Strategy 2: Last part match
|
|
388
|
-
# e.g., "import_cmd" matches "src.specfact_cli.
|
|
388
|
+
# e.g., "import_cmd" matches "src.specfact_cli.modules.import_cmd.src.commands"
|
|
389
389
|
imported_last = imported.split(".")[-1]
|
|
390
390
|
for module in known_modules:
|
|
391
391
|
if module.endswith(f".{imported_last}") or module == imported_last:
|
|
392
392
|
return module
|
|
393
393
|
|
|
394
394
|
# Strategy 3: Partial path match
|
|
395
|
-
# e.g., "specfact_cli.commands" matches "src.specfact_cli.
|
|
395
|
+
# e.g., "specfact_cli.commands" matches "src.specfact_cli.modules.import_cmd.src.commands"
|
|
396
396
|
for module in known_modules:
|
|
397
397
|
# Check if imported is a prefix of module
|
|
398
398
|
if module.startswith(imported + ".") or module == imported:
|
|
@@ -406,7 +406,7 @@ class GraphAnalyzer:
|
|
|
406
406
|
for module in known_modules:
|
|
407
407
|
module_parts = module.split(".")
|
|
408
408
|
# Check if there's overlap in the path
|
|
409
|
-
# e.g., "commands.import_cmd" might match "src.specfact_cli.
|
|
409
|
+
# e.g., "commands.import_cmd" might match "src.specfact_cli.modules.import_cmd.src.commands"
|
|
410
410
|
if len(imported_parts) >= 2 and len(module_parts) >= 2 and imported_parts[-2:] == module_parts[-2:]:
|
|
411
411
|
return module
|
|
412
412
|
|
|
@@ -257,7 +257,7 @@ def main(
|
|
|
257
257
|
bool | None,
|
|
258
258
|
typer.Option(
|
|
259
259
|
"--interactive/--no-interactive",
|
|
260
|
-
help="Force interaction mode (default auto based on CI
|
|
260
|
+
help="Force interaction mode (default auto based on terminal/CI detection)",
|
|
261
261
|
),
|
|
262
262
|
] = None,
|
|
263
263
|
) -> None:
|
|
@@ -274,6 +274,10 @@ def main(
|
|
|
274
274
|
- Explicit --mode flag (highest priority)
|
|
275
275
|
- Auto-detect from environment (CoPilot API, IDE integration)
|
|
276
276
|
- Default to CI/CD mode
|
|
277
|
+
|
|
278
|
+
Interaction Detection:
|
|
279
|
+
- Explicit --interactive/--no-interactive (highest priority)
|
|
280
|
+
- Auto-detect from terminal and CI environment
|
|
277
281
|
"""
|
|
278
282
|
global _show_banner
|
|
279
283
|
# Set banner flag based on --banner option
|
|
@@ -332,6 +336,33 @@ class _LazyDelegateGroup(click.Group):
|
|
|
332
336
|
def _make_delegate_command(self) -> click.Command:
|
|
333
337
|
cmd_name = self._lazy_cmd_name
|
|
334
338
|
|
|
339
|
+
def _normalize_init_optional_module_flags(argv: list[str]) -> list[str]:
|
|
340
|
+
"""
|
|
341
|
+
Normalize bare init module flags to sentinel values.
|
|
342
|
+
|
|
343
|
+
Typer/Click options declared with value types require an argument. To support
|
|
344
|
+
UX like `specfact init --enable-module` in interactive mode, rewrite bare flags
|
|
345
|
+
to include a sentinel token consumed by init command logic.
|
|
346
|
+
"""
|
|
347
|
+
if cmd_name != "init":
|
|
348
|
+
return argv
|
|
349
|
+
out: list[str] = []
|
|
350
|
+
i = 0
|
|
351
|
+
while i < len(argv):
|
|
352
|
+
token = argv[i]
|
|
353
|
+
if token in ("--enable-module", "--disable-module"):
|
|
354
|
+
out.append(token)
|
|
355
|
+
if i + 1 < len(argv) and not argv[i + 1].startswith("-"):
|
|
356
|
+
out.append(argv[i + 1])
|
|
357
|
+
i += 2
|
|
358
|
+
continue
|
|
359
|
+
out.append("__interactive_select__")
|
|
360
|
+
i += 1
|
|
361
|
+
continue
|
|
362
|
+
out.append(token)
|
|
363
|
+
i += 1
|
|
364
|
+
return out
|
|
365
|
+
|
|
335
366
|
def _invoke(args: tuple[str, ...]) -> None:
|
|
336
367
|
from typer.main import get_command
|
|
337
368
|
|
|
@@ -348,6 +379,7 @@ class _LazyDelegateGroup(click.Group):
|
|
|
348
379
|
p = getattr(p, "parent", None)
|
|
349
380
|
prog_name = " ".join(reversed(parts)) if parts else cmd_name
|
|
350
381
|
args_list = list(args)
|
|
382
|
+
args_list = _normalize_init_optional_module_flags(args_list)
|
|
351
383
|
# When the real app is a single command (e.g. drift has only "detect"), Typer
|
|
352
384
|
# builds a TyperCommand, not a Group. Then args are ["detect", "bundle", "--repo", ...]
|
|
353
385
|
# and the command expects ["bundle", "--repo", ...] (no leading "detect").
|
|
@@ -503,6 +535,23 @@ def cli_main() -> None:
|
|
|
503
535
|
# Normalize shell names in argv for Typer's built-in completion commands
|
|
504
536
|
normalize_shell_in_argv()
|
|
505
537
|
|
|
538
|
+
# Initialize debug mode early so --debug works even for eager flags like --help/--version.
|
|
539
|
+
debug_requested = "--debug" in sys.argv[1:]
|
|
540
|
+
if debug_requested:
|
|
541
|
+
set_debug_mode(True)
|
|
542
|
+
init_debug_log_file()
|
|
543
|
+
debug_log_path = runtime.get_debug_log_path()
|
|
544
|
+
if debug_log_path:
|
|
545
|
+
sys.stderr.write(f"[debug] log file: {debug_log_path}\n")
|
|
546
|
+
else:
|
|
547
|
+
sys.stderr.write("[debug] log file unavailable (no writable debug log path)\n")
|
|
548
|
+
runtime.debug_log_operation(
|
|
549
|
+
"cli_start",
|
|
550
|
+
"specfact",
|
|
551
|
+
"started",
|
|
552
|
+
extra={"argv": sys.argv[1:], "pid": os.getpid()},
|
|
553
|
+
)
|
|
554
|
+
|
|
506
555
|
# Check if --banner flag is present (before Typer processes it)
|
|
507
556
|
banner_requested = "--banner" in sys.argv
|
|
508
557
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Logging utility for standardized log setup across all modules
|
|
3
|
+
|
|
4
|
+
CrossHair: skip (logging internals and logger object realization are not symbolic-safe)
|
|
3
5
|
"""
|
|
4
6
|
|
|
5
7
|
import atexit
|
|
@@ -526,8 +528,13 @@ class LoggerSetup:
|
|
|
526
528
|
queue_handler = QueueHandler(log_queue)
|
|
527
529
|
logger.addHandler(queue_handler)
|
|
528
530
|
|
|
529
|
-
# Add a console handler
|
|
530
|
-
|
|
531
|
+
# Add a direct console handler only when no queue listener is active for this logger.
|
|
532
|
+
# Otherwise logs are already streamed by the QueueListener handler and would be duplicated.
|
|
533
|
+
if (
|
|
534
|
+
"pytest" not in sys.modules
|
|
535
|
+
and logger_name not in cls._log_listeners
|
|
536
|
+
and not any(isinstance(h, logging.StreamHandler) for h in logger.handlers)
|
|
537
|
+
):
|
|
531
538
|
console_handler = logging.StreamHandler(_safe_console_stream())
|
|
532
539
|
console_handler.setFormatter(log_format)
|
|
533
540
|
console_handler.setLevel(level)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Contract exports for protocol and validation integrations.
|
|
2
|
+
|
|
3
|
+
Keep this package import side-effect free so CrossHair can import
|
|
4
|
+
``specfact_cli.contracts.crosshair_props`` without loading heavy model/utils
|
|
5
|
+
packages that trigger subprocess-based initializers.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from importlib import import_module
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from specfact_cli.models.validation import ValidationReport
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["ValidationReport", "crosshair_props"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def __getattr__(name: str) -> Any:
|
|
22
|
+
"""Lazily resolve exported symbols to avoid import-time side effects."""
|
|
23
|
+
if name == "ValidationReport":
|
|
24
|
+
from specfact_cli.models.validation import ValidationReport as _ValidationReport
|
|
25
|
+
|
|
26
|
+
return _ValidationReport
|
|
27
|
+
if name == "crosshair_props":
|
|
28
|
+
return import_module(".crosshair_props", __name__)
|
|
29
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Module IO protocol contract for module bundle interactions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import abstractmethod
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Protocol
|
|
8
|
+
|
|
9
|
+
from specfact_cli.models.project import ProjectBundle
|
|
10
|
+
from specfact_cli.models.validation import ValidationReport
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ModuleIOContract(Protocol):
|
|
14
|
+
"""Protocol for module implementations that exchange data via ProjectBundle."""
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def import_to_bundle(self, source: Path, config: dict[str, Any]) -> ProjectBundle:
|
|
18
|
+
"""Import an external artifact and convert it into a ProjectBundle."""
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def export_from_bundle(self, bundle: ProjectBundle, target: Path, config: dict[str, Any]) -> None:
|
|
22
|
+
"""Export a ProjectBundle to an external artifact format."""
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def sync_with_bundle(self, bundle: ProjectBundle, external_source: str, config: dict[str, Any]) -> ProjectBundle:
|
|
26
|
+
"""Synchronize a bundle with an external source and return the updated bundle."""
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def validate_bundle(self, bundle: ProjectBundle, rules: dict[str, Any]) -> ValidationReport:
|
|
30
|
+
"""Run module-specific validation on a ProjectBundle."""
|
|
@@ -108,7 +108,7 @@ class PersonaExporter:
|
|
|
108
108
|
Returns:
|
|
109
109
|
Template context dictionary
|
|
110
110
|
"""
|
|
111
|
-
from specfact_cli.
|
|
111
|
+
from specfact_cli.utils.persona_ownership import match_section_pattern
|
|
112
112
|
|
|
113
113
|
context: dict[str, Any] = {
|
|
114
114
|
"bundle_name": bundle.bundle_name,
|