@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.
- package/README.md +4 -2
- package/dist/build.js +64 -83
- package/dist/canonical-evidence.js +11 -191
- package/dist/change-log.js +1 -1
- package/dist/config-flow.js +462 -0
- package/dist/config-mode.js +57 -0
- package/dist/confirmed.js +2 -2
- package/dist/engine/decision-v2-fields.js +188 -0
- package/dist/engine/ref-tokens.js +276 -0
- package/dist/engine/related-materials-field.js +148 -0
- package/dist/engine/supersedes-index.js +257 -0
- package/dist/google-confirm-page.js +54 -7
- package/dist/ledger-dir.js +1 -0
- package/dist/memory-dir.js +40 -0
- package/dist/rederivation.js +17 -8
- package/dist/render.js +905 -74
- package/dist/story.js +13 -9
- package/dist/supersedes.js +12 -110
- package/dist/view-dir.js +100 -2
- package/package.json +2 -2
package/dist/story.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.STORY_DIGEST_EMPTY_LINE = exports.STORY_MAX_MONTHS = exports.STORY_MAX_WEEKS = exports.STORY_MONTHS_DIR = exports.STORY_WEEKS_DIR = exports.NIGHT_CUTOFF_HOURS = exports.STORY_NIGHT_CUT_HOUR = exports.STORY_LINK_MIN_NAME = exports.STORY_LINK_KINDS = exports.STORY_MAX_FILE_BYTES = exports.STORY_COLLAPSE_QUIET_DAYS = exports.STORY_EMPTY_LINE = exports.STORY_MAX_DAYS = exports.
|
|
6
|
+
exports.STORY_DIGEST_EMPTY_LINE = exports.STORY_MAX_MONTHS = exports.STORY_MAX_WEEKS = exports.STORY_MONTHS_DIR = exports.STORY_WEEKS_DIR = exports.NIGHT_CUTOFF_HOURS = exports.STORY_NIGHT_CUT_HOUR = exports.STORY_LINK_MIN_NAME = exports.STORY_LINK_KINDS = exports.STORY_MAX_FILE_BYTES = exports.STORY_COLLAPSE_QUIET_DAYS = exports.STORY_EMPTY_LINE = exports.STORY_MAX_DAYS = exports.STORY_LEDGER_FILE = void 0;
|
|
7
7
|
exports.parseStoryLedger = parseStoryLedger;
|
|
8
8
|
exports.partialDaysOf = partialDaysOf;
|
|
9
9
|
exports.onDaysOf = onDaysOf;
|
|
@@ -54,7 +54,8 @@ const node_fs_1 = require("node:fs");
|
|
|
54
54
|
const node_path_1 = __importDefault(require("node:path"));
|
|
55
55
|
const ledger_dir_1 = require("./ledger-dir");
|
|
56
56
|
exports.STORY_LEDGER_FILE = "story-days.json";
|
|
57
|
-
|
|
57
|
+
/** ストーリーの置き場(`Cortex` のときは上の定数と同じ綴り)。置き場の名前は木で決まる(`memory-dir.ts`) */
|
|
58
|
+
const storyDir = (memoryDir, leaf) => `${memoryDir}/Story/${leaf}`;
|
|
58
59
|
/** 載せる日の上限(新しい日から。分類 B・約 3 か月) */
|
|
59
60
|
exports.STORY_MAX_DAYS = 90;
|
|
60
61
|
const DAY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
@@ -521,7 +522,7 @@ function linkRecordRefs(html, dayRepoPath, idOf) {
|
|
|
521
522
|
}
|
|
522
523
|
catch { /* 解けない綴りはそのまま照合して見つからなければ文字に落とす */ }
|
|
523
524
|
const resolved = target.startsWith("/") ? node_path_1.default.posix.normalize(target.slice(1)) : node_path_1.default.posix.join(baseDir, target);
|
|
524
|
-
const id = /^Cortex\/[^/]+\/records\/[^/]+\.md$/.test(resolved) ? idOf(resolved) : undefined;
|
|
525
|
+
const id = /^(?:Cortex|Memory)\/[^/]+\/records\/[^/]+\.md$/.test(resolved) ? idOf(resolved) : undefined;
|
|
525
526
|
if (!id)
|
|
526
527
|
return inner;
|
|
527
528
|
const attr = id.replace(/&/g, "&").replace(/"/g, """);
|
|
@@ -543,14 +544,17 @@ ledgerDir,
|
|
|
543
544
|
// 日の `relations` の target から名前のリンクの表を作る口(build が記録の表を握って渡す。無ければリンクは付けない)
|
|
544
545
|
linksOf = () => [],
|
|
545
546
|
// 本文の相対リンクが指す記録(リポジトリ相対パス)の id。画面にある記録だけ返す(無ければリンクは文字に落とす)
|
|
546
|
-
recordIdOf = () => undefined
|
|
547
|
+
recordIdOf = () => undefined,
|
|
548
|
+
// 記憶の置き場の名前(既定は今までの `Cortex`)
|
|
549
|
+
memoryDir = "Cortex") {
|
|
547
550
|
const ledger = await loadStoryLedger(repoRoot, true, ledgerDir);
|
|
548
551
|
if (!ledger)
|
|
549
552
|
return null;
|
|
550
553
|
const on = onDaysOf(ledger);
|
|
551
554
|
if (!on.size)
|
|
552
555
|
return null;
|
|
553
|
-
const
|
|
556
|
+
const daysDir = storyDir(memoryDir, "Days");
|
|
557
|
+
const root = node_path_1.default.join(repoRoot, daysDir);
|
|
554
558
|
let months;
|
|
555
559
|
try {
|
|
556
560
|
months = (await node_fs_1.promises.readdir(root, { withFileTypes: true })).filter((d) => d.isDirectory() && MONTH_RE.test(d.name)).map((d) => d.name);
|
|
@@ -582,7 +586,7 @@ recordIdOf = () => undefined) {
|
|
|
582
586
|
catch {
|
|
583
587
|
continue;
|
|
584
588
|
}
|
|
585
|
-
files.push({ day: day, abs: abs, rel: `${
|
|
589
|
+
files.push({ day: day, abs: abs, rel: `${daysDir}/${m}/${n}` });
|
|
586
590
|
}
|
|
587
591
|
}
|
|
588
592
|
files.sort((a, b) => (a.day < b.day ? 1 : a.day > b.day ? -1 : 0));
|
|
@@ -733,7 +737,7 @@ const isMonth = (key) => MONTH_RE.test(key) && Number(key.slice(5, 7)) >= 1 && N
|
|
|
733
737
|
*
|
|
734
738
|
* @param today 日本時間の今日(画面の「今週」の終わり。テストは時計を注入する)
|
|
735
739
|
*/
|
|
736
|
-
async function readStoryDigest(repoRoot, renderMarkdown, editUrlOf = () => null, today = storyTodayJst(), ledgerDir) {
|
|
740
|
+
async function readStoryDigest(repoRoot, renderMarkdown, editUrlOf = () => null, today = storyTodayJst(), ledgerDir, memoryDir = "Cortex") {
|
|
737
741
|
const ledger = await loadStoryLedger(repoRoot, false, ledgerDir);
|
|
738
742
|
if (!ledger)
|
|
739
743
|
return null;
|
|
@@ -763,8 +767,8 @@ async function readStoryDigest(repoRoot, renderMarkdown, editUrlOf = () => null,
|
|
|
763
767
|
}
|
|
764
768
|
return out;
|
|
765
769
|
};
|
|
766
|
-
const weeks = await load(
|
|
767
|
-
const months = await load(
|
|
770
|
+
const weeks = await load(storyDir(memoryDir, "Weeks"), isMonday, exports.STORY_MAX_WEEKS, storyWeekHeading);
|
|
771
|
+
const months = await load(storyDir(memoryDir, "Months"), isMonth, exports.STORY_MAX_MONTHS, storyMonthHeading);
|
|
768
772
|
if (!weeks.length && !months.length)
|
|
769
773
|
return null;
|
|
770
774
|
return { today: today, weeks: weeks, months: months };
|
package/dist/supersedes.js
CHANGED
|
@@ -1,115 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.decisionKeyOf =
|
|
7
|
-
exports.decisionDateOf = decisionDateOf;
|
|
8
|
-
exports.supersedesIndex = supersedesIndex;
|
|
9
|
-
exports.supersedesOf = supersedesOf;
|
|
10
|
-
exports.retiredIdsOf = retiredIdsOf;
|
|
3
|
+
exports.supersedesOf = exports.supersedesIndex = exports.retiredIdsOf = exports.decisionKeyOf = exports.decisionDateOf = void 0;
|
|
11
4
|
/**
|
|
12
|
-
* 決定の置き換え(`supersedes`)の逆引き(cortex-engine #699 F3・#1094 段 4 の 4-1
|
|
5
|
+
* 決定の置き換え(`supersedes`)の逆引き(cortex-engine #699 F3・#1094 段 4 の 4-1)の viewer の入口。
|
|
13
6
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* (tools は `test/fixtures/`)を置き、`test/supersedes-index-parity.test.mjs` が全ケースを流す。
|
|
19
|
-
* 規則を変えるときは engine の正本・この写し・題材を同じ日に直す(**tools 側で規則を足さない**)。
|
|
20
|
-
*
|
|
21
|
-
* ## 規則(2026-10-04 のオーナー決定を、2026-10-06 に engine #1311 で替えた)
|
|
22
|
-
*
|
|
23
|
-
* 1. 置き換えの正本は**新しい側の `relations[supersedes]` だけ**。古い側の `superseded_by`
|
|
24
|
-
* (engine の夜間の精製が書く写し)は逆引きの材料にしない
|
|
25
|
-
* 2. **確定した置き換え(`confirmed`)=新しい側が古い側を置き換えると書いている全部**(人の手の有無を問わない・
|
|
26
|
-
* engine #1311)。10/4 の「人が手を入れた古い決定は候補に留める」の例外は外した(候補を確かめる人がいない)。
|
|
27
|
-
* 人の直しを守るのは置き換えを決める書き手の判定で、ここ(逆引き)は人の手を見ない。
|
|
28
|
-
* 出力の形(`by[].confirmed`)は題材の互換のため残す(常に真)
|
|
29
|
-
* 3. **置き換えられた(もう有効でない・retired)=確定した置き換えが 1 本以上**
|
|
30
|
-
* 4. 置き換え先は**全部・新しい順**(決定日の降順 → ID の降順・同じ ID は 1 回)
|
|
31
|
-
* 5. 自分自身を指す・実在しない ID は数えない
|
|
32
|
-
* 6. **新しい側の決定日が古い側の決定日より前なら数えない**(`decision.supersede-direction`・向きが逆の置き換えは成り立たない)。
|
|
33
|
-
* 同じ日は数える。どちらかの日が読めないときも数える(engine の規則 6 と同じ)
|
|
34
|
-
*/
|
|
35
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
36
|
-
/**
|
|
37
|
-
* 決定を指す文字列を突き合わせの鍵にする(`decision:` の頭・パス・`.md` を落とす)。
|
|
38
|
-
* engine は `path.basename`(Linux で走る=posix)なので、ここも posix で固定する
|
|
39
|
-
*/
|
|
40
|
-
function decisionKeyOf(ref) {
|
|
41
|
-
return node_path_1.default.posix.basename(String(ref ?? "").trim().replace(/^decision:/, ""), ".md");
|
|
42
|
-
}
|
|
43
|
-
/** `YYYY-MM-DD`。frontmatter の `date`(`20260910` / `2026-09-10`)→ ID の先頭 8 桁 → 無ければ空 */
|
|
44
|
-
function decisionDateOf(date, id) {
|
|
45
|
-
const raw = String(date ?? "").trim();
|
|
46
|
-
const ymd = raw.match(/^(\d{4})-?(\d{2})-?(\d{2})/) || decisionKeyOf(id).match(/^(\d{4})(\d{2})(\d{2})/);
|
|
47
|
-
return ymd ? `${ymd[1]}-${ymd[2]}-${ymd[3]}` : "";
|
|
48
|
-
}
|
|
49
|
-
function normalize(d) {
|
|
50
|
-
if (!d || typeof d !== "object")
|
|
51
|
-
return null;
|
|
52
|
-
const r = d;
|
|
53
|
-
const id = String(r.id ?? "").trim();
|
|
54
|
-
if (!id)
|
|
55
|
-
return null;
|
|
56
|
-
return {
|
|
57
|
-
id,
|
|
58
|
-
key: decisionKeyOf(id),
|
|
59
|
-
date: decisionDateOf(r.date, id),
|
|
60
|
-
status: typeof r.status === "string" ? r.status.trim() : "",
|
|
61
|
-
supersedes: (Array.isArray(r.supersedes) ? r.supersedes : []).map(decisionKeyOf).filter(Boolean),
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
/** 新しい順(決定日の降順 → ID の降順)。日付の無いものは最後 */
|
|
65
|
-
function newestFirst(a, b) {
|
|
66
|
-
if (a.date !== b.date) {
|
|
67
|
-
if (!a.date)
|
|
68
|
-
return 1;
|
|
69
|
-
if (!b.date)
|
|
70
|
-
return -1;
|
|
71
|
-
return a.date < b.date ? 1 : -1;
|
|
72
|
-
}
|
|
73
|
-
return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* 置き換えの逆引き。
|
|
77
|
-
*
|
|
78
|
-
* @returns `Map<古い決定の鍵, SupersedesEntry>`。置き換えが 1 本も無い決定は入らない
|
|
7
|
+
* 原本は engine を束ねて引く(viewer/engine-src → dist/engine・便 R4): cortex-engine `scripts/gold/supersedes-index.mjs` の
|
|
8
|
+
* `supersedesIndex`・`supersedesOf`・`retiredIdsOf`・`decisionKeyOf`・`decisionDateOf`。規則(新しい側の `relations[supersedes]` だけを
|
|
9
|
+
* 正本にする・確定は常に真・向きが逆なら数えない 等)はここに書かない。
|
|
10
|
+
* 題材は engine から組み立てる `test/fixtures/supersedes-index-contract.json`(`test/supersedes-index-parity.test.mjs` が流す)。
|
|
79
11
|
*/
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
byKey.set(d.key, d);
|
|
87
|
-
const out = new Map();
|
|
88
|
-
for (const d of list) {
|
|
89
|
-
for (const target of new Set(d.supersedes)) {
|
|
90
|
-
const old = byKey.get(target);
|
|
91
|
-
if (!old || old.key === d.key)
|
|
92
|
-
continue; // 実在しない・自分自身
|
|
93
|
-
if (d.date && old.date && d.date < old.date)
|
|
94
|
-
continue; // 規則 6: 新しい側が日付で前なら向きが逆
|
|
95
|
-
const entry = out.get(old.key) || { id: old.id, by: [], retired: false };
|
|
96
|
-
if (entry.by.some((x) => decisionKeyOf(x.id) === d.key))
|
|
97
|
-
continue;
|
|
98
|
-
// 規則 2: 人の手の有無を問わず確定(engine #1311)
|
|
99
|
-
entry.by.push({ id: d.id, date: d.date, status: d.status, confirmed: true });
|
|
100
|
-
entry.retired = true;
|
|
101
|
-
out.set(old.key, entry);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
for (const entry of out.values())
|
|
105
|
-
entry.by.sort(newestFirst);
|
|
106
|
-
return out;
|
|
107
|
-
}
|
|
108
|
-
/** その決定の逆引き(無ければ空の形) */
|
|
109
|
-
function supersedesOf(index, id) {
|
|
110
|
-
return index.get(decisionKeyOf(id)) || { id: String(id ?? ""), by: [], retired: false };
|
|
111
|
-
}
|
|
112
|
-
/** 置き換えられた(確定した置き換えがある)決定の ID の集合 */
|
|
113
|
-
function retiredIdsOf(index) {
|
|
114
|
-
return new Set([...index.values()].filter((e) => e.retired).map((e) => e.id));
|
|
115
|
-
}
|
|
12
|
+
var supersedes_index_1 = require("./engine/supersedes-index");
|
|
13
|
+
Object.defineProperty(exports, "decisionDateOf", { enumerable: true, get: function () { return supersedes_index_1.decisionDateOf; } });
|
|
14
|
+
Object.defineProperty(exports, "decisionKeyOf", { enumerable: true, get: function () { return supersedes_index_1.decisionKeyOf; } });
|
|
15
|
+
Object.defineProperty(exports, "retiredIdsOf", { enumerable: true, get: function () { return supersedes_index_1.retiredIdsOf; } });
|
|
16
|
+
Object.defineProperty(exports, "supersedesIndex", { enumerable: true, get: function () { return supersedes_index_1.supersedesIndex; } });
|
|
17
|
+
Object.defineProperty(exports, "supersedesOf", { enumerable: true, get: function () { return supersedes_index_1.supersedesOf; } });
|
package/dist/view-dir.js
CHANGED
|
@@ -3,19 +3,23 @@ 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_HELD = exports.VIEW_NAMES = void 0;
|
|
6
|
+
exports.VIEW_INDEX_FILE = exports.VIEW_NAMES_V2 = exports.VIEW_HELD = exports.VIEW_NAMES = void 0;
|
|
7
7
|
exports.blobShaOf = blobShaOf;
|
|
8
8
|
exports.isReadableEnvelope = isReadableEnvelope;
|
|
9
9
|
exports.classifyView = classifyView;
|
|
10
|
+
exports.classifyViewV2 = classifyViewV2;
|
|
10
11
|
exports.checkoutGit = checkoutGit;
|
|
11
12
|
exports.planViews = planViews;
|
|
13
|
+
exports.planViewsV2 = planViewsV2;
|
|
14
|
+
exports.mergeViewsV2 = mergeViewsV2;
|
|
12
15
|
exports.mergeLedgerDir = mergeLedgerDir;
|
|
13
16
|
exports.viewCountsLine = viewCountsLine;
|
|
17
|
+
exports.viewCountsLineV2 = viewCountsLineV2;
|
|
14
18
|
/**
|
|
15
19
|
* 記憶 v2 の画面用ファイルの読み口 `--view-dir`(cortex-engine #1094 鎖 3 V10b・確定版 3 章 2)。
|
|
16
20
|
*
|
|
17
21
|
* engine の記憶側の晩の終わりの段 `views`(V10a・`scripts/memory-v2/memory/post.mjs`)が、`.cortex` の帳簿 8 本と順位(段 `ranking`)を
|
|
18
|
-
* 封筒 `{ v:1, name, run, at, commit, blob, text }` に包んで保管庫の `gold
|
|
22
|
+
* 封筒 `{ v:1, name, run, at, commit, blob, text }` に包んで保管庫の `gold/<世代>/c/view/<名前>.json`(旧い世代 `gold/v1/`・組み直した世代 `gold/v2/`)に置き、最後に目次 `view-index.json`
|
|
19
23
|
* (名前ごとに `{ blob, commit, at, absent }`)を置く。workflow(engine の `build-viewer.yml`)がそれを 1 行の `aws s3 sync` で作業場に
|
|
20
24
|
* 取り出し、このビューアに `--view-dir` で渡す。🔴 **ビューアは保管庫を知らないまま**(ほどくのは手元のファイルだけ・AWS SDK を足さない)。
|
|
21
25
|
*
|
|
@@ -35,6 +39,13 @@ exports.viewCountsLine = viewCountsLine;
|
|
|
35
39
|
* - 根拠の台帳(`memory-evidence`・便 B3)は案件リポに置き公開されない(engine の宣言表 `viewer-direct`)。目次の名前に入れず、読み手がいつも `<repo>/.cortex` から読む
|
|
36
40
|
* - 確認の帳簿(`gold-confirmation`・再導出の帯の読み手 `readRederivationLedgers` が読む)は置かれないので、いつも `.cortex` から読む
|
|
37
41
|
* - 名寄せの提案(`gold-proposals`)はビューアが読まなくなった(cortex-engine #1094 B-viewer V4・問いはポータルから)。置かれても使わない
|
|
42
|
+
*
|
|
43
|
+
* ## 組み直した案件(v2・木に `Memory/Home.md`・cortex-engine #1911 便 DC-2f・設計書 D-4)
|
|
44
|
+
*
|
|
45
|
+
* 上の比べと倒れは組み直していない案件(v1)だけ。組み直した案件は `.cortex` が空になる(便 DC-2)ので、`planViewsV2`・`mergeViewsV2` で
|
|
46
|
+
* 封筒を**無条件で採用**し(自分の sha で確かめられれば使う・`classifyViewV2`)、帳簿 8 本(`VIEW_NAMES_V2`)を `.cortex` から読まない。
|
|
47
|
+
* 確認の帳簿・再導出の帳簿は読まない(v1 本体だけが書き、便 V1N で書き手ごと消えた)。根拠の台帳は今どおり案件リポの `.cortex` から読む(上)。
|
|
48
|
+
* 取り出せない・確かめられない晩は**赤**(空の画面を緑で配らない・`build.ts`)
|
|
38
49
|
*/
|
|
39
50
|
const node_child_process_1 = require("node:child_process");
|
|
40
51
|
const node_crypto_1 = require("node:crypto");
|
|
@@ -58,6 +69,11 @@ exports.VIEW_NAMES = Object.freeze([
|
|
|
58
69
|
exports.VIEW_HELD = Object.freeze({
|
|
59
70
|
"gold-confirmation": "人が確認した版と機械の書き直し(再導出の帯の材料・readRederivationLedgers)",
|
|
60
71
|
});
|
|
72
|
+
/**
|
|
73
|
+
* 組み直した案件(v2・木に `Memory/Home.md`)で読む名前(cortex-engine #1911 便 DC-2f・設計書 D-4)。`VIEW_NAMES` から再導出の帳簿
|
|
74
|
+
* (`gold-rederivation`・v1 本体だけが書き、便 V1N で書き手ごと消えた)を除いた 8 本。確認の帳簿(`VIEW_HELD`)も読まない
|
|
75
|
+
*/
|
|
76
|
+
exports.VIEW_NAMES_V2 = Object.freeze(exports.VIEW_NAMES.filter((n) => n !== "gold-rederivation"));
|
|
61
77
|
/** 目次の名前(engine `VIEW_INDEX_NAME`) */
|
|
62
78
|
exports.VIEW_INDEX_FILE = "view-index.json";
|
|
63
79
|
const SHA_RE = /^[0-9a-f]{40}$/;
|
|
@@ -118,6 +134,21 @@ function classifyView({ envelope, expectedName, indexRow, currentBlob, head, isA
|
|
|
118
134
|
return "unverified";
|
|
119
135
|
}
|
|
120
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* 組み直した案件(v2)の 1 本の封筒の分類(cortex-engine #1911 便 DC-2f)。**帳簿の置き場(`.cortex`)と比べない・git を見ない**——v2 の案件では
|
|
139
|
+
* `.cortex` は空になる(便 DC-2)ので、封筒が自分の sha(本文の blob)で確かめられれば使う(`same`)。
|
|
140
|
+
* 形が違う・目次の行が読めない → `unreadable`、名前違い・本文の sha が blob と違う → `unexplained`。
|
|
141
|
+
* 目次と封筒の食い違い(取り出しと公開が重なった)は問わない(封筒が自分で確かめられるので)
|
|
142
|
+
*/
|
|
143
|
+
function classifyViewV2({ envelope, expectedName, indexRow }) {
|
|
144
|
+
if (!indexRow || !isReadableEnvelope(envelope))
|
|
145
|
+
return "unreadable";
|
|
146
|
+
if (envelope.name !== expectedName)
|
|
147
|
+
return "unexplained";
|
|
148
|
+
if (envelope.absent !== true && blobShaOf(envelope.text) !== envelope.blob)
|
|
149
|
+
return "unexplained";
|
|
150
|
+
return "same";
|
|
151
|
+
}
|
|
121
152
|
/** checkout の git(`repoRoot` で呼ぶ)。🔴 投げる口はそのまま投げる(比べの側で unexplained に倒す) */
|
|
122
153
|
function checkoutGit(repoRoot) {
|
|
123
154
|
const git = (args) => (0, node_child_process_1.execFileSync)("git", args, { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
@@ -244,6 +275,69 @@ async function planViews(viewDir, git, baseDir) {
|
|
|
244
275
|
counts[c] += 1;
|
|
245
276
|
return { classes, counts, use };
|
|
246
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* 組み直した案件(v2)の計画(cortex-engine #1911 便 DC-2f・設計書 D-4)。**帳簿の置き場(`.cortex`)も git も見ない**。名前は `VIEW_NAMES_V2` の 8 本。
|
|
280
|
+
* 🔴 **空の画面を緑で配らない**: 目次が無い・壊れている・読む名前が 1 本も無い、封筒が読めない・確かめられない(`unreadable`・`unexplained`。
|
|
281
|
+
* 形の違う目次の行も `unreadable`)が 1 本でもあれば投げる(ビルドを赤にする)。目次に行の無い名前は `missing`(その帳簿は無い=置かない)
|
|
282
|
+
*/
|
|
283
|
+
async function planViewsV2(viewDir) {
|
|
284
|
+
const index = await readIndex(viewDir);
|
|
285
|
+
if (index === null)
|
|
286
|
+
throw new Error(`組み直した案件ですが、記憶側の画面用ファイルの目次(${exports.VIEW_INDEX_FILE})がありません`);
|
|
287
|
+
if (index === "unreadable")
|
|
288
|
+
throw new Error(`組み直した案件ですが、記憶側の画面用ファイルの目次(${exports.VIEW_INDEX_FILE})を読めません`);
|
|
289
|
+
const classes = {};
|
|
290
|
+
const use = {};
|
|
291
|
+
const counts = { total: exports.VIEW_NAMES_V2.length, same: 0, stale: 0, unexplained: 0, unreadable: 0, unverified: 0, missing: 0 };
|
|
292
|
+
const bad = [];
|
|
293
|
+
for (const name of exports.VIEW_NAMES_V2) {
|
|
294
|
+
let c = "missing";
|
|
295
|
+
if (Object.prototype.hasOwnProperty.call(index, name)) {
|
|
296
|
+
const env = await readEnvelope(viewDir, name);
|
|
297
|
+
c = classifyViewV2({ envelope: env, expectedName: name, indexRow: index[name] });
|
|
298
|
+
if (c === "same")
|
|
299
|
+
use[name] = env.absent === true ? null : env.text;
|
|
300
|
+
else
|
|
301
|
+
bad.push(`${name}: ${c}`);
|
|
302
|
+
}
|
|
303
|
+
classes[name] = c;
|
|
304
|
+
counts[c] += 1;
|
|
305
|
+
}
|
|
306
|
+
// 読む名前が 1 本も無い目次は、取り出しか公開が壊れている(記憶側は無い帳簿も「無い」の行で載せる)
|
|
307
|
+
if (counts.missing === counts.total)
|
|
308
|
+
throw new Error(`組み直した案件ですが、記憶側の画面用ファイルの目次(${exports.VIEW_INDEX_FILE})に読む名前が 1 本もありません`);
|
|
309
|
+
if (bad.length > 0)
|
|
310
|
+
throw new Error(`組み直した案件の記憶側の画面用ファイルを確かめられません(${bad.join("・")})`);
|
|
311
|
+
return { classes, counts, use };
|
|
312
|
+
}
|
|
313
|
+
/** 封筒を読む(無い・JSON でない → `null`=読めない) */
|
|
314
|
+
async function readEnvelope(viewDir, name) {
|
|
315
|
+
const text = await readText(node_path_1.default.join(viewDir, `${name}.json`));
|
|
316
|
+
try {
|
|
317
|
+
return text === null ? null : JSON.parse(text);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* 組み直した案件(v2)の置き場を作る: 帳簿の置き場(`.cortex`)を写さず、空の一時フォルダに封筒の本文だけを置く(「無い」の封筒は置かない)。
|
|
325
|
+
* 戻りの `cleanup` で消す
|
|
326
|
+
*/
|
|
327
|
+
async function mergeViewsV2(plan) {
|
|
328
|
+
const dir = await promises_1.default.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), "cortex-view-"));
|
|
329
|
+
const cleanup = () => promises_1.default.rm(dir, { recursive: true, force: true });
|
|
330
|
+
try {
|
|
331
|
+
for (const [name, text] of Object.entries(plan.use))
|
|
332
|
+
if (text !== null)
|
|
333
|
+
await promises_1.default.writeFile(node_path_1.default.join(dir, `${name}.json`), text, "utf8");
|
|
334
|
+
}
|
|
335
|
+
catch (e) {
|
|
336
|
+
await cleanup();
|
|
337
|
+
throw e;
|
|
338
|
+
}
|
|
339
|
+
return { dir, cleanup };
|
|
340
|
+
}
|
|
247
341
|
/**
|
|
248
342
|
* 合わせの置き場を作る: `baseDir`(`.cortex` か `--ledger-dir`)の中身を一時フォルダに写し、same の名前だけ封筒の本文で差し替える
|
|
249
343
|
* (「無い」の封筒はその名前を消す)。戻りの `cleanup` で消す
|
|
@@ -272,3 +366,7 @@ async function mergeLedgerDir(baseDir, plan) {
|
|
|
272
366
|
function viewCountsLine(c) {
|
|
273
367
|
return `記憶 v2 の画面用ファイル: ${c.total} 本のうち 使った ${c.same}・後から変わった ${c.stale}・説明のつかない ${c.unexplained}・読めない ${c.unreadable}・履歴で確かめられない ${c.unverified}・目次に無い ${c.missing}(使わなかった分は今の帳簿から読みました)`;
|
|
274
368
|
}
|
|
369
|
+
/** 組み直した案件(v2)の数の 1 行(`.cortex` に倒さない・名前は出さない) */
|
|
370
|
+
function viewCountsLineV2(c) {
|
|
371
|
+
return `記憶 v2 の画面用ファイル(組み直した案件): ${c.total} 本のうち 使った ${c.same}・目次に無い ${c.missing}(目次に無い帳簿は無いものとして組みました。帳簿は .cortex から読みません)`;
|
|
372
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takagaki/cortex-decisions-viewer",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.210",
|
|
4
4
|
"description": "Cortexの意思決定記録(Decisions/*.md)を静的サイトにビルドして閲覧する。各レコードに「Edit on GitHub」リンクを付与する。",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"node": ">=18"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "tsc -p tsconfig.json",
|
|
32
|
+
"build": "tsc -p tsconfig.json && node scripts/bundle-engine.mjs",
|
|
33
33
|
"prepublishOnly": "npm run build",
|
|
34
34
|
"demo": "npm run build && node dist/cli.js build ../../aidd-project-cortex/Cortex/Decisions/records --out .demo-site",
|
|
35
35
|
"pretest": "node ../scripts/ci/assemble-engine.mjs",
|