@event4u/agent-config 2.6.0 → 2.7.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.
Files changed (132) hide show
  1. package/.agent-src/commands/agent-handoff.md +1 -0
  2. package/.agent-src/commands/agent-status.md +1 -0
  3. package/.agent-src/commands/agents/audit.md +1 -0
  4. package/.agent-src/commands/agents/init.md +1 -0
  5. package/.agent-src/commands/agents/optimize.md +1 -0
  6. package/.agent-src/commands/agents.md +1 -0
  7. package/.agent-src/commands/analyze-reference-repo.md +1 -0
  8. package/.agent-src/commands/bug-fix.md +1 -0
  9. package/.agent-src/commands/bug-investigate.md +1 -0
  10. package/.agent-src/commands/challenge-me/vision.md +1 -0
  11. package/.agent-src/commands/challenge-me/with-docs.md +1 -0
  12. package/.agent-src/commands/challenge-me.md +1 -0
  13. package/.agent-src/commands/chat-history/import.md +1 -0
  14. package/.agent-src/commands/chat-history/learn.md +1 -0
  15. package/.agent-src/commands/chat-history/show.md +1 -0
  16. package/.agent-src/commands/chat-history.md +1 -0
  17. package/.agent-src/commands/check-current-md.md +1 -0
  18. package/.agent-src/commands/commit/in-chunks.md +1 -0
  19. package/.agent-src/commands/commit.md +1 -0
  20. package/.agent-src/commands/compress.md +1 -0
  21. package/.agent-src/commands/context/create.md +1 -0
  22. package/.agent-src/commands/context/refactor.md +1 -0
  23. package/.agent-src/commands/context.md +1 -0
  24. package/.agent-src/commands/cost-report.md +1 -0
  25. package/.agent-src/commands/council/default.md +1 -0
  26. package/.agent-src/commands/council/design.md +1 -0
  27. package/.agent-src/commands/council/optimize.md +1 -0
  28. package/.agent-src/commands/council/pr.md +1 -0
  29. package/.agent-src/commands/council.md +1 -0
  30. package/.agent-src/commands/create-pr/description-only.md +1 -0
  31. package/.agent-src/commands/create-pr.md +1 -0
  32. package/.agent-src/commands/e2e-heal.md +1 -0
  33. package/.agent-src/commands/e2e-plan.md +1 -0
  34. package/.agent-src/commands/estimate-ticket.md +1 -0
  35. package/.agent-src/commands/feature/dev.md +1 -0
  36. package/.agent-src/commands/feature/explore.md +1 -0
  37. package/.agent-src/commands/feature/plan.md +1 -0
  38. package/.agent-src/commands/feature/refactor.md +1 -0
  39. package/.agent-src/commands/feature/roadmap.md +1 -0
  40. package/.agent-src/commands/feature.md +1 -0
  41. package/.agent-src/commands/fix/ci.md +1 -0
  42. package/.agent-src/commands/fix/portability.md +1 -0
  43. package/.agent-src/commands/fix/pr-bot-comments.md +1 -0
  44. package/.agent-src/commands/fix/pr-comments.md +1 -0
  45. package/.agent-src/commands/fix/pr-developer-comments.md +1 -0
  46. package/.agent-src/commands/fix/refs.md +1 -0
  47. package/.agent-src/commands/fix/seeder.md +1 -0
  48. package/.agent-src/commands/fix.md +1 -0
  49. package/.agent-src/commands/grill-me.md +1 -0
  50. package/.agent-src/commands/implement-ticket.md +1 -0
  51. package/.agent-src/commands/jira-ticket.md +1 -0
  52. package/.agent-src/commands/judge/on-diff.md +1 -0
  53. package/.agent-src/commands/judge/solo.md +1 -0
  54. package/.agent-src/commands/judge/steps.md +1 -0
  55. package/.agent-src/commands/judge.md +1 -0
  56. package/.agent-src/commands/memory/add.md +1 -0
  57. package/.agent-src/commands/memory/load.md +1 -0
  58. package/.agent-src/commands/memory/mine-session.md +1 -0
  59. package/.agent-src/commands/memory/promote.md +1 -0
  60. package/.agent-src/commands/memory/propose.md +1 -0
  61. package/.agent-src/commands/memory.md +1 -0
  62. package/.agent-src/commands/mode.md +1 -0
  63. package/.agent-src/commands/module/create.md +1 -0
  64. package/.agent-src/commands/module/explore.md +1 -0
  65. package/.agent-src/commands/module.md +1 -0
  66. package/.agent-src/commands/onboard.md +1 -0
  67. package/.agent-src/commands/optimize/agents-dir.md +1 -0
  68. package/.agent-src/commands/optimize/augmentignore.md +1 -0
  69. package/.agent-src/commands/optimize/rtk.md +1 -0
  70. package/.agent-src/commands/optimize/skills.md +1 -0
  71. package/.agent-src/commands/optimize-prompt.md +1 -0
  72. package/.agent-src/commands/optimize.md +1 -0
  73. package/.agent-src/commands/orchestrate.md +1 -0
  74. package/.agent-src/commands/override/create.md +1 -0
  75. package/.agent-src/commands/override/manage.md +1 -0
  76. package/.agent-src/commands/override.md +1 -0
  77. package/.agent-src/commands/package-reset.md +1 -0
  78. package/.agent-src/commands/package-test.md +1 -0
  79. package/.agent-src/commands/prepare-for-review.md +1 -0
  80. package/.agent-src/commands/project-analyze.md +1 -0
  81. package/.agent-src/commands/project-health.md +1 -0
  82. package/.agent-src/commands/quality-fix.md +1 -0
  83. package/.agent-src/commands/refine-ticket.md +1 -0
  84. package/.agent-src/commands/research/deep.md +1 -0
  85. package/.agent-src/commands/research/report.md +1 -0
  86. package/.agent-src/commands/research.md +1 -0
  87. package/.agent-src/commands/review-changes.md +1 -0
  88. package/.agent-src/commands/review-routing.md +1 -0
  89. package/.agent-src/commands/roadmap/ai-council.md +1 -0
  90. package/.agent-src/commands/roadmap/create.md +1 -0
  91. package/.agent-src/commands/roadmap/process-full.md +1 -0
  92. package/.agent-src/commands/roadmap/process-phase.md +1 -0
  93. package/.agent-src/commands/roadmap/process-step.md +1 -0
  94. package/.agent-src/commands/roadmap.md +1 -0
  95. package/.agent-src/commands/rule-compliance-audit.md +1 -0
  96. package/.agent-src/commands/set-cost-profile.md +1 -0
  97. package/.agent-src/commands/sync-agent-settings.md +1 -0
  98. package/.agent-src/commands/sync-gitignore/fix.md +1 -0
  99. package/.agent-src/commands/sync-gitignore.md +1 -0
  100. package/.agent-src/commands/tests/create.md +1 -0
  101. package/.agent-src/commands/tests/execute.md +1 -0
  102. package/.agent-src/commands/tests.md +1 -0
  103. package/.agent-src/commands/threat-model.md +1 -0
  104. package/.agent-src/commands/update-form-request-messages.md +1 -0
  105. package/.agent-src/commands/upstream-contribute.md +1 -0
  106. package/.agent-src/commands/work.md +1 -0
  107. package/.claude-plugin/marketplace.json +1 -1
  108. package/AGENTS.md +4 -4
  109. package/CHANGELOG.md +56 -2121
  110. package/README.md +58 -32
  111. package/config/gitignore-block.txt +5 -0
  112. package/docs/architecture/augment-projection.md +70 -0
  113. package/docs/architecture/claude-bundle.md +77 -0
  114. package/docs/architecture/compression.md +67 -0
  115. package/docs/architecture/multi-tool-projection.md +72 -0
  116. package/docs/architecture.md +30 -53
  117. package/docs/archive/CHANGELOG-pre-2.2.0.md +2138 -0
  118. package/docs/contracts/CHANGELOG-conventions.md +121 -0
  119. package/docs/contracts/command-surface-tiers.md +140 -0
  120. package/docs/contracts/mcp-cloud-scope.md +193 -21
  121. package/docs/contracts/mcp-phase-1-scope.md +1 -0
  122. package/docs/decisions/ADR-007-agent-discovery-scopes.md +67 -0
  123. package/docs/setup/enterprise-and-offline.md +201 -0
  124. package/docs/setup/per-ide/augment.md +37 -25
  125. package/package.json +1 -1
  126. package/scripts/_bootstrap_tier_frontmatter.py +151 -0
  127. package/scripts/agent-config +146 -83
  128. package/scripts/hermetic-install.sh +235 -0
  129. package/scripts/install.py +8 -1
  130. package/scripts/lint_command_tiers.py +115 -0
  131. package/scripts/mcp_server/__init__.py +5 -0
  132. package/scripts/schemas/command.schema.json +5 -0
