@llamaventures/cli 1.19.0 → 1.22.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 CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { createRequire } from "module";
4
4
  import { randomUUID } from "crypto";
5
+ import { readFile } from "fs/promises";
5
6
  import readline from "readline";
6
7
  import {
7
8
  DEFAULT_BASE_URL,
@@ -11,7 +12,6 @@ import {
11
12
  TOKEN_FILE,
12
13
  getAuthHeaders,
13
14
  getBaseUrl,
14
- getLastAgentEvent,
15
15
  getToken,
16
16
  print,
17
17
  readBriefing,
@@ -175,45 +175,6 @@ function slugifyTitle(title) {
175
175
  return slug;
176
176
  }
177
177
 
178
- function parseExpectedIds(raw) {
179
- const text = typeof raw === "string" ? raw : "";
180
- const expected = { dealIds: [], wikiSlugs: [], raw: [] };
181
- for (const item of text.split(",").map((s) => s.trim()).filter(Boolean)) {
182
- const [kind, ...rest] = item.split(":");
183
- const value = rest.join(":").trim();
184
- if (kind === "deal" && value) expected.dealIds.push(value);
185
- else if ((kind === "wiki" || kind === "slug") && value) expected.wikiSlugs.push(value);
186
- else expected.raw.push(item);
187
- }
188
- return expected;
189
- }
190
-
191
- async function submitEvalFeedback(action, flags, queryText = "") {
192
- const useLast = flags.last !== false;
193
- const last = useLast ? getLastAgentEvent() : null;
194
- const eventId =
195
- flags.event && flags.event !== true
196
- ? Number(flags.event)
197
- : last?.lastEventId ?? null;
198
- if ((action === "good" || action === "bad") && !eventId && !queryText) {
199
- throw new Error(`Usage: llama eval ${action} [--last] [--reason "..."]`);
200
- }
201
- const body = {
202
- action,
203
- eventId: Number.isFinite(eventId) ? eventId : undefined,
204
- query: queryText || undefined,
205
- surface: flags.surface && flags.surface !== true ? String(flags.surface) : last?.lastSurface ?? undefined,
206
- expected:
207
- flags.expect && flags.expect !== true
208
- ? parseExpectedIds(String(flags.expect))
209
- : {},
210
- reason: flags.reason && flags.reason !== true ? String(flags.reason) : undefined,
211
- privacyLevel:
212
- flags.privacy && flags.privacy !== true ? String(flags.privacy) : "internal",
213
- };
214
- return request("POST", "/api/agent/eval-feedback", body);
215
- }
216
-
217
178
  // Client-side fuzzy match — used as a fallback when the server hasn't yet
218
179
  // shipped the search/filter API (Fix B, 2026-04-25). Once the server
219
180
  // returns the `{deals,total,limit,offset}` envelope, this path is never
@@ -403,8 +364,8 @@ Agent onboarding (run once on first install):
403
364
  llama activity new-deals --since 24h # recent deal creations for agents
404
365
  llama activity updated-deals --since 7d # meaningful deal updates, grouped
405
366
  llama explain <url-or-object> # explain Command URL/object status + lifecycle
406
- llama eval good|bad --last # mark the latest CLI/MCP result for eval
407
- llama eval add "<query>" --expect wiki:<slug>|deal:<uuid>
367
+ llama pref list [--status proposed] # standing agent preferences (injected every turn)
368
+ llama pref add reply-style "Lead with the conclusion." [--team]
408
369
 
409
370
  External pitch — talk to Llama Ventures' intake agent (no token required):
410
371
  llama pitch start --name "Jane Doe" --email "jane@acme.ai"
@@ -496,16 +457,17 @@ Approvals (partner queue — self-claim approvals):
496
457
 
497
458
  Timeline / Posts:
498
459
  llama timeline <dealId> # full unified feed
499
- llama post <dealId> "message body" [--link url] [--link-name "name"]
460
+ llama post <dealId> "message body" [--link url] [--link-name "name"] [--cue]
461
+ # --cue only after explicit user approval
500
462
 
501
463
  Brief blocks:
502
464
  llama brief blocks <dealId> # list current block array
503
465
  llama brief block <dealId> <blockId> # fetch one block's body (manifest in 'llama deal show')
504
- llama brief add-text <dealId> --heading "..." --body "..."
505
- llama brief add-link <dealId> --url "..." --label "..." [--description "..."]
506
- llama brief add-embed <dealId> --url "..." [--label "..."]
507
- llama brief add-callout <dealId> --tone insight|info|warning|success --heading "..." --body "..."
508
- llama brief edit <dealId> <blockId> [--heading ...] [--body ...] [--url ...] [--label ...] [--tone ...]
466
+ llama brief add-text <dealId> --heading "..." --body "..." [--cue]
467
+ llama brief add-link <dealId> --url "..." --label "..." [--description "..."] [--cue]
468
+ llama brief add-embed <dealId> --url "..." [--label "..."] [--cue]
469
+ llama brief add-callout <dealId> --tone insight|info|warning|success --heading "..." --body "..." [--cue]
470
+ llama brief edit <dealId> <blockId> [--heading ...] [--body ...] [--url ...] [--label ...] [--tone ...] [--cue]
509
471
  [--source-section <key>] [--lock|--unlock] [--hide|--unhide]
510
472
  llama brief delete <dealId> <blockId>
511
473
  llama brief history <dealId> <blockId> [--limit 50] # prior versions of this block (newest first)
@@ -514,7 +476,7 @@ Brief blocks:
514
476
 
515
477
  Common flags on every add-*:
516
478
  --source-section <key> Target a structured section (team, highlights, recommendation,
517
- <persona>_analysis, ...). Without this, blocks land in "_other"
479
+ landscape_map, competitors). Without this, blocks land in "_other"
518
480
  at the bottom of the TOC. AI writers want this.
519
481
  --reply-to <blockId> Make the block a reply to <blockId>. Snapshots parent's heading
520
482
  + 200-char excerpt into meta so the back-link survives parent
@@ -523,10 +485,9 @@ Brief blocks:
523
485
  2026-05-03). Use bottom for batched writes that need to
