session-orchestrator 3.24.0 → 4.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.
- package/.agents/skills/architecture/SKILL.md +18 -0
- package/.agents/skills/autopilot/SKILL.md +17 -0
- package/.agents/skills/bootstrap/SKILL.md +20 -0
- package/.agents/skills/brainstorm/SKILL.md +22 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
- package/.agents/skills/debug/SKILL.md +22 -0
- package/.agents/skills/discovery/SKILL.md +20 -0
- package/.agents/skills/dispatcher/SKILL.md +15 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
- package/.agents/skills/ecosystem-health/SKILL.md +20 -0
- package/.agents/skills/eli5/SKILL.md +20 -0
- package/.agents/skills/eval/SKILL.md +21 -0
- package/.agents/skills/evolve/SKILL.md +21 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
- package/.agents/skills/gitlab-ops/SKILL.md +20 -0
- package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
- package/.agents/skills/grill/SKILL.md +22 -0
- package/.agents/skills/hook-development/SKILL.md +15 -0
- package/.agents/skills/mcp-builder/SKILL.md +15 -0
- package/.agents/skills/memory-cleanup/SKILL.md +21 -0
- package/.agents/skills/mode-selector/SKILL.md +17 -0
- package/.agents/skills/npm-publish/SKILL.md +16 -0
- package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
- package/.agents/skills/persona-panel/SKILL.md +17 -0
- package/.agents/skills/plan/SKILL.md +20 -0
- package/.agents/skills/playwright-driver/SKILL.md +20 -0
- package/.agents/skills/quality-gates/SKILL.md +20 -0
- package/.agents/skills/reconcile/SKILL.md +21 -0
- package/.agents/skills/remote-offload/SKILL.md +20 -0
- package/.agents/skills/repo-audit/SKILL.md +16 -0
- package/.agents/skills/session-end/SKILL.md +20 -0
- package/.agents/skills/session-plan/SKILL.md +20 -0
- package/.agents/skills/session-start/SKILL.md +20 -0
- package/.agents/skills/spinout/SKILL.md +16 -0
- package/.agents/skills/sunset-review/SKILL.md +16 -0
- package/.agents/skills/test-runner/SKILL.md +20 -0
- package/.agents/skills/tmux-layout/SKILL.md +21 -0
- package/.agents/skills/using-orchestrator/SKILL.md +17 -0
- package/.agents/skills/vault-mirror/SKILL.md +15 -0
- package/.agents/skills/vault-sync/SKILL.md +15 -0
- package/.agents/skills/wave-executor/SKILL.md +20 -0
- package/.agents/skills/write-executable-plan/SKILL.md +22 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/commands/autopilot.md +2 -2
- package/.cursor/commands/bootstrap.md +1 -1
- package/.cursor/commands/brainstorm.md +1 -1
- package/.cursor/commands/debug.md +1 -1
- package/.cursor/commands/discovery.md +1 -1
- package/.cursor/commands/dispatcher.md +2 -2
- package/.cursor/commands/eli5.md +2 -2
- package/.cursor/commands/eval.md +2 -2
- package/.cursor/commands/evolve.md +1 -1
- package/.cursor/commands/go.md +1 -1
- package/.cursor/commands/grill.md +2 -2
- package/.cursor/commands/memory-cleanup.md +2 -2
- package/.cursor/commands/persona-panel.md +1 -1
- package/.cursor/commands/plan.md +1 -1
- package/.cursor/commands/portfolio.md +1 -1
- package/.cursor/commands/reconcile.md +2 -2
- package/.cursor/commands/release.md +2 -2
- package/.cursor/commands/session.md +2 -2
- package/.cursor/commands/spinout.md +2 -2
- package/.cursor/commands/sunset-review.md +2 -2
- package/.cursor/commands/templates-ack.md +2 -2
- package/.cursor/commands/test.md +2 -2
- package/.cursor/skills/brainstorm/SKILL.md +1 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/quality-gates/SKILL.md +1 -1
- package/.cursor/skills/remote-offload/SKILL.md +1 -1
- package/.orchestrator/policy/blocked-commands.json +121 -0
- package/.orchestrator/policy/ecosystem.schema.json +66 -0
- package/.orchestrator/policy/quality-gates.example.json +16 -0
- package/.orchestrator/policy/quality-gates.schema.json +38 -0
- package/.orchestrator/policy/templates-policy.json +27 -0
- package/.orchestrator/policy/test-profiles.json +47 -0
- package/AGENTS.md +225 -0
- package/CHANGELOG.md +1125 -2
- package/NOTICE +11 -6
- package/README.md +127 -94
- package/agents/eval-judge.md +1 -1
- package/agents/skill-applied-judge.md +1 -1
- package/assets/wave-lifecycle.svg +98 -0
- package/commands/release.md +6 -3
- package/commands/session.md +18 -3
- package/docs/README.md +4 -0
- package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
- package/docs/baseline.md +67 -0
- package/docs/ci-setup.md +108 -62
- package/docs/codex-setup.md +65 -21
- package/docs/components.md +36 -15
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +9 -6
- package/docs/instruction-delivery.md +62 -0
- package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
- package/docs/migration-v4.md +341 -0
- package/docs/pi-setup.md +6 -1
- package/docs/plugin-architecture-v3.md +1 -1
- package/docs/rule-authoring.md +85 -19
- package/docs/scope-collision-guard.md +5 -5
- package/docs/session-config-reference.md +57 -56
- package/docs/session-config-template.md +6 -29
- package/docs/telemetry.md +157 -3
- package/docs/vault-docs-architecture.md +50 -11
- package/hooks/_lib/hook-import-set.json +1487 -0
- package/hooks/_lib/subagent-transcript.mjs +562 -0
- package/hooks/config-protection.mjs +2 -2
- package/hooks/cwd-change-restore.mjs +2 -2
- package/hooks/enforce-commands.mjs +69 -0
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +10 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +3 -3
- package/hooks/on-session-end.mjs +2 -2
- package/hooks/on-session-start.mjs +103 -2
- package/hooks/on-stop.mjs +36 -11
- package/hooks/operator-steer.mjs +2 -2
- package/hooks/post-bash-write-verify.mjs +85 -0
- package/hooks/post-edit-import-probe.mjs +344 -0
- package/hooks/post-subagent-discovery-validator.mjs +187 -431
- package/hooks/post-tool-batch-wave-signal.mjs +118 -4
- package/hooks/post-tool-failure-corrective-context.mjs +2 -2
- package/hooks/post-tooluse-frontend-slop.mjs +3 -3
- package/hooks/pre-bash-destructive-guard.mjs +39 -13
- package/hooks/skill-invocation-telemetry.mjs +17 -5
- package/hooks/subagent-telemetry.mjs +13 -4
- package/monitors/monitors.json +3 -3
- package/package.json +9 -1
- package/pi/prompts/session.md +2 -2
- package/plugin.json +27 -0
- package/scripts/backfill-abandoned-sessions.mjs +50 -4
- package/scripts/backfill-learnings-from-vault.mjs +9 -3
- package/scripts/dialectic-deriver.mjs +73 -8
- package/scripts/export-hw-learnings.mjs +113 -1
- package/scripts/generate-agents-skills.mjs +378 -0
- package/scripts/generate-cursor-adapter.mjs +45 -8
- package/scripts/generate-hook-import-set.mjs +249 -0
- package/scripts/lib/agent-status.mjs +13 -2
- package/scripts/lib/auto-dream.mjs +38 -36
- package/scripts/lib/autonomy/suitability.mjs +6 -0
- package/scripts/lib/autopilot/loop.mjs +2 -2
- package/scripts/lib/ci-status-banner.mjs +220 -75
- package/scripts/lib/codex/plugin-contract.mjs +82 -6
- package/scripts/lib/config/auto-dream.mjs +2 -1
- package/scripts/lib/config/block-header.mjs +8 -0
- package/scripts/lib/config/block-preprocess.mjs +177 -0
- package/scripts/lib/config/broken-window.mjs +2 -1
- package/scripts/lib/config/cold-start.mjs +2 -1
- package/scripts/lib/config/config-protection.mjs +22 -2
- package/scripts/lib/config/context-coverage.mjs +2 -1
- package/scripts/lib/config/cross-repo.mjs +2 -1
- package/scripts/lib/config/custom-phases.mjs +2 -1
- package/scripts/lib/config/dialectic.mjs +2 -1
- package/scripts/lib/config/discovery-validator.mjs +2 -1
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
- package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
- package/scripts/lib/config/docs-orchestrator.mjs +2 -1
- package/scripts/lib/config/docs-staleness.mjs +2 -1
- package/scripts/lib/config/drift-check.mjs +2 -1
- package/scripts/lib/config/eval.mjs +2 -1
- package/scripts/lib/config/events-rotation.mjs +2 -1
- package/scripts/lib/config/evolve.mjs +8 -2
- package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
- package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
- package/scripts/lib/config/handover-gate.mjs +2 -1
- package/scripts/lib/config/health-endpoints.mjs +7 -2
- package/scripts/lib/config/issue-budget.mjs +2 -1
- package/scripts/lib/config/loop-guard.mjs +2 -1
- package/scripts/lib/config/memory.mjs +2 -1
- package/scripts/lib/config/moc-staleness.mjs +2 -1
- package/scripts/lib/config/persona-gate-wave.mjs +2 -1
- package/scripts/lib/config/private-config-dir.mjs +67 -0
- package/scripts/lib/config/reconcile.mjs +2 -1
- package/scripts/lib/config/remote-hosts.mjs +2 -1
- package/scripts/lib/config/section-extractor.mjs +7 -1
- package/scripts/lib/config/skill-evolution.mjs +2 -1
- package/scripts/lib/config/slopcheck.mjs +2 -1
- package/scripts/lib/config/state-md-lock.mjs +2 -1
- package/scripts/lib/config/templates-first.mjs +2 -1
- package/scripts/lib/config/test.mjs +2 -1
- package/scripts/lib/config/vault-integration.mjs +7 -1
- package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
- package/scripts/lib/config/vault-staleness.mjs +2 -1
- package/scripts/lib/config/vault-sync.mjs +2 -1
- package/scripts/lib/config/verification-auto-fix.mjs +2 -1
- package/scripts/lib/config/wave-reviewers.mjs +2 -1
- package/scripts/lib/config/worktree-orphans.mjs +2 -1
- package/scripts/lib/convergence-monitor.mjs +82 -16
- package/scripts/lib/dispatcher/rank.mjs +124 -48
- package/scripts/lib/ecosystem-health.mjs +16 -2
- package/scripts/lib/eval/engine.mjs +9 -1
- package/scripts/lib/eval/session-resolve.mjs +23 -4
- package/scripts/lib/events.mjs +22 -6
- package/scripts/lib/frontmatter-guard.mjs +131 -13
- package/scripts/lib/gates/gate-full.mjs +26 -0
- package/scripts/lib/gates/gate-helpers.mjs +76 -0
- package/scripts/lib/hardware-pattern-detector.mjs +18 -1
- package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
- package/scripts/lib/host-identity.mjs +50 -11
- package/scripts/lib/instruction-budget-guard.mjs +171 -5
- package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
- package/scripts/lib/learnings/io.mjs +60 -6
- package/scripts/lib/memory-proposals/store.mjs +30 -22
- package/scripts/lib/owner-config-banner.mjs +43 -6
- package/scripts/lib/owner-config-loader.mjs +21 -10
- package/scripts/lib/owner-interview.mjs +3 -3
- package/scripts/lib/owner-yaml.mjs +207 -14
- package/scripts/lib/platform.mjs +108 -15
- package/scripts/lib/plugin-update-banner.mjs +406 -0
- package/scripts/lib/project-hygiene.mjs +38 -2
- package/scripts/lib/qg-command-drift-banner.mjs +50 -12
- package/scripts/lib/quality-gate.mjs +133 -44
- package/scripts/lib/reconcile/emitter.mjs +68 -6
- package/scripts/lib/reconcile/engine.mjs +13 -4
- package/scripts/lib/reconcile/idempotency.mjs +37 -4
- package/scripts/lib/reconcile/writer.mjs +40 -18
- package/scripts/lib/session-close-backfill.mjs +67 -9
- package/scripts/lib/session-id.mjs +12 -23
- package/scripts/lib/session-identity/own-session.mjs +125 -10
- package/scripts/lib/session-lock-shape.mjs +43 -0
- package/scripts/lib/session-lock.mjs +5 -10
- package/scripts/lib/session-registry.mjs +25 -9
- package/scripts/lib/session-schema/constants.mjs +36 -2
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +18 -1
- package/scripts/lib/sessions-staleness-banner.mjs +18 -11
- package/scripts/lib/skill-health/join.mjs +17 -4
- package/scripts/lib/state-md.mjs +78 -0
- package/scripts/lib/sunset/walker.mjs +6 -0
- package/scripts/lib/telemetry/schema.mjs +181 -9
- package/scripts/lib/telemetry/sync.mjs +368 -12
- package/scripts/lib/validate/check-agents-skills.mjs +327 -0
- package/scripts/lib/validate/check-agents.mjs +3 -3
- package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
- package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
- package/scripts/lib/validate/check-owner-leakage.mjs +281 -20
- package/scripts/lib/validate/check-skill-links.mjs +163 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +47 -28
- package/scripts/lib/validate/check-unwired-features.mjs +0 -2
- package/scripts/lib/validate/check-validator-registration.mjs +10 -4
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
- package/scripts/lib/vault-backfill/template.mjs +63 -6
- package/scripts/lib/vault-mirror/process.mjs +165 -42
- package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
- package/scripts/lib/vault-status/narrative-mirror.mjs +127 -18
- package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
- package/scripts/lib/wave-executor/remote-dispatch.mjs +5 -7
- package/scripts/lib/wave-resource-gate.mjs +8 -2
- package/scripts/lib/wave-sizing.mjs +4 -1
- package/scripts/lib/wave-transcript-tail.mjs +118 -4
- package/scripts/materialize-wave-scope.mjs +12 -5
- package/scripts/memory-propose.mjs +19 -5
- package/scripts/migrate-cold-start-seed.mjs +4 -1
- package/scripts/parse-config.mjs +60 -3
- package/scripts/release.mjs +337 -29
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- package/scripts/sweep-expired-learnings.mjs +90 -0
- package/scripts/sync-vault-schema.mjs +3 -1
- package/scripts/telemetry.mjs +2 -2
- package/scripts/validate-plugin.mjs +161 -0
- package/scripts/validate-wave-scope.mjs +28 -8
- package/scripts/wave-scope-binding.mjs +215 -0
- package/skills/_shared/instruction-file-resolution.md +10 -0
- package/skills/_shared/parallel-aware-preamble.md +1 -0
- package/skills/_shared/platform-tools.md +1 -1
- package/skills/_shared/state-ownership.md +1 -1
- package/skills/architecture/SKILL.md +7 -5
- package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
- package/skills/autopilot/SKILL.md +4 -18
- package/skills/claude-md-drift-check/SKILL.md +5 -1
- package/skills/claude-md-drift-check/checker.mjs +62 -2
- package/skills/convergence-monitoring/SIGNALS.md +55 -0
- package/skills/discovery/probes/vault-staleness.mjs +37 -13
- package/skills/discovery/probes-arch.md +20 -18
- package/skills/dispatcher/SKILL.md +3 -2
- package/skills/evolve/SKILL.md +65 -26
- package/skills/frontmatter-guard/SKILL.md +11 -5
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +33 -0
- package/skills/remote-offload/SKILL.md +1 -1
- package/skills/session-end/SKILL.md +18 -905
- package/skills/session-end/phase-3-6-tail.md +10 -3
- package/skills/session-end/plan-verification.md +221 -155
- package/skills/session-end/references/phase-2-quality-gate.md +93 -0
- package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
- package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
- package/skills/session-end/references/session-summary-template.md +62 -0
- package/skills/session-plan/SKILL.md +49 -0
- package/skills/session-start/SKILL.md +22 -904
- package/skills/session-start/phase-8-5-express-path.md +1 -1
- package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
- package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
- package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
- package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
- package/skills/session-start/references/phase-4-ssot-environment-check.md +155 -0
- package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
- package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
- package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
- package/skills/vault-sync/validator.mjs +21 -27
- package/skills/wave-executor/SKILL.md +15 -1
- package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
- package/skills/wave-executor/references/wave-loop-review.md +570 -0
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
- package/skills/wave-executor/wave-loop.md +14 -1309
- package/templates/_shared/journey-manifest.md +10 -6
- package/.cursor/commands/autopilot-multi.md +0 -14
- package/.cursor/commands/contract-version-bump.md +0 -14
- package/.cursor/commands/journey-audit.md +0 -14
- package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
- package/.cursor/skills/daily/SKILL.md +0 -12
- package/.cursor/skills/domain-model/SKILL.md +0 -13
- package/.cursor/skills/journey-audit/SKILL.md +0 -13
- package/.cursor/skills/skill-creator/SKILL.md +0 -13
- package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
- package/commands/autopilot-multi.md +0 -74
- package/commands/contract-version-bump.md +0 -28
- package/commands/journey-audit.md +0 -43
- package/pi/prompts/autopilot-multi.md +0 -12
- package/pi/prompts/contract-version-bump.md +0 -12
- package/pi/prompts/journey-audit.md +0 -12
- package/scripts/autopilot-multi.mjs +0 -885
- package/scripts/backfill-learnings-expires.mjs +0 -196
- package/scripts/backfill-learnings.mjs +0 -203
- package/scripts/fleet-instruction-scan.mjs +0 -141
- package/scripts/lib/autopilot/dep-graph.mjs +0 -417
- package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
- package/scripts/lib/webhook-url.mjs +0 -105
- package/scripts/lifecycle-sim-v6.mjs +0 -347
- package/scripts/migrate-learnings-jsonl.mjs +0 -189
- package/scripts/migrate-subagents-jsonl.mjs +0 -196
- package/scripts/upload-social-preview.mjs +0 -316
- package/skills/_shared/model-selection.md +0 -64
- package/skills/contract-version-bump/SKILL.md +0 -219
- package/skills/daily/SKILL.md +0 -222
- package/skills/daily/generate.sh +0 -92
- package/skills/daily/templates/daily.md.tpl +0 -36
- package/skills/journey-audit/SKILL.md +0 -270
- package/skills/skill-creator/SKILL.md +0 -168
- package/skills/ubiquitous-language/SKILL.md +0 -97
- package/skills/vault-sync/package-lock.json +0 -40
- /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
- /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* check-agents-skills.mjs — validate the CROSS-HARNESS PORTABLE SURFACE.
|
|
4
|
+
*
|
|
5
|
+
* Scope note on the name: "agents-skills" is the `.agents`/`AGENTS`-family
|
|
6
|
+
* surface, not just the skill mirror. Three artefacts are checked, because
|
|
7
|
+
* they are one feature — the set of files a NON-Claude harness (Codex CLI,
|
|
8
|
+
* Cursor, Amp, Copilot CLI, OpenCode, Kiro) reads when it opens this repo:
|
|
9
|
+
*
|
|
10
|
+
* A. root `AGENTS.md` — must be an alias of `CLAUDE.md` (symlink to the same
|
|
11
|
+
* inode, or byte-identical).
|
|
12
|
+
* B. root `plugin.json` — the agent-plugins.org 1.0.0 manifest; its `version`
|
|
13
|
+
* must equal `package.json`'s and the two existing plugin manifests'.
|
|
14
|
+
* C. `.agents/skills/<name>/SKILL.md` — one spec-legal mirror per source
|
|
15
|
+
* skill, no orphans, agentskills.io field list only, description ≤ 1024.
|
|
16
|
+
*
|
|
17
|
+
* INDEPENDENCE (load-bearing). This checker deliberately imports NOTHING from
|
|
18
|
+
* `scripts/generate-agents-skills.mjs` and re-derives the spec field list, the
|
|
19
|
+
* 1024 cap and the alias rule from the spec, not from the generator. A
|
|
20
|
+
* generator-vs-generator check only proves the generator is self-consistent —
|
|
21
|
+
* that is how the Cursor `argument-hint` defect survived. The oracles here are
|
|
22
|
+
* the repository's own filesystem (`skills/`, `CLAUDE.md`, `package.json`) and
|
|
23
|
+
* the published field list.
|
|
24
|
+
*
|
|
25
|
+
* Usage: node scripts/lib/validate/check-agents-skills.mjs <plugin-root>
|
|
26
|
+
* Exit codes: 0 — all checks passed · 1 — one or more failures.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { existsSync, readFileSync, readdirSync, statSync, lstatSync, realpathSync } from 'node:fs';
|
|
30
|
+
import { join } from 'node:path';
|
|
31
|
+
import yaml from 'js-yaml';
|
|
32
|
+
|
|
33
|
+
const pluginRoot = process.argv[2];
|
|
34
|
+
if (!pluginRoot) {
|
|
35
|
+
console.error('Usage: check-agents-skills.mjs <plugin-root>');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let passed = 0;
|
|
40
|
+
let failed = 0;
|
|
41
|
+
const pass = (msg) => { console.log(` PASS: ${msg}`); passed += 1; };
|
|
42
|
+
const fail = (msg) => { console.log(` FAIL: ${msg}`); failed += 1; };
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The complete agentskills.io field list permitted outside Claude Code.
|
|
46
|
+
* Re-derived from the spec here on purpose — see INDEPENDENCE above.
|
|
47
|
+
*/
|
|
48
|
+
const SPEC_KEYS = new Set(['name', 'description', 'license', 'compatibility', 'metadata', 'allowed-tools']);
|
|
49
|
+
const DESCRIPTION_MAX = 1024;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Per-mirror byte ceiling. A mirror is a frontmatter block plus a 6-line
|
|
53
|
+
* pointer; the largest one measured 2026-09-06 was ~1.9 KB (its description is
|
|
54
|
+
* 1012 chars). The ceiling exists to catch the failure this design prevents —
|
|
55
|
+
* a mirror that starts duplicating the canonical body, which would double the
|
|
56
|
+
* instruction corpus a foreign harness loads. Revisit trigger: raise it only
|
|
57
|
+
* together with a re-measurement of `.agents/skills/` total bytes, never to
|
|
58
|
+
* accommodate a body that was pasted in.
|
|
59
|
+
*/
|
|
60
|
+
const MIRROR_MAX_BYTES = 4096;
|
|
61
|
+
|
|
62
|
+
const AGENT_PLUGINS_SCHEMA = 'https://agent-plugins.org/schemas/1.0.0/plugin.schema.json';
|
|
63
|
+
|
|
64
|
+
/** Read + parse a JSON file; null on missing or malformed. */
|
|
65
|
+
function readJson(absPath) {
|
|
66
|
+
if (!existsSync(absPath)) return null;
|
|
67
|
+
try { return JSON.parse(readFileSync(absPath, 'utf8')); } catch { return null; }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Split a Markdown file into `{ frontmatter, body }`; frontmatter null when absent/unparseable. */
|
|
71
|
+
function splitFrontmatter(content) {
|
|
72
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(content);
|
|
73
|
+
if (!m) return { frontmatter: null, body: content };
|
|
74
|
+
try {
|
|
75
|
+
const parsed = yaml.load(m[1]);
|
|
76
|
+
return {
|
|
77
|
+
frontmatter: parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null,
|
|
78
|
+
body: m[2],
|
|
79
|
+
};
|
|
80
|
+
} catch {
|
|
81
|
+
return { frontmatter: null, body: m[2] };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// A. root AGENTS.md is an alias of CLAUDE.md
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
console.log('--- Check A: root AGENTS.md ↔ CLAUDE.md alias ---');
|
|
90
|
+
{
|
|
91
|
+
const claudePath = join(pluginRoot, 'CLAUDE.md');
|
|
92
|
+
const agentsPath = join(pluginRoot, 'AGENTS.md');
|
|
93
|
+
if (!existsSync(claudePath)) {
|
|
94
|
+
pass('no CLAUDE.md at plugin root — alias check not applicable');
|
|
95
|
+
} else if (!existsSync(agentsPath)) {
|
|
96
|
+
fail('CLAUDE.md exists but AGENTS.md does not — Codex CLI, OpenCode, Kiro and Amp '
|
|
97
|
+
+ 'read AGENTS.md and never CLAUDE.md, so this repo would ship without a Session Config for them '
|
|
98
|
+
+ '(remedy: node scripts/generate-agents-skills.mjs)');
|
|
99
|
+
} else {
|
|
100
|
+
let aliased = false;
|
|
101
|
+
let how = '';
|
|
102
|
+
try {
|
|
103
|
+
if (lstatSync(agentsPath).isSymbolicLink()) {
|
|
104
|
+
aliased = realpathSync(agentsPath) === realpathSync(claudePath);
|
|
105
|
+
how = 'symlink';
|
|
106
|
+
} else {
|
|
107
|
+
const a = statSync(agentsPath);
|
|
108
|
+
const c = statSync(claudePath);
|
|
109
|
+
if (a.ino !== 0 && a.ino === c.ino && a.dev === c.dev) { aliased = true; how = 'same inode'; }
|
|
110
|
+
}
|
|
111
|
+
} catch { /* fall through to the byte comparison */ }
|
|
112
|
+
if (!aliased) {
|
|
113
|
+
aliased = readFileSync(agentsPath).equals(readFileSync(claudePath));
|
|
114
|
+
how = 'byte-identical';
|
|
115
|
+
}
|
|
116
|
+
if (aliased) {
|
|
117
|
+
pass(`AGENTS.md is an alias of CLAUDE.md (${how})`);
|
|
118
|
+
} else {
|
|
119
|
+
fail('AGENTS.md and CLAUDE.md are two independent files that disagree — AGENTS.md is GENERATED; '
|
|
120
|
+
+ 'put the change in CLAUDE.md and run `node scripts/generate-agents-skills.mjs`');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// B. root plugin.json (agent-plugins.org 1.0.0)
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log('--- Check B: root plugin.json (agent-plugins.org 1.0.0) ---');
|
|
131
|
+
{
|
|
132
|
+
const rootManifest = readJson(join(pluginRoot, 'plugin.json'));
|
|
133
|
+
if (rootManifest === null) {
|
|
134
|
+
if (existsSync(join(pluginRoot, 'plugin.json'))) {
|
|
135
|
+
fail('plugin.json exists but is not valid JSON');
|
|
136
|
+
} else {
|
|
137
|
+
pass('no root plugin.json — vendor-neutral manifest not shipped');
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
if (rootManifest.$schema === AGENT_PLUGINS_SCHEMA) {
|
|
141
|
+
pass('plugin.json declares the agent-plugins.org 1.0.0 $schema');
|
|
142
|
+
} else {
|
|
143
|
+
fail(`plugin.json $schema is '${rootManifest.$schema ?? '(unset)'}', expected '${AGENT_PLUGINS_SCHEMA}'`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for (const field of ['name', 'version', 'description', 'license']) {
|
|
147
|
+
if (typeof rootManifest[field] === 'string' && rootManifest[field].trim()) {
|
|
148
|
+
pass(`plugin.json has a non-empty '${field}'`);
|
|
149
|
+
} else {
|
|
150
|
+
fail(`plugin.json is missing required field '${field}'`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Version parity across ALL manifests. Three manifests now carry a version
|
|
155
|
+
// and only `package.json` is bumped by the release script — a third copy
|
|
156
|
+
// that drifts silently is the whole reason this case exists.
|
|
157
|
+
const pkg = readJson(join(pluginRoot, 'package.json'));
|
|
158
|
+
const pkgVersion = pkg?.version ?? null;
|
|
159
|
+
if (!pkgVersion) {
|
|
160
|
+
fail('package.json has no version — cannot verify manifest version parity');
|
|
161
|
+
} else if (rootManifest.version === pkgVersion) {
|
|
162
|
+
pass(`plugin.json version matches package.json (${pkgVersion})`);
|
|
163
|
+
} else {
|
|
164
|
+
fail(`plugin.json version '${rootManifest.version}' != package.json version '${pkgVersion}' `
|
|
165
|
+
+ '— the release script bumps package.json only');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const claudeManifest = readJson(join(pluginRoot, '.claude-plugin', 'plugin.json'));
|
|
169
|
+
if (claudeManifest?.version && rootManifest.version !== claudeManifest.version) {
|
|
170
|
+
fail(`plugin.json version '${rootManifest.version}' != .claude-plugin/plugin.json version '${claudeManifest.version}'`);
|
|
171
|
+
} else if (claudeManifest?.version) {
|
|
172
|
+
pass('plugin.json version matches .claude-plugin/plugin.json');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Declared component paths must exist — a manifest may not advertise a
|
|
176
|
+
// component this repo does not ship.
|
|
177
|
+
let componentFail = 0;
|
|
178
|
+
for (const [key, value] of Object.entries(rootManifest)) {
|
|
179
|
+
if (typeof value !== 'string' || !value.startsWith('./')) continue;
|
|
180
|
+
if (key === '$schema') continue;
|
|
181
|
+
if (!existsSync(join(pluginRoot, value))) {
|
|
182
|
+
fail(`plugin.json component '${key}' points at '${value}' which does not exist`);
|
|
183
|
+
componentFail += 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (componentFail === 0) pass('all plugin.json component paths resolve on disk');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
// C. .agents/skills/ portable mirror
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
console.log('');
|
|
195
|
+
console.log('--- Check C: .agents/skills/ portable mirror ---');
|
|
196
|
+
{
|
|
197
|
+
const skillsDir = join(pluginRoot, 'skills');
|
|
198
|
+
const mirrorDir = join(pluginRoot, '.agents', 'skills');
|
|
199
|
+
|
|
200
|
+
const sourceSkills = existsSync(skillsDir) && statSync(skillsDir).isDirectory()
|
|
201
|
+
? readdirSync(skillsDir, { withFileTypes: true })
|
|
202
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.') && !e.name.startsWith('_'))
|
|
203
|
+
.map((e) => e.name)
|
|
204
|
+
.filter((n) => existsSync(join(skillsDir, n, 'SKILL.md')))
|
|
205
|
+
.sort()
|
|
206
|
+
: [];
|
|
207
|
+
|
|
208
|
+
if (!existsSync(mirrorDir)) {
|
|
209
|
+
if (sourceSkills.length === 0) {
|
|
210
|
+
pass('no skills/ and no .agents/skills/ — nothing to mirror');
|
|
211
|
+
} else {
|
|
212
|
+
fail(`.agents/skills/ is missing but ${sourceSkills.length} source skill(s) exist `
|
|
213
|
+
+ '(remedy: node scripts/generate-agents-skills.mjs)');
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
const mirrored = readdirSync(mirrorDir, { withFileTypes: true })
|
|
217
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.'))
|
|
218
|
+
.map((e) => e.name)
|
|
219
|
+
.sort();
|
|
220
|
+
|
|
221
|
+
const missing = sourceSkills.filter((n) => !mirrored.includes(n));
|
|
222
|
+
const orphans = mirrored.filter((n) => !sourceSkills.includes(n));
|
|
223
|
+
if (missing.length === 0) pass(`every source skill has a mirror (${sourceSkills.length})`);
|
|
224
|
+
else fail(`${missing.length} source skill(s) have no mirror: ${missing.join(', ')}`);
|
|
225
|
+
if (orphans.length === 0) pass('no orphan mirrors');
|
|
226
|
+
else fail(`${orphans.length} orphan mirror(s) with no source skill: ${orphans.join(', ')}`);
|
|
227
|
+
|
|
228
|
+
let fmFail = 0;
|
|
229
|
+
let keyFail = 0;
|
|
230
|
+
let descFail = 0;
|
|
231
|
+
let sizeFail = 0;
|
|
232
|
+
let pointerFail = 0;
|
|
233
|
+
let totalBytes = 0;
|
|
234
|
+
|
|
235
|
+
for (const name of mirrored) {
|
|
236
|
+
const file = join(mirrorDir, name, 'SKILL.md');
|
|
237
|
+
if (!existsSync(file)) {
|
|
238
|
+
fail(`.agents/skills/${name}/ has no SKILL.md`);
|
|
239
|
+
fmFail += 1;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const raw = readFileSync(file, 'utf8');
|
|
243
|
+
totalBytes += Buffer.byteLength(raw, 'utf8');
|
|
244
|
+
|
|
245
|
+
if (Buffer.byteLength(raw, 'utf8') > MIRROR_MAX_BYTES) {
|
|
246
|
+
fail(`.agents/skills/${name}/SKILL.md is ${Buffer.byteLength(raw, 'utf8')} bytes `
|
|
247
|
+
+ `(> ${MIRROR_MAX_BYTES}) — the mirror must point at the canonical body, never duplicate it`);
|
|
248
|
+
sizeFail += 1;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const { frontmatter, body } = splitFrontmatter(raw);
|
|
252
|
+
if (!frontmatter) {
|
|
253
|
+
fail(`.agents/skills/${name}/SKILL.md has no parseable YAML frontmatter`);
|
|
254
|
+
fmFail += 1;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
for (const key of Object.keys(frontmatter)) {
|
|
259
|
+
if (!SPEC_KEYS.has(key)) {
|
|
260
|
+
fail(`.agents/skills/${name}/SKILL.md frontmatter carries non-spec key '${key}' `
|
|
261
|
+
+ `(agentskills.io permits only: ${[...SPEC_KEYS].join(', ')})`);
|
|
262
|
+
keyFail += 1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (frontmatter.name !== name) {
|
|
267
|
+
fail(`.agents/skills/${name}/SKILL.md declares name '${frontmatter.name}' != directory '${name}'`);
|
|
268
|
+
keyFail += 1;
|
|
269
|
+
} else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {
|
|
270
|
+
fail(`.agents/skills/${name}/SKILL.md name is not kebab-case`);
|
|
271
|
+
keyFail += 1;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const desc = frontmatter.description;
|
|
275
|
+
if (typeof desc !== 'string' || !desc.trim()) {
|
|
276
|
+
fail(`.agents/skills/${name}/SKILL.md has an empty description`);
|
|
277
|
+
descFail += 1;
|
|
278
|
+
} else if (desc.length > DESCRIPTION_MAX) {
|
|
279
|
+
fail(`.agents/skills/${name}/SKILL.md description is ${desc.length} chars (> ${DESCRIPTION_MAX})`);
|
|
280
|
+
descFail += 1;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if ('metadata' in frontmatter) {
|
|
284
|
+
const md = frontmatter.metadata;
|
|
285
|
+
if (!md || typeof md !== 'object' || Array.isArray(md)) {
|
|
286
|
+
fail(`.agents/skills/${name}/SKILL.md metadata is not a string map`);
|
|
287
|
+
keyFail += 1;
|
|
288
|
+
} else {
|
|
289
|
+
for (const [mk, mv] of Object.entries(md)) {
|
|
290
|
+
if (typeof mv !== 'string') {
|
|
291
|
+
fail(`.agents/skills/${name}/SKILL.md metadata.${mk} is ${typeof mv}, expected string`);
|
|
292
|
+
keyFail += 1;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if ('allowed-tools' in frontmatter) {
|
|
299
|
+
const tools = frontmatter['allowed-tools'];
|
|
300
|
+
if (!Array.isArray(tools) || tools.some((t) => typeof t !== 'string' || !t.trim())) {
|
|
301
|
+
fail(`.agents/skills/${name}/SKILL.md allowed-tools is not an array of non-empty strings`);
|
|
302
|
+
keyFail += 1;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!body.includes(`skills/${name}/SKILL.md`)) {
|
|
307
|
+
fail(`.agents/skills/${name}/SKILL.md body does not cite the canonical skills/${name}/SKILL.md `
|
|
308
|
+
+ '— the mirror is a pointer, and a pointer with no target is dead weight');
|
|
309
|
+
pointerFail += 1;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (fmFail === 0 && mirrored.length > 0) pass(`all ${mirrored.length} mirrors have parseable frontmatter`);
|
|
314
|
+
if (keyFail === 0 && mirrored.length > 0) pass('all mirrors use only agentskills.io spec fields');
|
|
315
|
+
if (descFail === 0 && mirrored.length > 0) pass(`all mirror descriptions are non-empty and ≤ ${DESCRIPTION_MAX} chars`);
|
|
316
|
+
if (sizeFail === 0 && mirrored.length > 0) pass(`all mirrors ≤ ${MIRROR_MAX_BYTES} bytes (total ${totalBytes} bytes)`);
|
|
317
|
+
if (pointerFail === 0 && mirrored.length > 0) pass('all mirrors cite their canonical SKILL.md');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ---------------------------------------------------------------------------
|
|
322
|
+
// Results
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
|
|
325
|
+
console.log('');
|
|
326
|
+
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
327
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
@@ -547,7 +547,7 @@ if (existsSync(agentsDir)) {
|
|
|
547
547
|
// agents at a glance). With more than 9 agents, colors are deliberately
|
|
548
548
|
// shared — but two DISPATCHABLE agents sharing a color is a likely
|
|
549
549
|
// same-wave collision and surfaces as a WARN (not FAIL: deliberate
|
|
550
|
-
// cross-phase shares are legitimate — see
|
|
550
|
+
// cross-phase shares are legitimate — see docs/agent-authoring.md § Color
|
|
551
551
|
// Allocation Strategy).
|
|
552
552
|
// Non-dispatchable reference docs (description contains "NOT a dispatchable"
|
|
553
553
|
// or "Reference documentation") are excluded from the aggregation: they
|
|
@@ -581,7 +581,7 @@ if (existsSync(agentsDir)) {
|
|
|
581
581
|
for (const [color, names] of colorMap) {
|
|
582
582
|
if (names.length > 1) {
|
|
583
583
|
collisions++;
|
|
584
|
-
warn(`color collision: ${color} shared by dispatchable agents ${names.sort().join(', ')} — confirm they never co-run in one wave (
|
|
584
|
+
warn(`color collision: ${color} shared by dispatchable agents ${names.sort().join(', ')} — confirm they never co-run in one wave (docs/agent-authoring.md § Color Allocation Strategy)`);
|
|
585
585
|
}
|
|
586
586
|
}
|
|
587
587
|
if (collisions === 0) {
|
|
@@ -632,7 +632,7 @@ if (existsSync(agentsDir)) {
|
|
|
632
632
|
if (missing.length > 0) {
|
|
633
633
|
fail(
|
|
634
634
|
`${agentFile}: repo-write agent (Edit+Write) is missing ${missing.join(' and ')} ` +
|
|
635
|
-
'— see .claude/rules/parallel-sessions.md § PSA-007 and
|
|
635
|
+
'— see .claude/rules/parallel-sessions.md § PSA-007 and docs/agent-authoring.md § Git-Write Ban Requirement',
|
|
636
636
|
);
|
|
637
637
|
} else {
|
|
638
638
|
pass(`${agentFile}: PSA-007 git-write ban present`);
|