@llamaventures/cli 2.0.3 → 2.1.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 CHANGED
@@ -44,6 +44,14 @@ working memory; it never becomes Page automatically. Page is the bounded,
44
44
  human-visible current projection, so patch the exact semantic fields described
45
45
  by the live contract instead of hiding structured analysis in `notes`.
46
46
 
47
+ The Markdown Deal Story is a separate sidecar domain, not a sixth Occam
48
+ resource. Use `get_deal_memory` / `llama memory read` for accumulated narrative
49
+ understanding, and `update_deal_memory` / `llama memory write` to replace its
50
+ complete Markdown. Read first and pass the returned opaque version on every
51
+ update; a conflict means read again and reconcile. These calls still go only
52
+ through authenticated Core. Never request AWS credentials or call S3 or the
53
+ sidecar directly.
54
+
47
55
  Every Page content field is Agent-writable. A field's `author` or
48
56
  `semanticOwner` describes attribution, not permission. Preserve a real human
49
57
  judgment with its author; otherwise label the value as an Agent proposal / 待人确认.
@@ -207,4 +215,5 @@ artifact, then decide whether its content deserves Information or a Page patch.
207
215
  `DEAL_COMMAND_RETIRED`. Upgrade the CLI and retry the intended four-action
208
216
  command.
209
217
  - Wiki, admin audit, external pitch, authentication, and skill discovery are
