@llamaventures/cli 2.0.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 CHANGED
@@ -137,7 +137,12 @@ Update the human-facing state only when you know the intended field:
137
137
  {
138
138
  "operation": "page.patch",
139
139
  "dealId": "<uuid>",
140
- "patch": {"location": "San Francisco, CA"},
140
+ "patch": {
141
+ "location": {
142
+ "en": "San Francisco, CA",
143
+ "zh": "美国加州旧金山"
144
+ }
145
+ },
141
146
  "origin": {
142
147
  "kind": "user",
143
148
  "originalUserUtterance": "The company is in SF, CA."
@@ -145,6 +150,14 @@ Update the human-facing state only when you know the intended field:
145
150
  }
146
151
  ```
147
152
 
153
+ Human-visible Page prose is bilingual at write time. Store one field value as
154
+ `{"en":"natural English","zh":"自然中文"}`; do not create separate English
155
+ and Chinese Pages. Language-neutral company names, enums, URLs, numbers, dates,
156
+ person names, and source IDs remain scalar. A localized object missing either
157
+ language is invalid. New scalar Page prose is also invalid; historical scalar
158
+ prose is read-compatible only. Information and raw Input retain their original
159
+ language and provenance; do not manufacture a second source quote.
160
+
148
161
  Artifacts use `artifact.put`. Treat them as immutable source material. Read the
149
162
  artifact, then decide whether its content deserves Information or a Page patch.
150
163
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.0.1] - 2026-08-30
4
+
5
+ - Ship the four-action Occam Deal surface from the audited cleanup commit.
6
+ - Pin the CLI to the final 4.0.0 Core contract after removing the retired
7
+ Secretary analysis API and cron.
8
+ - Remove legacy Deal API examples from contract-verifier fixtures so the
9
+ package source and publish artifact contain no retired Deal action surface.
10
+ - Enforce bilingual values for newly Agent-authored Page prose while retaining
11
+ read compatibility for historical scalar content.
12
+ - Pin the release candidate to the final local Core API 5.0 contract.
13
+
3
14
  ## [2.0.0] - 2026-08-30
4
15
 
5
16
  - Replace the split Deal command surface with exactly four actions: `search`,
package/README.md CHANGED
@@ -86,6 +86,14 @@ the initial Live Page and Information, and appends Events atomically.
86
86
  - `page.patch` — update the human-visible Live Deal Page.
87
87
  - `artifact.put` — add an immutable memo/HTML/source artifact.
88
88
 
89
+ When Page prose is human-visible, write one bilingual field value as
90
+ `{"en":"natural English","zh":"自然中文"}`. The Web language switch selects
91
+ the reader's version from the same Page revision. Keep language-neutral names,
92
+ enums, URLs, numbers, dates, and source IDs scalar. Information and raw Input
93
+ stay in their original language with provenance. The CLI rejects new scalar
94
+ Page prose and incomplete language pairs before they reach Core; historical
95
+ scalar prose remains readable.
96
+
89
97
  Raw user input example:
90
98
 
91
99
  ```json
package/README.zh-CN.md CHANGED
@@ -84,6 +84,12 @@ Core 会补上 `operation: deal.create`,创建或复用 Drive 文件夹,并
84
84
  - `page.patch`:更新人类直接看到的 Live Deal Page;
85
85
  - `artifact.put`:添加不可变的 memo、HTML 或源文件。
86
86
 
87
+ 给人看的 Page 文字必须在写入时同时提供自然的中英文:
88
+ `{"en":"natural English","zh":"自然中文"}`。Web 的语言开关从同一个
89
+ Page revision 选择对应内容,不创建中文页和英文页两套真相。公司名、枚举、URL、数字、日期、
90
+ 人名和 source ID 等语言无关值继续使用 scalar;Information 和原始 Input 保留原语言与 provenance。
91
+ CLI 会在请求到达 Core 前拒绝新的 scalar Page 文案或缺少任一语言的 pair;历史 scalar 文案仍可读取。
92
+
87
93
  原始用户输入示例:
88
94
 
89
95
  ```json
package/bin/llama-mcp.mjs CHANGED
@@ -99,7 +99,7 @@ server.registerTool(
99
99
  server.registerTool(
100
100
  "write_deal",
101
101
  {
102
- description: "The only Deal mutation tool: input.submit, information.put, page.patch, or artifact.put.",
102
+ description: "The only Deal mutation tool: input.submit, information.put, page.patch, or artifact.put. Human-visible Page prose uses one value with both en and zh.",
103
103
  inputSchema: {
104
104
  operation: z.enum(["input.submit", "information.put", "page.patch", "artifact.put"]),
105
105
  dealId: z.string().uuid(),
package/bin/llama.mjs CHANGED
@@ -79,21 +79,6 @@ Core owns Chat Records, append-only Deal Events, Drive provisioning, audit,
79
79
  and idempotency. User-originated work must preserve exact wording in
80
80
  origin.originalUserUtterance or reference origin.originatingChatRecordId.`;
81
81
 
82
- const RETIRED_DEAL_AREAS = new Set([
83
- "activity",
84
- "approvals",
85
- "brief",
86
- "claim",
87
- "html",
88
- "memo",
89
- "mentions",
90
- "nominate",
91
- "nominations",
92
- "post",
93
- "timeline",
94
- "workflow",
95
- ]);
96
-
97
82
  function parseFlags(args, allowed = null) {
98
83
  const flags = {};
99
84
  const positional = [];
@@ -123,17 +108,11 @@ function usage(area) {
123
108
  console.log(area === "deal" ? HELP_DEAL : HELP_ROOT);
124
109
  }
125
110
 
126
- function assertActiveSurface(area, action) {
111
+ function assertDealAction(area, action) {
127
112
  if (area === "deal" && !DEAL_ACTIONS.includes(action)) {
128
113
  throw new Error(
129
- `DEAL_COMMAND_RETIRED: \`llama deal ${action || "<missing>"}\` is not part of CLI 2. ` +
130
- "Use only search, read, create --json, or write --json.",
131
- );
132
- }
133
- if (RETIRED_DEAL_AREAS.has(area)) {
134
- throw new Error(
135
- `DEAL_COMMAND_RETIRED: \`llama ${area}\` belonged to the split legacy Deal model. ` +
136
- "Use `llama deal read` or `llama deal write --json <file|->`.",
114
+ `Unknown Deal action: ${action || "<missing>"}. ` +
115
+ "Use search, read, create --json, or write --json.",
137
116
  );
138
117
  }
139
118
  }
@@ -426,7 +405,7 @@ async function main() {
426
405
  return;
427
406
  }
428
407
 
429
- assertActiveSurface(area, action);
408
+ assertDealAction(area, action);
430
409
 
431
410
  if (await handleAuth(area, action, rest)) return;
432
411
 
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "format": "llama.core-api-contract.v1",
3
3
  "name": "llama-core-api",
4
- "apiVersion": "4.0.0",
4
+ "apiVersion": "5.0.0",
5
5
  "openapiVersion": "3.0.3",
6
- "sha256": "69b5e29ae9585915da0fa9578abfd41099545f11eba8b2d12f14aa42cc970e4e",
7
- "pathCount": 247,
8
- "operationCount": 323
6
+ "sha256": "c48ed580f9930b06445f62b94959a2ca4bf9780e59473f17588e1e6554914014",
7
+ "pathCount": 110,
8
+ "operationCount": 136
9
9
  }
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "format": "llama.cli-build.v1",
3
3
  "packageName": "@llamaventures/cli",
4
- "packageVersion": "2.0.0",
5
- "sourceSha": "1564eee5aa59c89fc4e245f0a5be0fcbe96d7bf9",
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": "4.0.0",
11
+ "apiVersion": "5.0.0",
12
12
  "openapiVersion": "3.0.3",
13
- "sha256": "69b5e29ae9585915da0fa9578abfd41099545f11eba8b2d12f14aa42cc970e4e"
13
+ "sha256": "c48ed580f9930b06445f62b94959a2ca4bf9780e59473f17588e1e6554914014"
14
14
  }
15
15
  }
