@llamaventures/cli 1.6.0 → 1.7.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
@@ -157,6 +157,9 @@ llama deal list [--owner ...] [--status ...]
157
157
  # Pipeline — write
158
158
  llama deal create "Company" --description "..."
159
159
  llama deal update <dealId> <field> <value>
160
+ # writable: status theirStage stage notes dealOwner source description website
161
+ # location founders proposedAmount roundSize valuation sector subsector
162
+ # foundedYear leadInvestor investors (each write logs a deal_events row)
160
163
 
161
164
  # Brief blocks
162
165
  llama brief blocks <dealId>
@@ -205,6 +208,9 @@ llama wiki save <slug> --title "..." --file path.html --sources "..." [--content
205
208
  # --content-type html (or markdown) overrides the inference.
206
209
  # Refuses to switch content_type on an existing slug; delete + re-create
207
210
  # if you really mean to change format.
211
+ # Delete / restore (soft, reversible — CONSTITUTION §8):
212
+ llama wiki delete <slug> [--lang en|zh]
213
+ llama wiki restore <slug> [--lang en|zh]
208
214
 
209
215
  # Timeline + posts
210
216
  llama timeline <dealId>
@@ -231,7 +237,7 @@ Tools available:
231
237
  - `auth_status` — verify creds + identity (call first if anything 401s)
232
238
  - `deal_search` / `deal_show` / `deal_create` / `deal_update`
233
239
  - `brief_blocks` / `brief_add_text` / `brief_add_link` / `brief_add_callout`
234
- - `wiki_search` / `wiki_save` (accepts `content_type: 'markdown' | 'html'` — HTML entries render as full-viewport sandboxed iframe at `/wiki/<slug>`)
240
+ - `wiki_search` / `wiki_save` (accepts `content_type: 'markdown' | 'html'` — HTML entries render as full-viewport sandboxed iframe at `/wiki/<slug>`) / `wiki_delete` / `wiki_restore` (soft-delete, reversible)
235
241
  - `timeline` / `post`
236
242
  - `mentions_list`
237
243
  - `pitch_start` / `pitch_send_message` / `pitch_upload_file` / `pitch_status` / `pitch_finalize` — public intake (no Llama token needed; for founders / EAs / external agents)
@@ -241,6 +247,7 @@ You can also fetch this exact briefing as an MCP prompt named `agent_briefing`.
241
247
  ## Boundaries (what NOT to do)
242
248
 
243
249
  - **Don't impersonate a human's opinion.** Tag AI-generated content as `[AI · …]`.
250
+ - **Don't vouch for facts you haven't checked.** When you `add fact`, pass `--attested` only if you actually verified the claim against its source. Without it the fact is stored as *unverified* — that's the honest default, not a failure. You cannot mark a fact as human-confirmed; only a person can raise it there.
244
251
  - **Don't use absolute language** ("only", "all", "best", "no one", "极") unless verifiable.
245
252
  - **Don't bypass `llama` CLI / MCP for pipeline writes.** CSRF defence, rate limits, audit logs all flow through it.
246
253
  - **Don't write to retired surfaces.** Google Sheet is read-only archive. Legacy `~/.llama-command/config.json` auto-migrates.
package/README.md CHANGED
@@ -209,7 +209,14 @@ llama post <dealId> "message body" [--link url]
209
209
 
210
210
  # Wiki
211
211
  llama wiki search "<query>"
212
- llama wiki save <slug> --title "..." --content "..."
212
+ llama wiki read <slug> [--lang en|zh]
213
+ # Markdown entry:
214
+ llama wiki save <slug> --title "..." --content "..." --sources "url1;url2"
215
+ # HTML entry — standalone page at /wiki/<slug> (full-viewport sandboxed iframe):
216
+ llama wiki save <slug> --title "..." --file page.html --sources "..." [--content-type html]
217
+ # Delete / restore (soft, reversible):
218
+ llama wiki delete <slug> [--lang en|zh]
219
+ llama wiki restore <slug> [--lang en|zh]
213
220
 
214
221
  # Mentions inbox
215
222
  llama mentions
@@ -255,6 +262,7 @@ brief_add_link brief_add_callout
255
262
  timeline post
256
263
 
257
264
  wiki_search wiki_save
265
+ wiki_delete wiki_restore
258
266
 
259
267
  mentions_list
260
268
 
package/bin/llama-mcp.mjs CHANGED
@@ -197,7 +197,8 @@ server.registerTool(
197
197
  description:
198
198
  "Update a single whitelisted field on a deal. Writable fields: status, theirStage, " +
199
199
  "notes, stage, dealOwner, source, description, website, location, founders, " +
200
- "proposedAmount, roundSize, valuation. Logs a field_change event in deal_events.",
200
+ "proposedAmount, roundSize, valuation, sector, subsector, foundedYear, leadInvestor, " +
201
+ "investors. Logs a field_change event in deal_events.",
201
202
  inputSchema: {
202
203
  dealId: z.string(),
203
204
  field: z.string().describe("camelCase field name (see description for whitelist)"),
@@ -208,6 +209,82 @@ server.registerTool(
208
209
  callApi("POST", "/api/deals/update", { dealId, field, value })
209
210
  );
210
211
 
212
+ // ============================================================
213
+ // Deal facts (research substrate + trust ladder)
214
+ // ============================================================
215
+
216
+ server.registerTool(
217
+ "deal_fact_list",
218
+ {
219
+ description:
220
+ "List a deal's recorded facts (the research substrate). Each fact carries a " +
221
+ "category, a claim, a source, a confidence, and a trust rung (unverified → " +
222
+ "agent-verified → human-vouched → endorsed) plus who/what recorded it.",
223
+ inputSchema: {
224
+ dealId: z.string(),
225
+ },
226
+ },
227
+ async ({ dealId }) =>
228
+ callApi("GET", `/api/deals/${encodeURIComponent(dealId)}/facts`)
229
+ );
230
+
231
+ server.registerTool(
232
+ "deal_fact_add",
233
+ {
234
+ description:
235
+ "Record a factual claim about a deal. RESPONSIBILITY: set `attested` honestly — " +
236
+ "true ONLY if you actually verified the claim against its cited source (the fact " +
237
+ "is then stored at trust level 'agent-verified'); false/omitted if you are relaying " +
238
+ "something unconfirmed (stored 'unverified', which is the honest default). You CANNOT " +
239
+ "mark a fact as human-confirmed — only a person can raise it to 'human-vouched'. " +
240
+ "`confidence` is how certain the claim is; `attested` is whether YOU take responsibility " +
241
+ "for having checked it. category ∈ founders | financials | product | market | team | " +
242
+ "company_basics | risk | fundraise | milestone | meta.",
243
+ inputSchema: {
244
+ dealId: z.string(),
245
+ category: z.string(),
246
+ claim: z.string(),
247
+ source: z.string().optional().describe("where you found this (URL, 'deck p3', 'LinkedIn')"),
248
+ confidence: z.enum(["high", "medium", "low"]).optional(),
249
+ attested: z
250
+ .boolean()
251
+ .optional()
252
+ .describe("true → stored 'agent-verified'; false/omitted → 'unverified'. Answer honestly."),
253
+ },
254
+ },
255
+ async ({ dealId, category, claim, source, confidence, attested }) =>
256
+ callApi("POST", `/api/deals/${encodeURIComponent(dealId)}/facts`, {
257
+ category,
258
+ claim,
259
+ source: source ?? "",
260
+ confidence: confidence ?? "medium",
261
+ attested: attested === true,
262
+ })
263
+ );
264
+
265
+ server.registerTool(
266
+ "deal_fact_verify",
267
+ {
268
+ description:
269
+ "Verify a recorded fact. status='confirmed' vouches for it (raises to 'human-vouched'); " +
270
+ "status='disputed' marks it contradicted. Trust-ladder guardrails apply server-side " +
271
+ "(external-org callers are capped at 'unverified'; only Partners reach 'endorsed'). " +
272
+ "Optionally pass correctedValue when disputing.",
273
+ inputSchema: {
274
+ dealId: z.string(),
275
+ factId: z.union([z.string(), z.number()]),
276
+ status: z.enum(["confirmed", "disputed"]),
277
+ correctedValue: z.string().optional(),
278
+ },
279
+ },
280
+ async ({ dealId, factId, status, correctedValue }) =>
281
+ callApi(
282
+ "PATCH",
283
+ `/api/deals/${encodeURIComponent(dealId)}/facts/${encodeURIComponent(String(factId))}`,
284
+ { status, ...(correctedValue !== undefined ? { correctedValue } : {}) }
285
+ )
286
+ );
287
+
211
288
  // ============================================================
212
289
  // Brief blocks
213
290
  // ============================================================
@@ -272,6 +349,108 @@ server.registerTool(
272
349
  addBriefBlock(dealId, { type: "callout", tone, heading: heading ?? "", body })
273
350
  );
274
351
 
352
+ server.registerTool(
353
+ "brief_edit",
354
+ {
355
+ description:
356
+ "Edit an existing brief block in place. Pass only the fields you want to change " +
357
+ "(heading/body/url/label/description/tone). Meta toggles: locked (protect from bulk " +
358
+ "overwrite), hidden (fold), sourceSection (route watcher writes). Snapshots the prior " +
359
+ "version to history (reversible via brief_restore_version).",
360
+ inputSchema: {
361
+ dealId: z.string(),
362
+ blockId: z.string(),
363
+ heading: z.string().optional(),
364
+ body: z.string().optional(),
365
+ url: z.string().optional(),
366
+ label: z.string().optional(),
367
+ description: z.string().optional(),
368
+ tone: z.string().optional(),
369
+ locked: z.boolean().optional(),
370
+ hidden: z.boolean().optional(),
371
+ sourceSection: z.string().optional(),
372
+ },
373
+ },
374
+ async ({ dealId, blockId, heading, body, url, label, description, tone, locked, hidden, sourceSection }) => {
375
+ const patch = {};
376
+ for (const [k, v] of Object.entries({ heading, body, url, label, description, tone })) {
377
+ if (v !== undefined) patch[k] = v;
378
+ }
379
+ const meta = {};
380
+ if (locked !== undefined) meta.locked = locked;
381
+ if (hidden !== undefined) meta.hidden = hidden;
382
+ if (sourceSection !== undefined) meta.sourceSection = sourceSection;
383
+ if (Object.keys(meta).length > 0) patch.meta = meta;
384
+ return callApi(
385
+ "PATCH",
386
+ `/api/deals/${encodeURIComponent(dealId)}/blocks/${encodeURIComponent(blockId)}`,
387
+ patch
388
+ );
389
+ }
390
+ );
391
+
392
+ server.registerTool(
393
+ "brief_delete",
394
+ {
395
+ description:
396
+ "Soft-delete a brief block (reversible via brief_restore). Locked blocks are refused.",
397
+ inputSchema: { dealId: z.string(), blockId: z.string() },
398
+ },
399
+ async ({ dealId, blockId }) =>
400
+ callApi("DELETE", `/api/deals/${encodeURIComponent(dealId)}/blocks/${encodeURIComponent(blockId)}`)
401
+ );
402
+
403
+ server.registerTool(
404
+ "brief_restore",
405
+ {
406
+ description: "Restore a soft-deleted brief block.",
407
+ inputSchema: { dealId: z.string(), blockId: z.string() },
408
+ },
409
+ async ({ dealId, blockId }) =>
410
+ callApi("POST", `/api/deals/${encodeURIComponent(dealId)}/blocks/${encodeURIComponent(blockId)}/restore`)
411
+ );
412
+
413
+ server.registerTool(
414
+ "brief_history",
415
+ {
416
+ description:
417
+ "List the content-version history of a brief block (every overwrite is snapshotted). " +
418
+ "Use the returned history id with brief_restore_version.",
419
+ inputSchema: {
420
+ dealId: z.string(),
421
+ blockId: z.string(),
422
+ limit: z.number().optional(),
423
+ },
424
+ },
425
+ async ({ dealId, blockId, limit }) => {
426
+ const qs = limit ? `?limit=${encodeURIComponent(String(limit))}` : "";
427
+ return callApi(
428
+ "GET",
429
+ `/api/deals/${encodeURIComponent(dealId)}/blocks/${encodeURIComponent(blockId)}/history${qs}`
430
+ );
431
+ }
432
+ );
433
+
434
+ server.registerTool(
435
+ "brief_restore_version",
436
+ {
437
+ description:
438
+ "Restore a brief block to a specific historical version (find historyId via brief_history). " +
439
+ "Itself reversible — the outgoing version is snapshotted before replacement.",
440
+ inputSchema: {
441
+ dealId: z.string(),
442
+ blockId: z.string(),
443
+ historyId: z.number(),
444
+ },
445
+ },
446
+ async ({ dealId, blockId, historyId }) =>
447
+ callApi(
448
+ "POST",
449
+ `/api/deals/${encodeURIComponent(dealId)}/blocks/${encodeURIComponent(blockId)}/history`,
450
+ { history_id: historyId }
451
+ )
452
+ );
453
+
275
454
  // ============================================================
276
455
  // Wiki (knowledge base)
277
456
  // ============================================================
@@ -380,6 +559,44 @@ server.registerTool(
380
559
  })
381
560
  );
382
561
 
562
+ server.registerTool(
563
+ "wiki_delete",
564
+ {
565
+ description:
566
+ "Soft-delete a wiki page (reversible). The entry stops appearing in " +
567
+ "reads / search / backlinks; for HTML entries the standalone page + " +
568
+ "assets stop resolving too. Restore with wiki_restore. Use when the " +
569
+ "user asks to remove / delete / retire a wiki entry.",
570
+ inputSchema: {
571
+ slug: z.string().describe("kebab-case slug"),
572
+ lang: z.enum(["en", "zh"]).optional().describe("default: en"),
573
+ },
574
+ },
575
+ async ({ slug, lang }) =>
576
+ callApi(
577
+ "DELETE",
578
+ `/api/wiki/${encodeURIComponent(slug)}?lang=${lang === "zh" ? "zh" : "en"}`
579
+ )
580
+ );
581
+
582
+ server.registerTool(
583
+ "wiki_restore",
584
+ {
585
+ description:
586
+ "Restore a soft-deleted wiki page (undo wiki_delete). Brings back the " +
587
+ "entry + (for HTML entries) its standalone page and assets.",
588
+ inputSchema: {
589
+ slug: z.string().describe("kebab-case slug"),
590
+ lang: z.enum(["en", "zh"]).optional().describe("default: en"),
591
+ },
592
+ },
593
+ async ({ slug, lang }) =>
594
+ callApi(
595
+ "POST",
596
+ `/api/wiki/${encodeURIComponent(slug)}/restore?lang=${lang === "zh" ? "zh" : "en"}`
597
+ )
598
+ );
599
+
383
600
  // ============================================================
384
601
  // Timeline + posts
385
602
  // ============================================================
@@ -444,6 +661,109 @@ server.registerTool(
444
661
  }
445
662
  );
