@takagaki/cortex-decisions-viewer 0.12.199 → 0.12.210

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.
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // engine-src/supersedes-index.mjs
31
+ var supersedes_index_exports = {};
32
+ __export(supersedes_index_exports, {
33
+ SHADOW_SAMPLE_IDS: () => SHADOW_SAMPLE_IDS,
34
+ compareSupersedes: () => compareSupersedes,
35
+ decisionDateOf: () => decisionDateOf,
36
+ decisionKeyOf: () => decisionKeyOf,
37
+ legacyRetiredTargetsOf: () => legacyRetiredTargetsOf,
38
+ legacySupersededBy: () => legacySupersededBy,
39
+ legacySupersedesIndex: () => legacySupersedesIndex,
40
+ retiredIdsOf: () => retiredIdsOf,
41
+ splitSupersededBy: () => splitSupersededBy,
42
+ supersedesIndex: () => supersedesIndex,
43
+ supersedesIndexStateOf: () => supersedesIndexStateOf,
44
+ supersedesOf: () => supersedesOf,
45
+ supersedesShadowSummaryLines: () => supersedesShadowSummaryLines
46
+ });
47
+ module.exports = __toCommonJS(supersedes_index_exports);
48
+ var import_node_path = __toESM(require("node:path"), 1);
49
+
50
+ // engine-src/confirmed.mjs
51
+ var DRAFT_STATUS_V1 = "draft";
52
+ var CONFIRMED_STATUSES_V1 = Object.freeze({
53
+ Decisions: Object.freeze(["active"]),
54
+ Rules: Object.freeze(["active"]),
55
+ Glossary: Object.freeze(["active", "superseded"]),
56
+ Members: Object.freeze(["active", "inactive"])
57
+ });
58
+ var CONFIRMED_STATUSES_ANY_V1 = Object.freeze(["active", "superseded", "inactive"]);
59
+ function sectionOfPath(p) {
60
+ const s = typeof p === "string" ? p.replace(/\\/g, "/") : "";
61
+ for (const section of Object.keys(CONFIRMED_STATUSES_V1)) {
62
+ if (s.startsWith(`Memory/${section}/`) || s.includes(`/Memory/${section}/`)) return section;
63
+ }
64
+ return null;
65
+ }
66
+ function checked(status) {
67
+ if (status === null || status === void 0 || typeof status === "string") return status;
68
+ throw new TypeError(`confirmed: status \u306F\u6587\u5B57\u5217\u3067\u6E21\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5B9F\u969B: ${typeof status}\uFF09`);
69
+ }
70
+ var HANDS = null;
71
+ var REPORT = null;
72
+ var CREATED = /* @__PURE__ */ new Set();
73
+ var HANDS_OPS = Object.freeze(["own", "rewrite", "append"]);
74
+ var HANDS_STATES = Object.freeze(["on", "shadow"]);
75
+ var noStatus = (s) => s === void 0 || s === null || s === "";
76
+ function handsPathOf(p) {
77
+ if (typeof p !== "string" || !p) return null;
78
+ const s = p.normalize("NFC").replace(/\\/g, "/");
79
+ if (s.startsWith("Memory/")) return s;
80
+ let at = -1;
81
+ for (const m2 of s.matchAll(/(?:^|\/)(Memory\/(?:Decisions|Rules|Glossary|Members)\/)/g)) at = m2.index + m2[0].length - m2[1].length;
82
+ if (at >= 0) return s.slice(at);
83
+ const m = /(?:^|\/)(Memory\/.+)$/.exec(s);
84
+ return m ? m[1] : s;
85
+ }
86
+ function lockIn(h, p) {
87
+ const k = handsPathOf(p);
88
+ if (!k) return true;
89
+ const rec = h.records.get(k);
90
+ if (rec) return h.allLock ? true : rec.lock;
91
+ return !CREATED.has(k);
92
+ }
93
+ function touchedIn(h, p) {
94
+ const k = handsPathOf(p);
95
+ const rec = k ? h.records.get(k) : null;
96
+ return Boolean(rec && rec.touched);
97
+ }
98
+ var note = (name, p) => {
99
+ if (REPORT) REPORT[name].add(handsPathOf(p) ?? String(p));
100
+ };
101
+ var legacyMachine = (s) => s === DRAFT_STATUS_V1;
102
+ function legacyHuman(p, s) {
103
+ if (typeof s !== "string") return false;
104
+ const section = sectionOfPath(p);
105
+ return (section ? CONFIRMED_STATUSES_V1[section] : CONFIRMED_STATUSES_ANY_V1).includes(s);
106
+ }
107
+ function machineOwned(p, status) {
108
+ const s = checked(status);
109
+ const before = legacyMachine(s);
110
+ if (!HANDS) return before;
111
+ const locked = lockIn(HANDS, p);
112
+ const after = (before || noStatus(s)) && !locked;
113
+ if (before && locked) note("draft_lock", p);
114
+ if (before && !after) note("own_blocked", p);
115
+ if (!before && after) note("own_opened", p);
116
+ return HANDS.state === "on" ? after : before;
117
+ }
118
+ function humanOwned(p, status) {
119
+ const s = checked(status);
120
+ const before = legacyHuman(p, s);
121
+ if (!HANDS || !noStatus(s)) return before;
122
+ const after = touchedIn(HANDS, p);
123
+ if (after) note("human_touched", p);
124
+ return HANDS.state === "on" ? after : before;
125
+ }
126
+ var STATUS_VIEW = Object.freeze({ humanOwned, machineOwned });
127
+
128
+ // engine-src/supersedes-index.mjs
129
+ var DECISIONS_ANCHOR = "Memory/Decisions/records/";
130
+ function decisionKeyOf(ref) {
131
+ return import_node_path.default.basename(String(ref ?? "").trim().replace(/^decision:/, ""), ".md");
132
+ }
133
+ function decisionDateOf(date, id) {
134
+ const raw = String(date ?? "").trim();
135
+ const ymd = raw.match(/^(\d{4})-?(\d{2})-?(\d{2})/) || decisionKeyOf(id).match(/^(\d{4})(\d{2})(\d{2})/);
136
+ return ymd ? `${ymd[1]}-${ymd[2]}-${ymd[3]}` : "";
137
+ }
138
+ var normalize = (d) => {
139
+ if (!d || typeof d !== "object") return null;
140
+ const id = String(d.id ?? "").trim();
141
+ if (!id) return null;
142
+ return {
143
+ id,
144
+ key: decisionKeyOf(id),
145
+ date: decisionDateOf(d.date, id),
146
+ status: typeof d.status === "string" ? d.status.trim() : "",
147
+ // 口(`confirmed.mjs`)へ渡すだけ(逆引きの出力には載せない・tools の写しの契約は変わらない)
148
+ path: typeof d.path === "string" && d.path.includes("Memory/Decisions/") ? d.path : DECISIONS_ANCHOR,
149
+ supersedes: (Array.isArray(d.supersedes) ? d.supersedes : []).map(decisionKeyOf).filter(Boolean)
150
+ };
151
+ };
152
+ var newestFirst = (a, b) => {
153
+ if (a.date !== b.date) {
154
+ if (!a.date) return 1;
155
+ if (!b.date) return -1;
156
+ return a.date < b.date ? 1 : -1;
157
+ }
158
+ return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
159
+ };
160
+ function supersedesIndex(decisions, { view: _view = STATUS_VIEW } = {}) {
161
+ const list = [...decisions instanceof Map ? decisions.values() : decisions || []].map(normalize).filter(Boolean);
162
+ const byKey = /* @__PURE__ */ new Map();
163
+ for (const d of list) if (!byKey.has(d.key)) byKey.set(d.key, d);
164
+ const out = /* @__PURE__ */ new Map();
165
+ for (const d of list) {
166
+ for (const target of new Set(d.supersedes)) {
167
+ const old = byKey.get(target);
168
+ if (!old || old.key === d.key) continue;
169
+ if (d.date && old.date && d.date < old.date) continue;
170
+ const entry = out.get(old.key) || { id: old.id, by: [], retired: false };
171
+ if (entry.by.some((x) => decisionKeyOf(x.id) === d.key)) continue;
172
+ entry.by.push({ id: d.id, date: d.date, status: d.status, confirmed: true });
173
+ entry.retired = true;
174
+ out.set(old.key, entry);
175
+ }
176
+ }
177
+ for (const entry of out.values()) entry.by.sort(newestFirst);
178
+ return out;
179
+ }
180
+ function supersedesOf(index, id) {
181
+ return index.get(decisionKeyOf(id)) || { id: String(id ?? ""), by: [], retired: false };
182
+ }
183
+ function retiredIdsOf(index) {
184
+ return new Set([...index.values()].filter((e) => e.retired).map((e) => e.id));
185
+ }
186
+ function splitSupersededBy(entry) {
187
+ const by = entry && Array.isArray(entry.by) ? entry.by : [];
188
+ return {
189
+ confirmed: by.filter((x) => x.confirmed).map((x) => x.id),
190
+ unconfirmed: by.filter((x) => !x.confirmed).map((x) => x.id)
191
+ };
192
+ }
193
+ function supersedesIndexStateOf() {
194
+ return "on";
195
+ }
196
+ function legacySupersedesIndex(records) {
197
+ const out = /* @__PURE__ */ new Map();
198
+ for (const r of records || []) {
199
+ if (!r) continue;
200
+ for (const target of Array.isArray(r.supersedes) ? r.supersedes : []) {
201
+ out.set(target, [...out.get(target) || [], r.id].filter(Boolean));
202
+ }
203
+ }
204
+ return out;
205
+ }
206
+ function legacySupersededBy(index, id) {
207
+ return [...new Set(id ? index.get(id) || [] : [])].sort();
208
+ }
209
+ function legacyRetiredTargetsOf(records) {
210
+ const out = /* @__PURE__ */ new Set();
211
+ for (const target of legacySupersedesIndex(records).keys()) {
212
+ const t = String(target ?? "").trim();
213
+ if (t) out.add(t);
214
+ }
215
+ return out;
216
+ }
217
+ var SHADOW_SAMPLE_IDS = 5;
218
+ function compareSupersedes(decisions) {
219
+ const list = [...decisions || []].filter((d) => d && String(d.id ?? "").trim());
220
+ const ids = new Set(list.map((d) => String(d.id).trim()));
221
+ const legacyIndex = legacySupersedesIndex(list);
222
+ const legacy = new Set([...ids].filter((id) => legacySupersededBy(legacyIndex, id).length));
223
+ const next = retiredIdsOf(supersedesIndex(list));
224
+ return {
225
+ legacyRetired: legacy.size,
226
+ nextRetired: next.size,
227
+ revived: [...legacy].filter((id) => !next.has(id)).sort(),
228
+ newlyRetired: [...next].filter((id) => !legacy.has(id)).sort()
229
+ };
230
+ }
231
+ function supersedesShadowSummaryLines({ state, diff, labelChanges = 0, freshnessRows = null }) {
232
+ if (state !== "shadow" || !diff) return [];
233
+ const sample = (ids) => ids.slice(0, SHADOW_SAMPLE_IDS).map((id) => `\`${id}\``).join("\u30FB") + (ids.length > SHADOW_SAMPLE_IDS ? ` \u307B\u304B ${ids.length - SHADOW_SAMPLE_IDS} \u4EF6` : "");
234
+ return [
235
+ `- \u7F6E\u304D\u63DB\u3048\u306E\u9006\u5F15\u304D\uFF08\u6813 shadow\u30FB\u4ECA\u307E\u3067\u306E\u898F\u5247\u3067\u8AAD\u3093\u3067\u3044\u307E\u3059\uFF09: \u7F6E\u304D\u63DB\u3048\u6E08\u307F\u306E\u6C7A\u5B9A \u4ECA **${diff.legacyRetired}** \u4EF6 \u2192 \u65B0\u3057\u3044\u898F\u5247 **${diff.nextRetired}** \u4EF6`,
236
+ ` - \u4EBA\u306E\u624B\u306E\u3042\u308B\u53E4\u3044\u6C7A\u5B9A\u3067\u3001\u7F6E\u304D\u63DB\u3048\u3092\u5019\u88DC\u306B\u7559\u3081\u305F\u6C7A\u5B9A\uFF08\u65B0\u3057\u3044\u898F\u5247\u3067\u306F\u6709\u52B9\u306B\u623B\u308B\uFF09 **${diff.revived.length}** \u4EF6${diff.revived.length ? `: ${sample(diff.revived)}` : ""}`,
237
+ ...diff.newlyRetired.length ? [` - \u65B0\u3057\u3044\u898F\u5247\u3067\u3060\u3051\u7F6E\u304D\u63DB\u3048\u6E08\u307F\u306B\u306A\u308B\u6C7A\u5B9A ${diff.newlyRetired.length} \u4EF6: ${sample(diff.newlyRetired)}`] : [],
238
+ ` - \u62BD\u51FA\u306B\u6E21\u3059\u65E2\u5B58\u306E\u6C7A\u5B9A\u306E\u4E00\u89A7\u3067\u672D\u304C\u5909\u308F\u308B\u884C **${labelChanges}** \u4EF6`,
239
+ ` - \u9BAE\u5EA6\u306E\u5E33\u7C3F\u3067\u5909\u308F\u308B\u884C ${freshnessRows === null ? "\uFF08\u6570\u3048\u3066\u3044\u307E\u305B\u3093\uFF09" : `**${freshnessRows}** \u4EF6`}`
240
+ ];
241
+ }
242
+ // Annotate the CommonJS export names for ESM import in node:
243
+ 0 && (module.exports = {
244
+ SHADOW_SAMPLE_IDS,
245
+ compareSupersedes,
246
+ decisionDateOf,
247
+ decisionKeyOf,
248
+ legacyRetiredTargetsOf,
249
+ legacySupersededBy,
250
+ legacySupersedesIndex,
251
+ retiredIdsOf,
252
+ splitSupersededBy,
253
+ supersedesIndex,
254
+ supersedesIndexStateOf,
255
+ supersedesOf,
256
+ supersedesShadowSummaryLines
257
+ });
@@ -87,6 +87,10 @@ function googleConfirmPageJs() {
87
87
  var statusEl = $("gc-status");
88
88
  var goBtn = $("gc-go");
89
89
  var closeBtn = $("gc-close");
90
+ var busyEl = $("gc-busy");
91
+ var busyTextEl = $("gc-busy-text");
92
+ var busyNoteEl = $("gc-busy-note");
93
+ var pageEl = $("gc-page");
90
94
 
91
95
  var ctx = null;
92
96
  var flow = null;
@@ -98,6 +102,20 @@ function googleConfirmPageJs() {
98
102
  statusEl.textContent = text || "";
99
103
  statusEl.className = "gc-status" + (cls ? " " + cls : "");
100
104
  }
105
+ /** 窓の中全体を「読み込み中」で覆う(保存が終わるまで他の操作をしかけないため)。覆いの間は後ろの画面を操作できない */
106
+ function showBusy(text, note) {
107
+ busyTextEl.textContent = text;
108
+ busyNoteEl.textContent = note || "";
109
+ busyNoteEl.hidden = !note;
110
+ busyEl.hidden = false;
111
+ pageEl.setAttribute("inert", "");
112
+ pageEl.setAttribute("aria-hidden", "true");
113
+ }
114
+ function hideBusy() {
115
+ busyEl.hidden = true;
116
+ pageEl.removeAttribute("inert");
117
+ pageEl.removeAttribute("aria-hidden");
118
+ }
101
119
  function b64urlEncode(text) {
102
120
  return btoa(text).replace(/\\+/g, "-").replace(/\\//g, "_").replace(/=+$/, "");
103
121
  }
@@ -121,6 +139,7 @@ function googleConfirmPageJs() {
121
139
  function succeed(message, extra) {
122
140
  finished = true;
123
141
  busy = false;
142
+ hideBusy();
124
143
  goBtn.hidden = true;
125
144
  closeBtn.hidden = false;
126
145
  setStatus("✓ " + message + "。このウィンドウは閉じて構いません", "is-ok");
@@ -130,6 +149,7 @@ function googleConfirmPageJs() {
130
149
  /** 失敗: 理由を出し、押し直せるように戻す(別のアカウントでやり直す人のため)。本体にも理由を渡す */
131
150
  function retryable(message, extra) {
132
151
  busy = false;
152
+ hideBusy();
133
153
  goBtn.hidden = false;
134
154
  goBtn.disabled = false;
135
155
  goBtn.textContent = "もう一度 Google で確認する";
@@ -140,6 +160,7 @@ function googleConfirmPageJs() {
140
160
  /** 続けられない(本体が見つからない・結果が読めない): 理由と[閉じる]だけ */
141
161
  function dead(message) {
142
162
  busy = false;
163
+ hideBusy();
143
164
  finished = true;
144
165
  goBtn.hidden = true;
145
166
  closeBtn.hidden = false;
@@ -161,6 +182,10 @@ function googleConfirmPageJs() {
161
182
  });
162
183
  });
163
184
  }
185
+ /** 設定の表の案件の追加の意図(契約 §3。旧キー op を持たない)。保存の門(本人の Google)はトークンを添えて通る */
186
+ function intentBody(kind, target) {
187
+ return { v: 1, kind: kind, action: "add", target: target, baseRev: ctx.intent.baseRev, req: ctx.intent.req };
188
+ }
164
189
  function loadInfo() {
165
190
  var intake = ctx.intake;
166
191
  var url = intake.url + (intake.url.indexOf("?") === -1 ? "?" : "&") + "op=google-confirm-info&t=" + encodeURIComponent(intake.token);
@@ -213,7 +238,7 @@ function googleConfirmPageJs() {
213
238
  var g = window.google.picker;
214
239
  var mine = new g.DocsView(g.ViewId.FOLDERS).setIncludeFolders(true).setSelectFolderEnabled(true).setMimeTypes("application/vnd.google-apps.folder");
215
240
  var shared = new g.DocsView(g.ViewId.FOLDERS).setIncludeFolders(true).setSelectFolderEnabled(true).setEnableDrives(true).setMimeTypes("application/vnd.google-apps.folder");
216
- new g.PickerBuilder()
241
+ var picker = new g.PickerBuilder()
217
242
  .setAppId(info.projectNumber)
218
243
  .setDeveloperKey(info.apiKey)
219
244
  .setOAuthToken(accessToken)
@@ -224,8 +249,10 @@ function googleConfirmPageJs() {
224
249
  if (data.action === g.Action.PICKED && data.docs && data.docs[0]) resolve(data.docs[0]);
225
250
  else if (data.action === g.Action.CANCEL) resolve(null);
226
251
  })
227
- .build()
228
- .setVisible(true);
252
+ .build();
253
+ // Picker を操作できるように、出す前に覆いを外す(選ぶ・やめるのあとは、呼び出し側が覆いを戻すか結果を出す)
254
+ hideBusy();
255
+ picker.setVisible(true);
229
256
  });
230
257
  });
231
258
  }
