campfire-cli 0.1.16__tar.gz → 0.1.18__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 (229) hide show
  1. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/.github/workflows/release.yml +2 -5
  2. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/PKG-INFO +7 -5
  3. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/README.md +6 -4
  4. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/SPEC.md +2 -1
  5. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/pyproject.toml +1 -1
  6. campfire_cli-0.1.18/scripts/pypi_verify.py +67 -0
  7. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/scripts/quality_check.py +1 -1
  8. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/__init__.py +1 -1
  9. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/schema/operation_schema.py +6 -2
  10. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/SPEC.md +4 -1
  11. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/cli/document_cli.py +68 -34
  12. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/schema/document_schema.py +1 -1
  13. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_apply_service.py +45 -36
  14. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_move_service.py +81 -14
  15. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_service.py +15 -0
  16. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/agent_hints.py +13 -7
  17. campfire_cli-0.1.18/src/campfire_cli/resources/skills/SPEC.md +48 -0
  18. campfire_cli-0.1.18/src/campfire_cli/resources/skills/TEMPLATE.md +88 -0
  19. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-context-bootstrap/SKILL.md +58 -0
  20. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-conversation-router/SKILL.md +49 -0
  21. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-conversation-router/references/inbox-handoff.md +2 -0
  22. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-conversation-router/references/learning-intake.md +2 -2
  23. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-conversation-router/references/task-intake.md +3 -4
  24. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-document-capture/SKILL.md +96 -0
  25. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/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
  26. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/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 +2 -2
  27. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/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 +2 -2
  28. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-inbox-triage/SKILL.md +55 -0
  29. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-kanban-board/SKILL.md +59 -0
  30. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-task-management/SKILL.md +73 -0
  31. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-weekly-report-writing/SKILL.md +56 -0
  32. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-workspace-adoption/SKILL.md +59 -0
  33. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-workspace-maintenance/SKILL.md +73 -0
  34. campfire_cli-0.1.18/src/campfire_cli/resources/skills/campfire-workspace-onboarding/SKILL.md +67 -0
  35. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-workspace-onboarding/references//346/240/207/345/207/206/345/267/245/344/275/234/345/214/272/347/273/223/346/236/204.md +2 -3
  36. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-workspace-restructure/SKILL.md +38 -7
  37. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-workspace-restructure/references/restructure-spec.md +1 -1
  38. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/integration/test_cli.py +87 -6
  39. campfire_cli-0.1.18/tests/integration/test_skill_examples.py +96 -0
  40. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_document_apply.py +108 -0
  41. campfire_cli-0.1.18/tests/unit/test_operation_schema.py +14 -0
  42. campfire_cli-0.1.18/tests/unit/test_pypi_verify.py +94 -0
  43. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/uv.lock +1 -1
  44. campfire_cli-0.1.16/src/campfire_cli/resources/skills/SPEC.md +0 -33
  45. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-context-bootstrap/SKILL.md +0 -70
  46. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-conversation-router/SKILL.md +0 -53
  47. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-document-capture/SKILL.md +0 -120
  48. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-inbox-triage/SKILL.md +0 -23
  49. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-kanban-board/SKILL.md +0 -69
  50. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-task-management/SKILL.md +0 -81
  51. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-weekly-report-writing/SKILL.md +0 -21
  52. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-workspace-adoption/SKILL.md +0 -32
  53. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-workspace-maintenance/SKILL.md +0 -94
  54. campfire_cli-0.1.16/src/campfire_cli/resources/skills/campfire-workspace-onboarding/SKILL.md +0 -57
  55. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/.github/workflows/ci.yml +0 -0
  56. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/.gitignore +0 -0
  57. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/.python-version +0 -0
  58. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/AGENTS.md +0 -0
  59. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/ARCHITECTURE.md +0 -0
  60. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/COMMAND.md +0 -0
  61. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/DECISIONS.md +0 -0
  62. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/LICENSE +0 -0
  63. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/alembic/SPEC.md +0 -0
  64. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/alembic/env.py +0 -0
  65. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/alembic/script.py.mako +0 -0
  66. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/alembic/versions/001_initial_schema.py +0 -0
  67. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/alembic.ini +0 -0
  68. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/scripts/SPEC.md +0 -0
  69. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/__init__.py +0 -0
  70. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/env.py +0 -0
  71. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/script.py.mako +0 -0
  72. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/001_initial_schema.py +0 -0
  73. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/002_workspace_project_registry.py +0 -0
  74. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/003_unified_workspace_state.py +0 -0
  75. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/004_restructure_workspace_domain.py +0 -0
  76. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/005_decision_channel.py +0 -0
  77. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/006_workspace_topology_index.py +0 -0
  78. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/007_workspace_adoption.py +0 -0
  79. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/008_remove_adoption_batches.py +0 -0
  80. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/009_document_query_index.py +0 -0
  81. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/010_project_domain_identity.py +0 -0
  82. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/011_document_state_model.py +0 -0
  83. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/012_remove_decision_channel.py +0 -0
  84. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/alembic/versions/__init__.py +0 -0
  85. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/SPEC.md +0 -0
  86. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/__init__.py +0 -0
  87. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/SPEC.md +0 -0
  88. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/__init__.py +0 -0
  89. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/cli/base_cli.py +0 -0
  90. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/repository/base_repository.py +0 -0
  91. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/schema/base_schema.py +0 -0
  92. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/base/service/base_service.py +0 -0
  93. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/__init__.py +0 -0
  94. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/cli/__init__.py +0 -0
  95. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/cli/profile_cli.py +0 -0
  96. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/cli/type_cli.py +0 -0
  97. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/repository/__init__.py +0 -0
  98. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/repository/document_index_repository.py +0 -0
  99. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/repository/document_profile_repository.py +0 -0
  100. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/repository/document_type_repository.py +0 -0
  101. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/schema/__init__.py +0 -0
  102. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/__init__.py +0 -0
  103. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_index_builder.py +0 -0
  104. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_index_protocol.py +0 -0
  105. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_index_service.py +0 -0
  106. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_patch_values.py +0 -0
  107. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_profile_service.py +0 -0
  108. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_relocation.py +0 -0
  109. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_rule_service.py +0 -0
  110. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_scanner.py +0 -0
  111. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/document_type_service.py +0 -0
  112. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/frontmatter_apply.py +0 -0
  113. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/frontmatter_formatter.py +0 -0
  114. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/frontmatter_plan.py +0 -0
  115. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/kanban_service.py +0 -0
  116. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/profile_candidates.py +0 -0
  117. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/profile_registry.py +0 -0
  118. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/type_apply.py +0 -0
  119. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/document/service/type_plan.py +0 -0
  120. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/SPEC.md +0 -0
  121. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/__init__.py +0 -0
  122. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/cli/maintenance_cli.py +0 -0
  123. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/repository/maintenance_repository.py +0 -0
  124. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/schema/maintenance_schema.py +0 -0
  125. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/service/link_service.py +0 -0
  126. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/service/maintenance_protocol.py +0 -0
  127. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/service/maintenance_service.py +0 -0
  128. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/maintenance/service/moc_service.py +0 -0
  129. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/skill/SPEC.md +0 -0
  130. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/skill/__init__.py +0 -0
  131. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/skill/cli/skill_cli.py +0 -0
  132. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/skill/repository/skill_repository.py +0 -0
  133. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/skill/schema/skill_schema.py +0 -0
  134. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/skill/service/skill_service.py +0 -0
  135. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/SPEC.md +0 -0
  136. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/__init__.py +0 -0
  137. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/__init__.py +0 -0
  138. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/config_cli.py +0 -0
  139. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/domain_cli.py +0 -0
  140. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/project_cli.py +0 -0
  141. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/restructure_cli.py +0 -0
  142. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/space_cli.py +0 -0
  143. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/cli/workspace_cli.py +0 -0
  144. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/repository/__init__.py +0 -0
  145. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/repository/manifest_repository.py +0 -0
  146. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/repository/restructure_repository.py +0 -0
  147. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/repository/workspace_repository.py +0 -0
  148. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/schema/__init__.py +0 -0
  149. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/schema/adoption_schema.py +0 -0
  150. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/schema/restructure_schema.py +0 -0
  151. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/schema/workspace_schema.py +0 -0
  152. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/__init__.py +0 -0
  153. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/adoption_service.py +0 -0
  154. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/config_service.py +0 -0
  155. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/domain_restructure_service.py +0 -0
  156. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/project_service.py +0 -0
  157. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/restructure_protocol.py +0 -0
  158. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/restructure_service.py +0 -0
  159. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/restructure_verifier.py +0 -0
  160. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/structure_service.py +0 -0
  161. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/workspace_protocol.py +0 -0
  162. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/app/workspace/service/workspace_service.py +0 -0
  163. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/SPEC.md +0 -0
  164. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/__init__.py +0 -0
  165. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/cli_output.py +0 -0
  166. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/database/__init__.py +0 -0
  167. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/database/migrations.py +0 -0
  168. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/database/models.py +0 -0
  169. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/database/session.py +0 -0
  170. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/__init__.py +0 -0
  171. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/document_types.py +0 -0
  172. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/domain_context.py +0 -0
  173. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/frontmatter_format.py +0 -0
  174. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/frontmatter_schema.py +0 -0
  175. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/links.py +0 -0
  176. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/documents/markdown.py +0 -0
  177. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/exceptions/__init__.py +0 -0
  178. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/exceptions/base.py +0 -0
  179. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/filesystem/__init__.py +0 -0
  180. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/filesystem/atomic.py +0 -0
  181. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/filesystem/change_set.py +0 -0
  182. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/filesystem/cwd.py +0 -0
  183. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/filesystem/locking.py +0 -0
  184. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/governance/__init__.py +0 -0
  185. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/governance/issues.py +0 -0
  186. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/governance/locking.py +0 -0
  187. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/governance/snapshots.py +0 -0
  188. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/hashing.py +0 -0
  189. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/package_version.py +0 -0
  190. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/reports/__init__.py +0 -0
  191. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/reports/json_report.py +0 -0
  192. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/common/reports/markdown_report.py +0 -0
  193. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/config/SPEC.md +0 -0
  194. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/config/defaults.py +0 -0
  195. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/config/settings.py +0 -0
  196. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/container.py +0 -0
  197. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/main.py +0 -0
  198. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/__init__.py +0 -0
  199. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/bases/SPEC.md +0 -0
  200. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/bases//344/273/273/345/212/241/345/267/245/344/275/234/345/217/260-/344/270/252/344/272/272.base" +0 -0
  201. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/bases//344/273/273/345/212/241/345/267/245/344/275/234/345/217/260-/351/241/271/347/233/256.base" +0 -0
  202. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/bases//345/275/222/346/241/243/346/226/207/346/241/243/345/267/245/344/275/234/345/217/260.base" +0 -0
  203. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/bases//345/276/205/344/272/272/345/206/263/347/255/226/345/267/245/344/275/234/345/217/260.base" +0 -0
  204. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/bases//346/226/207/346/241/243/345/267/245/344/275/234/345/217/260.base" +0 -0
  205. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/defaults/__init__.py +0 -0
  206. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/defaults/config.yml +0 -0
  207. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-context-bootstrap/agents/openai.yaml +0 -0
  208. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-conversation-router/agents/openai.yaml +0 -0
  209. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/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
  210. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/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
  211. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/src/campfire_cli/resources/skills/campfire-weekly-report-writing/agents/openai.yaml +0 -0
  212. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/SPEC.md +0 -0
  213. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/conftest.py +0 -0
  214. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/perf/test_read_counts.py +0 -0
  215. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/perf/test_resolve_subprocess_count.py +0 -0
  216. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_agent_hints.py +0 -0
  217. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_atomic_write.py +0 -0
  218. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_base_service.py +0 -0
  219. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_config.py +0 -0
  220. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_document_index.py +0 -0
  221. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_domain_context.py +0 -0
  222. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_file_change_executor.py +0 -0
  223. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_frontmatter.py +0 -0
  224. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_generated_regions.py +0 -0
  225. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_kanban_service.py +0 -0
  226. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_migrations.py +0 -0
  227. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_package_version.py +0 -0
  228. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_repository_boundaries.py +0 -0
  229. {campfire_cli-0.1.16 → campfire_cli-0.1.18}/tests/unit/test_workspace_manifest.py +0 -0
