@event4u/agent-config 9.10.0 → 9.11.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 (121) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +59 -0
  3. package/README.md +12 -15
  4. package/agents/templates/.ai-council.yml.example +481 -0
  5. package/agents/templates/.ai-video.xml.example +247 -0
  6. package/dist/agent-src/rules/design-fidelity.md +1 -1
  7. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +15 -2
  8. package/dist/agent-src/skills/fe-design/SKILL.md +10 -0
  9. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  10. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +30 -30
  11. package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +88 -33
  12. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +20 -0
  13. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +20 -1
  14. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +179 -0
  15. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +155 -4
  16. package/dist/agent-src/templates/scripts/work_engine/state.ts +21 -4
  17. package/dist/cli/initRouting.js +74 -11
  18. package/dist/cli/initRouting.js.map +1 -1
  19. package/dist/cli/main.js +14 -3
  20. package/dist/cli/main.js.map +1 -1
  21. package/dist/cli-delegate/chunk-4SV3XGFA.js +6910 -0
  22. package/dist/cli-delegate/chunk-736JCWLM.js +1104 -0
  23. package/dist/cli-delegate/chunk-7DSAMZFU.js +356 -0
  24. package/dist/cli-delegate/chunk-7HQ52DHU.js +74 -0
  25. package/dist/cli-delegate/chunk-BJGXZNPM.js +266 -0
  26. package/dist/cli-delegate/chunk-FTAISGDQ.js +117 -0
  27. package/dist/cli-delegate/chunk-GME3Q44L.js +82 -0
  28. package/dist/cli-delegate/chunk-GRRPEPRN.js +336 -0
  29. package/dist/cli-delegate/chunk-HJ6DAJHR.js +502 -0
  30. package/dist/cli-delegate/chunk-IR7P7JWA.js +872 -0
  31. package/dist/cli-delegate/chunk-J55WI3RR.js +47 -0
  32. package/dist/cli-delegate/chunk-MCJYCQPF.js +35 -0
  33. package/dist/cli-delegate/chunk-NDJLNC6Q.js +169 -0
  34. package/dist/cli-delegate/chunk-OMIVVCG2.js +26 -0
  35. package/dist/cli-delegate/chunk-OY53J6II.js +7336 -0
  36. package/dist/cli-delegate/chunk-RDGRHAAB.js +259 -0
  37. package/dist/cli-delegate/chunk-TFG57JJM.js +1969 -0
  38. package/dist/cli-delegate/chunk-XX6TOPD7.js +715 -0
  39. package/dist/cli-delegate/chunk-YMFO6FDN.js +10603 -0
  40. package/dist/cli-delegate/cmd_analyze_session.js +294 -0
  41. package/dist/cli-delegate/cmd_conformance.js +646 -0
  42. package/dist/cli-delegate/cmd_converge.js +326 -0
  43. package/dist/cli-delegate/cmd_doctor.js +144 -0
  44. package/dist/cli-delegate/cmd_explain.js +2508 -0
  45. package/dist/cli-delegate/cmd_export.js +296 -0
  46. package/dist/cli-delegate/cmd_fleet.js +332 -0
  47. package/dist/cli-delegate/cmd_memory_get.js +3878 -0
  48. package/dist/cli-delegate/cmd_migrate.js +11 -0
  49. package/dist/cli-delegate/cmd_preflight.js +270 -0
  50. package/dist/cli-delegate/cmd_prune.js +444 -0
  51. package/dist/cli-delegate/cmd_refresh.js +28 -0
  52. package/dist/cli-delegate/cmd_settings_check.js +574 -0
  53. package/dist/cli-delegate/cmd_settings_migrate.js +223 -0
  54. package/dist/cli-delegate/cmd_sync.js +264 -0
  55. package/dist/cli-delegate/cmd_uninstall.js +656 -0
  56. package/dist/cli-delegate/cmd_update.js +425 -0
  57. package/dist/cli-delegate/cmd_upgrade.js +444 -0
  58. package/dist/cli-delegate/cmd_validate.js +305 -0
  59. package/dist/cli-delegate/cmd_versions.js +370 -0
  60. package/dist/discovery/deprecation-report.md +1 -1
  61. package/dist/discovery/discovery-manifest.json +14 -7
  62. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  63. package/dist/discovery/discovery-manifest.summary.md +2 -2
  64. package/dist/discovery/orphan-report.md +1 -1
  65. package/dist/discovery/packs.json +12 -7
  66. package/dist/discovery/trust-report.md +1 -1
  67. package/dist/discovery/workspaces.json +4 -3
  68. package/dist/install/emit_host_rules_cli.js +2 -1
  69. package/dist/install/emit_host_rules_cli.js.map +1 -1
  70. package/dist/install/install.mjs +410 -378
  71. package/dist/install/rule_scope.js +5 -1
  72. package/dist/install/rule_scope.js.map +1 -1
  73. package/dist/install/toolDetection.js +40 -12
  74. package/dist/install/toolDetection.js.map +1 -1
  75. package/dist/install/wizard-plan.js +2 -2
  76. package/dist/install/wizard-plan.js.map +1 -1
  77. package/dist/mcp/registry-manifest.json +1 -1
  78. package/dist/mcp/server.json +2 -2
  79. package/dist/mcp/server.mjs +1614 -765
  80. package/dist/router.json +1 -1
  81. package/package.json +4 -2
  82. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +30 -30
  83. package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +88 -33
  84. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +20 -0
  85. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +20 -1
  86. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +179 -0
  87. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +155 -4
  88. package/src/agent-src/templates/scripts/work_engine/state.ts +21 -4
  89. package/src/config/discovery/packs.yml +7 -0
  90. package/src/config/evaluator-budgets.json +1 -1
  91. package/src/config/pack-size-budget.json +27 -0
  92. package/src/install/emit_host_rules_cli.ts +2 -1
  93. package/src/install/rule_scope.ts +5 -1
  94. package/src/install/toolDetection.ts +39 -8
  95. package/src/install/wizard-plan.ts +2 -2
  96. package/src/scripts/_cli/cmd_conformance.ts +2 -1
  97. package/src/scripts/_cli/cmd_converge.ts +2 -1
  98. package/src/scripts/_cli/cmd_doctor.ts +214 -13
  99. package/src/scripts/_cli/cmd_export.ts +2 -1
  100. package/src/scripts/_cli/cmd_fleet.ts +2 -1
  101. package/src/scripts/_cli/cmd_migrate.ts +2 -1
  102. package/src/scripts/_cli/cmd_preflight.ts +2 -1
  103. package/src/scripts/_cli/cmd_refresh.ts +2 -1
  104. package/src/scripts/_cli/cmd_update.ts +2 -1
  105. package/src/scripts/_cli/cmd_upgrade.ts +2 -1
  106. package/src/scripts/_cli/cmd_versions.ts +2 -1
  107. package/src/scripts/_cli/detection_report.ts +480 -0
  108. package/src/scripts/_dispatch.bash +52 -14
  109. package/src/scripts/_lib/changelog_eras.ts +103 -9
  110. package/src/scripts/_lib/environment_detector.ts +441 -0
  111. package/src/scripts/_lib/package_root.ts +72 -0
  112. package/src/scripts/ai_council/config.ts +15 -7
  113. package/src/scripts/ai_council/modes.ts +68 -2
  114. package/src/scripts/ai_council/transport_resolver.ts +331 -0
  115. package/src/scripts/check_bundle_path_leakage.ts +10 -4
  116. package/src/scripts/check_dependency_floors.ts +153 -0
  117. package/src/scripts/check_pack_size.ts +188 -0
  118. package/src/scripts/council_cli.ts +6 -2
  119. package/src/scripts/evaluator_umbrella.sh +34 -1
  120. package/src/scripts/lint_eval_fixture_citations.ts +113 -0
  121. package/src/scripts/lint_ui_stack_bundles.ts +170 -0
