@takagaki/cortex-decisions-viewer 0.4.62 → 0.4.64

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
@@ -148,6 +148,26 @@ async function readFleetSources(repoRoot) {
148
148
  origin: s.origin != null ? String(s.origin) : undefined,
149
149
  }))
150
150
  : undefined;
151
+ // セットアップの充足チェック。**missing だけを通す。**
152
+ // na(使わないと宣言した能力)を通すと「設定する必要が無いものに設定を促す」偽の警告になり、
153
+ // #101 で潰した穴が復活する。unknown は AWS/gh へ到達できなかった回に出るので、
154
+ // 夜間実行がこけた日に嘘が出る。
155
+ // score / nextActions は通さない——nextActions は checks[].action を平坦化した
156
+ // 同じ内容の別キーで、通すと同じ文が2箇所に出る。
157
+ const checks = Array.isArray(obj.checks)
158
+ ? obj.checks
159
+ .filter((c) => c != null && typeof c === "object")
160
+ .filter((c) => String(c.status ?? "") === "missing")
161
+ .map((c) => ({
162
+ id: String(c.id ?? ""),
163
+ label: String(c.label ?? ""),
164
+ category: String(c.category ?? ""),
165
+ status: String(c.status ?? ""),
166
+ action: c.action != null ? String(c.action) : undefined,
167
+ detail: c.detail != null ? String(c.detail) : undefined,
168
+ }))
169
+ .filter((c) => c.id !== "")
170
+ : undefined;
151
171
  const internalSources = Array.isArray(obj.internalSources)
152
172
  ? obj.internalSources
153
173
  .filter((s) => s != null && typeof s === "object")