@@ -55,12 +55,9 @@ jobs:
55
55
  needs: publish
56
56
  runs-on: ubuntu-latest
57
57
  steps:
58
+ - uses: actions/checkout@v5
58
59
  - uses: astral-sh/setup-uv@v10.1.0
59
60
  - name: Install published package from PyPI
60
61
  shell: bash
61
62
  run: |
62
- version="${GITHUB_REF_NAME#v}"
63
- verify_dir="$RUNNER_TEMP/campfire-pypi-verify"
64
- uv venv "$verify_dir"
65
- uv pip install --python "$verify_dir/bin/python" --index-url https://pypi.org/simple "campfire-cli==$version"
66
- test "$("$verify_dir/bin/campfire" version)" = "$version"
63
+ python scripts/pypi_verify.py "${GITHUB_REF_NAME#v}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: campfire-cli
3
- Version: 0.1.16
3
+ Version: 0.1.18
4
4
  Summary: Local-first shared context and governance CLI for humans and agents
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -61,7 +61,7 @@ campfire maintenance sync --dry-run
61
61
 
62
62
  不指定 `--path` 运行 `campfire setup` 是降级执行而不是报错:仍会同步全局 Skill 与提示词路标,输出接入引导,并显式列出被跳过的 Manifest 相关步骤。
