@takagaki/cortex-decisions-viewer 0.4.71 → 0.4.73

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 CHANGED
@@ -292,10 +292,28 @@ async function readFleetSources(repoRoot) {
292
292
  capabilities = out;
293
293
  }
294
294
  const fleetGeneratedAt = typeof obj.generatedAt === "string" ? obj.generatedAt : undefined;
295
+ // いま同期している Backlog の接続先(fleet-status.json トップレベル・#111)。
296
+ //
297
+ // **画面に現在値を出すために要る。** 「接続先を変更」フォームが入力欄だけだったため、
298
+ // 実機で「何もセットされていない」と読まれ、同じURLが貼り直された(#127)。
299
+ //
300
+ // **domain / projectKey しか通さない。** 生成側は configPath / sections / strays /
301
+ // features も持っているが、画面が使うのは接続先の2つだけ。素通しにすると、engine が
302
+ // このオブジェクトに足したものが顧客の画面データへ黙って流れる(Lambda 側の
303
+ // FLEET_PUBLIC_KEYS と同じ考え方で、こちらも許可リストにする)。
304
+ //
305
+ // **値が無い形は落とす。** 正本もミラーも持たない案件では `{ source: "secrets" }` だけが
306
+ // 来る。空の器を通すと、画面は「接続先の情報がある」と判断して空文字を並べることになる
307
+ const bt = obj.backlogTarget != null && typeof obj.backlogTarget === "object" && !Array.isArray(obj.backlogTarget)
308
+ ? obj.backlogTarget
309
+ : null;
310
+ const backlogTarget = bt && typeof bt.domain === "string" && bt.domain && typeof bt.projectKey === "string" && bt.projectKey
311
+ ? { domain: bt.domain, projectKey: bt.projectKey }
312
+ : undefined;
295
313
  const secretSources = obj.secretSources && typeof obj.secretSources === "object"
296
314
  ? obj.secretSources
297
315
  : undefined;
298
- return { externalSources, internalSources, pipelines, tools, capabilities, fleetGeneratedAt, secretSources, checks, githubOwners };
316
+ return { externalSources, internalSources, pipelines, tools, capabilities, fleetGeneratedAt, secretSources, checks, githubOwners, backlogTarget };
299
317
  }
300
318
  /** パスがディレクトリとして存在するか */
301
319
  async function isDirectory(dirAbs) {
@@ -1179,6 +1197,7 @@ async function build(opts) {
1179
1197
  capabilities: fleet.capabilities,
1180
1198
  checks: fleet.checks,
1181
1199
  githubOwners: fleet.githubOwners,
1200
+ backlogTarget: fleet.backlogTarget,
1182
1201
  };
1183
1202
  // サムネイル(デザイン画面等)をサイトに同梱し、ノードのパスをサイト内相対に書き換える
1184
1203
  await node_fs_1.promises.mkdir(outAbs, { recursive: true });
package/dist/render.js CHANGED
@@ -1258,6 +1258,11 @@ a.ds-name:hover { text-decoration: underline; }
1258
1258
  .ds-addform .sec-input { margin-bottom: 6px; }
1259
1259
  .sec-input-inline { width: auto; max-width: 220px; margin-bottom: 0; }
1260
1260
  .sec-how { color: var(--muted); font-size: 12px; line-height: 1.7; margin: 0 0 10px; }
1261
+ /* いまの接続先(設定を変える口の直前に置く。値は本文色で、ラベルだけ弱める) */
1262
+ .ds-current { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin: 0 0 8px; font-size: 12.5px; }
1263
+ .ds-current-label { color: var(--muted); flex: 0 0 auto; }
1264
+ .ds-current-value { color: var(--text); font-weight: 600; word-break: break-all; }
1265
+ .ds-current-value.is-unset { color: var(--muted); font-weight: 400; }
1261
1266
  /* 入力欄のすぐ下。貼る直前に読める位置に置く */
1262
1267
  .sec-note { color: var(--muted); font-size: 12px; line-height: 1.7; margin: 6px 0 0; }
1263
1268
  .sec-how p { margin: 0; }
@@ -2453,7 +2458,7 @@ ${capabilityState.toString()}
2453
2458
  meeting_minutes: "会議",
2454
2459
  channels_json: "チャット",
2455
2460
  figma_token: "デザイン", figma_inventory: "デザイン",
2456
- submodules: "開発", dev_issues_derived: "開発",
2461
+ dev_sources_registered: "開発", dev_issues_derived: "開発",
2457
2462
  };
