@delorenj/pjangler 1.4.5 → 1.5.2
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/README.md +41 -520
- package/dist/assets/project-notebook-skill/SHA256SUMS +5 -5
- package/dist/assets/project-notebook-skill/export-manifest.json +5 -5
- package/dist/assets/project-notebook-skill/hooks/session-end.sh +20 -1
- package/dist/assets/project-notebook-skill/hooks/session-start.sh +20 -1
- package/dist/assets/project-notebook-skill/references/configuration.md +2 -0
- package/dist/assets/project-notebook-skill/scripts/project-hooks.py +33 -3
- package/dist/assets/project-notebook-skill/tests/test_project_hooks.py +37 -0
- package/dist/index.js +5747 -13483
- package/dist/mcp-server.js +6853 -14059
- package/dist/notebook/journal-service-main.js +5682 -0
- package/dist/project-registry-service.js +748 -0
- package/dist/prompt.js +2 -1
- package/package.json +15 -10
- package/scripts/install-project-registry.mjs +34 -0
- package/scripts/migrate-project-registry.mjs +117 -0
- package/src/project/registryClient.ts +62 -0
- package/templates/commonproject/copier.yml +16 -19
- package/templates/commonproject/template/.agents/hooks/README.md +10 -4
- package/templates/commonproject/template/.agents/hooks/hermes/hindsight-hook.sh +12 -2
- package/templates/commonproject/template/.agents/hooks/hooks.master.json +10 -10
- package/templates/commonproject/template/.agents/hooks/lib/hook-guard.sh +13 -0
- package/templates/commonproject/template/.agents/hooks/sync.py +66 -17
- package/templates/commonproject/template/.agents/skills.json +0 -1
- package/templates/commonproject/template/.github/workflows/code-review.yml.jinja +7 -1
- package/templates/commonproject/template/.project.json.jinja +1 -1
- package/templates/commonproject/template/mise.toml.jinja +11 -21
- package/contracts/fleet-contract.yaml +0 -513
- package/templates/commonproject/template/.mise/scripts/provision-packs.py +0 -587
- package/templates/commonproject/template/.mise/scripts/sync-skills.py +0 -2183
- package/templates/hermes-agent/copier.yml +0 -186
- package/templates/hermes-agent/template/.gitignore.jinja +0 -11
- package/templates/hermes-agent/template/.runtime-scaffold/.gitattributes +0 -10
- package/templates/hermes-agent/template/.runtime-scaffold/.gitignore.jinja +0 -44
- package/templates/hermes-agent/template/.runtime-scaffold/README.md +0 -56
- package/templates/hermes-agent/template/.runtime-scaffold/decisions/.gitkeep +0 -2
- package/templates/hermes-agent/template/.runtime-scaffold/logs/.gitkeep +0 -1
- package/templates/hermes-agent/template/.runtime-scaffold/memories/MEMORY.md +0 -50
- package/templates/hermes-agent/template/.runtime-scaffold/memories/USER.md +0 -51
- package/templates/hermes-agent/template/.scripts/00-banner.sh +0 -21
- package/templates/hermes-agent/template/.scripts/01-config.sh +0 -60
- package/templates/hermes-agent/template/.scripts/05-fleet-env.sh +0 -42
- package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +0 -222
- package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +0 -199
- package/templates/hermes-agent/template/.scripts/30-telegram.sh +0 -363
- package/templates/hermes-agent/template/.scripts/31-slack.sh +0 -457
- package/templates/hermes-agent/template/.scripts/40-plane.sh +0 -60
- package/templates/hermes-agent/template/.scripts/42-ticket-provider.sh +0 -373
- package/templates/hermes-agent/template/.scripts/60-bloodbank.sh +0 -18
- package/templates/hermes-agent/template/.scripts/70-systemd.sh +0 -354
- package/templates/hermes-agent/template/.scripts/80-registry.sh +0 -185
- package/templates/hermes-agent/template/.scripts/99-summary.sh +0 -87
- package/templates/hermes-agent/template/.scripts/_lib.sh +0 -1138
- package/templates/hermes-agent/template/.scripts/channel-transaction.py +0 -2340
- package/templates/hermes-agent/template/.scripts/checkpoint.sh +0 -82
- package/templates/hermes-agent/template/.scripts/config.example.toml +0 -70
- package/templates/hermes-agent/template/.scripts/credential-launch.sh +0 -85
- package/templates/hermes-agent/template/.scripts/heartbeat.sh +0 -283
- package/templates/hermes-agent/template/.scripts/lib/fleet-env.sh +0 -202
- package/templates/hermes-agent/template/.scripts/lib/parse-fleet-env.py +0 -761
- package/templates/hermes-agent/template/.scripts/lib/profile-config-lock.py +0 -182
- package/templates/hermes-agent/template/.scripts/lib/profile-config-seed.py +0 -108
- package/templates/hermes-agent/template/.scripts/lib/ticket-provider.sh +0 -199
- package/templates/hermes-agent/template/.scripts/lib/voice-config.py +0 -546
- package/templates/hermes-agent/template/.scripts/lifecycle.sh +0 -126
- package/templates/hermes-agent/template/.scripts/momo-wip-lock.py +0 -137
- package/templates/hermes-agent/template/.scripts/providers/linear.sh +0 -329
- package/templates/hermes-agent/template/.scripts/providers/plane.sh +0 -671
- package/templates/hermes-agent/template/.scripts/providers/trello.sh +0 -241
- package/templates/hermes-agent/template/.scripts/reporter-watchdog.py +0 -242
- package/templates/hermes-agent/template/.scripts/secret-scan.py +0 -134
- package/templates/hermes-agent/template/.scripts/sentinel/bin/emit-event.py +0 -106
- package/templates/hermes-agent/template/.scripts/sentinel/bin/issue-autonomous-review.sh +0 -339
- package/templates/hermes-agent/template/.scripts/sentinel/bin/issue-close-gate.sh +0 -179
- package/templates/hermes-agent/template/.scripts/sentinel/docs/autonomous-delegated-review.md +0 -162
- package/templates/hermes-agent/template/.scripts/sentinel/docs/bloodbank-events.md +0 -42
- package/templates/hermes-agent/template/.scripts/sentinel/docs/continuous-ticket-orchestration.md +0 -77
- package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +0 -116
- package/templates/hermes-agent/template/.scripts/store-onepassword-secret.py +0 -260
- package/templates/hermes-agent/template/SOUL.md.jinja +0 -197
- package/templates/hermes-agent/template/hermes.jinja +0 -109
- package/templates/hermes-agent/template/momo.jinja +0 -177
- package/templates/hermes-agent/template/role.yaml.jinja +0 -112
|
@@ -65,6 +65,22 @@ def _now_iso() -> str:
|
|
|
65
65
|
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
66
66
|
|
|
67
67
|
|
|
68
|
+
def hub_owns_hook(hook_id: str, agent: str) -> bool:
|
|
69
|
+
"""An activated central concern must not gain another native owner.
|
|
70
|
+
|
|
71
|
+
The manifest is written only after native cutover. Standalone CommonProject
|
|
72
|
+
consumers without Bloodbank retain the same project hook fallback.
|
|
73
|
+
"""
|
|
74
|
+
path = Path(os.environ.get("BB_HOOK_OWNERSHIP", Path.home() / ".config/33god/hook-hub/ownership.json"))
|
|
75
|
+
concern = {"skill-check-reminder": "skill-reminder", "merge-forward-session-rebalance": "merge-forward"}.get(hook_id, hook_id)
|
|
76
|
+
try:
|
|
77
|
+
manifest = json.loads(path.read_text())
|
|
78
|
+
return (manifest.get("version") == 1 and agent in manifest.get("clis", [])
|
|
79
|
+
and concern in manifest.get("handler_ids", []) and Path(manifest["registry"]).is_file())
|
|
80
|
+
except (OSError, ValueError, KeyError, TypeError):
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
68
84
|
def load_local() -> dict:
|
|
69
85
|
"""Per-dev overrides from .agents/local.json (gitignored). Fails open.
|
|
70
86
|
|
|
@@ -111,6 +127,8 @@ def build_event_groups(master: dict, agent_key: str) -> dict:
|
|
|
111
127
|
order: list[tuple[str, str | None]] = []
|
|
112
128
|
|
|
113
129
|
for hook in master["hooks"]:
|
|
130
|
+
if hub_owns_hook(hook["id"], agent_key):
|
|
131
|
+
continue
|
|
114
132
|
lifecycle = hook["lifecycle"]
|
|
115
133
|
event = ev_map.get(lifecycle)
|
|
116
134
|
if not event: # this agent doesn't map this lifecycle (e.g. hermes stub)
|
|
@@ -140,7 +158,7 @@ def build_event_groups(master: dict, agent_key: str) -> dict:
|
|
|
140
158
|
|
|
141
159
|
|
|
142
160
|
# --------------------------------------------------------------------------- #
|
|
143
|
-
# Claude dialect: own
|
|
161
|
+
# Claude dialect: own only commands under this project's canonical hook path.
|
|
144
162
|
# --------------------------------------------------------------------------- #
|
|
145
163
|
def render_claude(master: dict) -> dict:
|
|
146
164
|
target = REPO_ROOT / master["agents"]["claude"]["config_target"]
|
|
@@ -151,7 +169,14 @@ def render_claude(master: dict) -> dict:
|
|
|
151
169
|
except json.JSONDecodeError:
|
|
152
170
|
warn(f"{target} is not valid JSON; refusing to overwrite")
|
|
153
171
|
return {"target": target, "changed": False, "error": True}
|
|
154
|
-
|
|
172
|
+
hooks = settings.setdefault("hooks", {})
|
|
173
|
+
if not isinstance(hooks, dict):
|
|
174
|
+
warn(f"{target} has a non-object hooks key; refusing to overwrite")
|
|
175
|
+
return {"target": target, "changed": False, "error": True}
|
|
176
|
+
_strip_caf_hooks(hooks, "$CLAUDE_PROJECT_DIR/.agents/hooks/")
|
|
177
|
+
_strip_caf_hooks(hooks, f"{REPO_ROOT}/.agents/hooks/")
|
|
178
|
+
for event, groups in build_event_groups(master, "claude").items():
|
|
179
|
+
hooks.setdefault(event, []).extend(groups)
|
|
155
180
|
return {"target": target, "settings": settings, "changed": True}
|
|
156
181
|
|
|
157
182
|
|
|
@@ -192,8 +217,13 @@ def _strip_caf_hooks(hooks_obj: dict, marker: str) -> bool:
|
|
|
192
217
|
"""Remove our hooks from every event; drop emptied groups. Returns changed."""
|
|
193
218
|
changed = False
|
|
194
219
|
for event, groups in list(hooks_obj.items()):
|
|
220
|
+
if not isinstance(groups, list):
|
|
221
|
+
continue
|
|
195
222
|
new_groups = []
|
|
196
223
|
for group in groups:
|
|
224
|
+
if not isinstance(group, dict) or not isinstance(group.get("hooks", []), list):
|
|
225
|
+
new_groups.append(group)
|
|
226
|
+
continue
|
|
197
227
|
kept = [h for h in group.get("hooks", []) if marker not in h.get("command", "")]
|
|
198
228
|
if len(kept) != len(group.get("hooks", [])):
|
|
199
229
|
changed = True
|
|
@@ -246,10 +276,6 @@ def install_codex(master: dict) -> None:
|
|
|
246
276
|
if target.exists() and target.read_text() == serialized:
|
|
247
277
|
log(f"codex: up to date ({target})")
|
|
248
278
|
return
|
|
249
|
-
backup = target.with_suffix(target.suffix + ".caf-bak")
|
|
250
|
-
if target.exists() and not backup.exists():
|
|
251
|
-
backup.write_text(target.read_text())
|
|
252
|
-
log(f"codex: backed up -> {backup}")
|
|
253
279
|
target.write_text(serialized)
|
|
254
280
|
log(f"codex: injected project hooks into {target}")
|
|
255
281
|
|
|
@@ -301,6 +327,8 @@ def kimi_block(master: dict) -> str:
|
|
|
301
327
|
begin, end = _kimi_markers(master)
|
|
302
328
|
lines = [begin]
|
|
303
329
|
for hook in master["hooks"]:
|
|
330
|
+
if hub_owns_hook(hook["id"], "kimi"):
|
|
331
|
+
continue
|
|
304
332
|
event = ev.get(hook["lifecycle"])
|
|
305
333
|
if not event:
|
|
306
334
|
continue
|
|
@@ -314,6 +342,8 @@ def kimi_block(master: dict) -> str:
|
|
|
314
342
|
lines.append(f'command = "{cmd}"') # paths have no quotes/backslashes -> safe TOML string
|
|
315
343
|
lines.append(f"timeout = {timeout}")
|
|
316
344
|
lines.append("")
|
|
345
|
+
if len(lines) == 1:
|
|
346
|
+
return ""
|
|
317
347
|
lines.append(end)
|
|
318
348
|
return "\n".join(lines) + "\n"
|
|
319
349
|
|
|
@@ -334,6 +364,12 @@ def install_kimi(master: dict) -> None:
|
|
|
334
364
|
return
|
|
335
365
|
text = target.read_text() if target.exists() else ""
|
|
336
366
|
body, _ = _strip_kimi_block(text, master) # work against config minus our block
|
|
367
|
+
block = kimi_block(master)
|
|
368
|
+
if not block:
|
|
369
|
+
if body != text:
|
|
370
|
+
target.write_text(body)
|
|
371
|
+
log("kimi: retired project hooks owned by the central hub")
|
|
372
|
+
return
|
|
337
373
|
# Refuse if a foreign hooks definition exists (would collide with [[hooks]]).
|
|
338
374
|
if re.search(r"(?m)^\s*hooks\s*=\s*\[[^\]]", body) or re.search(r"(?m)^\s*\[\[hooks\]\]", body):
|
|
339
375
|
warn("kimi: existing non-CAF hooks found in config.toml; skipping to avoid a TOML conflict")
|
|
@@ -343,14 +379,10 @@ def install_kimi(master: dict) -> None:
|
|
|
343
379
|
body += "\n"
|
|
344
380
|
# Append "\n" + block (block ends with "\n"); the lone "\n" is what strip removes,
|
|
345
381
|
# so the body above is preserved verbatim on uninstall.
|
|
346
|
-
new = body + "\n" +
|
|
382
|
+
new = body + "\n" + block
|
|
347
383
|
if text == new:
|
|
348
384
|
log(f"kimi: up to date ({target})")
|
|
349
385
|
return
|
|
350
|
-
backup = target.with_suffix(target.suffix + ".caf-bak")
|
|
351
|
-
if target.exists() and not backup.exists():
|
|
352
|
-
backup.write_text(text)
|
|
353
|
-
log(f"kimi: backed up -> {backup}")
|
|
354
386
|
target.write_text(new)
|
|
355
387
|
log(f"kimi: injected project hooks into {target}")
|
|
356
388
|
|
|
@@ -381,14 +413,13 @@ def hermes_commands(master: dict) -> list[tuple[str, str, int]]:
|
|
|
381
413
|
return [
|
|
382
414
|
(event, f"{runner} {event}", timeout)
|
|
383
415
|
for _lifecycle, event in h["lifecycle_events"].items()
|
|
416
|
+
if any(hook["lifecycle"] == _lifecycle and not hub_owns_hook(hook["id"], "hermes") for hook in master["hooks"])
|
|
384
417
|
]
|
|
385
418
|
|
|
386
419
|
|
|
387
420
|
def _backup_once(path: Path) -> None:
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
backup.write_text(path.read_text())
|
|
391
|
-
log(f"hermes: backed up -> {backup.name}")
|
|
421
|
+
# Never copy potentially credential-bearing native settings beside source.
|
|
422
|
+
pass
|
|
392
423
|
|
|
393
424
|
|
|
394
425
|
def _load_yaml(path: Path):
|
|
@@ -410,6 +441,9 @@ def install_hermes(master: dict) -> None:
|
|
|
410
441
|
return
|
|
411
442
|
marker = codex_marker()
|
|
412
443
|
cmds = hermes_commands(master)
|
|
444
|
+
if not cmds:
|
|
445
|
+
uninstall_hermes(master)
|
|
446
|
+
return
|
|
413
447
|
|
|
414
448
|
# --- config.yaml hooks block ---
|
|
415
449
|
try:
|
|
@@ -419,13 +453,22 @@ def install_hermes(master: dict) -> None:
|
|
|
419
453
|
return
|
|
420
454
|
hooks = data.setdefault("hooks", {})
|
|
421
455
|
cfg_changed = False
|
|
456
|
+
desired_pairs = {(event, command) for event, command, _ in cmds}
|
|
457
|
+
for event, entries in list(hooks.items()):
|
|
458
|
+
if not isinstance(entries, list):
|
|
459
|
+
continue
|
|
460
|
+
kept = [entry for entry in entries if marker not in entry.get("command", "")
|
|
461
|
+
or (event, entry.get("command")) in desired_pairs]
|
|
462
|
+
if kept != entries:
|
|
463
|
+
hooks[event] = kept
|
|
464
|
+
cfg_changed = True
|
|
422
465
|
for event, command, timeout in cmds:
|
|
423
466
|
entries = hooks.setdefault(event, [])
|
|
424
467
|
ours = [e for e in entries if marker in e.get("command", "")]
|
|
425
468
|
if not ours:
|
|
426
469
|
entries.append({"command": command, "timeout": timeout})
|
|
427
470
|
cfg_changed = True
|
|
428
|
-
elif ours[0].get("command") != command
|
|
471
|
+
elif ours[0].get("command") != command or ours[0].get("timeout") != timeout:
|
|
429
472
|
ours[0]["command"] = command
|
|
430
473
|
ours[0]["timeout"] = timeout
|
|
431
474
|
cfg_changed = True
|
|
@@ -439,6 +482,11 @@ def install_hermes(master: dict) -> None:
|
|
|
439
482
|
allow_data = {"approvals": []}
|
|
440
483
|
approvals = allow_data.setdefault("approvals", [])
|
|
441
484
|
allow_changed = False
|
|
485
|
+
kept_approvals = [approval for approval in approvals if marker not in approval.get("command", "")
|
|
486
|
+
or (approval.get("event"), approval.get("command")) in desired_pairs]
|
|
487
|
+
if kept_approvals != approvals:
|
|
488
|
+
approvals = allow_data["approvals"] = kept_approvals
|
|
489
|
+
allow_changed = True
|
|
442
490
|
for event, command, _timeout in cmds:
|
|
443
491
|
if not any(a.get("command") == command and a.get("event") == event for a in approvals):
|
|
444
492
|
approvals.append({
|
|
@@ -554,9 +602,10 @@ def cmd_check(master: dict) -> int:
|
|
|
554
602
|
f"{base}/lib/hook-guard.sh {h['id']} {base}/{h['script']}"
|
|
555
603
|
for h in master["hooks"]
|
|
556
604
|
if master["agents"]["kimi"]["lifecycle_events"].get(h["lifecycle"])
|
|
605
|
+
and not hub_owns_hook(h["id"], "kimi")
|
|
557
606
|
]
|
|
558
607
|
missing = [c for c in want_cmds if c not in present]
|
|
559
|
-
if begin not in present or missing:
|
|
608
|
+
if (want_cmds and (begin not in present or missing)) or (not want_cmds and begin in present):
|
|
560
609
|
warn(f"DRIFT: kimi config.toml missing the project hooks block "
|
|
561
610
|
f"(run `mise run hooks:sync`)")
|
|
562
611
|
rc = 1
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
# Until it is set the job runs and fails at the action step — see the "Code
|
|
9
9
|
# Review" section of the CommonProject README.
|
|
10
10
|
#
|
|
11
|
+
# Runner: self-hosted on big-chungus ONLY. GitHub-hosted minutes are billed and
|
|
12
|
+
# the budget is $0, so a hosted label (`ubuntu-latest`, `macos-*`) just sits
|
|
13
|
+
# unstarted. Org repos get the AutomaticAI-io runners; a personal-account repo
|
|
14
|
+
# needs its own repo-level runner (procedure: delonet-conventions skill,
|
|
15
|
+
# references/ci-runners.md).
|
|
16
|
+
#
|
|
11
17
|
# Trigger: `pull_request`, deliberately NOT `pull_request_target`. The latter
|
|
12
18
|
# would hand repo secrets to code from forked PRs; nothing here needs it.
|
|
13
19
|
#
|
|
@@ -23,7 +29,7 @@ on:
|
|
|
23
29
|
|
|
24
30
|
jobs:
|
|
25
31
|
claude-review:
|
|
26
|
-
runs-on:
|
|
32
|
+
runs-on: [self-hosted, Linux, delonet]
|
|
27
33
|
permissions:
|
|
28
34
|
contents: read
|
|
29
35
|
pull-requests: read
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
{
|
|
7
7
|
"project_name": {{ project_name | tojson }},
|
|
8
8
|
"project_description": {{ project_description | tojson }},
|
|
9
|
-
"
|
|
9
|
+
"project_id": {{ project_slug | lower | tojson }},
|
|
10
10
|
"repo_path": "",
|
|
11
11
|
"ticket_provider": {
|
|
12
12
|
"type": {{ ticket_provider | tojson }},
|
|
@@ -20,35 +20,29 @@ _.file = [".env"]
|
|
|
20
20
|
#
|
|
21
21
|
# NOTE: hooks are an array of [[hooks.enter]] tables (NOT enter = [ ... ]) and
|
|
22
22
|
# every {{config_root}} path is single-quoted so it survives a space in the
|
|
23
|
-
# project path — mise runs each `
|
|
23
|
+
# project path — mise runs each `run` via `sh -c`. (`run`, not `script`: mise
|
|
24
|
+
# deprecated `script` for spawned hook commands and removes it in 2027.3.0.)
|
|
24
25
|
[[hooks.enter]]
|
|
25
|
-
|
|
26
|
+
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-agentfiles.sh' '{% raw %}{{config_root}}{% endraw %}'"
|
|
26
27
|
[[hooks.enter]]
|
|
27
28
|
# Atomic (PJAN-24/PJAN-57): shell complexity lives in the managed script so
|
|
28
29
|
# mise never interpolates temporary variables. The script uses mktemp, traps
|
|
29
30
|
# cleanup, and replaces .env only after op inject succeeds.
|
|
30
|
-
|
|
31
|
-
[[hooks.enter]]
|
|
32
|
-
script = "python3 '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/provision-packs.py' --root '{% raw %}{{config_root}}{% endraw %}'"
|
|
33
|
-
[[hooks.enter]]
|
|
34
|
-
script = "python3 '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/sync-skills.py' --scope project --root '{% raw %}{{config_root}}{% endraw %}'"
|
|
31
|
+
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/materialize-env.sh'"
|
|
35
32
|
[[hooks.enter]]
|
|
36
|
-
|
|
33
|
+
run = "[ -f '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/codegraph.sh' ] && '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/codegraph.sh' || true"
|
|
37
34
|
{%- if agent_hooks_layer %}
|
|
38
35
|
[[hooks.enter]]
|
|
39
|
-
|
|
36
|
+
run = "'{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py' --install --quiet"
|
|
40
37
|
{%- endif %}
|
|
41
38
|
{%- if agent_hooks_layer %}
|
|
42
39
|
[[hooks.leave]]
|
|
43
|
-
|
|
40
|
+
run = "'{% raw %}{{config_root}}{% endraw %}/.agents/hooks/sync.py' --uninstall --quiet"
|
|
44
41
|
{%- endif %}
|
|
45
42
|
|
|
46
43
|
[[watch_files]]
|
|
47
44
|
patterns = ["AGENTS.md"]
|
|
48
45
|
task = "link:agentfiles"
|
|
49
|
-
[[watch_files]]
|
|
50
|
-
patterns = [".agents/skills.json"]
|
|
51
|
-
task = "skills:sync"
|
|
52
46
|
{% if agent_hooks_layer %}
|
|
53
47
|
# Re-fan-out the agent hooks whenever the single source of truth changes.
|
|
54
48
|
[[watch_files]]
|
|
@@ -60,15 +54,11 @@ description = "Symlink all agent files to AGENTS.md"
|
|
|
60
54
|
run = "'{% raw %}{{config_root}}{% endraw %}/.mise/scripts/link-agentfiles.sh' '{% raw %}{{config_root}}{% endraw %}'"
|
|
61
55
|
|
|
62
56
|
[tasks."skills:sync"]
|
|
63
|
-
description = "
|
|
64
|
-
|
|
65
|
-
run = "
|
|
66
|
-
|
|
67
|
-
[tasks."skills:provision:packs"]
|
|
68
|
-
description = "Provision every Skillex pack declared in .agents/skills.json"
|
|
69
|
-
run = "python3 '{% raw %}{{config_root}}{% endraw %}/.mise/scripts/provision-packs.py' --root '{% raw %}{{config_root}}{% endraw %}'"
|
|
57
|
+
description = "Reconcile this project's selected skills"
|
|
58
|
+
tools = { "npm:@delorenj/skillex" = { version = "0.1.2", allow_low_downloads = true }, node = "24" }
|
|
59
|
+
run = "skillex sync --scope project --project '{% raw %}{{config_root}}{% endraw %}'"
|
|
70
60
|
{% if agent_hooks_layer %}
|
|
71
|
-
# --- Project-scoped agent hooks
|
|
61
|
+
# --- Project-scoped agent hooks (see .agents/hooks/README.md) ---
|
|
72
62
|
|
|
73
63
|
[tasks."hooks:sync"]
|
|
74
64
|
description = "Fan out .agents/hooks/hooks.master.json to each agent CLI (claude committed; codex/kimi injected; hermes adapter)"
|