mars-agents 0.0.3__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.
- mars_agents-0.0.3/.github/workflows/ci.yml +39 -0
- mars_agents-0.0.3/.github/workflows/release.yml +270 -0
- mars_agents-0.0.3/.gitignore +6 -0
- mars_agents-0.0.3/AGENTS.md +152 -0
- mars_agents-0.0.3/CLAUDE.md +152 -0
- mars_agents-0.0.3/Cargo.lock +1431 -0
- mars_agents-0.0.3/Cargo.toml +40 -0
- mars_agents-0.0.3/LICENSE +21 -0
- mars_agents-0.0.3/PKG-INFO +85 -0
- mars_agents-0.0.3/README.md +68 -0
- mars_agents-0.0.3/npm/.gitignore +4 -0
- mars_agents-0.0.3/npm/@haowjy/mars-agents/bin/mars +44 -0
- mars_agents-0.0.3/npm/@haowjy/mars-agents/package.json +23 -0
- mars_agents-0.0.3/npm/@haowjy/mars-agents-darwin-arm64/package.json +13 -0
- mars_agents-0.0.3/npm/@haowjy/mars-agents-darwin-x64/package.json +13 -0
- mars_agents-0.0.3/npm/@haowjy/mars-agents-linux-arm64/package.json +14 -0
- mars_agents-0.0.3/npm/@haowjy/mars-agents-linux-x64/package.json +14 -0
- mars_agents-0.0.3/pyproject.toml +25 -0
- mars_agents-0.0.3/scripts/release.sh +187 -0
- mars_agents-0.0.3/src/cli/add.rs +239 -0
- mars_agents-0.0.3/src/cli/cache.rs +182 -0
- mars_agents-0.0.3/src/cli/check.rs +367 -0
- mars_agents-0.0.3/src/cli/doctor.rs +212 -0
- mars_agents-0.0.3/src/cli/init.rs +219 -0
- mars_agents-0.0.3/src/cli/link.rs +790 -0
- mars_agents-0.0.3/src/cli/list.rs +186 -0
- mars_agents-0.0.3/src/cli/mod.rs +343 -0
- mars_agents-0.0.3/src/cli/outdated.rs +167 -0
- mars_agents-0.0.3/src/cli/output.rs +418 -0
- mars_agents-0.0.3/src/cli/override_cmd.rs +42 -0
- mars_agents-0.0.3/src/cli/remove.rs +34 -0
- mars_agents-0.0.3/src/cli/rename.rs +51 -0
- mars_agents-0.0.3/src/cli/repair.rs +104 -0
- mars_agents-0.0.3/src/cli/resolve_cmd.rs +95 -0
- mars_agents-0.0.3/src/cli/sync.rs +41 -0
- mars_agents-0.0.3/src/cli/upgrade.rs +35 -0
- mars_agents-0.0.3/src/cli/why.rs +133 -0
- mars_agents-0.0.3/src/config/mod.rs +703 -0
- mars_agents-0.0.3/src/discover/mod.rs +653 -0
- mars_agents-0.0.3/src/error.rs +278 -0
- mars_agents-0.0.3/src/frontmatter/mod.rs +273 -0
- mars_agents-0.0.3/src/fs/mod.rs +405 -0
- mars_agents-0.0.3/src/hash/mod.rs +217 -0
- mars_agents-0.0.3/src/lib.rs +15 -0
- mars_agents-0.0.3/src/lock/mod.rs +524 -0
- mars_agents-0.0.3/src/main.rs +6 -0
- mars_agents-0.0.3/src/manifest/mod.rs +188 -0
- mars_agents-0.0.3/src/merge/mod.rs +359 -0
- mars_agents-0.0.3/src/resolve/mod.rs +2009 -0
- mars_agents-0.0.3/src/source/git.rs +907 -0
- mars_agents-0.0.3/src/source/mod.rs +101 -0
- mars_agents-0.0.3/src/source/parse.rs +521 -0
- mars_agents-0.0.3/src/source/path.rs +152 -0
- mars_agents-0.0.3/src/sync/apply.rs +941 -0
- mars_agents-0.0.3/src/sync/diff.rs +595 -0
- mars_agents-0.0.3/src/sync/mod.rs +1124 -0
- mars_agents-0.0.3/src/sync/plan.rs +408 -0
- mars_agents-0.0.3/src/sync/target.rs +1180 -0
- mars_agents-0.0.3/src/types.rs +343 -0
- mars_agents-0.0.3/src/validate/mod.rs +322 -0
- mars_agents-0.0.3/tests/cli_integration.rs +4 -0
- mars_agents-0.0.3/tests/integration/mod.rs +1231 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
CARGO_TERM_COLOR: always
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
check:
|
|
13
|
+
name: Check (${{ matrix.rust }})
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
rust: [stable, nightly]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- uses: dtolnay/rust-toolchain@master
|
|
23
|
+
with:
|
|
24
|
+
toolchain: ${{ matrix.rust }}
|
|
25
|
+
components: rustfmt, clippy
|
|
26
|
+
|
|
27
|
+
- uses: Swatinem/rust-cache@v2
|
|
28
|
+
|
|
29
|
+
- name: Build
|
|
30
|
+
run: cargo build
|
|
31
|
+
|
|
32
|
+
- name: Test
|
|
33
|
+
run: cargo test
|
|
34
|
+
|
|
35
|
+
- name: Clippy
|
|
36
|
+
run: cargo clippy -- -D warnings
|
|
37
|
+
|
|
38
|
+
- name: Format check
|
|
39
|
+
run: cargo fmt --check
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
env:
|
|
8
|
+
CARGO_TERM_COLOR: always
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
name: Build (${{ matrix.target }})
|
|
13
|
+
runs-on: ${{ matrix.runner }}
|
|
14
|
+
strategy:
|
|
15
|
+
matrix:
|
|
16
|
+
include:
|
|
17
|
+
- target: x86_64-unknown-linux-gnu
|
|
18
|
+
runner: ubuntu-latest
|
|
19
|
+
artifact: mars-linux-x64
|
|
20
|
+
- target: aarch64-unknown-linux-gnu
|
|
21
|
+
runner: ubuntu-latest
|
|
22
|
+
artifact: mars-linux-arm64
|
|
23
|
+
- target: aarch64-apple-darwin
|
|
24
|
+
runner: macos-latest
|
|
25
|
+
artifact: mars-darwin-arm64
|
|
26
|
+
- target: x86_64-apple-darwin
|
|
27
|
+
runner: macos-15-intel
|
|
28
|
+
artifact: mars-darwin-x64
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
|
+
|
|
32
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
33
|
+
with:
|
|
34
|
+
targets: ${{ matrix.target }}
|
|
35
|
+
|
|
36
|
+
- uses: Swatinem/rust-cache@v2
|
|
37
|
+
with:
|
|
38
|
+
key: ${{ matrix.target }}
|
|
39
|
+
|
|
40
|
+
- name: Install Linux ARM64 cross toolchain
|
|
41
|
+
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
|
42
|
+
run: |
|
|
43
|
+
sudo apt-get update
|
|
44
|
+
sudo apt-get install -y gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
|
|
45
|
+
|
|
46
|
+
- name: Build
|
|
47
|
+
if: matrix.target != 'aarch64-unknown-linux-gnu'
|
|
48
|
+
run: cargo build --release --target ${{ matrix.target }}
|
|
49
|
+
|
|
50
|
+
- name: Build (Linux ARM64)
|
|
51
|
+
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
|
52
|
+
env:
|
|
53
|
+
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
|
54
|
+
run: cargo build --release --target ${{ matrix.target }}
|
|
55
|
+
|
|
56
|
+
- name: Strip binary
|
|
57
|
+
if: matrix.target != 'aarch64-unknown-linux-gnu'
|
|
58
|
+
run: strip target/${{ matrix.target }}/release/mars
|
|
59
|
+
|
|
60
|
+
- name: Strip binary (Linux ARM64)
|
|
61
|
+
if: matrix.target == 'aarch64-unknown-linux-gnu'
|
|
62
|
+
run: aarch64-linux-gnu-strip target/${{ matrix.target }}/release/mars
|
|
63
|
+
|
|
64
|
+
- name: Rename binary
|
|
65
|
+
run: cp target/${{ matrix.target }}/release/mars ${{ matrix.artifact }}
|
|
66
|
+
|
|
67
|
+
- uses: actions/upload-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: ${{ matrix.artifact }}
|
|
70
|
+
path: ${{ matrix.artifact }}
|
|
71
|
+
|
|
72
|
+
pypi-wheels:
|
|
73
|
+
name: Build PyPI wheels (${{ matrix.target }})
|
|
74
|
+
runs-on: ${{ matrix.runner }}
|
|
75
|
+
strategy:
|
|
76
|
+
matrix:
|
|
77
|
+
include:
|
|
78
|
+
- target: x86_64-unknown-linux-gnu
|
|
79
|
+
runner: ubuntu-latest
|
|
80
|
+
artifact: wheels-linux-x64
|
|
81
|
+
- target: aarch64-unknown-linux-gnu
|
|
82
|
+
runner: ubuntu-24.04-arm
|
|
83
|
+
artifact: wheels-linux-arm64
|
|
84
|
+
- target: aarch64-apple-darwin
|
|
85
|
+
runner: macos-latest
|
|
86
|
+
artifact: wheels-darwin-arm64
|
|
87
|
+
- target: x86_64-apple-darwin
|
|
88
|
+
runner: macos-15-intel
|
|
89
|
+
artifact: wheels-darwin-x64
|
|
90
|
+
steps:
|
|
91
|
+
- uses: actions/checkout@v4
|
|
92
|
+
|
|
93
|
+
- name: Build wheels
|
|
94
|
+
uses: PyO3/maturin-action@v1
|
|
95
|
+
with:
|
|
96
|
+
command: build
|
|
97
|
+
target: ${{ matrix.target }}
|
|
98
|
+
manylinux: auto
|
|
99
|
+
args: --release --out dist
|
|
100
|
+
|
|
101
|
+
- uses: actions/upload-artifact@v4
|
|
102
|
+
with:
|
|
103
|
+
name: ${{ matrix.artifact }}
|
|
104
|
+
path: dist/*.whl
|
|
105
|
+
|
|
106
|
+
pypi-sdist:
|
|
107
|
+
name: Build PyPI sdist
|
|
108
|
+
runs-on: ubuntu-latest
|
|
109
|
+
steps:
|
|
110
|
+
- uses: actions/checkout@v4
|
|
111
|
+
|
|
112
|
+
- name: Build sdist
|
|
113
|
+
uses: PyO3/maturin-action@v1
|
|
114
|
+
with:
|
|
115
|
+
command: sdist
|
|
116
|
+
args: --out dist
|
|
117
|
+
|
|
118
|
+
- uses: actions/upload-artifact@v4
|
|
119
|
+
with:
|
|
120
|
+
name: sdist
|
|
121
|
+
path: dist/*.tar.gz
|
|
122
|
+
|
|
123
|
+
pypi-publish:
|
|
124
|
+
name: Publish PyPI
|
|
125
|
+
needs: [pypi-wheels, pypi-sdist]
|
|
126
|
+
runs-on: ubuntu-latest
|
|
127
|
+
environment: pypi
|
|
128
|
+
permissions:
|
|
129
|
+
id-token: write
|
|
130
|
+
steps:
|
|
131
|
+
- uses: actions/download-artifact@v4
|
|
132
|
+
with:
|
|
133
|
+
path: dist
|
|
134
|
+
pattern: wheels-*
|
|
135
|
+
merge-multiple: true
|
|
136
|
+
|
|
137
|
+
- uses: actions/download-artifact@v4
|
|
138
|
+
with:
|
|
139
|
+
path: dist
|
|
140
|
+
name: sdist
|
|
141
|
+
|
|
142
|
+
- name: Publish to PyPI
|
|
143
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
144
|
+
with:
|
|
145
|
+
packages-dir: dist
|
|
146
|
+
|
|
147
|
+
github-release:
|
|
148
|
+
name: GitHub Release
|
|
149
|
+
needs: build
|
|
150
|
+
runs-on: ubuntu-latest
|
|
151
|
+
permissions:
|
|
152
|
+
contents: write
|
|
153
|
+
steps:
|
|
154
|
+
- uses: actions/checkout@v4
|
|
155
|
+
|
|
156
|
+
- uses: actions/download-artifact@v4
|
|
157
|
+
with:
|
|
158
|
+
path: artifacts/
|
|
159
|
+
merge-multiple: true
|
|
160
|
+
|
|
161
|
+
- name: Create release
|
|
162
|
+
uses: softprops/action-gh-release@v2
|
|
163
|
+
with:
|
|
164
|
+
generate_release_notes: true
|
|
165
|
+
files: artifacts/mars-*
|
|
166
|
+
|
|
167
|
+
npm-publish:
|
|
168
|
+
name: Publish npm packages
|
|
169
|
+
needs: build
|
|
170
|
+
runs-on: ubuntu-latest
|
|
171
|
+
permissions:
|
|
172
|
+
id-token: write
|
|
173
|
+
steps:
|
|
174
|
+
- uses: actions/checkout@v4
|
|
175
|
+
|
|
176
|
+
- uses: actions/setup-node@v4
|
|
177
|
+
with:
|
|
178
|
+
node-version: "lts/*"
|
|
179
|
+
registry-url: "https://registry.npmjs.org"
|
|
180
|
+
|
|
181
|
+
- name: Ensure npm supports trusted publishing
|
|
182
|
+
run: npm install -g npm@latest
|
|
183
|
+
|
|
184
|
+
- uses: actions/download-artifact@v4
|
|
185
|
+
with:
|
|
186
|
+
path: artifacts/
|
|
187
|
+
pattern: mars-*
|
|
188
|
+
merge-multiple: true
|
|
189
|
+
|
|
190
|
+
- name: Extract version from tag
|
|
191
|
+
id: version
|
|
192
|
+
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
|
193
|
+
|
|
194
|
+
- name: Verify tag matches Cargo.toml
|
|
195
|
+
run: |
|
|
196
|
+
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
|
197
|
+
TAG_VERSION=${{ steps.version.outputs.version }}
|
|
198
|
+
if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
|
|
199
|
+
echo "::error::Tag version ($TAG_VERSION) does not match Cargo.toml ($CARGO_VERSION)"
|
|
200
|
+
exit 1
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
- name: Prepare and publish platform packages
|
|
204
|
+
run: |
|
|
205
|
+
VERSION=${{ steps.version.outputs.version }}
|
|
206
|
+
|
|
207
|
+
publish_platform() {
|
|
208
|
+
local pkg_dir=$1
|
|
209
|
+
local binary=$2
|
|
210
|
+
local pkg_name
|
|
211
|
+
pkg_name=$(node -e "console.log(require('./$pkg_dir/package.json').name)")
|
|
212
|
+
|
|
213
|
+
# Skip if already published (idempotent on re-run)
|
|
214
|
+
if npm view "$pkg_name@$VERSION" version >/dev/null 2>&1; then
|
|
215
|
+
echo "Skipping $pkg_name@$VERSION — already published"
|
|
216
|
+
return 0
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
(
|
|
220
|
+
cd "$pkg_dir"
|
|
221
|
+
npm version "$VERSION" --no-git-tag-version --allow-same-version
|
|
222
|
+
cp "$GITHUB_WORKSPACE/artifacts/$binary" mars
|
|
223
|
+
chmod +x mars
|
|
224
|
+
npm publish --provenance --access public
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
publish_platform npm/@haowjy/mars-agents-linux-x64 mars-linux-x64
|
|
229
|
+
publish_platform npm/@haowjy/mars-agents-linux-arm64 mars-linux-arm64
|
|
230
|
+
publish_platform npm/@haowjy/mars-agents-darwin-arm64 mars-darwin-arm64
|
|
231
|
+
publish_platform npm/@haowjy/mars-agents-darwin-x64 mars-darwin-x64
|
|
232
|
+
|
|
233
|
+
- name: Publish CLI stub package
|
|
234
|
+
run: |
|
|
235
|
+
VERSION=${{ steps.version.outputs.version }}
|
|
236
|
+
|
|
237
|
+
# Skip if already published
|
|
238
|
+
if npm view "@haowjy/mars-agents@$VERSION" version >/dev/null 2>&1; then
|
|
239
|
+
echo "Skipping @haowjy/mars-agents@$VERSION — already published"
|
|
240
|
+
exit 0
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
(
|
|
244
|
+
cd npm/@haowjy/mars-agents
|
|
245
|
+
node -e "
|
|
246
|
+
const pkg = require('./package.json');
|
|
247
|
+
pkg.version = '$VERSION';
|
|
248
|
+
for (const dep of Object.keys(pkg.optionalDependencies || {})) {
|
|
249
|
+
pkg.optionalDependencies[dep] = '$VERSION';
|
|
250
|
+
}
|
|
251
|
+
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
252
|
+
"
|
|
253
|
+
npm publish --provenance --access public
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
cargo-publish:
|
|
257
|
+
name: Publish crate
|
|
258
|
+
needs: build
|
|
259
|
+
runs-on: ubuntu-latest
|
|
260
|
+
permissions:
|
|
261
|
+
contents: read
|
|
262
|
+
steps:
|
|
263
|
+
- uses: actions/checkout@v4
|
|
264
|
+
|
|
265
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
266
|
+
|
|
267
|
+
- name: Publish to crates.io
|
|
268
|
+
env:
|
|
269
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
270
|
+
run: cargo publish || true
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Development Guide: mars-agents
|
|
2
|
+
|
|
3
|
+
Mars is an agent package manager for `.agents/` directories. It installs agent profiles and skills from git/local sources, tracks ownership in `mars.lock`, and links managed content into tool directories like `.claude/`.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
1. **Resolve first, then act.** Validate + build full desired state before mutating files. If any conflict or error is detected during resolution, zero mutations occur.
|
|
8
|
+
- *Why*: Partial failures leave users in states that are hard to diagnose. A user who sees "3 conflicts" can fix all three and retry. A user whose command half-completed has to figure out what happened first.
|
|
9
|
+
|
|
10
|
+
2. **Atomic writes.** Config, lock, and installed files use temp + rename. Crash mid-write leaves the old file intact.
|
|
11
|
+
- *Why*: Mars manages files that agents and tools read continuously. A half-written mars.toml breaks every tool that reads it. tmp + rename is atomic on POSIX — no recovery logic needed.
|
|
12
|
+
|
|
13
|
+
3. **Lock file is authority.** `mars.lock` defines managed ownership and checksums. If it's not in the lock, it's not managed.
|
|
14
|
+
- *Why*: Without a single authority, mars can't distinguish "user added this manually" from "mars installed this." The lock makes ownership explicit — safe coexistence with unmanaged files.
|
|
15
|
+
|
|
16
|
+
4. **No heuristics.** User intent is expressed through explicit flags and arguments, not inferred from string patterns.
|
|
17
|
+
- *Why*: The dot-prefix heuristic (`starts_with('.')`) classified `./my-project` as a target dir — a real bug caught by reviewers. Explicit arguments are boring but predictable, and predictable tools earn trust.
|
|
18
|
+
|
|
19
|
+
## Managed Layout
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
project/
|
|
23
|
+
.agents/ # managed root (default)
|
|
24
|
+
mars.toml # desired sources + settings
|
|
25
|
+
mars.lock # generated lock/ownership/provenance
|
|
26
|
+
mars.local.toml # local overrides (gitignored)
|
|
27
|
+
.mars/ # internal state (sync.lock, cache)
|
|
28
|
+
agents/ # installed agent profiles
|
|
29
|
+
skills/ # installed skills
|
|
30
|
+
.claude/ # optional linked tool dir
|
|
31
|
+
agents -> ../.agents/agents
|
|
32
|
+
skills -> ../.agents/skills
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## MarsContext Invariant
|
|
36
|
+
|
|
37
|
+
`src/cli/mod.rs` defines:
|
|
38
|
+
|
|
39
|
+
- `MarsContext { managed_root, project_root }`
|
|
40
|
+
- Invariant enforced by `MarsContext::new`: managed root must be a subdirectory and therefore has a parent.
|
|
41
|
+
- `project_root` is always `managed_root.parent()` (canonicalized when possible).
|
|
42
|
+
|
|
43
|
+
This invariant is relied on by local-path resolution and link-target resolution.
|
|
44
|
+
|
|
45
|
+
## CLI Surface
|
|
46
|
+
|
|
47
|
+
### Global flags
|
|
48
|
+
|
|
49
|
+
| Flag | Meaning |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `--root <PATH>` | Use this managed root instead of auto-discovery. |
|
|
52
|
+
| `--json` | Machine-readable output. |
|
|
53
|
+
|
|
54
|
+
### Commands
|
|
55
|
+
|
|
56
|
+
| Command | Purpose |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `mars init [TARGET]` | Initialize managed root with `mars.toml` (optional `--link`). |
|
|
59
|
+
| `mars add <source>` | Add/update source, then sync. |
|
|
60
|
+
| `mars remove <source>` | Remove source, then prune managed items. |
|
|
61
|
+
| `mars sync` | Resolve + install to match config (`--force`, `--diff`, `--frozen`). |
|
|
62
|
+
| `mars upgrade [sources...]` | Maximize versions for all or selected sources. |
|
|
63
|
+
| `mars outdated` | Show available updates without applying changes. |
|
|
64
|
+
| `mars list` | List managed agents/skills (`--status` for checksum state). |
|
|
65
|
+
| `mars why <name>` | Explain source/provenance for an installed item. |
|
|
66
|
+
| `mars rename <from> <to>` | Add rename rule and sync to apply it. |
|
|
67
|
+
| `mars resolve [file]` | Mark conflicts resolved by updating installed checksums. |
|
|
68
|
+
| `mars override <source> --path <PATH>` | Set local dev override in `mars.local.toml`. |
|
|
69
|
+
| `mars link <target>` | Link managed `agents/` + `skills/` into tool dir (`--unlink`, `--force`). |
|
|
70
|
+
| `mars check [path]` | Validate a source package (structure/frontmatter/deps). |
|
|
71
|
+
| `mars doctor` | Validate config/lock/filesystem/link/dependency health. |
|
|
72
|
+
| `mars repair` | Force rebuild from config/sources (corrupt-lock recovery path). |
|
|
73
|
+
|
|
74
|
+
### Exit codes
|
|
75
|
+
|
|
76
|
+
| Code | Meaning |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `0` | Success (or clean report). |
|
|
79
|
+
| `1` | Action needed: unresolved conflicts (sync) or validation errors (check). |
|
|
80
|
+
| `2` | User/config/resolution/validation/link/frozen errors. |
|
|
81
|
+
| `3` | Source fetch, I/O, HTTP, or git command errors. |
|
|
82
|
+
|
|
83
|
+
## Sync Pipeline
|
|
84
|
+
|
|
85
|
+
Sync is orchestrated in `src/sync/mod.rs` under `.mars/sync.lock`:
|
|
86
|
+
|
|
87
|
+
1. Load config + local overrides; apply optional mutation.
|
|
88
|
+
2. Resolve graph (versions, deps, source identities).
|
|
89
|
+
3. Build target state.
|
|
90
|
+
4. Compute diff.
|
|
91
|
+
5. Create plan.
|
|
92
|
+
6. Apply plan.
|
|
93
|
+
7. Write new `mars.lock`.
|
|
94
|
+
|
|
95
|
+
Core apply chain: `target -> diff -> plan -> apply`.
|
|
96
|
+
|
|
97
|
+
## Source Fetching
|
|
98
|
+
|
|
99
|
+
- GitHub HTTPS sources: archive download (`/archive/<sha>.tar.gz`) into global cache.
|
|
100
|
+
- SSH / non-GitHub HTTPS git sources: `git clone`/`git fetch` + checkout.
|
|
101
|
+
- Local path sources: canonicalized filesystem paths, read directly (no copy cache).
|
|
102
|
+
|
|
103
|
+
Global cache root: `~/.mars/cache` (override with `MARS_CACHE_DIR`).
|
|
104
|
+
|
|
105
|
+
## Key Modules
|
|
106
|
+
|
|
107
|
+
| Module | Responsibility |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `src/cli/` | Clap args, root discovery, command dispatch, output formatting. |
|
|
110
|
+
| `src/config/` | `mars.toml` + `mars.local.toml` schemas, load/save, merge to effective config. |
|
|
111
|
+
| `src/lock/` | `mars.lock` schema, load/write, lock rebuild from apply outcomes. |
|
|
112
|
+
| `src/sync/` | End-to-end sync orchestration + `target/diff/plan/apply`. |
|
|
113
|
+
| `src/resolve/` | Dependency + version resolution and graph ordering. |
|
|
114
|
+
| `src/source/` | Source parsing/fetching (git + path) and global cache handling. |
|
|
115
|
+
| `src/discover/` | Discover agents/skills by filesystem conventions. |
|
|
116
|
+
| `src/validate/` | Agent-to-skill dependency validation. |
|
|
117
|
+
| `src/merge/` | Three-way merge/conflict handling. |
|
|
118
|
+
| `src/fs/` | Atomic writes/installs and advisory file lock (`flock`). |
|
|
119
|
+
| `src/frontmatter/` | YAML frontmatter parsing for agent/skill metadata. |
|
|
120
|
+
| `src/manifest/` | Optional per-source `mars.toml` manifest loading. |
|
|
121
|
+
| `src/hash/` | SHA-256 hashing for files/directories. |
|
|
122
|
+
| `src/types.rs` | Typed identifiers/newtypes used across modules. |
|
|
123
|
+
|
|
124
|
+
## Dev Workflow
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cargo build
|
|
128
|
+
cargo test
|
|
129
|
+
cargo clippy --all-targets -- -D warnings
|
|
130
|
+
cargo fmt --check
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Notes:
|
|
134
|
+
|
|
135
|
+
- Integration coverage is under `tests/` (CLI-level behavior).
|
|
136
|
+
- Prefer keeping changes localized to one module/command path when adding features.
|
|
137
|
+
|
|
138
|
+
## Releasing
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
./scripts/release.sh patch --push # 0.0.1 → 0.0.2, push to trigger CI
|
|
142
|
+
./scripts/release.sh minor --push # 0.0.2 → 0.1.0
|
|
143
|
+
./scripts/release.sh 1.0.0 --push # explicit version
|
|
144
|
+
./scripts/release.sh patch --dry # run checks only, don't tag
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The release script runs pre-release checks (fmt, clippy, tests, release build, version consistency between Cargo.toml and pyproject.toml), bumps both files, commits, tags, and optionally pushes. The `v*` tag triggers GitHub Actions to build platform wheels and publish to PyPI, npm, and crates.io.
|
|
148
|
+
|
|
149
|
+
Prerequisites for first release:
|
|
150
|
+
- Set up trusted publisher on PyPI (repo: `haowjy/mars-agents`, workflow: `release.yml`, environment: `pypi`)
|
|
151
|
+
- Create `pypi` environment in GitHub repo settings
|
|
152
|
+
- `NPM_TOKEN` and `CARGO_REGISTRY_TOKEN` secrets already configured
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Development Guide: mars-agents
|
|
2
|
+
|
|
3
|
+
Mars is an agent package manager for `.agents/` directories. It installs agent profiles and skills from git/local sources, tracks ownership in `mars.lock`, and links managed content into tool directories like `.claude/`.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
1. **Resolve first, then act.** Validate + build full desired state before mutating files. If any conflict or error is detected during resolution, zero mutations occur.
|
|
8
|
+
- *Why*: Partial failures leave users in states that are hard to diagnose. A user who sees "3 conflicts" can fix all three and retry. A user whose command half-completed has to figure out what happened first.
|
|
9
|
+
|
|
10
|
+
2. **Atomic writes.** Config, lock, and installed files use temp + rename. Crash mid-write leaves the old file intact.
|
|
11
|
+
- *Why*: Mars manages files that agents and tools read continuously. A half-written mars.toml breaks every tool that reads it. tmp + rename is atomic on POSIX — no recovery logic needed.
|
|
12
|
+
|
|
13
|
+
3. **Lock file is authority.** `mars.lock` defines managed ownership and checksums. If it's not in the lock, it's not managed.
|
|
14
|
+
- *Why*: Without a single authority, mars can't distinguish "user added this manually" from "mars installed this." The lock makes ownership explicit — safe coexistence with unmanaged files.
|
|
15
|
+
|
|
16
|
+
4. **No heuristics.** User intent is expressed through explicit flags and arguments, not inferred from string patterns.
|
|
17
|
+
- *Why*: The dot-prefix heuristic (`starts_with('.')`) classified `./my-project` as a target dir — a real bug caught by reviewers. Explicit arguments are boring but predictable, and predictable tools earn trust.
|
|
18
|
+
|
|
19
|
+
## Managed Layout
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
project/
|
|
23
|
+
.agents/ # managed root (default)
|
|
24
|
+
mars.toml # desired sources + settings
|
|
25
|
+
mars.lock # generated lock/ownership/provenance
|
|
26
|
+
mars.local.toml # local overrides (gitignored)
|
|
27
|
+
.mars/ # internal state (sync.lock, cache)
|
|
28
|
+
agents/ # installed agent profiles
|
|
29
|
+
skills/ # installed skills
|
|
30
|
+
.claude/ # optional linked tool dir
|
|
31
|
+
agents -> ../.agents/agents
|
|
32
|
+
skills -> ../.agents/skills
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## MarsContext Invariant
|
|
36
|
+
|
|
37
|
+
`src/cli/mod.rs` defines:
|
|
38
|
+
|
|
39
|
+
- `MarsContext { managed_root, project_root }`
|
|
40
|
+
- Invariant enforced by `MarsContext::new`: managed root must be a subdirectory and therefore has a parent.
|
|
41
|
+
- `project_root` is always `managed_root.parent()` (canonicalized when possible).
|
|
42
|
+
|
|
43
|
+
This invariant is relied on by local-path resolution and link-target resolution.
|
|
44
|
+
|
|
45
|
+
## CLI Surface
|
|
46
|
+
|
|
47
|
+
### Global flags
|
|
48
|
+
|
|
49
|
+
| Flag | Meaning |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `--root <PATH>` | Use this managed root instead of auto-discovery. |
|
|
52
|
+
| `--json` | Machine-readable output. |
|
|
53
|
+
|
|
54
|
+
### Commands
|
|
55
|
+
|
|
56
|
+
| Command | Purpose |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `mars init [TARGET]` | Initialize managed root with `mars.toml` (optional `--link`). |
|
|
59
|
+
| `mars add <source>` | Add/update source, then sync. |
|
|
60
|
+
| `mars remove <source>` | Remove source, then prune managed items. |
|
|
61
|
+
| `mars sync` | Resolve + install to match config (`--force`, `--diff`, `--frozen`). |
|
|
62
|
+
| `mars upgrade [sources...]` | Maximize versions for all or selected sources. |
|
|
63
|
+
| `mars outdated` | Show available updates without applying changes. |
|
|
64
|
+
| `mars list` | List managed agents/skills (`--status` for checksum state). |
|
|
65
|
+
| `mars why <name>` | Explain source/provenance for an installed item. |
|
|
66
|
+
| `mars rename <from> <to>` | Add rename rule and sync to apply it. |
|
|
67
|
+
| `mars resolve [file]` | Mark conflicts resolved by updating installed checksums. |
|
|
68
|
+
| `mars override <source> --path <PATH>` | Set local dev override in `mars.local.toml`. |
|
|
69
|
+
| `mars link <target>` | Link managed `agents/` + `skills/` into tool dir (`--unlink`, `--force`). |
|
|
70
|
+
| `mars check [path]` | Validate a source package (structure/frontmatter/deps). |
|
|
71
|
+
| `mars doctor` | Validate config/lock/filesystem/link/dependency health. |
|
|
72
|
+
| `mars repair` | Force rebuild from config/sources (corrupt-lock recovery path). |
|
|
73
|
+
|
|
74
|
+
### Exit codes
|
|
75
|
+
|
|
76
|
+
| Code | Meaning |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `0` | Success (or clean report). |
|
|
79
|
+
| `1` | Action needed: unresolved conflicts (sync) or validation errors (check). |
|
|
80
|
+
| `2` | User/config/resolution/validation/link/frozen errors. |
|
|
81
|
+
| `3` | Source fetch, I/O, HTTP, or git command errors. |
|
|
82
|
+
|
|
83
|
+
## Sync Pipeline
|
|
84
|
+
|
|
85
|
+
Sync is orchestrated in `src/sync/mod.rs` under `.mars/sync.lock`:
|
|
86
|
+
|
|
87
|
+
1. Load config + local overrides; apply optional mutation.
|
|
88
|
+
2. Resolve graph (versions, deps, source identities).
|
|
89
|
+
3. Build target state.
|
|
90
|
+
4. Compute diff.
|
|
91
|
+
5. Create plan.
|
|
92
|
+
6. Apply plan.
|
|
93
|
+
7. Write new `mars.lock`.
|
|
94
|
+
|
|
95
|
+
Core apply chain: `target -> diff -> plan -> apply`.
|
|
96
|
+
|
|
97
|
+
## Source Fetching
|
|
98
|
+
|
|
99
|
+
- GitHub HTTPS sources: archive download (`/archive/<sha>.tar.gz`) into global cache.
|
|
100
|
+
- SSH / non-GitHub HTTPS git sources: `git clone`/`git fetch` + checkout.
|
|
101
|
+
- Local path sources: canonicalized filesystem paths, read directly (no copy cache).
|
|
102
|
+
|
|
103
|
+
Global cache root: `~/.mars/cache` (override with `MARS_CACHE_DIR`).
|
|
104
|
+
|
|
105
|
+
## Key Modules
|
|
106
|
+
|
|
107
|
+
| Module | Responsibility |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `src/cli/` | Clap args, root discovery, command dispatch, output formatting. |
|
|
110
|
+
| `src/config/` | `mars.toml` + `mars.local.toml` schemas, load/save, merge to effective config. |
|
|
111
|
+
| `src/lock/` | `mars.lock` schema, load/write, lock rebuild from apply outcomes. |
|
|
112
|
+
| `src/sync/` | End-to-end sync orchestration + `target/diff/plan/apply`. |
|
|
113
|
+
| `src/resolve/` | Dependency + version resolution and graph ordering. |
|
|
114
|
+
| `src/source/` | Source parsing/fetching (git + path) and global cache handling. |
|
|
115
|
+
| `src/discover/` | Discover agents/skills by filesystem conventions. |
|
|
116
|
+
| `src/validate/` | Agent-to-skill dependency validation. |
|
|
117
|
+
| `src/merge/` | Three-way merge/conflict handling. |
|
|
118
|
+
| `src/fs/` | Atomic writes/installs and advisory file lock (`flock`). |
|
|
119
|
+
| `src/frontmatter/` | YAML frontmatter parsing for agent/skill metadata. |
|
|
120
|
+
| `src/manifest/` | Optional per-source `mars.toml` manifest loading. |
|
|
121
|
+
| `src/hash/` | SHA-256 hashing for files/directories. |
|
|
122
|
+
| `src/types.rs` | Typed identifiers/newtypes used across modules. |
|
|
123
|
+
|
|
124
|
+
## Dev Workflow
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
cargo build
|
|
128
|
+
cargo test
|
|
129
|
+
cargo clippy --all-targets -- -D warnings
|
|
130
|
+
cargo fmt --check
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Notes:
|
|
134
|
+
|
|
135
|
+
- Integration coverage is under `tests/` (CLI-level behavior).
|
|
136
|
+
- Prefer keeping changes localized to one module/command path when adding features.
|
|
137
|
+
|
|
138
|
+
## Releasing
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
./scripts/release.sh patch --push # 0.0.1 → 0.0.2, push to trigger CI
|
|
142
|
+
./scripts/release.sh minor --push # 0.0.2 → 0.1.0
|
|
143
|
+
./scripts/release.sh 1.0.0 --push # explicit version
|
|
144
|
+
./scripts/release.sh patch --dry # run checks only, don't tag
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The release script runs pre-release checks (fmt, clippy, tests, release build, version consistency between Cargo.toml and pyproject.toml), bumps both files, commits, tags, and optionally pushes. The `v*` tag triggers GitHub Actions to build platform wheels and publish to PyPI, npm, and crates.io.
|
|
148
|
+
|
|
149
|
+
Prerequisites for first release:
|
|
150
|
+
- Set up trusted publisher on PyPI (repo: `haowjy/mars-agents`, workflow: `release.yml`, environment: `pypi`)
|
|
151
|
+
- Create `pypi` environment in GitHub repo settings
|
|
152
|
+
- `NPM_TOKEN` and `CARGO_REGISTRY_TOKEN` secrets already configured
|