524
486
  preserve insertion order.
525
487
 
526
- Brief / persona refresh + agent-run revert:
488
+ Brief refresh + agent-run revert:
527
489
  llama deal refresh-brief <dealId> [--force] # re-eval stale sections
528
490
  # --force = every unlocked watcher-managed section
529
- llama deal refresh-persona <dealId> <persona-key> # server validates persona key
530
491
  llama deal revert-run <dealId> <runId> --section <key> # legacy 4-section model only
531
492
  # section: company|team|highlights|recommendation
532
493
 
@@ -536,17 +497,13 @@ Deal soft-delete / restore / trash list:
536
497
  llama deal trash # list deleted deals
537
498
 
538
499
  Deal facts (AI-extracted or human-asserted, with verification):
500
+ llama deal ingest <dealId> --file <packet.json> [--idempotency-key <key>] # atomic facts + optional Feed note
501
+ packet: {"source":{"kind":"meeting_note","title":"Office visit"},"facts":[{"category":"team","claim":"..."}],"note":"..."}
502
+ categories: company_basics | team | product | market | financials | fundraise | risk | milestone | meta
539
503
  llama deal fact list <dealId>
540
504
  llama deal fact add <dealId> --category <cat> --claim "<text>" [--source "..."] [--source-url <url>] [--confidence high|medium|low] [--attested]
541
505
  llama deal fact verify <dealId> <factId> --status confirmed|disputed [--corrected-value "..."]
542
506
 
543
- Skill corrections (persona-owner pushback — read by persona-watcher):
544
- llama skill-correction list <skill-slug> [--include-deleted]
545
- llama skill-correction add <skill-slug> "<correction text>" [--deal <uuid>] [--block <blockId>]
546
- llama skill-correction delete <id>
547
- Server enforces persona owner OR system admin on POST/DELETE; GET is open.
548
- External personas (owner_email=null) are admin-only for write.
549
-
550
507
  Mentions / Inbox:
551
508
  llama mentions # default: my unresolved cues
552
509
  llama mentions list [--everyone] [--all] # --everyone = team-wide; --all = include resolved
@@ -663,7 +620,6 @@ Common:
663
620
  llama agent bootstrap live Llama OS skill manifest from Command
664
621
  llama skills search "<query>" discover which skill to read
665
622
  llama explain <url-or-object> explain Command URLs, 404s, deleted objects
