@event4u/agent-config 9.20.0 → 9.22.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.
Files changed (239) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +86 -0
  3. package/dist/agent-src/commands/worktree/cleanup.md +17 -0
  4. package/dist/agent-src/commands/worktree/status.md +6 -0
  5. package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +22 -0
  6. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  7. package/dist/cli-delegate/{chunk-XGA2NTU4.js → chunk-3EWYC3YK.js} +40 -0
  8. package/dist/cli-delegate/cmd_handoff.js +1 -1
  9. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  10. package/dist/cli-delegate/cmd_route_audit.js +1 -1
  11. package/dist/discovery/deprecation-report.md +1 -1
  12. package/dist/discovery/discovery-manifest.json +5 -5
  13. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  14. package/dist/discovery/discovery-manifest.summary.md +1 -1
  15. package/dist/discovery/orphan-report.md +1 -1
  16. package/dist/discovery/packs.json +2 -2
  17. package/dist/discovery/trust-report.md +1 -1
  18. package/dist/discovery/workspaces.json +2 -2
  19. package/dist/hooks/dispatch.js +58 -2
  20. package/dist/mcp/registry-manifest.json +2 -2
  21. package/dist/mcp/server.json +2 -2
  22. package/dist/mcp/server.mjs +47 -29
  23. package/package.json +1 -1
  24. package/src/config/gate-coverage.yml +22 -4
  25. package/src/config/gate-violation-baselines.json +3 -8
  26. package/src/scripts/_lib/bench_ab_activation.ts +368 -0
  27. package/src/scripts/_lib/gate_population.ts +70 -0
  28. package/src/scripts/_lib/roadmap_granularity.ts +157 -0
  29. package/src/scripts/_lib/scan_scope.ts +44 -0
  30. package/src/scripts/_lib/stdin.ts +82 -0
  31. package/src/scripts/audit_adr_coverage.ts +38 -0
  32. package/src/scripts/audit_auto_rules.ts +17 -3
  33. package/src/scripts/audit_command_surface.ts +51 -0
  34. package/src/scripts/audit_initial_context.ts +39 -3
  35. package/src/scripts/audit_mcp_tools.ts +25 -0
  36. package/src/scripts/audit_overlap.ts +24 -1
  37. package/src/scripts/audit_skill_descriptions.ts +19 -0
  38. package/src/scripts/{verify_before_complete_hook.ts → before_complete_hook.ts} +16 -3
  39. package/src/scripts/bench_ab_task_runner.ts +18 -0
  40. package/src/scripts/bench_ab_v2_run.ts +147 -6
  41. package/src/scripts/bench_ab_v2_stats.ts +74 -2
  42. package/src/scripts/check_adr_frontmatter.ts +23 -3
  43. package/src/scripts/check_always_budget.ts +24 -0
  44. package/src/scripts/check_artefact_checksums.ts +24 -1
  45. package/src/scripts/check_artefact_count_messaging.ts +20 -0
  46. package/src/scripts/check_augmentignore.ts +22 -15
  47. package/src/scripts/check_backstop_debt.ts +22 -0
  48. package/src/scripts/check_beta_review_markers.ts +22 -1
  49. package/src/scripts/check_bridge_derivation.ts +22 -1
  50. package/src/scripts/check_bundle_path_leakage.ts +26 -0
  51. package/src/scripts/check_ci_strict_superset.ts +21 -3
  52. package/src/scripts/check_claims.ts +22 -0
  53. package/src/scripts/check_cli_registry_budget_sync.ts +33 -4
  54. package/src/scripts/check_cluster_patterns.ts +26 -4
  55. package/src/scripts/check_command_count_messaging.ts +20 -4
  56. package/src/scripts/check_comparison.ts +18 -0
  57. package/src/scripts/check_condensed_paths.ts +23 -2
  58. package/src/scripts/check_consumer_scope_flip.ts +21 -2
  59. package/src/scripts/check_council_config_location.ts +20 -0
  60. package/src/scripts/check_council_layout.ts +22 -2
  61. package/src/scripts/check_council_references.ts +23 -1
  62. package/src/scripts/check_dependency_floors.ts +19 -3
  63. package/src/scripts/check_discovery_determinism.ts +26 -0
  64. package/src/scripts/check_enforcement_coverage.ts +20 -0
  65. package/src/scripts/check_evaluator_budgets.ts +23 -0
  66. package/src/scripts/check_finding_dispositions.ts +29 -0
  67. package/src/scripts/check_gate_coverage.ts +63 -22
  68. package/src/scripts/check_gate_paths.ts +30 -5
  69. package/src/scripts/check_generated_artefact_headers.ts +21 -0
  70. package/src/scripts/check_generator_output_coverage.ts +23 -0
  71. package/src/scripts/check_gitignore_freshness.ts +23 -0
  72. package/src/scripts/check_host_loadability.ts +34 -8
  73. package/src/scripts/check_installer_import_purity.ts +22 -8
  74. package/src/scripts/check_kernel_prefix_stability.ts +19 -1
  75. package/src/scripts/check_kernel_rule_bundle.ts +23 -0
  76. package/src/scripts/check_knowledge_cards.ts +13 -0
  77. package/src/scripts/check_knowledge_pages.ts +23 -0
  78. package/src/scripts/check_knowledge_sharing.ts +27 -0
  79. package/src/scripts/check_md_language.ts +24 -0
  80. package/src/scripts/check_media_deps.ts +23 -0
  81. package/src/scripts/check_memory.ts +26 -1
  82. package/src/scripts/check_memory_contradiction.ts +16 -1
  83. package/src/scripts/check_memory_proposal.ts +15 -0
  84. package/src/scripts/check_memory_similarity.ts +16 -0
  85. package/src/scripts/check_module_management_neutral.ts +19 -11
  86. package/src/scripts/check_no_conflict_markers.ts +22 -1
  87. package/src/scripts/check_no_external_sources.ts +26 -1
  88. package/src/scripts/check_no_local_settings_committed.ts +37 -10
  89. package/src/scripts/check_no_new_legacy_path.ts +30 -1
  90. package/src/scripts/check_one_off_location.ts +43 -0
  91. package/src/scripts/check_originality_freshness.ts +25 -1
  92. package/src/scripts/check_overlay_cascade_subdirs.ts +21 -0
  93. package/src/scripts/check_pack_size.ts +22 -0
  94. package/src/scripts/check_preamble_payload_budget.ts +35 -5
  95. package/src/scripts/check_proposal.ts +24 -1
  96. package/src/scripts/check_public_catalog_links.ts +27 -0
  97. package/src/scripts/check_public_links.ts +19 -0
  98. package/src/scripts/check_quality_regression.ts +19 -0
  99. package/src/scripts/check_reach_channels.ts +44 -0
  100. package/src/scripts/check_reach_staleness.ts +27 -0
  101. package/src/scripts/check_release_adjacent_health.ts +28 -0
  102. package/src/scripts/check_release_highlights.ts +34 -0
  103. package/src/scripts/check_release_includes_discovery.ts +25 -6
  104. package/src/scripts/check_release_pr_shape.ts +18 -1
  105. package/src/scripts/check_release_published.ts +21 -0
  106. package/src/scripts/check_release_surface_equality.ts +22 -0
  107. package/src/scripts/check_release_trunk_sync.ts +19 -0
  108. package/src/scripts/check_reply_consistency.ts +22 -0
  109. package/src/scripts/check_roadmap_trackable.ts +20 -0
  110. package/src/scripts/check_role_doc_links.ts +23 -0
  111. package/src/scripts/check_rule_invariants.ts +14 -0
  112. package/src/scripts/check_secret_leak.ts +47 -0
  113. package/src/scripts/check_skill_gaps.ts +32 -0
  114. package/src/scripts/check_skill_requires.ts +19 -0
  115. package/src/scripts/check_source_pointer_freshness.ts +20 -0
  116. package/src/scripts/check_structural_breaking.ts +29 -2
  117. package/src/scripts/check_surface_tiers.ts +34 -0
  118. package/src/scripts/check_template_pin_drift.ts +23 -1
  119. package/src/scripts/check_test_coverage_diff.ts +17 -1
  120. package/src/scripts/check_token_optimizer_freshness.ts +18 -3
  121. package/src/scripts/check_token_quality_golden.ts +21 -0
  122. package/src/scripts/check_token_regression.ts +25 -0
  123. package/src/scripts/check_tracked_but_ignored.ts +26 -0
  124. package/src/scripts/check_trigger_eval_presence.ts +23 -1
  125. package/src/scripts/check_trigger_evals.ts +36 -0
  126. package/src/scripts/check_trunk_drift.ts +23 -0
  127. package/src/scripts/check_update_banner.ts +24 -0
  128. package/src/scripts/gate_scope_classify.ts +513 -0
  129. package/src/scripts/hook_manifest.yaml +1 -1
  130. package/src/scripts/hooks/block_kernel_rule_writes.ts +1 -1
  131. package/src/scripts/hooks/concern_registry.ts +2 -2
  132. package/src/scripts/lint_agent_security.ts +19 -0
  133. package/src/scripts/lint_agent_skill_names.ts +30 -0
  134. package/src/scripts/lint_agents_layout.ts +20 -0
  135. package/src/scripts/lint_agents_md.ts +20 -0
  136. package/src/scripts/lint_archived_skills.ts +24 -3
  137. package/src/scripts/lint_behavioural_eval_freshness.ts +29 -3
  138. package/src/scripts/lint_bench_ab.ts +25 -0
  139. package/src/scripts/lint_bench_corpus.ts +20 -4
  140. package/src/scripts/lint_breaking_changes_index.ts +24 -0
  141. package/src/scripts/lint_budget_ownership.ts +20 -3
  142. package/src/scripts/lint_changelog_rollback.ts +24 -0
  143. package/src/scripts/lint_command_flow_coverage.ts +22 -0
  144. package/src/scripts/lint_command_tiers.ts +29 -5
  145. package/src/scripts/lint_commit_subjects.ts +15 -0
  146. package/src/scripts/lint_confusables.ts +24 -0
  147. package/src/scripts/lint_consumer_internal_refs.ts +24 -0
  148. package/src/scripts/lint_design_quality.ts +22 -0
  149. package/src/scripts/lint_design_slop.ts +23 -0
  150. package/src/scripts/lint_discovery_manifest.ts +23 -0
  151. package/src/scripts/lint_discovery_vocabulary.ts +19 -0
  152. package/src/scripts/lint_documented_commands.ts +23 -0
  153. package/src/scripts/lint_empty_roadmaps.ts +23 -0
  154. package/src/scripts/lint_eval_fixture_citations.ts +19 -0
  155. package/src/scripts/lint_eval_freshness.ts +35 -0
  156. package/src/scripts/lint_examples.ts +18 -3
  157. package/src/scripts/lint_explain_trace.ts +23 -0
  158. package/src/scripts/lint_featured_skills.ts +26 -1
  159. package/src/scripts/lint_flows.ts +19 -0
  160. package/src/scripts/lint_frontmatter_boilerplate.ts +20 -0
  161. package/src/scripts/lint_ghostwriter_source.ts +26 -6
  162. package/src/scripts/lint_glama_drift.ts +24 -0
  163. package/src/scripts/lint_global_paths.ts +24 -0
  164. package/src/scripts/lint_governed_writes.ts +20 -0
  165. package/src/scripts/lint_hidden_unicode.ts +25 -0
  166. package/src/scripts/lint_hook_concern_budget.ts +39 -6
  167. package/src/scripts/lint_hook_manifest.ts +22 -0
  168. package/src/scripts/lint_instruction_smuggling.ts +23 -0
  169. package/src/scripts/lint_knowledge_scale.ts +32 -2
  170. package/src/scripts/lint_legal_pack.ts +31 -0
  171. package/src/scripts/lint_marketplace.ts +26 -0
  172. package/src/scripts/lint_marketplace_install_completeness.ts +23 -0
  173. package/src/scripts/lint_mcp_config_security.ts +24 -0
  174. package/src/scripts/lint_mcp_registry_manifest.ts +22 -1
  175. package/src/scripts/lint_memory_tripwire.ts +35 -0
  176. package/src/scripts/lint_missions.ts +23 -7
  177. package/src/scripts/lint_model_tier_coverage.ts +18 -0
  178. package/src/scripts/lint_namespace_collisions.ts +19 -0
  179. package/src/scripts/lint_no_new_atomic_commands.ts +33 -0
  180. package/src/scripts/lint_no_python_twin_rationale.ts +18 -0
  181. package/src/scripts/lint_one_off_age.ts +38 -2
  182. package/src/scripts/lint_orchestration_dsl.ts +23 -3
  183. package/src/scripts/lint_orchestrator_auto_detect.ts +19 -12
  184. package/src/scripts/lint_originality.ts +22 -4
  185. package/src/scripts/lint_originality_shingles.ts +28 -3
  186. package/src/scripts/lint_output_slop.ts +19 -0
  187. package/src/scripts/lint_override_kernel_guard.ts +30 -0
  188. package/src/scripts/lint_pack_first_win.ts +23 -0
  189. package/src/scripts/lint_pack_risk_class.ts +19 -3
  190. package/src/scripts/lint_persistence.ts +19 -0
  191. package/src/scripts/lint_persona_governance.ts +18 -3
  192. package/src/scripts/lint_positioning.ts +23 -0
  193. package/src/scripts/lint_pre_migration_refs.ts +24 -0
  194. package/src/scripts/lint_profile_overlay_set_only.ts +24 -0
  195. package/src/scripts/lint_provenance.ts +21 -0
  196. package/src/scripts/lint_provenance_vocabulary.ts +24 -1
  197. package/src/scripts/lint_readme_jargon.ts +21 -3
  198. package/src/scripts/lint_readme_serial_comma.ts +21 -3
  199. package/src/scripts/lint_readme_size.ts +21 -3
  200. package/src/scripts/lint_regression.ts +28 -0
  201. package/src/scripts/lint_roadmap_blockers.ts +43 -0
  202. package/src/scripts/lint_roadmap_ci_steps.ts +45 -0
  203. package/src/scripts/lint_roadmap_complexity.ts +47 -0
  204. package/src/scripts/lint_roadmap_later_disposition.ts +23 -0
  205. package/src/scripts/lint_rule_interactions.ts +16 -2
  206. package/src/scripts/lint_rule_tiers.ts +19 -6
  207. package/src/scripts/lint_showcase_sessions.ts +19 -3
  208. package/src/scripts/lint_skill_descriptions.ts +19 -0
  209. package/src/scripts/lint_skill_frontmatter_safety.ts +24 -0
  210. package/src/scripts/lint_skill_originality.ts +18 -3
  211. package/src/scripts/lint_skill_scripts_readonly.ts +20 -0
  212. package/src/scripts/lint_skill_tools.ts +84 -145
  213. package/src/scripts/lint_spawn_payload.ts +27 -1
  214. package/src/scripts/lint_store_boundary.ts +19 -0
  215. package/src/scripts/lint_subagent_determinism.ts +23 -1
  216. package/src/scripts/lint_supported_tools_matrix.ts +18 -0
  217. package/src/scripts/lint_surface_matrix.ts +19 -3
  218. package/src/scripts/lint_ticket_buildable.ts +23 -0
  219. package/src/scripts/lint_topics_yaml.ts +19 -12
  220. package/src/scripts/lint_trigger_precision.ts +27 -0
  221. package/src/scripts/lint_trust_coherence.ts +21 -0
  222. package/src/scripts/lint_ui_stack_bundles.ts +17 -3
  223. package/src/scripts/lint_value_dashboard.ts +19 -3
  224. package/src/scripts/lint_versioned_cache.ts +19 -1
  225. package/src/scripts/lint_workflow_security.ts +22 -14
  226. package/src/scripts/pr_url_reminder_hook.ts +1 -1
  227. package/src/scripts/skill_collision_clusters.ts +37 -3
  228. package/src/scripts/skill_discovery.ts +20 -0
  229. package/src/scripts/skill_eval_coverage.ts +22 -0
  230. package/src/scripts/skill_overlap.ts +32 -6
  231. package/src/scripts/skill_preview.ts +31 -0
  232. package/src/scripts/skill_trigger_eval.ts +18 -0
  233. package/src/scripts/skill_usage_collect.ts +21 -0
  234. package/src/scripts/skill_usage_report.ts +21 -0
  235. package/src/scripts/sweep_dead_scan_roots.ts +11 -3
  236. package/src/scripts/verify_physical_move.ts +24 -0
  237. package/src/scripts/worktree_cleanup_check.ts +319 -4
  238. package/src/scripts/check_bite_sized_granularity.ts +0 -116
  239. package/src/scripts/lint_workspace_boundary.ts +0 -267