@@ -34,13 +34,89 @@ CONSUMER_ROOT="$(pwd)"
34
34
  VERSION_FILE="$PACKAGE_ROOT/package.json"
35
35
 
36
36
  usage() {
37
+ # Tier filter — see docs/contracts/command-surface-tiers.md.
38
+ # Default prints Tier-0 only; --tier=1 adds Tier-1; --tier=all adds Tier-2.
39
+ local tier="${1:-0}"
40
+
37
41
  cat <<'EOF'
38
42
  agent-config — event4u/agent-config CLI
39
43
 
40
44
  Usage:
41
45
  ./agent-config <command> [options]
46
+ ./agent-config --help [--tier=0|1|all]
47
+ EOF
48
+
49
+ cat <<'EOF'
50
+
51
+ Tier 0 — daily-driver (init → sync → validate → work):
52
+ init One-shot project install. Forwards to `scripts/install`
53
+ with all args. Entry point for `npx @event4u/agent-config init`.
54
+ Flags: --tools=<list> | --ai=<list> | --yes | --force
55
+ sync Replay agents/installed-tools.lock — re-installs any
56
+ tool whose bridge marker is missing locally (ADR-008).
57
+ Flags: --dry-run | --force | --project=<path>
58
+ validate Read-only drift detection on the manifest
59
+ (marker missing, scope divergence, version drift).
60
+ Exits 1 on drift. Flags: --quiet | --skip-version-check
61
+ work Drive the work_engine Python engine on a free-form prompt
62
+ (Option-A loop; called by the /work command)
63
+ implement-ticket Drive the work_engine Python engine on a ticket envelope
64
+ (Option-A loop; called by the /implement-ticket command)
65
+ first-run Guided first-run setup — cost profile, settings, tooling
66
+ keys:install-anthropic Install the Anthropic API key for the AI Council
67
+ (interactive, /dev/tty only, writes ~/.config/agent-config/anthropic.key 0600)
68
+ keys:install-openai Install the OpenAI API key for the AI Council
69
+ (interactive, /dev/tty only, writes ~/.config/agent-config/openai.key 0600)
70
+ council:estimate Pre-call council cost preview (no API call, no spend)
71
+ Usage: council:estimate <question> [--input-mode prompt|roadmap]
72
+ council:run Run the council. Requires --confirm to spend.
73
+ Usage: council:run <question> --output <path> --confirm
74
+ council:render Re-render a saved council responses JSON to markdown
75
+ Usage: council:render <responses.json>
76
+ help Show this help (default Tier-0; --tier=1|all expands)
77
+ --version, -V Print package version
78
+ EOF
79
+
80
+ if [[ "$tier" == "1" || "$tier" == "all" ]]; then
81
+ cat <<'EOF'
82
+
83
+ Tier 1 — power-user (release shape, audit, migration):
84
+ update Update the agent_config_version pin in .agent-settings.yml
85
+ Flags: --check (read-only) | --to <version> (explicit pin)
86
+ versions List available @event4u/agent-config versions
87
+ on npm. Marks the current pin and latest.
88
+ Flags: --offline | --limit=N | --json
89
+ global Install to user-scope paths (~/.claude/, ~/.cursor/, …)
90
+ Forwards to `scripts/install --global` (ADR-007).
91
+ Flags: --tools=<list> | --ai=<list> | --yes | --force
92
+ export Eject a tool's canonical content into a chosen path
93
+ (real file, no symlink). Idempotent; --force overrides
94
+ content drift. See `./agent-config export --list`.
95
+ Flags: --tool=<id> | --output=<path> | --force | --list
96
+ uninstall Remove bridge markers (project) or lockfile
97
+ entries (global). Idempotent. User-deployed
98
+ content under ~/.<tool>/ is preserved unless
99
+ --purge is passed (destructive).
100
+ Flags: --global | --tools=<list> | --dry-run
101
+ | --purge | --force | --project=<path>
102
+ prune Remove project bridge markers not declared in
103
+ agents/installed-tools.lock (npm-prune style).
104
+ Hard-floors when lockfile is absent.
105
+ Flags: --dry-run | --json | --project=<path>
106
+ | --all-missing-lock
107
+ doctor Read-only drift report: manifest ↔ filesystem.
108
+ Lists missing, modified, and foreign files.
109
+ Exits 1 on drift, 2 on missing lockfile.
110
+ Flags: --json | --project=<path>
111
+ migrate One-shot migration off legacy composer / npm install paths
112
+ Flags: --dry-run (detect only)
113
+ EOF
114
+ fi
115
+
116
+ if [[ "$tier" == "all" ]]; then
117
+ cat <<'EOF'
42
118
 
43
- Commands:
119
+ Tier 2 — maintenance / internal (hooks, MCP, memory, telemetry):
44
120
  mcp:render Render mcp.json → .cursor/mcp.json, .windsurf/mcp.json
45
121
  (pass --claude-desktop to also write user-scope config)
46
122
  mcp:check Dry-run mcp:render; exit non-zero if targets are stale
@@ -52,15 +128,8 @@ Commands:
52
128
  roadmap:progress-check Fail if agents/roadmaps-progress.md is stale (for CI)
53
129
  hooks:install Install the pre-commit roadmap-progress hook
54
130
  (use --print to dump it, --force to overwrite an existing hook)
55
- keys:install-anthropic Install the Anthropic API key for the AI Council
56
- (interactive, /dev/tty only, writes ~/.config/agent-config/anthropic.key 0600)
57
- keys:install-openai Install the OpenAI API key for the AI Council
58
- (interactive, /dev/tty only, writes ~/.config/agent-config/openai.key 0600)
59
- first-run Guided first-run setup — cost profile, settings, tooling
60
- implement-ticket Drive the work_engine Python engine on a ticket envelope
61
- (Option-A loop; called by the /implement-ticket command)
62
- work Drive the work_engine Python engine on a free-form prompt
63
- (Option-A loop; called by the /work command)
131
+ hooks:status Print the runtime hook matrix (per-platform install + bindings)
132
+ Flags: --format json|table, --strict (CI), --project-root <path>
64
133
  migrate-state Migrate a legacy .implement-ticket-state.json file
65
134
  to the v1 .work-state.json schema (preserves .bak)
66
135
  memory:lookup Retrieve memory entries (text or JSON envelope)
@@ -83,92 +152,46 @@ Commands:
83
152
  dispatch:hook Universal hook dispatcher (Phase 7, hook-architecture-v1.md)
84
153
  Usage: dispatch:hook --platform <name> --event <event> [--native-event <native>]
85
154
  Reads scripts/hook_manifest.yaml and runs the resolved concern chain.
86
- hooks:status Print the runtime hook matrix (per-platform install + bindings)
87
- Flags: --format json|table, --strict (CI), --project-root <path>
88
155
  telemetry:record Append one artefact-engagement event (default-off)
89
156
  telemetry:status Print artefact-engagement telemetry status (read-only)
90
157
  telemetry:report Aggregate the engagement log into a quartile report
91
- council:estimate Pre-call council cost preview (no API call, no spend)
92
- Usage: council:estimate <question> [--input-mode prompt|roadmap]
93
- council:run Run the council. Requires --confirm to spend.
94
- Usage: council:run <question> --output <path> --confirm
95
- council:render Re-render a saved council responses JSON to markdown
96
- Usage: council:render <responses.json>
97
- update Update the agent_config_version pin in .agent-settings.yml
98
- Flags: --check (read-only) | --to <version> (explicit pin)
99
- migrate One-shot migration off legacy composer / npm install paths
100
- Flags: --dry-run (detect only)
101
- init One-shot project install. Forwards to `scripts/install`
102
- with all args. Entry point for `npx @event4u/agent-config init`.
103
- Flags: --tools=<list> | --ai=<list> | --yes | --force
104
- global Install to user-scope paths (~/.claude/, ~/.cursor/, …)
105
- Forwards to `scripts/install --global` (ADR-007).
106
- Flags: --tools=<list> | --ai=<list> | --yes | --force
107
- export Eject a tool's canonical content into a chosen path
108
- (real file, no symlink). Idempotent; --force overrides
109
- content drift. See `./agent-config export --list`.
110
- Flags: --tool=<id> | --output=<path> | --force | --list
111
- sync Replay agents/installed-tools.lock — re-installs any
112
- tool whose bridge marker is missing locally (ADR-008).
113
- Flags: --dry-run | --force | --project=<path>
114
- validate Read-only drift detection on the manifest
115
- (marker missing, scope divergence, version drift).
116
- Exits 1 on drift. Flags: --quiet | --skip-version-check
117
- uninstall Remove bridge markers (project) or lockfile
118
- entries (global). Idempotent. User-deployed
119
- content under ~/.<tool>/ is preserved unless
120
- --purge is passed (destructive).
121
- Flags: --global | --tools=<list> | --dry-run
122
- | --purge | --force | --project=<path>
123
- prune Remove project bridge markers not declared in
124
- agents/installed-tools.lock (npm-prune style).
125
- Hard-floors when lockfile is absent.
126
- Flags: --dry-run | --json | --project=<path>
127
- | --all-missing-lock
128
- doctor Read-only drift report: manifest ↔ filesystem.
129
- Lists missing, modified, and foreign files.
130
- Exits 1 on drift, 2 on missing lockfile.
131
- Flags: --json | --project=<path>
132
- versions List available @event4u/agent-config versions
133
- on npm. Marks the current pin and latest.
134
- Flags: --offline | --limit=N | --json
135
- help Show this help
136
- --version, -V Print package version
158
+ EOF
159
+ fi
137
160
 
138
- Examples:
139
- ./agent-config mcp:render
140
- ./agent-config mcp:render --claude-desktop
141
- ./agent-config mcp:check
142
- ./agent-config mcp:setup
143
- ./agent-config mcp:run
144
- ./agent-config roadmap:progress
145
- ./agent-config hooks:install
146
- ./agent-config keys:install-anthropic
147
- ./agent-config keys:install-openai
161
+ if [[ "$tier" == "0" ]]; then
162
+ cat <<'EOF'
163
+
164
+ (Hidden: 9 Tier-1 + 26 Tier-2 commands. Run `./agent-config --help --tier=1`
165
+ or `--tier=all` to see them. Tier criteria: docs/contracts/command-surface-tiers.md.)
166
+ EOF
167
+ fi
168
+
169
+ cat <<'EOF'
170
+
171
+ Examples (Tier 0):
172
+ ./agent-config init --tools=claude-code,cursor --yes
173
+ ./agent-config sync --dry-run
174
+ ./agent-config sync
175
+ ./agent-config validate
148
176
  ./agent-config first-run
149
- ./agent-config implement-ticket --state-file .work-state.json
150
177
  ./agent-config work --state-file .work-state.json --prompt-file prompt.txt
151
- ./agent-config migrate-state
152
- ./agent-config memory:lookup --types domain-invariants --key billing
153
- ./agent-config memory:signal --type architecture-decision --path src/Foo.php --body "…"
154
- ./agent-config memory:check --path agents/memory
155
- ./agent-config refine-ticket:detect ticket-body.txt
156
- ./agent-config telemetry:status
157
- ./agent-config telemetry:status --format json
158
- ./agent-config telemetry:report --since 30d --top 20
159
- ./agent-config telemetry:report --since 7d --format json --top 0
178
+ ./agent-config implement-ticket --state-file .work-state.json
179
+ ./agent-config keys:install-anthropic
180
+ ./agent-config keys:install-openai
160
181
  ./agent-config council:estimate prompt.txt
161
182
  ./agent-config council:run prompt.txt --output agents/council-sessions/out.json --confirm
162
183
  ./agent-config council:render agents/council-sessions/out.json
163
- ./agent-config init --tools=claude-code,cursor --yes
184
+ EOF
185
+
186
+ if [[ "$tier" == "1" || "$tier" == "all" ]]; then
187
+ cat <<'EOF'
188
+
189
+ Examples (Tier 1):
164
190
  ./agent-config global --tools=claude-code --yes
165
191
  ./agent-config global --ai=cursor,windsurf
166
192
  ./agent-config export --list
167
193
  ./agent-config export --tool=agents-md --output=AGENTS.md
168
194
  ./agent-config export --tool=copilot-instructions --output=.github/copilot-instructions.md
169
- ./agent-config sync --dry-run
170
- ./agent-config sync
171
- ./agent-config validate
172
195
  ./agent-config uninstall --tools=cursor --dry-run
173
196
  ./agent-config uninstall --global --tools=windsurf --purge
174
197
  ./agent-config prune --dry-run
@@ -180,6 +203,33 @@ Examples:
180
203
  ./agent-config versions --json
181
204
  ./agent-config init --offline --tools=claude-code,cursor --yes
182
205
  ./agent-config update --offline --to=2.2.0
206
+ EOF
207
+ fi
208
+
209
+ if [[ "$tier" == "all" ]]; then
210
+ cat <<'EOF'
211
+
212
+ Examples (Tier 2):
213
+ ./agent-config mcp:render
214
+ ./agent-config mcp:render --claude-desktop
215
+ ./agent-config mcp:check
216
+ ./agent-config mcp:setup
217
+ ./agent-config mcp:run
218
+ ./agent-config roadmap:progress
219
+ ./agent-config hooks:install
220
+ ./agent-config migrate-state
221
+ ./agent-config memory:lookup --types domain-invariants --key billing
222
+ ./agent-config memory:signal --type architecture-decision --path src/Foo.php --body "…"
223
+ ./agent-config memory:check --path agents/memory
224
+ ./agent-config refine-ticket:detect ticket-body.txt
225
+ ./agent-config telemetry:status
226
+ ./agent-config telemetry:status --format json
227
+ ./agent-config telemetry:report --since 30d --top 20
228
+ ./agent-config telemetry:report --since 7d --format json --top 0
229
+ EOF
230
+ fi
231
+
232
+ cat <<'EOF'
183
233
 
184
234
  All commands operate on the CURRENT DIRECTORY (your project root).
185
235
  The CLI is strictly consumer-facing. Maintainer tasks live in Taskfile.yml.
@@ -710,7 +760,20 @@ main() {
710
760
  prune) cmd_prune "$@" ;;
711
761
  doctor) cmd_doctor "$@" ;;