package/lib/client.mjs CHANGED
@@ -294,16 +294,6 @@ 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 (pathname === "/api/deals") return verb === "GET" ? "deal.search" : "deal.write";
298
- if (pathname === "/api/deals/create") return "deal.create";
299
- if (pathname === "/api/deals/update") return "deal.update";
300
- if (/^\/api\/deals\/[^/]+\/ingest$/.test(pathname)) return "deal.ingest";
301
- if (/^\/api\/deals\/[^/]+\/threads\/[^/]+$/.test(pathname)) return "deal.agent.run";
302
- if (/^\/api\/deals\/[^/]+\/threads$/.test(pathname)) return "deal.thread.create";
303
- if (/^\/api\/deals\/[^/]+\/facts/.test(pathname)) return verb === "GET" ? "deal.fact.list" : "deal.fact.write";
304
- if (/^\/api\/deals\/[^/]+\/posts$/.test(pathname)) return "deal.post";
305
- if (/^\/api\/deals\/[^/]+\/blocks/.test(pathname)) return verb === "GET" ? "brief.blocks" : "brief.write";
306
- if (/^\/api\/deals\/[^/]+$/.test(pathname)) return verb === "GET" ? "deal.show" : "deal.write";
307
297
  if (pathname === "/api/me") return "auth.status";
308
298
  if (pathname.startsWith("/api/agent/skills")) return "skills.read";
309
299
  if (pathname === "/api/agent/manifest") return "agent.bootstrap";
@@ -45,6 +45,89 @@ export function validateCommandOrigin(command) {
45
45
  return command;
46
46
  }
47
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
+
48
131
  export async function readJsonInput(path, stdin = process.stdin) {
49
132
  if (!path || path === true) throw new Error("--json <file|-> is required");
50
133
  const text = path === "-"
@@ -98,5 +181,13 @@ export function prepareDealCommand(action, input) {
98
181
  if (action === "write" && !DEAL_WRITE_OPERATIONS.includes(command.operation)) {
99
182
  throw new Error(`write JSON operation must be ${DEAL_WRITE_OPERATIONS.join(", ")}`);
100
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
+ }
101
192
  return ensureIdempotencyKey(validateCommandOrigin(command));
102
193
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llamaventures/cli",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "CLI + MCP server for the Llama Ventures investment workbench (command.llamaventures.vc).",
5
5
  "type": "module",
6
6
  "scripts": {