@productbrain/cli 0.1.0-beta.3503 → 0.1.0-beta.3516

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 (29) hide show
  1. package/dist/__tests__/gateway-dry-run-timeout.test.d.ts +2 -0
  2. package/dist/__tests__/gateway-dry-run-timeout.test.d.ts.map +1 -0
  3. package/dist/__tests__/gateway-dry-run-timeout.test.js +70 -0
  4. package/dist/__tests__/gateway-dry-run-timeout.test.js.map +1 -0
  5. package/dist/__tests__/gateway-timeout-body-phase.test.d.ts +2 -0
  6. package/dist/__tests__/gateway-timeout-body-phase.test.d.ts.map +1 -0
  7. package/dist/__tests__/gateway-timeout-body-phase.test.js +121 -0
  8. package/dist/__tests__/gateway-timeout-body-phase.test.js.map +1 -0
  9. package/dist/__tests__/route-latency-budget.test.d.ts +2 -0
  10. package/dist/__tests__/route-latency-budget.test.d.ts.map +1 -0
  11. package/dist/__tests__/route-latency-budget.test.js +103 -0
  12. package/dist/__tests__/route-latency-budget.test.js.map +1 -0
  13. package/dist/generated/routeLatencyBudget.generated.d.ts +55 -0
  14. package/dist/generated/routeLatencyBudget.generated.d.ts.map +1 -0
  15. package/dist/generated/routeLatencyBudget.generated.js +348 -0
  16. package/dist/generated/routeLatencyBudget.generated.js.map +1 -0
  17. package/dist/lib/client.d.ts +11 -9
  18. package/dist/lib/client.d.ts.map +1 -1
  19. package/dist/lib/client.js +57 -16
  20. package/dist/lib/client.js.map +1 -1
  21. package/dist/lib/gatewayTimeout.d.ts +88 -0
  22. package/dist/lib/gatewayTimeout.d.ts.map +1 -0
  23. package/dist/lib/gatewayTimeout.js +118 -0
  24. package/dist/lib/gatewayTimeout.js.map +1 -0
  25. package/dist/lib/kernelEnvelope.d.ts +31 -0
  26. package/dist/lib/kernelEnvelope.d.ts.map +1 -0
  27. package/dist/lib/kernelEnvelope.js +52 -0
  28. package/dist/lib/kernelEnvelope.js.map +1 -0
  29. package/package.json +2 -2