63
63
 
64
- `setup` 与 `skill sync` 会向 `~/.claude/CLAUDE.md`、`~/.agents/AGENTS.md` 注入幂等的 campfire 路标块(带注释标记、不触碰块外内容;`CAMPFIRE_AGENT_HINT_PATH` 可覆盖目标),并把托管 Skill 同步到 `~/.claude/skills`、`~/.agents/skills`(`CAMPFIRE_SKILL_TARGETS` 可覆盖)。Agent 冷启动时由此知道本机装有 campfire。
64
+ `setup` 会向 `~/.claude/CLAUDE.md`、`~/.agents/AGENTS.md` 注入幂等的 campfire 路标块,保留标记外内容;`CAMPFIRE_AGENT_HINT_PATH` 可覆盖目标。`setup` 与 `skill sync` 会把托管 Skill 同步到 `~/.claude/skills`、`~/.agents/skills`,可通过 `CAMPFIRE_SKILL_TARGETS` 覆盖。单独执行 `skill sync` 不更新提示词路标。
65
65
 
66
66
  ## 核心概念
67
67
 
@@ -85,7 +85,7 @@ Workspace ── Space ── Domain 树 ── 文档
85
85
 
86
86
  ```bash
87
87
  campfire tree # 完整命令树
88
- campfire workspace resolve # Agent 冷启动第一步:解析当前 Workspace
88
+ campfire workspace resolve # Workspace 不明确时解析
89
89
  campfire workspace list / show / export / import # 注册库管理与备份
90
90
  campfire workspace project resolve # 当前目录属于哪个已注册项目
91
91
 
@@ -94,7 +94,7 @@ campfire maintenance sync [--dry-run] [--scope] # 刷新 MOC 与相关文档页
94
94
 
95
95
  campfire document inspect / check / format # 单篇文档查看、校验、格式化
96
96
  campfire document list # 精确枚举和筛选受管文档
97
- campfire document apply / move # 创建更新、类型转换、跨 Domain 移动
97
+ campfire document apply / move / rename # 结构写入、跨 Domain 移动、原地改名
98
98
  campfire document profile list / show / resolve # Frontmatter Profile 规则
99
99
  campfire document type list # 文档类型与前缀
100
100
  campfire base list / show / check / sync # Obsidian Base 治理视图
@@ -146,7 +146,9 @@ campfire workspace restructure verify --batch move-001
146
146
 
147
147
  ## Agent 协作
148
148
 
149
- 全局 Skill(`campfire skill list` 查看托管清单,`campfire skill sync` 手动同步)定义了 Agent 的标准工作流:已给出唯一文件路径的正文读取或小改直接使用文件工具;新建文档、修改 Frontmatter/类型/归属或执行结构治理时才加载 bootstrap,并使用 `document apply/move` 等原子命令。`document apply --path` 创建或唯一更新时可省略 `.md`,创建时也可省略类型前缀。Frontmatter 契约已知时直接 apply;现有文档的字段类型或合法值未知时只执行一次 `document inspect` 后 apply。批量结构调整用 `workspace restructure`;归档在用户明确同意后通过 `document apply --set document_status=archived` 执行。关键歧义进入 `human-request`,不由 Agent 擅自决定。
149
+ 全局 Skill 定义 Agent 的文档工作流:已知路径的人工正文直接 Edit;新建文档先 apply 创建结构,再按返回的 `target` 补正文。只在治理上下文缺失时加载 bootstrap;字段契约未知时,新建查一次目标 Profile,更新查一次 inspect。已明确的信息不重复查询,用户已有授权不重复询问。文档相对路径以 Workspace 根目录为基准,不随 cwd 改变;创建时可省略类型前缀与 `.md`。改标题用 rename,跨 Domain 移动用 move,完成后仅执行实际 follow_up。归档仍需用户对具体文档明确同意,关键歧义不得自行猜测。
150
+
151
+ 仓库 Skill 编写规范见 `src/campfire_cli/resources/skills/SPEC.md`。本地与 CI 共用 `uv run python scripts/quality_check.py`;发布前使用 `--release` 增加构建、wheel 隔离安装与冒烟验证。测试日志包含最慢 10 项耗时。Release 的公共 PyPI 安装验证最多等待 3 分钟、间隔 15 秒重试,不重试上传;安装后版本不符直接失败。
150
152
 
151
153
  ## 许可
152
154
 
@@ -45,7 +45,7 @@ campfire maintenance sync --dry-run
45
45
 
46
46
  不指定 `--path` 运行 `campfire setup` 是降级执行而不是报错:仍会同步全局 Skill 与提示词路标,输出接入引导,并显式列出被跳过的 Manifest 相关步骤。
47
47
 
48
- `setup` 与 `skill sync` 会向 `~/.claude/CLAUDE.md`、`~/.agents/AGENTS.md` 注入幂等的 campfire 路标块(带注释标记、不触碰块外内容;`CAMPFIRE_AGENT_HINT_PATH` 可覆盖目标),并把托管 Skill 同步到 `~/.claude/skills`、`~/.agents/skills`(`CAMPFIRE_SKILL_TARGETS` 可覆盖)。Agent 冷启动时由此知道本机装有 campfire。
48
+ `setup` 会向 `~/.claude/CLAUDE.md`、`~/.agents/AGENTS.md` 注入幂等的 campfire 路标块,保留标记外内容;`CAMPFIRE_AGENT_HINT_PATH` 可覆盖目标。`setup` 与 `skill sync` 会把托管 Skill 同步到 `~/.claude/skills`、`~/.agents/skills`,可通过 `CAMPFIRE_SKILL_TARGETS` 覆盖。单独执行 `skill sync` 不更新提示词路标。
49
49
 
50
50
  ## 核心概念
51
51
 
@@ -69,7 +69,7 @@ Workspace ── Space ── Domain 树 ── 文档
69
69
 
70
70
  ```bash
