campfire-cli 0.1.12__tar.gz → 0.1.13__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.
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/.github/workflows/ci.yml +6 -9
- campfire_cli-0.1.13/.github/workflows/release.yml +39 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/ARCHITECTURE.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/COMMAND.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/PKG-INFO +3 -1
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/README.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/SPEC.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/pyproject.toml +1 -1
- campfire_cli-0.1.13/scripts/quality_check.py +108 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/__init__.py +1 -1
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/SPEC.md +1 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_apply_service.py +9 -6
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_rule_service.py +5 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/SPEC.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/service/maintenance_service.py +10 -2
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/service/moc_service.py +30 -1
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/agent_hints.py +7 -1
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/defaults/config.yml +6 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-document-capture/SKILL.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-document-capture/references//345/267/262/346/234/211/346/226/207/346/241/243/346/233/264/346/226/260.md +1 -1
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-workspace-maintenance/SKILL.md +3 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/SPEC.md +2 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/conftest.py +2 -1
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_document_apply.py +46 -0
- campfire_cli-0.1.13/tests/unit/test_generated_regions.py +96 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/uv.lock +1 -1
- campfire_cli-0.1.12/.github/workflows/release.yml +0 -19
- campfire_cli-0.1.12/tests/unit/test_generated_regions.py +0 -36
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/.gitignore +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/AGENTS.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/DECISIONS.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/LICENSE +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/alembic/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/alembic/env.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/alembic/script.py.mako +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/alembic/versions/001_initial_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/alembic.ini +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/scripts/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/env.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/script.py.mako +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/001_initial_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/002_workspace_project_registry.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/003_unified_workspace_state.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/004_restructure_workspace_domain.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/005_decision_channel.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/006_workspace_topology_index.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/007_workspace_adoption.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/008_remove_adoption_batches.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/009_document_query_index.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/010_project_domain_identity.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/alembic/versions/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/cli/base_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/repository/base_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/schema/base_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/schema/operation_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/base/service/base_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/cli/decision_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/repository/decision_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/schema/decision_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/service/decision_projection_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/decision/service/decision_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/cli/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/cli/document_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/cli/profile_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/cli/type_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/repository/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/repository/document_index_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/repository/document_profile_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/repository/document_type_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/schema/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/schema/document_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_index_builder.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_index_protocol.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_index_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_move_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_patch_values.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_profile_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_relocation.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_scanner.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/document_type_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/frontmatter_apply.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/frontmatter_formatter.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/frontmatter_plan.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/kanban_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/profile_registry.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/type_apply.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/document/service/type_plan.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/cli/maintenance_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/repository/maintenance_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/schema/maintenance_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/service/archive_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/service/link_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/service/maintenance_protocol.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/skill/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/skill/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/skill/cli/skill_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/skill/repository/skill_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/skill/schema/skill_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/skill/service/skill_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/config_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/domain_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/project_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/restructure_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/space_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/cli/workspace_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/repository/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/repository/manifest_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/repository/restructure_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/repository/workspace_repository.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/schema/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/schema/adoption_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/schema/restructure_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/schema/workspace_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/adoption_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/config_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/domain_restructure_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/project_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/restructure_protocol.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/restructure_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/restructure_verifier.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/structure_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/workspace_protocol.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/workspace/service/workspace_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/database/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/database/migrations.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/database/models.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/database/session.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/document_types.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/domain_context.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/frontmatter_format.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/frontmatter_schema.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/links.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/documents/markdown.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/exceptions/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/exceptions/base.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/filesystem/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/filesystem/atomic.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/filesystem/change_set.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/filesystem/cwd.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/filesystem/locking.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/governance/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/governance/issues.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/governance/locking.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/governance/snapshots.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/hashing.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/package_version.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/reports/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/reports/json_report.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/common/reports/markdown_report.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/config/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/config/defaults.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/config/settings.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/container.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/main.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/bases/Agent/346/211/247/350/241/214/345/267/245/344/275/234/345/217/260.base" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/bases/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/bases//344/273/273/345/212/241/345/267/245/344/275/234/345/217/260.base" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/bases//345/206/263/347/255/226/345/267/245/344/275/234/345/217/260.base" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/bases//345/276/205/345/275/222/346/241/243/346/226/207/346/241/243.base" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/bases//351/241/271/347/233/256/346/226/207/346/241/243.base" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/defaults/__init__.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/SPEC.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-context-bootstrap/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-context-bootstrap/agents/openai.yaml +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-conversation-router/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-conversation-router/agents/openai.yaml +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-conversation-router/references/inbox-handoff.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-conversation-router/references/learning-intake.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-conversation-router/references/task-intake.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-document-capture/references//344/273/273/345/212/241/344/270/216/350/256/241/345/210/222/346/262/211/346/267/200.md" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-document-capture/references//351/200/232/347/224/250/347/237/245/350/257/206/346/262/211/346/267/200.md" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-document-capture/references//351/227/256/351/242/230/344/270/216/345/206/263/347/255/226/346/262/211/346/267/200.md" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-document-capture/references//351/241/271/347/233/256/345/206/205/345/256/271/346/262/211/346/267/200.md" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-inbox-triage/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-kanban-board/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-task-management/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-weekly-report-writing/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-weekly-report-writing/agents/openai.yaml +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-workspace-adoption/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-workspace-maintenance/references//344/273/273/345/212/241/346/255/243/346/226/207/347/273/223/346/236/204.md" +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-workspace-restructure/SKILL.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/resources/skills/campfire-workspace-restructure/references/restructure-spec.md +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/integration/test_cli.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/perf/test_read_counts.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/perf/test_resolve_subprocess_count.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_agent_hints.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_atomic_write.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_common_governance.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_config.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_document_index.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_domain_context.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_file_change_executor.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_frontmatter.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_kanban_service.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_migrations.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_package_version.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_repository_boundaries.py +0 -0
- {campfire_cli-0.1.12 → campfire_cli-0.1.13}/tests/unit/test_workspace_manifest.py +0 -0
|
@@ -7,11 +7,10 @@ on:
|
|
|
7
7
|
|
|
8
8
|
jobs:
|
|
9
9
|
test:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
runs-on: ${{ matrix.os }}
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ci-${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
runs-on: ubuntu-latest
|
|
15
14
|
env:
|
|
16
15
|
PYTHONUTF8: "1"
|
|
17
16
|
steps:
|
|
@@ -22,7 +21,5 @@ jobs:
|
|
|
22
21
|
cache-dependency-glob: "uv.lock"
|
|
23
22
|
- name: Install dependencies
|
|
24
23
|
run: uv sync --frozen
|
|
25
|
-
- name:
|
|
26
|
-
run: uv run
|
|
27
|
-
- name: Test
|
|
28
|
-
run: uv run pytest -q
|
|
24
|
+
- name: Quality check
|
|
25
|
+
run: uv run python scripts/quality_check.py
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
quality:
|
|
9
|
+
strategy:
|
|
10
|
+
fail-fast: false
|
|
11
|
+
matrix:
|
|
12
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
13
|
+
runs-on: ${{ matrix.os }}
|
|
14
|
+
env:
|
|
15
|
+
PYTHONUTF8: "1"
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v5
|
|
18
|
+
- uses: astral-sh/setup-uv@v10.1.0
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
cache-dependency-glob: "uv.lock"
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv sync --frozen
|
|
24
|
+
- name: Release quality check
|
|
25
|
+
run: uv run python scripts/quality_check.py --release
|
|
26
|
+
|
|
27
|
+
publish:
|
|
28
|
+
needs: quality
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
permissions:
|
|
31
|
+
id-token: write
|
|
32
|
+
contents: read
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v5
|
|
35
|
+
- uses: astral-sh/setup-uv@v10.1.0
|
|
36
|
+
- name: Build
|
|
37
|
+
run: uv build
|
|
38
|
+
- name: Publish to PyPI
|
|
39
|
+
run: uv publish
|
|
@@ -82,6 +82,8 @@ Document App 同时拥有设备本地的文档查询投影。Indexer 从 Markdow
|
|
|
82
82
|
|
|
83
83
|
Frontmatter 规则采用声明式 Profile:`base` 是最小公共契约,`knowledge`、`project-doc`、`task` 只允许一层继承。Profile Loader 将配置编译为完整 EffectiveProfile,Resolver 根据文档类型和领域上下文选择 Profile,Validator 与 Formatter 共同消费该结果。字段规则不使用每种文档一个 Python 子类,也不在 Skill 中复制。
|
|
84
84
|
|
|
85
|
+
`template` 直接使用 base Profile,物理存放在 Domain 的 `_模板/`。模板作用域由 Domain 拓扑和路径确定;Skill 从目标 Domain 向祖先查找同名模板并使用最近的一份,系统不建立模板注册表或继承状态。
|
|
86
|
+
|
|
85
87
|
### CLI 设计理念:治理原语 + Skill SOP
|
|
86
88
|
|
|
87
89
|
Campfire 不是“Markdown 版 kubectl”,而是面向人机协作场景组合成熟 CLI 经验形成的独立设计。它在资源心智模型、`apply` 语义和机器可读接口上借鉴 kubectl,在“计划—审查—执行”上借鉴 Terraform,在稳定原语与上层工作流分离上借鉴 Git/Unix;Markdown SSOT、Agent 语义判断和显式 Maintenance 则是 Campfire 自身边界。
|
|
@@ -51,6 +51,8 @@ Space、Domain、Project 的 `create`/`adopt`,以及文档移动、重构、
|
|
|
51
51
|
|
|
52
52
|
`document apply` 可新建、更新、为已有正文补齐 Frontmatter,或通过显式 `--type` 原子转换文档类型。创建或唯一更新时可省略 `.md`;创建和类型转换时还可省略类型前缀。CLI 在 `normalization` 中返回每项标准化,并在 `target` 中返回最终路径;调用方不手工同步类型、前缀与 Markdown 后缀。`document move` 可在任意已声明 Domain 之间移动单篇文档并对齐可确定的 `domain`/`project`。目标 Profile 缺少语义字段时返回 `missing_fields`,调用方补齐明确业务值。只有实际写入成功的结果才可返回零或一个、且可直接执行的 scoped `maintenance sync` follow-up;Domain 内部路径会归一化为对应 Domain,预览、阻塞或无派生影响时返回空列表。具体参数以对应命令的 `-h` 为准。
|
|
53
53
|
|
|
54
|
+
`template` 使用 base Profile,必须位于 Domain 的 `_模板/`。模板查找与应用由 Skill 按最近 Domain 规则完成,不新增模板专用命令。
|
|
55
|
+
|
|
54
56
|
`--set` 的值类型由有效 Profile 决定,不使用 YAML 隐式类型推断。enum、string 和 date 保留原始字符串,boolean 只接受 `true` 或 `false`,list 只接受严格 JSON 数组。标量可写为 `--set lifecycle=completed`,列表在 Shell 中使用单引号保护,例如 `--set 'tags=["tag1","tag2"]'`。CLI 不把 `tag1,tag2` 猜成列表;格式错误时通过稳定错误码、期望类型和参数示例说明修复方式。字段与枚举不在本命令清单重复登记。
|
|
55
57
|
|
|
56
58
|
`document list` 是 SQLite 查询投影上的精确集合枚举,多个筛选条件使用 AND 语义,`--type task` 不隐式排除任何 lifecycle。`document inspect` 在原有 Profile 和问题上下文之外返回 declared、outgoing、incoming 与 unresolved 确定关系。两条读取命令查询前自动 reconcile;Agent 取得路径后用文件工具读取正文,不需要先跑 Maintenance。未来正文关键词、模糊匹配和相关性排序使用独立 `document search`,不改变 list/inspect 的确定语义。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: campfire-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.13
|
|
4
4
|
Summary: Local-first shared context and governance CLI for humans and agents
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -102,6 +102,8 @@ campfire document type list # 文档类型与前缀
|
|
|
102
102
|
campfire decision create / list / answer / close # 持久决策通道
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
Domain 可在 `_模板/` 中维护基础属性的 `template` 文档。Agent 创建结构化文档时按当前 Domain 到祖先 Domain 的顺序使用最近同名模板;模板只提供正文骨架,不替代目标文档 Profile。
|
|
106
|
+
|
|
105
107
|
结构治理命令默认只输出计划,追加 `--confirm` 才执行:
|
|
106
108
|
|
|
107
109
|
```bash
|
|
@@ -86,6 +86,8 @@ campfire document type list # 文档类型与前缀
|
|
|
86
86
|
campfire decision create / list / answer / close # 持久决策通道
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
Domain 可在 `_模板/` 中维护基础属性的 `template` 文档。Agent 创建结构化文档时按当前 Domain 到祖先 Domain 的顺序使用最近同名模板;模板只提供正文骨架,不替代目标文档 Profile。
|
|
90
|
+
|
|
89
91
|
结构治理命令默认只输出计划,追加 `--confirm` 才执行:
|
|
90
92
|
|
|
91
93
|
```bash
|
|
@@ -34,6 +34,7 @@ SQLite / Filesystem Implementation
|
|
|
34
34
|
- 命令不得读取“最近一次操作”等隐式 Session 状态推导对象或作用域;跨命令后续动作只使用当前结果显式返回的结构化 `follow_up`。
|
|
35
35
|
- 所有写入默认预检,语义计划默认未审批。
|
|
36
36
|
- 写入用例必须在治理锁内复核生成计划时的内容哈希,发现外部变化时拒绝覆盖。
|
|
37
|
+
- Domain 在 `_模板/` 中持有基础 Profile 的 `template` 文档;同名模板仅按目标 Domain 到祖先 Domain 的最近路径选择,不保存继承状态或合并模板。
|
|
37
38
|
|
|
38
39
|
代码风格参考 `templates/fastapi-template`,但不引入 HTTP、WebSocket、认证和异步数据库等无关能力。
|
|
39
40
|
|
|
@@ -84,6 +85,7 @@ Campfire 使用语义化版本:
|
|
|
84
85
|
- 删除或重命名公共命令、改变不可兼容的数据格式时增加主版本;`0.x` 阶段仍应显式记录破坏性变化。
|
|
85
86
|
- 配置文件的 `version` 独立于 Python 包版本;只有配置结构或解释语义变化时递增。
|
|
86
87
|
- PyPI、源码标签、构建产物和 CLI 报告的版本必须一致。
|
|
88
|
+
- 发布标签必须先通过三平台测试、构建与 wheel 隔离安装;Release workflow 不得在质量门禁失败时发布。
|
|
87
89
|
|
|
88
90
|
## 设备边界
|
|
89
91
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SPEC:
|
|
3
|
+
name: quality_check
|
|
4
|
+
purpose: 运行本地与 CI 共用的快速或发布质量门禁
|
|
5
|
+
idempotent: true
|
|
6
|
+
side_effects:
|
|
7
|
+
- 发布门禁在临时目录构建并安装包
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import subprocess
|
|
16
|
+
import tempfile
|
|
17
|
+
import tomllib
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def run(*command: str) -> None:
|
|
24
|
+
subprocess.run(command, cwd=ROOT, check=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def project_version() -> str:
|
|
28
|
+
with (ROOT / "pyproject.toml").open("rb") as handle:
|
|
29
|
+
return str(tomllib.load(handle)["project"]["version"])
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def check_tag(version: str) -> None:
|
|
33
|
+
tag = os.environ.get("GITHUB_REF_NAME")
|
|
34
|
+
if tag and tag.startswith("v") and tag != f"v{version}":
|
|
35
|
+
raise SystemExit(f"tag {tag} does not match project version {version}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def smoke_test_wheel(version: str) -> None:
|
|
39
|
+
with tempfile.TemporaryDirectory(prefix="campfire-quality-") as raw_directory:
|
|
40
|
+
directory = Path(raw_directory)
|
|
41
|
+
dist = directory / "dist"
|
|
42
|
+
environment = directory / "venv"
|
|
43
|
+
workspace = directory / "workspace"
|
|
44
|
+
run("uv", "build", "--out-dir", str(dist))
|
|
45
|
+
wheels = list(dist.glob("*.whl"))
|
|
46
|
+
source_distributions = list(dist.glob("*.tar.gz"))
|
|
47
|
+
if len(wheels) != 1 or len(source_distributions) != 1:
|
|
48
|
+
raise SystemExit("build must produce exactly one wheel and one source distribution")
|
|
49
|
+
wheel = wheels[0]
|
|
50
|
+
run("uv", "venv", str(environment))
|
|
51
|
+
executable_dir = "Scripts" if os.name == "nt" else "bin"
|
|
52
|
+
python = environment / executable_dir / ("python.exe" if os.name == "nt" else "python")
|
|
53
|
+
campfire = environment / executable_dir / (
|
|
54
|
+
"campfire.exe" if os.name == "nt" else "campfire"
|
|
55
|
+
)
|
|
56
|
+
run("uv", "pip", "install", "--python", str(python), str(wheel))
|
|
57
|
+
smoke_environment = os.environ.copy()
|
|
58
|
+
smoke_environment.update(
|
|
59
|
+
{
|
|
60
|
+
"CAMPFIRE_HOME": str(directory / "campfire-home"),
|
|
61
|
+
"CAMPFIRE_AGENT_HINT_PATH": str(directory / "agent-hints"),
|
|
62
|
+
"CAMPFIRE_SKILL_TARGETS": str(directory / "agent-skills"),
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
installed = subprocess.run(
|
|
66
|
+
[str(campfire), "version"],
|
|
67
|
+
cwd=ROOT,
|
|
68
|
+
check=True,
|
|
69
|
+
capture_output=True,
|
|
70
|
+
text=True,
|
|
71
|
+
env=smoke_environment,
|
|
72
|
+
).stdout.strip()
|
|
73
|
+
if installed != version:
|
|
74
|
+
raise SystemExit(f"installed version {installed} does not match {version}")
|
|
75
|
+
workspace.mkdir()
|
|
76
|
+
subprocess.run(
|
|
77
|
+
[str(campfire), "setup", "--path", str(workspace), "--id", "smoke"],
|
|
78
|
+
cwd=ROOT,
|
|
79
|
+
check=True,
|
|
80
|
+
capture_output=True,
|
|
81
|
+
text=True,
|
|
82
|
+
env=smoke_environment,
|
|
83
|
+
)
|
|
84
|
+
output = subprocess.run(
|
|
85
|
+
[str(campfire), "--workspace", "smoke", "document", "type", "list"],
|
|
86
|
+
cwd=ROOT,
|
|
87
|
+
check=True,
|
|
88
|
+
capture_output=True,
|
|
89
|
+
text=True,
|
|
90
|
+
env=smoke_environment,
|
|
91
|
+
).stdout
|
|
92
|
+
json.loads(output)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def main() -> None:
|
|
96
|
+
parser = argparse.ArgumentParser()
|
|
97
|
+
parser.add_argument("--release", action="store_true")
|
|
98
|
+
arguments = parser.parse_args()
|
|
99
|
+
run("uv", "run", "ruff", "check", "src", "tests", "scripts")
|
|
100
|
+
run("uv", "run", "pytest", "-q")
|
|
101
|
+
if arguments.release:
|
|
102
|
+
version = project_version()
|
|
103
|
+
check_tag(version)
|
|
104
|
+
smoke_test_wheel(version)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if __name__ == "__main__":
|
|
108
|
+
main()
|
|
@@ -45,6 +45,7 @@ document/
|
|
|
45
45
|
- `list`:按 Project、Domain、类型和生命周期对索引做精确 AND 筛选;返回全部生命周期,不读取或复制正文。
|
|
46
46
|
- `inspect`:向 Agent 返回单篇文档的 Domain、类型、有效 Profile、具体问题,以及 declared、outgoing、incoming、unresolved 四类确定关系。
|
|
47
47
|
- `apply`:根据目标路径和类型解析 Profile,不存在时生成文档,已有 Frontmatter 时只应用显式补丁,无 Frontmatter 时保留正文并补齐完整契约;先完整渲染并校验,追加 `--confirm` 后原子写入。
|
|
48
|
+
- `template`:只继承 base Profile,必须位于所属 Domain 的 `_模板/`;Domain 归属由物理路径解析,不在 Frontmatter 复制模板作用域或继承关系。
|
|
48
49
|
- `move`:在任意已声明 Domain 之间移动或改名一篇文档,按目标 Profile 对齐可确定的 `domain`/`project` 归属,并更新可确定解析的 Wiki、Markdown 和路径引用。目标 Profile 缺少业务字段时返回 `needs-input`,不猜测。
|
|
49
50
|
- `scanner`:统一解释受管根、忽略目录和豁免文件;Document 与 Maintenance 共用。
|
|
50
51
|
|
|
@@ -99,9 +99,16 @@ class DocumentApplyService:
|
|
|
99
99
|
|
|
100
100
|
today = date.today().isoformat()
|
|
101
101
|
frontmatter = dict(parsed.frontmatter)
|
|
102
|
+
profile = None
|
|
102
103
|
if not exists or not parsed.has_frontmatter:
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
defaults = self._creation_defaults(target, document_type, today)
|
|
105
|
+
profile = self._profiles.resolve(document_type, defaults, target)
|
|
106
|
+
if "domain" in profile.allowed:
|
|
107
|
+
defaults["domain"] = context.domain_id
|
|
108
|
+
if context.project_id and "project" in profile.allowed:
|
|
109
|
+
defaults["project"] = context.project_id
|
|
110
|
+
frontmatter.update(defaults)
|
|
111
|
+
profile = profile or self._profiles.resolve(document_type, frontmatter, target)
|
|
105
112
|
actual_hash = file_sha256(source) if exists else "missing"
|
|
106
113
|
unknown = sorted(set(request.values) - set(profile.allowed))
|
|
107
114
|
if unknown:
|
|
@@ -226,7 +233,6 @@ class DocumentApplyService:
|
|
|
226
233
|
def _creation_defaults(
|
|
227
234
|
self,
|
|
228
235
|
path: Path,
|
|
229
|
-
context: DomainContext,
|
|
230
236
|
document_type: str,
|
|
231
237
|
today: str,
|
|
232
238
|
) -> dict[str, Any]:
|
|
@@ -239,9 +245,6 @@ class DocumentApplyService:
|
|
|
239
245
|
"updated": today,
|
|
240
246
|
"tags": [],
|
|
241
247
|
}
|
|
242
|
-
values["domain"] = context.domain_id
|
|
243
|
-
if context.project_id:
|
|
244
|
-
values["project"] = context.project_id
|
|
245
248
|
return values
|
|
246
249
|
|
|
247
250
|
@staticmethod
|
|
@@ -349,6 +349,11 @@ class DocumentRuleService:
|
|
|
349
349
|
issues: list[dict[str, Any]] = []
|
|
350
350
|
status = frontmatter.get("status")
|
|
351
351
|
lifecycle = frontmatter.get("lifecycle")
|
|
352
|
+
in_template_directory = "_模板" in path.parts
|
|
353
|
+
if document_type == "template" and path.parent.name != "_模板":
|
|
354
|
+
issues.append({"code": "template-directory-required", "path": relative})
|
|
355
|
+
elif in_template_directory and document_type != "template":
|
|
356
|
+
issues.append({"code": "template-directory-type-mismatch", "path": relative})
|
|
352
357
|
in_archive = "archive" in path.parts
|
|
353
358
|
if in_archive != (status == "archived" and lifecycle == "archived") and (
|
|
354
359
|
in_archive or status == "archived" or lifecycle == "archived"
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
文档扫描、类型、Profile、任务状态、模板枚举、Frontmatter 顺序、跨字段不变量与确定关系索引均委托 Document App;本模块只负责检查编排、过滤、可见派生内容和报告。全量 check 或 scoped sync 通过消费方维护端口触发 Document Index 校正,不依赖具体 Document Service,也不得实现第二套索引规则。写入通过共享 ChangeSet Executor 复核内容哈希并原子提交。
|
|
6
6
|
|
|
7
|
+
Domain MOC 只列出该 Domain `_模板/` 中实际存在的模板;Maintenance 不计算或持久化模板继承结果,Agent 按 Domain 祖先路径就近选择。
|
|
8
|
+
|
|
7
9
|
受管范围由当前 Workspace 中实际存在的 `_空间.md` 动态发现,不使用固定 Space 白名单;`scope_roots` 只补充收件箱等非 Space 系统范围。声明文件由 Workspace App 校验,不计入普通文档问题。
|
|
8
10
|
|
|
9
11
|
`check --scope` 的 status 表示当前筛选结果,`workspace_status` 表示全 Workspace 状态。`sync --scope` 只发现并扫描 scope 内的 Domain 和文档,一次刷新 MOC、关系页并触发文档索引 reconcile;只受当前范围的结构问题阻塞。`document list/inspect` 不以 Maintenance 为前置步骤。单篇内容创建、补全和修改属于 Document App,批量迁移属于 Workspace Restructure。
|
|
@@ -212,6 +212,9 @@ class MaintenanceService:
|
|
|
212
212
|
notes_by_domain = {
|
|
213
213
|
domain.id: governance_sync.direct_notes(domain, marker_name) for domain in domains
|
|
214
214
|
}
|
|
215
|
+
templates_by_domain = {
|
|
216
|
+
domain.id: governance_sync.direct_templates(domain) for domain in domains
|
|
217
|
+
}
|
|
215
218
|
project_domain_ids = {
|
|
216
219
|
domain.id for domain in domains if domain.governance == "project-docs"
|
|
217
220
|
}
|
|
@@ -239,7 +242,12 @@ class MaintenanceService:
|
|
|
239
242
|
note_count += len(notes)
|
|
240
243
|
if domain.governance == "project-docs":
|
|
241
244
|
generated = governance_sync.generate_project_domain_content(
|
|
242
|
-
domain,
|
|
245
|
+
domain,
|
|
246
|
+
domains,
|
|
247
|
+
notes,
|
|
248
|
+
templates_by_domain[domain.id],
|
|
249
|
+
marker_name,
|
|
250
|
+
type_mapping,
|
|
243
251
|
)
|
|
244
252
|
else:
|
|
245
253
|
relation_page = None
|
|
@@ -256,7 +264,7 @@ class MaintenanceService:
|
|
|
256
264
|
if existing != relation_content:
|
|
257
265
|
changes.append((relation_page, relation_content))
|
|
258
266
|
generated = governance_sync.generate_domain_content(
|
|
259
|
-
domain, domains, notes, relation_page
|
|
267
|
+
domain, domains, notes, templates_by_domain[domain.id], relation_page
|
|
260
268
|
)
|
|
261
269
|
moc = domain.path / f"{domain.moc}.md"
|
|
262
270
|
if not moc.is_file():
|
{campfire_cli-0.1.12 → campfire_cli-0.1.13}/src/campfire_cli/app/maintenance/service/moc_service.py
RENAMED
|
@@ -18,6 +18,7 @@ SPEC:
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
+
import os
|
|
21
22
|
import re
|
|
22
23
|
from collections import Counter
|
|
23
24
|
from pathlib import Path
|
|
@@ -126,6 +127,26 @@ def direct_notes(domain: Domain, marker_name: str) -> list[Path]:
|
|
|
126
127
|
)
|
|
127
128
|
|
|
128
129
|
|
|
130
|
+
def direct_templates(domain: Domain) -> list[Path]:
|
|
131
|
+
"""Return templates physically owned by this Domain."""
|
|
132
|
+
directory = domain.path / "_模板"
|
|
133
|
+
if not directory.is_dir():
|
|
134
|
+
return []
|
|
135
|
+
return sorted(directory.glob("模板-*.md"), key=lambda path: path.name.casefold())
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def template_link(domain: Domain, template: Path) -> str:
|
|
139
|
+
moc_directory = (domain.path / f"{domain.moc}.md").parent
|
|
140
|
+
return Path(os.path.relpath(template.with_suffix(""), moc_directory)).as_posix()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def append_template_section(lines: list[str], domain: Domain, templates: list[Path]) -> None:
|
|
144
|
+
if not templates:
|
|
145
|
+
return
|
|
146
|
+
lines.extend(["", "## 文档模板", ""])
|
|
147
|
+
lines.extend(f"- [[{template_link(domain, item)}|{item.stem}]]" for item in templates)
|
|
148
|
+
|
|
149
|
+
|
|
129
150
|
def generate_relations(
|
|
130
151
|
notes: list[Path],
|
|
131
152
|
domain_by_note: dict[Path, str],
|
|
@@ -232,7 +253,11 @@ def write_if_changed(
|
|
|
232
253
|
|
|
233
254
|
|
|
234
255
|
def generate_domain_content(
|
|
235
|
-
domain: Domain,
|
|
256
|
+
domain: Domain,
|
|
257
|
+
domains: list[Domain],
|
|
258
|
+
notes: list[Path],
|
|
259
|
+
templates: list[Path],
|
|
260
|
+
relation_page: Path | None,
|
|
236
261
|
) -> str:
|
|
237
262
|
children = sorted(
|
|
238
263
|
[item for item in domains if item.parent_domain == domain.id],
|
|
@@ -245,6 +270,7 @@ def generate_domain_content(
|
|
|
245
270
|
lines.extend([f"- [[{child.moc}|{child.name}]]" for child in children] or ["- 暂无"])
|
|
246
271
|
lines.extend(["", "## 本领域文档", ""])
|
|
247
272
|
lines.extend([f"- [[{note.stem}]]" for note in notes] or ["- 暂无"])
|
|
273
|
+
append_template_section(lines, domain, templates)
|
|
248
274
|
lines.extend(["", "## 自动关系", ""])
|
|
249
275
|
lines.append(f"- [[{relation_page.stem}|相关文档计算结果]]" if relation_page else "- 暂无")
|
|
250
276
|
return "\n".join(lines)
|
|
@@ -254,6 +280,7 @@ def generate_project_domain_content(
|
|
|
254
280
|
domain: Domain,
|
|
255
281
|
domains: list[Domain],
|
|
256
282
|
notes: list[Path],
|
|
283
|
+
templates: list[Path],
|
|
257
284
|
marker_name: str,
|
|
258
285
|
project_doc_types: dict[str, dict[str, str]] | None = None,
|
|
259
286
|
) -> str:
|
|
@@ -316,6 +343,8 @@ def generate_project_domain_content(
|
|
|
316
343
|
rel = archived_note.relative_to(domain.path).with_suffix("")
|
|
317
344
|
lines.append(f"- [[{rel}|{archived_note.stem}]]:`{reason}`{suffix}")
|
|
318
345
|
lines.append("")
|
|
346
|
+
append_template_section(lines, domain, templates)
|
|
347
|
+
lines.append("")
|
|
319
348
|
return "\n".join(lines).rstrip()
|
|
320
349
|
|
|
321
350
|
|
|
@@ -14,7 +14,8 @@ HINT_BODY = """## Campfire 文档治理
|
|
|
14
14
|
当用户要求"沉淀/记录/写文档/归档/跟踪问题"到知识库或项目文档时:
|
|
15
15
|
|
|
16
16
|
1. 用户已给出唯一存在路径,且只读取或小范围修改人工正文时,
|
|
17
|
-
|
|
17
|
+
先读取文档开头和最近 `_领域.md` 的人工规则,再直接使用文件工具;
|
|
18
|
+
不加载 bootstrap,不调用 Campfire CLI。
|
|
18
19
|
2. 新建、Frontmatter、文件名、归属、移动、归档、派生维护或结构治理
|
|
19
20
|
需要 Workspace、Project、Domain 或 Profile 上下文;当前 Session
|
|
20
21
|
首次进入这类治理流程时加载 `campfire-context-bootstrap`。
|
|
@@ -33,10 +34,15 @@ HINT_BODY = """## Campfire 文档治理
|
|
|
33
34
|
7. `--set` 的值类型由有效 Profile 决定;列表使用严格 JSON 数组。
|
|
34
35
|
CLI 返回 `needs-input` 或输入错误时按结构化允许值和参数示例重试,
|
|
35
36
|
不为通过检查而猜测。
|
|
37
|
+
8. 创建结构化文档时,从目标 Domain 开始向父 Domain 查找
|
|
38
|
+
`_模板/模板-<用途>.md`,使用找到的第一份;不合并模板,不修改模板源文档。
|
|
39
|
+
模板不存在时使用对应 Skill 的最小结构,不自行发明复杂格式。
|
|
36
40
|
|
|
37
41
|
`.campfire.yaml`、声明 Frontmatter、自动生成区域、Base、关系页和 SQLite
|
|
38
42
|
是 CLI 管理资源。Agent 可以读取,但只能通过 Campfire 语义命令写入;缺少
|
|
39
43
|
对应命令时停止并报告能力缺口,不直接编辑。声明文件标记外正文不受此限制。
|
|
44
|
+
`_空间.md` 与 `_领域.md` 的人工正文维护局部业务规则;通用结构事实和索引
|
|
45
|
+
由 CLI 生成,不手工重复维护。
|
|
40
46
|
|
|
41
47
|
不要直接在代码仓库里创建笔记文件。Agent Hint 只规定入口纪律;
|
|
42
48
|
字段、枚举和顺序以 Campfire Profile 为唯一事实来源。
|
|
@@ -26,6 +26,7 @@ workspace:
|
|
|
26
26
|
- archive
|
|
27
27
|
- generated
|
|
28
28
|
- _总览
|
|
29
|
+
- _模板
|
|
29
30
|
- 记录
|
|
30
31
|
- 任务
|
|
31
32
|
- a_skill
|
|
@@ -48,6 +49,7 @@ governance:
|
|
|
48
49
|
- 记录
|
|
49
50
|
- archive
|
|
50
51
|
- _总览
|
|
52
|
+
- _模板
|
|
51
53
|
- a_skill
|
|
52
54
|
document_types:
|
|
53
55
|
version: 2
|
|
@@ -105,6 +107,9 @@ document_types:
|
|
|
105
107
|
board:
|
|
106
108
|
prefix: 看板-
|
|
107
109
|
label: 看板
|
|
110
|
+
template:
|
|
111
|
+
prefix: 模板-
|
|
112
|
+
label: 模板
|
|
108
113
|
requirement-doc:
|
|
109
114
|
prefix: 需求-
|
|
110
115
|
label: 需求
|
|
@@ -133,6 +138,7 @@ frontmatter_schema:
|
|
|
133
138
|
profile_by_type:
|
|
134
139
|
knowledge: knowledge
|
|
135
140
|
task: task
|
|
141
|
+
template: base
|
|
136
142
|
profile_by_governance:
|
|
137
143
|
project-docs: project-doc
|
|
138
144
|
profiles:
|
|
@@ -107,6 +107,8 @@ campfire --workspace personal maintenance sync --scope "mywork/【某项目】
|
|
|
107
107
|
|
|
108
108
|
预检通过后,知识、项目事实、方案、决策、问题、记录和任务统一交给 `campfire-workspace-maintenance` 选择 Space、Domain 与文档类型。创建文档、补齐无 Frontmatter 的既有正文、修改 Frontmatter 或显式变更类型,统一调用一次 `campfire document apply`;它会解析目标 Domain、继承 Project、从 type 推导文件名,并在完整 Profile 校验通过后原子写入。Frontmatter 契约已知时直接 apply;现有文档的字段类型或合法值未知时只执行一次 `document inspect` 后 apply,不从 `tree` 开始逐层探索。Agent 不手工同步 type 与文件名前缀。
|
|
109
109
|
|
|
110
|
+
创建结构化文档时,根据用户意图确定简短模板名,从目标 Domain 开始沿父 Domain 查找 `_模板/模板-<名称>.md`,使用第一份匹配模板。模板只提供正文骨架:目标 Frontmatter 仍由实际文档类型的 Profile 生成;删除不适用章节,不虚构内容,不修改模板源文件。同级存在歧义时询问用户,找不到时使用当前垂直 Skill 的最小结构。模板只能在用户明确要求或确认后创建、修改、移动或删除。
|
|
111
|
+
|
|
110
112
|
单篇文档在已声明 Domain 之间改名或移动使用一次 `document move`;Domain 合并或逻辑空删除加载 `campfire-workspace-restructure` 并使用 `domain merge/delete`,批量文档迁移或领域拆分才使用持久 restructure 批次。CLI 写入完成后只执行结果中实际返回的 `follow_up`,当前只可能是一个最小 scope 的 `maintenance sync`;没有 follow-up 就结束,不自行追加 dry-run、check 或全 Workspace 扫描。本 Skill 不复制文档 Profile、生命周期、字段枚举或结构重构步骤。
|
|
111
113
|
|
|
112
114
|
## Pending Decision
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
1. 确认候选文档是当前主题的权威对象;需要关系上下文时运行 `document inspect --path <path>`。
|
|
4
4
|
2. 保持原 Project 和 Domain,除非用户明确要求重新归属。
|
|
5
|
-
3.
|
|
5
|
+
3. 只改人工正文时先读取文档开头和最近 `_领域.md` 的人工维护规则,再做最小 Edit 并读取修改区域验证。
|
|
6
6
|
4. 修改 Frontmatter、类型或文件名时使用 `document apply`;移动时使用 `document move`。
|
|
7
7
|
5. 不修改 `AUTO-GENERATED` 标记内内容,只执行写命令实际返回的 follow-up。
|
|
@@ -34,6 +34,8 @@ campfire workspace rebuild --confirm
|
|
|
34
34
|
6. `maintenance sync --scope <path>` 只扫描 scope 内的 Domain 和文档,一次刷新 MOC、关系页并校正本机索引;不要随后无条件重复 sync 或扩大到整个 Workspace。
|
|
35
35
|
7. 报告原始笔记变化、自动生成物和仍需用户确认的事项。无法从正文、领域上下文或项目事实唯一决定时,调用 `campfire decision create`;获得回答后调用 `decision answer`,答案被原任务消费后调用 `decision close`。
|
|
36
36
|
|
|
37
|
+
Domain 可在 `_模板/` 中持有 `template` 类型文档。创建结构化文档时从目标 Domain 向父 Domain 查找同名模板并使用最近的一份;不合并模板,也不持久化继承结果。模板只使用 base Profile,创建和 Frontmatter 更新仍走 `document apply`。Maintenance 只在 Domain MOC 中列出当前 Domain 实际持有的模板。
|
|
38
|
+
|
|
37
39
|
## 路由
|
|
38
40
|
|
|
39
41
|
```text
|
|
@@ -76,6 +78,7 @@ Agent 负责理解正文、项目事实和业务语义;CLI 负责 Profile 校
|
|
|
76
78
|
- 整个 Workspace 只有一个根 `_收件箱/`;语义无法唯一判断时进入待用户确认,不为追求检查通过而猜测。
|
|
77
79
|
- `_空间.md` 声明 Space,`_领域.md` 声明可多级嵌套的 Domain;保留目录不是 Space 或 Domain。
|
|
78
80
|
- `.campfire.yaml`、声明 Frontmatter、`AUTO-GENERATED` 标记区域、Base、关系页和 SQLite 可读但不可由 Agent 直接写入;必须使用对应 Campfire 语义命令。`_空间.md` 和 `_领域.md` 标记外的 Markdown 正文可由人或 Agent 自由编辑。
|
|
81
|
+
- `_空间.md` 与 `_领域.md` 标记外正文维护当前作用域的特殊规则;可从结构和索引确定的通用事实由 CLI 生成,不在正文重复维护。
|
|
79
82
|
- 自动生成内容必须位于成对、唯一且闭合的 `AUTO-GENERATED` 标记内;CLI 只替换标记内部,标记异常时停止,不猜测边界。
|
|
80
83
|
- Project 单向绑定稳定根 Domain id;Domain 移动不改变绑定,子 Domain 通过祖先拓扑继承 Project。
|
|
81
84
|
- 一篇文档只有一个主物理 Domain,可以出现在多个自动索引中。
|
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
- Service 单元测试使用内存 Fake Protocol,不访问真实 Vault。
|
|
4
4
|
- Repository 与 CLI 集成测试使用临时 Vault 和临时 SQLite。
|
|
5
5
|
- 性能回归测试放 `tests/perf`,标记 `@pytest.mark.perf`;只断言确定性计数,如文件读取次数、子进程派生次数、`sys.modules` 成员,不断言墙钟时间。
|
|
6
|
+
- 所有测试默认隔离 Campfire 用户状态,不读取真实 `~/.campfire`、Workspace 注册、Skill 或 Agent Hint。
|
|
7
|
+
- CLI 测试验证参数和结构化契约;不把 ANSI、Rich 边框、终端换行或完整中文句子当作稳定 API。
|
|
6
8
|
- 所有写入路径必须覆盖预检失败、幂等、哈希变化和中途异常场景。
|
|
@@ -10,7 +10,8 @@ from campfire_cli.app.workspace.schema.workspace_schema import WorkspaceEntry, W
|
|
|
10
10
|
|
|
11
11
|
@pytest.fixture(autouse=True)
|
|
12
12
|
def _isolate_agent_hints(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
13
|
-
"""
|
|
13
|
+
"""Keep every user-scoped Campfire resource inside the test directory."""
|
|
14
|
+
monkeypatch.setenv("CAMPFIRE_HOME", str(tmp_path / "campfire-home"))
|
|
14
15
|
monkeypatch.setenv("CAMPFIRE_AGENT_HINT_PATH", str(tmp_path / "agent-hints"))
|
|
15
16
|
monkeypatch.setenv("CAMPFIRE_SKILL_TARGETS", str(tmp_path / "agent-skills"))
|
|
16
17
|
|
|
@@ -87,6 +87,52 @@ def test_apply_derives_create_filename_from_type(workspace: Path) -> None:
|
|
|
87
87
|
assert [item.scope for item in result.follow_up] == ["mywork/【Example】文档中心"]
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def test_apply_creates_base_profile_template_in_domain_template_directory(
|
|
91
|
+
workspace: Path,
|
|
92
|
+
) -> None:
|
|
93
|
+
domain = project_domain(workspace)
|
|
94
|
+
relative = "mywork/【Example】文档中心/_模板/版本发布清单.md"
|
|
95
|
+
|
|
96
|
+
result = service(workspace).apply(
|
|
97
|
+
DocumentApplyRequest(
|
|
98
|
+
path=relative,
|
|
99
|
+
document_type="template",
|
|
100
|
+
values={"description": "版本发布清单模板"},
|
|
101
|
+
body="# 版本发布清单\n",
|
|
102
|
+
confirm=True,
|
|
103
|
+
)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
target = domain / "_模板" / "模板-版本发布清单.md"
|
|
107
|
+
parsed = parse_document(target.read_text(encoding="utf-8"))
|
|
108
|
+
assert result.status == "applied"
|
|
109
|
+
assert result.profile == "base"
|
|
110
|
+
assert set(parsed.frontmatter) == {
|
|
111
|
+
"name",
|
|
112
|
+
"description",
|
|
113
|
+
"type",
|
|
114
|
+
"status",
|
|
115
|
+
"created",
|
|
116
|
+
"updated",
|
|
117
|
+
"tags",
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_apply_rejects_template_outside_domain_template_directory(workspace: Path) -> None:
|
|
122
|
+
project_domain(workspace)
|
|
123
|
+
|
|
124
|
+
result = service(workspace).apply(
|
|
125
|
+
DocumentApplyRequest(
|
|
126
|
+
path="mywork/【Example】文档中心/发布清单.md",
|
|
127
|
+
document_type="template",
|
|
128
|
+
values={"description": "版本发布清单模板"},
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
assert result.status == "blocked"
|
|
133
|
+
assert {issue["code"] for issue in result.issues} == {"template-directory-required"}
|
|
134
|
+
|
|
135
|
+
|
|
90
136
|
def test_apply_normalizes_missing_markdown_extension_and_type_prefix(
|
|
91
137
|
workspace: Path,
|
|
92
138
|
) -> None:
|