caelterra 0.1.6__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.
- caelterra-0.1.6/.github/workflows/release.yml +64 -0
- caelterra-0.1.6/.gitignore +14 -0
- caelterra-0.1.6/.pre-commit-config.yaml +22 -0
- caelterra-0.1.6/CHANGELOG.md +87 -0
- caelterra-0.1.6/DEPRECATED.md +21 -0
- caelterra-0.1.6/LICENSE +21 -0
- caelterra-0.1.6/PKG-INFO +9 -0
- caelterra-0.1.6/README.md +242 -0
- caelterra-0.1.6/pyproject.toml +40 -0
- caelterra-0.1.6/src/caelterra/SOUL.md +34 -0
- caelterra-0.1.6/src/caelterra/__init__.py +92 -0
- caelterra-0.1.6/src/caelterra/git_utils.py +27 -0
- caelterra-0.1.6/src/caelterra/plugin.yaml +4 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/SKILL.md +254 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/assets/skill-template.md +39 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/references/anti-patterns.md +104 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/references/degrees-of-freedom.md +57 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/references/spec.md +45 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/scripts/init-skill.sh +128 -0
- caelterra-0.1.6/src/caelterra/skills/create-skill/scripts/validate-skill.py +350 -0
- caelterra-0.1.6/src/caelterra/skills/optimise-skill/SKILL.md +224 -0
- caelterra-0.1.6/src/caelterra/skills/optimise-skill/agents/openai.yaml +4 -0
- caelterra-0.1.6/src/caelterra/skills/optimise-skill/references/definition.md +3 -0
- caelterra-0.1.6/src/caelterra/skills/optimise-skill/references/example_skill.md +33 -0
- caelterra-0.1.6/tests/__init__.py +0 -0
- caelterra-0.1.6/tests/conftest.py +36 -0
- caelterra-0.1.6/tests/integration/conftest.py +23 -0
- caelterra-0.1.6/tests/integration/test_cli.py +96 -0
- caelterra-0.1.6/tests/test_git_utils.py +65 -0
- caelterra-0.1.6/tests/test_sync.py +119 -0
- caelterra-0.1.6/uv.lock +672 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-and-publish:
|
|
14
|
+
name: Build, check, and publish to PyPI
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.11'
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v5
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: uv sync --dev
|
|
30
|
+
|
|
31
|
+
- name: Lint (ruff)
|
|
32
|
+
run: uv run ruff check .
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: uv run pytest --ignore=tests/integration/
|
|
36
|
+
|
|
37
|
+
- name: Extract version from tag
|
|
38
|
+
id: version
|
|
39
|
+
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
|
40
|
+
|
|
41
|
+
- name: Verify pyproject version matches tag
|
|
42
|
+
run: |
|
|
43
|
+
PYPROJECT_VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
|
|
44
|
+
TAG_VERSION="${{ steps.version.outputs.version }}"
|
|
45
|
+
if [ "$PYPROJECT_VERSION" != "$TAG_VERSION" ]; then
|
|
46
|
+
echo "❌ pyproject.toml version ($PYPROJECT_VERSION) != tag version ($TAG_VERSION)"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
echo "✅ Version $PYPROJECT_VERSION matches tag v$TAG_VERSION"
|
|
50
|
+
|
|
51
|
+
- name: Build package
|
|
52
|
+
run: uv build
|
|
53
|
+
|
|
54
|
+
- name: Publish to PyPI
|
|
55
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
56
|
+
|
|
57
|
+
- name: Create GitHub Release
|
|
58
|
+
uses: softprops/action-gh-release@v2
|
|
59
|
+
with:
|
|
60
|
+
name: "v${{ steps.version.outputs.version }}"
|
|
61
|
+
files: dist/*
|
|
62
|
+
draft: false
|
|
63
|
+
prerelease: false
|
|
64
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.11.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
name: ruff lint
|
|
7
|
+
args: [--exit-non-zero-on-fix]
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
10
|
+
rev: v1.16.1
|
|
11
|
+
hooks:
|
|
12
|
+
- id: mypy
|
|
13
|
+
name: mypy strict
|
|
14
|
+
args: [--strict]
|
|
15
|
+
additional_dependencies: [pytest]
|
|
16
|
+
|
|
17
|
+
- repo: https://github.com/psf/black-pre-commit-mirror
|
|
18
|
+
rev: 25.1.0
|
|
19
|
+
hooks:
|
|
20
|
+
- id: black
|
|
21
|
+
name: black format
|
|
22
|
+
args: [--quiet]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the **Caelterra** Hermes plugin are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## v0.1.5 — 2026-07-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Auto-detect default profile on `update`** — `_sync_installed_profiles()` now
|
|
15
|
+
detects the `default` profile even when it was never explicitly set up via
|
|
16
|
+
`caelterra setup`. If `~/.hermes/config.yaml` exists, the default profile is
|
|
17
|
+
auto-included in the sync, keeping its SOUL.md in lockstep with the bundle.
|
|
18
|
+
- **Tests** — 5 new tests covering auto-detect with SOUL.md, skills-only,
|
|
19
|
+
already-in-state, missing config.yaml, and skipped stale profiles.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `hermes caelterra update` now correctly updates the default profile's SOUL.md
|
|
24
|
+
even when the profile was not previously recorded in the installation state.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## v0.1.2 — 2026-07-11
|
|
29
|
+
|
|
30
|
+
Multi-profile support with state tracking. Removed `install.sh` — installation is now done exclusively via `hermes plugins install`.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **CLI: `status`** — shows per-profile Caelterra installation status (Skills only vs Skills + SOUL.md), last updated time, and lists profiles without Caelterra
|
|
35
|
+
- **State management** (`~/.hermes/caelterra_state.json`) — JSON file tracking installation mode and timestamp per profile
|
|
36
|
+
- **Multi-profile `setup`** — interactive profile selection (comma-separated or `all`), then choose Skills only or Skills + SOUL.md; installs to all selected profiles
|
|
37
|
+
- **Profile sync on `update`** — after pulling latest code, updates SOUL.md per each profile's recorded state (skills-only vs skills+SOUL.md)
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- `setup` now lists all available Hermes profiles and lets you select which ones to install to
|
|
42
|
+
- `update` refreshes SOUL.md automatically for profiles that were set up with `Skills + SOUL.md` mode
|
|
43
|
+
- Plugin version bumped to 0.1.2
|
|
44
|
+
|
|
45
|
+
### Removed
|
|
46
|
+
|
|
47
|
+
- **`install.sh`** — no longer needed; public repo supports `hermes plugins install LaiTszKin/caelterra` directly
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## v0.1.0 — 2026-07-11
|
|
52
|
+
|
|
53
|
+
Initial release. Caelterra is a Hermes plugin for team standardisation,
|
|
54
|
+
replacing the old `@laitszkin/apollo-toolkit` npm package.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **Plugin structure** — `__init__.py` entry point with `register()`, `plugin.yaml` manifest, `pyproject.toml`
|
|
59
|
+
- **Bundled skill** — `optimise-skill` for analysing and optimising SKILL.md files
|
|
60
|
+
- **CLI: `setup`** — creates `caelterra` Hermes profile, writes SOUL.md, installs bundled skills to global skills directory. Interactive prompt when overwriting existing SOUL.md (default: yes)
|
|
61
|
+
- **CLI: `update --check`** — fetches remote refs from GitHub and reports ahead/behind status
|
|
62
|
+
- **CLI: `update`** — fast-forward pulls latest changes, detects and removes stale bundled skills (interactive, default: yes), updates remaining skills, prompts before overwriting SOUL.md (default: yes)
|
|
63
|
+
- **Git utilities** (`git_utils.py` with TypedDict return types) — `is_git_repo`, `get_local_head`, `get_remote_url`, `get_default_branch`, `fetch_remote`, `get_remote_head`, `get_ahead_behind`, `pull_branch`
|
|
64
|
+
- **Interactive prompts** — `_prompt_yes_no()` with TTY detection, falls back to defaults in non-interactive (curl pipe) environments
|
|
65
|
+
- **Stale skill detection** — compares `~/.hermes/skills/` against bundled skills, interactively removes orphaned skills
|
|
66
|
+
- **Agent identity** (`SOUL.md`) — follows Hermes recommended format (Vibe / Style / Anti-Patterns / Technical posture)
|
|
67
|
+
- **Remote install** (`install.sh`) — single `curl ... | bash` command for team members
|
|
68
|
+
- **Quality gates** — `ruff check .`, `mypy --strict .`, `pre-commit` hooks (ruff → mypy → black)
|
|
69
|
+
- **Tests** — 10 pytest tests covering all `git_utils` functions with temporary git repositories
|
|
70
|
+
- **Documentation** — `README.md` (feature table, install guides, CLI reference, architecture overview, FAQ), `DEPRECATED.md` (npm deprecation instructions)
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
|
|
74
|
+
- Repository renamed from `apollo-toolkit` to `caelterra`
|
|
75
|
+
- Git history reset (orphan branch) — legacy npm package artifacts removed
|
|
76
|
+
- Build system migrated to `uv`
|
|
77
|
+
|
|
78
|
+
### Simplified
|
|
79
|
+
|
|
80
|
+
- Extracted `_is_skill_dir()` helper — replaced repeated `is_dir() and SKILL.md.exists()` pattern across 4 call sites
|
|
81
|
+
- Flattened `_update_pull()` error handling — early return on failure instead of nested `if/else`
|
|
82
|
+
|
|
83
|
+
## v0.0.0 — Pre-history
|
|
84
|
+
|
|
85
|
+
Before v0.1.0 this repository was the `@laitszkin/apollo-toolkit` npm package
|
|
86
|
+
(v0.2.0 – v5.3.2). That package has been deprecated. See `DEPRECATED.md` for
|
|
87
|
+
details.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Deprecated Packages
|
|
2
|
+
|
|
3
|
+
This repository was formerly the `@laitszkin/apollo-toolkit` npm package (v0.2.0 - v5.3.2).
|
|
4
|
+
|
|
5
|
+
It has been **repurposed** into the **Caelterra** Hermes plugin for team standardisation.
|
|
6
|
+
|
|
7
|
+
## Deprecation Instructions
|
|
8
|
+
|
|
9
|
+
If you have access to publish to the `@laitszkin/apollo-toolkit` npm package, deprecate it:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm deprecate @laitszkin/apollo-toolkit \
|
|
13
|
+
"This package has been deprecated. The repository is now Caelterra — a Hermes plugin for team standardisation. See https://github.com/LaiTszKin/caelterra"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
To deprecate specific versions:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm deprecate @laitszkin/apollo-toolkit@"<6.0.0" \
|
|
20
|
+
"Apollo Toolkit has been replaced by Caelterra Hermes plugin. See https://github.com/LaiTszKin/caelterra"
|
|
21
|
+
```
|
caelterra-0.1.6/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LaiTszKin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
caelterra-0.1.6/PKG-INFO
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: caelterra
|
|
3
|
+
Version: 0.1.6
|
|
4
|
+
Summary: Caelterra — Team standardisation plugin for Hermes
|
|
5
|
+
Author-email: LaiTszKin <laitszkin1206@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: fabricium>=0.1.1
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Caelterra
|
|
2
|
+
|
|
3
|
+
Caelterra 是一個 [Hermes Agent](https://hermes-agent.nousresearch.com) plugin,為團隊提供標準化的技能(skills)和版本管理工具。
|
|
4
|
+
|
|
5
|
+
> **前身:** 這個 repository 原本是 npm 套件 `@laitszkin/apollo-toolkit`。
|
|
6
|
+
> 從 v0.1.0 開始已轉型為 Hermes plugin。詳見 [DEPRECATED.md](./DEPRECATED.md)。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 功能
|
|
11
|
+
|
|
12
|
+
| 功能 | 說明 |
|
|
13
|
+
|------|------|
|
|
14
|
+
| **Bundled Skills** | 隨 plugin 附帶的精良 skill,團隊一鍵載入 |
|
|
15
|
+
| **Multi-Profile Setup** | `hermes caelterra setup` — 選擇要安裝的 profiles,可選 skills only 或 skills + SOUL.md |
|
|
16
|
+
| **狀態查詢** | `hermes caelterra status` — 查看各 profile 的安裝狀態 |
|
|
17
|
+
| **更新檢查** | `hermes caelterra update --check` — 比對 GitHub 有無新版本 |
|
|
18
|
+
| **自動更新** | `hermes caelterra update` — 拉取最新版,**自動偵測並移除過時 skill**,並依先前設定同步各 profile |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 安裝
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install caelterra && hermes plugins enable caelterra
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> `fabricium` 會作為依賴自動安裝。
|
|
29
|
+
|
|
30
|
+
安裝後執行:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
hermes caelterra setup
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
互動式選擇目標 profiles 和安裝模式即可。
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 使用方式
|
|
41
|
+
|
|
42
|
+
### CLI 命令
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
hermes caelterra setup # 互動式:選 profiles、選模式、安裝
|
|
46
|
+
hermes caelterra status # 查看各 profile 安裝狀態
|
|
47
|
+
hermes caelterra update --check # 檢查 GitHub 是否有新版本
|
|
48
|
+
hermes caelterra update # 拉取最新版 + 清理過時 skill + 同步 profiles
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 啟動 session
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
hermes -p caelterra
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 載入 skill
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 在 Hermes session 中
|
|
61
|
+
skill_view('optimise-skill')
|
|
62
|
+
|
|
63
|
+
# 或啟動時載入
|
|
64
|
+
hermes -s optimise-skill
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Bundled Skills
|
|
70
|
+
|
|
71
|
+
| Skill | 用途 |
|
|
72
|
+
|-------|------|
|
|
73
|
+
| `optimise-skill` | 五階段優化 SKILL.md:審查 → 解耦 → 重寫 → 驗證(含觸發測試、模擬執行、邊界攻擊)→ 交付。核心方法:三層分離 + Delta from Baseline + Gotchas 提取 |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 架構概覽
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
caelterra/
|
|
81
|
+
├── __init__.py # Plugin 入口:register() + CLI handlers
|
|
82
|
+
│ ├── _load_state() # 讀取安裝狀態 (JSON)
|
|
83
|
+
│ ├── _set_profile_state() # 寫入 profile 安裝狀態
|
|
84
|
+
│ ├── _list_profiles() # 掃描 ~/.hermes/profiles/
|
|
85
|
+
│ ├── _prompt_yes_no() # 互動式 yes/no,非 TTY 時自動默認
|
|
86
|
+
│ ├── _prompt_select_profiles() # 多選 profiles
|
|
87
|
+
│ ├── _ensure_profile() # 建立 Hermes profile
|
|
88
|
+
│ ├── _apply_soul_md() # 寫入 SOUL.md
|
|
89
|
+
│ ├── _is_skill_dir() # 判斷目錄是否為有效 skill
|
|
90
|
+
│ ├── _get_bundled_skill_names() # 掃描 bundled skills
|
|
91
|
+
│ ├── _remove_installed_skill() # 刪除已安裝的 skill
|
|
92
|
+
│ ├── _remove_stale_skills() # 偵測過時 skill
|
|
93
|
+
│ ├── _install_bundled_skills() # 安裝所有 bundled skills
|
|
94
|
+
│ ├── _setup_command() # setup CLI handler(multi-profile)
|
|
95
|
+
│ ├── _status_command() # status CLI handler
|
|
96
|
+
│ ├── _update_check() # update --check CLI handler
|
|
97
|
+
│ ├── _sync_installed_profiles() # 更新後同步 profiles
|
|
98
|
+
│ └── _update_pull() # update CLI handler(含 stale skill 檢測)
|
|
99
|
+
├── git_utils.py # Git 操作封裝(TypedDict)
|
|
100
|
+
│ ├── is_git_repo()
|
|
101
|
+
│ ├── get_local_head()
|
|
102
|
+
│ ├── get_remote_url()
|
|
103
|
+
│ ├── get_default_branch()
|
|
104
|
+
│ ├── fetch_remote()
|
|
105
|
+
│ ├── get_remote_head()
|
|
106
|
+
│ ├── get_ahead_behind()
|
|
107
|
+
│ └── pull_branch()
|
|
108
|
+
├── plugin.yaml # Hermes plugin manifest
|
|
109
|
+
├── pyproject.toml # Python 專案設定
|
|
110
|
+
├── .pre-commit-config.yaml # Pre-commit hooks(ruff → mypy → black)
|
|
111
|
+
├── SOUL.md # Agent identity(setup 時寫入 profile)
|
|
112
|
+
├── skills/
|
|
113
|
+
│ └── optimise-skill/ # Bundled skill
|
|
114
|
+
│ ├── SKILL.md
|
|
115
|
+
│ ├── agents/openai.yaml
|
|
116
|
+
│ └── references/
|
|
117
|
+
└── tests/
|
|
118
|
+
├── test_git_utils.py # 10 個 git_utils 單元測試
|
|
119
|
+
└── conftest.py # git repo fixture
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 更新流程
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
update 指令執行時:
|
|
126
|
+
|
|
127
|
+
1. 檢查有無未提交變更 → 有則阻止
|
|
128
|
+
2. Fetch remote refs
|
|
129
|
+
3. 檢查 ahead/behind → 如已最新則仍重新整理 skills + SOUL 後退出
|
|
130
|
+
4. Pull --ff-only
|
|
131
|
+
5. 掃描 ~/.hermes/skills/ 比對 bundled skills
|
|
132
|
+
→ 找出 installed 但 no longer bundled 的過時 skill
|
|
133
|
+
→ 互動式詢問是否刪除(默認是)
|
|
134
|
+
6. 更新其餘 skills
|
|
135
|
+
7. 讀取 ~/.hermes/caelterra_state.json
|
|
136
|
+
8. 對每個已安裝的 profile:
|
|
137
|
+
→ 更新 SOUL.md(如先前設定有包含)
|
|
138
|
+
→ 刷新 timestamp
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 安裝狀態
|
|
142
|
+
|
|
143
|
+
Caelterra 使用 `~/.hermes/caelterra_state.json` 追蹤各 profile 的安裝狀態:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"profiles": {
|
|
148
|
+
"caelterra": {
|
|
149
|
+
"soul_md": true,
|
|
150
|
+
"updated_at": "2026-07-11T12:00:00"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
- Profile 出現在 state → skills 已安裝
|
|
157
|
+
- `soul_md: true` → 該 profile 也安裝了 SOUL.md
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 開發
|
|
162
|
+
|
|
163
|
+
### 環境設定
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# 安裝依賴(含 dev)
|
|
167
|
+
uv sync --group dev
|
|
168
|
+
|
|
169
|
+
# 安裝 pre-commit hooks(提交前自動檢查)
|
|
170
|
+
uv run pre-commit install
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 品質關卡
|
|
174
|
+
|
|
175
|
+
提交前會自動執行(`pre-commit`):
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
uv run pre-commit run --all-files
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
執行順序:
|
|
182
|
+
|
|
183
|
+
| 關卡 | 失敗時 |
|
|
184
|
+
|------|--------|
|
|
185
|
+
| `ruff check .` | 禁止提交 |
|
|
186
|
+
| `mypy --strict .` | 禁止提交 |
|
|
187
|
+
| `black` | 自動 reformat |
|
|
188
|
+
|
|
189
|
+
### 執行測試
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
uv run pytest tests/ -v
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 型別檢查
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
uv run mypy --strict .
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Lint
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
uv run ruff check .
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## FAQ
|
|
210
|
+
|
|
211
|
+
### Caelterra 和 Jovaltus 有什麼關係?
|
|
212
|
+
|
|
213
|
+
沒有關係。Caelterra 是一個全新的 plugin,專注於團隊標準化的 skills 管理,不包含 Jovaltus 的開發 pipeline 功能。
|
|
214
|
+
|
|
215
|
+
### 如何新增一個 bundled skill?
|
|
216
|
+
|
|
217
|
+
在 `skills/` 下建立目錄,裡面放 `SKILL.md` 即可。Plugin 啟動時會自動註冊。
|
|
218
|
+
|
|
219
|
+
### 安裝狀態存在哪裡?
|
|
220
|
+
|
|
221
|
+
存在 `~/.hermes/caelterra_state.json`,追蹤每個 profile 的安裝模式和時間。
|
|
222
|
+
|
|
223
|
+
### 更新時如果有未提交變更?
|
|
224
|
+
|
|
225
|
+
更新會被阻止,系統會列出 dirty files,告訴你先 stash 或 commit。
|
|
226
|
+
|
|
227
|
+
### 支援同時安裝到多個 profile 嗎?
|
|
228
|
+
|
|
229
|
+
支援。`setup` 時可選擇多個 profiles,`update` 時會自動同步所有已安裝的 profiles。
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## 版本記錄
|
|
234
|
+
|
|
235
|
+
| 版本 | 日期 | 說明 |
|
|
236
|
+
|------|------|------|
|
|
237
|
+
| v0.1.1 | 2026-07-11 | Multi-profile setup/status/update、狀態管理 JSON、移除 install.sh |
|
|
238
|
+
| v0.1.0 | 2026-07-11 | 初始版本。Plugin 結構、setup/update CLI、optimise-skill 捆綁、互動式 prompt、stale skill 偵測移除、ruff + mypy + black pre-commit |
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT © LaiTszKin
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "caelterra"
|
|
3
|
+
version = "0.1.6"
|
|
4
|
+
description = "Caelterra — Team standardisation plugin for Hermes"
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
authors = [{ name = "LaiTszKin", email = "laitszkin1206@gmail.com" }]
|
|
8
|
+
dependencies = [
|
|
9
|
+
"fabricium>=0.1.1",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[project.entry-points."hermes_agent.plugins"]
|
|
13
|
+
caelterra = "caelterra"
|
|
14
|
+
|
|
15
|
+
[dependency-groups]
|
|
16
|
+
dev = [
|
|
17
|
+
"pytest>=8",
|
|
18
|
+
"ruff>=0.8",
|
|
19
|
+
"mypy>=1.16",
|
|
20
|
+
"black>=25",
|
|
21
|
+
"pre-commit>=4",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["hatchling"]
|
|
26
|
+
build-backend = "hatchling.build"
|
|
27
|
+
|
|
28
|
+
[tool.hatch.build.targets.wheel]
|
|
29
|
+
packages = ["src/caelterra"]
|
|
30
|
+
|
|
31
|
+
[tool.ruff]
|
|
32
|
+
target-version = "py310"
|
|
33
|
+
line-length = 100
|
|
34
|
+
|
|
35
|
+
[tool.ruff.lint]
|
|
36
|
+
select = ["E", "F", "I", "N", "W"]
|
|
37
|
+
|
|
38
|
+
[tool.black]
|
|
39
|
+
target-version = ["py310"]
|
|
40
|
+
line-length = 100
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Caelterra
|
|
2
|
+
|
|
3
|
+
You are a general-purpose assistant who solves problems.
|
|
4
|
+
You get things done — no matter the domain.
|
|
5
|
+
|
|
6
|
+
## Vibe
|
|
7
|
+
|
|
8
|
+
- Be direct. Say the thing. Skip the build-up.
|
|
9
|
+
- Have opinions. When one approach is better, say so.
|
|
10
|
+
- Brevity is a feature. If one sentence does it, stop there.
|
|
11
|
+
- When you don't know, say you don't know. No guessing, no hedging.
|
|
12
|
+
- Switch to Cantonese or Chinese when the user does; keep technical terms in English.
|
|
13
|
+
|
|
14
|
+
## Style
|
|
15
|
+
|
|
16
|
+
- Lead with the answer, then context if needed.
|
|
17
|
+
- Push back on bad ideas, weak assumptions, and vague requirements.
|
|
18
|
+
- Prefer concrete examples over abstract explanations.
|
|
19
|
+
- Structure complex answers — headings, lists, code blocks — so they scan.
|
|
20
|
+
- Admit uncertainty plainly: "I don't know" not "it might be possible that..."
|
|
21
|
+
|
|
22
|
+
## Anti-Patterns
|
|
23
|
+
|
|
24
|
+
- No sycophancy. Don't flatter a bad idea.
|
|
25
|
+
- No filler. "Great question!" is never the right opener.
|
|
26
|
+
- No over-explaining. Don't restate what the user already said.
|
|
27
|
+
- No false confidence. Don't fabricate an answer when the evidence is thin.
|
|
28
|
+
|
|
29
|
+
## Technical posture
|
|
30
|
+
|
|
31
|
+
- Simple systems beat clever systems. Prefer boring, proven patterns.
|
|
32
|
+
- Standards exist so teams don't have to rediscover every trade-off.
|
|
33
|
+
- If something can be verified automatically, it should be.
|
|
34
|
+
- Good solutions are reproducible and explainable to others.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Caelterra — team standardisation plugin for Hermes.
|
|
2
|
+
|
|
3
|
+
Registers bundled skills and CLI commands for multi-profile
|
|
4
|
+
setup, status, and version management.
|
|
5
|
+
|
|
6
|
+
Install via: hermes plugins install LaiTszKin/caelterra
|
|
7
|
+
|
|
8
|
+
Powered by Fabricium — shared Hermes plugin infrastructure.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from fabricium import HermesPlugin
|
|
17
|
+
from fabricium import state as fabricium_state
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class CaelterraPlugin(HermesPlugin):
|
|
23
|
+
"""Caelterra-specific plugin with multi-profile auto-detection.
|
|
24
|
+
|
|
25
|
+
Extends Fabricium's HermesPlugin with auto-detection of the
|
|
26
|
+
'default' profile during sync. When `caelterra update` runs,
|
|
27
|
+
if the default profile exists (~/.hermes/config.yaml) but
|
|
28
|
+
isn't in the installation state, it's auto-detected and synced.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def _sync_installed_profiles(self, context: str = "") -> None:
|
|
32
|
+
"""Override to auto-detect the 'default' profile.
|
|
33
|
+
|
|
34
|
+
Caelterra's multi-profile mode should keep the global
|
|
35
|
+
'default' profile in sync even when it wasn't explicitly
|
|
36
|
+
set up via `caelterra setup`.
|
|
37
|
+
"""
|
|
38
|
+
s = self._load_state()
|
|
39
|
+
profiles_state = s.get("profiles", {})
|
|
40
|
+
|
|
41
|
+
if not profiles_state:
|
|
42
|
+
print("\n No profiles in installation state.")
|
|
43
|
+
print(f" Run: hermes {self.name} setup")
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
ctx = f" ({context})" if context else ""
|
|
47
|
+
print(f"\n{'─' * 40}")
|
|
48
|
+
print(f"🔄 Syncing profiles{ctx}")
|
|
49
|
+
|
|
50
|
+
ts = datetime.now().isoformat(timespec="seconds")
|
|
51
|
+
|
|
52
|
+
# Auto-detect the "default" profile
|
|
53
|
+
default_home = fabricium_state._get_global_hermes_home()
|
|
54
|
+
if "default" not in profiles_state and (default_home / "config.yaml").exists():
|
|
55
|
+
has_soul = (default_home / "SOUL.md").exists()
|
|
56
|
+
profiles_state["default"] = {"soul_md": has_soul}
|
|
57
|
+
s["profiles"]["default"] = {"soul_md": has_soul, "updated_at": ts}
|
|
58
|
+
print("\n 📋 Auto-detected 'default' profile for syncing")
|
|
59
|
+
|
|
60
|
+
synced = 0
|
|
61
|
+
for profile_name, info in sorted(profiles_state.items()):
|
|
62
|
+
profile_dir = self._get_profile_dir(profile_name)
|
|
63
|
+
if not profile_dir.exists() or not (profile_dir / "config.yaml").exists():
|
|
64
|
+
print(f"\n ⏭ Profile '{profile_name}' no longer exists — skipping")
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
print(f"\n📁 Profile: {profile_name}")
|
|
68
|
+
|
|
69
|
+
if info.get("soul_md"):
|
|
70
|
+
print(" 🧠 Updating SOUL.md...")
|
|
71
|
+
self._apply_soul_md(profile_name)
|
|
72
|
+
else:
|
|
73
|
+
print(" ✓ Skills only (SOUL.md not tracked)")
|
|
74
|
+
|
|
75
|
+
s["profiles"][profile_name]["updated_at"] = ts
|
|
76
|
+
synced += 1
|
|
77
|
+
|
|
78
|
+
self._save_state(s)
|
|
79
|
+
print(f"\n ✅ {synced} profile(s) synced")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
plugin = CaelterraPlugin(
|
|
83
|
+
name="caelterra",
|
|
84
|
+
plugin_dir=Path(__file__).parent,
|
|
85
|
+
default_profile=None, # multi-profile mode
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def register(ctx: Any) -> None:
|
|
90
|
+
"""Register CLI commands and bundled skills with Hermes."""
|
|
91
|
+
plugin.register(ctx)
|
|
92
|
+
logger.info("Caelterra registered (via Fabricium)")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Backward-compatibility re-export from fabricium.git_utils.
|
|
2
|
+
|
|
3
|
+
All git utilities now live in Fabricium — the shared Hermes plugin
|
|
4
|
+
infrastructure library. This module exists so existing imports
|
|
5
|
+
like ``from caelterra import git_utils`` continue to work.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from fabricium.git_utils import ( # noqa: F401
|
|
9
|
+
AheadBehind,
|
|
10
|
+
CommitResult,
|
|
11
|
+
FetchResult,
|
|
12
|
+
PullResult,
|
|
13
|
+
commit,
|
|
14
|
+
fetch_remote,
|
|
15
|
+
get_ahead_behind,
|
|
16
|
+
get_default_branch,
|
|
17
|
+
get_diff,
|
|
18
|
+
get_diff_stat,
|
|
19
|
+
get_head_hash,
|
|
20
|
+
get_local_head,
|
|
21
|
+
get_remote_head,
|
|
22
|
+
get_remote_url,
|
|
23
|
+
is_ancestor,
|
|
24
|
+
is_git_repo,
|
|
25
|
+
pull_branch,
|
|
26
|
+
stage_all,
|
|
27
|
+
)
|