71
71
  campfire tree # 完整命令树
72
- campfire workspace resolve # Agent 冷启动第一步:解析当前 Workspace
72
+ campfire workspace resolve # Workspace 不明确时解析
73
73
  campfire workspace list / show / export / import # 注册库管理与备份
74
74
  campfire workspace project resolve # 当前目录属于哪个已注册项目
75
75
 
@@ -78,7 +78,7 @@ campfire maintenance sync [--dry-run] [--scope] # 刷新 MOC 与相关文档页
78
78
 
79
79
  campfire document inspect / check / format # 单篇文档查看、校验、格式化
80
80
  campfire document list # 精确枚举和筛选受管文档
81
- campfire document apply / move # 创建更新、类型转换、跨 Domain 移动
81
+ campfire document apply / move / rename # 结构写入、跨 Domain 移动、原地改名
82
82
  campfire document profile list / show / resolve # Frontmatter Profile 规则
83
83
  campfire document type list # 文档类型与前缀
84
84
  campfire base list / show / check / sync # Obsidian Base 治理视图
@@ -130,7 +130,9 @@ campfire workspace restructure verify --batch move-001
130
130
 
131
131
  ## Agent 协作
132
132
 
133
- 全局 Skill(`campfire skill list` 查看托管清单,`campfire skill sync` 手动同步)定义了 Agent 的标准工作流:已给出唯一文件路径的正文读取或小改直接使用文件工具;新建文档、修改 Frontmatter/类型/归属或执行结构治理时才加载 bootstrap,并使用 `document apply/move` 等原子命令。`document apply --path` 创建或唯一更新时可省略 `.md`,创建时也可省略类型前缀。Frontmatter 契约已知时直接 apply;现有文档的字段类型或合法值未知时只执行一次 `document inspect` 后 apply。批量结构调整用 `workspace restructure`;归档在用户明确同意后通过 `document apply --set document_status=archived` 执行。关键歧义进入 `human-request`,不由 Agent 擅自决定。
133
+ 全局 Skill 定义 Agent 的文档工作流:已知路径的人工正文直接 Edit;新建文档先 apply 创建结构,再按返回的 `target` 补正文。只在治理上下文缺失时加载 bootstrap;字段契约未知时,新建查一次目标 Profile,更新查一次 inspect。已明确的信息不重复查询,用户已有授权不重复询问。文档相对路径以 Workspace 根目录为基准,不随 cwd 改变;创建时可省略类型前缀与 `.md`。改标题用 rename,跨 Domain 移动用 move,完成后仅执行实际 follow_up。归档仍需用户对具体文档明确同意,关键歧义不得自行猜测。
134
+
135
+ 仓库 Skill 编写规范见 `src/campfire_cli/resources/skills/SPEC.md`。本地与 CI 共用 `uv run python scripts/quality_check.py`;发布前使用 `--release` 增加构建、wheel 隔离安装与冒烟验证。测试日志包含最慢 10 项耗时。Release 的公共 PyPI 安装验证最多等待 3 分钟、间隔 15 秒重试,不重试上传;安装后版本不符直接失败。
134
136
 
135
137
  ## 许可
136
138
 
