@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +214 -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/async-python-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/code-refactoring/SKILL.md +1 -1
- package/dist/agent-src/skills/code-review/evals/evals.json +87 -46
- package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/design-review/SKILL.md +1 -1
- package/dist/agent-src/skills/discovery-interview/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/editorial-calendar/SKILL.md +1 -1
- package/dist/agent-src/skills/github-ci/SKILL.md +1 -1
- 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-artifact-completeness/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +1 -1
- 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/laravel-validation/SKILL.md +1 -1
- package/dist/agent-src/skills/legal-intake-triage/SKILL.md +1 -1
- package/dist/agent-src/skills/legal-practice-profile/SKILL.md +1 -1
- package/dist/agent-src/skills/messaging-architecture/SKILL.md +1 -1
- package/dist/agent-src/skills/migration-architect/SKILL.md +1 -1
- package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -1
- package/dist/agent-src/skills/module-management/SKILL.md +1 -1
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +1 -1
- package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
- package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-optimizer/SKILL.md +1 -1
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +18 -18
- package/dist/agent-src/skills/scene-expander/SKILL.md +1 -1
- package/dist/agent-src/skills/secrets-management/SKILL.md +1 -1
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- 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 +64 -42
- 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 +267 -9
- package/src/config/gate-violation-baselines.json +72 -72
- package/src/config/preamble-payload-budget.json +71 -67
- 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/seating.ts +211 -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_passport_reconciliation.ts +274 -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/generate_pack_manifests.ts +78 -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/schemas/pack.schema.json +62 -4
- package/src/scripts/schemas/skill.schema.json +2 -2
- package/src/scripts/sync_pr_branch.ts +14 -7
- package/src/scripts/tighten_skill_descriptions.ts +264 -0
- 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,418 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport resolution for `mode: auto`, plus the two guards that keep it
|
|
3
|
+
* honest (Phase 2 of `road-to-zero-ceremony-detection`).
|
|
4
|
+
*
|
|
5
|
+
* `modes.ts` answers "which mode did the config ask for" — a pure precedence
|
|
6
|
+
* walk over four layers. This module answers the next question: when that
|
|
7
|
+
* answer is `auto`, which concrete transport does THIS machine support right
|
|
8
|
+
* now, how is it billed, and what happens when the chosen rung fails
|
|
9
|
+
* mid-invocation.
|
|
10
|
+
*
|
|
11
|
+
* ## The `auto` chain
|
|
12
|
+
*
|
|
13
|
+
* cli — the provider's CLI binary resolves AND a credential is present
|
|
14
|
+
* api — else a key resolves
|
|
15
|
+
* ∅ — else unavailable, with a one-line reason
|
|
16
|
+
*
|
|
17
|
+
* `manual` is deliberately NOT in the chain. It is free and always "available"
|
|
18
|
+
* (the human is the transport), so an availability-ranked chain would always
|
|
19
|
+
* end there and `auto` would silently become "ask the human to copy-paste".
|
|
20
|
+
* Manual stays an explicit opt-in.
|
|
21
|
+
*
|
|
22
|
+
* ## The billing invariant
|
|
23
|
+
*
|
|
24
|
+
* Billing is classified from (provider, detected auth source) by
|
|
25
|
+
* `classifyBilling` in `_lib/environment_detector.ts` — never from the
|
|
26
|
+
* transport this module picked. That is the property that keeps the existing
|
|
27
|
+
* per-provider rules intact under `auto`:
|
|
28
|
+
*
|
|
29
|
+
* - a VENDOR-OFFICIAL CLI under a subscription login is unmetered, so the USD
|
|
30
|
+
* cost gate stays off and `cli_call_budget` guards the plan quota instead;
|
|
31
|
+
* - a COMMUNITY wrapper (`grok`, `perplexity`) shells out to the same paid API
|
|
32
|
+
* and stays metered even though the transport is also spelled `cli`;
|
|
33
|
+
* - an unknown source is metered — deliberately over-gated.
|
|
34
|
+
*
|
|
35
|
+
* `makesProviderCall` below IS transport-derived, and is not a billing term:
|
|
36
|
+
* it records that `manual` performs no provider call at all, which is why no
|
|
37
|
+
* amount of billing classification applies to it.
|
|
38
|
+
*
|
|
39
|
+
* @see docs/contracts/ai-council-config.md § Transport modes
|
|
40
|
+
*/
|
|
41
|
+
import { classifyBilling, isCommunityCli, strongestAuth, PROVIDER_CLI_META, } from '../_lib/environment_detector.js';
|
|
42
|
+
import { resolve_mode } from './modes.js';
|
|
43
|
+
/** The accepted values of the `mode` key, including the resolver-only `auto`. */
|
|
44
|
+
export const VALID_TRANSPORT_MODES = new Set([
|
|
45
|
+
'api',
|
|
46
|
+
'manual',
|
|
47
|
+
'cli',
|
|
48
|
+
'auto',
|
|
49
|
+
]);
|
|
50
|
+
/** Auth sources that mean "the provider CLI can authenticate". */
|
|
51
|
+
const CLI_AUTH_SOURCES = new Set(['cli-subscription', 'cli-api-key']);
|
|
52
|
+
/** Auth sources that mean "a stored key exists for the api transport". */
|
|
53
|
+
const KEY_AUTH_SOURCES = new Set(['key-file', 'env-key']);
|
|
54
|
+
function hasSource(report, provider, allowed) {
|
|
55
|
+
return report.auth.some((a) => a.provider === provider && allowed.has(a.source));
|
|
56
|
+
}
|
|
57
|
+
/** Resolved CLI binary for `provider` from the report, or `null`. */
|
|
58
|
+
function cliBinary(report, provider) {
|
|
59
|
+
const meta = PROVIDER_CLI_META[provider];
|
|
60
|
+
if (meta === undefined)
|
|
61
|
+
return null;
|
|
62
|
+
const binaryName = meta[0];
|
|
63
|
+
const host = report.hosts.find((h) => h.binary !== null && stripExeSuffix(basename(h.binary)) === binaryName);
|
|
64
|
+
return host?.binary ?? null;
|
|
65
|
+
}
|
|
66
|
+
/** Last path segment, separator-agnostic (no `node:path` import needed). */
|
|
67
|
+
function basename(p) {
|
|
68
|
+
const parts = p.split(/[/\\]/);
|
|
69
|
+
return parts[parts.length - 1] ?? p;
|
|
70
|
+
}
|
|
71
|
+
/** Strip a Windows executable suffix so `claude.cmd` matches `claude`. */
|
|
72
|
+
function stripExeSuffix(name) {
|
|
73
|
+
return name.replace(/\.(exe|cmd)$/i, '');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolve one member's transport.
|
|
77
|
+
*
|
|
78
|
+
* Explicit `api` / `manual` / `cli` pass through unchanged — this function
|
|
79
|
+
* never overrides a mode the user or a per-member override asked for. Only
|
|
80
|
+
* `auto` walks the chain.
|
|
81
|
+
*/
|
|
82
|
+
export function resolveTransport(opts) {
|
|
83
|
+
const { provider, mode, report } = opts;
|
|
84
|
+
const auth = strongestAuth(report, provider);
|
|
85
|
+
const authSource = auth?.source ?? null;
|
|
86
|
+
const billing = classifyBilling(provider, authSource);
|
|
87
|
+
if (mode === 'manual') {
|
|
88
|
+
return {
|
|
89
|
+
available: true,
|
|
90
|
+
transport: 'manual',
|
|
91
|
+
// Classified from the auth source like every other member; it is
|
|
92
|
+
// simply never consulted because no provider call happens.
|
|
93
|
+
billing,
|
|
94
|
+
authSource,
|
|
95
|
+
makesProviderCall: false,
|
|
96
|
+
reason: null,
|
|
97
|
+
absentReason: null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (mode === 'api' || mode === 'cli') {
|
|
101
|
+
return {
|
|
102
|
+
available: true,
|
|
103
|
+
transport: mode,
|
|
104
|
+
billing,
|
|
105
|
+
authSource,
|
|
106
|
+
makesProviderCall: true,
|
|
107
|
+
reason: null,
|
|
108
|
+
absentReason: null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (mode !== 'auto') {
|
|
112
|
+
return unavailable(provider, billing, `mode=${JSON.stringify(mode)} is not one of ` +
|
|
113
|
+
`${[...VALID_TRANSPORT_MODES].sort().join(', ')}`);
|
|
114
|
+
}
|
|
115
|
+
// ── the auto chain ──────────────────────────────────────────────────
|
|
116
|
+
const override = (opts.binaryOverride ?? null)?.trim() ?? null;
|
|
117
|
+
const binary = override !== null && override !== '' ? override : cliBinary(report, provider);
|
|
118
|
+
const cliAuthed = hasSource(report, provider, CLI_AUTH_SOURCES);
|
|
119
|
+
if (binary !== null && cliAuthed) {
|
|
120
|
+
return {
|
|
121
|
+
available: true,
|
|
122
|
+
transport: 'cli',
|
|
123
|
+
billing,
|
|
124
|
+
authSource,
|
|
125
|
+
makesProviderCall: true,
|
|
126
|
+
reason: null,
|
|
127
|
+
absentReason: null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const keyPresent = opts.apiKeyPresent ?? hasSource(report, provider, KEY_AUTH_SOURCES);
|
|
131
|
+
if (keyPresent) {
|
|
132
|
+
return {
|
|
133
|
+
available: true,
|
|
134
|
+
transport: 'api',
|
|
135
|
+
billing,
|
|
136
|
+
authSource,
|
|
137
|
+
makesProviderCall: true,
|
|
138
|
+
reason: null,
|
|
139
|
+
absentReason: null,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return unavailable(provider, billing, autoUnavailableReason(provider, binary, cliAuthed), classifyStaticAbsentReason(binary));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The single reconciled entry point for "given this member's config, what
|
|
146
|
+
* transport does it actually run on" (road-to-always-on-orchestration
|
|
147
|
+
* Phase 3.1). Composes `modes.ts::resolve_mode` (which layer decided the
|
|
148
|
+
* mode) with `resolveTransport` (what `auto` expands to on THIS machine) so
|
|
149
|
+
* a caller never has to replicate either step by hand.
|
|
150
|
+
*
|
|
151
|
+
* This exists because the two functions previously lived at arm's length:
|
|
152
|
+
* `resolve_mode` can legitimately return the literal string `'auto'`, and
|
|
153
|
+
* nothing forced a caller to then route that value through
|
|
154
|
+
* `resolveTransport` — a hand-rolled `mode === 'api' | 'cli' | 'manual'`
|
|
155
|
+
* switch (the shape `council_cli.ts::build_members` still uses today) has
|
|
156
|
+
* no `'auto'` case and treats it as an unrecognised transport instead of
|
|
157
|
+
* expanding it. `resolveMemberTransport` is the fix: there is no longer a
|
|
158
|
+
* gap between "which mode was configured" and "which transport that becomes"
|
|
159
|
+
* for any caller that uses it instead of the two functions separately.
|
|
160
|
+
*/
|
|
161
|
+
export function resolveMemberTransport(opts) {
|
|
162
|
+
const configuredMode = resolve_mode(opts.provider, {
|
|
163
|
+
invocationMode: opts.invocationMode ?? null,
|
|
164
|
+
memberSettings: opts.memberSettings ?? null,
|
|
165
|
+
globalMode: opts.globalMode ?? null,
|
|
166
|
+
});
|
|
167
|
+
const resolved = resolveTransport({
|
|
168
|
+
provider: opts.provider,
|
|
169
|
+
mode: configuredMode,
|
|
170
|
+
report: opts.report,
|
|
171
|
+
binaryOverride: opts.binaryOverride ?? null,
|
|
172
|
+
// `exactOptionalPropertyTypes` rejects an explicit `undefined` for an
|
|
173
|
+
// optional-boolean field, so the key is omitted entirely rather than
|
|
174
|
+
// forwarded as `apiKeyPresent: undefined`.
|
|
175
|
+
...(opts.apiKeyPresent !== undefined ? { apiKeyPresent: opts.apiKeyPresent } : {}),
|
|
176
|
+
});
|
|
177
|
+
return { ...resolved, configuredMode };
|
|
178
|
+
}
|
|
179
|
+
function unavailable(_provider, billing, reason, absentReason = null) {
|
|
180
|
+
return {
|
|
181
|
+
available: false,
|
|
182
|
+
transport: null,
|
|
183
|
+
// Unavailable members never spend, but the class stays over-gated so a
|
|
184
|
+
// caller that ignores `available` cannot read this as "free".
|
|
185
|
+
billing,
|
|
186
|
+
authSource: null,
|
|
187
|
+
makesProviderCall: false,
|
|
188
|
+
reason,
|
|
189
|
+
absentReason,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* `no_binary` when the CLI binary itself never resolved (whether or not a
|
|
194
|
+
* credential was found — a credential with nothing to run it against is
|
|
195
|
+
* still "the binary is missing" from the caller's point of view); `no_auth`
|
|
196
|
+
* when the binary IS present but neither the cli-auth nor the key rung
|
|
197
|
+
* resolved. Mirrors `autoUnavailableReason`'s three-way branch below.
|
|
198
|
+
*/
|
|
199
|
+
function classifyStaticAbsentReason(binary) {
|
|
200
|
+
return binary === null ? 'no_binary' : 'no_auth';
|
|
201
|
+
}
|
|
202
|
+
/** The one-line reason `auto` prints when no rung resolved. */
|
|
203
|
+
function autoUnavailableReason(provider, binary, cliAuthed) {
|
|
204
|
+
const expected = PROVIDER_CLI_META[provider]?.[0] ?? provider;
|
|
205
|
+
if (binary === null && !cliAuthed) {
|
|
206
|
+
return (`no transport available: \`${expected}\` is not on PATH and no key resolves ` +
|
|
207
|
+
`— install the CLI and log in, or add an api_key_ref`);
|
|
208
|
+
}
|
|
209
|
+
if (binary === null) {
|
|
210
|
+
return (`no transport available: a credential is present but \`${expected}\` is not ` +
|
|
211
|
+
`on PATH and no key resolves — install the CLI, or add an api_key_ref`);
|
|
212
|
+
}
|
|
213
|
+
return (`no transport available: \`${expected}\` is on PATH but not authenticated and no ` +
|
|
214
|
+
`key resolves — log in to the CLI, or add an api_key_ref`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Failure classes that may fall through to the `api` rung.
|
|
218
|
+
*
|
|
219
|
+
* All three share one property: the CLI provably never reached the provider,
|
|
220
|
+
* so retrying on another transport cannot double-charge. Everything absent
|
|
221
|
+
* from this set — notably `timeout` and `server_error` — may have left a
|
|
222
|
+
* half-completed call behind, and falling through would risk paying twice for
|
|
223
|
+
* one question. `quota_exhausted` is excluded for a different reason: the
|
|
224
|
+
* quota is a cap the user deliberately set, so routing around it would defeat
|
|
225
|
+
* the guard rather than recover from a fault.
|
|
226
|
+
*/
|
|
227
|
+
const FALLBACK_ELIGIBLE = new Set([
|
|
228
|
+
'binary_missing',
|
|
229
|
+
'auth_rejected',
|
|
230
|
+
'cli_unsupported',
|
|
231
|
+
// `model_unservable` satisfies the same no-double-charge property in both
|
|
232
|
+
// of its shapes: the pre-spend gate refuses before any subprocess exists,
|
|
233
|
+
// and the call-time shape is a provider 400 — rejected at the request
|
|
234
|
+
// boundary, no generation performed.
|
|
235
|
+
'model_unservable',
|
|
236
|
+
]);
|
|
237
|
+
/** The base policy: exactly the three-plus-one no-double-charge classes. */
|
|
238
|
+
export const DEFAULT_FALLBACK_POLICY = { apiOnQuota: false };
|
|
239
|
+
/**
|
|
240
|
+
* Collapse the tri-state plus the grant into the boolean the eligibility rule
|
|
241
|
+
* needs. `'ask'` without a grant is `false` — never `true` by omission, which
|
|
242
|
+
* is the one direction that would turn a configured question into silent
|
|
243
|
+
* metered spend.
|
|
244
|
+
*/
|
|
245
|
+
export function effectiveApiOnQuota(policy) {
|
|
246
|
+
if (policy.apiOnQuota === 'ask')
|
|
247
|
+
return policy.billingGrant === true;
|
|
248
|
+
return policy.apiOnQuota === true;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Parse a config value into the tri-state, or throw.
|
|
252
|
+
*
|
|
253
|
+
* Rejecting is the point. A parser that mapped an unknown value onto a truthy
|
|
254
|
+
* default would turn a configured `off` into metered spend — the exact failure
|
|
255
|
+
* the `'ask'` posture exists to prevent, introduced by the code that adds it.
|
|
256
|
+
* Accepts the Python-ish spellings the council config has always allowed on
|
|
257
|
+
* the boolean side, plus `ask` on the new one.
|
|
258
|
+
*/
|
|
259
|
+
export function apiOnQuotaView(raw) {
|
|
260
|
+
// Lenient by design, unlike `parseApiOnQuota`: this feeds a DISPLAY
|
|
261
|
+
// surface, where throwing on a malformed file would blank the wizard
|
|
262
|
+
// instead of showing the operator the setting they need to fix. Reading
|
|
263
|
+
// by value rather than by truthiness is the half that still matters —
|
|
264
|
+
// `=== true` alone renders `'ask'` as `false`, and the next save
|
|
265
|
+
// downgrades a configured question to a configured no.
|
|
266
|
+
return raw === 'ask' ? 'ask' : raw === true;
|
|
267
|
+
}
|
|
268
|
+
export function parseApiOnQuota(raw) {
|
|
269
|
+
if (typeof raw === 'boolean')
|
|
270
|
+
return raw;
|
|
271
|
+
if (raw === undefined || raw === null)
|
|
272
|
+
return false;
|
|
273
|
+
if (typeof raw === 'string') {
|
|
274
|
+
const s = raw.trim().toLowerCase();
|
|
275
|
+
if (s === 'ask')
|
|
276
|
+
return 'ask';
|
|
277
|
+
if (s === 'true' || s === 'yes' || s === 'on' || s === '1')
|
|
278
|
+
return true;
|
|
279
|
+
if (s === '' || s === 'false' || s === 'no' || s === 'off' || s === '0') {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
throw new Error(`ai_council.fallback.api_on_quota: expected false | true | 'ask', got ${JSON.stringify(raw)}`);
|
|
284
|
+
}
|
|
285
|
+
/** Normalise a raw client error / skip reason into a `CliFailureClass`. */
|
|
286
|
+
export function classifyCliFailure(raw) {
|
|
287
|
+
const s = raw.trim().toLowerCase();
|
|
288
|
+
if (s === 'binary_missing' || s === 'file_not_found')
|
|
289
|
+
return 'binary_missing';
|
|
290
|
+
if (s === 'auth_expired' || s === 'auth_rejected' || s === 'unauthorized') {
|
|
291
|
+
return 'auth_rejected';
|
|
292
|
+
}
|
|
293
|
+
if (s === 'cli_unsupported' || s === 'unsupported' || s === 'parse_failed') {
|
|
294
|
+
return 'cli_unsupported';
|
|
295
|
+
}
|
|
296
|
+
// Prefix match, not equality: the detail carries the operator-facing reason
|
|
297
|
+
// after the code, and that sentence IS the value of this class — collapsing
|
|
298
|
+
// it back to a bare token would restore the opaque `exit_1` this replaced.
|
|
299
|
+
// Also matched on the provider's own wording, so a model refused at call
|
|
300
|
+
// time (one the deny-list has never seen) classifies the same as one the
|
|
301
|
+
// pre-spend gate caught.
|
|
302
|
+
if (s.startsWith('model_unservable') ||
|
|
303
|
+
// The token the PRODUCERS actually write. R2 round 6, finding 4:
|
|
304
|
+
// `clients.ts` emits `model_unsupported_on_transport` at both sites
|
|
305
|
+
// (the pre-spend gate at :1857 and the turn-failed path at :2002) and
|
|
306
|
+
// puts the vendor sentence in `metadata.detail`, never in `error` — so
|
|
307
|
+
// the class matched nothing a caller could produce and the contract's
|
|
308
|
+
// fourth eligible class was dead. The token is matched here rather
|
|
309
|
+
// than renamed at the producers because `code:` values reach the
|
|
310
|
+
// events log and a rename would break every reader of the history.
|
|
311
|
+
s.startsWith('model_unsupported_on_transport') ||
|
|
312
|
+
s.includes('is not supported when using codex')) {
|
|
313
|
+
return 'model_unservable';
|
|
314
|
+
}
|
|
315
|
+
if (s === 'timeout')
|
|
316
|
+
return 'timeout';
|
|
317
|
+
if (s === 'cli_quota_exhausted' || s === 'quota_exhausted')
|
|
318
|
+
return 'quota_exhausted';
|
|
319
|
+
if (/^exit_5\d\d$/.test(s) || s === 'server_error' || s === 'os')
|
|
320
|
+
return 'server_error';
|
|
321
|
+
return 'other';
|
|
322
|
+
}
|
|
323
|
+
/** True when `failure` is eligible to fall through to the `api` rung. */
|
|
324
|
+
export function isFallbackEligible(failure) {
|
|
325
|
+
return isFallbackEligibleUnder(failure, DEFAULT_FALLBACK_POLICY);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Policy-aware variant: the base set, plus `quota_exhausted` when the
|
|
329
|
+
* caller's policy opted in (`ai_council.fallback.api_on_quota`).
|
|
330
|
+
* `timeout` / `server_error` are ineligible under EVERY policy — a
|
|
331
|
+
* half-completed call must never be paid for twice, and no opt-in key
|
|
332
|
+
* exists (or may be added) to override that.
|
|
333
|
+
*/
|
|
334
|
+
export function isFallbackEligibleUnder(failure, policy) {
|
|
335
|
+
if (FALLBACK_ELIGIBLE.has(failure))
|
|
336
|
+
return true;
|
|
337
|
+
return effectiveApiOnQuota(policy) && failure === 'quota_exhausted';
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Maps a mid-flight `CliFailureClass` (a call was actually attempted and
|
|
341
|
+
* failed) onto the same `AbsentReason` enum a static resolution failure
|
|
342
|
+
* uses (road-to-always-on-orchestration Phase 3.2/3.4), so a pass artifact
|
|
343
|
+
* can bucket every absent member — whether it never got a transport at all
|
|
344
|
+
* or lost one partway through — under one vocabulary. Returns `null` for a
|
|
345
|
+
* failure class outside the four-value enum (`cli_unsupported`,
|
|
346
|
+
* `server_error`, `model_unservable`, `other`); a caller falls back to the raw
|
|
347
|
+
* failure detail for those rather than mis-classifying them.
|
|
348
|
+
*
|
|
349
|
+
* `model_unservable` is deliberately unmapped rather than folded into
|
|
350
|
+
* `no_auth`: the credential is fine, the model is not, and the `detail` string
|
|
351
|
+
* carries the specific reason. So the bucket a reader sees is still the generic
|
|
352
|
+
* `unavailable`, while the line beside it now names the cause — an incomplete
|
|
353
|
+
* improvement, stated as one.
|
|
354
|
+
*/
|
|
355
|
+
export function absentReasonFromCliFailure(failure) {
|
|
356
|
+
switch (failure) {
|
|
357
|
+
case 'binary_missing':
|
|
358
|
+
return 'no_binary';
|
|
359
|
+
case 'auth_rejected':
|
|
360
|
+
return 'no_auth';
|
|
361
|
+
case 'timeout':
|
|
362
|
+
return 'timeout';
|
|
363
|
+
case 'quota_exhausted':
|
|
364
|
+
return 'quota';
|
|
365
|
+
default:
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* One-shot, per-provider fallback ledger for a single invocation.
|
|
371
|
+
*
|
|
372
|
+
* Construct one per council run. `attempt` returns `'api'` at most ONCE per
|
|
373
|
+
* provider, and only for a fallback-eligible failure class; every later call
|
|
374
|
+
* for that provider returns `'stop'`. This is the double-spend guard: a
|
|
375
|
+
* timeout never falls through, and an eligible failure never falls through
|
|
376
|
+
* twice.
|
|
377
|
+
*/
|
|
378
|
+
export class MidFlightFallback {
|
|
379
|
+
used = new Set();
|
|
380
|
+
/** `'api'` to retry on the api rung, `'stop'` to surface the failure. */
|
|
381
|
+
attempt(provider, failure, policy = DEFAULT_FALLBACK_POLICY) {
|
|
382
|
+
if (!isFallbackEligibleUnder(failure, policy))
|
|
383
|
+
return 'stop';
|
|
384
|
+
if (this.used.has(provider))
|
|
385
|
+
return 'stop';
|
|
386
|
+
this.used.add(provider);
|
|
387
|
+
return 'api';
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Give a provider its one fallback back, because the twin never ran.
|
|
391
|
+
*
|
|
392
|
+
* R2 round 2, finding 8. `attempt` claims the slot at DECISION time, which
|
|
393
|
+
* is correct — the claim is what stops a dead binary being retried once per
|
|
394
|
+
* round. But a claim that is never CONSUMED must not stay spent: when the
|
|
395
|
+
* projected-spend gate refuses the escalation, no api call happens, and
|
|
396
|
+
* leaving the provider marked means the seat can never re-decide. Every
|
|
397
|
+
* later round then re-spawns the dead cli binary and gets `'stop'`, which
|
|
398
|
+
* is the exact per-round-ledger behaviour the invocation-scoped ledger was
|
|
399
|
+
* chosen to avoid.
|
|
400
|
+
*
|
|
401
|
+
* Called ONLY on a path where the twin was built and then not called.
|
|
402
|
+
* A provider that actually retried keeps its claim spent — that is the cap
|
|
403
|
+
* working.
|
|
404
|
+
*/
|
|
405
|
+
release(provider) {
|
|
406
|
+
this.used.delete(provider);
|
|
407
|
+
}
|
|
408
|
+
/** Providers that have already spent their one fallback. */
|
|
409
|
+
spent() {
|
|
410
|
+
return [...this.used].sort();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* True when `provider`'s CLI transport is a community wrapper — re-exported
|
|
415
|
+
* so callers reasoning about `auto` do not have to reach into the detector.
|
|
416
|
+
*/
|
|
417
|
+
export { isCommunityCli };
|
|
418
|
+
//# sourceMappingURL=transport_resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport_resolver.js","sourceRoot":"","sources":["../../../src/scripts/ai_council/transport_resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ import { detectRtk, rtkInstallCommands, RTK_UPSTREAM_REPO } from '../../install/
|
|
|
17
17
|
import { readSelectedTools, readSelectedPacks, writeSelectedTools } from '../../install/selectedTools.js';
|
|
18
18
|
import { detectAgentSwitch, AGENT_SWITCH_INSTALL_COMMAND, AGENT_SWITCH_REPO } from '../../install/agentSwitchDetection.js';
|
|
19
19
|
import { readDismissedRecommendations, dismissRecommendation } from '../../install/wizardDismissals.js';
|
|
20
|
+
import { apiOnQuotaView } from '../../scripts/ai_council/transport_resolver.js';
|
|
20
21
|
const STATE_REL = join('state', 'wizard-state.json');
|
|
21
22
|
const SETTINGS_REL = join('settings', '.agent-settings.yml');
|
|
22
23
|
const USER_IDENTITY_REL = join('settings', '.agent-user.yml');
|
|
@@ -245,7 +246,7 @@ function extractCouncilConfig(body) {
|
|
|
245
246
|
decision,
|
|
246
247
|
// Anything but a literal `true` reads as off — the same shape the
|
|
247
248
|
// CLI reader uses, so the two never disagree about spend.
|
|
248
|
-
fallback: { api_on_quota: fallbackCfg['api_on_quota']
|
|
249
|
+
fallback: { api_on_quota: apiOnQuotaView(fallbackCfg['api_on_quota']) },
|
|
249
250
|
};
|
|
250
251
|
}
|
|
251
252
|
function detectProjectSignals(root) {
|
|
@@ -510,7 +511,7 @@ const aiCouncilPayloadSchema = z.object({
|
|
|
510
511
|
* the write path is a comment-preserving `replaceScalar`, so an unmodelled
|
|
511
512
|
* block was never at risk. Contract: ai-council-config.md.
|
|
512
513
|
*/
|
|
513
|
-
fallbackApiOnQuota: z.boolean().optional(),
|
|
514
|
+
fallbackApiOnQuota: z.union([z.boolean(), z.literal('ask')]).optional(),
|
|
514
515
|
}).strict();
|
|
515
516
|
// road-to-reciprocal-ecosystem § Phase 1 — the closed set of dismissible
|
|
516
517
|
// passive-row recommendations. `agent-switch` is the only member today;
|