@llamaventures/cli 2.2.0 → 2.4.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 +5 -3
- package/CHANGELOG.md +16 -0
- package/README.md +14 -0
- package/README.zh-CN.md +11 -0
- package/bin/llama-mcp.mjs +27 -8
- package/bin/llama.mjs +28 -7
- package/contracts/core-api.json +2 -2
- package/contracts/required-operations.json +1 -0
- package/lib/build-manifest.json +4 -4
- package/lib/client.mjs +1 -0
- package/lib/content-read.mjs +49 -0
- package/lib/deal-actions.mjs +10 -2
- package/package.json +2 -2
package/AGENT_BRIEFING.md
CHANGED
|
@@ -168,9 +168,11 @@ means the truth depends on who judges: a value or comparative word with no
|
|
|
168
168
|
stated benchmark, or a claim about someone's future behavior or inner state. If
|
|
169
169
|
yes, the type is `human_subjective_view.people` (founders or team) or
|
|
170
170
|
`human_subjective_view.business` (company, product, market or deal),
|
|
171
|
-
`value.speaker` names that user,
|
|
172
|
-
from `origin.originalUserUtterance
|
|
173
|
-
|
|
171
|
+
`value.speaker` names that user, `value.rawText` quotes the user verbatim
|
|
172
|
+
from `origin.originalUserUtterance`, and `value.summary` is your own
|
|
173
|
+
restatement of those words (never a substitute for them). CLI and Core reject
|
|
174
|
+
anything else. If no, choose any type that fits; founder words are
|
|
175
|
+
`founder_claim`.
|
|
174
176
|
|
|
175
177
|
```json
|
|
176
178
|
{
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ this project adheres to [Semantic Versioning](https://semver.org).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.4.0] - 2026-09-09
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Read Deal artifact text and original bytes through Core with version/hash provenance.
|
|
14
|
+
- Read Wiki uploads and supported page references; paginate text with a pinned source hash.
|
|
15
|
+
- Verify source downloads and refuse to overwrite local files.
|
|
16
|
+
|
|
17
|
+
## [2.3.0] - 2026-09-04
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `human_subjective_view.people|business` now also requires `value.summary`,
|
|
21
|
+
the agent's own restatement of the user's words, and rejects a summary that
|
|
22
|
+
merely repeats `value.rawText`. Core enforces the same rule; the Deal Page
|
|
23
|
+
shows both the summary and the verbatim text.
|
|
24
|
+
|
|
9
25
|
## [2.2.0] - 2026-09-04
|
|
10
26
|
|
|
11
27
|
### Added
|
package/README.md
CHANGED
|
@@ -214,3 +214,17 @@ npm run verify:release
|
|
|
214
214
|
|
|
215
215
|
Release artifacts are source-SHA certified. Publishing to npm and changing the
|
|
216
216
|
production server's minimum version are separate, explicit release operations.
|
|
217
|
+
|
|
218
|
+
### Read original source content
|
|
219
|
+
|
|
220
|
+
Use `llama deal read <dealId> --artifact <artifactId>` to read a listed file's text,
|
|
221
|
+
source hash and page/paragraph anchors. Use `llama wiki read <slug> --format text`
|
|
222
|
+
for a Wiki page or its original uploaded document. `--attachment <referenceId>`
|
|
223
|
+
follows a supported reference listed by the Wiki read. Long reads return
|
|
224
|
+
`nextOffset`; continue with `--offset N --sha256 HASH`. `--output <file>` downloads
|
|
225
|
+
and hash-verifies the original bytes without overwriting a local file.
|
|
226
|
+
|
|
227
|
+
These options require a Core version with source-content reads. Scanned PDFs
|
|
228
|
+
may require OCR; no-text, missing files, unsupported formats and denied storage
|
|
229
|
+
are explicit outcomes, not evidence that a memo has been read. MCP exposes the
|
|
230
|
+
same text reads inside `read_deal` and `wiki_read`.
|
package/README.zh-CN.md
CHANGED
|
@@ -204,3 +204,14 @@ npm run verify:release
|
|
|
204
204
|
|
|
205
205
|
发布包会绑定准确 source SHA。npm publish 与生产服务端强制最低版本是两个
|
|
206
206
|
独立、需要明确授权的 release 动作。
|
|
207
|
+
|
|
208
|
+
### 读取原始材料
|
|
209
|
+
|
|
210
|
+
`llama deal read <dealId> --artifact <artifactId>` 读取文件正文、原文件哈希与页码/段落位置。
|
|
211
|
+
`llama wiki read <slug> --format text` 读取 Wiki 正文或上传的原文件;
|
|
212
|
+
`--attachment <referenceId>` 读取页面返回的受支持附件引用。
|
|
213
|
+
长文用 `--offset <nextOffset> --sha256 <source.sha256>` 继续,文件变化时会拒绝拼接。
|
|
214
|
+
`--output <文件路径>` 下载并核验原始字节,不覆盖已有文件。
|
|
215
|
+
|
|
216
|
+
需要服务端支持正文读取。扫描 PDF 不自动 OCR;无文字、缺失文件、不支持的格式、
|
|
217
|
+
权限不足都会明确报告。MCP 在原有 `read_deal` 和 `wiki_read` 中提供相同正文读取能力。
|
package/bin/llama-mcp.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { buildArtifactReadPath, buildWikiReadPath } from "../lib/content-read.mjs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -123,14 +124,27 @@ server.registerTool(
|
|
|
123
124
|
server.registerTool(
|
|
124
125
|
"read_deal",
|
|
125
126
|
{
|
|
126
|
-
description: "Read one Deal. Live Page is current human-visible state; Information is memory and never updates Page automatically. Page field semantics come from agent_bootstrap, not every Deal read.",
|
|
127
|
+
description: "Read one Deal. Live Page is current human-visible state; Information is memory and never updates Page automatically. Use artifactId to read original source text with page/paragraph anchors. Continue with nextOffset and source.sha256. Page field semantics come from agent_bootstrap, not every Deal read.",
|
|
127
128
|
inputSchema: {
|
|
128
129
|
dealId: z.string().min(1),
|
|
129
130
|
detail: z.enum(["overview", "memory", "files", "conversation", "history", "all"]).optional(),
|
|
131
|
+
artifactId: z.string().uuid().optional(),
|
|
132
|
+
version: z.number().int().min(1).optional(),
|
|
133
|
+
offset: z.number().int().min(0).optional(),
|
|
134
|
+
limit: z.number().int().min(1).max(50000).optional(),
|
|
135
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
130
136
|
},
|
|
131
137
|
},
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
async ({ dealId, detail, artifactId, ...options }) => {
|
|
139
|
+
if (artifactId) {
|
|
140
|
+
if (detail) throw new Error("Use artifactId or detail, not both");
|
|
141
|
+
// @core-api-operation GET /api/occam/deals/{dealId}/artifacts/{artifactId}
|
|
142
|
+
return callApi("GET", buildArtifactReadPath(dealId, artifactId, options));
|
|
143
|
+
}
|
|
144
|
+
if (Object.values(options).some(value => value !== undefined)) throw new Error("Content options require artifactId");
|
|
145
|
+
// @core-api-operation GET /api/occam/deals/{dealId}
|
|
146
|
+
return callApi("GET", buildDealReadPath(dealId, detail || "overview"));
|
|
147
|
+
},
|
|
134
148
|
);
|
|
135
149
|
|
|
136
150
|
server.registerTool(
|
|
@@ -152,7 +166,7 @@ server.registerTool(
|
|
|
152
166
|
server.registerTool(
|
|
153
167
|
"write_deal",
|
|
154
168
|
{
|
|
155
|
-
description: "The only Deal mutation tool. Pass one command: input.submit, information.put, page.patch, or artifact.put. All Page content fields are Agent-writable; author controls attribution, not permission. Before page.patch, use get_live_deal_page_schema for the exact fields being changed and write bilingual Page prose. page.patch is JSON Merge Patch: arrays replace whole arrays, so read-modify-write and preserve sibling slots. A Llama user's own judgment is human_subjective_view.people or human_subjective_view.business and must carry value.speaker
|
|
169
|
+
description: "The only Deal mutation tool. Pass one command: input.submit, information.put, page.patch, or artifact.put. All Page content fields are Agent-writable; author controls attribution, not permission. Before page.patch, use get_live_deal_page_schema for the exact fields being changed and write bilingual Page prose. page.patch is JSON Merge Patch: arrays replace whole arrays, so read-modify-write and preserve sibling slots. A Llama user's own judgment is human_subjective_view.people or human_subjective_view.business and must carry value.speaker, value.rawText quoted verbatim from origin.originalUserUtterance, and value.summary (the agent's restatement); it is rejected otherwise.",
|
|
156
170
|
// MCP SDK 1.30 only publishes object schemas at the tool root. Nesting one
|
|
157
171
|
// command preserves the real discriminated union instead of flattening four
|
|
158
172
|
// incompatible operations into false affordances.
|
|
@@ -344,11 +358,16 @@ server.registerTool(
|
|
|
344
358
|
server.registerTool(
|
|
345
359
|
"wiki_read",
|
|
346
360
|
{
|
|
347
|
-
description: "Read one Wiki article
|
|
348
|
-
inputSchema: {
|
|
361
|
+
description: "Read one Wiki article. format=text extracts its original upload or page body. attachment follows an ID listed in attachments. Continuations require offset and sha256.",
|
|
362
|
+
inputSchema: {
|
|
363
|
+
slug: z.string().min(1), lang: z.enum(["en", "zh"]).optional(),
|
|
364
|
+
format: z.literal("text").optional(), attachment: z.string().optional(),
|
|
365
|
+
offset: z.number().int().min(0).optional(), limit: z.number().int().min(1).max(50000).optional(),
|
|
366
|
+
sha256: z.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
367
|
+
},
|
|
349
368
|
},
|
|
350
|
-
|
|
351
|
-
|
|
369
|
+
// @core-api-operation GET /api/wiki/{slug}
|
|
370
|
+
async ({ slug, ...options }) => callApi("GET", buildWikiReadPath(slug, options)),
|
|
352
371
|
);
|
|
353
372
|
|
|
354
373
|
server.registerTool(
|
package/bin/llama.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { buildArtifactReadPath, buildWikiReadPath, saveContentSource } from "../lib/content-read.mjs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import { readFile } from "node:fs/promises";
|
|
5
6
|
import readline from "node:readline";
|
|
@@ -70,6 +71,8 @@ Separate preserved domains:
|
|
|
70
71
|
llama skills list|search|show
|
|
71
72
|
llama pref list|add|approve|retire
|
|
72
73
|
llama explain <url-or-object>
|
|
74
|
+
llama deal read <dealId> --artifact <artifactId> [--version N] [--offset N --sha256 HASH] [--limit N] [--output <file>]
|
|
75
|
+
llama wiki read <slug> --format text [--attachment <referenceId>] [--offset N --sha256 HASH] [--output <file>]
|
|
73
76
|
llama wiki search|read|save|delete|restore
|
|
74
77
|
llama admin auth-events|deal-events|agent-events
|
|
75
78
|
llama pitch start|say|upload|status|finalize|end
|
|
@@ -84,6 +87,15 @@ Exactly four actions:
|
|
|
84
87
|
llama deal create --json <file|->
|
|
85
88
|
llama deal write --json <file|->
|
|
86
89
|
|
|
90
|
+
Read original source content:
|
|
91
|
+
llama deal read <dealId> --artifact <artifactId> [--version N] [--offset N --sha256 HASH] [--limit N] [--output <file>]
|
|
92
|
+
llama wiki read <slug> --format text [--attachment <referenceId>] [--offset N --sha256 HASH] [--output <file>]
|
|
93
|
+
|
|
94
|
+
Artifact reads return source hashes, text and page/paragraph anchors. Continue with
|
|
95
|
+
--offset <nextOffset> --sha256 <source.sha256>. --output saves verified original
|
|
96
|
+
bytes without overwriting existing files. Wiki --format text reads the original
|
|
97
|
+
upload when present; --attachment follows a reference listed by the page.
|
|
98
|
+
|
|
87
99
|
Before any Page write:
|
|
88
100
|
llama agent bootstrap
|
|
89
101
|
llama page-schema read <field> [field...]
|
|
@@ -103,7 +115,7 @@ create JSON:
|
|
|
103
115
|
write JSON (CLI derives idempotencyKey when omitted):
|
|
104
116
|
input.submit: {"operation":"input.submit","dealId":"<uuid>","content":"<original input>","format":"text","source":{},"origin":{"kind":"user","originalUserUtterance":"..."}}
|
|
105
117
|
information.put:{"operation":"information.put","dealId":"<uuid>","type":"founder_claim","labels":["founder-stated"],"subject":{"topic":"traction"},"value":{"content":"...","source":{"kind":"first_meeting_transcript"}},"origin":{"kind":"user","originalUserUtterance":"..."}}
|
|
106
|
-
human judgment: {"operation":"information.put","dealId":"<uuid>","type":"human_subjective_view.people","subject":{"topic":"founder_execution"},"value":{"speaker":"<Llama user>","rawText":"<the user's verbatim words>","summary":"<
|
|
118
|
+
human judgment: {"operation":"information.put","dealId":"<uuid>","type":"human_subjective_view.people","subject":{"topic":"founder_execution"},"value":{"speaker":"<Llama user>","rawText":"<the user's verbatim words>","summary":"<the agent's restatement>"},"origin":{"kind":"user","originalUserUtterance":"<complete user input; must contain rawText>"}}
|
|
107
119
|
page.patch: {"operation":"page.patch","dealId":"<uuid>","patch":{"description":{"en":"...","zh":"..."}},"origin":{"kind":"agent"}}
|
|
108
120
|
artifact.put: {"operation":"artifact.put","dealId":"<uuid>","kind":"deck","title":"deck.pdf","mimeType":"application/pdf","contentBase64":"<file bytes, base64>","origin":{"kind":"user","originalUserUtterance":"..."}}
|
|
109
121
|
|
|
@@ -119,8 +131,9 @@ value.source records where the evidence came from.
|
|
|
119
131
|
human_subjective_view.people|business is a Llama user's own judgment about the
|
|
120
132
|
team or the deal. Subjective = the truth depends on who judges: a value or
|
|
121
133
|
comparative word with no benchmark, or a claim about someone's future behavior
|
|
122
|
-
or inner state. It requires value.speaker
|
|
123
|
-
origin.originalUserUtterance
|
|
134
|
+
or inner state. It requires value.speaker, value.rawText quoted verbatim from
|
|
135
|
+
origin.originalUserUtterance, and value.summary, the agent's own restatement of
|
|
136
|
+
those words; CLI and Core reject anything else. Other types are free.
|
|
124
137
|
|
|
125
138
|
Core owns Chat Records, append-only Deal Events, Drive provisioning, audit,
|
|
126
139
|
and idempotency. User-originated work must preserve exact wording in
|
|
@@ -460,7 +473,7 @@ async function handleWiki(action, rest) {
|
|
|
460
473
|
if (action === "read") {
|
|
461
474
|
if (!slug) throw new Error("Usage: llama wiki read <slug> [--lang en|zh]");
|
|
462
475
|
// @core-api-operation GET /api/wiki/{slug}
|
|
463
|
-
print(await request("GET",
|
|
476
|
+
print(await saveContentSource(await request("GET", buildWikiReadPath(slug, flags)), flags.output));
|
|
464
477
|
return;
|
|
465
478
|
}
|
|
466
479
|
if (action === "save") {
|
|
@@ -656,9 +669,17 @@ async function main() {
|
|
|
656
669
|
}
|
|
657
670
|
if (area === "deal" && action === "read") {
|
|
658
671
|
const dealId = rest[0];
|
|
659
|
-
const { flags } = parseFlags(rest.slice(1), ["detail"]);
|
|
660
|
-
|
|
661
|
-
|
|
672
|
+
const { flags } = parseFlags(rest.slice(1), ["detail", "artifact", "version", "format", "offset", "limit", "sha256", "output"]);
|
|
673
|
+
if (flags.artifact !== undefined) {
|
|
674
|
+
if (flags.detail !== undefined) throw new Error("Use --artifact or --detail, not both");
|
|
675
|
+
// @core-api-operation GET /api/occam/deals/{dealId}/artifacts/{artifactId}
|
|
676
|
+
const result = await request("GET", buildArtifactReadPath(dealId, flags.artifact, flags));
|
|
677
|
+
print(await saveContentSource(result, flags.output));
|
|
678
|
+
} else {
|
|
679
|
+
if (["version", "format", "offset", "limit", "sha256", "output"].some(key => flags[key] !== undefined)) throw new Error("Content options require --artifact");
|
|
680
|
+
// @core-api-operation GET /api/occam/deals/{dealId}
|
|
681
|
+
print(await request("GET", buildDealReadPath(dealId, flags.detail === true ? "overview" : flags.detail || "overview")));
|
|
682
|
+
}
|
|
662
683
|
return;
|
|
663
684
|
}
|
|
664
685
|
if (area === "deal" && ["create", "write"].includes(action)) {
|
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": "5.
|
|
4
|
+
"apiVersion": "5.8.0",
|
|
5
5
|
"openapiVersion": "3.0.3",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "ec68e92362c9f60eee94b81d73fb7cff2868c80d7c17c24a9e3122cc2743e7ad",
|
|
7
7
|
"pathCount": 113,
|
|
8
8
|
"operationCount": 140
|
|
9
9
|
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
{ "method": "GET", "path": "/api/oauth/authorize" },
|
|
19
19
|
{ "method": "GET", "path": "/api/occam/deals" },
|
|
20
20
|
{ "method": "GET", "path": "/api/occam/deals/{dealId}" },
|
|
21
|
+
{ "method": "GET", "path": "/api/occam/deals/{dealId}/artifacts/{artifactId}" },
|
|
21
22
|
{ "method": "GET", "path": "/api/wiki/{slug}" },
|
|
22
23
|
{ "method": "GET", "path": "/api/wiki/search" },
|
|
23
24
|
{ "method": "PATCH", "path": "/api/agent/preferences/{id}" },
|
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": "2.
|
|
5
|
-
"sourceSha": "
|
|
4
|
+
"packageVersion": "2.4.0",
|
|
5
|
+
"sourceSha": "5f2e08c216a111bc568e7dee925aa198674c6255",
|
|
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": "5.
|
|
11
|
+
"apiVersion": "5.8.0",
|
|
12
12
|
"openapiVersion": "3.0.3",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "ec68e92362c9f60eee94b81d73fb7cff2868c80d7c17c24a9e3122cc2743e7ad"
|
|
14
14
|
}
|
|
15
15
|
}
|
package/lib/client.mjs
CHANGED
|
@@ -291,6 +291,7 @@ function inferCommand(method, endpoint) {
|
|
|
291
291
|
if (pathname === "/api/wiki/search") return "wiki.search";
|
|
292
292
|
if (pathname === "/api/wiki/save") return "wiki.save";
|
|
293
293
|
if (/^\/api\/wiki\/[^/]+$/.test(pathname)) return verb === "GET" ? "wiki.read" : "wiki.write";
|
|
294
|
+
if (/^\/api\/occam\/deals\/[^/]+\/artifacts\/[^/]+$/.test(pathname)) return "deal.read";
|
|
294
295
|
if (pathname === "/api/occam/deals") return "deal.search";
|
|
295
296
|
if (pathname === "/api/occam/deals/commands") return "deal.write";
|
|
296
297
|
if (/^\/api\/occam\/deals\/[^/]+$/.test(pathname)) return "deal.read";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
function parameters(options) {
|
|
5
|
+
const params = new URLSearchParams();
|
|
6
|
+
const format = options.output ? "source" : options.format || "text";
|
|
7
|
+
if (!["text", "source"].includes(format)) throw new Error("--format must be text or source");
|
|
8
|
+
params.set("format", format);
|
|
9
|
+
for (const [key, min, max] of [["version", 1, Number.MAX_SAFE_INTEGER], ["offset", 0, 2000000], ["limit", 1, 50000]]) {
|
|
10
|
+
if (options[key] === undefined) continue;
|
|
11
|
+
if (!/^\d+$/.test(String(options[key])) || !Number.isSafeInteger(Number(options[key])) || Number(options[key]) < min || Number(options[key]) > max) throw new Error(`Invalid --${key}`);
|
|
12
|
+
params.set(key, String(options[key]));
|
|
13
|
+
}
|
|
14
|
+
if (options.sha256 !== undefined) {
|
|
15
|
+
if (!/^[a-f0-9]{64}$/.test(options.sha256)) throw new Error("Invalid --sha256");
|
|
16
|
+
params.set("sha256", options.sha256);
|
|
17
|
+
}
|
|
18
|
+
if (Number(options.offset) > 0 && !options.sha256) throw new Error("Continuation reads require --sha256 from the first response");
|
|
19
|
+
if (options.output !== undefined && (typeof options.output !== "string" || !options.output)) throw new Error("--output requires a file path");
|
|
20
|
+
return params;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function buildArtifactReadPath(dealId, artifactId, options = {}) {
|
|
24
|
+
if (typeof dealId !== "string" || !dealId || typeof artifactId !== "string" || !artifactId) throw new Error("Usage: llama deal read <dealId> --artifact <artifactId>");
|
|
25
|
+
return `/api/occam/deals/${encodeURIComponent(dealId)}/artifacts/${encodeURIComponent(artifactId)}?${parameters(options)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function buildWikiReadPath(slug, options = {}) {
|
|
29
|
+
if (typeof slug !== "string" || !slug) throw new Error("Usage: llama wiki read <slug>");
|
|
30
|
+
const params = options.format || options.output || options.attachment ? parameters(options) : new URLSearchParams();
|
|
31
|
+
params.set("lang", options.lang === "zh" ? "zh" : "en");
|
|
32
|
+
if (options.attachment !== undefined) {
|
|
33
|
+
if (typeof options.attachment !== "string" || !options.attachment) throw new Error("--attachment requires a reference ID from the wiki read");
|
|
34
|
+
params.set("attachment", options.attachment);
|
|
35
|
+
}
|
|
36
|
+
if (options.version !== undefined) throw new Error("Wiki reads pin --sha256, not --version");
|
|
37
|
+
if (!options.format && !options.output && !options.attachment && [options.offset, options.limit, options.sha256].some(x => x !== undefined)) throw new Error("Use --format text with pagination options");
|
|
38
|
+
return `/api/wiki/${encodeURIComponent(slug)}?${params}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function saveContentSource(result, output) {
|
|
42
|
+
if (!output) return result;
|
|
43
|
+
if (result?.format !== "source" || typeof result.contentBase64 !== "string") throw new Error("Server did not return original file bytes");
|
|
44
|
+
const bytes = Buffer.from(result.contentBase64, "base64");
|
|
45
|
+
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
46
|
+
if (sha256 !== result.source?.sha256 || bytes.length !== result.source?.byteSize) throw new Error("Downloaded file hash or size does not match the source");
|
|
47
|
+
await writeFile(output, bytes, { flag: "wx", mode: 0o600 });
|
|
48
|
+
return { saved: output, source: result.source, verified: true };
|
|
49
|
+
}
|
package/lib/deal-actions.mjs
CHANGED
|
@@ -12,8 +12,9 @@ export const DEAL_WRITE_OPERATIONS = Object.freeze([
|
|
|
12
12
|
/**
|
|
13
13
|
* A Llama user's own subjective judgment about the team (.people) or the deal
|
|
14
14
|
* (.business). An agent may record it, but the record must name the user and
|
|
15
|
-
* quote them verbatim from their own input,
|
|
16
|
-
*
|
|
15
|
+
* quote them verbatim from their own input, plus the agent's own restatement in
|
|
16
|
+
* value.summary, so the type alone stays a reliable filter and every record
|
|
17
|
+
* reads the same way. Core enforces the same rule; this check only fails faster.
|
|
17
18
|
*/
|
|
18
19
|
export const HUMAN_SUBJECTIVE_VIEW_TYPES = Object.freeze([
|
|
19
20
|
"human_subjective_view.people",
|
|
@@ -72,6 +73,13 @@ export function validateHumanSubjectiveView(information, origin) {
|
|
|
72
73
|
"human_subjective_view.* value.rawText must appear verbatim inside origin.originalUserUtterance; do not paraphrase",
|
|
73
74
|
);
|
|
74
75
|
}
|
|
76
|
+
const summary = stringField(information.value, "summary");
|
|
77
|
+
if (!summary) {
|
|
78
|
+
throw new Error("human_subjective_view.* requires value.summary: the agent's restatement of the user's words");
|
|
79
|
+
}
|
|
80
|
+
if (normalizeWhitespace(summary) === normalizeWhitespace(rawText)) {
|
|
81
|
+
throw new Error("human_subjective_view.* value.summary must restate value.rawText, not repeat it");
|
|
82
|
+
}
|
|
75
83
|
return information;
|
|
76
84
|
}
|
|
77
85
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llamaventures/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.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/deal-actions-cli.test.mjs scripts/deal-actions.test.mjs scripts/deal-memory-actions-cli.test.mjs scripts/deal-memory-actions.test.mjs scripts/mcp-four-action-surface.test.mjs scripts/page-schema-cli.test.mjs scripts/page-schema.test.mjs scripts/server-compatibility.test.mjs scripts/verify-core-api-contract.test.mjs && node scripts/verify-core-api-contract.mjs",
|
|
9
|
+
"test:contract": "node --test scripts/content-read.test.mjs scripts/build-manifest.test.mjs scripts/core-api-call-sites.test.mjs scripts/deal-actions-cli.test.mjs scripts/deal-actions.test.mjs scripts/deal-memory-actions-cli.test.mjs scripts/deal-memory-actions.test.mjs scripts/mcp-four-action-surface.test.mjs scripts/page-schema-cli.test.mjs scripts/page-schema.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",
|