campfire-cli 0.1.7__tar.gz → 0.1.8__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.
Files changed (205) hide show
  1. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/.github/workflows/ci.yml +2 -2
  2. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/.github/workflows/release.yml +2 -2
  3. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/ARCHITECTURE.md +4 -4
  4. campfire_cli-0.1.8/COMMAND.md +44 -0
  5. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/PKG-INFO +7 -9
  6. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/README.md +6 -8
  7. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/SPEC.md +6 -7
  8. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/pyproject.toml +1 -1
  9. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/__init__.py +1 -1
  10. campfire_cli-0.1.8/src/campfire_cli/alembic/versions/008_remove_adoption_batches.py +16 -0
  11. campfire_cli-0.1.8/src/campfire_cli/app/base/schema/operation_schema.py +33 -0
  12. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/SPEC.md +4 -4
  13. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_apply_service.py +40 -23
  14. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_move_service.py +27 -34
  15. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_scanner.py +22 -10
  16. campfire_cli-0.1.8/src/campfire_cli/app/maintenance/SPEC.md +19 -0
  17. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/cli/maintenance_cli.py +0 -34
  18. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/repository/maintenance_repository.py +41 -21
  19. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/schema/maintenance_schema.py +1 -32
  20. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/service/maintenance_protocol.py +6 -3
  21. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/service/maintenance_service.py +64 -61
  22. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/SPEC.md +3 -3
  23. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/cli/domain_cli.py +78 -3
  24. campfire_cli-0.1.8/src/campfire_cli/app/workspace/cli/restructure_cli.py +70 -0
  25. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/schema/adoption_schema.py +1 -26
  26. campfire_cli-0.1.8/src/campfire_cli/app/workspace/service/adoption_service.py +355 -0
  27. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/domain_restructure_service.py +5 -2
  28. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/structure_service.py +26 -42
  29. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/agent_hints.py +3 -2
  30. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/database/models.py +0 -18
  31. campfire_cli-0.1.8/src/campfire_cli/common/documents/domain_context.py +87 -0
  32. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/container.py +1 -5
  33. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/main.py +0 -2
  34. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/defaults/config.yml +4 -19
  35. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-context-bootstrap/SKILL.md +2 -0
  36. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-document-capture/SKILL.md +4 -3
  37. campfire_cli-0.1.8/src/campfire_cli/resources/skills/campfire-workspace-adoption/SKILL.md +32 -0
  38. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-workspace-maintenance/SKILL.md +15 -13
  39. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-workspace-restructure/SKILL.md +5 -5
  40. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/integration/test_cli.py +163 -315
  41. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_document_apply.py +77 -6
  42. campfire_cli-0.1.8/tests/unit/test_domain_context.py +85 -0
  43. campfire_cli-0.1.8/tests/unit/test_migrations.py +24 -0
  44. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/uv.lock +1 -1
  45. campfire_cli-0.1.7/COMMAND.md +0 -50
  46. campfire_cli-0.1.7/src/campfire_cli/app/base/schema/operation_schema.py +0 -23
  47. campfire_cli-0.1.7/src/campfire_cli/app/maintenance/SPEC.md +0 -22
  48. campfire_cli-0.1.7/src/campfire_cli/app/maintenance/service/plan_service.py +0 -411
  49. campfire_cli-0.1.7/src/campfire_cli/app/workspace/cli/adoption_cli.py +0 -83
  50. campfire_cli-0.1.7/src/campfire_cli/app/workspace/cli/restructure_cli.py +0 -133
  51. campfire_cli-0.1.7/src/campfire_cli/app/workspace/repository/adoption_repository.py +0 -55
  52. campfire_cli-0.1.7/src/campfire_cli/app/workspace/service/adoption_protocol.py +0 -11
  53. campfire_cli-0.1.7/src/campfire_cli/app/workspace/service/adoption_service.py +0 -386
  54. campfire_cli-0.1.7/src/campfire_cli/resources/skills/campfire-workspace-adoption/SKILL.md +0 -42
  55. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/.gitignore +0 -0
  56. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/AGENTS.md +0 -0
  57. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/DECISIONS.md +0 -0
  58. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/LICENSE +0 -0
  59. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/alembic/SPEC.md +0 -0
  60. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/alembic/env.py +0 -0
  61. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/alembic/script.py.mako +0 -0
  62. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/alembic/versions/001_initial_schema.py +0 -0
  63. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/alembic.ini +0 -0
  64. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/scripts/SPEC.md +0 -0
  65. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/__init__.py +0 -0
  66. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/env.py +0 -0
  67. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/script.py.mako +0 -0
  68. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/001_initial_schema.py +0 -0
  69. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/002_workspace_project_registry.py +0 -0
  70. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/003_unified_workspace_state.py +0 -0
  71. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/004_restructure_workspace_domain.py +0 -0
  72. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/005_decision_channel.py +0 -0
  73. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/006_workspace_topology_index.py +0 -0
  74. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/007_workspace_adoption.py +0 -0
  75. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/alembic/versions/__init__.py +0 -0
  76. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/SPEC.md +0 -0
  77. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/__init__.py +0 -0
  78. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/base/SPEC.md +0 -0
  79. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/base/__init__.py +0 -0
  80. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/base/cli/base_cli.py +0 -0
  81. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/base/repository/base_repository.py +0 -0
  82. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/base/schema/base_schema.py +0 -0
  83. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/base/service/base_service.py +0 -0
  84. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/SPEC.md +0 -0
  85. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/__init__.py +0 -0
  86. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/cli/decision_cli.py +0 -0
  87. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/repository/decision_repository.py +0 -0
  88. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/schema/decision_schema.py +0 -0
  89. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/service/decision_projection_service.py +0 -0
  90. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/decision/service/decision_service.py +0 -0
  91. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/__init__.py +0 -0
  92. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/cli/__init__.py +0 -0
  93. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/cli/document_cli.py +0 -0
  94. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/cli/profile_cli.py +0 -0
  95. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/cli/type_cli.py +0 -0
  96. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/repository/__init__.py +0 -0
  97. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/repository/document_profile_repository.py +0 -0
  98. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/repository/document_type_repository.py +0 -0
  99. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/schema/__init__.py +0 -0
  100. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/schema/document_schema.py +0 -0
  101. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/__init__.py +0 -0
  102. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_profile_service.py +0 -0
  103. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_rule_service.py +0 -0
  104. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_service.py +0 -0
  105. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/document_type_service.py +0 -0
  106. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/frontmatter_apply.py +0 -0
  107. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/frontmatter_formatter.py +0 -0
  108. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/frontmatter_plan.py +0 -0
  109. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/kanban_service.py +0 -0
  110. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/profile_registry.py +0 -0
  111. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/type_apply.py +0 -0
  112. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/document/service/type_plan.py +0 -0
  113. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/__init__.py +0 -0
  114. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/service/archive_service.py +0 -0
  115. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/service/link_service.py +0 -0
  116. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/maintenance/service/moc_service.py +0 -0
  117. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/skill/SPEC.md +0 -0
  118. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/skill/__init__.py +0 -0
  119. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/skill/cli/skill_cli.py +0 -0
  120. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/skill/repository/skill_repository.py +0 -0
  121. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/skill/schema/skill_schema.py +0 -0
  122. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/skill/service/skill_service.py +0 -0
  123. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/__init__.py +0 -0
  124. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/cli/__init__.py +0 -0
  125. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/cli/config_cli.py +0 -0
  126. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/cli/project_cli.py +0 -0
  127. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/cli/space_cli.py +0 -0
  128. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/cli/workspace_cli.py +0 -0
  129. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/repository/__init__.py +0 -0
  130. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/repository/manifest_repository.py +0 -0
  131. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/repository/restructure_repository.py +0 -0
  132. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/repository/workspace_repository.py +0 -0
  133. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/schema/__init__.py +0 -0
  134. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/schema/restructure_schema.py +0 -0
  135. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/schema/workspace_schema.py +0 -0
  136. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/__init__.py +0 -0
  137. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/config_service.py +0 -0
  138. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/project_service.py +0 -0
  139. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/restructure_protocol.py +0 -0
  140. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/restructure_service.py +0 -0
  141. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/restructure_verifier.py +0 -0
  142. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/workspace_protocol.py +0 -0
  143. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/app/workspace/service/workspace_service.py +0 -0
  144. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/SPEC.md +0 -0
  145. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/__init__.py +0 -0
  146. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/database/__init__.py +0 -0
  147. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/database/migrations.py +0 -0
  148. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/database/session.py +0 -0
  149. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/documents/__init__.py +0 -0
  150. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/documents/document_types.py +0 -0
  151. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/documents/frontmatter_schema.py +0 -0
  152. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/documents/markdown.py +0 -0
  153. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/exceptions/__init__.py +0 -0
  154. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/exceptions/base.py +0 -0
  155. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/filesystem/__init__.py +0 -0
  156. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/filesystem/atomic.py +0 -0
  157. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/filesystem/change_set.py +0 -0
  158. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/filesystem/cwd.py +0 -0
  159. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/filesystem/locking.py +0 -0
  160. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/governance/__init__.py +0 -0
  161. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/governance/issues.py +0 -0
  162. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/governance/locking.py +0 -0
  163. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/governance/snapshots.py +0 -0
  164. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/hashing.py +0 -0
  165. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/package_version.py +0 -0
  166. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/reports/__init__.py +0 -0
  167. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/reports/json_report.py +0 -0
  168. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/common/reports/markdown_report.py +0 -0
  169. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/config/SPEC.md +0 -0
  170. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/config/defaults.py +0 -0
  171. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/config/settings.py +0 -0
  172. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/__init__.py +0 -0
  173. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/bases/Agent/346/211/247/350/241/214/345/267/245/344/275/234/345/217/260.base" +0 -0
  174. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/bases/SPEC.md +0 -0
  175. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/bases//344/273/273/345/212/241/345/267/245/344/275/234/345/217/260.base" +0 -0
  176. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/bases//345/206/263/347/255/226/345/267/245/344/275/234/345/217/260.base" +0 -0
  177. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/bases//345/276/205/345/275/222/346/241/243/346/226/207/346/241/243.base" +0 -0
  178. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/bases//351/241/271/347/233/256/346/226/207/346/241/243.base" +0 -0
  179. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/defaults/__init__.py +0 -0
  180. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/SPEC.md +0 -0
  181. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-context-bootstrap/agents/openai.yaml +0 -0
  182. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-conversation-router/SKILL.md +0 -0
  183. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-conversation-router/agents/openai.yaml +0 -0
  184. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-conversation-router/references/inbox-handoff.md +0 -0
  185. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-conversation-router/references/learning-intake.md +0 -0
  186. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-conversation-router/references/task-intake.md +0 -0
  187. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-inbox-triage/SKILL.md +0 -0
  188. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-kanban-board/SKILL.md +0 -0
  189. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-task-management/SKILL.md +0 -0
  190. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-weekly-report-writing/SKILL.md +0 -0
  191. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/src/campfire_cli/resources/skills/campfire-weekly-report-writing/agents/openai.yaml +0 -0
  192. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/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
  193. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/SPEC.md +0 -0
  194. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/conftest.py +0 -0
  195. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/perf/test_read_counts.py +0 -0
  196. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/perf/test_resolve_subprocess_count.py +0 -0
  197. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_agent_hints.py +0 -0
  198. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_atomic_write.py +0 -0
  199. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_common_governance.py +0 -0
  200. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_config.py +0 -0
  201. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_file_change_executor.py +0 -0
  202. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_frontmatter.py +0 -0
  203. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_kanban_service.py +0 -0
  204. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_package_version.py +0 -0
  205. {campfire_cli-0.1.7 → campfire_cli-0.1.8}/tests/unit/test_repository_boundaries.py +0 -0
