@llamaventures/cli 1.5.0 → 1.6.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 +69 -3
- package/bin/llama-mcp.mjs +49 -8
- package/bin/llama.mjs +83 -6
- package/package.json +1 -1
package/AGENT_BRIEFING.md
CHANGED
|
@@ -29,13 +29,69 @@ Don't:
|
|
|
29
29
|
|
|
30
30
|
Conversation produces value → that value flows somewhere. This is not optional.
|
|
31
31
|
|
|
32
|
+
### Where does this HTML / thesis / artifact go? (decision tree)
|
|
33
|
+
|
|
34
|
+
When the user hands you an HTML page, thesis write-up, market map, dashboard, IC memo, sector landscape — anything that isn't a one-off note — pick the destination in this order. **Llama Command native (the workbench) outranks Netlify for everything internal.** Only escape to Netlify when the page is truly going to a public / founder-facing URL.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
HTML / thesis / artifact in hand
|
|
38
|
+
│
|
|
39
|
+
▼
|
|
40
|
+
┌─────────────────────────────────────────────────┐
|
|
41
|
+
│ Is it about ONE specific company or deal? │
|
|
42
|
+
│ (deal IC memo · dashboard for X · X 的 thesis │
|
|
43
|
+
│ · founder briefing for X · X 的 2×2 …) │
|
|
44
|
+
└──────────────┬──────────────────────────────────┘
|
|
45
|
+
│
|
|
46
|
+
yes ────►│ → Llama Command DEAL page
|
|
47
|
+
│ `llama html upload <dealId> --new --title "..." --file <path>`
|
|
48
|
+
│ Renders at /deals/<id>/browse/<slug>.
|
|
49
|
+
│ Use --doc <slug> + --file to update an existing one.
|
|
50
|
+
│
|
|
51
|
+
no ────►│ Is it cross-deal / institutional knowledge?
|
|
52
|
+
│ (sector landscape · market map · framework · firm-level
|
|
53
|
+
│ thesis · methodology · "AI infra in 2026" …)
|
|
54
|
+
│
|
|
55
|
+
│ yes ──► → Llama Command WIKI entry
|
|
56
|
+
│ Markdown body:
|
|
57
|
+
│ `llama wiki save <slug> --title "..." \`
|
|
58
|
+
│ ` --content "..." --sources "..."`
|
|
59
|
+
│ Standalone HTML page (full-viewport iframe):
|
|
60
|
+
│ `llama wiki save <slug> --title "..." \`
|
|
61
|
+
│ ` --file <path>.html --sources "..."`
|
|
62
|
+
│ Renders at /wiki/<slug>. Sources mandatory.
|
|
63
|
+
│
|
|
64
|
+
│ no ──► Likely doesn't need to live anywhere
|
|
65
|
+
│ durable — confirm with the user before
|
|
66
|
+
│ inventing a destination.
|
|
67
|
+
▼
|
|
68
|
+
┌─────────────────────────────────────────────────┐
|
|
69
|
+
│ Does the user EXPLICITLY say "share with │
|
|
70
|
+
│ founder" / "public share link" / "give it to │
|
|
71
|
+
│ <external person>" / "publish publicly"? │
|
|
72
|
+
└──────────────┬──────────────────────────────────┘
|
|
73
|
+
│
|
|
74
|
+
no ────►│ → STAY on Llama Command. Don't reach for Netlify.
|
|
75
|
+
│
|
|
76
|
+
yes ────►│ → Netlify (only this case).
|
|
77
|
+
│ Use the `netlify-access-guard` workflow:
|
|
78
|
+
│ server-side password + edge 401 verification.
|
|
79
|
+
│ Verify enforcement is at the Netlify edge, not a
|
|
80
|
+
│ browser-side JS fake.
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Default bias:** when in doubt, route to Llama Command. It has auth, audit, search, backlinks, and lives next to the rest of the team's context. Netlify is the escape hatch for genuinely-external surfaces — not "where pretty HTML goes."
|
|
84
|
+
|
|
85
|
+
The table below details the exact CLI for each destination.
|
|
86
|
+
|
|
32
87
|
| Type | Destination | How |
|
|
33
88
|
|---|---|---|
|
|
34
89
|
| Deal metadata (status, stage, valuation, founders, notes, etc.) | Pipeline (Postgres) | `llama deal create` / `llama deal update` |
|
|
35
90
|
| Brief blocks (text / link / embed / callout) | Pipeline | `llama brief add-text` / `add-link` / `add-callout` |
|
|
36
91
|
| **HTML artifact, internal — IC report, dashboard, market map, 2×2, any hand-authored page** | **Llama Command native** (Postgres + sandboxed iframe at `/deals/<id>/browse/<slug>`) | Default path when the user says "deploy to llama", "deploy to llama command", "部署到 llama command", "put this HTML on the deal page", "在 deal 里看这个". **You MUST declare intent — "new artifact" vs "update existing":**<br><br>**New artifact:** `llama html upload <dealId> --new --title "<artifact name>" --file <path>` (CLI slugifies the title; pass `--doc <slug>` to override).<br>**Update existing:** `llama html upload <dealId> --doc <slug> --file <path>` (slug must already exist — run `llama html docs <dealId>` first to see what's there).<br><br>The bare form `llama html upload <id> --file <path>` REFUSES if `main` already has content. Do NOT default to Netlify for internal pages. |
|
|
37
92
|
| HTML artifact, external — founder-facing share link | Netlify | Only when the user explicitly says "share link", "give it to the founder", "publish publicly". Use the `netlify-access-guard` workflow (server-side password + edge 401 verification). |
|
|
38
|
-
| Insights, decisions, framework improvements | Wiki | `llama wiki save` (with attribution — see below) |
|
|
93
|
+
| Insights, decisions, framework improvements | Wiki (markdown) | `llama wiki save <slug> --content "..."` (with attribution — see below) |
|
|
94
|
+
| **HTML wiki entry — standalone HTML page hosted at `/wiki/<slug>`** (sector landscape, market map, dashboard, hand-styled thesis page) | **Wiki (HTML)** | `llama wiki save <slug> --title "..." --file <path.html> --sources "..."`. Auto-detects content_type=html from extension. Public page is full-viewport sandboxed iframe takeover (no wiki chrome). Sources/status/title still required; appears in `wiki search` + backlinks. Use when the user says "deploy this HTML to wiki", "wiki 词条", "make this page a wiki entry". HTML must be self-contained (inline CSS/JS, image data URIs or external URLs) — asset bundles aren't supported on wiki yet. |
|
|
39
95
|
| Large files (deck / PDF / transcript) | Drive deal folder | the deal's `folder_url` (from `llama deal show`) → upload via your filesystem / Drive tool |
|
|
40
96
|
| Cross-team mentions | Inbox + email | `llama post <dealId> "@<teammate> ..."` — server fires email + UI badge to the recipient |
|
|
41
97
|
|
|
@@ -138,7 +194,17 @@ llama html reset <dealId> [--doc <slug>] # soft-
|
|
|
138
194
|
|
|
139
195
|
# Wiki (knowledge base)
|
|
140
196
|
llama wiki search "<query>"
|
|
141
|
-
llama wiki
|
|
197
|
+
llama wiki read <slug> [--lang en|zh]
|
|
198
|
+
|
|
199
|
+
# Markdown entry (default):
|
|
200
|
+
llama wiki save <slug> --title "..." --content "..." --sources "url1;url2"
|
|
201
|
+
|
|
202
|
+
# HTML entry — standalone page at /wiki/<slug>, full-viewport sandboxed iframe:
|
|
203
|
+
llama wiki save <slug> --title "..." --file path.html --sources "..." [--content-type html]
|
|
204
|
+
# .html / .htm extension auto-implies content_type=html.
|
|
205
|
+
# --content-type html (or markdown) overrides the inference.
|
|
206
|
+
# Refuses to switch content_type on an existing slug; delete + re-create
|
|
207
|
+
# if you really mean to change format.
|
|
142
208
|
|
|
143
209
|
# Timeline + posts
|
|
144
210
|
llama timeline <dealId>
|
|
@@ -165,7 +231,7 @@ Tools available:
|
|
|
165
231
|
- `auth_status` — verify creds + identity (call first if anything 401s)
|
|
166
232
|
- `deal_search` / `deal_show` / `deal_create` / `deal_update`
|
|
167
233
|
- `brief_blocks` / `brief_add_text` / `brief_add_link` / `brief_add_callout`
|
|
168
|
-
- `wiki_search` / `wiki_save`
|
|
234
|
+
- `wiki_search` / `wiki_save` (accepts `content_type: 'markdown' | 'html'` — HTML entries render as full-viewport sandboxed iframe at `/wiki/<slug>`)
|
|
169
235
|
- `timeline` / `post`
|
|
170
236
|
- `mentions_list`
|
|
171
237
|
- `pitch_start` / `pitch_send_message` / `pitch_upload_file` / `pitch_status` / `pitch_finalize` — public intake (no Llama token needed; for founders / EAs / external agents)
|
package/bin/llama-mcp.mjs
CHANGED
|
@@ -328,24 +328,56 @@ server.registerTool(
|
|
|
328
328
|
"wiki_save",
|
|
329
329
|
{
|
|
330
330
|
description:
|
|
331
|
-
"Create or update a wiki page
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
"
|
|
331
|
+
"Create or update a wiki page — Llama's CROSS-DEAL / institutional " +
|
|
332
|
+
"knowledge surface (sector landscape · market map · thesis · framework · " +
|
|
333
|
+
"methodology · anything not tied to ONE specific deal). Renders at " +
|
|
334
|
+
"/wiki/<slug>. " +
|
|
335
|
+
"**Routing — decide BEFORE calling:** " +
|
|
336
|
+
"(a) Deal-specific HTML (IC memo for X, dashboard for X) → use " +
|
|
337
|
+
"`html_upload` instead, NOT this. " +
|
|
338
|
+
"(b) Cross-deal / institutional (this tool) → /wiki/<slug>. " +
|
|
339
|
+
"(c) Founder-facing public share → Netlify only when user explicitly " +
|
|
340
|
+
"says so; Llama Command outranks Netlify for everything internal. " +
|
|
341
|
+
"By default `content` is markdown with attribution blocks " +
|
|
342
|
+
"(**[Name · YYYY-MM-DD · source · fact|opinion]**) for traceability. " +
|
|
343
|
+
"Set `content_type: 'html'` to deploy a standalone HTML page as the " +
|
|
344
|
+
"wiki entry (full-viewport sandboxed iframe takeover on /wiki/<slug>; " +
|
|
345
|
+
"the HTML itself is the page — no wiki chrome). `sources` is a " +
|
|
346
|
+
"separate citation list (URLs, doc names, or meeting references) — " +
|
|
347
|
+
"at least one required; URLs inside `content` do not count. For HTML " +
|
|
348
|
+
"asset bundles use the `llama wiki save --file ... --assets ...` CLI " +
|
|
349
|
+
"path; MCP only supports single-file HTML.",
|
|
335
350
|
inputSchema: {
|
|
336
351
|
slug: z.string().describe("kebab-case slug"),
|
|
337
352
|
title: z.string(),
|
|
338
|
-
content: z
|
|
353
|
+
content: z
|
|
354
|
+
.string()
|
|
355
|
+
.describe(
|
|
356
|
+
"body — markdown source by default, or raw HTML when content_type='html'"
|
|
357
|
+
),
|
|
339
358
|
sources: z
|
|
340
359
|
.array(z.string())
|
|
341
360
|
.min(1)
|
|
342
361
|
.describe(
|
|
343
362
|
"citation list — URLs, doc names, or meeting references. At least one required."
|
|
344
363
|
),
|
|
364
|
+
content_type: z
|
|
365
|
+
.enum(["markdown", "html"])
|
|
366
|
+
.optional()
|
|
367
|
+
.describe(
|
|
368
|
+
"'markdown' (default) renders via the wiki markdown pipeline. " +
|
|
369
|
+
"'html' stores the body as a standalone HTML page (sandboxed iframe)."
|
|
370
|
+
),
|
|
345
371
|
},
|
|
346
372
|
},
|
|
347
|
-
async ({ slug, title, content, sources }) =>
|
|
348
|
-
callApi("POST", "/api/wiki/save", {
|
|
373
|
+
async ({ slug, title, content, sources, content_type }) =>
|
|
374
|
+
callApi("POST", "/api/wiki/save", {
|
|
375
|
+
slug,
|
|
376
|
+
title,
|
|
377
|
+
content,
|
|
378
|
+
sources,
|
|
379
|
+
...(content_type ? { content_type } : {}),
|
|
380
|
+
})
|
|
349
381
|
);
|
|
350
382
|
|
|
351
383
|
// ============================================================
|
|
@@ -707,7 +739,16 @@ server.registerTool(
|
|
|
707
739
|
"html_upload",
|
|
708
740
|
{
|
|
709
741
|
description:
|
|
710
|
-
"Upload (PUT) a new HTML version for a
|
|
742
|
+
"Upload (PUT) a new HTML version for a SPECIFIC DEAL's /browse page " +
|
|
743
|
+
"(deal-scoped artifact: IC memo for X · dashboard for X · 2×2 for X). " +
|
|
744
|
+
"Renders at /deals/<id>/browse/<slug>. " +
|
|
745
|
+
"**Routing — pick the right destination BEFORE calling this:** " +
|
|
746
|
+
"(a) Deal-specific HTML (this tool) → /deals/<id>/browse/<slug>. " +
|
|
747
|
+
"(b) Cross-deal / institutional / thesis / sector landscape → use " +
|
|
748
|
+
"`wiki_save` with content_type='html' instead (/wiki/<slug>). " +
|
|
749
|
+
"(c) Founder-facing public share link → escape to Netlify only when " +
|
|
750
|
+
"the user explicitly says 'share with founder' / 'publish publicly'; " +
|
|
751
|
+
"Llama Command outranks Netlify for everything internal. " +
|
|
711
752
|
"Creates a NEW version row — the previous version is retained " +
|
|
712
753
|
"and restorable. Triggers SSE push so any open viewer auto- " +
|
|
713
754
|
"refreshes. Constraints: HTML body MUST start with " +
|
package/bin/llama.mjs
CHANGED
|
@@ -324,10 +324,25 @@ Mentions / Inbox:
|
|
|
324
324
|
llama mentions resolve <mentionId> # mark thread resolved (idempotent)
|
|
325
325
|
llama mentions unread # just the badge count
|
|
326
326
|
|
|
327
|
+
Where does this HTML / thesis / artifact go?
|
|
328
|
+
About ONE specific deal? ........ llama html upload <dealId> --new --title "..." --file <path>
|
|
329
|
+
(renders at /deals/<id>/browse/<slug>; see "Deal page HTML" below)
|
|
330
|
+
Cross-deal / institutional? ..... llama wiki save <slug> --title "..." --file <path>.html --sources "..."
|
|
331
|
+
(renders at /wiki/<slug>; see "Wiki" below)
|
|
332
|
+
Founder-facing public share? .... Netlify (with netlify-access-guard skill), only when user explicitly
|
|
333
|
+
says "share publicly". Llama Command outranks Netlify for everything
|
|
334
|
+
internal — don't reach for Netlify by default.
|
|
335
|
+
|
|
327
336
|
Wiki:
|
|
328
337
|
llama wiki search <query>
|
|
329
338
|
llama wiki read <slug>
|
|
330
|
-
|
|
339
|
+
Markdown entry (default):
|
|
340
|
+
llama wiki save <slug> --title "..." --content "..." --sources "url1;url2" [--type company] [--related "A;B"]
|
|
341
|
+
HTML entry — standalone HTML page at /wiki/<slug> (full-viewport sandboxed iframe):
|
|
342
|
+
llama wiki save <slug> --title "..." --file path.html --sources "..." [--content-type html]
|
|
343
|
+
(.html / .htm extension auto-implies content_type=html)
|
|
344
|
+
➜ Use Wiki when the artifact is NOT tied to one specific deal — sector landscape, market map,
|
|
345
|
+
thesis, framework, methodology. For deal-specific HTML use "llama html upload <dealId>" instead.
|
|
331
346
|
|
|
332
347
|
Memo (long-form HTML investment memo — Memo tab in the UI):
|
|
333
348
|
llama memo show <dealId> [--out <path>] [--json] # default: html → stdout (pipeable to file / browser)
|
|
@@ -336,6 +351,9 @@ Memo (long-form HTML investment memo — Memo tab in the UI):
|
|
|
336
351
|
llama memo reset <dealId> [--all] # default drops manual override; --all drops every version
|
|
337
352
|
|
|
338
353
|
Deal page HTML (hand-authored sandboxed pages on /deals/<id>/browse/<slug>):
|
|
354
|
+
➜ Use this for DEAL-SPECIFIC artifacts: IC memo for X, dashboard for X, 2×2 for X.
|
|
355
|
+
For cross-deal / institutional pages (sector landscape, market map, thesis) use
|
|
356
|
+
"llama wiki save <slug> --file ..." instead — see "Wiki" above.
|
|
339
357
|
Each deal can host many HTML artifacts (IC report, dashboard, market map, …).
|
|
340
358
|
Each one has a stable slug. UPLOAD must declare intent — update an existing
|
|
341
359
|
artifact or add a new one — to avoid silent overwrites.
|
|
@@ -1337,27 +1355,75 @@ https://command.llamaventures.vc/settings/tokens, run
|
|
|
1337
1355
|
}
|
|
1338
1356
|
|
|
1339
1357
|
// ----- Wiki: save (create or update) -----
|
|
1358
|
+
// Two body modes:
|
|
1359
|
+
// --content "..." inline markdown OR raw HTML (string)
|
|
1360
|
+
// --file <path> read body from a file; if .html/.htm,
|
|
1361
|
+
// content_type auto-detects to 'html'
|
|
1362
|
+
// --content-type <markdown|html> overrides auto-detect.
|
|
1363
|
+
// Refuses content_type mismatch on existing entries (server-side check;
|
|
1364
|
+
// CLI surfaces the server error verbatim).
|
|
1340
1365
|
if (area === "wiki" && action === "save") {
|
|
1341
1366
|
const { flags, positional } = parseFlags(rest);
|
|
1342
1367
|
const slug = positional[0];
|
|
1343
1368
|
const title = flags.title;
|
|
1344
|
-
const
|
|
1369
|
+
const inlineContent = flags.content;
|
|
1370
|
+
const filePath = flags.file;
|
|
1345
1371
|
const sourcesRaw = flags.sources;
|
|
1346
|
-
if (!slug || !title || !
|
|
1372
|
+
if (!slug || !title || !sourcesRaw || (!inlineContent && !filePath)) {
|
|
1347
1373
|
throw new Error(
|
|
1348
|
-
`Usage:
|
|
1374
|
+
`Usage:
|
|
1375
|
+
llama wiki save <slug> --title "..." --content "..." --sources "url1;url2" [--type company] [--related "A;B"] [--lang en|zh] [--content-type markdown|html]
|
|
1376
|
+
or
|
|
1377
|
+
llama wiki save <slug> --title "..." --file path/to/article.{md,html} --sources "url1;url2" [--type company] [--related "A;B"] [--lang en|zh] [--content-type markdown|html]
|
|
1378
|
+
|
|
1379
|
+
Pass either --content (inline) or --file (read from disk). With --file, content_type auto-detects from extension (.html/.htm → html, else markdown). Use --content-type to override.
|
|
1380
|
+
|
|
1381
|
+
Routing — is this the right command?
|
|
1382
|
+
✓ Cross-deal / institutional knowledge (sector landscape, market map, thesis, framework, methodology)
|
|
1383
|
+
→ YES, you're in the right place.
|
|
1384
|
+
✗ Deal-specific HTML (IC memo for X, dashboard for X, 2×2 for one company)
|
|
1385
|
+
→ use \`llama html upload <dealId> --new --title "..." --file <path>\` instead.
|
|
1386
|
+
✗ Founder-facing public share link
|
|
1387
|
+
→ escape to Netlify only when the user explicitly says "share publicly" / "give it to the founder";
|
|
1388
|
+
Llama Command outranks Netlify for everything internal.`
|
|
1349
1389
|
);
|
|
1350
1390
|
}
|
|
1391
|
+
if (inlineContent && filePath) {
|
|
1392
|
+
throw new Error("Pass either --content OR --file, not both.");
|
|
1393
|
+
}
|
|
1394
|
+
// Read body — either inline or from file.
|
|
1395
|
+
let body;
|
|
1396
|
+
let inferredType = "markdown";
|
|
1397
|
+
if (filePath) {
|
|
1398
|
+
const { readFileSync } = await import("fs");
|
|
1399
|
+
body = readFileSync(String(filePath), "utf-8");
|
|
1400
|
+
const lower = String(filePath).toLowerCase();
|
|
1401
|
+
if (lower.endsWith(".html") || lower.endsWith(".htm")) {
|
|
1402
|
+
inferredType = "html";
|
|
1403
|
+
}
|
|
1404
|
+
} else {
|
|
1405
|
+
body = String(inlineContent);
|
|
1406
|
+
}
|
|
1407
|
+
// Determine content_type: explicit flag wins over file-extension inference.
|
|
1408
|
+
let contentType = inferredType;
|
|
1409
|
+
if (flags["content-type"]) {
|
|
1410
|
+
const v = String(flags["content-type"]).toLowerCase();
|
|
1411
|
+
if (v !== "markdown" && v !== "html") {
|
|
1412
|
+
throw new Error(`--content-type must be 'markdown' or 'html', got "${v}"`);
|
|
1413
|
+
}
|
|
1414
|
+
contentType = v;
|
|
1415
|
+
}
|
|
1351
1416
|
const splitCsv = (v) => String(v).split(/[;|]/).map((s) => s.trim()).filter(Boolean);
|
|
1352
1417
|
const payload = {
|
|
1353
1418
|
slug,
|
|
1354
1419
|
title: String(title),
|
|
1355
|
-
content:
|
|
1420
|
+
content: body,
|
|
1356
1421
|
sources: splitCsv(sourcesRaw),
|
|
1357
1422
|
type: flags.type ? String(flags.type) : undefined,
|
|
1358
1423
|
related: flags.related ? splitCsv(flags.related) : undefined,
|
|
1359
1424
|
lang: flags.lang === "zh" ? "zh" : "en",
|
|
1360
1425
|
status: flags.status ? String(flags.status) : undefined,
|
|
1426
|
+
content_type: contentType,
|
|
1361
1427
|
};
|
|
1362
1428
|
print(await request("POST", "/api/wiki/save", payload));
|
|
1363
1429
|
return;
|
|
@@ -2052,7 +2118,18 @@ https://command.llamaventures.vc/settings/tokens, run
|
|
|
2052
2118
|
"\n" +
|
|
2053
2119
|
"Default (no --doc, no --new) targets slug 'main' but REFUSES if 'main'\n" +
|
|
2054
2120
|
"already has content — pass --doc main to update it explicitly, or\n" +
|
|
2055
|
-
"--new --title \"...\" to add a NEW artifact alongside
|
|
2121
|
+
"--new --title \"...\" to add a NEW artifact alongside.\n" +
|
|
2122
|
+
"\n" +
|
|
2123
|
+
"Routing — is this the right command?\n" +
|
|
2124
|
+
" ✓ DEAL-specific HTML (IC memo for X, dashboard for X, 2×2 for X)\n" +
|
|
2125
|
+
" → YES, you're in the right place. Pass <dealId> + --new / --doc.\n" +
|
|
2126
|
+
" ✗ Cross-deal / institutional knowledge (sector landscape, market map,\n" +
|
|
2127
|
+
" thesis, framework, methodology, anything not tied to one company)\n" +
|
|
2128
|
+
" → use `llama wiki save <slug> --title \"...\" --file <path>.html --sources \"...\"`\n" +
|
|
2129
|
+
" instead (renders at /wiki/<slug>).\n" +
|
|
2130
|
+
" ✗ Founder-facing public share link\n" +
|
|
2131
|
+
" → escape to Netlify only when the user explicitly says \"share publicly\";\n" +
|
|
2132
|
+
" Llama Command outranks Netlify for everything internal.",
|
|
2056
2133
|
);
|
|
2057
2134
|
}
|
|
2058
2135
|
const knownFlags = [
|