@@ -0,0 +1,348 @@
1
+ // GENERATED by scripts/generate-route-latency-budget.mjs from packages/kernel-client/src/routeLatencyBudget.ts
2
+ // and packages/kernel-client/src/generated/routes.generated.ts.
3
+ // DO NOT EDIT. Run `npm run route-budget:codegen` to regenerate.
4
+ //
5
+ // WP-575 (TEN-2917, TEN-1126), commits_to DEC-64. This file is emitted IDENTICALLY into
6
+ // packages/mcp-server and packages/cli so the two connectors cannot disagree about how
7
+ // long a gateway route may take — the defect this work package removes was exactly that
8
+ // disagreement (MCP hardcoded a blanket 10s, the CLI set none at all).
9
+ //
10
+ // The rationale — why route TYPE is the structural predictor of LLM exposure, and how
11
+ // each value is grounded in DEC-64 rather than invented — lives with the declaration in
12
+ // packages/kernel-client/src/routeLatencyBudget.ts. Read that file before changing a
13
+ // number here; changing it HERE does nothing, the next codegen run overwrites it.
14
+ //
15
+ // Why a copy and not an import: both connectors consume @productbrain/kernel-client
16
+ // TYPE-ONLY (mcp-server via a tsconfig paths alias for Railway's isolated Docker build,
17
+ // DEC-701; cli as a devDependency it must not emit into its published dist/). A budget
18
+ // sets an AbortSignal, so it is runtime code and cannot be type-erased. See the
19
+ // generator header for the full constraint.
20
+ /** The budget table, copied verbatim from the SSOT. Milliseconds. */
21
+ export const ROUTE_LATENCY_BUDGET_MS = {
22
+ query: 10_000,
23
+ mutation: 10_000,
24
+ action: 30_000,
25
+ };
26
+ /**
27
+ * PER-ROUTE OVERRIDES — routes whose OWN server-side deadline exceeds their type's budget
28
+ * (PR #533 review, Codex P1). Route type predicts LLM EXPOSURE, not LLM COUNT: a flat
29
+ * action budget assumed every action is one inline LLM call, and shipped actions declare
30
+ * far longer deadlines. Bounding those at the type budget aborts a call the server is
31
+ * still legitimately working on. Each value is derived from a deadline the SERVER
32
+ * declares — see the SSOT for the citation behind every number.
33
+ */
34
+ export const ROUTE_LATENCY_BUDGET_OVERRIDE_MS = {
35
+ // convex/intelligence/onboardingChat.ts:333 declares `timeoutMs: 45_000` for the extraction
36
+ // LLM call — 15s BEYOND the flat action budget. 60s clears it with room for the surrounding
37
+ // request/response work the 45s covers none of.
38
+ 'onboarding.chat': 60_000,
39
+ // convex/intelligence/spineCheck.ts:210 sets SPINE_CHECK_WALL_CLOCK_BUDGET_MS = 4 * 60_000
40
+ // for its SEQUENTIAL strategy probes (:225-239, deliberately not Promise.all), and :215
41
+ // reserves a tail of one 25s probe + an optional 25s story pass + 10s. The server's own
42
+ // design ceiling is scheduleSpineCheck's 5-min MAX_RUN_IN_FLIGHT_MS lease (:206-209).
43
+ // 5.5 min sits above that ceiling and far under Convex's 10-min action cap.
44
+ 'quality.spineCheck': 330_000,
45
+ };
46
+ /**
47
+ * The widest declared budget — the fail-safe default for a route name this map does not
48
+ * know. Derived from the tables rather than restated, so it cannot drift if a value moves.
49
+ * Spans the overrides too, so the unknown-route default is never TIGHTER than a budget
50
+ * already granted to a known route.
51
+ */
52
+ export const WIDEST_ROUTE_LATENCY_BUDGET_MS = Math.max(...Object.values(ROUTE_LATENCY_BUDGET_MS), ...Object.values(ROUTE_LATENCY_BUDGET_OVERRIDE_MS));
53
+ /** Every gateway route's Convex function type, from convex/http.ts's registry. */
54
+ const ROUTE_TYPE_ENTRIES = {
55
+ "resolveWorkspace": "query",
56
+ "feedback.submit": "mutation",
57
+ "feedback.listOwn": "query",
58
+ "feedback.list": "action",
59
+ "feedback.note": "action",
60
+ "feedback.group": "action",
61
+ "feedback.status": "action",
62
+ "organisation.status": "query",
63
+ "organisation.assignMembership": "mutation",
64
+ "organisation.removeMembership": "mutation",
65
+ "organisation.setOwnership": "mutation",
66
+ "organisation.clearOwnership": "mutation",
67
+ "organisation.activate": "mutation",
68
+ "organisation.upgrade": "mutation",
69
+ "organisation.upgradeRung2": "mutation",
70
+ "organisation.upgradeRung3": "mutation",
71
+ "organisation.upgradeRung4": "mutation",
72
+ "organisation.updateGovernanceMode": "mutation",
73
+ "organisation.hierarchy.show": "query",
74
+ "organisation.hierarchy.setParent": "mutation",
75
+ "organisation.hierarchy.clearParent": "mutation",
76
+ "chain.seed": "mutation",
77
+ "chain.listCollections": "query",
78
+ "chain.getCollection": "query",
79
+ "chain.getCollectionFields": "query",
80
+ "chain.auditCollections": "query",
81
+ "chain.exportDefinitions": "query",
82
+ "chain.createCollection": "mutation",
83
+ "chain.updateCollection": "mutation",
84
+ "chain.listEntries": "query",
85
+ "chain.getEntry": "query",
86
+ "chain.batchGetEntries": "query",
87
+ "chain.createEntry": "action",
88
+ "chain.updateEntry": "mutation",
89
+ "chain.restoreArchivedEntry": "mutation",
90
+ "chain.moveToCollection": "mutation",
91
+ "chain.shapeAdvisories": "query",
92
+ "chain.shapeAdvisorySummary": "query",
93
+ "chain.showShapeAdvisory": "query",
94
+ "chain.dispositionShapeAdvisory": "mutation",
95
+ "conflicts.list": "query",
96
+ "conflicts.resolve": "mutation",
97
+ "conflicts.summary": "query",
98
+ "conflicts.snooze": "mutation",
99
+ "conflicts.reverdict": "mutation",
100
+ "direction.list": "query",
101
+ "direction.refresh": "action",
102
+ "direction.defer": "mutation",
103
+ "chain.classifyCollection": "action",
104
+ "chain.classifyStrategyCategory": "query",
105
+ "chain.batchClassifyHeuristic": "query",
106
+ "chain.resolveCollection": "action",
107
+ "chain.searchEntries": "query",
108
+ "chain.searchByCanonicalName": "query",
109
+ "chain.commitEntry": "mutation",
110
+ "chain.verifyEntry": "mutation",
111
+ "chain.batchCommitConstellation": "mutation",
112
+ "chain.listEntryHistory": "query",
113
+ "chain.listEntryVersions": "query",
114
+ "chain.createEntryRelation": "mutation",
115
+ "chain.createEntryRelations": "mutation",
116
+ "chain.removeEntryRelation": "mutation",
117
+ "chain.normalizeEntryDataLLM": "action",
118
+ "chain.decomposeContent": "action",
119
+ "chain.normalizeEntryDataPreview": "action",
120
+ "chain.listEntryRelations": "query",
121
+ "chain.scoreLinkCandidates": "query",
122
+ "chain.evaluateCoherence": "query",
123
+ "chain.listAutoLinkSuggestions": "query",
124
+ "chain.acceptAutoLinkSuggestion": "mutation",
125
+ "chain.dismissAutoLinkSuggestion": "mutation",
126
+ "chain.quarantineAutoLinkSuggestion": "mutation",
127
+ "chain.resurrectAutoLinkSuggestion": "mutation",
128
+ "chain.expireAutoLinkSuggestion": "mutation",
129
+ "chain.clusterAutoLinkSuggestions": "query",
130
+ "chain.batchApplyAutoLinkSuggestions": "action",
131
+ "chain.validateCommitConstellation": "query",
132
+ "chain.getCaptureContract": "query",
133
+ "chain.gatherContext": "query",
134
+ "chain.getConstellation": "query",
135
+ "chain.auditBet": "query",
136
+ "agentKnowledge.facilitateEnvelope": "action",
137
+ "agentKnowledge.wrapupEnvelope": "action",
138
+ "agentKnowledge.captureEnvelope": "action",
139
+ "chain.graphSuggestLinks": "query",
140
+ "chain.graphGatherContext": "query",
141
+ "chain.assembleBuildContext": "query",
142
+ "chain.qualityCheck": "query",
143
+ "chain.changeDetection": "query",
144
+ "chain.structuralAggregation": "query",
145
+ "chain.detectSemanticConflicts": "action",
146
+ "chain.taskAwareGatherContext": "query",
147
+ "chain.journeyAwareGatherContext": "query",
148
+ "chain.resolveTaskStartup": "query",
149
+ "chain.getBindingGovernanceView": "query",
150
+ "chain.resolveTaskStartupHybrid": "action",
151
+ "chain.taskAwareHybridGatherContext": "action",
152
+ "chain.gatherFromSeeds": "query",
153
+ "chain.getEntryNeighborhood": "query",
154
+ "chain.deepChainWalk": "action",
155
+ "chain.recordBriefRun": "mutation",
156
+ "chain.getLastBriefRun": "query",
157
+ "chain.incrementalChanges": "query",
158
+ "chain.compoundQuery": "action",
159
+ "chain.dismissSuggestion": "mutation",
160
+ "chain.recordSessionSignal": "mutation",
161
+ "chain.workspaceReadiness": "query",
162
+ "chain.getCaptureHealth": "query",
163
+ "chain.getGroundingHealth": "query",
164
+ "chain.recordGroundingOutcome": "mutation",
165
+ "chain.suggestLinksForCapture": "query",
166
+ "chain.setOnboardingCompleted": "mutation",
167
+ "chain.checkCardinalityWarning": "query",
168
+ "chain.ingestDocument": "action",
169
+ "chain.getOrientEntries": "query",
170
+ "chain.getOrientView": "action",
171
+ "chain.getRitualsSurface": "query",
172
+ "chain.getGovernanceWithRelations": "action",
173
+ "chain.classifyGovernance": "query",
174
+ "chain.getVocabulary": "query",
175
+ "scoreboard.get": "action",
176
+ "rework.report": "mutation",
177
+ "chain.listLabels": "query",
178
+ "chain.createLabel": "mutation",
179
+ "chain.updateLabel": "mutation",
180
+ "chain.deleteLabel": "mutation",
181
+ "chain.applyLabel": "mutation",
182
+ "chain.removeLabel": "mutation",
183
+ "chain.listEntriesByLabel": "query",
184
+ "setup.getActiveSurface": "query",
185
+ "setup.materializeSetup": "action",
186
+ "setup.recordTamperRefusal": "mutation",
187
+ "setup.recordTransition": "mutation",
188
+ "setup.getCurrentSetupState": "query",
189
+ "setup.listAssetsForUser": "query",
190
+ "setup.ingestSetupAsset": "mutation",
191
+ "setup.ingestSetupAssetWithBody": "action",
192
+ "setup.fetchAssetBody": "action",
193
+ "setup.auditAssetBodies": "action",
194
+ "setup.repairAssetBody": "action",
195
+ "setup.listFailedAuditReceipts": "action",
196
+ "setup.markPersonalSetupAssetDormantFromSync": "mutation",
197
+ "setup.resolveSemanticRefs": "query",
198
+ "setup.updateLastProjectedHash": "mutation",
199
+ "setup.getSkillSystemHealth": "query",
200
+ "setup.recordActivationReceipt": "mutation",
201
+ "setup.recordSetupInvocation": "mutation",
202
+ "setup.getUserActivationState": "query",
203
+ "setup.getPbSetupState": "query",
204
+ "setup.getSkillBody": "action",
205
+ "setup.stampMcpOnlySurface": "mutation",
206
+ "setup.stampDetectedSurfaces": "mutation",
207
+ "setup.getKey32Snapshot": "query",
208
+ "setup.getKey33Snapshot": "query",
209
+ "gaps.record": "mutation",
210
+ "gaps.resolve": "mutation",
211
+ "gaps.top": "query",
212
+ "gaps.stats": "query",
213
+ "agent.startSession": "mutation",
214
+ "agent.resumeSession": "mutation",
215
+ "agent.closeSession": "mutation",
216
+ "agent.markOriented": "mutation",
217
+ "agent.touchSession": "mutation",
218
+ "agent.recordActivity": "mutation",
219
+ "agent.getSession": "query",
220
+ "agent.getActiveSession": "query",
221
+ "agent.recentSessions": "query",
222
+ "agent.activityStats": "query",
223
+ "agent.getActivityByDay": "query",
224
+ "agent.validateSession": "query",
225
+ "agent.getSessionWrapup": "query",
226
+ "agent.recordWrapup": "mutation",
227
+ "agent.reportOrientMetric": "mutation",
228
+ "agent.listSessions": "query",
229
+ "agent.showConversation": "query",
230
+ "usage.getWorkspaceSummary": "query",
231
+ "quality.evaluateHeuristicAndSchedule": "mutation",
232
+ "quality.reEvaluateEntry": "mutation",
233
+ "quality.evaluateAtCapture": "action",
234
+ "quality.evaluateAtCommit": "action",
235
+ "quality.evaluateForReview": "action",
236
+ "quality.getCachedVerdict": "query",
237
+ "quality.getLatestVerdictForEntry": "query",
238
+ "quality.spineCheck": "action",
239
+ "quality.scheduleSpineCheck": "mutation",
240
+ "quality.getLatestSpineVerdict": "query",
241
+ "onboarding.chat": "action",
242
+ "workspace.health": "query",
243
+ "workspace.healthAll": "query",
244
+ "workspace.backfill": "mutation",
245
+ "workspace.backfillAll": "mutation",
246
+ "authorityDomains.readiness": "query",
247
+ "authorityDomains.add": "mutation",
248
+ "authorityDomains.propose": "action",
249
+ "authorityDomains.review": "query",
250
+ "authorityDomains.queueKnownTag": "mutation",
251
+ "authorityDomains.ratify": "mutation",
252
+ "authorityDomains.reject": "mutation",
253
+ "authorityDomains.discardPending": "mutation",
254
+ "authorityDomains.recordSample": "mutation",
255
+ "authorityDomains.benchmark": "action",
256
+ "authorityDomains.activateCutover": "mutation",
257
+ "authorityDomains.principleDistribution": "query",
258
+ "performance.getVitalsSummary": "query",
259
+ "performance.getApiOverview": "query",
260
+ "performance.getRouteBreakdown": "query",
261
+ "performance.getSlowSamples": "query",
262
+ "performance.getSampleCount": "query",
263
+ "chainwork.listTypes": "query",
264
+ "chainwork.getChainType": "query",
265
+ "chainwork.scoreRun": "query",
266
+ "chainwork.getArtifact": "query",
267
+ "chainwork.getWorkflowRun": "query",
268
+ "chainwork.getLatestWorkflowRun": "query",
269
+ "chainwork.recordWorkflowCheckpoint": "mutation",
270
+ "chainwork.finalizeWorkflowRun": "action",
271
+ "chainwork.submitToKG": "action",
272
+ "chainwork.generate": "action",
273
+ "chainwork.getLastVerifiedBrief": "query",
274
+ "gitchain.createChain": "mutation",
275
+ "gitchain.editLink": "mutation",
276
+ "gitchain.updateChain": "mutation",
277
+ "gitchain.getChain": "query",
278
+ "gitchain.listChains": "query",
279
+ "gitchain.getHistory": "query",
280
+ "gitchain.listCommits": "query",
281
+ "gitchain.commitChain": "mutation",
282
+ "gitchain.diffVersions": "mutation",
283
+ "gitchain.runGate": "query",
284
+ "gitchain.createBranch": "mutation",
285
+ "gitchain.listBranches": "mutation",
286
+ "gitchain.checkConflicts": "mutation",
287
+ "gitchain.mergeBranch": "mutation",
288
+ "gitchain.addComment": "mutation",
289
+ "gitchain.resolveComment": "mutation",
290
+ "gitchain.listComments": "mutation",
291
+ "gitchain.revertChain": "mutation",
292
+ "staging.getCommittedSourceRefs": "query",
293
+ "staging.commitStagingEntryWithClassification": "action",
294
+ "governance.listProposals": "query",
295
+ "governance.countOpenProposals": "query",
296
+ "governance.respondToProposal": "mutation",
297
+ "maps.createMap": "mutation",
298
+ "maps.createAudienceMapSet": "mutation",
299
+ "maps.addToSlot": "mutation",
300
+ "maps.removeFromSlot": "mutation",
301
+ "maps.replaceInSlot": "mutation",
302
+ "maps.commitMap": "mutation",
303
+ "maps.getMap": "query",
304
+ "maps.listMaps": "query",
305
+ "maps.getJourneyMapWithEnrichment": "query",
306
+ "maps.listJourneyMaps": "query",
307
+ "maps.listMapCommits": "query",
308
+ };
309
+ /**
310
+ * NULL-PROTOTYPE, deliberately (PR #533 review, Codex P2).
311
+ *
312
+ * A plain object literal inherits Object.prototype, so an unknown route name that
313
+ * collides with an inherited member — `toString`, `constructor`, `valueOf` — resolves to a
314
+ * TRUTHY function instead of falling through to the widest-budget default below. That
315
+ * yielded `AbortSignal.timeout(undefined)`, which THROWS before the call ever reaches the
316
+ * gateway — turning the fail-safe default into a hard failure.
317
+ *
318
+ * The SSOT scans an array (`GATEWAY_ROUTES.find`) and has no such hole, so a plain-object
319
+ * copy DISAGREED with the source it is generated from — precisely the connector drift this
320
+ * file exists to end. A null prototype restores parity for every consumer of the map at
321
+ * once (`latencyBudgetMsForRoute` here, `routeMayMutate` in both connectors' seams) rather
322
+ * than guarding each lookup and leaving the next one to rediscover it.
323
+ */
324
+ export const ROUTE_TYPE_BY_NAME = Object.assign(Object.create(null), ROUTE_TYPE_ENTRIES);
325
+ /** Budget for a route TYPE. Total over the three kinds the registry can produce. */
326
+ export function latencyBudgetMsForRouteType(type) {
327
+ return ROUTE_LATENCY_BUDGET_MS[type];
328
+ }
329
+ /**
330
+ * Budget for a route by NAME.
331
+ *
332
+ * FAILS SAFE, DELIBERATELY: an unknown name gets the WIDEST budget, not the tightest and
333
+ * not a throw. Guessing low on a route we cannot classify would abort a call still
334
+ * legitimately in flight and re-create the exact false-failure this work package removes.
335
+ * Guessing high only delays surfacing a genuinely stuck call — and an unknown name is
336
+ * almost always a caller bug the gateway rejects in milliseconds anyway.
337
+ */
338
+ export function latencyBudgetMsForRoute(routeName) {
339
+ // `Object.hasOwn`, not truthiness: the override table is a plain literal, so a bare
340
+ // lookup would resolve INHERITED members to a truthy value. Same hole the null
341
+ // prototype closes above, guarded here because this table stays a plain literal.
342
+ if (Object.hasOwn(ROUTE_LATENCY_BUDGET_OVERRIDE_MS, routeName)) {
343
+ return ROUTE_LATENCY_BUDGET_OVERRIDE_MS[routeName];
344
+ }
345
+ const type = ROUTE_TYPE_BY_NAME[routeName];
346
+ return type ? latencyBudgetMsForRouteType(type) : WIDEST_ROUTE_LATENCY_BUDGET_MS;
347
+ }
348
+ //# sourceMappingURL=routeLatencyBudget.generated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routeLatencyBudget.generated.js","sourceRoot":"","sources":["../../src/generated/routeLatencyBudget.generated.ts"],"names":[],"mappings":"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"}
@@ -9,17 +9,9 @@
9
9
  * sandboxed environments (Claude Code, Cursor) without requiring
