@event4u/agent-config 14.8.0 → 14.10.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 (170) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +214 -237
  3. package/README.md +1 -1
  4. package/agents/templates/.ai-council.yml.example +34 -4
  5. package/dist/agent-src/commands/pr/merge.md +9 -5
  6. package/dist/agent-src/commands/review/changes.md +95 -14
  7. package/dist/agent-src/commands/roadmap/process-full.md +2 -2
  8. package/dist/agent-src/contexts/execution/host-capability-manifest.md +77 -0
  9. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +36 -0
  10. package/dist/agent-src/contexts/execution/subagent-response-contract.md +80 -0
  11. package/dist/agent-src/rules/untrusted-input-defense.md +9 -3
  12. package/dist/agent-src/skills/async-python-patterns/SKILL.md +1 -1
  13. package/dist/agent-src/skills/code-refactoring/SKILL.md +1 -1
  14. package/dist/agent-src/skills/code-review/evals/evals.json +87 -46
  15. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  16. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +1 -1
  17. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  18. package/dist/agent-src/skills/discovery-interview/SKILL.md +1 -1
  19. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  20. package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -1
  21. package/dist/agent-src/skills/editorial-calendar/SKILL.md +1 -1
  22. package/dist/agent-src/skills/github-ci/SKILL.md +1 -1
  23. package/dist/agent-src/skills/humanizer/SKILL.md +39 -0
  24. package/dist/agent-src/skills/humanizer/evals/strip_fixtures.json +57 -0
  25. package/dist/agent-src/skills/humanizer/references/fixtures.md +54 -0
  26. package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +1 -1
  27. package/dist/agent-src/skills/judge-injection-defense/SKILL.md +1 -1
  28. package/dist/agent-src/skills/judge-spec-compliance/SKILL.md +154 -0
  29. package/dist/agent-src/skills/judge-synthesis/SKILL.md +45 -0
  30. package/dist/agent-src/skills/laravel-validation/SKILL.md +1 -1
  31. package/dist/agent-src/skills/legal-intake-triage/SKILL.md +1 -1
  32. package/dist/agent-src/skills/legal-practice-profile/SKILL.md +1 -1
  33. package/dist/agent-src/skills/messaging-architecture/SKILL.md +1 -1
  34. package/dist/agent-src/skills/migration-architect/SKILL.md +1 -1
  35. package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -1
  36. package/dist/agent-src/skills/module-management/SKILL.md +1 -1
  37. package/dist/agent-src/skills/motion-choreographer/SKILL.md +1 -1
  38. package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
  39. package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
  40. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +1 -1
  41. package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
  42. package/dist/agent-src/skills/roadmap-writing/SKILL.md +18 -18
  43. package/dist/agent-src/skills/scene-expander/SKILL.md +1 -1
  44. package/dist/agent-src/skills/secrets-management/SKILL.md +1 -1
  45. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  46. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  47. package/dist/agent-src/templates/roadmaps.md +8 -0
  48. package/dist/cli/registry.js +2 -0
  49. package/dist/cli/registry.js.map +1 -1
  50. package/dist/cli-delegate/{chunk-MMSGVZKV.js → chunk-77GR3VD4.js} +65 -40
  51. package/dist/cli-delegate/{chunk-Q26HT4QT.js → chunk-E46KPN6K.js} +251 -150
  52. package/dist/cli-delegate/{chunk-EEJUMCDZ.js → chunk-PLSG6UL5.js} +1 -1
  53. package/dist/cli-delegate/cmd_conformance.js +89 -13
  54. package/dist/cli-delegate/cmd_doctor.js +3 -3
  55. package/dist/cli-delegate/cmd_handoff.js +2 -2
  56. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  57. package/dist/cli-delegate/cmd_route_audit.js +1 -1
  58. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  59. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  60. package/dist/discovery/deprecation-report.md +1 -1
  61. package/dist/discovery/discovery-manifest.json +64 -42
  62. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  63. package/dist/discovery/discovery-manifest.summary.md +3 -3
  64. package/dist/discovery/dormancy-report.md +1 -1
  65. package/dist/discovery/orphan-report.md +1 -1
  66. package/dist/discovery/packs.json +6 -5
  67. package/dist/discovery/trust-report.md +2 -2
  68. package/dist/discovery/workspaces.json +5 -4
  69. package/dist/hooks/dispatch.js +562 -204
  70. package/dist/mcp/registry-manifest.json +3 -3
  71. package/dist/mcp/server.json +2 -2
  72. package/dist/mcp/server.mjs +808 -331
  73. package/dist/scripts/_lib/claude_plugin.js +162 -0
  74. package/dist/scripts/_lib/claude_plugin.js.map +1 -0
  75. package/dist/scripts/_lib/environment_detector.js +397 -0
  76. package/dist/scripts/_lib/environment_detector.js.map +1 -0
  77. package/dist/scripts/_lib/spawn_env.js +129 -0
  78. package/dist/scripts/_lib/spawn_env.js.map +1 -0
  79. package/dist/scripts/ai_council/modes.js +199 -0
  80. package/dist/scripts/ai_council/modes.js.map +1 -0
  81. package/dist/scripts/ai_council/transport_resolver.js +418 -0
  82. package/dist/scripts/ai_council/transport_resolver.js.map +1 -0
  83. package/dist/server/routes/wizard.js +3 -2
  84. package/dist/server/routes/wizard.js.map +1 -1
  85. package/dist/ui/assets/index-Cxgy63kz.js +26 -0
  86. package/dist/ui/assets/index-Cxgy63kz.js.map +1 -0
  87. package/dist/ui/index.html +1 -1
  88. package/docs/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
  89. package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +17 -0
  90. package/package.json +7 -3
  91. package/src/config/estate-count-budget.json +13 -744
  92. package/src/config/evaluator-budgets.json +4 -4
  93. package/src/config/gate-coverage.yml +267 -9
  94. package/src/config/gate-violation-baselines.json +72 -72
  95. package/src/config/preamble-payload-budget.json +71 -67
  96. package/src/config/publish-surface.json +60 -0
  97. package/src/config/requirements-trace-budget.json +32 -0
  98. package/src/config/rule-stub-ceilings.json +8 -1
  99. package/src/scripts/_dispatch.bash +7 -0
  100. package/src/scripts/_lib/base_tree.ts +175 -0
  101. package/src/scripts/_lib/billing_grant.ts +165 -0
  102. package/src/scripts/_lib/billing_grant_cli.ts +123 -0
  103. package/src/scripts/_lib/council_fallback_posture.ts +53 -6
  104. package/src/scripts/_lib/council_fallback_wiring.ts +61 -1
  105. package/src/scripts/_lib/host_capability.ts +59 -5
  106. package/src/scripts/_lib/quota_parked.ts +133 -0
  107. package/src/scripts/_lib/retrieval_sanitize.ts +62 -0
  108. package/src/scripts/_lib/review_telemetry.ts +196 -0
  109. package/src/scripts/_lib/subagent_response.ts +92 -0
  110. package/src/scripts/adr/regenerate_index.ts +14 -7
  111. package/src/scripts/ai_council/clients.ts +12 -1
  112. package/src/scripts/ai_council/config.ts +72 -115
  113. package/src/scripts/ai_council/fallback_config.ts +19 -7
  114. package/src/scripts/ai_council/mid_flight_fallback.ts +88 -7
  115. package/src/scripts/ai_council/orchestrator.ts +2 -2
  116. package/src/scripts/ai_council/py_format.ts +124 -0
  117. package/src/scripts/ai_council/seating.ts +211 -0
  118. package/src/scripts/ai_council/transport_resolver.ts +65 -2
  119. package/src/scripts/audit_adr_coverage.ts +33 -6
  120. package/src/scripts/check_council_pin_staleness.ts +300 -0
  121. package/src/scripts/check_estate_count.ts +420 -293
  122. package/src/scripts/check_gate_coverage.ts +91 -0
  123. package/src/scripts/check_no_stub_inventory_table.ts +292 -0
  124. package/src/scripts/check_pack_passport_reconciliation.ts +274 -0
  125. package/src/scripts/check_pack_size.ts +234 -1
  126. package/src/scripts/check_publish_surface.ts +297 -0
  127. package/src/scripts/check_requirements_trace.ts +378 -0
  128. package/src/scripts/check_secret_leak.ts +166 -12
  129. package/src/scripts/code_graph/cli.ts +44 -5
  130. package/src/scripts/code_graph/extract.ts +87 -0
  131. package/src/scripts/council_cli.ts +12 -16
  132. package/src/scripts/detect_ai_tells.ts +87 -0
  133. package/src/scripts/dispatch_r2_reviewer.ts +42 -0
  134. package/src/scripts/generate_capabilities_index.ts +41 -0
  135. package/src/scripts/generate_pack_manifests.ts +78 -0
  136. package/src/scripts/git_authorization_hook.ts +54 -4
  137. package/src/scripts/hooks/block_unauthorized_git.ts +19 -1
  138. package/src/scripts/hooks/run_continuation_hook.ts +3 -1
  139. package/src/scripts/hooks/subagent_ledger_hook.ts +76 -11
  140. package/src/scripts/injection_scan_hook.ts +120 -10
  141. package/src/scripts/lint_adr_sweep_routing.ts +365 -0
  142. package/src/scripts/lint_workflow_security.ts +53 -10
  143. package/src/scripts/lint_workflow_security_allowlist.json +2 -18
  144. package/src/scripts/report_envelope_rate.ts +166 -0
  145. package/src/scripts/review_axis_report.ts +218 -0
  146. package/src/scripts/run_supervise.ts +46 -1
  147. package/src/scripts/schemas/evals.schema.json +5 -0
  148. package/src/scripts/schemas/pack.schema.json +62 -4
  149. package/src/scripts/schemas/skill.schema.json +2 -2
  150. package/src/scripts/sync_pr_branch.ts +14 -7
  151. package/src/scripts/tighten_skill_descriptions.ts +264 -0
  152. package/dist/cli/commands/commands.candidates.test.js +0 -257
  153. package/dist/cli/commands/commands.candidates.test.js.map +0 -1
  154. package/dist/cli/commands/profiles.test.js +0 -88
  155. package/dist/cli/commands/profiles.test.js.map +0 -1
  156. package/dist/cli/commands/recordTriggerEval.test.js +0 -113
  157. package/dist/cli/commands/recordTriggerEval.test.js.map +0 -1
  158. package/dist/cli/configRoot.test.js +0 -97
  159. package/dist/cli/configRoot.test.js.map +0 -1
  160. package/dist/cli/mcp/content.test.js +0 -54
  161. package/dist/cli/mcp/content.test.js.map +0 -1
  162. package/dist/cli/mcp/dispatch.test.js +0 -108
  163. package/dist/cli/mcp/dispatch.test.js.map +0 -1
  164. package/dist/server/writeRoot.test.js +0 -91
  165. package/dist/server/writeRoot.test.js.map +0 -1
  166. package/dist/shared/capabilities.test.js +0 -39
  167. package/dist/shared/capabilities.test.js.map +0 -1
  168. package/dist/ui/assets/index-C1pBRm1f.js +0 -26
  169. package/dist/ui/assets/index-C1pBRm1f.js.map +0 -1
  170. /package/dist/cli-delegate/{chunk-N7CDDGI3.js → chunk-CYH5SP6M.js} +0 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Claude Code plugin detection helpers — shared by `cmd_upgrade`,
