@delorenj/pjangler 1.2.19 → 1.2.25

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 (72) hide show
  1. package/dist/index.js +2353 -518
  2. package/dist/mcp-server.js +2331 -494
  3. package/package.json +14 -3
  4. package/templates/commonproject/copier.yml +6 -4
  5. package/templates/commonproject/template/.agents/hooks/README.md +13 -26
  6. package/templates/commonproject/template/.agents/hooks/lib/local-config.sh +4 -14
  7. package/templates/commonproject/template/.agents/hooks/sync.py +5 -6
  8. package/templates/commonproject/template/.agents/local.example.json +2 -8
  9. package/templates/commonproject/template/.agents/skills.json +6 -0
  10. package/templates/commonproject/template/.mise/scripts/provision-bmad-skills.py +480 -0
  11. package/templates/commonproject/template/.mise/scripts/sync-skills.py +449 -0
  12. package/templates/commonproject/template/mise.toml.jinja +16 -16
  13. package/templates/commonproject/tests/test_provision_bmad_skills.py +203 -0
  14. package/templates/commonproject/tests/test_sync_skills_topology.py +120 -0
  15. package/templates/hermes-agent/README.md +70 -29
  16. package/templates/hermes-agent/copier.yml +9 -6
  17. package/templates/hermes-agent/docs/architecture.md +75 -51
  18. package/templates/hermes-agent/docs/fleet-control-plane/architecture.md +11 -6
  19. package/templates/hermes-agent/docs/fleet-control-plane/epics-and-stories.md +2 -2
  20. package/templates/hermes-agent/docs/fleet-control-plane/prd.md +2 -3
  21. package/templates/hermes-agent/docs/operations.md +179 -81
  22. package/templates/hermes-agent/docs/runbooks/runtime-checkpoint-repair.md +31 -171
  23. package/templates/hermes-agent/docs/sentinel/README.md +10 -10
  24. package/templates/hermes-agent/docs/sentinel/architecture.md +6 -8
  25. package/templates/hermes-agent/docs/sentinel/development.md +12 -15
  26. package/templates/hermes-agent/docs/sentinel.md +1 -1
  27. package/templates/hermes-agent/install-local.sh +41 -4
  28. package/templates/hermes-agent/runtime-scaffold/README.md +4 -2
  29. package/templates/hermes-agent/scripts/degit-runtime.sh +192 -0
  30. package/templates/hermes-agent/scripts/fleet-prune-debris.sh +128 -0
  31. package/templates/hermes-agent/scripts/fleet-sync.sh +164 -7
  32. package/templates/hermes-agent/scripts/hermes-runtime-templatize.py +321 -0
  33. package/templates/hermes-agent/scripts/migrate-profile-scoped-chat-secrets.py +136 -0
  34. package/templates/hermes-agent/scripts/momo-unify-agent.py +224 -0
  35. package/templates/hermes-agent/scripts/repair-runtime-checkpoint.sh +7 -119
  36. package/templates/hermes-agent/template/.gitignore.jinja +5 -2
  37. package/templates/hermes-agent/template/.runtime-scaffold/README.md +4 -2
  38. package/templates/hermes-agent/template/.scripts/00-banner.sh +1 -1
  39. package/templates/hermes-agent/template/.scripts/01-config.sh +3 -0
  40. package/templates/hermes-agent/template/.scripts/10-hermes-profile.sh +12 -1
  41. package/templates/hermes-agent/template/.scripts/20-runtime-repo.sh +55 -129
  42. package/templates/hermes-agent/template/.scripts/30-telegram.sh +276 -22
  43. package/templates/hermes-agent/template/.scripts/31-slack.sh +362 -0
  44. package/templates/hermes-agent/template/.scripts/60-bloodbank.sh +8 -66
  45. package/templates/hermes-agent/template/.scripts/70-systemd.sh +44 -30
  46. package/templates/hermes-agent/template/.scripts/80-registry.sh +93 -13
  47. package/templates/hermes-agent/template/.scripts/99-summary.sh +1 -4
  48. package/templates/hermes-agent/template/.scripts/_lib.sh +66 -1
  49. package/templates/hermes-agent/template/.scripts/checkpoint.sh +3 -2
  50. package/templates/hermes-agent/template/.scripts/config.example.toml +10 -10
  51. package/templates/hermes-agent/template/.scripts/heartbeat.sh +12 -1
  52. package/templates/hermes-agent/template/.scripts/momo-wip-lock.py +137 -0
  53. package/templates/hermes-agent/template/.scripts/sentinel.prompt.md.jinja +21 -0
  54. package/templates/hermes-agent/template/SOUL.md.jinja +36 -15
  55. package/templates/hermes-agent/template/hermes.jinja +6 -3
  56. package/templates/hermes-agent/template/role.yaml.jinja +24 -13
  57. package/templates/hermes-agent/tests/test_bloodbank_consumer_contract.py +429 -130
  58. package/templates/hermes-agent/tests/test_fleet_upgrade_contract.py +176 -0
  59. package/templates/hermes-agent/tests/test_launcher_chat_secret_isolation.py +85 -0
  60. package/templates/hermes-agent/tests/test_local_runtime_provisioning.py +130 -0
  61. package/templates/hermes-agent/tests/test_operator_docs_local_runtime_contract.py +132 -0
  62. package/templates/hermes-agent/tests/test_profile_env_detach_contract.py +14 -0
  63. package/templates/hermes-agent/tests/test_profile_scoped_chat_secrets.py +89 -0
  64. package/templates/hermes-agent/tests/test_repository_privacy_contract.py +32 -0
  65. package/templates/hermes-agent/tests/test_slack_provisioning.py +344 -0
  66. package/templates/hermes-agent/tests/test_telegram_provisioning.py +475 -0
  67. package/templates/commonproject/template/.mise/scripts/link-project-skills-to-clis.sh +0 -110
  68. package/templates/commonproject/template/.mise/scripts/unlink-project-skills-from-clis.sh +0 -45
  69. package/templates/hermes-agent/.codegraph/daemon.pid +0 -6
  70. package/templates/hermes-agent/.omo/run-continuation/ses_0e5b28303ffeXxL53hZjKggXDW.json +0 -10
  71. package/templates/hermes-agent/runtime-scaffold/bloodbank-consumer.py +0 -181
  72. package/templates/hermes-agent/template/.runtime-scaffold/bloodbank-consumer.py +0 -181
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delorenj/pjangler",
3
- "version": "1.2.19",
3
+ "version": "1.2.25",
4
4
  "description": "Project subsystem bootstrapper CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -20,14 +20,18 @@