@@ -31,6 +31,7 @@ SQLite / Filesystem Implementation
31
31
  - Frontmatter Profile 只允许一层 `base` 配置继承;Profile Loader 编译完整规则,Validator 与 Formatter 共用同一个 EffectiveProfile。
32
32
  - 公共接口不得依赖调用方猜测未声明契约。参数类型与复杂输入格式必须能从当前命令帮助获得;错误必须同时提供稳定机器字段和可操作的修复信息,但不得为此复制 Profile 枚举或新增平行命令。
33
33
  - `tree` 只用于未知能力发现,不是 Agent 执行已知文档操作的固定前置步骤;Skill 必须把已知正文编辑、契约已知的 Frontmatter 写入和契约未知的 `inspect → apply` 分流清楚。
34
+ - Skill 的最短路径不得省略写入门禁;门禁表达必要前提,不强制重复查询或审批。编写与验收要求统一维护在 `src/campfire_cli/resources/skills/SPEC.md`,运行步骤放对应 Skill。
34
35
  - 命令不得读取“最近一次操作”等隐式 Session 状态推导对象或作用域;跨命令后续动作只使用当前结果显式返回的结构化 `follow_up`。
35
36
  - 所有写入默认预检,语义计划默认未审批。
36
37
  - 写入用例必须在治理锁内复核生成计划时的内容哈希,发现外部变化时拒绝覆盖。
@@ -41,7 +42,7 @@ SQLite / Filesystem Implementation
41
42
  ## CLI 输出契约
42
43
 
43
44
  - 正常输出 indent JSON;错误输出单行 JSON 并写 stderr,退出码非 0。
44
- - `status` 字段是 Agent 依赖的公共契约,只允许复用既有词汇,不得发明近义词。命令级词汇:ok、error、blocked、needs-input、needs-review、dry-run、synced、planned、ready、applied、issues-found、formatted、archived、up-to-date。文档、领域与 Decision 各有自己的字段词汇表。需要新状态先在本节登记。
45
+ - `status` 字段是 Agent 依赖的公共契约,只允许复用既有词汇,不得发明近义词。命令级词汇:ok、error、blocked、needs-input、needs-review、dry-run、synced、planned、ready、applied、moved、renamed、issues-found、formatted、archived、up-to-date。文档、领域与 Decision 各有自己的字段词汇表。需要新状态先在本节登记。
45
46
  - 可恢复的输入错误必须包含稳定 `code`、对应字段和机器可读的期望类型;当正确序列化方式不直观时,同时返回示例值或修复提示。自然语言 message 与示例可以演进,不作为调用方分支判断依据。
46
47
  - 前置条件缺失时优先降级执行:能完成的部分照常完成,输出 `needs-input` 并以 `skipped` 字段显式列出被跳过的步骤,而非整体报错退出。
47
48
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "campfire-cli"
3
- version = "0.1.16"
3
+ version = "0.1.18"
4
4
  description = "Local-first shared context and governance CLI for humans and agents"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -0,0 +1,67 @@