@@ -15,8 +15,8 @@ jobs:
15
15
  env:
16
16
  PYTHONUTF8: "1"
17
17
  steps:
18
- - uses: actions/checkout@v4
19
- - uses: astral-sh/setup-uv@v5
18
+ - uses: actions/checkout@v5
19
+ - uses: astral-sh/setup-uv@v10.1.0
20
20
  with:
21
21
  enable-cache: true
22
22
  cache-dependency-glob: "uv.lock"
@@ -11,8 +11,8 @@ jobs:
11
11
  id-token: write
12
12
  contents: read
13
13
  steps:
14
- - uses: actions/checkout@v4
15
- - uses: astral-sh/setup-uv@v5
14
+ - uses: actions/checkout@v5
15
+ - uses: astral-sh/setup-uv@v10.1.0
16
16
  - name: Build
17
17
  run: uv build
18
18
  - name: Publish to PyPI
@@ -97,7 +97,7 @@ Campfire 不是“Markdown 版 kubectl”,而是面向人机协作场景组合
97
97
  | --- | --- | --- |
98
98
  | 语义原子性 | 一条命令只表达一个可以用一句话说清的用户意图 | `document move` 表达“在已声明 Domain 之间正确移动一篇文档” |
99
99
  | 一致性原子性 | 为保持该意图不变量而必须一起变更的事实,属于同一个变更集;整体成功或恢复到执行前 | 移动文档时同步修复可确定解析的引用 |
