@takagaki/cortex-decisions-viewer 0.4.82 → 0.4.83
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/render.js +239 -1
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -1294,6 +1294,19 @@ a.ds-name:hover { text-decoration: underline; }
|
|
|
1294
1294
|
(flex: 1 1 100%)——状態バッジの横に押し込むと、いちばん読ませたい一文が
|
|
1295
1295
|
カード幅に負けて省略される。状態の語より弱く、しかし読める大きさで出す */
|
|
1296
1296
|
.ds-gate-help { flex: 1 1 100%; margin: 4px 0 0; font-size: 12px; line-height: 1.7; color: #6b7280; }
|
|
1297
|
+
/* 「接続を確認」を押した結果(2026-08-19)。**必ず自分の行を占める**(flex: 1 1 100%)。
|
|
1298
|
+
夜間のスナップショットの状態バッジと**同時に2つの判定を並べない**ため、押したあとは
|
|
1299
|
+
状態バッジをこの中の判定へ置き換える(同じ画面で「⚠️」と「接続OK」が並ぶのが、
|
|
1300
|
+
この節で3回直してきた壊れ方そのもの) */
|
|
1301
|
+
.ds-probe { flex: 1 1 100%; margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--border); }
|
|
1302
|
+
.ds-probe-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
|
|
1303
|
+
/* いつ測った結果かを必ず添える。夜間のスナップショットと混ざると、どちらの話か読めない */
|
|
1304
|
+
.ds-probe-at { font-size: 11.5px; color: var(--muted); }
|
|
1305
|
+
.ds-probe-help { margin: 6px 0 0; font-size: 12px; line-height: 1.7; color: #6b7280;
|
|
1306
|
+
min-width: 0; white-space: normal; overflow-wrap: anywhere; }
|
|
1307
|
+
/* Slack が名指しした不足スコープ。**そのまま読める形で出す**(言い換えると検索できない) */
|
|
1308
|
+
.ds-probe-scope { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: #fef3c7;
|
|
1309
|
+
border: 1px solid #fde68a; border-radius: 6px; padding: 1px 6px; user-select: all; }
|
|
1297
1310
|
/* 意図的にOFFにした能力(#125②)。**グレーにして誘わない**——未接続(入口を出してよい)
|
|
1298
1311
|
とは別物で、同じ色にすると「押して繋ぎましょう」と読まれる */
|
|
1299
1312
|
.ds-gate-off { color: #9ca3af; }
|
|
@@ -2022,6 +2035,11 @@ ${capabilityState.toString()}
|
|
|
2022
2035
|
// **状態だけでなく、次にすることを書く。** 「bot未招待」では何をすればよいか分からない
|
|
2023
2036
|
// (公開チャンネルでも招待が要ることは Slack の仕様で、知らない人のほうが多い)
|
|
2024
2037
|
"not_in_channel": { text: "Slackで招待してください", cls: "ds-gate-warn" },
|
|
2038
|
+
// **招待では直らない(2026-08-19 の不具合報告)。** 非公開チャンネルで groups:read が
|
|
2039
|
+
// 足りていたのに、実測がこれを「不明」に潰していたので画面には「接続OK」としか出ず、
|
|
2040
|
+
// 名前が引けない理由が一切分からなかった(原因の特定に半日かかった)。
|
|
2041
|
+
// **状態の語で「招待」と言わない**——言うと、何度招待しても直らないものを繰り返させる
|
|
2042
|
+
"missing_scope": { text: "権限が足りません", cls: "ds-gate-warn" },
|
|
2025
2043
|
"unreachable": { text: "アクセス不可", cls: "ds-gate-warn" },
|
|
2026
2044
|
"no_token": { text: "トークン未設定", cls: "ds-gate-muted" },
|
|
2027
2045
|
"unknown": { text: "不明", cls: "ds-gate-muted" },
|
|
@@ -3034,6 +3052,210 @@ ${capabilityState.toString()}
|
|
|
3034
3052
|
* 関わらず必ず出し、成功しても一覧からは消さずに行へ取り消し線を引く(一覧は夜間
|
|
3035
3053
|
* スナップショットなので、翌朝まで残るのが正しい状態)。
|
|
3036
3054
|
*/
|
|
3055
|
+
/* ---------------------------------------------------------------------------
|
|
3056
|
+
* 「接続を確認」(2026-08-19 の不具合報告3件)
|
|
3057
|
+
* ---------------------------------------------------------------------------
|
|
3058
|
+
* 3つの別々の原因(トークン未登録・groups:read 不足・スナップショットが古い)が、
|
|
3059
|
+
* **画面上はどれも区別できなかった。** 共通していたのは「画面を見ても次に何をすれば
|
|
3060
|
+
* いいか決まらない」こと。実測は毎晩1回しか走らないので、招待やスコープを直した人が
|
|
3061
|
+
* 直ったことを確かめる手段も無かった。**押した瞬間に測って、理由と次の一手を返す。**
|
|
3062
|
+
*
|
|
3063
|
+
* **判定はここで作らない。** 状態の語は DS_GATE、社内/顧客の出し分けは
|
|
3064
|
+
* DS_GATE_NO_TOKEN が持っていて、どちらも dsGateOf を通して取る。ここで文面を
|
|
3065
|
+
* 書き写すと、**同じ行の状態バッジと確認結果で語が割れる**(この節で3回直した形)。
|
|
3066
|
+
*
|
|
3067
|
+
* 他アダプタ(GitHub / Backlog / Figma / Drive)を足すときの拡張点:
|
|
3068
|
+
* - 判定と語彙は infra/lambda/shared/slack-gate.mjs 側に足す(画面は DS_GATE のまま)
|
|
3069
|
+
* - この節に増やすのは probeHelpNodes の「次の一手」だけ。**アダプタ固有の分岐を
|
|
3070
|
+
* probeVerdict に入れない**(入れた瞬間に判定が画面側にも生まれる)
|
|
3071
|
+
* - 行に出す条件(下の extSourceCard)を s.type === "slack" から広げる
|
|
3072
|
+
* ------------------------------------------------------------------------- */
|
|
3073
|
+
|
|
3074
|
+
/**
|
|
3075
|
+
* 確認結果の状態バッジ。**既存の dsGateOf をそのまま通す。**
|
|
3076
|
+
*
|
|
3077
|
+
* こうしておくと no_token の社内/顧客の出し分け(DS_GATE_NO_TOKEN)が確認結果にも
|
|
3078
|
+
* そのまま効く。写経すると、同じ画面で行は「管理者の設定が必要です」・確認結果は
|
|
3079
|
+
* 「トークン未設定」になり、社内チャンネルを登録した人が**また**顧客ワークスペースの
|
|
3080
|
+
* 接続へ吸い込まれる(2026-08-18 の不具合そのもの)。
|
|
3081
|
+
*/
|
|
3082
|
+
function probeVerdict(s, r) {
|
|
3083
|
+
return dsGateOf({ type: s.type, workspace: s.workspace, gate: r.gate });
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
/**
|
|
3087
|
+
* 判定ごとの「次の一手」。**状態の語だけでは足りない**——今日の3件はどれも
|
|
3088
|
+
* 「何が起きているか」は分かっても「次に何をすればいいか」が決まらなかった。
|
|
3089
|
+
*/
|
|
3090
|
+
function probeHelpNodes(s, r) {
|
|
3091
|
+
var p = function (t) { return el("p", { class: "ds-probe-help", text: t }); };
|
|
3092
|
+
var out = [];
|
|
3093
|
+
if (r.gate === "ok") {
|
|
3094
|
+
// **表示名が引けたかまで言う。** 読めているのに名前が「(名前未取得: C0BQ…)」の
|
|
3095
|
+
// ままだった案件があり、読めていること自体は正しかったので誰も疑わなかった
|
|
3096
|
+
out.push(p(r.name
|
|
3097
|
+
? "読めています。Slack で確認できた表示名は「" + r.name + "」です。"
|
|
3098
|
+
: "読めています。ただし表示名は引けませんでした(Slack の応答: " +
|
|
3099
|
+
(r.error || "不明") + ")。一覧の名前は登録したときのままになります。"));
|
|
3100
|
+
return out;
|
|
3101
|
+
}
|
|
3102
|
+
if (r.gate === "not_in_channel") {
|
|
3103
|
+
out.push(p("このチャンネルに Cortex を招待してください。公開チャンネルでも招待が必要で、" +
|
|
3104
|
+
"招待していないと中身を1件も読めません。Slack でこのチャンネルを開き、次のコマンドを貼ります。" +
|
|
3105
|
+
"招待したら、もう一度「接続を確認」を押して直ったことを確かめてください。"));
|
|
3106
|
+
// **手で打たせない。** 短い文字列でも打ち間違いは黙って失敗し、
|
|
3107
|
+
// 利用者には「招待したのに読まれない」としか見えない(copyRow の直上コメント)
|
|
3108
|
+
out.push(copyRow("/invite @Cortex"));
|
|
3109
|
+
return out;
|
|
3110
|
+
}
|
|
3111
|
+
if (r.gate === "missing_scope") {
|
|
3112
|
+
// **足りないスコープ名をそのまま出す(2026-08-19 の不具合の本体)。**
|
|
3113
|
+
// Slack は needed で名指しで返しているのに、実測がそれを捨てて「不明」にしていた。
|
|
3114
|
+
// **招待と言わない**——招待では直らないので、言うと直らない操作を繰り返させる
|
|
3115
|
+
var line = el("p", { class: "ds-probe-help" });
|
|
3116
|
+
line.appendChild(document.createTextNode("Cortex の Slack App に権限(スコープ)が足りません。不足しているのは "));
|
|
3117
|
+
line.appendChild(el("code", { class: "ds-probe-scope", text: r.needed || "不明(Slack が名前を返しませんでした)" }));
|
|
3118
|
+
line.appendChild(document.createTextNode(" です。"));
|
|
3119
|
+
out.push(line);
|
|
3120
|
+
out.push(p("これは招待では直りません。Slack App にこのスコープを追加して再インストールする必要があるので、" +
|
|
3121
|
+
"cortex の担当者にこのスコープ名をそのまま伝えてください。" +
|
|
3122
|
+
(r.readable
|
|
3123
|
+
? "なお、チャンネルの中身そのものは読めています(毎晩の取り込みは動いています)。直らないのは表示名です。"
|
|
3124
|
+
: "")));
|
|
3125
|
+
return out;
|
|
3126
|
+
}
|
|
3127
|
+
if (r.gate === "no_token") {
|
|
3128
|
+
// **社内/顧客の出し分けは既存の1箇所から取る。** ここで書き分けると必ずずれる
|
|
3129
|
+
var help = probeVerdict(s, r).help;
|
|
3130
|
+
if (help) out.push(p(help));
|
|
3131
|
+
return out;
|
|
3132
|
+
}
|
|
3133
|
+
if (r.gate === "unreachable") {
|
|
3134
|
+
out.push(p("チャンネルが見つからないか、アーカイブされています。" +
|
|
3135
|
+
"Slack でこのチャンネルがまだ存在するかを確かめてください。" +
|
|
3136
|
+
"アーカイブしたチャンネルなら、この行の「登録を解除」で読み取り対象から外せます。" +
|
|
3137
|
+
"存在するのに見つからない場合は、Cortex が入っていない別ワークスペースのチャンネルの可能性があるので、" +
|
|
3138
|
+
"cortex の担当者にご連絡ください。"));
|
|
3139
|
+
return out;
|
|
3140
|
+
}
|
|
3141
|
+
// unknown。**生のエラーを隠さない**——「不明」だけだと切り分けが始められない
|
|
3142
|
+
out.push(p("読めるかどうかを確かめられませんでした。Slack の応答は「" + (r.error || "不明") + "」です。" +
|
|
3143
|
+
"少し時間をおいてもう一度お試しください。同じ応答が続く場合は、この文言をそのまま cortex の担当者にお伝えください。"));
|
|
3144
|
+
return out;
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
/**
|
|
3148
|
+
* 表示名の取り直し。**確認とは別のボタンにしてある。**
|
|
3149
|
+
*
|
|
3150
|
+
* 確認(?op=probe)は読むだけなので誰でも押してよいと決めた(オーナー判断・2026-08-19)。
|
|
3151
|
+
* 名前の更新は案件リポジトリへのコミットなので、**設定変更と同じ入口(?op=config)**に
|
|
3152
|
+
* 通す(sendConfig)。確認のついでに黙って書き込む形にすると、「読むだけだから誰でも
|
|
3153
|
+
* 押してよい」という前提そのものが崩れる。**押す前に、何がどう変わるかを見せる。**
|
|
3154
|
+
*
|
|
3155
|
+
* 出すのは**違っているときだけ**。同じ名前のときにボタンだけ出すと、押しても
|
|
3156
|
+
* 「変更はありません」と返るだけの操作になる。
|
|
3157
|
+
*/
|
|
3158
|
+
function renameChannelRow(s, r, card) {
|
|
3159
|
+
if (!r.name || r.name === s.name) return null;
|
|
3160
|
+
var box = el("div");
|
|
3161
|
+
box.appendChild(el("p", { class: "ds-probe-help",
|
|
3162
|
+
text: "一覧の表示名「" + (s.name || "(未設定)") + "」は、Slack のいまの名前「" + r.name + "」と違います。" +
|
|
3163
|
+
"更新すると、この案件の設定ファイル(チャット/channels.json)の表示名だけが書き換わります。" +
|
|
3164
|
+
"読み取りの対象・範囲は変わりません。" }));
|
|
3165
|
+
var row = el("div", { class: "ds-toggle" });
|
|
3166
|
+
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "表示名を更新する" });
|
|
3167
|
+
var msg = el("div", { class: "ds-toggle-msg" });
|
|
3168
|
+
btn.addEventListener("click", function () {
|
|
3169
|
+
// **名前は送らない。** サーバが Slack から引き直したものだけを書く(引けなければ
|
|
3170
|
+
// 断って既存の名前を残す)。画面から任意の名前を送れる形にすると、
|
|
3171
|
+
// 名前の取り直しの顔をした自由な改名になる
|
|
3172
|
+
var payload = { op: "refresh-channel-name", ref: s.ref };
|
|
3173
|
+
if (s.workspace) payload.workspace = s.workspace;
|
|
3174
|
+
sendConfig(payload, msg, btn, function () {
|
|
3175
|
+
// 一覧は夜間のスナップショットなので、その場では変わらない。行だけ追いつかせる
|
|
3176
|
+
var nameEl = card.querySelector(".ds-name");
|
|
3177
|
+
if (nameEl) nameEl.textContent = r.name;
|
|
3178
|
+
btn.disabled = true;
|
|
3179
|
+
});
|
|
3180
|
+
});
|
|
3181
|
+
row.appendChild(btn);
|
|
3182
|
+
row.appendChild(msg);
|
|
3183
|
+
box.appendChild(row);
|
|
3184
|
+
return box;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
/**
|
|
3188
|
+
* 「接続を確認」の一式(ボタン+結果)。
|
|
3189
|
+
*
|
|
3190
|
+
* **押したら、その行の状態バッジを置き換える。** 夜間のスナップショットの判定と
|
|
3191
|
+
* いま測った判定を**同じ行に並べない**ため——並べると「⚠️ と 接続OK が同時に出ている」
|
|
3192
|
+
* になり、この節で3回直してきた食い違いを画面の側から作ることになる。
|
|
3193
|
+
* 置き換えたことが分かるよう、いつ測ったかを必ず添える。
|
|
3194
|
+
*
|
|
3195
|
+
* **結果は保存しない。** fleet-status.json は夜間のスナップショットのまま置く
|
|
3196
|
+
* (押すたびにコミットが増えるのを避ける)。表示名の取り直しだけが例外で、
|
|
3197
|
+
* そちらは正本(channels.json)を直す価値があるので別のボタンで書き込む。
|
|
3198
|
+
*/
|
|
3199
|
+
function probeSection(s, card, gateEl) {
|
|
3200
|
+
var wrap = el("div", { class: "ds-probe" });
|
|
3201
|
+
var head = el("div", { class: "ds-probe-head" });
|
|
3202
|
+
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "接続を確認" });
|
|
3203
|
+
var msg = el("span", { class: "ds-toggle-msg" });
|
|
3204
|
+
var at = el("span", { class: "ds-probe-at" });
|
|
3205
|
+
var body = el("div");
|
|
3206
|
+
head.appendChild(btn);
|
|
3207
|
+
head.appendChild(msg);
|
|
3208
|
+
head.appendChild(at);
|
|
3209
|
+
wrap.appendChild(head);
|
|
3210
|
+
wrap.appendChild(body);
|
|
3211
|
+
|
|
3212
|
+
btn.addEventListener("click", async function () {
|
|
3213
|
+
var intake = SITE.intake;
|
|
3214
|
+
if (!intake) return;
|
|
3215
|
+
btn.disabled = true;
|
|
3216
|
+
msg.className = "ds-toggle-msg";
|
|
3217
|
+
msg.textContent = "確認中…";
|
|
3218
|
+
at.textContent = "";
|
|
3219
|
+
body.textContent = "";
|
|
3220
|
+
var payload = { type: "slack", ref: s.ref };
|
|
3221
|
+
if (s.workspace) payload.workspace = s.workspace;
|
|
3222
|
+
var pfx = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&");
|
|
3223
|
+
try {
|
|
3224
|
+
var res = await fetch(pfx + "op=probe&t=" + encodeURIComponent(intake.token), {
|
|
3225
|
+
method: "POST",
|
|
3226
|
+
headers: { "content-type": "application/json" },
|
|
3227
|
+
body: JSON.stringify(payload),
|
|
3228
|
+
});
|
|
3229
|
+
var j = await res.json().catch(function () { return {}; });
|
|
3230
|
+
if (!res.ok) {
|
|
3231
|
+
// サーバの文言をそのまま出す(回数制限の案内・未対応のアダプタの説明を含んでいる)
|
|
3232
|
+
msg.className = "ds-toggle-msg is-error";
|
|
3233
|
+
msg.textContent = "✗ " + (j.message || "確認できませんでした。");
|
|
3234
|
+
btn.disabled = false;
|
|
3235
|
+
return;
|
|
3236
|
+
}
|
|
3237
|
+
msg.textContent = "";
|
|
3238
|
+
var v = probeVerdict(s, j);
|
|
3239
|
+
gateEl.className = "ds-gate " + v.cls;
|
|
3240
|
+
gateEl.textContent = v.text;
|
|
3241
|
+
at.textContent = "いま測った結果(" + (dsFmtTime(j.checkedAt) || "たった今") + ")";
|
|
3242
|
+
probeHelpNodes(s, j).forEach(function (n) { body.appendChild(n); });
|
|
3243
|
+
// **登録ファイルが channels.json の行にだけ出す。** 書き換える先がそこなので、
|
|
3244
|
+
// dev-sources.json だけに載っている行(origin: explicit)では必ず 404 になる
|
|
3245
|
+
// ——「登録を解除」が同じ理由で同じ条件を持っている
|
|
3246
|
+
if (s.origin !== "explicit") {
|
|
3247
|
+
var rename = renameChannelRow(s, j, card);
|
|
3248
|
+
if (rename) body.appendChild(rename);
|
|
3249
|
+
}
|
|
3250
|
+
} catch (e) {
|
|
3251
|
+
msg.className = "ds-toggle-msg is-error";
|
|
3252
|
+
msg.textContent = "✗ 通信に失敗しました。";
|
|
3253
|
+
}
|
|
3254
|
+
btn.disabled = false;
|
|
3255
|
+
});
|
|
3256
|
+
return wrap;
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3037
3259
|
function removeChannelButton(s, card) {
|
|
3038
3260
|
return removeButton({
|
|
3039
3261
|
label: "登録を解除",
|
|
@@ -4098,6 +4320,9 @@ ${capabilityState.toString()}
|
|
|
4098
4320
|
}));
|
|
4099
4321
|
}
|
|
4100
4322
|
var gate = dsGateOf(s);
|
|
4323
|
+
// **「接続を確認」が押されたら、この要素を live の判定で置き換える**(probeSection)。
|
|
4324
|
+
// 2つの判定を同じ行に並べないため、参照を持っておく
|
|
4325
|
+
var gateEl = el("span", { class: "ds-gate " + gate.cls, text: gate.text });
|
|
4101
4326
|
var card = el("div", { class: "ds-card" }, [
|
|
4102
4327
|
el("div", { class: "ds-card-main" }, [
|
|
4103
4328
|
el("span", { class: "ds-icon", text: meta.icon }),
|
|
@@ -4105,7 +4330,7 @@ ${capabilityState.toString()}
|
|
|
4105
4330
|
dsNameEl(s.name || "", s.url),
|
|
4106
4331
|
]),
|
|
4107
4332
|
badges,
|
|
4108
|
-
|
|
4333
|
+
gateEl,
|
|
4109
4334
|
]);
|
|
4110
4335
|
// チャンネルの登録解除。書き込み経路(intake Lambda)がある案件でだけ出す。
|
|
4111
4336
|
// **Slack だけ。** github は登録ファイルが別(dev-sources.json)で、下のトグルと
|
|
@@ -4171,6 +4396,19 @@ ${capabilityState.toString()}
|
|
|
4171
4396
|
// **ボタンより後ろに置く。** カードは横並びの flex なので、間に挟むと
|
|
4172
4397
|
// 「登録を解除」が案内文の下の行へ落ちて、既存案件の行の形が変わる
|
|
4173
4398
|
if (gate.help) card.appendChild(el("p", { class: "ds-gate-help", text: gate.help }));
|
|
4399
|
+
// 「接続を確認」(2026-08-19)。**押せる人を絞らない**——読むだけで設定を変えないので、
|
|
4400
|
+
// 気づいた人がその場で確かめられるほうがよい(オーナー判断)。書き込みになる
|
|
4401
|
+
// 「表示名を更新する」は、押した結果の中から別のボタンとして出る(probeSection)。
|
|
4402
|
+
//
|
|
4403
|
+
// **いまは Slack だけ。** GitHub は夜間の実測(probeGithubGate)が既にあるので繋ぐだけ、
|
|
4404
|
+
// Backlog / Figma / Drive は実測そのものが新規になる。同じ型で足せるよう、
|
|
4405
|
+
// 判定は infra/lambda/shared/slack-gate.mjs 側に置いてある(末尾に拡張点の説明がある)。
|
|
4406
|
+
//
|
|
4407
|
+
// **origin === "explicit" でも出す。** 確認は読むだけで、どの登録ファイル由来かに
|
|
4408
|
+
// 関係なく効く(書き込みになる「表示名を更新する」だけが由来で出し分かれる)
|
|
4409
|
+
if (SITE.intake && s.type === "slack" && s.ref) {
|
|
4410
|
+
card.appendChild(probeSection(s, card, gateEl));
|
|
4411
|
+
}
|
|
4174
4412
|
return card;
|
|
4175
4413
|
}
|
|
4176
4414
|
|
package/package.json
CHANGED