20
20
  },
21
21
  "scripts": {
22
22
  "build": "esbuild src/index.ts src/mcp-server.ts --bundle --packages=external --platform=node --format=esm --outdir=dist",
23
+ "check:audit:prod": "npm audit --omit=dev",
24
+ "check:lock": "node scripts/check-package-lock-parity.mjs",
25
+ "check:submodules": "node scripts/check-submodule-contract.mjs",
26
+ "check:tracked-secrets": "node scripts/check-tracked-secrets.mjs",
23
27
  "start": "node dist/index.js",
24
28
  "mcp": "node dist/mcp-server.js",
25
29
  "typecheck": "tsc --noEmit",
26
- "test": "node tests/parity-migrate-regressions.mjs && node tests/mcp-catalog-regressions.mjs && node tests/mcp-server-regressions.mjs && node tests/project-registry-regressions.mjs && node tests/pg-registry-regressions.mjs",
30
+ "test": "npm run check:lock && npm run check:submodules && npm run check:tracked-secrets && node tests/release-regressions.mjs && node tests/submodule-contract-regressions.mjs && node tests/secret-publication-gate-regressions.mjs && node tests/bmad-version-surface-regressions.mjs && node tests/bmad-transaction-regressions.mjs && node tests/parity-migrate-regressions.mjs && node tests/pjan-43-regressions.mjs && node tests/skillex-init-regressions.mjs && node tests/fleet-shared-bloodbank-regressions.mjs && node tests/mcp-catalog-regressions.mjs && node tests/mcp-server-regressions.mjs && node tests/project-registry-regressions.mjs && node tests/pg-registry-regressions.mjs",
27
31
  "migrate:up": "node-pg-migrate --migrations-dir migrations up",
28
32
  "migrate:down": "node-pg-migrate --migrations-dir migrations down",
29
33
  "migrate:create": "node-pg-migrate --migrations-dir migrations create",
30
- "prepublishOnly": "npm run build"
34
+ "prepublishOnly": "npm run check:lock && npm run check:submodules -- --remote --recursive --archive --npm && npm run build && npm run check:tracked-secrets"
31
35
  },