100
- | 可组合原子性 | 不相关的派生治理不隐式执行;命令用结构化 `follow_up` 声明后续步骤,由 Skill 决定组合顺序 | `document apply` 不自动运行 `maintenance sync/check` |
100
+ | 可组合原子性 | 不相关的派生治理不隐式执行;命令用结构化 `follow_up` 声明必要步骤,由 Skill 决定组合顺序 | `document apply` 只在必要时返回一个 scoped `maintenance sync` |
101
101
 
102
102
  命令副作用按下列边界分类:
103
103
 
@@ -118,14 +118,14 @@ Campfire 不是“Markdown 版 kubectl”,而是面向人机协作场景组合
118
118
  命令设计遵循以下约束:
119
119
 
120
120
  1. **对象域优先**:公共入口采用 `campfire <object-domain> <verb>`,例如 `document apply`、`maintenance check`;动词在所属业务对象内保持单义,不为同一行为保留多个别名。
121
- 2. **意图原子、派生显式**:`document apply` 只创建或更新目标文档,`document move` 原子完成单文档移动、目标 Profile 对齐和确定性引用修复;MOC、关系页和索引治理由 Skill 显式编排 `maintenance sync/check`。
121
+ 2. **意图原子、派生显式**:`document apply` 只创建或更新目标文档,`document move` 原子完成单文档移动、目标 Profile 对齐和确定性引用修复;命令只在 MOC、关系页或索引可能变化时返回一个最小 scope 的 `maintenance sync`。
122
122
  3. **契约声明式,变更显式**:Profile 是字段、类型、枚举、顺序和条件必填的 SSOT。Agent 提交业务值,CLI 解析有效 Profile 并拒绝猜测;已有文档只修改明确给出的字段或正文操作。
123
123
  4. **写入先证明安全**:写命令默认预览,显式确认后才提交;提交时在锁内复核快照或期望哈希,多文件变更作为一个 ChangeSet 执行,失败回滚,避免静默覆盖和部分写入。
124
124
  5. **人类与 Agent 共用一个契约**:命令和结果只有一套语义。JSON 状态、issues、missing fields 与 follow-up 供 Agent 稳定消费,`tree` 和分层 `-h` 供人类与 Agent 渐进发现,不维护第二套参数目录。
125
125
  6. **语义与机制分层**:人类决定高风险取舍,Agent 理解正文和业务语义,Skill 规定加载时机、事实门禁与 SOP,CLI 只执行可确定验证的治理机制。歧义进入 Decision,不为“自动化成功”而猜测。
126
126
  7. **聚合入口是少数例外**:`setup` 和 `upgrade` 可以编排多个服务,因为它们表达完整安装生命周期;日常内容治理保持原子能力,避免重新出现 `maintenance run` 一类不可审查的聚合入口。
127
127
 
128
- 横切关注点与业务 SOP 不使用同一种复用手段。哈希复核、写锁、原子替换和失败恢复由显式 ChangeSet Executor 复用;`apply → sync → check` 等业务顺序由 Skill 明文编排。不为了复用 Maintenance 而引入 AOP 切面、命令总线、全局钩子或隐式中间件。
128
+ 横切关注点与业务 SOP 不使用同一种复用手段。哈希复核、写锁、原子替换和失败恢复由显式 ChangeSet Executor 复用;写命令返回的 `follow_up` 由 Skill 消费。不为了复用 Maintenance 而引入 AOP 切面、命令总线、全局钩子或隐式中间件。
129
129
 
130
130
  因此,`document apply` 的准确含义是“对一个 Markdown 文档应用经 Profile 校验的显式意图”,不是“把完整声明持续调谐到某个服务端状态”。用户或 Agent 可以直接 edit 已有正文;无论通过 apply 还是 edit 写入,跨文档派生结果都由后续显式 Maintenance 收敛。
131
131
 
@@ -181,7 +181,7 @@ SQLite 中的 `spaces`、`domains` 与 `documents` 是本机查询投影,不
181
181
 
182
182
  ### 存量文件夹接管
183
183
 
184
- Adoption 是首次接管边界,不属于日常 Maintenance。外部目录只读并复制到 `_收件箱/待接管/<batch>`,Vault 内目录原地冻结事实;两者随后通过同一份计划建立一个粗粒度 Domain。CLI 负责文件清单、哈希、软链接与冲突保护、声明、初始 MOC 和 Project/Manifest 联动;Agent 负责阅读正文、选择目标 Space/Domain,并按 `follow_up` 显式刷新派生视图与索引。
184
+ Adoption 是首次接管边界,不属于日常 Maintenance。`workspace domain adopt` 一次完成只读盘点、预览和确认后的原子接管,不持久化中间批次。外部目录通过临时隐藏目录复制并校验,原来源保持不变;Vault 内目录原地声明或移动到目标。CLI 负责哈希、软链接与冲突保护、声明、初始 MOC 和 Project/Manifest 联动;Agent 负责阅读正文、选择目标 Space/Domain,并执行返回的 `follow_up`。
185
185
 
186
186
  ## 6. 本地 Web 工作台
187
187
 
