maind 0.1.0__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 (106) hide show
  1. maind-0.1.0/.dockerignore +13 -0
  2. maind-0.1.0/.gitignore +27 -0
  3. maind-0.1.0/.python-version +1 -0
  4. maind-0.1.0/.woodpecker/backend-build.yml +63 -0
  5. maind-0.1.0/.woodpecker/backend-manifest.yml +40 -0
  6. maind-0.1.0/Dockerfile +72 -0
  7. maind-0.1.0/HANDOFF.md +110 -0
  8. maind-0.1.0/Makefile +113 -0
  9. maind-0.1.0/PKG-INFO +320 -0
  10. maind-0.1.0/README.md +303 -0
  11. maind-0.1.0/docs/superpowers/PLAN2-CONTRACTS.md +59 -0
  12. maind-0.1.0/docs/superpowers/plans/2026-07-03-mindreon-sdk-foundation.md +1158 -0
  13. maind-0.1.0/docs/superpowers/plans/2026-07-03-mindreon-sdk-project-create.md +1439 -0
  14. maind-0.1.0/docs/superpowers/specs/2026-07-03-mindreon-sdk-design.md +189 -0
  15. maind-0.1.0/pyproject.toml +67 -0
  16. maind-0.1.0/src/mai/__init__.py +38 -0
  17. maind-0.1.0/src/mai/__main__.py +6 -0
  18. maind-0.1.0/src/mai/_core/__init__.py +1 -0
  19. maind-0.1.0/src/mai/_core/api_response.py +10 -0
  20. maind-0.1.0/src/mai/_core/cli_output.py +101 -0
  21. maind-0.1.0/src/mai/_core/fvm_provider.py +47 -0
  22. maind-0.1.0/src/mai/_core/image_copy.py +59 -0
  23. maind-0.1.0/src/mai/_core/operations/__init__.py +1 -0
  24. maind-0.1.0/src/mai/_core/operations/auth.py +49 -0
  25. maind-0.1.0/src/mai/_core/operations/config_center.py +84 -0
  26. maind-0.1.0/src/mai/_core/operations/files.py +87 -0
  27. maind-0.1.0/src/mai/_core/operations/fvm.py +175 -0
  28. maind-0.1.0/src/mai/_core/operations/images.py +134 -0
  29. maind-0.1.0/src/mai/_core/operations/projects.py +74 -0
  30. maind-0.1.0/src/mai/_core/operations/resources.py +222 -0
  31. maind-0.1.0/src/mai/_core/operations/seed.py +314 -0
  32. maind-0.1.0/src/mai/_core/operations/sync.py +274 -0
  33. maind-0.1.0/src/mai/_core/resource_target.py +57 -0
  34. maind-0.1.0/src/mai/_core/routes.py +97 -0
  35. maind-0.1.0/src/mai/_core/settings.py +52 -0
  36. maind-0.1.0/src/mai/_core/tools.py +136 -0
  37. maind-0.1.0/src/mai/_core/transport.py +163 -0
  38. maind-0.1.0/src/mai/_core/vcs.py +927 -0
  39. maind-0.1.0/src/mai/_core/workspace.py +685 -0
  40. maind-0.1.0/src/mai/app.py +106 -0
  41. maind-0.1.0/src/mai/async_client.py +193 -0
  42. maind-0.1.0/src/mai/cli/__init__.py +1 -0
  43. maind-0.1.0/src/mai/cli/config_file.py +39 -0
  44. maind-0.1.0/src/mai/client.py +233 -0
  45. maind-0.1.0/src/mai/commands/__init__.py +1 -0
  46. maind-0.1.0/src/mai/commands/_workspace_common.py +26 -0
  47. maind-0.1.0/src/mai/commands/config_center.py +59 -0
  48. maind-0.1.0/src/mai/commands/connect.py +37 -0
  49. maind-0.1.0/src/mai/commands/create.py +80 -0
  50. maind-0.1.0/src/mai/commands/download.py +175 -0
  51. maind-0.1.0/src/mai/commands/file.py +26 -0
  52. maind-0.1.0/src/mai/commands/image.py +135 -0
  53. maind-0.1.0/src/mai/commands/install.py +28 -0
  54. maind-0.1.0/src/mai/commands/login.py +39 -0
  55. maind-0.1.0/src/mai/commands/project.py +67 -0
  56. maind-0.1.0/src/mai/commands/publish.py +48 -0
  57. maind-0.1.0/src/mai/commands/release.py +169 -0
  58. maind-0.1.0/src/mai/commands/repo.py +107 -0
  59. maind-0.1.0/src/mai/commands/seed.py +603 -0
  60. maind-0.1.0/src/mai/commands/status.py +38 -0
  61. maind-0.1.0/src/mai/commands/sync.py +67 -0
  62. maind-0.1.0/src/mai/errors.py +47 -0
  63. maind-0.1.0/src/mai/models.py +48 -0
  64. maind-0.1.0/tests/__init__.py +0 -0
  65. maind-0.1.0/tests/cli/__init__.py +0 -0
  66. maind-0.1.0/tests/cli/test_config_center_cli.py +42 -0
  67. maind-0.1.0/tests/cli/test_config_file.py +23 -0
  68. maind-0.1.0/tests/cli/test_connect_download_cli.py +156 -0
  69. maind-0.1.0/tests/cli/test_create_cli.py +79 -0
  70. maind-0.1.0/tests/cli/test_file_cli.py +53 -0
  71. maind-0.1.0/tests/cli/test_help_cli.py +60 -0
  72. maind-0.1.0/tests/cli/test_image_cli.py +184 -0
  73. maind-0.1.0/tests/cli/test_install_cli.py +66 -0
  74. maind-0.1.0/tests/cli/test_login_cli.py +46 -0
  75. maind-0.1.0/tests/cli/test_project_cli.py +60 -0
  76. maind-0.1.0/tests/cli/test_publish_cli.py +95 -0
  77. maind-0.1.0/tests/cli/test_release_cli.py +70 -0
  78. maind-0.1.0/tests/cli/test_repo_cli.py +129 -0
  79. maind-0.1.0/tests/cli/test_seed_cli.py +493 -0
  80. maind-0.1.0/tests/cli/test_status_cli.py +50 -0
  81. maind-0.1.0/tests/cli/test_sync_cli.py +147 -0
  82. maind-0.1.0/tests/conftest.py +17 -0
  83. maind-0.1.0/tests/core/__init__.py +0 -0
  84. maind-0.1.0/tests/core/test_auth_op.py +85 -0
  85. maind-0.1.0/tests/core/test_config_center_op.py +55 -0
  86. maind-0.1.0/tests/core/test_files_op.py +49 -0
  87. maind-0.1.0/tests/core/test_fvm_op.py +151 -0
  88. maind-0.1.0/tests/core/test_images_op.py +77 -0
  89. maind-0.1.0/tests/core/test_projects_op.py +68 -0
  90. maind-0.1.0/tests/core/test_publish.py +140 -0
  91. maind-0.1.0/tests/core/test_resource_target.py +33 -0
  92. maind-0.1.0/tests/core/test_resources_op.py +163 -0
  93. maind-0.1.0/tests/core/test_routes.py +48 -0
  94. maind-0.1.0/tests/core/test_seed_op.py +188 -0
  95. maind-0.1.0/tests/core/test_settings.py +50 -0
  96. maind-0.1.0/tests/core/test_sync_op.py +361 -0
  97. maind-0.1.0/tests/core/test_tools.py +62 -0
  98. maind-0.1.0/tests/core/test_transport.py +165 -0
  99. maind-0.1.0/tests/core/test_vcs.py +302 -0
  100. maind-0.1.0/tests/core/test_workspace.py +180 -0
  101. maind-0.1.0/tests/core/test_workspace_repo.py +407 -0
  102. maind-0.1.0/tests/test_async_client.py +165 -0
  103. maind-0.1.0/tests/test_client.py +179 -0
  104. maind-0.1.0/tests/test_errors.py +35 -0
  105. maind-0.1.0/tests/test_packaging.py +14 -0
  106. maind-0.1.0/uv.lock +2551 -0
