@event4u/agent-config 8.13.0 → 9.0.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 (279) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +136 -0
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/agent-handoff.md +35 -0
  5. package/dist/agent-src/commands/agents/init.md +1 -0
  6. package/dist/agent-src/commands/agents/optimize.md +1 -0
  7. package/dist/agent-src/commands/agents/user/accept.md +3 -2
  8. package/dist/agent-src/commands/agents/user/init.md +5 -4
  9. package/dist/agent-src/commands/agents/user/update.md +3 -2
  10. package/dist/agent-src/commands/agents/user.md +1 -0
  11. package/dist/agent-src/commands/agents.md +1 -0
  12. package/dist/agent-src/commands/analytics/show.md +1 -0
  13. package/dist/agent-src/commands/analytics.md +1 -0
  14. package/dist/agent-src/commands/analyze/decision.md +1 -0
  15. package/dist/agent-src/commands/analyze/incident.md +1 -0
  16. package/dist/agent-src/commands/analyze/near-miss.md +1 -0
  17. package/dist/agent-src/commands/analyze/postmortem.md +1 -0
  18. package/dist/agent-src/commands/analyze/premortem.md +1 -0
  19. package/dist/agent-src/commands/analyze/reference-repo.md +1 -0
  20. package/dist/agent-src/commands/analyze.md +3 -2
  21. package/dist/agent-src/commands/brand/identity.md +6 -5
  22. package/dist/agent-src/commands/brand/review.md +6 -5
  23. package/dist/agent-src/commands/brand/strategy.md +6 -4
  24. package/dist/agent-src/commands/brand/tokens.md +7 -6
  25. package/dist/agent-src/commands/brand/voice.md +5 -4
  26. package/dist/agent-src/commands/brand.md +9 -7
  27. package/dist/agent-src/commands/bug/fix.md +1 -0
  28. package/dist/agent-src/commands/bug/investigate.md +1 -0
  29. package/dist/agent-src/commands/bug.md +2 -1
  30. package/dist/agent-src/commands/challenge-me/vision.md +1 -0
  31. package/dist/agent-src/commands/challenge-me/with-docs.md +1 -0
  32. package/dist/agent-src/commands/challenge-me.md +28 -6
  33. package/dist/agent-src/commands/chat-history.md +1 -0
  34. package/dist/agent-src/commands/check-current-md.md +1 -0
  35. package/dist/agent-src/commands/commit.md +1 -0
  36. package/dist/agent-src/commands/context/create.md +3 -2
  37. package/dist/agent-src/commands/context.md +1 -0
  38. package/dist/agent-src/commands/cost/profile.md +1 -0
  39. package/dist/agent-src/commands/cost.md +2 -1
  40. package/dist/agent-src/commands/council/analysis.md +1 -0
  41. package/dist/agent-src/commands/council/debate.md +1 -0
  42. package/dist/agent-src/commands/council/default.md +21 -20
  43. package/dist/agent-src/commands/council/design.md +1 -0
  44. package/dist/agent-src/commands/council/optimize.md +1 -0
  45. package/dist/agent-src/commands/council/pr.md +1 -0
  46. package/dist/agent-src/commands/council.md +1 -0
  47. package/dist/agent-src/commands/estimate-ticket.md +1 -0
  48. package/dist/agent-src/commands/feature/dev.md +1 -0
  49. package/dist/agent-src/commands/feature/explore.md +1 -0
  50. package/dist/agent-src/commands/feature/plan.md +1 -0
  51. package/dist/agent-src/commands/feature/refactor.md +1 -0
  52. package/dist/agent-src/commands/feature/roadmap.md +1 -0
  53. package/dist/agent-src/commands/feature.md +2 -1
  54. package/dist/agent-src/commands/fix/pr-comments.md +19 -0
  55. package/dist/agent-src/commands/fix.md +2 -1
  56. package/dist/agent-src/commands/ghostwriter/delete.md +1 -0
  57. package/dist/agent-src/commands/ghostwriter/fetch.md +1 -0
  58. package/dist/agent-src/commands/ghostwriter/show.md +1 -0
  59. package/dist/agent-src/commands/ghostwriter/write.md +1 -0
  60. package/dist/agent-src/commands/ghostwriter.md +1 -0
  61. package/dist/agent-src/commands/grill-me.md +17 -12
  62. package/dist/agent-src/commands/humanize.md +1 -0
  63. package/dist/agent-src/commands/image/analyse.md +2 -1
  64. package/dist/agent-src/commands/image/create.md +1 -0
  65. package/dist/agent-src/commands/image/verify.md +1 -0
  66. package/dist/agent-src/commands/image.md +16 -12
  67. package/dist/agent-src/commands/implement-ticket.md +1 -0
  68. package/dist/agent-src/commands/judge/on-diff.md +1 -0
  69. package/dist/agent-src/commands/judge/solo.md +1 -0
  70. package/dist/agent-src/commands/judge/steps.md +1 -0
  71. package/dist/agent-src/commands/judge.md +1 -0
  72. package/dist/agent-src/commands/knowledge/cross-repo.md +1 -0
  73. package/dist/agent-src/commands/knowledge/forget.md +1 -0
  74. package/dist/agent-src/commands/knowledge/ingest.md +1 -0
  75. package/dist/agent-src/commands/knowledge/list.md +10 -0
  76. package/dist/agent-src/commands/knowledge.md +1 -0
  77. package/dist/agent-src/commands/memory/learn-low-impact.md +1 -0
  78. package/dist/agent-src/commands/memory/mine-session.md +1 -0
  79. package/dist/agent-src/commands/memory/promote.md +3 -2
  80. package/dist/agent-src/commands/memory.md +1 -0
  81. package/dist/agent-src/commands/mission/upgrade.md +45 -24
  82. package/dist/agent-src/commands/mode.md +1 -0
  83. package/dist/agent-src/commands/module/create.md +1 -0
  84. package/dist/agent-src/commands/module/explore.md +1 -0
  85. package/dist/agent-src/commands/module.md +1 -0
  86. package/dist/agent-src/commands/optimize/agents-dir.md +1 -0
  87. package/dist/agent-src/commands/optimize/project.md +1 -0
  88. package/dist/agent-src/commands/optimize/prompt.md +1 -0
  89. package/dist/agent-src/commands/optimize.md +2 -1
  90. package/dist/agent-src/commands/orchestrate.md +1 -0
  91. package/dist/agent-src/commands/override.md +1 -0
  92. package/dist/agent-src/commands/package.md +2 -1
  93. package/dist/agent-src/commands/post-as/ghostwriter.md +1 -0
  94. package/dist/agent-src/commands/post-as/me.md +1 -0
  95. package/dist/agent-src/commands/post-as.md +1 -0
  96. package/dist/agent-src/commands/pr/create/description-only.md +1 -0
  97. package/dist/agent-src/commands/pr/create.md +19 -17
  98. package/dist/agent-src/commands/prediction-pool.md +7 -6
  99. package/dist/agent-src/commands/prepare-for-review.md +1 -0
  100. package/dist/agent-src/commands/profile/activate.md +1 -0
  101. package/dist/agent-src/commands/profile/deactivate.md +1 -0
  102. package/dist/agent-src/commands/profile.md +1 -0
  103. package/dist/agent-src/commands/project.md +2 -1
  104. package/dist/agent-src/commands/refine-ticket.md +7 -0
  105. package/dist/agent-src/commands/research/deep.md +1 -0
  106. package/dist/agent-src/commands/research.md +1 -0
  107. package/dist/agent-src/commands/review/routing.md +1 -0
  108. package/dist/agent-src/commands/review.md +2 -1
  109. package/dist/agent-src/commands/roadmap/ai-council.md +1 -0
  110. package/dist/agent-src/commands/roadmap/materialize.md +1 -0
  111. package/dist/agent-src/commands/roadmap/process-full.md +1 -0
  112. package/dist/agent-src/commands/roadmap/process-phase.md +1 -0
  113. package/dist/agent-src/commands/roadmap/process-step.md +1 -0
  114. package/dist/agent-src/commands/roadmap.md +1 -0
  115. package/dist/agent-src/commands/security-audit-config.md +2 -1
  116. package/dist/agent-src/commands/skill/preview.md +1 -0
  117. package/dist/agent-src/commands/skill.md +1 -0
  118. package/dist/agent-src/commands/skills/discover.md +1 -0
  119. package/dist/agent-src/commands/skills.md +1 -0
  120. package/dist/agent-src/commands/sync/agent-settings.md +1 -0
  121. package/dist/agent-src/commands/sync.md +2 -1
  122. package/dist/agent-src/commands/team/adversarial.md +3 -2
  123. package/dist/agent-src/commands/team/delegate.md +3 -2
  124. package/dist/agent-src/commands/team/review.md +3 -2
  125. package/dist/agent-src/commands/team/status.md +49 -18
  126. package/dist/agent-src/commands/team-knowledge.md +8 -6
  127. package/dist/agent-src/commands/team.md +21 -16
  128. package/dist/agent-src/commands/tests/e2e-heal.md +1 -0
  129. package/dist/agent-src/commands/tests/e2e-plan.md +1 -0
  130. package/dist/agent-src/commands/tests/execute.md +1 -0
  131. package/dist/agent-src/commands/tests.md +2 -1
  132. package/dist/agent-src/commands/update-form-request-messages.md +1 -0
  133. package/dist/agent-src/commands/upstream-contribute.md +1 -0
  134. package/dist/agent-src/commands/video/from-script.md +3 -2
  135. package/dist/agent-src/commands/video/from-song.md +22 -21
  136. package/dist/agent-src/commands/video/scene.md +1 -0
  137. package/dist/agent-src/commands/video/stitch.md +2 -1
  138. package/dist/agent-src/commands/video/storyboard.md +1 -0
  139. package/dist/agent-src/commands/video.md +1 -0
  140. package/dist/agent-src/commands/work.md +1 -0
  141. package/dist/agent-src/commands/worktree/cleanup.md +8 -7
  142. package/dist/agent-src/commands/worktree/create.md +1 -0
  143. package/dist/agent-src/commands/worktree/verify.md +1 -0
  144. package/dist/agent-src/commands/worktree.md +1 -0
  145. package/dist/agent-src/rules/active-remediation.md +12 -36
  146. package/dist/agent-src/rules/artifact-drafting-protocol.md +7 -64
  147. package/dist/agent-src/rules/context-hygiene.md +19 -113
  148. package/dist/agent-src/rules/design-fidelity.md +4 -60
  149. package/dist/agent-src/rules/domain-adoption-policy.md +10 -106
  150. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +12 -60
  151. package/dist/agent-src/rules/improve-before-implement.md +4 -0
  152. package/dist/agent-src/rules/minimal-safe-diff.md +6 -86
  153. package/dist/agent-src/rules/size-enforcement.md +10 -0
  154. package/dist/agent-src/rules/tool-safety.md +17 -3
  155. package/dist/agent-src/skills/agent-security-review/SKILL.md +12 -1
  156. package/dist/agent-src/skills/ai-council/SKILL.md +11 -0
  157. package/dist/agent-src/skills/bug-analyzer/SKILL.md +24 -2
  158. package/dist/agent-src/skills/code-review/SKILL.md +105 -93
  159. package/dist/agent-src/skills/code-review/checklists/backend.md +50 -0
  160. package/dist/agent-src/skills/code-review/checklists/database.md +19 -0
  161. package/dist/agent-src/skills/code-review/checklists/dependency.md +18 -0
  162. package/dist/agent-src/skills/code-review/checklists/docs.md +14 -0
  163. package/dist/agent-src/skills/code-review/checklists/frontend.md +19 -0
  164. package/dist/agent-src/skills/code-review/checklists/infra.md +17 -0
  165. package/dist/agent-src/skills/code-review/checklists/producing-the-review.md +62 -0
  166. package/dist/agent-src/skills/code-review/checklists/test-only.md +13 -0
  167. package/dist/agent-src/skills/code-review/evals/evals.json +53 -15
  168. package/dist/agent-src/skills/condense-memory/SKILL.md +3 -2
  169. package/dist/agent-src/skills/conventional-commits-writing/evals/evals.json +15 -0
  170. package/dist/agent-src/skills/docker/SKILL.md +10 -0
  171. package/dist/agent-src/skills/docx-authoring/SKILL.md +102 -0
  172. package/dist/agent-src/skills/github-ci/evals/evals.json +25 -0
  173. package/dist/agent-src/skills/humanizer/SKILL.md +79 -3
  174. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +112 -0
  175. package/dist/agent-src/skills/humanizer/references/fixtures.md +70 -0
  176. package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +7 -1
  177. package/dist/agent-src/skills/laravel/SKILL.md +10 -0
  178. package/dist/agent-src/skills/launch-readiness/SKILL.md +35 -0
  179. package/dist/agent-src/skills/merge-conflicts/SKILL.md +30 -0
  180. package/dist/agent-src/skills/pdf-tools/SKILL.md +101 -0
  181. package/dist/agent-src/skills/quality-tools/evals/evals.json +15 -0
  182. package/dist/agent-src/skills/security-audit/SKILL.md +29 -0
  183. package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +90 -0
  184. package/dist/agent-src/skills/security-maturity-assessment/evals/triggers.json +52 -0
  185. package/dist/agent-src/skills/skill-writing/SKILL.md +79 -0
  186. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +11 -3
  187. package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +103 -0
  188. package/dist/agent-src/skills/terraform/SKILL.md +10 -0
  189. package/dist/agent-src/skills/test-driven-development/SKILL.md +31 -0
  190. package/dist/agent-src/skills/threat-modeling/SKILL.md +15 -0
  191. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  192. package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  193. package/dist/agent-src/templates/scripts/telemetry/engagement.ts +30 -0
  194. package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +22 -9
  195. package/dist/agent-src/templates/scripts/telemetry_record.ts +5 -0
  196. package/dist/discovery/deprecation-report.md +1 -1
  197. package/dist/discovery/discovery-manifest.json +256 -190
  198. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  199. package/dist/discovery/discovery-manifest.summary.md +5 -5
  200. package/dist/discovery/orphan-report.md +1 -1
  201. package/dist/discovery/packs.json +20 -17
  202. package/dist/discovery/trust-report.md +3 -3
  203. package/dist/discovery/workspaces.json +16 -13
  204. package/dist/install/install.mjs +10 -2
  205. package/dist/mcp/registry-manifest.json +3 -3
  206. package/dist/router.json +1 -1
  207. package/dist/scripts/condense.js +5 -0
  208. package/dist/scripts/condense.js.map +1 -1
  209. package/dist/server/schemas/settings.js +5 -1
  210. package/dist/server/schemas/settings.js.map +1 -1
  211. package/docs/CLAIMS.md +8 -1
  212. package/docs/SKILL_CENSUS.md +8 -0
  213. package/docs/architecture.md +2 -2
  214. package/docs/benchmark.md +67 -2
  215. package/docs/catalog.md +2 -2
  216. package/docs/contracts/ai-council-config.md +9 -2
  217. package/docs/contracts/ai-team-config.md +37 -4
  218. package/docs/contracts/prelaunch-diagnostics.md +151 -0
  219. package/docs/contracts/release-pr-gating.md +1 -0
  220. package/docs/decisions/ADR-049-configuration-trust-boundary.md +9 -1
  221. package/docs/featured-skills.md +2 -2
  222. package/docs/getting-started-by-role.md +1 -1
  223. package/docs/getting-started.md +16 -5
  224. package/docs/governance-advantage.md +1 -1
  225. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +45 -0
  226. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +28 -0
  227. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +76 -0
  228. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +90 -0
  229. package/docs/guidelines/agent-infra/domain-adoption-gates.md +112 -0
  230. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
  231. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +99 -0
  232. package/docs/guidelines/agent-infra/skill-quality-checklist.md +13 -0
  233. package/docs/guidelines/design-fidelity-mechanics.md +76 -0
  234. package/docs/parity/command-frontmatter.md +60 -0
  235. package/docs/proof.md +6 -5
  236. package/package.json +1 -1
  237. package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  238. package/src/agent-src/templates/scripts/telemetry/engagement.ts +30 -0
  239. package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +22 -9
  240. package/src/agent-src/templates/scripts/telemetry_record.ts +5 -0
  241. package/src/config/agent-settings.template.yml +34 -10
  242. package/src/config/prelaunch-areas.yml +36 -0
  243. package/src/scripts/_cli/cmd_doctor.ts +118 -26
  244. package/src/scripts/_lib/claude_plugin.ts +77 -2
  245. package/src/scripts/_lib/orchestration_record.ts +5 -0
  246. package/src/scripts/_lib/tool_adapter_registry.ts +120 -0
  247. package/src/scripts/ai_team/config.ts +73 -1
  248. package/src/scripts/ai_team/review_gate.ts +636 -0
  249. package/src/scripts/ai_team/team_dispatch.ts +612 -0
  250. package/src/scripts/bench_ab_task_runner.ts +11 -1
  251. package/src/scripts/bench_parity_count.ts +279 -0
  252. package/src/scripts/build_linear_digest.ts +3 -1
  253. package/src/scripts/check_bridge_derivation.ts +172 -0
  254. package/src/scripts/check_consumer_scope_flip.ts +179 -0
  255. package/src/scripts/check_council_config_location.ts +115 -15
  256. package/src/scripts/check_host_loadability.ts +81 -0
  257. package/src/scripts/condense.ts +5 -0
  258. package/src/scripts/hook_manifest.yaml +12 -1
  259. package/src/scripts/lint_handoffs.ts +42 -0
  260. package/src/scripts/lint_skill_descriptions.ts +228 -0
  261. package/src/scripts/lint_skill_descriptions_allowlist.json +1 -0
  262. package/src/scripts/lint_skill_scripts_readonly.ts +145 -0
  263. package/src/scripts/lint_skill_scripts_readonly_allowlist.json +8 -0
  264. package/src/scripts/lint_supported_tools_matrix.ts +35 -0
  265. package/src/scripts/optimize_skill_description.ts +144 -0
  266. package/src/scripts/orchestration_record.ts +2 -1
  267. package/src/scripts/prelaunch_diagnostics.ts +248 -0
  268. package/src/scripts/run_skill_evals.ts +70 -4
  269. package/src/scripts/schemas/command.schema.json +7 -0
  270. package/src/scripts/schemas/evals.schema.json +105 -14
  271. package/src/scripts/schemas/prelaunch-report.schema.json +107 -0
  272. package/src/scripts/schemas/skill.schema.json +18 -1
  273. package/src/scripts/schemas/subagent.schema.json +6 -0
  274. package/src/scripts/skill_linter.ts +43 -3
  275. package/src/scripts/smoke_host_loadability.sh +73 -0
  276. package/src/scripts/team_review_gate_hook.ts +115 -0
  277. package/src/scripts/trigger_eval_grandfather.json +1 -2
  278. package/src/scripts/utilization_report.ts +225 -0
  279. package/src/server/schemas/settings.ts +9 -1