@@ -0,0 +1,44 @@
1
+ # Campfire 稳定命令
2
+
3
+ 人类与 Agent 先用 `campfire tree` 发现命令,再用任意层级的 `-h` 渐进加载参数。
4
+
5
+ ```bash
6
+ campfire setup --workspace <vault-path> [--id <workspace-id>] --default
7
+ campfire upgrade
8
+ campfire skill sync
9
+ campfire base sync
10
+ campfire workspace resolve
11
+ campfire workspace rebuild
12
+ campfire workspace rebuild --confirm
13
+ campfire workspace project bind --id <project-id> --local-path <repository-path>
14
+ campfire workspace space list
15
+ campfire workspace space check
16
+ campfire workspace space check --space <space-id>
17
+ campfire workspace config check
18
+ campfire workspace domain list
19
+ campfire workspace domain check
20
+ campfire workspace domain adopt --source <folder> --target-path <path> --id <id> --name <name> --space <id> --type <type> --governance <policy> [--parent <id>] [--project <id>] [--confirm]
21
+ campfire workspace domain rename --domain <id> --name <name> [--rename-directory|--target-path <path>] [--project-name <name>] [--confirm]
22
+ campfire workspace domain move --domain <id> --target-path <path> [--parent-domain <id>] [--confirm]
23
+ campfire workspace domain rekey --domain <id> --new-id <id> [--confirm]
24
+ campfire workspace restructure inventory --scope <path> --batch <id>
25
+ campfire workspace restructure plan --batch <id>
26
+ campfire workspace project resolve --path "$PWD"
27
+ campfire document apply --path <workspace-relative-markdown> --type <type> --set <field=value> [--body-file <path>] [--confirm]
28
+ campfire document move --from <source> --to <target> [--set <field=value>] [--unset <field>] [--expected-hash <sha256>] [--confirm]
29
+ campfire document inspect --path <file>
30
+ campfire document type list
31
+ campfire document profile list
32
+ campfire decision create --key <key> --question <question> --source-type <source>
33
+ campfire decision list --status pending
34
+ campfire decision show <decision-id>
35
+ campfire decision answer <decision-id> --answer <answer> --answered-by <actor>
36
+ campfire decision close <decision-id>
37
+ campfire decision sync
38
+ campfire maintenance check --summary
39
+ campfire maintenance sync --scope <path> [--dry-run]
40
+ campfire maintenance archive check [--scope <path>]
41
+ campfire maintenance archive apply [--scope <path>] --confirm
42
+ ```
43
+
44
+ Space、Domain、Project 的 `create`/`adopt`,以及文档移动、重构、归档写操作默认先预览;审查通过后才追加 `--confirm`。`document apply` 可新建、更新或为已有正文补齐 Frontmatter;`document move` 可在任意已声明 Domain 之间移动单篇文档并对齐可确定的 `domain`/`project`。目标 Profile 缺少语义字段时返回 `missing_fields`,调用方用 `--set`/`--unset` 补齐。写命令只返回实际需要的一个 scoped `maintenance sync` follow-up,没有派生影响时返回空列表。具体参数以对应命令的 `-h` 为准。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: campfire-cli
3
- Version: 0.1.7
3
+ Version: 0.1.8
4
4
  Summary: Local-first shared context and governance CLI for humans and agents
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -114,15 +114,13 @@ campfire workspace rebuild --confirm # 索引损坏时从 SSOT 完
114
114
 
115
115
  ## 存量接管与结构重构
116
116
 
117
- `workspace adopt` 负责首次接管已有文件夹:Vault 外来源先按哈希复制到 `_收件箱/待接管/<batch>`(原目录始终保留),Vault 内来源原地盘点;一次建立一个粗粒度 Domain,语义细分交给后续 Maintenance/Restructure 计划。
117
+ `workspace domain adopt` 用一条命令接管一个已有文件夹。Vault 外来源经临时暂存和哈希校验复制到目标 Domain,原目录始终保留;Vault 内来源原地声明或移动到明确目标。命令一次建立一个粗粒度 Domain,语义细分交给后续 Restructure。
118
118
 
119
119
  ```bash
120
- campfire workspace adopt inventory --source /path/to/folder --batch notes-001
121
- campfire workspace adopt plan --batch notes-001 --target-path "mynote/新领域" \
122
- --domain-id knowledge-new --name "新领域" --space knowledge \
120
+ campfire workspace domain adopt --source /path/to/folder --target-path "mynote/新领域" \
121
+ --id knowledge-new --name "新领域" --space knowledge \
123
122
  --type knowledge-domain --governance knowledge-docs
124
- campfire workspace adopt apply --batch notes-001 --confirm
125
- campfire workspace adopt verify --batch notes-001
123
+ # 审查同一份结构化计划后,对相同命令追加 --confirm
126
124
  ```
127
125
 
128
126
  单篇文档在已声明 Domain 之间移动使用 `document move`。批量文档或 Domain 结构重构先冻结范围,再传入 YAML/JSON 意图规格(含 Frontmatter 修改),逐项审查 `approved` 后执行:
@@ -141,12 +139,12 @@ campfire workspace restructure verify --batch move-001
141
139
  - **校验分工**:`maintenance check` 统一负责正式文档的 Schema 与枚举校验,并刷新可重建索引;结构声明由 `workspace space/domain check` 校验;`maintenance sync` 只因结构、MOC、路径或并发安全问题阻塞,单篇文档问题不阻止其他领域刷新。
142
140
  - **Frontmatter Profile**:声明式一层继承(`base` 或 `base → knowledge/project-doc/task`),`document profile show` 展示编译后的完整规则;Formatter 只按有效 Profile 排序并保留值,不允许字段由 Validator 报告、不自动删除。
143
141
  - **并发与提交安全**:写入前在治理锁内复核内容哈希,外部变化返回 `concurrent-change` / `source-hash-changed`,拒绝覆盖;多文件写入和路径移动经同一 ChangeSet 提交,失败恢复到执行前。
144
- - **显式后续治理**:写入命令以轻量 `follow_up` 返回 `maintenance sync/check` 的 Workspace 和 scope;Skill 顺序执行,CLI 不隐式捎带派生治理。
142
+ - **按需后续治理**:写入命令只在派生内容可能变化时返回一个最小 scope 的 `maintenance sync`;Skill 消费该结果,没有 follow-up 就结束,不固定追加 dry-run 或全量 check。
145
143
  - **配置两层模型**:产品默认契约在包内 `resources/defaults/config.yml`(SSOT),用户只在 `~/.campfire/config.yml` 写覆盖项;Mapping 递归合并,`campfire workspace config check` 验证有效配置。
146
144
 
147
145
  ## Agent 协作
148
146
 
149
- 全局 Skill(`campfire skill list` 查看托管清单,`campfire skill sync` 手动同步)定义了 Agent 的标准工作流:先 `workspace resolve` 解析上下文,再读取目标 Workspace 的 `AGENTS.md`;只读检查可直接执行,`restructure apply`、`maintenance apply`、`archive apply` 必须先审查计划并用显式确认参数。有歧义的分类和重构进入 Decision 待确认,不由 Agent 擅自决定。
147
+ 全局 Skill(`campfire skill list` 查看托管清单,`campfire skill sync` 手动同步)定义了 Agent 的标准工作流:首次读写先 `workspace resolve` 并读取 Workspace 的 `AGENTS.md`;单文档用 `document apply/move`,批量结构调整用 `workspace restructure`,归档用 `maintenance archive`。有歧义的分类和重构进入 Decision,不由 Agent 擅自决定。
150
148
 
151
149
  ## 许可
152
150
 