1
+ """SPEC:
2
+ name: pypi_verify
3
+ purpose: 有限等待公共 PyPI 安装可用,并验证已发布版本
4
+ idempotent: true
5
+ side_effects:
6
+ - 在临时虚拟环境安装已发布的包,不构建或上传产物
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import os
13
+ import subprocess
14
+ import tempfile
15
+ import time
16
+ from pathlib import Path
17
+
18
+
19
+ def verify(version: str, environment: Path) -> None:
20
+ """Retry installation for at most three minutes; never retry a version mismatch."""
21
+ subprocess.run(["uv", "venv", str(environment)], check=True)
22
+ bin_dir = environment / ("Scripts" if os.name == "nt" else "bin")
23
+ python = bin_dir / ("python.exe" if os.name == "nt" else "python")
24
+ campfire = bin_dir / ("campfire.exe" if os.name == "nt" else "campfire")
25
+ command = [
26
+ "uv",
27
+ "pip",
28
+ "install",
29
+ "--python",
30
+ str(python),
31
+ "--refresh",
32
+ "--index-url",
33
+ "https://pypi.org/simple",
34
+ f"campfire-cli=={version}",
35
+ ]
36
+ deadline = time.monotonic() + 180
37
+ while True:
38
+ try:
39
+ subprocess.run(command, check=True, timeout=max(0.001, deadline - time.monotonic()))
40
+ break
41
+ except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
42
+ remaining = deadline - time.monotonic()
43
+ if remaining <= 15:
44
+ raise
45
+ print("PyPI installation unavailable; retrying in 15 seconds", flush=True)
46
+ time.sleep(15)
47
+ installed = subprocess.run(
48
+ [str(campfire), "version"],
49
+ check=True,
50
+ capture_output=True,
51
+ text=True,
52
+ timeout=30,
53
+ ).stdout.strip()
54
+ if installed != version:
55
+ raise SystemExit(f"installed version {installed} does not match {version}")
56
+
57
+
58
+ def main() -> None:
59
+ parser = argparse.ArgumentParser()
60
+ parser.add_argument("version")
61
+ args = parser.parse_args()
62
+ with tempfile.TemporaryDirectory(prefix="campfire-pypi-") as directory:
63
+ verify(args.version, Path(directory) / "venv")
64
+
65
+
66
+ if __name__ == "__main__":
67
+ main()
@@ -103,7 +103,7 @@ def main() -> None:
103
103
  if arguments.artifact_dir is not None and not arguments.release:
104
104
  parser.error("--artifact-dir 只能与 --release 一起使用")
105
105
  run("uv", "run", "ruff", "check", "src", "tests", "scripts")
106
- run("uv", "run", "pytest", "-q")
106
+ run("uv", "run", "pytest", "-q", "--durations=10")
107
107
  if arguments.release:
108
108
  version = project_version()
109
109
  check_tag(version)
@@ -1,3 +1,3 @@
1
1
  """Campfire CLI package."""
2
2
 
3
- __version__ = "0.1.16"
3
+ __version__ = "0.1.18"
@@ -1,4 +1,5 @@
1
1
  from collections.abc import Iterable
2
+ from os import PathLike
2
3
  from pathlib import PurePosixPath
3
4
  from typing import Literal
4
5
 
@@ -13,10 +14,13 @@ class CommandFollowUp(BaseModel):
13
14
  scope: str
14
15
 
15
16
 
16
- def maintenance_sync_follow_up(workspace: str, scopes: Iterable[str]) -> list[CommandFollowUp]:
17
+ def maintenance_sync_follow_up(
18
+ workspace: str, scopes: Iterable[str | PathLike[str]]
19
+ ) -> list[CommandFollowUp]:
17
20
  """Build one sync follow-up at the smallest scope containing all changes."""
18
21
 
19
- paths = [PurePosixPath(scope.strip("/")) for scope in dict.fromkeys(scopes) if scope]
22
+ normalized = (str(scope).replace("\\", "/").strip("/") for scope in scopes if scope)
23
+ paths = [PurePosixPath(scope) for scope in dict.fromkeys(normalized)]
20
24
  if not paths:
21
25
  return []
22
26
  common = list(paths[0].parts)
@@ -46,7 +46,8 @@ document/
46
46
  - `inspect`:向 Agent 返回单篇文档的 Domain、类型、有效 Profile、具体问题,以及 declared、outgoing、incoming、unresolved 四类确定关系。
47
47
  - `apply`:根据目标路径和类型解析 Profile,不存在时生成文档,已有 Frontmatter 时只应用显式补丁,无 Frontmatter 时保留正文并补齐完整契约;先完整渲染并校验,追加 `--confirm` 后原子写入。
48
48
  - `template`:只继承 base Profile,必须位于所属 Domain 的 `_模板/`;Domain 归属由物理路径解析,不在 Frontmatter 复制模板作用域或继承关系。
49
- - `move`:在任意已声明 Domain 之间移动或改名一篇文档,按目标 Profile 对齐可确定的 `domain`/`project` 归属,并更新可确定解析的 Wiki、Markdown 和路径引用。目标 Profile 缺少业务字段时返回 `needs-input`,不猜测。
49
+ - `move`:在任意已声明 Domain 之间移动一篇文档,按目标 Profile 对齐可确定的 `domain`/`project` 归属,并更新可确定解析的 Wiki、Markdown 和路径引用。目标 Profile 缺少业务字段时返回 `needs-input`,不猜测。
50
+ - `rename`:保持一篇文档的物理目录与 Domain 归属不变,根据逻辑标题重算类型前缀文件名,并在同一变更集中更新 `name` 与可确定引用。目标存在时阻止,不覆盖或自动编号。
50
51
  - `scanner`:统一解释受管根、忽略目录和豁免文件;Document 与 Maintenance 共用。
51
52
 
52
53
  Document Service 可以被 Workspace Restructure 编排,但不得反向依赖 Maintenance。批量计划文件、运行记录、MOC、Base、归档和重构批次不属于 Document App。
@@ -67,6 +68,8 @@ Document 写入接口不得要求 Agent 猜测 Frontmatter 输入契约:
67
68
  - Document App 解析一次目标 EffectiveProfile,并由 apply 与 move 共用的值解码器转换补丁:enum、string 和 date 保留原始字符串,boolean 只接受明确的 `true` 或 `false`,list 只接受严格 JSON 数组。
68
69
  - Profile 与 Rule Service 继续拥有字段类型、合法值和业务校验,不保存命令行字符串。命令帮助负责 Shell 展示方式,并为列表值给出 `--set 'tags=["tag1","tag2"]'` 形式的最小例子。
69
70
  - 输入错误统一返回稳定错误码、字段、实际值、期望类型和可直接照抄的参数示例;apply 与 move 不得分别构造两套解码或诊断。
71
+ - apply 在 Profile 已明确时并列收集可确定的禁用字段、缺失字段与类型错误;无效赋值不再重复报同字段缺失。有错误不写入且 follow-up 为空;只有缺失输入时返回 needs-input,含其他问题时返回 blocked 并保留 missing_fields。
72
+ - 文档相对路径始终以 Workspace 根解析,不受 cwd 影响;apply 的 domain-missing 返回实际解析路径和带 Workspace 的领域发现入口,不默认枚举全量候选。
70
73
  - 不因输入格式不直观而增加 `--tags`、`--sources` 等字段专用参数,也不把逗号字符串静默猜成列表。
71
74
  - 现有文档的有效 Profile 已由 `document inspect` 返回。Skill 只在字段契约未知时安排一次 `inspect → apply`;契约已知的补丁直接 apply,正文小改不进入本接口。
72
75
 
@@ -21,6 +21,7 @@ SET_OPTION_HELP = (
21
21
  "值类型由有效 Profile 决定;列表使用严格 JSON,例如 "
22
22
  '--set \'tags=["tag1","tag2"]\'。'
23
23
  )
24
+ PATH_OPTION_HELP = "Workspace 根目录相对路径(不是 cwd 相对路径),或 Workspace 内绝对路径"
24
25
 
25
26
 
26
27
  def service(ctx: typer.Context) -> DocumentService:
@@ -31,19 +32,25 @@ def service(ctx: typer.Context) -> DocumentService:
31
32
 
32
33
 
33
34
  @document_cli.command("check")
34
- def check(ctx: typer.Context, path: str = typer.Option(..., "--path")) -> None:
35
+ def check(
36
+ ctx: typer.Context, path: str = typer.Option(..., "--path", help=PATH_OPTION_HELP)
37
+ ) -> None:
35
38
  """检查一篇 Markdown 文档是否符合当前类型与 Profile 契约。"""
36
39
  emit(invoke(lambda: service(ctx).check(path)))
37
40
 
38
41
 
39
42
  @document_cli.command("kanban-check")
40
- def kanban_check(ctx: typer.Context, path: str = typer.Option(..., "--path")) -> None:
43
+ def kanban_check(
44
+ ctx: typer.Context, path: str = typer.Option(..., "--path", help=PATH_OPTION_HELP)
45
+ ) -> None:
41
46
  """检查文档是否满足 Obsidian Kanban 插件的渲染契约。"""
42
47
  emit(invoke(lambda: service(ctx).kanban_check(path)))
43
48
 
44
49
 
45
50
  @document_cli.command("inspect")
46
- def inspect(ctx: typer.Context, path: str = typer.Option(..., "--path")) -> None:
51
+ def inspect(
52
+ ctx: typer.Context, path: str = typer.Option(..., "--path", help=PATH_OPTION_HELP)
53
+ ) -> None:
47
54
  """返回单篇文档的 Profile、领域、确定关系和问题上下文。
