@event4u/agent-config 14.8.0 → 14.9.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 +165 -237
- package/README.md +1 -1
- package/agents/templates/.ai-council.yml.example +34 -4
- package/dist/agent-src/commands/pr/merge.md +9 -5
- package/dist/agent-src/commands/review/changes.md +95 -14
- package/dist/agent-src/commands/roadmap/process-full.md +2 -2
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +77 -0
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +36 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +80 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +9 -3
- package/dist/agent-src/skills/code-review/evals/evals.json +87 -46
- package/dist/agent-src/skills/humanizer/SKILL.md +39 -0
- package/dist/agent-src/skills/humanizer/evals/strip_fixtures.json +57 -0
- package/dist/agent-src/skills/humanizer/references/fixtures.md +54 -0
- package/dist/agent-src/skills/judge-spec-compliance/SKILL.md +154 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +45 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +18 -18
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +8 -0
- package/dist/cli/registry.js +2 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-MMSGVZKV.js → chunk-77GR3VD4.js} +65 -40
- package/dist/cli-delegate/{chunk-Q26HT4QT.js → chunk-E46KPN6K.js} +251 -150
- package/dist/cli-delegate/{chunk-EEJUMCDZ.js → chunk-PLSG6UL5.js} +1 -1
- package/dist/cli-delegate/cmd_conformance.js +89 -13
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +2 -2
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +37 -15
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +562 -204
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +808 -331
- package/dist/scripts/_lib/claude_plugin.js +162 -0
- package/dist/scripts/_lib/claude_plugin.js.map +1 -0
- package/dist/scripts/_lib/environment_detector.js +397 -0
- package/dist/scripts/_lib/environment_detector.js.map +1 -0
- package/dist/scripts/_lib/spawn_env.js +129 -0
- package/dist/scripts/_lib/spawn_env.js.map +1 -0
- package/dist/scripts/ai_council/modes.js +199 -0
- package/dist/scripts/ai_council/modes.js.map +1 -0
- package/dist/scripts/ai_council/transport_resolver.js +418 -0
- package/dist/scripts/ai_council/transport_resolver.js.map +1 -0
- package/dist/server/routes/wizard.js +3 -2
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +26 -0
- package/dist/ui/assets/index-Cxgy63kz.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +17 -0
- package/package.json +7 -3
- package/src/config/estate-count-budget.json +13 -744
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +247 -9
- package/src/config/gate-violation-baselines.json +72 -72
- package/src/config/publish-surface.json +60 -0
- package/src/config/requirements-trace-budget.json +32 -0
- package/src/config/rule-stub-ceilings.json +8 -1
- package/src/scripts/_dispatch.bash +7 -0
- package/src/scripts/_lib/base_tree.ts +175 -0
- package/src/scripts/_lib/billing_grant.ts +165 -0
- package/src/scripts/_lib/billing_grant_cli.ts +123 -0
- package/src/scripts/_lib/council_fallback_posture.ts +53 -6
- package/src/scripts/_lib/council_fallback_wiring.ts +61 -1
- package/src/scripts/_lib/host_capability.ts +59 -5
- package/src/scripts/_lib/quota_parked.ts +133 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +62 -0
- package/src/scripts/_lib/review_telemetry.ts +196 -0
- package/src/scripts/_lib/subagent_response.ts +92 -0
- package/src/scripts/adr/regenerate_index.ts +14 -7
- package/src/scripts/ai_council/clients.ts +12 -1
- package/src/scripts/ai_council/config.ts +72 -115
- package/src/scripts/ai_council/fallback_config.ts +19 -7
- package/src/scripts/ai_council/mid_flight_fallback.ts +88 -7
- package/src/scripts/ai_council/orchestrator.ts +2 -2
- package/src/scripts/ai_council/py_format.ts +124 -0
- package/src/scripts/ai_council/transport_resolver.ts +65 -2
- package/src/scripts/audit_adr_coverage.ts +33 -6
- package/src/scripts/check_council_pin_staleness.ts +300 -0
- package/src/scripts/check_estate_count.ts +420 -293
- package/src/scripts/check_gate_coverage.ts +91 -0
- package/src/scripts/check_no_stub_inventory_table.ts +292 -0
- package/src/scripts/check_pack_size.ts +234 -1
- package/src/scripts/check_publish_surface.ts +297 -0
- package/src/scripts/check_requirements_trace.ts +378 -0
- package/src/scripts/check_secret_leak.ts +166 -12
- package/src/scripts/code_graph/cli.ts +44 -5
- package/src/scripts/code_graph/extract.ts +87 -0
- package/src/scripts/council_cli.ts +12 -16
- package/src/scripts/detect_ai_tells.ts +87 -0
- package/src/scripts/dispatch_r2_reviewer.ts +42 -0
- package/src/scripts/generate_capabilities_index.ts +41 -0
- package/src/scripts/git_authorization_hook.ts +54 -4
- package/src/scripts/hooks/block_unauthorized_git.ts +19 -1
- package/src/scripts/hooks/run_continuation_hook.ts +3 -1
- package/src/scripts/hooks/subagent_ledger_hook.ts +76 -11
- package/src/scripts/injection_scan_hook.ts +120 -10
- package/src/scripts/lint_adr_sweep_routing.ts +365 -0
- package/src/scripts/lint_workflow_security.ts +53 -10
- package/src/scripts/lint_workflow_security_allowlist.json +2 -18
- package/src/scripts/report_envelope_rate.ts +166 -0
- package/src/scripts/review_axis_report.ts +218 -0
- package/src/scripts/run_supervise.ts +46 -1
- package/src/scripts/schemas/evals.schema.json +5 -0
- package/src/scripts/sync_pr_branch.ts +14 -7
- package/dist/cli/commands/commands.candidates.test.js +0 -257
- package/dist/cli/commands/commands.candidates.test.js.map +0 -1
- package/dist/cli/commands/profiles.test.js +0 -88
- package/dist/cli/commands/profiles.test.js.map +0 -1
- package/dist/cli/commands/recordTriggerEval.test.js +0 -113
- package/dist/cli/commands/recordTriggerEval.test.js.map +0 -1
- package/dist/cli/configRoot.test.js +0 -97
- package/dist/cli/configRoot.test.js.map +0 -1
- package/dist/cli/mcp/content.test.js +0 -54
- package/dist/cli/mcp/content.test.js.map +0 -1
- package/dist/cli/mcp/dispatch.test.js +0 -108
- package/dist/cli/mcp/dispatch.test.js.map +0 -1
- package/dist/server/writeRoot.test.js +0 -91
- package/dist/server/writeRoot.test.js.map +0 -1
- package/dist/shared/capabilities.test.js +0 -39
- package/dist/shared/capabilities.test.js.map +0 -1
- package/dist/ui/assets/index-C1pBRm1f.js +0 -26
- package/dist/ui/assets/index-C1pBRm1f.js.map +0 -1
- /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":"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"}
|