@@ -249,6 +276,7 @@ function googleConfirmPageJs() {
249
276
  goBtn.hidden = true;
250
277
  closeBtn.hidden = true;
251
278
  setStatus("Google の画面へ移動しています…", "");
279
+ showBusy("Google の画面へ移動しています…");
252
280
  var info = null;
253
281
  loadInfo()
254
282
  .then(function (i) {
@@ -275,7 +303,9 @@ function googleConfirmPageJs() {
275
303
  busy = true;
276
304
  goBtn.hidden = true;
277
305
  closeBtn.hidden = true;
306
+ var isDrive = ctx.kind === "drive";
278
307
  setStatus("確認しています…", "");
308
+ showBusy(isDrive ? "Google のフォルダを開いています…" : "確認しています…");
279
309
  var tokens = null;
280
310
  var info = null;
281
311
  Promise.resolve()
@@ -297,13 +327,15 @@ function googleConfirmPageJs() {
297
327
  var body;
298
328
  if (ctx.kind === "drive") {
299
329
  if (!picked) throw { message: "フォルダを選ばずに閉じられました。もう一度押してください" };
330
+ if (ctx.mode === "confirm") showBusy("確認しています…");
331
+ else showBusy("保存しています…", "終わるまでこの窓を閉じずにお待ちください");
300
332
  body = ctx.mode === "confirm"
301
333
  ? { op: "confirm-drive-folder", id: ctx.id, folderId: picked.id }
302
- : { op: "add-drive-folder", folderId: picked.id };
334
+ : ctx.intent ? intentBody("drive", { folderId: picked.id }) : { op: "add-drive-folder", folderId: picked.id };
303
335
  } else {
304
336
  body = ctx.mode === "confirm"
305
337
  ? { op: "confirm-google-chat-space", ref: ctx.id }
306
- : { op: "add-google-chat-space", url: ctx.url };
338
+ : ctx.intent ? intentBody("google-chat", { url: ctx.url }) : { op: "add-google-chat-space", url: ctx.url };
307
339
  }
308
340
  return callIntake(Object.assign(body, tokens));
309
341
  })
@@ -322,13 +354,20 @@ function googleConfirmPageJs() {
322
354
  }
323
355
 
324
356
  /** 本体からの指示(opener か BroadcastChannel)。flow が合うものだけを 1 回だけ受ける */
357
+ /** 設定の表の案件の追加で本体が渡す {baseRev, req}。形が合わなければ null(旧キーの要求に倒す) */
358
+ function intentOf(i) {
359
+ if (!i || typeof i !== "object") return null;
360
+ if (typeof i.baseRev !== "number" || !isFinite(i.baseRev) || i.baseRev < 0 || Math.floor(i.baseRev) !== i.baseRev) return null;
361
+ if (typeof i.req !== "string" || !/^[A-Za-z0-9_-]{8,64}$/.test(i.req)) return null;
362
+ return { baseRev: i.baseRev, req: i.req };
363
+ }
325
364
  function acceptStart(d) {
326
365
  if (!d || d.type !== MSG.start || ctx) return;
327
366
  if (typeof d.flow !== "string" || !FLOW_RE.test(d.flow) || (flow && d.flow !== flow)) return;
328
367
  if (!d.intake || typeof d.intake.url !== "string" || typeof d.intake.token !== "string") return;
329
368
  if (d.kind !== "drive" && d.kind !== "google-chat") return;
330
369
  flow = d.flow;
331
- ctx = { intake: d.intake, ticket: typeof d.ticket === "string" ? d.ticket : null, kind: d.kind, mode: d.mode === "confirm" ? "confirm" : "add", url: typeof d.url === "string" ? d.url : "", id: typeof d.id === "string" ? d.id : "" };
370
+ ctx = { intake: d.intake, ticket: typeof d.ticket === "string" ? d.ticket : null, kind: d.kind, mode: d.mode === "confirm" ? "confirm" : "add", url: typeof d.url === "string" ? d.url : "", id: typeof d.id === "string" ? d.id : "", intent: intentOf(d.intent) };
332
371
  var isDrive = ctx.kind === "drive";
333
372
  var what = isDrive ? "Drive のフォルダ" : "Google Chat のスペース";
334
373
  titleEl.textContent = (ctx.mode === "confirm" ? what + "を確認する" : what + "を追加する");
@@ -365,6 +404,7 @@ function googleConfirmPageJs() {
365
404
  flow = returned.flow;
366
405
  openChannel();
367
406
  setStatus("確認の続きを準備しています…", "");
407
+ showBusy("確認しています…");
368
408
  var asked = 0;
369
409
  var timer = setInterval(function () {
370
410
  if (ctx) { clearInterval(timer); return; }
@@ -398,7 +438,7 @@ function renderGoogleConfirmPage(assets) {
398
438
  <link rel="stylesheet" href="${esc(assets.css)}" />
399
439
  </head>
400
440
  <body class="gc-body">
401
- <main class="gc-page">
441
+ <main id="gc-page" class="gc-page">
402
442
  <h1 id="gc-title" class="gc-title">Google で確認</h1>
403
443
  <p id="gc-lead" class="gc-lead"></p>
404
444
  <p id="gc-status" class="gc-status" role="status" aria-live="polite"></p>
@@ -407,6 +447,13 @@ function renderGoogleConfirmPage(assets) {
407
447
  <button id="gc-close" class="ds-toggle-btn" type="button" hidden>閉じる</button>
408
448
  </div>
409
449
  </main>
450
+ <div id="gc-busy" class="gc-busy" role="status" aria-live="polite" hidden>
451
+ <div class="gc-busy-box">
452
+ <span class="gc-spinner" aria-hidden="true"></span>
453
+ <p id="gc-busy-text" class="gc-busy-text"></p>
454
+ <p id="gc-busy-note" class="gc-busy-note" hidden></p>
455
+ </div>
456
+ </div>
410
457
  <script src="${esc(assets.js)}"></script>
411
458
  </body>
412
459
  </html>`;
@@ -10,6 +10,7 @@ exports.ledgerDirOf = ledgerDirOf;
10
10
  * ビューアが読む帳簿(9 本)の置き場(cortex-engine #1094 便 3-11 の tools(T1))。根拠の台帳(便 B3)は案件リポに置くので、ここを通さず `defaultLedgerDir` から読む(`memory-evidence.ts`)。
11
11
  *
12
12
  * 既定は `<リポジトリルート>/.cortex`(今までと同じ)。`--ledger-dir` で別のフォルダを指せる。
13
+ * 組み直した案件(木に `Memory/Home.md`)は帳簿をここから読まず、記憶側の画面用ファイルだけで組む(`view-dir.ts` の `planViewsV2`・cortex-engine #1911 便 DC-2f)。
13
14
  * ビューアは保管庫(S3)も栓も知らない(AWS SDK を足さない)。どこから持ってくるかは呼び出し側(workflow)の仕事で、
14
15
  * ここは「そのフォルダの下の `<名前>.json` を読む」だけ。
15
16
  *
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MEMORY_DIR_ALT = exports.NEXT_MEMORY_DIR = exports.LEGACY_MEMORY_DIR = void 0;
7
+ exports.memoryDirOfTree = memoryDirOfTree;
8
+ exports.memoryDirOfRoot = memoryDirOfRoot;
9
+ exports.promptInMemoryDir = promptInMemoryDir;
10
+ /**
11
+ * 記憶の置き場の名前(案件リポの直下のフォルダ)の見分け(cortex-engine #1911 便 T-12・設計 §1 T-2 の K4)。
12
+ *
13
+ * ビューアは全案件で 1 つの版しか動かせないので、置き場の名前が違う案件が混ざる間は**木の 1 つの事実**で決める:
14
+ * 木に `Memory/Home.md`(`REBUILT_MARKER`)があれば `Memory`(組み直した案件)、無ければ `Cortex`(今までの案件)。
15
+ * 🔴 今までの案件(`Cortex`)の出力は 1 バイトも変えない(`memoryDir` はキーごと出さない・文字列は元のまま)。
16
+ * 旧名を持つのは tools では `lambda/shared/memory-bridge.mjs` とここだけ(ビューアは lambda を import しないので 1 か所だけ写す)。
17
+ */
18
+ const node_path_1 = __importDefault(require("node:path"));
19
+ const config_mode_1 = require("./config-mode");
20
+ exports.LEGACY_MEMORY_DIR = "Cortex";
21
+ exports.NEXT_MEMORY_DIR = "Memory";
22
+ /** 記録・Home のパスの先頭にどちらの置き場が来てもよい形(形だけを見る正規表現の部品。`Cortex` と `Memory` の 2 つだけ) */
23
+ exports.MEMORY_DIR_ALT = "(?:Cortex|Memory)";
24
+ /** リポの根(作業ディレクトリ)の木から決める。印は設定の置き場のヒントと同じ 1 つ(`config-mode.ts` の `Memory/Home.md`・通常のファイルのとき) */
25
+ async function memoryDirOfTree(repoRoot) {
26
+ return (await (0, config_mode_1.configModeHint)(repoRoot)) === "table" ? exports.NEXT_MEMORY_DIR : exports.LEGACY_MEMORY_DIR;
27
+ }
28
+ /** 知識の根(`.../Cortex` か `.../Memory`)の名前から。それ以外(旧い Decisions 単独の構成)は `Cortex` */
29
+ function memoryDirOfRoot(knowledgeRoot) {
30
+ return knowledgeRoot !== null && node_path_1.default.basename(knowledgeRoot) === exports.NEXT_MEMORY_DIR ? exports.NEXT_MEMORY_DIR : exports.LEGACY_MEMORY_DIR;
31
+ }
32
+ /**
33
+ * 利用者に渡す起動文の中の置き場の名前を、その案件の名前に替える。`Cortex` のときは**そのまま返す**(1 バイトも変えない)。
34
+ * 替えるのは置き場の中の既知のもの(区画・Home・設定 3 種)だけ——製品名の `Cortex` や `Cortex/Runner` のような別物には触らない。
35
+ */
36
+ function promptInMemoryDir(text, dir) {
37
+ if (dir === exports.LEGACY_MEMORY_DIR)
38
+ return text;
39
+ return text.replace(/\bCortex\/(?=(?:Decisions|Glossary|Members|Rules|Story|Home\.md|sources\.json|notify\.json|viewer-config\.json)\b)/g, `${dir}/`);
40
+ }
@@ -24,6 +24,8 @@ exports.orderByActivity = orderByActivity;
24
24
  * | `.cortex/gold-activity.json` | 「最後に見た日」と触れた日の列(+観測の到達点 `cursor`) | 夜間(追記・剪定つき) |
25
25
  * | `.cortex/gold-term-strength.json` | 用語ごとの強さ(場面の数・使った人の数・資料の下地)と栓の状態 `state`(#790・engine #727) | 夜間(全置換) |
26
26
  *
27
+ * 確認の帳簿と再導出の帳簿は**組み直していない案件(v1)だけ**読む(組み直した案件は書き手が無い・cortex-engine #1911 便 DC-2f・`opts.v2`)。
28
+ *
27
29
  * 形の正本は cortex-engine `scripts/rederive/ledgers.mjs` と `docs/cortex-derived-files.md`
28
30
  * (強さの帳簿は `scripts/gold/term-gate.mjs` の `strengthLedgerOf`)。
29
31
  *
@@ -48,7 +50,7 @@ const ledger_dir_1 = require("./ledger-dir");
48
50
  /** 帳簿の版(違ったら空として扱う・engine `LEDGER_VERSION`) */
49
51
  exports.LEDGER_VERSION = 1;
50
52
  /** 並びを変える区画。**用語集だけ**(関係者の並びは関与の帳簿で `engagement.ts` が決める・便 14b) */
51
- const ORDER_SECTION_RE = /^Cortex\/Glossary\/records\/[^/]+\.md$/;
53
+ const ORDER_SECTION_RE = /^(?:Cortex|Memory)\/Glossary\/records\/[^/]+\.md$/;
52
54
  /** ACT-R base-level の減衰(#432 裁定 5-5: d = 0.5) */
53
55
  const ACTR_DECAY = 0.5;
54
56
  /**
@@ -122,13 +124,8 @@ async function readOne(ledgerDir, file, then = "帯と並びは出さずに続
122
124
  return parsed;
123
125
  }
124
126
  const asRecord = (v) => v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
125
- /**
126
- * 3 帳簿を読む。**フィールドは明示で列挙し、素通しはしない**(知らない欄を画面へ素通しにしない流儀)——
127
- * engine は単独で版を上げるので、画面が知らないキーが必ず先に入る。
128
- */
129
- async function readRederivationLedgers(repoRoot, ledgerDirArg) {
130
- const ledgerDir = (0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDirArg);
131
- const out = (0, exports.emptyLedgers)();
127
+ /** 確認の帳簿(`gold-confirmation`)と再導出の帳簿(`gold-rederivation`)を読む(v1 の案件だけ・`readRederivationLedgers`) */
128
+ async function readConfirmationAndRederivation(ledgerDir, out) {
132
129
  const conf = await readOne(ledgerDir, "gold-confirmation.json");
133
130
  const records = asRecord(conf?.records);
134
131
  if (records) {
@@ -194,6 +191,18 @@ async function readRederivationLedgers(repoRoot, ledgerDirArg) {
194
191
  }
195
192
  }
196
193
  }
194
+ }
195
+ /**
196
+ * 3 帳簿を読む。**フィールドは明示で列挙し、素通しはしない**(知らない欄を画面へ素通しにしない流儀)——
197
+ * engine は単独で版を上げるので、画面が知らないキーが必ず先に入る。
198
+ */
199
+ async function readRederivationLedgers(repoRoot, ledgerDirArg, opts = {}) {
200
+ const ledgerDir = (0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDirArg);
201
+ const out = (0, exports.emptyLedgers)();
202
+ // 🔴 確認の帳簿と再導出の帳簿は**組み直していない案件(v1)だけ**読む(v1 の画面の再導出の帯・確認の版に戻すが今も使う)。
203
+ // 組み直した案件(v2・木に `Memory/Home.md`)では書き手が無い(便 V1N)ので読まない(cortex-engine #1911 便 DC-2f・設計書 7 章 K32・消す日は全案件 v2)
204
+ if (opts.v2 !== true)
205
+ await readConfirmationAndRederivation(ledgerDir, out);
197
206
  const act = await readOne(ledgerDir, "gold-activity.json");
198
207
  const actSections = asRecord(act?.sections);
199
208
  if (actSections) {