campfire-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- campfire_cli/__init__.py +3 -0
- campfire_cli/alembic/__init__.py +1 -0
- campfire_cli/alembic/env.py +37 -0
- campfire_cli/alembic/script.py.mako +22 -0
- campfire_cli/alembic/versions/001_initial_schema.py +81 -0
- campfire_cli/alembic/versions/002_workspace_project_registry.py +47 -0
- campfire_cli/alembic/versions/003_unified_workspace_state.py +113 -0
- campfire_cli/alembic/versions/004_restructure_workspace_domain.py +23 -0
- campfire_cli/alembic/versions/005_decision_channel.py +71 -0
- campfire_cli/alembic/versions/006_workspace_topology_index.py +61 -0
- campfire_cli/alembic/versions/007_workspace_adoption.py +38 -0
- campfire_cli/alembic/versions/__init__.py +1 -0
- campfire_cli/app/SPEC.md +12 -0
- campfire_cli/app/__init__.py +1 -0
- campfire_cli/app/base/SPEC.md +3 -0
- campfire_cli/app/base/__init__.py +1 -0
- campfire_cli/app/base/cli/base_cli.py +37 -0
- campfire_cli/app/base/repository/base_repository.py +17 -0
- campfire_cli/app/base/schema/base_schema.py +18 -0
- campfire_cli/app/base/service/base_service.py +129 -0
- campfire_cli/app/decision/SPEC.md +16 -0
- campfire_cli/app/decision/__init__.py +1 -0
- campfire_cli/app/decision/cli/decision_cli.py +112 -0
- campfire_cli/app/decision/repository/decision_repository.py +199 -0
- campfire_cli/app/decision/schema/decision_schema.py +56 -0
- campfire_cli/app/decision/service/decision_projection_service.py +151 -0
- campfire_cli/app/decision/service/decision_service.py +124 -0
- campfire_cli/app/document/SPEC.md +51 -0
- campfire_cli/app/document/__init__.py +1 -0
- campfire_cli/app/document/cli/__init__.py +1 -0
- campfire_cli/app/document/cli/document_cli.py +63 -0
- campfire_cli/app/document/cli/profile_cli.py +65 -0
- campfire_cli/app/document/cli/type_cli.py +49 -0
- campfire_cli/app/document/repository/__init__.py +1 -0
- campfire_cli/app/document/repository/document_profile_repository.py +17 -0
- campfire_cli/app/document/repository/document_type_repository.py +17 -0
- campfire_cli/app/document/service/__init__.py +1 -0
- campfire_cli/app/document/service/document_profile_service.py +66 -0
- campfire_cli/app/document/service/document_rule_service.py +316 -0
- campfire_cli/app/document/service/document_scanner.py +38 -0
- campfire_cli/app/document/service/document_service.py +139 -0
- campfire_cli/app/document/service/document_type_service.py +28 -0
- campfire_cli/app/document/service/frontmatter_apply.py +98 -0
- campfire_cli/app/document/service/frontmatter_formatter.py +104 -0
- campfire_cli/app/document/service/frontmatter_plan.py +75 -0
- campfire_cli/app/document/service/profile_registry.py +166 -0
- campfire_cli/app/document/service/type_apply.py +185 -0
- campfire_cli/app/document/service/type_plan.py +80 -0
- campfire_cli/app/maintenance/SPEC.md +22 -0
- campfire_cli/app/maintenance/__init__.py +1 -0
- campfire_cli/app/maintenance/cli/maintenance_cli.py +103 -0
- campfire_cli/app/maintenance/repository/maintenance_repository.py +115 -0
- campfire_cli/app/maintenance/schema/maintenance_schema.py +109 -0
- campfire_cli/app/maintenance/service/archive_service.py +255 -0
- campfire_cli/app/maintenance/service/link_service.py +91 -0
- campfire_cli/app/maintenance/service/maintenance_protocol.py +25 -0
- campfire_cli/app/maintenance/service/maintenance_service.py +461 -0
- campfire_cli/app/maintenance/service/moc_service.py +310 -0
- campfire_cli/app/maintenance/service/plan_service.py +411 -0
- campfire_cli/app/skill/SPEC.md +3 -0
- campfire_cli/app/skill/__init__.py +1 -0
- campfire_cli/app/skill/cli/skill_cli.py +44 -0
- campfire_cli/app/skill/repository/skill_repository.py +33 -0
- campfire_cli/app/skill/schema/skill_schema.py +18 -0
- campfire_cli/app/skill/service/skill_service.py +146 -0
- campfire_cli/app/workspace/SPEC.md +25 -0
- campfire_cli/app/workspace/__init__.py +1 -0
- campfire_cli/app/workspace/cli/__init__.py +1 -0
- campfire_cli/app/workspace/cli/adoption_cli.py +83 -0
- campfire_cli/app/workspace/cli/config_cli.py +30 -0
- campfire_cli/app/workspace/cli/domain_cli.py +101 -0
- campfire_cli/app/workspace/cli/project_cli.py +135 -0
- campfire_cli/app/workspace/cli/restructure_cli.py +133 -0
- campfire_cli/app/workspace/cli/space_cli.py +65 -0
- campfire_cli/app/workspace/cli/workspace_cli.py +145 -0
- campfire_cli/app/workspace/repository/__init__.py +1 -0
- campfire_cli/app/workspace/repository/adoption_repository.py +55 -0
- campfire_cli/app/workspace/repository/manifest_repository.py +38 -0
- campfire_cli/app/workspace/repository/restructure_repository.py +93 -0
- campfire_cli/app/workspace/repository/workspace_repository.py +125 -0
- campfire_cli/app/workspace/schema/__init__.py +1 -0
- campfire_cli/app/workspace/schema/adoption_schema.py +47 -0
- campfire_cli/app/workspace/schema/restructure_schema.py +64 -0
- campfire_cli/app/workspace/schema/workspace_schema.py +225 -0
- campfire_cli/app/workspace/service/__init__.py +1 -0
- campfire_cli/app/workspace/service/adoption_protocol.py +11 -0
- campfire_cli/app/workspace/service/adoption_service.py +364 -0
- campfire_cli/app/workspace/service/config_service.py +189 -0
- campfire_cli/app/workspace/service/domain_restructure_service.py +316 -0
- campfire_cli/app/workspace/service/project_service.py +389 -0
- campfire_cli/app/workspace/service/restructure_protocol.py +19 -0
- campfire_cli/app/workspace/service/restructure_service.py +392 -0
- campfire_cli/app/workspace/service/restructure_verifier.py +83 -0
- campfire_cli/app/workspace/service/structure_service.py +494 -0
- campfire_cli/app/workspace/service/workspace_protocol.py +24 -0
- campfire_cli/app/workspace/service/workspace_service.py +304 -0
- campfire_cli/common/SPEC.md +12 -0
- campfire_cli/common/__init__.py +1 -0
- campfire_cli/common/database/__init__.py +4 -0
- campfire_cli/common/database/migrations.py +18 -0
- campfire_cli/common/database/models.py +215 -0
- campfire_cli/common/database/session.py +30 -0
- campfire_cli/common/documents/__init__.py +1 -0
- campfire_cli/common/documents/document_types.py +119 -0
- campfire_cli/common/documents/frontmatter_schema.py +42 -0
- campfire_cli/common/documents/markdown.py +66 -0
- campfire_cli/common/exceptions/__init__.py +7 -0
- campfire_cli/common/exceptions/base.py +19 -0
- campfire_cli/common/filesystem/__init__.py +6 -0
- campfire_cli/common/filesystem/atomic.py +30 -0
- campfire_cli/common/filesystem/locking.py +55 -0
- campfire_cli/common/governance/__init__.py +13 -0
- campfire_cli/common/governance/issues.py +38 -0
- campfire_cli/common/governance/locking.py +31 -0
- campfire_cli/common/governance/snapshots.py +26 -0
- campfire_cli/common/hashing.py +10 -0
- campfire_cli/common/reports/__init__.py +1 -0
- campfire_cli/common/reports/json_report.py +8 -0
- campfire_cli/common/reports/markdown_report.py +29 -0
- campfire_cli/config/SPEC.md +5 -0
- campfire_cli/config/defaults.py +64 -0
- campfire_cli/config/settings.py +50 -0
- campfire_cli/container.py +130 -0
- campfire_cli/main.py +133 -0
- campfire_cli/resources/__init__.py +1 -0
- campfire_cli/resources/bases/Agent/346/211/247/350/241/214/345/267/245/344/275/234/345/217/260.base +35 -0
- campfire_cli/resources/bases/SPEC.md +3 -0
- campfire_cli/resources/bases//344/273/273/345/212/241/345/267/245/344/275/234/345/217/260.base +49 -0
- campfire_cli/resources/bases//345/206/263/347/255/226/345/267/245/344/275/234/345/217/260.base +40 -0
- campfire_cli/resources/bases//345/276/205/345/275/222/346/241/243/346/226/207/346/241/243.base +28 -0
- campfire_cli/resources/bases//351/241/271/347/233/256/346/226/207/346/241/243.base +35 -0
- campfire_cli/resources/defaults/__init__.py +1 -0
- campfire_cli/resources/defaults/config.yml +458 -0
- campfire_cli/resources/skills/SPEC.md +3 -0
- campfire_cli/resources/skills/campfire-context-bootstrap/SKILL.md +62 -0
- campfire_cli/resources/skills/campfire-context-bootstrap/agents/openai.yaml +3 -0
- campfire_cli/resources/skills/campfire-conversation-router/SKILL.md +53 -0
- campfire_cli/resources/skills/campfire-conversation-router/agents/openai.yaml +3 -0
- campfire_cli/resources/skills/campfire-conversation-router/references/inbox-handoff.md +19 -0
- campfire_cli/resources/skills/campfire-conversation-router/references/learning-intake.md +31 -0
- campfire_cli/resources/skills/campfire-conversation-router/references/task-intake.md +28 -0
- campfire_cli/resources/skills/campfire-document-capture/SKILL.md +109 -0
- campfire_cli/resources/skills/campfire-inbox-triage/SKILL.md +23 -0
- campfire_cli/resources/skills/campfire-weekly-report-writing/SKILL.md +21 -0
- campfire_cli/resources/skills/campfire-weekly-report-writing/agents/openai.yaml +3 -0
- campfire_cli/resources/skills/campfire-workspace-adoption/SKILL.md +42 -0
- campfire_cli/resources/skills/campfire-workspace-maintenance/SKILL.md +74 -0
- 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 +23 -0
- campfire_cli/resources/skills/campfire-workspace-restructure/SKILL.md +52 -0
- campfire_cli-0.1.0.dist-info/METADATA +141 -0
- campfire_cli-0.1.0.dist-info/RECORD +154 -0
- campfire_cli-0.1.0.dist-info/WHEEL +4 -0
- campfire_cli-0.1.0.dist-info/entry_points.txt +2 -0
- campfire_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Workspace App SPEC
|
|
2
|
+
|
|
3
|
+
本模块管理 Workspace、Space、Domain、Project 注册表和 Workspace 初始化。Workspace id 与 Project id 是本机治理状态的稳定键;路径只是可变定位信息。用户级 `CAMPFIRE_HOME/campfire.db` 是唯一数据库,保存注册数据、文档索引和工作流状态;每个 Workspace 只保留配置与人类可审阅的运行产物,不再拥有独立数据库。所有工具状态均位于 `CAMPFIRE_HOME`,不得向目标 Workspace 创建工具状态目录。
|
|
4
|
+
|
|
5
|
+
解析优先级为显式 `--workspace`、当前目录所属的已注册 Workspace、默认 Workspace。写操作仍由具体业务模块执行。
|
|
6
|
+
|
|
7
|
+
`workspace add` 只接入已存在目录;`workspace create` 要求目标路径不存在,并创建全局收件箱、带 `_空间.md` 的知识/工作 Space 和治理视图基础目录。两者写入全局 SQLite 注册表,不向 Workspace 写工具状态。
|
|
8
|
+
|
|
9
|
+
`workspace space/domain create` 只创建不存在的新目录;对应的 `adopt` 原地纳管已有目录,只新增 `_空间.md`,或 `_领域.md` 和声明的 MOC,不移动、改名或删除已有内容。两者默认只输出计划,追加 `--confirm` 才写入。
|
|
10
|
+
|
|
11
|
+
`workspace config check` 统一校验包内产品默认值和当前 Workspace 的有效治理契约,包括目录与 Space 冲突、文档类型前缀、Profile 引用和继承、归档策略以及托管资源列表。
|
|
12
|
+
|
|
13
|
+
`workspace restructure` 负责一次性改变已有 Workspace 的物理结构:冻结范围、生成带内容哈希的审批计划、执行跨领域移动或改名、更新引用并验证迁移事实。纯移动不得重写文档内容;`verify` 只验证本批次 source/target 结果,文档格式合规由 Maintenance 独立检查。该能力属于 Workspace Service,不设独立 App,也不用于日常增量维护。
|
|
14
|
+
|
|
15
|
+
Space 是 Workspace 根下以 `_空间.md` 声明的顶级内容容器;Domain 位于 Space 内,以 `_领域.md` 声明并可任意嵌套。子 Domain 必须处于父 Domain 路径下、属于同一 Space 并继承 governance。`_收件箱` 与 `治理视图` 是系统区域,不是 Space。Maintenance 只消费本模块发现的结构,不维护第二套领域规则。
|
|
16
|
+
|
|
17
|
+
Space 与 Domain 声明文件只由本模块解释和校验;Document App 对其返回 `not-applicable`。`workspace space check --space <id>` 支持对单个 Space 做局部复检。
|
|
18
|
+
|
|
19
|
+
Project 是 Workspace 连接的外部工作资源,记录稳定 id、显示名称、文档领域、本地代码路径、Git remote、默认分支和生命周期状态。Project 业务代码归属本模块,对外使用 `campfire workspace project` 子命令。提供本地 Git 路径时可自动发现 remote 和分支;动态 Git 状态不写入注册表。
|
|
20
|
+
|
|
21
|
+
`project resolve` 只按规范化后的本地 Git 根目录和 remote 识别已注册 Project,不凭目录名称猜测;零匹配和多匹配都返回可判断状态。`project check` 只报告源码路径、remote、默认分支和文档领域的漂移,不自动更新稳定身份或归属。
|
|
22
|
+
|
|
23
|
+
`project create` 用于新 Project onboarding,默认只返回计划,追加 `--confirm` 后通过 Domain Service 创建工作 Space 内的项目根 Domain 并注册 Project。初始化不虚构业务子领域;已存在文档中心必须使用 `project add` 接入。
|
|
24
|
+
|
|
25
|
+
注册数据只通过 CLI 和 SQLite 维护。JSON 仅用于显式 export/import;import 默认只预检,必须使用 `--confirm` 才替换当前注册数据。不读取旧 JSON 注册表,不维护双事实源。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Registered Workspace management application."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Workspace CLI delivery adapter."""
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from campfire_cli.common.exceptions import AppError
|
|
9
|
+
from campfire_cli.container import AppContainer
|
|
10
|
+
|
|
11
|
+
adoption_cli = typer.Typer(
|
|
12
|
+
help="把已有文档文件夹安全接管为受管 Domain",
|
|
13
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def service(ctx: typer.Context):
|
|
18
|
+
return AppContainer.build(ctx.find_root().params.get("workspace")).adoption
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def invoke(operation) -> None:
|
|
22
|
+
try:
|
|
23
|
+
result = operation()
|
|
24
|
+
typer.echo(json.dumps(result.model_dump(mode="json"), ensure_ascii=False, indent=2))
|
|
25
|
+
except AppError as exc:
|
|
26
|
+
typer.echo(json.dumps({"status": "error", "message": str(exc)}, ensure_ascii=False))
|
|
27
|
+
raise typer.Exit(exc.exit_code) from exc
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@adoption_cli.command("inventory")
|
|
31
|
+
def inventory(
|
|
32
|
+
ctx: typer.Context,
|
|
33
|
+
source: Path = typer.Option(..., "--source"),
|
|
34
|
+
batch: str = typer.Option(..., "--batch"),
|
|
35
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
36
|
+
) -> None:
|
|
37
|
+
"""盘点目录;外部来源追加 --confirm 后复制到待接管暂存区。"""
|
|
38
|
+
invoke(lambda: service(ctx).inventory(batch, source, confirm))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@adoption_cli.command("plan")
|
|
42
|
+
def plan(
|
|
43
|
+
ctx: typer.Context,
|
|
44
|
+
batch: str = typer.Option(..., "--batch"),
|
|
45
|
+
target_path: str = typer.Option(..., "--target-path"),
|
|
46
|
+
domain_id: str = typer.Option(..., "--domain-id"),
|
|
47
|
+
name: str = typer.Option(..., "--name"),
|
|
48
|
+
space_id: str = typer.Option(..., "--space"),
|
|
49
|
+
domain_type: str = typer.Option(..., "--type"),
|
|
50
|
+
governance: str = typer.Option(..., "--governance"),
|
|
51
|
+
parent_domain: str | None = typer.Option(None, "--parent-domain"),
|
|
52
|
+
project_id: str | None = typer.Option(None, "--project"),
|
|
53
|
+
) -> None:
|
|
54
|
+
"""声明整个来源文件夹的目标 Domain,并生成接管计划。"""
|
|
55
|
+
invoke(
|
|
56
|
+
lambda: service(ctx).plan(
|
|
57
|
+
batch,
|
|
58
|
+
target_path=target_path,
|
|
59
|
+
domain_id=domain_id,
|
|
60
|
+
name=name,
|
|
61
|
+
space_id=space_id,
|
|
62
|
+
domain_type=domain_type,
|
|
63
|
+
governance=governance,
|
|
64
|
+
parent_domain=parent_domain,
|
|
65
|
+
project_id=project_id,
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@adoption_cli.command("apply")
|
|
71
|
+
def apply(
|
|
72
|
+
ctx: typer.Context,
|
|
73
|
+
batch: str = typer.Option(..., "--batch"),
|
|
74
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
75
|
+
) -> None:
|
|
76
|
+
"""预检接管计划;追加 --confirm 后移动到正式领域并建立声明。"""
|
|
77
|
+
invoke(lambda: service(ctx).apply(batch, confirm))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@adoption_cli.command("verify")
|
|
81
|
+
def verify(ctx: typer.Context, batch: str = typer.Option(..., "--batch")) -> None:
|
|
82
|
+
"""验证文件哈希、领域声明与最终位置。"""
|
|
83
|
+
invoke(lambda: service(ctx).verify(batch))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from campfire_cli.app.workspace.cli.workspace_cli import emit, invoke
|
|
8
|
+
from campfire_cli.app.workspace.repository.workspace_repository import SqliteWorkspaceRepository
|
|
9
|
+
from campfire_cli.app.workspace.service.config_service import WorkspaceConfigService
|
|
10
|
+
from campfire_cli.app.workspace.service.workspace_service import WorkspaceService
|
|
11
|
+
from campfire_cli.config.settings import WorkspaceSettings, campfire_home
|
|
12
|
+
|
|
13
|
+
config_cli = typer.Typer(
|
|
14
|
+
help="检查 Workspace 治理配置契约",
|
|
15
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def service(workspace: str | None) -> WorkspaceConfigService:
|
|
20
|
+
home = campfire_home()
|
|
21
|
+
resolved = WorkspaceService(home, SqliteWorkspaceRepository(home)).resolve(
|
|
22
|
+
workspace, Path.cwd()
|
|
23
|
+
)
|
|
24
|
+
settings = WorkspaceSettings.load(resolved.workspace_id, Path(resolved.workspace))
|
|
25
|
+
return WorkspaceConfigService(settings)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@config_cli.command("check")
|
|
29
|
+
def check(workspace: str | None = typer.Option(None, "--workspace")) -> None:
|
|
30
|
+
emit(invoke(lambda: service(workspace).check()))
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from campfire_cli.app.workspace.cli.workspace_cli import emit, invoke
|
|
8
|
+
from campfire_cli.app.workspace.repository.workspace_repository import SqliteWorkspaceRepository
|
|
9
|
+
from campfire_cli.app.workspace.service.structure_service import DomainService
|
|
10
|
+
from campfire_cli.app.workspace.service.workspace_service import WorkspaceService
|
|
11
|
+
from campfire_cli.config.settings import campfire_home
|
|
12
|
+
|
|
13
|
+
domain_cli = typer.Typer(
|
|
14
|
+
help="管理 Space 内可嵌套的内容领域", context_settings={"help_option_names": ["-h", "--help"]}
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def service(workspace: str | None) -> DomainService:
|
|
19
|
+
home = campfire_home()
|
|
20
|
+
resolved = WorkspaceService(home, SqliteWorkspaceRepository(home)).resolve(
|
|
21
|
+
workspace, Path.cwd()
|
|
22
|
+
)
|
|
23
|
+
return DomainService(Path(resolved.workspace), home)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@domain_cli.command("list")
|
|
27
|
+
def list_domains(
|
|
28
|
+
space: str | None = typer.Option(None, "--space"),
|
|
29
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
30
|
+
) -> None:
|
|
31
|
+
emit(invoke(lambda: service(workspace).list(space)))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@domain_cli.command("show")
|
|
35
|
+
def show(domain_id: str, workspace: str | None = typer.Option(None, "--workspace")) -> None:
|
|
36
|
+
emit(invoke(lambda: service(workspace).show(domain_id)))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@domain_cli.command("check")
|
|
40
|
+
def check(workspace: str | None = typer.Option(None, "--workspace")) -> None:
|
|
41
|
+
emit(invoke(lambda: service(workspace).check()))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@domain_cli.command("create")
|
|
45
|
+
def create(
|
|
46
|
+
domain_id: str = typer.Option(..., "--id"),
|
|
47
|
+
name: str = typer.Option(..., "--name"),
|
|
48
|
+
path: str = typer.Option(..., "--path"),
|
|
49
|
+
space: str = typer.Option(..., "--space"),
|
|
50
|
+
domain_type: str = typer.Option(..., "--type"),
|
|
51
|
+
governance: str = typer.Option(..., "--governance"),
|
|
52
|
+
parent: str | None = typer.Option(None, "--parent"),
|
|
53
|
+
project: str | None = typer.Option(None, "--project"),
|
|
54
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
55
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
56
|
+
) -> None:
|
|
57
|
+
emit(
|
|
58
|
+
invoke(
|
|
59
|
+
lambda: service(workspace).create(
|
|
60
|
+
domain_id=domain_id,
|
|
61
|
+
name=name,
|
|
62
|
+
path=path,
|
|
63
|
+
space_id=space,
|
|
64
|
+
domain_type=domain_type,
|
|
65
|
+
governance=governance,
|
|
66
|
+
parent_domain=parent,
|
|
67
|
+
project_id=project,
|
|
68
|
+
confirm=confirm,
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@domain_cli.command("adopt")
|
|
75
|
+
def adopt(
|
|
76
|
+
domain_id: str = typer.Option(..., "--id"),
|
|
77
|
+
name: str = typer.Option(..., "--name"),
|
|
78
|
+
path: str = typer.Option(..., "--path"),
|
|
79
|
+
space: str = typer.Option(..., "--space"),
|
|
80
|
+
domain_type: str = typer.Option(..., "--type"),
|
|
81
|
+
governance: str = typer.Option(..., "--governance"),
|
|
82
|
+
parent: str | None = typer.Option(None, "--parent"),
|
|
83
|
+
project: str | None = typer.Option(None, "--project"),
|
|
84
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
85
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
86
|
+
) -> None:
|
|
87
|
+
emit(
|
|
88
|
+
invoke(
|
|
89
|
+
lambda: service(workspace).adopt(
|
|
90
|
+
domain_id=domain_id,
|
|
91
|
+
name=name,
|
|
92
|
+
path=path,
|
|
93
|
+
space_id=space,
|
|
94
|
+
domain_type=domain_type,
|
|
95
|
+
governance=governance,
|
|
96
|
+
parent_domain=parent,
|
|
97
|
+
project_id=project,
|
|
98
|
+
confirm=confirm,
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from campfire_cli.app.workspace.cli.workspace_cli import emit, invoke
|
|
8
|
+
from campfire_cli.app.workspace.repository.workspace_repository import SqliteWorkspaceRepository
|
|
9
|
+
from campfire_cli.app.workspace.schema.workspace_schema import ProjectUpsertRequest
|
|
10
|
+
from campfire_cli.app.workspace.service.project_service import ProjectService
|
|
11
|
+
from campfire_cli.config.settings import campfire_home
|
|
12
|
+
|
|
13
|
+
project_cli = typer.Typer(
|
|
14
|
+
help="注册代码项目及其 Workspace 文档领域",
|
|
15
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def service() -> ProjectService:
|
|
20
|
+
root = campfire_home()
|
|
21
|
+
return ProjectService(root, SqliteWorkspaceRepository(root))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def request(
|
|
25
|
+
project_id: str,
|
|
26
|
+
workspace_id: str,
|
|
27
|
+
name: str,
|
|
28
|
+
document_domain: str,
|
|
29
|
+
local_path: Path | None,
|
|
30
|
+
git_remote_url: str | None,
|
|
31
|
+
default_branch: str | None,
|
|
32
|
+
status: str,
|
|
33
|
+
) -> ProjectUpsertRequest:
|
|
34
|
+
return ProjectUpsertRequest(
|
|
35
|
+
project_id=project_id,
|
|
36
|
+
workspace_id=workspace_id,
|
|
37
|
+
name=name,
|
|
38
|
+
document_domain=document_domain,
|
|
39
|
+
local_path=local_path,
|
|
40
|
+
git_remote_url=git_remote_url,
|
|
41
|
+
default_branch=default_branch,
|
|
42
|
+
status=status,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def project_options(operation: str):
|
|
47
|
+
def command(
|
|
48
|
+
project_id: str = typer.Option(..., "--id"),
|
|
49
|
+
workspace_id: str = typer.Option(..., "--workspace"),
|
|
50
|
+
name: str = typer.Option(..., "--name"),
|
|
51
|
+
document_domain: str = typer.Option(..., "--document-domain"),
|
|
52
|
+
local_path: Path | None = typer.Option(None, "--local-path"),
|
|
53
|
+
git_remote_url: str | None = typer.Option(None, "--git-remote-url"),
|
|
54
|
+
default_branch: str | None = typer.Option(None, "--default-branch"),
|
|
55
|
+
status: str = typer.Option("active", "--status"),
|
|
56
|
+
) -> None:
|
|
57
|
+
payload = request(
|
|
58
|
+
project_id,
|
|
59
|
+
workspace_id,
|
|
60
|
+
name,
|
|
61
|
+
document_domain,
|
|
62
|
+
local_path,
|
|
63
|
+
git_remote_url,
|
|
64
|
+
default_branch,
|
|
65
|
+
status,
|
|
66
|
+
)
|
|
67
|
+
target = service()
|
|
68
|
+
emit(invoke(lambda: getattr(target, operation)(payload)))
|
|
69
|
+
|
|
70
|
+
return command
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
project_cli.command("add", help="注册一个新 Project;提供本地 Git 路径时自动发现 remote 和分支。")(
|
|
74
|
+
project_options("add")
|
|
75
|
+
)
|
|
76
|
+
project_cli.command("update", help="完整更新一个已注册 Project。")(project_options("update"))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@project_cli.command("create")
|
|
80
|
+
def create(
|
|
81
|
+
project_id: str = typer.Option(..., "--id"),
|
|
82
|
+
workspace_id: str = typer.Option(..., "--workspace"),
|
|
83
|
+
name: str = typer.Option(..., "--name"),
|
|
84
|
+
document_domain: str = typer.Option(..., "--document-domain"),
|
|
85
|
+
local_path: Path | None = typer.Option(None, "--local-path"),
|
|
86
|
+
git_remote_url: str | None = typer.Option(None, "--git-remote-url"),
|
|
87
|
+
default_branch: str | None = typer.Option(None, "--default-branch"),
|
|
88
|
+
status: str = typer.Option("active", "--status"),
|
|
89
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
90
|
+
) -> None:
|
|
91
|
+
"""预览并初始化新 Project 文档中心;追加 --confirm 后创建并注册。"""
|
|
92
|
+
payload = request(
|
|
93
|
+
project_id,
|
|
94
|
+
workspace_id,
|
|
95
|
+
name,
|
|
96
|
+
document_domain,
|
|
97
|
+
local_path,
|
|
98
|
+
git_remote_url,
|
|
99
|
+
default_branch,
|
|
100
|
+
status,
|
|
101
|
+
)
|
|
102
|
+
emit(invoke(lambda: service().create(payload, confirm)))
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@project_cli.command("list")
|
|
106
|
+
def list_projects(workspace_id: str | None = typer.Option(None, "--workspace")) -> None:
|
|
107
|
+
"""列出全部 Project,或按 Workspace 过滤。"""
|
|
108
|
+
emit(invoke(lambda: service().list(workspace_id)))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@project_cli.command("show")
|
|
112
|
+
def show(project_id: str) -> None:
|
|
113
|
+
"""显示一个 Project 的注册元数据。"""
|
|
114
|
+
emit(invoke(lambda: service().show(project_id)))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@project_cli.command("resolve")
|
|
118
|
+
def resolve(path: Path | None = typer.Option(None, "--path")) -> None:
|
|
119
|
+
"""按本地路径和 Git remote 解析已注册 Project,不修改注册数据。"""
|
|
120
|
+
emit(invoke(lambda: service().resolve(path or Path.cwd())))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@project_cli.command("check")
|
|
124
|
+
def check(project_id: str) -> None:
|
|
125
|
+
"""检查 Project 的源码路径、Git 信息和文档领域是否仍然有效。"""
|
|
126
|
+
emit(invoke(lambda: service().check(project_id)))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@project_cli.command("bind")
|
|
130
|
+
def bind(
|
|
131
|
+
project_id: str = typer.Option(..., "--id"),
|
|
132
|
+
local_path: Path = typer.Option(..., "--local-path"),
|
|
133
|
+
) -> None:
|
|
134
|
+
"""在当前设备上绑定 Project 源码路径,不把绝对路径写入 Manifest。"""
|
|
135
|
+
emit(invoke(lambda: service().bind(project_id, local_path)))
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from campfire_cli.common.governance import enrich_issue
|
|
9
|
+
from campfire_cli.container import AppContainer
|
|
10
|
+
|
|
11
|
+
restructure_cli = typer.Typer(
|
|
12
|
+
help="按审批计划重构 Workspace 物理结构",
|
|
13
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
14
|
+
)
|
|
15
|
+
domain_restructure_cli = typer.Typer(
|
|
16
|
+
help="重构领域名称、路径或稳定身份",
|
|
17
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
18
|
+
)
|
|
19
|
+
restructure_cli.add_typer(domain_restructure_cli, name="domain")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def emit(result: object) -> None:
|
|
23
|
+
payload = result.model_dump(mode="json")
|
|
24
|
+
payload["issues"] = [enrich_issue(issue) for issue in payload.get("issues", [])]
|
|
25
|
+
typer.echo(json.dumps(payload, ensure_ascii=False, indent=2))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def service(ctx: typer.Context, workspace: str | None):
|
|
29
|
+
selector = workspace or ctx.find_root().params.get("workspace")
|
|
30
|
+
return AppContainer.build(selector).restructure
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def domain_service(ctx: typer.Context, workspace: str | None):
|
|
34
|
+
selector = workspace or ctx.find_root().params.get("workspace")
|
|
35
|
+
return AppContainer.build(selector).domain_restructure
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@domain_restructure_cli.command("rename")
|
|
39
|
+
def rename_domain(
|
|
40
|
+
ctx: typer.Context,
|
|
41
|
+
domain_id: str = typer.Option(..., "--domain"),
|
|
42
|
+
name: str = typer.Option(..., "--name"),
|
|
43
|
+
rename_directory: bool = typer.Option(False, "--rename-directory"),
|
|
44
|
+
target_path: str | None = typer.Option(None, "--target-path"),
|
|
45
|
+
project_name: str | None = typer.Option(None, "--project-name"),
|
|
46
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
47
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
48
|
+
) -> None:
|
|
49
|
+
"""修改领域显示名称;可显式联动目录和 Project 展示名称。"""
|
|
50
|
+
emit(
|
|
51
|
+
domain_service(ctx, workspace).rename(
|
|
52
|
+
domain_id,
|
|
53
|
+
name,
|
|
54
|
+
rename_directory=rename_directory,
|
|
55
|
+
target_path=target_path,
|
|
56
|
+
project_name=project_name,
|
|
57
|
+
confirm=confirm,
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@domain_restructure_cli.command("move")
|
|
63
|
+
def move_domain(
|
|
64
|
+
ctx: typer.Context,
|
|
65
|
+
domain_id: str = typer.Option(..., "--domain"),
|
|
66
|
+
target_path: str = typer.Option(..., "--target-path"),
|
|
67
|
+
parent_domain: str | None = typer.Option(None, "--parent-domain"),
|
|
68
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
69
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
70
|
+
) -> None:
|
|
71
|
+
"""移动完整领域目录,并更新父领域、Project、Manifest 和路径引用。"""
|
|
72
|
+
emit(
|
|
73
|
+
domain_service(ctx, workspace).move(
|
|
74
|
+
domain_id, target_path, parent_domain=parent_domain, confirm=confirm
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@domain_restructure_cli.command("rekey")
|
|
80
|
+
def rekey_domain(
|
|
81
|
+
ctx: typer.Context,
|
|
82
|
+
domain_id: str = typer.Option(..., "--domain"),
|
|
83
|
+
new_id: str = typer.Option(..., "--new-id"),
|
|
84
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
85
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
86
|
+
) -> None:
|
|
87
|
+
"""高风险修改稳定 domain_id,并更新直接子领域引用。"""
|
|
88
|
+
emit(domain_service(ctx, workspace).rekey(domain_id, new_id, confirm=confirm))
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@restructure_cli.command("inventory")
|
|
92
|
+
def inventory(
|
|
93
|
+
ctx: typer.Context,
|
|
94
|
+
scope: str = typer.Option(..., "--scope"),
|
|
95
|
+
batch: str = typer.Option(..., "--batch"),
|
|
96
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
97
|
+
) -> None:
|
|
98
|
+
"""冻结范围并生成批次事实清单。"""
|
|
99
|
+
emit(service(ctx, workspace).inventory(batch, scope))
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@restructure_cli.command("plan")
|
|
103
|
+
def plan(
|
|
104
|
+
ctx: typer.Context,
|
|
105
|
+
batch: str = typer.Option(..., "--batch"),
|
|
106
|
+
spec: Path | None = typer.Option(
|
|
107
|
+
None, "--spec", help="显式重构意图 YAML/JSON;支持跨目录移动和 Frontmatter Patch"
|
|
108
|
+
),
|
|
109
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
110
|
+
) -> None:
|
|
111
|
+
"""生成带源哈希且默认未审批的逐文件计划。"""
|
|
112
|
+
emit(service(ctx, workspace).plan(batch, spec))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@restructure_cli.command("apply")
|
|
116
|
+
def apply(
|
|
117
|
+
ctx: typer.Context,
|
|
118
|
+
batch: str = typer.Option(..., "--batch"),
|
|
119
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
120
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
121
|
+
) -> None:
|
|
122
|
+
"""预检或执行已审批批次。"""
|
|
123
|
+
emit(service(ctx, workspace).apply(batch, confirm))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@restructure_cli.command("verify")
|
|
127
|
+
def verify(
|
|
128
|
+
ctx: typer.Context,
|
|
129
|
+
batch: str = typer.Option(..., "--batch"),
|
|
130
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
131
|
+
) -> None:
|
|
132
|
+
"""执行批次最终验收并固化结果。"""
|
|
133
|
+
emit(service(ctx, workspace).verify(batch))
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from campfire_cli.app.workspace.cli.workspace_cli import emit, invoke
|
|
8
|
+
from campfire_cli.app.workspace.repository.workspace_repository import SqliteWorkspaceRepository
|
|
9
|
+
from campfire_cli.app.workspace.service.structure_service import SpaceService
|
|
10
|
+
from campfire_cli.app.workspace.service.workspace_service import WorkspaceService
|
|
11
|
+
from campfire_cli.config.settings import campfire_home
|
|
12
|
+
|
|
13
|
+
space_cli = typer.Typer(
|
|
14
|
+
help="管理 Workspace 顶级内容空间", context_settings={"help_option_names": ["-h", "--help"]}
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def service(workspace: str | None) -> SpaceService:
|
|
19
|
+
home = campfire_home()
|
|
20
|
+
resolved = WorkspaceService(home, SqliteWorkspaceRepository(home)).resolve(
|
|
21
|
+
workspace, Path.cwd()
|
|
22
|
+
)
|
|
23
|
+
return SpaceService(Path(resolved.workspace), home)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@space_cli.command("list")
|
|
27
|
+
def list_spaces(workspace: str | None = typer.Option(None, "--workspace")) -> None:
|
|
28
|
+
emit(invoke(lambda: service(workspace).list()))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@space_cli.command("show")
|
|
32
|
+
def show(space_id: str, workspace: str | None = typer.Option(None, "--workspace")) -> None:
|
|
33
|
+
emit(invoke(lambda: service(workspace).show(space_id)))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@space_cli.command("check")
|
|
37
|
+
def check(
|
|
38
|
+
space_id: str | None = typer.Option(None, "--space", help="只检查指定 Space id"),
|
|
39
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
40
|
+
) -> None:
|
|
41
|
+
emit(invoke(lambda: service(workspace).check(space_id)))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@space_cli.command("create")
|
|
45
|
+
def create(
|
|
46
|
+
space_id: str = typer.Option(..., "--id"),
|
|
47
|
+
name: str = typer.Option(..., "--name"),
|
|
48
|
+
path: str = typer.Option(..., "--path"),
|
|
49
|
+
space_type: str = typer.Option(..., "--type"),
|
|
50
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
51
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
52
|
+
) -> None:
|
|
53
|
+
emit(invoke(lambda: service(workspace).create(space_id, name, path, space_type, confirm)))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@space_cli.command("adopt")
|
|
57
|
+
def adopt(
|
|
58
|
+
space_id: str = typer.Option(..., "--id"),
|
|
59
|
+
name: str = typer.Option(..., "--name"),
|
|
60
|
+
path: str = typer.Option(..., "--path"),
|
|
61
|
+
space_type: str = typer.Option(..., "--type"),
|
|
62
|
+
workspace: str | None = typer.Option(None, "--workspace"),
|
|
63
|
+
confirm: bool = typer.Option(False, "--confirm"),
|
|
64
|
+
) -> None:
|
|
65
|
+
emit(invoke(lambda: service(workspace).adopt(space_id, name, path, space_type, confirm)))
|