@llamaventures/cli 1.11.0 → 1.13.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/bin/llama.mjs +146 -5
- package/package.json +1 -1
package/bin/llama.mjs
CHANGED
|
@@ -228,12 +228,18 @@ Deals:
|
|
|
228
228
|
llama deal feed <dealId> # every contribution (facts + notes), human-typed or assistant-drafted, newest first
|
|
229
229
|
llama deal update <dealId> <field> <value>
|
|
230
230
|
Writable fields: status, theirStage, stage, notes, dealOwner, source,
|
|
231
|
-
description, website, location, founders,
|
|
232
|
-
valuation,
|
|
231
|
+
description, website, location, founders, founderInfo, proposedAmount,
|
|
232
|
+
roundSize, valuation, deckLink, folderUrl, sector, subsector,
|
|
233
|
+
foundedYear, leadInvestor, investors, agentActive.
|
|
233
234
|
e.g. llama deal update <dealId> website https://acme.ai
|
|
234
235
|
llama deal update <dealId> sector "Developer Tools"
|
|
235
236
|
llama deal update <dealId> foundedYear 2024
|
|
236
237
|
llama deal update <dealId> leadInvestor "Acme Capital"
|
|
238
|
+
llama deal extra set <dealId> <key> <value> # system-admin only
|
|
239
|
+
Patch one top-level key in deals.extra JSONB. Value is parsed as
|
|
240
|
+
JSON when possible ('{"a":1}', 'true', '3'), else stored as a
|
|
241
|
+
string. Audited to deal_events as field_change "extra.<key>".
|
|
242
|
+
llama deal extra unset <dealId> <key> # delete the key (admin)
|
|
237
243
|
llama deal search <query> [--founder name] [--owner <user-key>] [--status Diligence]
|
|
238
244
|
[--theirStage Raising] [--stage Seed]
|
|
239
245
|
[--limit 200] [--offset 0]
|
|
@@ -375,6 +381,11 @@ Deal page HTML (hand-authored sandboxed pages on /deals/<id>/browse/<slug>):
|
|
|
375
381
|
llama html docs create <dealId> <slug> [--title "..."] # pre-create a slot
|
|
376
382
|
llama html docs archive <dealId> <slug> # soft-archive (browse hides)
|
|
377
383
|
|
|
384
|
+
Link a card to a wiki article (one file, multiple entrances — the wiki
|
|
385
|
+
stays canonical, the deal card is a live, read-only pointer):
|
|
386
|
+
llama html link <dealId> --wiki <slug> [--lang en|zh] [--title "..."]
|
|
387
|
+
llama html unlink <dealId> <slug> # revert to a normal self-hosted doc
|
|
388
|
+
|
|
378
389
|
Update an EXISTING artifact (slug must exist):
|
|
379
390
|
llama html upload <dealId> --doc <slug> --file <path> [--assets DIR]
|
|
380
391
|
|
|
@@ -1095,6 +1106,39 @@ https://command.llamaventures.vc/settings/tokens, run
|
|
|
1095
1106
|
return;
|
|
1096
1107
|
}
|
|
1097
1108
|
|
|
1109
|
+
// ----- deals.extra JSONB patches (system-admin only, server-gated) -----
|
|
1110
|
+
// Same endpoint as `deal update`, but `extraKey` instead of `field`.
|
|
1111
|
+
// Server patches one top-level key via jsonb_set and audits the change
|
|
1112
|
+
// to deal_events as field_change with field "extra.<key>". value=null
|
|
1113
|
+
// deletes the key.
|
|
1114
|
+
if (area === "deal" && action === "extra") {
|
|
1115
|
+
const sub = rest[0];
|
|
1116
|
+
const dealId = rest[1];
|
|
1117
|
+
const key = rest[2];
|
|
1118
|
+
if (sub === "set") {
|
|
1119
|
+
const raw = rest.slice(3).join(" ");
|
|
1120
|
+
if (!dealId || !key || !raw) {
|
|
1121
|
+
throw new Error(
|
|
1122
|
+
"Usage: llama deal extra set <dealId> <key> <value> (value parsed as JSON when possible, else stored as string)"
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
let value;
|
|
1126
|
+
try {
|
|
1127
|
+
value = JSON.parse(raw);
|
|
1128
|
+
} catch {
|
|
1129
|
+
value = raw;
|
|
1130
|
+
}
|
|
1131
|
+
print(await request("POST", "/api/deals/update", { dealId, extraKey: key, value }));
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
if (sub === "unset") {
|
|
1135
|
+
if (!dealId || !key) throw new Error("Usage: llama deal extra unset <dealId> <key>");
|
|
1136
|
+
print(await request("POST", "/api/deals/update", { dealId, extraKey: key, value: null }));
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
throw new Error("Usage: llama deal extra set|unset <dealId> <key> [value]");
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1098
1142
|
if (area === "deal" && action === "search") {
|
|
1099
1143
|
const { flags, positional } = parseFlags(rest);
|
|
1100
1144
|
const q = positional.join(" ").trim();
|
|
@@ -2132,6 +2176,27 @@ Routing — is this the right command?
|
|
|
2132
2176
|
return `/api/deals/${encodeURIComponent(dealId)}/documents/${encodeURIComponent(slug)}/html`;
|
|
2133
2177
|
}
|
|
2134
2178
|
|
|
2179
|
+
// Surface a clean `linked_wiki` field on linked docs so the listing
|
|
2180
|
+
// reads as "this card points at wiki/<slug>" rather than exposing the
|
|
2181
|
+
// raw source_wiki_* columns. Non-linked docs are returned unchanged.
|
|
2182
|
+
function withLinkedWiki(data) {
|
|
2183
|
+
if (!data || !Array.isArray(data.documents)) return data;
|
|
2184
|
+
return {
|
|
2185
|
+
...data,
|
|
2186
|
+
documents: data.documents.map((d) =>
|
|
2187
|
+
d && d.source_wiki_slug
|
|
2188
|
+
? {
|
|
2189
|
+
...d,
|
|
2190
|
+
linked_wiki: {
|
|
2191
|
+
slug: d.source_wiki_slug,
|
|
2192
|
+
lang: d.source_wiki_lang || "en",
|
|
2193
|
+
},
|
|
2194
|
+
}
|
|
2195
|
+
: d,
|
|
2196
|
+
),
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2135
2200
|
// docs — list / create / archive documents on a deal.
|
|
2136
2201
|
//
|
|
2137
2202
|
// Forms:
|
|
@@ -2159,7 +2224,7 @@ Routing — is this the right command?
|
|
|
2159
2224
|
"GET",
|
|
2160
2225
|
`/api/deals/${encodeURIComponent(dealId)}/documents`,
|
|
2161
2226
|
);
|
|
2162
|
-
print(data);
|
|
2227
|
+
print(withLinkedWiki(data));
|
|
2163
2228
|
return;
|
|
2164
2229
|
}
|
|
2165
2230
|
if (docSub === "list") {
|
|
@@ -2171,7 +2236,7 @@ Routing — is this the right command?
|
|
|
2171
2236
|
"GET",
|
|
2172
2237
|
`/api/deals/${encodeURIComponent(dealId)}/documents`,
|
|
2173
2238
|
);
|
|
2174
|
-
print(data);
|
|
2239
|
+
print(withLinkedWiki(data));
|
|
2175
2240
|
return;
|
|
2176
2241
|
}
|
|
2177
2242
|
if (docSub === "create") {
|
|
@@ -2210,6 +2275,82 @@ Routing — is this the right command?
|
|
|
2210
2275
|
);
|
|
2211
2276
|
}
|
|
2212
2277
|
|
|
2278
|
+
// link — turn a deal doc card into a live, read-only pointer to a wiki
|
|
2279
|
+
// HTML article. "One file, multiple entrances": the wiki stays the
|
|
2280
|
+
// canonical home, the card just renders the wiki's HTML. Edits go to
|
|
2281
|
+
// the wiki source; uploads to a linked slug are refused server-side.
|
|
2282
|
+
//
|
|
2283
|
+
// llama html link <dealId> --wiki <slug> [--lang en|zh] [--title "..."]
|
|
2284
|
+
//
|
|
2285
|
+
// Default deal-side slug = the wiki slug. Default title = the wiki
|
|
2286
|
+
// article's title (fetched from `llama wiki read`).
|
|
2287
|
+
if (sub === "link") {
|
|
2288
|
+
const dealId = rest[0];
|
|
2289
|
+
const { flags } = parseFlags(rest.slice(1), ["wiki", "lang", "title", "slug"]);
|
|
2290
|
+
const wikiSlug =
|
|
2291
|
+
typeof flags.wiki === "string" && flags.wiki.trim()
|
|
2292
|
+
? flags.wiki.trim()
|
|
2293
|
+
: null;
|
|
2294
|
+
if (!dealId || !wikiSlug) {
|
|
2295
|
+
throw new Error(
|
|
2296
|
+
"Usage: llama html link <dealId> --wiki <slug> [--lang en|zh] [--title \"...\"]",
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
const lang = flags.lang === "zh" ? "zh" : "en";
|
|
2300
|
+
// Deal-side slug defaults to the wiki slug; --slug overrides.
|
|
2301
|
+
const dealSlug =
|
|
2302
|
+
typeof flags.slug === "string" && flags.slug.trim()
|
|
2303
|
+
? flags.slug.trim()
|
|
2304
|
+
: wikiSlug;
|
|
2305
|
+
// Title defaults to the wiki article's title.
|
|
2306
|
+
let title =
|
|
2307
|
+
typeof flags.title === "string" && flags.title.trim()
|
|
2308
|
+
? flags.title.trim()
|
|
2309
|
+
: null;
|
|
2310
|
+
if (!title) {
|
|
2311
|
+
try {
|
|
2312
|
+
const article = await request(
|
|
2313
|
+
"GET",
|
|
2314
|
+
`/api/wiki/${encodeURIComponent(wikiSlug)}?lang=${lang}`,
|
|
2315
|
+
);
|
|
2316
|
+
title = article?.frontmatter?.title || wikiSlug;
|
|
2317
|
+
} catch {
|
|
2318
|
+
// Fall back to the slug as the title; the server still validates
|
|
2319
|
+
// that the wiki article exists + is HTML on the POST below.
|
|
2320
|
+
title = wikiSlug;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
const data = await request(
|
|
2324
|
+
"POST",
|
|
2325
|
+
`/api/deals/${encodeURIComponent(dealId)}/documents`,
|
|
2326
|
+
{
|
|
2327
|
+
slug: dealSlug,
|
|
2328
|
+
title,
|
|
2329
|
+
source_wiki_slug: wikiSlug,
|
|
2330
|
+
source_wiki_lang: lang,
|
|
2331
|
+
},
|
|
2332
|
+
);
|
|
2333
|
+
print(data);
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
// unlink — revert a linked card back to a normal self-hosted doc.
|
|
2338
|
+
// llama html unlink <dealId> <slug>
|
|
2339
|
+
if (sub === "unlink") {
|
|
2340
|
+
const dealId = rest[0];
|
|
2341
|
+
const slug = rest[1];
|
|
2342
|
+
if (!dealId || !slug) {
|
|
2343
|
+
throw new Error("Usage: llama html unlink <dealId> <slug>");
|
|
2344
|
+
}
|
|
2345
|
+
const data = await request(
|
|
2346
|
+
"PATCH",
|
|
2347
|
+
`/api/deals/${encodeURIComponent(dealId)}/documents/${encodeURIComponent(slug)}`,
|
|
2348
|
+
{ source_wiki_slug: null },
|
|
2349
|
+
);
|
|
2350
|
+
print(data);
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2213
2354
|
// show — fetch the current HTML. Default: print to stdout (pipeable).
|
|
2214
2355
|
if (sub === "show") {
|
|
2215
2356
|
const dealId = rest[0];
|
|
@@ -2648,7 +2789,7 @@ Routing — is this the right command?
|
|
|
2648
2789
|
}
|
|
2649
2790
|
|
|
2650
2791
|
throw new Error(
|
|
2651
|
-
`Unknown html subcommand "${sub || ""}". Use: docs / show / upload / versions / restore / reset.`,
|
|
2792
|
+
`Unknown html subcommand "${sub || ""}". Use: docs / link / unlink / show / upload / versions / restore / reset.`,
|
|
2652
2793
|
);
|
|
2653
2794
|
}
|
|
2654
2795
|
|