@llamaventures/cli 1.26.0 → 2.0.1
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 +140 -346
- package/CHANGELOG.md +24 -0
- package/README.md +123 -212
- package/README.zh-CN.md +117 -204
- package/bin/llama-mcp.mjs +209 -1995
- package/bin/llama.mjs +363 -3508
- package/contracts/core-api.json +4 -4
- package/contracts/required-operations.json +27 -348
- package/lib/build-manifest.json +4 -4
- package/lib/client.mjs +12 -15
- package/lib/deal-actions.mjs +193 -0
- package/package.json +2 -2
- package/contracts/investment-workflow-v2.md +0 -19
- package/lib/workflow-audit.mjs +0 -13
- package/lib/workflow-remediation.mjs +0 -45
package/contracts/core-api.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "llama.core-api-contract.v1",
|
|
3
3
|
"name": "llama-core-api",
|
|
4
|
-
"apiVersion": "
|
|
4
|
+
"apiVersion": "5.0.0",
|
|
5
5
|
"openapiVersion": "3.0.3",
|
|
6
|
-
"sha256": "
|
|
7
|
-
"pathCount":
|
|
8
|
-
"operationCount":
|
|
6
|
+
"sha256": "c48ed580f9930b06445f62b94959a2ca4bf9780e59473f17588e1e6554914014",
|
|
7
|
+
"pathCount": 110,
|
|
8
|
+
"operationCount": 136
|
|
9
9
|
}
|
|
@@ -2,353 +2,32 @@
|
|
|
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
|
-
"method": "POST",
|
|
35
|
-
"path": "/api/agent/client-events"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"method": "GET",
|
|
39
|
-
"path": "/api/agent/explain"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"method": "GET",
|
|
43
|
-
"path": "/api/agent/manifest"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"method": "GET",
|
|
47
|
-
"path": "/api/agent/preferences"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"method": "POST",
|
|
51
|
-
"path": "/api/agent/preferences"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"method": "PATCH",
|
|
55
|
-
"path": "/api/agent/preferences/{id}"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"method": "GET",
|
|
59
|
-
"path": "/api/agent/skills"
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"method": "GET",
|
|
63
|
-
"path": "/api/agent/skills/{slug}"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"method": "GET",
|
|
67
|
-
"path": "/api/deals"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"method": "POST",
|
|
71
|
-
"path": "/api/deals/create"
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"method": "GET",
|
|
75
|
-
"path": "/api/deals/deleted"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
"method": "POST",
|
|
79
|
-
"path": "/api/deals/update"
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"method": "DELETE",
|
|
83
|
-
"path": "/api/deals/{dealId}"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
"method": "GET",
|
|
87
|
-
"path": "/api/deals/{dealId}"
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
"method": "POST",
|
|
91
|
-
"path": "/api/deals/{dealId}/agent-runs/{runId}/revert"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"method": "GET",
|
|
95
|
-
"path": "/api/deals/{dealId}/blocks"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"method": "PUT",
|
|
99
|
-
"path": "/api/deals/{dealId}/blocks"
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
"method": "DELETE",
|
|
103
|
-
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
"method": "GET",
|
|
107
|
-
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
"method": "PATCH",
|
|
111
|
-
"path": "/api/deals/{dealId}/blocks/{blockId}"
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
"method": "GET",
|
|
115
|
-
"path": "/api/deals/{dealId}/blocks/{blockId}/history"
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
"method": "POST",
|
|
119
|
-
"path": "/api/deals/{dealId}/blocks/{blockId}/history"
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
"method": "POST",
|
|
123
|
-
"path": "/api/deals/{dealId}/blocks/{blockId}/restore"
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"method": "GET",
|
|
127
|
-
"path": "/api/deals/{dealId}/collaborators"
|
|
128
|
-
},
|
|
129
|
-
{
|
|
130
|
-
"method": "POST",
|
|
131
|
-
"path": "/api/deals/{dealId}/collaborators"
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
"method": "DELETE",
|
|
135
|
-
"path": "/api/deals/{dealId}/collaborators/{userId}"
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
"method": "POST",
|
|
139
|
-
"path": "/api/deals/{dealId}/collaborators/{userId}/restore"
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
"method": "GET",
|
|
143
|
-
"path": "/api/deals/{dealId}/command-center"
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
"method": "GET",
|
|
147
|
-
"path": "/api/deals/{dealId}/documents"
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"method": "POST",
|
|
151
|
-
"path": "/api/deals/{dealId}/documents"
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"method": "DELETE",
|
|
155
|
-
"path": "/api/deals/{dealId}/documents/{slug}"
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"method": "PATCH",
|
|
159
|
-
"path": "/api/deals/{dealId}/documents/{slug}"
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
"method": "DELETE",
|
|
163
|
-
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"method": "GET",
|
|
167
|
-
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
"method": "PUT",
|
|
171
|
-
"path": "/api/deals/{dealId}/documents/{slug}/html"
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
"method": "GET",
|
|
175
|
-
"path": "/api/deals/{dealId}/documents/{slug}/html/history"
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
"method": "POST",
|
|
179
|
-
"path": "/api/deals/{dealId}/documents/{slug}/html/restore/{version}"
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
"method": "POST",
|
|
183
|
-
"path": "/api/deals/{dealId}/enrich"
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
"method": "GET",
|
|
187
|
-
"path": "/api/deals/{dealId}/facts"
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
"method": "POST",
|
|
191
|
-
"path": "/api/deals/{dealId}/facts"
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
"method": "PATCH",
|
|
195
|
-
"path": "/api/deals/{dealId}/facts/{factId}"
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
"method": "POST",
|
|
199
|
-
"path": "/api/deals/{dealId}/facts/{factId}/uncontest"
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
"method": "GET",
|
|
203
|
-
"path": "/api/deals/{dealId}/feed"
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
"method": "PUT",
|
|
207
|
-
"path": "/api/deals/{dealId}/founders"
|
|
208
|
-
},
|
|
209
|
-
{
|
|
210
|
-
"method": "POST",
|
|
211
|
-
"path": "/api/deals/{dealId}/ingest"
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
"method": "GET",
|
|
215
|
-
"path": "/api/deals/{dealId}/links"
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"method": "POST",
|
|
219
|
-
"path": "/api/deals/{dealId}/links"
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
"method": "DELETE",
|
|
223
|
-
"path": "/api/deals/{dealId}/links/{linkId}"
|
|
224
|
-
},
|
|
225
|
-
{
|
|
226
|
-
"method": "POST",
|
|
227
|
-
"path": "/api/deals/{dealId}/links/{linkId}/restore"
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
"method": "GET",
|
|
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": "GET",
|
|
263
|
-
"path": "/api/deals/{dealId}/workflow"
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
"method": "POST",
|
|
267
|
-
"path": "/api/deals/{dealId}/workflow"
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
"method": "POST",
|
|
271
|
-
"path": "/api/external/chat"
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
"method": "POST",
|
|
275
|
-
"path": "/api/external/start-session"
|
|
276
|
-
},
|
|
277
|
-
{
|
|
278
|
-
"method": "POST",
|
|
279
|
-
"path": "/api/external/upload"
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
"method": "GET",
|
|
283
|
-
"path": "/api/me"
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
"method": "GET",
|
|
287
|
-
"path": "/api/me/nominations"
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
"method": "GET",
|
|
291
|
-
"path": "/api/mentions"
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
"method": "GET",
|
|
295
|
-
"path": "/api/mentions/unread-count"
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
"method": "POST",
|
|
299
|
-
"path": "/api/mentions/{id}/resolve"
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
"method": "POST",
|
|
303
|
-
"path": "/api/nominations/{approvalId}"
|
|
304
|
-
},
|
|
305
|
-
{
|
|
306
|
-
"method": "GET",
|
|
307
|
-
"path": "/api/oauth/authorize"
|
|
308
|
-
},
|
|
309
|
-
{
|
|
310
|
-
"method": "POST",
|
|
311
|
-
"path": "/api/oauth/revoke"
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
"method": "POST",
|
|
315
|
-
"path": "/api/oauth/token"
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
"method": "GET",
|
|
319
|
-
"path": "/api/partner/approvals"
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
"method": "POST",
|
|
323
|
-
"path": "/api/partner/approvals"
|
|
324
|
-
},
|
|
325
|
-
{
|
|
326
|
-
"method": "GET",
|
|
327
|
-
"path": "/api/users"
|
|
328
|
-
},
|
|
329
|
-
{
|
|
330
|
-
"method": "POST",
|
|
331
|
-
"path": "/api/wiki/save"
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
"method": "GET",
|
|
335
|
-
"path": "/api/wiki/search"
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
"method": "DELETE",
|
|
339
|
-
"path": "/api/wiki/{slug}"
|
|
340
|
-
},
|
|
341
|
-
{
|
|
342
|
-
"method": "GET",
|
|
343
|
-
"path": "/api/wiki/{slug}"
|
|
344
|
-
},
|
|
345
|
-
{
|
|
346
|
-
"method": "POST",
|
|
347
|
-
"path": "/api/wiki/{slug}/file"
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
"method": "POST",
|
|
351
|
-
"path": "/api/wiki/{slug}/restore"
|
|
352
|
-
}
|
|
5
|
+
{ "method": "DELETE", "path": "/api/wiki/{slug}" },
|
|
6
|
+
{ "method": "GET", "path": "/api/admin/agent-events" },
|
|
7
|
+
{ "method": "GET", "path": "/api/admin/auth-events" },
|
|
8
|
+
{ "method": "GET", "path": "/api/admin/deal-events" },
|
|
9
|
+
{ "method": "GET", "path": "/api/agent/briefing" },
|
|
10
|
+
{ "method": "GET", "path": "/api/agent/explain" },
|
|
11
|
+
{ "method": "GET", "path": "/api/agent/manifest" },
|
|
12
|
+
{ "method": "GET", "path": "/api/agent/preferences" },
|
|
13
|
+
{ "method": "GET", "path": "/api/agent/skills" },
|
|
14
|
+
{ "method": "GET", "path": "/api/agent/skills/{slug}" },
|
|
15
|
+
{ "method": "GET", "path": "/api/me" },
|
|
16
|
+
{ "method": "GET", "path": "/api/oauth/authorize" },
|
|
17
|
+
{ "method": "GET", "path": "/api/occam/deals" },
|
|
18
|
+
{ "method": "GET", "path": "/api/occam/deals/{dealId}" },
|
|
19
|
+
{ "method": "GET", "path": "/api/wiki/{slug}" },
|
|
20
|
+
{ "method": "GET", "path": "/api/wiki/search" },
|
|
21
|
+
{ "method": "PATCH", "path": "/api/agent/preferences/{id}" },
|
|
22
|
+
{ "method": "POST", "path": "/api/agent/client-events" },
|
|
23
|
+
{ "method": "POST", "path": "/api/agent/preferences" },
|
|
24
|
+
{ "method": "POST", "path": "/api/external/chat" },
|
|
25
|
+
{ "method": "POST", "path": "/api/external/start-session" },
|
|
26
|
+
{ "method": "POST", "path": "/api/external/upload" },
|
|
27
|
+
{ "method": "POST", "path": "/api/oauth/revoke" },
|
|
28
|
+
{ "method": "POST", "path": "/api/oauth/token" },
|
|
29
|
+
{ "method": "POST", "path": "/api/occam/deals/commands" },
|
|
30
|
+
{ "method": "POST", "path": "/api/wiki/{slug}/restore" },
|
|
31
|
+
{ "method": "POST", "path": "/api/wiki/save" }
|
|
353
32
|
]
|
|
354
33
|
}
|
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": "
|
|
5
|
-
"sourceSha": "
|
|
4
|
+
"packageVersion": "2.0.1",
|
|
5
|
+
"sourceSha": "ac71158a0bd630d602012e5750be8c1babb93f2d",
|
|
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": "5.0.0",
|
|
12
12
|
"openapiVersion": "3.0.3",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "c48ed580f9930b06445f62b94959a2ca4bf9780e59473f17588e1e6554914014"
|
|
14
14
|
}
|
|
15
15
|
}
|
package/lib/client.mjs
CHANGED
|
@@ -59,11 +59,11 @@ export function getPackageVersion() {
|
|
|
59
59
|
return packageVersionCache;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
// Canonical entrypoint.
|
|
63
|
-
// but its NextAuth callback URL doesn't match, so browser
|
|
64
|
-
// to mint a token at /settings/tokens) fails there with a
|
|
65
|
-
// error. Always default to canonical — override with
|
|
66
|
-
// if testing.
|
|
62
|
+
// Canonical entrypoint. The hosting provider's assigned hostname also
|
|
63
|
+
// serves the API, but its NextAuth callback URL doesn't match, so browser
|
|
64
|
+
// login (needed to mint a token at /settings/tokens) fails there with a
|
|
65
|
+
// server-config error. Always default to canonical — override with
|
|
66
|
+
// $LLAMA_API_URL only if testing.
|
|
67
67
|
export const DEFAULT_BASE_URL = "https://command.llamaventures.vc";
|
|
68
68
|
|
|
69
69
|
// Canonical token location (single line, mode 0600). Aligns with the
|
|
@@ -212,6 +212,7 @@ function agentClientHeaders(command) {
|
|
|
212
212
|
return {
|
|
213
213
|
"X-Llama-Client": runtimeClient,
|
|
214
214
|
"X-Llama-Client-Version": getPackageVersion(),
|
|
215
|
+
"X-Llama-Client-Capabilities": "core.read.v1,occam.deal.v1",
|
|
215
216
|
"X-Llama-Client-Source-Sha": build.sourceSha,
|
|
216
217
|
"X-Llama-API-Contract-Version": build.coreApiContract.apiVersion,
|
|
217
218
|
"X-Llama-API-Contract-Digest": build.coreApiContract.sha256,
|
|
@@ -290,16 +291,9 @@ function inferCommand(method, endpoint) {
|
|
|
290
291
|
if (pathname === "/api/wiki/search") return "wiki.search";
|
|
291
292
|
if (pathname === "/api/wiki/save") return "wiki.save";
|
|
292
293
|
if (/^\/api\/wiki\/[^/]+$/.test(pathname)) return verb === "GET" ? "wiki.read" : "wiki.write";
|
|
293
|
-
if (pathname === "/api/deals") return
|
|
294
|
-
if (pathname === "/api/deals/
|
|
295
|
-
if (
|
|
296
|
-
if (/^\/api\/deals\/[^/]+\/ingest$/.test(pathname)) return "deal.ingest";
|
|
297
|
-
if (/^\/api\/deals\/[^/]+\/threads\/[^/]+$/.test(pathname)) return "deal.agent.run";
|
|
298
|
-
if (/^\/api\/deals\/[^/]+\/threads$/.test(pathname)) return "deal.thread.create";
|
|
299
|
-
if (/^\/api\/deals\/[^/]+\/facts/.test(pathname)) return verb === "GET" ? "deal.fact.list" : "deal.fact.write";
|
|
300
|
-
if (/^\/api\/deals\/[^/]+\/posts$/.test(pathname)) return "deal.post";
|
|
301
|
-
if (/^\/api\/deals\/[^/]+\/blocks/.test(pathname)) return verb === "GET" ? "brief.blocks" : "brief.write";
|
|
302
|
-
if (/^\/api\/deals\/[^/]+$/.test(pathname)) return verb === "GET" ? "deal.show" : "deal.write";
|
|
294
|
+
if (pathname === "/api/occam/deals") return "deal.search";
|
|
295
|
+
if (pathname === "/api/occam/deals/commands") return "deal.write";
|
|
296
|
+
if (/^\/api\/occam\/deals\/[^/]+$/.test(pathname)) return "deal.read";
|
|
303
297
|
if (pathname === "/api/me") return "auth.status";
|
|
304
298
|
if (pathname.startsWith("/api/agent/skills")) return "skills.read";
|
|
305
299
|
if (pathname === "/api/agent/manifest") return "agent.bootstrap";
|
|
@@ -536,12 +530,14 @@ function apiResponseError(data, status) {
|
|
|
536
530
|
);
|
|
537
531
|
error.code = data.code;
|
|
538
532
|
error.details = data;
|
|
533
|
+
error.status = status;
|
|
539
534
|
return error;
|
|
540
535
|
}
|
|
541
536
|
if (data?.code !== "MENTION_APPROVAL_REQUIRED") {
|
|
542
537
|
const error = new Error(message);
|
|
543
538
|
if (typeof data?.code === "string") error.code = data.code;
|
|
544
539
|
error.details = data;
|
|
540
|
+
error.status = status;
|
|
545
541
|
return error;
|
|
546
542
|
}
|
|
547
543
|
const recipients = Array.isArray(data?.cue?.recipients)
|
|
@@ -563,6 +559,7 @@ function apiResponseError(data, status) {
|
|
|
563
559
|
);
|
|
564
560
|
error.code = data.code;
|
|
565
561
|
error.details = data;
|
|
562
|
+
error.status = status;
|
|
566
563
|
return error;
|
|
567
564
|
}
|
|
568
565
|
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
export const DEAL_ACTIONS = Object.freeze(["search", "read", "create", "write"]);
|
|
5
|
+
export const DEAL_WRITE_OPERATIONS = Object.freeze([
|
|
6
|
+
"input.submit",
|
|
7
|
+
"information.put",
|
|
8
|
+
"page.patch",
|
|
9
|
+
"artifact.put",
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
function canonicalJson(value) {
|
|
13
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
14
|
+
if (value && typeof value === "object") {
|
|
15
|
+
return `{${Object.keys(value)
|
|
16
|
+
.sort()
|
|
17
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
|
|
18
|
+
.join(",")}}`;
|
|
19
|
+
}
|
|
20
|
+
return JSON.stringify(value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function ensureIdempotencyKey(command) {
|
|
24
|
+
if (typeof command?.idempotencyKey === "string" && command.idempotencyKey.trim()) {
|
|
25
|
+
return command;
|
|
26
|
+
}
|
|
27
|
+
const digest = createHash("sha256").update(canonicalJson(command)).digest("hex").slice(0, 40);
|
|
28
|
+
return { ...command, idempotencyKey: `cli:${digest}` };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function validateCommandOrigin(command) {
|
|
32
|
+
const origin = command?.origin;
|
|
33
|
+
if (!origin || !["user", "agent", "system"].includes(origin.kind)) {
|
|
34
|
+
throw new Error("Mutation JSON must include origin.kind: user, agent, or system");
|
|
35
|
+
}
|
|
36
|
+
if (
|
|
37
|
+
origin.kind === "user" &&
|
|
38
|
+
!(typeof origin.originalUserUtterance === "string" && origin.originalUserUtterance.trim()) &&
|
|
39
|
+
!(typeof origin.originatingChatRecordId === "string" && origin.originatingChatRecordId.trim())
|
|
40
|
+
) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"User-originated mutation JSON must preserve origin.originalUserUtterance or origin.originatingChatRecordId",
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return command;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function validateLocalizedTextPairs(value, path = "page") {
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
value.forEach((item, index) => validateLocalizedTextPairs(item, `${path}[${index}]`));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (!value || typeof value !== "object") return;
|
|
54
|
+
const hasEnglish = Object.prototype.hasOwnProperty.call(value, "en");
|
|
55
|
+
const hasChinese = Object.prototype.hasOwnProperty.call(value, "zh");
|
|
56
|
+
if (hasEnglish || hasChinese) {
|
|
57
|
+
if (
|
|
58
|
+
Object.keys(value).some((key) => key !== "en" && key !== "zh") ||
|
|
59
|
+
typeof value.en !== "string" ||
|
|
60
|
+
!value.en.trim() ||
|
|
61
|
+
typeof value.zh !== "string" ||
|
|
62
|
+
!value.zh.trim()
|
|
63
|
+
) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`${path} localized text must contain only non-empty en and zh values`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const [key, child] of Object.entries(value)) {
|
|
71
|
+
validateLocalizedTextPairs(child, `${path}.${key}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const LANGUAGE_NEUTRAL_PAGE_KEYS = new Set([
|
|
76
|
+
"companyName", "companyKey", "state", "pipelineStatus", "stage",
|
|
77
|
+
"theirStage", "ownerUserId", "sourceUserId", "website", "dealOwner",
|
|
78
|
+
"source", "sourceDirection", "proposedAmount", "roundSize", "valuation",
|
|
79
|
+
"founders", "deckLink", "location", "foundedYear", "leadInvestor",
|
|
80
|
+
"dateAdded", "tab", "sourcePerson", "createdByName", "createdByLabel",
|
|
81
|
+
"createdVia", "id", "name", "key", "slug", "url", "href", "email",
|
|
82
|
+
"linkedin", "handle", "status", "kind", "type", "tier", "confidence",
|
|
83
|
+
"currency", "unit", "format", "mimeType", "sha256", "timestamp",
|
|
84
|
+
"date", "year",
|
|
85
|
+
]);
|
|
86
|
+
const LANGUAGE_NEUTRAL_PAGE_CONTAINERS = new Set([
|
|
87
|
+
"manualTags", "investors", "founderEmails", "labels", "tags",
|
|
88
|
+
]);
|
|
89
|
+
const OPAQUE_PAGE_CONTAINERS = new Set([
|
|
90
|
+
"migration", "extra", "fieldProvenance",
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
function pathKeys(path) {
|
|
94
|
+
return path.match(/[^.[\]]+/g)?.filter((part) => !/^\d+$/u.test(part)) ?? [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isLanguageNeutralPagePath(path) {
|
|
98
|
+
const keys = pathKeys(path);
|
|
99
|
+
if (keys.some((key) => OPAQUE_PAGE_CONTAINERS.has(key))) return true;
|
|
100
|
+
if (keys.some((key) => LANGUAGE_NEUTRAL_PAGE_CONTAINERS.has(key))) return true;
|
|
101
|
+
const key = keys.at(-1) ?? "";
|
|
102
|
+
if (LANGUAGE_NEUTRAL_PAGE_KEYS.has(key)) return true;
|
|
103
|
+
return /(?:Id|Ids|URL|Url|URI|Uri|Link|Email|Emails|At|Date|Year|Key|Slug|Hash)$/u.test(key);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function validateAgentAuthoredPageProse(value, path = "page") {
|
|
107
|
+
if (typeof value === "string") {
|
|
108
|
+
if (!isLanguageNeutralPagePath(path)) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`${path} agent-authored prose must be one value with non-empty en and zh`,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (Array.isArray(value)) {
|
|
116
|
+
value.forEach((item, index) => validateAgentAuthoredPageProse(item, `${path}[${index}]`));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!value || typeof value !== "object") return;
|
|
120
|
+
if (
|
|
121
|
+
Object.prototype.hasOwnProperty.call(value, "en") ||
|
|
122
|
+
Object.prototype.hasOwnProperty.call(value, "zh")
|
|
123
|
+
) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
for (const [key, child] of Object.entries(value)) {
|
|
127
|
+
validateAgentAuthoredPageProse(child, `${path}.${key}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export async function readJsonInput(path, stdin = process.stdin) {
|
|
132
|
+
if (!path || path === true) throw new Error("--json <file|-> is required");
|
|
133
|
+
const text = path === "-"
|
|
134
|
+
? await new Promise((resolve, reject) => {
|
|
135
|
+
let value = "";
|
|
136
|
+
stdin.setEncoding("utf8");
|
|
137
|
+
stdin.on("data", (chunk) => { value += chunk; });
|
|
138
|
+
stdin.on("end", () => resolve(value));
|
|
139
|
+
stdin.on("error", reject);
|
|
140
|
+
})
|
|
141
|
+
: await readFile(path, "utf8");
|
|
142
|
+
try {
|
|
143
|
+
return JSON.parse(text);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw new Error(`Invalid JSON from ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function buildDealSearchPath(query, flags = {}) {
|
|
150
|
+
const params = new URLSearchParams();
|
|
151
|
+
if (query) params.set("q", query);
|
|
152
|
+
if (flags.state && flags.state !== true) params.set("state", String(flags.state));
|
|
153
|
+
if (flags.limit && flags.limit !== true) params.set("limit", String(flags.limit));
|
|
154
|
+
return `/api/occam/deals${params.size ? `?${params}` : ""}`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function buildDealReadPath(dealId, detail = "overview") {
|
|
158
|
+
if (!dealId || dealId.startsWith("--")) {
|
|
159
|
+
throw new Error("Usage: llama deal read <dealId> [--detail overview|memory|files|conversation|history|all]");
|
|
160
|
+
}
|
|
161
|
+
const expansion = {
|
|
162
|
+
overview: "",
|
|
163
|
+
memory: "information",
|
|
164
|
+
files: "artifacts",
|
|
165
|
+
conversation: "chat",
|
|
166
|
+
history: "feed",
|
|
167
|
+
all: "information,artifacts,chat,feed",
|
|
168
|
+
}[detail];
|
|
169
|
+
if (expansion === undefined) throw new Error(`Unknown detail: ${detail}`);
|
|
170
|
+
return `/api/occam/deals/${encodeURIComponent(dealId)}${expansion ? `?expand=${expansion}` : ""}`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function prepareDealCommand(action, input) {
|
|
174
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
175
|
+
throw new Error("Mutation JSON must be an object");
|
|
176
|
+
}
|
|
177
|
+
const command = action === "create" ? { operation: "deal.create", ...input } : input;
|
|
178
|
+
if (action === "create" && command.operation !== "deal.create") {
|
|
179
|
+
throw new Error("create JSON must describe one deal.create intent");
|
|
180
|
+
}
|
|
181
|
+
if (action === "write" && !DEAL_WRITE_OPERATIONS.includes(command.operation)) {
|
|
182
|
+
throw new Error(`write JSON operation must be ${DEAL_WRITE_OPERATIONS.join(", ")}`);
|
|
183
|
+
}
|
|
184
|
+
if (action === "create") {
|
|
185
|
+
validateLocalizedTextPairs(command.page ?? {});
|
|
186
|
+
validateAgentAuthoredPageProse(command.page ?? {});
|
|
187
|
+
}
|
|
188
|
+
if (action === "write" && command.operation === "page.patch") {
|
|
189
|
+
validateLocalizedTextPairs(command.patch ?? {});
|
|
190
|
+
validateAgentAuthoredPageProse(command.patch ?? {});
|
|
191
|
+
}
|
|
192
|
+
return ensureIdempotencyKey(validateCommandOrigin(command));
|
|
193
|
+
}
|