@@ -0,0 +1,13 @@
1
+ .git
2
+ .idea
3
+ .mypy_cache
4
+ .pytest_cache
5
+ .ruff_cache
6
+ .venv
7
+ .vscode
8
+ __pycache__
9
+ *.py[cod]
10
+ *.egg-info
11
+ build
12
+ dist
13
+ htmlcov
maind-0.1.0/.gitignore ADDED
@@ -0,0 +1,27 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+
7
+ # Build
8
+ dist/
9
+ build/
10
+
11
+ # Virtualenv / uv
12
+ .venv/
13
+
14
+ # Test / tooling caches
15
+ .pytest_cache/
16
+ .ruff_cache/
17
+ .mypy_cache/
18
+ .coverage
19
+ htmlcov/
20
+
21
+ # Editor / OS
22
+ .DS_Store
23
+
24
+ # SDD controller scratch (briefs, reports, diffs, ledger)
25
+ .superpowers/
26
+ .vscode
27
+ .idea
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,63 @@
1
+ # =========================================================================
2
+ # Mai CLI 镜像构建 Workflow (amd64 + arm64 并行)
3
+ # =========================================================================
4
+ clone:
5
+ git:
6
+ image: harbor.mindreon.com/ops/woodpeckerci/plugin-git:latest
7
+ environment:
8
+ CI_NETRC_MACHINE: gitlab.mindreon.com
9
+ CI_NETRC_USERNAME: { from_secret: gitlab_username }
10
+ CI_NETRC_PASSWORD: { from_secret: gitlab_password }
11
+
12
+ matrix:
13
+ include:
14
+ - PLATFORM: linux/amd64
15
+ ARCH: amd64
16
+ - PLATFORM: linux/arm64
17
+ ARCH: arm64
18
+
19
+ labels:
20
+ platform: ${PLATFORM}
21
+
22
+ steps:
23
+ build-cli-branch:
24
+ image: harbor.mindreon.com/ops/woodpeckerci/plugin-docker-buildx:6.0
25
+ privileged: true
26
+ volumes:
27
+ - /var/run/docker.sock:/var/run/docker.sock
28
+ settings:
29
+ dockerfile: Dockerfile
30
+ repo: harbor.mindreon.com/baize/mai-cli
31
+ registry: harbor.mindreon.com
32
+ username: { from_secret: harbor_username }
33
+ password: { from_secret: harbor_password }
34
+ cache: true
35
+ daemon_off: true
36
+ platforms:
37
+ - ${PLATFORM}
38
+ provenance: false
39
+ auto_tag: false
40
+ tags:
41
+ - ${CI_COMMIT_BRANCH//\//-}-${ARCH}
42
+ when:
43
+ event: [push, manual]
44
+
45
+ build-cli-tag:
46
+ image: harbor.mindreon.com/ops/woodpeckerci/plugin-docker-buildx:6.0
47
+ privileged: true
48
+ volumes:
49
+ - /var/run/docker.sock:/var/run/docker.sock
50
+ settings:
51
+ dockerfile: Dockerfile
52
+ repo: harbor.mindreon.com/baize/mai-cli
53
+ registry: harbor.mindreon.com
54
+ username: { from_secret: harbor_username }
55
+ password: { from_secret: harbor_password }
56
+ cache: true
57
+ daemon_off: true
58
+ platforms:
59
+ - ${PLATFORM}
60
+ provenance: false
61
+ tags: ${CI_COMMIT_TAG}-${ARCH}
62
+ when:
63
+ event: tag
@@ -0,0 +1,40 @@
1
+ depends_on:
2
+ - backend-build
3
+
4
+ skip_clone: true
5
+
6
+ labels:
7
+ platform: linux/amd64
8
+
9
+ steps:
10
+ manifest-cli-branch:
11
+ image: harbor.mindreon.com/ops/woodpeckerci/plugin-docker-buildx:6.0
12
+ volumes:
13
+ - /var/run/docker.sock:/var/run/docker.sock
14
+ environment:
15
+ HARBOR_USER: { from_secret: harbor_username }
16
+ HARBOR_PWD: { from_secret: harbor_password }
17
+ REGISTRY: harbor.mindreon.com
18
+ REPO: harbor.mindreon.com/baize/mai-cli
19
+ commands:
20
+ - echo $HARBOR_PWD | docker login $REGISTRY -u $HARBOR_USER --password-stdin
21
+ - docker manifest create --amend $REPO:${CI_COMMIT_BRANCH//\//-} $REPO:${CI_COMMIT_BRANCH//\//-}-amd64 $REPO:${CI_COMMIT_BRANCH//\//-}-arm64
22
+ - docker manifest push $REPO:${CI_COMMIT_BRANCH//\//-}
23
+ when:
24
+ event: [push, manual]
25
+
26
+ manifest-cli-tag:
27
+ image: harbor.mindreon.com/ops/woodpeckerci/plugin-docker-buildx:6.0
28
+ volumes:
29
+ - /var/run/docker.sock:/var/run/docker.sock
30
+ environment:
31
+ HARBOR_USER: { from_secret: harbor_username }
32
+ HARBOR_PWD: { from_secret: harbor_password }
33
+ REGISTRY: harbor.mindreon.com
34
+ REPO: harbor.mindreon.com/baize/mai-cli
35
+ commands:
36
+ - echo $HARBOR_PWD | docker login $REGISTRY -u $HARBOR_USER --password-stdin
37
+ - docker manifest create --amend $REPO:$CI_COMMIT_TAG $REPO:$CI_COMMIT_TAG-amd64 $REPO:$CI_COMMIT_TAG-arm64
38
+ - docker manifest push $REPO:$CI_COMMIT_TAG
39
+ when:
40
+ event: tag
maind-0.1.0/Dockerfile ADDED
@@ -0,0 +1,72 @@
1
+ FROM harbor.mindreon.com/ops/python:3.12-slim AS builder
2
+
3
+ COPY --from=harbor.mindreon.com/ops/astral/uv:latest /uv /uvx /bin/
4
+
5
+ ENV DEBIAN_FRONTEND=noninteractive \
6
+ PATH=/opt/venv/bin:$PATH \
7
+ PIP_NO_CACHE_DIR=1 \
8
+ PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
9
+ PIP_TRUSTED_HOST=pypi.tuna.tsinghua.edu.cn \
10
+ UV_PROJECT_ENVIRONMENT=/opt/venv
11
+
12
+ WORKDIR /opt/mai-cli
13
+
14
+ RUN sed -i \
15
+ -e 's#http://deb.debian.org/debian#https://mirrors.tuna.tsinghua.edu.cn/debian#g' \
16
+ -e 's#http://deb.debian.org/debian-security#https://mirrors.tuna.tsinghua.edu.cn/debian-security#g' \
17
+ /etc/apt/sources.list.d/debian.sources && \
18
+ apt-get update && apt-get install -y --no-install-recommends \
19
+ bash \
20
+ ca-certificates \
21
+ git \
22
+ make \
23
+ openssh-client \
24
+ skopeo \
25
+ && rm -rf /var/lib/apt/lists/*
26
+
27
+ COPY pyproject.toml uv.lock README.md ./
28
+ COPY src ./src
29
+
30
+ RUN uv sync --frozen --no-dev --no-editable --no-cache
31
+
32
+ RUN mai --help >/dev/null && \
33
+ python -m mai --help >/dev/null && \
34
+ python -c "import dvc.repo, huggingface_hub, modelscope_hub, botocore" && \
35
+ dvc version >/dev/null && \
36
+ hf --help >/dev/null && \
37
+ ms -V >/dev/null 2>&1 && \
38
+ modelscope -V >/dev/null 2>&1 && \
39
+ skopeo --version >/dev/null && \
40
+ git --version >/dev/null
41
+
42
+ FROM harbor.mindreon.com/ops/python:3.12-slim AS runtime
43
+
44
+ ENV DEBIAN_FRONTEND=noninteractive \
45
+ PATH=/opt/venv/bin:$PATH \
46
+ PYTHONUNBUFFERED=1 \
47
+ PYTHONDONTWRITEBYTECODE=1
48
+
49
+ RUN sed -i \
50
+ -e 's#http://deb.debian.org/debian#https://mirrors.tuna.tsinghua.edu.cn/debian#g' \
51
+ -e 's#http://deb.debian.org/debian-security#https://mirrors.tuna.tsinghua.edu.cn/debian-security#g' \
52
+ /etc/apt/sources.list.d/debian.sources && \
53
+ apt-get update && apt-get install -y --no-install-recommends \
54
+ bash \
55
+ ca-certificates \
56
+ git \
57
+ openssh-client \
58
+ skopeo \
59
+ && rm -rf /var/lib/apt/lists/*
60
+
61
+ COPY --from=builder /opt/venv /opt/venv
62
+
63
+ RUN ln -sf /opt/venv/bin/mai /usr/local/bin/mai && \
64
+ ln -sf /opt/venv/bin/dvc /usr/local/bin/dvc && \
65
+ ln -sf /opt/venv/bin/hf /usr/local/bin/hf && \
66
+ ln -sf /opt/venv/bin/ms /usr/local/bin/ms && \
67
+ ln -sf /opt/venv/bin/modelscope /usr/local/bin/modelscope && \
68
+ mkdir -p /workspace
69
+
70
+ WORKDIR /workspace
71
+
72
+ CMD ["mai", "--help"]
maind-0.1.0/HANDOFF.md ADDED
@@ -0,0 +1,110 @@
1
+ # 交接文档 —— Mindreon Python SDK + CLI
2
+
3
+ > 更新时间: 2026-07-03
4
+ > 目的: 把当前上下文完整交接,任何人(或新会话)据此可无缝接手。
5
+
6
+ ## 一句话概况
7
+
8
+ 把现有的 `mindreon-cli`(Node.js) 重构为 **Python 的 SDK + CLI 二合一** 包,放进后端仓库既能 `import` 当 SDK、又能命令行当 CLI。**设计与实施计划已完成并提交;代码实现尚未开始(0/8 任务)。**
9
+
10
+ ## 背景与动机
11
+
12
+ - 原始诉求: 维护者是 **Python 后端工程师(不会 Node)**,本想做一个放进后端仓库的 **Python SDK,同时具备 SDK 和 CLI 能力**。
13
+ - 现状问题: 现有 `../mindreon-cli` 是 Claude Code 迭代中"跑偏"用 **Node.js** 写出来的(已发布 npm、有 Docker 镜像、v0.1.26)。维护者驾驭不了 Node,且 Node 包无法被 Python 后端 import。
14
+ - 结论: 用 Python 重写。**不是语言偏好,而是**(1) 维护者不会 Node = Node 版是不可维护的黑盒;(2) 目标是"SDK 放后端仓库",Node 架构上做不到。
15
+
16
+ ## 关键决策(已定)
17
+
18
+ | # | 决策点 | 结论 |
19
+ |---|--------|------|
20
+ | 1 | 定位 | Python,**SDK 为核心 + CLI 是薄壳**;业务逻辑只写一遍 |
21
+ | 2 | 后端环境 | FastAPI (async) |
22
+ | 3 | sync/async | **双客户端一次到位**:同步核心 + `MindreonClient` / `AsyncMindreonClient`;异步用 `anyio.to_thread` 包同步实现(不追求 git/dvc 的"真异步") |
23
+ | 4 | 认证/配置 | 显式参数 + 环境变量(OpenAI 式)+ `from_config_file()`;`~/.config/mindreon/config.json` 读写**归 CLI 层**,SDK 不碰家目录 |
24
+ | 5 | 外部工具 | git/git-lfs/dvc/modelscope/skopeo 全部 **subprocess + 运行时检测**;核心 SDK 只依赖 httpx/pyyaml(轻);dvc/modelscope 库调用留作未来可选 extras |
25
+ | 6 | 仓库形态 | **单包 `mindreon`**,SDK + CLI 同包 |
26
+
27
+ 三个方法级默认(可推翻,已写进 spec 的"默认决策"节):
28
+ - `create_model` / `create_dataset` **分开**(不合并成 `create(kind,...)`)
29
+ - `ref` 用字符串 `"model:name"` 为主,也接受 `ResourceRef(kind,name)`
30
+ - 工作区用 **`Workspace` 对象**封装 `status/add/commit/push`
31
+
32
+ ## 架构(三层)
33
+
34
+ ```
35
+ 返回结构化对象 ← SDK 门面(sync + async) ← CLI 薄壳(Typer)
36
+ ↑ ↑ ↑
37
+ dataclass MindreonClient 解析参数→调门面→打印
38
+ AsyncMindreonClient
39
+
40
+ _core 内部实现(同步纯逻辑:httpx / subprocess)
41
+ ```
42
+
43
+ 目标目录结构(尚未落地,见 spec):`src/mindreon/{client,async_client,models,errors}.py` + `_core/{settings,transport,routes,resources,workspace,tools,operations/}` + `cli/{app,commands/,config_file}`。
44
+
45
+ ## 已产出物(均在本仓库,已提交)
46
+
47
+ | 路径 | 内容 |
48
+ |------|------|
49
+ | `docs/superpowers/specs/2026-07-03-mindreon-sdk-design.md` | 完整设计规格(架构/双客户端/认证/错误/测试/迁移/6 项决策) |
50
+ | `docs/superpowers/plans/2026-07-03-mindreon-sdk-foundation.md` | **实施计划 1**:8 个 TDD 任务,打通架构基座 + login/status 端到端 |
51
+ | `src/mindreon_cli/` + `tests/` | 早期**骨架**(见下),包名仍是旧的 `mindreon_cli`,计划 Task 1 会改名为 `mindreon` |
52
+
53
+ ### 现有骨架能干什么(已可运行)
54
+
55
+ - `uv sync` 装环境;`uv run mindreon --help` 列出全部 16 命令;`uv run mindreon status`/`login` 已真实现;其余命令注册为 stub(报 "not yet implemented")。
56
+ - 已通过: `pytest`(15 passed)、`ruff`、`mypy --strict`。
57
+ - ⚠️ 注意: 这套骨架是**按"CLI 移植"思路搭的**,不是 SDK-first。计划 1 会把它重构成三层架构。
58
+
59
+ ## 当前状态(精确)
60
+
61
+ - **分支**: `master` (⚠️ 还没开 feature 分支;按 subagent-driven 流程,实现前必须开)
62
+ - **提交历史**:
63
+ - `192cda0` docs: add SDK foundation implementation plan
64
+ - `63e726c` docs: add Mindreon Python SDK + CLI design spec
65
+ - `bc3f989` chore: scaffold Python port skeleton
66
+ - **未提交改动**: `docs/.../2026-07-03-mindreon-sdk-foundation.md` 有一处**已做但未提交**的修正 —— 给 Task 1 补了"改名后同步替换 `tests/` 里对 `mindreon_cli` 的绝对导入"(原计划漏了,会导致 Task 1 测试失败)。
67
+ - **实现进度**: **0 / 8 任务**。尚未执行计划 1 的任何 Task,包名仍为 `mindreon_cli`。
68
+ - **进度 ledger**: 尚未创建(`.superpowers/sdd/progress.md`)。
69
+
70
+ ## 下一步(接手就做)
71
+
72
+ 1. **提交那处计划修正**,创建功能分支,初始化 ledger:
73
+ ```bash
74
+ cd mindreon-cli-py
75
+ git add docs && git commit -m "docs: fix Task 1 to rewrite test imports on rename"
76
+ git checkout -b feature/sdk-foundation
77
+ mkdir -p .superpowers/sdd && printf '# SDD Progress\n\n' > .superpowers/sdd/progress.md
78
+ ```
79
+ 2. **按 `superpowers:subagent-driven-development` 流程执行计划 1** 的 Task 1→8:
80
+ 每个 Task 派一个全新 implementer 子代理(计划里含完整代码,多为机械转录,用便宜模型即可),完成后派 reviewer 子代理审(spec 合规 + 代码质量),有 Critical/Important 问题派 fix 子代理,再复审,通过后记 ledger、下一个 Task。全程连续执行,不中途 check-in。
81
+ 3. **计划 1 完成后**,做整分支 code review,然后用 `superpowers:finishing-a-development-branch` 收尾。
82
+ 4. **后续计划(各自独立成文再执行)**:
83
+ - 计划 2: `project` + `create`
84
+ - 计划 3: `connect` + `download` + `repo`(首次引入 `Workspace` / subprocess / `tools.py`)
85
+ - 计划 4: `publish` + `file` + `image` + `seed`
86
+
87
+ ## 快速上手(验证环境)
88
+
89
+ ```bash
90
+ cd mindreon-cli-py
91
+ uv sync
92
+ uv run mindreon --help
93
+ MAI_CONFIG_DIR=/tmp/mr uv run mindreon status
94
+ uv run pytest -q # 现有骨架 15 passed
95
+ ```
96
+
97
+ 调试: VS Code 用 `.vscode/launch.json`(有 `mindreon: status` / `login` / `pytest` 配置)。
98
+
99
+ ## 注意事项 / 坑
100
+
101
+ - **Python 版环境变量**: 统一使用 `MAI_*`,例如 `MAI_API_URL`、`MAI_AUTH_TOKEN`、`MAI_CONFIG_DIR`。不要再兼容 Node 版旧前缀。
102
+ - **计划 Task 1 的 `perl -pi -e` 命令**用于替换 tests 引用;macOS 上 `perl` 比 `sed -i` 稳。
103
+ - **不要在 `master` 上直接实现**(subagent-driven 硬规则)。
104
+ - **Node 版参考源**: `../mindreon-cli/src/`。计划里标注 `upload_file`/`seed_*`/`build_image` 的确切参数需在实现对应命令时读 Node 源码(`file.js`/`seed.js`/`image.js`)对齐 —— 但这些属于后续计划 2-4,计划 1 不涉及。
105
+ - **协调者工具怪癖**(本会话所用): `TaskCreate`/`TaskUpdate` 是单条操作(每次一个 `subject`/`taskId`),不接受数组批量。
106
+
107
+ ## 参考
108
+
109
+ - 目标产物: 可 `pip install mindreon` → `from mindreon import MindreonClient` / `mindreon <cmd>`。
110
+ - 流程链路: `brainstorming`(设计)→ `writing-plans`(计划)→ `subagent-driven-development`(执行)→ `finishing-a-development-branch`(收尾)。
maind-0.1.0/Makefile ADDED
@@ -0,0 +1,113 @@
1
+ IMAGE_NAME ?= mindreon/mai-cli
2
+ IMAGE_TAG ?= latest
3
+ IMAGE ?= $(IMAGE_NAME):$(IMAGE_TAG)
4
+ PLATFORMS ?= linux/amd64,linux/arm64
5
+ BUILDER ?= mai-cli-builder
6
+ TWINE ?= uv run --with twine twine
7
+
8
+ .PHONY: help install dev run test cov lint format typecheck build package-check release-check publish-pypi publish-testpypi publish-pip clean buildx-create image-build-local image-push image-build-push image-buildx image-buildx-push image-run-help
9
+
10
+ help: ## Show this help
11
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
12
+ awk 'BEGIN {FS = ":.*?## "}; {printf " %-12s %s\n", $$1, $$2}'
13
+
14
+ install: ## Create venv and install package + dev deps (editable)
15
+ uv sync
16
+
17
+ dev: install ## Alias for install
18
+
19
+ run: ## Run the CLI, e.g. make run ARGS="status"
20
+ uv run mai $(ARGS)
21
+
22
+ test: ## Run the test suite
23
+ uv run pytest
24
+
25
+ cov: ## Run tests with coverage report
26
+ uv run pytest --cov=mai --cov-report=term-missing
27
+
28
+ lint: ## Lint with ruff
29
+ uv run ruff check src tests
30
+
31
+ format: ## Auto-format with ruff
32
+ uv run ruff format src tests
33
+
34
+ typecheck: ## Static type check with mypy
35
+ uv run mypy
36
+
37
+ build: ## Build wheel + sdist into dist/
38
+ uv build
39
+
40
+ package-check: build ## Check dist/* package metadata
41
+ $(TWINE) check dist/*
42
+
43
+ release-check: lint typecheck test package-check ## Run all checks before publishing
44
+
45
+ publish-pypi: package-check ## Publish dist/* to PyPI using PYPI_USERNAME/PYPI_PASSWORD
46
+ @username="$${PYPI_USERNAME:-$${TWINE_USERNAME:-}}"; \
47
+ password="$${PYPI_PASSWORD:-$${TWINE_PASSWORD:-}}"; \
48
+ if [ -z "$$username" ] || [ -z "$$password" ]; then \
49
+ echo "Set PYPI_USERNAME and PYPI_PASSWORD before publishing."; \
50
+ exit 1; \
51
+ fi; \
52
+ TWINE_USERNAME="$$username" TWINE_PASSWORD="$$password" $(TWINE) upload --verbose dist/*
53
+
54
+ publish-testpypi: package-check ## Publish dist/* to TestPyPI
55
+ @username="$${PYPI_USERNAME:-$${TWINE_USERNAME:-}}"; \
56
+ password="$${PYPI_PASSWORD:-$${TWINE_PASSWORD:-}}"; \
57
+ if [ -z "$$username" ] || [ -z "$$password" ]; then \
58
+ echo "Set PYPI_USERNAME and PYPI_PASSWORD before publishing."; \
59
+ exit 1; \
60
+ fi; \
61
+ TWINE_USERNAME="$$username" TWINE_PASSWORD="$$password" \
62
+ TWINE_REPOSITORY_URL="https://test.pypi.org/legacy/" \
63
+ $(TWINE) upload --verbose dist/*
64
+
65
+ publish-pip: package-check ## Publish dist/* to custom PYPI_REPOSITORY_URL
66
+ @username="$${PYPI_USERNAME:-$${TWINE_USERNAME:-}}"; \
67
+ password="$${PYPI_PASSWORD:-$${TWINE_PASSWORD:-}}"; \
68
+ url="$${PYPI_REPOSITORY_URL:-$${TWINE_REPOSITORY_URL:-}}"; \
69
+ if [ -z "$$url" ]; then \
70
+ echo "Set PYPI_REPOSITORY_URL for custom pip repository publishing."; \
71
+ exit 1; \
72
+ fi; \
73
+ if [ -z "$$username" ] || [ -z "$$password" ]; then \
74
+ echo "Set PYPI_USERNAME and PYPI_PASSWORD before publishing."; \
75
+ exit 1; \
76
+ fi; \
77
+ TWINE_USERNAME="$$username" TWINE_PASSWORD="$$password" TWINE_REPOSITORY_URL="$$url" \
78
+ $(TWINE) upload --verbose dist/*
79
+
80
+ clean: ## Remove build/venv artifacts
81
+ rm -rf dist build .pytest_cache .ruff_cache .mypy_cache **/__pycache__
82
+
83
+ buildx-create: ## Create or select Docker buildx builder
84
+ @if ! docker buildx inspect $(BUILDER) >/dev/null 2>&1; then \
85
+ docker buildx create --name $(BUILDER) --use; \
86
+ else \
87
+ docker buildx use $(BUILDER); \
88
+ fi
89
+ docker buildx inspect --bootstrap >/dev/null
90
+
91
+ image-build-local: ## Build local Docker image
92
+ docker build -t $(IMAGE) .
93
+
94
+ image-push: ## Push Docker image
95
+ docker push $(IMAGE)
96
+
97
+ image-build-push: image-build-local image-push ## Build and push Docker image
98
+
99
+ image-buildx: buildx-create ## Build multi-platform image without pushing
100
+ docker buildx build \
101
+ --platform $(PLATFORMS) \
102
+ -t $(IMAGE) \
103
+ .
104
+
105
+ image-buildx-push: buildx-create ## Build and push multi-platform image
106
+ docker buildx build \
107
+ --platform $(PLATFORMS) \
108
+ -t $(IMAGE) \
109
+ --push \
110
+ .
111
+
112
+ image-run-help: ## Run mai --help in Docker image
113
+ docker run --rm $(IMAGE) mai --help