48
55
 
49
56
  示例:campfire document inspect --path "mywork/项目/记录-进展.md"
@@ -62,22 +69,24 @@ def list_documents(
62
69
  limit: int | None = typer.Option(None, "--limit", min=1),
63
70
  ) -> None:
64
71
  """按 Project、Domain、类型与状态列出受管内容文档。"""
65
- emit(invoke(
66
- lambda: service(ctx).list(
67
- project=project,
68
- domain=domain,
69
- document_type=document_type,
70
- document_status=document_status,
71
- task_status=task_status,
72
- limit=limit,
72
+ emit(
73
+ invoke(
74
+ lambda: service(ctx).list(
75
+ project=project,
76
+ domain=domain,
77
+ document_type=document_type,
78
+ document_status=document_status,
79
+ task_status=task_status,
80
+ limit=limit,
81
+ )
73
82
  )
74
- ))
83
+ )
75
84
 
76
85
 
77
86
  @document_cli.command("format")
78
87
  def format_document(
79
88
  ctx: typer.Context,
80
- path: str = typer.Option(..., "--path", help="现有 Markdown 文档路径"),
89
+ path: str = typer.Option(..., "--path", help=PATH_OPTION_HELP),
81
90
  confirm: bool = typer.Option(False, "--confirm"),
82
91
  ) -> None:
83
92
  """预览或执行一篇文档的 Frontmatter 字段排序。"""
@@ -112,7 +121,7 @@ def apply_document(
112
121
  path: str = typer.Option(
113
122
  ...,
114
123
  "--path",
115
- help="目标 Markdown 路径;创建或唯一更新时可省略 .md,类型前缀可省略",
124
+ help=PATH_OPTION_HELP + ";创建或唯一更新时可省略 .md,创建时可省略类型前缀",
116
125
  ),
117
126
  document_type: str | None = typer.Option(None, "--type"),
118
127
  set_values: list[str] | None = typer.Option(None, "--set", help=SET_OPTION_HELP),
@@ -128,23 +137,25 @@ def apply_document(
128
137
  已有文档的 --type 发生变化时,同一原子操作同步文件名和引用。
129
138
  """
130
139
  values = invoke(lambda: parse_values(set_values or []))
131
- emit(invoke(
132
- lambda: service(ctx).apply(
133
- DocumentApplyRequest(
134
- path=path,
135
- document_type=document_type,
136
- values=values,
137
- expected_hash=expected_hash,
138
- confirm=confirm,
140
+ emit(
141
+ invoke(
142
+ lambda: service(ctx).apply(
143
+ DocumentApplyRequest(
144
+ path=path,
145
+ document_type=document_type,
146
+ values=values,
147
+ expected_hash=expected_hash,
148
+ confirm=confirm,
149
+ )
139
150
  )
140
151
  )
141
- ))
152
+ )
142
153
 
143
154
 
144
155
  @document_cli.command("move")
145
156
  def move_document(
146
157
  ctx: typer.Context,
147
- source: str = typer.Option(..., "--path", help="源文档的 Workspace 相对路径"),
158
+ source: str = typer.Option(..., "--path", help=PATH_OPTION_HELP),
148
159
  target_domain: str = typer.Option(..., "--domain", help="目标 Domain 的稳定 id"),
149
160
  name: str | None = typer.Option(None, "--name", help="可选的新文件名;省略时保持原文件名"),
150
161
  set_values: list[str] | None = typer.Option(None, "--set", help=SET_OPTION_HELP),
@@ -154,14 +165,37 @@ def move_document(
154
165
  ) -> None:
155
166
  """预览或移动一篇文档,并按目标 Domain 契约更新归属与引用。"""
156
167
  values = invoke(lambda: parse_values(set_values or []))
157
- emit(invoke(
158
- lambda: service(ctx).move(
159
- source,
160
- target_domain,
161
- name=name,
162
- values=values,
163
- unset_fields=tuple(unset_fields or []),
164
- expected_hash=expected_hash,
165
- confirm=confirm,
168
+ emit(
169
+ invoke(
170
+ lambda: service(ctx).move(
171
+ source,
172
+ target_domain,
173
+ name=name,
174
+ values=values,
175
+ unset_fields=tuple(unset_fields or []),
176
+ expected_hash=expected_hash,
177
+ confirm=confirm,
178
+ )
179
+ )
180
+ )
181
+
182
+
183
+ @document_cli.command("rename")
184
+ def rename_document(
185
+ ctx: typer.Context,
186
+ source: str = typer.Option(..., "--path", help=PATH_OPTION_HELP),
187
+ name: str = typer.Option(..., "--name", help="新标题;不含类型前缀和 .md 后缀"),
188
+ expected_hash: str | None = typer.Option(None, "--expected-hash"),
189
+ confirm: bool = typer.Option(False, "--confirm"),
190
+ ) -> None:
191
+ """预览或原地改名一篇文档,并同步标题、文件名与受管引用。"""
192
+ emit(
193
+ invoke(
194
+ lambda: service(ctx).rename(
195
+ source,
196
+ name,
197
+ expected_hash=expected_hash,
198
+ confirm=confirm,
199
+ )
166
200
  )
167
- ))
201
+ )
@@ -34,7 +34,7 @@ class DocumentApplyResult(BaseModel):
34
34
 
35
35
 
36
36
  class DocumentMoveResult(BaseModel):
37
- status: Literal["ready", "needs-input", "blocked", "moved"]
37
+ status: Literal["ready", "needs-input", "blocked", "moved", "renamed", "up-to-date"]
38
38
  workspace_id: str
39
39
  source: str
40
40
  target: str
@@ -97,9 +97,13 @@ class DocumentApplyService:
97
97
  else source
98
98
  )
99
99
  target_name = target.relative_to(self._settings.vault_root).as_posix()
100
- context = None if is_system_scope_path(
101
- self._settings.vault_root, target, self._settings.document_types
102
- ) else self._domain_context(target)
100
+ context = (
101
+ None
102
+ if is_system_scope_path(
103
+ self._settings.vault_root, target, self._settings.document_types
104
+ )
105
+ else self._domain_context(target)
106
+ )
103
107
  relative_target = target.relative_to(self._settings.vault_root).as_posix()
104
108
  if document_type == "human-request" and not relative_target.startswith(
105
109
  f"{self._settings.governance['human_request_root']}/"
@@ -131,40 +135,22 @@ class DocumentApplyService:
131
135
  frontmatter.pop(field, None)
132
136
  actual_hash = file_sha256(source) if exists else "missing"
133
137
  unknown = sorted(set(request.values) - set(profile.allowed))
134
- if unknown:
135
- return self._result(
136
- request,
137
- target_name,
138
- action,
139
- profile.name,
140
- actual_hash,
141
- "blocked",
142
- [
143
- {
144
- "code": "frontmatter-field-not-allowed",
145
- "path": request.path,
146
- "field": key,
147
- }
148
- for key in unknown
149
- ],
150
- )
151
-
138
+ candidates = workspace_candidate_sets(self._settings.vault_root)
152
139
  values, input_issues = decode_patch_values(
153
140
  profile,
154
- request.values,
141
+ {key: value for key, value in request.values.items() if key in profile.allowed},
155
142
  request.path,
156
- workspace_candidate_sets(self._settings.vault_root),
143
+ candidates,
157
144
  )
158
- if input_issues:
159
- return self._result(
160
- request,
161
- target_name,
162
- action,
163
- profile.name,
164
- actual_hash,
165
- "blocked",
166
- input_issues,
167
- )
145
+ input_issues[:0] = [
146
+ {
147
+ "code": "frontmatter-field-not-allowed",
148
+ "path": request.path,
149
+ "field": key,
150
+ "allowed": list(profile.allowed),
151
+ }
152
+ for key in unknown
153
+ ]
168
154
  # Field semantics are fully declared by the selected Profile; no type-specific injection.
169
155
  frontmatter.update(values)
170
156
  frontmatter["type"] = document_type
@@ -195,12 +181,22 @@ class DocumentApplyService:
195
181
  else:
196
182
  rendered = render_document(frontmatter, next_body, list(profile.field_order))
197
183
  issues = self._rules.check_content(self._settings.vault_root, target, rendered, profile)
184
+ # Rejected assignments already have a precise diagnostic; their fallback values
185
+ # must not produce contradictory missing-field or value errors.
186
+ invalid_fields = {item["field"] for item in input_issues}
187
+ issues = input_issues + [item for item in issues if item.get("field") not in invalid_fields]
198
188
  if target != source and target.exists():
199
189
  issues.insert(0, {"code": "target-exists", "path": target_name})
200
- enrich_profile_issues(issues, profile, workspace_candidate_sets(self._settings.vault_root))
190
+ enrich_profile_issues(issues, profile, candidates)
201
191
  missing_codes = {"frontmatter-field-missing", "frontmatter-field-empty"}
202
192
  missing = [item for item in issues if item["code"] in missing_codes]
203
- status = "needs-input" if missing else "blocked" if issues else "planned"
193
+ status = (
194
+ "blocked"
195
+ if any(item["code"] not in missing_codes for item in issues)
196
+ else "needs-input"
197
+ if missing
198
+ else "planned"
199
+ )
204
200
  result = self._result(
205
201
  request,
206
202
  target_name,
@@ -354,4 +350,17 @@ class DocumentApplyService:
354
350
  self._settings.governance.get("domain_marker", "_领域.md"),
355
351
  )
356
352
  except DomainContextError as exc:
357
- raise exc
353
+ if exc.code == "domain-missing":
354
+ exc.details.update(
355
+ resolved_path=str(path),
356
+ path_base="workspace",
357
+ workspace_root=str(self._settings.vault_root),
358
+ hint=(
359
+ "相对路径以 Workspace 根目录为基准,而不是 cwd;请先选择已声明的 Domain。"
360
+ ),
361
+ next_action={
362
+ "command": "workspace domain list",
363
+ "arguments": {"workspace": self._settings.workspace_id},
364
+ },
365
+ )
366
+ raise