446
663
 
664
+ server.registerTool(
665
+ "mentions_resolve",
666
+ {
667
+ description: "Mark an @-mention as resolved (clears it from the recipient's open cues).",
668
+ inputSchema: { mentionId: z.union([z.string(), z.number()]) },
669
+ },
670
+ async ({ mentionId }) =>
671
+ callApi("POST", `/api/mentions/${encodeURIComponent(String(mentionId))}/resolve`)
672
+ );
673
+
674
+ // ============================================================
675
+ // Skill corrections (persona-owner pushback workflow)
676
+ // ============================================================
677
+
678
+ server.registerTool(
679
+ "skill_correction_list",
680
+ {
681
+ description:
682
+ "List the recorded corrections (long-term rules) for a persona/skill. These shape how " +
683
+ "that persona's analysis is generated.",
684
+ inputSchema: {
685
+ skillSlug: z.string(),
686
+ includeDeleted: z.boolean().optional(),
687
+ },
688
+ },
689
+ async ({ skillSlug, includeDeleted }) => {
690
+ const params = new URLSearchParams({ skill: skillSlug });
691
+ if (includeDeleted) params.set("include_deleted", "1");
692
+ return callApi("GET", `/api/skill-corrections?${params}`);
693
+ }
694
+ );
695
+
696
+ server.registerTool(
697
+ "skill_correction_add",
698
+ {
699
+ description:
700
+ "Record a long-term correction rule for a persona/skill (e.g. 'always check burn multiple " +
701
+ "before commenting on efficiency'). ALWAYS reconfirm the distilled rule with the user before " +
702
+ "calling — this changes how the persona behaves going forward. Optionally tie it to the deal/" +
703
+ "block where it came up.",
704
+ inputSchema: {
705
+ skillSlug: z.string(),
706
+ correctionText: z.string(),
707
+ dealUuid: z.string().optional(),
708
+ blockId: z.string().optional(),
709
+ },
710
+ },
711
+ async ({ skillSlug, correctionText, dealUuid, blockId }) =>
712
+ callApi("POST", "/api/skill-corrections", {
713
+ skill_slug: skillSlug,
714
+ correction_text: correctionText,
715
+ triggered_in_deal_uuid: dealUuid ?? null,
716
+ triggered_in_block_id: blockId ?? null,
717
+ })
718
+ );
719
+
720
+ server.registerTool(
721
+ "skill_correction_delete",
722
+ {
723
+ description: "Soft-delete a recorded skill correction by id.",
724
+ inputSchema: { id: z.union([z.string(), z.number()]) },
725
+ },
726
+ async ({ id }) =>
727
+ callApi("DELETE", `/api/skill-corrections/${encodeURIComponent(String(id))}`)
728
+ );
729
+
730
+ // ============================================================
731
+ // Brief / persona refresh (signal-driven re-evaluation)
732
+ // ============================================================
733
+
734
+ server.registerTool(
735
+ "deal_refresh_brief",
736
+ {
737
+ description:
738
+ "Trigger a stale-section re-evaluation of a deal's brief. Pass force=true to bypass the " +
739
+ "debounce. Returns a runId (or null if debounced / deal inactive).",
740
+ inputSchema: {
741
+ dealId: z.string(),
742
+ force: z.boolean().optional(),
743
+ },
744
+ },
745
+ async ({ dealId, force }) =>
746
+ callApi(
747
+ "POST",
748
+ `/api/deals/${encodeURIComponent(dealId)}/refresh-brief${force ? "?force=1" : ""}`
749
+ )
750
+ );
751
+
752
+ server.registerTool(
753
+ "deal_refresh_persona",
754
+ {
755
+ description:
756
+ "Regenerate one persona's analysis section for a deal. persona ∈ gavin | kyle | jack | " +
757
+ "david | bryan | herman | hongjiang | liuyi | kevin. Returns a runId (or null if debounced).",
758
+ inputSchema: {
759
+ dealId: z.string(),
760
+ persona: z.string(),
761
+ },
762
+ },
763
+ async ({ dealId, persona }) =>
764
+ callApi("POST", `/api/deals/${encodeURIComponent(dealId)}/refresh-persona`, { persona })
765
+ );
766
+
447
767
  // ============================================================
