@productbrain/cli 0.1.0-beta.3508 → 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.
- package/dist/__tests__/gateway-dry-run-timeout.test.d.ts +2 -0
- package/dist/__tests__/gateway-dry-run-timeout.test.d.ts.map +1 -0
- package/dist/__tests__/gateway-dry-run-timeout.test.js +70 -0
- package/dist/__tests__/gateway-dry-run-timeout.test.js.map +1 -0
- package/dist/__tests__/gateway-timeout-body-phase.test.d.ts +2 -0
- package/dist/__tests__/gateway-timeout-body-phase.test.d.ts.map +1 -0
- package/dist/__tests__/gateway-timeout-body-phase.test.js +121 -0
- package/dist/__tests__/gateway-timeout-body-phase.test.js.map +1 -0
- package/dist/__tests__/route-latency-budget.test.d.ts +2 -0
- package/dist/__tests__/route-latency-budget.test.d.ts.map +1 -0
- package/dist/__tests__/route-latency-budget.test.js +103 -0
- package/dist/__tests__/route-latency-budget.test.js.map +1 -0
- package/dist/generated/routeLatencyBudget.generated.d.ts +55 -0
- package/dist/generated/routeLatencyBudget.generated.d.ts.map +1 -0
- package/dist/generated/routeLatencyBudget.generated.js +348 -0
- package/dist/generated/routeLatencyBudget.generated.js.map +1 -0
- package/dist/lib/client.d.ts +11 -9
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +57 -16
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/gatewayTimeout.d.ts +88 -0
- package/dist/lib/gatewayTimeout.d.ts.map +1 -0
- package/dist/lib/gatewayTimeout.js +118 -0
- package/dist/lib/gatewayTimeout.js.map +1 -0
- package/dist/lib/kernelEnvelope.d.ts +31 -0
- package/dist/lib/kernelEnvelope.d.ts.map +1 -0
- package/dist/lib/kernelEnvelope.js +52 -0
- package/dist/lib/kernelEnvelope.js.map +1 -0
- 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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"}
|
package/dist/lib/client.d.ts
CHANGED
|
@@ -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. */
|
package/dist/lib/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
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"}
|
package/dist/lib/client.js
CHANGED
|
@@ -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 =
|
|
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
|
}
|