@@ -39,6 +39,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
39
39
  import * as YAML from 'yaml';
40
40
 
41
41
  import * as user_global_paths from '../_lib/user_global_paths.js';
42
+ import { resolvePackageRoot } from '../_lib/package_root.js';
42
43
 
43
44
  type Dict = Record<string, unknown>;
44
45
 
@@ -67,7 +68,7 @@ const _HERE = fileURLToPath(import.meta.url);
67
68
 
68
69
  /** Resolve the @event4u/agent-config package root (this repo). */
69
70
  function _package_root(): string {
70
- return path.resolve(path.dirname(_HERE), '..', '..', '..');
71
+ return resolvePackageRoot(import.meta.url);
71
72
  }
72
73
 
73
74
  const SETTINGS_FILENAME = 'agent-settings.yml';
@@ -102,7 +102,22 @@ import {
102
102
  } from '../_lib/agent_settings.js';
103
103
  import * as ai_council_clients from '../ai_council/clients.js';
104
104
  import * as ai_council_config from '../ai_council/config.js';
105
+ import {
106
+ PROVIDER_CLI_META,
107
+ codexHome,
108
+ detectEnvironment,
109
+ } from '../_lib/environment_detector.js';
110
+ import {
111
+ absentCouncilFacts,
112
+ buildDetectionReport,
113
+ detectionJson,
114
+ renderDetectionLines,
115
+ type CouncilFacts,
116
+ type CouncilMemberFacts,
117
+ type DetectionReport,
118
+ } from './detection_report.js';
105
119
  import { review_gate_doctor_signal } from '../ai_team/review_gate.js';