@@ -157,6 +177,9 @@ async function readFleetSources(repoRoot) {
157
177
  label: String(s.label ?? ""),
158
178
  url: s.url != null ? String(s.url) : undefined,
159
179
  lastSync: s.lastSync != null ? String(s.lastSync) : undefined,
180
+ // 取り込み済みの件数。**「同期が走った」と「実際に入った」は別物。**
181
+ // これが無いと、初回全量同期をしていない案件が「接続OK」に見える
182
+ itemCount: typeof s.itemCount === "number" ? s.itemCount : undefined,
160
183
  // 会議名に入れる合図。**古い fleet-status.json の matchKeys は引き継がない**
161
184
  // (client名と廃止した meetingNamePatterns の寄せ集めで、いま照合には使われていない。
162
185
  // 出すと「この語を会議名に入れれば拾われる」と読めてしまう)。
@@ -225,7 +248,7 @@ async function readFleetSources(repoRoot) {
225
248
  const secretSources = obj.secretSources && typeof obj.secretSources === "object"
226
249
  ? obj.secretSources
227
250
  : undefined;
228
- return { externalSources, internalSources, pipelines, tools, fleetGeneratedAt, secretSources };
251
+ return { externalSources, internalSources, pipelines, tools, fleetGeneratedAt, secretSources, checks };
229
252
  }
230
253
  /** パスがディレクトリとして存在するか */
231
254
  async function isDirectory(dirAbs) {
@@ -1101,6 +1124,7 @@ async function build(opts) {
1101
1124
  internalSources: fleet.internalSources,
1102
1125
  pipelines: fleet.pipelines,
1103
1126
  tools: fleet.tools,
1127
+ checks: fleet.checks,
1104
1128
  };
1105
1129
  // サムネイル(デザイン画面等)をサイトに同梱し、ノードのパスをサイト内相対に書き換える
1106
1130
  await node_fs_1.promises.mkdir(outAbs, { recursive: true });
package/dist/render.js CHANGED
@@ -172,6 +172,36 @@ function externalCapability(type) {
172
172
  return "開発";
173
173
  return CAP_OTHER;
174
174
  }
175
+ /**
176
+ * 貼られたURLから Backlog の接続先を読む。
177
+ *
178
+ * **クライアントへは .toString() で渡す。** テンプレート文字列の中に正規表現を
179
+ * 手で書くと、バックスラッシュが二重に潰れて別物になる(実際に
180
+ * `\\/` が `/` になり、クライアントJSが構文エラーで丸ごと落ちた)。
181
+ * 既存の sourceNeedsAttention / capabilityState と同じ流儀にする。
182
+ *
183
+ * **判定の正本は Lambda 側**(そちらが書き込む)。ここは確認文の表示用で、
184
+ * 食い違うと「画面はこう見せたのに別のものが書かれた」になるので、
185
+ * 同じ形かをテストで突き合わせている。
186
+ */
187
+ function backlogTargetOf(input) {
188
+ const s = String(input == null ? "" : input).trim();
189
+ const m = s.match(/^https?:\/\/([a-z0-9-]+\.(?:backlog\.jp|backlog\.com|backlogtool\.com))\/(.*)$/i);
190
+ if (!m)
191
+ return null;
192
+ const domain = m[1].toLowerCase();
193
+ const rest = m[2];
194
+ // **数値のプロジェクトIDは弾く。** 取り違えの検査(艦隊のキーとの照合)を
195
+ // 迂回できてしまう。Backlog はドキュメントのURLをこの形でも出す
196
+ const num = /^[0-9]+$/;
197
+ const head = rest.match(/^(?:projects|document|wiki|find|board|gantt|git)\/([A-Za-z0-9_]+)(?:[/?#]|$)/);
198
+ if (head)
199
+ return num.test(head[1]) ? null : { domain: domain, projectKey: head[1].toUpperCase() };
200
+ const view = rest.match(/^view\/([A-Za-z0-9_]+)-\d+/);
201
+ if (view)
202
+ return num.test(view[1]) ? null : { domain: domain, projectKey: view[1].toUpperCase() };
203
+ return null;
204
+ }
175
205
  function capabilityState(cap, ctx) {
176
206
  // **能力→パイプラインの対応はここに持つ。** 呼び出し側に渡させると、
177
207
  // クライアント側(この関数を .toString() で受け取る側)が同じ表を書き写すことになり、
@@ -224,7 +254,13 @@ function capabilityState(cap, ctx) {
224
254
  const pipeSkipped = ctx.pipes.some(function (p) {
225
255
  return pipeRe != null && pipeRe.test(p.id) && p.applicable === false;
226
256
  });
227
- const syncedForReal = internal != null && ((internal.lastSync && !pipeSkipped) || internal.url);
257
+ // **「同期が走った」と「実際にデータが入った」は別物。** 初回全量同期をしていない案件は、
258
+ // 毎晩の差分同期が成功し続けても0件のままになる(cortex-context の課題管理が実例で、
259
+ // lastSync はあるのに取り込み件数は0だった)。件数を見ないと、タイルが「接続OK」と言い、
260
+ // 同じ画面のセットアップ残りが「初回同期がまだです」と言う状態になる。
261
+ // 件数が無い(古い fleet-status.json・件数を持たない能力)ときは、いままでの判定に従う。
262
+ const emptyForReal = internal != null && internal.itemCount === 0;
263
+ const syncedForReal = internal != null && !emptyForReal && ((internal.lastSync && !pipeSkipped) || internal.url);
228
264
  const idle = !off &&
229
265
  (isLive
230
266
  ? liveExts.length === 0
@@ -944,6 +980,19 @@ a.ds-name:hover { text-decoration: underline; }
944
980
  width: 40px; height: 40px; flex: 0 0 40px; font-size: 26px; line-height: 1;
945
981
  }
946
982
  .ds-tile-logo svg { width: 100%; height: 100%; }
983
+ /* セットアップの残り。**直し方を状態と同じ大きさで出す**——
984
+ 何が足りないかだけ分かっても、次の一歩が分からなければ画面の意味が薄い */
985
+ .ds-tile-todo { color: var(--muted); }
986
+ .ds-checks { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; }
987
+ .ds-check-cat { font-size: 12px; font-weight: 700; color: var(--muted); margin-top: 8px; }
988
+ .ds-check {
989
+ display: flex; flex-direction: column; gap: 3px;
990
+ border-left: 3px solid #fcd34d; background: #fffbeb;
991
+ border-radius: 0 8px 8px 0; padding: 8px 12px;
992
+ }
993
+ .ds-check-label { font-size: 13px; font-weight: 700; color: var(--text); }
994
+ .ds-check-action { font-size: 13px; color: var(--text); line-height: 1.7; }
995
+ .ds-check-detail { font-size: 12px; color: var(--muted); }
947
996
  .ds-tile-desc { font-size: 12.5px; color: var(--muted); }
948
997
  .ds-tile-sub { font-size: 12.5px; margin-top: 2px; }
949
998
  .ds-tile-chev { color: var(--muted); }
@@ -969,6 +1018,9 @@ a.ds-name:hover { text-decoration: underline; }
969
1018
  .ds-gate-warn { color: #b45309; }
970
1019
  .ds-gate-muted { color: #6b7280; }
971
1020
  .ds-pipes { display: flex; flex-direction: column; gap: 8px; }
1021
+ /* 実行状況の行に直し方を添える。同じ run の未達を別の節にも出すと画面に2回並ぶ */
1022
+ .ds-pipe-wrap { display: flex; flex-direction: column; gap: 3px; }
1023
+ .ds-pipe-todo { font-size: 12.5px; color: var(--muted); line-height: 1.7; padding-left: 4px; }
972
1024
  .ds-pipe {
973
1025
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
974
1026
  padding: 10px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow);
@@ -1112,6 +1164,7 @@ const CLIENT_JS = `
1112
1164
  // 直列化した先(ここ)で undefined を参照して壊れる。
1113
1165
  var CAP_OTHER = ${JSON.stringify(CAP_OTHER)};
1114
1166
  ${externalCapability.toString()}
1167
+ ${backlogTargetOf.toString()}
1115
1168
  ${sourceNeedsAttention.toString()}
1116
1169
  ${capabilityState.toString()}
1117
1170
  // 「はじめに」セクションのチュートリアルデータ(ビルド時に埋め込み。ボタンURL・チャレンジ4の決定は解決済み)
@@ -1827,14 +1880,34 @@ ${capabilityState.toString()}
1827
1880
  if (aliases.length) {
1828
1881
  // **目印が無くても入る会議。** 既に走っていて改名を頼みにくい定例を、
1829
1882
  // いまの名前のまま登録したもの。出さないと「なぜこれだけ入るのか」
1830
- // 「新しい定例をどこに足すのか」が画面から分からない
1831
- var shown = aliases.slice(0, 5).join(" / ");
1832
- if (aliases.length > 5) shown += " 他" + (aliases.length - 5) + "件";
1883
+ // 「新しい定例をどこに足すのか」が画面から分からない。
1884
+ //
1885
+ // **1件ずつ外せるようにする。** 追加はできて削除はできない、だと
1886
+ // 間違えて登録した名前(日付つきのファイル名など)を消す手段が無い
1833
1887
  col.appendChild(el("span", {
1834
1888
  class: "ds-keys",
1835
- text: "目印なしで取り込む会議: " + shown,
1889
+ text: "目印なしで取り込む会議:",
1836
1890
  title: "この名前の会議は、目印が無くてもこの案件に振り分けられます(大小文字・前後の空白は問いません。ファイル名に使えない記号(コロン・スラッシュ等)は同じものとして扱います)。既に走っている定例を改名せずに取り込むための登録です。",
1837
1891
  }));
1892
+ var alist = el("div", { class: "ds-subitems" });
1893
+ aliases.forEach(function (a) {
1894
+ var row = el("div", { class: "ds-subitem" }, [el("span", { class: "ds-name", text: a })]);
1895
+ row.appendChild(removeButton({
1896
+ label: "この会議を外す",
1897
+ confirmLines: function () {
1898
+ return [
1899
+ "「" + a + "」を取り込み対象から外します。",
1900
+ "",
1901
+ "以後この名前の会議は、会議名に目印を入れない限り取り込まれません。",
1902
+ "",
1903
+ "外しますか?",
1904
+ ];
1905
+ },
1906
+ build: function () { return { op: "remove-meeting-alias", alias: a }; },
1907
+ }));
1908
+ alist.appendChild(row);
1909
+ });
1910
+ col.appendChild(alist);
1838
1911
  }
1839
1912
  if (s.driveSync === false) {
1840
1913
  col.appendChild(el("span", { class: "ds-drive-note", text: "Drive自動同期は未設定(手動で置いたファイルの変換のみ)" }));
@@ -1957,6 +2030,50 @@ ${capabilityState.toString()}
1957
2030
  var STATE_LABEL = { ok: "● 接続OK", idle: "⦿ 未接続", off: "未使用", warn: "⚠️" };
1958
2031
  var SECRET_OF_CAP = { "デザイン": "figma", "課題管理": "backlog", "開発": "external-sources" };
1959
2032
 
2033
+ // ---- セットアップの残り(checks)----
2034
+ //
2035
+ // **能力に紐づくものはその能力のタイルへ、紐づかないものは節にまとめる。**
2036
+ // 独立した一覧にすると、鍵カードの「現在: 未設定」やタイルの状態と
2037
+ // 同じことを別の言い方で二度言うことになり、ズレたときに読み手が
2038
+ // どちらを信じるか決められない(#101 で判定を1箇所に集めたのと同じ理由)。
2039
+ //
2040
+ // **missing 以外は出さない。** na は「使わないと宣言した能力」で、出すと
2041
+ // 「設定する必要が無いものに設定を促す」偽の警告になる(#101 で潰した穴)。
2042
+ // ビルド時とライブの両方で絞っているが、ここでも見る——経路が増えたときに
2043
+ // 絞り忘れると、いちばん見せてはいけないものが出る側に倒れるため。
2044
+ // **夜間 run の項目は、下の「自動化パイプライン」節が同じ run を出している。**
2045
+ // 両方に出すと、同じ失敗が1画面に2回並ぶ。実行状況はパイプライン節に任せ、
2046
+ // ここでは直し方だけをその行に添える(下の renderPipelines で使う)
2047
+ var PIPE_CHECK = { "update-gold": "nightly_decisionlog", "sync-backlog": "nightly_backlog", "sync-designs": "figma_sync" };
2048
+ var CHECK_CAP = {
2049
+ backlog_secrets: "課題管理", backlog_synced: "課題管理",
2050
+ meeting_minutes: "会議",
2051
+ channels_json: "チャット",
2052
+ figma_token: "デザイン", figma_inventory: "デザイン",
2053
+ submodules: "開発", dev_issues_derived: "開発",
2054
+ };
2055
+ var allChecks = (fleetVal("checks") || []).filter(function (c) {
2056
+ return c != null && c.status === "missing";
2057
+ });
2058
+ // **タイルに出せたものを覚えておく。** 振り分け先の能力タイルが立たない案件
2059
+ //(tools に宣言が無い・行も無い)では出す場所が無くなり、項目が**黙って消える**。
2060
+ // 消えた分は下の節へ落とす——振り分けを間違えても、消えるよりは出る方がよい
2061
+ var shownOnTile = {};
2062
+ function checksFor(cap) {
2063
+ return allChecks.filter(function (c) { return CHECK_CAP[c.id] === cap; });
2064
+ }
2065
+ /** 残りの1件を、直し方まで含めて1行にする */
2066
+ function checkLine(c) {
2067
+ var row = el("div", { class: "ds-check" });
2068
+ row.appendChild(el("span", { class: "ds-check-label", text: c.label }));
2069
+ if (c.action) row.appendChild(el("span", { class: "ds-check-action", text: c.action }));
2070
+ // **detail は内部値が入ることがある**("none" / "success")。読めるものだけ出す
2071
+ if (c.detail && !/^(none|success|failure|skipped|unknown)$/.test(c.detail)) {
2072
+ row.appendChild(el("span", { class: "ds-check-detail", text: c.detail }));
2073
+ }
2074
+ return row;
2075
+ }
2076
+
1960
2077
  /** タイルの2行目(状態と読み取り範囲)。**件数は出せる能力だけ出す** */
1961
2078
  function tileSub(cap, st) {
1962
2079
  var internal = internals.filter(function (s) { return s.kind === cap; })[0];
@@ -2066,6 +2183,18 @@ ${capabilityState.toString()}
2066
2183
  if (tools[cap] !== "none" && sk && (SITE.secretKinds || []).indexOf(sk) >= 0 && !((fleetVal("secretSources") || {})[sk])) {
2067
2184
  body.appendChild(el("div", { class: "ds-tile-note", text: "⚠ トークンが未設定です" }));
2068
2185
  }
2186
+ // セットアップの残りのうち、この能力のもの。**鍵の注記と同じ位置**に出して
2187
+ // 「何が足りないか」と「何をすればよいか」を同じ場所で読めるようにする
2188
+ checksFor(cap).forEach(function (c) {
2189
+ // **直し方が無いものはタイルに出さないが、出したことにもしない。**
2190
+ // shownOnTile を先に立てると節からも外れ、画面のどこにも出なくなる
2191
+ //(実データで mitsubishi の nightly_backlog / figma_token、verdy の
2192
+ // nightly_backlog が消えていた)。タイルは状態を読む場所なので
2193
+ //「足りない」だけの行では埋めず、節の側で拾う
2194
+ if (!c.action) return;
2195
+ shownOnTile[c.id] = true;
2196
+ body.appendChild(el("div", { class: "ds-tile-note ds-tile-todo", text: "→ " + c.action }));
2197
+ });
2069
2198
  var tile = el("button", { class: "ds-tile", type: "button", id: "ds-" + cap }, [
2070
2199
  ic,
2071
2200
  body,
@@ -2124,11 +2253,46 @@ ${capabilityState.toString()}
2124
2253
  }
2125
2254
  children.push(el("span", { class: "ds-pipe-label", text: p.label || p.id || "" }));
2126
2255
  if (t) children.push(el("span", { class: "ds-pipe-time", text: "最終成功: " + t }));
2127
- plist.appendChild(el("div", { class: "ds-pipe" }, children));
2256
+ var row = el("div", { class: "ds-pipe" }, children);
2257
+ // **直し方はこの行に添える。** 同じ run の未達を「セットアップの残り」にも出すと、
2258
+ // 同じ失敗が1画面に2回並ぶ。実行状況はここが正本なので、直し方だけを持ってくる
2259
+ var pc = allChecks.filter(function (c) { return c.id === PIPE_CHECK[p.id]; })[0];
2260
+ if (pc && pc.action) {
2261
+ shownOnTile[pc.id] = true;
2262
+ row = el("div", { class: "ds-pipe-wrap" }, [row, el("div", { class: "ds-pipe-todo", text: "→ " + pc.action })]);
2263
+ }
2264
+ plist.appendChild(row);
2128
2265
  });
2129
2266
  sec.appendChild(plist);
2130
2267
  }
2131
2268
 
2269
+ // ---- セットアップの残り(どこにも出せなかったもの)----
2270
+ //
2271
+ // **パイプライン節より後に計算する。** 夜間 run の直し方はその行に添えるので、
2272
+ // 先に計算すると shownOnTile がまだ立っておらず、同じ文が2箇所に出る
2273
+ //
2274
+ // **8/8案件で未達の scaffold_drift が、ここで初めて誰かの目に入る。**
2275
+ // 能力のタイルに居場所が無い項目(基盤・Cortex・シークレット)は、
2276
+ // ここに出さないとどこにも出ない。
2277
+ var loose = allChecks.filter(function (c) { return !shownOnTile[c.id]; });
2278
+ if (loose.length) {
2279
+ sec.appendChild(el("div", { class: "ds-sub", text: "セットアップの残り" }));
2280
+ sec.appendChild(el("p", { class: "ds-note", text: "毎晩の自動チェックで見つかった、まだ済んでいない設定です。" }));
2281
+ var byCat = {};
2282
+ var catOrder = [];
2283
+ loose.forEach(function (c) {
2284
+ var k = c.category || "その他";
2285
+ if (!byCat[k]) { byCat[k] = []; catOrder.push(k); }
2286
+ byCat[k].push(c);
2287
+ });
2288
+ var todo = el("div", { class: "ds-checks" });
2289
+ catOrder.forEach(function (k) {
2290
+ todo.appendChild(el("div", { class: "ds-check-cat", text: k }));
2291
+ byCat[k].forEach(function (c) { todo.appendChild(checkLine(c)); });
2292
+ });
2293
+ sec.appendChild(todo);
2294
+ }
2295
+
2132
2296
  return sec;
2133
2297
  }
2134
2298
  function renderDataSources() {
@@ -2232,6 +2396,18 @@ ${capabilityState.toString()}
2232
2396
  // 宣言で隠すと、動いているのに説明が出ない状態になる。
2233
2397
  if (s.kind === "会議" && s.ingestState === "on") {
2234
2398
  box.appendChild(meetingHowTo());
2399
+ // **改名を頼めない定例のための逃げ道。** 通常は会議名に【合図】を入れてもらうが、
2400
+ // 顧客が主催する定例では改名を頼めない。実際の会議名をそのまま登録して拾う
2401
+ box.appendChild(addForm({
2402
+ title: "+ 会議名をそのまま取り込み対象にする",
2403
+ placeholder: "例: GDO様 定例",
2404
+ requiredNote: "会議名を入力してください。",
2405
+ hint: "合図(【…】)を入れられない会議のための設定です。ここに入れた名前と**完全に一致する**会議だけが取り込まれます(部分一致はしません)。カレンダーに出ている会議名だけを入れてください——日付や「- Gemini によるメモ」のような後ろに付く文字列を含めると、どの会議とも一致しません。Bot の招待は別途必要です。",
2406
+ confirmLines: function (v) {
2407
+ return ["この名前の会議を取り込み対象にします。", "", v, "", "追加しますか?"];
2408
+ },
2409
+ build: function (alias) { return { op: "add-meeting-alias", alias: alias }; },
2410
+ }));
2235
2411
  used = true;
2236
2412
  } else if (s.kind === "会議" && usable("会議", "google-meet")) {
2237
2413
  if (s.ingestState === "unset") {
@@ -2249,6 +2425,46 @@ ${capabilityState.toString()}
2249
2425
  }
2250
2426
  }
2251
2427
 
2428
+ // 課題管理: 接続先(ドメイン・プロジェクトキー)をURL1本で設定する。
2429
+ // **URLを貼らせる。** ドメインとキーを別々に入れさせると「スペースID」
2430
+ // 「プロジェクトキー」「プロジェクト名」の区別が付かず取り違える。
2431
+ // 実データでも cm1.backlog.jp と jleague.backlog.jp が混在している
2432
+ if (s.kind === "課題管理" && usable("課題管理", "backlog")) {
2433
+ // **設定ファイルが無い案件にはフォームを出さない。** 書き込み先が無いので
2434
+ // 貼っても 404 で終わる。三菱電機は tools が backlog なのに
2435
+ // backlog-settings.json が1つも無い(固定IP経由の同期で、UIからの投入は
2436
+ // 鍵と同じく対応していない)。会議・共有資料は unset / broken を文言で
2437
+ // 伝えてフォームを出さない形なので、課題管理だけ不揃いだった
2438
+ if (!s.url) {
2439
+ box.appendChild(el("p", { class: "sec-how", text: "この案件の課題管理の設定ファイル(backlog-settings.json)がまだありません。先に初回の同期を実行するか、担当者にご連絡ください。" }));
2440
+ used = true;
2441
+ } else box.appendChild(addForm({
2442
+ title: "接続先を変更",
2443
+ placeholder: "https://<スペース>.backlog.jp/projects/<プロジェクトキー>",
2444
+ requiredNote: "BacklogのURLを入力してください(プロジェクトキーが入った形。数字だけのURLは受け付けません)。",
2445
+ hint: "Backlog でこの案件のプロジェクトを開き、ブラウザのURLをそのまま貼ってください(課題の画面のURLでも構いません)。APIキーは下の「Backlog のAPIキー」から別に登録します。",
2446
+ confirmLines: function (v) {
2447
+ // **解析した結果を見せる。** 貼ったURLをそのまま出すと、どのプロジェクトを
2448
+ // 指すことになるかが確定前に分からない。実際 /projects/PJ-CORTEX は
2449
+ // ハイフンで切れて PJ と解釈される(黙って別プロジェクトを指す)
2450
+ var t = backlogTargetOf(v);
2451
+ return [
2452
+ "この案件が同期する Backlog プロジェクトを設定します。",
2453
+ "",
2454
+ "別のプロジェクトを指すと、次の同期で別案件の課題が入ります。",
2455
+ "",
2456
+ t ? t.domain + " / " + t.projectKey : v,
2457
+ "",
2458
+ "※ 変わるのは同期先だけです。ビューアからの起票先と Webhook の配送先は別途の対応が要ります。",
2459
+ "",
2460
+ "設定しますか?",
2461
+ ];
2462
+ },
2463
+ build: function (url) { return { op: "set-backlog-target", url: url }; },
2464
+ }));
2465
+ used = true;
2466
+ }
2467
+
2252
2468
  if (s.kind === "共有資料" && usable("共有資料", "google-drive")) {
2253
2469
  if (s.driveState === "unset") {
2254
2470
  box.appendChild(el("p", { class: "sec-how", text: "資料の同期設定がこのリポジトリにありません(materials-config.json)。先に設置が必要です。" }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takagaki/cortex-decisions-viewer",
3
- "version": "0.4.62",
3
+ "version": "0.4.64",
4
4
  "description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,