32
36
  "keywords": [
33
37
  "cli",
@@ -52,5 +56,12 @@
52
56
  "esbuild": "^0.25.0",
53
57
  "node-pg-migrate": "^8.0.0",
54
58
  "typescript": "^5"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/delorenj/pjangler.git"
63
+ },
64
+ "publishConfig": {
65
+ "registry": "https://npm.pkg.github.com"
55
66
  }
56
67
  }
@@ -90,8 +90,9 @@ agent_hooks_layer:
90
90
  default: true
91
91
  when: false
92
92
 
93
- # When agent_hooks_layer is false, omit the project-scoped hook tree + skill-link
94
- # scripts entirely (the mise.toml wiring is already gated inside the template).
93
+ # When agent_hooks_layer is false, omit only the project-scoped hook tree. The
94
+ # skills manifest stays — sync-skills.py writes project-local CLI dirs and is safe
95
+ # even on machines that already run a global ~/.agents/hooks install.
95
96
  # The `.copier-noop-never-matches` sentinel keeps every pattern non-empty when the
96
97
  # layer is enabled, which copier requires.
97
98
  _exclude:
@@ -105,8 +106,6 @@ _exclude:
105
106
  - "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/hooks{% endif %}"
106
107
  - "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/hooks/**{% endif %}"
107
108
  - "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.agents/local.example.json{% endif %}"
108
- - "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.mise/scripts/link-project-skills-to-clis.sh{% endif %}"
109
- - "{% if agent_hooks_layer %}.copier-noop-never-matches{% else %}.mise/scripts/unlink-project-skills-from-clis.sh{% endif %}"
110
109
 
111
110
  # --- Post-generation tasks ---
112
111
  #
@@ -120,5 +119,8 @@ _tasks:
120
119
  - "printf '\\n# Secrets + per-dev agent-hook/skill overrides (see .agents/local.example.json)\\n.env\\n.env.*\\n!.env.op\\n.agents/local.json\\n.kimi-code/\\n.lastagent\\n**/.claude/settings.local.json\\n' >> .gitignore"
121
120
  - "ln -sf AGENTS.md CLAUDE.md"
122
121
  - "ln -sf AGENTS.md GEMINI.md"
122
+ # Materialize the pinned Skillex BMAD manifest + symlink topology without
123
+ # copying pack content or disturbing project-specific, non-BMAD skills.
124
+ - "python3 .mise/scripts/provision-bmad-skills.py"
123
125
  # Stamp the repo's absolute path into .project.json (the SOT) post-render.
124
126
  - "python3 -c \"import json,os,pathlib; p=pathlib.Path('.project.json'); d=json.loads(p.read_text()); d['repo_path']=os.getcwd(); p.write_text(json.dumps(d,indent=2)+chr(10))\""
@@ -15,6 +15,7 @@ master writes zero bytes).
15
15
  mise run hooks-sync # fan out the master -> claude + codex + hermes
16
16
  mise run hooks-check # drift gate (read-only; used in CI)
17
17
  mise run hooks-uninstall # remove codex + hermes injections