120
+ import { resolvePackageRoot } from '../_lib/package_root.js';
106
121
  import {
107
122
  LEGACY_ALL,
108
123
  excludedRuleBasenames,
@@ -758,6 +773,7 @@ const CHECK_IDS = [
758
773
  'humanizer-runtime',
759
774
  'tier-usage-readiness',
760
775
  'council-cli',
776
+ 'detection',
761
777
  'team',
762
778
  'unsupported-combos',
763
779
  'wizard-state',
@@ -784,6 +800,7 @@ const GLOBAL_CHECK_IDS: ReadonlySet<string> = new Set([
784
800
  'humanizer-runtime',
785
801
  'tier-usage-readiness',
786
802
  'council-cli',
803
+ 'detection',
787
804
  'team',
788
805
  'wizard-state',
789
806
  'settings-review-pending',
@@ -994,7 +1011,7 @@ function _check_manifest_integrity(manifest: Dict): Dict {
994
1011
  /** Resolve the @event4u/agent-config package root (this repo). */
995
1012
  function _package_root(): string {
996
1013
  // cmd_doctor lives at src/scripts/_cli/cmd_doctor.{py,ts}; parents[3] = repo.
997
- return path.resolve(path.dirname(_HERE), '..', '..', '..');
1014
+ return resolvePackageRoot(import.meta.url);
998
1015
  }
999
1016
 
1000
1017
  /** Read `version` from this package's package.json; null on error. */
@@ -2055,16 +2072,13 @@ function osErrorStr(exc: unknown): string {
2055
2072
  }
2056
2073
 
2057
2074
  /**
2058
- * Provider → (default binary, billable flag). Mirrors the `CliClient`
2059
- * subclass attributes without importing them at module load time.
2075
+ * Provider → (default binary, community-wrapper flag). Canonical definition
2076
+ * lives in `_lib/environment_detector.ts` so this check and the detection
2077
+ * report cannot drift on the billing-relevant boolean; aliased here to keep
2078
+ * the existing call sites unchanged.
2060
2079
  */
2061
- const _CLI_PROVIDER_META: Record<string, [string, boolean]> = {
2062
- anthropic: ['claude', false],
2063
- openai: ['codex', false],
2064
- gemini: ['gemini', false],
2065
- xai: ['grok', true],
2066
- perplexity: ['perplexity', true],
2067
- };
2080
+ const _CLI_PROVIDER_META: Readonly<Record<string, readonly [string, boolean]>> =
2081
+ PROVIDER_CLI_META;
2068
2082
 
2069
2083
  function _check_council_cli(project_root: string): Dict {
2070
2084
  // Python wraps the council-module import in a try/except ImportError so a
@@ -2207,11 +2221,12 @@ function pyFloat(value: number): string {
2207
2221
 
2208
2222
  /**
2209
2223
  * Codex CLI home — `CODEX_HOME` env override (the codex CLI's own
2210
- * convention), else `~/.codex`.
2224
+ * convention), else `~/.codex`. Single definition in
2225
+ * `_lib/environment_detector.ts` so the detection report and this check probe
2226
+ * the same path; aliased here to keep the existing call sites unchanged.
2211
2227
  */
2212
2228
  function _codex_home(): string {
2213
- const env = (process.env['CODEX_HOME'] ?? '').trim();
2214
- return env !== '' ? env : path.join(os.homedir(), '.codex');
2229
+ return codexHome();
2215
2230
  }
2216
2231
 
2217
2232
  /**
@@ -2368,6 +2383,162 @@ function _read_ai_team_block(project_root: string): Dict {
2368
2383
  * check reports ok ("team mode not configured (default-off)"); WARN fires
2369
2384
  * only on failing sub-signals or inconsistent half-configured states.
2370
2385
  */
2386
+ // ---------------------------------------------------------------------------
2387
+ // detection check (road-to-zero-ceremony-detection Phases 3 + 4)
2388
+ // ---------------------------------------------------------------------------
2389
+
2390
+ /** Per-process memo so the check row and the rendered section agree exactly. */
2391
+ let _detection_memo: { root: string; report: DetectionReport } | null = null;
2392
+
2393
+ /**
2394
+ * Read the council-config facts the detection rows need. Never throws — an
2395
+ * absent or unreadable config degrades to "no config", which the report renders
2396
+ * as a fix rather than a failure.
2397
+ */
2398
+ function _read_council_facts(project_root: string): CouncilFacts {
2399
+ const { load_council_config, resolve_config_path } = ai_council_config;
2400
+ const config_path = String(resolve_config_path(project_root));
2401
+ if (!pathExists(config_path)) {
2402
+ return absentCouncilFacts(config_path);
2403
+ }
2404
+ let cfg: ai_council_config.CouncilConfig;
2405
+ try {
2406
+ cfg = load_council_config(config_path);
2407
+ } catch {
2408
+ // An invalid config is reported by the `council-cli` check, which owns
2409
+ // that problem; here it simply means no facts are derivable.
2410
+ return absentCouncilFacts(config_path);
2411
+ }
2412
+ const members: Record<string, CouncilMemberFacts> = {};
2413
+ for (const [name, m] of cfg.members) {
2414
+ members[name] = {
2415
+ enabled: m.enabled,
2416
+ mode: m.mode,
2417
+ binary: m.binary,
2418
+ apiKeyRef: m.api_key_ref,
2419
+ };
2420
+ }
2421
+ const cliCaps: Record<string, number> = {};
2422
+ for (const [provider, cap] of cfg.cli_call_budget.max_calls_per_day) {
2423
+ cliCaps[provider] = cap;
2424
+ }
2425
+ return {
2426
+ configPath: config_path,
2427
+ configPresent: true,
2428
+ enabled: cfg.enabled,
2429
+ defaultsMode: cfg.defaults.mode,
2430
+ members,
2431
+ cliCaps,
2432
+ costBudgetMaxUsd: cfg.cost_budget.max_total_usd,
2433
+ };
2434
+ }
2435
+
2436
+ /** Build (once per process, per root) the detection report. */
2437
+ function _detection_report(project_root: string): DetectionReport {
2438
+ if (_detection_memo !== null && _detection_memo.root === project_root) {
2439
+ return _detection_memo.report;
2440
+ }
2441
+ const council = _read_council_facts(project_root);
2442
+ let used: Record<string, number> = {};
2443
+ try {
2444
+ const counts = ai_council_clients.load_cli_call_counts();
2445
+ for (const provider of Object.keys(council.cliCaps)) {
2446
+ used[provider] = Number((counts as Dict)[provider] ?? 0);
2447
+ }
2448
+ } catch {
2449
+ used = {};
2450
+ }
2451
+ const report = buildDetectionReport({
2452
+ environment: detectEnvironment(),
2453
+ council,
2454
+ cliCallsUsed: used,
2455
+ });
2456
+ _detection_memo = { root: project_root, report };
2457
+ return report;
2458
+ }
2459
+
2460
+ /** Test seam — drop the memo so a fixture root is not served a stale report. */
2461
+ function _reset_detection_memo(): void {
2462
+ _detection_memo = null;
2463
+ }
2464
+
2465
+ /**
2466
+ * `detection` health check — what this machine can do, and what it is allowed
2467
+ * to do, as two separate facts.
2468
+ *
2469
+ * Reports per provider: detected · authenticated · auth source · billing class
2470
+ * · enabled-in-config, plus the transport `auto` would pick and a one-line fix
2471
+ * for every unusable capability. All rows come from the read-only, spend-free
2472
+ * detector; nothing here makes a provider call.
2473
+ *
2474
+ * Status model — a recorded consent decision is NOT a defect:
2475
+ *
2476
+ * - no council config, or council disabled → `ok` ("not configured"), with the
2477
+ * fix. Absent feature ≠ broken feature (same stance as the `team` check).
2478
+ * - detected but `enabled: false` → `ok`. That flag is a deliberate spend gate;
2479
+ * warning on it would train the user to silence their own consent record.
2480
+ * - enabled to spend but no transport resolves → `warn`. That IS broken: the
2481
+ * member is permitted to run and cannot.
2482
+ */
2483
+ function _check_detection(project_root: string): Dict {
2484
+ const report = _detection_report(project_root);
2485
+ const detected = report.providers.filter((r) => r.detected);
2486
+ const hosts_installed = report.hosts.filter((h) => h.installed).length;
2487
+
2488
+ if (!report.council_config_present) {
2489
+ return {
2490
+ id: 'detection',
2491
+ status: 'ok',
2492
+ message:
2493
+ `${hosts_installed} host(s) · ${detected.length} provider(s) detected · ` +
2494
+ 'council not configured (default-off)',
2495
+ remedy: report.providers[0]?.fix ?? `create ${report.council_config_path}`,
2496
+ };
2497
+ }
2498
+
2499
+ if (!report.council_enabled) {
2500
+ return {
2501
+ id: 'detection',
2502
+ status: 'ok',
2503
+ message:
2504
+ `${hosts_installed} host(s) · ${detected.length} provider(s) detected · ` +
2505
+ 'council disabled (default-off)',
2506
+ remedy: `set \`enabled: true\` in ${report.council_config_path}`,
2507
+ };
2508
+ }
2509
+
2510
+ const broken = report.providers.filter((r) => r.enabledInConfig && !r.available);
2511
+ const spending = report.providers.filter((r) => r.enabledInConfig && r.available);
2512
+ const unpermitted = detected.filter((r) => !r.enabledInConfig);
2513
+
2514
+ const summary =
2515
+ `${hosts_installed} host(s) · ${spending.length} member(s) ready ` +
2516
+ `(${spending.map((r) => `${r.provider}→${r.transport}/${r.billing}`).join(', ') || 'none'})` +
2517
+ (unpermitted.length === 0
2518
+ ? ''
2519
+ : ` · ${unpermitted.length} detected but not allowed to spend: ` +
2520
+ unpermitted.map((r) => r.provider).join(', '));
2521
+
2522
+ if (broken.length > 0) {
2523
+ return {
2524
+ id: 'detection',
2525
+ status: 'warn',
2526
+ message: `${summary} · ${broken.length} enabled member(s) have no transport`,
2527
+ remedy: broken.map((r) => `${r.provider}: ${r.fix}`).join(' · '),
2528
+ };
2529
+ }
2530
+
2531
+ return {
2532
+ id: 'detection',
2533
+ status: 'ok',
2534
+ message: summary,
2535
+ remedy:
2536
+ unpermitted.length === 0
2537
+ ? `run \`agent-config doctor --check detection\` for the full table`
2538
+ : unpermitted.map((r) => r.fix).join(' · '),
2539
+ };
2540
+ }
2541
+
2371
2542
  function _check_team(project_root: string): Dict {
2372
2543
  const ai_team = _read_ai_team_block(project_root);
2373
2544
  const enabled = _settings_flag(ai_team['enabled']);
@@ -2819,6 +2990,7 @@ function _run_checks(
2819
2990
  'humanizer-runtime': () => _check_humanizer_runtime(),
2820
2991
  'tier-usage-readiness': () => _check_tier_usage_readiness(project_root),
2821
2992
  'council-cli': () => _check_council_cli(project_root),
2993
+ 'detection': () => _check_detection(project_root),
2822
2994
  team: () => _check_team(project_root),
2823
2995
  'unsupported-combos': () => _check_unsupported_combos(manifest),
2824
2996
  'wizard-state': _check_wizard_state,
@@ -2895,6 +3067,7 @@ function _run_checks_no_manifest(
2895
3067
  'humanizer-runtime': () => _check_humanizer_runtime(),
2896
3068
  'tier-usage-readiness': () => _check_tier_usage_readiness(project_root),
2897
3069
  'council-cli': () => _check_council_cli(project_root),
3070
+ 'detection': () => _check_detection(project_root),
2898
3071
  team: () => _check_team(project_root),
2899
3072
  'unsupported-combos': () => _skipped_manifest_check('unsupported-combos'),
2900
3073
  'wizard-state': _check_wizard_state,
@@ -2945,8 +3118,10 @@ function _run_no_manifest(
2945
3118
  );
2946
3119
  }
2947
3120
  _emit_checks_text(checks);
3121
+ _emit_detection_text(project_root, checks);
2948
3122
  } else {
2949
3123
  _emit_checks_text(checks);
3124
+ _emit_detection_text(project_root, checks);
2950
3125
  }
2951
3126
 
2952
3127
  if (opts.check !== null) {
@@ -2983,6 +3158,12 @@ function _emit_json(
2983
3158
  }
2984
3159
  if (checks !== null) {
2985
3160
  payload['checks'] = checks;
3161
+ // The detection section rides along whenever checks ran, so the agent /
3162
+ // GUI contract carries the full provider → transport → billing table
3163
+ // and not just the one-line check row.
3164
+ if (checks.some((c) => c['id'] === 'detection')) {
3165
+ payload['detection'] = detectionJson(_detection_report(project_root));
3166
+ }
2986
3167
  }
2987
3168
  print(_jsonDumpsIndentAscii(payload, 2));
2988
3169
  }
@@ -3002,6 +3183,21 @@ function _emit_checks_text(checks: Dict[]): void {
3002
3183
  print('');
3003
3184
  }
3004
3185
 
3186
+ /**
3187
+ * The detection section in text mode. Rendered from the same report the
3188
+ * `detection` check row and the `--json` payload use, so the three cannot
3189
+ * disagree about which members spend money.
3190
+ */
3191
+ function _emit_detection_text(project_root: string, checks: Dict[]): void {
3192
+ if (!checks.some((c) => c['id'] === 'detection')) {
3193
+ return;
3194
+ }
3195
+ for (const line of renderDetectionLines(_detection_report(project_root))) {
3196
+ print(line);
3197
+ }
3198
+ print('');
3199
+ }
3200
+
3005
3201
  function _emit_text(
3006
3202
  project_root: string,
3007
3203
  missing: Dict[],
@@ -3304,6 +3500,7 @@ function main(argv: string[] | null = null): number {
3304
3500
  print(` 📍 project_root: ${project_root} (origin: ${origin})`);
3305
3501
  }
3306
3502
  _emit_checks_text(checks);
3503
+ _emit_detection_text(project_root, checks);
3307
3504
  if (opts.check === null) {
3308
3505
  _emit_text(project_root, missing, modified, foreign, tag_drift);
3309
3506
  }
@@ -3389,6 +3586,10 @@ export {
3389
3586
  _check_mcp_beta_readiness,
3390
3587
  _check_tier_usage_readiness,
3391
3588
  _check_council_cli,
3589
+ _check_detection,
3590
+ _detection_report,
3591
+ _read_council_facts,
3592
+ _reset_detection_memo,
3392
3593
  _check_team,
3393
3594
  _check_unsupported_combos,
3394
3595
  _check_wizard_state,
@@ -44,6 +44,7 @@ import * as os from 'node:os';
44
44
  import * as path from 'node:path';
45
45
  import * as crypto from 'node:crypto';
46
46
  import { fileURLToPath, pathToFileURL } from 'node:url';
47
+ import { resolvePackageRoot } from '../_lib/package_root.js';
47
48
 
48
49
  import {
49
50
  AIDER_MARKER,
@@ -57,7 +58,7 @@ import {
57
58
  ZED_MARKER,
58
59
  } from '../install.js';
59
60
 
60
- const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
61
+ const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
61
62
  const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'dist/agent-src', 'templates');
62
63
 
63
64
  // ---------------------------------------------------------------------------
@@ -32,9 +32,10 @@ import * as YAML from 'yaml';
32
32
 
33
33
  import { runPreflight, hasBlockingFinding, type PreflightFinding } from '../../install/preflight.js';
34
34
  import type { ConflictPolicy } from '../../install/types.js';
35
+ import { resolvePackageRoot } from '../_lib/package_root.js';
35
36
 
36
37
  const _HERE = fileURLToPath(import.meta.url);
37
- const PACKAGE_ROOT = path.resolve(path.dirname(_HERE), '..', '..', '..');
38
+ const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
38
39
 
39
40
  /** One fleet target, parsed from `fleet.yaml`. */
40
41
  export interface FleetRepo {
@@ -75,6 +75,7 @@ import process from 'node:process';
75
75
  import { fileURLToPath, pathToFileURL } from 'node:url';
76
76
 
77
77
  import { resolve_project_root } from '../_lib/agent_settings.js';
78
+ import { resolvePackageRoot } from '../_lib/package_root.js';
78
79
  // NOTE: the v0→v1 migrator is NOT statically imported. It lives in the
79
80
  // consumer-shipped work_engine template, which ships as `.ts` (run via tsx),
80
81
  // while this CLI is compiled to `dist/cli/*.js` and run under plain `node` in
@@ -521,7 +522,7 @@ function _load_state_migrator(): StateMigrator | null {
521
522
  // Locate the shipped v0→v1 migration driver (`.ts`). Prefer the shipped
522
523
  // `dist/` tree; fall back to the dev `src/` tree. A stripped install with
523
524
  // no engine yields `null` (Python ImportError parity).
524
- const pkg_root = path.resolve(_HERE_DIR, '..', '..', '..');
525
+ const pkg_root = resolvePackageRoot(import.meta.url);
525
526
  const rel = path.join(
526
527
  'agent-src', 'templates', 'scripts', 'work_engine', 'migration', 'v0_to_v1.ts',
527
528
  );
@@ -28,11 +28,12 @@ import {
28
28
  } from '../../install/preflight.js';
29
29
  import { GLOBAL_DEPLOY_SOURCES, expandWizardSources } from '../../install/wizard-plan.js';
30
30
  import type { ConflictPolicy } from '../../install/types.js';
31
+ import { resolvePackageRoot } from '../_lib/package_root.js';
31
32
 
32
33
  const _HERE = fileURLToPath(import.meta.url);
33
34
 
34
35
  /** Package root — three levels above `src/scripts/_cli/`. */
35
- const PACKAGE_ROOT = path.resolve(path.dirname(_HERE), '..', '..', '..');
36
+ const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
36
37
 
37
38
  const USAGE =
38
39
  'usage: cmd_preflight [-h] [--tools a,b,...] [--target DIR] [--json]\n';
@@ -69,8 +69,9 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
69
69
  import * as cli_wrapper from '../_lib/cli_wrapper.js';
70
70
  import * as sync_gitignore from '../sync_gitignore.js';
71
71
  import * as sync_gitattributes from '../sync_gitattributes.js';
72
+ import { resolvePackageRoot } from '../_lib/package_root.js';
72
73
 
73
- const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
74
+ const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
74
75
 
75
76
  // ---------------------------------------------------------------------------
76
77
  // Parity primitives (ADR-200).
@@ -67,6 +67,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
67
67
 
68
68
  import * as installed_lock from '../_lib/installed_lock.js';
69
69
  import * as update_check from '../_lib/update_check.js';
70
+ import { resolvePackageRoot } from '../_lib/package_root.js';
70
71
  import {
71
72
  DEFAULT_PROJECT_FILE,
72
73
  LOCAL_PROJECT_FILE,
@@ -550,7 +551,7 @@ function _refresh_global_lockfile(version: string, out: OutSink): void {
550
551
 
551
552
  /** Read `version` from the package's own `package.json`. */
552
553
  function _detect_installed_version(): string {
553
- const pkg_json = path.join(path.resolve(_HERE_DIR, '..', '..', '..'), 'package.json');
554
+ const pkg_json = path.join(resolvePackageRoot(import.meta.url), 'package.json');
554
555
  try {
555
556
  const data = JSON.parse(fs.readFileSync(pkg_json, { encoding: 'utf-8' })) as Record<
556
557
  string,
@@ -93,9 +93,10 @@ import * as claude_plugin from '../_lib/claude_plugin.js';
93
93
  import { event4u_root, write_target } from '../_lib/user_global_paths.js';
94
94
  import { project_settings_path } from '../_lib/agent_settings.js';
95
95
  import { _is_source_repo } from './cmd_refresh.js';
96
+ import { resolvePackageRoot } from '../_lib/package_root.js';
96
97
 
97
98
  const PACKAGE_NAME = '@event4u/agent-config';
98
- const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
99
+ const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
99
100
 
100
101
  // ---------------------------------------------------------------------------
101
102
  // Parity primitives (ADR-200).
@@ -47,6 +47,7 @@ import { spawnSync } from 'node:child_process';
47
47
  import { fileURLToPath, pathToFileURL } from 'node:url';
48
48
 
49
49
  import { project_settings_path, resolve_project_root } from '../_lib/agent_settings.js';
50
+ import { resolvePackageRoot } from '../_lib/package_root.js';
50
51
 
51
52
  const PACKAGE_NAME = '@event4u/agent-config';
52
53
 
@@ -171,7 +172,7 @@ function _project_root(): string {
171
172
  /** Return `version` from the local `package.json`, or `""` if absent. */
172
173
  function _local_package_version(): string {
173
174
  const candidates = [
174
- path.join(path.resolve(_HERE_DIR, '..', '..', '..'), 'package.json'),
175
+ path.join(resolvePackageRoot(import.meta.url), 'package.json'),
175
176
  path.join(_project_root(), 'package.json'),
176
177
  ];
177
178
  for (const p of candidates) {