@event4u/agent-config 2.4.1 → 2.6.0
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.
package/CHANGELOG.md
CHANGED
|
@@ -343,6 +343,26 @@ our recommendation order, not its support status.
|
|
|
343
343
|
users" tension without removing any path that an existing user
|
|
344
344
|
might rely on.
|
|
345
345
|
|
|
346
|
+
## [2.6.0](https://github.com/event4u-app/agent-config/compare/2.4.1...2.6.0) (2026-05-13)
|
|
347
|
+
|
|
348
|
+
### Features
|
|
349
|
+
|
|
350
|
+
* **claude-desktop:** bundle commands as desktop skills ([50cd319](https://github.com/event4u-app/agent-config/commit/50cd31988ac571ecdf883c5d2c6d62c209820ebc))
|
|
351
|
+
|
|
352
|
+
### Other
|
|
353
|
+
|
|
354
|
+
* 2.5.0 ([1da0e10](https://github.com/event4u-app/agent-config/commit/1da0e1014b9cf24cf41d820795f96f2668ce738c))
|
|
355
|
+
|
|
356
|
+
Tests: 3530 (+9 since 2.4.1)
|
|
357
|
+
|
|
358
|
+
## [2.5.0](https://github.com/event4u-app/agent-config/compare/2.4.1...2.5.0) (2026-05-13)
|
|
359
|
+
|
|
360
|
+
### Features
|
|
361
|
+
|
|
362
|
+
* **claude-desktop:** bundle commands as desktop skills ([50cd319](https://github.com/event4u-app/agent-config/commit/50cd31988ac571ecdf883c5d2c6d62c209820ebc))
|
|
363
|
+
|
|
364
|
+
Tests: 3530 (+9 since 2.4.1)
|
|
365
|
+
|
|
346
366
|
## [2.4.1](https://github.com/event4u-app/agent-config/compare/2.4.0...2.4.1) (2026-05-13)
|
|
347
367
|
|
|
348
368
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -3,20 +3,32 @@
|
|
|
3
3
|
Claude Desktop has no filesystem convention for skills; the Customize →
|
|
4
4
|
Skills UI accepts a ZIP per skill via the Upload button. This module
|
|
5
5
|
walks ``<package_root>/.agent-src/skills/*`` and produces one
|
|
6
|
-
``<skill-name>.zip`` per directory into ``dest_dir``.
|
|
6
|
+
``<skill-name>.zip`` per directory into ``dest_dir``. It additionally
|
|
7
|
+
walks ``<package_root>/.agent-src/commands/`` and produces one
|
|
8
|
+
``<command-slug>.zip`` per command ``.md`` file so Claude Desktop sees
|
|
9
|
+
the same surface that Claude Code exposes via the ``.claude/skills/``
|
|
10
|
+
symlink wrapper layer.
|
|
7
11
|
|
|
8
12
|
Contract:
|
|
9
13
|
|
|
10
14
|
- Each ZIP contains ``SKILL.md`` plus every sibling file under the same
|
|
11
15
|
directory (recursive). Symlinks are dereferenced so the ZIP is
|
|
12
16
|
self-contained.
|
|
17
|
+
- Command bundles wrap a single ``.agent-src/commands/<path>.md`` file
|
|
18
|
+
as ``SKILL.md`` inside the ZIP. Nested commands flatten to
|
|
19
|
+
``<cluster>-<leaf>`` slugs (e.g. ``council/default.md`` →
|
|
20
|
+
``council-default.zip``) to mirror ``compress.py``.
|
|
13
21
|
- Exclusions: ``.git*``, ``__pycache__``, ``*.pyc`` — matched on the
|
|
14
22
|
basename of any path component.
|
|
15
23
|
- A skill folder without a ``SKILL.md`` is skipped (defensive: avoids
|
|
16
24
|
shipping Claude-Code orchestrator stubs that don't follow the
|
|
17
25
|
Anthropic skill schema).
|
|
26
|
+
- Command files named ``AGENTS.md`` are skipped (cluster authoring docs,
|
|
27
|
+
not invocable commands).
|
|
28
|
+
- A command slug that collides with an existing skill name is skipped —
|
|
29
|
+
the real skill bundle wins, matching ``compress.generate_claude_commands``.
|
|
18
30
|
- Writes are atomic via tempfile → ``os.replace``.
|
|
19
|
-
- Idempotent: each ZIP gets a sibling ``<
|
|
31
|
+
- Idempotent: each ZIP gets a sibling ``<slug>.sha256`` recording
|
|
20
32
|
the manifest digest. If the recomputed digest matches the recorded
|
|
21
33
|
one, the existing ZIP is left untouched (unless ``force=True``).
|
|
22
34
|
"""
|
|
@@ -148,3 +160,79 @@ def build_skill_bundles(
|
|
|
148
160
|
digest_path.write_text(digest + "\n", encoding="utf-8")
|
|
149
161
|
written.append(zip_path)
|
|
150
162
|
return written
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _command_slug(source_file: Path, commands_root: Path) -> str:
|
|
166
|
+
"""Return the flat slug for a command source file.
|
|
167
|
+
|
|
168
|
+
Mirrors ``scripts/compress.py::_command_slug``: top-level commands
|
|
169
|
+
keep their stem (``commit.md`` → ``commit``); nested commands flatten
|
|
170
|
+
the relative path with ``-`` (``council/default.md`` →
|
|
171
|
+
``council-default``).
|
|
172
|
+
"""
|
|
173
|
+
rel = source_file.relative_to(commands_root)
|
|
174
|
+
return "-".join(rel.with_suffix("").parts)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _iter_command_files(commands_root: Path) -> Iterable[Path]:
|
|
178
|
+
"""Yield every command ``.md`` file under ``commands_root`` (recursive).
|
|
179
|
+
|
|
180
|
+
Skips ``AGENTS.md`` cluster authoring docs, matching
|
|
181
|
+
``scripts/compress.py::_iter_commands``.
|
|
182
|
+
"""
|
|
183
|
+
for source_file in sorted(commands_root.rglob("*.md")):
|
|
184
|
+
if source_file.name == "AGENTS.md":
|
|
185
|
+
continue
|
|
186
|
+
yield source_file
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def build_command_bundles(
|
|
190
|
+
package_root: Path,
|
|
191
|
+
dest_dir: Path,
|
|
192
|
+
force: bool = False,
|
|
193
|
+
curation: Optional[list[str]] = None,
|
|
194
|
+
) -> list[Path]:
|
|
195
|
+
"""Build per-command ZIPs under ``dest_dir``.
|
|
196
|
+
|
|
197
|
+
Each ZIP contains a single ``SKILL.md`` whose bytes are the source
|
|
198
|
+
command ``.md`` file — same wrapping pattern that
|
|
199
|
+
``compress.generate_claude_commands`` uses for Claude Code via
|
|
200
|
+
``.claude/skills/<slug>/SKILL.md`` symlinks.
|
|
201
|
+
|
|
202
|
+
Slugs that collide with an existing skill folder under
|
|
203
|
+
``<package_root>/.agent-src/skills/`` are skipped so the real skill
|
|
204
|
+
bundle wins.
|
|
205
|
+
|
|
206
|
+
Returns the list of ZIP paths that were (re-)written this call. ZIPs
|
|
207
|
+
skipped because their content digest matched the existing sidecar
|
|
208
|
+
are not in the returned list (but remain on disk).
|
|
209
|
+
|
|
210
|
+
``curation`` optionally restricts the build to the given command
|
|
211
|
+
slugs; ``None`` bundles every command file.
|
|
212
|
+
"""
|
|
213
|
+
commands_root = package_root / ".agent-src" / "commands"
|
|
214
|
+
if not commands_root.is_dir():
|
|
215
|
+
return []
|
|
216
|
+
skills_root = package_root / ".agent-src" / "skills"
|
|
217
|
+
skill_names: set[str] = set()
|
|
218
|
+
if skills_root.is_dir():
|
|
219
|
+
skill_names = {entry.name for entry in skills_root.iterdir() if entry.is_dir()}
|
|
220
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
221
|
+
written: list[Path] = []
|
|
222
|
+
for source_file in _iter_command_files(commands_root):
|
|
223
|
+
slug = _command_slug(source_file, commands_root)
|
|
224
|
+
if slug in skill_names:
|
|
225
|
+
continue
|
|
226
|
+
if curation is not None and slug not in curation:
|
|
227
|
+
continue
|
|
228
|
+
files = [(source_file.resolve(), ("SKILL.md",))]
|
|
229
|
+
digest = _manifest_digest(files)
|
|
230
|
+
zip_path = dest_dir / f"{slug}.zip"
|
|
231
|
+
digest_path = dest_dir / f"{slug}.sha256"
|
|
232
|
+
recorded = digest_path.read_text(encoding="utf-8").strip() if digest_path.exists() else ""
|
|
233
|
+
if not force and recorded == digest and zip_path.exists():
|
|
234
|
+
continue
|
|
235
|
+
_atomic_write_zip(zip_path, files)
|
|
236
|
+
digest_path.write_text(digest + "\n", encoding="utf-8")
|
|
237
|
+
written.append(zip_path)
|
|
238
|
+
return written
|
package/scripts/install.py
CHANGED
|
@@ -2888,6 +2888,7 @@ def _deploy_claude_desktop(
|
|
|
2888
2888
|
bundler = _load_claude_desktop_bundler_module()
|
|
2889
2889
|
bundles_dir = _claude_desktop_bundles_dir()
|
|
2890
2890
|
bundler.build_skill_bundles(package_root, bundles_dir, force=force)
|
|
2891
|
+
bundler.build_command_bundles(package_root, bundles_dir, force=force)
|
|
2891
2892
|
# Count total existing ZIPs (idempotent runs may not rewrite any).
|
|
2892
2893
|
bundle_count = sum(1 for _ in bundles_dir.glob("*.zip")) if bundles_dir.is_dir() else 0
|
|
2893
2894
|
_, _, marker_paths = _write_claude_desktop_marker(
|