@event4u/agent-config 11.0.0 → 12.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 +173 -229
- package/agents/templates/.ai-council.yml.example +46 -3
- package/dist/agent-src/commands/agent-handoff.md +0 -1
- package/dist/agent-src/commands/agent-status.md +0 -1
- package/dist/agent-src/commands/agents/audit.md +0 -1
- package/dist/agent-src/commands/agents/init.md +0 -1
- package/dist/agent-src/commands/agents/optimize.md +0 -1
- package/dist/agent-src/commands/agents/user/accept.md +0 -1
- package/dist/agent-src/commands/agents/user/delete.md +0 -1
- package/dist/agent-src/commands/agents/user/init.md +0 -1
- package/dist/agent-src/commands/agents/user/review.md +0 -1
- package/dist/agent-src/commands/agents/user/show.md +0 -1
- package/dist/agent-src/commands/agents/user/update.md +0 -1
- package/dist/agent-src/commands/agents/user.md +0 -1
- package/dist/agent-src/commands/agents.md +0 -1
- package/dist/agent-src/commands/analytics/prune.md +0 -1
- package/dist/agent-src/commands/analytics/show.md +0 -1
- package/dist/agent-src/commands/analytics.md +0 -1
- package/dist/agent-src/commands/analyze/conformance.md +0 -1
- package/dist/agent-src/commands/analyze/decision.md +0 -1
- package/dist/agent-src/commands/analyze/inbox.md +0 -1
- package/dist/agent-src/commands/analyze/incident.md +0 -1
- package/dist/agent-src/commands/analyze/near-miss.md +0 -1
- package/dist/agent-src/commands/analyze/postmortem.md +0 -1
- package/dist/agent-src/commands/analyze/premortem.md +0 -1
- package/dist/agent-src/commands/analyze/reference-repo.md +0 -1
- package/dist/agent-src/commands/analyze.md +0 -1
- package/dist/agent-src/commands/brand/identity.md +0 -1
- package/dist/agent-src/commands/brand/review.md +0 -1
- package/dist/agent-src/commands/brand/strategy.md +0 -1
- package/dist/agent-src/commands/brand/tokens.md +0 -1
- package/dist/agent-src/commands/brand/voice.md +0 -1
- package/dist/agent-src/commands/brand.md +0 -1
- package/dist/agent-src/commands/bug/fix.md +0 -1
- package/dist/agent-src/commands/bug/investigate.md +0 -1
- package/dist/agent-src/commands/bug.md +0 -1
- package/dist/agent-src/commands/challenge-me/vision.md +0 -1
- package/dist/agent-src/commands/challenge-me/with-docs.md +0 -1
- package/dist/agent-src/commands/challenge-me.md +0 -1
- package/dist/agent-src/commands/chat-history/import.md +0 -1
- package/dist/agent-src/commands/chat-history.md +0 -1
- package/dist/agent-src/commands/check-current-md.md +0 -1
- package/dist/agent-src/commands/commit/in-chunks.md +0 -1
- package/dist/agent-src/commands/commit.md +0 -1
- package/dist/agent-src/commands/condense.md +0 -1
- package/dist/agent-src/commands/context/create.md +0 -1
- package/dist/agent-src/commands/context/refactor.md +0 -1
- package/dist/agent-src/commands/context.md +0 -1
- package/dist/agent-src/commands/contribution-precheck.md +0 -1
- package/dist/agent-src/commands/cost/profile.md +0 -1
- package/dist/agent-src/commands/cost/report.md +0 -1
- package/dist/agent-src/commands/cost.md +0 -1
- package/dist/agent-src/commands/council/analysis.md +0 -1
- package/dist/agent-src/commands/council/debate.md +0 -1
- package/dist/agent-src/commands/council/default.md +0 -1
- package/dist/agent-src/commands/council/design.md +0 -1
- package/dist/agent-src/commands/council/optimize.md +0 -1
- package/dist/agent-src/commands/council/pr.md +0 -1
- package/dist/agent-src/commands/council.md +0 -1
- package/dist/agent-src/commands/design-system/capture.md +0 -1
- package/dist/agent-src/commands/design-system/generate.md +0 -1
- package/dist/agent-src/commands/design-system/import.md +0 -1
- package/dist/agent-src/commands/design-system.md +0 -1
- package/dist/agent-src/commands/estimate-ticket.md +0 -1
- package/dist/agent-src/commands/explain-run.md +0 -1
- package/dist/agent-src/commands/feature/dev.md +0 -1
- package/dist/agent-src/commands/feature/explore.md +0 -1
- package/dist/agent-src/commands/feature/plan.md +0 -1
- package/dist/agent-src/commands/feature/refactor.md +0 -1
- package/dist/agent-src/commands/feature/roadmap.md +0 -1
- package/dist/agent-src/commands/feature.md +0 -1
- package/dist/agent-src/commands/fix/ci.md +0 -1
- package/dist/agent-src/commands/fix/comments.md +0 -1
- package/dist/agent-src/commands/fix/portability.md +0 -1
- package/dist/agent-src/commands/fix/pr-comments-loop.md +0 -1
- package/dist/agent-src/commands/fix/pr-comments.md +0 -1
- package/dist/agent-src/commands/fix/quality.md +0 -1
- package/dist/agent-src/commands/fix/refs.md +0 -1
- package/dist/agent-src/commands/fix/route.md +0 -1
- package/dist/agent-src/commands/fix/seeder.md +0 -1
- package/dist/agent-src/commands/fix.md +0 -1
- package/dist/agent-src/commands/ghostwriter/delete.md +0 -1
- package/dist/agent-src/commands/ghostwriter/fetch.md +0 -1
- package/dist/agent-src/commands/ghostwriter/list.md +0 -1
- package/dist/agent-src/commands/ghostwriter/show.md +0 -1
- package/dist/agent-src/commands/ghostwriter/write.md +0 -1
- package/dist/agent-src/commands/ghostwriter.md +0 -1
- package/dist/agent-src/commands/grill-me.md +0 -1
- package/dist/agent-src/commands/humanize.md +0 -1
- package/dist/agent-src/commands/image/analyse.md +0 -1
- package/dist/agent-src/commands/image/create.md +0 -1
- package/dist/agent-src/commands/image/verify.md +0 -1
- package/dist/agent-src/commands/image.md +0 -1
- package/dist/agent-src/commands/implement-ticket.md +0 -1
- package/dist/agent-src/commands/jira-ticket.md +0 -1
- package/dist/agent-src/commands/judge/on-diff.md +0 -1
- package/dist/agent-src/commands/judge/solo.md +0 -1
- package/dist/agent-src/commands/judge/steps.md +0 -1
- package/dist/agent-src/commands/judge.md +0 -1
- package/dist/agent-src/commands/knowledge/cross-repo.md +0 -1
- package/dist/agent-src/commands/knowledge/forget.md +0 -1
- package/dist/agent-src/commands/knowledge/ingest.md +0 -1
- package/dist/agent-src/commands/knowledge/list.md +0 -1
- package/dist/agent-src/commands/knowledge.md +0 -1
- package/dist/agent-src/commands/memory/add.md +0 -1
- package/dist/agent-src/commands/memory/learn-low-impact.md +0 -1
- package/dist/agent-src/commands/memory/load.md +0 -1
- package/dist/agent-src/commands/memory/mine-session.md +0 -1
- package/dist/agent-src/commands/memory/promote.md +0 -1
- package/dist/agent-src/commands/memory/propose.md +0 -1
- package/dist/agent-src/commands/memory.md +0 -1
- package/dist/agent-src/commands/mission/upgrade.md +0 -1
- package/dist/agent-src/commands/mode.md +0 -1
- package/dist/agent-src/commands/module/create.md +0 -1
- package/dist/agent-src/commands/module/explore.md +0 -1
- package/dist/agent-src/commands/module.md +0 -1
- package/dist/agent-src/commands/optimize/agents-dir.md +0 -1
- package/dist/agent-src/commands/optimize/augmentignore.md +0 -1
- package/dist/agent-src/commands/optimize/deep.md +0 -1
- package/dist/agent-src/commands/optimize/project.md +0 -1
- package/dist/agent-src/commands/optimize/prompt.md +0 -1
- package/dist/agent-src/commands/optimize/rtk.md +0 -1
- package/dist/agent-src/commands/optimize/skills.md +0 -1
- package/dist/agent-src/commands/optimize.md +0 -1
- package/dist/agent-src/commands/orchestrate.md +0 -1
- package/dist/agent-src/commands/override/create.md +0 -1
- package/dist/agent-src/commands/override/manage.md +0 -1
- package/dist/agent-src/commands/override.md +0 -1
- package/dist/agent-src/commands/package/reset.md +0 -1
- package/dist/agent-src/commands/package/test.md +0 -1
- package/dist/agent-src/commands/package.md +0 -1
- package/dist/agent-src/commands/post-as/ghostwriter.md +0 -1
- package/dist/agent-src/commands/post-as/me.md +0 -1
- package/dist/agent-src/commands/post-as.md +0 -1
- package/dist/agent-src/commands/pr/create/description-only.md +0 -1
- package/dist/agent-src/commands/pr/create.md +23 -9
- package/dist/agent-src/commands/prediction-pool.md +0 -1
- package/dist/agent-src/commands/prepare-for-review.md +0 -1
- package/dist/agent-src/commands/profile/activate.md +0 -1
- package/dist/agent-src/commands/profile/deactivate.md +0 -1
- package/dist/agent-src/commands/profile/show.md +0 -1
- package/dist/agent-src/commands/profile.md +0 -1
- package/dist/agent-src/commands/project/analyze.md +0 -1
- package/dist/agent-src/commands/project/health.md +0 -1
- package/dist/agent-src/commands/project.md +0 -1
- package/dist/agent-src/commands/refine-ticket.md +0 -1
- package/dist/agent-src/commands/research/deep.md +0 -1
- package/dist/agent-src/commands/research/report.md +0 -1
- package/dist/agent-src/commands/research.md +0 -1
- package/dist/agent-src/commands/review/changes.md +0 -1
- package/dist/agent-src/commands/review/routing.md +0 -1
- package/dist/agent-src/commands/review.md +0 -1
- package/dist/agent-src/commands/roadmap/ai-council.md +0 -1
- package/dist/agent-src/commands/roadmap/create.md +0 -1
- package/dist/agent-src/commands/roadmap/materialize.md +0 -1
- package/dist/agent-src/commands/roadmap/next.md +0 -1
- package/dist/agent-src/commands/roadmap/process-full.md +0 -1
- package/dist/agent-src/commands/roadmap/process-phase.md +0 -1
- package/dist/agent-src/commands/roadmap/process-step.md +0 -1
- package/dist/agent-src/commands/roadmap.md +0 -1
- package/dist/agent-src/commands/rule-compliance-audit.md +0 -1
- package/dist/agent-src/commands/security-audit-config.md +0 -1
- package/dist/agent-src/commands/skill/preview.md +0 -1
- package/dist/agent-src/commands/skill.md +0 -1
- package/dist/agent-src/commands/skills/discover.md +0 -1
- package/dist/agent-src/commands/skills.md +0 -1
- package/dist/agent-src/commands/sync/agent-settings.md +0 -1
- package/dist/agent-src/commands/sync/gitignore/fix.md +0 -1
- package/dist/agent-src/commands/sync/gitignore.md +0 -1
- package/dist/agent-src/commands/sync.md +0 -1
- package/dist/agent-src/commands/tdd/green.md +0 -1
- package/dist/agent-src/commands/tdd/red.md +0 -1
- package/dist/agent-src/commands/tdd/refactor.md +0 -1
- package/dist/agent-src/commands/tdd.md +0 -1
- package/dist/agent-src/commands/team/adversarial.md +0 -1
- package/dist/agent-src/commands/team/delegate.md +0 -1
- package/dist/agent-src/commands/team/review.md +0 -1
- package/dist/agent-src/commands/team/status.md +0 -1
- package/dist/agent-src/commands/team-knowledge/bootstrap.md +0 -1
- package/dist/agent-src/commands/team-knowledge/consolidate.md +0 -1
- package/dist/agent-src/commands/team-knowledge.md +0 -1
- package/dist/agent-src/commands/team.md +0 -1
- package/dist/agent-src/commands/tests/create.md +0 -1
- package/dist/agent-src/commands/tests/e2e-heal.md +0 -1
- package/dist/agent-src/commands/tests/e2e-plan.md +0 -1
- package/dist/agent-src/commands/tests/execute.md +0 -1
- package/dist/agent-src/commands/tests.md +0 -1
- package/dist/agent-src/commands/threat-model.md +0 -1
- package/dist/agent-src/commands/update-form-request-messages.md +0 -1
- package/dist/agent-src/commands/upstream-contribute.md +0 -1
- package/dist/agent-src/commands/video/from-script.md +0 -1
- package/dist/agent-src/commands/video/from-song.md +0 -1
- package/dist/agent-src/commands/video/scene.md +0 -1
- package/dist/agent-src/commands/video/stitch.md +0 -1
- package/dist/agent-src/commands/video/storyboard.md +0 -1
- package/dist/agent-src/commands/video.md +0 -1
- package/dist/agent-src/commands/work.md +0 -1
- package/dist/agent-src/commands/worktree/cleanup.md +0 -1
- package/dist/agent-src/commands/worktree/create.md +0 -1
- package/dist/agent-src/commands/worktree/status.md +0 -1
- package/dist/agent-src/commands/worktree/verify.md +0 -1
- package/dist/agent-src/commands/worktree.md +0 -1
- package/dist/agent-src/contexts/model-recommendations.md +6 -4
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/scripts/roadmap_gates.ts +30 -2
- package/dist/agent-src/scripts/update_roadmap_progress.ts +32 -1
- package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +9 -1
- package/dist/agent-src/skills/pdf-tools/SKILL.md +1 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +7 -7
- package/dist/agent-src/skills/skill-writing/SKILL.md +35 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +41 -3
- package/dist/cli/commands/commands.candidates.test.js +1 -1
- package/dist/cli/commands/commands.candidates.test.js.map +1 -1
- package/dist/cli/commands/commands.js +9 -15
- package/dist/cli/commands/commands.js.map +1 -1
- package/dist/cli/commands/profiles.test.js +7 -7
- package/dist/cli/commands/profiles.test.js.map +1 -1
- package/dist/cli/discovery/loadManifest.js.map +1 -1
- package/dist/cli/main.js +2 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/chunk-K34QTSD5.js +3895 -0
- package/dist/cli-delegate/{chunk-L565YFXH.js → chunk-LKZ5DOYW.js} +557 -297
- package/dist/cli-delegate/{chunk-NN4KW4HZ.js → chunk-O52B4F5S.js} +123 -2338
- package/dist/cli-delegate/cmd_conformance.js +18 -6
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +1 -1
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +1 -1
- package/dist/cli-delegate/cmd_uninstall.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +213 -412
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +2 -2
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +3 -3
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +3 -3
- package/dist/hooks/dispatch.js +2588 -1082
- package/dist/install/install.mjs +744 -482
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +159 -15
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/model_tier.js +9 -0
- package/dist/scripts/_lib/model_tier.js.map +1 -1
- package/dist/scripts/condense.js +50 -0
- package/dist/scripts/condense.js.map +1 -1
- package/docs/MIGRATION.md +21 -1
- package/docs/contracts/settings-classes.md +41 -0
- package/package.json +1 -1
- package/src/agent-src/scripts/roadmap_gates.ts +30 -2
- package/src/agent-src/scripts/update_roadmap_progress.ts +32 -1
- package/src/config/agent-settings.template.yml +34 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +39 -9
- package/src/config/gate-violation-baselines.json +9 -3
- package/src/config/hook-token-budget.json +7 -1
- package/src/config/preamble-payload-budget.json +28 -0
- package/src/scripts/_dispatch.bash +52 -5
- package/src/scripts/_lib/git_common_dir.ts +173 -0
- package/src/scripts/_lib/model_tier.ts +9 -0
- package/src/scripts/_lib/release_highlights.ts +108 -7
- package/src/scripts/_lib/skill_catalogue.ts +862 -0
- package/src/scripts/ai_council/clients.ts +182 -3
- package/src/scripts/ai_council/config.ts +16 -1
- package/src/scripts/ai_council/low_impact.ts +14 -1
- package/src/scripts/ai_council/orchestrator.ts +14 -1
- package/src/scripts/ai_council/transport_resolver.ts +32 -2
- package/src/scripts/audit_command_surface.ts +21 -15
- package/src/scripts/build_catalog_index.ts +1 -1
- package/src/scripts/build_discovery_manifest.ts +30 -34
- package/src/scripts/capture_skill_catalogue.ts +185 -328
- package/src/scripts/check_branch_freshness.ts +217 -62
- package/src/scripts/check_release_published.ts +6 -2
- package/src/scripts/check_release_trunk_sync.ts +18 -2
- package/src/scripts/condense.ts +50 -1
- package/src/scripts/dispatch_r2_reviewer.ts +15 -5
- package/src/scripts/evidence_report.ts +15 -4
- package/src/scripts/gen_discovery_baseline.ts +3 -3
- package/src/scripts/hook_manifest.yaml +67 -13
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/orchestration_record_hook.ts +21 -0
- package/src/scripts/hooks/subagent_ledger_hook.ts +17 -4
- package/src/scripts/hooks/tool_result_bytes_hook.ts +219 -0
- package/src/scripts/hot_context_hook.ts +13 -1
- package/src/scripts/install.ts +129 -0
- package/src/scripts/janitor.ts +77 -2
- package/src/scripts/lint_command_tiers.ts +29 -75
- package/src/scripts/lint_originality.ts +101 -14
- package/src/scripts/lint_plan_risk_register.ts +22 -9
- package/src/scripts/lint_roadmap_blockers.ts +109 -6
- package/src/scripts/lint_scheduled_deprecations.ts +738 -0
- package/src/scripts/migration_status.ts +17 -1
- package/src/scripts/probe_review_binding_drift.ts +731 -0
- package/src/scripts/release.ts +95 -1
- package/src/scripts/schemas/command.schema.json +6 -11
- package/src/scripts/schemas/skill.schema.json +12 -2
- package/src/scripts/schemas/subagent.schema.json +2 -2
- package/src/scripts/session_eol_report.ts +81 -0
- package/src/scripts/skill_linter.ts +82 -2
- package/src/scripts/workspace_doctor.ts +464 -0
- package/src/scripts/worktree_cleanup_check.ts +113 -8
- package/dist/cli-delegate/chunk-AYKQGIBG.js +0 -1594
|
@@ -19,10 +19,24 @@
|
|
|
19
19
|
* frontmatter keys it carries, and its position in the sorted catalogue. This
|
|
20
20
|
* is the host's INPUT and it is fully file-measurable.
|
|
21
21
|
*
|
|
22
|
-
* OBSERVATION
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* OBSERVATION — which entries actually arrived, and how many did not. This
|
|
23
|
+
* side has TWO sources and every record says which one it came from:
|
|
24
|
+
*
|
|
25
|
+
* `self-report` — an agent reading its own context lists the bare names.
|
|
26
|
+
* Only the agent can see this. It is not enforcement and nothing here
|
|
27
|
+
* pretends otherwise. This is the claude-shaped path.
|
|
28
|
+
*
|
|
29
|
+
* `host-event` — the host publishes its own truncation on a machine
|
|
30
|
+
* channel. `codex exec --json` emits an `item.completed` error event whose
|
|
31
|
+
* message states how many entries it dropped, so the count is READ, never
|
|
32
|
+
* transcribed. This is the codex-shaped path and it is deterministic.
|
|
33
|
+
*
|
|
34
|
+
* Hosts do not truncate the same way, so a record also carries a
|
|
35
|
+
* `truncation_mode`: `per-entry` (some entries arrive bare, others full —
|
|
36
|
+
* claude) versus `budget-strip-and-drop` (every description stripped, then N
|
|
37
|
+
* entries dropped wholesale — codex). Pooling the two into one verdict would
|
|
38
|
+
* average two different mechanisms into a number describing neither, so the
|
|
39
|
+
* report is always per host.
|
|
26
40
|
*
|
|
27
41
|
* The join of the two answers the question the census could not: not "how many
|
|
28
42
|
* are bare" but WHICH PROPERTY separates bare from described. That is the
|
|
@@ -33,370 +47,213 @@
|
|
|
33
47
|
* while an earlier one was bare, which no head-N budget explains.
|
|
34
48
|
*
|
|
35
49
|
* PRIVACY BY CONSTRUCTION. An observation record carries skill names, integer
|
|
36
|
-
* counts
|
|
37
|
-
* text, file bodies, paths outside the catalogue, or user
|
|
38
|
-
* shape `domain-safety-pii` § Surface 2 requires of a log
|
|
39
|
-
*
|
|
50
|
+
* counts, a host label and two closed enums. The record type has no field able
|
|
51
|
+
* to hold prompt text, file bodies, paths outside the catalogue, or user
|
|
52
|
+
* content — the same shape `domain-safety-pii` § Surface 2 requires of a log
|
|
53
|
+
* event. The codex path reads a host message and keeps only the integer in it;
|
|
54
|
+
* the message text itself never reaches a record. Do not widen it with a
|
|
55
|
+
* free-form field.
|
|
56
|
+
*
|
|
57
|
+
* A ZERO IS NEVER INFERRED FROM SILENCE. If the host's budget event is absent
|
|
58
|
+
* or unparseable — reworded upstream, or removed — the capture fails loudly
|
|
59
|
+
* rather than recording `dropped: 0`, because a broken parser and a fixed
|
|
60
|
+
* defect would otherwise look identical. Recording a genuine no-truncation run
|
|
61
|
+
* takes an explicit `--assert-no-truncation`.
|
|
40
62
|
*
|
|
41
|
-
* Exit codes: 0 report produced · 1 usage/IO error
|
|
42
|
-
* (a catalogue scan that found nothing must never read as a clean result)
|
|
63
|
+
* Exit codes: 0 report produced · 1 usage/IO error, an empty catalogue root
|
|
64
|
+
* (a catalogue scan that found nothing must never read as a clean result), or
|
|
65
|
+
* an unreadable host observation.
|
|
43
66
|
*/
|
|
44
67
|
|
|
45
68
|
import * as fs from 'node:fs';
|
|
69
|
+
import * as os from 'node:os';
|
|
46
70
|
import * as path from 'node:path';
|
|
47
71
|
import { fileURLToPath } from 'node:url';
|
|
48
72
|
|
|
73
|
+
import {
|
|
74
|
+
DEFAULT_CATALOGUE_ROOTS,
|
|
75
|
+
OBSERVATION_LOG,
|
|
76
|
+
analyzeSelector,
|
|
77
|
+
buildHostEventRecord,
|
|
78
|
+
buildObservationRecord,
|
|
79
|
+
formatPerHostVerdicts,
|
|
80
|
+
formatReport,
|
|
81
|
+
knownHostLimits,
|
|
82
|
+
measureCatalogueVolume,
|
|
83
|
+
parseHostBudgetEvent,
|
|
84
|
+
readObservationLog,
|
|
85
|
+
readProjectedCatalogue,
|
|
86
|
+
type SelectorReport,
|
|
87
|
+
} from './_lib/skill_catalogue.js';
|
|
88
|
+
|
|
89
|
+
// Re-exported so the CLI module stays the one public name for this tool.
|
|
90
|
+
export * from './_lib/skill_catalogue.js';
|
|
91
|
+
|
|
49
92
|
const _HERE = fileURLToPath(import.meta.url);
|
|
50
93
|
const REPO = path.resolve(path.dirname(_HERE), '..', '..');
|
|
51
94
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
/** 1-based position in the alphabetically sorted catalogue. */
|
|
67
|
-
position: number;
|
|
68
|
-
/** Whether the projected SKILL.md declares a `description:`. */
|
|
69
|
-
hasDescription: boolean;
|
|
70
|
-
/** Character length of the declared description; 0 when absent. */
|
|
71
|
-
descriptionLength: number;
|
|
72
|
-
/** Top-level frontmatter keys the entry declares. */
|
|
73
|
-
frontmatterKeys: string[];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface SelectorCandidate {
|
|
77
|
-
/** Stable identifier for the property under test. */
|
|
78
|
-
id: string;
|
|
79
|
-
/** Human-readable statement of what the property is. */
|
|
80
|
-
describes: string;
|
|
81
|
-
/** True when the property's values are disjoint across the two groups. */
|
|
82
|
-
separates: boolean;
|
|
83
|
-
/** Why it does or does not separate, in one line. */
|
|
84
|
-
detail: string;
|
|
95
|
+
function resolveCatalogueRoot(explicit: string | null): string {
|
|
96
|
+
if (explicit) {
|
|
97
|
+
if (!fs.existsSync(explicit)) {
|
|
98
|
+
throw new Error(`catalogue root does not exist: ${explicit}`);
|
|
99
|
+
}
|
|
100
|
+
return explicit;
|
|
101
|
+
}
|
|
102
|
+
for (const candidate of DEFAULT_CATALOGUE_ROOTS) {
|
|
103
|
+
const abs = path.join(REPO, candidate);
|
|
104
|
+
if (fs.existsSync(abs)) return abs;
|
|
105
|
+
}
|
|
106
|
+
throw new Error(
|
|
107
|
+
`no catalogue root found — tried ${DEFAULT_CATALOGUE_ROOTS.join(', ')} under ${REPO}`,
|
|
108
|
+
);
|
|
85
109
|
}
|
|
86
110
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
observedDescribed: string[];
|
|
92
|
-
/** Observed names that the projection does not know. */
|
|
93
|
-
unknownObserved: string[];
|
|
94
|
-
candidates: SelectorCandidate[];
|
|
95
|
-
verdict: 'selector-found' | 'no-selector' | 'insufficient-observation';
|
|
111
|
+
function argValue(flag: string): string | null {
|
|
112
|
+
const index = process.argv.indexOf(flag);
|
|
113
|
+
if (index === -1 || index + 1 >= process.argv.length) return null;
|
|
114
|
+
return process.argv[index + 1]!;
|
|
96
115
|
}
|
|
97
116
|
|
|
98
|
-
/**
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
const end = content.indexOf('\n---', 3);
|
|
102
|
-
if (end === -1) return '';
|
|
103
|
-
return content.slice(3, end);
|
|
117
|
+
/** `~` expanded against the current user's home. */
|
|
118
|
+
function expandHome(p: string): string {
|
|
119
|
+
return p.startsWith('~/') ? path.join(os.homedir(), p.slice(2)) : p;
|
|
104
120
|
}
|
|
105
121
|
|
|
106
122
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* YAML parse would drag a dependency into a measurement tool.
|
|
123
|
+
* `--limits` — publish the per-host picture: what each host was measured to
|
|
124
|
+
* deliver, and whether the observed hosts truncate the same way.
|
|
110
125
|
*/
|
|
111
|
-
function
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
const match = /^([A-Za-z_][A-Za-z0-9_-]*):/.exec(line);
|
|
115
|
-
if (match) keys.push(match[1]!);
|
|
116
|
-
}
|
|
117
|
-
return keys;
|
|
118
|
-
}
|
|
126
|
+
function runLimitsMode(): number {
|
|
127
|
+
const records = readObservationLog(path.join(REPO, OBSERVATION_LOG));
|
|
128
|
+
const limits = knownHostLimits(records);
|
|
119
129
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
* two-character indicator and report `descriptionLength: 2`. That would feed
|
|
126
|
-
* the length-based selector candidate noise, and a length threshold could be
|
|
127
|
-
* reported or refuted on it. Block scalars are therefore folded properly.
|
|
128
|
-
*/
|
|
129
|
-
function descriptionOf(frontmatter: string): string {
|
|
130
|
-
const lines = frontmatter.split('\n');
|
|
131
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
132
|
-
const match = /^description:\s*(.*)$/.exec(lines[i]!);
|
|
133
|
-
if (!match) continue;
|
|
134
|
-
const rest = match[1]!.trim();
|
|
135
|
-
|
|
136
|
-
if (/^[|>][-+]?\d*$/.test(rest)) {
|
|
137
|
-
const body: string[] = [];
|
|
138
|
-
for (let j = i + 1; j < lines.length; j += 1) {
|
|
139
|
-
const line = lines[j]!;
|
|
140
|
-
if (line.trim() === '') {
|
|
141
|
-
body.push('');
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
if (!/^\s/.test(line)) break; // dedented, so the block ended
|
|
145
|
-
body.push(line.trim());
|
|
146
|
-
}
|
|
147
|
-
return body.join(' ').trim();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return rest.replace(/^["']|["']$/g, '');
|
|
130
|
+
if (process.argv.includes('--json')) {
|
|
131
|
+
process.stdout.write(
|
|
132
|
+
`${JSON.stringify({ hosts: [...limits.values()], observations: records.length }, null, 2)}\n`,
|
|
133
|
+
);
|
|
134
|
+
return 0;
|
|
151
135
|
}
|
|
152
|
-
return '';
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Read every `<root>/<name>/SKILL.md` into a catalogue entry, sorted by name —
|
|
157
|
-
* the order a host listing follows and therefore the order a positional
|
|
158
|
-
* hypothesis is measured against.
|
|
159
|
-
*/
|
|
160
|
-
export function readProjectedCatalogue(root: string): CatalogueEntry[] {
|
|
161
|
-
// Membership is decided by "does <name>/SKILL.md resolve", never by
|
|
162
|
-
// `Dirent.isDirectory()`. The host-facing projection is a tree of SYMLINKS
|
|
163
|
-
// into `dist/agent-src/skills/`, and a Dirent for a symlink reports
|
|
164
|
-
// `isDirectory() === false` — that filter silently read 47 of 289 entries
|
|
165
|
-
// and reported the result as a complete catalogue. `existsSync` follows
|
|
166
|
-
// the link, so the scan sees what the host sees.
|
|
167
|
-
const names = fs
|
|
168
|
-
.readdirSync(root)
|
|
169
|
-
.filter((n) => fs.existsSync(path.join(root, n, 'SKILL.md')))
|
|
170
|
-
.sort();
|
|
171
136
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
137
|
+
process.stdout.write(`${formatPerHostVerdicts(records)}\n\n`);
|
|
138
|
+
if (limits.size === 0) {
|
|
139
|
+
process.stdout.write(
|
|
140
|
+
'measured truncations: none.\nOnly a host that publishes its own dropped count yields one; a\nself-reported observation states which entries arrived bare, which is a\nselector question, not a ceiling.\n',
|
|
141
|
+
);
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
process.stdout.write('measured truncations:\n');
|
|
145
|
+
for (const limit of [...limits.values()].sort((a, b) => a.host.localeCompare(b.host))) {
|
|
146
|
+
process.stdout.write(
|
|
147
|
+
` ${limit.host}: dropped ${limit.droppedEntries} entries on ${limit.observedAt}, ` +
|
|
148
|
+
`at a projection of ${limit.projectedVolume}\n`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return 0;
|
|
184
152
|
}
|
|
185
153
|
|
|
186
|
-
/**
|
|
187
|
-
function
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
154
|
+
/** `--volume <host-root>` — the projection half for one host, byte-accurate. */
|
|
155
|
+
function runVolumeMode(rootArg: string): number {
|
|
156
|
+
const root = expandHome(rootArg);
|
|
157
|
+
if (!fs.existsSync(root)) {
|
|
158
|
+
process.stderr.write(`❌ host root does not exist: ${root}\n`);
|
|
159
|
+
return 1;
|
|
160
|
+
}
|
|
161
|
+
const volume = measureCatalogueVolume(argValue('--host') ?? path.basename(root).replace(/^\./, ''), root);
|
|
162
|
+
if (process.argv.includes('--json')) {
|
|
163
|
+
process.stdout.write(`${JSON.stringify(volume, null, 2)}\n`);
|
|
164
|
+
return 0;
|
|
165
|
+
}
|
|
166
|
+
process.stdout.write(
|
|
167
|
+
`host: ${volume.host}\nroot: ${volume.root}\n` +
|
|
168
|
+
`skill entries: ${volume.skillEntries}\ncommand entries: ${volume.commandEntries}\n` +
|
|
169
|
+
`artefacts offered: ${volume.artefacts}\n` +
|
|
170
|
+
`description payload: ${volume.descriptionBytes} bytes\n\n` +
|
|
171
|
+
'This is the PROJECTION half — what the host is offered, not what it delivered.\n',
|
|
172
|
+
);
|
|
173
|
+
return 0;
|
|
194
174
|
}
|
|
195
175
|
|
|
196
176
|
/**
|
|
197
|
-
*
|
|
198
|
-
* any, separates the bare entries from the described ones.
|
|
177
|
+
* `--host-event <file|->` — record what the host itself published.
|
|
199
178
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
* a partial observation would need its own described list, so the caller
|
|
204
|
-
* passes one when it has it.
|
|
179
|
+
* The deterministic path. `-` reads stdin, so the capture composes directly:
|
|
180
|
+
* codex exec --json --skip-git-repo-check "reply with exactly: OK" \
|
|
181
|
+
* | capture_skill_catalogue --host-event - --host codex --host-root ~/.codex
|
|
205
182
|
*/
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// while the same typo in --observed was surfaced.
|
|
220
|
-
const unknownObserved = [
|
|
221
|
-
...new Set([
|
|
222
|
-
...observedBare.filter((n) => !known.has(n)),
|
|
223
|
-
...(observedDescribed ?? []).filter((n) => !known.has(n)),
|
|
224
|
-
]),
|
|
225
|
-
].sort();
|
|
226
|
-
|
|
227
|
-
const base = {
|
|
228
|
-
entriesTotal: projected.length,
|
|
229
|
-
observedBare: [...bare].sort(),
|
|
230
|
-
observedDescribed: [...described].sort(),
|
|
231
|
-
unknownObserved,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
if (bare.length === 0 || described.length === 0) {
|
|
235
|
-
return {
|
|
236
|
-
...base,
|
|
237
|
-
candidates: [],
|
|
238
|
-
verdict: 'insufficient-observation' as const,
|
|
239
|
-
};
|
|
183
|
+
function runHostEventMode(source: string): number {
|
|
184
|
+
const stream =
|
|
185
|
+
source === '-'
|
|
186
|
+
? fs.readFileSync(0, 'utf-8')
|
|
187
|
+
: fs.readFileSync(expandHome(source), 'utf-8');
|
|
188
|
+
|
|
189
|
+
const hostRootArg = argValue('--host-root');
|
|
190
|
+
if (!hostRootArg) {
|
|
191
|
+
process.stderr.write(
|
|
192
|
+
'❌ --host-event requires --host-root <dir> — the dropped count is only\n' +
|
|
193
|
+
' meaningful against the number of artefacts the host was offered.\n',
|
|
194
|
+
);
|
|
195
|
+
return 1;
|
|
240
196
|
}
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// 1. The projection itself — does the entry even declare a description?
|
|
247
|
-
const bareWithDesc = bareEntries.filter((e) => e.hasDescription).length;
|
|
248
|
-
const describedWithoutDesc = describedEntries.filter((e) => !e.hasDescription).length;
|
|
249
|
-
candidates.push({
|
|
250
|
-
id: 'declares-description',
|
|
251
|
-
describes: 'the projected SKILL.md declares a `description:`',
|
|
252
|
-
separates: bareWithDesc === 0 && describedWithoutDesc === 0,
|
|
253
|
-
detail: `${bareWithDesc}/${bareEntries.length} bare entries declare one; ${describedWithoutDesc}/${describedEntries.length} described entries do not`,
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
// 2. The head-N hypothesis the census proposed — falsifiable here.
|
|
257
|
-
const barePositions = bareEntries.map((e) => e.position);
|
|
258
|
-
const describedPositions = describedEntries.map((e) => e.position);
|
|
259
|
-
const positional = Math.max(...describedPositions) < Math.min(...barePositions);
|
|
260
|
-
candidates.push({
|
|
261
|
-
id: 'positional-head',
|
|
262
|
-
describes: 'every described entry sorts before every bare entry (a head-N budget)',
|
|
263
|
-
separates: positional,
|
|
264
|
-
detail: positional
|
|
265
|
-
? `described top out at #${Math.max(...describedPositions)}, bare start at #${Math.min(...barePositions)}`
|
|
266
|
-
: `described reach #${Math.max(...describedPositions)} while bare start at #${Math.min(...barePositions)} — the ranges overlap, so no head-N cut explains this`,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// 3. Description length as a budget proxy.
|
|
270
|
-
const lengthSeparates = rangesAreDisjoint(
|
|
271
|
-
bareEntries.map((e) => e.descriptionLength),
|
|
272
|
-
describedEntries.map((e) => e.descriptionLength),
|
|
273
|
-
);
|
|
274
|
-
candidates.push({
|
|
275
|
-
id: 'description-length',
|
|
276
|
-
describes: 'description length ranges do not overlap between the groups',
|
|
277
|
-
separates: lengthSeparates,
|
|
278
|
-
detail: lengthSeparates
|
|
279
|
-
? 'a length threshold separates the two groups'
|
|
280
|
-
: 'length ranges overlap',
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
// 4. Any frontmatter key whose presence tracks the split exactly.
|
|
284
|
-
const allKeys = new Set<string>();
|
|
285
|
-
for (const entry of projected) for (const key of entry.frontmatterKeys) allKeys.add(key);
|
|
286
|
-
for (const key of [...allKeys].sort()) {
|
|
287
|
-
const bareHas = bareEntries.filter((e) => e.frontmatterKeys.includes(key)).length;
|
|
288
|
-
const describedHas = describedEntries.filter((e) =>
|
|
289
|
-
e.frontmatterKeys.includes(key),
|
|
290
|
-
).length;
|
|
291
|
-
const separates =
|
|
292
|
-
(bareHas === 0 && describedHas === describedEntries.length) ||
|
|
293
|
-
(describedHas === 0 && bareHas === bareEntries.length);
|
|
294
|
-
if (!separates) continue;
|
|
295
|
-
candidates.push({
|
|
296
|
-
id: `frontmatter:${key}`,
|
|
297
|
-
describes: `presence of the \`${key}:\` frontmatter key`,
|
|
298
|
-
separates: true,
|
|
299
|
-
detail: `bare ${bareHas}/${bareEntries.length}, described ${describedHas}/${describedEntries.length}`,
|
|
300
|
-
});
|
|
197
|
+
const host = argValue('--host') ?? 'unknown';
|
|
198
|
+
const volume = measureCatalogueVolume(host, expandHome(hostRootArg));
|
|
199
|
+
if (volume.artefacts === 0) {
|
|
200
|
+
process.stderr.write(`❌ host root ${volume.root} offers no catalogue artefacts\n`);
|
|
201
|
+
return 1;
|
|
301
202
|
}
|
|
302
203
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
host: string;
|
|
317
|
-
entries_total: number;
|
|
318
|
-
bare_count: number;
|
|
319
|
-
described_count: number;
|
|
320
|
-
bare_names: string[];
|
|
321
|
-
verdict: SelectorReport['verdict'];
|
|
322
|
-
separating_candidates: string[];
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
export function buildObservationRecord(
|
|
326
|
-
report: SelectorReport,
|
|
327
|
-
host: string,
|
|
328
|
-
observedAt: string,
|
|
329
|
-
): ObservationRecord {
|
|
330
|
-
return {
|
|
331
|
-
schema: 1,
|
|
332
|
-
observed_at: observedAt,
|
|
333
|
-
host,
|
|
334
|
-
entries_total: report.entriesTotal,
|
|
335
|
-
bare_count: report.observedBare.length,
|
|
336
|
-
described_count: report.observedDescribed.length,
|
|
337
|
-
bare_names: report.observedBare,
|
|
338
|
-
verdict: report.verdict,
|
|
339
|
-
separating_candidates: report.candidates.filter((c) => c.separates).map((c) => c.id),
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
export function formatReport(report: SelectorReport): string {
|
|
344
|
-
const lines: string[] = [];
|
|
345
|
-
lines.push(`catalogue root: ${report.catalogueRoot}`);
|
|
346
|
-
lines.push(`entries: ${report.entriesTotal}`);
|
|
347
|
-
lines.push(
|
|
348
|
-
`observed: ${report.observedBare.length} bare · ${report.observedDescribed.length} described (self-reported)`,
|
|
349
|
-
);
|
|
350
|
-
if (report.unknownObserved.length > 0) {
|
|
351
|
-
lines.push(
|
|
352
|
-
`⚠️ ${report.unknownObserved.length} observed name(s) absent from the projection: ${report.unknownObserved.join(', ')}`,
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
if (report.verdict === 'insufficient-observation') {
|
|
356
|
-
lines.push('');
|
|
357
|
-
lines.push(
|
|
358
|
-
'verdict: insufficient-observation — an observation needs at least one bare AND one described entry to separate anything.',
|
|
204
|
+
const event = parseHostBudgetEvent(stream);
|
|
205
|
+
if (event === null) {
|
|
206
|
+
if (!process.argv.includes('--assert-no-truncation')) {
|
|
207
|
+
process.stderr.write(
|
|
208
|
+
'❌ no parseable skills-budget event in this stream.\n' +
|
|
209
|
+
' That is UNKNOWN, not zero: a reworded or removed host message looks\n' +
|
|
210
|
+
' exactly like a fixed defect. If this run genuinely did not truncate,\n' +
|
|
211
|
+
' say so with --assert-no-truncation.\n',
|
|
212
|
+
);
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
process.stdout.write(
|
|
216
|
+
`host: ${host}\noffered: ${volume.artefacts}\ndropped: 0 (asserted — no budget event in the stream)\n`,
|
|
359
217
|
);
|
|
360
|
-
return
|
|
361
|
-
}
|
|
362
|
-
lines.push('');
|
|
363
|
-
lines.push('selector candidates:');
|
|
364
|
-
for (const candidate of report.candidates) {
|
|
365
|
-
lines.push(` ${candidate.separates ? '✅' : '❌'} ${candidate.id} — ${candidate.describes}`);
|
|
366
|
-
lines.push(` ${candidate.detail}`);
|
|
218
|
+
return 0;
|
|
367
219
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
220
|
+
|
|
221
|
+
process.stdout.write(
|
|
222
|
+
`host: ${host}\nroot: ${volume.root}\n` +
|
|
223
|
+
`artefacts offered: ${volume.artefacts} (${volume.skillEntries} skills + ${volume.commandEntries} commands)\n` +
|
|
224
|
+
`description payload: ${volume.descriptionBytes} bytes\n` +
|
|
225
|
+
`dropped by the host: ${event.droppedCount}\n` +
|
|
226
|
+
`descriptions stripped: ${event.descriptionsStripped ? 'yes — all of them' : 'no'}\n\n` +
|
|
227
|
+
'Source: host-event (read from the host\'s own JSON channel, not self-reported).\n' +
|
|
228
|
+
'No delivered count is printed: the offered figure above is THIS tool\'s\n' +
|
|
229
|
+
'projection and the dropped figure is the host\'s, and a controlled probe\n' +
|
|
230
|
+
'showed they do not share a denominator. Subtracting them would invent a number.\n',
|
|
373
231
|
);
|
|
374
|
-
return lines.join('\n');
|
|
375
|
-
}
|
|
376
232
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (!
|
|
380
|
-
|
|
233
|
+
if (process.argv.includes('--record')) {
|
|
234
|
+
const stampedAt = argValue('--observed-at');
|
|
235
|
+
if (!stampedAt) {
|
|
236
|
+
process.stderr.write('❌ --record requires --observed-at <ISO date>\n');
|
|
237
|
+
return 1;
|
|
381
238
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
239
|
+
const logPath = path.join(REPO, OBSERVATION_LOG);
|
|
240
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
241
|
+
const record = buildHostEventRecord(host, stampedAt, volume.artefacts, event, volume.skillEntries);
|
|
242
|
+
fs.appendFileSync(logPath, `${JSON.stringify(record)}\n`);
|
|
243
|
+
process.stdout.write(`recorded → ${OBSERVATION_LOG}\n`);
|
|
387
244
|
}
|
|
388
|
-
|
|
389
|
-
`no catalogue root found — tried ${DEFAULT_CATALOGUE_ROOTS.join(', ')} under ${REPO}`,
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
function argValue(flag: string): string | null {
|
|
394
|
-
const index = process.argv.indexOf(flag);
|
|
395
|
-
if (index === -1 || index + 1 >= process.argv.length) return null;
|
|
396
|
-
return process.argv[index + 1]!;
|
|
245
|
+
return 0;
|
|
397
246
|
}
|
|
398
247
|
|
|
399
248
|
function main(): number {
|
|
249
|
+
if (process.argv.includes('--limits')) return runLimitsMode();
|
|
250
|
+
|
|
251
|
+
const volumeRoot = argValue('--volume');
|
|
252
|
+
if (volumeRoot) return runVolumeMode(volumeRoot);
|
|
253
|
+
|
|
254
|
+
const hostEvent = argValue('--host-event');
|
|
255
|
+
if (hostEvent) return runHostEventMode(hostEvent);
|
|
256
|
+
|
|
400
257
|
const root = resolveCatalogueRoot(argValue('--catalogue-root'));
|
|
401
258
|
const projected = readProjectedCatalogue(root);
|
|
402
259
|
|