@llamaventures/cli 1.8.0 → 1.9.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 +23 -2
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/llama.mjs +27 -4
- package/lib/client.mjs +1 -1
- package/lib/version-check.mjs +118 -0
- package/package.json +5 -5
package/AGENT_BRIEFING.md
CHANGED
|
@@ -11,6 +11,15 @@ You are not just an AI assistant. You're an **extension of a team member** — w
|
|
|
11
11
|
- **Be direct, terse, action-oriented.** Save your words for the genuine judgment calls.
|
|
12
12
|
- **Critical when thinking, helpful when executing.** Push back on weak logic, then ship the work cleanly.
|
|
13
13
|
|
|
14
|
+
## Onboard the human (teach as you go)
|
|
15
|
+
|
|
16
|
+
Most teammates don't know everything this CLI can do. Part of your job is to surface capabilities — without turning into a feature brochure.
|
|
17
|
+
|
|
18
|
+
- **First substantive interaction:** in one or two lines, point at the 2-3 capabilities most relevant to what they're doing right now, then do the work. Don't dump the whole command surface. (Examples by intent: someone pasting deal info → "I'll split that into facts vs notes and file it"; someone with a write-up → the artifact decision tree below; someone exploring → `llama deal search` / `llama deal feed`.)
|
|
19
|
+
- **Teach in context, one line at a time.** When they do something that touches a feature they may not know, mention it once — e.g. after filing a fact: "Filed. `llama deal feed <id>` shows everything the team's added on this deal." Never more than one such aside per turn.
|
|
20
|
+
- **Point at `llama --help`** for the full surface rather than reciting it. The CLI uses progressive help: `llama --help` is a short overview, `llama <area> --help` drills in.
|
|
21
|
+
- **Stay current.** If you suspect the CLI is stale, run `llama version --check`; if it reports an upgrade, tell the user the one-line `npm i -g @llamaventures/cli@latest` command. Don't nag repeatedly.
|
|
22
|
+
|
|
14
23
|
## Pipeline First (hard rule)
|
|
15
24
|
|
|
16
25
|
Any time the user mentions a company name or founder name:
|
|
@@ -95,6 +104,18 @@ HTML / thesis / artifact in hand
|
|
|
95
104
|
|
|
96
105
|
**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."
|
|
97
106
|
|
|
107
|
+
### Adding content to ONE deal — fact vs post vs brief (the #1 mis-route)
|
|
108
|
+
|
|
109
|
+
These three look similar but land in different surfaces. Don't infer from the command name — pick by intent:
|
|
110
|
+
|
|
111
|
+
| You want to… | Command | Lands in |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| Record a **sourced, verifiable fact** | `llama deal fact add <dealId> --category <cat> --claim "…" --source <url>` | Facts → deal **Feed** (FACT card) + citable in the **Memo** |
|
|
114
|
+
| Leave a **comment / opinion / question / reaction** for the team | `llama post <dealId> "…"` (`@name` to notify) | Posts → deal **Feed** (POST card); `@mention` fires email + UI badge |
|
|
115
|
+
| Write **narrative that belongs in the IC memo** | `llama brief add-text <dealId> --heading "…" --body "…"` | Brief blocks → **Memo tab only — NOT in the Feed** |
|
|
116
|
+
|
|
117
|
+
⚠️ The trap: `brief add-text` is **not** visible in the Activity Feed. If the team should see it in the feed, use `llama post`. If it's a claim that needs a source + verification, use `llama deal fact add`. (It's `deal fact add`, not `fact-add`.)
|
|
118
|
+
|
|
98
119
|
The table below details the exact CLI for each destination.
|
|
99
120
|
|
|
100
121
|
| Type | Destination | How |
|
|
@@ -104,7 +125,7 @@ The table below details the exact CLI for each destination.
|
|
|
104
125
|
| **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. |
|
|
105
126
|
| 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). |
|
|
106
127
|
| Insights, decisions, framework improvements | Wiki (markdown) | `llama wiki save <slug> --content "..."` (with attribution — see below) |
|
|
107
|
-
| **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. |
|
|
128
|
+
| **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. **Native comments + working in-page (#) anchor links are injected automatically** — readers discuss inline and the table of contents scrolls; you don't wire anything up (pages that already embed the comment widget are left as-is). |
|
|
108
129
|
| Large files (deck / PDF / transcript) | Drive deal folder | the deal's `folder_url` (from `llama deal show`) → upload via your filesystem / Drive tool |
|
|
109
130
|
| Cross-team mentions | Inbox + email | `llama post <dealId> "@<teammate> ..."` — server fires email + UI badge to the recipient |
|
|
110
131
|
|
|
@@ -293,7 +314,7 @@ the intake agent; relay the conversation, then surface the verdict.
|
|
|
293
314
|
- This file: `AGENT_BRIEFING.md` in the `@llamaventures/cli` npm package
|
|
294
315
|
- Re-printable any time: `llama agent-onboard`
|
|
295
316
|
- MCP prompt: `agent_briefing` from the `llama-mcp` server
|
|
296
|
-
- Public source: <https://github.com/
|
|
317
|
+
- Public source: <https://github.com/Llama-Ventures/llama-cli/blob/main/AGENT_BRIEFING.md>
|
|
297
318
|
|
|
298
319
|
You're now a Llama Ventures teammate (or an external agent helping a
|
|
299
320
|
founder pitch us). Welcome.
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
15
|
<a href="https://www.npmjs.com/package/@llamaventures/cli"><img alt="npm" src="https://img.shields.io/npm/v/@llamaventures/cli?label=npm&color=cb3837&logo=npm&logoColor=white"></a>
|
|
16
|
-
<a href="https://github.com/
|
|
16
|
+
<a href="https://github.com/Llama-Ventures/llama-cli/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Llama-Ventures/llama-cli/actions/workflows/ci.yml/badge.svg"></a>
|
|
17
17
|
<a href="https://docs.npmjs.com/trusted-publishers"><img alt="Provenance" src="https://img.shields.io/badge/provenance-signed-2e8b57?logo=npm"></a>
|
|
18
18
|
<a href="https://nodejs.org/"><img alt="Node" src="https://img.shields.io/node/v/@llamaventures/cli?color=339933&logo=nodedotjs&logoColor=white"></a>
|
|
19
19
|
<a href="https://modelcontextprotocol.io"><img alt="MCP 2024-11-05" src="https://img.shields.io/badge/MCP-2024--11--05-7d3aed"></a>
|
package/README.zh-CN.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
15
|
<a href="https://www.npmjs.com/package/@llamaventures/cli"><img alt="npm" src="https://img.shields.io/npm/v/@llamaventures/cli?label=npm&color=cb3837&logo=npm&logoColor=white"></a>
|
|
16
|
-
<a href="https://github.com/
|
|
16
|
+
<a href="https://github.com/Llama-Ventures/llama-cli/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Llama-Ventures/llama-cli/actions/workflows/ci.yml/badge.svg"></a>
|
|
17
17
|
<a href="https://docs.npmjs.com/trusted-publishers"><img alt="Provenance" src="https://img.shields.io/badge/provenance-signed-2e8b57?logo=npm"></a>
|
|
18
18
|
<a href="https://nodejs.org/"><img alt="Node" src="https://img.shields.io/node/v/@llamaventures/cli?color=339933&logo=nodedotjs&logoColor=white"></a>
|
|
19
19
|
<a href="https://modelcontextprotocol.io"><img alt="MCP 2024-11-05" src="https://img.shields.io/badge/MCP-2024--11--05-7d3aed"></a>
|
package/bin/llama.mjs
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
} from "../lib/external.mjs";
|
|
31
31
|
import { LLAMA_CLI_CLIENT_ID, pkceLoopbackFlow, revokeToken as revokeOAuthToken } from "../lib/oauth-flow.mjs";
|
|
32
32
|
import { deleteBundle, detectBackend, readBundle, writeBundle } from "../lib/oauth-storage.mjs";
|
|
33
|
+
import { maybeNudgeUpdate, getUpdateNudge } from "../lib/version-check.mjs";
|
|
33
34
|
|
|
34
35
|
function parseFlags(args, knownFlags = null) {
|
|
35
36
|
const flags = {};
|
|
@@ -348,6 +349,7 @@ Wiki:
|
|
|
348
349
|
HTML entry — standalone HTML page at /wiki/<slug> (full-viewport sandboxed iframe):
|
|
349
350
|
llama wiki save <slug> --title "..." --file path.html --sources "..." [--content-type html]
|
|
350
351
|
(.html / .htm extension auto-implies content_type=html)
|
|
352
|
+
Native comments + working in-page (#) links are added automatically — just upload self-contained HTML.
|
|
351
353
|
➜ Use Wiki when the artifact is NOT tied to one specific deal — sector landscape, market map,
|
|
352
354
|
thesis, framework, methodology. For deal-specific HTML use "llama html upload <dealId>" instead.
|
|
353
355
|
Delete / restore (soft — reversible):
|
|
@@ -763,6 +765,14 @@ async function main() {
|
|
|
763
765
|
const { createRequire } = await import("module");
|
|
764
766
|
const requireFromHere = createRequire(import.meta.url);
|
|
765
767
|
const { version } = requireFromHere("../package.json");
|
|
768
|
+
// `llama version --check` — explicitly check npm for a newer release and
|
|
769
|
+
// print the upgrade line (or "up to date"). Lets an agent surface the
|
|
770
|
+
// nudge on demand, separate from the throttled, TTY-gated auto-nudge.
|
|
771
|
+
if (action === "--check" || action === "check") {
|
|
772
|
+
const nudge = await getUpdateNudge();
|
|
773
|
+
console.log(nudge || `llama CLI ${version} — up to date`);
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
766
776
|
console.log(version);
|
|
767
777
|
return;
|
|
768
778
|
}
|
|
@@ -775,6 +785,14 @@ async function main() {
|
|
|
775
785
|
usage(area);
|
|
776
786
|
return;
|
|
777
787
|
}
|
|
788
|
+
// `llama <area> <action> --help` (e.g. `brief add-text --help`). Without this
|
|
789
|
+
// short-circuit, "--help" falls through to the action handler, where rest[0]
|
|
790
|
+
// can be read as a positional (e.g. dealId="--help") and trigger a REAL write.
|
|
791
|
+
// Catch --help/-h anywhere in the sub-command args and print group help first.
|
|
792
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
793
|
+
usage(area);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
778
796
|
|
|
779
797
|
// `llama agent-onboard` — print the bundled AGENT_BRIEFING.md so an AI
|
|
780
798
|
// agent reads it once and internalises the Llama Ventures workflow
|
|
@@ -2633,7 +2651,12 @@ Routing — is this the right command?
|
|
|
2633
2651
|
process.exitCode = 1;
|
|
2634
2652
|
}
|
|
2635
2653
|
|
|
2636
|
-
main()
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2654
|
+
main()
|
|
2655
|
+
// Soft, throttled, TTY-gated update nudge. Runs AFTER the command's own
|
|
2656
|
+
// output and is awaited so the registry check completes before exit — but
|
|
2657
|
+
// it can never fail the command (all errors swallowed internally).
|
|
2658
|
+
.then(() => maybeNudgeUpdate())
|
|
2659
|
+
.catch((error) => {
|
|
2660
|
+
console.error(`Error: ${error.message}`);
|
|
2661
|
+
process.exit(1);
|
|
2662
|
+
});
|
package/lib/client.mjs
CHANGED
|
@@ -38,7 +38,7 @@ export function readBriefing() {
|
|
|
38
38
|
"AGENT_BRIEFING.md not found at " +
|
|
39
39
|
briefingPath +
|
|
40
40
|
". This shouldn't happen in a published @llamaventures/cli install — " +
|
|
41
|
-
"report at https://github.com/
|
|
41
|
+
"report at https://github.com/Llama-Ventures/llama-cli/issues."
|
|
42
42
|
);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Soft update nudge for @llamaventures/cli.
|
|
2
|
+
//
|
|
3
|
+
// Philosophy: minimal friction. We NEVER block a command and we NEVER spam.
|
|
4
|
+
// The npm registry is the source of truth for "latest published", so we
|
|
5
|
+
// query it directly — no llama-command changes, nothing to keep in sync.
|
|
6
|
+
//
|
|
7
|
+
// Friction controls, all of which must pass before we print anything:
|
|
8
|
+
// 1. TTY-gated — only nudge an interactive human (process.stdout.isTTY).
|
|
9
|
+
// MCP server / piped output / CI → silent, so agents and
|
|
10
|
+
// scripts never see noise that could corrupt parsed output.
|
|
11
|
+
// 2. Throttled — at most once per 24h, tracked by a timestamp file.
|
|
12
|
+
// 3. stderr only — the nudge never touches stdout, so `llama ... | jq` etc
|
|
13
|
+
// stay clean even in the rare case it does print.
|
|
14
|
+
// 4. Best-effort — every error path (offline, registry down, parse fail) is
|
|
15
|
+
// swallowed. A nudge must never break or delay a command.
|
|
16
|
+
|
|
17
|
+
import fs from "fs";
|
|
18
|
+
import path from "path";
|
|
19
|
+
import { createRequire } from "module";
|
|
20
|
+
import { TOKEN_DIR } from "./client.mjs";
|
|
21
|
+
|
|
22
|
+
const REGISTRY_URL = "https://registry.npmjs.org/@llamaventures/cli/latest";
|
|
23
|
+
const STAMP_FILE = path.join(TOKEN_DIR, ".update-check");
|
|
24
|
+
const THROTTLE_MS = 24 * 60 * 60 * 1000; // once per day
|
|
25
|
+
const FETCH_TIMEOUT_MS = 2000;
|
|
26
|
+
|
|
27
|
+
function installedVersion() {
|
|
28
|
+
try {
|
|
29
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
30
|
+
return requireFromHere("../package.json").version;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Compare two semver strings. Returns true if `latest` is strictly newer than
|
|
37
|
+
// `current`. Pre-release tags are ignored (we only ship plain x.y.z).
|
|
38
|
+
function isNewer(latest, current) {
|
|
39
|
+
const a = String(latest).split(".").map((n) => parseInt(n, 10));
|
|
40
|
+
const b = String(current).split(".").map((n) => parseInt(n, 10));
|
|
41
|
+
for (let i = 0; i < 3; i++) {
|
|
42
|
+
const x = a[i] || 0;
|
|
43
|
+
const y = b[i] || 0;
|
|
44
|
+
if (x > y) return true;
|
|
45
|
+
if (x < y) return false;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function checkedRecently() {
|
|
51
|
+
try {
|
|
52
|
+
const last = parseInt(fs.readFileSync(STAMP_FILE, "utf8").trim(), 10);
|
|
53
|
+
return Number.isFinite(last) && Date.now() - last < THROTTLE_MS;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function touchStamp() {
|
|
60
|
+
try {
|
|
61
|
+
fs.mkdirSync(TOKEN_DIR, { recursive: true, mode: 0o700 });
|
|
62
|
+
fs.writeFileSync(STAMP_FILE, `${Date.now()}\n`, { mode: 0o600 });
|
|
63
|
+
} catch {
|
|
64
|
+
// Best-effort. If we can't write the stamp we may nudge again tomorrow —
|
|
65
|
+
// harmless. Never throw.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function fetchLatest() {
|
|
70
|
+
const controller = new AbortController();
|
|
71
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
72
|
+
try {
|
|
73
|
+
// The /latest convenience endpoint returns full JSON under the default
|
|
74
|
+
// Accept. (The abbreviated "vnd.npm.install-v1+json" metadata type is only
|
|
75
|
+
// valid on the full packument endpoint — it 406s here.)
|
|
76
|
+
const res = await fetch(REGISTRY_URL, { signal: controller.signal });
|
|
77
|
+
if (!res.ok) return null;
|
|
78
|
+
const data = await res.json();
|
|
79
|
+
return typeof data?.version === "string" ? data.version : null;
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
} finally {
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Compute the nudge line without any side effects (no TTY/throttle gating).
|
|
89
|
+
* Returns the one-line string if an upgrade is available, else null. Used by
|
|
90
|
+
* the explicit `llama version --check` command so an agent can surface it.
|
|
91
|
+
*/
|
|
92
|
+
export async function getUpdateNudge() {
|
|
93
|
+
const current = installedVersion();
|
|
94
|
+
if (!current) return null;
|
|
95
|
+
const latest = await fetchLatest();
|
|
96
|
+
if (!latest || !isNewer(latest, current)) return null;
|
|
97
|
+
return `⬆ llama CLI ${current} → ${latest} available · npm i -g @llamaventures/cli@latest`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Fire-and-forget soft nudge for interactive humans. Safe to call without
|
|
102
|
+
* awaiting; resolves to true if it printed a nudge, false otherwise. Honors
|
|
103
|
+
* all four friction controls above. Set $LLAMA_NO_UPDATE_CHECK=1 to disable.
|
|
104
|
+
*/
|
|
105
|
+
export async function maybeNudgeUpdate() {
|
|
106
|
+
try {
|
|
107
|
+
if (process.env.LLAMA_NO_UPDATE_CHECK) return false;
|
|
108
|
+
if (!process.stdout.isTTY) return false; // humans only
|
|
109
|
+
if (checkedRecently()) return false;
|
|
110
|
+
touchStamp(); // stamp before the network call so a slow/failed check still throttles
|
|
111
|
+
const nudge = await getUpdateNudge();
|
|
112
|
+
if (!nudge) return false;
|
|
113
|
+
process.stderr.write(`${nudge}\n`);
|
|
114
|
+
return true;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llamaventures/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "CLI + MCP server for the Llama Ventures investment workbench (command.llamaventures.vc).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,13 +18,13 @@
|
|
|
18
18
|
"node": ">=18"
|
|
19
19
|
},
|
|
20
20
|
"license": "MIT",
|
|
21
|
-
"homepage": "https://github.com/
|
|
21
|
+
"homepage": "https://github.com/Llama-Ventures/llama-cli#readme",
|
|
22
22
|
"repository": {
|
|
23
23
|
"type": "git",
|
|
24
|
-
"url": "git+https://github.com/
|
|
24
|
+
"url": "git+https://github.com/Llama-Ventures/llama-cli.git"
|
|
25
25
|
},
|
|
26
26
|
"bugs": {
|
|
27
|
-
"url": "https://github.com/
|
|
27
|
+
"url": "https://github.com/Llama-Ventures/llama-cli/issues"
|
|
28
28
|
},
|
|
29
29
|
"keywords": [
|
|
30
30
|
"llama-ventures",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"anthropic"
|
|
40
40
|
],
|
|
41
41
|
"author": "Llama Ventures, Inc.",
|
|
42
|
-
"funding": "https://github.com/
|
|
42
|
+
"funding": "https://github.com/Llama-Ventures/llama-cli",
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|