2458
2463
  var allChecks = (fleetVal("checks") || []).filter(function (c) {
2459
2464
  return c != null && c.status === "missing";
@@ -2839,6 +2844,34 @@ ${capabilityState.toString()}
2839
2844
  });
2840
2845
  }
2841
2846
 
2847
+ /**
2848
+ * いま同期している Backlog の接続先(#127)。
2849
+ *
2850
+ * **2つの経路から引く。** 正本は fleet の backlogTarget(engine が正本
2851
+ * issues-config.json → ミラーの順で解決した値)だが、**このキーを載せているのは
2852
+ * 新しい engine だけ**で、艦隊の多くは @v1 のまま持っていない。無いときは
2853
+ * 内部ソースの url(同じ値から機械導出されたプロジェクトURL)を解析して補う。
2854
+ * ここを backlogTarget だけにすると、**設定済みの案件に「未設定」と出す**
2855
+ * ——今回直している誤読(何もセットされていないと読んで貼り直す)を、
2856
+ * 画面の側からもう一度作ることになる。
2857
+ *
2858
+ * **解析できないときは黙らない。** 「未設定」と明示する。行ごと消すと、
2859
+ * 「表示が無い=まだ何も無い」なのか「出し忘れ」なのかが読み手に区別できない。
2860
+ */
2861
+ function currentBacklogTargetLine(s) {
2862
+ var t = fleetVal("backlogTarget");
2863
+ if (!t || !t.domain || !t.projectKey) t = (s && s.url && backlogTargetOf(s.url)) || null;
2864
+ var p = el("p", { class: "ds-current" });
2865
+ p.appendChild(el("span", { class: "ds-current-label", text: "現在の接続先" }));
2866
+ p.appendChild(
2867
+ el("span", {
2868
+ class: t ? "ds-current-value" : "ds-current-value is-unset",
2869
+ text: t ? t.domain + " / " + t.projectKey : "未設定",
2870
+ }),
2871
+ );
2872
+ return p;
2873
+ }
2874
+
2842
2875
  /**
2843
2876
  * リポジトリ内の情報源に足す操作(会議の取り込みON/OFF・Driveフォルダ追加とON/OFF・Figmaファイル追加)。
2844
2877
  *
@@ -2875,17 +2908,22 @@ ${capabilityState.toString()}
2875
2908
  // 別名は上のチップ(読み取り専用の記録)で見せるに留める。Lambda 側も add/remove とも断る。
2876
2909
  used = true;
2877
2910
  } else if (s.kind === "会議" && usable("会議", "google-meet")) {
2911
+ // **文面に設定ファイル名を出さない(2026-08-12 の文言原則)。** ここが見ているのは
2912
+ // 会議の取り込み設定(ingest-config.json の有無と enabled)だが、それは
2913
+ // 注: ここは埋め込みJSのテンプレートリテラル内。コメントでもバッククォートを使わない
2914
+ // 読む人の操作対象ではない——画面から直せないものなので、次の一歩は「担当者へ連絡」。
2915
+ // 「手で直してください」も出さない(PM に設定ファイルを編集させる案内になっていた)。
2878
2916
  if (s.ingestState === "unset") {
2879
- box.appendChild(el("p", { class: "sec-how", text: "会議の取り込み設定がこのリポジトリにありません(ingest-config.json)。先に設置が必要です。" }));
2917
+ box.appendChild(el("p", { class: "sec-how", text: "この案件では議事録の自動取り込みがまだ用意されていません。cortex の担当者にご連絡ください。" }));
2880
2918
  used = true;
2881
2919
  } else if (s.ingestState === "broken") {
2882
- box.appendChild(el("p", { class: "sec-how", text: "会議の取り込み設定(ingest-config.json)が壊れているため、ここからは変更できません。手で直してください。" }));
2920
+ box.appendChild(el("p", { class: "sec-how", text: "議事録の取り込み設定を読み取れないため、この画面からは変更できません。cortex の担当者にご連絡ください。" }));
2883
2921
  used = true;
2884
2922
  } else if (s.ingestState === "off") {
2885
2923
  // 自動取り込みを止めている案件(例: Teams を使っていて手動で取り込む運用)。
2886
2924
  // ここでトグルを出すと「押せば始まる」と読めるが、実際は設定ファイルの意思表示なので
2887
2925
  // 画面から気軽に反転させるものではない。状態だけを伝える。
2888
- box.appendChild(el("p", { class: "sec-how", text: "この案件は会議の自動取り込みを行わない設定です(ingest-config.json の enabled が false)。" }));
2926
+ box.appendChild(el("p", { class: "sec-how", text: "この案件は議事録の自動取り込みを停止しています。" }));
2889
2927
  used = true;
2890
2928
  }
2891
2929
  }
@@ -2895,6 +2933,13 @@ ${capabilityState.toString()}
2895
2933
  // 「プロジェクトキー」「プロジェクト名」の区別が付かず取り違える。
2896
2934
  // 実データでも cm1.backlog.jp と jleague.backlog.jp が混在している
2897
2935
  if (s.kind === "課題管理" && usable("課題管理", "backlog")) {
2936
+ // **いまどこに繋がっているかを、フォームより先に出す(#127)。**
2937
+ //
2938
+ // 実機で踏んだ欠陥: この節は入力欄と placeholder しか無く、保存済みの接続先が
2939
+ // 画面のどこにも出ていなかった。保存直後に出る楽観的なチップはリロードで消えるので、
2940
+ // **利用者は「何もセットされていない」と読み、同じURLを貼り直した**。
2941
+ // 設定を変える口の隣には、いまの値が必ず要る。
2942
+ box.appendChild(currentBacklogTargetLine(s));
2898
2943
  // **設定ファイルが無い案件にはフォームを出さない。** 書き込み先が無いので
2899
2944
  // 貼っても 404 で終わる。三菱電機は tools が backlog なのに
2900
2945
  // backlog-settings.json が1つも無い(固定IP経由の同期で、UIからの投入は
@@ -2905,10 +2950,13 @@ ${capabilityState.toString()}
2905
2950
  // 同期ミラー(backlog-settings.json)の位置から決めている。ミラーが1つも
2906
2951
  // 無い案件では正本をどこへ置けばよいかも決められないので、条件は変わらない
2907
2952
  if (!s.url) {
2908
- box.appendChild(el("p", { class: "sec-how", text: "この案件の課題管理の設定ファイル(同期ミラーの backlog-settings.json)がまだありません。接続先の正本(issues-config.json)の置き場もここから決められないため、先に初回の同期を実行するか、担当者にご連絡ください。" }));
2953
+ box.appendChild(el("p", { class: "sec-how", text: "この案件はまだ一度も Backlog と同期していないため、この画面からは接続先を設定できません。先に初回の同期を実行するか、cortex の担当者にご連絡ください。" }));
2909
2954
  used = true;
2910
2955
  } else box.appendChild(addForm({
2911
2956
  title: "接続先を変更",
2957
+ // **「追加」ではなく「保存」。** 接続先は1件しか持てない置き換えで、
2958
+ // 「追加」だと2つ目を足せると読める(実機テストでの指摘・複数対応は #127)
2959
+ submitLabel: "保存",
2912
2960
  placeholder: "https://<スペース>.backlog.jp/projects/<プロジェクトキー>",
2913
2961
  requiredNote: "BacklogのURLを入力してください(プロジェクトキーが入った形。数字だけのURLは受け付けません)。",
2914
2962
  hint: "Backlog でこの案件のプロジェクトを開き、ブラウザのURLをそのまま貼ってください(課題の画面のURLでも構いません)。APIキーは下の「Backlog のAPIキー」から別に登録します。",
@@ -2940,12 +2988,14 @@ ${capabilityState.toString()}
2940
2988
  }
2941
2989
 
2942
2990
  if (s.kind === "共有資料" && usable("共有資料", "google-drive")) {
2991
+ // 状態の出どころは資料の取り込み設定(materials-config.json)だが、会議と同じく
2992
+ // 文面には出さない(2026-08-12 の文言原則)。画面から直せない状態の次の一歩は担当者への連絡。
2943
2993
  if (s.driveState === "unset") {
2944
- box.appendChild(el("p", { class: "sec-how", text: "資料の同期設定がこのリポジトリにありません(materials-config.json)。先に設置が必要です。" }));
2994
+ box.appendChild(el("p", { class: "sec-how", text: "この案件では共有資料の取り込みがまだ用意されていません。cortex の担当者にご連絡ください。" }));
2945
2995
  used = true;
2946
2996
  } else if (s.driveState === "broken") {
2947
2997
  // 壊れていると書き込みも失敗する。フォームを出して押させない
2948
- box.appendChild(el("p", { class: "sec-how", text: "資料の同期設定(materials-config.json)が壊れているため、ここからは変更できません。手で直してください。" }));
2998
+ box.appendChild(el("p", { class: "sec-how", text: "共有資料の取り込み設定を読み取れないため、この画面からは変更できません。cortex の担当者にご連絡ください。" }));
2949
2999
  used = true;
2950
3000
  } else if (s.driveState) {
2951
3001
  // フォルダが1件も無いのに ON/OFF だけ出しても意味が無いので、追加フォームを先に出す
@@ -3323,14 +3373,21 @@ ${capabilityState.toString()}
3323
3373
 
3324
3374
  /**
3325
3375
  * 「+…を追加」のフォーム。URLをそのまま貼れるようにする(IDだけを要求すると転記ミスが増える)。
3326
- * @param opts { title, placeholder, hint, needsName, confirmLines, build(values) }
3376
+ *
3377
+ * **ボタンの語は呼び出し側が決める(既定は「追加」)。** 課題管理の「接続先を変更」だけは
3378
+ * 1件しか持てない設定の**置き換え**なのに、ボタンが「追加」だと**複数登録できる**と読める
3379
+ * (実機テストでの指摘。複数接続先の対応は #127 の将来要件で、いまは持てない)。
3380
+ * 押した結果の表示(+/追加済み)も同じ理由で語を揃える。
3381
+ *
3382
+ * @param opts { title, placeholder, hint, needsName, confirmLines, build(values), submitLabel }
3327
3383
  */
