@event4u/agent-config 16.0.0 → 16.2.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +289 -140
- package/CONTRIBUTING.md +9 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +26 -0
- package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
- package/dist/agent-src/commands/challenge-me/closure.md +178 -0
- package/dist/agent-src/commands/challenge-me.md +9 -2
- package/dist/agent-src/commands/council/default.md +25 -5
- package/dist/agent-src/commands/feature/plan.md +28 -1
- package/dist/agent-src/commands/feature/roadmap.md +28 -1
- package/dist/agent-src/commands/implement-ticket.md +27 -0
- package/dist/agent-src/commands/jira-ticket.md +27 -0
- package/dist/agent-src/commands/pr/create.md +29 -0
- package/dist/agent-src/commands/pr/merge.md +60 -9
- package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
- package/dist/agent-src/commands/roadmap/create.md +74 -27
- package/dist/agent-src/commands/roadmap/materialize.md +27 -0
- package/dist/agent-src/commands/roadmap/process-full.md +123 -18
- package/dist/agent-src/commands/team.md +22 -0
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +19 -23
- package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
- package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
- package/dist/agent-src/rules/autonomous-execution.md +15 -8
- package/dist/agent-src/rules/delegation-policy.md +23 -45
- package/dist/agent-src/rules/design-fidelity.md +32 -37
- package/dist/agent-src/rules/evaluator-independence.md +43 -49
- package/dist/agent-src/rules/test-first.md +41 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
- package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
- package/dist/agent-src/skills/database/data/manifest.json +4 -4
- package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
- package/dist/agent-src/skills/design-review/SKILL.md +80 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +30 -5
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
- package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
- package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +23 -0
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +218 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +260 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli-delegate/check_update_banner.js +40 -2
- package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-4XFP2Y3E.js} +1 -1
- package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
- package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
- package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
- package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-7XGBX6ZH.js} +973 -555
- package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
- package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-FP36SWJD.js} +587 -141
- package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-IGD6ERX6.js} +62 -7
- package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-JNMVLWLR.js} +99 -14
- package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
- package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
- package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
- package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
- package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
- package/dist/cli-delegate/{chunk-QJWAUMJW.js → chunk-YJ72UIAK.js} +730 -15
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +985 -831
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +9 -7
- package/dist/cli-delegate/cmd_fleet.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +7 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +4 -2
- package/dist/cli-delegate/cmd_prune.js +10 -8
- package/dist/cli-delegate/cmd_route_audit.js +3 -3
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +4 -4
- package/dist/cli-delegate/cmd_settings_get.js +28 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +10 -8
- package/dist/cli-delegate/cmd_uninstall.js +16 -13
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +12 -10
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +90 -43
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +10 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +8 -6
- package/dist/hooks/dispatch.js +7682 -2772
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudeRuleRewrite.js +14 -3
- package/dist/install/conflict.js +60 -10
- package/dist/install/conflictTracker.js +218 -0
- package/dist/install/fsPrimitives.js +54 -0
- package/dist/install/install.mjs +2200 -1559
- package/dist/install/manifestFiles.js +259 -0
- package/dist/install/preflight.js +14 -2
- package/dist/install/preserve.js +157 -0
- package/dist/install/recordedOwnership.js +132 -0
- package/dist/install/txlog.js +11 -2
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +3066 -1470
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +3 -2
- package/dist/scripts/_lib/fs_atomic.js +167 -0
- package/dist/scripts/_lib/installed_tools.js +460 -0
- package/dist/scripts/_lib/lean_projection_mode.js +3 -2
- package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
- package/dist/server/routes/install.js +8 -0
- package/dist/server/routes/wizard.js +9 -3
- package/dist/server/schemas/settings.js +40 -5
- package/dist/shared/missionExecution.js +97 -0
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/MIGRATION.md +103 -0
- package/docs/contracts/settings-classes.md +28 -7
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/docs/guidelines/design-fidelity-routing.md +29 -0
- package/package.json +4 -4
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +260 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +168 -27
- package/src/config/auto-rule-budget.json +16 -0
- package/src/config/ci-local-parity.yml +36 -5
- package/src/config/continuity-surface.json +23 -2
- package/src/config/gate-coverage.yml +377 -13
- package/src/config/gate-violation-baselines.json +10 -6
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +4 -2
- package/src/config/loop-surfaces.yaml +215 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/platform-anchor.json +3 -2
- package/src/config/release-gate-locality.yml +11 -0
- package/src/config/routing-coverage-seed.json +33 -5
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/install/claudeRuleRewrite.ts +16 -2
- package/src/install/conflict.ts +65 -9
- package/src/install/conflictTracker.ts +299 -0
- package/src/install/fsPrimitives.ts +54 -0
- package/src/install/manifestFiles.ts +312 -0
- package/src/install/preflight.ts +16 -2
- package/src/install/preserve.ts +205 -0
- package/src/install/recordedOwnership.ts +149 -0
- package/src/install/txlog.ts +11 -2
- package/src/install/types.ts +19 -4
- package/src/scripts/_cli/cmd_conformance.ts +88 -15
- package/src/scripts/_cli/cmd_doctor.ts +7 -20
- package/src/scripts/_cli/cmd_route_explain.ts +9 -2
- package/src/scripts/_cli/cmd_settings_get.ts +44 -0
- package/src/scripts/_cli/doctor_execution.ts +173 -0
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_lib/activation_payload.ts +247 -0
- package/src/scripts/_lib/agent_settings.ts +4 -2
- package/src/scripts/_lib/authority_path.ts +102 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cascade_base.ts +94 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/changelog_eras.ts +7 -2
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/continuation_ladder.ts +149 -2
- package/src/scripts/_lib/council_transport.ts +129 -0
- package/src/scripts/_lib/delivery_ready.ts +112 -0
- package/src/scripts/_lib/forge_protection.ts +381 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/json_python_parity.ts +127 -0
- package/src/scripts/_lib/lean_projection_mode.ts +14 -3
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/loop_surfaces.ts +382 -0
- package/src/scripts/_lib/mission_record.ts +190 -0
- package/src/scripts/_lib/obligation_frequency.ts +217 -0
- package/src/scripts/_lib/obligations.ts +513 -0
- package/src/scripts/_lib/orchestration_record.ts +11 -20
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +201 -11
- package/src/scripts/_lib/release_holds.ts +493 -0
- package/src/scripts/_lib/release_migration_gate.ts +184 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -0
- package/src/scripts/_lib/turn_end_refusals.ts +525 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/typed_op_grant.ts +246 -0
- package/src/scripts/_lib/typed_op_watch.ts +185 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/ai_council/config.ts +8 -11
- package/src/scripts/ai_council/fallback_config.ts +5 -3
- package/src/scripts/ai_council/ownership_classes.ts +118 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/ask_block_census.ts +285 -15
- package/src/scripts/before_complete_hook.ts +340 -23
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +866 -0
- package/src/scripts/check_finding_dispositions.ts +22 -3
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +1025 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +47 -5
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_preamble_payload_budget.ts +75 -2
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +568 -0
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_rule_projection_integrity.ts +22 -12
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_test_delta.ts +294 -0
- package/src/scripts/check_test_weakening.ts +299 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +447 -0
- package/src/scripts/compile_hook_manifest.ts +102 -18
- package/src/scripts/council_record_shape.ts +209 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +127 -11
- package/src/scripts/hooks/block_config_weakening.ts +229 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +314 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +1 -2
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +221 -5
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +25 -19
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +97 -2
- package/src/scripts/hooks/exit_codes.ts +128 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +128 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +539 -0
- package/src/scripts/hooks/obligation_settle_hook.ts +328 -0
- package/src/scripts/hooks/one_question_per_ask_hook.ts +25 -4
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +55 -4
- package/src/scripts/hooks/run_continuation_hook.ts +30 -35
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +49 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +1 -2
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +337 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_doctor.ts +85 -0
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +109 -210
- package/src/scripts/janitor.ts +7 -0
- package/src/scripts/lint_decision_classes.ts +464 -0
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +66 -0
- package/src/scripts/lint_major_migration_sections.ts +450 -0
- package/src/scripts/lint_plan_risk_register.ts +47 -3
- package/src/scripts/lint_roadmap_blockers.ts +139 -12
- package/src/scripts/lint_roadmap_producers.ts +202 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_rule_budget.ts +101 -5
- package/src/scripts/measure_skill_ranker_baseline.ts +305 -51
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/release.ts +14 -98
- package/src/scripts/release_drill.ts +267 -1
- package/src/scripts/release_publication.ts +64 -1
- package/src/scripts/report_enforcement_drift.ts +566 -0
- package/src/scripts/report_host_injection_effect.ts +3 -11
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_standing_payload_by_host.ts +26 -152
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/command.schema.json +48 -0
- package/src/scripts/schemas/review-findings.schema.json +4 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/scope_growth.ts +219 -0
- package/src/scripts/self_review_gate.ts +359 -10
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/trigger_eval_grandfather.json +0 -3
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +774 -0
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +62 -7
- package/src/shared/missionExecution.ts +126 -0
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
- package/dist/ui/assets/index-D0jaCRPM.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
- /package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-7RQP4UDH.js} +0 -0
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Hard-gate linter for the roadmap `## Blockers` contract
|
|
4
4
|
* (`templates/roadmaps.md` rule 20 / `roadmap-ci-steps-policy` siblings).
|
|
5
5
|
*
|
|
6
|
-
* Validates, for every active roadmap
|
|
6
|
+
* Validates, for every active roadmap and every parked idea one directory
|
|
7
|
+
* down in `stubs/`:
|
|
7
8
|
*
|
|
8
9
|
* 1. Every `### blocker: <id>` entry declares all five required fields
|
|
9
10
|
* (Status, Owner, Blocks, What to do, Resolved when).
|
|
@@ -22,16 +23,71 @@
|
|
|
22
23
|
* road-to-asked-not-parked exists to stop; without this field a marker
|
|
23
24
|
* cannot distinguish a declined decision from an unoffered one.
|
|
24
25
|
*
|
|
25
|
-
* HARD, not ratcheted, and it can be: no
|
|
26
|
-
* checkbox annotation today, so on the day it ships
|
|
27
|
-
* nothing — the same "no backlog to grandfather"
|
|
28
|
-
* contract above makes.
|
|
29
|
-
*
|
|
26
|
+
* HARD, not ratcheted, and it can be: no file in scope carries a real
|
|
27
|
+
* checkbox annotation pointing at a blocker today, so on the day it ships
|
|
28
|
+
* the rule fires on nothing — the same "no backlog to grandfather"
|
|
29
|
+
* argument the `Class:` contract above makes. Re-measured when `stubs/`
|
|
30
|
+
* entered scope on 2026-09-28: 7 stubs carry checkboxes and 0 of them
|
|
31
|
+
* carry a `blocked-by:` marker, so the rule stays latent there too.
|
|
32
|
+
* `later/`, `archive/` and `skipped/` are outside this gate's glob and
|
|
33
|
+
* are untouched by it; `stubs/` is inside it — see § SCOPE.
|
|
34
|
+
*
|
|
35
|
+
* 5. An entry that declares `- **Ownership:**` declares one of the three
|
|
36
|
+
* OWNER-OWNED classes (`product-owned`, `business-owned`,
|
|
37
|
+
* `destructive-owned`). A technical class there is a judgement call
|
|
38
|
+
* parked in a file instead of closed, which is the shape ADR-268 § 10
|
|
39
|
+
* retires: a technical decision does not become owner-owned because it is
|
|
40
|
+
* hard, so it routes back through the closure pass rather than into
|
|
41
|
+
* `## Blockers`.
|
|
42
|
+
*
|
|
43
|
+
* HARD rather than ratcheted, on the same "no backlog to grandfather"
|
|
44
|
+
* argument the `Class:` contract makes: `Ownership:` is a new opt-in
|
|
45
|
+
* field, so on the day it ships no entry in the tree declares one and the
|
|
46
|
+
* rule fires on nothing.
|
|
47
|
+
*
|
|
48
|
+
* SCOPE — the active tree plus `stubs/`, and deliberately nothing else.
|
|
49
|
+
*
|
|
50
|
+
* Widened from the active tree alone by an owner ruling on 2026-09-28. Before
|
|
51
|
+
* it, a stub's hold was unreachable by every blocker gate: a parked idea is
|
|
52
|
+
* where a hold sits LONGEST, so excluding it exempted exactly the entries most
|
|
53
|
+
* likely to rot. The rejected alternative was to keep the scope and reword the
|
|
54
|
+
* acceptance criterion that named this gate — refused because a criterion
|
|
55
|
+
* edited to match what was achieved stops being an acceptance test.
|
|
56
|
+
*
|
|
57
|
+
* Measured on the tree the widening shipped against: 121 files under `stubs/`
|
|
58
|
+
* (120 stubs plus the directory README), of which 6 carry a `### blocker:`
|
|
59
|
+
* heading and 4 declare one open inside a `## Blockers` section. Zero hard
|
|
60
|
+
* violations, zero additions to the decidability ratchet, zero new
|
|
61
|
+
* active/archived overlaps. So it lands on nothing — the same "no backlog to
|
|
62
|
+
* grandfather" argument the `Class:` and `Ownership:` contracts make.
|
|
63
|
+
*
|
|
64
|
+
* REACH, stated honestly, because the obvious reading of the paragraph above
|
|
65
|
+
* is wrong: this does NOT hold every future stub blocker to the contract. Both
|
|
66
|
+
* scanners require the entry to sit under a `## Blockers` heading, and 2 of
|
|
67
|
+
* today's 6 put it under `## State` instead — so a third of the population is
|
|
68
|
+
* in the glob and still unread. Stub headings are free-form, unlike the
|
|
69
|
+
* template-driven roadmaps this gate was written for, so that is the likely
|
|
70
|
+
* shape rather than an edge case. Widening the glob fixes WHERE the gate looks
|
|
71
|
+
* and not WHAT it can parse; the second half is the sibling defect recorded in
|
|
72
|
+
* `stubs/road-to-blocker-parse-visibility.md`, and it is untouched here.
|
|
73
|
+
*
|
|
74
|
+
* `later/`, `archive/` and `skipped/` stay OUT, and the reason is not symmetry:
|
|
75
|
+
* those record decisions already taken (parked, closed, dropped), so a blocker
|
|
76
|
+
* left unresolved there is history rather than debt. A stub records a decision
|
|
77
|
+
* still to take. The polarity is pinned in both directions by
|
|
78
|
+
* `tests/scripts/lint_roadmap_blockers.test.ts` § the scanned scope, so
|
|
79
|
+
* widening further cannot happen by accident.
|
|
80
|
+
*
|
|
81
|
+
* One consequence worth naming rather than discovering: `_archiveOverlap`
|
|
82
|
+
* defaults its ACTIVE corpus to this glob, so a stub declaring a blocker open
|
|
83
|
+
* that an archived roadmap also declares open now fails. That is the same
|
|
84
|
+
* self-contradiction the assertion already caught one directory up, and it
|
|
85
|
+
* measured 0 on the widening tree.
|
|
30
86
|
*
|
|
31
87
|
* Fenced code blocks are stripped before scanning so a roadmap that shows
|
|
32
88
|
* the `## Blockers` shape as a documentation example is not flagged.
|
|
33
89
|
*
|
|
34
|
-
* Exit codes: 0 = clean /
|
|
90
|
+
* Exit codes: 0 = clean / nothing in scope, 1 = violations.
|
|
35
91
|
*/
|
|
36
92
|
|
|
37
93
|
import * as fs from 'node:fs';
|
|
@@ -45,7 +101,14 @@ const _HERE = fileURLToPath(import.meta.url);
|
|
|
45
101
|
const QUIET = process.argv.slice(2).includes('--quiet');
|
|
46
102
|
|
|
47
103
|
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
48
|
-
|
|
104
|
+
/**
|
|
105
|
+
* The scanned scope, for display. Two plain globs rather than one brace
|
|
106
|
+
* expression: nothing globs with this string, and a `{,stubs/}` empty
|
|
107
|
+
* alternative is bash-only syntax that would mislead anyone who tried.
|
|
108
|
+
*/
|
|
109
|
+
const ROADMAP_GLOB = 'agents/roadmaps/*.md + agents/roadmaps/stubs/*.md';
|
|
110
|
+
/** The one subdirectory inside the glob. See § SCOPE for why only this one. */
|
|
111
|
+
const SCANNED_SUBDIRS: readonly string[] = ['stubs'];
|
|
49
112
|
|
|
50
113
|
const FENCED_CODE_RE = /^[ \t]*```[^\n]*\n[\s\S]*?^[ \t]*```[ \t]*$/gm;
|
|
51
114
|
const BLOCKERS_SECTION_RE = /^##[ \t]+Blockers[ \t]*$/im;
|
|
@@ -107,6 +170,29 @@ const KNOWN_CLASSES: ReadonlySet<string> = new Set(['0', '1', '2', '3']);
|
|
|
107
170
|
/** The classes whose whole claim is that an agent can execute them. */
|
|
108
171
|
const RUNNABLE_CLASSES: ReadonlySet<string> = new Set(['0', '1']);
|
|
109
172
|
|
|
173
|
+
/**
|
|
174
|
+
* The ownership axis, as a blocker may declare it.
|
|
175
|
+
*
|
|
176
|
+
* Only the three owner-owned classes are legal here. A blocker IS the record
|
|
177
|
+
* of a decision the agent correctly did not own; a technical class in that
|
|
178
|
+
* field says the opposite — that something the ownership ladder can close was
|
|
179
|
+
* filed instead. The remaining five ownership classes are deliberately absent
|
|
180
|
+
* rather than listed as "also accepted".
|
|
181
|
+
*/
|
|
182
|
+
const OWNERSHIP_FIELD_RE = /^-[ \t]*\*\*Ownership:\*\*[ \t]*`?([a-z-]+)`?/im;
|
|
183
|
+
const OWNER_OWNED_CLASSES: ReadonlySet<string> = new Set([
|
|
184
|
+
'product-owned',
|
|
185
|
+
'business-owned',
|
|
186
|
+
'destructive-owned',
|
|
187
|
+
]);
|
|
188
|
+
const TECHNICAL_CLASSES: ReadonlySet<string> = new Set([
|
|
189
|
+
'deterministic',
|
|
190
|
+
'reversible-technical',
|
|
191
|
+
'contested-technical',
|
|
192
|
+
'critical-technical',
|
|
193
|
+
'spend-exhaustion',
|
|
194
|
+
]);
|
|
195
|
+
|
|
110
196
|
/**
|
|
111
197
|
* The authored class, or `''` when the entry declares none.
|
|
112
198
|
*
|
|
@@ -248,6 +334,28 @@ function _scanBoth(rawText: string): ScanResult {
|
|
|
248
334
|
});
|
|
249
335
|
}
|
|
250
336
|
}
|
|
337
|
+
const ownership = OWNERSHIP_FIELD_RE.exec(body);
|
|
338
|
+
if (ownership !== null) {
|
|
339
|
+
const declared = ownership[1] as string;
|
|
340
|
+
if (TECHNICAL_CLASSES.has(declared)) {
|
|
341
|
+
violations.push({
|
|
342
|
+
line: _lineAt(text, sectionStart + cur.start),
|
|
343
|
+
message:
|
|
344
|
+
`blocker '${cur.id}' declares ownership '${declared}', which is ` +
|
|
345
|
+
'a technical class — a technical decision does not become ' +
|
|
346
|
+
'owner-owned because it is hard (ADR-268 § 10). Route it back ' +
|
|
347
|
+
'through the closure pass and record the answer as a ' +
|
|
348
|
+
'`## Decisions` row instead of parking it here',
|
|
349
|
+
});
|
|
350
|
+
} else if (!OWNER_OWNED_CLASSES.has(declared)) {
|
|
351
|
+
violations.push({
|
|
352
|
+
line: _lineAt(text, sectionStart + cur.start),
|
|
353
|
+
message:
|
|
354
|
+
`blocker '${cur.id}' declares unknown ownership '${declared}' ` +
|
|
355
|
+
'(expected product-owned, business-owned or destructive-owned)',
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|
|
251
359
|
const gaps = DECIDABILITY_FIELDS.filter(([, re]) => !re.test(body)).map(
|
|
252
360
|
([name]) => name,
|
|
253
361
|
);
|
|
@@ -312,13 +420,14 @@ function _scanBoth(rawText: string): ScanResult {
|
|
|
312
420
|
return { hard: violations, decidability };
|
|
313
421
|
}
|
|
314
422
|
|
|
315
|
-
/** Sorted
|
|
316
|
-
function
|
|
317
|
-
const dir = path.join(REPO_ROOT, 'agents', 'roadmaps');
|
|
423
|
+
/** Sorted `*.md` directly inside `dir` — never recursive. */
|
|
424
|
+
function _globFlat(dir: string): string[] {
|
|
318
425
|
let entries: fs.Dirent[];
|
|
319
426
|
try {
|
|
320
427
|
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
321
428
|
} catch {
|
|
429
|
+
// A missing directory is not an error: `stubs/` is optional, and the
|
|
430
|
+
// dead-scope assertion in `main` is what catches a MOVED root.
|
|
322
431
|
return [];
|
|
323
432
|
}
|
|
324
433
|
const out: string[] = [];
|
|
@@ -330,6 +439,21 @@ function _globRoadmaps(): string[] {
|
|
|
330
439
|
return out.sort();
|
|
331
440
|
}
|
|
332
441
|
|
|
442
|
+
/**
|
|
443
|
+
* The files this gate judges: active roadmaps, plus `stubs/`. See § SCOPE.
|
|
444
|
+
*
|
|
445
|
+
* Takes its root so the scope can be driven from a fixture tree. Asserting the
|
|
446
|
+
* rule against the real tree would only restate today's file list; the test
|
|
447
|
+
* pins which DIRECTORIES are in and which are out, in both directions.
|
|
448
|
+
*/
|
|
449
|
+
function _globRoadmaps(roadmapRoot: string = path.join(REPO_ROOT, 'agents', 'roadmaps')): string[] {
|
|
450
|
+
const out = _globFlat(roadmapRoot);
|
|
451
|
+
for (const sub of SCANNED_SUBDIRS) {
|
|
452
|
+
out.push(..._globFlat(path.join(roadmapRoot, sub)));
|
|
453
|
+
}
|
|
454
|
+
return out;
|
|
455
|
+
}
|
|
456
|
+
|
|
333
457
|
function _relPosix(target: string, root: string): string {
|
|
334
458
|
return path.relative(root, target).split(path.sep).join('/');
|
|
335
459
|
}
|
|
@@ -503,7 +627,7 @@ function main(): number {
|
|
|
503
627
|
const roadmaps = _globRoadmaps();
|
|
504
628
|
if (roadmaps.length === 0) {
|
|
505
629
|
if (!QUIET) {
|
|
506
|
-
process.stdout.write(`✅
|
|
630
|
+
process.stdout.write(`✅ nothing in scope under ${ROADMAP_GLOB}\n`);
|
|
507
631
|
}
|
|
508
632
|
return 0;
|
|
509
633
|
}
|
|
@@ -628,10 +752,13 @@ if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
|
628
752
|
export {
|
|
629
753
|
REPO_ROOT,
|
|
630
754
|
ROADMAP_GLOB,
|
|
755
|
+
_stripFencedCode,
|
|
631
756
|
REQUIRED_FIELDS,
|
|
632
757
|
DECIDABILITY_FIELDS,
|
|
633
758
|
KNOWN_CLASSES,
|
|
634
759
|
RUNNABLE_CLASSES,
|
|
760
|
+
OWNER_OWNED_CLASSES,
|
|
761
|
+
TECHNICAL_CLASSES,
|
|
635
762
|
_blockerClass,
|
|
636
763
|
_hasExecutableSubstance,
|
|
637
764
|
_scan,
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Every roadmap producer ends in closure — mechanically, not by convention.
|
|
4
|
+
*
|
|
5
|
+
* A command that produces a plan and hands it back with open decisions in it
|
|
6
|
+
* has moved those decisions into execution, where meeting one costs a run.
|
|
7
|
+
* The entrance list used to be hard-coded in three command bodies, so the
|
|
8
|
+
* other six producers were simply not in it and nothing said so.
|
|
9
|
+
*
|
|
10
|
+
* The declaration is now the command's own: `produces_roadmap: true` in the
|
|
11
|
+
* frontmatter. This gate reds a command that declares it and does not end in
|
|
12
|
+
* the closure pass, which is the half a hard-coded list could never check.
|
|
13
|
+
*
|
|
14
|
+
* What counts as ending in closure: the body references the closure pass by
|
|
15
|
+
* one of its two names — the `/challenge-me closure` sub-command, or the
|
|
16
|
+
* `closure_scan` detector it runs. Deliberately a reference check rather than
|
|
17
|
+
* a prose check: prose drifts, and a gate that guesses at intent from wording
|
|
18
|
+
* is the detector that gets weakened until it finds nothing.
|
|
19
|
+
*
|
|
20
|
+
* Exit codes: 0 clean · 1 violations · 2 internal error / bad argv.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import * as fs from 'node:fs';
|
|
24
|
+
import * as path from 'node:path';
|
|
25
|
+
import process from 'node:process';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
|
|
28
|
+
import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
|
|
29
|
+
|
|
30
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
31
|
+
const _PROG = 'lint_roadmap_producers';
|
|
32
|
+
|
|
33
|
+
/** The frontmatter declaration a producer carries. */
|
|
34
|
+
export const DECLARATION_RE = /^produces_roadmap:\s*true\s*$/m;
|
|
35
|
+
|
|
36
|
+
/** Either name of the closure pass discharges the obligation. */
|
|
37
|
+
export const CLOSURE_REFS: readonly RegExp[] = [
|
|
38
|
+
/\/challenge-me\s+closure/,
|
|
39
|
+
/challenge-me\/closure/,
|
|
40
|
+
/\bclosure_scan\b/,
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
export interface Violation {
|
|
44
|
+
readonly file: string;
|
|
45
|
+
readonly reason: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function _frontmatter(text: string): string {
|
|
49
|
+
if (!text.startsWith('---')) return '';
|
|
50
|
+
const end = text.indexOf('\n---', 3);
|
|
51
|
+
return end < 0 ? '' : text.slice(0, end);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function declaresProducer(text: string): boolean {
|
|
55
|
+
return DECLARATION_RE.test(_frontmatter(text));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function endsInClosure(text: string): boolean {
|
|
59
|
+
return CLOSURE_REFS.some((re) => re.test(text));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function checkFile(rel: string, text: string): Violation[] {
|
|
63
|
+
if (!declaresProducer(text)) return [];
|
|
64
|
+
if (endsInClosure(text)) return [];
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
file: rel,
|
|
68
|
+
reason:
|
|
69
|
+
'declares `produces_roadmap: true` and does not end in the closure pass — ' +
|
|
70
|
+
'a producer hands back an execution contract, not a plan with open decisions ' +
|
|
71
|
+
'in it. Reference `/challenge-me closure` (or the `closure_scan` detector) ' +
|
|
72
|
+
'as the command’s last step.',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function _walk(dir: string, out: string[]): void {
|
|
78
|
+
let entries: fs.Dirent[];
|
|
79
|
+
try {
|
|
80
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
81
|
+
} catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
85
|
+
const full = path.join(dir, e.name);
|
|
86
|
+
if (e.isDirectory()) _walk(full, out);
|
|
87
|
+
else if (e.isFile() && e.name === 'command.md') out.push(full);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function listCommands(root: string): string[] {
|
|
92
|
+
const out: string[] = [];
|
|
93
|
+
_walk(root, out);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function _repoRoot(): string {
|
|
98
|
+
return path.resolve(path.dirname(_HERE), '..', '..');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function _usage(): string {
|
|
102
|
+
return (
|
|
103
|
+
`usage: ${_PROG} [-h] [--quiet] [--json] [--self-test]\n\n` +
|
|
104
|
+
`Every command declaring \`produces_roadmap: true\` ends in the closure pass.\n`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function main(argv?: readonly string[]): number {
|
|
109
|
+
const args = argv ?? process.argv.slice(2);
|
|
110
|
+
let quiet = false;
|
|
111
|
+
let json = false;
|
|
112
|
+
let selfTest = false;
|
|
113
|
+
const unknown: string[] = [];
|
|
114
|
+
for (const a of args) {
|
|
115
|
+
if (a === '-h' || a === '--help') {
|
|
116
|
+
process.stdout.write(_usage());
|
|
117
|
+
return 0;
|
|
118
|
+
} else if (a === '--quiet') quiet = true;
|
|
119
|
+
else if (a === '--json') json = true;
|
|
120
|
+
else if (a === '--self-test') selfTest = true;
|
|
121
|
+
else unknown.push(a);
|
|
122
|
+
}
|
|
123
|
+
if (unknown.length) {
|
|
124
|
+
process.stderr.write(`${_usage()}${_PROG}: error: unrecognized arguments: ${unknown.join(' ')}\n`);
|
|
125
|
+
return 2;
|
|
126
|
+
}
|
|
127
|
+
if (selfTest) return _selfTest();
|
|
128
|
+
|
|
129
|
+
const repo = _repoRoot();
|
|
130
|
+
const root = path.join(repo, 'src', 'domains');
|
|
131
|
+
const files = listCommands(root);
|
|
132
|
+
const producers = files.filter((f) => declaresProducer(fs.readFileSync(f, 'utf-8')));
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// The corpus is the DECLARED producers, not every command: a tree where
|
|
136
|
+
// nobody declares the key is a tree where the declaration was lost, and
|
|
137
|
+
// that is exactly the silent-disarm this assertion exists to catch.
|
|
138
|
+
assertScanned({
|
|
139
|
+
gate: _PROG,
|
|
140
|
+
scanned: producers.length,
|
|
141
|
+
units: 'roadmap producer(s)',
|
|
142
|
+
roots: ['src/domains'],
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
if (e instanceof DeadScopeError) {
|
|
146
|
+
process.stderr.write(`❌ ${e.message}\n`);
|
|
147
|
+
return 2;
|
|
148
|
+
}
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const violations: Violation[] = [];
|
|
153
|
+
for (const f of producers) {
|
|
154
|
+
violations.push(...checkFile(path.relative(repo, f), fs.readFileSync(f, 'utf-8')));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (json) {
|
|
158
|
+
process.stdout.write(JSON.stringify(violations, null, 2) + '\n');
|
|
159
|
+
return violations.length ? 1 : 0;
|
|
160
|
+
}
|
|
161
|
+
if (violations.length) {
|
|
162
|
+
process.stderr.write(`❌ ${_PROG}: ${violations.length} producer(s) do not end in closure\n`);
|
|
163
|
+
for (const v of violations) process.stderr.write(` ${v.file} — ${v.reason}\n`);
|
|
164
|
+
return 1;
|
|
165
|
+
}
|
|
166
|
+
if (!quiet) {
|
|
167
|
+
process.stdout.write(
|
|
168
|
+
`✅ ${_PROG}: ${producers.length} roadmap producer(s), all ending in closure\n`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Both directions in-process: a producer without closure reds, one with it does not. */
|
|
175
|
+
function _selfTest(): number {
|
|
176
|
+
const withClosure = '---\nname: x\nproduces_roadmap: true\n---\n\nRun `/challenge-me closure`.\n';
|
|
177
|
+
const without = '---\nname: x\nproduces_roadmap: true\n---\n\nHand the plan back.\n';
|
|
178
|
+
const notAProducer = '---\nname: x\n---\n\nHand the plan back.\n';
|
|
179
|
+
const failures: string[] = [];
|
|
180
|
+
if (checkFile('a.md', without).length === 0) failures.push('a producer without closure did not red');
|
|
181
|
+
if (checkFile('b.md', withClosure).length !== 0) failures.push('a producer with closure red');
|
|
182
|
+
if (checkFile('c.md', notAProducer).length !== 0) failures.push('a non-producer was judged');
|
|
183
|
+
if (failures.length) {
|
|
184
|
+
for (const f of failures) process.stderr.write(`❌ ${_PROG} --self-test: ${f}\n`);
|
|
185
|
+
return 1;
|
|
186
|
+
}
|
|
187
|
+
process.stdout.write(`✅ ${_PROG} --self-test: both directions hold\n`);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function _isCliEntry(): boolean {
|
|
192
|
+
if (!process.argv[1]) return false;
|
|
193
|
+
try {
|
|
194
|
+
return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
195
|
+
} catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (_isCliEntry() || process.argv[1] === _HERE) {
|
|
201
|
+
process.exitCode = main();
|
|
202
|
+
}
|
|
@@ -69,6 +69,22 @@ export interface SkillPrompt {
|
|
|
69
69
|
readonly kind: PromptKind;
|
|
70
70
|
readonly recommended_for_user_types: readonly string[];
|
|
71
71
|
readonly user_type_match: UserTypeMatch;
|
|
72
|
+
/**
|
|
73
|
+
* Declared parameters, from the frontmatter `inputs:` block.
|
|
74
|
+
*
|
|
75
|
+
* Empty for every artifact that declares none, which is the whole corpus
|
|
76
|
+
* today — so `arguments: []` on the wire stays the behaviour for an
|
|
77
|
+
* undeclared prompt rather than becoming a special case
|
|
78
|
+
* (road-to-an-invocation-contract-that-reaches-the-wire 3.2).
|
|
79
|
+
*/
|
|
80
|
+
readonly inputs: readonly PromptInput[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** One declared parameter, reduced to what the MCP `arguments` shape carries. */
|
|
84
|
+
export interface PromptInput {
|
|
85
|
+
readonly name: string;
|
|
86
|
+
readonly description: string;
|
|
87
|
+
readonly required: boolean;
|
|
72
88
|
}
|
|
73
89
|
|
|
74
90
|
/** Walk up from this file to the repo root (parent of `scripts/`). */
|
|
@@ -92,6 +108,124 @@ export function _project_root(): string {
|
|
|
92
108
|
* Avoids a YAML dependency for Phase 1; the frontmatter shape is
|
|
93
109
|
* enforced by `task lint-skills` upstream.
|
|
94
110
|
*/
|
|
111
|
+
/** The raw frontmatter block of a document, or `''` when it has none. */
|
|
112
|
+
export function _frontmatter_text(text: string): string {
|
|
113
|
+
if (!text.startsWith('---\n')) return '';
|
|
114
|
+
const parts = _splitMax(text, '---\n', 2);
|
|
115
|
+
return parts.length < 3 ? '' : (parts[1] as string);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Parse the frontmatter `inputs:` block out of raw frontmatter text.
|
|
120
|
+
*
|
|
121
|
+
* WHY THIS EXISTS RATHER THAN A YAML CALL. `_strip_frontmatter` is a flat
|
|
122
|
+
* `key: value` line scanner and cannot represent a nested list — `inputs:`
|
|
123
|
+
* would land as an empty string and its `- name: x` lines as stray keys. The
|
|
124
|
+
* MCP server is deliberately stdlib-only and is bundled for the wire, so
|
|
125
|
+
* pulling a YAML parser in to read one optional block would pay a dependency
|
|
126
|
+
* on every install for a block almost nothing declares yet.
|
|
127
|
+
*
|
|
128
|
+
* IT READS ONE SHAPE AND REFUSES THE REST. Accepted:
|
|
129
|
+
*
|
|
130
|
+
* inputs:
|
|
131
|
+
* - name: target
|
|
132
|
+
* type: string
|
|
133
|
+
* required: true
|
|
134
|
+
* description: What to act on.
|
|
135
|
+
*
|
|
136
|
+
* Refused, by yielding NOTHING for the whole block: the flow form
|
|
137
|
+
* (`inputs: [{name: a}]`), a block scalar (`description: >`), and any nested
|
|
138
|
+
* mapping under an item key. Refusing is not silent — `check_inputs_parity`
|
|
139
|
+
* compares this reader against a real YAML parse for every declaring artifact
|
|
140
|
+
* and FAILS the build on any difference, so an unsupported form is a red gate
|
|
141
|
+
* with a named remedy rather than a wrong argument on the wire.
|
|
142
|
+
*
|
|
143
|
+
* That gate is the answer to the defect an independent review found here: the
|
|
144
|
+
* key scan used to run at any depth, so a `default:` MAPPING whose first child
|
|
145
|
+
* was `name:` overwrote the parameter's own name and the server offered a host
|
|
146
|
+
* an argument that did not exist. The header promised "no guessed input" while
|
|
147
|
+
* the code guessed. Depth is now tracked, and where this reader cannot be sure
|
|
148
|
+
* it declines and the parity gate makes the decline visible.
|
|
149
|
+
*/
|
|
150
|
+
export function _parse_inputs(fm: string): PromptInput[] {
|
|
151
|
+
const lines = fm.split('\n');
|
|
152
|
+
let i = lines.findIndex((l) => /^inputs:/.test(l));
|
|
153
|
+
if (i === -1) return [];
|
|
154
|
+
// The flow form carries its payload on the `inputs:` line itself. This
|
|
155
|
+
// reader does not parse it; the parity gate turns that into a failure.
|
|
156
|
+
if (!/^inputs:\s*$/.test(lines[i] as string)) return [];
|
|
157
|
+
|
|
158
|
+
const out: PromptInput[] = [];
|
|
159
|
+
let current: { name?: string; description?: string; required?: boolean } | null = null;
|
|
160
|
+
/** Indent of the key lines belonging to the item being read. */
|
|
161
|
+
let keyIndent: number | null = null;
|
|
162
|
+
let refused = false;
|
|
163
|
+
|
|
164
|
+
const flush = (): void => {
|
|
165
|
+
if (current?.name !== undefined) {
|
|
166
|
+
out.push({
|
|
167
|
+
name: current.name,
|
|
168
|
+
description: current.description ?? '',
|
|
169
|
+
required: current.required === true,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
current = null;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const clean = (raw: string): string => {
|
|
176
|
+
const v = raw.trim();
|
|
177
|
+
// An unquoted trailing comment is not part of the value — the same strip
|
|
178
|
+
// `_strip_frontmatter` applies, kept consistent deliberately.
|
|
179
|
+
const hashed = /^(?!["'])([^#]*?)\s+#.*$/.exec(v);
|
|
180
|
+
return _stripQuotes((hashed === null ? v : (hashed[1] ?? '')).trim());
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
for (i += 1; i < lines.length && !refused; i += 1) {
|
|
184
|
+
const line = lines[i] as string;
|
|
185
|
+
if (line.trim() === '') continue;
|
|
186
|
+
// A comment at any column is not block content and does not end the block.
|
|
187
|
+
if (/^\s*#/.test(line)) continue;
|
|
188
|
+
// A non-indented line ends the block.
|
|
189
|
+
if (!/^\s/.test(line)) break;
|
|
190
|
+
|
|
191
|
+
const indent = (/^(\s*)/.exec(line) as RegExpExecArray)[1]!.replace(/\t/g, ' ').length;
|
|
192
|
+
|
|
193
|
+
const item = /^\s*-\s+([A-Za-z_]\w*):\s*(.*)$/.exec(line);
|
|
194
|
+
if (item !== null) {
|
|
195
|
+
flush();
|
|
196
|
+
current = {};
|
|
197
|
+
keyIndent = line.indexOf('-') + 2;
|
|
198
|
+
if (item[1] === 'name') current.name = clean(item[2] ?? '');
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const kv = /^\s+([A-Za-z_]\w*):\s*(.*)$/.exec(line);
|
|
203
|
+
if (kv === null || current === null || keyIndent === null) continue;
|
|
204
|
+
// Deeper than the item's own keys: a nested mapping or sequence this
|
|
205
|
+
// reader does not model. Decline the whole block rather than absorb it.
|
|
206
|
+
if (indent > keyIndent) {
|
|
207
|
+
refused = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
const key = kv[1] as string;
|
|
211
|
+
const rawValue = (kv[2] ?? '').trim();
|
|
212
|
+
// A block scalar or an empty value means the real content is on the
|
|
213
|
+
// following lines, which this reader does not join.
|
|
214
|
+
if (rawValue === '' || rawValue === '>' || rawValue === '|') {
|
|
215
|
+
refused = true;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
const value = clean(rawValue);
|
|
219
|
+
if (key === 'name') current.name = value;
|
|
220
|
+
else if (key === 'description') current.description = value;
|
|
221
|
+
else if (key === 'required') current.required = value.toLowerCase() === 'true';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (refused) return [];
|
|
225
|
+
flush();
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
|
|
95
229
|
export function _strip_frontmatter(text: string): [Record<string, string>, string] {
|
|
96
230
|
if (!text.startsWith('---\n')) {
|
|
97
231
|
return [{}, text];
|
|
@@ -365,6 +499,7 @@ function _load_file(p: string, kind: PromptKind, fallback_name: string): SkillPr
|
|
|
365
499
|
kind,
|
|
366
500
|
recommended_for_user_types: _parse_inline_array(meta.recommended_for_user_types ?? ''),
|
|
367
501
|
user_type_match: '',
|
|
502
|
+
inputs: _parse_inputs(_frontmatter_text(text)),
|
|
368
503
|
};
|
|
369
504
|
}
|
|
370
505
|
|
|
@@ -548,7 +683,13 @@ export function to_mcp_prompt_meta(prompt: SkillPrompt): Record<string, unknown>
|
|
|
548
683
|
name: wire,
|
|
549
684
|
title: prompt.name,
|
|
550
685
|
description: prompt.description,
|
|
551
|
-
|
|
686
|
+
// Derived from the declaration, never invented. An artifact that
|
|
687
|
+
// declares nothing still serves `[]` — see `_parse_inputs`.
|
|
688
|
+
arguments: prompt.inputs.map((i) => ({
|
|
689
|
+
name: i.name,
|
|
690
|
+
description: i.description,
|
|
691
|
+
required: i.required,
|
|
692
|
+
})),
|
|
552
693
|
_meta: meta,
|
|
553
694
|
};
|
|
554
695
|
}
|