@llamaventures/cli 1.19.0 → 1.22.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/AGENT_BRIEFING.md +11 -6
- package/CHANGELOG.md +49 -1
- package/README.md +12 -4
- package/README.zh-CN.md +9 -2
- package/bin/llama-mcp.mjs +133 -138
- package/bin/llama.mjs +102 -179
- package/contracts/core-api.json +4 -4
- package/contracts/required-operations.json +336 -85
- package/lib/build-manifest.json +4 -4
- package/lib/client.mjs +48 -3
- package/lib/server-compatibility.mjs +96 -0
- package/package.json +2 -2
|
@@ -2,90 +2,341 @@
|
|
|
2
2
|
"format": "llama.cli-core-api-operations.v1",
|
|
3
3
|
"coreApiContract": "contracts/core-api.json",
|
|
4
4
|
"requiredOperations": [
|
|
5
|
-
{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
{
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
{
|
|
5
|
+
{
|
|
6
|
+
"method": "GET",
|
|
7
|
+
"path": "/api/admin/agent-events"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"method": "GET",
|
|
11
|
+
"path": "/api/admin/auth-events"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"method": "GET",
|
|
15
|
+
"path": "/api/admin/deal-events"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"method": "GET",
|
|
19
|
+
"path": "/api/agent/activity"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"method": "GET",
|
|
23
|
+
"path": "/api/agent/briefing"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"method": "POST",
|
|
27
|
+
"path": "/api/agent/client-events"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"method": "GET",
|
|
31
|
+
"path": "/api/agent/explain"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"method": "GET",
|
|
35
|
+
"path": "/api/agent/manifest"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"method": "GET",
|
|
39
|
+
"path": "/api/agent/preferences"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"method": "POST",
|
|
43
|
+
"path": "/api/agent/preferences"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"method": "PATCH",
|
|
47
|
+
"path": "/api/agent/preferences/{id}"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"method": "GET",
|
|
51
|
+
"path": "/api/agent/skills"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"method": "GET",
|
|
55
|
+
"path": "/api/agent/skills/{slug}"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"method": "GET",
|
|
59
|
+
"path": "/api/deals"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"method": "POST",
|
|
63
|
+
"path": "/api/deals/create"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"method": "GET",
|
|
67
|
+
"path": "/api/deals/deleted"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"method": "POST",
|
|
71
|
+
"path": "/api/deals/update"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"method": "DELETE",
|
|
75
|
+
"path": "/api/deals/{dealId}"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"method": "GET",
|
|
79
|
+
"path": "/api/deals/{dealId}"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"method": "POST",
|
|
83
|
+
"path": "/api/deals/{dealId}/agent-runs/{runId}/revert"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"method": "GET",
|
|
87
|
+
"path": "/api/deals/{dealId}/blocks"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"method": "PUT",
|
|
91
|
+
"path": "/api/deals/{dealId}/blocks"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"method": "DELETE",
|
|
95
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"method": "GET",
|
|
99
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"method": "PATCH",
|
|
103
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"method": "GET",
|
|
107
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}/history"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"method": "POST",
|
|
111
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}/history"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"method": "POST",
|
|
115
|
+
"path": "/api/deals/{dealId}/blocks/{blockId}/restore"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"method": "GET",
|
|
119
|
+
"path": "/api/deals/{dealId}/collaborators"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"method": "POST",
|
|
123
|
+
"path": "/api/deals/{dealId}/collaborators"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"method": "DELETE",
|
|
127
|
+
"path": "/api/deals/{dealId}/collaborators/{userId}"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"method": "POST",
|
|
131
|
+
"path": "/api/deals/{dealId}/collaborators/{userId}/restore"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"method": "GET",
|
|
135
|
+
"path": "/api/deals/{dealId}/command-center"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"method": "GET",
|
|
139
|
+
"path": "/api/deals/{dealId}/documents"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"method": "POST",
|
|
143
|
+
"path": "/api/deals/{dealId}/documents"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"method": "DELETE",
|
|
147
|
+
"path": "/api/deals/{dealId}/documents/{slug}"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"method": "PATCH",
|
|
151
|
+
"path": "/api/deals/{dealId}/documents/{slug}"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"method": "DELETE",
|
|
155
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"method": "GET",
|
|
159
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"method": "PUT",
|
|
163
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"method": "GET",
|
|
167
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html/history"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"method": "POST",
|
|
171
|
+
"path": "/api/deals/{dealId}/documents/{slug}/html/restore/{version}"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"method": "POST",
|
|
175
|
+
"path": "/api/deals/{dealId}/enrich"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"method": "GET",
|
|
179
|
+
"path": "/api/deals/{dealId}/facts"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"method": "POST",
|
|
183
|
+
"path": "/api/deals/{dealId}/facts"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"method": "PATCH",
|
|
187
|
+
"path": "/api/deals/{dealId}/facts/{factId}"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"method": "GET",
|
|
191
|
+
"path": "/api/deals/{dealId}/feed"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"method": "PUT",
|
|
195
|
+
"path": "/api/deals/{dealId}/founders"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"method": "POST",
|
|
199
|
+
"path": "/api/deals/{dealId}/ingest"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"method": "GET",
|
|
203
|
+
"path": "/api/deals/{dealId}/links"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"method": "POST",
|
|
207
|
+
"path": "/api/deals/{dealId}/links"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"method": "DELETE",
|
|
211
|
+
"path": "/api/deals/{dealId}/links/{linkId}"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"method": "POST",
|
|
215
|
+
"path": "/api/deals/{dealId}/links/{linkId}/restore"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"method": "DELETE",
|
|
219
|
+
"path": "/api/deals/{dealId}/memo"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"method": "GET",
|
|
223
|
+
"path": "/api/deals/{dealId}/memo"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"method": "POST",
|
|
227
|
+
"path": "/api/deals/{dealId}/memo"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"method": "PUT",
|
|
231
|
+
"path": "/api/deals/{dealId}/memo"
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"method": "POST",
|
|
235
|
+
"path": "/api/deals/{dealId}/posts"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"method": "POST",
|
|
239
|
+
"path": "/api/deals/{dealId}/propose-owner"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"method": "POST",
|
|
243
|
+
"path": "/api/deals/{dealId}/refresh-brief"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"method": "POST",
|
|
247
|
+
"path": "/api/deals/{dealId}/restore"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"method": "POST",
|
|
251
|
+
"path": "/api/deals/{dealId}/threads"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"method": "POST",
|
|
255
|
+
"path": "/api/deals/{dealId}/threads/{threadId}"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"method": "GET",
|
|
259
|
+
"path": "/api/deals/{dealId}/timeline"
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"method": "POST",
|
|
263
|
+
"path": "/api/external/chat"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"method": "POST",
|
|
267
|
+
"path": "/api/external/start-session"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"method": "POST",
|
|
271
|
+
"path": "/api/external/upload"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"method": "GET",
|
|
275
|
+
"path": "/api/me"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"method": "GET",
|
|
279
|
+
"path": "/api/me/nominations"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"method": "GET",
|
|
283
|
+
"path": "/api/mentions"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"method": "GET",
|
|
287
|
+
"path": "/api/mentions/unread-count"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"method": "POST",
|
|
291
|
+
"path": "/api/mentions/{id}/resolve"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
"method": "POST",
|
|
295
|
+
"path": "/api/nominations/{approvalId}"
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
"method": "GET",
|
|
299
|
+
"path": "/api/oauth/authorize"
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"method": "POST",
|
|
303
|
+
"path": "/api/oauth/revoke"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"method": "POST",
|
|
307
|
+
"path": "/api/oauth/token"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"method": "GET",
|
|
311
|
+
"path": "/api/partner/approvals"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"method": "POST",
|
|
315
|
+
"path": "/api/partner/approvals"
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"method": "GET",
|
|
319
|
+
"path": "/api/users"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"method": "POST",
|
|
323
|
+
"path": "/api/wiki/save"
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"method": "GET",
|
|
327
|
+
"path": "/api/wiki/search"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"method": "DELETE",
|
|
331
|
+
"path": "/api/wiki/{slug}"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"method": "GET",
|
|
335
|
+
"path": "/api/wiki/{slug}"
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"method": "POST",
|
|
339
|
+
"path": "/api/wiki/{slug}/restore"
|
|
340
|
+
}
|
|
90
341
|
]
|
|
91
342
|
}
|
package/lib/build-manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "llama.cli-build.v1",
|
|
3
3
|
"packageName": "@llamaventures/cli",
|
|
4
|
-
"packageVersion": "1.
|
|
5
|
-
"sourceSha": "
|
|
4
|
+
"packageVersion": "1.22.0",
|
|
5
|
+
"sourceSha": "3e3ede496804de031650e23fc29e1a6763c41daf",
|
|
6
6
|
"sourceKind": "github",
|
|
7
7
|
"sourceDirty": false,
|
|
8
8
|
"coreApiContract": {
|
|
9
9
|
"format": "llama.core-api-contract.v1",
|
|
10
10
|
"name": "llama-core-api",
|
|
11
|
-
"apiVersion": "
|
|
11
|
+
"apiVersion": "3.5.0",
|
|
12
12
|
"openapiVersion": "3.0.3",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "31c7d23ee06bd4282aa2451698604cc30df4792d4a0e9674593a809b4eb55767"
|
|
14
14
|
}
|
|
15
15
|
}
|
package/lib/client.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import { execFile as _execFile } from "child_process";
|
|
|
15
15
|
import { promisify } from "util";
|
|
16
16
|
import { createHash, randomUUID } from "crypto";
|
|
17
17
|
import { getBuildInfo } from "./build-info.mjs";
|
|
18
|
+
import { maybeNudgeServerCompatibility } from "./server-compatibility.mjs";
|
|
18
19
|
|
|
19
20
|
const execFile = promisify(_execFile);
|
|
20
21
|
|
|
@@ -198,7 +199,6 @@ function rememberAgentEvent(event) {
|
|
|
198
199
|
...readAgentSession(),
|
|
199
200
|
sessionId: event.sessionId || currentAgentSessionId(),
|
|
200
201
|
lastEventId: event.eventId,
|
|
201
|
-
lastCandidateId: event.candidateId ?? null,
|
|
202
202
|
lastCommand: event.command ?? null,
|
|
203
203
|
lastQuery: event.query ?? null,
|
|
204
204
|
lastSurface: event.surface ?? null,
|
|
@@ -293,6 +293,7 @@ function inferCommand(method, endpoint) {
|
|
|
293
293
|
if (pathname === "/api/deals") return verb === "GET" ? "deal.search" : "deal.write";
|
|
294
294
|
if (pathname === "/api/deals/create") return "deal.create";
|
|
295
295
|
if (pathname === "/api/deals/update") return "deal.update";
|
|
296
|
+
if (/^\/api\/deals\/[^/]+\/ingest$/.test(pathname)) return "deal.ingest";
|
|
296
297
|
if (/^\/api\/deals\/[^/]+\/threads\/[^/]+$/.test(pathname)) return "deal.agent.run";
|
|
297
298
|
if (/^\/api\/deals\/[^/]+\/threads$/.test(pathname)) return "deal.thread.create";
|
|
298
299
|
if (/^\/api\/deals\/[^/]+\/facts/.test(pathname)) return verb === "GET" ? "deal.fact.list" : "deal.fact.write";
|
|
@@ -523,6 +524,48 @@ export async function requestSse(method, endpoint, body, opts = {}) {
|
|
|
523
524
|
return requestSseWithRetry(method, endpoint, body, opts, /* allowRetry */ true);
|
|
524
525
|
}
|
|
525
526
|
|
|
527
|
+
function apiResponseError(data, status) {
|
|
528
|
+
const message =
|
|
529
|
+
typeof data === "object" && data?.error ? data.error : `HTTP ${status}`;
|
|
530
|
+
if (data?.code === "CLI_VERSION_UNSUPPORTED") {
|
|
531
|
+
const recovery = data?.recovery?.command || "npm i -g @llamaventures/cli@latest";
|
|
532
|
+
const error = new Error(
|
|
533
|
+
`Error[CLI_VERSION_UNSUPPORTED]: ${message}\n` +
|
|
534
|
+
`Recovery: ${recovery}\n` +
|
|
535
|
+
"Retry the original Llama command after upgrading.",
|
|
536
|
+
);
|
|
537
|
+
error.code = data.code;
|
|
538
|
+
error.details = data;
|
|
539
|
+
return error;
|
|
540
|
+
}
|
|
541
|
+
if (data?.code !== "MENTION_APPROVAL_REQUIRED") {
|
|
542
|
+
const error = new Error(message);
|
|
543
|
+
if (typeof data?.code === "string") error.code = data.code;
|
|
544
|
+
error.details = data;
|
|
545
|
+
return error;
|
|
546
|
+
}
|
|
547
|
+
const recipients = Array.isArray(data?.cue?.recipients)
|
|
548
|
+
? data.cue.recipients
|
|
549
|
+
.map((recipient) => {
|
|
550
|
+
const name = recipient?.name || `user ${recipient?.user_id ?? "unknown"}`;
|
|
551
|
+
return recipient?.intent ? `${name} (${recipient.intent})` : name;
|
|
552
|
+
})
|
|
553
|
+
.join(", ")
|
|
554
|
+
: "unknown";
|
|
555
|
+
const channels = Array.isArray(data?.cue?.channels)
|
|
556
|
+
? data.cue.channels.join(" + ")
|
|
557
|
+
: "inbox + email";
|
|
558
|
+
const error = new Error(
|
|
559
|
+
`Error[MENTION_APPROVAL_REQUIRED]: ${message}\n` +
|
|
560
|
+
`Recipients: ${recipients}\n` +
|
|
561
|
+
`Channels: ${channels}\n` +
|
|
562
|
+
"Ask the user for explicit permission, then retry the exact write with --cue (CLI) or cueAuthorized=true (MCP).",
|
|
563
|
+
);
|
|
564
|
+
error.code = data.code;
|
|
565
|
+
error.details = data;
|
|
566
|
+
return error;
|
|
567
|
+
}
|
|
568
|
+
|
|
526
569
|
async function requestWithRetry(method, endpoint, body, opts, allowRetry) {
|
|
527
570
|
const authHeaders = await getAuthHeaders();
|
|
528
571
|
if (Object.keys(authHeaders).length === 0) throw noAuthError();
|
|
@@ -538,6 +581,7 @@ async function requestWithRetry(method, endpoint, body, opts, allowRetry) {
|
|
|
538
581
|
},
|
|
539
582
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
540
583
|
});
|
|
584
|
+
maybeNudgeServerCompatibility(res.headers);
|
|
541
585
|
|
|
542
586
|
// 401 + we sent an OAuth Bearer + this is the first attempt → try a
|
|
543
587
|
// forced refresh once. Covers two cases: (a) clock skew between client
|
|
@@ -582,7 +626,7 @@ async function requestWithRetry(method, endpoint, body, opts, allowRetry) {
|
|
|
582
626
|
data: null,
|
|
583
627
|
errorMessage: message,
|
|
584
628
|
});
|
|
585
|
-
throw
|
|
629
|
+
throw apiResponseError(data, res.status);
|
|
586
630
|
}
|
|
587
631
|
await recordClientTelemetry({
|
|
588
632
|
authHeaders,
|
|
@@ -613,6 +657,7 @@ async function requestSseWithRetry(method, endpoint, body, opts, allowRetry) {
|
|
|
613
657
|
},
|
|
614
658
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
615
659
|
});
|
|
660
|
+
maybeNudgeServerCompatibility(res.headers);
|
|
616
661
|
|
|
617
662
|
if (res.status === 401 && allowRetry && (await bearerCameFromOAuth())) {
|
|
618
663
|
let refreshed = null;
|
|
@@ -651,7 +696,7 @@ async function requestSseWithRetry(method, endpoint, body, opts, allowRetry) {
|
|
|
651
696
|
data: null,
|
|
652
697
|
errorMessage: message,
|
|
653
698
|
});
|
|
654
|
-
throw
|
|
699
|
+
throw apiResponseError(data, res.status);
|
|
655
700
|
}
|
|
656
701
|
|
|
657
702
|
const reader = res.body?.getReader();
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Consume the compatibility policy returned by Llama Command.
|
|
2
|
+
//
|
|
3
|
+
// Unlike the npm-registry nudge, this path is intentionally NOT TTY-gated:
|
|
4
|
+
// coding agents and MCP hosts need to see the server's recommendation too.
|
|
5
|
+
// It remains safe for scripts because it writes only to stderr and shares the
|
|
6
|
+
// existing once-per-day update stamp with lib/version-check.mjs.
|
|
7
|
+
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import os from "os";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
|
|
13
|
+
const DEFAULT_STAMP_FILE = path.join(os.homedir(), ".llama", ".update-check");
|
|
14
|
+
const THROTTLE_MS = 24 * 60 * 60 * 1000;
|
|
15
|
+
|
|
16
|
+
function installedVersion() {
|
|
17
|
+
try {
|
|
18
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
19
|
+
return String(requireFromHere("../package.json").version || "unknown");
|
|
20
|
+
} catch {
|
|
21
|
+
return "unknown";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readHeader(headers, name) {
|
|
26
|
+
if (typeof headers?.get === "function") return headers.get(name);
|
|
27
|
+
if (!headers || typeof headers !== "object") return null;
|
|
28
|
+
const match = Object.entries(headers).find(
|
|
29
|
+
([key]) => key.toLowerCase() === name.toLowerCase(),
|
|
30
|
+
);
|
|
31
|
+
return match ? String(match[1]) : null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function parseServerCompatibility(headers) {
|
|
35
|
+
const status = readHeader(headers, "x-llama-cli-status");
|
|
36
|
+
if (!["ok", "stale", "unsupported", "unknown"].includes(status)) return null;
|
|
37
|
+
return {
|
|
38
|
+
status,
|
|
39
|
+
recommendedVersion: readHeader(headers, "x-llama-cli-recommended-version"),
|
|
40
|
+
minimumVersion: readHeader(headers, "x-llama-cli-minimum-version"),
|
|
41
|
+
upgradeCommand:
|
|
42
|
+
readHeader(headers, "x-llama-cli-upgrade-command") ||
|
|
43
|
+
"npm i -g @llamaventures/cli@latest",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function checkedRecently(stampFile, now) {
|
|
48
|
+
try {
|
|
49
|
+
const last = Number.parseInt(fs.readFileSync(stampFile, "utf8").trim(), 10);
|
|
50
|
+
return Number.isFinite(last) && now - last < THROTTLE_MS;
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function touchStamp(stampFile, now) {
|
|
57
|
+
try {
|
|
58
|
+
fs.mkdirSync(path.dirname(stampFile), { recursive: true, mode: 0o700 });
|
|
59
|
+
fs.writeFileSync(stampFile, `${now}\n`, { mode: 0o600 });
|
|
60
|
+
} catch {
|
|
61
|
+
// Best-effort only. Compatibility hints must never break a command.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function formatServerCompatibilityNudge(policy, currentVersion = installedVersion()) {
|
|
66
|
+
if (policy?.status !== "stale" || !policy.recommendedVersion) return null;
|
|
67
|
+
return (
|
|
68
|
+
`warning[CLI_UPDATE_RECOMMENDED]: Llama Command recommends ` +
|
|
69
|
+
`@llamaventures/cli ${policy.recommendedVersion}; this client is ${currentVersion}. ` +
|
|
70
|
+
`Upgrade: ${policy.upgradeCommand}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function maybeNudgeServerCompatibility(headers, options = {}) {
|
|
75
|
+
try {
|
|
76
|
+
const env = options.env ?? process.env;
|
|
77
|
+
if (env.LLAMA_NO_UPDATE_CHECK) return false;
|
|
78
|
+
const policy = parseServerCompatibility(headers);
|
|
79
|
+
const nudge = formatServerCompatibilityNudge(
|
|
80
|
+
policy,
|
|
81
|
+
options.currentVersion ?? installedVersion(),
|
|
82
|
+
);
|
|
83
|
+
if (!nudge) return false;
|
|
84
|
+
const now = options.now ?? Date.now();
|
|
85
|
+
const stampFile = options.stampFile ?? DEFAULT_STAMP_FILE;
|
|
86
|
+
if (checkedRecently(stampFile, now)) return false;
|
|
87
|
+
touchStamp(stampFile, now);
|
|
88
|
+
const write = options.write ?? ((line) => process.stderr.write(`${line}\n`));
|
|
89
|
+
write(nudge);
|
|
90
|
+
return true;
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const SERVER_COMPATIBILITY_STAMP_FILE = DEFAULT_STAMP_FILE;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llamaventures/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"description": "CLI + MCP server for the Llama Ventures investment workbench (command.llamaventures.vc).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "npm run test:agent-routing && npm run test:contract",
|
|
8
8
|
"test:agent-routing": "node scripts/verify-agent-routing.mjs",
|
|
9
|
-
"test:contract": "node --test scripts/build-manifest.test.mjs scripts/core-api-call-sites.test.mjs scripts/verify-core-api-contract.test.mjs && node scripts/verify-core-api-contract.mjs",
|
|
9
|
+
"test:contract": "node --test scripts/build-manifest.test.mjs scripts/core-api-call-sites.test.mjs scripts/server-compatibility.test.mjs scripts/verify-core-api-contract.test.mjs && node scripts/verify-core-api-contract.mjs",
|
|
10
10
|
"verify:artifact": "node scripts/verify-release-artifact.mjs",
|
|
11
11
|
"verify:release": "npm test && npm run verify:artifact && node scripts/verify-tarball-clean.mjs",
|
|
12
12
|
"prepack": "node scripts/prepare-build-manifest.mjs",
|