@@ -105,10 +105,15 @@ export function _spawn_subagent(
105
105
  *
106
106
  * Deterministic on purpose: this only *counts*. The substantive judgement —
107
107
  * is each match a real finding, and what should `n` be per host — is the
108
- * calibration layer (Phase 1 gold set + per-host floor), which is gated on the
109
- * P0 cross-model distributions and therefore NOT wired here yet. So
110
- * `finding_floor` is available as a mechanism and exercised by fixtures, but is
111
- * not an enforcing CI gate until calibrated.
108
+ * calibration layer. CALIBRATED 2026-07-12: the cross-model count-distribution
109
+ * pass (`bench_parity_count.ts`, design in
110
+ * `docs/design/cross-model-parity-eval.md`) recorded per-host finding-count
111
+ * distributions over the orchestration corpus for 2 vendors and derived
112
+ * per-task floors from the cross-host lower envelope
113
+ * (`internal/bench/reports/parity-count.json`). `finding_floor` is therefore an
114
+ * ENFORCING gate: a fixture's `n` is justified against the cross-vendor norm,
115
+ * not one vendor's output shape. New floors follow the same envelope rule
116
+ * (max(1, min over hosts of median count); negative controls excluded).
112
117
  */
113
118
  export function _count_findings(output: string, pattern?: string): number {
114
119
  if (pattern !== undefined && pattern !== '') {
@@ -130,6 +135,31 @@ export function _count_findings(output: string, pattern?: string): number {
130
135
  return count;
131
136
  }
132
137
 
138
+ /**
139
+ * Load the recorded tool trace from `<run_dir>/tool-trace.json` — an array of
140
+ * tool-call names (strings) or `{tool: string}` objects. Returns null when the
141
+ * file is absent (→ tool-choice / trajectory assertions report manual-pending).
142
+ */
143
+ export function _load_tool_trace(run_dir: string): string[] | null {
144
+ const p = path.join(run_dir, 'tool-trace.json');
145
+ if (!_exists(p)) return null;
146
+ const raw = JSON.parse(fs.readFileSync(p, 'utf-8')) as Array<string | { tool?: string }>;
147
+ if (!Array.isArray(raw)) return null;
148
+ return raw.map((e) => (typeof e === 'string' ? e : (e.tool ?? ''))).filter((s) => s !== '');
149
+ }
150
+
151
+ /** Count meaningful steps: tool calls net of retries (a call whose name equals
152
+ * the immediately-preceding call name is a retry, not a new step). */
153
+ export function _count_meaningful_steps(trace: string[]): number {
154
+ let steps = 0;
155
+ let prev: string | null = null;
156
+ for (const t of trace) {
157
+ if (t !== prev) steps += 1;
158
+ prev = t;
159
+ }
160
+ return steps;
161
+ }
162
+
133
163
  export function _grade_assertions(
134
164
  output: string,
135
165
  run_dir: string,
@@ -141,6 +171,10 @@ export function _grade_assertions(
141
171
  if (kind === 'contains') {
142
172
  const ok = output.includes(a['value'] as string);
143
173
  results.push({ kind, value: a['value'] as JsonValue, pass: ok });
174
+ } else if (kind === 'not_contains') {
175
+ // U2 golden-adversarial negative: benign look-alikes must NOT be flagged.
176
+ const ok = !output.includes(a['value'] as string);
177
+ results.push({ kind, value: a['value'] as JsonValue, pass: ok });
144
178
  } else if (kind === 'file_exists') {
145
179
  const apath = a['path'] as string;
146
180
  const ok = _exists(path.join(run_dir, apath)) || _exists(apath);
@@ -157,6 +191,38 @@ export function _grade_assertions(
157
191
  const pattern = a['pattern'] as string | undefined;
158
192
  const count = _count_findings(output, pattern);
159
193
  results.push({ kind, n, count, pass: count >= n });
194
+ } else if (kind === 'tool-choice') {
195
+ // Evaluated against the recorded tool trace (<run_dir>/tool-trace.json).
196
+ // No trace (e.g. scaffold-only / CI without a live run) → manual-pending,
197
+ // NEVER a silent pass.
198
+ const mustUse = (a['must_use'] as string[] | undefined) ?? [];
199
+ const mustNot = (a['must_not_use'] as string[] | undefined) ?? [];
200
+ const trace = _load_tool_trace(run_dir);
201
+ if (trace === null) {
202
+ results.push({
203
+ kind, must_use: mustUse, must_not_use: mustNot, pass: null,
204
+ note: 'manual-pending: no tool-trace.json in run dir — record a trace or grade manually',
205
+ });
206
+ } else {
207
+ const used = new Set(trace);
208
+ const missing = mustUse.filter((t) => !used.has(t));
209
+ const forbidden = mustNot.filter((t) => used.has(t));
210
+ results.push({
211
+ kind, must_use: mustUse, must_not_use: mustNot,
212
+ missing, forbidden, pass: missing.length === 0 && forbidden.length === 0,
213
+ });
214
+ }
215
+ } else if (kind === 'trajectory_budget') {
216
+ // Meaningful step = one tool call net of retries (a retry is a call whose
217
+ // tool name repeats the immediately-preceding call). No trace → manual-pending.
218
+ const budget = a['n'] as number;
219
+ const trace = _load_tool_trace(run_dir);
220
+ if (trace === null) {
221
+ results.push({ kind, n: budget, pass: null, note: 'manual-pending: no tool-trace.json in run dir' });
222
+ } else {
223
+ const steps = _count_meaningful_steps(trace);
224
+ results.push({ kind, n: budget, steps, pass: steps <= budget });
225
+ }
160
226
  } else {
161
227
  results.push({ kind: kind ?? null, pass: false, note: `unknown assertion kind ${_pyRepr(kind)}` });
162
228
  }
@@ -35,6 +35,13 @@
35
35
  "default": true,
36
36
  "description": "Commands are always user-invoked; model-invocation is disabled."
37
37
  },
38
+ "argument-hint": {
39
+ "type": "string",
40
+ "minLength": 1,
41
+ "maxLength": 120,
42
+ "description": "Official-spec argument hint shown next to the slash command in hosts that render one (Claude Code). Bracket notation: `<required>` / `[optional]`, e.g. '<ticket-key | url> [notes]'. Set on every command whose body documents an invocation argument; omit on zero-argument commands. Projection: commands symlink into .claude/skills/<slug>/SKILL.md, so the field reaches Claude Code verbatim; other hosts ignore it (see docs/parity/command-frontmatter.md).",
43
+ "$comment": "road-to-ecosystem-harvest-skill-quality-gates Phase 4, Source C (official CLI command-authoring standard)."
44
+ },
38
45
  "skills": {
39
46
  "type": "array",
40
47
  "items": {
@@ -3,10 +3,13 @@
3
3
  "$id": "https://github.com/event4u-app/agent-config/scripts/schemas/evals.schema.json",
4
4
  "x-schemaVersion": "1.0.0",
5
5
  "title": "Skill behavioural evals (evals.json)",
6
- "$comment": "Behavioural-eval spec consumed by run_skill_evals.ts (scaffold/aggregate/report) and counted by skill_eval_coverage.ts. Distinct from triggers.json (activation/routing axis). Roadmap: road-to-skill-eval-coverage Phase 1. Assertion kinds mirror _grade_assertions() in run_skill_evals.ts exactly — add a kind there before adding it here.",
6
+ "$comment": "Behavioural-eval spec consumed by run_skill_evals.ts (scaffold/aggregate/report) and counted by skill_eval_coverage.ts. Distinct from triggers.json (activation/routing axis). Roadmap: road-to-skill-eval-coverage Phase 1. Assertion kinds mirror _grade_assertions() in run_skill_evals.ts exactly \u2014 add a kind there before adding it here.",
7
7
  "type": "object",
8
8
  "additionalProperties": false,
9
- "required": ["skill", "scenarios"],
9
+ "required": [
10
+ "skill",
11
+ "scenarios"
12
+ ],
10
13
  "properties": {
11
14
  "skill": {
12
15
  "type": "string",
@@ -20,7 +23,7 @@
20
23
  "skill_body_sha": {
21
24
  "type": "string",
22
25
  "pattern": "^[0-9a-f]{64}$",
23
- "description": "Optional SHA-256 of the skill's SKILL.md body at the time these evals were authored/last verified. When present, lint_behavioural_eval_freshness flags the eval stale if the current SKILL.md sha differs — the body changed, so the eval may no longer exercise it. Absent = unpinned (out of scope for the staleness gate), mirroring lint_eval_freshness's upstream:null handling."
26
+ "description": "Optional SHA-256 of the skill's SKILL.md body at the time these evals were authored/last verified. When present, lint_behavioural_eval_freshness flags the eval stale if the current SKILL.md sha differs \u2014 the body changed, so the eval may no longer exercise it. Absent = unpinned (out of scope for the staleness gate), mirroring lint_eval_freshness's upstream:null handling."
24
27
  },
25
28
  "scenarios": {
26
29
  "type": "array",
@@ -29,7 +32,11 @@
29
32
  "items": {
30
33
  "type": "object",
31
34
  "additionalProperties": false,
32
- "required": ["id", "prompt", "assertions"],
35
+ "required": [
36
+ "id",
37
+ "prompt",
38
+ "assertions"
39
+ ],
33
40
  "properties": {
34
41
  "id": {
35
42
  "type": "string",
@@ -41,6 +48,20 @@
41
48
  "minLength": 1,
42
49
  "description": "The input fixture handed to the skill under test."
43
50
  },
51
+ "environment": {
52
+ "type": "string",
53
+ "minLength": 1,
54
+ "description": "Optional precondition note (v2, additive) — the environment the scenario assumes (e.g. 'a git repo with an open PR', 'quality.local_auto_run: true'). Advisory context for the runner/operator; not graded."
55
+ },
56
+ "requires_human": {
57
+ "type": "boolean",
58
+ "description": "Optional (v2, additive). When true, the scenario cannot be auto-graded in CI — the runner skips it and reports `manual-pending` (NEVER a silent pass). Pair with human_instructions."
59
+ },
60
+ "human_instructions": {
61
+ "type": "string",
62
+ "minLength": 1,
63
+ "description": "Optional (v2, additive). Steps for a human to grade a requires_human scenario."
64
+ },
44
65
  "assertions": {
45
66
  "type": "array",
46
67
  "minItems": 1,
@@ -50,9 +71,14 @@
50
71
  {
51
72
  "type": "object",
52
73
  "additionalProperties": false,
53
- "required": ["kind", "value"],
74
+ "required": [
75
+ "kind",
76
+ "value"
77
+ ],
54
78
  "properties": {
55
- "kind": { "const": "contains" },
79
+ "kind": {
80
+ "const": "contains"
81
+ },
56
82
  "value": {
57
83
  "type": "string",
58
84
  "minLength": 1,
@@ -63,9 +89,14 @@
63
89
  {
64
90
  "type": "object",
65
91
  "additionalProperties": false,
66
- "required": ["kind", "path"],
92
+ "required": [
93
+ "kind",
94
+ "path"
95
+ ],
67
96
  "properties": {
68
- "kind": { "const": "file_exists" },
97
+ "kind": {
98
+ "const": "file_exists"
99
+ },
69
100
  "path": {
70
101
  "type": "string",
71
102
  "minLength": 1,
@@ -76,13 +107,18 @@
76
107
  {
77
108
  "type": "object",
78
109
  "additionalProperties": false,
79
- "required": ["kind", "n"],
110
+ "required": [
111
+ "kind",
112
+ "n"
113
+ ],
80
114
  "properties": {
81
- "kind": { "const": "finding_floor" },
115
+ "kind": {
116
+ "const": "finding_floor"
117
+ },
82
118
  "n": {
83
119
  "type": "integer",
84
120
  "minimum": 0,
85
- "description": "Minimum number of findings the output must carry (counted deterministically). 0 is a trivially-passing floor (the grader passes when count >= n) — used where the case only guards against over-reporting."
121
+ "description": "Minimum number of findings the output must carry (counted deterministically). 0 is a trivially-passing floor (the grader passes when count >= n) \u2014 used where the case only guards against over-reporting."
86
122
  },
87
123
  "pattern": {
88
124
  "type": "string",
@@ -93,13 +129,68 @@
93
129
  {
94
130
  "type": "object",
95
131
  "additionalProperties": false,
96
- "required": ["kind", "criterion"],
132
+ "required": [
133
+ "kind",
134
+ "criterion"
135
+ ],
97
136
  "properties": {
98
- "kind": { "const": "rubric" },
137
+ "kind": {
138
+ "const": "rubric"
139
+ },
99
140
  "criterion": {
100
141
  "type": "string",
101
142
  "minLength": 1,
102
- "description": "Natural-language pass criterion graded by a sub-agent. NON-deterministic — the grader returns pass:null until a pinned judge fills it. Use only where no deterministic check exists; record the judge as a known limit."
143
+ "description": "Natural-language pass criterion graded by a sub-agent. NON-deterministic \u2014 the grader returns pass:null until a pinned judge fills it. Use only where no deterministic check exists; record the judge as a known limit."
144
+ }
145
+ }
146
+ },
147
+ {
148
+ "type": "object",
149
+ "additionalProperties": false,
150
+ "required": [
151
+ "kind",
152
+ "value"
153
+ ],
154
+ "properties": {
155
+ "kind": {
156
+ "const": "not_contains"
157
+ },
158
+ "value": {
159
+ "type": "string",
160
+ "minLength": 1,
161
+ "description": "Substring the output must contain (deterministic)."
162
+ }
163
+ }
164
+ },
165
+ {
166
+ "type": "object",
167
+ "additionalProperties": false,
168
+ "required": ["kind"],
169
+ "properties": {
170
+ "kind": { "const": "tool-choice" },
171
+ "must_use": {
172
+ "type": "array",
173
+ "items": { "type": "string", "minLength": 1 },
174
+ "description": "Tool names the run MUST have called (checked against <run_dir>/tool-trace.json). v2, additive."
175
+ },
176
+ "must_not_use": {
177
+ "type": "array",
178
+ "items": { "type": "string", "minLength": 1 },
179
+ "description": "Tool names the run MUST NOT have called. v2, additive."
180
+ }
181
+ },
182
+ "$comment": "Evaluated against the recorded tool trace. No trace present → pass:null manual-pending, never a silent pass."
183
+ },
184
+ {
185
+ "type": "object",
186
+ "additionalProperties": false,
187
+ "required": ["kind", "n"],
188
+ "properties": {
189
+ "kind": { "const": "trajectory_budget" },
190
+ "n": {
191
+ "type": "integer",
192
+ "minimum": 1,
193
+ "description": "Ceiling on meaningful steps = tool calls net of retries (a call repeating the immediately-preceding call name is a retry, not a step). Counted from <run_dir>/tool-trace.json; no trace → manual-pending. v2, additive."
103
194
  }
104
195
  }
105
196
  }
@@ -0,0 +1,107 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/event4u-app/agent-config/scripts/schemas/prelaunch-report.schema.json",
4
+ "x-schemaVersion": "1.0.0",
5
+ "title": "Pre-launch diagnostic report",
6
+ "$comment": "road-to-ecosystem-harvest-prelaunch-diagnostics Phase 1 (Source L). Contract: docs/contracts/prelaunch-diagnostics.md. Area vocabulary: src/config/prelaunch-areas.yml. Epistemics: pass requires evidence; absence of findings is unknown, never an automatic pass; not-applicable requires a reason. NO numeric score field — the 0-100 score is council-locked (revisit note in the roadmap); adding one here is a contract violation.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": ["schema_version", "project", "run_at", "areas", "findings"],
10
+ "properties": {
11
+ "schema_version": {
12
+ "type": "string",
13
+ "enum": ["prelaunch-report-v1"]
14
+ },
15
+ "project": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "description": "Consumer project identifier (repo slug or name)."
19
+ },
20
+ "run_at": {
21
+ "type": "string",
22
+ "minLength": 1,
23
+ "description": "ISO-8601 timestamp of the diagnostic run."
24
+ },
25
+ "areas": {
26
+ "type": "object",
27
+ "additionalProperties": false,
28
+ "description": "Per-area epistemic state. Keys come from src/config/prelaunch-areas.yml. An area missing here is UNKNOWN by definition.",
29
+ "patternProperties": {
30
+ "^[a-z][a-z0-9-]*$": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["state"],
34
+ "properties": {
35
+ "state": {
36
+ "type": "string",
37
+ "enum": ["pass", "finding", "unknown", "not-applicable"],
38
+ "description": "pass = evidence-cited clean; finding = at least one open finding (IDs in findings[]); unknown = not diagnosed — NEVER an automatic pass; not-applicable = does not exist on this launch surface (reason required)."
39
+ },
40
+ "evidence": {
41
+ "type": "string",
42
+ "minLength": 1,
43
+ "description": "Citation proving the state — file:line, command output, run URL. REQUIRED when state is pass (enforced by the validator; a pass without evidence is assertion, not diagnosis)."
44
+ },
45
+ "reason": {
46
+ "type": "string",
47
+ "minLength": 1,
48
+ "description": "REQUIRED when state is not-applicable — why the area does not exist on this surface."
49
+ }
50
+ }
51
+ }
52
+ }
53
+ },
54
+ "findings": {
55
+ "type": "array",
56
+ "description": "Every finding ever assigned in this project, open or resolved — IDs are immutable and never re-assigned, so resolved findings stay (status flips, the entry never disappears).",
57
+ "items": {
58
+ "type": "object",
59
+ "additionalProperties": false,
60
+ "required": ["id", "area", "severity", "title", "status"],
61
+ "properties": {
62
+ "id": {
63
+ "type": "string",
64
+ "pattern": "^AC-[A-Z][A-Z0-9]{1,7}-[0-9]{3}$",
65
+ "description": "Immutable finding ID: AC-<AREA-CODE>-NNN. The AREA code comes from prelaunch-areas.yml; NNN is zero-padded, monotonically assigned, NEVER re-used — a retitled or re-scoped finding keeps its ID; a genuinely new problem gets the next number."
66
+ },
67
+ "area": {
68
+ "type": "string",
69
+ "pattern": "^[a-z][a-z0-9-]*$",
70
+ "description": "Area key (prelaunch-areas.yml) the finding belongs to; must agree with the ID's area code (validator-enforced)."
71
+ },
72
+ "severity": {
73
+ "type": "string",
74
+ "enum": ["P0", "P1", "P2", "P3"],
75
+ "description": "P0 = launch-blocking; P1 = fix-before-general-rollout; P2 = fix-soon; P3 = nice-to-have. Any OPEN P0 refuses a ready verdict regardless of every other area."
76
+ },
77
+ "title": {
78
+ "type": "string",
79
+ "minLength": 1,
80
+ "maxLength": 200,
81
+ "description": "Human title. Mutable — the ID, not the title, is the diff key."
82
+ },
83
+ "evidence": {
84
+ "type": "string",
85
+ "minLength": 1,
86
+ "description": "Citation locating the finding (file:line, endpoint, config key)."
87
+ },
88
+ "status": {
89
+ "type": "string",
90
+ "enum": ["open", "fixed", "accepted-risk", "deferred-with-reason", "suppressed-with-evidence", "not-applicable"],
91
+ "description": "Fix-loop status vocabulary (Phase 3). Everything except open/fixed requires `reason`; suppressed-with-evidence additionally requires a matching entry in the project suppression file."
92
+ },
93
+ "reason": {
94
+ "type": "string",
95
+ "minLength": 1,
96
+ "description": "REQUIRED for accepted-risk / deferred-with-reason / suppressed-with-evidence / not-applicable."
97
+ }
98
+ }
99
+ }
100
+ },
101
+ "questions": {
102
+ "type": "array",
103
+ "items": {"type": "string", "minLength": 1},
104
+ "description": "Questions that would change the diagnosis — open information gaps the next run should answer; the honest sibling of the unknowns."
105
+ }
106
+ }
107
+ }
@@ -23,6 +23,11 @@
23
23
  "maxLength": 220,
24
24
  "description": "Trigger phrase; ≤ 200 chars recommended, 220 is the ceiling (lean-initial-context: descriptions load eagerly via progressive disclosure). Over-cap is a soft warning, not a hard fail — a warning window so authors adapt."
25
25
  },
26
+ "compatibility": {
27
+ "type": "string",
28
+ "maxLength": 500,
29
+ "description": "Agent-Skills spec field (optional): machine-readable declaration of environment requirements — system packages, network access, product/host constraints. Mirrors the public spec so media/doc skills can state requirements outside prose."
30
+ },
26
31
  "source": {
27
32
  "type": "string",
28
33
  "enum": ["package", "project"],
@@ -87,6 +92,12 @@
87
92
  "enum": ["large"],
88
93
  "description": "Optional orthogonal modifier (ADR-035): the skill needs a large-context model regardless of reasoning tier (e.g. summarising a 500-page log). Sparse — most skills omit it. Metadata only; does not change the native Claude `model:` (the tier owns the model choice)."
89
94
  },
95
+ "effort": {
96
+ "type": "string",
97
+ "enum": ["low", "medium", "high", "max"],
98
+ "description": "Optional pinned reasoning-effort level for hosts with an effort knob (Claude Code `--effort` / agent frontmatter). Passthrough: skills project verbatim, so the key reaches Claude Code as-is and is inert on hosts without the knob. The bench harness pins it per run (bench_ab_task_runner `--effort`) so measurements are reproducible. Orthogonal to `model_tier` (capability band) — effort tunes how hard the model thinks, not which model runs. Omit unless the skill measurably needs a non-default effort.",
99
+ "$comment": "road-to-ecosystem-harvest-skill-quality-gates Phase 4, Source S (pinned effort frontmatter)."
100
+ },
90
101
  "council_depth": {
91
102
  "type": "string",
92
103
  "enum": ["deep"],
@@ -130,7 +141,13 @@
130
141
  },
131
142
  "allowed_tools": {
132
143
  "type": "array",
133
- "items": { "type": "string" }
144
+ "items": { "type": "string" },
145
+ "description": "Allow-list of tool grants. Prefer the scoped-grant syntax over bare tool names where the host supports it — e.g. Bash(npm test:*) instead of Bash — per tool-safety Least Agency."
146
+ },
147
+ "disallowed_tools": {
148
+ "type": "array",
149
+ "items": { "type": "string" },
150
+ "description": "U3 (ecosystem harvest): optional deny-list layered UNDER allowed_tools — defense-in-depth; a tool matching here is refused even if a broad allow pattern would admit it. Supports the scoped-grant syntax (e.g. Bash(git push:*))."
134
151
  },
135
152
  "command": {
136
153
  "type": "array",
@@ -37,6 +37,12 @@
37
37
  "enum": ["lite", "medium", "high", "inherit"],
38
38
  "description": "Vendor-neutral capability band (ADR-034/035). high/medium/lite project to a native Claude `model:` (high→opus, medium→sonnet, lite→haiku) via model_tier.ts; `inherit` is a documented passthrough sentinel (→ CC `model: inherit`), not a new mapping."
39
39
  },
40
+ "effort": {
41
+ "type": "string",
42
+ "enum": ["low", "medium", "high", "max"],
43
+ "description": "Optional pinned reasoning-effort level. Projects into the generated .claude/agents/<name>.md frontmatter (`effort:`) on hosts with an effort knob; ignored elsewhere. Orthogonal to `model_tier`. Omit for host-default effort.",
44
+ "$comment": "road-to-ecosystem-harvest-skill-quality-gates Phase 4, Source S."
45
+ },
40
46
  "tools": {
41
47
  "type": "array",
42
48
  "minItems": 1,
@@ -196,7 +196,7 @@ const VALID_EXECUTION_FIELDS = new Set([
196
196
  'timeout_seconds',
197
197
  'safety_mode',
198
198
  'allowed_tools',
199
- 'command',
199
+ 'command', 'disallowed_tools',
200
200
  ]);
201
201
 
202
202
  // --- Wing-3 GTM cognition-boundary patterns ---
@@ -1404,6 +1404,29 @@ export function lint_skill(p: string, text: string): LintResult {
1404
1404
  issues.push(new Issue('warning', 'missing_description', 'Frontmatter description is missing or unreadable'));
1405
1405
  }
1406
1406
 
1407
+ // --- Agent-Skills spec alignment (U2, ecosystem harvest 2026-07-13) ---
1408
+ // Public-spec name rules for spec-portable skills: frontmatter `name`
1409
+ // must match the parent directory; no consecutive hyphens.
1410
+ {
1411
+ const fmNameMatch = text.match(/^name:\s*["']?([A-Za-z0-9-]+)["']?\s*$/m);
1412
+ const fmName = fmNameMatch ? fmNameMatch[1] : null;
1413
+ if (basename(p) === 'SKILL.md' && fmName && fmName !== parentName(p)) {
1414
+ issues.push(new Issue(
1415
+ 'error',
1416
+ 'spec_name_dir_mismatch',
1417
+ `Frontmatter name \`${fmName}\` must match the parent directory \`${parentName(p)}\` (Agent-Skills spec)`,
1418
+ ));
1419
+ }
1420
+ const nameForHyphens = fmName ?? (basename(p) === 'SKILL.md' ? parentName(p) : stem(p));
1421
+ if (nameForHyphens && nameForHyphens.includes('--')) {
1422
+ issues.push(new Issue(
1423
+ 'error',
1424
+ 'spec_name_consecutive_hyphens',
1425
+ `Skill name \`${nameForHyphens}\` contains consecutive hyphens (Agent-Skills spec forbids them)`,
1426
+ ));
1427
+ }
1428
+ }
1429
+
1407
1430
  // --- Bare-noun name check ---
1408
1431
  const skillName = basename(p) === 'SKILL.md' ? parentName(p) : stem(p);
1409
1432
  if (skillName && !skillName.includes('-') && skillName.length >= 3) {
@@ -1670,7 +1693,7 @@ export function validate_evals_json(skillPath: string): Issue[] {
1670
1693
  );
1671
1694
  return issues;
1672
1695
  }
1673
- const validKinds = ['contains', 'file_exists', 'rubric', 'finding_floor'];
1696
+ const validKinds = ['contains', 'not_contains', 'file_exists', 'rubric', 'finding_floor', 'tool-choice', 'trajectory_budget'];
1674
1697
  const validKindsSet = new Set(validKinds);
1675
1698
  scenarios.forEach((scenario, idx) => {
1676
1699
  const loc = `scenarios[${idx}]`;
@@ -1726,8 +1749,25 @@ export function validate_evals_json(skillPath: string): Issue[] {
1726
1749
  new Issue('warning', 'evals_json_assertion_field_type', `${aLoc} (kind=finding_floor) 'pattern' must be a string`),
1727
1750
  );
1728
1751
  }
1752
+ } else if (kind === 'tool-choice') {
1753
+ // tool-choice (eval-schema v2): `must_use` / `must_not_use` are both
1754
+ // OPTIONAL string arrays — validate type only when present.
1755
+ for (const f of ['must_use', 'must_not_use']) {
1756
+ if (f in a && !(Array.isArray(a[f]) && (a[f] as unknown[]).every((x) => typeof x === 'string'))) {
1757
+ issues.push(
1758
+ new Issue('warning', 'evals_json_assertion_field_type', `${aLoc} (kind=tool-choice) '${f}' must be an array of strings`),
1759
+ );
1760
+ }
1761
+ }
1762
+ } else if (kind === 'trajectory_budget') {
1763
+ // trajectory_budget (eval-schema v2): required integer `n` >= 1.
1764
+ if (typeof a.n !== 'number' || !Number.isInteger(a.n) || (a.n as number) < 1) {
1765
+ issues.push(
1766
+ new Issue('warning', 'evals_json_assertion_field_type', `${aLoc} (kind=trajectory_budget) 'n' must be an integer >= 1`),
1767
+ );
1768
+ }
1729
1769
  } else {
1730
- const requiredField = { contains: 'value', file_exists: 'path', rubric: 'criterion' }[kind] as string;
1770
+ const requiredField = { contains: 'value', not_contains: 'value', file_exists: 'path', rubric: 'criterion' }[kind] as string;
1731
1771
  if (!(requiredField in a) || typeof a[requiredField] !== 'string') {
1732
1772
  issues.push(
1733
1773
  new Issue(
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ # smoke_host_loadability.sh — real-host loadability smoke
3
+ # (road-to-ecosystem-harvest-skill-quality-gates Phase 4, Source G).
4
+ #
5
+ # The static check (check_host_loadability.ts) proves the generated trees
6
+ # PARSE; this smoke proves the real Claude Code CLI actually ACCEPTS them:
7
+ #
8
+ # 1. `claude plugin validate .claude-plugin` — the host's own validator on
9
+ # the marketplace manifest + plugin dirs.
10
+ # 2. Temp-home install: add this repo as a marketplace in a throwaway HOME,
11
+ # install the bootstrap-shim plugin, assert it shows up in
12
+ # `claude plugin list`. Nothing touches the developer's real ~/.claude.
13
+ # 3. Metadata cross-consistency (marketplace ↔ plugin dirs ↔ docs):
14
+ # lint_marketplace + lint_marketplace_install_completeness +
15
+ # lint_supported_tools_matrix + check_host_loadability.
16
+ #
17
+ # Contract: OPTIONAL in CI (runners without the claude CLI skip with exit 0
18
+ # and a notice), REQUIRED before releases — pass --require to make a missing
19
+ # CLI a failure (wired into the release flow, see docs/contracts/release-pr-gating.md).
20
+ set -euo pipefail
21
+
22
+ REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
23
+ cd "$REPO_ROOT"
24
+
25
+ REQUIRE=0
26
+ for arg in "$@"; do
27
+ case "$arg" in
28
+ --require) REQUIRE=1 ;;
29
+ *) echo "usage: smoke_host_loadability.sh [--require]" >&2; exit 2 ;;
30
+ esac
31
+ done
32
+
33
+ CLAUDE_BIN="${CLAUDE_CLI:-$(command -v claude || true)}"
34
+ if [ -n "$CLAUDE_BIN" ] && [ ! -x "$CLAUDE_BIN" ]; then
35
+ CLAUDE_BIN=""
36
+ fi
37
+ if [ -z "$CLAUDE_BIN" ]; then
38
+ if [ "$REQUIRE" -eq 1 ]; then
39
+ echo "❌ claude CLI not found and --require set (release gate). Install Claude Code or set CLAUDE_CLI." >&2
40
+ exit 1
41
+ fi
42
+ echo "⚠️ claude CLI not found — real-host smoke skipped (static checks still run)."
43
+ ./scripts-run src/scripts/check_host_loadability --root .
44
+ ./scripts-run src/scripts/lint_supported_tools_matrix
45
+ exit 0
46
+ fi
47
+
48
+ MARKETPLACE_NAME="$(node -e "console.log(JSON.parse(require('node:fs').readFileSync('.claude-plugin/marketplace.json','utf8')).name)")"
49
+ PLUGIN_NAME="$(node -e "console.log(JSON.parse(require('node:fs').readFileSync('.claude-plugin/marketplace.json','utf8')).plugins[0].name)")"
50
+
51
+ echo "→ 1/3 host-CLI manifest validation (claude plugin validate)"
52
+ # validate expects the directory that CONTAINS .claude-plugin/.
53
+ "$CLAUDE_BIN" plugin validate "$REPO_ROOT"
54
+
55
+ echo "→ 2/3 temp-home install + load assertion (${PLUGIN_NAME}@${MARKETPLACE_NAME})"
56
+ TMP_HOME="$(mktemp -d)"
57
+ cleanup() { rm -rf "$TMP_HOME"; }
58
+ trap cleanup EXIT
59
+ export ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-}"
60
+ HOME="$TMP_HOME" "$CLAUDE_BIN" plugin marketplace add "$REPO_ROOT"
61
+ HOME="$TMP_HOME" "$CLAUDE_BIN" plugin install "${PLUGIN_NAME}@${MARKETPLACE_NAME}"
62
+ if ! HOME="$TMP_HOME" "$CLAUDE_BIN" plugin list | grep -q "$PLUGIN_NAME"; then
63
+ echo "❌ plugin '${PLUGIN_NAME}' not listed after temp-home install — host did not load it" >&2
64
+ exit 1
65
+ fi
66
+
67
+ echo "→ 3/3 metadata cross-consistency (marketplace ↔ plugin dirs ↔ docs)"
68
+ ./scripts-run src/scripts/lint_marketplace
69
+ ./scripts-run src/scripts/lint_marketplace_install_completeness
70
+ ./scripts-run src/scripts/lint_supported_tools_matrix
71
+ ./scripts-run src/scripts/check_host_loadability --root .
72
+
73
+ echo "✅ host-loadability smoke green (validate + temp-home install + cross-consistency)"