@@ -98,15 +98,13 @@ campfire workspace rebuild --confirm # 索引损坏时从 SSOT 完
98
98
 
99
99
  ## 存量接管与结构重构
100
100
 
101
- `workspace adopt` 负责首次接管已有文件夹:Vault 外来源先按哈希复制到 `_收件箱/待接管/<batch>`(原目录始终保留),Vault 内来源原地盘点;一次建立一个粗粒度 Domain,语义细分交给后续 Maintenance/Restructure 计划。
101
+ `workspace domain adopt` 用一条命令接管一个已有文件夹。Vault 外来源经临时暂存和哈希校验复制到目标 Domain,原目录始终保留;Vault 内来源原地声明或移动到明确目标。命令一次建立一个粗粒度 Domain,语义细分交给后续 Restructure。
102
102
 
103
103
  ```bash
104
- campfire workspace adopt inventory --source /path/to/folder --batch notes-001
105
- campfire workspace adopt plan --batch notes-001 --target-path "mynote/新领域" \
106
- --domain-id knowledge-new --name "新领域" --space knowledge \
104
+ campfire workspace domain adopt --source /path/to/folder --target-path "mynote/新领域" \
105
+ --id knowledge-new --name "新领域" --space knowledge \
107
106
  --type knowledge-domain --governance knowledge-docs
108
- campfire workspace adopt apply --batch notes-001 --confirm
109
- campfire workspace adopt verify --batch notes-001
107
+ # 审查同一份结构化计划后,对相同命令追加 --confirm
110
108
  ```
111
109
 
112
110
  单篇文档在已声明 Domain 之间移动使用 `document move`。批量文档或 Domain 结构重构先冻结范围,再传入 YAML/JSON 意图规格(含 Frontmatter 修改),逐项审查 `approved` 后执行:
@@ -125,12 +123,12 @@ campfire workspace restructure verify --batch move-001
125
123
  - **校验分工**:`maintenance check` 统一负责正式文档的 Schema 与枚举校验,并刷新可重建索引;结构声明由 `workspace space/domain check` 校验;`maintenance sync` 只因结构、MOC、路径或并发安全问题阻塞,单篇文档问题不阻止其他领域刷新。
126
124
  - **Frontmatter Profile**:声明式一层继承(`base` 或 `base → knowledge/project-doc/task`),`document profile show` 展示编译后的完整规则;Formatter 只按有效 Profile 排序并保留值,不允许字段由 Validator 报告、不自动删除。
127
125
  - **并发与提交安全**:写入前在治理锁内复核内容哈希,外部变化返回 `concurrent-change` / `source-hash-changed`,拒绝覆盖;多文件写入和路径移动经同一 ChangeSet 提交,失败恢复到执行前。
128
- - **显式后续治理**:写入命令以轻量 `follow_up` 返回 `maintenance sync/check` 的 Workspace 和 scope;Skill 顺序执行,CLI 不隐式捎带派生治理。
126
+ - **按需后续治理**:写入命令只在派生内容可能变化时返回一个最小 scope 的 `maintenance sync`;Skill 消费该结果,没有 follow-up 就结束,不固定追加 dry-run 或全量 check。
129
127
  - **配置两层模型**:产品默认契约在包内 `resources/defaults/config.yml`(SSOT),用户只在 `~/.campfire/config.yml` 写覆盖项;Mapping 递归合并,`campfire workspace config check` 验证有效配置。
130
128
 
131
129
  ## Agent 协作
132
130
 
133
- 全局 Skill(`campfire skill list` 查看托管清单,`campfire skill sync` 手动同步)定义了 Agent 的标准工作流:先 `workspace resolve` 解析上下文,再读取目标 Workspace 的 `AGENTS.md`;只读检查可直接执行,`restructure apply`、`maintenance apply`、`archive apply` 必须先审查计划并用显式确认参数。有歧义的分类和重构进入 Decision 待确认,不由 Agent 擅自决定。
131
+ 全局 Skill(`campfire skill list` 查看托管清单,`campfire skill sync` 手动同步)定义了 Agent 的标准工作流:首次读写先 `workspace resolve` 并读取 Workspace 的 `AGENTS.md`;单文档用 `document apply/move`,批量结构调整用 `workspace restructure`,归档用 `maintenance archive`。有歧义的分类和重构进入 Decision,不由 Agent 擅自决定。
134
132
 
135
133
  ## 许可
136
134
 
@@ -105,16 +105,15 @@ Campfire 使用语义化版本:
105
105
 
106
106
  - SQLite `spaces`、`domains`、`documents` 只允许作为可重建本机投影,不得反向覆盖 Markdown SSOT。
107
107
  - `setup` 与 `maintenance check` 必须自动刷新完整拓扑和文档索引。
108
- - 领域重构只提交当前结构意图,并返回 scoped `maintenance sync` 与
109
- `maintenance check` follow-up;调用方必须显式执行它们以刷新受影响 MOC
110
- 和当前 Workspace 索引。
108
+ - 写命令只在派生状态可能变化时返回一个 scoped `maintenance sync` follow-up;
109
+ 调用方只执行实际返回的 follow-up,不固定追加 check 或全量扫描。
111
110
  - `workspace rebuild` 默认只预览;`--confirm` 后从 Manifest 和 Markdown 完整替换派生索引。
112
111
 
113
112
  ## Workspace 接管
114
113
 
115
- - 外部来源必须只读,先复制到 `_收件箱/待接管/<batch>`;不得删除或修改原目录。
114
+ - 外部来源必须只读,经临时隐藏目录复制和哈希校验后落到目标;不得删除或修改原目录。
116
115
  - Vault 内来源原地盘点,不得重复复制。
117
- - 软链接、目标冲突、暂存冲突和源哈希变化必须 fail closed。
116
+ - 软链接、目标冲突和源哈希变化必须 fail closed。
118
117
  - 接管计划一次建立一个粗粒度 Domain;CLI 不得自行推断文档语义或子领域。
119
- - `apply` 默认只预检,显式 `--confirm` 后才移动暂存内容并创建领域声明。
120
- - `verify` 必须核对接管文件、哈希和领域声明;接管后的格式与细分治理继续使用 Maintenance 和 Restructure。
118
+ - `workspace domain adopt` 默认只预览,显式 `--confirm` 后在一个 ChangeSet 中移动或复制内容并创建领域声明。
119
+ - 提交成功前必须核对接管文件、哈希和领域声明;接管后的细分治理继续使用 Restructure。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "campfire-cli"
3
- version = "0.1.7"
3
+ version = "0.1.8"
4
4
  description = "Local-first shared context and governance CLI for humans and agents"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """Campfire CLI package."""