448
768
  // External pitch (founder intake) — no Llama Command token required
449
769
  // ============================================================
package/bin/llama.mjs CHANGED
@@ -226,6 +226,13 @@ Deals:
226
226
  llama deal create "Company" --source <name> --description "..." --website https://...
227
227
  llama deal show <dealId>
228
228
  llama deal update <dealId> <field> <value>
229
+ Writable fields: status, theirStage, stage, notes, dealOwner, source,
230
+ description, website, location, founders, proposedAmount, roundSize,
231
+ valuation, sector, subsector, foundedYear, leadInvestor, investors.
232
+ e.g. llama deal update <dealId> website https://acme.ai
233
+ llama deal update <dealId> sector "Developer Tools"
234
+ llama deal update <dealId> foundedYear 2024
235
+ llama deal update <dealId> leadInvestor "Acme Capital"
229
236
  llama deal search <query> [--founder name] [--owner <user-key>] [--status Diligence]
230
237
  [--theirStage Raising] [--stage Seed]
231
238
  [--limit 200] [--offset 0]
@@ -307,7 +314,7 @@ Deal soft-delete / restore / trash list:
307
314
 
308
315
  Deal facts (AI-extracted or human-asserted, with verification):
309
316
  llama deal fact list <dealId> # ⚠ session-only on server today