18
+ mise run skills-sync # sync .agents/skills.json -> local CLI skill dirs
18
19
  mise run hindsight-setup # one-time: pull the shared CAF Hindsight key into .env
19
20
  ```
20
21
 
@@ -70,8 +71,7 @@ Copy [`.agents/local.example.json`](../local.example.json) → `.agents/local.js
70
71
  "hooks": {
71
72
  "disabled": ["hindsight-recall"], // hook ids — skipped at runtime, ALL agents
72
73
  "disabled_agents": ["codex"] // claude|codex|hermes — codex/hermes injection skipped/removed
73
- },
74
- "skills": { "disabled": ["bmad-help"] } // skill dir names — not symlinked for you
74
+ }
75
75
  }
76
76
  ```
77
77
 
@@ -83,32 +83,18 @@ Copy [`.agents/local.example.json`](../local.example.json) → `.agents/local.js
83
83
  - **Disabled agents** are enforced at **install** time (codex/hermes injection is
84
84
  skipped, and removed if previously installed). `CAF_HOOKS_SKIP_CODEX=1` is an
85
85
  env shortcut for `disabled_agents:["codex"]`.
86
- - **Disabled skills** are honored by the skill fan-out (below).
86
+ ## Skill fan-out `.agents/skills.json` each CLI
87
87
 
