@takagaki/cortex-decisions-viewer 0.4.62 → 0.4.63

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
@@ -148,6 +148,26 @@ async function readFleetSources(repoRoot) {
148
148
  origin: s.origin != null ? String(s.origin) : undefined,
149
149
  }))
150
150
  : undefined;
151
+ // セットアップの充足チェック。**missing だけを通す。**
152
+ // na(使わないと宣言した能力)を通すと「設定する必要が無いものに設定を促す」偽の警告になり、
153
+ // #101 で潰した穴が復活する。unknown は AWS/gh へ到達できなかった回に出るので、
154
+ // 夜間実行がこけた日に嘘が出る。
155
+ // score / nextActions は通さない——nextActions は checks[].action を平坦化した
156
+ // 同じ内容の別キーで、通すと同じ文が2箇所に出る。
157
+ const checks = Array.isArray(obj.checks)
158
+ ? obj.checks
159
+ .filter((c) => c != null && typeof c === "object")
160
+ .filter((c) => String(c.status ?? "") === "missing")
161
+ .map((c) => ({
162
+ id: String(c.id ?? ""),
163
+ label: String(c.label ?? ""),
164
+ category: String(c.category ?? ""),
165
+ status: String(c.status ?? ""),
166
+ action: c.action != null ? String(c.action) : undefined,
167
+ detail: c.detail != null ? String(c.detail) : undefined,
168
+ }))
169
+ .filter((c) => c.id !== "")
170
+ : undefined;
151
171
  const internalSources = Array.isArray(obj.internalSources)
152
172
  ? obj.internalSources
153
173
  .filter((s) => s != null && typeof s === "object")
