@takagaki/cortex-decisions-viewer 0.12.132 → 0.12.134

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
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.DECISION_FIRMNESS = exports.PROJECT_ICON_EXTS = exports.MIRROR_RELS = void 0;
39
+ exports.RELATED_MATERIALS_SECTIONS = exports.RELATED_URL_MAX = exports.RELATED_MATERIALS_FIELD = exports.DECISION_FIRMNESS = exports.PROJECT_ICON_EXTS = exports.MIRROR_RELS = void 0;
40
40
  exports.sanitizeBody = sanitizeBody;
41
41
  exports.findProjectIcon = findProjectIcon;
42
42
  exports.readFleetSources = readFleetSources;
@@ -60,6 +60,10 @@ exports.build = build;
60
60
  exports.decisionFirmnessOf = decisionFirmnessOf;
61
61
  exports.decisionTopicOf = decisionTopicOf;
62
62
  exports.decidedByOf = decidedByOf;
63
+ exports.isRelatedUrl = isRelatedUrl;
64
+ exports.relatedMaterialsRead = relatedMaterialsRead;
65
+ exports.relatedMaterialsView = relatedMaterialsView;
66
+ exports.attachRelatedMaterials = attachRelatedMaterials;
63
67
  exports.createRefResolver = createRefResolver;
64
68
  const node_crypto_1 = require("node:crypto");
65
69
  const node_fs_1 = require("node:fs");