210
- separate domains. They do not expand the Deal action space.
218
+ separate domains. Deal Memory is also separate. None expands the four-action
219
+ Occam Deal space.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ All notable changes to `@llamaventures/cli` are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
5
+ this project adheres to [Semantic Versioning](https://semver.org).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [2.1.0] - 2026-09-03
10
+
11
+ ### Added
12
+ - Add `llama memory read|write` and matching `get_deal_memory` /
13
+ `update_deal_memory` MCP tools for one canonical Markdown Deal Story, using
14
+ the existing Llama login through Core's authenticated sidecar adapter.
15
+
16
+ ### Changed
17
+ - Make the authenticated live bootstrap mandatory before Deal work and clarify
18
+ that it loads the server-owned two-part private Brain plus the separate Live
19
+ Deal Page field contract. CLI remains only the tool/transport layer.
20
+ - Teach CLI and MCP Agents that Information never updates Page automatically,
21
+ every Page content field is Agent-writable, and field authorship controls
22
+ attribution rather than permission.
23
+ - Pin the additive Deal Memory operations to Core API 5.1.0 while preserving
24
+ exactly four Occam Deal actions and five Occam resources.
25
+
3
26
  ## [2.0.3] - 2026-08-31
4
27
 
5
28
  - Show Core validation codes and field paths instead of collapsing malformed
@@ -49,20 +72,6 @@
49
72
  - Keep Wiki, admin audit, external pitch, authentication, preferences, and
50
73
  progressive skill discovery as separate non-Deal domains.
51
74
 
52
- All notable changes to `@llamaventures/cli` are documented here.
53
- The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
54
- this project adheres to [Semantic Versioning](https://semver.org).
55
-
56
- ## [Unreleased]
57
-
58
- ### Changed
59
- - Make the authenticated live bootstrap mandatory before Deal work and clarify
60
- that it loads the server-owned two-part private Brain plus the separate Live
61
- Deal Page field contract. CLI remains only the tool/transport layer.
62
- - Teach CLI and MCP Agents that Information never updates Page automatically,
63
- every Page content field is Agent-writable, and field authorship controls
64
- attribution rather than permission.
65
-
66
75
  ## [1.26.0] - 2026-08-11
67
76
 
68
77
  ### Added
package/README.md CHANGED
@@ -122,6 +122,27 @@ For user-originated work, preserve the exact words in
122
122
  Chat and Event are system-owned. There is no caller-controlled Event append or
123
123
  general Chat-forging operation.
124
124
 
125
+ ## Deal Memory sidecar
126
+
127
+ Deal Memory is a separate domain alongside the five-resource Deal model. Each
128
+ deal can have one canonical, human-readable Markdown Deal Story:
129
+
130
+ ```bash
131
+ llama memory read <dealId>
132
+ llama memory read <dealId> --raw
133
+ llama memory write <dealId> --markdown deal-story.md
134
+ llama memory write <dealId> --markdown deal-story.md --expected-version '"etag-from-read"'
135
+ ```
136
+
137
+ The first write omits `--expected-version`. Updating an existing story requires
138
+ the opaque `version` returned by `read`; a stale value fails instead of losing a
139
+ concurrent edit. This uses the same `llama auth login` identity. CLI calls the
140
+ authenticated Command Core adapter only—it has no sidecar URL, service token,
141
+ S3 credentials, or direct database access.
142
+
143
+ `llama deal read --detail memory` still means structured Deal Information.
144
+ `llama memory read` means the separate accumulated Markdown Deal Story.
145
+
125
146
  ## Five Deal resources
126
147
 
127
148
  1. Live Deal Page — current human-visible state.
@@ -149,7 +170,9 @@ Its Deal surface is also exactly four tools:
149
170
  - `write_deal`
150
171
 
151
172
  Authentication, skill discovery, Wiki, admin audit, preferences, and external
152
- pitch remain separate non-Deal domains.
173
+ pitch remain separate non-Deal domains. Deal Memory likewise has two separate
174
+ MCP tools, `get_deal_memory` and `update_deal_memory`; it does not add a fifth
175
+ Occam Deal tool.
153
176
 
154
177
  ## Agent bootstrap
155
178
 
package/README.zh-CN.md CHANGED
@@ -116,6 +116,26 @@ llama deal write --json write.json
116
116
  Chat 和 Event 由系统拥有。Agent 不能自行伪造 Event 类型、顺序、作者、
117
117
  时间,也没有通用的 Chat 写入工具。
118
118
 
119
+ ## Deal Memory sidecar
120
+
121
+ Deal Memory 是与五资源 Deal 模型并行、完全解耦的领域。每个 Deal 可以有一个
122
+ 人和 Agent 都能直接阅读的 Markdown Deal Story:
123
+
124
+ ```bash
125
+ llama memory read <dealId>
126
+ llama memory read <dealId> --raw
127
+ llama memory write <dealId> --markdown deal-story.md
128
+ llama memory write <dealId> --markdown deal-story.md --expected-version '"read 返回的 etag"'
129
+ ```
130
+
131
+ 第一次创建时不传 `--expected-version`;以后更新必须使用前一次 `read` 返回的
132
+ 不透明 `version`,旧版本会安全失败,不会覆盖他人的新内容。它复用同一个
133
+ `llama auth login` 身份。CLI 只调用经过认证的 Command Core adapter,不持有
134
+ sidecar URL、service token、S3 凭证,也不直接访问数据库。
135
+
136
+ `llama deal read --detail memory` 仍表示结构化 Deal Information;
137
+ `llama memory read` 表示独立的 Markdown Deal Story。
138
+
119
139
  ## Deal 只有五种业务资源
120
140
 
121
141
  1. Live Deal Page:人类看到的当前状态;
@@ -141,7 +161,9 @@ MCP 的 Deal 工具同样恰好四个:
141
161
  - `write_deal`
142
162
 
143
163
  认证、skill discovery、Wiki、admin audit、preferences 和 external pitch
144
- 属于其他独立领域,不会扩大 Deal action space。
164
+ 属于其他独立领域,不会扩大 Deal action space。Deal Memory 同样是独立领域,
165
+ 对应 `get_deal_memory` 和 `update_deal_memory` 两个 MCP 工具,并不增加第五个
166
+ Occam Deal 工具。
145
167
 
146
168
  ## Agent 启动
147
169
 
package/bin/llama-mcp.mjs CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  compactDealWriteResult,
26
26
  prepareDealCommand,
27
27
  } from "../lib/deal-actions.mjs";
28
+ import { buildDealMemoryPath } from "../lib/deal-memory-actions.mjs";
28
29
 
29
30
  const requireFromHere = createRequire(import.meta.url);
30
31
  const { version: PKG_VERSION } = requireFromHere("../package.json");
@@ -164,6 +165,36 @@ server.registerTool(
164
165
  ),
165
166
  );
166
167
 