@@ -157,6 +177,9 @@ async function readFleetSources(repoRoot) {
157
177
  label: String(s.label ?? ""),
158
178
  url: s.url != null ? String(s.url) : undefined,
159
179
  lastSync: s.lastSync != null ? String(s.lastSync) : undefined,
180
+ // 取り込み済みの件数。**「同期が走った」と「実際に入った」は別物。**
181
+ // これが無いと、初回全量同期をしていない案件が「接続OK」に見える
182
+ itemCount: typeof s.itemCount === "number" ? s.itemCount : undefined,
160
183
  // 会議名に入れる合図。**古い fleet-status.json の matchKeys は引き継がない**
161
184
  // (client名と廃止した meetingNamePatterns の寄せ集めで、いま照合には使われていない。
162
185
  // 出すと「この語を会議名に入れれば拾われる」と読めてしまう)。
@@ -225,7 +248,7 @@ async function readFleetSources(repoRoot) {
225
248
  const secretSources = obj.secretSources && typeof obj.secretSources === "object"
226
249
  ? obj.secretSources
227
250
  : undefined;
228
- return { externalSources, internalSources, pipelines, tools, fleetGeneratedAt, secretSources };
251
+ return { externalSources, internalSources, pipelines, tools, fleetGeneratedAt, secretSources, checks };
229
252
  }
230
253
  /** パスがディレクトリとして存在するか */
231
254
  async function isDirectory(dirAbs) {
@@ -1101,6 +1124,7 @@ async function build(opts) {
1101
1124
  internalSources: fleet.internalSources,
1102
1125
  pipelines: fleet.pipelines,
1103
1126
  tools: fleet.tools,
1127
+ checks: fleet.checks,
1104
1128
  };
1105
1129
  // サムネイル(デザイン画面等)をサイトに同梱し、ノードのパスをサイト内相対に書き換える
1106
1130
  await node_fs_1.promises.mkdir(outAbs, { recursive: true });
package/dist/render.js CHANGED
@@ -224,7 +224,13 @@ function capabilityState(cap, ctx) {
224
224
  const pipeSkipped = ctx.pipes.some(function (p) {
225
225
  return pipeRe != null && pipeRe.test(p.id) && p.applicable === false;
226
226
  });
227
- const syncedForReal = internal != null && ((internal.lastSync && !pipeSkipped) || internal.url);
227
+ // **「同期が走った」と「実際にデータが入った」は別物。** 初回全量同期をしていない案件は、
228
+ // 毎晩の差分同期が成功し続けても0件のままになる(cortex-context の課題管理が実例で、
229
+ // lastSync はあるのに取り込み件数は0だった)。件数を見ないと、タイルが「接続OK」と言い、
230
+ // 同じ画面のセットアップ残りが「初回同期がまだです」と言う状態になる。
231
+ // 件数が無い(古い fleet-status.json・件数を持たない能力)ときは、いままでの判定に従う。
232
+ const emptyForReal = internal != null && internal.itemCount === 0;
233
+ const syncedForReal = internal != null && !emptyForReal && ((internal.lastSync && !pipeSkipped) || internal.url);
228
234
  const idle = !off &&
229
235
  (isLive
230
236
  ? liveExts.length === 0
@@ -944,6 +950,19 @@ a.ds-name:hover { text-decoration: underline; }
944
950
  width: 40px; height: 40px; flex: 0 0 40px; font-size: 26px; line-height: 1;
945
951
  }
946
952
  .ds-tile-logo svg { width: 100%; height: 100%; }
953
+ /* セットアップの残り。**直し方を状態と同じ大きさで出す**——
954
+ 何が足りないかだけ分かっても、次の一歩が分からなければ画面の意味が薄い */
955
+ .ds-tile-todo { color: var(--muted); }
956
+ .ds-checks { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
957
+ .ds-check-cat { font-size: 12px; font-weight: 700; color: var(--muted); margin-top: 8px; }
958
+ .ds-check {
959
+ display: flex; flex-direction: column; gap: 3px;
960
+ border-left: 3px solid #fcd34d; background: #fffbeb;
961
+ border-radius: 0 8px 8px 0; padding: 8px 12px;
962
+ }
963
+ .ds-check-label { font-size: 13px; font-weight: 700; color: var(--text); }
964
+ .ds-check-action { font-size: 13px; color: var(--text); line-height: 1.7; }
965
+ .ds-check-detail { font-size: 12px; color: var(--muted); }
947
966
  .ds-tile-desc { font-size: 12.5px; color: var(--muted); }
948
967
  .ds-tile-sub { font-size: 12.5px; margin-top: 2px; }
949
968
  .ds-tile-chev { color: var(--muted); }
@@ -969,6 +988,9 @@ a.ds-name:hover { text-decoration: underline; }
969
988
  .ds-gate-warn { color: #b45309; }
970
989
  .ds-gate-muted { color: #6b7280; }
971
990
  .ds-pipes { display: flex; flex-direction: column; gap: 8px; }
991
+ /* 実行状況の行に直し方を添える。同じ run の未達を別の節にも出すと画面に2回並ぶ */
992
+ .ds-pipe-wrap { display: flex; flex-direction: column; gap: 3px; }
993
+ .ds-pipe-todo { font-size: 12.5px; color: var(--muted); line-height: 1.7; padding-left: 4px; }
972
994
  .ds-pipe {
973
995
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
974
996
  padding: 10px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow);
@@ -1957,6 +1979,50 @@ ${capabilityState.toString()}
1957
1979
  var STATE_LABEL = { ok: "● 接続OK", idle: "⦿ 未接続", off: "未使用", warn: "⚠️" };
1958
1980
  var SECRET_OF_CAP = { "デザイン": "figma", "課題管理": "backlog", "開発": "external-sources" };
1959
1981
 
1982
+ // ---- セットアップの残り(checks)----
1983
+ //
1984
+ // **能力に紐づくものはその能力のタイルへ、紐づかないものは節にまとめる。**
1985
+ // 独立した一覧にすると、鍵カードの「現在: 未設定」やタイルの状態と
1986
+ // 同じことを別の言い方で二度言うことになり、ズレたときに読み手が
1987
+ // どちらを信じるか決められない(#101 で判定を1箇所に集めたのと同じ理由)。
1988
+ //
1989
+ // **missing 以外は出さない。** na は「使わないと宣言した能力」で、出すと
1990
+ // 「設定する必要が無いものに設定を促す」偽の警告になる(#101 で潰した穴)。
1991
+ // ビルド時とライブの両方で絞っているが、ここでも見る——経路が増えたときに
1992
+ // 絞り忘れると、いちばん見せてはいけないものが出る側に倒れるため。
1993
+ // **夜間 run の項目は、下の「自動化パイプライン」節が同じ run を出している。**
1994
+ // 両方に出すと、同じ失敗が1画面に2回並ぶ。実行状況はパイプライン節に任せ、
1995
+ // ここでは直し方だけをその行に添える(下の renderPipelines で使う)
1996
+ var PIPE_CHECK = { "update-gold": "nightly_decisionlog", "sync-backlog": "nightly_backlog", "sync-designs": "figma_sync" };
1997
+ var CHECK_CAP = {
1998
+ backlog_secrets: "課題管理", backlog_synced: "課題管理",
1999
+ meeting_minutes: "会議",
2000
+ channels_json: "チャット",
2001
+ figma_token: "デザイン", figma_inventory: "デザイン",
2002
+ submodules: "開発", dev_issues_derived: "開発",
2003
+ };
2004
+ var allChecks = (fleetVal("checks") || []).filter(function (c) {
2005
+ return c != null && c.status === "missing";
2006
+ });
2007
+ // **タイルに出せたものを覚えておく。** 振り分け先の能力タイルが立たない案件
2008
+ //(tools に宣言が無い・行も無い)では出す場所が無くなり、項目が**黙って消える**。
2009
+ // 消えた分は下の節へ落とす——振り分けを間違えても、消えるよりは出る方がよい
2010
+ var shownOnTile = {};
2011
+ function checksFor(cap) {
2012
+ return allChecks.filter(function (c) { return CHECK_CAP[c.id] === cap; });
2013
+ }
2014
+ /** 残りの1件を、直し方まで含めて1行にする */
2015
+ function checkLine(c) {
2016
+ var row = el("div", { class: "ds-check" });
2017
+ row.appendChild(el("span", { class: "ds-check-label", text: c.label }));
2018
+ if (c.action) row.appendChild(el("span", { class: "ds-check-action", text: c.action }));
2019
+ // **detail は内部値が入ることがある**("none" / "success")。読めるものだけ出す
2020
+ if (c.detail && !/^(none|success|failure|skipped|unknown)$/.test(c.detail)) {
2021
+ row.appendChild(el("span", { class: "ds-check-detail", text: c.detail }));
2022
+ }
2023
+ return row;
2024
+ }
2025
+
1960
2026
  /** タイルの2行目(状態と読み取り範囲)。**件数は出せる能力だけ出す** */
1961
2027
  function tileSub(cap, st) {
1962
2028
  var internal = internals.filter(function (s) { return s.kind === cap; })[0];
@@ -2066,6 +2132,18 @@ ${capabilityState.toString()}
2066
2132
  if (tools[cap] !== "none" && sk && (SITE.secretKinds || []).indexOf(sk) >= 0 && !((fleetVal("secretSources") || {})[sk])) {
2067
2133
  body.appendChild(el("div", { class: "ds-tile-note", text: "⚠ トークンが未設定です" }));
2068
2134
  }
2135
+ // セットアップの残りのうち、この能力のもの。**鍵の注記と同じ位置**に出して
2136
+ // 「何が足りないか」と「何をすればよいか」を同じ場所で読めるようにする
2137
+ checksFor(cap).forEach(function (c) {
2138
+ // **直し方が無いものはタイルに出さないが、出したことにもしない。**
2139
+ // shownOnTile を先に立てると節からも外れ、画面のどこにも出なくなる
2140
+ //(実データで mitsubishi の nightly_backlog / figma_token、verdy の
2141
+ // nightly_backlog が消えていた)。タイルは状態を読む場所なので
2142
+ //「足りない」だけの行では埋めず、節の側で拾う
2143
+ if (!c.action) return;
2144
+ shownOnTile[c.id] = true;
2145
+ body.appendChild(el("div", { class: "ds-tile-note ds-tile-todo", text: "→ " + c.action }));
2146
+ });
2069
2147
  var tile = el("button", { class: "ds-tile", type: "button", id: "ds-" + cap }, [
2070
2148
  ic,
2071
2149
  body,
@@ -2124,11 +2202,46 @@ ${capabilityState.toString()}
2124
2202
  }
2125
2203
  children.push(el("span", { class: "ds-pipe-label", text: p.label || p.id || "" }));
2126
2204
  if (t) children.push(el("span", { class: "ds-pipe-time", text: "最終成功: " + t }));
2127
- plist.appendChild(el("div", { class: "ds-pipe" }, children));
2205
+ var row = el("div", { class: "ds-pipe" }, children);
2206
+ // **直し方はこの行に添える。** 同じ run の未達を「セットアップの残り」にも出すと、
2207
+ // 同じ失敗が1画面に2回並ぶ。実行状況はここが正本なので、直し方だけを持ってくる
2208
+ var pc = allChecks.filter(function (c) { return c.id === PIPE_CHECK[p.id]; })[0];
2209
+ if (pc && pc.action) {
2210
+ shownOnTile[pc.id] = true;
2211
+ row = el("div", { class: "ds-pipe-wrap" }, [row, el("div", { class: "ds-pipe-todo", text: "→ " + pc.action })]);
2212
+ }
2213
+ plist.appendChild(row);
2128
2214
  });
2129
2215
  sec.appendChild(plist);
2130
2216
  }
2131
2217
 
2218
+ // ---- セットアップの残り(どこにも出せなかったもの)----
2219
+ //
2220
+ // **パイプライン節より後に計算する。** 夜間 run の直し方はその行に添えるので、
2221
+ // 先に計算すると shownOnTile がまだ立っておらず、同じ文が2箇所に出る
2222
+ //
2223
+ // **8/8案件で未達の scaffold_drift が、ここで初めて誰かの目に入る。**
2224
+ // 能力のタイルに居場所が無い項目(基盤・Cortex・シークレット)は、
2225
+ // ここに出さないとどこにも出ない。
2226
+ var loose = allChecks.filter(function (c) { return !shownOnTile[c.id]; });
2227
+ if (loose.length) {
2228
+ sec.appendChild(el("div", { class: "ds-sub", text: "セットアップの残り" }));
2229
+ sec.appendChild(el("p", { class: "ds-note", text: "毎晩の自動チェックで見つかった、まだ済んでいない設定です。" }));
2230
+ var byCat = {};
2231
+ var catOrder = [];
2232
+ loose.forEach(function (c) {
2233
+ var k = c.category || "その他";
2234
+ if (!byCat[k]) { byCat[k] = []; catOrder.push(k); }
2235
+ byCat[k].push(c);
2236
+ });
2237
+ var todo = el("div", { class: "ds-checks" });
2238
+ catOrder.forEach(function (k) {
2239
+ todo.appendChild(el("div", { class: "ds-check-cat", text: k }));
2240
+ byCat[k].forEach(function (c) { todo.appendChild(checkLine(c)); });
2241
+ });
2242
+ sec.appendChild(todo);
2243
+ }
2244
+
2132
2245
  return sec;
2133
2246
  }
2134
2247
  function renderDataSources() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.4.62",
3
+ "version": "0.4.63",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,