@takagaki/cortex-decisions-viewer 0.12.105 → 0.12.106

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/dist/build.js CHANGED
@@ -1582,130 +1582,24 @@ function backlogViewKey(url) {
1582
1582
  const m = url.match(/\/view\/([A-Z][A-Z0-9_]*-\d+)(?:[#?]|$)/);
1583
1583
  return m ? m[1] : null;
1584
1584
  }
1585
- const SCAN_SKIP_DIRS = new Set(["tmp", "node_modules", "templates", "resources", "src", "Decisions"]);
1586
- const SCAN_SKIP_FILES = new Set(["readme.md", "template.md", "link.md"]);
1587
1585
  /**
1588
- * Gold層以外の全md(Bronze/Silver)を走査し、ノード+エッジ候補にする(関連は全てつなげる思想)。
1589
- * - frontmatterがあるもの(議事録 minute: / 変換資料 material: 等): そのidをノードIDに、relations/sourceを辺に
1590
- * - 課題md(課題管理/issues 等): 本文の課題キーをノードIDに、URLは実Backlogリンク
1591
- * - それ以外: リポジトリ相対パスをノードIDに(GitHubのコピーへ飛べる)
1592
- * - 全ファイル共通で、本文中のhttp(s)リンクを rel: link の辺にする(Backlog課題URLは課題キーに正規化)
1593
- * - どこにも繋がらない孤立ファイルはノードにしない
1594
- */
1595
- async function scanContent(repoRoot, goldDirName, repoBaseUrl, branch) {
1596
- const entries = [];
1597
- let topDirs;
1598
- try {
1599
- topDirs = await node_fs_1.promises.readdir(repoRoot, { withFileTypes: true });
1600
- }
1601
- catch {
1602
- return entries;
1603
- }
1604
- for (const top of topDirs) {
1605
- if (!top.isDirectory() || top.name.startsWith("."))
1606
- continue;
1607
- if (top.name === goldDirName || SCAN_SKIP_DIRS.has(top.name))
1608
- continue;
1609
- for (const file of await walkMd(path.join(repoRoot, top.name))) {
1610
- const parts = path.relative(repoRoot, file).split(path.sep);
1611
- if (parts.some((p) => SCAN_SKIP_DIRS.has(p)))
1612
- continue;
1613
- if (SCAN_SKIP_FILES.has(path.basename(file).toLowerCase()))
1614
- continue;
1615
- let raw;
1616
- try {
1617
- raw = await node_fs_1.promises.readFile(file, "utf8");
1618
- }
1619
- catch {
1620
- continue;
1621
- }
1622
- const rel = parts.join("/");
1623
- const blobUrl = repoBaseUrl ? `${repoBaseUrl}/blob/${branch}/${encodePath(rel)}` : undefined;
1624
- // 生データ(Bronze/Silver)はオントロジー検証の対象外。frontmatterが壊れていても
1625
- // ビルド全体を巻き込まず、そのファイルだけ飛ばす(議事録・資料のグラフ化のために
1626
- // 全mdをパースするが、生データのYAML揺れで落ちてはならない)。
1627
- let data;
1628
- let content;
1629
- try {
1630
- ({ data, content } = (0, gray_matter_1.default)(raw));
1631
- }
1632
- catch (e) {
1633
- console.warn(` ⚠ frontmatterのパースに失敗したため、グラフ走査からスキップ: ${rel}` +
1634
- ` (${e instanceof Error ? e.message.split("\n")[0] : String(e)})`);
1635
- continue;
1636
- }
1637
- // ノードの素性: frontmatterのID → 課題キー → リポジトリ相対パス の順で決める
1638
- let id = rel;
1639
- let label = path.basename(rel);
1640
- let group = "bronze";
1641
- let url = blobUrl;
1642
- const edges = [];
1643
- let thumb;
1644
- if (data != null && data.id != null && data.type != null) {
1645
- id = String(data.id);
1646
- label = data.title != null ? String(data.title) : id;
1647
- group = data.type === "issue" ? "bronze" : "silver";
1648
- if (data.thumbnail != null)
1649
- thumb = String(data.thumbnail);
1650
- const source = data.source != null ? String(data.source).trim() : "";
1651
- if (source) {
1652
- if (/^https?:\/\//.test(source)) {
1653
- if (data.type === "material" || data.type === "design")
1654
- url = source; // 正本(Drive・Figma等)に飛べるようにする
1655
- edges.push({ target: source, rel: "source" });
1656
- }
1657
- else {
1658
- // 同ディレクトリの文字起こし等への相対参照は、リポジトリ相対パスに解決して繋ぐ
1659
- const cand = path.join(path.dirname(file), source);
1660
- try {
1661
- await node_fs_1.promises.stat(cand);
1662
- edges.push({ target: path.relative(repoRoot, cand).split(path.sep).join("/"), rel: "source" });
1663
- }
1664
- catch {
1665
- edges.push({ target: source, rel: "source" });
1666
- }
1667
- }
1668
- }
1669
- for (const r of toRelations(data.relations))
1670
- if (!exports.MIRROR_RELS.has(r.rel))
1671
- edges.push({ target: r.target, rel: r.rel });
1672
- }
1673
- else {
1674
- const keyMatch = raw.slice(0, 4000).match(/^- 課題キー: (\S+)$/m);
1675
- const h1 = content.match(/^#\s+(.+)$/m);
1676
- if (keyMatch) {
1677
- id = keyMatch[1];
1678
- label = h1 ? `${id} ${h1[1].trim()}`.slice(0, 60) : id;
1679
- const urlMatch = raw.match(/\[Backlog Issue Link\]\((https?:[^)]+)\)/);
1680
- if (urlMatch)
1681
- url = urlMatch[1];
1682
- }
1683
- else {
1684
- if (h1)
1685
- label = h1[1].trim().slice(0, 60);
1686
- }
1687
- }
1688
- for (const link of extractBodyLinks(content)) {
1689
- if (url && link.split("#")[0] === url.split("#")[0])
1690
- continue; // 自分自身の正本リンクは張らない
1691
- const key = backlogViewKey(link);
1692
- edges.push({ target: key ?? link, rel: "link" });
1693
- }
1694
- const filtered = edges.filter((e) => e.target !== id);
1695
- if (filtered.length === 0)
1696
- continue; // どこにも繋がらないファイルはノイズになるため載せない
1697
- entries.push({ id, label, group, url, thumb, edges: filtered });
1698
- }
1699
- }
1700
- return entries;
1701
- }
1702
- /**
1703
- * 全レコードのfrontmatter(relations / source / references)と本文リンク、
1704
- * およびBronze/Silver走査結果(scanContent)から関係グラフを構築する。
1705
- * 参照先がリポジトリ内のレコードでないIDは、層を推定したファントムノードとして表示する
1586
+ * 全レコードのfrontmatter(relations / source / references)と本文リンクから関係グラフを構築する(engine #551・分類A 10/1)。
1587
+ *
1588
+ * 🔴 **同期ミラー(会議/・課題管理/・共有資料/・デザイン/等)のファイルを走査して点にしない。**
1589
+ * 点にするのは Gold(決定・用語・ルール・関係者・Home)と、Gold の relations/source/references/
1590
+ * 本文リンクが指す先だけ。かつてはリポジトリ内の全mdを走査して無関係なファイルまで点にしていたが
1591
+ * (旧 `scanContent`)、Gold と繋がらない点・GitHubの写し(blob)へ飛ぶだけの点が大半を占め、
1592
+ * 「つながり画面」の名が指すつながりそのもの(Goldと根拠)を見えなくしていた。
1593
+ *
1594
+ * 参照先がリポジトリ内のレコードでないIDは、層を推定したノードとして表示する
1706
1595
  * (minute:/material:→Silver、課題キー・外部URL→Bronze、Goldの未解決ID→phantom)。
1596
+ * **根拠の点の飛び先は元ツールのURLだけ**(Backlog・Slack・Drive・Figma・GitHub等)。根拠がまだ
1597
+ * 同期ミラーのパスのまま(元ツールのURLに書き換わっていない)記録は、点にするが飛び先を付けない
1598
+ * (分類B。URLへの書き換えはengine #968で別便が設計中)——押せそうで404のリンクより、押せない
1599
+ * ほうがよい(`createRefResolver` と同じ考え方)。崩れた文字(宛先に見えない参照)も同様に、
1600
+ * 点は作るが飛び先は付けない。
1707
1601
  */
1708
- function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl, branch, refs) {
1602
+ function buildGraph(decisions, home, sections, targetUrls, repoBaseUrl) {
1709
1603
  const nodes = new Map();
1710
1604
  const edges = [];
1711
1605
  const addNode = (node) => {
@@ -1734,6 +1628,18 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
1734
1628
  for (const sec of sections)
1735
1629
  for (const r of sec.records)
1736
1630
  fileNameToId.set(r.fileName, r.id);
1631
+ // 🔴 **GitHubの写し(blob)へ飛ぶ点は作らない**(2026-10-01 オーナー決定・分類B)。
1632
+ // `targetUrls`(minute:/material:)や詳細画面と共用の解決器(RefResolver)は、元ツールの
1633
+ // URLが無いとき自分のリポジトリの blob URL に倒すことがある(詳細画面ではそれでよい設計)。
1634
+ // グラフの点としては、それは元ツールのURLではないので飛び先にしない——点は作るが、
1635
+ // 元ツールのURLに書き換わる(engine #968)まで押せなくする。
1636
+ //
1637
+ // 🔴 **`minute:` も例外にしない。** `buildTargetUrlMap` は議事録の正本URLを持たず、
1638
+ // `minute:{定例名}:{日付}` の飛び先はいつも自分の blob URL(詳細画面ではそれを「正本」として
1639
+ // 扱う設計・1バイトも変えない)。だがグラフとしては、まさにその「GitHubの写しへ飛ぶ点」
1640
+ // (leaderの実測で77件)を無くすのが今回の決定の本題なので、ここも揃えて飛び先を外す
1641
+ // (`graph-gold-only.test.mjs` の「議事録を根拠にした決定」で固定)。
1642
+ const dropMirrorBlob = (url) => url == null || (repoBaseUrl != null && url.startsWith(`${repoBaseUrl}/blob/`)) ? undefined : url;
1737
1643
  // 参照先IDから層を推定してノード化する
1738
1644
  const classifyTarget = (target) => {
1739
1645
  if (nodes.has(target))
@@ -1751,31 +1657,27 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
1751
1657
  target.startsWith("figma-comment:")) {
1752
1658
  group = "silver";
1753
1659
  // 表に無い design: / figma-comment: はキーから組む(詳細画面の resolve と同じ順)
1754
- const url = targetUrls.get(target) ?? figmaUrlFromRef(target);
1660
+ const url = dropMirrorBlob(targetUrls.get(target) ?? figmaUrlFromRef(target));
1755
1661
  if (url)
1756
1662
  return addNode({ id: target, label, group, url });
1757
1663
  }
1758
1664
  else if (/^[A-Z][A-Z0-9_]*-\d+$/.test(target)) {
1759
1665
  group = "bronze"; // 課題キー → 同期mdから解決した実Backlog URLに飛べるようにする
1760
- const url = targetUrls.get(target);
1666
+ const url = dropMirrorBlob(targetUrls.get(target));
1761
1667
  if (url)
1762
1668
  return addNode({ id: target, label, group, url });
1763
1669
  }
1764
1670
  else if (/^https?:\/\//.test(target)) {
1765
1671
  group = "external";
1766
1672
  label = target.replace(/^https?:\/\//, "").slice(0, 60);
1767
- return addNode({ id: target, label, group, url: target });
1673
+ return addNode({ id: target, label, group, url: dropMirrorBlob(target) });
1768
1674
  }
1769
1675
  else if (target.includes("/") || target.toLowerCase().endsWith(".md")) {
1770
- group = "silver"; // リポジトリ内ファイルへのパス参照 → GitHubのコピーへ飛べるようにする
1676
+ // リポジトリ内ファイルへの生のパス参照(同期ミラーの議事録・資料など)。
1677
+ // 元ツールのURLがまだ無い記録は、点にするが飛び先を付けない(#968 の書き換えを待つ)
1678
+ group = "silver";
1771
1679
  label = target.split("/").pop() ?? target;
1772
- // **実在するものだけリンクにする。** 詳細画面(resolveReference)と同じ判定を使う。
1773
- // ここだけ無条件に blob URL を作っていたため、同じ参照が「詳細ではテキスト・
1774
- // グラフでは404リンク」に分かれていた(グラフのノードは window.open される)。
1775
- const blobUrl = repoBaseUrl && refs.exists(target)
1776
- ? `${repoBaseUrl}/blob/${branch}/${encodePath(target)}`
1777
- : undefined;
1778
- return addNode({ id: target, label, group, url: blobUrl });
1680
+ return addNode({ id: target, label, group });
1779
1681
  }
1780
1682
  return addNode({ id: target, label, group });
1781
1683
  };
@@ -1794,11 +1696,12 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
1794
1696
  const addReferenceEdges = (fromId, references) => {
1795
1697
  for (const ref of references) {
1796
1698
  if (ref.url) {
1699
+ const url = dropMirrorBlob(ref.url);
1797
1700
  const id = addNode({
1798
1701
  id: ref.url,
1799
1702
  label: ref.label.slice(0, 60),
1800
- group: "external",
1801
- url: ref.url,
1703
+ group: url ? "external" : "silver",
1704
+ url,
1802
1705
  });
1803
1706
  edges.push({ from: fromId, to: id, rel: "reference" });
1804
1707
  }
@@ -1813,21 +1716,6 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
1813
1716
  edges.push({ from: fromId, to: classifyTarget(key ?? link), rel: "link" });
1814
1717
  }
1815
1718
  };
1816
- // Bronze/Silverのノードを先に登録する(Gold・Bronze/Silver双方からの参照が同一ノードに解決されるように)
1817
- for (const c of content) {
1818
- const existing = nodes.get(c.id);
1819
- if (!existing) {
1820
- addNode({ id: c.id, label: c.label, group: c.group, url: c.url ?? targetUrls.get(c.id), thumb: c.thumb });
1821
- }
1822
- else {
1823
- if (!existing.url && c.url)
1824
- existing.url = c.url;
1825
- if (existing.group === "phantom") {
1826
- existing.group = c.group;
1827
- existing.label = c.label;
1828
- }
1829
- }
1830
- }
1831
1719
  for (const d of decisions) {
1832
1720
  addRelationEdges(d.id, d.relations);
1833
1721
  addReferenceEdges(d.id, d.references);
@@ -1845,11 +1733,6 @@ function buildGraph(decisions, home, sections, content, targetUrls, repoBaseUrl,
1845
1733
  addLinkEdges(r.id, r.bodyLinks);
1846
1734
  }
1847
1735
  }
1848
- for (const c of content) {
1849
- for (const e of c.edges) {
1850
- edges.push({ from: c.id, to: classifyTarget(e.target), rel: e.rel });
1851
- }
1852
- }
1853
1736
  // 自己ループと重複辺を除去する(同じURLが複数回貼られていても辺は1本)
1854
1737
  const seen = new Set();
1855
1738
  const deduped = edges.filter((e) => {
@@ -2348,8 +2231,7 @@ async function build(opts) {
2348
2231
  console.warn(`gold-proposals.json: レコードに突き合わない提案が ${unmatched.length} 件ありました(表示しません): ` +
2349
2232
  unmatched.slice(0, 5).join(", ") + (unmatched.length > 5 ? " ほか" : ""));
2350
2233
  }
2351
- const contentEntries = await scanContent(repoRoot, knowledgeRoot ? path.basename(knowledgeRoot) : null, repo.baseUrl, repo.branch);
2352
- const graph = buildGraph(decisions, home, graphSections, contentEntries, targetUrls, repo.baseUrl, repo.branch, refs);
2234
+ const graph = buildGraph(decisions, home, graphSections, targetUrls, repo.baseUrl);
2353
2235
  computeLayout(graph); // 各ノードに x/y を書き込む(クライアントはこれを初期位置に使いウォームアップ省略)
2354
2236
  // データソースと自動化(fleet-status.json 由来)。無ければ undefined でセクション非表示。
2355
2237
  const fleet = await readFleetSources(repoRoot);
@@ -2536,9 +2418,10 @@ async function parseDecision(raw, fileName, repoRelDir, repoBaseUrl, branch, ref
2536
2418
  }
2537
2419
  function createRefResolver(opts) {
2538
2420
  const { repoRoot, targetUrls, repoBaseUrl, branch } = opts;
2539
- // **走査結果を流用しない。** scanContent は `.md` しか歩かず SCAN_SKIP_DIRS を除外するので、
2540
- // 実在する `.txt`(Geminiメモ)や `tmp/` 配下のファイルを「実在しない」と誤判定して
2541
- // **いま動いているリンクを消す**。参照は1リポジトリあたり数百件なので stat で十分。
2421
+ // **他の走査結果を流用しない。** 全md一覧(Decisions走査や、かつてのグラフ走査 `scanContent`)は
2422
+ // `.md` しか歩かず一部のディレクトリを除外するので、実在する `.txt`(Geminiメモ)や
2423
+ // `tmp/` 配下のファイルを「実在しない」と誤判定して**いま動いているリンクを消す**。
2424
+ // 参照は1リポジトリあたり数百件なので stat で十分。
2542
2425
  const seen = new Map();
2543
2426
  const exists = (relPath) => {
2544
2427
  const hit = seen.get(relPath);
@@ -50,7 +50,7 @@ exports.ENGAGEMENT_LEDGER_VERSION = 1;
50
50
  /** 半減期(日)。engine `weights.mjs` の `HALF_LIFE_DAYS`(正本 6-B「半減期 90 日固定」) */
51
51
  exports.HALF_LIFE_DAYS = 90;
52
52
  /**
53
- * 行為 1 件の重み。engine `weights.mjs` の `WEIGHTS` の写し(25 値・**表に無い `kind` は 0**)。
53
+ * 行為 1 件の重み。engine `weights.mjs` の `WEIGHTS` の写し(26 値・**表に無い `kind` は 0**)。
54
54
  *
55
55
  * 🔴 契約の表(fixture)は `message.posted` しか使っていないので、**ここの写し間違いは表では
56
56
  * 捕まらない**。重みの番人は `test/member-engagement-parity.test.mjs` の `[重み]` が持つ。
@@ -77,14 +77,19 @@ exports.WEIGHTS = Object.freeze({
77
77
  "review.submitted": 1.5,
78
78
  "utterance.spoken": 1.0,
79
79
  "meeting.held": 1.0,
80
- "record.confirmed": 2.0,
81
- "record.edited": 2.0,
80
+ // 記憶の記録の確認・編集(cortex-engine #551 Q6)。0——記憶の手入れは「案件に関わっている」とは別物で、
81
+ // 手入れをする運用の人が案件の中心人物より上に並ばないように数えない。行は正本と同じく残す
82
+ "record.confirmed": 0,
83
+ "record.edited": 0,
82
84
  "record.deleted": 0,
83
85
  // 本文を取り込んだ(engine #695)。人の行為ではないので 0(話した人は `utterance.spoken` で数える)
84
86
  "body.captured": 0,
85
87
  // 人の宣言の指紋(cortex-engine #699 F1)。宣言の取り込みが書く行で、関与には数えない(0)。
86
88
  // 場は宣言専用(`decl:<owner/repo>`)で帳簿にもともと入らないが、網羅のため写す
87
89
  "decl.recorded": 0,
90
+ // 人が承認して push した記憶の訂正(cortex-engine #935)。同じコミットから `record.edited` も起きるので、
91
+ // 数えると二重になる。0
92
+ "correction.stated": 0,
88
93
  });
89
94
  const DAY_MS = 86400000;
90
95
  const cmp = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
package/dist/render.js CHANGED
@@ -19604,9 +19604,10 @@ ${calendarAddUrl.toString()}
19604
19604
  // 出し分けはサーバの DELETABLE_SECTIONS と同じ4区画。ここは「押せないボタンを
19605
19605
  // 出さない」ためのもので、**守りはサーバ側**(promote と同じ関係)。
19606
19606
  var DELETABLE_PATH = /^Cortex\\/(Decisions|Glossary|Members|Rules)\\/records\\/[^/]+\\.md$/;
19607
- // 削除で除外リストにも載る区画。**Decisions は削除だけ**——決定は一度きりの事象で
19608
- // 同じものが再抽出されることは原則なく、engine 側にも決定の除外の仕組みが無い
19609
- var DELETE_EXCLUDES = { Glossary: true, Members: true, Rules: true };
19607
+ // 削除で除外リストにも載る区画(サーバの DELETABLE_SECTIONS で値が null でない区画の写し)。
19608
+ // Decisions は cortex-engine #551 Q7 で足した——消した下書きの決定の題名が README の「除外決定」に載り、
19609
+ // 夜間の AI は同じ題の決定を二度と作らない(engine が「除外決定」を読むようになった)
19610
+ var DELETE_EXCLUDES = { Decisions: true, Glossary: true, Members: true, Rules: true };
19610
19611
  function deletableRecordPath(rec) {
19611
19612
  if (!SITE.intake) return "";
19612
19613
  var p = repoPathOf(rec);
@@ -19615,7 +19616,7 @@ ${calendarAddUrl.toString()}
19615
19616
  var base = p.slice(p.lastIndexOf("/") + 1).toLowerCase();
19616
19617
  return base === "readme.md" || base === "template.md" ? "" : p;
19617
19618
  }
19618
- /** 削除で除外リストに載る区画なら、その区画の表示名。載らない区画(Decisions)は空文字 */
19619
+ /** 削除で除外リストに載る区画なら、その区画の表示名。載らない区画(今は無い)は空文字 */
19619
19620
  function deleteExclusionLabel(p) {
19620
19621
  var m = /^Cortex\\/([^/]+)\\//.exec(p);
19621
19622
  var dir = m ? m[1] : "";
@@ -20009,16 +20010,31 @@ ${calendarAddUrl.toString()}
20009
20010
  report: { color: "#22d3ee", label: "レポート" },
20010
20011
  overview: { color: "#fb923c", label: "Home" },
20011
20012
  record: { color: "#0e7490", label: "その他レコード" },
20012
- silver: { color: "#9ca3af", label: "コンテキスト(課題・議事録・資料・リンク等)" },
20013
- bronze: { color: "#9ca3af", label: "コンテキスト(課題・議事録・資料・リンク等)" },
20014
- external: { color: "#9ca3af", label: "コンテキスト(課題・議事録・資料・リンク等)" },
20013
+ silver: { color: "#9ca3af", label: "根拠(課題・議事録・資料・リンク等)" },
20014
+ bronze: { color: "#9ca3af", label: "根拠(課題・議事録・資料・リンク等)" },
20015
+ external: { color: "#9ca3af", label: "根拠(課題・議事録・資料・リンク等)" },
20015
20016
  phantom: { color: "#d4d9e0", label: "参照先が見つからないもの" },
20016
20017
  };
20017
- var WEAK_RELS = { reference: true, source: true, link: true };
20018
- var REL_COLOR = {
20019
- based_on: "#2563eb", derived_from: "#0d9488", relates_to: "#94a3b8",
20020
- supersedes: "#dc2626", reference: "#d1d5db", source: "#d1d5db", link: "#e2e8f0",
20018
+ /* 線(関係)の種類ごとの色・ラベルと、「Goldどうし」か「根拠」かの分類(engine #551・分類A 10/1)。
20019
+ * **一覧(凡例)はこの表から組む**ので、将来 about(決定・ルール→用語)や is_a/part_of、
20020
+ * 人→用語・人→人の線を足すときは、ここに1行足すだけでよい——凡例もトグルも自動で追従し、
20021
+ * 既存の行・色は変わらない(語彙が増えても凡例が崩れない作り)。
20022
+ * kind: "gold"=Goldのレコードどうしを結ぶ線/"evidence"=Goldがその根拠を指す線(弱いつながり)。 */
20023
+ var REL_META = {
20024
+ based_on: { color: "#2563eb", label: "根拠", kind: "gold" },
20025
+ derived_from: { color: "#0d9488", label: "生成元", kind: "gold" },
20026
+ relates_to: { color: "#94a3b8", label: "関連", kind: "gold" },
20027
+ supersedes: { color: "#dc2626", label: "置換", kind: "gold" },
20028
+ reference: { color: "#d1d5db", label: "参照", kind: "evidence" },
20029
+ source: { color: "#d1d5db", label: "出典", kind: "evidence" },
20030
+ link: { color: "#e2e8f0", label: "リンク", kind: "evidence" },
20021
20031
  };
20032
+ var WEAK_RELS = {};
20033
+ var REL_COLOR = {};
20034
+ Object.keys(REL_META).forEach(function (r) {
20035
+ REL_COLOR[r] = REL_META[r].color;
20036
+ if (REL_META[r].kind === "evidence") WEAK_RELS[r] = true;
20037
+ });
20022
20038
  var graphState = { showWeak: true, q: "" };
20023
20039
 
20024
20040
  function renderGraph() {
@@ -20049,16 +20065,17 @@ ${calendarAddUrl.toString()}
20049
20065
  legend.appendChild(item);
20050
20066
  });
20051
20067
 
20052
- // 線(関係)の色凡例。グラフ内の有無に関わらず全種別を表示する
20053
- legend.appendChild(el("span", { class: "sep", text: "線:" }));
20054
- var REL_LABEL = {
20055
- based_on: "根拠", derived_from: "生成元", relates_to: "関連",
20056
- supersedes: "置換", reference: "参照", source: "出典", link: "リンク",
20057
- };
20058
- Object.keys(REL_LABEL).forEach(function (r) {
20059
- var li = el("span", {}, [el("span", { class: "line" }), document.createTextNode(REL_LABEL[r])]);
20060
- li.querySelector(".line").style.borderTopColor = REL_COLOR[r];
20061
- legend.appendChild(li);
20068
+ // 線(関係)の色凡例。グラフ内の有無に関わらず全種別を、Goldどうし/根拠の2群で表示する
20069
+ [["gold", "線(Goldどうし):"], ["evidence", "線(根拠):"]].forEach(function (pair) {
20070
+ var kind = pair[0], heading = pair[1];
20071
+ var keys = Object.keys(REL_META).filter(function (r) { return REL_META[r].kind === kind; });
20072
+ if (!keys.length) return;
20073
+ legend.appendChild(el("span", { class: "sep", text: heading }));
20074
+ keys.forEach(function (r) {
20075
+ var li = el("span", {}, [el("span", { class: "line" }), document.createTextNode(REL_META[r].label)]);
20076
+ li.querySelector(".line").style.borderTopColor = REL_META[r].color;
20077
+ legend.appendChild(li);
20078
+ });
20062
20079
  });
20063
20080
 
20064
20081
  var toggle = el("label", {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.12.105",
3
+ "version": "0.12.106",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,