712
762
  versions) cmd_versions "$@" ;;
713
- help|--help|-h|"") usage ;;
763
+ help|--help|-h|"")
764
+ # Optional `--tier=0|1|all` filter (default 0).
765
+ local tier_arg="0"
766
+ for arg in "$@"; do
767
+ case "$arg" in
768
+ --tier=0|--tier=1|--tier=all) tier_arg="${arg#--tier=}" ;;
769
+ --tier|-t) ;; # next arg
770
+ 0|1|all)
771
+ # Positional after --tier/-t.
772
+ tier_arg="$arg" ;;
773
+ --all) tier_arg="all" ;;
774
+ esac
775
+ done
776
+ usage "$tier_arg" ;;
714
777
  --version|-V) print_version ;;
715
778
  *)
716
779
  echo "❌ agent-config: unknown command: $cmd" >&2
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env bash
2
+ # scripts/hermetic-install.sh — verified-offline install entrypoint.
3
+ #
4
+ # Phase 2 Step 5 of agents/roadmaps/road-to-distribution-maturity.md.
5
+ # Council-revised semantic: this is a **verified-offline install**.
6
+ # The script name keeps "hermetic" for roadmap continuity; the
7
+ # Anthropic Phase 2 verdict requires the checksum manifest to be
8
+ # delivered through a separate channel (not bundled in the tarball)
9
+ # so the trust model is not circular.
10
+ #
11
+ # Operator brings the trust root (--gpg-key). No embedded key.
12
+ # Unix-only (macOS + Linux). Windows is future scope per o1 verdict.
13
+ #
14
+ # Sub-criteria from the roadmap:
15
+ # (a) stages a tarball from `npm pack` or operator-supplied .tgz
16
+ # (b) verifies sha256sum against a separate-channel manifest +
17
+ # operator GPG key
18
+ # (c) invokes `scripts/install.py --offline --package-dir=<staging>`
19
+ # (d) writes additive lockfile fields under schema_version: 1
20
+ # (installation_mode, package_checksum, signature_verified)
21
+ #
22
+ # Exit codes:
23
+ # 0 — install + verification succeeded
24
+ # 1 — argument error
25
+ # 2 — checksum mismatch
26
+ # 3 — GPG verification failed
27
+ # 4 — install.py invocation failed
28
+ # 5 — required dependency missing
29
+
30
+ set -euo pipefail
31
+
32
+ # ---------------------------------------------------------------- usage
33
+
34
+ usage() {
35
+ cat <<'USAGE'
36
+ Usage:
37
+ hermetic-install.sh --tarball <file.tgz> --manifest <file.sha256>
38
+ --gpg-key <pubkey.gpg> [--package-dir <staging>]
39
+ [--package-version <semver>] [--dry-run]
40
+
41
+ Required:
42
+ --tarball Path to the agent-config-<version>.tgz produced
43
+ by `npm pack @event4u/agent-config@<version>`.
44
+ --manifest Path to the separate-channel sha256 manifest.
45
+ Manifest must be detached-signed by the operator
46
+ key; the script verifies the signature before
47
+ using the manifest for checksum comparison.
48
+ --gpg-key Path to the operator-supplied GPG public key
49
+ (ASCII-armored or binary). No embedded trust root.
50
+
51
+ Optional:
52
+ --package-dir Staging dir for the extracted tarball
53
+ (default: $(mktemp -d)).
54
+ --package-version Override the semver written to installed.lock
55
+ (default: parse package.json after extraction).
56
+ --dry-run Verify everything but skip install.py invocation.
57
+
58
+ Exit codes: 0 ok · 1 args · 2 checksum · 3 gpg · 4 install · 5 dep
59
+ USAGE
60
+ }
61
+
62
+ # ---------------------------------------------------------------- deps
63
+
64
+ require() {
65
+ command -v "$1" >/dev/null 2>&1 || {
66
+ echo "❌ missing required command: $1" >&2
67
+ exit 5
68
+ }
69
+ }
70
+
71
+ require bash
72
+ require tar
73
+ require gpg
74
+
75
+ # Prefer sha256sum (Linux); fall back to shasum -a 256 (macOS).
76
+ SHA256_CMD=""
77
+ if command -v sha256sum >/dev/null 2>&1; then
78
+ SHA256_CMD="sha256sum"
79
+ elif command -v shasum >/dev/null 2>&1; then
80
+ SHA256_CMD="shasum -a 256"
81
+ else
82
+ echo "❌ missing sha256sum / shasum" >&2
83
+ exit 5
84
+ fi
85
+
86
+ # ---------------------------------------------------------------- args
87
+
88
+ TARBALL=""
89
+ MANIFEST=""
90
+ GPG_KEY=""
91
+ PACKAGE_DIR=""
92
+ PACKAGE_VERSION=""
93
+ DRY_RUN=0
94
+
95
+ while [[ $# -gt 0 ]]; do
96
+ case "$1" in
97
+ --tarball) TARBALL="$2"; shift 2 ;;
98
+ --manifest) MANIFEST="$2"; shift 2 ;;
99
+ --gpg-key) GPG_KEY="$2"; shift 2 ;;
100
+ --package-dir) PACKAGE_DIR="$2"; shift 2 ;;
101
+ --package-version) PACKAGE_VERSION="$2"; shift 2 ;;
102
+ --dry-run) DRY_RUN=1; shift ;;
103
+ -h|--help) usage; exit 0 ;;
104
+ *) echo "❌ unknown arg: $1" >&2; usage; exit 1 ;;
105
+ esac
106
+ done
107
+
108
+ if [[ -z "$TARBALL" || -z "$MANIFEST" || -z "$GPG_KEY" ]]; then
109
+ echo "❌ --tarball, --manifest, --gpg-key are required" >&2
110
+ usage
111
+ exit 1
112
+ fi
113
+
114
+ for f in "$TARBALL" "$MANIFEST" "$GPG_KEY"; do
115
+ [[ -f "$f" ]] || { echo "❌ file not found: $f" >&2; exit 1; }
116
+ done
117
+
118
+ # ---------------------------------------------------------------- gpg
119
+
120
+ # Use a throwaway GPG home so we never touch the operator's
121
+ # real keyring. Cleanup on exit.
122
+ GPGHOME="$(mktemp -d)"
123
+ trap 'rm -rf "$GPGHOME"' EXIT
124
+ export GNUPGHOME="$GPGHOME"
125
+
126
+ echo "🔐 importing operator GPG key from $GPG_KEY"
127
+ gpg --batch --quiet --import "$GPG_KEY"
128
+
129
+ # Verify the manifest signature. Expect detached signature at
130
+ # <manifest>.asc OR inline-signed manifest. Try both.
131
+ if [[ -f "${MANIFEST}.asc" ]]; then
132
+ echo "🔐 verifying detached signature: ${MANIFEST}.asc"
133
+ gpg --batch --quiet --verify "${MANIFEST}.asc" "$MANIFEST" || {
134
+ echo "❌ GPG verification failed (detached)" >&2
135
+ exit 3
136
+ }
137
+ else
138
+ echo "🔐 verifying inline signature on $MANIFEST"
139
+ gpg --batch --quiet --verify "$MANIFEST" || {
140
+ echo "❌ GPG verification failed (inline)" >&2
141
+ echo " hint: provide ${MANIFEST}.asc as a detached signature" >&2
142
+ exit 3
143
+ }
144
+ fi
145
+ SIGNATURE_VERIFIED=true
146
+
147
+ # ---------------------------------------------------------------- sha
148
+
149
+ echo "🔍 computing tarball checksum"
150
+ ACTUAL_SHA="$($SHA256_CMD "$TARBALL" | awk '{print $1}')"
151
+
152
+ # Manifest format: lines of "<sha256> <relative-tarball-path>".
153
+ # Match by basename to avoid path-prefix surprises.
154
+ TARBALL_BASE="$(basename "$TARBALL")"
155
+ EXPECTED_SHA="$(awk -v base="$TARBALL_BASE" '
156
+ $2 == base || $2 == "*"base || $2 ~ "/"base"$" {print $1; exit}
157
+ ' "$MANIFEST")"
158
+
159
+ if [[ -z "$EXPECTED_SHA" ]]; then
160
+ echo "❌ no checksum entry for $TARBALL_BASE in manifest" >&2
161
+ exit 2
162
+ fi
163
+
164
+ if [[ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]]; then
165
+ echo "❌ checksum mismatch" >&2
166
+ echo " expected: $EXPECTED_SHA" >&2
167
+ echo " actual: $ACTUAL_SHA" >&2
168
+ exit 2
169
+ fi
170
+
171
+ PACKAGE_CHECKSUM="sha256:${ACTUAL_SHA}"
172
+ echo "✅ checksum verified: $PACKAGE_CHECKSUM"
173
+
174
+ # ---------------------------------------------------------------- stage
175
+
176
+ if [[ -z "$PACKAGE_DIR" ]]; then
177
+ PACKAGE_DIR="$(mktemp -d -t agent-config-hermetic-XXXXXX)"
178
+ fi
179
+ mkdir -p "$PACKAGE_DIR"
180
+ echo "📦 staging tarball into $PACKAGE_DIR"
181
+ tar -xzf "$TARBALL" -C "$PACKAGE_DIR"
182
+
183
+ # npm pack produces a top-level `package/` directory.
184
+ STAGED="$PACKAGE_DIR/package"
185
+ [[ -d "$STAGED" ]] || {
186
+ echo "❌ staged dir missing expected 'package/' subdir: $STAGED" >&2
187
+ exit 4
188
+ }
189
+
190
+ if [[ -z "$PACKAGE_VERSION" ]] && [[ -f "$STAGED/package.json" ]]; then
191
+ # Pull the literal value bound to the "version" key, not the next
192
+ # quoted token on the same line (which is the package name when
193
+ # package.json is single-line).
194
+ PACKAGE_VERSION="$(
195
+ sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
196
+ "$STAGED/package.json" | head -n 1
197
+ )"
198
+ fi
199
+ [[ -n "$PACKAGE_VERSION" ]] || {
200
+ echo "❌ could not determine package version" >&2
201
+ exit 4
202
+ }
203
+
204
+ # ---------------------------------------------------------------- install.py
205
+
206
+ if [[ "$DRY_RUN" -eq 1 ]]; then
207
+ echo "🟡 --dry-run: skipping install.py invocation"
208
+ echo " would invoke: scripts/install.py --offline --package-dir=$STAGED"
209
+ echo " installation_mode=hermetic"
210
+ echo " package_checksum=$PACKAGE_CHECKSUM"
211
+ echo " signature_verified=$SIGNATURE_VERIFIED"
212
+ exit 0
213
+ fi
214
+
215
+ # install.py is shipped inside the staged package — invoke that
216
+ # copy, not whatever happens to be in $PWD.
217
+ INSTALL_PY="$STAGED/scripts/install.py"
218
+ [[ -f "$INSTALL_PY" ]] || {
219
+ echo "❌ install.py not found in staged package: $INSTALL_PY" >&2
220
+ exit 4
221
+ }
222
+
223
+ echo "🚀 invoking install.py --offline --package-dir=$STAGED"
224
+ # Pass the hermetic metadata via environment so install.py can record
225
+ # the additive lockfile fields without changing its CLI surface.
226
+ AGENT_CONFIG_INSTALLATION_MODE="hermetic" \
227
+ AGENT_CONFIG_PACKAGE_CHECKSUM="$PACKAGE_CHECKSUM" \
228
+ AGENT_CONFIG_SIGNATURE_VERIFIED="$SIGNATURE_VERIFIED" \
229
+ AGENT_CONFIG_PACKAGE_VERSION="$PACKAGE_VERSION" \
230
+ python3 "$INSTALL_PY" --offline --package-dir="$STAGED" || {
231
+ echo "❌ install.py exited non-zero" >&2
232
+ exit 4
233
+ }
234
+
235
+ echo "✅ verified-offline install complete (version $PACKAGE_VERSION)"
@@ -2023,7 +2023,14 @@ SCOPE_SUPPORT = {
2023
2023
  "cline": "both",
2024
2024
  "gemini-cli": "both",
2025
2025
  "copilot": "both",
2026
- "augment": "both",
2026
+ # `augment` is global-only by design: a single user-scope deploy to
2027
+ # `~/.augment/` is the canonical surface. The package owner accepts
2028
+ # that the full rule set exceeds Augment's 49,512-char workspace-
2029
+ # guidelines limit — the overflow is a known, surfaced trade-off
2030
+ # (see ADR-007 § Amendment 2026-05-13 — global-only). Project-scope
2031
+ # installs are rejected so the per-repo `.augment/` surface stays
2032
+ # out of the install matrix entirely.
2033
+ "augment": "global",
2027
2034
  "aider": "both",
2028
2035
  "codex": "both",
2029
2036
  # Phase 2.4: roocode / kilocode lifted to "both" — global deploys
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env python3
2
+ """Lint slash-command frontmatter for the `tier:` key.
3
+
4
+ Hard-fails CI if any command under .agent-src.uncompressed/commands/
5
+ lacks a `tier:` declaration or uses an unknown tier value. The valid
6
+ tier set is locked by docs/contracts/command-surface-tiers.md.
7
+
8
+ Hooked into `task ci` after `task lint-rule-tiers`.
9
+
10
+ Exit codes:
11
+ 0 every command declares a valid tier
12
+ 1 one or more commands missing or using an invalid tier
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ QUIET = "--quiet" in sys.argv
20
+
21
+ REPO = Path(__file__).resolve().parents[1]
22
+ COMMANDS_DIR = REPO / ".agent-src.uncompressed" / "commands"
23
+ # Consumer-facing projection — must also carry tier so .augment/commands/
24
+ # (which symlinks to .agent-src/commands/) renders the tier filter.
25
+ COMMANDS_DIR_COMPRESSED = REPO / ".agent-src" / "commands"
26
+
27
+ VALID_TIERS = frozenset({"0", "1", "2"})
28
+
29
+
30
+ def parse_tier(text: str) -> str | None:
31
+ if not text.startswith("---\n"):
32
+ return None
33
+ end = text.find("\n---\n", 4)
34
+ if end == -1:
35
+ return None
36
+ for line in text[4:end].splitlines():
37
+ if ":" not in line:
38
+ continue
39
+ k, _, v = line.partition(":")
40
+ if k.strip() == "tier":
41
+ return v.strip().strip('"').strip("'")
42
+ return None
43
+
44
+
45
+ def lint(commands_dir: Path, *, quiet: bool = False) -> int:
46
+ """Lint a commands directory. Returns 0 on success, 1 on failure."""
47
+ if not commands_dir.is_dir():
48
+ print(
49
+ f"lint_command_tiers: no commands dir at {commands_dir}",
50
+ file=sys.stderr,
51
+ )
52
+ return 1
53
+
54
+ files = sorted(commands_dir.rglob("*.md"))
55
+ # Sub-AGENTS.md companions are not slash commands.
56
+ commands = [p for p in files if p.name != "AGENTS.md"]
57
+
58
+ if not commands:
59
+ print(
60
+ f"lint_command_tiers: no commands found under {commands_dir}",
61
+ file=sys.stderr,
62
+ )
63
+ return 1
64
+
65
+ missing: list[str] = []
66
+ invalid: list[tuple[str, str]] = []
67
+
68
+ for cmd in commands:
69
+ rel = cmd.relative_to(commands_dir).as_posix()
70
+ tier = parse_tier(cmd.read_text(encoding="utf-8"))
71
+ if tier is None:
72
+ missing.append(rel)
73
+ elif tier not in VALID_TIERS:
74
+ invalid.append((rel, tier))
75
+
76
+ if missing or invalid:
77
+ print(
78
+ f"❌ lint_command_tiers: {len(missing)} missing, "
79
+ f"{len(invalid)} invalid (of {len(commands)} commands)",
80
+ file=sys.stderr,
81
+ )
82
+ for name in missing:
83
+ print(f" missing tier: {name}", file=sys.stderr)
84
+ for name, tier in invalid:
85
+ print(f" invalid tier '{tier}': {name}", file=sys.stderr)
86
+ print(
87
+ f" valid tiers: {sorted(VALID_TIERS)}",
88
+ file=sys.stderr,
89
+ )
90
+ print(
91
+ " contract: docs/contracts/command-surface-tiers.md",
92
+ file=sys.stderr,
93
+ )
94
+ return 1
95
+
96
+ if not quiet:
97
+ print(
98
+ f"✅ lint_command_tiers: {len(commands)} commands, "
99
+ f"all tier values valid"
100
+ )
101
+ return 0
102
+
103
+
104
+ def main() -> int:
105
+ rc = lint(COMMANDS_DIR, quiet=QUIET)
106
+ # The compressed projection is the consumer-facing tree (via the
107
+ # .augment/commands → .agent-src/commands symlink). It must also
108
+ # carry tier so the surface stays uniform.
109
+ if COMMANDS_DIR_COMPRESSED.is_dir():
110
+ rc |= lint(COMMANDS_DIR_COMPRESSED, quiet=QUIET)
111
+ return rc
112
+
113
+
114
+ if __name__ == "__main__":
115
+ raise SystemExit(main())
@@ -1,5 +1,10 @@
1
1
  """MCP server for agent-config — Phase 1 MVP.
2
2
 
3
+ mcp_scope: full — local stdio access can be extended to tool execution
4
+ under the Phase 7 wake-up triggers in `docs/contracts/mcp-cloud-scope.md`.
5
+ The hosted Worker (`workers/mcp/`) is `mcp_scope: lite` and is
6
+ intentionally narrower.
7
+
3
8
  Exposes a hand-picked subset of `.agent-src/skills/` as MCP `prompts`
4
9
  over stdio. Read-only and instructional per the A0 execution-safety
5
10
  boundary in `agents/roadmaps/road-to-mcp-server.md`. No `tools`
@@ -12,6 +12,11 @@
12
12
  "pattern": "^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)?$",
13
13
  "$comment": "Top-level commands use the bare slug (`commit`). Nested cluster commands under `commands/<cluster>/<sub>.md` use the colon form (`council:default`) to mirror Claude Code's `/cluster:sub` rendering. Directory slug for `.claude/skills/` is the hyphenated form (`council-default`), generated by compress.py."
14
14
  },
15
+ "tier": {
16
+ "type": "integer",
17
+ "enum": [0, 1, 2],
18
+ "description": "Command-surface tier per docs/contracts/command-surface-tiers.md. 0 = daily-driver (rendered in default `./agent-config --help`), 1 = power-user (rendered with `--tier=1`), 2 = maintenance/internal (rendered only with `--tier=all`). Default for new commands is 2 — promotion is gated by ADR criteria, never by author preference."
19
+ },
15
20
  "description": {
16
21
  "type": "string",
17
22
  "minLength": 1,