2
2
 
3
- __version__ = "0.1.7"
3
+ __version__ = "0.1.8"
@@ -0,0 +1,16 @@
1
+ """Remove obsolete multi-stage Workspace adoption state."""
2
+
3
+ from alembic import op
4
+
5
+ revision = "008"
6
+ down_revision = "007"
7
+ branch_labels = None
8
+ depends_on = None
9
+
10
+
11
+ def upgrade() -> None:
12
+ op.drop_table("adoption_batches")
13
+
14
+
15
+ def downgrade() -> None:
16
+ raise RuntimeError("The adoption workflow consolidation is intentionally irreversible")
@@ -0,0 +1,33 @@
1
+ from collections.abc import Iterable
2
+ from pathlib import PurePosixPath
3
+ from typing import Literal
4
+
5
+ from pydantic import BaseModel
6
+
7
+
8
+ class CommandFollowUp(BaseModel):
9
+ """Describe one deterministic governance command that a caller should run next."""
10
+
11
+ command: Literal["maintenance sync"]
12
+ workspace: str
13
+ scope: str
14
+
15
+
16
+ def maintenance_sync_follow_up(workspace: str, scopes: Iterable[str]) -> list[CommandFollowUp]:
17
+ """Build one sync follow-up at the smallest scope containing all changes."""
18
+
19
+ paths = [PurePosixPath(scope.strip("/")) for scope in dict.fromkeys(scopes) if scope]
20
+ if not paths:
21
+ return []
22
+ common = list(paths[0].parts)
23
+ for path in paths[1:]:
24
+ shared: list[str] = []
25
+ for left, right in zip(common, path.parts, strict=False):
26
+ if left != right:
27
+ break
28
+ shared.append(left)
29
+ common = shared
30
+ if not common:
31
+ break
32
+ scope = PurePosixPath(*common).as_posix() if common else "."
33
+ return [CommandFollowUp(command="maintenance sync", workspace=workspace, scope=scope)]
@@ -2,7 +2,7 @@
2
2
 
3
3
  本模块承载面向用户和 Agent 的文档业务能力,包括单篇检查与格式化、类型契约、Profile 契约、命名和 Frontmatter 治理。
4
4
 
5
- Document App 负责文档自身及其规则;Maintenance App 负责跨文档统一计划、执行、验收和派生内容同步;Workspace Restructure 用例负责存量结构重构。纯解析、序列化和路径安全等无业务状态的原子能力保留在 `common/documents/`。
5
+ Document App 负责单篇文档及其规则;Maintenance App 负责检查、派生内容同步和归档;Workspace Restructure 负责存量批量结构重构。纯解析、序列化和路径安全等无业务状态的原子能力保留在 `common/documents/`。
6
6
 
7
7
  ## 当前能力
8
8
 
@@ -38,13 +38,13 @@ document/
38
38
  - `frontmatter`:检查、规划、执行和格式化文档属性。
39
39
  - `rule`:统一解释类型、Profile、枚举与跨字段不变量。
40
40
  - `inspect`:向 Agent 返回单篇文档的 Domain、类型、有效 Profile 和具体问题。
41
- - `apply`:根据目标路径和类型解析 Profile,不存在时生成文档,已存在时仅应用显式补丁;先完整渲染并校验,追加 `--confirm` 后原子写入。
41
+ - `apply`:根据目标路径和类型解析 Profile,不存在时生成文档,已有 Frontmatter 时只应用显式补丁,无 Frontmatter 时保留正文并补齐完整契约;先完整渲染并校验,追加 `--confirm` 后原子写入。
42
42
  - `move`:在任意已声明 Domain 之间移动或改名一篇文档,按目标 Profile 对齐可确定的 `domain`/`project` 归属,并更新可确定解析的 Wiki、Markdown 和路径引用。目标 Profile 缺少业务字段时返回 `needs-input`,不猜测。
43
43
  - `scanner`:统一解释受管根、忽略目录和豁免文件;Document 与 Maintenance 共用。
44
44
 
45
- Document Service 可以被 Maintenance 和 Workspace Restructure 编排,但不得反向依赖它们。批量计划文件、运行记录、MOC、Base、归档和重构批次不属于 Document App。
45
+ Document Service 可以被 Workspace Restructure 编排,但不得反向依赖 Maintenance。批量计划文件、运行记录、MOC、Base、归档和重构批次不属于 Document App。
46
46
 
47
- `apply` 与 `move` 只保证目标文档操作自身有效,不触发 Maintenance。Skill SOP 在写入后显式编排 scoped `maintenance sync` 和 `maintenance check`。所有写入先生成完整 ChangeSet,再经共享 Executor 在乐观锁内提交;多文件操作失败时恢复提交前内容。
47
+ `apply` 与 `move` 只保证目标文档操作自身有效,不触发 Maintenance。结果只在派生状态可能变化时返回一个最小 scope 的 `maintenance sync`;调用方不得固定追加 check。所有写入先生成完整 ChangeSet,再经共享 Executor 在乐观锁内提交;多文件操作失败时恢复提交前内容。
48
48
 
49
49
  包内 `config.yml` 的默认 Profile 与用户级 `~/.campfire/config.yml` 覆盖共同构成当前治理契约。
50
50
 
@@ -4,7 +4,7 @@ from datetime import date
4
4
  from pathlib import Path
5
5
  from typing import Any
6
6
 
