@takagaki/cortex-decisions-viewer 0.4.61 → 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 +25 -1
- package/dist/render.js +128 -15
- package/package.json +1 -1
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
|
-
|
|
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);
|
|
@@ -1708,7 +1730,10 @@ ${capabilityState.toString()}
|
|
|
1708
1730
|
m.modal.appendChild(el("div", { class: "modal-actions" }, [
|
|
1709
1731
|
el("button", { class: "ds-toggle-btn", type: "button", text: "閉じる" }),
|
|
1710
1732
|
]));
|
|
1711
|
-
|
|
1733
|
+
// **close をそのまま渡さない。** ハンドラに渡すと close(MouseEvent) になる。
|
|
1734
|
+
// いまは skipRefresh の判定が厳密比較なので効いているが、truthy 判定に
|
|
1735
|
+
// 緩めた瞬間「閉じる」ボタンだけが黙って取り込まなくなる
|
|
1736
|
+
m.modal.querySelector(".modal-actions button").addEventListener("click", function () { m.close(); });
|
|
1712
1737
|
m.overlay.appendChild(m.modal);
|
|
1713
1738
|
showModal(m.overlay, m.modal);
|
|
1714
1739
|
}
|
|
@@ -1842,7 +1867,11 @@ ${capabilityState.toString()}
|
|
|
1842
1867
|
col.appendChild(el("span", { class: "ds-inactive-note", text: "未使用(この案件では設定されていません)" }));
|
|
1843
1868
|
}
|
|
1844
1869
|
// id は接続マップのノードclickの飛び先(アンカー)
|
|
1845
|
-
|
|
1870
|
+
// **id は付けない。** #101 以前はこのカードが接続マップの飛び先だったが、
|
|
1871
|
+
// いまはタイルが飛び先。両方に付けると同じ id が2つある不正なHTMLになり、
|
|
1872
|
+
// モーダルの中身がタイルより前に来る変更が入った瞬間、getElementById が
|
|
1873
|
+
// 「開いていないモーダルの中」を指して黙って無反応になる
|
|
1874
|
+
var card = el("div", { class: "ds-card" + (inactive ? " ds-inactive" : "") }, [
|
|
1846
1875
|
el("div", { class: "ds-card-main" }, [
|
|
1847
1876
|
el("span", { class: "ds-icon", text: DS_KIND_ICON[s.kind] || "📁" }),
|
|
1848
1877
|
el("span", { class: "ds-type", text: s.kind || "" }),
|
|
@@ -1873,15 +1902,10 @@ ${capabilityState.toString()}
|
|
|
1873
1902
|
});
|
|
1874
1903
|
var UNIT = { "slack": "チャンネル", "github-issues": "リポジトリ", "github-discussions": "リポジトリ" };
|
|
1875
1904
|
// チャット未使用: Slackグループの位置(先頭)に「存在するが未設定」のグレー行を出す
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
var devAnchored = devOff;
|
|
1905
|
+
// **アンカーは渡さない**(タイルが飛び先。同 §id の重複を作らない)
|
|
1906
|
+
if (chatOff) pushCap("チャット", inactiveSourceRow("💬", "チャット", null));
|
|
1879
1907
|
groups.forEach(function (g) {
|
|
1880
1908
|
var meta = DS_TYPE[g.type] || { icon: "🔗", label: g.type || "その他" };
|
|
1881
|
-
// 接続マップのノードclickの飛び先(アンカー)。チャット=Slack群の先頭・開発=GitHub群の先頭
|
|
1882
|
-
var anchorId = null;
|
|
1883
|
-
if (g.type === "slack" && !chatAnchored) { anchorId = "ds-チャット"; chatAnchored = true; }
|
|
1884
|
-
if (g.type.indexOf("github") === 0 && !devAnchored) { anchorId = "ds-開発"; devAnchored = true; }
|
|
1885
1909
|
var cards = el("div", { class: "ds-list" });
|
|
1886
1910
|
g.items.forEach(function (s) { cards.appendChild(extSourceCard(s, meta)); });
|
|
1887
1911
|
if (g.items.length >= 4) {
|
|
@@ -1906,10 +1930,8 @@ ${capabilityState.toString()}
|
|
|
1906
1930
|
: "⚠️ " + bad + "件に問題" }),
|
|
1907
1931
|
]);
|
|
1908
1932
|
var det = el("details", { class: "ds-group" }, [sum, cards]);
|
|
1909
|
-
if (anchorId) det.id = anchorId;
|
|
1910
1933
|
pushCap(capOf(g.type), det);
|
|
1911
1934
|
} else {
|
|
1912
|
-
if (anchorId && cards.firstChild) cards.firstChild.id = anchorId;
|
|
1913
1935
|
// **appendChild と違い pushCap はノードを動かさない。** firstChild を条件にすると
|
|
1914
1936
|
// 永久に真のままになる(実際に無限ループを作った)。先に配列へ取り出す。
|
|
1915
1937
|
var kids = [];
|
|
@@ -1919,7 +1941,7 @@ ${capabilityState.toString()}
|
|
|
1919
1941
|
});
|
|
1920
1942
|
}
|
|
1921
1943
|
// 開発未使用: グレー行も能力の受け皿へ
|
|
1922
|
-
if (devOff) pushCap("開発", inactiveSourceRow("🐙", "GitHub",
|
|
1944
|
+
if (devOff) pushCap("開発", inactiveSourceRow("🐙", "GitHub", null));
|
|
1923
1945
|
|
|
1924
1946
|
// **追加フォームはグループの外に置く。** グループは0件だと描かれず、4件以上だと
|
|
1925
1947
|
// 畳まれる(既定は閉)。中に入れると**新規案件(0件)=一番追加したい場面**で消える。
|
|
@@ -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
|
-
|
|
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() {
|
|
@@ -3417,7 +3530,7 @@ ${capabilityState.toString()}
|
|
|
3417
3530
|
nameInput.addEventListener("input", update);
|
|
3418
3531
|
|
|
3419
3532
|
// 閉じる経路(Escape・背景クリック)は makeModal 側に用意されている
|
|
3420
|
-
cancelBtn.addEventListener("click", mk.close);
|
|
3533
|
+
cancelBtn.addEventListener("click", function () { mk.close(); });
|
|
3421
3534
|
submitBtn.addEventListener("click", function () { submitIntake(kind, selectedFiles, nameInput.value, status, submitBtn); });
|
|
3422
3535
|
}
|
|
3423
3536
|
async function submitIntake(kind, files, submitter, status, submitBtn) {
|
package/package.json
CHANGED