666
- llama eval bad --last mark latest CLI/MCP result as an eval candidate
667
623
 
668
624
  Command groups — run \`llama help <group>\` for that group's commands:
669
625
  deal create · show · feed · update · enrich · search · collaborators · links · delete
@@ -672,7 +628,7 @@ Command groups — run \`llama help <group>\` for that group's commands:
672
628
  facts deal facts + skill corrections (the sourced, trust-rated layer)
673
629
  timeline timeline · posts · mentions
674
630
  wiki cross-deal knowledge entries (markdown or HTML)
675
- eval mark real CLI/MCP searches good/bad or add a golden-query candidate
631
+ pref standing agent preferences: list · add · retire · approve
676
632
  memo long-form HTML investment memo
677
633
  html deal-specific HTML artifacts (/deals/<id>/browse/<slug>)
678
634
  pitch external founder intake (no token needed)
@@ -691,7 +647,7 @@ the CLI auto-detects it — no token needed (\`llc_\` tokens are a fallback).`;
691
647
  const HELP_AREA_MATCH = {
692
648
  deal: [/^Deals/, /^Collaborators/, /^Soft-delete/, /^Deal links/, /^Deal soft-delete/],
693
649
  activity: [/^Agent activity/],
694
- brief: [/^Brief blocks/, /^Brief \/ persona/],
650
+ brief: [/^Brief blocks/],
695
651
  facts: [/^Deal facts/, /^Skill corrections/],
696
652
  timeline: [/^Timeline/, /^Mentions/],
697
653
  wiki: [/^Wiki/, /^Where does this HTML/],
@@ -1164,6 +1120,49 @@ async function main() {
1164
1120
  throw new Error(`Unknown skills subcommand "${sub}". Use: list / search / show.`);
1165
1121
  }
1166
1122
 
1123
+ // `llama pref ...` — standing agent preferences (learning-domain v1).
1124
+ // Own user scope activates immediately; team scope needs a system admin.
1125
+ if (area === "pref" || area === "prefs" || area === "preferences") {
1126
+ const sub = action;
1127
+ if (!sub || sub === "list") {
1128
+ const { flags } = parseFlags(rest, ["json", "status"]);
1129
+ const params = new URLSearchParams();
1130
+ if (flags.status && flags.status !== true) params.set("status", String(flags.status));
1131
+ const result = await request("GET", `/api/agent/preferences${params.toString() ? `?${params}` : ""}`);
1132
+ print(result);
1133
+ return;
1134
+ }
1135
+ if (sub === "add") {
1136
+ const { flags, positional } = parseFlags(rest, ["team", "evidence", "json"]);
1137
+ const key = positional[0];
1138
+ const content = positional.slice(1).join(" ").trim();
1139
+ if (!key || !content) {
1140
+ throw new Error('Usage: llama pref add <key> "<content, max 280 chars>" [--team] [--evidence "..."]');
1141
+ }
1142
+ const result = await request("POST", "/api/agent/preferences", {
1143
+ scope: flags.team ? "team" : "user",
1144
+ key,
1145
+ content,
1146
+ evidence: flags.evidence && flags.evidence !== true ? String(flags.evidence) : undefined,
1147
+ });
1148
+ print(result);
1149
+ return;
1150
+ }
1151
+ if (sub === "retire" || sub === "approve") {
1152
+ const { positional } = parseFlags(rest, ["json"]);
1153
+ const id = Number(positional[0]);
1154
+ if (!Number.isInteger(id) || id <= 0) {
1155
+ throw new Error(`Usage: llama pref ${sub} <id>`);
1156
+ }
1157
+ const result = await request("PATCH", `/api/agent/preferences/${id}`, {
1158
+ status: sub === "approve" ? "active" : "retired",
1159
+ });
1160
+ print(result);
1161
+ return;
1162
+ }
1163
+ throw new Error(`Unknown pref subcommand "${sub}". Use: list / add / retire / approve.`);
1164
+ }
1165
+
1167
1166
  if (area === "explain" || (area === "agent" && action === "explain")) {
1168
1167
  const args = area === "explain" ? [action, ...rest].filter(Boolean) : rest;
1169
1168
  const { flags, positional } = parseFlags(args, ["json", "type", "id", "lang"]);
@@ -1201,43 +1200,6 @@ async function main() {
1201
1200
  return;
1202
1201
  }
1203
1202
 
1204
- if (area === "eval") {
1205
- const sub = action;
1206
- if (sub === "good" || sub === "bad") {
1207
- const { flags, positional } = parseFlags(rest, [
1208
- "last",
1209
- "event",
1210
- "reason",
1211
- "expect",
1212
- "surface",
1213
- "privacy",
1214
- ]);
1215
- const q = positional.join(" ").trim();
1216
- print(await submitEvalFeedback(sub, flags, q));
1217
- return;
1218
- }
1219
- if (sub === "add") {
1220
- const { flags, positional } = parseFlags(rest, [
1221
- "event",
1222
- "expect",
1223
- "reason",
1224
- "surface",
1225
- "privacy",
1226
- ]);
1227
- const q = positional.join(" ").trim();
1228
- if (!q && !flags.event) {
1229
- throw new Error(
1230
- `Usage: llama eval add "<query>" --surface deal|wiki --expect wiki:<slug>|deal:<uuid>`,
1231
- );
1232
- }
1233
- print(await submitEvalFeedback("add", flags, q));
1234
- return;
1235
- }
1236
- throw new Error(
1237
- "Usage: llama eval good|bad [--last] [--reason ...] OR llama eval add \"<query>\" --expect wiki:<slug>|deal:<uuid>",
1238
- );
1239
- }
1240
-
1241
1203
  // `llama pitch ...` — external founder-pitch family. No Llama token
1242
1204
  // required; bootstraps a session against /api/external/* via PoW + cookie.
1243
1205
  // See lib/external.mjs and AGENT_BRIEFING.md for the full surface.
@@ -1763,6 +1725,36 @@ async function main() {
1763
1725
  return;
1764
1726
  }
1765
1727
 
1728
+ // ----- Canonical source-packet ingest (atomic facts + optional Feed note) -----
1729
+ if (area === "deal" && action === "ingest") {
1730
+ const dealId = rest[0];
1731
+ const { flags } = parseFlags(rest.slice(1), ["file", "idempotency-key"]);
1732
+ if (!dealId || !flags.file || flags.file === true) {
1733
+ throw new Error(
1734
+ "Usage: llama deal ingest <dealId> --file <packet.json> [--idempotency-key <key>]\n" +
1735
+ 'Packet: {"source":{"kind":"meeting_note","title":"Office visit"},' +
1736
+ '"facts":[{"category":"team","claim":"..."}],"note":"..."}'
1737
+ );
1738
+ }
1739
+
1740
+ let packet;
1741
+ try {
1742
+ packet = JSON.parse(await readFile(String(flags.file), "utf8"));
1743
+ } catch (error) {
1744
+ throw new Error(`Cannot read ingest packet ${flags.file}: ${error?.message ?? String(error)}`);
1745
+ }
1746
+ if (!packet || Array.isArray(packet) || typeof packet !== "object") {
1747
+ throw new Error("Ingest packet must be a JSON object");
1748
+ }
1749
+ if (flags["idempotency-key"] !== undefined && flags["idempotency-key"] !== true) {
1750
+ packet.idempotencyKey = String(flags["idempotency-key"]);
1751
+ }
1752
+
1753
+ // @core-api-operation POST /api/deals/{dealId}/ingest
1754
+ print(await request("POST", `/api/deals/${encodeURIComponent(dealId)}/ingest`, packet));
1755
+ return;
1756
+ }
1757
+
1766
1758
  // ----- Deal facts (AI-extracted or human-asserted, with verification) -----
1767
1759
  if (area === "deal" && action === "fact") {
1768
1760
  const sub = rest[0];
@@ -1839,24 +1831,6 @@ async function main() {
1839
1831
  return;
1840
1832
  }
1841
1833
 
1842
- // ----- Persona refresh: re-run a single persona-watcher -----
1843
- // Persona keys are validated server-side. Returns runId or null
1844
- // (debounced / deal inactive). Used by /admin and the per-block
1845
- // "重新生成" flow.
1846
- if (area === "deal" && action === "refresh-persona") {
1847
- const dealId = rest[0];
1848
- const persona = rest[1];
1849
- if (!dealId || !persona) {
1850
- throw new Error(`Usage: llama deal refresh-persona <dealId> <persona-key>`);
1851
- }
1852
- print(await request(
1853
- "POST",
1854
- `/api/deals/${encodeURIComponent(dealId)}/refresh-persona`,
1855
- { persona }
1856
- ));
1857
- return;
1858
- }
1859
-
1860
1834
  // ----- Agent-run revert (legacy 4-section brief model) -----
1861
1835
  // Reverts a single section to the `before` value snapshotted by the
1862
1836
  // watcher run. Does NOT re-fire the watcher (intentional: human action).
@@ -1961,7 +1935,7 @@ async function main() {
1961
1935
  const { flags, positional } = parseFlags(rest);
1962
1936
  const body = positional[0];
1963
1937
  if (!dealId || !body) {
1964
- throw new Error(`Usage: llama post <dealId> "message body" [--link url] [--link-name "name"]`);
1938
+ throw new Error(`Usage: llama post <dealId> "message body" [--link url] [--link-name "name"] [--cue]`);
1965
1939
  }
1966
1940
  const attachments = flags.link
1967
1941
  ? [{ url: String(flags.link), name: flags["link-name"] ? String(flags["link-name"]) : String(flags.link) }]
@@ -1969,7 +1943,7 @@ async function main() {
1969
1943
  print(await request(
1970
1944
  "POST",
1971
1945
  `/api/deals/${encodeURIComponent(dealId)}/posts`,
1972
- { body, attachments }
1946
+ { body, attachments, cue_authorized: flags.cue === true }
1973
1947
  ));
1974
1948
  return;
1975
1949
  }
@@ -2135,7 +2109,7 @@ Routing — is this the right command?
2135
2109
  const meta = { updated_at: new Date().toISOString(), updated_by: "cli", by_agent: false };
2136
2110
 
2137
2111
  // --source-section <key>: target a structured section (e.g. team /
2138
- // highlights / <persona>_analysis). Without this, blocks land in the
2112
+ // highlights / competitors). Without this, blocks land in the
2139
2113
  // "_other" group at the bottom of the TOC. AI writers want this
2140
2114
  // virtually always — without it they cannot contribute to existing
2141
2115
  // structured sections.
@@ -2195,7 +2169,10 @@ Routing — is this the right command?
2195
2169
  if (!cur) cur = await request("GET", `/api/deals/${encodeURIComponent(dealId)}/blocks`);
2196
2170
  const existing = cur.blocks ?? [];
2197
2171
  const next = position === "top" ? [block, ...existing] : [...existing, block];
2198
- print(await request("PUT", `/api/deals/${encodeURIComponent(dealId)}/blocks`, { blocks: next }));
2172
+ print(await request("PUT", `/api/deals/${encodeURIComponent(dealId)}/blocks`, {
2173
+ blocks: next,
2174
+ cue_authorized: flags.cue === true,
2175
+ }));
2199
2176
  console.log(`Created block ${id}`);
2200
2177
  return;
2201
2178
  }
@@ -2205,7 +2182,7 @@ Routing — is this the right command?
2205
2182
  const dealId = rest[0];
2206
2183
  const blockId = rest[1];
2207
2184
  if (!dealId || !blockId) {
2208
- throw new Error("Usage: llama brief edit <dealId> <blockId> [--heading ...] [--body ...] [--url ...] [--label ...] [--description ...] [--tone ...] [--source-section ...] [--lock|--unlock] [--hide|--unhide]");
2185
+ throw new Error("Usage: llama brief edit <dealId> <blockId> [--heading ...] [--body ...] [--url ...] [--label ...] [--description ...] [--tone ...] [--source-section ...] [--lock|--unlock] [--hide|--unhide] [--cue]");
2209
2186
  }
2210
2187
  const patch = {};
2211
2188
  for (const k of ["heading", "body", "url", "label", "description", "tone"]) {
@@ -2225,8 +2202,11 @@ Routing — is this the right command?
2225
2202
  metaPatch.sourceSection = String(flags["source-section"]);
2226
2203
  }
2227
2204
  if (Object.keys(metaPatch).length > 0) patch.meta = metaPatch;
2205
+ if (flags.cue === true) patch.cue_authorized = true;
2228
2206
 
2229
- if (Object.keys(patch).length === 0) throw new Error("at least one field flag required");
2207
+ if (Object.keys(patch).length === 0 || (Object.keys(patch).length === 1 && patch.cue_authorized === true)) {
2208
+ throw new Error("at least one field flag required");
2209
+ }
2230
2210
  print(await request("PATCH", `/api/deals/${encodeURIComponent(dealId)}/blocks/${encodeURIComponent(blockId)}`, patch));
2231
2211
  return;
2232
2212
  }
@@ -2379,63 +2359,6 @@ Routing — is this the right command?
2379
2359
  throw new Error(`Unknown mentions subcommand "${sub}". Use: list / show / resolve / unread.`);
2380
2360
  }
2381
2361
 
2382
- // ----- Skill corrections (persona-owner pushback workflow) -----
2383
- // Persona owners (or system admins) record long-term rules each
2384
- // persona-DD skill must obey. Read by the persona-watcher and prepended
2385
- // to the system prompt at run time. Soft-delete is non-cascading —
2386
- // deleting a row does NOT auto-fire watcher; the next natural run
2387
- // (manual / stale_re_eval) just stops including the deleted rule.
2388
- //
2389
- // Permissions enforced server-side: only the persona owner (per
2390
- // PERSONA_SKILLS in src/lib/persona-skills.ts) or a system admin can
2391
- // POST or DELETE. Anyone can GET. External personas (owner_email=null)
2392
- // are admin-only for write.
2393
- if (area === "skill-correction") {
2394
- const sub = action;
2395
-
2396
- if (sub === "list") {
2397
- const skillSlug = rest[0];
2398
- if (!skillSlug) {
2399
- throw new Error("Usage: llama skill-correction list <skill-slug> [--include-deleted]");
2400
- }
2401
- const { flags } = parseFlags(rest.slice(1));
2402
- const params = new URLSearchParams({ skill: skillSlug });
2403
- if (flags["include-deleted"]) params.set("include_deleted", "1");
2404
- print(await request("GET", `/api/skill-corrections?${params.toString()}`));
2405
- return;
2406
- }
2407
-
2408
- if (sub === "add") {
2409
- const { flags, positional } = parseFlags(rest);
2410
- const skillSlug = positional[0];
2411
- const correctionText = positional.slice(1).join(" ").trim();
2412
- if (!skillSlug || !correctionText) {
2413
- throw new Error(
2414
- `Usage: llama skill-correction add <skill-slug> "<correction text>" ` +
2415
- `[--deal <uuid>] [--block <blockId>]`
2416
- );
2417
- }
2418
- print(await request("POST", "/api/skill-corrections", {
2419
- skill_slug: skillSlug,
2420
- correction_text: correctionText,
2421
- triggered_in_deal_uuid: flags.deal ? String(flags.deal) : null,
2422
- triggered_in_block_id: flags.block ? String(flags.block) : null,
2423
- }));
2424
- return;
2425
- }
2426
-
2427
- if (sub === "delete") {
2428
- const id = rest[0];
2429
- if (!id) throw new Error("Usage: llama skill-correction delete <id>");
2430
- print(await request("DELETE", `/api/skill-corrections/${encodeURIComponent(id)}`));
2431
- return;
2432
- }
2433
-
2434
- throw new Error(
2435
- `Unknown skill-correction subcommand "${sub || ""}". Use: list / add / delete.`
2436
- );
2437
- }
2438
-
2439
2362
  // ----- Memo (long-form HTML investment memo) -----
2440
2363
  // The Memo tab in the deal page renders HTML stored in deal_memos.
2441
2364
  // Two sources of memo content:
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "format": "llama.core-api-contract.v1",
3
3
  "name": "llama-core-api",
4
- "apiVersion": "1.0.1",
4
+ "apiVersion": "3.5.0",
5
5
  "openapiVersion": "3.0.3",
6
- "sha256": "95ce3639aeee15b0fed09830116838f2a11fd2e40e4f35bf80d785664ecf8d96",
7
- "pathCount": 211,
8
- "operationCount": 273
6
+ "sha256": "31c7d23ee06bd4282aa2451698604cc30df4792d4a0e9674593a809b4eb55767",
7
+ "pathCount": 216,
8
+ "operationCount": 281
9
9
  }