@@ -2530,6 +2534,8 @@ async function buildSite(opts, views) {
2530
2534
  const records = await loadGenericRecords(recordsDir, exclude, repo.baseUrl, repo.branch);
2531
2535
  // 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)
2532
2536
  attachHumanTouched(records, recordsDir, repoRoot, ledgers.confirmation, touchedBy);
2537
+ // 関連の資料(cortex-engine #1094 F8)。ルール・用語だけ・欄の無い記録には何も付かない
2538
+ attachRelatedMaterials(e.name, records, refs);
2533
2539
  // ルールの取り下げ(`retracted_by`・cortex-engine #1094 便 4-2d)。ルールの区画だけ・取り下げの無い案件では何も付かない
2534
2540
  if (e.name === "Rules")
2535
2541
  attachRetractedBy(records, decisions, (d) => rawDates.get(d) ?? d.fm.date);
@@ -2745,6 +2751,8 @@ async function parseDecision(raw, fileName, repoRelDir, repoBaseUrl, branch, ref
2745
2751
  const firmness = decisionFirmnessOf(data.firmness);
2746
2752
  const topic = decisionTopicOf(data.topic);
2747
2753
  const decidedBy = decidedByOf(data.decided_by);
2754
+ // 関連の資料(#1094 F8)。通る URL が 0 本ならキーごと載せない
2755
+ const relatedMaterials = relatedMaterialsView(data, refs);
2748
2756
  // 本文先頭の H1 はタイトルと重複するため除去(詳細画面ではタイトルを別途表示する)
2749
2757
  const bodyHtml = await renderRecordBody(content);
2750
2758
  const filePath = repoRelDir ? `${repoRelDir}/${fileName}` : fileName;
@@ -2778,6 +2786,7 @@ async function parseDecision(raw, fileName, repoRelDir, repoBaseUrl, branch, ref
2778
2786
  ...(firmness ? { firmness } : {}),
2779
2787
  ...(topic ? { topic } : {}),
2780
2788
  ...(decidedBy ? { decidedBy } : {}),
2789
+ ...(relatedMaterials ? { relatedMaterials } : {}),
2781
2790
  };
2782
2791
  }
2783
2792
  /**
@@ -2830,6 +2839,62 @@ function decidedByOf(value) {
2830
2839
  return undefined;
2831
2840
  return value.map(decidedByEntryOf).filter((e) => e !== null);
2832
2841
  }
2842
+ /**
2843
+ * 関連の資料の欄 `related_materials` の読み手(決定・ルール・用語・cortex-engine #1094 F8)。
2844
+ *
2845
+ * 🔴 **写し。正本は cortex-engine `scripts/gold/related-materials-field.mjs` の `isRelatedUrl` と `relatedMaterialsRead`**。
2846
+ * 同じバイト列の表 `test/fixtures/related-materials-contract.json` を両リポに置き、`test/related-materials-view.test.mjs` の
2847
+ * 「[契約] …」が全ケースを流す。規則を変えるときは engine の正本・この写し・表を同じ日に直す。
2848
+ * 重複も上限も見ない(人が足した分を落とさない)。`decided_by` の URL の門(`DECIDED_BY_URL_RE`)とは別の、engine と同じ門
2849
+ */
2850
+ exports.RELATED_MATERIALS_FIELD = "related_materials";
2851
+ exports.RELATED_URL_MAX = 2000;
2852
+ // eslint-disable-next-line no-control-regex
2853
+ const RELATED_URL_RE = /^https?:\/\/[^\s<>"\[\]〔〕\u0000-\u001f\u007f]+$/i;
2854
+ /** 欄に置いてよい URL か(http(s)・空白と制御文字・`<>"[]〔〕` を含まない・ホストあり・2000 字まで) */
2855
+ function isRelatedUrl(v) {
2856
+ if (typeof v !== "string" || !v || v.length > exports.RELATED_URL_MAX)
2857
+ return false;
2858
+ if (!RELATED_URL_RE.test(v))
2859
+ return false;
2860
+ try {
2861
+ const u = new URL(v);
2862
+ return (u.protocol === "http:" || u.protocol === "https:") && u.hostname !== "";
2863
+ }
2864
+ catch {
2865
+ return false;
2866
+ }
2867
+ }
2868
+ /** frontmatter → 欄の URL の並び(通るものだけ・順はそのまま)。欄が無い・リストでなければ [] */
2869
+ function relatedMaterialsRead(fm) {
2870
+ const v = fm && typeof fm === "object" ? fm[exports.RELATED_MATERIALS_FIELD] : null;
2871
+ return Array.isArray(v) ? v.filter(isRelatedUrl) : [];
2872
+ }
2873
+ /** 画面に載せる形(名前は根拠と同じ解決=帳の題名・URL の種類の名前)。通る URL が 0 本なら undefined(キーごと載せない) */
2874
+ function relatedMaterialsView(fm, refs) {
2875
+ const urls = relatedMaterialsRead(fm);
2876
+ if (!urls.length)
2877
+ return undefined;
2878
+ return urls.map((u) => {
2879
+ // 名前は scheme だけ小文字にして引く(根拠の解決は大文字の `HTTPS://` を URL と読まずパスに落とす)。飛び先は書かれたまま
2880
+ const q = u.replace(/^https?:/i, (m) => m.toLowerCase());
2881
+ const r = refs.resolve(q);
2882
+ // 名前が引けなければ(解決が引いた文字をそのまま返した)、書かれた URL のまま出す
2883
+ return { label: r.label && r.label !== q ? r.label : u, url: u };
2884
+ });
2885
+ }
2886
+ /** 関連の資料を持てる汎用の区画(関係者・ストーリーの日・Home の欄は拾わない) */
2887
+ exports.RELATED_MATERIALS_SECTIONS = new Set(["Rules", "Glossary"]);
2888
+ /** 区画の記録に関連の資料を載せる(ルール・用語だけ・欄の無い記録にはキーごと付けない) */
2889
+ function attachRelatedMaterials(section, records, refs) {
2890
+ if (!exports.RELATED_MATERIALS_SECTIONS.has(section))
2891
+ return;
2892
+ for (const r of records) {
2893
+ const view = relatedMaterialsView(r.fm, refs);
2894
+ if (view)
2895
+ r.relatedMaterials = view;
2896
+ }
2897
+ }
2833
2898
  /**
2834
2899
  * 解決した参照 → 書かれていた値(#968 tools 1)。つながり画面は点の鍵をこの値から決める
2835
2900
  * (`site-data` に載せない——機械の語を画面の材料に増やさない)
package/dist/render.js CHANGED
@@ -3607,7 +3607,7 @@ function derivePendingTile(regKey, registered, rows) {
3607
3607
  });
3608
3608
  }
3609
3609
  // **優先順: 失敗 > 未測定 > OK。** 失敗は測った事実なので、未測定の行が混ざっていても
3610
- // 隠さない(行は「Slackで招待してください」と出ているのにタイルが「確認中」では、
3610
+ // 隠さない(行は「未招待」と出ているのにタイルが「確認中」では、
3611
3611
  // 行とタイルが違うことを言う)。「接続OK」だけは全行が測定済みのときに限る
3612
3612
  if (badRows.length)
3613
3613
  return { kind: "bad", rows: badRows };
@@ -6115,6 +6115,8 @@ button.ops-card-btn:disabled { opacity: .6; cursor: default; }
6115
6115
  .deciders { display: flex; flex-wrap: wrap; gap: 8px; }
6116
6116
  .refs { margin: 0; padding-left: 18px; }
6117
6117
  .refs li { margin: 4px 0; }
6118
+ /* 関連の資料(#1094 F8): 名前の引けない資料は URL のまま(最大 2000 字)なので、狭い画面ではみ出さないよう折り返す */
6119
+ .related-materials li { overflow-wrap: anywhere; }
6118
6120
  .body {
6119
6121
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
6120
6122
  padding: 4px 22px 8px; margin-top: 8px;
@@ -7043,6 +7045,27 @@ ${calendarAddUrl.toString()}
7043
7045
  function retractedFadedClass(rec) {
7044
7046
  return isRetracted(rec) ? " is-faded" : "";
7045
7047
  }
7048
+ /**
7049
+ * 詳細の節「関連の資料」(cortex-engine #1094 F8)。記録を生んだ会話に貼られた資料へのリンク。
7050
+ * 根拠(「参照」)とは混ぜない。ビルドが engine と同じ門で検めてあるが、画面でも http(s) だけをリンクにする(二重に見る)。
7051
+ * 関連の資料の無い記録では null(要素を作らない)
7052
+ */
7053
+ function relatedMaterialsSection(r) {
7054
+ if (!r || !r.relatedMaterials || !r.relatedMaterials.length) return null;
7055
+ // 🔴 大文字の scheme(HTTPS://)も engine の門では通るので、ここも大文字小文字を区別しない(isHttp は区別する=ほかの画面の前例のまま触らない)
7056
+ var items = r.relatedMaterials.filter(function (m) { return m && typeof m.url === "string" && /^https?:\\/\\//i.test(m.url); });
7057
+ if (!items.length) return null;
7058
+ var box = el("div", { class: "related-materials-section" });
7059
+ box.appendChild(el("div", { class: "section-label", text: "関連の資料" }));
7060
+ var ul = el("ul", { class: "refs related-materials" });
7061
+ items.forEach(function (m) {
7062
+ var li = el("li");
7063
+ li.appendChild(el("a", { href: m.url, target: "_blank", rel: "noopener", text: m.label || m.url }));
7064
+ ul.appendChild(li);
7065
+ });
7066
+ box.appendChild(ul);
7067
+ return box;
7068
+ }
7046
7069
  /** 詳細の節「取り下げを決めた決定」。取り下げの無い記録では null(要素を作らない) */
7047
7070
  function retractSection(r) {
7048
7071
  if (!isRetracted(r)) return null;
@@ -9834,13 +9857,15 @@ ${calendarAddUrl.toString()}
9834
9857
  // **状態だけでなく、次にすることを書く。** 「bot未招待」では何をすればよいか分からない
9835
9858
  // (公開チャンネルでも招待が要ることは Slack の仕様で、知らない人のほうが多い)
9836
9859
  //
9837
- // 🔴 **一手は行の中に出す(c-07)。** 札は症状(未招待)、一手は「Cortex が招待されていません:
9860
+ // 🔴 **一手は行の中に出す(c-07)。** 札は症状(未招待)、一手は「Cortex を招待してください:
9838
9861
  // /invite @Cortex[コピー]」の 1 行。追加の欄の手順 1 にあったコピー行はここへ移した。
9839
- // help を持たせたので、showsRestingReason は夜間の理由文(機械の語)を重ねない
9862
+ // help を持たせたので、showsRestingReason は夜間の理由文(機械の語)を重ねない。
9863
+ // 🔴 **札と一手が同じことを 2 回言わない(#1328)。** 札に「招待してください」と書くと、
9864
+ // 一手の「招待されていません」と同じ文が 2 つ並ぶ。札は短い症状、一手は行動
9840
9865
  "not_in_channel": {
9841
- text: "Slackで招待してください",
9866
+ text: "未招待",
9842
9867
  cls: "ds-gate-warn",
9843
- help: "Cortex が招待されていません:",
9868
+ help: "Cortex を招待してください:",
9844
9869
  copy: "/invite @Cortex",
9845
9870
  },
9846
9871
  // **招待では直らない(2026-08-19 の不具合報告)。** 非公開チャンネルで groups:read が
@@ -10009,11 +10034,10 @@ ${calendarAddUrl.toString()}
10009
10034
  customer: {
10010
10035
  text: "トークン未設定",
10011
10036
  cls: "ds-gate-muted",
10012
- // 🔴 **一手は「この Slack を Cortex に接続してください。[接続する]」の 1 行(c-07)。**
10013
- // 常設の[Slack ワークスペースに接続する]は撤去し、接続はこの行の一手が持つ。
10014
- // 主語は「この Slack」(承認画面はワークスペースを指定できない——slackConnectInline の項)
10015
- help: "この Slack を Cortex に接続してください。",
10016
- act: "connect",
10037
+ // 🔴 **行は札だけ(#1328)。** 一手「この Slack を Cortex に接続してください。[接続する]」は、
10038
+ // 同じワークスペースの組の先頭に 1 回だけ置く(slackConnectNote)。10 チャンネルが
10039
+ // 同じ一手を 10 回言わない。主語は「この Slack」(承認画面はワークスペースを指定できない
10040
+ // ——slackConnectInline の項)
10017
10041
  },
10018
10042
  /* -------------------------------------------------------------------------
10019
10043
  * GitHub。**「トークン未設定」と言ってはいけない**(2026-08-21)
@@ -10184,26 +10208,57 @@ ${calendarAddUrl.toString()}
10184
10208
  * Slack の「理由不明」の行(unreachable・組織不明の仮置き)に出す一手(c-07)。
10185
10209
  * **広い方の 1 行**にする——原因は行の分類では絞れない(0.12.2 の実測)ので、片方に賭けない。
10186
10210
  *
10187
- * - ワークスペースが分かっていて、台帳の接続が切れている/未接続 → 「この Slack を Cortex に接続してください。[接続する]」
10211
+ * - ワークスペースが分かっていて、台帳の接続が切れている/未接続 → 行には何も出さない(空の配列)。
10212
+ * 一手は組の先頭の slackConnectNote が 1 回だけ言う
10188
10213
  * - ワークスペースが分かっていて、接続が生きている → 招待だけ
10189
- * - 社内・組織不明(分類が当てにならない)→ 招待 + 「お客様の Slack なら、ワークスペースを接続してください。[接続する]」
10214
+ * - 社内・組織不明(分類が当てにならない)→ 招待だけ(「お客様の Slack なら接続」は組の先頭が言う)
10190
10215
  *
10191
- * 🔴 **投入の口(SITE.intake)が無い案件では接続を出さない**(押せない案内を置かない)。
10216
+ * 🔴 **接続は行の一手に置かない(#1328)。** 同じワークスペースの全チャンネルが同じ一文を
10217
+ * 繰り返していた。**行は札と、その行だけの一手(招待)だけ**。
10218
+ * 🔴 **空の配列を返す(null にしない)。** null を返すと呼び側が夜間の理由文(機械の語)を代わりに出す。
10219
+ * 投入の口(SITE.intake)が無い案件は接続を出せないので、従来どおり招待だけを返す。
10192
10220
  */
10193
10221
  function slackRowHelpParts(row) {
10194
10222
  if (!row) return null;
10195
10223
  var invite = ["Cortex からこのチャンネルが見えません。Cortex を招待してください:", { copy: "/invite @Cortex" }];
10196
- var canConnect = !!SITE.intake;
10197
10224
  if (row.workspace) {
10198
10225
  var st = tokenStateOf(slackWorkspaces(), row.workspace);
10199
- if (st === "revoked" || st === "missing") {
10200
- return canConnect ? ["この Slack を Cortex に接続してください。", { act: "connect" }] : invite;
10201
- }
10202
- return invite;
10226
+ if (st === "revoked" || st === "missing") return SITE.intake ? [] : invite;
10203
10227
  }
10204
- return canConnect
10205
- ? invite.concat([" お客様の Slack なら、ワークスペースを接続してください。", { act: "connect" }])
10206
- : invite;
10228
+ return invite;
10229
+ }
10230
+ /**
10231
+ * この Slack の行が、ワークスペースの接続([接続する])で直る行か(#1328)。
10232
+ * 組の先頭に一手を置くかどうかの判断だけに使う。**行には出さない。**
10233
+ *
10234
+ * - 顧客の no_token(組織不明の行を含む。社内の no_token は画面から直せないので含めない・2026-08-18)
10235
+ * - まだ測っていない組織不明の仮置きの行
10236
+ * - unreachable で、ワークスペースが不明(社内に分類・印なし)/台帳の接続が切れている・未接続
10237
+ * 投入の口(SITE.intake)が無い案件は押せないので、常に false。
10238
+ */
10239
+ function slackRowNeedsConnect(s) {
10240
+ if (!SITE.intake || !s || s.type !== "slack") return false;
10241
+ if (s.gate === "no_token") return !isInternalSlack(s);
10242
+ if (!s.gate) return s.orgUnknown === true;
10243
+ if (s.gate !== "unreachable") return false;
10244
+ if (!s.workspace) return true;
10245
+ var st = tokenStateOf(slackWorkspaces(), s.workspace);
10246
+ return st === "revoked" || st === "missing";
10247
+ }
10248
+ /**
10249
+ * ワークスペースごとの組の先頭に置く、接続の一手(0 または 1 個の段落)。
10250
+ * 「この Slack を Cortex に接続してください。[接続する]」(その組が顧客のワークスペースだと分かっているとき)か、
10251
+ * 「お客様の Slack なら、ワークスペースを接続してください。[接続する]」(社内・組織不明の組)。
10252
+ * **行の中の ds-gate-help ではない**(行の補足は最大 1 段・押した結果が行の補足を隠す仕掛けに巻き込まない)。
10253
+ * @param g groupSlackByOrg の 1 組
10254
+ */
10255
+ function slackConnectNote(g) {
10256
+ var needy = g.items.filter(slackRowNeedsConnect);
10257
+ if (!needy.length) return null;
10258
+ var sure = (g.key !== "__internal__" && g.key !== "__unknown__")
10259
+ || needy.every(function (s) { return s.gate === "no_token"; });
10260
+ var say = sure ? "この Slack を Cortex に接続してください。" : "お客様の Slack なら、ワークスペースを接続してください。";
10261
+ return restingHelpNode([say, { act: "connect" }], "ds-group-note ds-ws-connect");
10207
10262
  }
10208
10263
  /** 押した結果に添えるパーツ(無ければ null)。行と同じ表から引く(写経しない) */
10209
10264
  function probedHelpPartsOf(type, gate) {
@@ -10310,7 +10365,7 @@ ${calendarAddUrl.toString()}
10310
10365
  * **GitHub の no_token は出す**(#1233・帯を撤去したので行が一手を持つ。
10311
10366
  * テナント外の断り(#841)は「担当者へ」の 1 文(needed))
10312
10367
  * - not_in_channel でない(help は無いが、**状態の語そのものが操作の指示**
10313
- * 「Slackで招待してください」。その下に夜間の「読めませんでした: not_in_channel」を
10368
+ * 「未招待」。その下に夜間の「読めませんでした: not_in_channel」を
10314
10369
  * 並べても情報が増えず、招待という具体的な指示を薄める。help の有無とは別の軸)
10315
10370
  * - dsGateOf(s).help が無い(あれば DS_GATE の固定文が次の一手を持っている)
10316
10371
  */
@@ -11313,8 +11368,11 @@ ${calendarAddUrl.toString()}
11313
11368
  out.push(resolved);
11314
11369
  }
11315
11370
  // 🔴 **接続が切れた/未接続のワークスペースの枠(brokenOrgNodes)は撤去した(c-07)。**
11316
- // そのワークスペースの読めていない行が、一手「この Slack を Cortex に接続してください。[接続する]」を
11317
- // 持つ(slackRowHelpParts と DS_GATE_NO_TOKEN.customer)。入口を失わないための約束は決定メモに書いた
11371
+ // 一手「この Slack を Cortex に接続してください。[接続する]」は、そのワークスペースの組の先頭に
11372
+ // 1 回だけ置く(slackConnectNote・#1328)。行は札と、その行だけの一手(招待)だけを持つ。
11373
+ // 入口を失わないための約束は決定メモに書いた
11374
+ var connectNote = slackConnectNote(g);
11375
+ if (connectNote) out.push(connectNote);
11318
11376
  cards.forEach(function (n) { out.push(n); });
11319
11377
  });
11320
11378
  return out;
@@ -12652,14 +12710,24 @@ ${calendarAddUrl.toString()}
12652
12710
  // 🔴 **Figma・Drive・Backlog の「未接続(…が登録されていません)」は作らない(c-07)。** 0 件のとき、
12653
12711
  // 同じ窓に一覧の ds-empty「…はまだ登録されていません。」が出ていて二重だった。しかも一覧は
12654
12712
  // liveList で追加に追随するが、この一文は開いた時点の値なので、1 件足すと「未接続」が足した行の
12655
- // 上に残る。**一覧の 1 行だけ**を残す。off・broken の一文は残す(Slack・GitHub は触らない)。
12713
+ // 上に残る。**一覧の 1 行だけ**を残す。off・broken の一文は残す(Slack は触らない。GitHub は下の unsetDup の項)。
12656
12714
  // 🔴 **「登録されていません」と言うだけの一文だけを落とす。** 「雛形のプレースホルダです」のように、
12657
12715
  // 一覧の 1 行が言わない手がかりを運ぶ一文は残す(なぜ未接続扱いなのかが読めなくなる)
12716
+ // 🔴 **GitHub の 0 件も同じ(#1328)。** 一覧の「読み取り対象の開発リポジトリがまだありません。」が
12717
+ // 出る回(夜間の組の一覧が読めていて 0 件)に限って、上の「未接続(登録がありません)」を落とす。
12718
+ // 一覧の 1 行が出ない回(まだ夜間が走っていない・組の一覧が読めない)は、この一文が唯一の言葉なので残す
12658
12719
  var unsetDup = noteIsUnset
12659
- && /登録されていません/.test(noteText)
12660
- && ((cap === "デザイン" && (!adapter || adapter === "figma"))
12661
- || (cap === "共有資料" && (!adapter || adapter === "google-drive"))
12662
- || (cap === "課題管理" && (!adapter || adapter === "backlog")));
12720
+ && ((/登録されていません/.test(noteText)
12721
+ && ((cap === "デザイン" && (!adapter || adapter === "figma"))
12722
+ || (cap === "共有資料" && (!adapter || adapter === "google-drive"))
12723
+ || (cap === "課題管理" && (!adapter || adapter === "backlog"))))
12724
+ || (/登録(されていません|がありません)/.test(noteText)
12725
+ && cap === "開発" && (!adapter || adapter === "github")
12726
+ && Array.isArray(githubOwnersView()) && githubOwnersView().length === 0
12727
+ // 一覧の 1 行が出る条件(liveListWanted と、行が 0 本)と同じにする。投入の口が無い案件では
12728
+ // 一覧の箱が出ないので、この一文が唯一の言葉になる
12729
+ && !!SITE.intake
12730
+ && !(fleetVal("externalSources") || []).some(function (x) { return sourceAdapter(x.type) === "github"; })));
12663
12731
  if (!unsetDup) {
12664
12732
  var noteEl = el("p", { class: "modal-desc", text: noteText });
12665
12733
  // **消さずに hidden で伏せる。** 節点を残しておかないと、この一文を探している
@@ -16380,7 +16448,7 @@ ${calendarAddUrl.toString()}
16380
16448
  requiredNote: "チャンネルのURLを入力してください。",
16381
16449
  // 🔴 **追加の欄は入力と[追加]だけ(c-07)。** 以前は「/invite を貼る → リンクを貼る → 組織不明なら接続 →
16382
16450
  // Gold 昇格の対象」の手順 4 行を置いていたが、足してから読めなければ、そのチャンネルの行の中が
16383
- // 理由に合った一手(「Cortex が招待されていません:/invite @Cortex[コピー]」・「この Slack を Cortex に接続してください。[接続する]」)を出す。
16451
+ // 理由に合った一手(「Cortex を招待してください:/invite @Cortex[コピー]」。接続の一手は組の先頭(slackConnectNote))を出す。
16384
16452
  // 「毎晩の Gold 昇格の対象・止め方」「お客様の Slack は管理者の承認が要る」は、モーダル上部の説明文が 1 回だけ持つ。
16385
16453
  // **選んだワークスペースを送る(#104)。** 空文字=社内ワークスペースなのでキーごと落とす
16386
16454
  // (サーバ側は「未宣言・null・空」を区別しない約束で、無いことで既定を表す)
@@ -17376,10 +17444,11 @@ ${calendarAddUrl.toString()}
17376
17444
  // 印(orgUnknown)があれば出す。**印が無い行(測っていない)には何も出さない**
17377
17445
  if (s.type === "slack" && s.orgUnknown === true && !s.gate && SITE.intake) {
17378
17446
  var pendingParts = slackRowHelpParts(s);
17379
- if (pendingParts) card.appendChild(restingHelpNode(pendingParts, "ds-gate-help ds-gate-resting"));
17447
+ if (pendingParts && pendingParts.length) card.appendChild(restingHelpNode(pendingParts, "ds-gate-help ds-gate-resting"));
17380
17448
  } else if (!(opts && opts.quietHelp) && showsRestingReason(s)) {
17381
17449
  var restingParts = restingHelpPartsOf(s.type, s.gate, s);
17382
- if (restingParts) card.appendChild(restingHelpNode(restingParts, "ds-gate-help ds-gate-resting"));
17450
+ // 空の配列は「行には何も出さない」(接続は組の先頭が言う・slackRowHelpParts)。夜間の理由文にも落とさない
17451
+ if (restingParts) { if (restingParts.length) card.appendChild(restingHelpNode(restingParts, "ds-gate-help ds-gate-resting")); }
17383
17452
  else if (!(String(s.type).indexOf("github") === 0 && (s.gate === "unreachable" || s.gate === "no_token") && !githubOrgRefused(s))) {
17384
17453
  // GitHub の読めない行は表が一手を決める(出さないと決めた行=確かめられなかった組織には、
17385
17454
  // 理由文も重ねない)。テナント外の断りだけ、サーバの needed の 1 文がここへ来る
@@ -20491,6 +20560,10 @@ ${calendarAddUrl.toString()}
20491
20560
  app.appendChild(genBody);
20492
20561
  loadBody(r, genBody);
20493
20562
 
20563
+ // 関連の資料(#1094 F8)。本文の後・取り下げの節の前。ルール・用語にしか載らない
20564
+ var relm2 = relatedMaterialsSection(r);
20565
+ if (relm2) app.appendChild(relm2);
20566
+
20494
20567
  // 取り下げ(便 4-2d)。本文の後・「その後の記録」の前。取り下げの無い記録では何も作らない
20495
20568
  var retr = retractSection(r);
20496
20569
  if (retr) app.appendChild(retr);
@@ -21466,6 +21539,10 @@ ${calendarAddUrl.toString()}
21466
21539
  app.appendChild(ul);
21467
21540
  }
21468
21541
 
21542
+ // 関連の資料(#1094 F8)。「参照」(根拠)の後・置き換えの前。根拠と混ぜない
21543
+ var relm = relatedMaterialsSection(d);
21544
+ if (relm) app.appendChild(relm);
21545
+
21469
21546
  // 置き換え(#699 F3)。本文・参照の後、「その後の記録」の前。置き換えの無い決定では何も作らない
21470
21547
  var sup = supersedeSection(d);
21471
21548
  if (sup) app.appendChild(sup);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.12.132",
3
+ "version": "0.12.134",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,