88
- ## Skill fan-out — `.agents/skills` each CLI
88
+ `.agents/skills.json` is the project's skill manifest. `sync-skills.py --scope
89
+ project` resolves that manifest into project-local CLI dirs (for example
90
+ `./.codex/skills`, `./.hermes/skills`, `./.kimi-code/skills`) and honors
91
+ `inherit_global: true` so a dev's global `~/.agents/skills.json` loadout is
92
+ merged in automatically.
89
93
 
90
- `.agents/skills/` is the project's enabled skill set (committed inherited skills +
91
- `./skills/*` app skills symlinked in on enter). `link-project-skills-to-clis.sh`
92
- fans it out as per-skill symlinks to every agent CLI that doesn't read `.agents/`
93
- natively a small `SKILL_TARGETS` table:
94
-
95
- | CLI | target dir | scope |
96
- |---|---|---|
97
- | Codex | `~/.codex/skills` | **global** — link ours in, never clobber foreign entries, removed on `leave` |
98
- | Kimi | `./.kimi-code/skills` | **local** — a project-scoped mirror we fully manage (stale real copies replaced with symlinks) |
99
-
100
- Add a CLI = one `dir|scope` line. Per-dev control via `.agents/local.json`
101
- `skills`:
102
-
103
- - `disabled: [...]` — never link these; pruned from managed mirrors.
104
- - `defer_to_global: true` — **only if you run a global `~/.agents/skills` system.**
105
- Skips any project skill whose name also exists there, so your global copy wins
106
- and you get **zero duplicates** (it even yields the slot in `~/.codex/skills`).
107
- Teammates with no global layer leave it `false` (default) and **inherit the full
108
- set**. Override the global dir with `AGENTS_GLOBAL_SKILLS_DIR`.
109
-
110
- Tasks: `mise run skills-relink` (re-fan), `mise run link-project-skills-to-clis`,
111
- `mise run unlink-project-skills-from-clis`.
94
+ - Project-local skills with the same name shadow the global ones.
95
+ - No `defer_to_global` flag or bash cleanup scripts are needed anymore.
96
+ - The manifest is the only hand-edited skill SSOT; run `mise run skills-sync`
97
+ after changing it, or just re-enter the repo.
112
98
 
113
99
  ## Hindsight credentials — `mise run hindsight-setup`
114
100
 
@@ -137,6 +123,7 @@ Without a key the hooks **no-op gracefully** — recall/retain just do nothing.
137
123
  ```
138
124
  .agents/
139
125
  local.example.json # per-dev override template (copy -> local.json, gitignored)
126
+ skills.json # project skill manifest (SSOT for sync-skills.py)
140
127
  hooks/
141
128
  hooks.master.json # SSOT — the only hand-edited config
142
129
  sync.py # fan-out engine (--install / --uninstall / --check)
@@ -4,10 +4,9 @@
4
4
  # Source this, then call:
5
5
  # hook_disabled <hook-id> # true if .hooks.disabled[] contains the id
6
6
  # agent_disabled <agent> # true if .hooks.disabled_agents[] contains the agent
7
- # skill_disabled <skill-name> # true if .skills.disabled[] contains the name
8
7
  #
9
8
  # All FAIL OPEN (return 1 = "not disabled") when `.agents/local.json` or `jq` is
10
- # absent, so a missing/garbled local config can never silently kill hooks/skills.
9
+ # absent, so a missing/garbled local config can never silently kill hooks.
11
10
  #
12
11
  # `.agents/local.json` is gitignored — each dev owns their own. See
13
12
  # `.agents/local.example.json` for the schema.
@@ -30,22 +29,13 @@ _caf_listed() {
30
29
 
31
30
  hook_disabled() { _caf_listed '.hooks.disabled' "$1"; }
32
31
  agent_disabled() { _caf_listed '.hooks.disabled_agents' "$1"; }
33
- skill_disabled() { _caf_listed '.skills.disabled' "$1"; }
34
32
 
35
- # True if the dev opted to let their GLOBAL agent system (~/.agents/skills) provide
36
- # any overlapping skill, so the project linker should skip it (no duplicates).
37
- # Teammates with no global layer omit this and inherit the full project set.
33
+ # True if the dev opted to let their GLOBAL agent system (~/.agents/hooks) provide
34
+ # the hook layer, so project-scoped per-user injections should be suppressed.
38
35
  skills_defer_to_global() {
39
36
  local f
40
37
  f="$(_caf_local_json)" || return 1
41
38
  [[ -f "$f" ]] || return 1
42
39
  command -v jq >/dev/null 2>&1 || return 1
43
- jq -e '.skills.defer_to_global == true' "$f" >/dev/null 2>&1
44
- }
45
-
46
- # True if <skill-name> is provided by the global agent SSOT. `-e` follows the
47
- # ~/.agents/skills symlink (-> skillex/skill-sets/global) and its entries.
48
- skill_is_global() {
49
- local name="$1" gdir="${AGENTS_GLOBAL_SKILLS_DIR:-$HOME/.agents/skills}"
50
- [[ -e "${gdir}/${name}" ]]
40
+ jq -e '.hooks.defer_to_global == true' "$f" >/dev/null 2>&1
51
41
  }
@@ -72,10 +72,10 @@ def load_local() -> dict:
72
72
  (so even Claude's committed hooks honor them); this only needs disabled
73
73
  AGENTS, which gate install. CAF_HOOKS_SKIP_CODEX=1 is an env shortcut.
74
74
 
75
- `defer_to_global` (under either `hooks` or `skills`) means "I already run
76
- these hooks from a global agent system" — so the shared per-user injections
77
- (codex/kimi/hermes) are suppressed and actively removed. Claude's committed
78
- repo settings are harmless and left in place.
75
+ `hooks.defer_to_global` means "I already run these hooks from a global agent
76
+ system" — so the shared per-user injections (codex/kimi/hermes) are
77
+ suppressed and actively removed. Claude's committed repo settings are
78
+ harmless and left in place.
79
79
  """
80
80
  disabled_agents: set[str] = set()
81
81
  defer_to_global = False
@@ -84,9 +84,8 @@ def load_local() -> dict:
84
84
  try:
85
85
  data = json.loads(p.read_text() or "{}")
86
86
  hooks_cfg = data.get("hooks") or {}
87
- skills_cfg = data.get("skills") or {}
88
87
  disabled_agents = set(hooks_cfg.get("disabled_agents") or [])
89
- defer_to_global = bool(hooks_cfg.get("defer_to_global")) or bool(skills_cfg.get("defer_to_global"))
88
+ defer_to_global = bool(hooks_cfg.get("defer_to_global"))
90
89
  except (json.JSONDecodeError, OSError) as exc:
91
90
  warn(f"ignoring malformed .agents/local.json: {exc}")
92
91
  if os.environ.get("CAF_HOOKS_SKIP_CODEX") == "1":
@@ -1,17 +1,11 @@
1
1
  {
2
- "$comment": "PER-DEV LOCAL OVERRIDES — copy this file to .agents/local.json (gitignored) and edit. Lets you opt out of individual hooks, whole agents, or specific auto-linked skills, and tune how project skills fan out to your agent CLIs — without touching committed config. Hooks self-skip at RUNTIME via .agents/hooks/lib/hook-guard.sh (so even Claude's committed hooks honor it); codex/hermes injections additionally skip at INSTALL time. Re-run `mise run hooks-sync` / `mise run skills-relink` (or re-cd into the repo) after editing.",
2
+ "$comment": "PER-DEV LOCAL OVERRIDES — copy this file to .agents/local.json (gitignored) and edit. Lets you opt out of individual hooks or whole injected agents without touching committed config. Hooks self-skip at RUNTIME via .agents/hooks/lib/hook-guard.sh (so even Claude's committed hooks honor it); codex/hermes injections additionally skip at INSTALL time. Re-run `mise run hooks-sync` (or re-cd into the repo) after editing.",
3
3
  "hooks": {
4
4
  "$disabled_help": "Hook ids from .agents/hooks/hooks.master.json: skill-check-reminder, hindsight-recall, hindsight-retain, hindsight-session-end. Listed ids are skipped at runtime across ALL agents.",
5
5
  "disabled": [],
6
6
  "$disabled_agents_help": "Agent keys: claude, codex, kimi, hermes. Listed agents are NOT installed (codex/kimi/hermes injections are skipped/removed). Claude's hooks are committed and can't be fully removed per-dev — disable them individually via `disabled` instead.",
7
7
  "disabled_agents": [],
8
- "$defer_to_global_help": "Set true if you already run these hooks from a GLOBAL agent system (~/.agents/hooks). When true, sync.py suppresses AND removes the shared per-user injections (codex/kimi/hermes) so a project never double-injects into ~/.codex / ~/.kimi-code; Claude's committed repo settings are left in place. Implied by skills.defer_to_global. On a machine with a global install, pjangler skips scaffolding this whole layer, so you rarely need to set this by hand.",
9
- "defer_to_global": false
10
- },
11
- "skills": {
12
- "$disabled_help": "Skill directory names under .agents/skills/. Listed skills are NOT symlinked into any agent CLI dir for you, and are pruned from your managed mirrors.",
13
- "disabled": [],
14
- "$defer_to_global_help": "Set true ONLY if you run a global agent system at ~/.agents/skills. When true, the linker skips any project skill whose name also exists in your global SSOT, so your global copy wins and you get ZERO duplicates/conflicts (and yields the slot in shared dirs like ~/.codex/skills). Teammates with no global layer leave this false (the default) and inherit the FULL project skill set. Override the global dir with the AGENTS_GLOBAL_SKILLS_DIR env var.",
8
+ "$defer_to_global_help": "Set true if you already run these hooks from a GLOBAL agent system (~/.agents/hooks). When true, sync.py suppresses AND removes the shared per-user injections (codex/kimi/hermes) so a project never double-injects into ~/.codex / ~/.kimi-code; Claude's committed repo settings are left in place. On a machine with a global install, pjangler skips scaffolding this whole layer, so you rarely need to set this by hand.",
15
9
  "defer_to_global": false
16
10
  }
17
11
  }
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/skillex/schemas/main/skills.schema.json",
3
+ "inherit_global": true,
4
+ "registry": "https://github.com/delorenj/skillex.git",
5
+ "skills": []
6
+ }