@llamaventures/cli 1.18.1 → 1.19.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/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ this project adheres to [Semantic Versioning](https://semver.org).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.19.0] - 2026-07-16
10
+
11
+ ### Added
12
+ - Pin each CLI artifact to the exact versioned Llama Core OpenAPI contract,
13
+ source commit, and complete source-derived operation inventory.
14
+ - Verify the contract identity and required Core operations during tests,
15
+ packaging, clean tarball installation, and release-gate validation.
16
+
17
+ ### Changed
18
+ - Treat Core HTTP as the CLI's only backend boundary and expose contract/build
19
+ provenance through `llama version --json` for independent rollback audits.
20
+
9
21
  ## [1.18.1] - 2026-07-09
10
22
 
11
23
  ### Changed
package/README.md CHANGED
@@ -42,6 +42,7 @@
42
42
  ```bash
43
43
  npm i -g @llamaventures/cli # Node 18+; also puts `llama-mcp` on your PATH
44
44
  llama --version
45
+ llama version --json # package, source commit, and pinned Core API contract
45
46
  llama auth status # round-trips against /api/me
46
47
  ```
47
48
 
package/README.zh-CN.md CHANGED
@@ -67,6 +67,7 @@ Pitch 完成后档案自动进我们团队的 inbox,我们会主动联系你
67
67
  ```bash
68
68
  npm i -g @llamaventures/cli # Node 18+;llama-mcp 也会一起装上 PATH
69
69
  llama --version
70
+ llama version --json # 包版本、源码 commit 与固定的 Core API 契约
70
71
  llama auth status # 会跑一次 /api/me 验证
71
72
  ```
72
73
 
package/bin/llama.mjs CHANGED
@@ -35,6 +35,7 @@ import {
35
35
  import { LLAMA_CLI_CLIENT_ID, pkceLoopbackFlow, revokeToken as revokeOAuthToken } from "../lib/oauth-flow.mjs";
36
36
  import { deleteBundle, detectBackend, readBundle, writeBundle } from "../lib/oauth-storage.mjs";
37
37
  import { maybeNudgeUpdate, getUpdateNudge } from "../lib/version-check.mjs";
38
+ import { getBuildInfo } from "../lib/build-info.mjs";
38
39
 
39
40
  const requireFromHere = createRequire(import.meta.url);
40
41
  const { version: PKG_VERSION } = requireFromHere("../package.json");
@@ -425,6 +426,7 @@ Manually-set \`llc_\` tokens are used as a fallback.
425
426
 
426
427
  Deals:
427
428
  llama deal create "Company" --source <name> --deal-owner <name|email|userId> --source-direction Inbound|Outbound --description "..." --status Interested|Outreached|Sourced --website https://...
429
+ llama deal founders set <dealId> --json '[{"name":"Ada","email":"ada@example.com","linkedin_url":"https://linkedin.com/in/ada"}]'
428
430
  llama deal show <dealId>
429
431
  llama deal feed <dealId> # every contribution (facts + notes), human-typed or assistant-drafted, newest first
430
432
  llama deal update <dealId> <field> <value>
@@ -1005,6 +1007,10 @@ async function runPitchRepl() {
1005
1007
  async function main() {
1006
1008
  const [area, action, ...rest] = process.argv.slice(2);
1007
1009
  if (area === "--version" || area === "-v" || area === "version") {
1010
+ if (action === "--json" || action === "json") {
1011
+ print(getBuildInfo());
1012
+ return;
1013
+ }
1008
1014
  // `llama version --check` — explicitly check npm for a newer release and
1009
1015
  // print the upgrade line (or "up to date"). Lets an agent surface the
1010
1016
  // nudge on demand, separate from the throttled, TTY-gated auto-nudge.
@@ -1484,6 +1490,26 @@ async function main() {
1484
1490
  return;
1485
1491
  }
1486
1492
 
1493
+ if (area === "deal" && action === "founders") {
1494
+ const sub = rest[0];
1495
+ const dealId = rest[1];
1496
+ const { flags } = parseFlags(rest.slice(2), ["json"]);
1497
+ if (sub !== "set" || !dealId || typeof flags.json !== "string") {
1498
+ throw new Error(
1499
+ "Usage: llama deal founders set <dealId> --json '[{\"name\":\"Ada\",\"email\":\"ada@example.com\"}]'"
1500
+ );
1501
+ }
1502
+ let founders;
1503
+ try {
1504
+ founders = JSON.parse(flags.json);
1505
+ } catch {
1506
+ throw new Error("--json must be a valid JSON array");
1507
+ }
1508
+ if (!Array.isArray(founders)) throw new Error("--json must be a JSON array");
1509
+ print(await request("PUT", `/api/deals/${encodeURIComponent(dealId)}/founders`, { founders }));
1510
+ return;
1511
+ }
1512
+
1487
1513
  // ----- deals.extra JSONB patches (system-admin only, server-gated) -----
1488
1514
  // Same endpoint as `deal update`, but `extraKey` instead of `field`.
1489
1515
  // Server patches one top-level key via jsonb_set and audits the change
@@ -1700,6 +1726,8 @@ async function main() {
1700
1726
  const linkId = rest[2];
1701
1727
  if (!linkId) throw new Error(`Usage: llama deal link ${sub} <dealId> <linkId>`);
1702
1728
  const path = `/api/deals/${encodeURIComponent(dealId)}/links/${encodeURIComponent(linkId)}`;
1729
+ // @core-api-operation DELETE /api/deals/{dealId}/links/{linkId}
1730
+ // @core-api-operation POST /api/deals/{dealId}/links/{linkId}/restore
1703
1731
  print(await request(
1704
1732
  sub === "delete" ? "DELETE" : "POST",
1705
1733
  sub === "delete" ? path : `${path}/restore`
@@ -1967,6 +1995,7 @@ async function main() {
1967
1995
  if (!slug) throw new Error("Usage: llama wiki read <slug> [--lang en|zh]");
1968
1996
  const lang = flags.lang === "zh" ? "zh" : "en";
1969
1997
  const path = `/api/wiki/${encodeURIComponent(slug)}?lang=${lang}`;
1998
+ // @core-api-operation GET /api/wiki/{slug}
1970
1999
  print(await request("GET", path));
1971
2000
  return;
1972
2001
  }
@@ -2298,6 +2327,9 @@ Routing — is this the right command?
2298
2327
  if (flags["errors-only"]) params.set("errors_only", "1");
2299
2328
  }
2300
2329
  const qs = params.toString() ? `?${params.toString()}` : "";
2330
+ // @core-api-operation GET /api/admin/auth-events
2331
+ // @core-api-operation GET /api/admin/deal-events
2332
+ // @core-api-operation GET /api/admin/agent-events
2301
2333
  print(await request("GET", `/api/admin/${sub}${qs}`));
2302
2334
  return;
2303
2335
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "format": "llama.core-api-contract.v1",
3
+ "name": "llama-core-api",
4
+ "apiVersion": "1.0.1",
5
+ "openapiVersion": "3.0.3",
6
+ "sha256": "95ce3639aeee15b0fed09830116838f2a11fd2e40e4f35bf80d785664ecf8d96",
7
+ "pathCount": 211,
8
+ "operationCount": 273
9
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "format": "llama.cli-core-api-operations.v1",
3
+ "coreApiContract": "contracts/core-api.json",
4
+ "requiredOperations": [
5
+ { "method": "DELETE", "path": "/api/deals/{dealId}" },
6
+ { "method": "DELETE", "path": "/api/deals/{dealId}/blocks/{blockId}" },
7
+ { "method": "DELETE", "path": "/api/deals/{dealId}/collaborators/{userId}" },
8
+ { "method": "DELETE", "path": "/api/deals/{dealId}/documents/{slug}" },
9
+ { "method": "DELETE", "path": "/api/deals/{dealId}/documents/{slug}/html" },
10
+ { "method": "DELETE", "path": "/api/deals/{dealId}/links/{linkId}" },
11
+ { "method": "DELETE", "path": "/api/deals/{dealId}/memo" },
12
+ { "method": "DELETE", "path": "/api/skill-corrections/{id}" },
13
+ { "method": "DELETE", "path": "/api/wiki/{slug}" },
14
+ { "method": "GET", "path": "/api/admin/agent-events" },
15
+ { "method": "GET", "path": "/api/admin/auth-events" },
16
+ { "method": "GET", "path": "/api/admin/deal-events" },
17
+ { "method": "GET", "path": "/api/agent/activity" },
18
+ { "method": "GET", "path": "/api/agent/briefing" },
19
+ { "method": "GET", "path": "/api/agent/explain" },
20
+ { "method": "GET", "path": "/api/agent/manifest" },
21
+ { "method": "GET", "path": "/api/agent/skills" },
22
+ { "method": "GET", "path": "/api/agent/skills/{slug}" },
23
+ { "method": "GET", "path": "/api/deals" },
24
+ { "method": "GET", "path": "/api/deals/{dealId}" },
25
+ { "method": "GET", "path": "/api/deals/{dealId}/blocks" },
26
+ { "method": "GET", "path": "/api/deals/{dealId}/blocks/{blockId}" },
27
+ { "method": "GET", "path": "/api/deals/{dealId}/blocks/{blockId}/history" },
28
+ { "method": "GET", "path": "/api/deals/{dealId}/collaborators" },
29
+ { "method": "GET", "path": "/api/deals/{dealId}/command-center" },
30
+ { "method": "GET", "path": "/api/deals/{dealId}/documents" },
31
+ { "method": "GET", "path": "/api/deals/{dealId}/documents/{slug}/html" },
32
+ { "method": "GET", "path": "/api/deals/{dealId}/documents/{slug}/html/history" },
33
+ { "method": "GET", "path": "/api/deals/{dealId}/facts" },
34
+ { "method": "GET", "path": "/api/deals/{dealId}/feed" },
35
+ { "method": "GET", "path": "/api/deals/{dealId}/links" },
36
+ { "method": "GET", "path": "/api/deals/{dealId}/memo" },
37
+ { "method": "GET", "path": "/api/deals/{dealId}/timeline" },
38
+ { "method": "GET", "path": "/api/deals/deleted" },
39
+ { "method": "GET", "path": "/api/me" },
40
+ { "method": "GET", "path": "/api/me/nominations" },
41
+ { "method": "GET", "path": "/api/mentions" },
42
+ { "method": "GET", "path": "/api/mentions/unread-count" },
43
+ { "method": "GET", "path": "/api/oauth/authorize" },
44
+ { "method": "GET", "path": "/api/partner/approvals" },
45
+ { "method": "GET", "path": "/api/skill-corrections" },
46
+ { "method": "GET", "path": "/api/users" },
47
+ { "method": "GET", "path": "/api/wiki/{slug}" },
48
+ { "method": "GET", "path": "/api/wiki/search" },
49
+ { "method": "PATCH", "path": "/api/deals/{dealId}/blocks/{blockId}" },
50
+ { "method": "PATCH", "path": "/api/deals/{dealId}/documents/{slug}" },
51
+ { "method": "PATCH", "path": "/api/deals/{dealId}/facts/{factId}" },
52
+ { "method": "POST", "path": "/api/agent/client-events" },
53
+ { "method": "POST", "path": "/api/agent/eval-feedback" },
54
+ { "method": "POST", "path": "/api/deals/{dealId}/agent-runs/{runId}/revert" },
55
+ { "method": "POST", "path": "/api/deals/{dealId}/blocks/{blockId}/history" },
56
+ { "method": "POST", "path": "/api/deals/{dealId}/blocks/{blockId}/restore" },
57
+ { "method": "POST", "path": "/api/deals/{dealId}/collaborators" },
58
+ { "method": "POST", "path": "/api/deals/{dealId}/collaborators/{userId}/restore" },
59
+ { "method": "POST", "path": "/api/deals/{dealId}/documents" },
60
+ { "method": "POST", "path": "/api/deals/{dealId}/documents/{slug}/html/restore/{version}" },
61
+ { "method": "POST", "path": "/api/deals/{dealId}/enrich" },
62
+ { "method": "POST", "path": "/api/deals/{dealId}/facts" },
63
+ { "method": "POST", "path": "/api/deals/{dealId}/links" },
64
+ { "method": "POST", "path": "/api/deals/{dealId}/links/{linkId}/restore" },
65
+ { "method": "POST", "path": "/api/deals/{dealId}/memo" },
66
+ { "method": "POST", "path": "/api/deals/{dealId}/posts" },
67
+ { "method": "POST", "path": "/api/deals/{dealId}/propose-owner" },
68
+ { "method": "POST", "path": "/api/deals/{dealId}/refresh-brief" },
69
+ { "method": "POST", "path": "/api/deals/{dealId}/refresh-persona" },
70
+ { "method": "POST", "path": "/api/deals/{dealId}/restore" },
71
+ { "method": "POST", "path": "/api/deals/{dealId}/threads" },
72
+ { "method": "POST", "path": "/api/deals/{dealId}/threads/{threadId}" },
73
+ { "method": "POST", "path": "/api/deals/create" },
74
+ { "method": "POST", "path": "/api/deals/update" },
75
+ { "method": "POST", "path": "/api/external/chat" },
76
+ { "method": "POST", "path": "/api/external/start-session" },
77
+ { "method": "POST", "path": "/api/external/upload" },
78
+ { "method": "POST", "path": "/api/mentions/{id}/resolve" },
79
+ { "method": "POST", "path": "/api/nominations/{approvalId}" },
80
+ { "method": "POST", "path": "/api/oauth/revoke" },
81
+ { "method": "POST", "path": "/api/oauth/token" },
82
+ { "method": "POST", "path": "/api/partner/approvals" },
83
+ { "method": "POST", "path": "/api/skill-corrections" },
84
+ { "method": "POST", "path": "/api/wiki/{slug}/restore" },
85
+ { "method": "POST", "path": "/api/wiki/save" },
86
+ { "method": "PUT", "path": "/api/deals/{dealId}/blocks" },
87
+ { "method": "PUT", "path": "/api/deals/{dealId}/documents/{slug}/html" },
88
+ { "method": "PUT", "path": "/api/deals/{dealId}/founders" },
89
+ { "method": "PUT", "path": "/api/deals/{dealId}/memo" }
90
+ ]
91
+ }
@@ -0,0 +1,34 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ const requireFromHere = createRequire(import.meta.url);
4
+
5
+ function readJson(relativePath) {
6
+ try {
7
+ return requireFromHere(relativePath);
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+
13
+ export function getBuildInfo() {
14
+ const built = readJson("./build-manifest.json");
15
+ if (built) return built;
16
+
17
+ const packageJson = readJson("../package.json") || {};
18
+ const contract = readJson("../contracts/core-api.json") || {};
19
+ return {
20
+ format: "llama.cli-build.v1",
21
+ packageName: packageJson.name || "@llamaventures/cli",
22
+ packageVersion: packageJson.version || "unknown",
23
+ sourceSha: "local/unknown",
24
+ sourceKind: "local",
25
+ sourceDirty: null,
26
+ coreApiContract: {
27
+ format: contract.format || "unknown",
28
+ name: contract.name || "llama-core-api",
29
+ apiVersion: contract.apiVersion || "unknown",
30
+ openapiVersion: contract.openapiVersion || "unknown",
31
+ sha256: contract.sha256 || "unknown",
32
+ },
33
+ };
34
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "format": "llama.cli-build.v1",
3
+ "packageName": "@llamaventures/cli",
4
+ "packageVersion": "1.19.0",
5
+ "sourceSha": "5f615ca16d607fc0da09887952afdf42301a43f8",
6
+ "sourceKind": "github",
7
+ "sourceDirty": false,
8
+ "coreApiContract": {
9
+ "format": "llama.core-api-contract.v1",
10
+ "name": "llama-core-api",
11
+ "apiVersion": "1.0.1",
12
+ "openapiVersion": "3.0.3",
13
+ "sha256": "95ce3639aeee15b0fed09830116838f2a11fd2e40e4f35bf80d785664ecf8d96"
14
+ }
15
+ }
package/lib/client.mjs CHANGED
@@ -14,6 +14,7 @@ import { fileURLToPath } from "url";
14
14
  import { execFile as _execFile } from "child_process";
15
15
  import { promisify } from "util";
16
16
  import { createHash, randomUUID } from "crypto";
17
+ import { getBuildInfo } from "./build-info.mjs";
17
18
 
18
19
  const execFile = promisify(_execFile);
19
20
 
@@ -207,9 +208,13 @@ function rememberAgentEvent(event) {
207
208
  }
208
209
 
209
210
  function agentClientHeaders(command) {
211
+ const build = getBuildInfo();
210
212
  return {
211
213
  "X-Llama-Client": runtimeClient,
212
214
  "X-Llama-Client-Version": getPackageVersion(),
215
+ "X-Llama-Client-Source-Sha": build.sourceSha,
216
+ "X-Llama-API-Contract-Version": build.coreApiContract.apiVersion,
217
+ "X-Llama-API-Contract-Digest": build.coreApiContract.sha256,
213
218
  "X-Llama-Agent-Client": detectAgentClient(),
214
219
  "X-Llama-Agent-Session": currentAgentSessionId(),
215
220
  "X-Llama-Command": command || "unknown",
@@ -173,6 +173,7 @@ export async function pkceLoopbackFlow({ baseUrl, scope, resource }) {
173
173
  });
174
174
 
175
175
  // Build authorize URL and open browser.
176
+ // @core-api-operation GET /api/oauth/authorize
176
177
  const authorizeUrl = new URL(`${baseUrl}/api/oauth/authorize`);
177
178
  authorizeUrl.searchParams.set("response_type", "code");
178
179
  authorizeUrl.searchParams.set("client_id", CLIENT_ID);
@@ -73,6 +73,7 @@ async function fetchLatest() {
73
73
  // The /latest convenience endpoint returns full JSON under the default
74
74
  // Accept. (The abbreviated "vnd.npm.install-v1+json" metadata type is only
75
75
  // valid on the full packument endpoint — it 406s here.)
76
+ // @core-api-ignore external npm registry version check
76
77
  const res = await fetch(REGISTRY_URL, { signal: controller.signal });
77
78
  if (!res.ok) return null;
78
79
  const data = await res.json();
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@llamaventures/cli",
3
- "version": "1.18.1",
3
+ "version": "1.19.0",
4
4
  "description": "CLI + MCP server for the Llama Ventures investment workbench (command.llamaventures.vc).",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "test": "npm run test:agent-routing",
7
+ "test": "npm run test:agent-routing && npm run test:contract",
8
8
  "test:agent-routing": "node scripts/verify-agent-routing.mjs",
9
- "verify:release": "npm test && node scripts/verify-tarball-clean.mjs && npm pack --dry-run"
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",
10
+ "verify:artifact": "node scripts/verify-release-artifact.mjs",
11
+ "verify:release": "npm test && npm run verify:artifact && node scripts/verify-tarball-clean.mjs",
12
+ "prepack": "node scripts/prepare-build-manifest.mjs",
13
+ "postpack": "node scripts/cleanup-build-manifest.mjs"
10
14
  },
11
15
  "bin": {
12
16
  "llama": "bin/llama.mjs",
@@ -14,6 +18,7 @@
14
18
  },
15
19
  "files": [
16
20
  "bin/",
21
+ "contracts/",
17
22
  "lib/",
18
23
  "AGENT_BRIEFING.md",
19
24
  "CHANGELOG.md",