@takagaki/cortex-decisions-viewer 0.12.32 → 0.12.34
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 +68 -4
- package/dist/render.js +321 -61
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -297,6 +297,16 @@ async function findProjectIcon(knowledgeRoot) {
|
|
|
297
297
|
* ——「朝は正しいのに、開いて数秒すると表示が変わる」という一番気づきにくい食い違いになる。
|
|
298
298
|
*/
|
|
299
299
|
const SECRET_SPACE_STATES = ["new", "legacy", "false"];
|
|
300
|
+
/**
|
|
301
|
+
* 使っているツールの種別と状態の語彙(engine の `project-tools.mjs` の
|
|
302
|
+
* TOOL_KINDS / TOOL_STATES と**同じ並び・同じ語**)。
|
|
303
|
+
*
|
|
304
|
+
* 🔴 **知らない語の行は落とす。** 画面は kind でアイコンを、state で表示語を引くので、
|
|
305
|
+
* 知らない語を通すと「アイコンも状態も無い行」が並ぶ——engine が語を増やした日に、
|
|
306
|
+
* 顧客の画面が壊れて見える。落とせばその行が出ないだけで、他の行は今までどおり出る。
|
|
307
|
+
*/
|
|
308
|
+
const TOOL_KINDS = ["backlog", "github", "slack", "google-chat", "figma", "google-drive", "google-meet"];
|
|
309
|
+
const TOOL_STATES = ["reading", "waiting", "stopped", "unknown"];
|
|
300
310
|
/**
|
|
301
311
|
* リポジトリルートの fleet-status.json から externalSources / internalSources / pipelines を読む。
|
|
302
312
|
* ファイルが無い・パース不能・当該フィールドが無い場合は undefined を返し、
|
|
@@ -476,8 +486,56 @@ async function readFleetSources(repoRoot) {
|
|
|
476
486
|
applicable: typeof p.applicable === "boolean" ? p.applicable : undefined,
|
|
477
487
|
}))
|
|
478
488
|
: undefined;
|
|
479
|
-
//
|
|
480
|
-
//
|
|
489
|
+
// 案件が使っているツール(engine が登録簿 7 種から算出・#275)。
|
|
490
|
+
//
|
|
491
|
+
// **同じ `tools` という名前で、昔は能力→ツールの「宣言マップ」が入っていた**(#125 ⑤ で
|
|
492
|
+
// engine が出力から落とした)。艦隊には再生成前の古いスナップショットが残っていて、
|
|
493
|
+
// そこには `{ 開発: "github" }` のような**版を持たない別の形**が入っている。
|
|
494
|
+
// だから **version で見分ける**——`version: 1` でなければ、宣言マップも未知の新形式も
|
|
495
|
+
// 同じく「読まない」に倒れる。
|
|
496
|
+
//
|
|
497
|
+
// **知らないフィールドは黙って捨てる(明示の許可リスト)。** この JSON は engine が
|
|
498
|
+
// 単独で版を上げるので、画面が知らないキーは必ず先に入る。素通しにすると、
|
|
499
|
+
// 認証情報の伏せ字処理を通していない値が顧客の画面へ黙って流れる。
|
|
500
|
+
let tools;
|
|
501
|
+
if (obj.tools != null) {
|
|
502
|
+
const t = typeof obj.tools === "object" && !Array.isArray(obj.tools) ? obj.tools : null;
|
|
503
|
+
if (!t || t.version !== 1) {
|
|
504
|
+
// **1 行だけ残す。** 静かに消えると「engine が出していない」のか
|
|
505
|
+
// 「出しているが画面が読めていない」のかが切り分けられない
|
|
506
|
+
console.warn(`fleet-status.json の tools が未対応の形です(使用ツールの一覧は出しません): version=${String(t ? t.version : typeof obj.tools)}`);
|
|
507
|
+
}
|
|
508
|
+
else if (!Array.isArray(t.items)) {
|
|
509
|
+
console.warn(`fleet-status.json の tools.items が配列ではありません(使用ツールの一覧は出しません): ${typeof t.items}`);
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
const items = t.items
|
|
513
|
+
.filter((x) => x != null && typeof x === "object" && !Array.isArray(x))
|
|
514
|
+
.map((x) => ({
|
|
515
|
+
// **短縮記法にしないこと。** fleet-passthrough のテストが「画面が読むフィールドを
|
|
516
|
+
// build.ts が受け渡しているか」を `名前:` の字面で走査している
|
|
517
|
+
kind: String(x.kind ?? ""),
|
|
518
|
+
label: String(x.label ?? ""),
|
|
519
|
+
name: String(x.name ?? ""),
|
|
520
|
+
// 🔴 **url だけは null を保つ。** 「開ける先が無いと分かっている」(Google Meet)を
|
|
521
|
+
// 空文字に潰すと、画面が「名前もURLも空の行」と区別できなくなる
|
|
522
|
+
// **https?:// 以外は null に落とす。** fleet-status.json は案件リポにコミットされる
|
|
523
|
+
// ファイルなので、engine の導出以外(手編集・古い生成物)でも中身を書ける。
|
|
524
|
+
// `javascript:` のような値をそのまま href に載せない(el() の注意書きと同じ作法)
|
|
525
|
+
url: typeof x.url === "string" && /^https?:\/\//.test(x.url) ? x.url : null,
|
|
526
|
+
note: String(x.note ?? ""),
|
|
527
|
+
cap: String(x.cap ?? ""),
|
|
528
|
+
question: String(x.question ?? ""),
|
|
529
|
+
ref: String(x.ref ?? ""),
|
|
530
|
+
workspace: String(x.workspace ?? ""),
|
|
531
|
+
state: String(x.state ?? ""),
|
|
532
|
+
}))
|
|
533
|
+
.filter((x) => TOOL_KINDS.indexOf(x.kind) >= 0 && TOOL_STATES.indexOf(x.state) >= 0);
|
|
534
|
+
// **items が 0 件でも器は通す。** 「まだ 1 つも接続が無い」(接続の導線を出す)と
|
|
535
|
+
// 「この項目を知らない古い生成物」(何も出さない)は別の状態
|
|
536
|
+
tools = { version: 1, items: items, paragraph: String(t.paragraph ?? "") };
|
|
537
|
+
}
|
|
538
|
+
}
|
|
481
539
|
// 能力ごとの導出済みの状態(#125①が載せ、#125②で画面の正本になった)。
|
|
482
540
|
//
|
|
483
541
|
// **列挙し忘れは静かに消える。** このマッピングは素通しではなく明示の許可リストで、
|
|
@@ -585,7 +643,7 @@ async function readFleetSources(repoRoot) {
|
|
|
585
643
|
if (Object.keys(out).length)
|
|
586
644
|
secretSpaces = out;
|
|
587
645
|
}
|
|
588
|
-
return { externalSources, slackWorkspaces, internalSources, pipelines, capabilities, fleetGeneratedAt, secretSources, secretSpaces, checks, githubOwners, backlogTarget };
|
|
646
|
+
return { externalSources, slackWorkspaces, internalSources, pipelines, capabilities, fleetGeneratedAt, secretSources, secretSpaces, checks, githubOwners, backlogTarget, tools };
|
|
589
647
|
}
|
|
590
648
|
/**
|
|
591
649
|
* AIからの更新提案(`.cortex/gold-proposals.json`)を読む。
|
|
@@ -731,7 +789,10 @@ function isUnwritten(body) {
|
|
|
731
789
|
*
|
|
732
790
|
* @returns sections … 最上部に出す節(新形式・旧形式のどちらでも拾う)
|
|
733
791
|
* unfilled … 案件の概要・ゴールが未記入か(警告カードを出すか)
|
|
734
|
-
* restHtml …
|
|
792
|
+
* restHtml … 自己記述と旧説明を除いた残りの本文(案件ごとに書き足された節)。
|
|
793
|
+
* 手書きの「使用ツール」節もここに残る——**落とすのは画面側**(#275)。
|
|
794
|
+
* engine が `tools` を載せている案件でだけ落とす判断なので、
|
|
795
|
+
* `SITE.tools` を知らないここでは決められない
|
|
735
796
|
*/
|
|
736
797
|
async function buildHomeGrounding(rawMarkdown) {
|
|
737
798
|
const content = (0, gray_matter_1.default)(rawMarkdown).content;
|
|
@@ -1837,6 +1898,9 @@ async function build(opts) {
|
|
|
1837
1898
|
checks: fleet.checks,
|
|
1838
1899
|
githubOwners: fleet.githubOwners,
|
|
1839
1900
|
backlogTarget: fleet.backlogTarget,
|
|
1901
|
+
// 使っているツール(engine が登録簿から算出・#275)。**短縮記法にしないこと**
|
|
1902
|
+
// ——fleet-passthrough のテストが `名前:` の字面で受け渡しを走査している
|
|
1903
|
+
tools: fleet.tools,
|
|
1840
1904
|
// **undefined ならキーごと出さない**——画面は
|
|
1841
1905
|
// 「アイコンがある/無い」をキーの有無で見る(空の器を通さない)
|
|
1842
1906
|
projectIcon: projectIcon ? { file: projectIcon.file, repoPath: projectIcon.repoPath } : undefined,
|
package/dist/render.js
CHANGED
|
@@ -9,6 +9,8 @@ exports.isRepositorySlug = isRepositorySlug;
|
|
|
9
9
|
exports.devRepositoryRefs = devRepositoryRefs;
|
|
10
10
|
exports.claudeCodeRepositories = claudeCodeRepositories;
|
|
11
11
|
exports.claudeCodeUrl = claudeCodeUrl;
|
|
12
|
+
exports.toolStateLabel = toolStateLabel;
|
|
13
|
+
exports.toolStateWithLive = toolStateWithLive;
|
|
12
14
|
exports.isAlreadyRegistered = isAlreadyRegistered;
|
|
13
15
|
exports.sanitizeRegisteredNow = sanitizeRegisteredNow;
|
|
14
16
|
exports.sanitizeStateNow = sanitizeStateNow;
|
|
@@ -16,6 +18,7 @@ exports.overlayStateOnFleet = overlayStateOnFleet;
|
|
|
16
18
|
exports.chatRowsToAdd = chatRowsToAdd;
|
|
17
19
|
exports.gchatRowsToAdd = gchatRowsToAdd;
|
|
18
20
|
exports.devRowsToAdd = devRowsToAdd;
|
|
21
|
+
exports.markExcludedPendingRows = markExcludedPendingRows;
|
|
19
22
|
exports.designRowsToAdd = designRowsToAdd;
|
|
20
23
|
exports.materialRowsToAdd = materialRowsToAdd;
|
|
21
24
|
exports.issuesRefOf = issuesRefOf;
|
|
@@ -60,7 +63,9 @@ function renderSite(site, assets) {
|
|
|
60
63
|
: "";
|
|
61
64
|
// 組み立ての正本は claudeCodeUrl 1か所(#404)。ここは薄い包みに留める。
|
|
62
65
|
// `?? []` は必須——build.ts は fleet-status.json が無い案件で externalSources を持たない
|
|
63
|
-
|
|
66
|
+
// 第4引数は使っているツールの段落(#275)。**7導線すべてに同じ段落を付ける**ため、
|
|
67
|
+
// 渡す場所も codeUrl 1か所に寄せる(クライアント側の codeUrl と対)
|
|
68
|
+
const codeUrl = (prompt) => claudeCodeUrl(prompt, repoSlug, site.externalSources ?? [], site.tools && site.tools.paragraph);
|
|
64
69
|
/** ヘッダー「AIに聞く」の指示文。data-ai-prompt に同じ値を残し、接続状況が届いたら href を組み直す */
|
|
65
70
|
const ASK_PROMPT = "このプロジェクトの概要について教えてください。";
|
|
66
71
|
const askUrl = codeUrl(ASK_PROMPT);
|
|
@@ -451,12 +456,103 @@ function claudeCodeRepositories(projectRepo, devRefs) {
|
|
|
451
456
|
*
|
|
452
457
|
* repositories はカンマ区切りで**素のまま**載せる(公式の例がその形で、スラッシュも
|
|
453
458
|
* エンコードしない)。指示文だけ encodeURIComponent する。
|
|
459
|
+
*
|
|
460
|
+
* `toolsParagraph`(#275)は「この案件が使っているツール: …」の 1 段落。非空なら
|
|
461
|
+
* **指示文の先頭に付ける**。7 導線すべてがこの 1 関数を通るので、ここに置くだけで
|
|
462
|
+
* どのボタンから開いても AI が最初に案件の道具立てを知る——**呼び出し側で足さないこと**
|
|
463
|
+
* (足すと、足し忘れたボタンだけ文脈の無い起動になる)。
|
|
464
|
+
* `data-ai-prompt` には元の指示文を残す(貼り替えもこの関数を通るので段落は保たれる)。
|
|
454
465
|
*/
|
|
455
|
-
function claudeCodeUrl(prompt, projectRepo, externals) {
|
|
466
|
+
function claudeCodeUrl(prompt, projectRepo, externals, toolsParagraph) {
|
|
456
467
|
var repos = claudeCodeRepositories(projectRepo, devRepositoryRefs(externals));
|
|
457
468
|
if (!repos.length)
|
|
458
469
|
return CLAUDE_CODE_HOME;
|
|
459
|
-
|
|
470
|
+
var text = toolsParagraph ? String(toolsParagraph) + "\n\n" + prompt : prompt;
|
|
471
|
+
return "https://claude.ai/code?repositories=" + repos.join(",") + "&prompt=" + encodeURIComponent(text);
|
|
472
|
+
}
|
|
473
|
+
// ---------------------------------------------------------------------------
|
|
474
|
+
// Home の「使用ツール」(engine #275)— 一覧は engine が登録簿から算出した `SITE.tools`
|
|
475
|
+
//
|
|
476
|
+
// **ビューアは登録簿(channels.json 等)を読まない。** 読むと「使っていると言う条件」が
|
|
477
|
+
// engine と画面で 2 枚になり、片方だけ直った日から一覧と AI の起動文が食い違う
|
|
478
|
+
// (viewer/test/no-registry-read.test.mjs が見張っている)。
|
|
479
|
+
// ---------------------------------------------------------------------------
|
|
480
|
+
/**
|
|
481
|
+
* 種別のアイコン。**DS_TYPE(データソース一覧)と同じ絵柄にそろえる**——同じツールが
|
|
482
|
+
* 2 つの画面で違う顔をしていると、同じものだと分からない。
|
|
483
|
+
*/
|
|
484
|
+
const TOOL_KIND_ICONS = {
|
|
485
|
+
"backlog": "📋",
|
|
486
|
+
"github": "🐙",
|
|
487
|
+
"slack": "💬",
|
|
488
|
+
"google-chat": "💬",
|
|
489
|
+
"figma": "🎨",
|
|
490
|
+
"google-drive": "📁",
|
|
491
|
+
"google-meet": "🎥",
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* 状態の表示語と色。**4 語しか出さない**(読み取り中/承認待ち/停止中/未確認)。
|
|
495
|
+
*
|
|
496
|
+
* 色は既存の `ds-gate-*` を流用する——同じ画面で「緑=読めている・橙=人の操作待ち・
|
|
497
|
+
* 灰=分からない」の意味を 2 通りに増やさない。
|
|
498
|
+
*
|
|
499
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
500
|
+
*/
|
|
501
|
+
function toolStateLabel(state) {
|
|
502
|
+
if (state === "reading")
|
|
503
|
+
return { text: "読み取り中", cls: "ds-gate-ok" };
|
|
504
|
+
if (state === "waiting")
|
|
505
|
+
return { text: "承認待ち", cls: "ds-gate-warn" };
|
|
506
|
+
// 止めているものは警告色にしない(直す必要が無いので、橙にすると直しに行かせてしまう)
|
|
507
|
+
if (state === "stopped")
|
|
508
|
+
return { text: "停止中", cls: "ds-gate-muted" };
|
|
509
|
+
return { text: "未確認", cls: "ds-gate-muted" };
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* ビルド時の状態に、接続状態ストアの実測(`stateNow`)を重ねた state を返す。
|
|
513
|
+
*
|
|
514
|
+
* 🔴 **`stopped` は上書きしない。** 止めているのは登録簿から決まる事実で、
|
|
515
|
+
* ストアが「届く」と答えても読み取っていない。**止めたものを「読み取り中」と言わない**。
|
|
516
|
+
*
|
|
517
|
+
* 🔴 **突き合わせの鍵は行が自分で持っている**(cap + question + ref、Slack だけ workspace)。
|
|
518
|
+
* ここで種別ごとの if 連鎖を書き直すと、engine の書き手(connection-state-write-*)と
|
|
519
|
+
* 鍵の作り方が 2 枚になる。**github だけ大小を無視する**——登録簿の owner/repo と
|
|
520
|
+
* ストアの ref は、人が貼った URL 由来で大小が揺れる。
|
|
521
|
+
*
|
|
522
|
+
* 行が無ければビルド時の値のまま(**「不明」に化けさせない**——夜間が測った結果を
|
|
523
|
+
* ライブが答えなかっただけで消すと、朝には出ていたものが消える)。
|
|
524
|
+
*
|
|
525
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
526
|
+
*/
|
|
527
|
+
function toolStateWithLive(item, rows) {
|
|
528
|
+
if (!item)
|
|
529
|
+
return "unknown";
|
|
530
|
+
if (item.state === "stopped")
|
|
531
|
+
return "stopped";
|
|
532
|
+
var hit = null;
|
|
533
|
+
(rows || []).forEach(function (r) {
|
|
534
|
+
if (hit || !r)
|
|
535
|
+
return;
|
|
536
|
+
if (r.cap !== item.cap || r.question !== item.question)
|
|
537
|
+
return;
|
|
538
|
+
var a = String(r.ref == null ? "" : r.ref);
|
|
539
|
+
var b = String(item.ref == null ? "" : item.ref);
|
|
540
|
+
if (item.cap === "dev" ? a.toLowerCase() !== b.toLowerCase() : a !== b)
|
|
541
|
+
return;
|
|
542
|
+
// チャンネルIDはワークスペースの中でしか一意でない(overlayStateOnFleet と同じ鍵)
|
|
543
|
+
if (item.cap === "chat" && String(r.workspace || "") !== String(item.workspace || ""))
|
|
544
|
+
return;
|
|
545
|
+
hit = r;
|
|
546
|
+
});
|
|
547
|
+
if (!hit)
|
|
548
|
+
return String(item.state || "unknown");
|
|
549
|
+
if (hit.status === "ok")
|
|
550
|
+
return "reading";
|
|
551
|
+
// **「測ったが分からなかった」は「承認待ち」に寄せない**(人が押す操作が無い)
|
|
552
|
+
if (hit.status === "unknown")
|
|
553
|
+
return "unknown";
|
|
554
|
+
// failed / skipped / not_in_channel / missing_scope / no_token … は全部「人の操作待ち」
|
|
555
|
+
return "waiting";
|
|
460
556
|
}
|
|
461
557
|
/**
|
|
462
558
|
* 外部ソースの行が「この能力・このアダプタのタイル」に属するか。
|
|
@@ -1011,6 +1107,44 @@ function devRowsToAdd(externals, rows) {
|
|
|
1011
1107
|
}
|
|
1012
1108
|
return out;
|
|
1013
1109
|
}
|
|
1110
|
+
/**
|
|
1111
|
+
* 仮置きで足した GitHub の行に、「読み取り停止中」の印を写す(#409 の後追い)。
|
|
1112
|
+
*
|
|
1113
|
+
* 🔴 **仮置きの行は印を持たない。** `pendingExternalRow` が作れるのは payload から
|
|
1114
|
+
* 切り出せる値だけで、その repo が `exclude` に居るかは登録ファイル側にしかない。
|
|
1115
|
+
*
|
|
1116
|
+
* それが問題になるのはこの一続きのときだけ:
|
|
1117
|
+
* 読み取りを止めた repo を**もう一度追加すると、サーバは「既に登録されています」と断る**
|
|
1118
|
+
*(`sources` には残っているため)。#409 で画面はその断りを事実として受け取り行を出すように
|
|
1119
|
+
* なったが、**印が無いので「読み取り中の行」として並ぶ**——止めたはずのものが動いて
|
|
1120
|
+
* 見えるので、**止め忘れたと思ってもう一度止めに行く**ことになる。まとめ表にも
|
|
1121
|
+
* 即時読み取りの `dev` にもその行は居ない(除外は `devExcluded` に分かれている)ので、
|
|
1122
|
+
* 他のどこからも印は付かない。
|
|
1123
|
+
*
|
|
1124
|
+
* **クロージャを持たない純関数に保つこと**(`.toString()` でクライアントへ渡す)。
|
|
1125
|
+
*/
|
|
1126
|
+
function markExcludedPendingRows(view, reg) {
|
|
1127
|
+
const v = view || {};
|
|
1128
|
+
const rows = v.externalSources;
|
|
1129
|
+
if (!reg || !Array.isArray(reg.devExcluded) || !Array.isArray(rows))
|
|
1130
|
+
return v;
|
|
1131
|
+
const excluded = {};
|
|
1132
|
+
for (const r of reg.devExcluded)
|
|
1133
|
+
if (r && r.ref)
|
|
1134
|
+
excluded[String(r.ref).toLowerCase()] = true;
|
|
1135
|
+
let changed = false;
|
|
1136
|
+
const next = rows.map(function (s) {
|
|
1137
|
+
if (!s || s.pending !== true || !s.ref || s.goldState)
|
|
1138
|
+
return s;
|
|
1139
|
+
if (String(s.type || "").indexOf("github") !== 0)
|
|
1140
|
+
return s;
|
|
1141
|
+
if (excluded[String(s.ref).toLowerCase()] !== true)
|
|
1142
|
+
return s;
|
|
1143
|
+
changed = true;
|
|
1144
|
+
return Object.assign({}, s, { goldState: "excluded" });
|
|
1145
|
+
});
|
|
1146
|
+
return changed ? Object.assign({}, v, { externalSources: next }) : v;
|
|
1147
|
+
}
|
|
1014
1148
|
/** デザインの行で、まとめ表がまだ知らないもの(鍵はファイルキー) */
|
|
1015
1149
|
function designRowsToAdd(files, rows) {
|
|
1016
1150
|
const have = {};
|
|
@@ -2663,6 +2797,21 @@ button.site-icon[aria-busy="true"] .site-icon-plus { opacity: 0; }
|
|
|
2663
2797
|
padding-bottom: 6px; border-bottom: 1px solid var(--border);
|
|
2664
2798
|
}
|
|
2665
2799
|
.home-grounding > .home-grounding-title:first-child { margin-top: 0; }
|
|
2800
|
+
/* ---- Home の「使用ツール」(engine が登録簿から算出・#275)----
|
|
2801
|
+
自己記述の直後に出る一覧。**本文より目立たせない**——案件の説明を押しのけない。
|
|
2802
|
+
状態チップは操作タブと同じ .ds-gate 系を使う(同じ意味の色を2通りに増やさない) */
|
|
2803
|
+
.home-tools { margin: 0 0 8px; }
|
|
2804
|
+
.home-tools-list { list-style: none; margin: 8px 0 0; padding: 0; }
|
|
2805
|
+
.home-tools-item {
|
|
2806
|
+
display: flex; flex-wrap: wrap; gap: 6px 12px; align-items: center;
|
|
2807
|
+
padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 13.5px;
|
|
2808
|
+
}
|
|
2809
|
+
.home-tools-item:last-child { border-bottom: none; }
|
|
2810
|
+
/* 種別は幅をそろえて縦に読めるようにする(名前の頭が段違いだと一覧に見えない) */
|
|
2811
|
+
.home-tools-kind { flex: 0 0 auto; min-width: 9.5em; font-weight: 600; color: var(--muted); }
|
|
2812
|
+
.home-tools-name { flex: 1 1 220px; min-width: 0; word-break: break-all; }
|
|
2813
|
+
.home-tools-state { flex: 0 0 auto; }
|
|
2814
|
+
.home-tools-empty, .home-tools-note { font-size: 12.5px; color: var(--muted); line-height: 1.7; margin: 8px 0 0; }
|
|
2666
2815
|
/* ---- レコード詳細の「AIによる最近の変更」(リポジトリの git 履歴 由来)----
|
|
2667
2816
|
カードは詳細ページの提案(.proposals)と同系色にする——どちらも
|
|
2668
2817
|
「AIがやったこと・言っていることを読む」もので種類が同じ。
|
|
@@ -3604,6 +3753,7 @@ ${sanitizeRegisteredNow.toString()}
|
|
|
3604
3753
|
${chatRowsToAdd.toString()}
|
|
3605
3754
|
${gchatRowsToAdd.toString()}
|
|
3606
3755
|
${devRowsToAdd.toString()}
|
|
3756
|
+
${markExcludedPendingRows.toString()}
|
|
3607
3757
|
${designRowsToAdd.toString()}
|
|
3608
3758
|
${materialRowsToAdd.toString()}
|
|
3609
3759
|
${issueRowsToAdd.toString()}
|
|
@@ -3649,6 +3799,12 @@ var STATE_STATUSES = ${JSON.stringify(STATE_STATUSES)};
|
|
|
3649
3799
|
var STATE_ROW_FIELDS = ${JSON.stringify(STATE_ROW_FIELDS)};
|
|
3650
3800
|
${sanitizeStateNow.toString()}
|
|
3651
3801
|
${overlayStateOnFleet.toString()}
|
|
3802
|
+
// Home の「使用ツール」(#275)。**判定と表示語の実体はビルド時の定義**——
|
|
3803
|
+
// 画面側に書き写すと、状態の言い換えが 2 枚になって片方だけ直る。
|
|
3804
|
+
// 🔴 この定数行を落とすと、流し込んだ描画がアイコンを引けずに素の kind を出す
|
|
3805
|
+
var TOOL_KIND_ICONS = ${JSON.stringify(TOOL_KIND_ICONS)};
|
|
3806
|
+
${toolStateLabel.toString()}
|
|
3807
|
+
${toolStateWithLive.toString()}
|
|
3652
3808
|
${nextStateDelay.toString()}
|
|
3653
3809
|
// 工程1.5: 正本を直接読む(secretsNow / capabilitiesNow / githubOwners)。
|
|
3654
3810
|
// **判定の実体はビルド時の定義**——画面側に書き写すと許可リストが2枚になる
|
|
@@ -4050,8 +4206,62 @@ ${deriveCapTile.toString()}
|
|
|
4050
4206
|
// 🔴 **var MERGE_KEYS の宣言より上に codeUrl を呼ぶトップレベル文を足さないこと。**
|
|
4051
4207
|
// fleetVal は MERGE_KEYS を読むが、var の初期化は宣言行に達するまで走らない
|
|
4052
4208
|
// (関数宣言の巻き上げでは undefined を読む)。呼び出しは全て描画(route)以降に置く
|
|
4209
|
+
// 第4引数は使っているツールの段落(#275)。**焼き込んだ SITE から取る**——この段落は
|
|
4210
|
+
// engine が毎朝 fleet-status.json に載せるもので、ライブ(op=state)は運んでこない
|
|
4053
4211
|
function codeUrl(prompt) {
|
|
4054
|
-
return claudeCodeUrl(prompt, REPO_SLUG, fleetVal("externalSources") || []);
|
|
4212
|
+
return claudeCodeUrl(prompt, REPO_SLUG, fleetVal("externalSources") || [], SITE.tools && SITE.tools.paragraph);
|
|
4213
|
+
}
|
|
4214
|
+
/**
|
|
4215
|
+
* 🔴 **「1件も登録されていない」と「確かめられなかった」を分ける(#409)。**
|
|
4216
|
+
*
|
|
4217
|
+
* サーバは登録ファイルを読めなかった能力を、**キーごと応答から落とす**
|
|
4218
|
+
*(「読めなかった」を「0件」と混ぜないため。intake の buildRegisteredNow)。
|
|
4219
|
+
* ところが画面はそれを「足す行が無い」としか受け取っていなかったので、
|
|
4220
|
+
* **確かめられなかった結果が「登録されていません」として出ていた**。
|
|
4221
|
+
* オーナーはそれを見て未登録だと読み、追加して「既に登録されています」と断られた。
|
|
4222
|
+
*
|
|
4223
|
+
* 🔴 **能力ごとのキーの有無で判定してはいけない(実装レビューの指摘)。** サーバは
|
|
4224
|
+
* 「読めなかった」ときだけでなく **「そのファイルがまだ無い」ときにも同じくキーを落とす**
|
|
4225
|
+
* (読んだ本文が null でも undefined でも、文字列でなければ同じ枝に落ちる)。
|
|
4226
|
+
* キーの有無で見ると、**その能力をまだ使っていない案件**——つまり立ち上げ直後の、
|
|
4227
|
+
* この画面が一番よく見られる状態——に**永久に消えない誤警報**が出る
|
|
4228
|
+
* (「再読み込みしてください」と言われても、設定ファイルは再読み込みでは生えない)。
|
|
4229
|
+
* しかも製品としては、その状態は「登録されていません」と言い切ると決めてある
|
|
4230
|
+
* (engine の capabilities: ファイルの有無は実装の都合で、利用者にはどちらも「まだ登録していない」)。
|
|
4231
|
+
*
|
|
4232
|
+
* **だから応答まるごとで見る。** 登録ファイルの一覧(registeredNow)と
|
|
4233
|
+
* 能力の状態(capabilitiesNow)は**サーバの同じ return から出る**ので、
|
|
4234
|
+
* **両方とも無いときだけ**が「そもそも読みに行けなかった」——今回の症状の
|
|
4235
|
+
* 3経路(ツリー取得の失敗・ツリーの打ち切り・応答そのものの失敗)は全部これに当たる。
|
|
4236
|
+
*
|
|
4237
|
+
* ⚠ この粒度では、**ファイル1本だけが読めなかった回**(8秒の打ち切り・単発の失敗)は
|
|
4238
|
+
* 拾えない。そちらはサーバがログを出す経路なので、まず記録から追えるようにしてある。
|
|
4239
|
+
*/
|
|
4240
|
+
function registrationUnreadable() {
|
|
4241
|
+
return liveAnswered && LIVE_REGISTERED === null && LIVE_CAPS === null;
|
|
4242
|
+
}
|
|
4243
|
+
/**
|
|
4244
|
+
* 一覧に添える1行。**帯は症状・行は一手・繰り返さない。**
|
|
4245
|
+
* 応答がまだ届いていない間は出さない(確かめる前に「確かめられなかった」と言わない)。
|
|
4246
|
+
*
|
|
4247
|
+
* **0件のときは一覧の代わり**——空の一覧そのものを出さない(オーナーが踏んだのは
|
|
4248
|
+
* 「空の一覧を見て未登録だと読んだ」ことなので)。
|
|
4249
|
+
*
|
|
4250
|
+
* 🔴 **行があるときも黙らない。** まとめ表が行を持っていれば一覧は出るが、
|
|
4251
|
+
* **その日足したばかりの行だけが欠けたまま、完全な一覧に見える**——利用者の読み違い方は
|
|
4252
|
+
* 0件のときと同じで、「自分が足したものは登録されていない」と読む。行は本物なので消さず、
|
|
4253
|
+
* **欠けているかもしれないことだけを添える**。
|
|
4254
|
+
*
|
|
4255
|
+
* ⚠ 「表示は前の晩の内容です」とは言わない。一覧にはまとめ表(前の晩)だけでなく
|
|
4256
|
+
* **このブラウザが覚えている反映待ちの行も混ざる**ので、言い切ると画面自身が嘘をつく。
|
|
4257
|
+
* 利用者が知りたいのは日付ではなく「自分が足したものが抜けているかどうか」。
|
|
4258
|
+
*/
|
|
4259
|
+
function unverifiedListNote(noun, hasRows) {
|
|
4260
|
+
if (!registrationUnreadable()) return null;
|
|
4261
|
+
var head = "登録されている" + noun + "を確認できませんでした。";
|
|
4262
|
+
return el("div", { class: "ds-note", text: hasRows
|
|
4263
|
+
? head + "最近足したものが抜けているかもしれません。再読み込みしてください。"
|
|
4264
|
+
: head + "再読み込みしてください。" });
|
|
4055
4265
|
}
|
|
4056
4266
|
// AI 導線の a はここでだけ作る。href を決めてよいのは codeUrl だけ(#404)。
|
|
4057
4267
|
// 指示文を属性に残すのは、接続状況の応答が届いたときに href を組み直すため(syncAiLinks)
|
|
@@ -4997,6 +5207,10 @@ ${deriveCapTile.toString()}
|
|
|
4997
5207
|
var g = SITE.homeGrounding;
|
|
4998
5208
|
if (g && g.unfilled) app.appendChild(homeUnfilledCard());
|
|
4999
5209
|
if (g && g.sections.length) app.appendChild(homeGroundingSections(g.sections));
|
|
5210
|
+
// **使っているツールは自己記述の直後・本文の前**(#275)。案件の説明を読んだ流れで
|
|
5211
|
+
// 「どこに情報があるか」を見せる。中身は engine が登録簿から算出したもの
|
|
5212
|
+
var toolsSec = homeToolsSection();
|
|
5213
|
+
if (toolsSec) app.appendChild(toolsSec);
|
|
5000
5214
|
|
|
5001
5215
|
var homeBody = el("div", { class: "body" });
|
|
5002
5216
|
app.appendChild(homeBody);
|
|
@@ -5021,6 +5235,74 @@ ${deriveCapTile.toString()}
|
|
|
5021
5235
|
return box;
|
|
5022
5236
|
}
|
|
5023
5237
|
|
|
5238
|
+
/**
|
|
5239
|
+
* Home の「使用ツール」(#275)。engine が登録簿 7 種から算出した SITE.tools を描く。
|
|
5240
|
+
*
|
|
5241
|
+
* 🔴 **SITE.tools が無ければ何も出さない。** 生成が古い案件(この項目を知らない
|
|
5242
|
+
* fleet-status.json)では、手書きの節が本文に残っているので、そちらがそのまま出る
|
|
5243
|
+
* ——ここで「まだ接続していません」と出すと、繋いである案件に嘘を出すことになる。
|
|
5244
|
+
*
|
|
5245
|
+
* **0 件は 1 行で言い切る。** 空の一覧を出すと「読み込み中」に見える。
|
|
5246
|
+
*/
|
|
5247
|
+
function homeToolsSection() {
|
|
5248
|
+
var t = SITE.tools;
|
|
5249
|
+
// build を通った値は必ず items を持つ。持たない形(renderSite 直渡し・壊れた埋め込み)は
|
|
5250
|
+
// 「この項目を知らない」と同じ扱いにして節ごと出さない
|
|
5251
|
+
if (!t || !Array.isArray(t.items)) return null;
|
|
5252
|
+
var box = el("section", { class: "home-tools" });
|
|
5253
|
+
box.appendChild(el("h2", { class: "home-grounding-title", text: "使用ツール" }));
|
|
5254
|
+
var items = t.items || [];
|
|
5255
|
+
if (!items.length) {
|
|
5256
|
+
box.appendChild(el("p", { class: "home-tools-empty", text: "まだツールを接続していません。操作タブから接続できます。" }));
|
|
5257
|
+
return box;
|
|
5258
|
+
}
|
|
5259
|
+
var ul = el("ul", { class: "home-tools-list" });
|
|
5260
|
+
items.forEach(function (it) {
|
|
5261
|
+
var li = el("li", { class: "home-tools-item" });
|
|
5262
|
+
// 種別は**ツール名**(能力名でも単位語でもない)。DS_TYPE の行の約束と同じ
|
|
5263
|
+
li.appendChild(el("span", {
|
|
5264
|
+
class: "home-tools-kind",
|
|
5265
|
+
text: (TOOL_KIND_ICONS[it.kind] || "🔗") + " " + (it.label || it.kind),
|
|
5266
|
+
}));
|
|
5267
|
+
var name = it.name || it.ref || "";
|
|
5268
|
+
// **開ける先が無い行(Google Meet)はリンクにしない。** 押せないリンクを出すより
|
|
5269
|
+
// 素のテキストのほうが正直(url は engine が null で「無い」と言い切っている)
|
|
5270
|
+
// href に載せる前に isHttp を通す(build 側の許可リストと二重の守り。el() の注意書きのとおり)
|
|
5271
|
+
if (it.url && isHttp(it.url)) li.appendChild(el("a", { class: "home-tools-name", href: it.url, target: "_blank", rel: "noopener", text: name }));
|
|
5272
|
+
else li.appendChild(el("span", { class: "home-tools-name", text: name }));
|
|
5273
|
+
// ライブの実測が届いていれば重ねる(stopped は上書きしない・toolStateWithLive)
|
|
5274
|
+
var st = toolStateWithLive(it, LIVE_STATE);
|
|
5275
|
+
var lab = toolStateLabel(st);
|
|
5276
|
+
var chip = el("span", { class: "home-tools-state ds-gate " + lab.cls, text: lab.text });
|
|
5277
|
+
// 状態そのものを属性に残す(表示語を読み替えずに検査・スタイルできるように)
|
|
5278
|
+
chip.setAttribute("data-state", st);
|
|
5279
|
+
li.appendChild(chip);
|
|
5280
|
+
ul.appendChild(li);
|
|
5281
|
+
});
|
|
5282
|
+
box.appendChild(ul);
|
|
5283
|
+
// **どこで直せるか・いつの情報かを 1 行で言う。** 操作タブで繋いだ直後は
|
|
5284
|
+
// この一覧に出ない(engine が毎朝作り直すまで)ので、黙っていると「効いていない」と読まれる
|
|
5285
|
+
box.appendChild(el("p", {
|
|
5286
|
+
class: "home-tools-note",
|
|
5287
|
+
text: "接続の追加・変更は操作タブで行います(この一覧は毎朝更新されます)。",
|
|
5288
|
+
}));
|
|
5289
|
+
return box;
|
|
5290
|
+
}
|
|
5291
|
+
|
|
5292
|
+
/**
|
|
5293
|
+
* 接続状況(op=state)が届いたときに「使用ツール」を描き直す(#275)。
|
|
5294
|
+
*
|
|
5295
|
+
* 🔴 **document を素で引かない(app.ownerDocument)。** 応答は画面が畳まれた後に
|
|
5296
|
+
* 届くことがある(syncAiLinks と同じ理由)。Home 以外のタブを開いていれば節そのものが
|
|
5297
|
+
* 無いので、何もせずに戻る
|
|
5298
|
+
*/
|
|
5299
|
+
function syncHomeTools() {
|
|
5300
|
+
var old = app.ownerDocument.querySelector(".home-tools");
|
|
5301
|
+
if (!old || !old.parentNode) return;
|
|
5302
|
+
var next = homeToolsSection();
|
|
5303
|
+
if (next) old.parentNode.replaceChild(next, old);
|
|
5304
|
+
}
|
|
5305
|
+
|
|
5024
5306
|
/**
|
|
5025
5307
|
* 未記入の警告。**「書かれていないと何が起きるか」まで書く。**
|
|
5026
5308
|
*
|
|
@@ -5068,7 +5350,13 @@ ${deriveCapTile.toString()}
|
|
|
5068
5350
|
var kids = Array.prototype.slice.call(mount.children);
|
|
5069
5351
|
var dropping = false;
|
|
5070
5352
|
kids.forEach(function (n) {
|
|
5071
|
-
|
|
5353
|
+
// 🔴 **「使用ツール」は HOME_DROP_HEADINGS に入れない。** 落としてよいのは
|
|
5354
|
+
// 自動の一覧を出す案件(SITE.tools がある)だけ——engine が算出を載せていない
|
|
5355
|
+
// 案件で手書きの節まで消すと、**画面から使用ツールが丸ごと消える**(#275)
|
|
5356
|
+
if (n.tagName === "H2") {
|
|
5357
|
+
var h2 = (n.textContent || "").trim();
|
|
5358
|
+
dropping = !!HOME_DROP_HEADINGS[h2] || (h2 === "使用ツール" && !!SITE.tools);
|
|
5359
|
+
}
|
|
5072
5360
|
// H2 より上位の見出しが来たら、そこで打ち切る(節の外まで消さない)
|
|
5073
5361
|
else if (n.tagName === "H1") dropping = false;
|
|
5074
5362
|
if (dropping && n.parentNode) n.parentNode.removeChild(n);
|
|
@@ -6499,7 +6787,7 @@ ${deriveCapTile.toString()}
|
|
|
6499
6787
|
// 状態ストアの答えは常に勝つ(まとめ表は gate を焼き込まない。overlayStateOnFleet の項)
|
|
6500
6788
|
if (!MERGED) {
|
|
6501
6789
|
MERGED = overlayStateOnFleet(
|
|
6502
|
-
applyPendingOps(mergeRegisteredFleet(rawView(), LIVE_REGISTERED), pend),
|
|
6790
|
+
markExcludedPendingRows(applyPendingOps(mergeRegisteredFleet(rawView(), LIVE_REGISTERED), pend), LIVE_REGISTERED),
|
|
6503
6791
|
LIVE_STATE,
|
|
6504
6792
|
);
|
|
6505
6793
|
}
|
|
@@ -7431,44 +7719,6 @@ ${deriveCapTile.toString()}
|
|
|
7431
7719
|
* (素の Decisions ビュー)で行も無い能力に空の箱を積むと、押しても何も無いモーダルになる。
|
|
7432
7720
|
*/
|
|
7433
7721
|
function liveListWanted(kind) { return !!SITE.intake || liveExternals(kind).length > 0; }
|
|
7434
|
-
/**
|
|
7435
|
-
* 🔴 **「1件も登録されていない」と「確かめられなかった」を分ける(#409)。**
|
|
7436
|
-
*
|
|
7437
|
-
* サーバは登録ファイルを読めなかった能力を、**キーごと応答から落とす**
|
|
7438
|
-
*(「読めなかった」を「0件」と混ぜないため。intake の buildRegisteredNow)。
|
|
7439
|
-
* ところが画面はそれを「足す行が無い」としか受け取っていなかったので、
|
|
7440
|
-
* **確かめられなかった結果が「登録されていません」として出ていた**。
|
|
7441
|
-
* オーナーはそれを見て未登録だと読み、追加して「既に登録されています」と断られた。
|
|
7442
|
-
*
|
|
7443
|
-
* 🔴 **能力ごとのキーの有無で判定してはいけない(実装レビューの指摘)。** サーバは
|
|
7444
|
-
* 「読めなかった」ときだけでなく **「そのファイルがまだ無い」ときにも同じくキーを落とす**
|
|
7445
|
-
* (読んだ本文が null でも undefined でも、文字列でなければ同じ枝に落ちる)。
|
|
7446
|
-
* キーの有無で見ると、**その能力をまだ使っていない案件**——つまり立ち上げ直後の、
|
|
7447
|
-
* この画面が一番よく見られる状態——に**永久に消えない誤警報**が出る
|
|
7448
|
-
* (「再読み込みしてください」と言われても、設定ファイルは再読み込みでは生えない)。
|
|
7449
|
-
* しかも製品としては、その状態は「登録されていません」と言い切ると決めてある
|
|
7450
|
-
* (engine の capabilities: ファイルの有無は実装の都合で、利用者にはどちらも「まだ登録していない」)。
|
|
7451
|
-
*
|
|
7452
|
-
* **だから応答まるごとで見る。** 登録ファイルの一覧(registeredNow)と
|
|
7453
|
-
* 能力の状態(capabilitiesNow)は**サーバの同じ return から出る**ので、
|
|
7454
|
-
* **両方とも無いときだけ**が「そもそも読みに行けなかった」——今回の症状の
|
|
7455
|
-
* 3経路(ツリー取得の失敗・ツリーの打ち切り・応答そのものの失敗)は全部これに当たる。
|
|
7456
|
-
*
|
|
7457
|
-
* ⚠ この粒度では、**ファイル1本だけが読めなかった回**(8秒の打ち切り・単発の失敗)は
|
|
7458
|
-
* 拾えない。そちらはサーバがログを出す経路なので、まず記録から追えるようにしてある。
|
|
7459
|
-
*/
|
|
7460
|
-
function registrationUnreadable() {
|
|
7461
|
-
return liveAnswered && LIVE_REGISTERED === null && LIVE_CAPS === null;
|
|
7462
|
-
}
|
|
7463
|
-
/**
|
|
7464
|
-
* 空の一覧の代わりに出す1行。**帯は症状・行は一手・繰り返さない。**
|
|
7465
|
-
* 空の一覧そのものを出さない——今回オーナーが踏んだのは「空の一覧を見て未登録だと読んだ」ことなので。
|
|
7466
|
-
* 応答がまだ届いていない間は出さない(確かめる前に「確かめられなかった」と言わない)。
|
|
7467
|
-
*/
|
|
7468
|
-
function unverifiedListNote(noun) {
|
|
7469
|
-
if (!registrationUnreadable()) return null;
|
|
7470
|
-
return el("div", { class: "ds-note", text: "登録されている" + noun + "を確認できませんでした。再読み込みしてください。" });
|
|
7471
|
-
}
|
|
7472
7722
|
// **箱にはアダプタのタグを付ける(#153)。** pushCap の無タグは「どのタイルにも出す」
|
|
7473
7723
|
// 既定なので、タグを忘れると Slack の一覧が Google Chat モーダルに丸ごと出る
|
|
7474
7724
|
if (liveListWanted("slack")) pushCap("チャット", liveList(
|
|
@@ -7476,11 +7726,10 @@ ${deriveCapTile.toString()}
|
|
|
7476
7726
|
function () { return externalsSig("slack", slackWorkspaces()); },
|
|
7477
7727
|
function (box) {
|
|
7478
7728
|
var items = liveExternals("slack");
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
}
|
|
7729
|
+
// 注記は**行より前**に置く(0件なら一覧の代わり・行があれば添え書き)
|
|
7730
|
+
var noteSlack = unverifiedListNote("チャンネル", items.length > 0);
|
|
7731
|
+
if (noteSlack) box.appendChild(noteSlack);
|
|
7732
|
+
if (!items.length) return;
|
|
7484
7733
|
var meta = DS_TYPE["slack"] || { icon: "🔗", label: "Slack" };
|
|
7485
7734
|
slackRows(items, meta).forEach(function (n) { box.appendChild(n); });
|
|
7486
7735
|
},
|
|
@@ -7492,11 +7741,10 @@ ${deriveCapTile.toString()}
|
|
|
7492
7741
|
function () { return externalsSig("google-chat", null); },
|
|
7493
7742
|
function (box) {
|
|
7494
7743
|
var items = liveExternals("google-chat");
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
}
|
|
7744
|
+
// 注記は**行より前**に置く(0件なら一覧の代わり・行があれば添え書き)
|
|
7745
|
+
var noteGchat = unverifiedListNote("スペース", items.length > 0);
|
|
7746
|
+
if (noteGchat) box.appendChild(noteGchat);
|
|
7747
|
+
if (!items.length) return;
|
|
7500
7748
|
var meta = DS_TYPE["google-chat"] || { icon: "💬", label: "Google Chat" };
|
|
7501
7749
|
items.forEach(function (s) { box.appendChild(extSourceCard(s, meta)); });
|
|
7502
7750
|
},
|
|
@@ -7506,11 +7754,10 @@ ${deriveCapTile.toString()}
|
|
|
7506
7754
|
function () { return externalsSig("github", githubOwnersView() || null); },
|
|
7507
7755
|
function (box) {
|
|
7508
7756
|
var items = liveExternals("github");
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
}
|
|
7757
|
+
// 注記は**行より前**に置く(0件なら一覧の代わり・行があれば添え書き)
|
|
7758
|
+
var noteDev = unverifiedListNote("リポジトリ", items.length > 0);
|
|
7759
|
+
if (noteDev) box.appendChild(noteDev);
|
|
7760
|
+
if (!items.length) return;
|
|
7514
7761
|
// **meta は行ごとに引く**(issues と discussions でアイコンとラベルが違う)
|
|
7515
7762
|
githubRows(items).forEach(function (n) { box.appendChild(n); });
|
|
7516
7763
|
},
|
|
@@ -9512,10 +9759,14 @@ ${deriveCapTile.toString()}
|
|
|
9512
9759
|
box.appendChild(liveList("共有資料", function () {
|
|
9513
9760
|
var d = driveNow();
|
|
9514
9761
|
// 仮置きの印(drivePending)も署名に入れる——外れたときに印だけ残さない(#388)
|
|
9515
|
-
|
|
9762
|
+
// 「確かめられたか」も混ぜる(#409。混ぜないと注記の要否が変わっても作り直されない)
|
|
9763
|
+
return JSON.stringify([d.driveFolderIds || [], d.driveFolderNames || {}, d.driveState || "", d.drivePending || {}, registrationUnreadable()]);
|
|
9516
9764
|
}, function (listBox) {
|
|
9517
9765
|
var src = driveNow();
|
|
9518
9766
|
var folders = src.driveFolderIds || [];
|
|
9767
|
+
// 兄弟の穴を一緒に塞ぐ(#409)。ここも同じ registeredNow から行を足している
|
|
9768
|
+
var noteDrive = unverifiedListNote("フォルダ", folders.length > 0);
|
|
9769
|
+
if (noteDrive) listBox.appendChild(noteDrive);
|
|
9519
9770
|
// 名前は任意。**無ければIDを出す**(既存の案件は名前を持っていない)
|
|
9520
9771
|
var fnames = src.driveFolderNames || {};
|
|
9521
9772
|
if (folders.length) {
|
|
@@ -9651,9 +9902,13 @@ ${deriveCapTile.toString()}
|
|
|
9651
9902
|
// **署名に取り込みの状態も混ぜる(段C第二弾)。** 一覧のJSONだけだと、応答が返る前に
|
|
9652
9903
|
// モーダルを開いた人には取り込みが1件も出ない(designIngestSigOf の項に経緯)
|
|
9653
9904
|
figGroup.appendChild(liveList("デザイン", function () {
|
|
9654
|
-
|
|
9905
|
+
// 「確かめられたか」も混ぜる(#409。混ぜないと注記の要否が変わっても作り直されない)
|
|
9906
|
+
return JSON.stringify(figsOf()) + "|" + designIngestSigOf(figsOf()) + "|" + registrationUnreadable();
|
|
9655
9907
|
}, function (listBox) {
|
|
9656
9908
|
var figs = figsOf();
|
|
9909
|
+
// 兄弟の穴を一緒に塞ぐ(#409)。ここも同じ registeredNow から行を足している
|
|
9910
|
+
var noteFig = unverifiedListNote("ファイル", figs.length > 0);
|
|
9911
|
+
if (noteFig) listBox.appendChild(noteFig);
|
|
9657
9912
|
// **一覧から消えた鍵は「外し済み」から落とす**(figsRemoved の項に経緯)。
|
|
9658
9913
|
// サーバが削除を認めた印なので、ここから先に同じ鍵が現れたら**貼り直された別の登録**
|
|
9659
9914
|
var figKeys = figs.map(function (f) { return f.key; });
|
|
@@ -11198,6 +11453,8 @@ ${deriveCapTile.toString()}
|
|
|
11198
11453
|
// 🔴 **後段の仕事より後ろに置く。** ここで投げると、図の復帰・取り直しタイマーが
|
|
11199
11454
|
// 丸ごと落ちる(href を貼り替えるだけの処理に、そこまで巻き込ませない)
|
|
11200
11455
|
syncAiLinks();
|
|
11456
|
+
// Home を開いていれば「使用ツール」の状態を実測で描き直す(#275)
|
|
11457
|
+
syncHomeTools();
|
|
11201
11458
|
// 取得中に保存が効いていたら、迂回付きでもう一度取りに行く
|
|
11202
11459
|
if (freshWanted) loadLiveFleet();
|
|
11203
11460
|
})
|
|
@@ -11226,6 +11483,9 @@ ${deriveCapTile.toString()}
|
|
|
11226
11483
|
// つまり**立ち上げ直後の案件=開発リポジトリを登録したばかりの案件**では、
|
|
11227
11484
|
// この行だけがヘッダーの導線を追いつかせる。**後段の仕事より後ろに置く**(上と同じ理由)
|
|
11228
11485
|
syncAiLinks();
|
|
11486
|
+
// 🔴 **ここでも「使用ツール」を描き直す(#275)。** 実測(stateNow)は fleet より
|
|
11487
|
+
// 先に読んでいるので、まとめ表を持たない案件でもこの経路で状態が確定する
|
|
11488
|
+
syncHomeTools();
|
|
11229
11489
|
// 取得中に保存が効いていたら、迂回付きでもう一度取りに行く
|
|
11230
11490
|
if (freshWanted) loadLiveFleet();
|
|
11231
11491
|
});
|
package/package.json
CHANGED