@event4u/agent-config 16.1.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 +237 -248
- package/dist/agent-src/commands/roadmap/process-full.md +1 -1
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- 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 +2 -2
- package/dist/agent-src/skills/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +16 -1
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- 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/ui-component-architect/SKILL.md +23 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -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/{chunk-S3VFXMTM.js → chunk-4XFP2Y3E.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-7XGBX6ZH.js} +471 -387
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-FP36SWJD.js} +432 -144
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-IGD6ERX6.js} +31 -0
- package/dist/cli-delegate/{chunk-FXYUYU4N.js → chunk-JNMVLWLR.js} +42 -1
- package/dist/cli-delegate/{chunk-QJWAUMJW.js → chunk-YJ72UIAK.js} +730 -15
- package/dist/cli-delegate/cmd_conformance.js +902 -782
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +4 -4
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +10 -10
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +6666 -2581
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/install.mjs +848 -733
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +2747 -1510
- package/dist/server/schemas/settings.js +23 -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/contracts/settings-classes.md +6 -4
- package/package.json +4 -4
- 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 +29 -0
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +2 -2
- package/src/config/gate-coverage.yml +234 -3
- package/src/config/gate-violation-baselines.json +7 -3
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +2 -2
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +18 -4
- package/src/scripts/_cli/cmd_doctor.ts +5 -19
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/obligations.ts +119 -8
- 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 +2 -1
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -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/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_team/team_dispatch.ts +4 -0
- 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 +245 -3
- package/src/scripts/check_finding_dispositions.ts +22 -3
- package/src/scripts/check_generator_sync.ts +71 -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_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/compile_hook_manifest.ts +60 -16
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +42 -5
- 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 +2 -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 +100 -9
- 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 +1 -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 +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- 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 +8 -5
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- 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/install.ts +3 -4
- 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 +55 -0
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- 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_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/prepack-check.mjs +53 -0
- package/src/scripts/release_publication.ts +13 -1
- 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 +1 -1
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +4 -0
- package/src/scripts/schemas/skill.schema.json +44 -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 -2
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +31 -0
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/ui/assets/index-DH1xc62v.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
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* The invocation-surface census — what a host or an MCP client is told about
|
|
4
|
+
* how to invoke an artifact, counted by a unit defined before it is counted.
|
|
5
|
+
*
|
|
6
|
+
* road-to-an-invocation-contract-that-reaches-the-wire 1.1. Report only: it
|
|
7
|
+
* exits 0 on every corpus, carries the `report_` prefix so the gate population
|
|
8
|
+
* classifies it out, and asserts no threshold.
|
|
9
|
+
*
|
|
10
|
+
* THE UNIT, AND WHY THE SOURCE FIGURES DO NOT REPRODUCE
|
|
11
|
+
*
|
|
12
|
+
* The roadmap's Goal states 11 skills using `${...}`, 4 using `<UPPERCASE>` and
|
|
13
|
+
* 2 using `{{...}}`. NONE of the three reproduces, and the reason is the same
|
|
14
|
+
* one every time: a natural grep counts matches inside CODE, where the token
|
|
15
|
+
* belongs to the language being demonstrated rather than to this package.
|
|
16
|
+
*
|
|
17
|
+
* - `${viewport.name}` in `playwright-testing` is a JavaScript template
|
|
18
|
+
* literal in an example.
|
|
19
|
+
* - `${local.env.aws_account_id}` and `${get_env(...)}` in `terragrunt` are
|
|
20
|
+
* HCL interpolation in example configuration.
|
|
21
|
+
* - `${user.id}` in `testing-anti-patterns` is another JS template literal.
|
|
22
|
+
* - `` `<TBD>` `` in `livewire-architect` is a table-cell marker the prose is
|
|
23
|
+
* TALKING ABOUT — "the component shape table is filled in (no `<TBD>`
|
|
24
|
+
* cells)" — not a slot anything substitutes.
|
|
25
|
+
*
|
|
26
|
+
* A census that counts those is not measuring invocation syntax; it is
|
|
27
|
+
* measuring how many skills teach a templating language. So the unit here is:
|
|
28
|
+
*
|
|
29
|
+
* **one occurrence of a placeholder token in PROSE** — outside fenced code
|
|
30
|
+
* blocks, outside indented code blocks, and outside inline code spans.
|
|
31
|
+
*
|
|
32
|
+
* That is the opposite of the choice `ask_block_census` makes for its own
|
|
33
|
+
* subject, deliberately: there the fenced block IS the rendered hand-back being
|
|
34
|
+
* counted, so stripping fences would blind it. Here a fence is foreign
|
|
35
|
+
* territory, and NOT stripping it is what produced a figure four times the real
|
|
36
|
+
* one. Both scripts publish the reasoning above the number for the same reason.
|
|
37
|
+
*
|
|
38
|
+
* NO NUMBER IS CARRIED FORWARD from the roadmap. The figures below are this
|
|
39
|
+
* script's own, under the definition above, and the per-file breakdown is
|
|
40
|
+
* printed so a reader can disagree with the definition rather than having to
|
|
41
|
+
* trust it.
|
|
42
|
+
*
|
|
43
|
+
* WHAT ELSE IS COUNTED
|
|
44
|
+
*
|
|
45
|
+
* Per artifact: whether it declares an `inputs:` frontmatter block (the
|
|
46
|
+
* structured declaration Phase 2 introduces — zero today, by construction), and
|
|
47
|
+
* whether it carries an `argument-hint`. The hint coverage is the figure Phase
|
|
48
|
+
* 3 closes.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
import fs from 'node:fs';
|
|
52
|
+
import path from 'node:path';
|
|
53
|
+
import { execFileSync } from 'node:child_process';
|
|
54
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
55
|
+
|
|
56
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
57
|
+
export const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
58
|
+
|
|
59
|
+
/** Projected commands — what a host actually installs. */
|
|
60
|
+
const COMMANDS_REL = path.join('dist', 'agent-src', 'commands');
|
|
61
|
+
|
|
62
|
+
/** Skill sources. */
|
|
63
|
+
const SKILLS_REL = path.join('src', 'skills');
|
|
64
|
+
|
|
65
|
+
const DEFAULT_OUT = path.join('agents', 'evidence', 'analysis', 'invocation-surface-census.md');
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The placeholder syntaxes tracked, and which one this package treats as its
|
|
69
|
+
* own.
|
|
70
|
+
*
|
|
71
|
+
* `canonical` is descriptive, not a ruling: it records which form the corpus
|
|
72
|
+
* uses in prose today. Nothing here rewrites a body, and the drift ratchet that
|
|
73
|
+
* consumes this census fails on GROWTH of the foreign forms only — never on the
|
|
74
|
+
* absolute number and never on the plurality form.
|
|
75
|
+
*/
|
|
76
|
+
export const SYNTAXES = [
|
|
77
|
+
{ id: 'dollar-brace', label: '${…}', re: /\$\{[^}\s][^}]*\}/g, canonical: true },
|
|
78
|
+
{ id: 'angle-upper', label: '<UPPER>', re: /<[A-Z][A-Z_]+>/g, canonical: false },
|
|
79
|
+
{ id: 'double-brace', label: '{{…}}', re: /\{\{[^}\n]+\}\}/g, canonical: false },
|
|
80
|
+
] as const;
|
|
81
|
+
|
|
82
|
+
export type SyntaxId = (typeof SYNTAXES)[number]['id'];
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Remove every region where a placeholder token belongs to demonstrated code
|
|
86
|
+
* rather than to this package's own invocation surface.
|
|
87
|
+
*
|
|
88
|
+
* FENCES ARE SCANNED, NOT REGEX-MATCHED. An earlier version used one regex
|
|
89
|
+
* requiring the closing fence at the opener's own indent, and independent
|
|
90
|
+
* review found three ways real markdown leaks through it: an UNCLOSED fence
|
|
91
|
+
* (the rest of the file then counts as prose), a closing fence indented one to
|
|
92
|
+
* three spaces (legal CommonMark), and a four-backtick fence wrapping a
|
|
93
|
+
* three-backtick one. The `{{…}}` ceiling of zero rests on this stripper, so a
|
|
94
|
+
* leak here is a ratchet that silently stops guarding. The scanner below
|
|
95
|
+
* follows the CommonMark rules that matter: a closing fence uses the same
|
|
96
|
+
* character, is at least as long as the opener, and an unclosed fence runs to
|
|
97
|
+
* end of file.
|
|
98
|
+
*
|
|
99
|
+
* INDENTED CODE IS NOT JUST "FOUR SPACES". The same review measured the naive
|
|
100
|
+
* rule blanking 217 non-fence prose lines across the skill corpus, 74 of them
|
|
101
|
+
* list continuations — a nested bullet is indented exactly like a code block
|
|
102
|
+
* and is prose. So an indented run counts as code only when it is NOT inside a
|
|
103
|
+
* list: a list is open while indented content follows a bullet, and closes at
|
|
104
|
+
* the first non-indented, non-blank line.
|
|
105
|
+
*/
|
|
106
|
+
export function proseOnly(text: string): string {
|
|
107
|
+
const lines = text.split('\n');
|
|
108
|
+
const out: string[] = [];
|
|
109
|
+
|
|
110
|
+
let fence: { char: string; len: number } | null = null;
|
|
111
|
+
let listIndent: number | null = null;
|
|
112
|
+
let prevBlank = true;
|
|
113
|
+
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
const fenceOpen = /^(\s*)(`{3,}|~{3,})/.exec(line);
|
|
116
|
+
|
|
117
|
+
if (fence !== null) {
|
|
118
|
+
// Inside a fence: only a matching closer ends it. Everything is dropped.
|
|
119
|
+
if (
|
|
120
|
+
fenceOpen !== null &&
|
|
121
|
+
fenceOpen[2]!.startsWith(fence.char) &&
|
|
122
|
+
fenceOpen[2]!.length >= fence.len &&
|
|
123
|
+
line.slice(fenceOpen[1]!.length + fenceOpen[2]!.length).trim() === ''
|
|
124
|
+
) {
|
|
125
|
+
fence = null;
|
|
126
|
+
}
|
|
127
|
+
out.push('');
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (fenceOpen !== null) {
|
|
132
|
+
fence = { char: fenceOpen[2]![0]!, len: fenceOpen[2]!.length };
|
|
133
|
+
out.push('');
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const blank = line.trim() === '';
|
|
138
|
+
if (blank) {
|
|
139
|
+
out.push(line);
|
|
140
|
+
prevBlank = true;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const indent = /^(\s*)/.exec(line)![1]!.replace(/\t/g, ' ').length;
|
|
145
|
+
const bullet = /^\s*([-*+]|\d+[.)])\s/.test(line);
|
|
146
|
+
|
|
147
|
+
if (bullet) {
|
|
148
|
+
listIndent = indent;
|
|
149
|
+
} else if (listIndent !== null && indent <= listIndent) {
|
|
150
|
+
listIndent = null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// An indented run is code only outside a list, and only when it starts
|
|
154
|
+
// after a blank line — the CommonMark precondition for indented code.
|
|
155
|
+
const inList = listIndent !== null && indent > listIndent;
|
|
156
|
+
const indentedCode = indent >= 4 && !inList && prevBlank;
|
|
157
|
+
|
|
158
|
+
out.push(indentedCode ? '' : line);
|
|
159
|
+
prevBlank = false;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return out.join('\n').replace(/`[^`\n]*`/g, '');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface ArtifactRow {
|
|
166
|
+
/** Repo-relative path. */
|
|
167
|
+
readonly file: string;
|
|
168
|
+
/** `command` or `skill`. */
|
|
169
|
+
readonly kind: 'command' | 'skill';
|
|
170
|
+
/** Does the frontmatter carry a structured `inputs:` block? */
|
|
171
|
+
readonly declaresInputs: boolean;
|
|
172
|
+
/** Does the frontmatter carry an `argument-hint`? */
|
|
173
|
+
readonly hasHint: boolean;
|
|
174
|
+
/** Prose placeholder occurrences, per syntax. Absent syntaxes are omitted. */
|
|
175
|
+
readonly placeholders: Readonly<Partial<Record<SyntaxId, number>>>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface Census {
|
|
179
|
+
readonly rows: readonly ArtifactRow[];
|
|
180
|
+
readonly commands: number;
|
|
181
|
+
readonly skills: number;
|
|
182
|
+
/** Commands carrying an `argument-hint`. */
|
|
183
|
+
readonly commandsWithHint: number;
|
|
184
|
+
/** Artifacts declaring `inputs:`. */
|
|
185
|
+
readonly declaring: number;
|
|
186
|
+
/** Prose occurrences per syntax, whole corpus. */
|
|
187
|
+
readonly occurrences: Readonly<Record<SyntaxId, number>>;
|
|
188
|
+
/** Files carrying at least one occurrence, per syntax. */
|
|
189
|
+
readonly files: Readonly<Record<SyntaxId, number>>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function frontmatter(text: string): string {
|
|
193
|
+
const m = /^---\n([\s\S]*?)\n---/.exec(text);
|
|
194
|
+
return m === null ? '' : m[1]!;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function walk(dir: string, match: (name: string) => boolean, out: string[] = []): string[] {
|
|
198
|
+
if (!fs.existsSync(dir)) return out;
|
|
199
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
200
|
+
const p = path.join(dir, e.name);
|
|
201
|
+
if (e.isDirectory()) walk(p, match, out);
|
|
202
|
+
else if (match(e.name)) out.push(p);
|
|
203
|
+
}
|
|
204
|
+
return out;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function census(root: string): Census {
|
|
208
|
+
const files: { file: string; kind: 'command' | 'skill' }[] = [
|
|
209
|
+
...walk(path.join(root, COMMANDS_REL), (n) => n.endsWith('.md')).map((f) => ({
|
|
210
|
+
file: f,
|
|
211
|
+
kind: 'command' as const,
|
|
212
|
+
})),
|
|
213
|
+
...walk(path.join(root, SKILLS_REL), (n) => n === 'SKILL.md').map((f) => ({
|
|
214
|
+
file: f,
|
|
215
|
+
kind: 'skill' as const,
|
|
216
|
+
})),
|
|
217
|
+
].sort((a, b) => a.file.localeCompare(b.file));
|
|
218
|
+
|
|
219
|
+
const occurrences: Record<string, number> = {};
|
|
220
|
+
const fileCounts: Record<string, number> = {};
|
|
221
|
+
for (const s of SYNTAXES) {
|
|
222
|
+
occurrences[s.id] = 0;
|
|
223
|
+
fileCounts[s.id] = 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const rows: ArtifactRow[] = [];
|
|
227
|
+
for (const { file, kind } of files) {
|
|
228
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
229
|
+
const fm = frontmatter(text);
|
|
230
|
+
const prose = proseOnly(text);
|
|
231
|
+
|
|
232
|
+
const placeholders: Partial<Record<SyntaxId, number>> = {};
|
|
233
|
+
for (const s of SYNTAXES) {
|
|
234
|
+
const n = (prose.match(s.re) ?? []).length;
|
|
235
|
+
if (n === 0) continue;
|
|
236
|
+
placeholders[s.id] = n;
|
|
237
|
+
occurrences[s.id] = (occurrences[s.id] ?? 0) + n;
|
|
238
|
+
fileCounts[s.id] = (fileCounts[s.id] ?? 0) + 1;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
rows.push({
|
|
242
|
+
file: path.relative(root, file),
|
|
243
|
+
kind,
|
|
244
|
+
declaresInputs: /^inputs:/m.test(fm),
|
|
245
|
+
hasHint: /^argument-hint:/m.test(fm),
|
|
246
|
+
placeholders,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
rows,
|
|
252
|
+
commands: rows.filter((r) => r.kind === 'command').length,
|
|
253
|
+
skills: rows.filter((r) => r.kind === 'skill').length,
|
|
254
|
+
commandsWithHint: rows.filter((r) => r.kind === 'command' && r.hasHint).length,
|
|
255
|
+
declaring: rows.filter((r) => r.declaresInputs).length,
|
|
256
|
+
occurrences: occurrences as Record<SyntaxId, number>,
|
|
257
|
+
files: fileCounts as Record<SyntaxId, number>,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function pin(root: string): { sha: string; date: string } {
|
|
262
|
+
const git = (args: string[]): string =>
|
|
263
|
+
execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim();
|
|
264
|
+
try {
|
|
265
|
+
return {
|
|
266
|
+
sha: git(['rev-parse', 'HEAD']),
|
|
267
|
+
date: git(['show', '-s', '--format=%cI', 'HEAD']),
|
|
268
|
+
};
|
|
269
|
+
} catch {
|
|
270
|
+
return { sha: 'unknown', date: 'unknown' };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function render(c: Census, p: { sha: string; date: string }): string {
|
|
275
|
+
const L: string[] = [];
|
|
276
|
+
L.push('<!-- evidence-type: analysis -->');
|
|
277
|
+
L.push(`<!-- invocation-surface-census: v1 | commit: ${p.sha} | commit-date: ${p.date} -->`);
|
|
278
|
+
L.push('');
|
|
279
|
+
L.push('# Invocation-surface census');
|
|
280
|
+
L.push('');
|
|
281
|
+
L.push(
|
|
282
|
+
'Emitted by `src/scripts/report_invocation_surface.ts`. **Read that script’s module',
|
|
283
|
+
);
|
|
284
|
+
L.push(
|
|
285
|
+
'header before reading a number here** — it defines the counting unit, and the unit is',
|
|
286
|
+
);
|
|
287
|
+
L.push('the whole disagreement with the figures this roadmap started from.');
|
|
288
|
+
L.push('');
|
|
289
|
+
L.push(
|
|
290
|
+
'**A placeholder occurrence is a token in PROSE** — outside fenced code blocks, indented',
|
|
291
|
+
);
|
|
292
|
+
L.push(
|
|
293
|
+
'code blocks and inline code spans. A skill teaching Terraform contains `${local.x}`; a',
|
|
294
|
+
);
|
|
295
|
+
L.push(
|
|
296
|
+
'skill teaching Playwright contains `${viewport.name}`. Counting those measures how many',
|
|
297
|
+
);
|
|
298
|
+
L.push('skills teach a templating language, not how this package declares invocation.');
|
|
299
|
+
L.push('');
|
|
300
|
+
L.push(`- **Commit pin:** \`${p.sha}\` (${p.date})`);
|
|
301
|
+
L.push(`- **Corpus:** \`${COMMANDS_REL}/**/*.md\` — ${String(c.commands)} command(s); \`${SKILLS_REL}/*/SKILL.md\` — ${String(c.skills)} skill(s)`);
|
|
302
|
+
L.push('');
|
|
303
|
+
|
|
304
|
+
L.push('## Declaration coverage');
|
|
305
|
+
L.push('');
|
|
306
|
+
L.push(
|
|
307
|
+
`- Artifacts declaring a structured \`inputs:\` block: **${String(c.declaring)}** of ${String(c.rows.length)}.`,
|
|
308
|
+
);
|
|
309
|
+
L.push(
|
|
310
|
+
`- Commands carrying an \`argument-hint\`: **${String(c.commandsWithHint)}** of ${String(c.commands)} — ${String(c.commands - c.commandsWithHint)} carry none.`,
|
|
311
|
+
);
|
|
312
|
+
L.push('');
|
|
313
|
+
|
|
314
|
+
L.push('## Prose placeholder occurrences');
|
|
315
|
+
L.push('');
|
|
316
|
+
L.push('| syntax | role | occurrences | files |');
|
|
317
|
+
L.push('|---|---|---|---|');
|
|
318
|
+
for (const s of SYNTAXES) {
|
|
319
|
+
L.push(
|
|
320
|
+
`| \`${s.label}\` | ${s.canonical ? 'plurality form' : 'foreign'} | ${String(c.occurrences[s.id])} | ${String(c.files[s.id])} |`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
L.push('');
|
|
324
|
+
|
|
325
|
+
const carrying = c.rows.filter((r) => Object.keys(r.placeholders).length > 0);
|
|
326
|
+
if (carrying.length === 0) {
|
|
327
|
+
L.push('No artifact carries a placeholder token in prose.');
|
|
328
|
+
} else {
|
|
329
|
+
L.push('### Which files, and what they actually contain');
|
|
330
|
+
L.push('');
|
|
331
|
+
L.push('| file | syntax | n |');
|
|
332
|
+
L.push('|---|---|---|');
|
|
333
|
+
for (const r of carrying) {
|
|
334
|
+
for (const s of SYNTAXES) {
|
|
335
|
+
const n = r.placeholders[s.id];
|
|
336
|
+
if (n === undefined) continue;
|
|
337
|
+
L.push(`| \`${r.file}\` | \`${s.label}\` | ${String(n)} |`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
L.push('');
|
|
342
|
+
return L.join('\n');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function main(argv: readonly string[]): number {
|
|
346
|
+
const write = argv.includes('--write');
|
|
347
|
+
const json = argv.includes('--json');
|
|
348
|
+
const outIdx = argv.indexOf('--out');
|
|
349
|
+
const out = outIdx >= 0 ? argv[outIdx + 1] : undefined;
|
|
350
|
+
|
|
351
|
+
const c = census(REPO_ROOT);
|
|
352
|
+
|
|
353
|
+
if (json) {
|
|
354
|
+
process.stdout.write(`${JSON.stringify(c, null, 2)}\n`);
|
|
355
|
+
return 0;
|
|
356
|
+
}
|
|
357
|
+
if (write) {
|
|
358
|
+
const target = path.resolve(REPO_ROOT, out ?? DEFAULT_OUT);
|
|
359
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
360
|
+
fs.writeFileSync(target, render(c, pin(REPO_ROOT)), 'utf8');
|
|
361
|
+
process.stdout.write(
|
|
362
|
+
`report_invocation_surface: wrote ${path.relative(REPO_ROOT, target)}\n`,
|
|
363
|
+
);
|
|
364
|
+
return 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
process.stdout.write(
|
|
368
|
+
`report_invocation_surface · ${String(c.commands)} command(s), ${String(c.skills)} skill(s)\n`,
|
|
369
|
+
);
|
|
370
|
+
process.stdout.write(
|
|
371
|
+
` argument-hint: ${String(c.commandsWithHint)}/${String(c.commands)} command(s) · inputs: ${String(c.declaring)} artifact(s)\n`,
|
|
372
|
+
);
|
|
373
|
+
for (const s of SYNTAXES) {
|
|
374
|
+
process.stdout.write(
|
|
375
|
+
` ${s.label.padEnd(9)} ${s.canonical ? 'plurality' : 'foreign '} occ=${String(c.occurrences[s.id])} files=${String(c.files[s.id])}\n`,
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
return 0;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
382
|
+
process.exit(main(process.argv.slice(2)));
|
|
383
|
+
}
|