310
- llama deal fact add <dealId> --category <cat> --claim "<text>" [--source <url>] [--confidence high|medium|low]
317
+ llama deal fact add <dealId> --category <cat> --claim "<text>" [--source <url>] [--confidence high|medium|low] [--attested]
311
318
  llama deal fact verify <dealId> <factId> --status confirmed|disputed [--corrected-value "..."]
312
319
 
313
320
  Skill corrections (persona-owner pushback — read by persona-watcher):
@@ -343,6 +350,9 @@ Wiki:
343
350
  (.html / .htm extension auto-implies content_type=html)
344
351
  ➜ Use Wiki when the artifact is NOT tied to one specific deal — sector landscape, market map,
345
352
  thesis, framework, methodology. For deal-specific HTML use "llama html upload <dealId>" instead.
353
+ Delete / restore (soft — reversible):
354
+ llama wiki delete <slug> [--lang en|zh]
355
+ llama wiki restore <slug> [--lang en|zh]
346
356
 
347
357
  Memo (long-form HTML investment memo — Memo tab in the UI):
348
358
  llama memo show <dealId> [--out <path>] [--json] # default: html → stdout (pipeable to file / browser)
@@ -1144,14 +1154,18 @@ https://command.llamaventures.vc/settings/tokens, run
1144
1154
  if (!flags.category || !flags.claim) {
1145
1155
  throw new Error(
1146
1156
  `Usage: llama deal fact add <dealId> --category <cat> --claim "<text>" ` +
1147
- `[--source <url>] [--confidence high|medium|low]`
1157
+ `[--source <url>] [--confidence high|medium|low] [--attested]`
1148
1158
  );
1149
1159
  }
