@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +86 -0
- package/dist/agent-src/commands/worktree/cleanup.md +17 -0
- package/dist/agent-src/commands/worktree/status.md +6 -0
- package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +22 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/{chunk-XGA2NTU4.js → chunk-3EWYC3YK.js} +40 -0
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +5 -5
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.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 +58 -2
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +47 -29
- package/package.json +1 -1
- package/src/config/gate-coverage.yml +22 -4
- package/src/config/gate-violation-baselines.json +3 -8
- package/src/scripts/_lib/bench_ab_activation.ts +368 -0
- package/src/scripts/_lib/gate_population.ts +70 -0
- package/src/scripts/_lib/roadmap_granularity.ts +157 -0
- package/src/scripts/_lib/scan_scope.ts +44 -0
- package/src/scripts/_lib/stdin.ts +82 -0
- package/src/scripts/audit_adr_coverage.ts +38 -0
- package/src/scripts/audit_auto_rules.ts +17 -3
- package/src/scripts/audit_command_surface.ts +51 -0
- package/src/scripts/audit_initial_context.ts +39 -3
- package/src/scripts/audit_mcp_tools.ts +25 -0
- package/src/scripts/audit_overlap.ts +24 -1
- package/src/scripts/audit_skill_descriptions.ts +19 -0
- package/src/scripts/{verify_before_complete_hook.ts → before_complete_hook.ts} +16 -3
- package/src/scripts/bench_ab_task_runner.ts +18 -0
- package/src/scripts/bench_ab_v2_run.ts +147 -6
- package/src/scripts/bench_ab_v2_stats.ts +74 -2
- package/src/scripts/check_adr_frontmatter.ts +23 -3
- package/src/scripts/check_always_budget.ts +24 -0
- package/src/scripts/check_artefact_checksums.ts +24 -1
- package/src/scripts/check_artefact_count_messaging.ts +20 -0
- package/src/scripts/check_augmentignore.ts +22 -15
- package/src/scripts/check_backstop_debt.ts +22 -0
- package/src/scripts/check_beta_review_markers.ts +22 -1
- package/src/scripts/check_bridge_derivation.ts +22 -1
- package/src/scripts/check_bundle_path_leakage.ts +26 -0
- package/src/scripts/check_ci_strict_superset.ts +21 -3
- package/src/scripts/check_claims.ts +22 -0
- package/src/scripts/check_cli_registry_budget_sync.ts +33 -4
- package/src/scripts/check_cluster_patterns.ts +26 -4
- package/src/scripts/check_command_count_messaging.ts +20 -4
- package/src/scripts/check_comparison.ts +18 -0
- package/src/scripts/check_condensed_paths.ts +23 -2
- package/src/scripts/check_consumer_scope_flip.ts +21 -2
- package/src/scripts/check_council_config_location.ts +20 -0
- package/src/scripts/check_council_layout.ts +22 -2
- package/src/scripts/check_council_references.ts +23 -1
- package/src/scripts/check_dependency_floors.ts +19 -3
- package/src/scripts/check_discovery_determinism.ts +26 -0
- package/src/scripts/check_enforcement_coverage.ts +20 -0
- package/src/scripts/check_evaluator_budgets.ts +23 -0
- package/src/scripts/check_finding_dispositions.ts +29 -0
- package/src/scripts/check_gate_coverage.ts +63 -22
- package/src/scripts/check_gate_paths.ts +30 -5
- package/src/scripts/check_generated_artefact_headers.ts +21 -0
- package/src/scripts/check_generator_output_coverage.ts +23 -0
- package/src/scripts/check_gitignore_freshness.ts +23 -0
- package/src/scripts/check_host_loadability.ts +34 -8
- package/src/scripts/check_installer_import_purity.ts +22 -8
- package/src/scripts/check_kernel_prefix_stability.ts +19 -1
- package/src/scripts/check_kernel_rule_bundle.ts +23 -0
- package/src/scripts/check_knowledge_cards.ts +13 -0
- package/src/scripts/check_knowledge_pages.ts +23 -0
- package/src/scripts/check_knowledge_sharing.ts +27 -0
- package/src/scripts/check_md_language.ts +24 -0
- package/src/scripts/check_media_deps.ts +23 -0
- package/src/scripts/check_memory.ts +26 -1
- package/src/scripts/check_memory_contradiction.ts +16 -1
- package/src/scripts/check_memory_proposal.ts +15 -0
- package/src/scripts/check_memory_similarity.ts +16 -0
- package/src/scripts/check_module_management_neutral.ts +19 -11
- package/src/scripts/check_no_conflict_markers.ts +22 -1
- package/src/scripts/check_no_external_sources.ts +26 -1
- package/src/scripts/check_no_local_settings_committed.ts +37 -10
- package/src/scripts/check_no_new_legacy_path.ts +30 -1
- package/src/scripts/check_one_off_location.ts +43 -0
- package/src/scripts/check_originality_freshness.ts +25 -1
- package/src/scripts/check_overlay_cascade_subdirs.ts +21 -0
- package/src/scripts/check_pack_size.ts +22 -0
- package/src/scripts/check_preamble_payload_budget.ts +35 -5
- package/src/scripts/check_proposal.ts +24 -1
- package/src/scripts/check_public_catalog_links.ts +27 -0
- package/src/scripts/check_public_links.ts +19 -0
- package/src/scripts/check_quality_regression.ts +19 -0
- package/src/scripts/check_reach_channels.ts +44 -0
- package/src/scripts/check_reach_staleness.ts +27 -0
- package/src/scripts/check_release_adjacent_health.ts +28 -0
- package/src/scripts/check_release_highlights.ts +34 -0
- package/src/scripts/check_release_includes_discovery.ts +25 -6
- package/src/scripts/check_release_pr_shape.ts +18 -1
- package/src/scripts/check_release_published.ts +21 -0
- package/src/scripts/check_release_surface_equality.ts +22 -0
- package/src/scripts/check_release_trunk_sync.ts +19 -0
- package/src/scripts/check_reply_consistency.ts +22 -0
- package/src/scripts/check_roadmap_trackable.ts +20 -0
- package/src/scripts/check_role_doc_links.ts +23 -0
- package/src/scripts/check_rule_invariants.ts +14 -0
- package/src/scripts/check_secret_leak.ts +47 -0
- package/src/scripts/check_skill_gaps.ts +32 -0
- package/src/scripts/check_skill_requires.ts +19 -0
- package/src/scripts/check_source_pointer_freshness.ts +20 -0
- package/src/scripts/check_structural_breaking.ts +29 -2
- package/src/scripts/check_surface_tiers.ts +34 -0
- package/src/scripts/check_template_pin_drift.ts +23 -1
- package/src/scripts/check_test_coverage_diff.ts +17 -1
- package/src/scripts/check_token_optimizer_freshness.ts +18 -3
- package/src/scripts/check_token_quality_golden.ts +21 -0
- package/src/scripts/check_token_regression.ts +25 -0
- package/src/scripts/check_tracked_but_ignored.ts +26 -0
- package/src/scripts/check_trigger_eval_presence.ts +23 -1
- package/src/scripts/check_trigger_evals.ts +36 -0
- package/src/scripts/check_trunk_drift.ts +23 -0
- package/src/scripts/check_update_banner.ts +24 -0
- package/src/scripts/gate_scope_classify.ts +513 -0
- package/src/scripts/hook_manifest.yaml +1 -1
- package/src/scripts/hooks/block_kernel_rule_writes.ts +1 -1
- package/src/scripts/hooks/concern_registry.ts +2 -2
- package/src/scripts/lint_agent_security.ts +19 -0
- package/src/scripts/lint_agent_skill_names.ts +30 -0
- package/src/scripts/lint_agents_layout.ts +20 -0
- package/src/scripts/lint_agents_md.ts +20 -0
- package/src/scripts/lint_archived_skills.ts +24 -3
- package/src/scripts/lint_behavioural_eval_freshness.ts +29 -3
- package/src/scripts/lint_bench_ab.ts +25 -0
- package/src/scripts/lint_bench_corpus.ts +20 -4
- package/src/scripts/lint_breaking_changes_index.ts +24 -0
- package/src/scripts/lint_budget_ownership.ts +20 -3
- package/src/scripts/lint_changelog_rollback.ts +24 -0
- package/src/scripts/lint_command_flow_coverage.ts +22 -0
- package/src/scripts/lint_command_tiers.ts +29 -5
- package/src/scripts/lint_commit_subjects.ts +15 -0
- package/src/scripts/lint_confusables.ts +24 -0
- package/src/scripts/lint_consumer_internal_refs.ts +24 -0
- package/src/scripts/lint_design_quality.ts +22 -0
- package/src/scripts/lint_design_slop.ts +23 -0
- package/src/scripts/lint_discovery_manifest.ts +23 -0
- package/src/scripts/lint_discovery_vocabulary.ts +19 -0
- package/src/scripts/lint_documented_commands.ts +23 -0
- package/src/scripts/lint_empty_roadmaps.ts +23 -0
- package/src/scripts/lint_eval_fixture_citations.ts +19 -0
- package/src/scripts/lint_eval_freshness.ts +35 -0
- package/src/scripts/lint_examples.ts +18 -3
- package/src/scripts/lint_explain_trace.ts +23 -0
- package/src/scripts/lint_featured_skills.ts +26 -1
- package/src/scripts/lint_flows.ts +19 -0
- package/src/scripts/lint_frontmatter_boilerplate.ts +20 -0
- package/src/scripts/lint_ghostwriter_source.ts +26 -6
- package/src/scripts/lint_glama_drift.ts +24 -0
- package/src/scripts/lint_global_paths.ts +24 -0
- package/src/scripts/lint_governed_writes.ts +20 -0
- package/src/scripts/lint_hidden_unicode.ts +25 -0
- package/src/scripts/lint_hook_concern_budget.ts +39 -6
- package/src/scripts/lint_hook_manifest.ts +22 -0
- package/src/scripts/lint_instruction_smuggling.ts +23 -0
- package/src/scripts/lint_knowledge_scale.ts +32 -2
- package/src/scripts/lint_legal_pack.ts +31 -0
- package/src/scripts/lint_marketplace.ts +26 -0
- package/src/scripts/lint_marketplace_install_completeness.ts +23 -0
- package/src/scripts/lint_mcp_config_security.ts +24 -0
- package/src/scripts/lint_mcp_registry_manifest.ts +22 -1
- package/src/scripts/lint_memory_tripwire.ts +35 -0
- package/src/scripts/lint_missions.ts +23 -7
- package/src/scripts/lint_model_tier_coverage.ts +18 -0
- package/src/scripts/lint_namespace_collisions.ts +19 -0
- package/src/scripts/lint_no_new_atomic_commands.ts +33 -0
- package/src/scripts/lint_no_python_twin_rationale.ts +18 -0
- package/src/scripts/lint_one_off_age.ts +38 -2
- package/src/scripts/lint_orchestration_dsl.ts +23 -3
- package/src/scripts/lint_orchestrator_auto_detect.ts +19 -12
- package/src/scripts/lint_originality.ts +22 -4
- package/src/scripts/lint_originality_shingles.ts +28 -3
- package/src/scripts/lint_output_slop.ts +19 -0
- package/src/scripts/lint_override_kernel_guard.ts +30 -0
- package/src/scripts/lint_pack_first_win.ts +23 -0
- package/src/scripts/lint_pack_risk_class.ts +19 -3
- package/src/scripts/lint_persistence.ts +19 -0
- package/src/scripts/lint_persona_governance.ts +18 -3
- package/src/scripts/lint_positioning.ts +23 -0
- package/src/scripts/lint_pre_migration_refs.ts +24 -0
- package/src/scripts/lint_profile_overlay_set_only.ts +24 -0
- package/src/scripts/lint_provenance.ts +21 -0
- package/src/scripts/lint_provenance_vocabulary.ts +24 -1
- package/src/scripts/lint_readme_jargon.ts +21 -3
- package/src/scripts/lint_readme_serial_comma.ts +21 -3
- package/src/scripts/lint_readme_size.ts +21 -3
- package/src/scripts/lint_regression.ts +28 -0
- package/src/scripts/lint_roadmap_blockers.ts +43 -0
- package/src/scripts/lint_roadmap_ci_steps.ts +45 -0
- package/src/scripts/lint_roadmap_complexity.ts +47 -0
- package/src/scripts/lint_roadmap_later_disposition.ts +23 -0
- package/src/scripts/lint_rule_interactions.ts +16 -2
- package/src/scripts/lint_rule_tiers.ts +19 -6
- package/src/scripts/lint_showcase_sessions.ts +19 -3
- package/src/scripts/lint_skill_descriptions.ts +19 -0
- package/src/scripts/lint_skill_frontmatter_safety.ts +24 -0
- package/src/scripts/lint_skill_originality.ts +18 -3
- package/src/scripts/lint_skill_scripts_readonly.ts +20 -0
- package/src/scripts/lint_skill_tools.ts +84 -145
- package/src/scripts/lint_spawn_payload.ts +27 -1
- package/src/scripts/lint_store_boundary.ts +19 -0
- package/src/scripts/lint_subagent_determinism.ts +23 -1
- package/src/scripts/lint_supported_tools_matrix.ts +18 -0
- package/src/scripts/lint_surface_matrix.ts +19 -3
- package/src/scripts/lint_ticket_buildable.ts +23 -0
- package/src/scripts/lint_topics_yaml.ts +19 -12
- package/src/scripts/lint_trigger_precision.ts +27 -0
- package/src/scripts/lint_trust_coherence.ts +21 -0
- package/src/scripts/lint_ui_stack_bundles.ts +17 -3
- package/src/scripts/lint_value_dashboard.ts +19 -3
- package/src/scripts/lint_versioned_cache.ts +19 -1
- package/src/scripts/lint_workflow_security.ts +22 -14
- package/src/scripts/pr_url_reminder_hook.ts +1 -1
- package/src/scripts/skill_collision_clusters.ts +37 -3
- package/src/scripts/skill_discovery.ts +20 -0
- package/src/scripts/skill_eval_coverage.ts +22 -0
- package/src/scripts/skill_overlap.ts +32 -6
- package/src/scripts/skill_preview.ts +31 -0
- package/src/scripts/skill_trigger_eval.ts +18 -0
- package/src/scripts/skill_usage_collect.ts +21 -0
- package/src/scripts/skill_usage_report.ts +21 -0
- package/src/scripts/sweep_dead_scan_roots.ts +11 -3
- package/src/scripts/verify_physical_move.ts +24 -0
- package/src/scripts/worktree_cleanup_check.ts +319 -4
- package/src/scripts/check_bite_sized_granularity.ts +0 -116
- 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
|
-
};
|