3328
3384
  function addForm(opts) {
3329
3385
  var main = el("input", { class: "sec-input", type: "text", placeholder: opts.placeholder, autocomplete: "off" });
3330
3386
  var name = opts.needsName
3331
3387
  ? el("input", { class: "sec-input", type: "text", placeholder: opts.namePlaceholder || "表示名", autocomplete: "off" })
3332
3388
  : null;
3333
- var btn = el("button", { class: "ds-toggle-btn", type: "button", text: "追加" });
3389
+ var submitLabel = opts.submitLabel || "追加";
3390
+ var btn = el("button", { class: "ds-toggle-btn", type: "button", text: submitLabel });
3334
3391
  var msg = el("div", { class: "ds-toggle-msg" });
3335
3392
 
3336
3393
  btn.addEventListener("click", function () {
@@ -3358,9 +3415,9 @@ ${capabilityState.toString()}
3358
3415
  // (実際にそうなった)。だから押した結果をここで見せる。
3359
3416
  pending.appendChild(
3360
3417
  el("div", { class: "ds-pending-item" }, [
3361
- el("span", { class: "ds-pending-mark", text: "+" }),
3418
+ el("span", { class: "ds-pending-mark", text: opts.submitLabel ? "✓" : "+" }),
3362
3419
  el("span", { class: "ds-pending-name", text: addedName || added }),
3363
- el("span", { class: "ds-pending-note", text: "追加済み・反映中" }),
3420
+ el("span", { class: "ds-pending-note", text: submitLabel + "済み・反映中" }),
3364
3421
  ]),
3365
3422
  );
3366
3423
  });
@@ -3491,8 +3548,19 @@ ${capabilityState.toString()}
3491
3548
 
3492
3549
  /**
3493
3550
  * 登録の由来の表示(#118)。値は fleet-status.json の origin
3494
- * (explicit … 登録ファイルに手で書いた / derived … .gitmodules 等からの自動導出 / both)。
3551
+ * (explicit … 登録ファイルに手で書いた / derived … 自動導出 / both)。
3495
3552
  * **知らない値には何も出さない**(生の内部値を顧客の画面に出さないため)。
3553
+ *
3554
+ * **#119 で、開発リポの自動導出は無くなった。** .gitmodules の submodule を登録として
3555
+ * 扱うのをやめた(手元でコードを読みたいという案件のカスタマイズであって、中身を顧客可視の
3556
+ * Gold に上げてよいという同意ではない)ので、いま engine が derived を付けるのは
3557
+ * Slack だけ。**新しく生成されるデータでは github の行は必ず explicit になる。**
3558
+ *
3559
+ * **それでも derived / both の表示と、下の削除の出し分けは残す。** 再生成前の
3560
+ * fleet-status.json にはまだ derived が入っている(艦隊の実データで確認: cortex-context
3561
+ * 5件・mitsubishi 5件・verdy 4件・gdo 1件)。ここを消すと、その案件では
3562
+ * **「登録から削除」が出てはいけない行に出て**、押しても翌日また現れる。
3563
+ * 全案件の再生成が回りきったら、github 側のこの分岐を落とす。
3496
3564
  */
3497
3565
  var ORIGIN_LABEL = { explicit: "明示登録", derived: "自動検出", both: "明示登録+自動検出" };
3498
3566
  var ORIGIN_HELP = {
@@ -3517,7 +3585,9 @@ ${capabilityState.toString()}
3517
3585
  // 登録の由来(#118)。**「登録から削除」が出る/出ないの理由がこれ。** 導出されたリポは
3518
3586
  // 登録ファイルから消しても翌日また現れるので削除を出していないが、画面には
3519
3587
  // 「同じ見た目の行なのに、片方にだけ削除がある」としか映らず、毎回考え直すことになる。
3520
- // GitHub の行だけに出す(削除の出し分けがあるのはここだけで、他は全部 explicit)
3588
+ // **GitHub の行だけに出す。** 由来で出し分けているのはここだけだから——Slack も
3589
+ // channels.json 由来の derived だが、あちらに削除は無く、由来を見せても打つ手が増えない。
3590
+ // #119 以降、新しいデータの github は必ず explicit(詳細は ORIGIN_LABEL)
3521
3591
  if (String(s.type).indexOf("github") === 0 && ORIGIN_LABEL[s.origin]) {
3522
3592
  badges.appendChild(el("span", {
3523
3593
  class: "badge ds-origin",
@@ -3559,9 +3629,13 @@ ${capabilityState.toString()}
3559
3629
  return { op: "set-github-source-enabled", repo: s.ref, value: next };
3560
3630
  },
3561
3631
  }));
3562
- // **削除は「手で登録したもの」にだけ出す。** .gitmodules 等から自動で見つかったリポは
3632
+ // **削除は「手で登録したもの」にだけ出す。** 自動で見つかったリポは
3563
3633
  // 登録ファイルから消しても翌日また現れる(=消えないのに消せたように見える)。
3564
3634
  // 止めたいだけなら上の「読み取りを止める」で足りる。
3635
+ //
3636
+ // **#119 以降、新しいデータの github は必ず explicit** なので、この条件は
3637
+ // いずれ常に真になる。それまでは残す——再生成前のスナップショットには derived が
3638
+ // まだ入っており、条件を外すと押しても戻ってくる削除ボタンが出る(ORIGIN_LABEL 参照)。
3565
3639
  if (s.origin === "explicit") {
3566
3640
  card.appendChild(removeButton({
3567
3641
  label: "登録から削除",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.4.71",
3
+ "version": "0.4.73",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,