@easysociable/cli 0.1.4 → 0.1.5
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.
|
@@ -379,7 +379,7 @@ def _parse_compact_count(raw: str) -> str:
|
|
|
379
379
|
def _fill_engagement_from_blob(out: dict[str, str], blob: str) -> None:
|
|
380
380
|
if not blob:
|
|
381
381
|
return
|
|
382
|
-
# Prefer kind-first matches (
|
|
382
|
+
# Prefer kind-first matches (list form), then num-first (capture prose).
|
|
383
383
|
for kind, num in ENGAGEMENT_KIND_NUM_RE.findall(blob):
|
|
384
384
|
key = f"src_{_normalize_metric_kind(kind)}"
|
|
385
385
|
if key in out and not out[key]:
|
|
@@ -395,10 +395,10 @@ def _fill_engagement_from_blob(out: dict[str, str], blob: str) -> None:
|
|
|
395
395
|
|
|
396
396
|
|
|
397
397
|
def parse_engagement_snapshot(text: str) -> dict[str, str]:
|
|
398
|
-
"""Parse engagement into src_* fields from
|
|
398
|
+
"""Parse engagement into src_* fields from Capture / Raw notes.
|
|
399
399
|
|
|
400
400
|
Supports:
|
|
401
|
-
-
|
|
401
|
+
- Compact: `engagement snapshot: likes 113 / replies 18 / ... @ 2026-08-30`
|
|
402
402
|
- Capture prose: `Engagement snapshot (fetch DATE): ~92.9k views · 1086 likes · ...`
|
|
403
403
|
- Raw list under `## Engagement snapshot` with `- likes: 3`
|
|
404
404
|
Parenthetical secondary demos after the primary snapshot are ignored.
|
|
@@ -684,6 +684,7 @@ def build_graph() -> dict:
|
|
|
684
684
|
"need_ids",
|
|
685
685
|
"product_ids",
|
|
686
686
|
"product_fit",
|
|
687
|
+
"recommendation_ids",
|
|
687
688
|
"run",
|
|
688
689
|
)
|
|
689
690
|
if topic_rows:
|
|
@@ -801,6 +802,7 @@ def build_graph() -> dict:
|
|
|
801
802
|
"need_ids": row.get("need_ids", "") or "",
|
|
802
803
|
"product_ids": row.get("product_ids", "") or "",
|
|
803
804
|
"product_fit": row.get("product_fit", "") or "",
|
|
805
|
+
"recommendation_ids": row.get("recommendation_ids", "") or "",
|
|
804
806
|
"run_id": row["run"].strip(),
|
|
805
807
|
"usage": usage,
|
|
806
808
|
"src_heat_note": "来源帖热度,不是你的帖",
|
|
@@ -811,6 +813,13 @@ def build_graph() -> dict:
|
|
|
811
813
|
edge(nid("topic", ident), nid("capture", row["capture_id"]), "from_capture")
|
|
812
814
|
if row["run"].strip().startswith("RUN-"):
|
|
813
815
|
edge(nid("topic", ident), nid("run", row["run"].strip()), "opened_run")
|
|
816
|
+
# Index cells are enough for edges; item frontmatter may repeat the same ids.
|
|
817
|
+
for need_id in re.findall(r"\bN-\d{8}-\d{2}\b", row.get("need_ids", "") or ""):
|
|
818
|
+
edge(nid("topic", ident), nid("need", need_id), "from_need")
|
|
819
|
+
for product_id in PRODUCT_RE.findall(row.get("product_ids", "") or ""):
|
|
820
|
+
edge(nid("topic", ident), nid("product", product_id), "uses_product")
|
|
821
|
+
for recommendation_id in RECOMMENDATION_RE.findall(row.get("recommendation_ids", "") or ""):
|
|
822
|
+
edge(nid("topic", ident), nid("recommendation", recommendation_id), "reviews")
|
|
814
823
|
if item and (ROOT / item).exists():
|
|
815
824
|
body = read(item)
|
|
816
825
|
fm = re.match(r"^---\n(.*?)\n---", body, re.S)
|
|
@@ -1238,7 +1247,7 @@ def build_graph() -> dict:
|
|
|
1238
1247
|
|
|
1239
1248
|
|
|
1240
1249
|
def _self_check() -> None:
|
|
1241
|
-
# ponytail: tiny parser asserts; expand if capture/
|
|
1250
|
+
# ponytail: tiny parser asserts; expand if capture/raw formats drift again.
|
|
1242
1251
|
d = parse_engagement_snapshot(
|
|
1243
1252
|
"- **engagement snapshot:** likes 113 / replies 18 / bookmarks 17 / views 9574 @ 2026-08-30\n"
|
|
1244
1253
|
)
|
|
@@ -648,6 +648,11 @@
|
|
|
648
648
|
gap_needs_n: "需求原话未选题 {n}",
|
|
649
649
|
gap_lib_n: "Capture 未入库 {n}",
|
|
650
650
|
gap_review_n: "已发但无法复盘 {n}",
|
|
651
|
+
topics_lead: "选题必须有明确输入:need / inbox / user / product / recommendation。没有 Discovery 中间层;来源热度不是选题。",
|
|
652
|
+
kv_lane: "Lane",
|
|
653
|
+
kv_mode: "生成路径",
|
|
654
|
+
kv_needs: "需求",
|
|
655
|
+
kv_recs: "推荐对象",
|
|
651
656
|
kv_profile: "Profile",
|
|
652
657
|
kind_profile: "Profile", kind_account: "账号",
|
|
653
658
|
profile_pillars: "支柱",
|
|
@@ -764,6 +769,11 @@
|
|
|
764
769
|
gap_needs_n: "{n} needs not yet in a topic",
|
|
765
770
|
gap_lib_n: "{n} captures not ingested",
|
|
766
771
|
gap_review_n: "{n} shipped posts not reviewable",
|
|
772
|
+
topics_lead: "Topics need an explicit input: need, inbox, user, product, or recommendation. No Discovery layer; source heat is not a topic.",
|
|
773
|
+
kv_lane: "Lane",
|
|
774
|
+
kv_mode: "Generation mode",
|
|
775
|
+
kv_needs: "Needs",
|
|
776
|
+
kv_recs: "Recommendations",
|
|
767
777
|
kv_profile: "Profile",
|
|
768
778
|
kind_profile: "Profile", kind_account: "Account",
|
|
769
779
|
profile_pillars: "Pillars",
|
|
@@ -946,9 +956,8 @@
|
|
|
946
956
|
let topicPillar = "";
|
|
947
957
|
let topicSrc = "";
|
|
948
958
|
let topicUsage = "";
|
|
949
|
-
let discStatus = "";
|
|
950
|
-
let discSort = "recommend";
|
|
951
959
|
let capIngest = "";
|
|
960
|
+
const TOPIC_SOURCES = ["need", "inbox", "user", "product", "recommendation"];
|
|
952
961
|
let selected = null;
|
|
953
962
|
const $list = document.getElementById("list");
|
|
954
963
|
const $insp = document.getElementById("insp");
|
|
@@ -1353,7 +1362,7 @@
|
|
|
1353
1362
|
function qmatch(n) {
|
|
1354
1363
|
const q = $q.value.trim().toLowerCase();
|
|
1355
1364
|
if (!q) return true;
|
|
1356
|
-
const blob = [n.ident, n.label, n.kind, n.status, n.pillar, n.lane, n.generation_mode, n.profile, n.profiles, n.src_handle, n.url, n.notes, n.type, n.atom_type, n.topic_id, n.audience, n.product_ids, n.product_fit, n.recommendation_ids].filter(Boolean).join(" ").toLowerCase();
|
|
1365
|
+
const blob = [n.ident, n.label, n.kind, n.status, n.pillar, n.lane, n.generation_mode, n.profile, n.profiles, n.src_handle, n.url, n.notes, n.type, n.atom_type, n.topic_id, n.audience, n.need_ids, n.product_ids, n.product_fit, n.recommendation_ids, n.source_type, n.capture_id].filter(Boolean).join(" ").toLowerCase();
|
|
1357
1366
|
return blob.includes(q);
|
|
1358
1367
|
}
|
|
1359
1368
|
function connected(id) {
|
|
@@ -1454,7 +1463,7 @@
|
|
|
1454
1463
|
}).join("");
|
|
1455
1464
|
return `<div class="heat" title="${esc(t("heat_hint"))}">${chips}</div>${hint}`;
|
|
1456
1465
|
}
|
|
1457
|
-
function
|
|
1466
|
+
function listRowEl(n, extra) {
|
|
1458
1467
|
const d = document.createElement("div");
|
|
1459
1468
|
d.className = "row" + (selected === n.id ? " sel" : "");
|
|
1460
1469
|
d.dataset.kind = n.kind;
|
|
@@ -1473,46 +1482,6 @@
|
|
|
1473
1482
|
</div>`;
|
|
1474
1483
|
return d;
|
|
1475
1484
|
}
|
|
1476
|
-
function angleRecommendRank(n) {
|
|
1477
|
-
const r = String(n.angle_recommend || "").toLowerCase();
|
|
1478
|
-
if (r === "promote") return 0;
|
|
1479
|
-
if (r === "library") return 1;
|
|
1480
|
-
if (r === "hold") return 2;
|
|
1481
|
-
if (r === "reject") return 3;
|
|
1482
|
-
if (String(n.next_action || "") === "promote_to_topic") return 0;
|
|
1483
|
-
return 4;
|
|
1484
|
-
}
|
|
1485
|
-
function discoveryUnprocessed(n) {
|
|
1486
|
-
const st = String(n.status || "");
|
|
1487
|
-
if (st === "promoted" || st === "rejected") return false;
|
|
1488
|
-
const ang = String(n.angle_status || "");
|
|
1489
|
-
if (ang === "accepted") return false;
|
|
1490
|
-
if (ang === "held" || ang === "rejected") return false;
|
|
1491
|
-
if (ang === "proposed" && (n.angle_recommend === "promote" || !n.angle_recommend)) return true;
|
|
1492
|
-
if (String(n.next_action || "") === "promote_to_topic") return true;
|
|
1493
|
-
return false;
|
|
1494
|
-
}
|
|
1495
|
-
function sortDiscoveries(rows, mode) {
|
|
1496
|
-
const missing = -1;
|
|
1497
|
-
const num = (n, key) => {
|
|
1498
|
-
const v = Number(String(n[`src_${key}`] ?? "").replace(/,/g, ""));
|
|
1499
|
-
return Number.isFinite(v) ? v : missing;
|
|
1500
|
-
};
|
|
1501
|
-
return rows.slice().sort((a, b) => {
|
|
1502
|
-
if (mode === "recommend" || !mode) {
|
|
1503
|
-
const rec = angleRecommendRank(a) - angleRecommendRank(b);
|
|
1504
|
-
if (rec !== 0) return rec;
|
|
1505
|
-
}
|
|
1506
|
-
let cmp = 0;
|
|
1507
|
-
if (mode === "likes") cmp = num(b, "likes") - num(a, "likes");
|
|
1508
|
-
else if (mode === "replies") cmp = num(b, "replies") - num(a, "replies");
|
|
1509
|
-
else if (mode === "views") cmp = num(b, "views") - num(a, "views");
|
|
1510
|
-
else if (mode === "date") cmp = String(b.date || "").localeCompare(String(a.date || ""));
|
|
1511
|
-
else cmp = num(b, "bookmarks") - num(a, "bookmarks");
|
|
1512
|
-
if (cmp !== 0) return cmp;
|
|
1513
|
-
return String(b.date || "").localeCompare(String(a.date || ""));
|
|
1514
|
-
});
|
|
1515
|
-
}
|
|
1516
1485
|
function pills(n) {
|
|
1517
1486
|
const bits = [];
|
|
1518
1487
|
if (n.kind === "need") {
|
|
@@ -1522,18 +1491,10 @@
|
|
|
1522
1491
|
if (n.source_type) bits.push(`<span class="pill">${esc(n.source_type)}</span>`);
|
|
1523
1492
|
if (n.frequency) bits.push(`<span class="pill">×${esc(n.frequency)}</span>`);
|
|
1524
1493
|
}
|
|
1525
|
-
if (n.kind === "discovery") {
|
|
1526
|
-
const st = n.status || "";
|
|
1527
|
-
const cls = st === "read" || st === "promoted" ? "ok"
|
|
1528
|
-
: (st === "saved" || st === "rejected" || st === "unread" ? "gap" : "");
|
|
1529
|
-
if (st) bits.push(`<span class="pill ${cls}">${esc(st)}</span>`);
|
|
1530
|
-
if (n.angle_recommend) bits.push(`<span class="pill ${n.angle_recommend === "promote" && discoveryUnprocessed(n) ? "gap" : ""}">${esc(n.angle_recommend)}</span>`);
|
|
1531
|
-
else if (discoveryUnprocessed(n)) bits.push(`<span class="pill gap">${esc(t("gap_angle"))}</span>`);
|
|
1532
|
-
if (n.source_role) bits.push(`<span class="pill">${esc(n.source_role)}</span>`);
|
|
1533
|
-
if (n.next_action && n.next_action !== "none") bits.push(`<span class="pill">${esc(n.next_action)}</span>`);
|
|
1534
|
-
}
|
|
1535
1494
|
if (n.kind === "topic") {
|
|
1536
1495
|
bits.push(`<span class="pill">${esc(n.status)}</span>`);
|
|
1496
|
+
if (n.source_type) bits.push(`<span class="pill">${esc(n.source_type)}</span>`);
|
|
1497
|
+
if (n.generation_mode) bits.push(`<span class="pill">${esc(n.generation_mode)}</span>`);
|
|
1537
1498
|
bits.push(n.usage === "unused" ? `<span class="pill gap">${t("unused")}</span>` : `<span class="pill ok">${esc(n.usage)}</span>`);
|
|
1538
1499
|
}
|
|
1539
1500
|
if (n.kind === "run") {
|
|
@@ -1594,7 +1555,7 @@
|
|
|
1594
1555
|
n.frequency ? `×${n.frequency}` : "",
|
|
1595
1556
|
n.topic_ids && n.topic_ids !== "none" ? n.topic_ids : "",
|
|
1596
1557
|
].filter(Boolean).join(" · ");
|
|
1597
|
-
cards.appendChild(
|
|
1558
|
+
cards.appendChild(listRowEl(n, meta));
|
|
1598
1559
|
});
|
|
1599
1560
|
if (!needs.length) {
|
|
1600
1561
|
cards.innerHTML = `<p class='empty'>${t("no_need")}</p><p class="note">${esc(t("need_empty_hint"))}</p>`;
|
|
@@ -1709,58 +1670,31 @@
|
|
|
1709
1670
|
onReady(wrap);
|
|
1710
1671
|
}
|
|
1711
1672
|
|
|
1712
|
-
function
|
|
1713
|
-
|
|
1714
|
-
const
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
(w) => {
|
|
1727
|
-
const status = w.querySelector("#d-st");
|
|
1728
|
-
const sortEl = w.querySelector("#d-sort");
|
|
1729
|
-
const paint = () => {
|
|
1730
|
-
discStatus = status.value;
|
|
1731
|
-
discSort = sortEl.value || "recommend";
|
|
1732
|
-
const cards = document.createElement("div");
|
|
1733
|
-
cards.className = "cards";
|
|
1734
|
-
let rows = nodesOf("discovery").filter(qmatch);
|
|
1735
|
-
if (discStatus) rows = rows.filter(x => x.status === discStatus);
|
|
1736
|
-
rows = sortDiscoveries(rows, discSort);
|
|
1737
|
-
rows.forEach(x => {
|
|
1738
|
-
const meta = [
|
|
1739
|
-
x.angle_recommend || "",
|
|
1740
|
-
x.source_role,
|
|
1741
|
-
x.next_action && x.next_action !== "none" ? x.next_action : "",
|
|
1742
|
-
`@${x.source_handle || "—"}`,
|
|
1743
|
-
].filter(Boolean).join(" · ");
|
|
1744
|
-
cards.appendChild(discoveryRowEl(x, meta));
|
|
1745
|
-
});
|
|
1746
|
-
if (!rows.length) cards.innerHTML = `<p class='empty'>${t("no_discovery")}</p>`;
|
|
1747
|
-
[...$list.querySelectorAll(".cards")].forEach(n => n.remove());
|
|
1748
|
-
$list.appendChild(cards);
|
|
1749
|
-
};
|
|
1750
|
-
status.onchange = paint;
|
|
1751
|
-
sortEl.onchange = paint;
|
|
1752
|
-
paint();
|
|
1753
|
-
}
|
|
1754
|
-
);
|
|
1673
|
+
function topicMeta(x) {
|
|
1674
|
+
const score = x.fit ? `${x.craft}/${x.fit}` : (x.craft || x.total || "—");
|
|
1675
|
+
const bits = [
|
|
1676
|
+
score,
|
|
1677
|
+
formatPillar(x.pillar),
|
|
1678
|
+
x.lane,
|
|
1679
|
+
x.generation_mode,
|
|
1680
|
+
x.source_type,
|
|
1681
|
+
x.need_ids && x.need_ids !== "none" ? x.need_ids : "",
|
|
1682
|
+
x.product_ids && x.product_ids !== "none" ? x.product_ids : "",
|
|
1683
|
+
x.recommendation_ids && x.recommendation_ids !== "none" ? x.recommendation_ids : "",
|
|
1684
|
+
x.capture_id || "",
|
|
1685
|
+
].filter(Boolean);
|
|
1686
|
+
return bits.join(" · ");
|
|
1755
1687
|
}
|
|
1756
1688
|
|
|
1757
1689
|
function renderTopics() {
|
|
1758
1690
|
$list.innerHTML = "";
|
|
1691
|
+
$list.insertAdjacentHTML("beforeend", `<p class="lead">${esc(t("topics_lead"))}</p>`);
|
|
1692
|
+
if (topicSrc && !TOPIC_SOURCES.includes(topicSrc)) topicSrc = "";
|
|
1759
1693
|
const statuses = [...new Set(nodesOf("topic").map(x => x.status).filter(Boolean))];
|
|
1760
1694
|
filterBar(
|
|
1761
1695
|
`<select id="f-st"><option value="">${t("f_status")}</option>${statuses.map(s => `<option value="${s}" ${s === topicStatus ? "selected" : ""}>${esc(s)}</option>`).join("")}</select>
|
|
1762
1696
|
<select id="f-p"><option value="">${t("f_pillar")}</option>${pillarIds().map(id => `<option value="${id}" ${id === topicPillar ? "selected" : ""}>${esc(formatPillar(id))}</option>`).join("")}</select>
|
|
1763
|
-
<select id="f-src"><option value="">${t("f_src")}</option>${
|
|
1697
|
+
<select id="f-src"><option value="">${t("f_src")}</option>${TOPIC_SOURCES.map(s => `<option value="${s}" ${s === topicSrc ? "selected" : ""}>${s}</option>`).join("")}</select>
|
|
1764
1698
|
<select id="f-u"><option value="">${t("f_use")}</option>
|
|
1765
1699
|
<option value="unused" ${topicUsage === "unused" ? "selected" : ""}>${t("f_unused")}</option>
|
|
1766
1700
|
<option value="promoted" ${topicUsage === "promoted" ? "selected" : ""}>${t("f_promoted")}</option></select>`,
|
|
@@ -1783,8 +1717,7 @@
|
|
|
1783
1717
|
if (topicSrc) rows = rows.filter(x => x.source_type === topicSrc);
|
|
1784
1718
|
if (topicUsage) rows = rows.filter(x => x.usage === topicUsage);
|
|
1785
1719
|
rows.forEach(x => {
|
|
1786
|
-
|
|
1787
|
-
cards.appendChild(rowEl(x, `${score} · ${formatPillar(x.pillar)} · ${x.source_type} @${x.src_handle || "—"}`));
|
|
1720
|
+
cards.appendChild(rowEl(x, topicMeta(x)));
|
|
1788
1721
|
});
|
|
1789
1722
|
if (!rows.length) cards.innerHTML = `<p class='empty'>${t("no_topic")}</p>`;
|
|
1790
1723
|
$list.appendChild(cards);
|
|
@@ -1826,7 +1759,7 @@
|
|
|
1826
1759
|
let caps = nodesOf("capture").filter(qmatch).sort((a, b) => (b.date || "").localeCompare(a.date || ""));
|
|
1827
1760
|
if (capIngest === "ingested") caps = caps.filter(c => c.status === "ingested");
|
|
1828
1761
|
if (capIngest === "not_ingested") caps = caps.filter(c => c.status !== "ingested");
|
|
1829
|
-
caps.forEach(c => cards.appendChild(
|
|
1762
|
+
caps.forEach(c => cards.appendChild(listRowEl(c, `${c.type} · ${c.status} · raw ${c.has_raw ? t("raw_yes") : t("raw_no")}`)));
|
|
1830
1763
|
if (!caps.length) cards.innerHTML = `<p class='empty'>${t("no_note")}</p>`;
|
|
1831
1764
|
$list.appendChild(cards);
|
|
1832
1765
|
return;
|
|
@@ -2047,20 +1980,18 @@
|
|
|
2047
1980
|
|
|
2048
1981
|
function gapsFor(profileId) {
|
|
2049
1982
|
const topics = profileId ? nodesOfAll("topic").filter(n => n.profile === profileId) : nodesOfAll("topic");
|
|
2050
|
-
const discs = profileId ? nodesOfAll("discovery").filter(n => n.profile === profileId) : nodesOfAll("discovery");
|
|
2051
1983
|
const needs = profileId ? nodesOfAll("need").filter(n => n.profile === profileId) : nodesOfAll("need");
|
|
2052
1984
|
const caps = profileId ? nodesOfAll("capture").filter(n => n.profile === profileId) : nodesOfAll("capture");
|
|
2053
1985
|
const pubs = profileId ? nodesOfAll("published").filter(n => n.profile === profileId) : nodesOfAll("published");
|
|
2054
1986
|
const needCount = needs.length;
|
|
2055
1987
|
const gaps = [
|
|
2056
1988
|
[topics.filter(x => x.status === "ready" && x.usage === "unused").length, "gap_ready_n"],
|
|
2057
|
-
[discs.filter(discoveryUnprocessed).length, "gap_angle_n"],
|
|
2058
1989
|
[needs.filter(n => n.status === "captured" && (!n.topic_ids || n.topic_ids === "none")).length, "gap_needs_n"],
|
|
2059
1990
|
[caps.filter(c => c.status !== "ingested").length, "gap_lib_n"],
|
|
2060
1991
|
[pubs.filter(p => !p.reviewable).length, "gap_review_n"],
|
|
2061
1992
|
].filter(([n]) => n > 0);
|
|
2062
1993
|
if (GRAPH.needs_index_present && needCount < 3) {
|
|
2063
|
-
gaps.splice(
|
|
1994
|
+
gaps.splice(1, 0, [needCount, "gap_needs_thin_n"]);
|
|
2064
1995
|
}
|
|
2065
1996
|
return gaps;
|
|
2066
1997
|
}
|
|
@@ -2166,20 +2097,21 @@
|
|
|
2166
2097
|
? `${n.win || 0}w / ${n.loss || 0}l / n=${n.n}`
|
|
2167
2098
|
: "",
|
|
2168
2099
|
[t("kv_pillar")]: formatPillar(n.pillar),
|
|
2169
|
-
|
|
2170
|
-
"
|
|
2100
|
+
[t("kv_lane")]: n.kind === "topic" ? (n.lane || "") : "",
|
|
2101
|
+
[t("kv_mode")]: n.kind === "topic" ? (n.generation_mode || "") : "",
|
|
2171
2102
|
[t("kv_plat")]: n.platform || n.platforms,
|
|
2172
2103
|
[t("kv_profile")]: n.profile || n.profile_id || (n.profiles || ""),
|
|
2173
2104
|
[t("kv_score")]: n.fit ? `${n.craft} opp / ${n.fit} aud` : n.total,
|
|
2174
|
-
[t("kv_use")]: n.
|
|
2175
|
-
[t("kv_src")]: n.
|
|
2176
|
-
|
|
2105
|
+
[t("kv_use")]: n.usage,
|
|
2106
|
+
[t("kv_src")]: n.source_type,
|
|
2107
|
+
[t("kv_needs")]: n.kind === "topic" ? (n.need_ids || "") : "",
|
|
2177
2108
|
Quote: n.kind === "need" ? (n.quote || "") : "",
|
|
2178
2109
|
Speaker: n.kind === "need" ? (n.speaker || "") : "",
|
|
2179
2110
|
Frequency: n.kind === "need" ? (n.frequency || "") : "",
|
|
2180
2111
|
Topics: n.kind === "need" ? (n.topic_ids || "") : "",
|
|
2181
2112
|
Products: n.kind === "topic" ? (n.product_ids || "") : "",
|
|
2182
2113
|
"Product fit": n.kind === "topic" ? (n.product_fit || "") : "",
|
|
2114
|
+
[t("kv_recs")]: n.kind === "topic" ? (n.recommendation_ids || "") : "",
|
|
2183
2115
|
Audience: n.kind === "product" ? (n.audience || "") : "",
|
|
2184
2116
|
Price: n.kind === "product" ? (n.price || "") : "",
|
|
2185
2117
|
"Effective from": n.kind === "product" ? (n.effective_from || "") : "",
|
|
@@ -2187,10 +2119,10 @@
|
|
|
2187
2119
|
Relationship: n.kind === "recommendation" ? (n.relationship || "") : "",
|
|
2188
2120
|
"Last researched": n.kind === "recommendation" ? (n.last_researched || "") : "",
|
|
2189
2121
|
Handle: n.source_handle || n.src_handle || "",
|
|
2190
|
-
[t("kv_heat_at")]:
|
|
2122
|
+
[t("kv_heat_at")]: n.kind === "capture" ? (n.engagement_at || "") : "",
|
|
2191
2123
|
[t("kv_result")]: n.result,
|
|
2192
2124
|
}).filter(([, v]) => v);
|
|
2193
|
-
const heatBlock =
|
|
2125
|
+
const heatBlock = n.kind === "capture"
|
|
2194
2126
|
? `${heatStripHtml(n, { hint: true })}${n.source_url ? `<p class="note">${t("src_url")}<a href="${esc(n.source_url)}" target="_blank" rel="noreferrer">${esc(n.source_url)}</a></p>` : ""}`
|
|
2195
2127
|
: "";
|
|
2196
2128
|
$insp.innerHTML = `<h2>${t("obj")}</h2>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easysociable/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Agent-first CLI for EasySociable: Content Engine, Template, Slideshow, and MCP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"tsup": "^8.0.2",
|
|
50
50
|
"typescript": "^5.8.3",
|
|
51
51
|
"vitest": "^1.3.1",
|
|
52
|
+
"@easysociable/template-gateway-client": "0.0.0",
|
|
52
53
|
"@easysociable/mcp-server": "0.0.0",
|
|
53
54
|
"@easysociable/tsconfig": "0.0.0",
|
|
54
|
-
"@easysociable/template-gateway-client": "0.0.0",
|
|
55
55
|
"@easysociable/vitest-config": "0.0.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
Binary file
|