7
- from campfire_cli.app.base.schema.operation_schema import maintenance_follow_up
7
+ from campfire_cli.app.base.schema.operation_schema import maintenance_sync_follow_up
8
8
  from campfire_cli.app.document.schema import (
9
9
  DocumentApplyRequest,
10
10
  DocumentApplyResult,
@@ -13,6 +13,10 @@ from campfire_cli.app.document.service.document_rule_service import DocumentRule
13
13
  from campfire_cli.app.document.service.frontmatter_formatter import render_patch
14
14
  from campfire_cli.app.document.service.profile_registry import ProfileRegistry
15
15
  from campfire_cli.common.documents.document_types import prefixed_name
16
+ from campfire_cli.common.documents.domain_context import (
17
+ DomainContextError,
18
+ resolve_domain_context,
19
+ )
16
20
  from campfire_cli.common.documents.markdown import parse_document, render_document
17
21
  from campfire_cli.common.exceptions import ConfigurationError, GovernanceBlockedError
18
22
  from campfire_cli.common.filesystem import FileChangeExecutor, FileChangeSet, FileWrite, safe_path
@@ -41,8 +45,6 @@ class DocumentApplyService:
41
45
  exists = path.is_file()
42
46
  original = path.read_text(encoding="utf-8") if exists else ""
43
47
  parsed = parse_document(original)
44
- if exists and not parsed.has_frontmatter:
45
- raise GovernanceBlockedError("已有文档缺少 Frontmatter,不能安全 apply")
46
48
 
47
49
  current_type = parsed.frontmatter.get("type")
48
50
  document_type = request.document_type or (
@@ -52,7 +54,12 @@ class DocumentApplyService:
52
54
  raise ConfigurationError("创建文档时必须提供 --type")
53
55
  if document_type not in self._settings.document_types.get("types", {}):
54
56
  raise ConfigurationError(f"未知文档类型:{document_type}")
55
- if exists and request.document_type and current_type != request.document_type:
57
+ if (
58
+ exists
59
+ and parsed.has_frontmatter
60
+ and request.document_type
61
+ and current_type != request.document_type
62
+ ):
56
63
  raise GovernanceBlockedError("不允许通过 document apply 改变已有文档的 type")
57
64
 
58
65
  expected_name = prefixed_name(path.name, document_type, self._settings.document_types)
@@ -63,7 +70,7 @@ class DocumentApplyService:
63
70
 
64
71
  today = date.today().isoformat()
65
72
  frontmatter = dict(parsed.frontmatter)
66
- if not exists:
73
+ if not exists or not parsed.has_frontmatter:
67
74
  frontmatter.update(self._creation_defaults(path, document_type, today))
68
75
  for key in ("project", "domain"):
69
76
  if key in request.values and request.values[key] != frontmatter.get(key):
@@ -81,6 +88,7 @@ class DocumentApplyService:
81
88
  return self._result(
82
89
  request,
83
90
  exists,
91
+ parsed.has_frontmatter,
84
92
  profile.name,
85
93
  actual_hash,
86
94
  "blocked",
@@ -95,7 +103,7 @@ class DocumentApplyService:
95
103
  )
96
104
 
97
105
  next_body = self._next_body(request, parsed.body, exists)
98
- if exists:
106
+ if exists and parsed.has_frontmatter:
99
107
  rendered, render_errors = render_patch(
100
108
  original,
101
109
  {**request.values, "updated": today},
@@ -106,6 +114,7 @@ class DocumentApplyService:
106
114
  return self._result(
107
115
  request,
108
116
  exists,
117
+ parsed.has_frontmatter,
109
118
  profile.name,
110
119
  actual_hash,
111
120
  "blocked",
@@ -132,6 +141,7 @@ class DocumentApplyService:
132
141
  result = self._result(
133
142
  request,
134
143
  exists,
144
+ parsed.has_frontmatter,
135
145
  profile.name,
136
146
  actual_hash,
137
147
  status,
@@ -167,22 +177,20 @@ class DocumentApplyService:
167
177
  "updated": today,
168
178
  "tags": [],
169
179
  }
170
- marker_name = self._settings.governance.get("domain_marker", "_领域.md")
171
- current = path.parent
172
- while current == self._settings.vault_root or self._settings.vault_root in current.parents:
173
- marker = current / marker_name
174
- if marker.is_file():
175
- domain = parse_document(marker.read_text(encoding="utf-8")).frontmatter
176
- if domain.get("domain_id"):
177
- values["domain"] = domain["domain_id"]
178
- project = domain.get("project_id") or domain.get("project")
179
- if project:
180
- values["project"] = project
181
- return values
182
- if current == self._settings.vault_root:
183
- break
184
- current = current.parent
185
- raise ConfigurationError("正式文档必须位于已声明的 Domain 内")
180
+ try:
181
+ context = resolve_domain_context(
182
+ self._settings.vault_root,
183
+ path,
184
+ self._settings.governance.get("domain_marker", "_领域.md"),
185
+ )
186
+ except DomainContextError as exc:
187
+ raise ConfigurationError(
188
+ f"无法解析目标 Domain 上下文:{exc.code}: {exc.detail}"
189
+ ) from exc
190
+ values["domain"] = context.domain_id
191
+ if context.project_id:
192
+ values["project"] = context.project_id
193
+ return values
186
194
 
187
195
  @staticmethod
188
196
  def _next_body(request: DocumentApplyRequest, current: str, exists: bool) -> str:
@@ -208,6 +216,7 @@ class DocumentApplyService:
208
216
  self,
209
217
  request: DocumentApplyRequest,
210
218
  exists: bool,
219
+ had_frontmatter: bool,
211
220
  profile: str,
212
221
  expected_hash: str,
213
222
  status: str,
@@ -215,6 +224,10 @@ class DocumentApplyService:
215
224
  missing_fields: list[str] | None = None,
216
225
  ) -> DocumentApplyResult:
217
226
  scope = Path(request.path).parent.as_posix()
227
+ derived_fields = {"name", "type", "status", "lifecycle", "domain", "project", "related"}
228
+ needs_sync = not exists or not had_frontmatter
229
+ needs_sync = needs_sync or bool(set(request.values) & derived_fields)
230
+ needs_sync = needs_sync or request.body is not None
218
231
  return DocumentApplyResult(
219
232
  status=status,
220
233
  workspace_id=self._settings.workspace_id,
@@ -224,5 +237,9 @@ class DocumentApplyService:
224
237
  expected_hash=expected_hash,
225
238
  issues=issues,
226
239
  missing_fields=missing_fields or [],
227
- follow_up=maintenance_follow_up(self._settings.workspace_id, [scope]),
240
+ follow_up=(
241
+ maintenance_sync_follow_up(self._settings.workspace_id, [scope])
242
+ if not issues and needs_sync
243
+ else []
244
+ ),
228
245
  )
@@ -1,12 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
- from dataclasses import dataclass
4
3
  from datetime import date
5
4
  from pathlib import Path
6
5
  from typing import Any
7
6
  from urllib.parse import quote
8
7
 
9
- from campfire_cli.app.base.schema.operation_schema import maintenance_follow_up
8
+ from campfire_cli.app.base.schema.operation_schema import maintenance_sync_follow_up
10
9
  from campfire_cli.app.document.schema import DocumentMoveResult
11
10
  from campfire_cli.app.document.service.document_rule_service import DocumentRuleService
12
11
  from campfire_cli.app.document.service.frontmatter_formatter import render_patch
@@ -17,6 +16,11 @@ from campfire_cli.app.document.service.type_apply import (
17
16
  rewrite_wikilinks,
18
17
  )
19
18
  from campfire_cli.common.documents.document_types import prefixed_name
19
+ from campfire_cli.common.documents.domain_context import (
20
+ DomainContext,
21
+ DomainContextError,
22
+ resolve_domain_context,
23
+ )
20
24
  from campfire_cli.common.documents.markdown import parse_document
21
25
  from campfire_cli.common.exceptions import ConfigurationError
22
26
  from campfire_cli.common.filesystem import FileChangeExecutor, FileChangeSet, FileWrite, safe_path
@@ -26,13 +30,6 @@ from campfire_cli.config.settings import WorkspaceSettings
26
30
  STRUCTURAL_FIELDS = {"domain", "project", "updated"}
27
31
 
28
32
 
29
- @dataclass(frozen=True)
30
- class DomainContext:
31
- root: Path
32
- domain_id: str
33
- project_id: str | None
34
-
35
-
36
33
  class DocumentMoveService:
37
34
  """Move one document between declared Domains and preserve document invariants."""
38
35
 
@@ -69,15 +66,19 @@ class DocumentMoveService:
69
66
  actual_hash = file_sha256(source)
70
67
  original = source.read_text(encoding="utf-8")
71
68
  parsed = parse_document(original)
72
- source_domain = self._domain_context(source)
73
- target_domain = self._domain_context(target)
69
+ source_domain, source_domain_issue = self._domain_context(source)
70
+ target_domain, target_domain_issue = self._domain_context(target)
74
71
  issues: list[dict[str, Any]] = []
75
72
  if target.exists():
76
73
  issues.append({"code": "target-exists", "path": target_name})
77
74
  if source_domain is None:
78
- issues.append({"code": "source-domain-missing", "path": source_name})
75
+ issues.append(
76
+ {"code": source_domain_issue or "source-domain-missing", "path": source_name}
77
+ )
79
78
  if target_domain is None:
80
- issues.append({"code": "target-domain-missing", "path": target_name})
79
+ issues.append(
80
+ {"code": target_domain_issue or "target-domain-missing", "path": target_name}
81
+ )
81
82
  elif self._is_reserved_target(target_domain, target):
82
83
  issues.append({"code": "target-directory-reserved", "path": target_name})
83
84
  if not parsed.has_frontmatter:
@@ -211,7 +212,7 @@ class DocumentMoveService:
211
212
  frontmatter_changes=frontmatter_changes,
212
213
  issues=issues,
213
214
  missing_fields=missing_fields,
214
- follow_up=maintenance_follow_up(
215
+ follow_up=maintenance_sync_follow_up(
215
216
  self._settings.workspace_id,
216
217
  (
217
218
  context.root.relative_to(self._settings.vault_root).as_posix()
@@ -272,26 +273,18 @@ class DocumentMoveService:
272
273
  changed.append(reference.relative_to(self._settings.vault_root).as_posix())
273
274
  return [FileWrite(path, text) for path, text in writes.items()], changed, expected
274
275
 
275
- def _domain_context(self, path: Path) -> DomainContext | None:
276
- marker_name = self._settings.governance.get("domain_marker", "_领域.md")
277
- current = path.parent
278
- while current == self._settings.vault_root or self._settings.vault_root in current.parents:
279
- marker = current / marker_name
280
- if marker.is_file():
281
- values = parse_document(marker.read_text(encoding="utf-8")).frontmatter
282
- domain_id = values.get("domain_id")
283
- if not isinstance(domain_id, str) or not domain_id:
284
- return None
285
- project = values.get("project_id") or values.get("project")
286
- return DomainContext(
287
- root=current,
288
- domain_id=domain_id,
289
- project_id=project if isinstance(project, str) and project else None,
290
- )
291
- if current == self._settings.vault_root:
292
- break
293
- current = current.parent
294
- return None
276
+ def _domain_context(self, path: Path) -> tuple[DomainContext | None, str | None]:
277
+ try:
278
+ return (
279
+ resolve_domain_context(
280
+ self._settings.vault_root,
281
+ path,
282
+ self._settings.governance.get("domain_marker", "_领域.md"),
283
+ ),
284
+ None,
285
+ )
286
+ except DomainContextError as exc:
287
+ return None, exc.code
295
288
 
296
289
  def _is_reserved_target(self, context: DomainContext, target: Path) -> bool:
297
290
  relative = target.parent.relative_to(context.root)
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from collections.abc import Iterable
5
6
  from pathlib import Path
6
7
  from typing import Any
7
8
 
@@ -13,21 +14,32 @@ def exempt_document(path: Path, config: dict[str, Any]) -> bool:
13
14
  return path.name in set(config.get("exempt_basenames", []))
14
15
 
15
16
 
16
- def iter_documents(root: Path, config: dict[str, Any]) -> list[Path]:
17
+ def iter_documents(
18
+ root: Path,
19
+ config: dict[str, Any],
20
+ roots: Iterable[Path] | None = None,
21
+ ) -> list[Path]:
17
22
  root = root.resolve()
18
23
  ignored = set(config.get("ignored_directories", []))
19
24
  documents: set[Path] = set()
20
25
  space_marker = config.get("space_marker", "_空间.md")
21
- spaces = [
22
- marker.parent.relative_to(root).as_posix() for marker in root.glob(f"*/{space_marker}")
23
- ]
24
- if spaces:
25
- inboxes = [value for value in config.get("scope_roots", []) if value.startswith("_收件箱/")]
26
- scope_roots = [*spaces, *inboxes]
26
+ if roots is not None:
27
+ scope_paths = [path.resolve() for path in roots]
27
28
  else:
28
- scope_roots = config.get("scope_roots", [])
29
- for raw_root in scope_roots:
30
- scope = safe_path(root, raw_root)
29
+ spaces = [
30
+ marker.parent.relative_to(root).as_posix() for marker in root.glob(f"*/{space_marker}")
31
+ ]
32
+ if spaces:
33
+ inboxes = [
34
+ value for value in config.get("scope_roots", []) if value.startswith("_收件箱/")
35
+ ]
36
+ scope_roots = [*spaces, *inboxes]
37
+ else:
38
+ scope_roots = config.get("scope_roots", [])
39
+ scope_paths = [safe_path(root, raw_root) for raw_root in scope_roots]
40
+ for scope in scope_paths:
41
+ if scope != root and root not in scope.parents:
42
+ continue
31
43
  if not scope.exists():
32
44
  continue
33
45
  for path in scope.rglob("*.md"):