@takagaki/cortex-decisions-viewer 0.6.0 → 0.7.0
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 +29 -1
- package/dist/render.js +393 -152
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -126,6 +126,14 @@ function resolveKnowledgeRoot(decisionsDirAbs) {
|
|
|
126
126
|
}
|
|
127
127
|
return null;
|
|
128
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* スペースごとの Backlog キーの登録状況で、画面へ運んでよい値。
|
|
131
|
+
*
|
|
132
|
+
* **Lambda 側(infra/lambda/intake/logic.mjs の FLEET_MAP_VALUE_ALLOW)と同じにすること。**
|
|
133
|
+
* 片方だけ増やすと、静的ビルドでは出ないものがライブ差し替えの瞬間だけ出る
|
|
134
|
+
* ——「朝は正しいのに、開いて数秒すると表示が変わる」という一番気づきにくい食い違いになる。
|
|
135
|
+
*/
|
|
136
|
+
const SECRET_SPACE_STATES = ["new", "legacy", "false"];
|
|
129
137
|
/**
|
|
130
138
|
* リポジトリルートの fleet-status.json から externalSources / internalSources / pipelines を読む。
|
|
131
139
|
* ファイルが無い・パース不能・当該フィールドが無い場合は undefined を返し、
|
|
@@ -375,7 +383,26 @@ async function readFleetSources(repoRoot) {
|
|
|
375
383
|
const secretSources = obj.secretSources && typeof obj.secretSources === "object"
|
|
376
384
|
? obj.secretSources
|
|
377
385
|
: undefined;
|
|
378
|
-
|
|
386
|
+
// スペースごとの Backlog キーの登録状況(画面が接続先の行ごとに出す)。
|
|
387
|
+
//
|
|
388
|
+
// **値は列挙した3つだけを通す。** この値は顧客のブラウザまで届くので、engine が
|
|
389
|
+
// 語を増やしたときに知らない文字列をそのまま画面へ運ばない
|
|
390
|
+
// (Lambda 側の FLEET_MAP_VALUE_ALLOW と**同じ3つ**にそろえること。片方だけ増やすと、
|
|
391
|
+
// 静的では出ないものがライブ差し替えの瞬間だけ出る=一番気づきにくい食い違い)。
|
|
392
|
+
//
|
|
393
|
+
// **1つも残らなければキーごと落とす。** 空の器を通すと、画面が「確かめたうえで0件」と
|
|
394
|
+
// 読んで「未登録」と断定する。**知らないことは、キーが無いことで表す**
|
|
395
|
+
let secretSpaces;
|
|
396
|
+
if (obj.secretSpaces != null && typeof obj.secretSpaces === "object" && !Array.isArray(obj.secretSpaces)) {
|
|
397
|
+
const out = {};
|
|
398
|
+
for (const [space, v] of Object.entries(obj.secretSpaces)) {
|
|
399
|
+
if (typeof v === "string" && SECRET_SPACE_STATES.includes(v))
|
|
400
|
+
out[space] = v;
|
|
401
|
+
}
|
|
402
|
+
if (Object.keys(out).length)
|
|
403
|
+
secretSpaces = out;
|
|
404
|
+
}
|
|
405
|
+
return { externalSources, slackWorkspaces, internalSources, pipelines, capabilities, fleetGeneratedAt, secretSources, secretSpaces, checks, githubOwners, backlogTarget };
|
|
379
406
|
}
|
|
380
407
|
/** パスがディレクトリとして存在するか */
|
|
381
408
|
async function isDirectory(dirAbs) {
|
|
@@ -1312,6 +1339,7 @@ async function build(opts) {
|
|
|
1312
1339
|
slackWorkspaces: fleet.slackWorkspaces,
|
|
1313
1340
|
fleetGeneratedAt: fleet.fleetGeneratedAt,
|
|
1314
1341
|
secretSources: fleet.secretSources,
|
|
1342
|
+
secretSpaces: fleet.secretSpaces,
|
|
1315
1343
|
internalSources: fleet.internalSources,
|
|
1316
1344
|
pipelines: fleet.pipelines,
|
|
1317
1345
|
capabilities: fleet.capabilities,
|
package/dist/render.js
CHANGED
|
@@ -1107,18 +1107,17 @@ a:hover { text-decoration: underline; }
|
|
|
1107
1107
|
display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
|
|
1108
1108
|
}
|
|
1109
1109
|
.ds-card-main { display: flex; align-items: center; gap: 10px; flex: 1 1 auto; min-width: 0; }
|
|
1110
|
-
/*
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
.ds-
|
|
1121
|
-
.ds-card.ds-capbody > .ds-card-main { flex: 0 0 auto; }
|
|
1110
|
+
/* 能力モーダルの中身は**箱に入れない**(2026-08-21・オーナー実機指摘)。
|
|
1111
|
+
かつては .ds-card.ds-capbody という枠で包み、その中に「📋 課題管理 Backlog」と
|
|
1112
|
+
能力名まで書いていた。押しているのは Backlog のタイルで、**モーダルの見出しも
|
|
1113
|
+
ツール名(Backlog)**なので、枠と能力名は「課題管理・Backlog」という入れ子の
|
|
1114
|
+
重複でしかなかった。いまは見出しの直下へ中身をそのまま並べ、ここは
|
|
1115
|
+
**縦に積む役だけ**を持つ(枠線・背景・影は持たない)。
|
|
1116
|
+
⚠ **枠が無くなったので、未使用(enabled: false)の灰色の破線は出ない。**
|
|
1117
|
+
代わりに未使用を示すのは (1) 下の .ds-inactive の子孫ルール(中の文字が灰色になる)と
|
|
1118
|
+
(2)「未使用(この案件では設定されていません)」の一行(.ds-inactive-note)。
|
|
1119
|
+
モーダルは1つの能力しか映さないので、他の行と並べて灰色で見分ける必要が無い。 */
|
|
1120
|
+
.ds-capblock { display: flex; flex-direction: column; gap: 10px; }
|
|
1122
1121
|
.ds-icon { font-size: 18px; line-height: 1; flex: 0 0 auto; }
|
|
1123
1122
|
.ds-type { font-size: 12px; font-weight: 600; color: var(--muted); flex: 0 0 auto; }
|
|
1124
1123
|
.ds-name { font-size: 14.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -1304,6 +1303,10 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1304
1303
|
.ds-toggle-msg.is-ok { color: #1a7f37; }
|
|
1305
1304
|
.ds-toggle-msg.is-error { color: #b42318; }
|
|
1306
1305
|
.badge.ds-notify { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; }
|
|
1306
|
+
/* 読み取りを止めてあるリポジトリ(2026-08-21)。**それまではトグルの向きが示していた**ので、
|
|
1307
|
+
トグルを撤去したいま、読み取られていないことを示すのはこのバッジだけ。
|
|
1308
|
+
**判断のバッジなので、由来や組織のバッジより強く出す** */
|
|
1309
|
+
.badge.ds-excluded { background: #f3f4f6; color: #4b5563; border: 1px solid #d1d5db; }
|
|
1307
1310
|
/* 登録の由来(#118)。**薄く出す**——読み取りの可否や Gold 対象かより弱い情報で、
|
|
1308
1311
|
ここが目立つと「除外」「未宣言」の判断のバッジと同じ強さに見えてしまう */
|
|
1309
1312
|
.badge.ds-origin { background: transparent; color: var(--muted); border: 1px dashed var(--border); }
|
|
@@ -1371,6 +1374,31 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1371
1374
|
.sec-state { font-size: 12.5px; font-weight: 600; margin: 0 0 8px; color: var(--muted); }
|
|
1372
1375
|
.sec-state.is-managed { color: #1a7f37; }
|
|
1373
1376
|
.sec-state.is-none { color: var(--muted); font-weight: 400; }
|
|
1377
|
+
/* 登録されているか分からない(engine がスペース別の状況をまだ出していない)。
|
|
1378
|
+
**未登録と同じ見た目にしない**——断定していないことが色でも分かるようにする */
|
|
1379
|
+
.sec-state.is-unknown { color: var(--muted); font-weight: 400; font-style: italic; }
|
|
1380
|
+
/* 鍵の欄の置き場(2026-08-21)。レコードの行の中と、一覧の直後の2か所で使う。
|
|
1381
|
+
**.ds-card は flex-wrap: wrap の横並び**なので、100% の basis を与えて
|
|
1382
|
+
行の中で自分の段へ落とす(行そのものの並びは変えない——縦組みのクラスを
|
|
1383
|
+
流用すると Slack / GitHub の行まで縦に割れる)。 */
|
|
1384
|
+
.ds-keyrow { flex: 1 1 100%; min-width: 0; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
|
|
1385
|
+
/* 一覧の直後に置くとき(Figma)は、行の中ではないので区切り線を持たない */
|
|
1386
|
+
.ds-keyrow-list { margin-top: 10px; padding-top: 0; border-top: none; }
|
|
1387
|
+
/* 行の中に入った鍵カードは、カードの枠を持たない(行の一部に見せる) */
|
|
1388
|
+
.ops-card.ds-keycard { border: none; box-shadow: none; padding: 0; background: transparent; gap: 6px; }
|
|
1389
|
+
.ops-card.ds-keycard > .ops-card-head { gap: 8px; }
|
|
1390
|
+
.ops-card.ds-keycard .ops-card-icon { font-size: 16px; }
|
|
1391
|
+
.ops-card.ds-keycard .ops-card-title { font-size: 13px; }
|
|
1392
|
+
/* 押すまで入力欄を出さない(2026-08-21・オーナー指摘)。summary はボタンに見せる */
|
|
1393
|
+
.sec-input-fold { border: none; margin: 0; }
|
|
1394
|
+
.sec-input-fold > summary {
|
|
1395
|
+
cursor: pointer; display: inline-block; list-style: none;
|
|
1396
|
+
padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border);
|
|
1397
|
+
background: #fff; color: var(--text); font-size: 12.5px; font-weight: 600;
|
|
1398
|
+
}
|
|
1399
|
+
.sec-input-fold > summary::-webkit-details-marker { display: none; }
|
|
1400
|
+
.sec-input-fold > summary:hover { border-color: var(--accent); color: var(--accent); }
|
|
1401
|
+
.sec-input-fold[open] > summary { margin-bottom: 8px; }
|
|
1374
1402
|
.ds-addform { border: 1px dashed var(--border); border-radius: 8px; padding: 12px 14px; margin-top: 10px; background: #fff; }
|
|
1375
1403
|
.ds-addform-title { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
|
|
1376
1404
|
.ds-addform .sec-input { margin-bottom: 6px; }
|
|
@@ -1398,6 +1426,12 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1398
1426
|
padding: 18px; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: 10px;
|
|
1399
1427
|
}
|
|
1400
1428
|
/* リアルタイム同期の設定手順(#113)。番号付きなのは「上から順に1回やる」作業だから */
|
|
1429
|
+
/* **上に余白を置く(2026-08-21・オーナー実機指摘「リアルタイム同期のセクションが
|
|
1430
|
+
くっついてて気持ち悪かった。上のスペースがないから違和感ある」)。**
|
|
1431
|
+
直前に来るのは接続先の追加フォーム(.ds-addform)で、そちらは margin-top: 10px を
|
|
1432
|
+
持っている。こちらが 0 だと2つの箱が接して1枚に見える。**同じ 10px で釣り合わせる。**
|
|
1433
|
+
⚠ CSS は jsdom から見えないので、この余白はテストでは守れない(実機で見ること)。 */
|
|
1434
|
+
.rt-card { margin-top: 10px; }
|
|
1401
1435
|
.rt-steps { margin: 0; padding-left: 1.4em; color: var(--text); font-size: 13px; line-height: 1.9; }
|
|
1402
1436
|
.rt-steps li { margin: 2px 0; }
|
|
1403
1437
|
/* URLは長いので、入力欄を伸ばしてボタンを右に置く(折り返しても崩れないように wrap) */
|
|
@@ -2767,14 +2801,6 @@ ${capabilityState.toString()}
|
|
|
2767
2801
|
}
|
|
2768
2802
|
|
|
2769
2803
|
|
|
2770
|
-
var DS_KIND_ICON = {
|
|
2771
|
-
"課題管理": "📋",
|
|
2772
|
-
"会議": "🗒️",
|
|
2773
|
-
"共有資料": "📎",
|
|
2774
|
-
"デザイン": "🎨",
|
|
2775
|
-
"開発": "🐙",
|
|
2776
|
-
"チャット": "💬",
|
|
2777
|
-
};
|
|
2778
2804
|
function dsFmtTime(iso) {
|
|
2779
2805
|
var d = new Date(iso);
|
|
2780
2806
|
if (isNaN(d.getTime())) return "";
|
|
@@ -2975,14 +3001,33 @@ ${capabilityState.toString()}
|
|
|
2975
3001
|
* 能力モーダル。**中身は既存の部品をそのまま入れる。**
|
|
2976
3002
|
* 一覧・追加フォーム・鍵・手動投入は作り直さない(先出しバッジやライブ差し替えを壊さないため)。
|
|
2977
3003
|
*/
|
|
3004
|
+
/**
|
|
3005
|
+
* 能力(課題管理・会議…)→ **押したタイルのツール名**(Backlog・Google Meet…)。
|
|
3006
|
+
*
|
|
3007
|
+
* 2026-08-21 のオーナー実機指摘「押してるのはそのツールなんだから、Backlog とか
|
|
3008
|
+
* Google ドライブとして出る必要がある」。出どころは ADAPTER_CATALOG(能力→アダプタ)で、
|
|
3009
|
+
* **今日は能力あたり1アダプタなので一意に決まる**(#107 / #127 で複数になったら、
|
|
3010
|
+
* ここが「どれを見出しにするか」を決める場所になる)。
|
|
3011
|
+
*
|
|
3012
|
+
* ⚠ **カタログに無いものは、そのまま返す。** ここには能力名だけでなく
|
|
3013
|
+
* 「文字起こしを手動で追加」のような**能力ではない見出し**も渡ってくるし、
|
|
3014
|
+
* 未知の能力(engine が先に増やした場合)も来る。空にすると
|
|
3015
|
+
* **名前の無いダイアログ**になり、何を開いたのか分からなくなる——落とすなら能力名まで。
|
|
3016
|
+
*/
|
|
3017
|
+
function capToolLabel(cap) {
|
|
3018
|
+
var list = ADAPTER_CATALOG[cap] || [];
|
|
3019
|
+
var tool = list.length ? list[0] : "";
|
|
3020
|
+
return (tool && CM_TOOL_LABEL_C[tool]) || cap;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
2978
3023
|
function openCapabilityModal(cap, items, note) {
|
|
2979
|
-
var m = makeModal(cap, true);
|
|
3024
|
+
var m = makeModal(capToolLabel(cap), true);
|
|
2980
3025
|
// **何が読み取られるのかを必ず書く。** 一覧に並ぶものと読み取られるものの関係は、
|
|
2981
3026
|
// 書いていないと分からない(チャットは「載っていれば全部」、開発はリポジトリ単位でOFFできる)
|
|
2982
3027
|
if (cap === "チャット") {
|
|
2983
3028
|
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるチャンネルは、例外なく全て毎晩の Gold 昇格が読み取り、Decision・用語集の材料になります。読み取りを止めるには「登録を解除」してください。" }));
|
|
2984
3029
|
} else if (cap === "開発") {
|
|
2985
|
-
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるリポジトリの Issues を毎晩の Gold
|
|
3030
|
+
m.modal.appendChild(el("p", { class: "modal-desc", text: "ここに並んでいるリポジトリの Issues を毎晩の Gold 昇格が読み取り、Decision・用語集の材料になります。読み取りをやめるには「登録から削除」してください。" }));
|
|
2986
3031
|
}
|
|
2987
3032
|
// **なぜこの状態なのかを、押した先でも読めるようにする(#125②)。** タイルは常時出す
|
|
2988
3033
|
// ようになったので、未接続の能力を押したときに中身が空になる場面が増えた。
|
|
@@ -3003,7 +3048,32 @@ ${capabilityState.toString()}
|
|
|
3003
3048
|
showModal(m.overlay, m.modal);
|
|
3004
3049
|
}
|
|
3005
3050
|
|
|
3051
|
+
/**
|
|
3052
|
+
* 鍵の欄の置き場(2026-08-21・オーナー指摘「APIキーのセクションが下にあって、
|
|
3053
|
+
* 変わってないように見えます」)。
|
|
3054
|
+
*
|
|
3055
|
+
* 鍵の欄は**レコードの行の内側**(Backlog は接続先の行ごと・Figma は一覧の直後)に出す。
|
|
3056
|
+
* ところが**出す責任はここには移していない**——鍵カードを作っているのは
|
|
3057
|
+
* 「SECRET_FORMS」のループで、そこには
|
|
3058
|
+
* - intake を持たない案件でも鍵の欄を出す(internalControls は SITE.intake で早期return)
|
|
3059
|
+
* - OFF にした能力には入力欄を出さない
|
|
3060
|
+
* という2つのゲートが掛かっている。**内側で作り直すと、その両方が外れる**
|
|
3061
|
+
* (前者は「鍵の欄しか無い案件でデータソース節が丸ごと消える」形で実際に起きた)。
|
|
3062
|
+
*
|
|
3063
|
+
* そこで**置き場だけを内側から渡す**。ここに登録された受け皿へ、ループが作った
|
|
3064
|
+
* 鍵カードを差し込む。受け皿が無ければ従来どおり能力カードの直下へ積む。
|
|
3065
|
+
*
|
|
3066
|
+
* - backlog … スペース(ドメイン小文字)→ 受け皿。接続先が無い案件は空文字のキー
|
|
3067
|
+
* - backlogNamed … 保存時にスペースを名乗ってよいか(名簿由来の行だけ true)
|
|
3068
|
+
* - figma … 一覧の直後の受け皿(Figma の鍵は案件に1本なので1つだけ)
|
|
3069
|
+
*
|
|
3070
|
+
* **描き直すたびに作り直す。** ライブ差し替えで節ごと作り直されるので、
|
|
3071
|
+
* 前回の受け皿(切り離された古いノード)が残っていると、鍵の欄が画面から消える。
|
|
3072
|
+
*/
|
|
3073
|
+
var KEY_SLOTS = { backlog: {}, backlogNamed: false, figma: null };
|
|
3074
|
+
|
|
3006
3075
|
function buildDataSources() {
|
|
3076
|
+
KEY_SLOTS = { backlog: {}, backlogNamed: false, figma: null };
|
|
3007
3077
|
var internals = fleetVal("internalSources") || [];
|
|
3008
3078
|
var sources = fleetVal("externalSources") || [];
|
|
3009
3079
|
var pipes = fleetVal("pipelines") || [];
|
|
@@ -3087,8 +3157,18 @@ ${capabilityState.toString()}
|
|
|
3087
3157
|
// 用意してからここを戻す(syncNowRow と Lambda の op=sync は残してある)。
|
|
3088
3158
|
// sec.appendChild(syncNowRow());
|
|
3089
3159
|
internals.forEach(function (s) {
|
|
3090
|
-
//
|
|
3091
|
-
|
|
3160
|
+
// 補足行(会議の照合キー・Drive未設定の注記)を重ねられるよう縦組みにする。
|
|
3161
|
+
//
|
|
3162
|
+
// **情報源の名前は出さない(2026-08-21・オーナー指摘)。** モーダルの見出しが
|
|
3163
|
+
// ツール名(Backlog / Figma / Google Drive …)になったので、その直下にもう一度
|
|
3164
|
+
// 名前を出すと**同じことを2回言う**。実データの label は
|
|
3165
|
+
// 「Backlog 課題・ドキュメント(同期ミラー)」のような説明的な文で、見出しの
|
|
3166
|
+
// 言い換えにしかなっていない。
|
|
3167
|
+
//
|
|
3168
|
+
// **リンクを失わないことは確かめてある。** url を持つのは課題管理(プロジェクト)と
|
|
3169
|
+
// デザイン(Figmaファイル)だけで、どちらも**レコードの行が同じ先へリンクしている**。
|
|
3170
|
+
// 会議・共有資料は url を持たない。
|
|
3171
|
+
var col = el("div", { class: "ds-col" }, []);
|
|
3092
3172
|
// 照合キーの表示はここ1箇所に集約する(下の案内と二重に出さない)。
|
|
3093
3173
|
// **ON/OFFのトグルは出さない。** 取り込むかどうかは「Bot を会議に招待したか」で決まる
|
|
3094
3174
|
// (Router.gs:「フィルタは持たない…招待が同意のゲート」)。enabled はルーティングの
|
|
@@ -3163,27 +3243,31 @@ ${capabilityState.toString()}
|
|
|
3163
3243
|
// モーダルの中身がタイルより前に来る変更が入った瞬間、getElementById が
|
|
3164
3244
|
// 「開いていないモーダルの中」を指して黙って無反応になる
|
|
3165
3245
|
//
|
|
3166
|
-
//
|
|
3167
|
-
//
|
|
3168
|
-
//
|
|
3169
|
-
//
|
|
3170
|
-
//
|
|
3171
|
-
//
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3246
|
+
// **枠(.ds-card)とアイコン・能力名(.ds-icon / .ds-type)を落とす**
|
|
3247
|
+
// (2026-08-21・オーナー実機指摘)。Backlog のタイルを押して開いたモーダルの中に
|
|
3248
|
+
// 「📋 課題管理 Backlog」という箱がもう一段あり、見出しと同じことを二度言っていた。
|
|
3249
|
+
// モーダルの見出しがツール名になったので、ここは**見出しの直下に中身を並べる**だけ。
|
|
3250
|
+
//
|
|
3251
|
+
// 🔴 **落としたのは見出しと重複する2つだけ。** 会議の合図(.ds-keys)・別名チップ・
|
|
3252
|
+
// Drive / 未使用の注記・情報源へのリンクは col がそのまま抱えており、
|
|
3253
|
+
// 最終同期(.ds-sync)も条件ごと残している。
|
|
3254
|
+
//
|
|
3255
|
+
// **data-cap を付ける。** 能力名の文字列が画面から消えたので、
|
|
3256
|
+
// 「これはどの能力のブロックか」を掴む手掛かりがここしか無くなる(テストが引く)。
|
|
3257
|
+
var block = el("div", {
|
|
3258
|
+
class: "ds-capblock" + (inactive ? " ds-inactive" : ""),
|
|
3259
|
+
"data-cap": s.kind || "",
|
|
3260
|
+
}, [
|
|
3261
|
+
col,
|
|
3178
3262
|
!inactive && s.lastSync && dsFmtTime(s.lastSync)
|
|
3179
3263
|
? el("span", { class: "ds-sync", text: "最終同期: " + dsFmtTime(s.lastSync) })
|
|
3180
3264
|
: null,
|
|
3181
3265
|
]);
|
|
3182
|
-
//
|
|
3266
|
+
// 会議・共有資料・デザインの操作をブロック内に置く(その情報源の文脈で押せるように)
|
|
3183
3267
|
var ctl = internalControls(s, inactive);
|
|
3184
|
-
if (ctl)
|
|
3268
|
+
if (ctl) block.appendChild(ctl);
|
|
3185
3269
|
// 能力ごとの受け皿へ入れる(並べるのは下の CAP_ORDER のループ)
|
|
3186
|
-
pushCap(s.kind,
|
|
3270
|
+
pushCap(s.kind, block);
|
|
3187
3271
|
});
|
|
3188
3272
|
}
|
|
3189
3273
|
|
|
@@ -3349,10 +3433,34 @@ ${capabilityState.toString()}
|
|
|
3349
3433
|
// **Backlog は接続先のスペースごとにカードを出す(2026-08-20・#127)。**
|
|
3350
3434
|
// キーはスペースごとに別なので、欄が1つだと**どちらの鍵を入れたのか
|
|
3351
3435
|
// 誰にも分からない**まま片方の棚に入る(入れたのに動かない、が起きる)。
|
|
3436
|
+
//
|
|
3437
|
+
// **置き場は行の中(2026-08-21)。** backlogTargetsSection が接続先の行ごとに
|
|
3438
|
+
// 受け皿を用意しているので、そこへ差し込む。受け皿が無い案件
|
|
3439
|
+
//(intake を持たない・固定IP同期)では従来どおり能力カードの直下へ積む
|
|
3440
|
+
//——**ここで return してしまうと、鍵の欄しか無い案件で鍵が丸ごと消える。**
|
|
3352
3441
|
if (k === "backlog") {
|
|
3442
|
+
var slots = KEY_SLOTS.backlog;
|
|
3443
|
+
var spaces = Object.keys(slots);
|
|
3444
|
+
if (spaces.length) {
|
|
3445
|
+
spaces.forEach(function (space) {
|
|
3446
|
+
slots[space].appendChild(secretCard(k, SECRET_FORMS[k], {
|
|
3447
|
+
// **名乗るのは名簿由来の行だけ。** 同期ミラーのURLから作った行で
|
|
3448
|
+
// スペースを名乗ると、名簿とミラーがずれている案件で**黙って別の棚に入る**
|
|
3449
|
+
space: KEY_SLOTS.backlogNamed ? space : "",
|
|
3450
|
+
stateSpace: space,
|
|
3451
|
+
spaceCount: spaces.length,
|
|
3452
|
+
inRow: true,
|
|
3453
|
+
}));
|
|
3454
|
+
});
|
|
3455
|
+
return;
|
|
3456
|
+
}
|
|
3353
3457
|
backlogSecretCards().forEach(function (n) { pushCap(SECRET_CAP[k], n); });
|
|
3354
3458
|
return;
|
|
3355
3459
|
}
|
|
3460
|
+
if (k === "figma" && KEY_SLOTS.figma) {
|
|
3461
|
+
KEY_SLOTS.figma.appendChild(secretCard(k, SECRET_FORMS[k], { inRow: true }));
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3356
3464
|
pushCap(SECRET_CAP[k], secretCard(k, SECRET_FORMS[k]));
|
|
3357
3465
|
});
|
|
3358
3466
|
|
|
@@ -3480,7 +3588,8 @@ ${capabilityState.toString()}
|
|
|
3480
3588
|
} else if (live.length) {
|
|
3481
3589
|
// 単位は分かるものだけ。知らない種別に勝手な単位を付けない。
|
|
3482
3590
|
// **「N件をGoldに使用」の内訳は出さない。** チャンネルは載っていれば全部が対象で、
|
|
3483
|
-
// github
|
|
3591
|
+
// github の除外は行のバッジ(「読み取り停止中」)が示す
|
|
3592
|
+
//(件数の内訳は Gold トグルがあった頃の名残)
|
|
3484
3593
|
var unit = cap === "チャット" ? "チャンネル" : cap === "開発" ? "リポジトリ" : "件";
|
|
3485
3594
|
parts.push(live.length + unit);
|
|
3486
3595
|
} else if (cap === "共有資料" && adapter === "google-drive" && internal && internal.driveFolderIds) {
|
|
@@ -3643,7 +3752,7 @@ ${capabilityState.toString()}
|
|
|
3643
3752
|
|
|
3644
3753
|
// 注記は全能力の後ろに1つ。**何が Gold の材料になるのかを1文で言う。**
|
|
3645
3754
|
if (anyCap) {
|
|
3646
|
-
sec.appendChild(el("p", { class: "ds-note", text: "登録されている Slack チャンネルと GitHub リポジトリは、毎晩の Gold 昇格が読み取り、Decision
|
|
3755
|
+
sec.appendChild(el("p", { class: "ds-note", text: "登録されている Slack チャンネルと GitHub リポジトリは、毎晩の Gold 昇格が読み取り、Decision・用語集の材料になります。チャンネルは登録を解除すると、リポジトリは登録から削除すると、以後は読み取られません。" }));
|
|
3647
3756
|
}
|
|
3648
3757
|
|
|
3649
3758
|
if (pipes.length) {
|
|
@@ -3723,7 +3832,7 @@ ${capabilityState.toString()}
|
|
|
3723
3832
|
* 注: ここは埋め込みJSのテンプレートリテラル内。**コメントでもバッククォートを使わない**
|
|
3724
3833
|
*(リテラルが閉じて構文エラーになる。実際にそれで壊した)。
|
|
3725
3834
|
*
|
|
3726
|
-
*
|
|
3835
|
+
* **これが画面から Slack の読み取りを止める唯一の手段。** チャンネル単位の Gold トグルは撤去した
|
|
3727
3836
|
* (載っているチャンネルは例外なく全て Gold 昇格の対象)。事故(社内限定の会話が顧客可視の
|
|
3728
3837
|
* Gold へ流れ始めた)に画面から手を打てないと、git で channels.json を直接編集するしかない。
|
|
3729
3838
|
*
|
|
@@ -4072,12 +4181,16 @@ ${capabilityState.toString()}
|
|
|
4072
4181
|
* **キーはスペースごとに別。** 欄が1つだと、複数スペースの案件で
|
|
4073
4182
|
* 「どちらの鍵を入れたのか」が誰にも分からないまま片方の棚に入る。
|
|
4074
4183
|
*
|
|
4075
|
-
*
|
|
4184
|
+
* **ここは受け皿が無いときの退避先(2026-08-21)。** ふつうは接続先の行の中へ
|
|
4185
|
+
* 差し込む(KEY_SLOTS のコメント参照)。この関数が使われるのは、
|
|
4186
|
+
* 行を描く経路そのものが無い案件——intake を持たない案件——だけ。
|
|
4076
4187
|
*
|
|
4077
|
-
*
|
|
4078
|
-
*
|
|
4079
|
-
*
|
|
4080
|
-
*
|
|
4188
|
+
* ## 登録状況はスペースごとに引く
|
|
4189
|
+
*
|
|
4190
|
+
* 夜間の実測(secretSources.backlog)は**種別ごと**の1つの値で、スペース別の充足を
|
|
4191
|
+
* 表せない。1枚目に帰属させると**片方だけ入れた状態で両方に「登録済み」と出る**
|
|
4192
|
+
* ——画面が嘘をつく。スペース別の答えは secretSpaces(engine 側)が持ち、
|
|
4193
|
+
* それが無い生成物では**断定しない**(「確認中」に倒す)。
|
|
4081
4194
|
*
|
|
4082
4195
|
* ## 接続先がまだ無いとき
|
|
4083
4196
|
*
|
|
@@ -4085,9 +4198,11 @@ ${capabilityState.toString()}
|
|
|
4085
4198
|
*/
|
|
4086
4199
|
function backlogSecretCards() {
|
|
4087
4200
|
var spaces = backlogSpacesNow();
|
|
4088
|
-
if (spaces.length <= 1) return [secretCard("backlog", SECRET_FORMS["backlog"])];
|
|
4201
|
+
if (spaces.length <= 1) return [secretCard("backlog", SECRET_FORMS["backlog"], { spaceCount: spaces.length })];
|
|
4089
4202
|
return spaces.map(function (space) {
|
|
4090
|
-
return secretCard("backlog", SECRET_FORMS["backlog"], {
|
|
4203
|
+
return secretCard("backlog", SECRET_FORMS["backlog"], {
|
|
4204
|
+
space: space, stateSpace: space, spaceCount: spaces.length,
|
|
4205
|
+
});
|
|
4091
4206
|
});
|
|
4092
4207
|
}
|
|
4093
4208
|
|
|
@@ -4170,9 +4285,48 @@ ${capabilityState.toString()}
|
|
|
4170
4285
|
return row;
|
|
4171
4286
|
}
|
|
4172
4287
|
|
|
4288
|
+
/**
|
|
4289
|
+
* 描く順番。**同じスペースの行を隣り合わせにする(2026-08-21)。**
|
|
4290
|
+
*
|
|
4291
|
+
* 鍵の欄はそのスペースの**最後の行の下**に1つだけ出すので、
|
|
4292
|
+
* 「cm1/A, jleague/B, cm1/C」のように入り混じっていると
|
|
4293
|
+
* **どの行の鍵なのかが読めない**(cm1 の鍵が jleague の行を挟んだ先に出る)。
|
|
4294
|
+
* スペースの初出の順は保つので、一覧の見え方は今までと変わらない。
|
|
4295
|
+
*/
|
|
4296
|
+
function grouped(list) {
|
|
4297
|
+
var order = [];
|
|
4298
|
+
var byDomain = {};
|
|
4299
|
+
for (var i = 0; i < list.length; i++) {
|
|
4300
|
+
var d = String(list[i].domain || "").toLowerCase();
|
|
4301
|
+
if (!byDomain[d]) { byDomain[d] = []; order.push(d); }
|
|
4302
|
+
byDomain[d].push(list[i]);
|
|
4303
|
+
}
|
|
4304
|
+
var out = [];
|
|
4305
|
+
for (var j = 0; j < order.length; j++) out = out.concat(byDomain[order[j]]);
|
|
4306
|
+
return out;
|
|
4307
|
+
}
|
|
4308
|
+
|
|
4173
4309
|
function paint() {
|
|
4174
4310
|
while (listEl.firstChild) listEl.removeChild(listEl.firstChild);
|
|
4175
|
-
|
|
4311
|
+
var shown = grouped(targets);
|
|
4312
|
+
// そのスペースの**最後の行**を覚えておく(鍵の欄はそこへ入れる)
|
|
4313
|
+
var lastRowOf = {};
|
|
4314
|
+
for (var i = 0; i < shown.length; i++) {
|
|
4315
|
+
var row = removeRow(shown[i]);
|
|
4316
|
+
listEl.appendChild(row);
|
|
4317
|
+
lastRowOf[String(shown[i].domain || "").toLowerCase()] = row;
|
|
4318
|
+
}
|
|
4319
|
+
// 🔴 **鍵の欄は作り直さない。入れ直すだけ。** ここは追加・削除の応答でも
|
|
4320
|
+
// 呼ばれるので、作り直すと**接続先を1つ足しただけで入力中の鍵と「保存中…」が消える**
|
|
4321
|
+
//(ライブ差し替えで踏んだのと同じ事故が、別の経路で復活する)。
|
|
4322
|
+
// appendChild は既存ノードを移すだけなので、入力値もイベントも保たれる
|
|
4323
|
+
for (var d in keySlots) {
|
|
4324
|
+
if (!Object.prototype.hasOwnProperty.call(keySlots, d)) continue;
|
|
4325
|
+
if (!d) continue; // 接続先が無い案件の受け皿は box 側に置いてある(行が無い)
|
|
4326
|
+
var host = lastRowOf[d];
|
|
4327
|
+
if (host) host.appendChild(keySlots[d]);
|
|
4328
|
+
else if (keySlots[d].parentNode) keySlots[d].parentNode.removeChild(keySlots[d]);
|
|
4329
|
+
}
|
|
4176
4330
|
// **0件を黙って見せない。** 表示が無いと「まだ何も無い」のか「出し忘れ」なのか
|
|
4177
4331
|
// 区別できない。**一覧の外**(Figma / Drive と同じ)に、件数に応じて出し入れする
|
|
4178
4332
|
// ——出しっぱなしにすると、設定済みの案件にも「未設定」と書いた行が残る
|
|
@@ -4201,10 +4355,40 @@ ${capabilityState.toString()}
|
|
|
4201
4355
|
return { onTargets: adoptTargets, staleNote: TARGETS_RACE_NOTE };
|
|
4202
4356
|
}
|
|
4203
4357
|
|
|
4358
|
+
// **鍵の欄の受け皿を、行のスペースごとに1つ用意する(2026-08-21・オーナー指摘)。**
|
|
4359
|
+
//
|
|
4360
|
+
// 🔴 **行のドメインから引くこと。** backlogSpacesNow() は backlogTargetsNow(null) を
|
|
4361
|
+
// 呼ぶので、fleet が接続先を持たない案件(同期ミラーのURLから1行だけ作っている案件)では
|
|
4362
|
+
// **空を返す**——行は出るのに鍵の欄が1つも付かない、という空振りになる。
|
|
4363
|
+
//
|
|
4364
|
+
// **この画面から投入できない案件(固定IP同期)には出さない。** 押しても Lambda が
|
|
4365
|
+
// 「固定IP経由のため対応していません」で断るので、導線そのものを作らない。
|
|
4366
|
+
// 判定は鍵カードを出すループの条件と同じ線(SITE.secretKinds に backlog があるか)。
|
|
4367
|
+
var keySlots = {};
|
|
4368
|
+
if (editable && !Object.keys(KEY_SLOTS.backlog).length) {
|
|
4369
|
+
// 保存時にスペースを名乗ってよいのは、名簿(fleet の backlogTarget)由来の行だけ。
|
|
4370
|
+
// 同期ミラーのURLから作った行で名乗ると、名簿とミラーがずれている案件で
|
|
4371
|
+
// **黙って別の棚に入る**(入れたのに動かない、が一番起きてほしくない形)
|
|
4372
|
+
KEY_SLOTS.backlogNamed = backlogTargetsNow(null).length > 0;
|
|
4373
|
+
var domains = [];
|
|
4374
|
+
for (var ti = 0; ti < targets.length; ti++) {
|
|
4375
|
+
var dom = String(targets[ti].domain || "").toLowerCase();
|
|
4376
|
+
if (dom && domains.indexOf(dom) === -1) domains.push(dom);
|
|
4377
|
+
}
|
|
4378
|
+
// **0件の案件にも1つ出す。** 「接続先を足してからでないと鍵を入れられない」形にすると、
|
|
4379
|
+
// 立ち上げ直後の案件が最初の一歩を踏めない(#138 で直したのと同じ穴)。
|
|
4380
|
+
// 空文字のキーは「どのスペースとも結び付いていない受け皿」で、行の中には入らない
|
|
4381
|
+
if (!domains.length) domains.push("");
|
|
4382
|
+
for (var di = 0; di < domains.length; di++) keySlots[domains[di]] = el("div", { class: "ds-keyrow" });
|
|
4383
|
+
KEY_SLOTS.backlog = keySlots;
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4204
4386
|
// **box を先に作る。** paint() は 0件の1行を box へ出し入れするので、
|
|
4205
4387
|
// 箱が無いと最初の描画で「未設定」の行が出ない
|
|
4206
4388
|
var box = el("div", {}, [listEl]);
|
|
4207
4389
|
paint();
|
|
4390
|
+
// 接続先がまだ無い案件の受け皿は、0件の1行の直後に置く(行が無いので中へ入れられない)
|
|
4391
|
+
if (keySlots[""]) box.appendChild(keySlots[""]);
|
|
4208
4392
|
if (editable) {
|
|
4209
4393
|
box.appendChild(addForm({
|
|
4210
4394
|
// **「追加」に戻す(#127)。** 1件しか持てなかった頃は「保存」(置き換え)だったが、
|
|
@@ -4215,7 +4399,7 @@ ${capabilityState.toString()}
|
|
|
4215
4399
|
// **手順のリストにする(2026-08-20・Slack からの横展開)。**
|
|
4216
4400
|
// **リスト(ol.sec-steps)そのものは維持する**——他の能力の手順と形を揃える。
|
|
4217
4401
|
//
|
|
4218
|
-
// **鍵の発行手順は二重に持たない。**
|
|
4402
|
+
// **鍵の発行手順は二重に持たない。** 正本は接続先の行の下にある鍵の欄
|
|
4219
4403
|
//(SECRET_FORMS.backlog の how)で、ここからは参照するだけ。
|
|
4220
4404
|
//
|
|
4221
4405
|
// ## 4行 → 2行に圧縮した(2026-08-21・オーナー指摘「何も変わってない気がする」)
|
|
@@ -4225,8 +4409,8 @@ ${capabilityState.toString()}
|
|
|
4225
4409
|
// ここ以外に置き場が無いので、**消さずに2行へ畳んでいる**:
|
|
4226
4410
|
// - 「起票先は変わりません」… 追加の確認をやめたとき(2026-08-20)に
|
|
4227
4411
|
// ここへ移してきたもの。落とすと知る手段が無くなる
|
|
4228
|
-
// - 「スペースごとに別のキー」…
|
|
4229
|
-
//
|
|
4412
|
+
// - 「スペースごとに別のキー」… 鍵の欄からは読めない。1スペースの案件は
|
|
4413
|
+
// 行が1本しか無いので、これから2つ目を足す人に「別の鍵が要る」が届かない
|
|
4230
4414
|
// - 「案件専用URLの登録」… 救出先の realtimeSyncCard() は稼働中の案件では
|
|
4231
4415
|
// 手順一式を <details> に畳むので、**いちばん要る人に対して閉じている**
|
|
4232
4416
|
hint: [
|
|
@@ -4507,6 +4691,15 @@ ${capabilityState.toString()}
|
|
|
4507
4691
|
// 「読めていない」のか区別できない(Driveは driveState で理由まで出している)
|
|
4508
4692
|
box.appendChild(el("p", { class: "ds-empty", text: "同期対象のFigmaファイルはまだ登録されていません。" }));
|
|
4509
4693
|
}
|
|
4694
|
+
// **鍵の欄は一覧の直後に1つ(2026-08-21・オーナー指摘)。**
|
|
4695
|
+
// Backlog と違い、Figma の鍵は**案件に1本**(ファイルごとではない)。
|
|
4696
|
+
// 行ごとに出すと同じ欄が並ぶだけなので、一覧をひとまとまりと見て、その下に置く。
|
|
4697
|
+
// **中身を作るのはここではない**——SECRET_FORMS のループが差し込む
|
|
4698
|
+
//(intake / OFF のゲートをループ側に残すため。KEY_SLOTS のコメント参照)
|
|
4699
|
+
if (!KEY_SLOTS.figma) {
|
|
4700
|
+
KEY_SLOTS.figma = el("div", { class: "ds-keyrow ds-keyrow-list" });
|
|
4701
|
+
box.appendChild(KEY_SLOTS.figma);
|
|
4702
|
+
}
|
|
4510
4703
|
box.appendChild(addForm({
|
|
4511
4704
|
title: "+ Figmaファイルを追加",
|
|
4512
4705
|
placeholder: "https://www.figma.com/design/…",
|
|
@@ -4515,11 +4708,11 @@ ${capabilityState.toString()}
|
|
|
4515
4708
|
// **手順のリストにする(2026-08-20・Slack からの横展開)。**
|
|
4516
4709
|
// 一続きの文章だと、読む人が「自分がいま何をすべきか」を自分で切り出すことになる。
|
|
4517
4710
|
//
|
|
4518
|
-
// **手順1・2
|
|
4711
|
+
// **手順1・2は要約にとどめ、正本は上の鍵の欄に置く**(SECRET_FORMS.figma の
|
|
4519
4712
|
// how / note)。全文をここに移すと二重になり、片方だけ直る形になる
|
|
4520
4713
|
// ——カードは接続マップとタイルの注記と条件を揃えているので、動かすと壊れやすい。
|
|
4521
4714
|
hint: [
|
|
4522
|
-
"Figma でトークンを発行します(読み取りだけ。スコープ2
|
|
4715
|
+
"Figma でトークンを発行します(読み取りだけ。スコープ2つ)。手順は上の「Figma のトークン」の欄にあります。",
|
|
4523
4716
|
"発行したアカウントを、読み取りたい Figma ファイルに閲覧者として招待します(招待が無いと、トークンが正しくても読めません)。",
|
|
4524
4717
|
"そのファイルのURLを下の欄に貼って「追加」を押します。",
|
|
4525
4718
|
"追加したファイルは、画面名と Figma へのリンクが毎晩同期されます(画像は取り込まれません)。",
|
|
@@ -4634,7 +4827,7 @@ ${capabilityState.toString()}
|
|
|
4634
4827
|
hint: [
|
|
4635
4828
|
{ text: "読み取りたいリポジトリがある組織に、Cortex の GitHub App を入れます(Issues の読み取りだけ)。", node: appInstallLink() },
|
|
4636
4829
|
"そのリポジトリを下の欄に入れて「追加」を押します(owner/repo でも、GitHub のURLでも構いません)。",
|
|
4637
|
-
"追加したリポジトリの Issues が、毎晩の Gold
|
|
4830
|
+
"追加したリポジトリの Issues が、毎晩の Gold 昇格の材料になります。やめるときは、その行の「登録から削除」を押します。",
|
|
4638
4831
|
],
|
|
4639
4832
|
build: function (repo, name) { return { op: "add-github-source", repo: repo, name: name }; },
|
|
4640
4833
|
adder: "github",
|
|
@@ -4878,39 +5071,30 @@ ${capabilityState.toString()}
|
|
|
4878
5071
|
}
|
|
4879
5072
|
|
|
4880
5073
|
/**
|
|
4881
|
-
* ON/OFF
|
|
4882
|
-
*
|
|
5074
|
+
* ⚠ **ON/OFF のトグル(stateToggle)は関数ごと撤去した(2026-08-21・オーナー判断)。**
|
|
5075
|
+
*
|
|
5076
|
+
* 唯一の利用者が GitHub の「読み取りを止める/始める」だった。オーナー指摘:
|
|
5077
|
+
* 「登録から削除っていうボタンがあるのに、これがある理由がわかんないです」。
|
|
5078
|
+
*
|
|
5079
|
+
* 作った理由は「**自動で見つかったリポジトリ(derived)は登録簿から消しても
|
|
5080
|
+
* 翌日また現れるので、止めることだけはできるようにする**」だったが、
|
|
5081
|
+
* #119 以降に生成されたデータの github は必ず explicit で、全9案件36リポジトリの
|
|
5082
|
+
* 実測でも derived は0件・excluded も0件だった。
|
|
5083
|
+
*
|
|
5084
|
+
* **残さずに消す。** 呼び出しが1つも無い関数を残すと、壊しても何も起きない
|
|
5085
|
+
* =変異検証の網から静かに漏れる(このリポジトリが繰り返し踏んでいる形)。
|
|
5086
|
+
* 同じ理由で「ds-toggle-btn is-on」(押した向きを示すクラス)の生成元も無くなった。
|
|
5087
|
+
*
|
|
5088
|
+
* ⚠ **confirmOn(広げる向きだけ確認する)の利用者もこれだけだった。**
|
|
5089
|
+
* 「広げる向きの確認を await し損ねていないか」を見ていた検査は**引き継げない**
|
|
5090
|
+
* ——removeButton は向きに関わらず必ず確認するので、同じ性質を持たない。
|
|
5091
|
+
*
|
|
5092
|
+
* ⚠ **サーバ側の受け口(op=set-github-source-enabled)は残してある。**
|
|
5093
|
+
* 理由は logic.mjs の RETIRED_CONFIG_OPS のコメントに書いた。
|
|
4883
5094
|
*/
|
|
4884
|
-
function stateToggle(opts) {
|
|
4885
|
-
var wrap = el("div", { class: "ds-toggle" });
|
|
4886
|
-
var on = opts.on === true;
|
|
4887
|
-
var btn = el("button", { class: "ds-toggle-btn" + (on ? " is-on" : ""), type: "button" });
|
|
4888
|
-
var msg = el("div", { class: "ds-toggle-msg" });
|
|
4889
|
-
var paint = function () {
|
|
4890
|
-
btn.textContent = on ? opts.labelOn : opts.labelOff;
|
|
4891
|
-
btn.className = "ds-toggle-btn" + (on ? " is-on" : "");
|
|
4892
|
-
};
|
|
4893
|
-
paint();
|
|
4894
|
-
|
|
4895
|
-
btn.addEventListener("click", async function () {
|
|
4896
|
-
var next = !on;
|
|
4897
|
-
// 読み始める方向(危険)だけ確認する。止める方向は素通し
|
|
4898
|
-
if (next && opts.confirmOn && !(await confirmDanger(opts.confirmOn, { returnTo: btn }))) { msg.textContent = ""; return; }
|
|
4899
|
-
sendConfig(opts.build(next), msg, btn, function () {
|
|
4900
|
-
// **押した内容をボタンに反映し、逆向きの操作を残す。**
|
|
4901
|
-
// **カードごと作り直さない。** 上の msg に出した結果表示が消えてしまう
|
|
4902
|
-
on = next;
|
|
4903
|
-
paint();
|
|
4904
|
-
});
|
|
4905
|
-
});
|
|
4906
|
-
wrap.appendChild(btn);
|
|
4907
|
-
wrap.appendChild(msg);
|
|
4908
|
-
return wrap;
|
|
4909
|
-
}
|
|
4910
5095
|
|
|
4911
5096
|
/**
|
|
4912
|
-
*
|
|
4913
|
-
* 向きに関わらず取り消せないので常に確認する)。
|
|
5097
|
+
* 削除ボタン。**必ず確認を出す**(取り消せないので、向きに関わらず確認する)。
|
|
4914
5098
|
*
|
|
4915
5099
|
* 成功しても一覧からは消さない。接続状況は夜間バッチのスナップショットで、消したつもりの行が
|
|
4916
5100
|
* 翌朝まで残るのが正しい状態のため——行に取り消し線を引き、ボタンだけを無効にする
|
|
@@ -5119,15 +5303,30 @@ ${capabilityState.toString()}
|
|
|
5119
5303
|
var ORIGIN_LABEL = { explicit: "明示登録", derived: "自動検出", both: "明示登録+自動検出" };
|
|
5120
5304
|
var ORIGIN_HELP = {
|
|
5121
5305
|
explicit: "開発の登録ファイル(dev-sources.json)に登録されているリポジトリです。ここから登録を削除できます。",
|
|
5122
|
-
|
|
5306
|
+
// **「読み取りを止めることはできます」は書かない(2026-08-21)。** そのボタンを
|
|
5307
|
+
// 撤去したので嘘になる。この行は画面からは変えられない(dev-sources.json の
|
|
5308
|
+
// exclude を直接編集する)——そう書いておかないと、無い操作を探させることになる
|
|
5309
|
+
derived: ".gitmodules から自動で見つかったリポジトリです。登録ファイルに無いので、この画面からは変更できません。",
|
|
5123
5310
|
both: "登録ファイルにも書かれていて、.gitmodules からも見つかっているリポジトリです。",
|
|
5124
5311
|
};
|
|
5125
5312
|
|
|
5126
5313
|
function extSourceCard(s, meta) {
|
|
5127
5314
|
var badges = el("div", { class: "ds-badges" });
|
|
5128
5315
|
// **Gold 対象かのバッジは持たない。** 一覧に並ぶ Slack チャンネルは例外なく全て対象で、
|
|
5129
|
-
// 行ごとに「対象です」と書いても情報が増えない。
|
|
5130
|
-
//
|
|
5316
|
+
// 行ごとに「対象です」と書いても情報が増えない。
|
|
5317
|
+
//
|
|
5318
|
+
// 🔴 **github の除外(goldState: "excluded")だけは印を出す(2026-08-21)。**
|
|
5319
|
+
// それまでは行のトグル(「読み取りを始める/止める」)が**向きで示していた**ので、
|
|
5320
|
+
// トグルを撤去すると**読み取られていないのに印が1つも無い行**になる。
|
|
5321
|
+
// sourceNeedsAttention も excluded を警告から外すので、他に気づく手掛かりが無い。
|
|
5322
|
+
// 実測では0件だが、exclude は dev-sources.json に手で書けるので「今日は0件」でしかない
|
|
5323
|
+
if (String(s.type).indexOf("github") === 0 && s.goldState === "excluded") {
|
|
5324
|
+
badges.appendChild(el("span", {
|
|
5325
|
+
class: "badge ds-excluded",
|
|
5326
|
+
text: "読み取り停止中",
|
|
5327
|
+
title: "このリポジトリは読み取り対象から除外されています(開発の登録ファイル dev-sources.json の exclude)。この画面からは戻せません。",
|
|
5328
|
+
}));
|
|
5329
|
+
}
|
|
5131
5330
|
if (s.notify === true) badges.appendChild(el("span", { class: "badge ds-notify", text: "通知先" }));
|
|
5132
5331
|
// **どのワークスペースのチャンネルかを、必ず行に出す(#104・2026-08-20 に社内も)。**
|
|
5133
5332
|
//
|
|
@@ -5223,28 +5422,16 @@ ${capabilityState.toString()}
|
|
|
5223
5422
|
if (SITE.intake && s.type === "slack" && s.ref && s.origin !== "explicit") {
|
|
5224
5423
|
card.appendChild(removeChannelButton(s, card));
|
|
5225
5424
|
}
|
|
5226
|
-
// GitHub
|
|
5425
|
+
// GitHubリポの登録から削除。**ON/OFF のトグルは撤去した(2026-08-21)**
|
|
5426
|
+
//(stateToggle のコメント参照)。
|
|
5227
5427
|
if (SITE.intake && s.type.indexOf("github") === 0 && s.ref) {
|
|
5228
|
-
card.appendChild(stateToggle({
|
|
5229
|
-
on: s.goldState !== "excluded",
|
|
5230
|
-
labelOn: "読み取りを止める",
|
|
5231
|
-
labelOff: "読み取りを始める",
|
|
5232
|
-
confirmOn: [
|
|
5233
|
-
"このリポジトリの Issues を、Gold 昇格の材料に戻します。",
|
|
5234
|
-
"",
|
|
5235
|
-
"Issues の内容から、Decision・用語集が作られます。",
|
|
5236
|
-
"",
|
|
5237
|
-
s.ref,
|
|
5238
|
-
"",
|
|
5239
|
-
"有効にしますか?",
|
|
5240
|
-
],
|
|
5241
|
-
build: function (next) {
|
|
5242
|
-
return { op: "set-github-source-enabled", repo: s.ref, value: next };
|
|
5243
|
-
},
|
|
5244
|
-
}));
|
|
5245
5428
|
// **削除は「手で登録したもの」にだけ出す。** 自動で見つかったリポは
|
|
5246
5429
|
// 登録ファイルから消しても翌日また現れる(=消えないのに消せたように見える)。
|
|
5247
|
-
//
|
|
5430
|
+
//
|
|
5431
|
+
// ⚠ **トグルを撤去したので、derived / both / 由来不明の行には操作が1つも無くなる**
|
|
5432
|
+
//(分類B・2026-08-21 に記録)。実測で derived は0件だが、.gitmodules からの
|
|
5433
|
+
// 導出経路が消えたわけではない。再び現れたら、その行は**画面からは止められない**
|
|
5434
|
+
// ——dev-sources.json の exclude を直接編集する。
|
|
5248
5435
|
//
|
|
5249
5436
|
// **#119 以降、新しいデータの github は必ず explicit** なので、この条件は
|
|
5250
5437
|
// いずれ常に真になる。それまでは残す——再生成前のスナップショットには derived が
|
|
@@ -5256,7 +5443,10 @@ ${capabilityState.toString()}
|
|
|
5256
5443
|
return [
|
|
5257
5444
|
"「" + s.ref + "」を、読み取り対象の登録から削除します。",
|
|
5258
5445
|
"",
|
|
5259
|
-
|
|
5446
|
+
// **「読み取りを止める」への案内は消した(2026-08-21)。** そのボタンごと
|
|
5447
|
+
// 撤去したので、指す先が画面に無い。**代わりの手段は書かない**
|
|
5448
|
+
//——削除がその手段そのもので、他に無い
|
|
5449
|
+
"次回の Gold 昇格から、このリポジトリの Issues は読み取られません。",
|
|
5260
5450
|
"",
|
|
5261
5451
|
"すでに作られた Decision・用語集は消えません。",
|
|
5262
5452
|
"",
|
|
@@ -5562,7 +5752,12 @@ ${capabilityState.toString()}
|
|
|
5562
5752
|
return el("div", { class: "ops-card rt-card is-live" }, [
|
|
5563
5753
|
el("div", { class: "ops-card-head" }, [
|
|
5564
5754
|
el("span", { class: "ops-card-icon", text: "⚡" }),
|
|
5565
|
-
|
|
5755
|
+
// **「(任意)」を付ける(2026-08-21・オーナー指摘「リアルタイム同期は
|
|
5756
|
+
// オプションなので、一番下に配置してほしい」)。** 設定しなくても毎晩の同期で
|
|
5757
|
+
// 反映されるので、必須の手順と並べると「まだ終わっていない」と読まれる。
|
|
5758
|
+
// ⚠ **改名箇所は2つある**(稼働中の枝と未設定の枝)。片方だけ直すと、
|
|
5759
|
+
// **これから設定する人にだけ「(任意)」が付かない**=一番読ませたい人に届かない
|
|
5760
|
+
el("h3", { class: "ops-card-title", text: "リアルタイム同期(任意)" }),
|
|
5566
5761
|
el("span", { class: "rt-live-badge", text: "✓ 稼働中" }),
|
|
5567
5762
|
]),
|
|
5568
5763
|
lines,
|
|
@@ -5574,7 +5769,9 @@ ${capabilityState.toString()}
|
|
|
5574
5769
|
return el("div", { class: "ops-card rt-card" }, [
|
|
5575
5770
|
el("div", { class: "ops-card-head" }, [
|
|
5576
5771
|
el("span", { class: "ops-card-icon", text: "⚡" }),
|
|
5577
|
-
|
|
5772
|
+
// **稼働中の枝と同じ見出しにする**(上の ⚠ 参照。片方だけ直すと、
|
|
5773
|
+
// これから設定する人にだけ「(任意)」が付かない)
|
|
5774
|
+
el("h3", { class: "ops-card-title", text: "リアルタイム同期(任意)" }),
|
|
5578
5775
|
]),
|
|
5579
5776
|
el("p", { class: "ops-card-desc", text: "Backlog で課題やコメントが変わったときに、その内容をすぐ取り込みます(毎晩の同期を待たずに反映されます)。Backlog 側で一度だけ設定してください。" }),
|
|
5580
5777
|
].concat(steps));
|
|
@@ -5657,39 +5854,68 @@ ${capabilityState.toString()}
|
|
|
5657
5854
|
}
|
|
5658
5855
|
|
|
5659
5856
|
/**
|
|
5660
|
-
*
|
|
5661
|
-
*
|
|
5662
|
-
*
|
|
5857
|
+
* 鍵が登録されているかを、そのカードが担当する範囲で答える(2026-08-21)。
|
|
5858
|
+
*
|
|
5859
|
+
* 返す値は "yes" / "no" / "unknown" の**3つ**。
|
|
5860
|
+
*
|
|
5861
|
+
* 🔴 **"unknown" を潰さないこと。** スペースごとの登録状況(secretSpaces)を出すのは
|
|
5862
|
+
* engine 側で、配布は**画面が先・engine が後**——secretSpaces を知らない生成物を
|
|
5863
|
+
* 画面が読む期間が必ずある。そこで「未登録」に倒すと、
|
|
5864
|
+
* **入っている鍵を「入っていない」と断定して、要らない貼り直しをさせる。**
|
|
5865
|
+
*
|
|
5866
|
+
* @returns { known, src } src は取得元の文字列("yes" のときだけ意味を持つ)
|
|
5867
|
+
*/
|
|
5868
|
+
function secretStateOf(kind, stateSpace, spaceCount) {
|
|
5869
|
+
var perKind = (fleetVal("secretSources") || {})[kind] || "";
|
|
5870
|
+
var spaces = fleetVal("secretSpaces");
|
|
5871
|
+
if (kind === "backlog" && stateSpace && spaces && typeof spaces === "object") {
|
|
5872
|
+
var v = spaces[stateSpace];
|
|
5873
|
+
if (v === "new") return { known: "yes", src: "Secrets Manager" };
|
|
5874
|
+
if (v === "legacy") return { known: "yes", src: "Secrets Manager(旧名)" };
|
|
5875
|
+
if (v === "false") return { known: "no", src: "" };
|
|
5876
|
+
}
|
|
5877
|
+
// **スペースが1つに定まるなら、種別ごとの値で答えてよい。** 取り違えようがないので、
|
|
5878
|
+
// engine が secretSpaces を出す前から今までどおりの表示を保てる
|
|
5879
|
+
if ((spaceCount || 0) <= 1) return { known: perKind ? "yes" : "no", src: perKind };
|
|
5880
|
+
// 複数スペースなのに、スペース別の答えが無い。**片方だけ入れた状態を表せない**ので
|
|
5881
|
+
// 断定しない(「登録済み」も「未登録」も、どちらかのスペースで嘘になる)
|
|
5882
|
+
return { known: "unknown", src: "" };
|
|
5883
|
+
}
|
|
5884
|
+
|
|
5885
|
+
/**
|
|
5886
|
+
* @param opts { space, stateSpace, spaceCount, inRow }
|
|
5887
|
+
* space … 保存時に名乗る Backlog スペース(名乗らないときは空)
|
|
5888
|
+
* stateSpace … 状態を引くスペース(画面の行のドメイン)
|
|
5889
|
+
* spaceCount … 画面に出ているスペースの数(1つなら種別ごとの値で答えられる)
|
|
5890
|
+
* inRow … レコードの行の中に置く(枠と影を持たない見た目にする)
|
|
5663
5891
|
*/
|
|
5664
5892
|
function secretCard(kind, meta, opts) {
|
|
5665
5893
|
var cardSpace = (opts && opts.space) || "";
|
|
5666
|
-
var
|
|
5667
|
-
|
|
5894
|
+
var stateSpace = (opts && opts.stateSpace) || "";
|
|
5895
|
+
var spaceCount = (opts && opts.spaceCount) || 0;
|
|
5896
|
+
var inRow = !!(opts && opts.inRow);
|
|
5897
|
+
// **いま登録されているか**を先に出す。入れ直したのに反映されていない状態が
|
|
5668
5898
|
// 画面で分かるようにする(接続状況は夜間バッチのスナップショットなので、
|
|
5669
5899
|
// 保存の直後は前日の値のまま。時刻は上の節に出している)。
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
var
|
|
5673
|
-
//
|
|
5674
|
-
//
|
|
5675
|
-
|
|
5900
|
+
var st = secretStateOf(kind, stateSpace, spaceCount);
|
|
5901
|
+
var src = st.known === "yes" ? st.src : "";
|
|
5902
|
+
var cardTitle = meta.title;
|
|
5903
|
+
// 🔴 **「登録済み」は「読めている」を意味しない。** 鍵が入っていても、そのアカウントから
|
|
5904
|
+
// プロジェクトが見えなければ同期は失敗する。**「接続OK」「同期OK」とは書かないこと**
|
|
5905
|
+
//(同期できているかのバッジは、夜間処理が接続先ごとの成否を保存してからの別作業)。
|
|
5906
|
+
//
|
|
5676
5907
|
// **前方一致で見る。** #105 の移行期は「Secrets Manager(旧名)」も来る。
|
|
5677
5908
|
// 完全一致にすると、旧名で動いている案件だけが repo secret と同じ見た目になり、
|
|
5678
5909
|
// 「管理下にあるのに未移行」という一番知りたい状態が画面から消える
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
text: "スペースごとの登録状況は、まだ表示できません(貼り直すと、このスペースの鍵として上書きされます)" })
|
|
5689
|
-
: src
|
|
5690
|
-
? el("p", { class: "sec-state" + (src.indexOf("Secrets Manager") === 0 ? " is-managed" : ""),
|
|
5691
|
-
text: "現在: " + src + " から取得中" })
|
|
5692
|
-
: el("p", { class: "sec-state is-none", text: "現在: 未設定" });
|
|
5910
|
+
var state = st.known === "yes"
|
|
5911
|
+
? el("p", { class: "sec-state" + (src.indexOf("Secrets Manager") === 0 ? " is-managed" : ""),
|
|
5912
|
+
text: "登録済み(" + src + " から取得中)" })
|
|
5913
|
+
: st.known === "no"
|
|
5914
|
+
? el("p", { class: "sec-state is-none", text: "未登録" })
|
|
5915
|
+
// **断定しない(レビュー指摘)。** 黙って消すと、利用者は
|
|
5916
|
+
// 「入っているのか未登録なのか」も「なぜ表示が無いのか」も知る手段が無い
|
|
5917
|
+
: el("p", { class: "sec-state is-unknown",
|
|
5918
|
+
text: "登録状況を確認中です(スペースごとの状況は、次回の自動チェックのあとに表示されます)" });
|
|
5693
5919
|
|
|
5694
5920
|
var input = el("input", { class: "sec-input", type: "password", placeholder: "トークンを貼り付け", autocomplete: "off" });
|
|
5695
5921
|
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "保存" });
|
|
@@ -5752,18 +5978,33 @@ ${capabilityState.toString()}
|
|
|
5752
5978
|
var guidanceBox = el("details", { class: "sec-fold" }, [el("summary", { text: "発行のしかた" })]);
|
|
5753
5979
|
for (var gi = 0; gi < guidance.length; gi++) guidanceBox.appendChild(guidance[gi]);
|
|
5754
5980
|
|
|
5755
|
-
//
|
|
5981
|
+
// **押すまで入力欄を出さない(2026-08-21・オーナー指摘)。**
|
|
5982
|
+
// 「今のAPIキーのセクション、欄があると思うんだけど…押すとフォームだけ出てくる」。
|
|
5756
5983
|
//
|
|
5757
|
-
//
|
|
5758
|
-
//
|
|
5984
|
+
// 🔴 **前回とは向きが逆。** 前回は「.sec-input は畳まない」と決めていたが、
|
|
5985
|
+
// 鍵の欄がレコードの行の下へ移り、**行に常時ぶら下がる入力欄**になったため、
|
|
5986
|
+
// 一覧の見通しを取り戻す側へ倒した。**状態(.sec-state)は畳まない**ので、
|
|
5987
|
+
// 「保存したのに反映されていない」は開かなくても読める。
|
|
5759
5988
|
//
|
|
5760
|
-
//
|
|
5989
|
+
// ⚠ **DOM には常に置く**(押すまで生成しない作りにしない)。ライブ差し替えは
|
|
5990
|
+
// input のノードを直接触るし、テストも card.querySelector("input.sec-input") で掴む。
|
|
5991
|
+
// ⚠ **<summary> は button ではない**ので、「保存」を掴む既存の取り方は変わらない。
|
|
5992
|
+
var inputFold = el("details", { class: "sec-input-fold" }, [
|
|
5993
|
+
el("summary", { class: "sec-input-summary", text: st.known === "yes" ? "入れ直す" : "登録する" }),
|
|
5994
|
+
]);
|
|
5995
|
+
inputFold.appendChild(input);
|
|
5996
|
+
inputFold.appendChild(el("div", { class: "ds-toggle" }, [btn, msg]));
|
|
5997
|
+
|
|
5998
|
+
// ライブ取得後に状態の行だけを差し替えるための目印(カードごと作り直すと入力が消える)
|
|
5999
|
+
//
|
|
6000
|
+
// **並びは「状態 → 貼る(畳む) → 畳んだ手順」。**
|
|
6001
|
+
//
|
|
6002
|
+
// 🔴 **.sec-state / .sec-preferred は <details> の外に置くこと。**
|
|
5761
6003
|
// - .sec-state … 保存したのに反映されていない状態が分かる唯一の手段。
|
|
5762
6004
|
// 押すまで見えないと成立しない
|
|
5763
6005
|
// - .sec-preferred … 「誰のアカウントで発行するのか」を**手順より先に**伝える行。
|
|
5764
|
-
//
|
|
5765
|
-
|
|
5766
|
-
return el("div", { class: "ops-card", "data-secret-kind": kind }, [
|
|
6006
|
+
// 未登録のときだけ出る=これから貼る人にだけ出るので、畳むと存在理由が消える
|
|
6007
|
+
return el("div", { class: "ops-card" + (inRow ? " ds-keycard" : ""), "data-secret-kind": kind }, [
|
|
5767
6008
|
el("div", { class: "ops-card-head" }, [
|
|
5768
6009
|
el("span", { class: "ops-card-icon", text: meta.icon }),
|
|
5769
6010
|
el("h3", { class: "ops-card-title", text: cardTitle }),
|
|
@@ -5772,11 +6013,11 @@ ${capabilityState.toString()}
|
|
|
5772
6013
|
// 代入するので、無条件に出すと画面に文字列 undefined が出る
|
|
5773
6014
|
meta.desc ? el("p", { class: "ops-card-desc", text: meta.desc }) : null,
|
|
5774
6015
|
state,
|
|
5775
|
-
//
|
|
5776
|
-
//
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
6016
|
+
// **未登録のときだけ、先に試すべき手を出す。** 既に動いているカードに
|
|
6017
|
+
// 「まずこれをやれ」と出すと、直す必要が無いものを触らせることになる。
|
|
6018
|
+
// **「確認中」にも出さない**——入っているかもしれないものを触らせない
|
|
6019
|
+
st.known === "no" && meta.selfServe ? el("p", { class: "sec-preferred", text: meta.selfServe.text }) : null,
|
|
6020
|
+
inputFold,
|
|
5780
6021
|
guidanceBox,
|
|
5781
6022
|
// **扱いの説明はカードに持たせる。** 節の見出しの下に置いていたときは、
|
|
5782
6023
|
// #101 でカードだけがモーダルへ移り、説明だけが画面から消えた。
|
|
@@ -5925,10 +6166,10 @@ ${capabilityState.toString()}
|
|
|
5925
6166
|
* モーダルを app に載せて、中へフォーカスを移す。
|
|
5926
6167
|
*
|
|
5927
6168
|
* **「最初の focusable」に載せてはいけない。** 一覧の先頭に来るのは
|
|
5928
|
-
*
|
|
5929
|
-
*
|
|
5930
|
-
*
|
|
5931
|
-
*
|
|
6169
|
+
* 「登録を解除」「このファイルを外す」といった設定を書き換えるボタンで、
|
|
6170
|
+
* タイルを Enter で開いてもう一度 Enter を押しただけで、そこへ手が届く。
|
|
6171
|
+
* いま並んでいるものは確認を必ず出すが、**確認を出さない操作が1つ増えるだけで
|
|
6172
|
+
* この形は復活する**ので、載せ先の側で塞いでおく。
|
|
5932
6173
|
* 移す先は閉じるボタン——押しても何も壊れないものにする。
|
|
5933
6174
|
*/
|
|
5934
6175
|
/**
|