1160
+ // --attested: the caller takes responsibility that this is accurate
1161
+ // (verified against the source). With it, the fact is recorded as
1162
+ // vouched; without it, it stays unverified. Declare honestly.
1150
1163
  print(await request("POST", `/api/deals/${encodeURIComponent(dealId)}/facts`, {
1151
1164
  category: String(flags.category),
1152
1165
  claim: String(flags.claim),
1153
1166
  source: flags.source ? String(flags.source) : "",
1154
1167
  confidence: flags.confidence ? String(flags.confidence) : "medium",
1168
+ attested: flags.attested === true,
1155
1169
  }));
1156
1170
  return;
1157
1171
  }
@@ -1429,6 +1443,24 @@ Routing — is this the right command?
1429
1443
  return;
1430
1444
  }
1431
1445
 
1446
+ // ----- Wiki: delete (soft) / restore -----
1447
+ // Soft-delete (CONSTITUTION §8 reversible). For HTML entries the
1448
+ // sentinel deal_browse_html body + assets are soft-deleted too;
1449
+ // `llama wiki restore <slug>` brings it all back.
1450
+ if (area === "wiki" && (action === "delete" || action === "restore")) {
1451
+ const { flags, positional } = parseFlags(rest);
1452
+ const slug = positional[0];
1453
+ if (!slug) throw new Error(`Usage: llama wiki ${action} <slug> [--lang en|zh]`);
1454
+ const lang = flags.lang === "zh" ? "zh" : "en";
1455
+ const qs = `?lang=${lang}`;
1456
+ if (action === "delete") {
1457
+ print(await request("DELETE", `/api/wiki/${encodeURIComponent(slug)}${qs}`));
1458
+ } else {
1459
+ print(await request("POST", `/api/wiki/${encodeURIComponent(slug)}/restore${qs}`));
1460
+ }
1461
+ return;
1462
+ }
1463
+
1432
1464
  // ----- Brief blocks: list / add-* / edit / delete -----
1433
1465
  // The block-based deal brief stores an ordered array of typed blocks
1434
1466
  // (text / link / embed / callout) per deal. These commands wrap the
@@ -2139,8 +2171,8 @@ Routing — is this the right command?
2139
2171
  const { flags } = parseFlags(rest.slice(1), knownFlags);
2140
2172
 
2141
2173
  // --slug is the natural agent guess (DB column is `document_slug`).
2142
- // Accept it as an alias for --doc so the failure mode that bit
2143
- // Gavin (silent fall-through to 'main') can't happen again.
2174
+ // Accept it as an alias for --doc so the earlier failure mode
2175
+ // (silent fall-through to 'main') can't happen again.
2144
2176
  if (flags.slug && !flags.doc) {
2145
2177
  process.stderr.write("note: --slug accepted as alias for --doc.\n");
2146
2178
  flags.doc = flags.slug;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llamaventures/cli",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "CLI + MCP server for the Llama Ventures investment workbench (command.llamaventures.vc).",
5
5
  "type": "module",
6
6
  "bin": {