10
10
  * NODE_OPTIONS="--use-env-proxy".
11
11
  */
12
+ import type { ValidationErrorDetail } from './kernelEnvelope.js';
12
13
  import { CLIError } from './errors.js';
13
14
  import { type KernelCallOptions } from './rate-limit.js';
14
- /** Structured field-level detail from a VALIDATION_FAILED response. */
15
- export interface ValidationErrorDetail {
16
- fieldKey: string;
17
- fieldLabel: string;
18
- invalidValue: unknown;
19
- validOptions?: string[];
20
- errorType: 'type_mismatch' | 'invalid_option' | 'required';
21
- message: string;
22
- }
23
15
  /** Error thrown by kernelCall/kernelCallWithSession when the server returns a non-OK response. */
24
16
  export declare class McpError extends CLIError {
25
17
  details?: ValidationErrorDetail[];
@@ -28,6 +20,7 @@ export declare class McpError extends CLIError {
28
20
  constructor(message: string, code?: string, details?: ValidationErrorDetail[], retryAfterSeconds?: number);
29
21
  }
30
22
  export { resetTouchThrottle, type KernelCallOptions } from './rate-limit.js';
23
+ export type { KernelEnvelope, ValidationErrorDetail } from './kernelEnvelope.js';
31
24
  /** Result of validateKey — used by `pb login` to verify a key before saving. */
32
25
  export type ValidateKeyResult = {
33
26
  valid: true;
@@ -43,6 +36,15 @@ export type ValidateKeyResult = {
43
36
  * Returns { valid: true, workspaceId } on success.
44
37
  * Returns { valid: false, error } on auth failure (401) or other server error.
45
38
  * Throws on network/timeout errors so the caller can distinguish "bad key" from "can't reach server".
39
+ *
40
+ * WP-575: `timeoutMs` now DEFAULTS to `resolveWorkspace`'s declared budget instead of a
41
+ * local `5000` literal — that literal was the last connector-owned timeout on the gateway
42
+ * path, and the point of this work package is that no connector gets to pick its own. It
43
+ * stays an explicit parameter so a caller (or a test) can still override deliberately.
44
+ * Widening 5s -> the declared 10s costs nothing in the case people actually hit: an
45
+ * unreachable host fails with ECONNREFUSED/ENOTFOUND immediately, not by timeout. The
46
+ * timeout only governs a server that ACCEPTS the connection then stalls, where waiting the
47
+ * route's real declared budget before calling the key invalid is the correct behavior.
46
48
  */
47
49
  export declare function validateKey(apiKey: string, siteUrl: string, timeoutMs?: number): Promise<ValidateKeyResult>;
48
50
  /** Get a human-friendly spinner label for an MCP function name. */
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAIlD,OAAO,EAAkC,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzF,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,eAAe,GAAG,gBAAgB,GAAG,UAAU,CAAC;IAC3D,OAAO,EAAE,MAAM,CAAC;CACjB;AA8CD,kGAAkG;AAClG,qBAAa,QAAS,SAAQ,QAAQ;IACpC,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAClC,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,EAAE,EAAE,iBAAiB,CAAC,EAAE,MAAM;CAe1G;AAID,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAkE7E,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GACzB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,SAAO,GACf,OAAO,CAAC,iBAAiB,CAAC,CAqC5B;AA6BD,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC,CAsBlB;AASD,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1C,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,CAAC,CAAC,CA8BZ;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAClD,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC,CA0B9F;AA0BD;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EACrD,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,CAAC,CAAC,CAyCZ"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAkB,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGjF,OAAO,EAAE,QAAQ,EAAa,MAAM,aAAa,CAAC;AAGlD,OAAO,EAAkC,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AA+CzF,kGAAkG;AAClG,qBAAa,QAAS,SAAQ,QAAQ;IACpC,OAAO,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAClC,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,EAAE,EAAE,iBAAiB,CAAC,EAAE,MAAM;CAe1G;AAID,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAK7E,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAoDjF,gFAAgF;AAChF,MAAM,MAAM,iBAAiB,GACzB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,SAA8C,GACtD,OAAO,CAAC,iBAAiB,CAAC,CAqC5B;AA6BD,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC,CAgClB;AASD,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1C,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,CAAC,CAAC,CAgCZ;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAClD,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC,CA4B9F;AA+BD;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EACrD,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EAClC,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,CAAC,CAAC,CA+CZ"}
@@ -9,11 +9,18 @@
9
9
  * sandboxed environments (Claude Code, Cursor) without requiring
10
10
  * NODE_OPTIONS="--use-env-proxy".
11
11
  */
12
+ // WP-575 (TEN-2917): every gateway call is bounded by the budget DECLARED at the route
13
+ // contract — see ./gatewayTimeout.ts for why a copy, and why the CLI had none before.
14
+ import { latencyBudgetMsForRoute } from '../generated/routeLatencyBudget.generated.js';
15
+ import { gatewayTimeoutError, isTimeoutAbort } from './gatewayTimeout.js';
16
+ // The envelope's shape and how to read one off a Response — including the body-phase budget
17
+ // abort (WP-575 review). Split out under STD-2/DEC-1504; see ./kernelEnvelope.ts's header for
18
+ // why the seam is real and not a line-count dodge.
19
+ import { parseKernelEnvelope, recordLatestFromResponse } from './kernelEnvelope.js';
12
20
  import { getConfig, resolveAdminConfig } from './config.js';
13
21
  import { readSession } from './session.js';
14
22
  import { CLIError, ErrorCode } from './errors.js';
15
23
  import { withSpinner } from './spinner.js';
16
- import { recordServerLatest } from './update-check.js';
17
24
  import { maybeRetry, shouldTouchSession } from './rate-limit.js';
18
25
  /**
19
26
  * Map MCP server error codes to CLIError categories.
@@ -85,13 +92,6 @@ export class McpError extends CLIError {
85
92
  // WP-579: the rate-limit retry and touch throttle live in rate-limit.ts — two
86
93
  // self-contained policies with their own state, kept out of this module's budget (STD-2).
87
94
  export { resetTouchThrottle } from './rate-limit.js';
88
- function recordLatestFromResponse(res) {
89
- recordServerLatest(res.headers?.get?.('pb-latest-cli-version') ?? null);
90
- }
91
- async function parseKernelEnvelope(res) {
92
- recordLatestFromResponse(res);
93
- return (await res.json().catch(() => ({})));
94
- }
95
95
  // Configure proxy at module load — runs once, before any fetch call.
96
96
  // Node.js fetch (undici) ignores HTTPS_PROXY env vars. We detect the proxy
97
97
  // and install a ProxyAgent as the global dispatcher so all fetch() calls
@@ -107,8 +107,16 @@ catch {
107
107
  // undici unavailable or proxy config failed — rethrowWithGuidance handles it.
108
108
  }
109
109
  /** Detect a sandbox/network-blocked fetch and re-throw with guidance. */
110
- function rethrowWithGuidance(err, siteUrl) {
110
+ function rethrowWithGuidance(err, siteUrl,
111
+ // WP-575: the route being called, the budget it was given, and the call's own args, so a
112
+ // budget abort can be reported as itself rather than collapsing into "Could not reach
113
+ // <host>" — and so a dry run is never told its write may have landed (see ./gatewayTimeout.ts).
114
+ route) {
111
115
  const msg = err instanceof Error ? err.message : String(err);
116
+ // WP-575: a budget abort is not an unreachable host — the connection succeeded, we stopped
117
+ // waiting, and for a write route the server may have finished. See ./gatewayTimeout.ts.
118
+ if (route && isTimeoutAbort(err))
119
+ throw gatewayTimeoutError(route.fn, route.budgetMs, route.args);
112
120
  if (msg === 'fetch failed' || msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
113
121
  const host = new URL(siteUrl).hostname;
114
122
  const proxy = process.env.https_proxy || process.env.HTTPS_PROXY;
@@ -136,8 +144,17 @@ function rethrowWithGuidance(err, siteUrl) {
136
144
  * Returns { valid: true, workspaceId } on success.
137
145
  * Returns { valid: false, error } on auth failure (401) or other server error.
138
146
  * Throws on network/timeout errors so the caller can distinguish "bad key" from "can't reach server".
147
+ *
148
+ * WP-575: `timeoutMs` now DEFAULTS to `resolveWorkspace`'s declared budget instead of a
149
+ * local `5000` literal — that literal was the last connector-owned timeout on the gateway
150
+ * path, and the point of this work package is that no connector gets to pick its own. It
151
+ * stays an explicit parameter so a caller (or a test) can still override deliberately.
152
+ * Widening 5s -> the declared 10s costs nothing in the case people actually hit: an
153
+ * unreachable host fails with ECONNREFUSED/ENOTFOUND immediately, not by timeout. The
154
+ * timeout only governs a server that ACCEPTS the connection then stalls, where waiting the
155
+ * route's real declared budget before calling the key invalid is the correct behavior.
139
156
  */
140
- export async function validateKey(apiKey, siteUrl, timeoutMs = 5000) {
157
+ export async function validateKey(apiKey, siteUrl, timeoutMs = latencyBudgetMsForRoute('resolveWorkspace')) {
141
158
  return withSpinner('Validating API key', async () => {
142
159
  const controller = new AbortController();
143
160
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -209,6 +226,16 @@ export function spinnerLabel(fn) {
209
226
  */
210
227
  export async function adminCall(command, args) {
211
228
  const { apiKey, siteUrl } = resolveAdminConfig();
229
+ // WP-575 deliberately leaves /api/admin UNBOUNDED (PR #533 review, Codex P2 — an earlier
230
+ // round bounded it and that was the regression). Admin commands are long-running BULK
231
+ // operations (`manage:delete-workspace` cascading 100-row batches, `seed:backfill-starter`
232
+ // across workspaces) and are NOT in the route registry, so the fail-safe "widest" fallback
233
+ // is a real number for a route the contract describes and a guess for one it doesn't —
234
+ // an arbitrary ceiling on a destructive operation that can abort it mid-flight, which is
235
+ // worse than the hang it would prevent. (That fallback is whatever
236
+ // WIDEST_ROUTE_LATENCY_BUDGET_MS happens to be — today 330_000, since it spans the override
237
+ // table too — which is the point: a number that MOVES when an unrelated route's override
238
+ // changes is not a budget for this surface.) It needs its own MEASURED budget: follow-up work.
212
239
  let res;
213
240
  try {
214
241
  res = await fetch(`${siteUrl}/api/admin`, {
@@ -238,6 +265,7 @@ const PB_TELEMETRY_SOURCE = 'cli';
238
265
  export async function kernelCall(fn, args = {}, options) {
239
266
  const { apiKey, siteUrl } = getConfig();
240
267
  const label = spinnerLabel(fn);
268
+ const budgetMs = latencyBudgetMsForRoute(fn);
241
269
  // Spinner OUTSIDE the retry: withSpinner reports a terminal `— failed` line on any throw,
242
270
  // so a spinner per attempt would paint up to MAX_RATE_LIMIT_RETRIES false failures for a
243
271
  // call that ultimately succeeds, then sit silent through each Retry-After wait.
@@ -246,6 +274,7 @@ export async function kernelCall(fn, args = {}, options) {
246
274
  try {
247
275
  res = await fetch(`${siteUrl}/api/aki`, {
248
276
  method: 'POST',
277
+ signal: AbortSignal.timeout(budgetMs),
249
278
  headers: {
250
279
  'Content-Type': 'application/json',
251
280
  Authorization: `Bearer ${apiKey}`,
@@ -256,9 +285,9 @@ export async function kernelCall(fn, args = {}, options) {
256
285
  });
257
286
  }
258
287
  catch (err) {
259
- rethrowWithGuidance(err, siteUrl);
288
+ rethrowWithGuidance(err, siteUrl, { fn, budgetMs, args });
260
289
  }
261
- const envelope = await parseKernelEnvelope(res);
290
+ const envelope = await parseKernelEnvelope(res, { fn, budgetMs, args });
262
291
  if (!res.ok || envelope.ok === false) {
263
292
  throw new McpError(envelope.message || envelope.error || res.statusText, envelope.code, envelope.details, envelope.retryAfterSeconds);
264
293
  }
@@ -275,11 +304,13 @@ export async function kernelCall(fn, args = {}, options) {
275
304
  export async function kernelCallEnvelope(fn, args = {}, options) {
276
305
  const { apiKey, siteUrl } = getConfig();
277
306
  const label = spinnerLabel(fn);
307
+ const budgetMs = latencyBudgetMsForRoute(fn);
278
308
  return withSpinner(label, () => maybeRetry(async () => {
279
309
  let res;
280
310
  try {
281
311
  res = await fetch(`${siteUrl}/api/aki`, {
282
312
  method: 'POST',
313
+ signal: AbortSignal.timeout(budgetMs),
283
314
  headers: {
284
315
  'Content-Type': 'application/json',
285
316
  Authorization: `Bearer ${apiKey}`,
@@ -289,9 +320,9 @@ export async function kernelCallEnvelope(fn, args = {}, options) {
289
320
  });
290
321
  }
291
322
  catch (err) {
292
- rethrowWithGuidance(err, siteUrl);
323
+ rethrowWithGuidance(err, siteUrl, { fn, budgetMs, args });
293
324
  }
294
- const envelope = await parseKernelEnvelope(res);
325
+ const envelope = await parseKernelEnvelope(res, { fn, budgetMs, args });
295
326
  if (!res.ok || envelope.ok === false) {
296
327
  throw new McpError(envelope.message || envelope.error || res.statusText, envelope.code, envelope.details, envelope.retryAfterSeconds);
297
328
  }
@@ -306,6 +337,11 @@ async function mcpFetchRaw(fn, args, apiKey, siteUrl) {
306
337
  try {
307
338
  await fetch(`${siteUrl}/api/aki`, {
308
339
  method: 'POST',
340
+ // WP-575: fire-and-forget still gets the declared budget. Errors are swallowed either
341
+ // way, so this is not about the message — it is about not leaving a socket and a
342
+ // pending promise open indefinitely on a stuck backend behind an already-returned
343
+ // command. "Best-effort" was never meant to mean "unbounded".
344
+ signal: AbortSignal.timeout(latencyBudgetMsForRoute(fn)),
309
345
  headers: {
310
346
  'Content-Type': 'application/json',
311
347
  Authorization: `Bearer ${apiKey}`,
@@ -340,19 +376,24 @@ export async function kernelCallWithSession(fn, args = {}, options) {
340
376
  // DEC-1207: attribute this connector for the gateway's context.served seam.
341
377
  'x-pb-source': PB_TELEMETRY_SOURCE,
342
378
  };
379
+ // WP-575 + WP-579 compose deliberately: the budget is derived ONCE per route, but the
380
+ // AbortSignal is created inside the retried callback, so each 429 retry attempt gets its
381
+ // own full budget rather than sharing one deadline across all attempts.
382
+ const budgetMs = latencyBudgetMsForRoute(fn);
343
383
  const result = await withSpinner(label, () => maybeRetry(async () => {
344
384
  let res;
345
385
  try {
346
386
  res = await fetch(`${siteUrl}/api/aki`, {
347
387
  method: 'POST',
388
+ signal: AbortSignal.timeout(budgetMs),
348
389
  headers,
349
390
  body: JSON.stringify({ fn, args }),
350
391
  });
351
392
  }
352
393
  catch (err) {
353
- rethrowWithGuidance(err, siteUrl);
394
+ rethrowWithGuidance(err, siteUrl, { fn, budgetMs, args });
354
395
  }
355
- const envelope = await parseKernelEnvelope(res);
396
+ const envelope = await parseKernelEnvelope(res, { fn, budgetMs, args });
356
397
  if (!res.ok || envelope.ok === false) {
357
398
  throw new McpError(envelope.message || envelope.error || res.statusText, envelope.code, envelope.details, envelope.retryAfterSeconds);
358
399
  }