3
+ * `cmd_doctor`, and the installer.
4
+ *
5
+ * Claude Code loads the FULL top-level command set (`/implement-ticket`,
6
+ * `/work`, `/review-changes`, …) from the installed plugin
7
+ * (`agent-config@event4u-agent-config`), NOT from the `~/.claude/commands/`
8
+ * file projection. A file-only install therefore silently misses top-level
9
+ * commands while namespaced subcommands (`/fix:pr-comments`, …) keep working
10
+ * — and an installed plugin stays pinned to its install-time git SHA until
11
+ * `claude plugin update` runs. These helpers detect both states so
12
+ * upgrade / doctor / install can refresh the plugin or surface the gap.
13
+ */
14
+ import * as fs from 'node:fs';
15
+ import * as os from 'node:os';
16
+ import * as path from 'node:path';
17
+ import process from 'node:process';
18
+ export const CLAUDE_PLUGIN_ID = 'agent-config';
19
+ export const CLAUDE_MARKETPLACE_NAME = 'event4u-agent-config';
20
+ export const CLAUDE_MARKETPLACE_REPO = 'event4u-app/agent-config';
21
+ /** The one-time install commands surfaced when the plugin is missing. */
22
+ export const CLAUDE_PLUGIN_INSTALL_HINT = [
23
+ `claude plugin marketplace add ${CLAUDE_MARKETPLACE_REPO}`,
24
+ `claude plugin install ${CLAUDE_PLUGIN_ID}@${CLAUDE_MARKETPLACE_NAME}`,
25
+ ];
26
+ /**
27
+ * Official OpenAI codex plugin for Claude Code (team mode's Claude-Code
28
+ * transport). Marketplace name verified against the upstream repo's
29
+ * `.claude-plugin/marketplace.json` (`name: "openai-codex"`, plugin
30
+ * `name: "codex"`) at HEAD 2026-07-12.
31
+ */
32
+ export const CODEX_PLUGIN_ID = 'codex';
33
+ export const CODEX_MARKETPLACE_NAME = 'openai-codex';
34
+ export const CODEX_MARKETPLACE_REPO = 'openai/codex-plugin-cc';
35
+ /** The one-time install commands surfaced when the codex plugin is missing. */
36
+ export const CODEX_PLUGIN_INSTALL_HINT = [
37
+ `claude plugin marketplace add ${CODEX_MARKETPLACE_REPO}`,
38
+ `claude plugin install ${CODEX_PLUGIN_ID}@${CODEX_MARKETPLACE_NAME}`,
39
+ ];
40
+ /** Claude Code config dir — `CLAUDE_CONFIG_DIR` env override, else `~/.claude`. */
41
+ export function claude_config_dir() {
42
+ const env = (process.env['CLAUDE_CONFIG_DIR'] ?? '').trim();
43
+ return env !== '' ? env : path.join(os.homedir(), '.claude');
44
+ }
45
+ /**
46
+ * True when a plugin with the given id is recorded in Claude Code's
47
+ * `plugins/installed_plugins.json` (any marketplace — matched by the
48
+ * `<id>@` key prefix). Unreadable / absent file → false. Read-only.
49
+ */
50
+ function _plugin_id_recorded(plugin_id) {
51
+ const p = path.join(claude_config_dir(), 'plugins', 'installed_plugins.json');
52
+ let data;
53
+ try {
54
+ data = JSON.parse(fs.readFileSync(p, 'utf-8'));
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ if (data === null || typeof data !== 'object')
60
+ return false;
61
+ const plugins = data.plugins;
62
+ if (plugins === null || plugins === undefined || typeof plugins !== 'object')
63
+ return false;
64
+ return Object.keys(plugins).some((k) => k.startsWith(`${plugin_id}@`));
65
+ }
66
+ /**
67
+ * True when the agent-config plugin is recorded in Claude Code's
68
+ * `plugins/installed_plugins.json` (any marketplace — matched by the
69
+ * `agent-config@` id prefix). Unreadable / absent file → false.
70
+ */
71
+ export function claude_plugin_installed() {
72
+ return _plugin_id_recorded(CLAUDE_PLUGIN_ID);
73
+ }
74
+ /** Marketplace names (the `@<marketplace>` suffix) a plugin id is installed from. */
75
+ function _plugin_marketplaces(plugin_id) {
76
+ const p = path.join(claude_config_dir(), 'plugins', 'installed_plugins.json');
77
+ let data;
78
+ try {
79
+ data = JSON.parse(fs.readFileSync(p, 'utf-8'));
80
+ }
81
+ catch {
82
+ return [];
83
+ }
84
+ if (data === null || typeof data !== 'object')
85
+ return [];
86
+ const plugins = data.plugins;
87
+ if (plugins === null || plugins === undefined || typeof plugins !== 'object')
88
+ return [];
89
+ const prefix = `${plugin_id}@`;
90
+ return Object.keys(plugins)
91
+ .filter((k) => k.startsWith(prefix))
92
+ .map((k) => k.slice(prefix.length));
93
+ }
94
+ /** `source.repo` recorded for a marketplace in `known_marketplaces.json`, or null. */
95
+ function _marketplace_source_repo(marketplace) {
96
+ const p = path.join(claude_config_dir(), 'plugins', 'known_marketplaces.json');
97
+ let data;
98
+ try {
99
+ data = JSON.parse(fs.readFileSync(p, 'utf-8'));
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ if (data === null || typeof data !== 'object')
105
+ return null;
106
+ const entry = data[marketplace];
107
+ if (entry === null || entry === undefined || typeof entry !== 'object')
108
+ return null;
109
+ const source = entry.source;
110
+ if (source === null || source === undefined || typeof source !== 'object')
111
+ return null;
112
+ const repo = source.repo;
113
+ return typeof repo === 'string' && repo.trim() !== '' ? repo.trim() : null;
114
+ }
115
+ /**
116
+ * Presence + identity of the official OpenAI codex plugin. Read-only:
117
+ * detection never writes under `~/.claude/`. See `CodexPluginIdentity`
118
+ * for the verification contract.
119
+ */
120
+ export function codex_plugin_identity() {
121
+ const marketplaces = _plugin_marketplaces(CODEX_PLUGIN_ID);
122
+ if (marketplaces.length === 0) {
123
+ return { installed: false, identity_verified: false };
124
+ }
125
+ const want = CODEX_MARKETPLACE_REPO.toLowerCase();
126
+ const identity_verified = marketplaces.some((m) => (_marketplace_source_repo(m) ?? '').toLowerCase() === want);
127
+ return { installed: true, identity_verified };
128
+ }
129
+ /**
130
+ * True when the official OpenAI codex plugin is recorded in Claude Code's
131
+ * `plugins/installed_plugins.json` (any marketplace — matched by the
132
+ * `codex@` id prefix). Unreadable / absent file → false. Read-only:
133
+ * detection never writes under `~/.claude/`. Presence only — for
134
+ * namespace-resistant identity use `codex_plugin_identity()`.
135
+ */
136
+ export function codex_plugin_installed() {
137
+ return codex_plugin_identity().installed;
138
+ }
139
+ /**
140
+ * Version recorded in the installed marketplace snapshot's
141
+ * `.claude-plugin/marketplace.json` (`metadata.version` — bumped per
142
+ * release, so it tracks the package version the snapshot was taken from).
143
+ * Null when the snapshot is absent or unreadable.
144
+ */
145
+ export function claude_plugin_snapshot_version() {
146
+ const p = path.join(claude_config_dir(), 'plugins', 'marketplaces', CLAUDE_MARKETPLACE_NAME, '.claude-plugin', 'marketplace.json');
147
+ let data;
148
+ try {
149
+ data = JSON.parse(fs.readFileSync(p, 'utf-8'));
150
+ }
151
+ catch {
152
+ return null;
153
+ }
154
+ if (data === null || typeof data !== 'object')
155
+ return null;
156
+ const metadata = data.metadata;
157
+ if (metadata === null || metadata === undefined || typeof metadata !== 'object')
158
+ return null;
159
+ const v = metadata.version;
160
+ return typeof v === 'string' && v.trim() !== '' ? v.trim() : null;
161
+ }
162
+ //# sourceMappingURL=claude_plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude_plugin.js","sourceRoot":"","sources":["../../../src/scripts/_lib/claude_plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,397 @@
1
+ /**
2
+ * Read-only environment detection — one report, no spend (Phase 1 of
3
+ * `road-to-zero-ceremony-detection`).
4
+ *
5
+ * Answers "what does this machine already have?" in a single pass so the
6
+ * `doctor` surface and the council's transport resolution read the SAME
7
+ * facts instead of each probing on its own. Three record kinds:
8
+ *
9
+ * - `hosts` — which AI hosts are installed, their resolved binary, version.
10
+ * - `auth` — which provider credentials are PRESENT, and of which source.
11
+ * - `keys` — the `api_key_ref`-shaped reference for each present key.
12
+ *
13
+ * ## Guarantees
14
+ *
15
+ * - **Zero network.** Nothing here opens a socket. Enforced by the static
16
+ * import check in the test suite, not by convention.
17
+ * - **Zero spend.** The only subprocess is `<binary> --version`, which no
18
+ * provider bills. No completion, no token, ever — the roadmap's
19
+ * install-time-completion item was cut for exactly this reason.
20
+ * - **Presence, never validity.** An `auth` record says "a credential of this
21
+ * shape exists at this path". It does NOT say the credential works, is
22
+ * unexpired, or is accepted by the provider. Runtime auth failure stays
23
+ * authoritative (`CliClient._AUTH_FAILURE_PATTERNS`).
24
+ * - **Read-only.** Reads the filesystem and the injected env map; writes
25
+ * nothing, creates no directory.
26
+ *
27
+ * ## No third probe shape — what each field absorbs
28
+ *
29
+ * Auth probing already existed in two shapes before this module and a third
30
+ * must not appear. This module composes; it re-implements nothing:
31
+ *
32
+ * | Field | Absorbed from |
33
+ * |---|---|
34
+ * | `hosts[].installed` | `install/toolDetection.ts::detectInstalledTools` (the 23-host signal table) |
35
+ * | `hosts[].binary` | `install/toolDetection.ts::resolveToolBinary` (same table, path-returning) |
36
+ * | `hosts[].version` | `install/agentSwitchDetection.ts::parseVersionOutput` (the first-dotted-number parser) |
37
+ * | `auth` (`openai`, `cli-*`) | `_cli/cmd_doctor.ts`'s read-only `$CODEX_HOME/auth.json` probe — `codexHome()` moved HERE and imported back, so there is one definition |
38
+ * | `auth` (`anthropic`, `cli-subscription`) | `_lib/claude_plugin.ts::claude_config_dir` (`CLAUDE_CONFIG_DIR` override incl.) |
39
+ * | `auth` (`key-file`) | `_lib/user_global_paths.ts::resolve_with_fallback` (new namespace, legacy read-fallback) |
40
+ *
41
+ * The council's TTL'd `AuthCache` (`ai_council/solo_dispatch.ts`) is the third
42
+ * existing shape and is deliberately NOT absorbed: it caches a *liveness*
43
+ * verdict from an injected probe that may spend a call. This module only
44
+ * reports presence, so it needs no TTL — a per-process memo is enough.
45
+ *
46
+ * ## Known limitation — CLI logins the filesystem does not reveal
47
+ *
48
+ * A vendor CLI that stores its subscription credential OUTSIDE the filesystem
49
+ * is undetectable here. Measured case: on macOS the `claude` CLI keeps its
50
+ * OAuth credential in the system Keychain, so `~/.claude/.credentials.json`
51
+ * is absent even for a logged-in Claude Pro user. The detector reports
52
+ * `cli-subscription` only where a credential FILE exists (Linux, and the
53
+ * `CLAUDE_CONFIG_DIR` profile layouts).
54
+ *
55
+ * Consequence, stated because it costs money: with no detectable CLI login,
56
+ * `mode: auto` skips the cli rung and resolves to `api` — metered — for a user
57
+ * who does hold a subscription. This is a FALSE NEGATIVE, which is the
58
+ * direction this module is built to fail in (a false positive would claim a
59
+ * subscription that is not there and switch the USD gate off). The remedy is an
60
+ * explicit `mode: cli` on the member; `doctor` shows the detected source so the
61
+ * gap is visible rather than silent. Reading the Keychain would require a
62
+ * `security(1)` subprocess against a credential store — a spend-free but
63
+ * privacy-relevant probe, and out of scope here.
64
+ *
65
+ * @see docs/contracts/ai-council-config.md § Transport modes — the billing rules
66
+ * `classifyBilling` implements.
67
+ */
68
+ import { spawnSync } from 'node:child_process';
69
+ import * as fs from 'node:fs';
70
+ import * as os from 'node:os';
71
+ import * as path from 'node:path';
72
+ import { detectInstalledTools, knownToolIds, resolveToolBinary, } from '../../install/toolDetection.js';
73
+ import { parseVersionOutput } from '../../install/agentSwitchDetection.js';
74
+ import { claude_config_dir } from './claude_plugin.js';
75
+ import { hardenedSpawnEnv } from './spawn_env.js';
76
+ import { resolve_with_fallback } from './user_global_paths.js';
77
+ /**
78
+ * Provider → (default CLI binary, community-wrapper flag).
79
+ *
80
+ * Mirrors the `CliClient` subclass attributes without importing the client
81
+ * layer. The boolean is the load-bearing billing input: a VENDOR-OFFICIAL CLI
82
+ * (`false`) runs under the user's subscription; a COMMUNITY wrapper (`true`)
83
+ * shells out to the same paid API and stays metered. Canonical here so
84
+ * `cmd_doctor` and this module cannot drift.
85
+ */
86
+ export const PROVIDER_CLI_META = {
87
+ anthropic: ['claude', false],
88
+ openai: ['codex', false],
89
+ gemini: ['gemini', false],
90
+ xai: ['grok', true],
91
+ perplexity: ['perplexity', true],
92
+ };
93
+ /** Provider → environment variable carrying a raw API key. */
94
+ const PROVIDER_ENV_KEY = {
95
+ anthropic: 'ANTHROPIC_API_KEY',
96
+ openai: 'OPENAI_API_KEY',
97
+ gemini: 'GEMINI_API_KEY',
98
+ xai: 'XAI_API_KEY',
99
+ perplexity: 'PERPLEXITY_API_KEY',
100
+ };
101
+ /** Provider → key-file name under the user-global root (`file:` ref target). */
102
+ const PROVIDER_KEY_FILE = {
103
+ anthropic: 'anthropic.key',
104
+ openai: 'openai.key',
105
+ gemini: 'gemini.key',
106
+ xai: 'xai.key',
107
+ perplexity: 'perplexity.key',
108
+ };
109
+ /** Providers this module knows how to classify, in a stable order. */
110
+ export function knownProviders() {
111
+ return Object.keys(PROVIDER_CLI_META);
112
+ }
113
+ /** True when `provider`'s CLI is a community wrapper around the paid API. */
114
+ export function isCommunityCli(provider) {
115
+ return PROVIDER_CLI_META[provider]?.[1] ?? false;
116
+ }
117
+ /**
118
+ * Billing class from (provider, detected auth source) — NEVER from transport.
119
+ *
120
+ * This signature is the invariant: there is no transport / mode parameter, so
121
+ * no caller can make billing depend on which transport was chosen. That is
122
+ * what keeps the per-provider rules intact when `auto` picks a transport at
123
+ * invocation time: a vendor-official CLI logged in under a subscription is
124
+ * unmetered; everything else — including a community CLI and including an
125
+ * unknown source — is metered, i.e. deliberately over-gated.
126
+ *
127
+ * `null` source means "nothing detected" and classifies as `per-token`: the
128
+ * safe direction is to keep the USD gate on.
129
+ */
130
+ export function classifyBilling(provider, source) {
131
+ if (source !== 'cli-subscription')
132
+ return 'per-token';
133
+ if (isCommunityCli(provider))
134
+ return 'per-token';
135
+ return 'subscription';
136
+ }
137
+ /**
138
+ * Codex CLI home — `CODEX_HOME` env override (the codex CLI's own
139
+ * convention), else `~/.codex`. Single definition; `cmd_doctor` imports it.
140
+ */
141
+ export function codexHome(env) {
142
+ const map = env ?? process.env;
143
+ const override = (map['CODEX_HOME'] ?? '').trim();
144
+ return override !== '' ? override : path.join(homeOf(env), '.codex');
145
+ }
146
+ function homeOf(env) {
147
+ const map = env ?? process.env;
148
+ const injected = (map['HOME'] ?? '').trim();
149
+ return injected !== '' ? injected : os.homedir();
150
+ }
151
+ const VERSION_PROBE_TIMEOUT_MS = 2000;
152
+ /** Keychain service name Claude Code writes its subscription credential under. */
153
+ export const CLAUDE_KEYCHAIN_SERVICE = 'Claude Code-credentials';
154
+ /**
155
+ * Is the Claude Code subscription credential in the macOS login Keychain?
156
+ *
157
+ * Claude Code stores its OAuth credential in the Keychain on macOS and only
158
+ * falls back to `~/.claude/.credentials.json` elsewhere. Looking for the file
159
+ * alone therefore reports "no subscription" on the platform where the
160
+ * subscription is most likely to exist — which sent every macOS anthropic
161
+ * member down the metered `api` rung while a paid Claude subscription sat
162
+ * unused on the same machine. That is the defect this probe closes.
163
+ *
164
+ * `-w` is deliberately NOT passed: without it `security` prints attributes and
165
+ * never the password, so the secret cannot reach a log, a report, or a crash
166
+ * dump. Presence is read from the exit code alone.
167
+ */
168
+ function defaultProbeKeychain(service) {
169
+ if (process.platform !== 'darwin')
170
+ return false;
171
+ try {
172
+ const res = spawnSync('security', ['find-generic-password', '-s', service], {
173
+ timeout: VERSION_PROBE_TIMEOUT_MS,
174
+ encoding: 'utf-8',
175
+ windowsHide: true,
176
+ env: hardenedSpawnEnv(),
177
+ });
178
+ if (res.error !== undefined || res.signal !== null)
179
+ return false;
180
+ return res.status === 0;
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }
186
+ /**
187
+ * `<binary> --version` under a hardened env. Never throws — a spawn error,
188
+ * timeout, signal, or unparseable output all collapse to `null`, which the
189
+ * caller degrades to `'unknown'`.
190
+ *
191
+ * Hardened per `docs/spawn-site-policy.md` (this runs on the consumer runtime
192
+ * via `doctor`). Note the env scrub deliberately does NOT strip
193
+ * `CLAUDE_CONFIG_DIR` — see `docs/threat-model.md` row i.
194
+ */
195
+ function defaultProbeVersion(binary) {
196
+ try {
197
+ const res = spawnSync(binary, ['--version'], {
198
+ timeout: VERSION_PROBE_TIMEOUT_MS,
199
+ encoding: 'utf-8',
200
+ windowsHide: true,
201
+ env: hardenedSpawnEnv(),
202
+ });
203
+ if (res.error !== undefined || res.signal !== null)
204
+ return null;
205
+ return `${res.stdout ?? ''}\n${res.stderr ?? ''}`;
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ function isFile(p) {
212
+ try {
213
+ return fs.statSync(p).isFile();
214
+ }
215
+ catch {
216
+ return false;
217
+ }
218
+ }
219
+ function exists(p) {
220
+ try {
221
+ return fs.existsSync(p);
222
+ }
223
+ catch {
224
+ return false;
225
+ }
226
+ }
227
+ /**
228
+ * Classify a codex `auth.json` by which credential shape it carries.
229
+ *
230
+ * OAuth tokens ⇒ the user logged in with a ChatGPT plan (`cli-subscription`);
231
+ * anything else ⇒ metered (`cli-api-key`). A present-but-unreadable or
232
+ * malformed file also reports `cli-api-key` — the over-gated direction, since
233
+ * assuming a plan would switch the USD gate off on no evidence.
234
+ */
235
+ function classifyCodexAuth(authPath) {
236
+ let data;
237
+ try {
238
+ data = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
239
+ }
240
+ catch {
241
+ // Present but unreadable: over-gate (metered) rather than assume a plan.
242
+ return 'cli-api-key';
243
+ }
244
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
245
+ return 'cli-api-key';
246
+ }
247
+ const d = data;
248
+ const tokens = d['tokens'];
249
+ const hasOauth = typeof tokens === 'object' &&
250
+ tokens !== null &&
251
+ !Array.isArray(tokens) &&
252
+ Object.keys(tokens).length > 0;
253
+ if (hasOauth)
254
+ return 'cli-subscription';
255
+ return 'cli-api-key';
256
+ }
257
+ /** Provider-specific `cli-subscription` evidence path, or `null` when none applies. */
258
+ function cliSubscriptionEvidence(provider, home, env, claudeConfigDir, probeKeychain) {
259
+ if (provider === 'anthropic') {
260
+ const configDir = claudeConfigDir;
261
+ for (const rel of ['.credentials.json', 'credentials.json']) {
262
+ const p = path.join(configDir, rel);
263
+ if (isFile(p))
264
+ return { source: 'cli-subscription', evidence: p };
265
+ }
266
+ // macOS keeps the credential in the Keychain instead of the file above.
267
+ // The evidence string is a locator, never the secret.
268
+ if (probeKeychain(CLAUDE_KEYCHAIN_SERVICE)) {
269
+ return { source: 'cli-subscription', evidence: `keychain:${CLAUDE_KEYCHAIN_SERVICE}` };
270
+ }
271
+ return null;
272
+ }
273
+ if (provider === 'openai') {
274
+ const p = path.join(codexHome(env), 'auth.json');
275
+ if (isFile(p))
276
+ return { source: classifyCodexAuth(p), evidence: p };
277
+ return null;
278
+ }
279
+ if (provider === 'gemini') {
280
+ const p = path.join(home, '.gemini', 'oauth_creds.json');
281
+ if (isFile(p))
282
+ return { source: 'cli-subscription', evidence: p };
283
+ return null;
284
+ }
285
+ // xai / perplexity ship no subscription login — their CLIs read an API key.
286
+ return null;
287
+ }
288
+ function detectHosts(opts) {
289
+ const installedMap = detectInstalledTools({
290
+ ...(opts.home !== undefined ? { home: opts.home } : {}),
291
+ pathEnv: opts.pathEnv,
292
+ });
293
+ const probe = opts.probeVersion ?? defaultProbeVersion;
294
+ const out = [];
295
+ for (const id of knownToolIds()) {
296
+ const binary = resolveToolBinary(id, opts.pathEnv);
297
+ let version = null;
298
+ if (binary !== null) {
299
+ let raw;
300
+ try {
301
+ raw = probe(binary);
302
+ }
303
+ catch {
304
+ raw = null;
305
+ }
306
+ // An unparseable version degrades to 'unknown' — never throws,
307
+ // never omits the host from the report.
308
+ version = raw === null ? 'unknown' : (parseVersionOutput(raw) ?? 'unknown');
309
+ }
310
+ out.push({ id, installed: installedMap[id] ?? false, binary, version });
311
+ }
312
+ return out;
313
+ }
314
+ function detectAuth(opts) {
315
+ const env = opts.env ?? process.env;
316
+ const home = opts.home ?? homeOf(opts.env);
317
+ // Delegate to claude_plugin's resolver on the live path (it owns the
318
+ // CLAUDE_CONFIG_DIR override); derive from the injected home otherwise.
319
+ const claudeConfigDir = opts.home === undefined && opts.env === undefined
320
+ ? claude_config_dir()
321
+ : ((env['CLAUDE_CONFIG_DIR'] ?? '').trim() || path.join(home, '.claude'));
322
+ const probeKeychain = opts.probeKeychain ?? defaultProbeKeychain;
323
+ const auth = [];
324
+ const keys = [];
325
+ for (const provider of knownProviders()) {
326
+ const cli = cliSubscriptionEvidence(provider, home, env, claudeConfigDir, probeKeychain);
327
+ if (cli !== null) {
328
+ auth.push({ provider, source: cli.source, evidence: cli.evidence });
329
+ }
330
+ const keyFile = PROVIDER_KEY_FILE[provider];
331
+ if (keyFile !== undefined) {
332
+ let resolved = null;
333
+ try {
334
+ resolved = resolve_with_fallback(keyFile, { env });
335
+ }
336
+ catch {
337
+ resolved = null;
338
+ }
339
+ if (resolved !== null && exists(resolved)) {
340
+ auth.push({ provider, source: 'key-file', evidence: resolved });
341
+ keys.push({ provider, ref: `file:${keyFile}` });
342
+ }
343
+ }
344
+ const envVar = PROVIDER_ENV_KEY[provider];
345
+ if (envVar !== undefined && (env[envVar] ?? '').trim() !== '') {
346
+ auth.push({ provider, source: 'env-key', evidence: `env:${envVar}` });
347
+ keys.push({ provider, ref: `env:${envVar}` });
348
+ }
349
+ }
350
+ return { auth, keys };
351
+ }
352
+ /**
353
+ * Strongest auth source detected for `provider`, or `null`.
354
+ *
355
+ * "Strongest" is the transport-preference order `auto` walks: a vendor CLI
356
+ * login beats a stored key. Pure over an already-built report.
357
+ */
358
+ export function strongestAuth(report, provider) {
359
+ const order = [
360
+ 'cli-subscription',
361
+ 'cli-api-key',
362
+ 'key-file',
363
+ 'env-key',
364
+ ];
365
+ for (const source of order) {
366
+ const hit = report.auth.find((a) => a.provider === provider && a.source === source);
367
+ if (hit !== undefined)
368
+ return hit;
369
+ }
370
+ return null;
371
+ }
372
+ let _cached = null;
373
+ /**
374
+ * Build the environment report.
375
+ *
376
+ * Cached per process for the no-argument call (the production shape) so
377
+ * `doctor` and transport resolution observe one consistent snapshot; any call
378
+ * that injects options bypasses the cache and returns a fresh read, so tests
379
+ * and fixture machines never poison each other. Reset with
380
+ * `resetEnvironmentCache()`.
381
+ */
382
+ export function detectEnvironment(opts = {}) {
383
+ const isDefaultCall = Object.keys(opts).length === 0;
384
+ if (isDefaultCall && _cached !== null)
385
+ return _cached;
386
+ const hosts = detectHosts(opts);
387
+ const { auth, keys } = detectAuth(opts);
388
+ const report = { hosts, auth, keys };
389
+ if (isDefaultCall)
390
+ _cached = report;
391
+ return report;
392
+ }
393
+ /** Drop the per-process memo. Tests only. */
394
+ export function resetEnvironmentCache() {
395
+ _cached = null;
396
+ }
397
+ //# sourceMappingURL=environment_detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment_detector.js","sourceRoot":"","sources":["../../../src/scripts/_lib/environment_detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EACH,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAe,MAAM,wBAAwB,CAAC;AA4C5E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAyD;IACnF,SAAS,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;IAC5B,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB,MAAM,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC;CACnC,CAAC;AAEF,8DAA8D;AAC9D,MAAM,gBAAgB,GAAqC;IACvD,SAAS,EAAE,mBAAmB;IAC9B,MAAM,EAAE,gBAAgB;IACxB,MAAM,EAAE,gBAAgB;IACxB,GAAG,EAAE,aAAa;IAClB,UAAU,EAAE,oBAAoB;CACnC,CAAC;AAEF,gFAAgF;AAChF,MAAM,iBAAiB,GAAqC;IACxD,SAAS,EAAE,eAAe;IAC1B,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;IACpB,GAAG,EAAE,SAAS;IACd,UAAU,EAAE,gBAAgB;CAC/B,CAAC;AAEF,sEAAsE;AACtE,MAAM,UAAU,cAAc;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC1C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC3C,OAAO,iBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,MAAyB;IACvE,IAAI,MAAM,KAAK,kBAAkB;QAAE,OAAO,WAAW,CAAC;IACtD,IAAI,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IACjD,OAAO,cAAc,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAmB;IACzC,MAAM,GAAG,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,OAAO,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,MAAM,CAAC,GAAmB;IAC/B,MAAM,GAAG,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,wBAAwB,GAAG,IAAI,CAAC;AA8BtC,kFAAkF;AAClF,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE;;;;;;;;;;;;;GAaG;AACH,SAAS,oBAAoB,CAAC,OAAe;IACzC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,uBAAuB,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE;YACxE,OAAO,EAAE,wBAAwB;YACjC,QAAQ,EAAE,OAAO;YACjB,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,gBAAgB,EAAE;SAC1B,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACjE,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,MAAc;IACvC,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE;YACzC,OAAO,EAAE,wBAAwB;YACjC,QAAQ,EAAE,OAAO;YACjB,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,gBAAgB,EAAE;SAC1B,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAChE,OAAO,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,KAAK,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,SAAS,MAAM,CAAC,CAAS;IACrB,IAAI,CAAC;QACD,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,SAAS,MAAM,CAAC,CAAS;IACrB,IAAI,CAAC;QACD,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,QAAgB;IACvC,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACL,yEAAyE;QACzE,OAAO,aAAa,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACnE,OAAO,aAAa,CAAC;IACzB,CAAC;IACD,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC3B,MAAM,QAAQ,GACV,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,MAAiC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9D,IAAI,QAAQ;QAAE,OAAO,kBAAkB,CAAC;IACxC,OAAO,aAAa,CAAC;AACzB,CAAC;AAED,uFAAuF;AACvF,SAAS,uBAAuB,CAC5B,QAAgB,EAChB,IAAY,EACZ,GAAW,EACX,eAAuB,EACvB,aAA4B;IAE5B,IAAI,QAAQ,KAAK,WAAW,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,eAAe,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,EAAE,CAAC;YAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACpC,IAAI,MAAM,CAAC,CAAC,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACtE,CAAC;QACD,wEAAwE;QACxE,sDAAsD;QACtD,IAAI,aAAa,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACzC,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,YAAY,uBAAuB,EAAE,EAAE,CAAC;QAC3F,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;QACjD,IAAI,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACpE,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,kBAAkB,CAAC,CAAC;QACzD,IAAI,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAClE,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,4EAA4E;IAC5E,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,IAA8B;IAC/C,MAAM,YAAY,GAAG,oBAAoB,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,OAAO,EAAE,IAAI,CAAC,OAAO;KACxB,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,IAAI,mBAAmB,CAAC;IACvD,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,YAAY,EAAE,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,OAAO,GAAgB,IAAI,CAAC;QAChC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,IAAI,GAAkB,CAAC;YACvB,IAAI,CAAC;gBACD,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACL,GAAG,GAAG,IAAI,CAAC;YACf,CAAC;YACD,+DAA+D;YAC/D,wCAAwC;YACxC,OAAO,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC;QAChF,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,IAA8B;IAI9C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,qEAAqE;IACrE,wEAAwE;IACxE,MAAM,eAAe,GACjB,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;QAC7C,CAAC,CAAC,iBAAiB,EAAE;QACrB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAClF,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,oBAAoB,CAAC;IACjE,MAAM,IAAI,GAAmB,EAAE,CAAC;IAChC,MAAM,IAAI,GAAkB,EAAE,CAAC;IAE/B,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,uBAAuB,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;QACzF,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,QAAQ,GAAkB,IAAI,CAAC;YACnC,IAAI,CAAC;gBACD,QAAQ,GAAG,qBAAqB,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACvD,CAAC;YAAC,MAAM,CAAC;gBACL,QAAQ,GAAG,IAAI,CAAC;YACpB,CAAC;YACD,IAAI,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAChE,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,OAAO,EAAE,EAAE,CAAC,CAAC;YACpD,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC5D,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,MAAM,EAAE,EAAE,CAAC,CAAC;YACtE,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,MAAM,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;IACL,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CACzB,MAAyB,EACzB,QAAgB;IAEhB,MAAM,KAAK,GAA0B;QACjC,kBAAkB;QAClB,aAAa;QACb,UAAU;QACV,SAAS;KACZ,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;QACpF,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,IAAI,OAAO,GAA6B,IAAI,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAiC,EAAE;IACjE,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IACrD,IAAI,aAAa,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC;IACtD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,MAAM,GAAsB,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,aAAa;QAAE,OAAO,GAAG,MAAM,CAAC;IACpC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,qBAAqB;IACjC,OAAO,GAAG,IAAI,CAAC;AACnB,CAAC"}