@event4u/agent-config 8.13.0 → 9.1.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +183 -0
- package/MIGRATION.md +14 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/agent-handoff.md +35 -0
- package/dist/agent-src/commands/agents/init.md +1 -0
- package/dist/agent-src/commands/agents/optimize.md +1 -0
- package/dist/agent-src/commands/agents/user/accept.md +3 -2
- package/dist/agent-src/commands/agents/user/init.md +5 -4
- package/dist/agent-src/commands/agents/user/update.md +3 -2
- package/dist/agent-src/commands/agents/user.md +1 -0
- package/dist/agent-src/commands/agents.md +1 -0
- package/dist/agent-src/commands/analytics/show.md +1 -0
- package/dist/agent-src/commands/analytics.md +1 -0
- package/dist/agent-src/commands/analyze/decision.md +1 -0
- package/dist/agent-src/commands/analyze/incident.md +1 -0
- package/dist/agent-src/commands/analyze/near-miss.md +1 -0
- package/dist/agent-src/commands/analyze/postmortem.md +1 -0
- package/dist/agent-src/commands/analyze/premortem.md +1 -0
- package/dist/agent-src/commands/analyze/reference-repo.md +1 -0
- package/dist/agent-src/commands/analyze.md +3 -2
- package/dist/agent-src/commands/brand/identity.md +6 -5
- package/dist/agent-src/commands/brand/review.md +6 -5
- package/dist/agent-src/commands/brand/strategy.md +6 -4
- package/dist/agent-src/commands/brand/tokens.md +7 -6
- package/dist/agent-src/commands/brand/voice.md +5 -4
- package/dist/agent-src/commands/brand.md +9 -7
- package/dist/agent-src/commands/bug/fix.md +1 -0
- package/dist/agent-src/commands/bug/investigate.md +1 -0
- package/dist/agent-src/commands/bug.md +2 -1
- package/dist/agent-src/commands/challenge-me/vision.md +1 -0
- package/dist/agent-src/commands/challenge-me/with-docs.md +1 -0
- package/dist/agent-src/commands/challenge-me.md +28 -6
- package/dist/agent-src/commands/chat-history.md +1 -0
- package/dist/agent-src/commands/check-current-md.md +1 -0
- package/dist/agent-src/commands/commit.md +1 -0
- package/dist/agent-src/commands/context/create.md +3 -2
- package/dist/agent-src/commands/context.md +1 -0
- package/dist/agent-src/commands/cost/profile.md +1 -0
- package/dist/agent-src/commands/cost.md +2 -1
- package/dist/agent-src/commands/council/analysis.md +1 -0
- package/dist/agent-src/commands/council/debate.md +1 -0
- package/dist/agent-src/commands/council/default.md +21 -20
- package/dist/agent-src/commands/council/design.md +1 -0
- package/dist/agent-src/commands/council/optimize.md +1 -0
- package/dist/agent-src/commands/council/pr.md +1 -0
- package/dist/agent-src/commands/council.md +1 -0
- package/dist/agent-src/commands/estimate-ticket.md +1 -0
- package/dist/agent-src/commands/explain-run.md +88 -0
- package/dist/agent-src/commands/feature/dev.md +1 -0
- package/dist/agent-src/commands/feature/explore.md +1 -0
- package/dist/agent-src/commands/feature/plan.md +1 -0
- package/dist/agent-src/commands/feature/refactor.md +1 -0
- package/dist/agent-src/commands/feature/roadmap.md +1 -0
- package/dist/agent-src/commands/feature.md +2 -1
- package/dist/agent-src/commands/fix/pr-comments.md +19 -0
- package/dist/agent-src/commands/fix.md +2 -1
- package/dist/agent-src/commands/ghostwriter/delete.md +1 -0
- package/dist/agent-src/commands/ghostwriter/fetch.md +1 -0
- package/dist/agent-src/commands/ghostwriter/show.md +1 -0
- package/dist/agent-src/commands/ghostwriter/write.md +1 -0
- package/dist/agent-src/commands/ghostwriter.md +1 -0
- package/dist/agent-src/commands/grill-me.md +17 -12
- package/dist/agent-src/commands/humanize.md +1 -0
- package/dist/agent-src/commands/image/analyse.md +2 -1
- package/dist/agent-src/commands/image/create.md +1 -0
- package/dist/agent-src/commands/image/verify.md +1 -0
- package/dist/agent-src/commands/image.md +16 -12
- package/dist/agent-src/commands/implement-ticket.md +1 -0
- package/dist/agent-src/commands/judge/on-diff.md +1 -0
- package/dist/agent-src/commands/judge/solo.md +1 -0
- package/dist/agent-src/commands/judge/steps.md +1 -0
- package/dist/agent-src/commands/judge.md +1 -0
- package/dist/agent-src/commands/knowledge/cross-repo.md +1 -0
- package/dist/agent-src/commands/knowledge/forget.md +1 -0
- package/dist/agent-src/commands/knowledge/ingest.md +1 -0
- package/dist/agent-src/commands/knowledge/list.md +10 -0
- package/dist/agent-src/commands/knowledge.md +1 -0
- package/dist/agent-src/commands/memory/learn-low-impact.md +1 -0
- package/dist/agent-src/commands/memory/mine-session.md +1 -0
- package/dist/agent-src/commands/memory/promote.md +3 -2
- package/dist/agent-src/commands/memory.md +1 -0
- package/dist/agent-src/commands/mission/upgrade.md +45 -24
- package/dist/agent-src/commands/mode.md +1 -0
- package/dist/agent-src/commands/module/create.md +1 -0
- package/dist/agent-src/commands/module/explore.md +1 -0
- package/dist/agent-src/commands/module.md +1 -0
- package/dist/agent-src/commands/optimize/agents-dir.md +1 -0
- package/dist/agent-src/commands/optimize/project.md +1 -0
- package/dist/agent-src/commands/optimize/prompt.md +1 -0
- package/dist/agent-src/commands/optimize.md +2 -1
- package/dist/agent-src/commands/orchestrate.md +1 -0
- package/dist/agent-src/commands/override.md +1 -0
- package/dist/agent-src/commands/package.md +2 -1
- package/dist/agent-src/commands/post-as/ghostwriter.md +1 -0
- package/dist/agent-src/commands/post-as/me.md +1 -0
- package/dist/agent-src/commands/post-as.md +1 -0
- package/dist/agent-src/commands/pr/create/description-only.md +139 -8
- package/dist/agent-src/commands/pr/create.md +35 -22
- package/dist/agent-src/commands/prediction-pool.md +7 -6
- package/dist/agent-src/commands/prepare-for-review.md +1 -0
- package/dist/agent-src/commands/profile/activate.md +1 -0
- package/dist/agent-src/commands/profile/deactivate.md +1 -0
- package/dist/agent-src/commands/profile.md +1 -0
- package/dist/agent-src/commands/project.md +2 -1
- package/dist/agent-src/commands/refine-ticket.md +7 -0
- package/dist/agent-src/commands/research/deep.md +1 -0
- package/dist/agent-src/commands/research.md +1 -0
- package/dist/agent-src/commands/review/routing.md +1 -0
- package/dist/agent-src/commands/review.md +2 -1
- package/dist/agent-src/commands/roadmap/ai-council.md +1 -0
- package/dist/agent-src/commands/roadmap/materialize.md +1 -0
- package/dist/agent-src/commands/roadmap/process-full.md +1 -0
- package/dist/agent-src/commands/roadmap/process-phase.md +1 -0
- package/dist/agent-src/commands/roadmap/process-step.md +1 -0
- package/dist/agent-src/commands/roadmap.md +1 -0
- package/dist/agent-src/commands/security-audit-config.md +2 -1
- package/dist/agent-src/commands/skill/preview.md +1 -0
- package/dist/agent-src/commands/skill.md +1 -0
- package/dist/agent-src/commands/skills/discover.md +1 -0
- package/dist/agent-src/commands/skills.md +1 -0
- package/dist/agent-src/commands/sync/agent-settings.md +1 -0
- package/dist/agent-src/commands/sync.md +2 -1
- package/dist/agent-src/commands/team/adversarial.md +3 -2
- package/dist/agent-src/commands/team/delegate.md +3 -2
- package/dist/agent-src/commands/team/review.md +3 -2
- package/dist/agent-src/commands/team/status.md +49 -18
- package/dist/agent-src/commands/team-knowledge.md +8 -6
- package/dist/agent-src/commands/team.md +21 -16
- package/dist/agent-src/commands/tests/e2e-heal.md +1 -0
- package/dist/agent-src/commands/tests/e2e-plan.md +1 -0
- package/dist/agent-src/commands/tests/execute.md +1 -0
- package/dist/agent-src/commands/tests.md +2 -1
- package/dist/agent-src/commands/update-form-request-messages.md +1 -0
- package/dist/agent-src/commands/upstream-contribute.md +1 -0
- package/dist/agent-src/commands/video/from-script.md +3 -2
- package/dist/agent-src/commands/video/from-song.md +22 -21
- package/dist/agent-src/commands/video/scene.md +1 -0
- package/dist/agent-src/commands/video/stitch.md +2 -1
- package/dist/agent-src/commands/video/storyboard.md +1 -0
- package/dist/agent-src/commands/video.md +1 -0
- package/dist/agent-src/commands/work.md +1 -0
- package/dist/agent-src/commands/worktree/cleanup.md +8 -7
- package/dist/agent-src/commands/worktree/create.md +1 -0
- package/dist/agent-src/commands/worktree/verify.md +1 -0
- package/dist/agent-src/commands/worktree.md +1 -0
- package/dist/agent-src/rules/active-remediation.md +12 -36
- package/dist/agent-src/rules/artifact-drafting-protocol.md +7 -64
- package/dist/agent-src/rules/context-hygiene.md +19 -113
- package/dist/agent-src/rules/design-fidelity.md +4 -60
- package/dist/agent-src/rules/domain-adoption-policy.md +10 -106
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +12 -60
- package/dist/agent-src/rules/improve-before-implement.md +4 -0
- package/dist/agent-src/rules/minimal-safe-diff.md +6 -86
- package/dist/agent-src/rules/size-enforcement.md +10 -0
- package/dist/agent-src/rules/tool-safety.md +17 -3
- package/dist/agent-src/skills/agent-security-review/SKILL.md +12 -1
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -0
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +24 -2
- package/dist/agent-src/skills/code-review/SKILL.md +105 -93
- package/dist/agent-src/skills/code-review/checklists/backend.md +50 -0
- package/dist/agent-src/skills/code-review/checklists/database.md +19 -0
- package/dist/agent-src/skills/code-review/checklists/dependency.md +18 -0
- package/dist/agent-src/skills/code-review/checklists/docs.md +14 -0
- package/dist/agent-src/skills/code-review/checklists/frontend.md +19 -0
- package/dist/agent-src/skills/code-review/checklists/infra.md +17 -0
- package/dist/agent-src/skills/code-review/checklists/producing-the-review.md +62 -0
- package/dist/agent-src/skills/code-review/checklists/test-only.md +13 -0
- package/dist/agent-src/skills/code-review/evals/evals.json +53 -15
- package/dist/agent-src/skills/condense-memory/SKILL.md +3 -2
- package/dist/agent-src/skills/conventional-commits-writing/evals/evals.json +15 -0
- package/dist/agent-src/skills/docker/SKILL.md +10 -0
- package/dist/agent-src/skills/docx-authoring/SKILL.md +102 -0
- package/dist/agent-src/skills/github-ci/evals/evals.json +25 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +79 -3
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +112 -0
- package/dist/agent-src/skills/humanizer/references/fixtures.md +70 -0
- package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +7 -1
- package/dist/agent-src/skills/laravel/SKILL.md +10 -0
- package/dist/agent-src/skills/launch-readiness/SKILL.md +35 -0
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +146 -0
- package/dist/agent-src/skills/llm-provider-knowledge/evals/triggers.json +20 -0
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +30 -0
- package/dist/agent-src/skills/pdf-tools/SKILL.md +101 -0
- package/dist/agent-src/skills/quality-tools/evals/evals.json +15 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +29 -0
- package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +90 -0
- package/dist/agent-src/skills/security-maturity-assessment/evals/triggers.json +52 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +79 -0
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +11 -3
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +11 -0
- package/dist/agent-src/skills/subagent-orchestration/schemas/team-review-status.json +103 -0
- package/dist/agent-src/skills/terraform/SKILL.md +10 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +31 -0
- package/dist/agent-src/skills/threat-modeling/SKILL.md +15 -0
- package/dist/agent-src/skills/token-optimizer/SKILL.md +10 -4
- package/dist/agent-src/templates/agent-settings.md +28 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/dist/agent-src/templates/scripts/telemetry/engagement.ts +30 -0
- package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +22 -9
- package/dist/agent-src/templates/scripts/telemetry_record.ts +5 -0
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +4 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +314 -194
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +5 -5
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +23 -18
- package/dist/discovery/trust-report.md +8 -8
- package/dist/discovery/workspaces.json +18 -13
- package/dist/install/install.mjs +48 -33
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +4 -1
- package/dist/scripts/_lib/agent_settings.js.map +1 -1
- package/dist/scripts/condense.js +5 -0
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +10 -1
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/CLAIMS.md +9 -2
- package/docs/MIGRATION.md +20 -0
- package/docs/SKILL_CENSUS.md +8 -0
- package/docs/architecture.md +3 -3
- package/docs/benchmark.md +67 -2
- package/docs/catalog.md +2 -2
- package/docs/command-flows.md +1 -1
- package/docs/contracts/agents-layout.md +1 -1
- package/docs/contracts/ai-council-config.md +9 -2
- package/docs/contracts/ai-team-config.md +37 -4
- package/docs/contracts/consumer-bridge.md +55 -63
- package/docs/contracts/install-layout.md +1 -1
- package/docs/contracts/migrate-command.md +1 -1
- package/docs/contracts/prelaunch-diagnostics.md +151 -0
- package/docs/contracts/release-pr-gating.md +1 -0
- package/docs/customization.md +22 -1
- package/docs/decisions/ADR-020-global-only-consumer-scope.md +34 -0
- package/docs/decisions/ADR-049-configuration-trust-boundary.md +9 -1
- package/docs/featured-skills.md +2 -2
- package/docs/getting-started-by-role.md +1 -1
- package/docs/getting-started.md +17 -6
- package/docs/governance-advantage.md +1 -1
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +45 -0
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +28 -0
- package/docs/guidelines/agent-infra/api-cost-levers.md +126 -0
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +76 -0
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +90 -0
- package/docs/guidelines/agent-infra/domain-adoption-gates.md +112 -0
- package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +99 -0
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +13 -0
- package/docs/guidelines/design-fidelity-mechanics.md +76 -0
- package/docs/installation.md +2 -1
- package/docs/maintainers/dev-mode.md +3 -2
- package/docs/parity/command-frontmatter.md +60 -0
- package/docs/proof.md +7 -6
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/src/agent-src/templates/scripts/telemetry/engagement.ts +30 -0
- package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +22 -9
- package/src/agent-src/templates/scripts/telemetry_record.ts +5 -0
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +4 -1
- package/src/config/agent-settings.template.yml +73 -10
- package/src/config/gitignore-block.txt +16 -6
- package/src/config/prelaunch-areas.yml +36 -0
- package/src/scripts/_cli/cmd_conformance.ts +2 -2
- package/src/scripts/_cli/cmd_doctor.ts +280 -39
- package/src/scripts/_cli/cmd_refresh.ts +35 -118
- package/src/scripts/_lib/agent_settings.ts +4 -1
- package/src/scripts/_lib/claude_plugin.ts +77 -2
- package/src/scripts/_lib/orchestration_record.ts +5 -0
- package/src/scripts/_lib/tool_adapter_registry.ts +120 -0
- package/src/scripts/ai_council/clients.ts +68 -6
- package/src/scripts/ai_council/pricing.ts +62 -0
- package/src/scripts/ai_team/config.ts +73 -1
- package/src/scripts/ai_team/review_gate.ts +636 -0
- package/src/scripts/ai_team/team_dispatch.ts +612 -0
- package/src/scripts/bench_ab_task_runner.ts +11 -1
- package/src/scripts/bench_parity_count.ts +279 -0
- package/src/scripts/build_linear_digest.ts +3 -1
- package/src/scripts/check_bridge_derivation.ts +172 -0
- package/src/scripts/check_consumer_scope_flip.ts +179 -0
- package/src/scripts/check_council_config_location.ts +115 -15
- package/src/scripts/check_host_loadability.ts +81 -0
- package/src/scripts/condense.ts +5 -0
- package/src/scripts/council_cli.ts +19 -3
- package/src/scripts/hook_manifest.yaml +12 -1
- package/src/scripts/install.ts +44 -45
- package/src/scripts/lint_agents_layout.ts +10 -4
- package/src/scripts/lint_breaking_changes_index.ts +303 -0
- package/src/scripts/lint_handoffs.ts +42 -0
- package/src/scripts/lint_skill_descriptions.ts +228 -0
- package/src/scripts/lint_skill_descriptions_allowlist.json +1 -0
- package/src/scripts/lint_skill_scripts_readonly.ts +145 -0
- package/src/scripts/lint_skill_scripts_readonly_allowlist.json +8 -0
- package/src/scripts/lint_supported_tools_matrix.ts +35 -0
- package/src/scripts/mcp_server/tools.ts +1 -3
- package/src/scripts/optimize_skill_description.ts +144 -0
- package/src/scripts/orchestration_record.ts +2 -1
- package/src/scripts/prelaunch_diagnostics.ts +248 -0
- package/src/scripts/run_skill_evals.ts +70 -4
- package/src/scripts/schemas/agent-settings.schema.json +17 -0
- package/src/scripts/schemas/command.schema.json +7 -0
- package/src/scripts/schemas/evals.schema.json +105 -14
- package/src/scripts/schemas/prelaunch-report.schema.json +107 -0
- package/src/scripts/schemas/skill.schema.json +18 -1
- package/src/scripts/schemas/subagent.schema.json +6 -0
- package/src/scripts/self_review_gate.test.ts +11 -0
- package/src/scripts/self_review_gate.ts +7 -1
- package/src/scripts/skill_eval_coverage.ts +4 -1
- package/src/scripts/skill_linter.ts +43 -3
- package/src/scripts/smoke_host_loadability.sh +73 -0
- package/src/scripts/team_review_gate_hook.ts +115 -0
- package/src/scripts/trigger_eval_grandfather.json +1 -2
- package/src/scripts/utilization_report.ts +225 -0
- package/src/server/schemas/settings.ts +24 -1
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
* global root + Claude plugin hooks are rewritten from the
|
|
17
17
|
* currently-installed package. Idempotent: a second run is a no-op diff.
|
|
18
18
|
* - `--project` — refresh the **minimal** project surface ADR-020 permits for
|
|
19
|
-
* a consumer:
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* a consumer: an `agents/overrides/` scaffold and the managed `agents/`
|
|
20
|
+
* block in `.gitignore`, plus cleanup of any legacy
|
|
21
|
+
* `agents/.event4u-bridge.yml` (the marker was retired — ADR-020 amendment
|
|
22
|
+
* 2026-07-13; the global root is resolved from `~/.event4u/agent-config`).
|
|
23
|
+
* Writes **no** distributed content. No wizard.
|
|
22
24
|
*
|
|
23
25
|
* Bare `agent-config refresh` (no scope flag) errors — never a silent global
|
|
24
26
|
* default (council 2026-05-30).
|
|
@@ -39,17 +41,15 @@
|
|
|
39
41
|
* `cannot run <cmd[0]>: <err>` line to stderr and returns 1, mirroring the
|
|
40
42
|
* Python `except OSError`. The runner is injectable for tests.
|
|
41
43
|
* - `_lib.*` / `scripts.install` / `scripts.sync_gitignore` imports resolve to
|
|
42
|
-
* the `.ts` twins. `scripts.install.
|
|
43
|
-
* module-private in the install twin (not exported); it is replicated
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* `user_global_paths.event4u_root`) is replicated alongside, keeping the
|
|
47
|
-
* shared import surface unchanged (same approach as `cmd_update.ts`).
|
|
44
|
+
* the `.ts` twins. `scripts.install._remove_legacy_consumer_bridge_marker`
|
|
45
|
+
* is module-private in the install twin (not exported); it is replicated
|
|
46
|
+
* here — a small `isFile` + `fs.rmSync` guard gated on dev-mode / source
|
|
47
|
+
* repo, matching the install-twin source.
|
|
48
48
|
* - `Path(__file__).resolve().parents[3]` → `path.resolve(_HERE_DIR, '..',
|
|
49
49
|
* '..', '..')`. `.is_file()` / `.is_dir()` / `.exists()` →
|
|
50
50
|
* `_isFile` / `_isDir` / `_exists`. The `packages/` source-marker glob probe
|
|
51
51
|
* becomes a `readdirSync` scan of `packages/` (the source-marker dir name is
|
|
52
|
-
* the `SRC_MARKER_DIR` constant, shared with the
|
|
52
|
+
* the `SRC_MARKER_DIR` constant, shared with the marker-cleanup guard).
|
|
53
53
|
* - `print(..., file=out/err)` → an injectable `OutSink` defaulting to
|
|
54
54
|
* `process.stdout` / `process.stderr`. The Python `out`/`err` kwargs default
|
|
55
55
|
* to `sys.stdout` / `sys.stderr`.
|
|
@@ -60,17 +60,13 @@
|
|
|
60
60
|
* `except ImportError` branch wording.
|
|
61
61
|
*/
|
|
62
62
|
|
|
63
|
-
import * as crypto from 'node:crypto';
|
|
64
63
|
import * as fs from 'node:fs';
|
|
65
|
-
import * as os from 'node:os';
|
|
66
64
|
import * as path from 'node:path';
|
|
67
65
|
import { spawnSync } from 'node:child_process';
|
|
68
66
|
import process from 'node:process';
|
|
69
67
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
70
68
|
|
|
71
|
-
import * as installed_lock from '../_lib/installed_lock.js';
|
|
72
69
|
import * as cli_wrapper from '../_lib/cli_wrapper.js';
|
|
73
|
-
import * as user_global_paths from '../_lib/user_global_paths.js';
|
|
74
70
|
import * as sync_gitignore from '../sync_gitignore.js';
|
|
75
71
|
|
|
76
72
|
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
|
@@ -149,103 +145,30 @@ const CONSUMER_BRIDGE_MARKER_RELPATH = path.join('agents', '.event4u-bridge.yml'
|
|
|
149
145
|
*/
|
|
150
146
|
const SRC_MARKER_DIR = '.agent-src.uncondensed';
|
|
151
147
|
|
|
152
|
-
/** `Path.resolve()` — absolute, symlink-resolved where possible. */
|
|
153
|
-
function resolvePath(p: string): string {
|
|
154
|
-
try {
|
|
155
|
-
return fs.realpathSync(path.resolve(p));
|
|
156
|
-
} catch {
|
|
157
|
-
return path.resolve(p);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function _format_global_root_for_marker(global_root: string): string {
|
|
162
|
-
const home = resolvePath(os.homedir());
|
|
163
|
-
const resolved = resolvePath(global_root);
|
|
164
|
-
const rel = path.relative(home, resolved);
|
|
165
|
-
if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
166
|
-
return global_root;
|
|
167
|
-
}
|
|
168
|
-
return `~/${rel.split(path.sep).join('/')}`;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/** `datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")`. */
|
|
172
|
-
function utcStamp(now?: Date): string {
|
|
173
|
-
const d = now ?? new Date();
|
|
174
|
-
const pad = (n: number, w = 2): string => String(n).padStart(w, '0');
|
|
175
|
-
return (
|
|
176
|
-
`${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}` +
|
|
177
|
-
`T${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}Z`
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function mkdirp(p: string): void {
|
|
182
|
-
fs.mkdirSync(p, { recursive: true });
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** `tempfile.mkstemp` + write + `os.chmod(0o644)` + `os.replace` (atomic). */
|
|
186
|
-
function atomicWrite0644(target: string, body: string, prefix: string): void {
|
|
187
|
-
const dir = path.dirname(target);
|
|
188
|
-
const tmpName = path.join(
|
|
189
|
-
dir,
|
|
190
|
-
`${prefix}${process.pid}.${crypto.randomBytes(6).toString('hex')}.yml.tmp`,
|
|
191
|
-
);
|
|
192
|
-
let fd: number | null = null;
|
|
193
|
-
try {
|
|
194
|
-
fd = fs.openSync(tmpName, 'wx', 0o644);
|
|
195
|
-
fs.writeFileSync(fd, body, 'utf-8');
|
|
196
|
-
fs.closeSync(fd);
|
|
197
|
-
fd = null;
|
|
198
|
-
fs.chmodSync(tmpName, 0o644);
|
|
199
|
-
fs.renameSync(tmpName, target);
|
|
200
|
-
} catch (err) {
|
|
201
|
-
if (fd !== null) {
|
|
202
|
-
try {
|
|
203
|
-
fs.closeSync(fd);
|
|
204
|
-
} catch {
|
|
205
|
-
/* fd may already be closed */
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
try {
|
|
209
|
-
fs.unlinkSync(tmpName);
|
|
210
|
-
} catch {
|
|
211
|
-
/* best-effort cleanup */
|
|
212
|
-
}
|
|
213
|
-
throw err;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
148
|
|
|
217
149
|
/**
|
|
218
|
-
* Mirrors `install.
|
|
219
|
-
*
|
|
150
|
+
* Mirrors `install._remove_legacy_consumer_bridge_marker` (module-private).
|
|
151
|
+
* The consumer bridge marker was retired (ADR-020 amendment 2026-07-13); the
|
|
152
|
+
* global root is resolved from the well-known `~/.event4u/agent-config` path.
|
|
153
|
+
* `refresh --project` deletes any legacy `agents/.event4u-bridge.yml` a prior
|
|
154
|
+
* install committed. Returns the removed path, or `null` when nothing to do
|
|
155
|
+
* (no marker / dev mode / source repo).
|
|
220
156
|
*/
|
|
221
|
-
function
|
|
157
|
+
function _remove_legacy_consumer_bridge_marker(
|
|
222
158
|
project_root: string,
|
|
223
|
-
installer_version: string,
|
|
224
159
|
env: NodeJS.ProcessEnv | null = null,
|
|
225
|
-
now: Date | null = null,
|
|
226
160
|
): string | null {
|
|
227
161
|
const env_map = env ?? process.env;
|
|
228
162
|
if (env_map['AGENT_CONFIG_DEV_MODE'] === '1') return null;
|
|
229
163
|
if (_isDir(path.join(project_root, SRC_MARKER_DIR))) return null;
|
|
230
164
|
|
|
231
|
-
const global_root_str = _format_global_root_for_marker(
|
|
232
|
-
user_global_paths.event4u_root(env_map),
|
|
233
|
-
);
|
|
234
|
-
const stamp = utcStamp(now ?? undefined);
|
|
235
|
-
|
|
236
|
-
const body =
|
|
237
|
-
'# event4u/agent-config — consumer bridge marker (auto-written).\n' +
|
|
238
|
-
'# Spec: docs/contracts/consumer-bridge.md (event4u-bridge/v1).\n' +
|
|
239
|
-
'# Reader contract: expand ~ against the current $HOME; fail closed\n' +
|
|
240
|
-
'# when global_root is missing on disk; never write back through it.\n' +
|
|
241
|
-
'schema: event4u-bridge/v1\n' +
|
|
242
|
-
`global_root: ${global_root_str}\n` +
|
|
243
|
-
`installed_at: ${stamp}\n` +
|
|
244
|
-
`installer_version: ${installer_version}\n`;
|
|
245
|
-
|
|
246
165
|
const target = path.join(project_root, CONSUMER_BRIDGE_MARKER_RELPATH);
|
|
247
|
-
|
|
248
|
-
|
|
166
|
+
if (!_isFile(target)) return null;
|
|
167
|
+
try {
|
|
168
|
+
fs.rmSync(target);
|
|
169
|
+
} catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
249
172
|
return target;
|
|
250
173
|
}
|
|
251
174
|
|
|
@@ -292,10 +215,10 @@ function _refresh_global(runner: Runner, out: OutSink, err: OutSink): number {
|
|
|
292
215
|
/**
|
|
293
216
|
* True when `project_root` is the agent-config package itself.
|
|
294
217
|
*
|
|
295
|
-
* `
|
|
218
|
+
* `_remove_legacy_consumer_bridge_marker` only guards on a root-level
|
|
296
219
|
* `.agent-src.uncondensed/`, which the monorepo keeps under `packages/<pkg>/`
|
|
297
|
-
* instead — so the narrow guard misses here and would
|
|
298
|
-
*
|
|
220
|
+
* instead — so the narrow guard misses here and would touch the maintainer
|
|
221
|
+
* tree. This broader check (condensed output, packaged
|
|
299
222
|
* source, or the package's own `package.json` name) makes `refresh --project`
|
|
300
223
|
* a no-op in any agent-config checkout. Consumers use dev-mode, not refresh.
|
|
301
224
|
*/
|
|
@@ -350,20 +273,14 @@ function _refresh_project(project_root: string, out: OutSink, err: OutSink): num
|
|
|
350
273
|
return 0;
|
|
351
274
|
}
|
|
352
275
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
'agent-config source repo (or AGENT_CONFIG_DEV_MODE=1). Nothing ' +
|
|
360
|
-
'to scaffold in a maintainer checkout.',
|
|
361
|
-
);
|
|
362
|
-
return 0;
|
|
276
|
+
// Bridge marker retired (ADR-020 amendment 2026-07-13). The global root is
|
|
277
|
+
// resolved from the well-known `~/.event4u/agent-config` path, so there is
|
|
278
|
+
// no per-project marker to scaffold — clean up any legacy one instead.
|
|
279
|
+
const removed = _remove_legacy_consumer_bridge_marker(project_root);
|
|
280
|
+
if (removed !== null) {
|
|
281
|
+
_print(out, `✅ removed legacy bridge marker: ${removed}`);
|
|
363
282
|
}
|
|
364
283
|
|
|
365
|
-
_print(out, `✅ bridge marker: ${marker}`);
|
|
366
|
-
|
|
367
284
|
const overrides = path.join(project_root, 'agents', 'overrides');
|
|
368
285
|
fs.mkdirSync(overrides, { recursive: true });
|
|
369
286
|
const keep = path.join(overrides, 'README.md');
|
|
@@ -372,8 +289,8 @@ function _refresh_project(project_root: string, out: OutSink, err: OutSink): num
|
|
|
372
289
|
keep,
|
|
373
290
|
'# Project overrides\n\n' +
|
|
374
291
|
'Project-local overrides/extensions of shared skills, rules, and ' +
|
|
375
|
-
'commands. The only project-side agent surface ADR-020 permits ' +
|
|
376
|
-
'
|
|
292
|
+
'commands. The only project-side agent surface ADR-020 permits. ' +
|
|
293
|
+
'See the `override-management` skill.\n',
|
|
377
294
|
);
|
|
378
295
|
}
|
|
379
296
|
_print(out, `✅ overrides scaffold: ${overrides}`);
|
|
@@ -543,7 +460,7 @@ export {
|
|
|
543
460
|
_is_source_repo,
|
|
544
461
|
_refresh_project,
|
|
545
462
|
_sync_gitignore,
|
|
546
|
-
|
|
463
|
+
_remove_legacy_consumer_bridge_marker,
|
|
547
464
|
ArgparseExit,
|
|
548
465
|
};
|
|
549
466
|
export type { Args, Runner };
|
|
@@ -254,7 +254,10 @@ const _AGENTS_DIR_MARKERS: readonly string[] = [
|
|
|
254
254
|
'roadmaps',
|
|
255
255
|
'settings/.ai-council.yml',
|
|
256
256
|
'roadmaps-progress.md',
|
|
257
|
-
|
|
257
|
+
// `overrides/` is the guaranteed minimal-consumer surface (ADR-020).
|
|
258
|
+
// Replaced the retired `.event4u-bridge.yml` marker (ADR-020 amendment
|
|
259
|
+
// 2026-07-13) so a bare consumer `agents/` dir stays anchorable.
|
|
260
|
+
'overrides',
|
|
258
261
|
];
|
|
259
262
|
|
|
260
263
|
/**
|
|
@@ -79,14 +79,89 @@ export function claude_plugin_installed(): boolean {
|
|
|
79
79
|
return _plugin_id_recorded(CLAUDE_PLUGIN_ID);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Codex plugin detection richness — presence plus namespace-resistant
|
|
84
|
+
* identity verification.
|
|
85
|
+
*
|
|
86
|
+
* `installed` — a `codex@<marketplace>` key exists in
|
|
87
|
+
* `plugins/installed_plugins.json` (prefix match, any marketplace).
|
|
88
|
+
* `identity_verified` — at least one such marketplace resolves, via the
|
|
89
|
+
* sibling `plugins/known_marketplaces.json` registry
|
|
90
|
+
* (`{ "<marketplace>": { source: { source: "github", repo: "owner/repo" } } }`
|
|
91
|
+
* — the real on-disk shape; `installed_plugins.json` entries themselves
|
|
92
|
+
* carry no repo/owner field), to the official upstream repo
|
|
93
|
+
* (`CODEX_MARKETPLACE_REPO`). When the registry file is absent, unreadable,
|
|
94
|
+
* or its entry has no `source.repo`, identity stays UNVERIFIED (honest
|
|
95
|
+
* fallback: prefix match only) — never inferred from the marketplace
|
|
96
|
+
* name alone, which any squatter can reuse.
|
|
97
|
+
*/
|
|
98
|
+
export interface CodexPluginIdentity {
|
|
99
|
+
readonly installed: boolean;
|
|
100
|
+
readonly identity_verified: boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Marketplace names (the `@<marketplace>` suffix) a plugin id is installed from. */
|
|
104
|
+
function _plugin_marketplaces(plugin_id: string): string[] {
|
|
105
|
+
const p = path.join(claude_config_dir(), 'plugins', 'installed_plugins.json');
|
|
106
|
+
let data: unknown;
|
|
107
|
+
try {
|
|
108
|
+
data = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
109
|
+
} catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
if (data === null || typeof data !== 'object') return [];
|
|
113
|
+
const plugins = (data as { plugins?: unknown }).plugins;
|
|
114
|
+
if (plugins === null || plugins === undefined || typeof plugins !== 'object') return [];
|
|
115
|
+
const prefix = `${plugin_id}@`;
|
|
116
|
+
return Object.keys(plugins as Record<string, unknown>)
|
|
117
|
+
.filter((k) => k.startsWith(prefix))
|
|
118
|
+
.map((k) => k.slice(prefix.length));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** `source.repo` recorded for a marketplace in `known_marketplaces.json`, or null. */
|
|
122
|
+
function _marketplace_source_repo(marketplace: string): string | null {
|
|
123
|
+
const p = path.join(claude_config_dir(), 'plugins', 'known_marketplaces.json');
|
|
124
|
+
let data: unknown;
|
|
125
|
+
try {
|
|
126
|
+
data = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
if (data === null || typeof data !== 'object') return null;
|
|
131
|
+
const entry = (data as Record<string, unknown>)[marketplace];
|
|
132
|
+
if (entry === null || entry === undefined || typeof entry !== 'object') return null;
|
|
133
|
+
const source = (entry as { source?: unknown }).source;
|
|
134
|
+
if (source === null || source === undefined || typeof source !== 'object') return null;
|
|
135
|
+
const repo = (source as { repo?: unknown }).repo;
|
|
136
|
+
return typeof repo === 'string' && repo.trim() !== '' ? repo.trim() : null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Presence + identity of the official OpenAI codex plugin. Read-only:
|
|
141
|
+
* detection never writes under `~/.claude/`. See `CodexPluginIdentity`
|
|
142
|
+
* for the verification contract.
|
|
143
|
+
*/
|
|
144
|
+
export function codex_plugin_identity(): CodexPluginIdentity {
|
|
145
|
+
const marketplaces = _plugin_marketplaces(CODEX_PLUGIN_ID);
|
|
146
|
+
if (marketplaces.length === 0) {
|
|
147
|
+
return { installed: false, identity_verified: false };
|
|
148
|
+
}
|
|
149
|
+
const want = CODEX_MARKETPLACE_REPO.toLowerCase();
|
|
150
|
+
const identity_verified = marketplaces.some(
|
|
151
|
+
(m) => (_marketplace_source_repo(m) ?? '').toLowerCase() === want,
|
|
152
|
+
);
|
|
153
|
+
return { installed: true, identity_verified };
|
|
154
|
+
}
|
|
155
|
+
|
|
82
156
|
/**
|
|
83
157
|
* True when the official OpenAI codex plugin is recorded in Claude Code's
|
|
84
158
|
* `plugins/installed_plugins.json` (any marketplace — matched by the
|
|
85
159
|
* `codex@` id prefix). Unreadable / absent file → false. Read-only:
|
|
86
|
-
* detection never writes under `~/.claude/`.
|
|
160
|
+
* detection never writes under `~/.claude/`. Presence only — for
|
|
161
|
+
* namespace-resistant identity use `codex_plugin_identity()`.
|
|
87
162
|
*/
|
|
88
163
|
export function codex_plugin_installed(): boolean {
|
|
89
|
-
return
|
|
164
|
+
return codex_plugin_identity().installed;
|
|
90
165
|
}
|
|
91
166
|
|
|
92
167
|
/**
|
|
@@ -62,6 +62,10 @@ export interface RecordInput {
|
|
|
62
62
|
first_pass_success?: boolean | undefined;
|
|
63
63
|
/** QUALITY: slice retried on a higher tier after a verification failure. Optional boolean (null = not measured). */
|
|
64
64
|
escalated?: boolean | undefined;
|
|
65
|
+
/** U5 (reliability-measurement): the subagent-type combination this dispatch
|
|
66
|
+
* ran (ordered agent-type ids, e.g. ['implementer','implementer','judge']) —
|
|
67
|
+
* with `outcome`, lets the orchestrator prefer combos that worked. Ids only. */
|
|
68
|
+
agent_combo?: string[] | undefined;
|
|
65
69
|
// Audit-log envelope (sensible defaults for a dispatch record)
|
|
66
70
|
phase?: LinePhase | undefined;
|
|
67
71
|
outcome?: LineOutcome | undefined;
|
|
@@ -173,6 +177,7 @@ export function buildOrchestrationLine(input: RecordInput): BuiltLine {
|
|
|
173
177
|
session_tier: input.session_tier ?? null,
|
|
174
178
|
first_pass_success: input.first_pass_success ?? null,
|
|
175
179
|
escalated: input.escalated ?? null,
|
|
180
|
+
agent_combo: input.agent_combo ?? [],
|
|
176
181
|
};
|
|
177
182
|
|
|
178
183
|
const line: Record<string, unknown> = {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tool_adapter_registry.ts — canonical supported-tools adapter set.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth binding three surfaces that previously drifted
|
|
5
|
+
* independently (road-to-ecosystem-harvest-skill-quality-gates Phase 4,
|
|
6
|
+
* Source AA):
|
|
7
|
+
*
|
|
8
|
+
* 1. the README `## Supported tools` § "Project-installed" matrix,
|
|
9
|
+
* 2. this registry (reviewed, canonical),
|
|
10
|
+
* 3. the generator output roots in `check_generator_output_coverage.ts`.
|
|
11
|
+
*
|
|
12
|
+
* `lint_supported_tools_matrix.ts` fails CI when (1) ≠ (2) in either
|
|
13
|
+
* direction, and when a generator tool tag in (3) has no registry entry
|
|
14
|
+
* covering its root. Adding/removing a supported tool therefore requires
|
|
15
|
+
* touching README + registry (+ generator roots when native) in one commit.
|
|
16
|
+
*/
|
|
17
|
+
import { GENERATOR_OUTPUT_ROOTS } from '../check_generator_output_coverage.js';
|
|
18
|
+
|
|
19
|
+
export interface AdapterEntry {
|
|
20
|
+
/** Tool name exactly as the README matrix first column renders it (without bold markers / parenthetical). */
|
|
21
|
+
readonly tool: string;
|
|
22
|
+
/** How the tool consumes the package. */
|
|
23
|
+
readonly kind: 'native' | 'agents-md' | 'marker';
|
|
24
|
+
/** Generated / written roots this tool reads (repo-relative). Empty for agents-md / marker tools. */
|
|
25
|
+
readonly roots: readonly string[];
|
|
26
|
+
/** Tool tag used by GENERATOR_OUTPUT_ROOTS, when the condense pipeline owns a root for it. */
|
|
27
|
+
readonly generator_tag?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const ADAPTER_REGISTRY: readonly AdapterEntry[] = [
|
|
31
|
+
{
|
|
32
|
+
tool: 'Claude Code',
|
|
33
|
+
kind: 'native',
|
|
34
|
+
roots: ['.claude/rules', '.claude/skills', '.claude/agents', '.claude/personas', '.claude/user-types'],
|
|
35
|
+
generator_tag: 'claude-code',
|
|
36
|
+
},
|
|
37
|
+
{ tool: 'Cursor', kind: 'native', roots: ['.cursor/rules', '.cursor/commands'], generator_tag: 'cursor' },
|
|
38
|
+
{ tool: 'Cline', kind: 'native', roots: ['.clinerules'] },
|
|
39
|
+
{
|
|
40
|
+
tool: 'Windsurf',
|
|
41
|
+
kind: 'native',
|
|
42
|
+
roots: ['.windsurfrules', '.windsurf/rules', '.windsurf/workflows'],
|
|
43
|
+
generator_tag: 'windsurf',
|
|
44
|
+
},
|
|
45
|
+
{ tool: 'Gemini CLI', kind: 'native', roots: ['GEMINI.md'], generator_tag: 'gemini' },
|
|
46
|
+
{ tool: 'GitHub Copilot', kind: 'native', roots: ['.github/copilot-instructions.md'] },
|
|
47
|
+
{ tool: 'Roo Code', kind: 'agents-md', roots: [] },
|
|
48
|
+
{ tool: 'Codex CLI', kind: 'agents-md', roots: [] },
|
|
49
|
+
{ tool: 'Continue.dev', kind: 'agents-md', roots: [] },
|
|
50
|
+
{ tool: 'Aider', kind: 'marker', roots: [] },
|
|
51
|
+
{ tool: 'Augment', kind: 'marker', roots: ['.augment'], generator_tag: 'augment' },
|
|
52
|
+
{ tool: 'Claude Desktop', kind: 'marker', roots: [] },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Extract the tool names from the README's `## Supported tools` §
|
|
57
|
+
* "Project-installed" table. Returns names with bold markers and trailing
|
|
58
|
+
* parentheticals stripped, in table order.
|
|
59
|
+
*/
|
|
60
|
+
export function parse_supported_tools(readme: string): string[] {
|
|
61
|
+
const section = readme.split(/^## Supported tools\s*$/m)[1];
|
|
62
|
+
if (section === undefined) return [];
|
|
63
|
+
// Stop at the next H2/H3 AFTER the first table (the "Plugin-installed" H3).
|
|
64
|
+
const lines = section.split('\n');
|
|
65
|
+
const tools: string[] = [];
|
|
66
|
+
let inTable = false;
|
|
67
|
+
for (const line of lines) {
|
|
68
|
+
const t = line.trim();
|
|
69
|
+
if (/^###\s/.test(t) && inTable) break; // next sub-section after the table
|
|
70
|
+
if (/^\|/.test(t)) {
|
|
71
|
+
inTable = true;
|
|
72
|
+
const cell = t.split('|')[1]?.trim() ?? '';
|
|
73
|
+
if (cell === '' || cell === 'Tool' || /^:?-+:?$/.test(cell)) continue;
|
|
74
|
+
const name = cell
|
|
75
|
+
.replace(/\*\*/g, '')
|
|
76
|
+
.replace(/\s*\(.*\)\s*$/, '')
|
|
77
|
+
.trim();
|
|
78
|
+
if (name && name !== '---') tools.push(name);
|
|
79
|
+
} else if (inTable && t !== '' && !/^\|/.test(t)) {
|
|
80
|
+
// Table ended (legend line etc.).
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return tools;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Compare README matrix ↔ registry ↔ generator roots. Returns human-readable errors; empty = green. */
|
|
88
|
+
export function lint_matrix(readme: string): string[] {
|
|
89
|
+
const errors: string[] = [];
|
|
90
|
+
const readmeTools = parse_supported_tools(readme);
|
|
91
|
+
const readmeSet = new Set(readmeTools);
|
|
92
|
+
const registrySet = new Set(ADAPTER_REGISTRY.map((e) => e.tool));
|
|
93
|
+
|
|
94
|
+
for (const t of registrySet) {
|
|
95
|
+
if (!readmeSet.has(t)) {
|
|
96
|
+
errors.push(`registry tool '${t}' missing from the README Supported-tools matrix`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const t of readmeSet) {
|
|
100
|
+
if (!registrySet.has(t)) {
|
|
101
|
+
errors.push(`README Supported-tools row '${t}' has no ADAPTER_REGISTRY entry`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Generator leg: every tool-tagged generator output root must be claimed
|
|
106
|
+
// by the registry entry carrying that tag.
|
|
107
|
+
const byTag = new Map(ADAPTER_REGISTRY.filter((e) => e.generator_tag).map((e) => [e.generator_tag, e]));
|
|
108
|
+
for (const { root, tool } of GENERATOR_OUTPUT_ROOTS) {
|
|
109
|
+
if (tool === null) continue;
|
|
110
|
+
const entry = byTag.get(tool);
|
|
111
|
+
if (!entry) {
|
|
112
|
+
errors.push(`generator output root '${root}' (tool '${tool}') has no ADAPTER_REGISTRY entry with that generator_tag`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (!entry.roots.includes(root)) {
|
|
116
|
+
errors.push(`generator output root '${root}' (tool '${tool}') is not listed in ADAPTER_REGISTRY entry '${entry.tool}'`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return errors;
|
|
120
|
+
}
|
|
@@ -138,6 +138,12 @@ export class CouncilResponse {
|
|
|
138
138
|
text: string;
|
|
139
139
|
input_tokens: number;
|
|
140
140
|
output_tokens: number;
|
|
141
|
+
// Prompt-cache accounting (Anthropic). `cache_read_input_tokens` bill at
|
|
142
|
+
// ~0.1× input; `cache_creation_input_tokens` at 1.25×/2×. Both default 0
|
|
143
|
+
// (no cache, or a provider that does not report them) so existing callers
|
|
144
|
+
// and the persisted response JSON stay backward-compatible.
|
|
145
|
+
cache_creation_input_tokens: number;
|
|
146
|
+
cache_read_input_tokens: number;
|
|
141
147
|
latency_ms: number;
|
|
142
148
|
error: string | null;
|
|
143
149
|
metadata: Record<string, unknown>;
|
|
@@ -148,6 +154,8 @@ export class CouncilResponse {
|
|
|
148
154
|
text: string;
|
|
149
155
|
input_tokens?: number;
|
|
150
156
|
output_tokens?: number;
|
|
157
|
+
cache_creation_input_tokens?: number;
|
|
158
|
+
cache_read_input_tokens?: number;
|
|
151
159
|
latency_ms?: number;
|
|
152
160
|
error?: string | null;
|
|
153
161
|
metadata?: Record<string, unknown>;
|
|
@@ -157,6 +165,8 @@ export class CouncilResponse {
|
|
|
157
165
|
this.text = opts.text;
|
|
158
166
|
this.input_tokens = opts.input_tokens ?? 0;
|
|
159
167
|
this.output_tokens = opts.output_tokens ?? 0;
|
|
168
|
+
this.cache_creation_input_tokens = opts.cache_creation_input_tokens ?? 0;
|
|
169
|
+
this.cache_read_input_tokens = opts.cache_read_input_tokens ?? 0;
|
|
160
170
|
this.latency_ms = opts.latency_ms ?? 0;
|
|
161
171
|
this.error = opts.error ?? null;
|
|
162
172
|
// Python dataclass uses `field(default_factory=dict)` — each instance
|
|
@@ -278,6 +288,15 @@ interface ApiClientOptions {
|
|
|
278
288
|
model?: string | undefined;
|
|
279
289
|
client?: unknown;
|
|
280
290
|
api_key?: string | null | undefined;
|
|
291
|
+
// Anthropic prompt caching (GA — no beta header). **Explicit opt-in,
|
|
292
|
+
// default OFF** — a caller must pass `true` to send the stable `system` +
|
|
293
|
+
// artefact prefix as cache-controlled blocks (member 2..N in a round, and
|
|
294
|
+
// round-2+ within the 5-min TTL, then read it at ~0.1× input). The council
|
|
295
|
+
// builder opts in via `_construct_api_member`; any other `AnthropicClient`
|
|
296
|
+
// caller (e.g. an API-mode team, a single-shot feature) gets NO caching
|
|
297
|
+
// unless it asks — so a single call never pays the ~1.25× write premium by
|
|
298
|
+
// surprise. Only AnthropicClient consumes this; other providers ignore it.
|
|
299
|
+
enable_prompt_cache?: boolean | undefined;
|
|
281
300
|
}
|
|
282
301
|
|
|
283
302
|
/** Shared ctor-options shape for the CLI clients. */
|
|
@@ -335,10 +354,15 @@ export class AnthropicClient extends ExternalAIClient {
|
|
|
335
354
|
override name = 'anthropic';
|
|
336
355
|
override billable = true;
|
|
337
356
|
private _client: unknown;
|
|
357
|
+
// Prompt caching is explicit opt-in (default OFF) — see
|
|
358
|
+
// ApiClientOptions.enable_prompt_cache. Prevents silent activation (and the
|
|
359
|
+
// write premium) for callers that don't benefit from a shared-prefix cache.
|
|
360
|
+
private _enablePromptCache: boolean;
|
|
338
361
|
|
|
339
362
|
constructor(opts: ApiClientOptions = {}) {
|
|
340
363
|
super();
|
|
341
364
|
this.model = opts.model ?? DEFAULT_ANTHROPIC_MODEL;
|
|
365
|
+
this._enablePromptCache = opts.enable_prompt_cache ?? false;
|
|
342
366
|
if (opts.client !== undefined && opts.client !== null) {
|
|
343
367
|
this._client = opts.client;
|
|
344
368
|
return;
|
|
@@ -381,12 +405,44 @@ export class AnthropicClient extends ExternalAIClient {
|
|
|
381
405
|
if (typeof create !== 'function') {
|
|
382
406
|
throw new TypeError("'messages.create' is not callable");
|
|
383
407
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
408
|
+
// Prompt caching (GA — no beta header). Breakpoints on BOTH the
|
|
409
|
+
// system block (stable across rounds) and the user artefact block
|
|
410
|
+
// (the large system+artefact prefix is byte-identical across
|
|
411
|
+
// members 2..N within a round, so they read it at ~0.1× input).
|
|
412
|
+
// base_system_prompt alone is often below the model's min cacheable
|
|
413
|
+
// prefix and would never cache solo — the artefact block is where
|
|
414
|
+
// the real saving lands. Two breakpoints (≤ the 4 allowed).
|
|
415
|
+
const kwargs: Record<string, unknown> = this._enablePromptCache
|
|
416
|
+
? {
|
|
417
|
+
model: this.model,
|
|
418
|
+
max_tokens,
|
|
419
|
+
system: [
|
|
420
|
+
{
|
|
421
|
+
type: 'text',
|
|
422
|
+
text: system_prompt,
|
|
423
|
+
cache_control: { type: 'ephemeral' },
|
|
424
|
+
},
|
|
425
|
+
],
|
|
426
|
+
messages: [
|
|
427
|
+
{
|
|
428
|
+
role: 'user',
|
|
429
|
+
content: [
|
|
430
|
+
{
|
|
431
|
+
type: 'text',
|
|
432
|
+
text: user_prompt,
|
|
433
|
+
cache_control: { type: 'ephemeral' },
|
|
434
|
+
},
|
|
435
|
+
],
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
}
|
|
439
|
+
: {
|
|
440
|
+
model: this.model,
|
|
441
|
+
max_tokens,
|
|
442
|
+
system: system_prompt,
|
|
443
|
+
messages: [{ role: 'user', content: user_prompt }],
|
|
444
|
+
};
|
|
445
|
+
response = create.call(messages, kwargs);
|
|
390
446
|
} catch (exc) {
|
|
391
447
|
return new CouncilResponse({
|
|
392
448
|
provider: this.name,
|
|
@@ -426,6 +482,12 @@ export class AnthropicClient extends ExternalAIClient {
|
|
|
426
482
|
text,
|
|
427
483
|
input_tokens: usage ? (_getattr(usage, 'input_tokens', 0) as number) : 0,
|
|
428
484
|
output_tokens: usage ? (_getattr(usage, 'output_tokens', 0) as number) : 0,
|
|
485
|
+
cache_creation_input_tokens: usage
|
|
486
|
+
? (_getattr(usage, 'cache_creation_input_tokens', 0) as number)
|
|
487
|
+
: 0,
|
|
488
|
+
cache_read_input_tokens: usage
|
|
489
|
+
? (_getattr(usage, 'cache_read_input_tokens', 0) as number)
|
|
490
|
+
: 0,
|
|
429
491
|
latency_ms,
|
|
430
492
|
});
|
|
431
493
|
}
|
|
@@ -101,6 +101,68 @@ export function estimate_cost(
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
// ── prompt-cache repricing ─────────────────────────────────────────
|
|
105
|
+
//
|
|
106
|
+
// Prompt-cache multipliers derived from the base input rate (Anthropic, GA —
|
|
107
|
+
// no beta header): cache reads bill at ~0.1× input; cache writes at 1.25×
|
|
108
|
+
// (5-min TTL) / 2× (1-h TTL). Kept as CONSTANTS, not columns in
|
|
109
|
+
// `.agent-prices.md`, because that table's row format is byte-frozen (see the
|
|
110
|
+
// file header) and downstream tests pin it.
|
|
111
|
+
export const CACHE_READ_MULTIPLIER = 0.1;
|
|
112
|
+
export const CACHE_WRITE_MULTIPLIER_5M = 1.25;
|
|
113
|
+
export const CACHE_WRITE_MULTIPLIER_1H = 2.0;
|
|
114
|
+
|
|
115
|
+
export interface CacheTokenBreakdown {
|
|
116
|
+
input_tokens: number; // uncached input, billed at the full rate
|
|
117
|
+
cache_read_input_tokens?: number; // billed at CACHE_READ_MULTIPLIER × input
|
|
118
|
+
cache_creation_input_tokens?: number; // billed at the write multiplier
|
|
119
|
+
output_tokens: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Realized cost of a call given OBSERVED cache-token counts (from
|
|
124
|
+
* `CouncilResponse.usage`). Deliberately separate from `estimate_cost`, which
|
|
125
|
+
* stays cache-agnostic (a conservative 0%-cache-hit pre-flight) so the budget
|
|
126
|
+
* gate never under-predicts. This function is the post-hoc actual that surfaces
|
|
127
|
+
* the saving. `ttl` selects the write multiplier (default 5-min).
|
|
128
|
+
*/
|
|
129
|
+
export function reprice_with_cache(
|
|
130
|
+
provider: string,
|
|
131
|
+
model: string,
|
|
132
|
+
tokens: CacheTokenBreakdown,
|
|
133
|
+
table: PriceTable,
|
|
134
|
+
ttl: '5m' | '1h' = '5m',
|
|
135
|
+
): CostEstimate {
|
|
136
|
+
const price = lookup(table, provider, model);
|
|
137
|
+
const read = tokens.cache_read_input_tokens ?? 0;
|
|
138
|
+
const write = tokens.cache_creation_input_tokens ?? 0;
|
|
139
|
+
const totalInput = tokens.input_tokens + read + write;
|
|
140
|
+
if (price === null) {
|
|
141
|
+
return {
|
|
142
|
+
provider,
|
|
143
|
+
model,
|
|
144
|
+
input_tokens: totalInput,
|
|
145
|
+
output_tokens: tokens.output_tokens,
|
|
146
|
+
input_usd: 0.0,
|
|
147
|
+
output_usd: 0.0,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const writeMult = ttl === '1h' ? CACHE_WRITE_MULTIPLIER_1H : CACHE_WRITE_MULTIPLIER_5M;
|
|
151
|
+
const inputUsd =
|
|
152
|
+
(tokens.input_tokens / 1_000_000) * price.input_per_1m_usd +
|
|
153
|
+
(read / 1_000_000) * price.input_per_1m_usd * CACHE_READ_MULTIPLIER +
|
|
154
|
+
(write / 1_000_000) * price.input_per_1m_usd * writeMult;
|
|
155
|
+
const outputUsd = (tokens.output_tokens / 1_000_000) * price.output_per_1m_usd;
|
|
156
|
+
return {
|
|
157
|
+
provider,
|
|
158
|
+
model,
|
|
159
|
+
input_tokens: totalInput,
|
|
160
|
+
output_tokens: tokens.output_tokens,
|
|
161
|
+
input_usd: inputUsd,
|
|
162
|
+
output_usd: outputUsd,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
104
166
|
// ── staleness ──────────────────────────────────────────────────────
|
|
105
167
|
|
|
106
168
|
/** Return the most recent Monday 00:00 UTC as a date (YYYY-MM-DD). */
|