168
+ // Deal Memory is a separate sidecar domain. These do not add an Occam Deal
169
+ // business resource or widen the deliberately closed four-tool Deal surface.
170
+ server.registerTool(
171
+ "get_deal_memory",
172
+ {
173
+ description: "Read the complete canonical Markdown Deal Story and its opaque concurrency version.",
174
+ inputSchema: { dealId: z.string().uuid() },
175
+ },
176
+ // @core-api-operation GET /api/deal-memory/{dealId}/story
177
+ async ({ dealId }) => callApi("GET", buildDealMemoryPath(dealId)),
178
+ );
179
+
180
+ server.registerTool(
181
+ "update_deal_memory",
182
+ {
183
+ description: "Create or replace the complete Markdown Deal Story. Existing stories require the version returned by get_deal_memory; stale writes fail safely.",
184
+ inputSchema: {
185
+ dealId: z.string().uuid(),
186
+ markdown: z.string().min(1).max(1_048_576),
187
+ expected_version: z.string().min(1).optional(),
188
+ },
189
+ },
190
+ // @core-api-operation PUT /api/deal-memory/{dealId}/story
191
+ async ({ dealId, markdown, expected_version }) => callApi(
192
+ "PUT",
193
+ buildDealMemoryPath(dealId),
194
+ { markdown, ...(expected_version ? { expected_version } : {}) },
195
+ ),
196
+ );
197
+
167
198
  server.registerTool(
168
199
  "auth_status",
169
200
  {
package/bin/llama.mjs CHANGED
@@ -39,6 +39,10 @@ import {
39
39
  prepareDealCommand,
40
40
  readJsonInput,
41
41
  } from "../lib/deal-actions.mjs";
42
+ import {
43
+ buildDealMemoryPath,
44
+ readMarkdownInput,
45
+ } from "../lib/deal-memory-actions.mjs";
42
46
 
43
47
  const requireFromHere = createRequire(import.meta.url);
44
48
  const { version: PKG_VERSION } = requireFromHere("../package.json");
@@ -51,6 +55,10 @@ Deal has exactly four actions:
51
55
  llama deal create --json <file|->
52
56
  llama deal write --json <file|->
53
57
 
58
+ Deal Memory is a separate sidecar domain through the same login:
59
+ llama memory read <dealId> [--raw]
60
+ llama memory write <dealId> --markdown <file|-> [--expected-version <version>]
61
+
54
62
  Separate preserved domains:
55
63
  llama auth status|login|logout
56
64
  llama token set|show
@@ -98,6 +106,19 @@ Core owns Chat Records, append-only Deal Events, Drive provisioning, audit,
98
106
  and idempotency. User-originated work must preserve exact wording in
99
107
  origin.originalUserUtterance or reference origin.originatingChatRecordId.`;
100
108
 
109
+ const HELP_MEMORY = `Llama Deal Memory — one canonical Markdown Deal Story
110
+
111
+ llama memory read <dealId> [--raw]
112
+ llama memory write <dealId> --markdown <file|-> [--expected-version <version>]
113
+
114
+ Read returns the full JSON record, including its opaque version. --raw prints
115
+ only the exact Markdown. A first write creates the story without a version.
116
+ Every later write must pass the version from the preceding read; stale writes
117
+ fail instead of overwriting newer understanding.
118
+
119
+ This uses your existing Llama authentication. The CLI talks only to Command
120
+ Core and never receives Deal Memory service credentials or AWS access.`;
121
+
101
122
  function parseFlags(args, allowed = null) {
102
123
  const flags = {};
103
124
  const positional = [];
@@ -124,7 +145,7 @@ function parseFlags(args, allowed = null) {
124
145
  }
125
146
 
126
147
  function usage(area) {
127
- console.log(area === "deal" ? HELP_DEAL : HELP_ROOT);
148
+ console.log(area === "deal" ? HELP_DEAL : area === "memory" ? HELP_MEMORY : HELP_ROOT);
128
149
  }
129
150
 
130
151
  function assertDealAction(area, action) {
@@ -576,6 +597,32 @@ async function main() {
576
597
  return;
577
598
  }
578
599
 
600
+ if (area === "memory" && action === "read") {
601
+ const { flags, positional } = parseFlags(rest, ["raw"]);
602
+ const path = buildDealMemoryPath(positional[0]);
603
+ // @core-api-operation GET /api/deal-memory/{dealId}/story
604
+ const result = await request("GET", path);
605
+ if (flags.raw) process.stdout.write(result.markdown);
606
+ else print(result);
607
+ return;
608
+ }
609
+ if (area === "memory" && action === "write") {
610
+ const { flags, positional } = parseFlags(rest, ["markdown", "expected-version"]);
611
+ const path = buildDealMemoryPath(positional[0]);
612
+ const markdown = await readMarkdownInput(flags.markdown);
613
+ // @core-api-operation PUT /api/deal-memory/{dealId}/story
614
+ print(await request("PUT", path, {
615
+ markdown,
616
+ ...(typeof flags["expected-version"] === "string"
617
+ ? { expected_version: flags["expected-version"] }
618
+ : {}),
619
+ }));
620
+ return;
621
+ }
622
+ if (area === "memory") {
623
+ throw new Error("Memory actions: read, write.");
624
+ }
625
+
579
626
  if (area === "wiki") {
580
627
  await handleWiki(action, rest);
581
628
  return;
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "format": "llama.core-api-contract.v1",
3
3
  "name": "llama-core-api",
4
- "apiVersion": "5.0.0",
4
+ "apiVersion": "5.1.0",
5
5
  "openapiVersion": "3.0.3",
6
- "sha256": "c48ed580f9930b06445f62b94959a2ca4bf9780e59473f17588e1e6554914014",
7
- "pathCount": 110,
8
- "operationCount": 136
6
+ "sha256": "948a8d02ae833e8cfa2302bc3c615fc1d3c792ae774ebc25b16be81fd1b85fee",
7
+ "pathCount": 111,
8
+ "operationCount": 138
9
9
  }
@@ -12,6 +12,7 @@
12
12
  { "method": "GET", "path": "/api/agent/preferences" },
13
13
  { "method": "GET", "path": "/api/agent/skills" },
14
14
  { "method": "GET", "path": "/api/agent/skills/{slug}" },
15
+ { "method": "GET", "path": "/api/deal-memory/{dealId}/story" },
15
16
  { "method": "GET", "path": "/api/me" },
16
17
  { "method": "GET", "path": "/api/oauth/authorize" },
17
18
  { "method": "GET", "path": "/api/occam/deals" },
@@ -28,6 +29,7 @@
28
29
  { "method": "POST", "path": "/api/oauth/token" },
29
30
  { "method": "POST", "path": "/api/occam/deals/commands" },
30
31
  { "method": "POST", "path": "/api/wiki/{slug}/restore" },
31
- { "method": "POST", "path": "/api/wiki/save" }
32
+ { "method": "POST", "path": "/api/wiki/save" },
33
+ { "method": "PUT", "path": "/api/deal-memory/{dealId}/story" }
32
34
  ]
33
35
  }
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "format": "llama.cli-build.v1",
3
3
  "packageName": "@llamaventures/cli",
4
- "packageVersion": "2.0.3",
5
- "sourceSha": "dc1618ab65b6cb2e73b107e7d56315ce2076744e",
4
+ "packageVersion": "2.1.0",
5
+ "sourceSha": "0a29fd1ecdfb2064a90d36e323549a0445b3a21e",
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.0.0",
11
+ "apiVersion": "5.1.0",
12
12
  "openapiVersion": "3.0.3",
13
- "sha256": "c48ed580f9930b06445f62b94959a2ca4bf9780e59473f17588e1e6554914014"
13
+ "sha256": "948a8d02ae833e8cfa2302bc3c615fc1d3c792ae774ebc25b16be81fd1b85fee"
14
14
  }
15
15
  }
package/lib/client.mjs CHANGED
@@ -294,6 +294,9 @@ function inferCommand(method, endpoint) {
294
294
  if (pathname === "/api/occam/deals") return "deal.search";
295
295
  if (pathname === "/api/occam/deals/commands") return "deal.write";
296
296
  if (/^\/api\/occam\/deals\/[^/]+$/.test(pathname)) return "deal.read";
297
+ if (/^\/api\/deal-memory\/[^/]+\/story$/.test(pathname)) {
298
+ return verb === "GET" ? "memory.read" : "memory.write";
299
+ }
297
300
  if (pathname === "/api/me") return "auth.status";
298
301
  if (pathname.startsWith("/api/agent/skills")) return "skills.read";
299
302
  if (pathname === "/api/agent/manifest") return "agent.bootstrap";
@@ -0,0 +1,31 @@
1
+ import { readFile } from "node:fs/promises";
2
+
3
+ export const MAX_DEAL_STORY_BYTES = 1_048_576;
4
+
5
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
6
+
7
+ export function buildDealMemoryPath(dealId) {
8
+ if (!UUID.test(String(dealId || ""))) {
9
+ throw new Error("Deal Memory requires a valid deal UUID");
10
+ }
11
+ return `/api/deal-memory/${encodeURIComponent(dealId)}/story`;
12
+ }
13
+
14
+ export async function readMarkdownInput(path, stdin = process.stdin) {
15
+ if (!path || path === true) throw new Error("--markdown <file|-> is required");
16
+ const markdown = path === "-"
17
+ ? await new Promise((resolve, reject) => {
18
+ let value = "";
19
+ stdin.setEncoding("utf8");
20
+ stdin.on("data", (chunk) => { value += chunk; });
21
+ stdin.on("end", () => resolve(value));
22
+ stdin.on("error", reject);
23
+ })
24
+ : await readFile(path, "utf8");
25
+ if (!markdown) throw new Error("Deal Story Markdown cannot be empty");
26
+ const bytes = Buffer.byteLength(markdown, "utf8");
27
+ if (bytes > MAX_DEAL_STORY_BYTES) {
28
+ throw new Error(`Deal Story is ${bytes} bytes; maximum is ${MAX_DEAL_STORY_BYTES}`);
29
+ }
30
+ return markdown;
31
+ }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@llamaventures/cli",
3
- "version": "2.0.3",
3
+ "version": "2.1.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/mcp-four-action-surface.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/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/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",