@@ -1,267 +0,0 @@
1
- #!/usr/bin/env tsx
2
- /**
3
- * Workspace-boundary drift check — import-edge enforcement.
4
- *
5
- * Ported from the retired Python `src/scripts/lint_workspace_boundary.py` (ADR-200,
6
- * Python→TypeScript migration). The CLI contract is pinned — the
7
- * `--quiet` flag, the `sorted(repo.glob(WORKSPACE_GLOB))` scan order (pathlib
8
- * component-wise), the FORBIDDEN-pattern set (Python `re` → JS `RegExp`, all
9
- * ASCII so a 1:1 translation), the `# boundary-exception:` pragma skip, the
10
- * per-violation message shape, and the exit codes (0 holds · 1 forbidden
11
- * import · 2 internal). snake_case is kept on the public surface.
12
- *
13
- * Governed by `docs/contracts/workspace-boundary.md` + ADR-095. Fails when a
14
- * workspace module (`src/cli/python/workspace_*.py`) imports an owner-module of
15
- * a domain the workspace does NOT own: skill design, profile/pack semantics,
16
- * video-provider logic, MCP-registry policy, analytics product strategy.
17
- *
18
- * Scope (read this before trusting a green run): this enforces **import edges
19
- * only**. Semantic drift — a workspace module that encodes profile-semantics or
20
- * analytics-product-strategy judgement without importing anything forbidden — is
21
- * NOT catchable here and stays doc-governance, enforced in review against the
22
- * contract. A green run is a supplement to boundary thinking, not a substitute.
23
- *
24
- * Allowed: stdlib, third-party deps, intra-workspace imports (`workspace_*`),
25
- * and any import line carrying a `# boundary-exception: <reason>` pragma.
26
- *
27
- * Usage: python3 src/scripts/lint_workspace_boundary.py [--quiet]
28
- * Exit: 0 = boundary holds · 1 = a forbidden import was found · 2 = internal.
29
- *
30
- * --- Parity notes (ADR-200) ---
31
- *
32
- * - The Python source uses `ast.walk` to find every `ast.Import` /
33
- * `ast.ImportFrom` at any nesting level and records `node.lineno`. The twin
34
- * reproduces that with a small line scanner that recognises top-level AND
35
- * indented `import …` / `from … import …` statements (matching the only
36
- * shapes Python's grammar admits for these node types), yielding the same
37
- * `(module, lineno)` pairs — `lineno` is the line of the `import` / `from`
38
- * keyword, exactly as `ast` reports it. A parenthesized multi-line
39
- * `from x import (\n…\n)` records the `from` line, like `ast`.
40
- * - `Path.read_text(encoding="utf-8")` → `fs.readFileSync(p, "utf-8")`; a
41
- * decode/read error surfaces as the `unparseable` violation line (the Python
42
- * path only hits this on `SyntaxError`, marked `pragma: no cover`).
43
- * - `process.exitCode` is set; `process.exit()` is never called.
44
- */
45
-
46
- import * as fs from 'node:fs';
47
- import * as path from 'node:path';
48
- import { fileURLToPath, pathToFileURL } from 'node:url';
49
-
50
- const _HERE = fileURLToPath(import.meta.url);
51
-
52
- const WORKSPACE_GLOB = 'src/cli/python/workspace_*.py';
53
- const PRAGMA = 'boundary-exception:';
54
-
55
- // Owner-modules of the NOT-owned domains. Matched against each dotted segment
56
- // of an imported module name with segment boundaries, so `packaging` does not
57
- // trip `pack` and `workspace_skills` is handled by the intra-workspace allow.
58
- const FORBIDDEN: ReadonlyArray<readonly [RegExp, string]> = [
59
- [/(?:^|[._-])condense(?:$|[._-])/, 'skill design / condensation'],
60
- [/(?:^|[._-])skill_linter(?:$|[._-])/, 'skill design'],
61
- [/(?:^|[._-])skill_management(?:$|[._-])/, 'skill design'],
62
- [/(?:^|[._-])skill_writing(?:$|[._-])/, 'skill design'],
63
- [/(?:^|[._-])discovery_manifest(?:$|[._-])/, 'profile/pack semantics'],
64
- [/(?:^|[._-])(?:profiles?|packs?)(?:$|[._-])/, 'profile/pack semantics'],
65
- [/ai[_-]?video/, 'video-provider logic'],
66
- [/(?:^|[._-])mcp(?:$|[._-])/, 'MCP-registry policy'],
67
- [/(?:^|[._-])router(?:$|[._-])/, 'router / projection policy'],
68
- [/(?:^|[._-])persona/, 'persona / skill design'],
69
- ];
70
-
71
- function _is_intra_workspace(module: string): boolean {
72
- const head = module.split('.', 1)[0] as string;
73
- return head === 'workspace' || head.startsWith('workspace_');
74
- }
75
-
76
- function _forbidden_reason(module: string): string | null {
77
- if (_is_intra_workspace(module)) {
78
- return null;
79
- }
80
- for (const [pat, reason] of FORBIDDEN) {
81
- if (pat.test(module)) {
82
- return reason;
83
- }
84
- }
85
- return null;
86
- }
87
-
88
- /**
89
- * Yield `[module_name, lineno]` for every import in `src`, mirroring
90
- * `ast.walk` over `ast.Import` / `ast.ImportFrom`.
91
- *
92
- * `ast` reports the keyword line as `lineno` (1-based). `ast.Import` for
93
- * `import a.b, c` yields one entry per alias, all on the same line; the module
94
- * name is the dotted path. `ast.ImportFrom` yields one entry: `node.module`
95
- * (the dotted module after `from`, `None` for `from . import x`).
96
- */
97
- function* _imported_modules(src: string): Generator<[string, number]> {
98
- const lines = src.split('\n');
99
- for (let i = 0; i < lines.length; i++) {
100
- const raw = lines[i] as string;
101
- const stripped = raw.replace(/^[ \t\f\v]+/, '');
102
- const lineno = i + 1;
103
-
104
- // from <module> import … — module is the dotted path after `from`.
105
- // `from . import x` / `from .pkg import y` → ast.module is the part
106
- // after leading dots (or None). The leading-dot (relative) form has
107
- // module = the text after the dots; a bare `from . import` has
108
- // module=None and is skipped (no name to test).
109
- const fromMatch = /^from[ \t]+(\.*)([A-Za-z_][\w.]*)?[ \t]+import\b/.exec(stripped);
110
- if (fromMatch) {
111
- const mod = fromMatch[2];
112
- if (mod !== undefined) {
113
- yield [mod, lineno];
114
- }
115
- continue;
116
- }
117
-
118
- // import a, b.c, d as e — one alias per dotted name; ast records the
119
- // dotted name (`alias.name`), all on this single keyword line.
120
- const importMatch = /^import[ \t]+(.+)$/.exec(stripped);
121
- if (importMatch) {
122
- // Strip a trailing comment, then split on commas; for each clause
123
- // take the dotted module name before any `as` alias.
124
- let body = importMatch[1] as string;
125
- const hash = body.indexOf('#');
126
- if (hash >= 0) {
127
- body = body.slice(0, hash);
128
- }
129
- for (const clause of body.split(',')) {
130
- const name = clause.trim().split(/[ \t]+as[ \t]+/)[0]?.trim();
131
- if (name) {
132
- yield [name, lineno];
133
- }
134
- }
135
- }
136
- }
137
- }
138
-
139
- function check_file(p: string): string[] {
140
- let src: string;
141
- try {
142
- src = fs.readFileSync(p, { encoding: 'utf-8' });
143
- } catch (exc) {
144
- // pragma: no cover — mirrors the Python SyntaxError path.
145
- return [`${p}: unparseable (${(exc as Error).message})`];
146
- }
147
- const lines = src.split('\n');
148
- const out: string[] = [];
149
- for (const [module, lineno] of _imported_modules(src)) {
150
- const reason = _forbidden_reason(module);
151
- if (reason === null) {
152
- continue;
153
- }
154
- const line = lineno > 0 && lineno <= lines.length ? (lines[lineno - 1] as string) : '';
155
- if (line.includes(PRAGMA)) {
156
- continue; // reviewed, deliberate exception
157
- }
158
- out.push(
159
- `${path.basename(p)}:${lineno}: imports \`${module}\` ` +
160
- `(not-owned domain: ${reason})`,
161
- );
162
- }
163
- return out;
164
- }
165
-
166
- /** `sorted(repo.glob("src/cli/python/workspace_*.py"))` — pathlib order. */
167
- function _globWorkspaceSorted(repo: string): string[] {
168
- const dir = path.join(repo, 'src', 'cli', 'python');
169
- let entries: string[];
170
- try {
171
- entries = fs.readdirSync(dir);
172
- } catch {
173
- return [];
174
- }
175
- const out: string[] = [];
176
- for (const name of entries) {
177
- if (name.startsWith('workspace_') && name.endsWith('.py')) {
178
- const full = path.join(dir, name);
179
- try {
180
- if (fs.statSync(full).isFile()) {
181
- out.push(full);
182
- }
183
- } catch {
184
- // ignore
185
- }
186
- }
187
- }
188
- out.sort();
189
- return out;
190
- }
191
-
192
- function main(argv: readonly string[]): number {
193
- const quiet = argv.includes('--quiet');
194
- // Path(__file__).resolve().parent.parent.parent — src/scripts → repo root.
195
- const repo = path.resolve(path.dirname(_HERE), '..', '..');
196
- const files = _globWorkspaceSorted(repo);
197
- if (files.length === 0) {
198
- process.stdout.write(
199
- `⚠️ lint-workspace-boundary: no files match ${WORKSPACE_GLOB}\n`,
200
- );
201
- return 0;
202
- }
203
- const violations: string[] = [];
204
- for (const f of files) {
205
- violations.push(...check_file(f));
206
- }
207
- if (violations.length) {
208
- process.stdout.write(
209
- '❌ Workspace-boundary violation(s) — a workspace module imports ' +
210
- 'an owner-module of a domain the workspace does NOT own ' +
211
- '(docs/contracts/workspace-boundary.md):\n',
212
- );
213
- for (const v of violations) {
214
- process.stdout.write(` 🔴 ${v}\n`);
215
- }
216
- process.stdout.write(
217
- '\nFix: move the logic to the owning surface and consume its ' +
218
- 'output, or add `# boundary-exception: <reason>` if the import is ' +
219
- 'genuinely justified (reviewed like any boundary change).\n',
220
- );
221
- return 1;
222
- }
223
- if (!quiet) {
224
- process.stdout.write(
225
- `✅ Workspace boundary holds — ${files.length} module(s), ` +
226
- 'no forbidden imports.\n',
227
- );
228
- }
229
- return 0;
230
- }
231
-
232
- function _isCliEntry(): boolean {
233
- if (process.argv[1] === undefined) {
234
- return false;
235
- }
236
- const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
237
- if (import.meta.url === argvUrl) {
238
- return true;
239
- }
240
- // A symlinked invocation (e.g. via an installed `.augment/` projection,
241
- // or macOS /var → /private/var temp dirs) makes the raw URLs differ:
242
- // import.meta.url is the resolved real path while argv[1] keeps the
243
- // symlink path. Compare realpaths so the entry guard still fires
244
- // (without this the CLI silently no-ops when run through a symlink).
245
- try {
246
- const here = fs.realpathSync(fileURLToPath(import.meta.url));
247
- const argv = fs.realpathSync(path.resolve(process.argv[1]));
248
- return here === argv;
249
- } catch {
250
- return false;
251
- }
252
- }
253
-
254
- if (_isCliEntry() || process.argv[1] === _HERE) {
255
- process.exitCode = main(process.argv.slice(2));
256
- }
257
-
258
- export {
259
- WORKSPACE_GLOB,
260
- PRAGMA,
261
- FORBIDDEN,
262
- _is_intra_workspace,
263
- _forbidden_reason,
264
- _imported_modules,
265
- check_file,
266
- main,
267
- };