@takagaki/cortex-decisions-viewer 0.12.210 → 0.12.215
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 +62 -5
- package/dist/memory-evidence.js +12 -6
- package/dist/render.js +215 -267
- package/dist/view-dir.js +26 -7
- package/package.json +1 -1
package/dist/build.js
CHANGED
|
@@ -266,12 +266,14 @@ const MEMORY_DIR_CANDIDATES = ["Memory/Decisions/records", "Memory/Decisions"];
|
|
|
266
266
|
/**
|
|
267
267
|
* Decisionsディレクトリを解決する。明示指定があればそれを使い、
|
|
268
268
|
* 未指定なら Cortex/Decisions/records → Cortex/Decisions → Decisions の順で存在するものを採用する。
|
|
269
|
+
* 組み直した案件(木に `Memory/Home.md`)は Memory/Decisions/records → Memory/Decisions だけ。
|
|
269
270
|
*/
|
|
270
271
|
async function resolveDecisionsDir(dir) {
|
|
271
272
|
if (dir)
|
|
272
273
|
return path.resolve(dir);
|
|
273
274
|
const rebuilt = (await (0, memory_dir_1.memoryDirOfTree)(process.cwd())) === "Memory";
|
|
274
|
-
|
|
275
|
+
// 🔴 組み直した案件は `Memory/` だけを探す(今までの置き場〈Cortex/…・Decisions〉へ倒れない・cortex-engine #1911 便 GV)
|
|
276
|
+
const candidates = rebuilt ? MEMORY_DIR_CANDIDATES : DEFAULT_DIR_CANDIDATES;
|
|
275
277
|
for (const candidate of candidates) {
|
|
276
278
|
const abs = path.resolve(candidate);
|
|
277
279
|
try {
|
|
@@ -285,6 +287,52 @@ async function resolveDecisionsDir(dir) {
|
|
|
285
287
|
}
|
|
286
288
|
throw new Error(`Decisionsディレクトリが見つかりません(${candidates.join(" / ")} を確認してください)`);
|
|
287
289
|
}
|
|
290
|
+
/** 取り出した区画にファイルが 1 本も無いか(無いフォルダも空と読む・読めないフォルダは空と読まない) */
|
|
291
|
+
async function viewDirIsEmpty(viewDir) {
|
|
292
|
+
try {
|
|
293
|
+
return (await node_fs_1.promises.readdir(viewDir)).length === 0;
|
|
294
|
+
}
|
|
295
|
+
catch (e) {
|
|
296
|
+
return e?.code === "ENOENT";
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** 記憶の中身に数えない Markdown(入口・説明・雛形) */
|
|
300
|
+
const MEMORY_NON_CONTENT_MD = new Set(["home.md", "readme.md", "template.md"]);
|
|
301
|
+
/**
|
|
302
|
+
* 組み直した案件の木の記憶の中身の数(`Memory/` の下の .md。Home・README・template は数えない)。区画の名前も `records/` の有無も決め打ちしない
|
|
303
|
+
* (記録・ストーリー・区画の直下の記録を全部数える)。リンクはたどる(`stat`)。空の画面に倒してよいかの判定にだけ使う(cortex-engine #1911 便 GV)。
|
|
304
|
+
* 🔴 読めない階層・深すぎる階層は 1 と数える(空に倒れる側にしない)。`Memory/` が無い木も 1(組み直した案件の印と食い違う)
|
|
305
|
+
*/
|
|
306
|
+
async function memoryContentCount(dir, depth = 0) {
|
|
307
|
+
if (depth > 8)
|
|
308
|
+
return 1;
|
|
309
|
+
let names;
|
|
310
|
+
try {
|
|
311
|
+
names = await node_fs_1.promises.readdir(dir);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return 1;
|
|
315
|
+
}
|
|
316
|
+
let n = 0;
|
|
317
|
+
for (const name of names) {
|
|
318
|
+
const abs = path.join(dir, name);
|
|
319
|
+
let st;
|
|
320
|
+
try {
|
|
321
|
+
st = await node_fs_1.promises.stat(abs);
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
n += 1;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (st.isDirectory())
|
|
328
|
+
n += await memoryContentCount(abs, depth + 1);
|
|
329
|
+
else if (name.toLowerCase().endsWith(".md") && !MEMORY_NON_CONTENT_MD.has(name.toLowerCase()))
|
|
330
|
+
n += 1;
|
|
331
|
+
if (n > 0)
|
|
332
|
+
return n;
|
|
333
|
+
}
|
|
334
|
+
return n;
|
|
335
|
+
}
|
|
288
336
|
/**
|
|
289
337
|
* DecisionsディレクトリからCortex(Gold層)ルートを推定する。
|
|
290
338
|
* Cortex/Decisions/records → 2つ上、Cortex/Decisions → 1つ上。
|
|
@@ -2446,17 +2494,25 @@ async function buildSite(opts, views) {
|
|
|
2446
2494
|
const repoRoot = knowledgeRoot ? path.dirname(knowledgeRoot) : path.dirname(dirAbs);
|
|
2447
2495
|
// 記憶の置き場の名前(知識の根の名前から。`Cortex` ならこれまでと同じ出力)
|
|
2448
2496
|
const memoryDir = (0, memory_dir_1.memoryDirOfRoot)(knowledgeRoot);
|
|
2449
|
-
// 帳簿 9 本の置き場(既定は `<repoRoot>/.cortex`)。読み口はこの 1
|
|
2497
|
+
// 帳簿 9 本の置き場(既定は `<repoRoot>/.cortex`)。読み口はこの 1 つから読む(根拠の台帳は組み直していない案件だけ `<repoRoot>/.cortex`)
|
|
2450
2498
|
let ledgerDir = (0, ledger_dir_1.ledgerDirOf)(repoRoot, opts.ledgerDir);
|
|
2451
2499
|
// 設定の置き場のヒント(便 DS-8b)。組み直した案件(木に `Memory/Home.md`)だけ `table`。最初の描画(骨組みを出すか)だけに使い、応答の mode が勝つ
|
|
2452
2500
|
const configMode = await (0, config_mode_1.configModeHint)(repoRoot);
|
|
2453
|
-
// 🔴 組み直した案件(v2・cortex-engine #1911 便 DC-2f・設計書 D-4)は封筒を無条件で採用し、帳簿 8
|
|
2501
|
+
// 🔴 組み直した案件(v2・cortex-engine #1911 便 DC-2f・設計書 D-4)は封筒を無条件で採用し、帳簿 8 本と根拠の台帳(便 DC-2e)を `.cortex` から読まない。
|
|
2454
2502
|
// 封筒が無い・確かめられない回は投げる(空の画面を緑で配らない)。下の倒れ(catch)は組み直していない案件だけ
|
|
2455
2503
|
const rebuilt = configMode === "table";
|
|
2456
2504
|
if (rebuilt) {
|
|
2457
2505
|
if (!opts.viewDir)
|
|
2458
2506
|
throw new Error("組み直した案件(Memory/Home.md)のビルドには記憶側の画面用ファイル(--view-dir)が要ります(帳簿は .cortex から組みません)");
|
|
2459
|
-
|
|
2507
|
+
// 記憶がまだ 1 件も無い案件(組み直した直後で、記憶側がまだ画面用ファイルを 1 度も置いていない)は空の画面を組む(cortex-engine #1911 便 GV)。
|
|
2508
|
+
// 🔴 空に倒れるのは「取り出した区画にファイルが 1 本も無い」かつ「読んだ決定と木の記憶の中身(記録・ストーリー)が 0 件」のときだけ。記録があるのに目次が無い・目次が空や壊れている・
|
|
2509
|
+
// 封筒の欠けは、取り出しか公開が壊れている(今どおり赤)
|
|
2510
|
+
const viewDirAbs = path.resolve(opts.viewDir);
|
|
2511
|
+
const empty = mdFiles.length === 0 && (await viewDirIsEmpty(viewDirAbs)) && (await memoryContentCount(path.join(repoRoot, "Memory"))) === 0;
|
|
2512
|
+
// 黙って緑にしない: 警告の 1 行を出す(記憶側の最初の通常の夜が目次を置けば、次のビルドから消える)
|
|
2513
|
+
if (empty)
|
|
2514
|
+
console.warn("記憶 v2 の画面用ファイル(組み直した案件): 記憶がまだ 1 件も無く、記憶側の画面用ファイルもまだ 1 本も無いので、空の画面を組みます");
|
|
2515
|
+
const plan = empty ? (0, view_dir_1.emptyPlanV2)() : await (0, view_dir_1.planViewsV2)(viewDirAbs);
|
|
2460
2516
|
const merged = await (0, view_dir_1.mergeViewsV2)(plan);
|
|
2461
2517
|
views.cleanup = merged.cleanup;
|
|
2462
2518
|
views.counts = plan.counts;
|
|
@@ -2502,7 +2558,8 @@ async function buildSite(opts, views) {
|
|
|
2502
2558
|
// 目次と同じ順位(engine #551)。**読めないなら `null`** で、つながり画面の点は今までどおり一律
|
|
2503
2559
|
const memoryRanking = await (0, ranking_1.readMemoryRanking)(repoRoot, ledgerDir);
|
|
2504
2560
|
// 根拠の台帳(便 B3)。**読めないなら `null`** で、根拠の段は記録に書かれた references のリンクだけ
|
|
2505
|
-
|
|
2561
|
+
// 組み直していない案件は案件リポの .cortex から(--ledger-dir に従わない)。組み直した案件は封筒をほどいた置き場から(便 DC-2e・memory-evidence.ts)
|
|
2562
|
+
const memoryEvidence = await (0, memory_evidence_1.readMemoryEvidence)(repoRoot, rebuilt ? ledgerDir : null);
|
|
2506
2563
|
// 人の手の表の写し(engine #1094 q-10)。あれば記憶 v2 の案件で、確認の印とボタンを出さない。**無い案件は今と 1 バイトも同じ**(キーごと無い)
|
|
2507
2564
|
// 「記憶 v2 の案件か」は 1 本の栓 `memory_v2_writer` の値で決める(cortex-engine #1094 鎖 3 V10b)。橋の間は写しとの OR
|
|
2508
2565
|
const memoryHands = await (0, hands_1.readMemoryHands)(repoRoot, ledgerDir);
|
package/dist/memory-evidence.js
CHANGED
|
@@ -20,10 +20,12 @@ exports.evidenceLookup = evidenceLookup;
|
|
|
20
20
|
* 無ければ `null`(黙る)。壊れている・版が違えば `null` と build のログに 1 行(`ranking.ts` と同じ作法)。
|
|
21
21
|
* どちらも画面は `references` のリンクだけで「根拠」の段を描く。
|
|
22
22
|
*
|
|
23
|
-
* ## 🔴
|
|
23
|
+
* ## 🔴 置き場は案件の形で決まる
|
|
24
24
|
*
|
|
25
|
-
* 引用の文字は案件リポ(git
|
|
26
|
-
*
|
|
25
|
+
* 組み直していない案件: 引用の文字は案件リポ(git)に置く(前のオーナー決定 B・cortex-engine #1911 のリーダーの答え 6239629719 の 1)。
|
|
26
|
+
* `--ledger-dir`・`--view-dir` を渡しても、いつも `<repo>/.cortex` から読む。
|
|
27
|
+
* 組み直した案件(木に `Memory/Home.md`): 決定 B はオーナー決定 Q6(cortex-engine #1911 6375271707)で覆り、引用は保管庫の項目ごとのオブジェクトに置く。
|
|
28
|
+
* 記憶側が組んだ封筒 `memory-evidence` を `--view-dir` からだけ読む(`.cortex` は読まない・cortex-engine #1911 便 DC-2e)。
|
|
27
29
|
*
|
|
28
30
|
* ## 項目ごとの形の検め
|
|
29
31
|
*
|
|
@@ -119,11 +121,15 @@ function parseMemoryEvidence(text) {
|
|
|
119
121
|
return null;
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
|
-
/**
|
|
123
|
-
|
|
124
|
+
/**
|
|
125
|
+
* 読む。無い → `null`(黙る)・壊れている/版違い → `null`(build のログに 1 行)。
|
|
126
|
+
* 組み直していない案件は案件リポの `.cortex` から(`--ledger-dir` に従わない)。組み直した案件(cortex-engine #1911 便 DC-2e)は
|
|
127
|
+
* `viewDir`(記憶側の封筒をほどいた置き場・`mergeViewsV2`)から読み、`.cortex` は読まない(引用は案件リポに置かない)
|
|
128
|
+
*/
|
|
129
|
+
async function readMemoryEvidence(repoRoot, viewDir = null) {
|
|
124
130
|
let text;
|
|
125
131
|
try {
|
|
126
|
-
text = await promises_1.default.readFile(node_path_1.default.join((0, ledger_dir_1.defaultLedgerDir)(repoRoot), exports.MEMORY_EVIDENCE_FILE), "utf8");
|
|
132
|
+
text = await promises_1.default.readFile(node_path_1.default.join(viewDir ?? (0, ledger_dir_1.defaultLedgerDir)(repoRoot), exports.MEMORY_EVIDENCE_FILE), "utf8");
|
|
127
133
|
}
|
|
128
134
|
catch {
|
|
129
135
|
return null;
|
package/dist/render.js
CHANGED
|
@@ -1182,7 +1182,7 @@ const STATE_ROW_FIELDS = ["cap", "ref", "workspace", "question", "status", "at",
|
|
|
1182
1182
|
*/
|
|
1183
1183
|
const RUN_URL_RE = /^https:\/\/github\.com\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/actions\/runs\/[0-9]+$/;
|
|
1184
1184
|
/** `runUrl` を持てる書き手(Actions の run の中で動く engine の書き手)。ほかの書き手の値は出さない */
|
|
1185
|
-
const RUN_URL_WRITERS = ["ingest", "gold", "nightly"];
|
|
1185
|
+
const RUN_URL_WRITERS = ["ingest", "gold", "nightly", "bronze"];
|
|
1186
1186
|
/**
|
|
1187
1187
|
* `runUrl` が無い行の出どころの語(#560)。run が無い書き手だけ。**`ingest` / `gold` は
|
|
1188
1188
|
* 載せない**——`runUrl` が無いのは古い engine か固定 IP の CodeBuild で、行からは区別できない
|
|
@@ -2336,8 +2336,8 @@ const SECRET_NOW_STATES = ["registered", "missing", "unknown"];
|
|
|
2336
2336
|
/**
|
|
2337
2337
|
* `secretsNow`(鍵が登録されているか・列2)の許可リスト。
|
|
2338
2338
|
*
|
|
2339
|
-
* 応答の1行は `{ adapter, kind, state, source, space? }`。画面が使うのは kind / state /
|
|
2340
|
-
* space だけで、**adapter は使わない**(鍵カードは種別で引く)。source は「どの棚が
|
|
2339
|
+
* 応答の1行は `{ adapter, kind, state, source, space?, savedAt? }`。画面が使うのは kind / state /
|
|
2340
|
+
* space / savedAt だけで、**adapter は使わない**(鍵カードは種別で引く)。source は「どの棚が
|
|
2341
2341
|
* 答えたか」の内部語なので、画面に出す語へ畳むのは読み出し側(`secretStateFromNow`)。
|
|
2342
2342
|
*/
|
|
2343
2343
|
function sanitizeSecretsNow(v) {
|
|
@@ -2359,6 +2359,9 @@ function sanitizeSecretsNow(v) {
|
|
|
2359
2359
|
// 揃えないと**入っている鍵を「未登録」と言う**(`issuesRefOf` と同じ理由)
|
|
2360
2360
|
if (typeof r.space === "string" && r.space)
|
|
2361
2361
|
row.space = r.space.toLowerCase();
|
|
2362
|
+
// 保存日時(受付が Secrets Manager の LastChangedDate から載せる ISO)。日付として読める形だけ通す(札の「M/D に保存」の材料・便 KU)
|
|
2363
|
+
if (typeof r.savedAt === "string" && /^\d{4}-\d{2}-\d{2}T[\d:.]+(Z|[+-]\d{2}:?\d{2})$/.test(r.savedAt) && !isNaN(new Date(r.savedAt).getTime()))
|
|
2364
|
+
row.savedAt = r.savedAt;
|
|
2362
2365
|
out.push(row);
|
|
2363
2366
|
}
|
|
2364
2367
|
return out.length ? out : null;
|
|
@@ -2393,7 +2396,7 @@ function secretStateFromNow(rows, kind, space) {
|
|
|
2393
2396
|
hit = mine[0];
|
|
2394
2397
|
}
|
|
2395
2398
|
if (hit.state === "registered")
|
|
2396
|
-
return { known: "yes", src: "Secrets Manager" };
|
|
2399
|
+
return hit.savedAt ? { known: "yes", src: "Secrets Manager", savedAt: hit.savedAt } : { known: "yes", src: "Secrets Manager" };
|
|
2397
2400
|
if (hit.state === "missing")
|
|
2398
2401
|
return { known: "no", src: "" };
|
|
2399
2402
|
return null;
|
|
@@ -5734,7 +5737,6 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
5734
5737
|
.ds-more { margin-top: 14px; }
|
|
5735
5738
|
.ds-more > summary { cursor: pointer; color: var(--muted); font-size: 12px; }
|
|
5736
5739
|
.ds-more[open] > summary { margin-bottom: 8px; }
|
|
5737
|
-
.ds-more-key { margin: 6px 0 0; font-size: 12.5px; color: var(--text); display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
|
|
5738
5740
|
/* 行の状態に添える「次に誰が何をするか」(2026-08-18)。**必ず自分の行を占める**
|
|
5739
5741
|
(flex: 1 1 100%)——状態バッジの横に押し込むと、いちばん読ませたい一文が
|
|
5740
5742
|
カード幅に負けて省略される。状態の語より弱く、しかし読める大きさで出す */
|
|
@@ -5794,7 +5796,10 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
5794
5796
|
.ops-intro { color: var(--muted); font-size: 14px; line-height: 1.8; margin: 4px 0 8px; }
|
|
5795
5797
|
.ops-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
|
|
5796
5798
|
.sec-state { font-size: 12.5px; font-weight: 600; margin: 0 0 8px; color: var(--muted); }
|
|
5797
|
-
.sec-state.is-managed { color: #1a7f37; }
|
|
5799
|
+
.sec-state.is-managed, .sec-state.is-ok { color: #1a7f37; }
|
|
5800
|
+
.sec-state.is-failed { color: #b42318; }
|
|
5801
|
+
.sec-state.is-checking { color: var(--muted); font-weight: 400; font-style: italic; }
|
|
5802
|
+
.sec-saved { margin: 6px 0 0; }
|
|
5798
5803
|
.sec-state.is-none { color: var(--muted); font-weight: 400; }
|
|
5799
5804
|
/* 登録されているか分からない(engine がスペース別の状況をまだ出していない)。
|
|
5800
5805
|
**未登録と同じ見た目にしない**——断定していないことが色でも分かるようにする */
|
|
@@ -5830,16 +5835,6 @@ a.ds-tile:hover { text-decoration: none; }
|
|
|
5830
5835
|
.ops-card.ds-keycard > .ops-card-head { gap: 8px; }
|
|
5831
5836
|
.ops-card.ds-keycard .ops-card-icon { font-size: 16px; }
|
|
5832
5837
|
.ops-card.ds-keycard .ops-card-title { font-size: 13px; }
|
|
5833
|
-
/* 押すまで入力欄を出さない(2026-08-21・オーナー指摘)。summary はボタンに見せる */
|
|
5834
|
-
.sec-input-fold { border: none; margin: 0; }
|
|
5835
|
-
.sec-input-fold > summary {
|
|
5836
|
-
cursor: pointer; display: inline-block; list-style: none;
|
|
5837
|
-
padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border);
|
|
5838
|
-
background: #fff; color: var(--text); font-size: 12.5px; font-weight: 600;
|
|
5839
|
-
}
|
|
5840
|
-
.sec-input-fold > summary::-webkit-details-marker { display: none; }
|
|
5841
|
-
.sec-input-fold > summary:hover { border-color: var(--accent); color: var(--accent); }
|
|
5842
|
-
.sec-input-fold[open] > summary { margin-bottom: 8px; }
|
|
5843
5838
|
.ds-addform { border: 1px dashed var(--border); border-radius: 8px; padding: 12px 14px; margin-top: 10px; background: #fff; }
|
|
5844
5839
|
.ds-addform-title { font-size: 13px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
|
|
5845
5840
|
.ds-addform .sec-input { margin-bottom: 6px; }
|
|
@@ -10156,7 +10151,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10156
10151
|
// 🔴 **Backlog の行の一手(c-07 の 2 本目)。** 行の中身(そのスペースのキーの有無・同期経路・
|
|
10157
10152
|
// スペースの数)で決まるので関数で持つ。row は { domain, projectKey, gate }。
|
|
10158
10153
|
// DS_GATE_CAP.issues は札(APIキーが未登録です)だけを持ち、help を持たせない(一手の置き場は 1 か所)。
|
|
10159
|
-
// 部品の型は 文字列 / { copy, bare } / { act: "backlog-
|
|
10154
|
+
// 部品の型は 文字列 / { copy, bare } / { act: "backlog-route-on", label }
|
|
10160
10155
|
backlog: {
|
|
10161
10156
|
no_token: {
|
|
10162
10157
|
resting: function (row) { return backlogRowHelpParts(row); },
|
|
@@ -10298,21 +10293,16 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10298
10293
|
/**
|
|
10299
10294
|
* 行の一手に置くボタン(c-07)。**押せないボタンは作らない**(null)。
|
|
10300
10295
|
* - "connect" … [接続する]。Slack の承認画面へ送る(slackConnectInline)。投入の口が無ければ null
|
|
10301
|
-
*
|
|
10302
|
-
*
|
|
10303
|
-
* 受け皿が無いスペースには作らない(別のスペースの欄へ落とさない)
|
|
10296
|
+
* 🔴 **鍵を入れるボタンは作らない(便 KU)。** 鍵の欄は接続先の行の中に最初から見えている(secretCard)ので、
|
|
10297
|
+
* 「入れる」の入口を行の一手に重ねない(同じ鍵に[入れる]が 3 か所あった)
|
|
10304
10298
|
* - "backlog-route-on" … [切り替える]。同期経路を固定 IP 経由にする(setBacklogRoute)
|
|
10305
10299
|
* @param label 省略時は既定の語
|
|
10306
|
-
* @param arg
|
|
10300
|
+
* @param arg 部品が要る材料(今は使う一手が無い)
|
|
10307
10301
|
*/
|
|
10308
10302
|
function actNode(act, label, arg) {
|
|
10309
10303
|
if (!SITE.intake) return null;
|
|
10310
10304
|
if (act === "connect") return slackConnectInline(label || "接続する");
|
|
10311
|
-
// Backlog の行の一手(c-07 の 2 本目)。arg はスペース(ドメイン)。**受け皿が無ければ作らない**
|
|
10312
|
-
if (act === "backlog-key") return backlogKeyJump(arg, label || "入れる");
|
|
10313
10305
|
if (act === "backlog-route-on") return backlogRouteOnButton(label || "切り替える");
|
|
10314
|
-
// 鍵の欄(KEY_SLOTS.figma)が無い構成では、移る先が無いので出さない
|
|
10315
|
-
if (act === "figma-key") return secretKindsShown().indexOf("figma") >= 0 ? figmaKeyJump(label || "トークンを入れる") : null;
|
|
10316
10306
|
return null;
|
|
10317
10307
|
}
|
|
10318
10308
|
/**
|
|
@@ -10488,13 +10478,12 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10488
10478
|
},
|
|
10489
10479
|
issues: { no_token: { text: "APIキーが未登録です", cls: "ds-gate-muted" } },
|
|
10490
10480
|
design: {
|
|
10491
|
-
// 🔴 **鍵が無い行の一手は、行の中の 1 行(c-07)。**
|
|
10481
|
+
// 🔴 **鍵が無い行の一手は、行の中の 1 行(c-07)。** 一手の文が下の「Figma のトークン」の欄を指す(ボタンは無い・便 KU)
|
|
10492
10482
|
no_token: {
|
|
10493
10483
|
text: "トークンが未登録です",
|
|
10494
10484
|
cls: "ds-gate-muted",
|
|
10495
|
-
help: "Figma
|
|
10485
|
+
help: "Figma のトークンを、下の欄に入れてください。",
|
|
10496
10486
|
helpLink: { href: FIGMA_SETTINGS_URL, label: "Figma の設定でトークンを発行する →" },
|
|
10497
|
-
act: "figma-key",
|
|
10498
10487
|
},
|
|
10499
10488
|
// 「アクセス不可」では、トークンの失効なのか(403)ファイルを共有していないのか(404)が
|
|
10500
10489
|
// 画面から見分けられない(理由が文字の中だけ=機械の語に依存した分岐は書かない・c-07)。
|
|
@@ -10505,9 +10494,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
10505
10494
|
unreachable: {
|
|
10506
10495
|
text: "ファイルを読めません",
|
|
10507
10496
|
cls: "ds-gate-warn",
|
|
10508
|
-
help: "
|
|
10509
|
-
act: "figma-key",
|
|
10510
|
-
actLabel: "トークンを入れ直す",
|
|
10497
|
+
help: "このファイルに、トークンを発行したアカウントを閲覧者として招待してください(トークンが切れているときは、下の欄に入れ直してください)。",
|
|
10511
10498
|
},
|
|
10512
10499
|
},
|
|
10513
10500
|
};
|
|
@@ -11109,24 +11096,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
11109
11096
|
return wrap;
|
|
11110
11097
|
}
|
|
11111
11098
|
|
|
11112
|
-
/**
|
|
11113
|
-
* [トークンを入れる]/[トークンを入れ直す](Figma の行の一手・c-07)。
|
|
11114
|
-
* 一覧の直後にある「Figma のトークン」の欄(KEY_SLOTS.figma)の入力へ移って focus する。
|
|
11115
|
-
* **欄は 0 件のあいだ畳まれている**が、行がある=ファイルが 1 件以上あるので畳まれていない。
|
|
11116
|
-
* 入力が見つからなければ何もしない(鍵の欄を作る口が無い構成)。
|
|
11117
|
-
*/
|
|
11118
|
-
function figmaKeyJump(label) {
|
|
11119
|
-
var btn = el("button", { class: "ds-toggle-btn ds-act-inline", type: "button", text: label || "トークンを入れる" });
|
|
11120
|
-
btn.addEventListener("click", function () {
|
|
11121
|
-
var slot = KEY_SLOTS.figma;
|
|
11122
|
-
var input = slot && slot.querySelector("input, textarea");
|
|
11123
|
-
if (!input) return;
|
|
11124
|
-
try { if (input.scrollIntoView) input.scrollIntoView({ block: "center" }); } catch (e) { /* 動かせなくても focus は試す */ }
|
|
11125
|
-
input.focus();
|
|
11126
|
-
});
|
|
11127
|
-
return btn;
|
|
11128
|
-
}
|
|
11129
|
-
|
|
11130
11099
|
/** 台帳から、そのワークスペースの接続状態を引く(無ければ null=断定しない) */
|
|
11131
11100
|
function tokenStateOf(workspaces, teamId) {
|
|
11132
11101
|
var list = workspaces || [];
|
|
@@ -12425,32 +12394,15 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
12425
12394
|
// **対応表に無い種別は隠さない**(keyTargetCount の既定と同じく出す側に倒す)。
|
|
12426
12395
|
// 3つ目の鍵が足されて分岐を書き忘れた場合は key-card-visibility の [全種0件] が落ちる
|
|
12427
12396
|
var hide = shown[KEY_CARDS[i].kind] === false;
|
|
12428
|
-
// 🔴 **Backlog の行の中のカードは、0 件の判定(上)に加えて「見せる理由があるとき」だけ見せる**
|
|
12429
|
-
//(c-07 の 2 本目)。0 件が勝つ——0 件のあいだは理由があっても出さない(順序の逆な案内になる)
|
|
12430
|
-
if (!hide && KEY_CARDS[i].compact) hide = !backlogKeyCardWanted(KEY_CARDS[i]);
|
|
12431
12397
|
KEY_CARDS[i].el.hidden = hide;
|
|
12432
|
-
|
|
12398
|
+
// 🔴 札は見せる瞬間に当て直す(作ったときの答えは古いことがある。取り直しが後から届く・#227)
|
|
12399
|
+
if (!hide && KEY_CARDS[i].refresh) KEY_CARDS[i].refresh();
|
|
12433
12400
|
}
|
|
12434
12401
|
eachKeySlot(function (slot) {
|
|
12435
12402
|
slot.hidden = !slot.querySelector("[data-secret-kind]:not([hidden])");
|
|
12436
12403
|
});
|
|
12437
12404
|
}
|
|
12438
12405
|
|
|
12439
|
-
/**
|
|
12440
|
-
* Backlog の行の中の鍵カードを、いま見せるか(c-07 の 2 本目・スペースごとの判定)。次の 4 つのどれか:
|
|
12441
|
-
* ① キーが要る(backlogKeyNeededForSpace=登録状況が「未登録」・足した直後で答えがまだ無い等)
|
|
12442
|
-
* ② 一手の[入れる]/[入れ直す]・「その他」の[入れ直す]が押された(forced)
|
|
12443
|
-
* ③ 触り始めた(開いた・値がある・結果の文がある)。🔴 **保存直後の「✓ 保存しました」と入力中の値を畳まない**(#223)
|
|
12444
|
-
* 使えているスペースのカードは、ふだん隠れている(DOM には常に在る=入力中の値・結果は消えない)。
|
|
12445
|
-
*/
|
|
12446
|
-
function backlogKeyCardWanted(ent) {
|
|
12447
|
-
if (ent.forced) return true;
|
|
12448
|
-
if (ent.fold && ent.fold.open) return true;
|
|
12449
|
-
if (ent.input && ent.input.value !== "") return true;
|
|
12450
|
-
if (ent.msg && ent.msg.textContent !== "") return true;
|
|
12451
|
-
return backlogKeyNeededForSpace(ent.space);
|
|
12452
|
-
}
|
|
12453
|
-
|
|
12454
12406
|
/** いま在る鍵の受け皿(.ds-keyrow)を順に渡す。置き場の正本は KEY_SLOTS */
|
|
12455
12407
|
function eachKeySlot(fn) {
|
|
12456
12408
|
var slots = KEY_SLOTS.backlog || {};
|
|
@@ -13046,6 +12998,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
13046
12998
|
KEY_CARDS = [];
|
|
13047
12999
|
// Backlog の節の行の控え・結果の帯・描き直しの口も作り直す(切り離された古い節を掴んだままにしない)
|
|
13048
13000
|
BACKLOG_UI = { rows: [], msg: null, repaintRows: null };
|
|
13001
|
+
FIGMA_UI = { keys: [] };
|
|
13049
13002
|
// 作り直しはスナップショットから描き直すこと。応答で採った件数はここで捨てる
|
|
13050
13003
|
ADOPTED_TARGET_COUNT = null;
|
|
13051
13004
|
var internals = fleetVal("internalSources") || [];
|
|
@@ -14501,6 +14454,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
14501
14454
|
MERGED = null;
|
|
14502
14455
|
repaintOpenLists();
|
|
14503
14456
|
refreshDataSources();
|
|
14457
|
+
syncKeyCardVisibility(); // 鍵の札(接続OK/失敗)も同じ結果で当て直す
|
|
14504
14458
|
}
|
|
14505
14459
|
// 本物の行を 1 回だけ取りに行く(据え置きのまま・「reloadLiveState」の項)
|
|
14506
14460
|
reloadLiveState();
|
|
@@ -15452,7 +15406,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15452
15406
|
}
|
|
15453
15407
|
var ipLabel = ip ? "固定の送信元 IP(" + ip + ")" : "固定の送信元 IP";
|
|
15454
15408
|
if (keyState === "no") {
|
|
15455
|
-
return "同期は" + ipLabel + "から行います。お客様にこの IP
|
|
15409
|
+
return "同期は" + ipLabel + "から行います。お客様にこの IP の許可を依頼し、接続先の行の下の欄に API キーを貼って[保存して接続を確認]を押すと同期が始まります。";
|
|
15456
15410
|
}
|
|
15457
15411
|
// 2 文に収める(実装レビューの指摘)。押した直後の帯(サーバの文面)も「許可を依頼」を言うが、
|
|
15458
15412
|
// 帯は数秒で読み終える結果で、この行は次に開いたときも残る状態——役目が違うので両方に置く
|
|
@@ -15551,7 +15505,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15551
15505
|
* 部品の置き場:
|
|
15552
15506
|
* - 一手 … DS_GATE_RESTING_HELP.backlog → backlogRowHelpParts(行の中身で決まる)
|
|
15553
15507
|
* - キーの欄 … これまでと同じスペースごとの受け皿(KEY_SLOTS.backlog・#223)に同じカード。
|
|
15554
|
-
* 変えるのは見え方だけ(syncKeyCardVisibility
|
|
15508
|
+
* 変えるのは見え方だけ(syncKeyCardVisibility)
|
|
15555
15509
|
* - 同期経路の切り替え … setBacklogRoute に 1 本化。入口はタイルの一手・[接続を確認]の結果・「その他」のスイッチ
|
|
15556
15510
|
* - 札(事実)… 経路札「固定 IP 経由」・リアルタイム札(appendBacklogChips)
|
|
15557
15511
|
* ------------------------------------------------------------------------- */
|
|
@@ -15562,6 +15516,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15562
15516
|
* 🔴 **鍵の置き場の正本は KEY_SLOTS。ここは行の控えだけ**(#223 の「節の中に受け皿の控えを持たない」は守る)。
|
|
15563
15517
|
*/
|
|
15564
15518
|
var BACKLOG_UI = { rows: [], msg: null, repaintRows: null };
|
|
15519
|
+
/** Figma の鍵が効くファイル(鍵カードの札が引く。一覧を描くときに入れ替える) */
|
|
15520
|
+
var FIGMA_UI = { keys: [] };
|
|
15565
15521
|
|
|
15566
15522
|
/** いま見えている行のスペース(小文字・重複なし) */
|
|
15567
15523
|
function backlogDomainsNow() {
|
|
@@ -15614,27 +15570,13 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15614
15570
|
return false;
|
|
15615
15571
|
}
|
|
15616
15572
|
|
|
15617
|
-
/** そのスペースの鍵カードを見せるか(行のどれかが要るか。行が無ければ要らない) */
|
|
15618
|
-
function backlogKeyNeededForSpace(space) {
|
|
15619
|
-
var domains = backlogDomainsNow();
|
|
15620
|
-
var dom = space || (domains.length === 1 ? domains[0] : "");
|
|
15621
|
-
if (!dom) return false;
|
|
15622
|
-
var rows = BACKLOG_UI.rows || [];
|
|
15623
|
-
for (var i = 0; i < rows.length; i++) {
|
|
15624
|
-
if (String(rows[i].domain || "").toLowerCase() !== dom) continue;
|
|
15625
|
-
var r = reachableStateOf("issues", issuesRefOf(rows[i].domain, rows[i].projectKey));
|
|
15626
|
-
if (backlogKeyNeeded(dom, r ? r.status : null)) return true;
|
|
15627
|
-
}
|
|
15628
|
-
return false;
|
|
15629
|
-
}
|
|
15630
|
-
|
|
15631
15573
|
/**
|
|
15632
15574
|
* Backlog の行に出す一手のパーツ(無ければ null)。**スペースをまたがない**(ボタンはその行のスペースの受け皿だけを引く)。
|
|
15633
15575
|
*
|
|
15634
|
-
* キーが要る → 「API
|
|
15635
|
-
* 読めない・通常経路 →
|
|
15636
|
-
* 読めない・固定 IP → 「お客様に固定の送信元 IP(…)の許可を依頼してください。[コピー]
|
|
15637
|
-
* 読めない・経路不明 →
|
|
15576
|
+
* キーが要る → 「API キーを、下の欄に入れてください。」(複数スペースならスペース名つき)
|
|
15577
|
+
* 読めない・通常経路 → 「読めません。下の欄に API キーを入れ直してください。 Backlog に IP 制限があるなら、固定 IP 経由で読んでください。[切り替える]」
|
|
15578
|
+
* 読めない・固定 IP → 「お客様に固定の送信元 IP(…)の許可を依頼してください。[コピー] 許可済みなら、下の欄に API キーを入れ直してください。」
|
|
15579
|
+
* 読めない・経路不明 → 「読めません。下の欄に API キーを入れ直してください。」(切り替えが押せるか分からないので[切り替える]は出さない)
|
|
15638
15580
|
*
|
|
15639
15581
|
* 🔴 **理由の語(HTTP の番号等)には依存しない。** 401・403・404 は画面から見分けられないので、読めない行は広い方の 1 行。
|
|
15640
15582
|
* IP 制限と確定できるのは[接続を確認]の応答の reason だけ(appendBacklogProbeSwitch)。
|
|
@@ -15646,10 +15588,10 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15646
15588
|
var dom = String(row.domain || "").toLowerCase();
|
|
15647
15589
|
var multi = backlogDomainsNow().length > 1;
|
|
15648
15590
|
if (backlogKeyNeeded(dom, row.gate)) {
|
|
15649
|
-
|
|
15591
|
+
// 🔴 鍵の欄は接続先の行の中に最初から見えている(便 KU)。ここは指す文だけでボタンは置かない
|
|
15592
|
+
return [(multi ? dom + " の " : "") + "API キーを、下の欄に入れてください。"];
|
|
15650
15593
|
}
|
|
15651
15594
|
if (row.gate !== "unreachable") return null;
|
|
15652
|
-
var reenter = { act: "backlog-key", space: dom, label: "入れ直す" };
|
|
15653
15595
|
var route = LIVE_BACKLOG_ROUTE;
|
|
15654
15596
|
if (route === "fixed-ip") {
|
|
15655
15597
|
// IP が取れていなければ IP も[コピー]も出さない(嘘の値を書かない・#516)
|
|
@@ -15657,9 +15599,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15657
15599
|
var head = ip
|
|
15658
15600
|
? ["お客様に固定の送信元 IP(" + ip + ")の許可を依頼してください。", { copy: ip, bare: true }]
|
|
15659
15601
|
: ["お客様に固定の送信元 IP の許可を依頼してください。"];
|
|
15660
|
-
return head.concat(["
|
|
15602
|
+
return head.concat([" 許可済みなら、下の欄に API キーを入れ直してください。"]);
|
|
15661
15603
|
}
|
|
15662
|
-
var base = ["
|
|
15604
|
+
var base = ["読めません。下の欄に API キーを入れ直してください。"];
|
|
15663
15605
|
if (route === "runner") {
|
|
15664
15606
|
// 切り替えは案件全体の経路(スペースごとではない)。複数スペースでは強めに言う
|
|
15665
15607
|
var scope = multi
|
|
@@ -15690,54 +15632,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15690
15632
|
return appendReachableReason(row, "issues", ref);
|
|
15691
15633
|
}
|
|
15692
15634
|
|
|
15693
|
-
/** そのスペースの鍵の受け皿(無ければ null)。名無しの受け皿は、スペースが 1 つ以下のあいだだけ代わりを務める(ensureKeySlots の項) */
|
|
15694
|
-
function backlogKeySlotFor(space) {
|
|
15695
|
-
var slots = KEY_SLOTS.backlog || {};
|
|
15696
|
-
var d = String(space || "").toLowerCase();
|
|
15697
|
-
if (d && slots[d]) return slots[d];
|
|
15698
|
-
if (slots[""] && backlogDomainsNow().length <= 1) return slots[""];
|
|
15699
|
-
return null;
|
|
15700
|
-
}
|
|
15701
|
-
|
|
15702
|
-
/** そのスペースの鍵カードの控え(無ければ null)。**ほかのスペースのカードへ落とさない** */
|
|
15703
|
-
function backlogKeyEntryFor(space) {
|
|
15704
|
-
var d = String(space || "").toLowerCase();
|
|
15705
|
-
var list = [];
|
|
15706
|
-
for (var i = 0; i < KEY_CARDS.length; i++) {
|
|
15707
|
-
if (KEY_CARDS[i].kind === "backlog" && KEY_CARDS[i].compact) list.push(KEY_CARDS[i]);
|
|
15708
|
-
}
|
|
15709
|
-
for (var j = 0; j < list.length; j++) if (d && list[j].space === d) return list[j];
|
|
15710
|
-
if (backlogDomainsNow().length <= 1) {
|
|
15711
|
-
for (var k = 0; k < list.length; k++) if (list[k].space === "") return list[k];
|
|
15712
|
-
}
|
|
15713
|
-
return null;
|
|
15714
|
-
}
|
|
15715
|
-
|
|
15716
|
-
/** そのスペースの鍵カードを見せて、入力へ移る([入れる]・[入れ直す])。見つからなければ false */
|
|
15717
|
-
function openBacklogKeyCard(space) {
|
|
15718
|
-
var ent = backlogKeyEntryFor(space);
|
|
15719
|
-
if (!ent) return false;
|
|
15720
|
-
ent.forced = true;
|
|
15721
|
-
ent.fold.open = true;
|
|
15722
|
-
syncKeyCardVisibility();
|
|
15723
|
-
try { if (ent.input.scrollIntoView) ent.input.scrollIntoView({ block: "center" }); } catch (e) { /* 動かせなくても focus は試す */ }
|
|
15724
|
-
ent.input.focus();
|
|
15725
|
-
return true;
|
|
15726
|
-
}
|
|
15727
|
-
|
|
15728
|
-
/**
|
|
15729
|
-
* [入れる]/[入れ直す]。**そのスペースの受け皿が無ければ作らない**(別のスペースの欄へ移さない)。
|
|
15730
|
-
* 🔴 **作る条件は受け皿(KEY_SLOTS)だけ。カードの控えは押した時点で引く**——節は鍵カードより先に組み立てられる
|
|
15731
|
-
*(buildDataSources の順序)ので、行を描く時点ではカードがまだ無い。受け皿は節が先に作っている
|
|
15732
|
-
*/
|
|
15733
|
-
function backlogKeyJump(space, label) {
|
|
15734
|
-
if (secretKindsShown().indexOf("backlog") < 0) return null;
|
|
15735
|
-
if (!backlogKeySlotFor(space)) return null;
|
|
15736
|
-
var btn = el("button", { class: "ds-toggle-btn ds-act-inline", type: "button", text: label || "入れる" });
|
|
15737
|
-
btn.addEventListener("click", function () { openBacklogKeyCard(space); });
|
|
15738
|
-
return btn;
|
|
15739
|
-
}
|
|
15740
|
-
|
|
15741
15635
|
/**
|
|
15742
15636
|
* 同期経路の切り替え(固定 IP 経由 ⇄ 通常)。**スイッチ(「その他」)とタイルの[切り替える]が同じこの関数を呼ぶ**
|
|
15743
15637
|
* ——操作を 2 本書かない(op・値・確認なし・応答の route を正とする・changed:false の取り直しは 1 つだけ持つ)。
|
|
@@ -15960,7 +15854,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
15960
15854
|
* 画面から外した)
|
|
15961
15855
|
* -------------------------------------------------------------------------
|
|
15962
15856
|
* run の無い書き手の行は、出どころを語で示す(「中央の処理」「その場で確認」)。run のある
|
|
15963
|
-
* 行(ingest / gold / nightly)は何も添えない——リンク先が実行用リポや案件リポの GitHub
|
|
15857
|
+
* 行(ingest / gold / nightly / bronze)は何も添えない——リンク先が実行用リポや案件リポの GitHub
|
|
15964
15858
|
* Actions で、多くの利用者には開けないため。出すかどうかの判断は純関数
|
|
15965
15859
|
* (runLogUrlOf / runSourceWordOf)が持ち、ここは描くだけ。
|
|
15966
15860
|
* ----------------------------------------------------------------------- */
|
|
@@ -16881,7 +16775,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16881
16775
|
// 🔴 **追加の欄は URL の入力と[追加]だけ(c-07 の 2 本目)。** 手順の文は置かない(hint を渡さない)。
|
|
16882
16776
|
// 外した情報の行き先:
|
|
16883
16777
|
// - 「起票先は変わりません」「毎晩同期します」「外すには」… 上部の説明文(openCapabilityModal)
|
|
16884
|
-
// - 「スペースごとに別のAPIキー」…
|
|
16778
|
+
// - 「スペースごとに別のAPIキー」… 足した行の中のスペースごとの鍵の欄(札つき)
|
|
16885
16779
|
// - 「専用 URL の登録が要ります」… 追加した行のリアルタイム札(未受信)と、一覧の下の一手[設定する]
|
|
16886
16780
|
build: function (url) {
|
|
16887
16781
|
return { op: "backlog-target-add", url: url, baseGeneration: targetsGenerationOf(targets) };
|
|
@@ -16940,21 +16834,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16940
16834
|
box.appendChild(rtBox);
|
|
16941
16835
|
|
|
16942
16836
|
var routeWrap = backlogRouteSwitch();
|
|
16943
|
-
var keyRows = liveList("backlog-key-rows", function () {
|
|
16944
|
-
var ds = backlogDomainsNow();
|
|
16945
|
-
return JSON.stringify(ds.map(function (d) { return [d, secretStateOf("backlog", d, ds.length).known]; }));
|
|
16946
|
-
}, function (b) {
|
|
16947
|
-
var ds = backlogDomainsNow();
|
|
16948
|
-
ds.forEach(function (d) {
|
|
16949
|
-
var st = secretStateOf("backlog", d, ds.length);
|
|
16950
|
-
var word = st.known === "yes" ? "登録済みです" : st.known === "no" ? "未登録です" : "確認中です";
|
|
16951
|
-
// ボタンはそのスペースの鍵カードを開く(受け皿が無ければ作らない)
|
|
16952
|
-
b.appendChild(el("p", { class: "ds-more-key" }, [
|
|
16953
|
-
el("span", { text: d + ":API キーは" + word }),
|
|
16954
|
-
backlogKeyJump(d, st.known === "no" ? "入れる" : "入れ直す"),
|
|
16955
|
-
]));
|
|
16956
|
-
});
|
|
16957
|
-
});
|
|
16958
16837
|
var rtMore = liveList("backlog-realtime-more", function () {
|
|
16959
16838
|
var st = backlogRealtimeState();
|
|
16960
16839
|
return JSON.stringify([st ? [st.total, st.live] : null, backlogFactsSigOf()]);
|
|
@@ -16970,7 +16849,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16970
16849
|
moreEl = el("details", { class: "ds-more" }, [
|
|
16971
16850
|
el("summary", { text: "その他" }),
|
|
16972
16851
|
routeWrap,
|
|
16973
|
-
keyRows,
|
|
16974
16852
|
rtMore,
|
|
16975
16853
|
]);
|
|
16976
16854
|
box.appendChild(moreEl);
|
|
@@ -16984,7 +16862,6 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
16984
16862
|
moreEl.hidden = !(keyTargetCount("課題管理") > 0 || LIVE_BACKLOG_ROUTE === "fixed-ip");
|
|
16985
16863
|
rtBox.__rebuild();
|
|
16986
16864
|
if (routeWrap.__live) routeWrap.__live.__rebuild();
|
|
16987
|
-
keyRows.__rebuild();
|
|
16988
16865
|
rtMore.__rebuild();
|
|
16989
16866
|
}
|
|
16990
16867
|
}
|
|
@@ -17328,6 +17205,7 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
17328
17205
|
// サーバが削除を認めた印なので、ここから先に同じ鍵が現れたら**貼り直された別の登録**
|
|
17329
17206
|
var figKeys = figs.map(function (f) { return f.key; });
|
|
17330
17207
|
figsRemoved = figsRemoved.filter(function (k) { return figKeys.indexOf(k) >= 0; });
|
|
17208
|
+
FIGMA_UI.keys = figKeys.filter(function (k) { return figsRemoved.indexOf(k) < 0; });
|
|
17331
17209
|
// **残り件数は「押した時点」で数える。** 一覧(figs)は夜間バッチのスナップショットで、
|
|
17332
17210
|
// このページを開いている間はもちろん、その日のうちに再読み込みしても更新されない。
|
|
17333
17211
|
// 描画時点の件数で判定すると、3件を1件ずつ外していったとき最後の1件でも警告が出ない。
|
|
@@ -19875,9 +19753,8 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19875
19753
|
var stateSpace = (opts && opts.stateSpace) || "";
|
|
19876
19754
|
var spaceCount = (opts && opts.spaceCount) || 0;
|
|
19877
19755
|
var inRow = !!(opts && opts.inRow);
|
|
19878
|
-
// 🔴 **Backlog
|
|
19879
|
-
//
|
|
19880
|
-
// 触り始めた後だけ見える(syncKeyCardVisibility)。旧カード(行の外・intake 無しの案件)と Figma は従来どおり。
|
|
19756
|
+
// 🔴 **Backlog の行の中のカードは見出しを持たない**(行の中なので「何の鍵か」は札と欄が言う)。
|
|
19757
|
+
// 接続先が 1 件以上あるあいだは常に見える(0 件のときだけ syncKeyCardVisibility が畳む)。
|
|
19881
19758
|
var compact = kind === "backlog" && inRow;
|
|
19882
19759
|
/**
|
|
19883
19760
|
* 鍵がどこまで効くのか(#229)。**置き場所だけでは伝わらないので、言葉にする。**
|
|
@@ -19892,11 +19769,9 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19892
19769
|
// **いま登録されているか**を先に出す。入れ直したのに反映されていない状態が
|
|
19893
19770
|
// 画面で分かるようにする(接続状況は夜間バッチのスナップショットなので、
|
|
19894
19771
|
// 保存の直後は前日の値のまま。時刻は上の節に出している)。
|
|
19895
|
-
var st = secretStateOf(kind, stateSpace, spaceCount);
|
|
19896
19772
|
var cardTitle = meta.title;
|
|
19897
|
-
// 🔴 **「登録済み」は「読めている」を意味しない。**
|
|
19898
|
-
//
|
|
19899
|
-
//(同期できているかのバッジは、夜間処理が接続先ごとの成否を保存してからの別作業)。
|
|
19773
|
+
// 🔴 **「登録済み」は「読めている」を意味しない。** 「接続OK」を札に出してよいのは、そのスペース(Figma は全ファイル)の
|
|
19774
|
+
// 行の「届くか」がすべて ok のときだけ(statusOf)。測っていなければ「登録済み」止まり。
|
|
19900
19775
|
//
|
|
19901
19776
|
// **前方一致で見る。** #105 の移行期は「Secrets Manager(旧名)」も来る。
|
|
19902
19777
|
// 完全一致にすると、旧名で動いている案件だけが repo secret と同じ見た目になり、
|
|
@@ -19907,27 +19782,140 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19907
19782
|
// 同じ 1 語にし、**生の値は data-src に置く**(判定の is-managed は生の値のまま)。
|
|
19908
19783
|
// 知らない値が来ても生で出さない——project-wording.test.mjs が画面の語を見張る
|
|
19909
19784
|
var state = el("p", { class: "sec-state" });
|
|
19910
|
-
|
|
19911
|
-
|
|
19912
|
-
|
|
19785
|
+
// 🔴 **鍵の窓は 1 か所・欄は最初から見えている・ボタンは 1 つ(便 KU)。** 以前は[入れる]で開く畳み+[保存]+別の[接続を確認]の 3 段で、
|
|
19786
|
+
// 同じ鍵の[入れる]が行の一手・「その他」・畳みの 3 か所にあった。いまは 状態の札 → 伏せ字の欄(空のまま)→ [保存して接続を確認]。
|
|
19787
|
+
// 保存した値は読み戻さない(書き込み専用)。登録済みでも欄は空で、入れ直すときだけ貼る(伏せ字を欄に入れて伏せ字ごと保存する事故を避ける)
|
|
19788
|
+
var cap = kind === "backlog" ? "issues" : "design";
|
|
19789
|
+
var input = el("input", { class: "sec-input", type: "password", placeholder: "トークンを貼り付け", autocomplete: "off", spellcheck: "false" });
|
|
19913
19790
|
var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "保存" });
|
|
19914
19791
|
var msg = el("div", { class: "ds-toggle-msg" });
|
|
19792
|
+
var savedNote = el("p", { class: "sec-note sec-saved" });
|
|
19793
|
+
// 札が読む材料の控え。checking=保存〜確認の最中、savedHere=この画面で保存した(正本 secretsNow は最大 10 秒古い答えを返すので、registered を返すまで「登録済み」以上に固定する)
|
|
19794
|
+
var ent = { kind: kind, el: null, compact: compact, space: stateSpace, input: input, msg: msg, checking: false, savedHere: false };
|
|
19795
|
+
|
|
19796
|
+
function spaceCountNow() { return kind === "backlog" ? backlogDomainsNow().length : spaceCount; }
|
|
19797
|
+
/** この鍵が効く接続先の ref(Backlog=そのスペースの行・Figma=一覧のファイル)。登録済みの一覧だけを引く=孤児の行を混ぜない */
|
|
19798
|
+
function refsNow() {
|
|
19799
|
+
var out = [];
|
|
19800
|
+
if (kind === "backlog") {
|
|
19801
|
+
var ds = backlogDomainsNow();
|
|
19802
|
+
var dom = stateSpace || (ds.length === 1 ? ds[0] : "");
|
|
19803
|
+
var rows = BACKLOG_UI.rows || [];
|
|
19804
|
+
for (var i = 0; i < rows.length; i++) {
|
|
19805
|
+
if (dom && String(rows[i].domain || "").toLowerCase() === dom) out.push(issuesRefOf(rows[i].domain, rows[i].projectKey));
|
|
19806
|
+
}
|
|
19807
|
+
} else {
|
|
19808
|
+
out = (FIGMA_UI.keys || []).slice();
|
|
19809
|
+
}
|
|
19810
|
+
return out;
|
|
19811
|
+
}
|
|
19812
|
+
/** 接続の確認の口があるか。組み直した案件(表)も同じ口(受付 op=probe の direct・同期を起こさずその場で 1 本叩く)で確かめる */
|
|
19813
|
+
function probeOk() { return !!SITE.intake && !!dispatchProbeTypeOf(cap); }
|
|
19814
|
+
/** 「M/D に保存」。受付の savedAt(Secrets Manager の LastChangedDate)から出す。ブラウザには覚えない(端末が変わると消えるため) */
|
|
19815
|
+
function savedDate(st) {
|
|
19816
|
+
var d = st && st.savedAt ? new Date(st.savedAt) : null;
|
|
19817
|
+
return d && !isNaN(d.getTime()) ? (d.getMonth() + 1) + "/" + d.getDate() : "";
|
|
19818
|
+
}
|
|
19819
|
+
function secretNow() {
|
|
19820
|
+
var s = secretStateOf(kind, stateSpace, spaceCountNow());
|
|
19821
|
+
if (ent.savedHere) {
|
|
19822
|
+
if (s.known === "yes") ent.savedHere = false; // 正本が追いついた
|
|
19823
|
+
else return { known: "yes", src: "" };
|
|
19824
|
+
}
|
|
19825
|
+
return s;
|
|
19826
|
+
}
|
|
19827
|
+
/**
|
|
19828
|
+
* 札 1 つの決め方。**未登録/確認中/接続OK〈時刻〉/失敗〈理由の一言〉/登録済み**。
|
|
19829
|
+
* 「失敗」の一言は行の札の語(dsGateForCap)をそのまま使う。測っていない行・鍵が無かった頃の古い行(no_token)は数えず、
|
|
19830
|
+
* 一部だけ測れているときも「接続OK」と言い切らない(登録済みに倒す)。
|
|
19831
|
+
*/
|
|
19832
|
+
function statusOf(st) {
|
|
19833
|
+
if (ent.checking) return ["is-checking", "確認中"];
|
|
19834
|
+
if (st.known === "no") return ["is-none", "未登録"];
|
|
19835
|
+
if (st.known !== "yes") return ["is-unknown", "確認中"];
|
|
19836
|
+
var refs = refsNow(), bad = null, ok = 0, latest = "";
|
|
19837
|
+
for (var i = 0; i < refs.length; i++) {
|
|
19838
|
+
var r = reachableStateOf(cap, refs[i]);
|
|
19839
|
+
if (!r || r.status === "no_token") continue;
|
|
19840
|
+
if (r.status === "ok") { ok++; if (String(r.at || "") > latest) latest = String(r.at || ""); }
|
|
19841
|
+
else if (!bad) bad = r;
|
|
19842
|
+
}
|
|
19843
|
+
if (bad) return ["is-failed", "失敗(" + dsGateForCap(cap, bad.status).text + ")"];
|
|
19844
|
+
if (ok && ok === refs.length) {
|
|
19845
|
+
var t = dsFmtTime(latest);
|
|
19846
|
+
return ["is-ok", "接続OK" + (t ? "(" + t + ")" : "")];
|
|
19847
|
+
}
|
|
19848
|
+
return null; // 登録済み
|
|
19849
|
+
}
|
|
19850
|
+
function paint() {
|
|
19851
|
+
var st = secretNow();
|
|
19852
|
+
var s = statusOf(st);
|
|
19853
|
+
if (s) {
|
|
19854
|
+
// 取得元は札の語に関わらず data-src に置く(判定の is-managed は生の値の前方一致・#841)
|
|
19855
|
+
var srcRaw = st.known === "yes" ? (st.src || "") : "";
|
|
19856
|
+
state.className = "sec-state " + s[0] + (srcRaw.indexOf("Secrets Manager") === 0 ? " is-managed" : "");
|
|
19857
|
+
if (srcRaw) state.setAttribute("data-src", srcRaw); else state.removeAttribute("data-src");
|
|
19858
|
+
state.textContent = s[1];
|
|
19859
|
+
} else {
|
|
19860
|
+
applySecretState(state, st);
|
|
19861
|
+
}
|
|
19862
|
+
var reg = st.known === "yes";
|
|
19863
|
+
var d = savedDate(st);
|
|
19864
|
+
savedNote.hidden = !reg;
|
|
19865
|
+
savedNote.textContent = reg ? "登録済み" + (d ? "(" + d + " に保存)" : "") + "。入れ直すときだけ貼ってください" : "";
|
|
19866
|
+
if (!btn.disabled) btn.textContent = probeOk() ? "保存して接続を確認" : "保存";
|
|
19867
|
+
if (preferred) {
|
|
19868
|
+
var want = st.known === "no";
|
|
19869
|
+
if (want && !preferred.parentNode && card) card.insertBefore(preferred, input);
|
|
19870
|
+
else if (!want && preferred.parentNode) preferred.parentNode.removeChild(preferred);
|
|
19871
|
+
}
|
|
19872
|
+
}
|
|
19873
|
+
/** 保存のあとの接続の確認。結果は行と同じ形で置く(applyProbeResult)。返すのは添える 1 文(無ければ空) */
|
|
19874
|
+
async function checkAfterSave() {
|
|
19875
|
+
var type = dispatchProbeTypeOf(cap);
|
|
19876
|
+
// Figma は回数制限(1 分あたりの枠)に収まるよう先頭の 2 ファイルだけ。残りは各行の[接続を確認]
|
|
19877
|
+
var refs = refsNow().slice(0, kind === "figma" ? 2 : 20);
|
|
19878
|
+
for (var i = 0; i < refs.length; i++) {
|
|
19879
|
+
// 無応答で札が「確認中」のまま固まらないよう、1 本ごとに 15 秒で見切る
|
|
19880
|
+
var ctrl = typeof AbortController === "function" ? new AbortController() : null;
|
|
19881
|
+
var giveUp = ctrl ? setTimeout(function () { ctrl.abort(); }, 15000) : null;
|
|
19882
|
+
try {
|
|
19883
|
+
var res = await callIntake("probe", { type: type, ref: refs[i] }, ctrl ? { signal: ctrl.signal } : undefined);
|
|
19884
|
+
var j = await res.json().catch(function () { return {}; });
|
|
19885
|
+
if (giveUp != null) clearTimeout(giveUp);
|
|
19886
|
+
if (res.ok && j.gate) {
|
|
19887
|
+
applyProbeResult(cap, refs[i], "", { gate: j.gate, checkedAt: j.checkedAt, needed: "", detail: j.detail || "" });
|
|
19888
|
+
} else if (!res.ok) {
|
|
19889
|
+
return "接続の確認はできませんでした:" + ((j && j.message) || "少し待ってからもう一度お試しください。");
|
|
19890
|
+
} else {
|
|
19891
|
+
return "接続の確認は少し後に札へ出ます。";
|
|
19892
|
+
}
|
|
19893
|
+
} catch (e) {
|
|
19894
|
+
if (giveUp != null) clearTimeout(giveUp);
|
|
19895
|
+
return "接続の確認は通信に失敗しました。";
|
|
19896
|
+
}
|
|
19897
|
+
}
|
|
19898
|
+
return "";
|
|
19899
|
+
}
|
|
19915
19900
|
|
|
19916
19901
|
btn.addEventListener("click", async function () {
|
|
19917
19902
|
var value = input.value;
|
|
19918
|
-
if (!value.trim()) {
|
|
19903
|
+
if (!value.trim()) {
|
|
19904
|
+
msg.className = "ds-toggle-msg";
|
|
19905
|
+
// 登録済みで空のまま押しても何も変えない(置き換えるのは、貼ったときだけ)
|
|
19906
|
+
msg.textContent = secretNow().known === "yes" ? "何も変えていません。入れ直すときだけ値を貼ってください。" : "";
|
|
19907
|
+
if (secretNow().known !== "yes") { msg.className = "ds-toggle-msg is-error"; msg.textContent = "⚠ トークンを入力してください。"; }
|
|
19908
|
+
return;
|
|
19909
|
+
}
|
|
19919
19910
|
|
|
19920
|
-
//
|
|
19911
|
+
// 保存〜確認の全体を 1 回の busy で囲む(#222・beginBusy の項)
|
|
19921
19912
|
var endBusy = beginBusy(btn);
|
|
19922
19913
|
msg.className = "ds-toggle-msg";
|
|
19923
19914
|
msg.textContent = "保存中…";
|
|
19924
19915
|
var intake = SITE.intake;
|
|
19925
19916
|
try {
|
|
19926
19917
|
// **シークレット名は送らない。** どの連携かだけを送り、書き込み先はサーバが案件から決める。
|
|
19927
|
-
//
|
|
19928
|
-
// こちらが渡すのは「どのスペースの鍵か」という材料だけ。
|
|
19929
|
-
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に
|
|
19930
|
-
// 貼った鍵が「スペースを特定できません」で断られる
|
|
19918
|
+
// **押した時点で読む。** 組み立て時に固めると、接続先を登録した直後に貼った鍵が「スペースを特定できません」で断られる
|
|
19931
19919
|
var res = await callIntake("secret", secretPayload(intake, kind, value, cardSpace));
|
|
19932
19920
|
var j = await res.json().catch(function () { return {}; });
|
|
19933
19921
|
if (!res.ok) {
|
|
@@ -19937,30 +19925,38 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19937
19925
|
return;
|
|
19938
19926
|
}
|
|
19939
19927
|
msg.className = "ds-toggle-msg is-ok";
|
|
19940
|
-
// 🔴 **「保存中…」を消してから成功を書く(#220)。**
|
|
19941
|
-
// 画面に「保存中…✓ 保存しました。同期を開始しました。」と**2つの状態が同居**して
|
|
19942
|
-
// いた。appendChild は足すだけなので、消す一文が要る(sendConfig 側には在った)。
|
|
19943
|
-
// **語を書く前に必ずここを通すこと**——次に文面を足す人が同じ形で踏む
|
|
19928
|
+
// 🔴 **「保存中…」を消してから成功を書く(#220)。** appendChild は足すだけなので、消す一文が要る
|
|
19944
19929
|
msg.textContent = "";
|
|
19945
19930
|
msg.appendChild(document.createTextNode("✓ " + (j.message || "保存しました。")));
|
|
19946
|
-
// 起動できたときだけ、実行状況への導線を出す(鍵を入れた直後に効いたか確かめられる)
|
|
19947
19931
|
if (j.runsUrl) {
|
|
19948
19932
|
msg.appendChild(document.createTextNode(" "));
|
|
19949
19933
|
msg.appendChild(el("a", { href: j.runUrl || j.runsUrl, target: "_blank", rel: "noopener", title: "GitHub Actions の実行ログを開きます(プロジェクトリポジトリへのアクセスが要ります)", text: "実行状況を見る →" })); // その run を特定できていればそれ、無ければ一覧
|
|
19950
19934
|
}
|
|
19951
19935
|
// 入れた値は画面に残さない(肩越しに見えるのを防ぐ)
|
|
19952
19936
|
input.value = "";
|
|
19953
|
-
|
|
19954
|
-
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
19937
|
+
ent.savedHere = true;
|
|
19938
|
+
var willCheck = probeOk() && refsNow().length > 0;
|
|
19939
|
+
ent.checking = willCheck;
|
|
19940
|
+
paint();
|
|
19941
|
+
// 🔴 Backlog の行の一手は登録状況の正本に合わせて当て直す。正本(secretsNow)は取り直しで届く
|
|
19942
|
+
if (compact && typeof BACKLOG_UI.repaintRows === "function") BACKLOG_UI.repaintRows();
|
|
19943
|
+
if (willCheck) {
|
|
19944
|
+
var note = await checkAfterSave();
|
|
19945
|
+
if (note) msg.appendChild(document.createTextNode(" " + note));
|
|
19959
19946
|
}
|
|
19947
|
+
ent.checking = false;
|
|
19948
|
+
endBusy();
|
|
19949
|
+
paint();
|
|
19950
|
+
loadLiveFleet(true);
|
|
19960
19951
|
} catch (e) {
|
|
19961
|
-
|
|
19962
|
-
|
|
19952
|
+
ent.checking = false;
|
|
19953
|
+
// 保存が済んだあとの不調を「通信に失敗」と言わない(貼り直しに誘導しない)
|
|
19954
|
+
if (!ent.savedHere) {
|
|
19955
|
+
msg.className = "ds-toggle-msg is-error";
|
|
19956
|
+
msg.textContent = "✗ 通信に失敗しました。";
|
|
19957
|
+
}
|
|
19963
19958
|
endBusy();
|
|
19959
|
+
paint();
|
|
19964
19960
|
}
|
|
19965
19961
|
});
|
|
19966
19962
|
|
|
@@ -19972,21 +19968,17 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19972
19968
|
meta.note ? el("p", { class: "sec-how", text: meta.note }) : null,
|
|
19973
19969
|
meta.selfServe ? el("p", { class: "sec-how", text: meta.selfServe.note }) : null,
|
|
19974
19970
|
].filter(Boolean);
|
|
19975
|
-
// **「畳んである中に何があるか」を summary に書く。**
|
|
19976
|
-
// 発行のしかたを探している人がここを開く手掛かりを持てない(rt カードと同じ流儀)
|
|
19971
|
+
// **「畳んである中に何があるか」を summary に書く。**
|
|
19977
19972
|
var guidanceBox = el("details", { class: "sec-fold" }, [el("summary", { text: "発行のしかた" })]);
|
|
19978
19973
|
for (var gi = 0; gi < guidance.length; gi++) guidanceBox.appendChild(guidance[gi]);
|
|
19979
|
-
// **手順の動画+画像(#547・#1353)。**
|
|
19980
|
-
// meta.guide を持つ種別(Figma)はカルーセル1つに乗せる。meta.guide も meta.shots も
|
|
19981
|
-
// 持たない種別(Backlog)ではこの節は素通りする
|
|
19974
|
+
// **手順の動画+画像(#547・#1353)。** meta.guide を持つ種別(Figma)はカルーセル1つに乗せる
|
|
19982
19975
|
if (meta.guide && meta.guideInModal) {
|
|
19983
19976
|
// モーダルの上に出している種別(Backlog・Figma)は、ここには重ねない
|
|
19984
19977
|
} else if (meta.guide) {
|
|
19985
19978
|
var carousel = buildGuideCarousel(kind, meta.guide);
|
|
19986
19979
|
if (carousel) guidanceBox.appendChild(carousel);
|
|
19987
19980
|
} else if (meta.shots) {
|
|
19988
|
-
//
|
|
19989
|
-
// この口に載せ替えるまでの踏み板として残す
|
|
19981
|
+
// 後方互換(旧形)
|
|
19990
19982
|
for (var si = 0; si < meta.shots.length; si++) {
|
|
19991
19983
|
var shot = meta.shots[si];
|
|
19992
19984
|
guidanceBox.appendChild(el("p", { class: "sec-how", text: shot.heading }));
|
|
@@ -19994,86 +19986,33 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
19994
19986
|
}
|
|
19995
19987
|
}
|
|
19996
19988
|
|
|
19997
|
-
//
|
|
19998
|
-
//
|
|
19999
|
-
//
|
|
20000
|
-
// 🔴 **前回とは向きが逆。** 前回は「.sec-input は畳まない」と決めていたが、
|
|
20001
|
-
// 鍵の欄がレコードの行の下へ移り、**行に常時ぶら下がる入力欄**になったため、
|
|
20002
|
-
// 一覧の見通しを取り戻す側へ倒した。**状態(.sec-state)は畳まない**ので、
|
|
20003
|
-
// 「保存したのに反映されていない」は開かなくても読める。
|
|
20004
|
-
//
|
|
20005
|
-
// ⚠ **DOM には常に置く**(押すまで生成しない作りにしない)。ライブ差し替えは
|
|
20006
|
-
// input のノードを直接触るし、テストも card.querySelector("input.sec-input") で掴む。
|
|
20007
|
-
// ⚠ **<summary> は button ではない**ので、「保存」を掴む既存の取り方は変わらない。
|
|
20008
|
-
var inputFold = el("details", { class: "sec-input-fold" }, [
|
|
20009
|
-
// Backlog の行の中のカードは、一手の語([入れる]・[入れ直す])と揃える。Figma は「登録する」のまま
|
|
20010
|
-
el("summary", { class: "sec-input-summary", text: st.known === "yes" ? "入れ直す" : (compact ? "入れる" : "登録する") }),
|
|
20011
|
-
]);
|
|
20012
|
-
inputFold.appendChild(input);
|
|
20013
|
-
inputFold.appendChild(el("div", { class: "ds-toggle" }, [btn, msg]));
|
|
20014
|
-
// 🔴 **値の扱いの 1 文は、開いた中に残す**(顧客に鍵の貼り付けを求める画面でいちばん落としてはいけない説明・#101)。
|
|
20015
|
-
// 短くした版(行の中のカード)。「他のプロジェクトには影響しません」は仕組みの事実で、利用者が選ぶものではないので外す
|
|
20016
|
-
if (compact) inputFold.appendChild(el("p", { class: "sec-note", text: "入れた値は保存だけでき、あとから表示されません。" }));
|
|
20017
|
-
|
|
20018
|
-
// ライブ取得後に状態の行だけを差し替えるための目印(カードごと作り直すと入力が消える)
|
|
20019
|
-
//
|
|
20020
|
-
// **並びは「状態 → 貼る(畳む) → 畳んだ手順」。**
|
|
20021
|
-
//
|
|
20022
|
-
// 🔴 **.sec-state / .sec-preferred は <details> の外に置くこと。**
|
|
20023
|
-
// - .sec-state … 保存したのに反映されていない状態が分かる唯一の手段。
|
|
20024
|
-
// 押すまで見えないと成立しない
|
|
20025
|
-
// - .sec-preferred … 「誰のアカウントで発行するのか」を**手順より先に**伝える行。
|
|
20026
|
-
// 未登録のときだけ出る=これから貼る人にだけ出るので、畳むと存在理由が消える
|
|
19989
|
+
// 🔴 **.sec-state / .sec-preferred は常に見える場所に置く。** 札は「保存したのに反映されていない」が分かる唯一の手段。
|
|
19990
|
+
// .sec-preferred は「誰のアカウントで発行するのか」を手順より先に伝える行(未登録のときだけ出る)
|
|
20027
19991
|
var preferred = meta.selfServe ? el("p", { class: "sec-preferred", text: meta.selfServe.text }) : null;
|
|
20028
19992
|
var card = el("div", { class: "ops-card" + (inRow ? " ds-keycard" : ""), "data-secret-kind": kind }, [
|
|
20029
|
-
// 行の中の Backlog
|
|
19993
|
+
// 行の中の Backlog カードは見出しを持たない(何の鍵かは札と欄が言う)
|
|
20030
19994
|
compact ? null : el("div", { class: "ops-card-head" }, [
|
|
20031
19995
|
el("span", { class: "ops-card-icon", text: meta.icon }),
|
|
20032
19996
|
el("h3", { class: "ops-card-title", text: cardTitle }),
|
|
20033
19997
|
]),
|
|
20034
|
-
// **desc は無い種別がある(2026-08-21)。** el() は text をそのまま textContent へ
|
|
20035
|
-
// 代入するので、無条件に出すと画面に文字列 undefined が出る
|
|
20036
19998
|
meta.desc ? el("p", { class: "ops-card-desc", text: meta.desc }) : null,
|
|
20037
|
-
// **鍵の効く範囲は、登録状況より先に言う。**
|
|
20038
|
-
// 「どのファイルの話か」を確かめ直すことになる(#229)
|
|
19999
|
+
// **鍵の効く範囲は、登録状況より先に言う。** (#229)
|
|
20039
20000
|
scopeNote ? el("p", { class: "sec-scope", text: scopeNote }) : null,
|
|
20040
20001
|
state,
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
|
|
20045
|
-
|
|
20002
|
+
input,
|
|
20003
|
+
el("div", { class: "ds-toggle" }, [btn, msg]),
|
|
20004
|
+
savedNote,
|
|
20005
|
+
// 🔴 **値の扱いの 1 文は常に出す**(顧客に鍵の貼り付けを求める画面でいちばん落としてはいけない説明・#101)
|
|
20006
|
+
el("p", { class: "sec-note", text: compact
|
|
20007
|
+
? "入れた値は保存だけでき、あとから表示されません。"
|
|
20008
|
+
: "入れた値はここには表示されません(保存だけできます)。保存先はプロジェクトごとに分かれているので、他のプロジェクトには影響しません。" }),
|
|
20046
20009
|
guidanceBox,
|
|
20047
|
-
// **扱いの説明はカードに持たせる。** 節の見出しの下に置いていたときは、
|
|
20048
|
-
// #101 でカードだけがモーダルへ移り、説明だけが画面から消えた。
|
|
20049
|
-
// 顧客にトークンの貼り付けを求める画面で、貼った値がどう扱われるかの
|
|
20050
|
-
// 説明が落ちるのは、いちばん落としてはいけない種類の欠落
|
|
20051
|
-
// 行の中の Backlog カードは、同じ 1 文を開いた中(上の inputFold)に短くして持つ
|
|
20052
|
-
compact ? null : el("p", { class: "sec-note", text: "入れた値はここには表示されません(保存だけできます)。保存先はプロジェクトごとに分かれているので、他のプロジェクトには影響しません。" }),
|
|
20053
20010
|
]);
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
//
|
|
20058
|
-
|
|
20059
|
-
// fold/input/msg=触り始めたかの判定と、入力への移動・refresh=見せる瞬間の状態の当て直し
|
|
20060
|
-
var entry = { kind: kind, el: card, compact: compact, space: stateSpace, forced: false, fold: inputFold, input: input, msg: msg };
|
|
20061
|
-
if (compact) {
|
|
20062
|
-
entry.refresh = function () {
|
|
20063
|
-
// 作ったときの答えは古いことがある(取り直しが後から届く)。見せる瞬間に状態の行と summary と
|
|
20064
|
-
// 「自分で繋げばよい」の 1 行を当て直す(入れた直後に前の答えのまま出さない・#227)
|
|
20065
|
-
var now = secretStateOf(kind, stateSpace, backlogDomainsNow().length);
|
|
20066
|
-
applySecretState(state, now);
|
|
20067
|
-
var sum = inputFold.querySelector(".sec-input-summary");
|
|
20068
|
-
if (sum) sum.textContent = now.known === "yes" ? "入れ直す" : "入れる";
|
|
20069
|
-
if (preferred) {
|
|
20070
|
-
var want = now.known === "no";
|
|
20071
|
-
if (want && !preferred.parentNode) card.insertBefore(preferred, inputFold);
|
|
20072
|
-
else if (!want && preferred.parentNode) preferred.parentNode.removeChild(preferred);
|
|
20073
|
-
}
|
|
20074
|
-
};
|
|
20075
|
-
}
|
|
20076
|
-
KEY_CARDS.push(entry);
|
|
20011
|
+
ent.el = card;
|
|
20012
|
+
ent.refresh = paint;
|
|
20013
|
+
paint();
|
|
20014
|
+
// **作った鍵カードは1枚残らずここに載せる。** 出し入れ(接続先が0件のときに畳む)は DOM 検索ではなくこの控えで回す
|
|
20015
|
+
KEY_CARDS.push(ent);
|
|
20077
20016
|
return card;
|
|
20078
20017
|
}
|
|
20079
20018
|
|
|
@@ -21632,13 +21571,22 @@ ${story_1.splitByNameLinks.toString()}
|
|
|
21632
21571
|
Members: "この関係者の記録を消し、以後同じ人で作り直さないよう「除外メンバー」の一覧に足します。",
|
|
21633
21572
|
Rules: "このルールを消し、以後同じ題で作り直さないよう「除外ルール」の一覧に足します。",
|
|
21634
21573
|
};
|
|
21574
|
+
// 組み直した案件(記録が Memory/ の下)は除外の一覧を持たない。消したことは履歴で覚え、以後作り直さない
|
|
21575
|
+
// (cortex-engine #1911 便 DC-2d・オーナー決定 10/25。上の表は Cortex/ の案件のための橋)
|
|
21576
|
+
var DELETE_EFFECTS_MEMORY = {
|
|
21577
|
+
Decisions: "この決定を消し、以後同じ決定を作り直しません。",
|
|
21578
|
+
Glossary: "この用語を消し、以後同じ語を作り直しません。",
|
|
21579
|
+
Members: "この関係者の記録を消し、以後同じ人を作り直しません。",
|
|
21580
|
+
Rules: "このルールを消し、以後同じルールを作り直しません。",
|
|
21581
|
+
};
|
|
21635
21582
|
function deleteConfirmLines(rec, path) {
|
|
21636
|
-
var m = /^(
|
|
21637
|
-
var dir = m ? m[
|
|
21583
|
+
var m = /^(Cortex|Memory)\\/([^/]+)\\//.exec(path || "");
|
|
21584
|
+
var dir = m ? m[2] : "";
|
|
21585
|
+
var effects = m && m[1] === "Memory" ? DELETE_EFFECTS_MEMORY : DELETE_EFFECTS;
|
|
21638
21586
|
var title = (rec && rec.title) || (rec && rec.fileName) || "(題なし)";
|
|
21639
21587
|
return [
|
|
21640
21588
|
dirLabel(dir) + "「" + title + "」を削除します。",
|
|
21641
|
-
|
|
21589
|
+
effects[dir] || "この記録を消します。",
|
|
21642
21590
|
"消した中身は履歴に残り、あとから戻せます。",
|
|
21643
21591
|
];
|
|
21644
21592
|
}
|
package/dist/view-dir.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.VIEW_INDEX_FILE = exports.VIEW_NAMES_V2 = exports.VIEW_HELD = exports.VIEW_NAMES = void 0;
|
|
6
|
+
exports.VIEW_INDEX_FILE = exports.VIEW_NAMES_V2 = exports.EVIDENCE_VIEW_NAME = exports.VIEW_HELD = exports.VIEW_NAMES = void 0;
|
|
7
7
|
exports.blobShaOf = blobShaOf;
|
|
8
8
|
exports.isReadableEnvelope = isReadableEnvelope;
|
|
9
9
|
exports.classifyView = classifyView;
|
|
@@ -11,6 +11,7 @@ exports.classifyViewV2 = classifyViewV2;
|
|
|
11
11
|
exports.checkoutGit = checkoutGit;
|
|
12
12
|
exports.planViews = planViews;
|
|
13
13
|
exports.planViewsV2 = planViewsV2;
|
|
14
|
+
exports.emptyPlanV2 = emptyPlanV2;
|
|
14
15
|
exports.mergeViewsV2 = mergeViewsV2;
|
|
15
16
|
exports.mergeLedgerDir = mergeLedgerDir;
|
|
16
17
|
exports.viewCountsLine = viewCountsLine;
|
|
@@ -36,15 +37,16 @@ exports.viewCountsLineV2 = viewCountsLineV2;
|
|
|
36
37
|
* ## 名前(engine の宣言表 `publish: "viewer"` の行・V10a の `VIEW_HELD`)
|
|
37
38
|
*
|
|
38
39
|
* - 読む 10 本のうち、記憶側が置くのは 8 本+順位 1 本(`VIEW_NAMES`)
|
|
39
|
-
* - 根拠の台帳(`memory-evidence`・便 B3
|
|
40
|
+
* - 根拠の台帳(`memory-evidence`・便 B3)は、組み直していない案件では案件リポに置き公開されない。目次の名前に入れず、読み手が `<repo>/.cortex` から読む。
|
|
41
|
+
* 組み直した案件(便 DC-2e)では記憶側が封筒で置くので、`VIEW_NAMES_V2` にだけ入れる
|
|
40
42
|
* - 確認の帳簿(`gold-confirmation`・再導出の帯の読み手 `readRederivationLedgers` が読む)は置かれないので、いつも `.cortex` から読む
|
|
41
43
|
* - 名寄せの提案(`gold-proposals`)はビューアが読まなくなった(cortex-engine #1094 B-viewer V4・問いはポータルから)。置かれても使わない
|
|
42
44
|
*
|
|
43
45
|
* ## 組み直した案件(v2・木に `Memory/Home.md`・cortex-engine #1911 便 DC-2f・設計書 D-4)
|
|
44
46
|
*
|
|
45
47
|
* 上の比べと倒れは組み直していない案件(v1)だけ。組み直した案件は `.cortex` が空になる(便 DC-2)ので、`planViewsV2`・`mergeViewsV2` で
|
|
46
|
-
* 封筒を**無条件で採用**し(自分の sha で確かめられれば使う・`classifyViewV2`)、帳簿
|
|
47
|
-
* 確認の帳簿・再導出の帳簿は読まない(v1 本体だけが書き、便 V1N
|
|
48
|
+
* 封筒を**無条件で採用**し(自分の sha で確かめられれば使う・`classifyViewV2`)、帳簿 9 本(`VIEW_NAMES_V2`・根拠の台帳を含む)を `.cortex` から読まない。
|
|
49
|
+
* 確認の帳簿・再導出の帳簿は読まない(v1 本体だけが書き、便 V1N で書き手ごと消えた)。根拠の台帳も封筒から読む(便 DC-2e・上)。
|
|
48
50
|
* 取り出せない・確かめられない晩は**赤**(空の画面を緑で配らない・`build.ts`)
|
|
49
51
|
*/
|
|
50
52
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -69,11 +71,16 @@ exports.VIEW_NAMES = Object.freeze([
|
|
|
69
71
|
exports.VIEW_HELD = Object.freeze({
|
|
70
72
|
"gold-confirmation": "人が確認した版と機械の書き直し(再導出の帯の材料・readRederivationLedgers)",
|
|
71
73
|
});
|
|
74
|
+
/**
|
|
75
|
+
* 根拠の台帳の封筒の名前(cortex-engine #1911 便 DC-2e)。組み直した案件だけが読む(記憶側の段 `evidence` が保管庫の項目ごとの引用から組んで置く)。
|
|
76
|
+
* 組み直していない案件は今どおり案件リポの `.cortex` から読む(`memory-evidence.ts`)ので `VIEW_NAMES` には入れない
|
|
77
|
+
*/
|
|
78
|
+
exports.EVIDENCE_VIEW_NAME = "memory-evidence";
|
|
72
79
|
/**
|
|
73
80
|
* 組み直した案件(v2・木に `Memory/Home.md`)で読む名前(cortex-engine #1911 便 DC-2f・設計書 D-4)。`VIEW_NAMES` から再導出の帳簿
|
|
74
|
-
* (`gold-rederivation`・v1 本体だけが書き、便 V1N
|
|
81
|
+
* (`gold-rederivation`・v1 本体だけが書き、便 V1N で書き手ごと消えた)を除き、根拠の台帳(便 DC-2e)を足した 9 本(名前順)。確認の帳簿(`VIEW_HELD`)も読まない
|
|
75
82
|
*/
|
|
76
|
-
exports.VIEW_NAMES_V2 = Object.freeze(exports.VIEW_NAMES.filter((n) => n !== "gold-rederivation"));
|
|
83
|
+
exports.VIEW_NAMES_V2 = Object.freeze([...exports.VIEW_NAMES.filter((n) => n !== "gold-rederivation"), exports.EVIDENCE_VIEW_NAME].sort());
|
|
77
84
|
/** 目次の名前(engine `VIEW_INDEX_NAME`) */
|
|
78
85
|
exports.VIEW_INDEX_FILE = "view-index.json";
|
|
79
86
|
const SHA_RE = /^[0-9a-f]{40}$/;
|
|
@@ -276,7 +283,7 @@ async function planViews(viewDir, git, baseDir) {
|
|
|
276
283
|
return { classes, counts, use };
|
|
277
284
|
}
|
|
278
285
|
/**
|
|
279
|
-
* 組み直した案件(v2)の計画(cortex-engine #1911 便 DC-2f・設計書 D-4)。**帳簿の置き場(`.cortex`)も git も見ない**。名前は `VIEW_NAMES_V2` の
|
|
286
|
+
* 組み直した案件(v2)の計画(cortex-engine #1911 便 DC-2f・設計書 D-4)。**帳簿の置き場(`.cortex`)も git も見ない**。名前は `VIEW_NAMES_V2` の 9 本。
|
|
280
287
|
* 🔴 **空の画面を緑で配らない**: 目次が無い・壊れている・読む名前が 1 本も無い、封筒が読めない・確かめられない(`unreadable`・`unexplained`。
|
|
281
288
|
* 形の違う目次の行も `unreadable`)が 1 本でもあれば投げる(ビルドを赤にする)。目次に行の無い名前は `missing`(その帳簿は無い=置かない)
|
|
282
289
|
*/
|
|
@@ -310,6 +317,18 @@ async function planViewsV2(viewDir) {
|
|
|
310
317
|
throw new Error(`組み直した案件の記憶側の画面用ファイルを確かめられません(${bad.join("・")})`);
|
|
311
318
|
return { classes, counts, use };
|
|
312
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* 記憶がまだ 1 件も無い組み直した案件の計画(cortex-engine #1911 便 GV)。読む名前は全部 `missing`(帳簿は無い=置かない)。
|
|
322
|
+
* 🔴 呼んでよいのは「取り出した区画にファイルが 1 本も無い」かつ「木の記録とストーリーが 0 件」のときだけ(`build.ts`)。記録があるのに目次が無い・目次が壊れている・封筒を確かめられないのは
|
|
323
|
+
* 今どおり `planViewsV2` が投げる(空の画面を緑で配らない)
|
|
324
|
+
*/
|
|
325
|
+
function emptyPlanV2() {
|
|
326
|
+
const classes = {};
|
|
327
|
+
for (const name of exports.VIEW_NAMES_V2)
|
|
328
|
+
classes[name] = "missing";
|
|
329
|
+
const total = exports.VIEW_NAMES_V2.length;
|
|
330
|
+
return { classes, use: {}, counts: { total, same: 0, stale: 0, unexplained: 0, unreadable: 0, unverified: 0, missing: total } };
|
|
331
|
+
}
|
|
313
332
|
/** 封筒を読む(無い・JSON でない → `null`=読めない) */
|
|
314
333
|
async function readEnvelope(viewDir, name) {
|
|
315
334
|
const text = await readText(node_path_1.default.join(viewDir, `${name}.json`));
|
package/package.json
CHANGED