@takagaki/cortex-decisions-viewer 0.12.124 → 0.12.126

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.
Files changed (2) hide show
  1. package/dist/render.js +108 -272
  2. package/package.json +1 -1
package/dist/render.js CHANGED
@@ -5487,7 +5487,6 @@ a.ds-name:hover { text-decoration: underline; }
5487
5487
  border: 1px solid #f0b429; background: #fffdf5; border-radius: 12px;
5488
5488
  padding: 12px 16px; display: flex; flex-direction: column; gap: 8px;
5489
5489
  }
5490
- .ds-orgnote.is-resolved { border-color: transparent; background: transparent; padding: 0; }
5491
5490
  .ds-orgnote-title { font-weight: 700; font-size: 13.5px; color: #8a5a00; }
5492
5491
  /* 案内が指す行。**囲うことで「どのチャンネルの話か」を示す**(開閉はしない) */
5493
5492
  .ds-orgnote-rows { display: flex; flex-direction: column; gap: 8px; margin-top: 2px; }
@@ -5755,10 +5754,6 @@ a.ds-tile:hover { text-decoration: none; }
5755
5754
  とは別物で、同じ色にすると「押して繋ぎましょう」と読まれる */
5756
5755
  .ds-gate-off { color: #9ca3af; }
5757
5756
  .ds-pipes { display: flex; flex-direction: column; gap: 8px; }
5758
- /* GitHub App のインストールへのリンク。**独立した「組織ごとの接続状況」の節は
5759
- 2026-08-20 に廃止した**(行のラベル+必要な行だけ囲う形へ)が、
5760
- このクラスだけは案内と手順の両方で使い続けている */
5761
- .ds-owner-install { font-size: 12.5px; white-space: nowrap; }
5762
5757
  /* 実行状況の行に直し方を添える。同じ run の未達を別の節にも出すと画面に2回並ぶ */
5763
5758
  .ds-pipe-wrap { display: flex; flex-direction: column; gap: 3px; }
5764
5759
  .ds-pipe-todo { font-size: 12.5px; color: var(--muted); line-height: 1.7; padding-left: 4px; }
@@ -9927,11 +9922,13 @@ ${calendarAddUrl.toString()}
9927
9922
  * 行と能力タイルが「トークン未設定」と言う**状態を作らないこと。
9928
9923
  *
9929
9924
  * **help は付けない。** 次の一手(インストール導線)は組織ごとの案内
9930
- * (githubNotConnectedNodes)が1つだけ持つ。行ごとに繰り返すと一覧が案内で埋まる。
9925
+ * (githubRowHelpParts)が行ごとに持つ(#1233・帯は撤去した)。
9931
9926
  * ----------------------------------------------------------------------- */
9932
9927
  github: {
9933
9928
  text: "App が未インストール",
9934
- cls: "ds-gate-muted",
9929
+ // 読めていない=記録できていない=要対応。灰色(muted)だと「まだ何もしていないだけ」に見え、
9930
+ // 気づかれないまま記録が止まる(2026-10-10 オーナー)。既存の警告色(ds-gate-warn)に揃える
9931
+ cls: "ds-gate-warn",
9935
9932
  },
9936
9933
  /* GitHub で、案件のテナントに無い組織を窓口が断った回(#841)。gate は同じ no_token でも
9937
9934
  * 「App が未インストール」と言うと、利用者が導入を探しに行く(窓口は導入・リポの有無を
@@ -9939,7 +9936,8 @@ ${calendarAddUrl.toString()}
9939
9936
  * **help は付けない。** 次の一手(担当者へ)はサーバの needed の 1 文が持つ */
9940
9937
  githubRefused: {
9941
9938
  text: "確かめられません",
9942
- cls: "ds-gate-muted",
9939
+ // 読めていない(記録できていない)点は「App が未インストール」と同じ=要対応なので同じ警告色
9940
+ cls: "ds-gate-warn",
9943
9941
  },
9944
9942
  };
9945
9943
  /** 窓口がテナント外の組織として断った印(Intake の応答の reason・ストアの行の detail。#841) */
@@ -9952,13 +9950,13 @@ ${calendarAddUrl.toString()}
9952
9950
  * 休止状態の行に、状態の語に添えて**押す前から**出す定型の補足(#346)と、
9953
9951
  * 「接続を確認」を押した結果に添える定型の1文(#356)。
9954
9952
  * 鍵は「アダプタ種別(helpTypeOf)× 状態」。値は { resting, probed } で、どちらも文の
9955
- * パーツの配列。文字列はテキスト、{ link: <リンクの文字列> } は GitHub App の
9956
- * インストール設定へのリンク(GITHUB_APP_INSTALL_URL)。
9953
+ * パーツの配列。文字列はテキスト、{ link, kind } は GitHub App の
9954
+ * リンク(githubAppLinkUrl(kind) が宛先を作る)。
9957
9955
  *
9958
9956
  * ## 文の長さ(#356・オーナー却下を受けた原則)
9959
9957
  * **帯は症状だけ・行は具体的な一手だけ・説明を繰り返さない。** 0.12.22 では帯と行と
9960
9958
  * 押した結果に同じ admin の4文が3回出ており、オーナーが「長すぎ・冗長」と却下した。
9961
- * - resting … **1文+リンクだけ**(誰が・どこで。「何が起きているか」は帯が言う)
9959
+ * - resting … **1文+リンクだけ**(誰が・どこで。「何が起きているか」は状態の札が言う)
9962
9960
  * - probed … **状態に応じた1文だけ**(1行目のサーバの needed が言わないことだけ)。
9963
9961
  * 押した結果に resting を繰り返さない——resting は押した瞬間に隠れ、needed が
9964
9962
  * 同じ操作(Configure から追加)を宛先つきで言う
@@ -9976,7 +9974,7 @@ ${calendarAddUrl.toString()}
9976
9974
  * 🔴 **DS_GATE[状態] が help を持つ状態にはエントリを置かない。** 置くと行の補足が2段になる
9977
9975
  * (github-state-reason.test.mjs の「行の補足は最大1段」が見張る)。
9978
9976
  *
9979
- * 🔴 **URL を文字列で書き写さない**(帯・押した結果と同じ定数を使う。写経すると張り替えで
9977
+ * 🔴 **URL を文字列で書き写さない**(押した結果と同じ定数を使う。写経すると張り替えで
9980
9978
  * 片方だけ古くなる)。
9981
9979
  *
9982
9980
  * エントリがある状態では**この文だけ**を出し、サーバの needed / detail は出さない
@@ -9990,19 +9988,19 @@ ${calendarAddUrl.toString()}
9990
9988
  */
9991
9989
  var DS_GATE_RESTING_HELP = {
9992
9990
  github: {
9991
+ // 🔴 **読めない行の中に、理由に合った一手だけを出す(#1233)。** 全体の帯は撤去した。
9992
+ // 一手は組織の App の導入状況(githubRowHelpParts)で決まるので、関数で持つ
9993
9993
  unreachable: {
9994
- // 誰が(admin)・どこで(Configure の Repository access)だけ。理由は帯、宛先はリンクが持つ。
9995
- // 着地点(Repository access)を名指しするのは、押す前の画面からこの語が消えないため
9996
- //(設計レビュー②)。「admin が…してください」はオーナーの原文の形
9997
- resting: [
9998
- "このリポジトリの admin(管理者権限を持つ人)が、Configure の Repository access に追加してください。",
9999
- { link: "インストール設定を開く" },
10000
- ],
9994
+ resting: function (row) { return githubRowHelpParts(row); },
10001
9995
  // 2026-09-02 の実測: admin でないリポジトリを Configure で選ぶと「request」タグが付き、
10002
9996
  // 組織オーナーの承認待ちになる("Okay, updated" と出るのに対象に入らない)。
10003
9997
  // 1行目(サーバの needed)はこれを言わないので、ここだけが持つ
10004
9998
  probed: ["GitHub 側で request と表示された場合は、組織オーナーの承認待ちです。"],
10005
9999
  },
10000
+ // App が組織に入っていない行(鍵が 1 本も無かった)。帯を撤去したので、この行が一手を持つ
10001
+ no_token: {
10002
+ resting: function (row) { return githubRowHelpParts(row); },
10003
+ },
10006
10004
  },
10007
10005
  };
10008
10006
  /**
@@ -10019,9 +10017,32 @@ ${calendarAddUrl.toString()}
10019
10017
  return (byType && byType[gate]) || null;
10020
10018
  }
10021
10019
  /** 休止状態の行に出すパーツ(無ければ null) */
10022
- function restingHelpPartsOf(type, gate) {
10020
+ function restingHelpPartsOf(type, gate, row) {
10023
10021
  var e = restingHelpEntryOf(type, gate);
10024
- return (e && e.resting) || null;
10022
+ var r = e && e.resting;
10023
+ return (typeof r === "function" ? r(row) : r) || null;
10024
+ }
10025
+ /**
10026
+ * GitHub の読めない行に出す一手(#1233)。**組織の App の導入状況で理由に合わせる**。
10027
+ * 窓口の断りの名前(installation_not_found 等)は行まで届いていないので、同じ分かれ目の
10028
+ * 「appInstalled」 を使う(true=App は入っている=このリポジトリが選ばれていない)。
10029
+ *
10030
+ * - no_token(鍵が 1 本も無い)/appInstalled が false・不明 → 「App を入れてください」(広い方)
10031
+ * - unreachable で appInstalled が true → 「このリポジトリを選んでください」
10032
+ *
10033
+ * 出さないもの: テナント外の断り(#841・導入の有無を明かさない)と、確かめられなかった
10034
+ * 組織(source: "unknown"・帯が導線を出さない設計)
10035
+ */
10036
+ function githubRowHelpParts(row) {
10037
+ if (!row) return null;
10038
+ if (githubOrgRefused(row)) return null;
10039
+ var owner = String(row.ref || "").split("/")[0];
10040
+ var meta = owner ? githubOwnerMeta(owner) : null;
10041
+ if (meta && meta.source === "unknown") return null;
10042
+ if (row.gate === "unreachable" && meta && meta.appInstalled === true) {
10043
+ return ["GitHub App の設定で、このリポジトリを選んでください。", { link: "インストール設定を開く →", kind: "settings" }];
10044
+ }
10045
+ return ["この組織に Cortex の GitHub App を入れてください。", { link: "GitHub App を入れる →", kind: "install" }];
10025
10046
  }
10026
10047
  /** 押した結果に添えるパーツ(無ければ null)。行と同じ表から引く(写経しない) */
10027
10048
  function probedHelpPartsOf(type, gate) {
@@ -10033,7 +10054,7 @@ ${calendarAddUrl.toString()}
10033
10054
  var p = el("p", { class: cls });
10034
10055
  parts.forEach(function (part) {
10035
10056
  if (typeof part === "string") p.appendChild(document.createTextNode(part));
10036
- else if (part && part.link) p.appendChild(el("a", { href: GITHUB_APP_INSTALL_URL, target: "_blank", rel: "noopener", text: part.link }));
10057
+ else if (part && part.link) p.appendChild(el("a", { href: githubAppLinkUrl(part.kind), target: "_blank", rel: "noopener", text: part.link }));
10037
10058
  });
10038
10059
  return p;
10039
10060
  }
@@ -10088,16 +10109,18 @@ ${calendarAddUrl.toString()}
10088
10109
  * - 状態がある(未測定の行には出すものが無い)
10089
10110
  * - ok でない
10090
10111
  * - missing_scope でない(スコープ名の札 .ds-probe-scope が既に持つ)
10091
- * - no_token でない(GitHub は組織の帯が導線を1つだけ持つ設計・Slack は DS_GATE_NO_TOKEN の help)。
10092
- * **ただし GitHub のテナント外の断り(#841)は出す**——帯は出ない(導入状態が分からない)ので、
10093
- * 「担当者へ」の 1 文(needed)を持つのはこの行だけ
10112
+ * - no_token でない(Slack は DS_GATE_NO_TOKEN の help)。
10113
+ * **GitHub の no_token は出す**(#1233・帯を撤去したので行が一手を持つ。
10114
+ * テナント外の断り(#841)は「担当者へ」の 1 文(needed))
10094
10115
  * - not_in_channel でない(help は無いが、**状態の語そのものが操作の指示**
10095
10116
  * 「Slackで招待してください」。その下に夜間の「読めませんでした: not_in_channel」を
10096
10117
  * 並べても情報が増えず、招待という具体的な指示を薄める。help の有無とは別の軸)
10097
10118
  * - dsGateOf(s).help が無い(あれば DS_GATE の固定文が次の一手を持っている)
10098
10119
  */
10099
10120
  function showsRestingReason(s) {
10100
- if (s.gate === "no_token" && String(s.type || "").indexOf("github") === 0 && githubOrgRefused(s)) return true;
10121
+ // GitHub の no_token は常に出す(#1233・帯を撤去したので、行が一手を持つ)。
10122
+ // 非テナント外は githubRowHelpParts の一手、テナント外の断り(#841)はサーバの needed の 1 文
10123
+ if (s.gate === "no_token" && String(s.type || "").indexOf("github") === 0) return true;
10101
10124
  if (!s.gate || s.gate === "ok" || s.gate === "missing_scope" || s.gate === "no_token" || s.gate === "not_in_channel") return false;
10102
10125
  return !dsGateOf(s).help;
10103
10126
  }
@@ -10985,26 +11008,13 @@ ${calendarAddUrl.toString()}
10985
11008
  var again = !!(x.ref && seenRef[x.ref]);
10986
11009
  if (x.ref) seenRef[x.ref] = 1;
10987
11010
  var rowCard = extSourceCard(x, DS_TYPE[x.type] || { icon: "🔗", label: x.type || "その他" }, { quietHelp: again });
10988
- // 同じリポの issues / discussions を、接続確認の結果で揃えるための目印(updateGithubOrgBand)
11011
+ // 同じリポの issues / discussions を、接続確認の結果で揃えるための目印(syncGithubSiblingRows)
10989
11012
  if (rowCard && rowCard.setAttribute && x.ref) rowCard.setAttribute("data-ref", x.ref);
10990
11013
  return rowCard;
10991
11014
  });
10992
- if (g.state === "warn") {
10993
- var warnBox = orgNoteBox(githubNotConnectedNodes(g), cards);
10994
- // 「接続を確認」が通ったとき帯をその場で畳めるよう、いま読めていないリポの一覧を持たせる
10995
- //(probeSection → updateGithubOrgBand)。同じリポの issues / discussions は 1 本と数える
10996
- var unreadRefs = [];
10997
- g.items.forEach(function (x) {
10998
- if (x.ref && x.gate && x.gate !== "ok" && unreadRefs.indexOf(x.ref) < 0) unreadRefs.push(x.ref);
10999
- });
11000
- warnBox.setAttribute("data-unread-refs", JSON.stringify(unreadRefs));
11001
- // 見出しの件数は夜間の値のことがある(画面の行数と違う)。初期値を持ち、増減だけ当てる
11002
- var titleEl = warnBox.querySelector(":scope > .ds-orgnote-title");
11003
- var m0 = titleEl ? /^⚠️ (\\d+)件のリポジトリを読み取れていません/.exec(titleEl.textContent || "") : null;
11004
- if (m0) warnBox.setAttribute("data-unread-count", m0[1]);
11005
- out.push(warnBox);
11006
- return;
11007
- }
11015
+ // 🔴 **読めない組織を箱で囲まない(#1233)。** 読めないリポジトリが 1 件あるだけで、
11016
+ // 並んでいる全部のタイルが黄色の枠に入っていた。エラーは読めない行の中だけに出す
11017
+ //(理由に合った一手は extSourceCard の githubRowHelpParts)。
11008
11018
  if (g.state === "unsure") {
11009
11019
  // **確かめられなかった夜は、そう言う。** gh の不在・タイムアウト・
11010
11020
  // ネットワーク断で起きる。「接続OK」と出すと同じ画面の集計と食い違い、
@@ -11019,28 +11029,17 @@ ${calendarAddUrl.toString()}
11019
11029
  }
11020
11030
 
11021
11031
  /**
11022
- * 「接続を確認」の結果を、行が属する組織の帯へ反映する。
11032
+ * 「接続を確認」の結果を、同じリポジトリの兄弟の行(issues / discussions)へそろえる。
11023
11033
  *
11024
- * 読めた行を帯の「読めていないリポ」から外し、**最後の 1 本だったら帯を畳む**。
11025
- * まだ読めない行が残るなら帯は残し、見出しの件数だけ減らす。読めなかった結果は
11026
- * 帯に戻す(読めていた行が後から読めなくなった場合も、帯が嘘をつかない)。
11027
- * 帯が無い行(組織が繋がっている)では何もしない。
11034
+ * 帯は撤去した(#1233)。残すのは「行は 2 本でも接続は 1 つ」なので押した行と同じ判定に
11035
+ * そろえる仕事だけ。**条件なしで毎回そろえる**(帯の有無・状態の変化に依らない)。
11036
+ * 兄弟は同じ親(一覧・確かめられなかった組織の箱)の直下にいる。
11028
11037
  */
11029
- function updateGithubOrgBand(card, ref, ok) {
11030
- var box = card.closest ? card.closest(".ds-orgnote") : null;
11031
- if (!box || !ref) return;
11032
- var raw = box.getAttribute("data-unread-refs");
11033
- if (raw == null) return;
11034
- var refs;
11035
- try { refs = JSON.parse(raw) || []; } catch (e) { return; }
11036
- var at = refs.indexOf(ref);
11037
- if (ok && at >= 0) refs.splice(at, 1);
11038
- else if (!ok && at < 0) refs.push(ref);
11039
- else return;
11040
- box.setAttribute("data-unread-refs", JSON.stringify(refs));
11041
- // 同じリポの兄弟の行(issues / discussions)も、押した行と同じ判定に揃える
11038
+ function syncGithubSiblingRows(card, ref, ok) {
11039
+ var parent = card.parentNode;
11040
+ if (!parent || !ref) return;
11042
11041
  var gateSrc = card.querySelector(".ds-gate");
11043
- var sibs = box.querySelectorAll(".ds-card[data-ref]");
11042
+ var sibs = parent.querySelectorAll(":scope > .ds-card[data-ref]");
11044
11043
  for (var si = 0; gateSrc && si < sibs.length; si++) {
11045
11044
  var sib = sibs[si];
11046
11045
  if (sib === card || sib.getAttribute("data-ref") !== ref) continue;
@@ -11049,31 +11048,6 @@ ${calendarAddUrl.toString()}
11049
11048
  var sh = sib.querySelectorAll(".ds-gate-help");
11050
11049
  for (var hi = 0; hi < sh.length; hi++) sh[hi].hidden = ok;
11051
11050
  }
11052
- var title = box.querySelector(":scope > .ds-orgnote-title");
11053
- var cnt = parseInt(box.getAttribute("data-unread-count"), 10);
11054
- if (!isNaN(cnt)) {
11055
- cnt = Math.max(0, cnt + (ok ? -1 : 1));
11056
- box.setAttribute("data-unread-count", String(cnt));
11057
- }
11058
- var hasBand = !!title;
11059
- if (!hasBand) return;
11060
- if (refs.length === 0) {
11061
- // 帯だけを隠す。行(.ds-orgnote-rows)は残す
11062
- for (var i = 0; i < box.children.length; i++) {
11063
- var c = box.children[i];
11064
- if (c.classList.contains("ds-orgnote-rows")) continue;
11065
- c.hidden = true;
11066
- }
11067
- box.classList.add("is-resolved");
11068
- return;
11069
- }
11070
- for (var k = 0; k < box.children.length; k++) {
11071
- var ch = box.children[k];
11072
- if (!ch.classList.contains("ds-orgnote-rows")) ch.hidden = false;
11073
- }
11074
- box.classList.remove("is-resolved");
11075
- // 見出しが件数を持つ形(「N件のリポジトリを読み取れていません」)だけ数え直す
11076
- if (!isNaN(cnt)) title.textContent = "⚠️ " + Math.max(1, cnt) + "件のリポジトリを読み取れていません";
11077
11051
  }
11078
11052
 
11079
11053
  /** 確かめられなかった組織の案内。**導線は出さない** */
@@ -11092,111 +11066,6 @@ ${calendarAddUrl.toString()}
11092
11066
  ];
11093
11067
  }
11094
11068
 
11095
- /**
11096
- * 繋がっていない組織の案内。
11097
- *
11098
- * **「読めない」の原因は1つではない。** 以前はどの組織にも
11099
- * 「この組織に Cortex の GitHub App を入れると読めるようになります」と出していたが、
11100
- * **App は入っているのにそのリポジトリが選ばれていない**組織にはこれが効かない。
11101
- * インストールは済んでいるので、押しても画面は変わらず、何度押しても直らない。
11102
- *
11103
- * 「appInstalled」 が原因を分ける(engine がインストールトークンを取れたかどうか):
11104
- *
11105
- * | 値 | 意味 | 案内 |
11106
- * |---|---|---|
11107
- * | 「false」 | App のトークンが取れなかった=未インストール | インストールへ |
11108
- * | 「true」 | 取れたのに読めない=そのリポジトリが未選択 | **インストール設定**へ |
11109
- * | 「null」 | その夜は確かめられなかった | **どちらも出さない**(押しても直るとは限らない) |
11110
- *
11111
- * **自社か顧客かで文言を分けない。** 組織名(「classmethod-*」)で分岐すると、
11112
- * 新しい自社組織が増えたときに黙って間違った案内を出す。どちらにも通じる文にする。
11113
- */
11114
- function githubNotConnectedNodes(g) {
11115
- var out = [];
11116
- var o = g.meta || {};
11117
- // **件数はグループが数えたものを優先する(工程1.5)。** まとめ表の 「repos」 /
11118
- // 「unreadable」 は夜間の値で、いま画面に出ている行の数と食い違うことがある
11119
- //(#101 で3度直した形)。「groupGithubByOwner」 は**いま並んでいる行**を数えている
11120
- var repos = o.repos != null ? o.repos : g.repos != null ? g.repos : g.items.length;
11121
- var unread = o.unreadable != null ? o.unreadable : g.unread != null ? g.unread : g.items.length;
11122
- var installed = o.appInstalled;
11123
- // **読める件数を出す。** 総数だけ出すと、同じ画面の集計と食い違う(#101 で3度直した形)
11124
- var head = repos + "リポジトリ中 " + unread + "件が読めていません。";
11125
- // 🔴 **見出しは 「installed」 の分岐の中で出す(#346)。** ここで1つに畳んでいたので、
11126
- // App 導入済みの組織にも「まだ接続されていません」と出て、**同じ帯の本文と矛盾**した
11127
- // (実機でオーナーが踏み、利用者が「組織の接続からやり直し」と誤解した)
11128
- if (installed === true) {
11129
- // 🔴 **帯は症状だけ(#356・オーナー却下を受けた原則)。** 0.12.22 ではここに9文
11130
- // (App の説明・Configure の手順・admin の4文・移動改名削除・お客様の組織)を入れ、
11131
- // 同じ説明が行と押した結果にも出て3回繰り返された。見出しは件数だけ・本文は2文だけ。
11132
- // **組織名は見出しに入れない**——各行のバッジ「{組織}(GitHub App)」が持っている。
11133
- // 組織が複数ある画面でも、組織ごとの帯のまま・見出しは同じ形。
11134
- //
11135
- // **見出しでは「読み取り対象に選ばれていません」と言い切らない。** 「appInstalled」 が
11136
- // 分けられるのは「①未インストール」と「②未選択/③消えた・改名」までで、**②と③は
11137
- // 分かれない**(App のトークンではどちらも 404)。見出しは事実だけを言う
11138
- out.push(el("div", {
11139
- class: "ds-orgnote-title",
11140
- text: "⚠️ " + unread + "件のリポジトリを読み取れていません",
11141
- }));
11142
- // App は入っている。**インストールをもう一度促さないこと**——済んでいる操作を促すのは
11143
- // 「設定する必要が無いものに設定を促す」偽の警告と同じで、しかも直らない。
11144
- //
11145
- // 「誰が・どこで」は各行の1文(DS_GATE_RESTING_HELP)が持つ。ここで繰り返さない。
11146
- // 「移動・改名・削除の可能性 → 登録から外して」も言わない——②と③を区別する材料が
11147
- // 無く、外す手段は行の「登録から削除」(#354)が常に持つ。
11148
- // 「お客様の組織では、組織のオーナーに承認を依頼」も外した——request(承認待ち)の
11149
- // 1文は押した結果が持つ(同じ表の probed)。
11150
- //
11151
- // ⚠ **件数の文 「head」(「{N}リポジトリ中 {M}件が読めていません。」)もこの枝では
11152
- // 出さない(#356)。** #101 で3度直した「読める件数を出す」を意図して覆した——見出しが
11153
- // 件数を持つので、本文で二重に言うと帯が3文になる。分母(登録数)は画面から消えるが、
11154
- // 箱の中に行が全部並んでいるので数えられる。false / null の枝は従来どおり head を出す。
11155
- //
11156
- // **「各行の案内」ではなく「アクセス不可の行の案内」と言う。** 帯の箱には読めている行も
11157
- // 一緒に入る(unread が1件でもあれば組織ごと warn)。案内を持つのは「アクセス不可」の
11158
- // 行だけなので、行に出ている状態の語そのもので指す(設計レビュー②の指摘)。
11159
- //
11160
- // **「読み取り対象に入っていません」はオーナーの文(#356)。** 2026-08-21 の
11161
- // 「②未選択と③消えた・改名を区別できないので断定しない」は、帯の本文については
11162
- // この文で覆した(見出しは引き続き断定しない)。③の逃げ道は「登録から削除」。
11163
- //
11164
- // **設定画面の宛先は App 個別ページ(#346)。** いまの宛先と、そこに着ける人の条件は
11165
- // 「appSettingsLink」 の項にある
11166
- out.push(el("p", {
11167
- class: "ds-group-note",
11168
- text: "GitHub App の読み取り対象に入っていません。アクセス不可の行の案内に従って追加してください。",
11169
- }));
11170
- out.push(appSettingsLink("インストール設定を開く →"));
11171
- return out;
11172
- }
11173
- if (installed === false) {
11174
- out.push(el("div", { class: "ds-orgnote-title", text: "⚠️ " + g.title + " はまだ接続されていません" }));
11175
- out.push(el("p", {
11176
- class: "ds-group-note",
11177
- text: head + "この組織に Cortex の GitHub App を入れると読めるようになります(Issues の読み取りだけ)。"
11178
- + "お客様の組織では、組織のオーナーに承認を依頼してください。",
11179
- }));
11180
- out.push(appInstallLink("この組織にインストール →"));
11181
- return out;
11182
- }
11183
- // 「null」(確かめられなかった)と、この値を知らない古い fleet-status.json。
11184
- // **導線を出さない。** どちらが原因か分からないので、押させると外れたほうを
11185
- // 押させることになる(済んでいるインストールをもう一度、あるいは効かない設定画面へ)。
11186
- //
11187
- // 見出しは件数を言わない(件数は本文だけが持つ・見出しと二重に言わない)。
11188
- // 「githubUnsureNodes」 の「接続を確認できませんでした」(=その夜、確かめる処理自体が
11189
- // 走らなかった)とは意味が違う——こちらは**読めなかった事実はあるが、App の導入状況が
11190
- // 分からない**ので、語を分ける
11191
- out.push(el("div", { class: "ds-orgnote-title", text: "⚠️ " + g.title + " のリポジトリが読めていません(原因は確かめられていません)" }));
11192
- out.push(el("p", {
11193
- class: "ds-group-note",
11194
- text: head + "原因(GitHub App が入っていない/入っているがこれらのリポジトリが選ばれていない)は、"
11195
- + "今回の実行では確かめられませんでした。翌朝の表示をご確認ください。",
11196
- }));
11197
- return out;
11198
- }
11199
-
11200
11069
  /**
11201
11070
  * Slack のチャンネルを**平らに**並べる(2026-08-20)。
11202
11071
  *
@@ -11398,38 +11267,14 @@ ${calendarAddUrl.toString()}
11398
11267
  var GITHUB_APP_INSTALL_URL = "https://github.com/apps/classmethod-cortex-reader/installations/new";
11399
11268
 
11400
11269
  /**
11401
- * GitHub App のインストールへ行くリンク(2026-08-20 に部品化)。
11402
- *
11403
- * **同じものを2箇所に書かない。** 組織ごとの案内と、追加フォームの手順が
11404
- * 同じ導線を持つ(#138 で「1箇所にしか無い」ことが事故になったので、
11405
- * **むしろ複数あるのが正しい**)。写経すると、URLの張り替えで片方だけ古くなる。
11406
- *
11407
- * **正本は手順の側。** 組織ごとの案内は行が無いと出ないので、
11408
- * 行0件の案件では手順側しか残らない。
11409
- *
11410
- * **⚠️ ただし手順は追加フォームの中にあり、追加フォームは
11411
- * SITE.intake が無いと丸ごと消える**(renderExternalAdders の冒頭)。
11412
- * つまり **intake 無し+行0件** の案件では App の導線が1本も無くなる。
11413
- * いまは config.ts の intakeUrl が艦隊で1つ・全案件に渡っているので
11414
- * その組み合わせは起きない(2026-08-20 に確認)。
11415
- * **案件ごとに intake を出し分けるようになったら、ここを見直すこと。**
11416
- */
11417
- function appInstallLink(label) {
11418
- return el("a", {
11419
- class: "ds-owner-install",
11420
- href: GITHUB_APP_INSTALL_URL,
11421
- target: "_blank", rel: "noopener",
11422
- text: label || "GitHub App を入れる →",
11423
- });
11424
- }
11425
-
11426
- /**
11427
- * すでに入っている App の**インストール設定**(対象リポジトリの追加)へ行くリンク。
11270
+ * GitHub App の宛先 URL の作り手(入れる/インストール設定)。
11271
+ * すでに入っている App の**インストール設定**(対象リポジトリの追加)へ行くリンクの宛先でもある。
11428
11272
  *
11429
11273
  * **宛先は App 個別ページ(「GITHUB_APP_INSTALL_URL」 と同じ定数・#346)。**
11430
11274
  * 「infra/lambda/shared/github-gate.mjs」 の 「githubConfigureUrl」 とも同じ宛先なので、
11431
- * **押す前(この帯・行の補足)と押した後(確認結果の文中)でリンク先が割れない**。
11432
- * 関数は残してある——呼び手が「入れる」ではなく「設定を開く」意図で呼ぶ場所だから。
11275
+ * **押す前(行の一手)と押した後(確認結果の文中)でリンク先が割れない**。
11276
+ * 「kind」(install / settings)は意図を渡すための引数で、いまは宛先が同じ。会社ごとの App
11277
+ *(classmethod-cortex-portal #254)で割れる日に、ここだけを直す。
11433
11278
  *
11434
11279
  * ## なぜ他の2つの宛先を使わないか
11435
11280
  *
@@ -11453,13 +11298,11 @@ ${calendarAddUrl.toString()}
11453
11298
  * **GitHub 側の画面が変わったらここが最初に嘘になる。** 宛先を変えるときは
11454
11299
  * 「githubConfigureUrl」(サーバ)と揃えること。
11455
11300
  */
11456
- function appSettingsLink(label) {
11457
- return el("a", {
11458
- class: "ds-owner-install",
11459
- href: GITHUB_APP_INSTALL_URL,
11460
- target: "_blank", rel: "noopener",
11461
- text: label || "インストール設定を開く →",
11462
- });
11301
+ function githubAppLinkUrl(kind) {
11302
+ // 「kind」: "install"(組織に App を入れる)/"settings"(入っている App の対象リポジトリを選ぶ)。
11303
+ // いまは同じ宛先(App 個別ページ)。会社ごとの App(classmethod-cortex-portal #254)が動くと
11304
+ // 宛先が変わるので、**行の案内のリンクは全部ここを通す**(URL を 1 か所から作る)
11305
+ return ({ install: GITHUB_APP_INSTALL_URL, settings: GITHUB_APP_INSTALL_URL })[kind] || GITHUB_APP_INSTALL_URL;
11463
11306
  }
11464
11307
 
11465
11308
  /**
@@ -14316,9 +14159,8 @@ ${calendarAddUrl.toString()}
14316
14159
  // 再読み込みまで)で、「接続を確認 → 閉じる → その場で接続OK」にならない。
14317
14160
  // 据え置きあり=GitHub は叩かない(ストアの行は据え置きの対象外で毎回引く)。
14318
14161
  // 取り込む能力の即答(appendDispatchProbe)は先に同じ 1 行を持っている
14319
- // 組織の帯も同じ結果で描き直す(読めた最後の 1 本なら帯が消える)。
14320
- // 帯はページ描画時に 1 度だけ組むので、ここで触らないと再読み込みまで残る
14321
- if (probeTypeOf(s.type) === "github") updateGithubOrgBand(card, s.ref, j.gate === "ok");
14162
+ // 同じリポジトリの兄弟の行(issues / discussions)も同じ判定にそろえる
14163
+ if (probeTypeOf(s.type) === "github") syncGithubSiblingRows(card, s.ref, j.gate === "ok");
14322
14164
  reloadLiveState();
14323
14165
  } catch (e) {
14324
14166
  msg.className = "ds-toggle-msg is-error";
@@ -14334,11 +14176,10 @@ ${calendarAddUrl.toString()}
14334
14176
  label: "登録を解除",
14335
14177
  confirmLines: function () {
14336
14178
  return [
14337
- "「" + (s.name || s.ref) + "」を、Gold 昇格の読み取り対象から外します。",
14179
+ "「" + (s.name || s.ref) + "」を、読み取り対象から外します。",
14338
14180
  "",
14339
- "次回の Gold 昇格(毎晩22時ごろ)から、このチャンネルは読み取られなくなります。",
14340
- "",
14341
- "※ 既に Gold 層に入った内容は消えません(Decision・用語集はそのまま残ります)。",
14181
+ // 外したときの約束の 1 文(intake の REMOVED_PROMISE と同じ・cortex-engine #1094 c-30 G7)
14182
+ "外すと、次の晩から読まなくなります。すでに記憶に入った内容は残ります。",
14342
14183
  "",
14343
14184
  "解除しますか?",
14344
14185
  ];
@@ -14433,11 +14274,10 @@ ${calendarAddUrl.toString()}
14433
14274
  label: "登録を解除",
14434
14275
  confirmLines: function () {
14435
14276
  return [
14436
- "「" + (s.name || s.ref) + "」を、Gold 昇格の読み取り対象から外します。",
14437
- "",
14438
- "次回の Gold 昇格(毎晩22時ごろ)から、このスペースは読み取られなくなります。",
14277
+ "「" + (s.name || s.ref) + "」を、読み取り対象から外します。",
14439
14278
  "",
14440
- "※ 既に Gold 層に入った内容は消えません(Decision・用語集はそのまま残ります)。",
14279
+ // 外したときの約束の 1 文(intake の REMOVED_PROMISE と同じ・cortex-engine #1094 c-30 G7)
14280
+ "外すと、次の晩から読まなくなります。すでに記憶に入った内容は残ります。",
14441
14281
  // 解除は通知先の宣言(notify.json)を触らない(#572)。通知先のまま解除すると
14442
14282
  // 行が消えて画面から止められなくなる——先に止める手順をここで言う
14443
14283
  "※ 通知先にしている場合は、先に「通知を止める」を押してください(解除しても通知先は変わりません)。",
@@ -16224,24 +16064,10 @@ ${calendarAddUrl.toString()}
16224
16064
  placeholder: "owner/repo または https://github.com/owner/repo",
16225
16065
  namePlaceholder: "メモ(任意)",
16226
16066
  requiredNote: "リポジトリを入力してください。",
16227
- // **手順のリストにする(2026-08-20・Slack からの横展開)。**
16228
- //
16229
- // **App の導線をここに常設する(#138 の再発防止・唯一の防波堤)。**
16230
- // それまでは「組織ごとの接続状況」という独立した一覧の中にしか
16231
- // 導線が無く、**まだ何も繋いでいない案件=一番 App を入れてほしい案件**の
16232
- // 画面に App へ行く道が1本も無かった(実機で踏んだ)。
16233
- //
16234
- // **行が0件でも、この手順は必ず出る**(追加フォームはグループの外にある)。
16235
- // 組織ごとの案内は行が無いと出ないので、**常設の正本はこちら**。
16236
- // 「案内側に導線があるから手順側は省く」とやると即再発する。
16237
- hint: [
16238
- { text: "読み取りたいリポジトリがある組織に、Cortex の GitHub App を入れます(Issues の読み取りだけ)。", node: appInstallLink() },
16239
- "そのリポジトリを下の欄に入れて「追加」を押します(owner/repo でも、GitHub のURLでも構いません)。",
16240
- // #660: 「Gold 昇格の材料になります」は嘘になった(性質が種類で固定・GitHub は
16241
- // 決定の抽出に使わない)。**手順の最終行が伝える重さは「記録に入る」**——
16242
- // 追加が Gold 昇格の意思決定になるチャット(上の 2 つ)とは別の文にする
16243
- "追加したリポジトリの Issues と PR の活動が、毎晩の記録に入ります(決定・用語集の材料にはしません)。やめるときは、その行の「登録から削除」を押します。",
16244
- ],
16067
+ // 🔴 **追加の欄は入力と[追加]だけ(#1233)。** 以前は「App を入れる → リポジトリを足す」の
16068
+ // 手順(1・2・3)と「GitHub App を入れる →」のリンクを置いていたが、リポジトリを足すのが先で、
16069
+ // 読めなければ足した行の中が理由に合った一手を出す(githubRowHelpParts)。
16070
+ // 「毎晩の記録に入る・決定と用語の材料にはしない」の説明は、モーダル上部の説明文が 1 回だけ持つ。
16245
16071
  build: function (repo, name) { return { op: "add-github-source", repo: repo, name: name }; },
16246
16072
  adder: "github",
16247
16073
  }));
@@ -17149,21 +16975,28 @@ ${calendarAddUrl.toString()}
17149
16975
  //
17150
16976
  // **ボタンより後ろに置く。** カードは横並びの flex なので、間に挟むと
17151
16977
  // 「登録を解除」が案内文の下の行へ落ちて、既存案件の行の形が変わる
17152
- gateHelpNodes(gate, "ds-gate-help").forEach(function (n) { card.appendChild(n); });
17153
- // **最後に測った理由と直し方を、押す前から出す(#346)。** 「アクセス不可 8時間前に確認」
17154
- // だけでは、押さない人(初見の PM 等)が止まる。表にエントリがある状態は定型の補足
17155
- // (リンク込み)だけ、無い状態は needed → detail のフォールバック。どちらも ds-gate-help
17156
- // を付ける——押した結果で置き換えるとき probeSection がまとめて隠す。
17157
- // **同じリポジトリの2本目の行(Discussions)には出さない**(opts.quietHelp)。
17158
- // 同じ長文が2行に並ぶと一覧が案内で埋まる。URL のリンク化は neededNode(innerHTML は使わない)
17159
- if (!(opts && opts.quietHelp) && showsRestingReason(s)) {
17160
- var restingParts = restingHelpPartsOf(s.type, s.gate);
17161
- if (restingParts) card.appendChild(restingHelpNode(restingParts, "ds-gate-help ds-gate-resting"));
17162
- else {
17163
- // **能力に畳んでから渡す(#548)。** ここへ来るのは Slack / GitHub / Google Chat の
17164
- // 行だけなので、ボタンが書いた detail(判定語)は従来どおり出さない
17165
- var reason = stateReasonOf({ needed: s.needed, detail: s.detail, gateBy: s.gateBy, cap: gateCapOfType(s.type) });
17166
- if (reason) card.appendChild(neededNode(reason, "ds-gate-help ds-gate-reason"));
16978
+ // **案内の段は「登録から削除」「接続を確認」より後ろに置く(#1233)。** 案内は 100% 幅の段
16979
+ // なので、間に挟むと「接続を確認」だけが案内の下へ落ち、正常な行と並びが違って見える。
16980
+ // 押した結果(probe.detail)の手前に置く——結果が出たら案内は stale 処理で隠れる
16981
+ function appendRowHelp() {
16982
+ gateHelpNodes(gate, "ds-gate-help").forEach(function (n) { card.appendChild(n); });
16983
+ // **最後に測った理由と直し方を、押す前から出す(#346)。** 「アクセス不可 8時間前に確認」
16984
+ // だけでは、押さない人(初見の PM 等)が止まる。表にエントリがある状態は定型の補足
16985
+ // (リンク込み)だけ、無い状態は needed → detail のフォールバック。どちらも ds-gate-help
16986
+ // を付ける——押した結果で置き換えるとき probeSection がまとめて隠す。
16987
+ // **同じリポジトリの2本目の行(Discussions)には出さない**(opts.quietHelp)。
16988
+ // 同じ長文が2行に並ぶと一覧が案内で埋まる。URL のリンク化は neededNode(innerHTML は使わない)
16989
+ if (!(opts && opts.quietHelp) && showsRestingReason(s)) {
16990
+ var restingParts = restingHelpPartsOf(s.type, s.gate, s);
16991
+ if (restingParts) card.appendChild(restingHelpNode(restingParts, "ds-gate-help ds-gate-resting"));
16992
+ else if (!(String(s.type).indexOf("github") === 0 && (s.gate === "unreachable" || s.gate === "no_token") && !githubOrgRefused(s))) {
16993
+ // GitHub の読めない行は表が一手を決める(出さないと決めた行=確かめられなかった組織には、
16994
+ // 理由文も重ねない)。テナント外の断りだけ、サーバの needed の 1 文がここへ来る
16995
+ // **能力に畳んでから渡す(#548)。** ここへ来るのは Slack / GitHub / Google Chat の
16996
+ // 行だけなので、ボタンが書いた detail(判定語)は従来どおり出さない
16997
+ var reason = stateReasonOf({ needed: s.needed, detail: s.detail, gateBy: s.gateBy, cap: gateCapOfType(s.type) });
16998
+ if (reason) card.appendChild(neededNode(reason, "ds-gate-help ds-gate-reason"));
16999
+ }
17167
17000
  }
17168
17001
  }
17169
17002
  // 🔴 **「材料にしていない」の補足(「ds-not-ingested-note」)は撤去した(#660)。**
@@ -17193,8 +17026,11 @@ ${calendarAddUrl.toString()}
17193
17026
  var probe = probeSection(s, card, gateEl);
17194
17027
  // **ボタンは行の中(「登録を解除」の隣)。** 独立した段を作ると1行が2段になる
17195
17028
  card.appendChild(probe.btn);
17029
+ appendRowHelp();
17196
17030
  // 押した結果の詳細だけを下に。**押すまでは空**なので行は伸びない
17197
17031
  card.appendChild(probe.detail);
17032
+ } else {
17033
+ appendRowHelp();
17198
17034
  }
17199
17035
  return card;
17200
17036
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.12.124",
3
+ "version": "0.12.126",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,