@takagaki/cortex-decisions-viewer 0.12.117 → 0.12.119
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 +91 -154
- package/dist/cli.js +2 -0
- package/dist/engagement.js +5 -4
- package/dist/evidence-names.js +1 -1
- package/dist/ledger-dir.js +28 -0
- package/dist/minify.js +29 -0
- package/dist/ranking.js +6 -5
- package/dist/rederivation.js +22 -233
- package/dist/render.js +208 -700
- package/dist/repo.js +0 -79
- package/dist/story.js +11 -8
- package/dist/supersedes.js +13 -8
- package/package.json +2 -1
package/dist/build.js
CHANGED
|
@@ -40,8 +40,9 @@ exports.DECISION_FIRMNESS = exports.PROJECT_ICON_EXTS = exports.MIRROR_RELS = vo
|
|
|
40
40
|
exports.sanitizeBody = sanitizeBody;
|
|
41
41
|
exports.findProjectIcon = findProjectIcon;
|
|
42
42
|
exports.readFleetSources = readFleetSources;
|
|
43
|
-
exports.
|
|
44
|
-
exports.
|
|
43
|
+
exports.orderRecordsByLedgers = orderRecordsByLedgers;
|
|
44
|
+
exports.humanTouchedOf = humanTouchedOf;
|
|
45
|
+
exports.attachHumanTouched = attachHumanTouched;
|
|
45
46
|
exports.rawFrontmatterDate = rawFrontmatterDate;
|
|
46
47
|
exports.attachSupersedes = attachSupersedes;
|
|
47
48
|
exports.readGoldProposals = readGoldProposals;
|
|
@@ -110,7 +111,10 @@ function takeProposals(filePath) {
|
|
|
110
111
|
const external_id_1 = require("./external-id");
|
|
111
112
|
const home_project_1 = require("./home-project");
|
|
112
113
|
const supersedes_1 = require("./supersedes");
|
|
114
|
+
const confirmed_1 = require("./confirmed");
|
|
115
|
+
const minify_1 = require("./minify");
|
|
113
116
|
const render_1 = require("./render");
|
|
117
|
+
const ledger_dir_1 = require("./ledger-dir");
|
|
114
118
|
/**
|
|
115
119
|
* この画面を作ったパッケージの版。**package.json を唯一の出どころにする。**
|
|
116
120
|
* 別に持つと、公開した版と画面に出る版がずれる(しかも気づけない)。
|
|
@@ -703,117 +707,57 @@ async function readFleetSources(repoRoot) {
|
|
|
703
707
|
return { externalSources, slackWorkspaces, internalSources, pipelines, capabilities, fleetGeneratedAt, secretSources, secretSpaces, checks, githubOwners, backlogTarget, tools };
|
|
704
708
|
}
|
|
705
709
|
/**
|
|
706
|
-
*
|
|
710
|
+
* 区画のレコードを活性度・強さの順に並べる(用語集だけが動く・#665 便 12b → #1094 便 e4 で帯を外した)。
|
|
707
711
|
*
|
|
708
|
-
* 🔴
|
|
709
|
-
* 44 案件のうち帳簿を持つのは栓 `rederive` を入れた案件だけなので、ここが「何もしない」に
|
|
710
|
-
* 倒れることが**既定の経路**である。
|
|
711
|
-
*
|
|
712
|
-
* 🔴 **突き合わせはビルド時にここで閉じる**(`proposals` と同じ)。画面側でパスを組み立て直すと、
|
|
713
|
-
* `repoPathOf` が `editUrl` 由来なので **`repoBaseUrl` が無い案件で帯が黙って消える**。
|
|
712
|
+
* 🔴 **帳簿が無い案件では、渡された配列をそのまま返す**(並びも従来のまま)。
|
|
714
713
|
*/
|
|
715
|
-
|
|
716
|
-
// 番人テストが「git に渡った key」を数えるための差し替え口。本番は常に既定の `readBlobsAt`
|
|
717
|
-
readBlobs = repo_1.readBlobsAt) {
|
|
714
|
+
function orderRecordsByLedgers(records, recordsDir, ctx, nowIso) {
|
|
718
715
|
if (!ctx)
|
|
719
716
|
return records;
|
|
720
|
-
// 🔴 **レコードのパスは `repoRoot` から作る**(`toRepoRelative` の `process.cwd()` 起点で
|
|
721
|
-
// 作らない)。帳簿のキーは常にリポジトリルート相対(`Cortex/Glossary/records/…`)なので、
|
|
722
|
-
// Decisions ディレクトリから CLI を叩いた案件では cwd 起点だと 1 件も突き合わない
|
|
723
717
|
const recordsRel = path.relative(ctx.repoRoot, recordsDir).split(path.sep).join("/");
|
|
724
718
|
const pathOf = (r) => (recordsRel ? `${recordsRel}/${r.fileName}` : r.fileName);
|
|
725
|
-
|
|
726
|
-
// ——ここで別のものを渡すと、画面の札と食い違う(「未確認」の札が付いた記録に帯が出る)
|
|
727
|
-
const statusOf = (r) => r.rstatus;
|
|
728
|
-
// 決定表の行 5〜7 の材料。**帯の候補になったレコードのぶんだけ**今の版を読み、指紋を作る。
|
|
729
|
-
// 帳簿に人が確認した版の指紋が無い候補だけ、`<基準コミット>:<path>` をまとめて 1 回 git から引く。
|
|
730
|
-
// 🔴 **キーが 0 件の区画では git を起こさない**(この関数は区画ごとに呼ばれる)
|
|
731
|
-
const keyOf = new Map();
|
|
732
|
-
// 今の版は**作業ツリーから読む**——画面が描いているのはこのファイルであって HEAD ではない
|
|
733
|
-
const now = new Map();
|
|
734
|
-
const nowSha = new Map();
|
|
735
|
-
for (const r of records) {
|
|
736
|
-
const key = (0, rederivation_1.rederivedContentKey)(pathOf(r), statusOf(r), ctx.ledgers);
|
|
737
|
-
if (!key)
|
|
738
|
-
continue;
|
|
739
|
-
const p = pathOf(r);
|
|
740
|
-
let nowRaw;
|
|
741
|
-
try {
|
|
742
|
-
nowRaw = await node_fs_1.promises.readFile(path.join(ctx.repoRoot, p), "utf8");
|
|
743
|
-
}
|
|
744
|
-
catch {
|
|
745
|
-
// 読めなければ「読めなかった」側(`rederivedBandOf` が帯を出さずに数える)
|
|
746
|
-
continue;
|
|
747
|
-
}
|
|
748
|
-
now.set(p, nowRaw);
|
|
749
|
-
const sha = (0, rederivation_1.contentShaOf)(nowRaw);
|
|
750
|
-
nowSha.set(p, sha);
|
|
751
|
-
const conf = ctx.ledgers.confirmation.get(p);
|
|
752
|
-
// 🔴 **今の版が機械の書き直しの版でなければ git を読まない**(帯は出ないと決まっている)。
|
|
753
|
-
// 人が確認した版の指紋が帳簿にあれば、それで決まるので git を読まない(engine #546)
|
|
754
|
-
if (sha !== conf?.rewritten?.contentSha)
|
|
755
|
-
continue;
|
|
756
|
-
if (conf.contentSha) {
|
|
757
|
-
if (ctx.blobs)
|
|
758
|
-
ctx.blobs.skipped++;
|
|
759
|
-
continue;
|
|
760
|
-
}
|
|
761
|
-
keyOf.set(r, key);
|
|
762
|
-
}
|
|
763
|
-
if (ctx.blobs)
|
|
764
|
-
ctx.blobs.read += keyOf.size;
|
|
765
|
-
const bases = keyOf.size ? readBlobs(ctx.repoRoot, [...keyOf.values()]) : new Map();
|
|
766
|
-
const verdict = (p, baseCommit) => {
|
|
767
|
-
const nowRaw = now.get(p);
|
|
768
|
-
const baseRaw = bases.get(`${baseCommit}:${p}`);
|
|
769
|
-
if (nowRaw == null || baseRaw == null) {
|
|
770
|
-
// 浅い clone の窓の外・確認の後に改名された・基準コミットにこの path が無い。
|
|
771
|
-
// **帯は出さない**(誤報より無言)が、静かに消える経路なのでログの器に数える
|
|
772
|
-
ctx.miss.unreadable.add(p);
|
|
773
|
-
return "unknown";
|
|
774
|
-
}
|
|
775
|
-
return (0, rederivation_1.sameRederivedContent)(baseRaw, nowRaw) ? "same" : "changed";
|
|
776
|
-
};
|
|
777
|
-
const nowShaOf = (p) => nowSha.get(p) ?? null;
|
|
778
|
-
for (const r of records) {
|
|
779
|
-
const band = (0, rederivation_1.rederivedBandOf)(pathOf(r), statusOf(r), ctx.ledgers, nowShaOf, verdict, ctx.miss);
|
|
780
|
-
// **印が立たないレコードにはキーごと付けない**(空の器を通さない)
|
|
781
|
-
if (band)
|
|
782
|
-
r.rederived = band;
|
|
783
|
-
}
|
|
784
|
-
return (0, rederivation_1.orderByActivity)(records, pathOf, statusOf, ctx.ledgers, nowIso);
|
|
719
|
+
return (0, rederivation_1.orderByActivity)(records, pathOf, (r) => r.rstatus, ctx.ledgers, nowIso);
|
|
785
720
|
}
|
|
786
721
|
/**
|
|
787
|
-
*
|
|
722
|
+
* 記録に人の手があるか(cortex-engine #1094 段 4・削除の確認の文面を替える材料)。
|
|
723
|
+
*
|
|
724
|
+
* 次のどちらかで真:
|
|
725
|
+
* 1. status が人の値(口の `humanOwned`・区画の語彙。旧い記録の「確認済み」)
|
|
726
|
+
* 2. 確認の帳簿(`.cortex/gold-confirmation.json`)にその path の `confirmed` の行がある(消した行を除く)
|
|
788
727
|
*
|
|
789
|
-
* 🔴
|
|
790
|
-
*
|
|
791
|
-
*
|
|
728
|
+
* 🔴 **ビルドの git は使わない**(確定版 0 章 7)。cortex-bot の夜のコミットを人と数え、浅い clone では
|
|
729
|
+
* 全部が人になるため。engine の人の手の表がビューアに届く段 5 で差し替える。
|
|
730
|
+
* 取りこぼしの代償は「確認の一言が出ない」だけ(消せる範囲は変わらない)。
|
|
792
731
|
*
|
|
793
|
-
* @
|
|
732
|
+
* @param p リポジトリルート相対の path(`Cortex/<区画>/records/…`)。帳簿の鍵は NFC なので NFC でも引く
|
|
733
|
+
* @param status その記録の `rstatus`(`String()` 済み)
|
|
794
734
|
*/
|
|
795
|
-
function
|
|
735
|
+
function humanTouchedOf(p, status, confirmation) {
|
|
736
|
+
if ((0, confirmed_1.humanOwned)(p, status))
|
|
737
|
+
return true;
|
|
738
|
+
const row = confirmation.get(p) ?? confirmation.get(p.normalize("NFC"));
|
|
739
|
+
return !!row && row.deleted !== true;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* 区画の記録に人の手の印(`humanTouched: true`)を載せる。**人の手が無い記録にはキーごと付けない**
|
|
743
|
+
* (今の SiteData の形を保つ)。path は `repoRoot` 起点で作る(帳簿の鍵はリポジトリルート相対)。
|
|
744
|
+
* 置き換えの逆引き(`attachSupersedes`)より前に呼ぶ。
|
|
745
|
+
*/
|
|
746
|
+
function attachHumanTouched(records, recordsDir, repoRoot, confirmation) {
|
|
796
747
|
const recordsRel = path.relative(repoRoot, recordsDir).split(path.sep).join("/");
|
|
797
|
-
const
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
const row = ledger.get(p);
|
|
802
|
-
if (!row)
|
|
803
|
-
continue;
|
|
804
|
-
matched.add(p);
|
|
805
|
-
const shown = (0, rederivation_1.shownFollowupOf)(row);
|
|
806
|
-
if (shown)
|
|
807
|
-
d.followup = shown;
|
|
748
|
+
for (const r of records) {
|
|
749
|
+
const p = recordsRel ? `${recordsRel}/${r.fileName}` : r.fileName;
|
|
750
|
+
if (humanTouchedOf(p, r.rstatus, confirmation))
|
|
751
|
+
r.humanTouched = true;
|
|
808
752
|
}
|
|
809
|
-
return [...ledger.keys()].filter((k) => !matched.has(k.normalize("NFC")));
|
|
810
753
|
}
|
|
811
754
|
/**
|
|
812
755
|
* 決定に置き換えの逆引き(置き換え先・置き換えた決定)を載せる(cortex-engine #699 F3・A-1')。
|
|
813
756
|
*
|
|
814
757
|
* 🔴 **逆引きは `supersedes.ts`(engine `scripts/gold/supersedes-index.mjs` の写し)だけで組む**。
|
|
815
758
|
* 材料は新しい側の `relations[supersedes]` だけで、古い側の `superseded_by`(夜間の精製が書く写し)は
|
|
816
|
-
*
|
|
759
|
+
* 読まない。確定=古い側に人の手が無い(status が人の値でない)か、新しい側を人が確認した(cortex-engine #1094 段 4)。
|
|
760
|
+
* 口には記録の path(`Cortex/Decisions/records/…`・`repoRoot` 起点)を渡す。
|
|
817
761
|
*
|
|
818
762
|
* 置き換えが無い決定には**キーごと付けない**(今までと同じ SiteData)
|
|
819
763
|
*/
|
|
@@ -835,9 +779,11 @@ function rawFrontmatterDate(raw) {
|
|
|
835
779
|
v = v.replace(/\s+#.*$/, "").trim();
|
|
836
780
|
return v;
|
|
837
781
|
}
|
|
838
|
-
function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date) {
|
|
782
|
+
function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date, pathOf = () => undefined) {
|
|
839
783
|
const input = decisions.map((d) => ({
|
|
840
784
|
id: d.id,
|
|
785
|
+
// 口(`humanOwned`)に区画を伝える path。無ければ写しが決定の区画で聞く
|
|
786
|
+
path: pathOf(d),
|
|
841
787
|
// 🔴 **frontmatter に書かれたままの date の文字列**(`rawFrontmatterDate`)。gray-matter は時刻・時差つきの
|
|
842
788
|
// date を Date に読み、sanitizeFm は UTC の日付にするので、`2026-07-01T01:00:00+09:00` が 6/30 にずれる。
|
|
843
789
|
// engine は日付を Date にしない読み方(CORE_SCHEMA)で書かれた文字列の先頭 8 桁を使う。
|
|
@@ -897,11 +843,16 @@ function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date) {
|
|
|
897
843
|
function optionalText(v) {
|
|
898
844
|
return typeof v === "string" && v.trim() !== "" ? v : "";
|
|
899
845
|
}
|
|
900
|
-
|
|
846
|
+
/**
|
|
847
|
+
* engine の `normalized_match`(表記ゆれ)のカードの理由の文に入っている句。画面から外す印(#1094 便 35a-1)。
|
|
848
|
+
* 🔴 engine の `scripts/silver/build.mjs` の `WHY_NOT_DECIDED.normalized_match` の文を変えるときはここも揃える(片方だけだと静かに外れなくなる)
|
|
849
|
+
*/
|
|
850
|
+
const NORMALIZE_CARD_WHY = /区切り・姓と名の順・会社名を除くと同じ名前/;
|
|
851
|
+
async function readGoldProposals(repoRoot, ledgerDir) {
|
|
901
852
|
const empty = new Map();
|
|
902
853
|
let json;
|
|
903
854
|
try {
|
|
904
|
-
const raw = await node_fs_1.promises.readFile(path.join(
|
|
855
|
+
const raw = await node_fs_1.promises.readFile(path.join((0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDir), "gold-proposals.json"), "utf8");
|
|
905
856
|
json = JSON.parse(raw);
|
|
906
857
|
}
|
|
907
858
|
catch (e) {
|
|
@@ -986,6 +937,11 @@ async function readGoldProposals(repoRoot) {
|
|
|
986
937
|
// この 1 欄だけ覆した(決定ログ 20260925-699-f7b.md)
|
|
987
938
|
if (row.decide === "portal")
|
|
988
939
|
proposal.decide = "portal";
|
|
940
|
+
// 表記ゆれ(区切り・姓と名の順・会社名を直すと名簿に当たる)の名寄せカードは出さない(cortex-engine #1094 便 35a-1・
|
|
941
|
+
// 10/5 オーナー: 画面に人が押す操作を残さない)。engine は今後これを数えるだけにして自動で結ぶ。
|
|
942
|
+
// 🔴 見分けは engine の理由の文(`normalized_match` の `why`)。ほかの名寄せカードは今までどおり出す
|
|
943
|
+
if (proposal.kind === "identity" && NORMALIZE_CARD_WHY.test(proposal.why ?? ""))
|
|
944
|
+
continue;
|
|
989
945
|
const list = byPath.get(recordPath);
|
|
990
946
|
if (list)
|
|
991
947
|
list.push(proposal);
|
|
@@ -1514,7 +1470,7 @@ async function buildTargetUrlMap(repoRoot, repoBaseUrl, branch) {
|
|
|
1514
1470
|
* 🔴 **`buildTargetUrlMap` は触らない**(移る間だけ残す表・詳細画面の飛び先の正本)。ここは名前と、
|
|
1515
1471
|
* 写しのパス → 根拠の ID の対応だけを持つ。資料の題名を Drive の鍵にも載せるために、表の URL を読むだけ
|
|
1516
1472
|
*/
|
|
1517
|
-
async function buildEvidenceBook(repoRoot, targetUrls, externalSources = []) {
|
|
1473
|
+
async function buildEvidenceBook(repoRoot, targetUrls, externalSources = [], ledgerDir) {
|
|
1518
1474
|
const book = (0, evidence_names_1.emptyEvidenceBook)();
|
|
1519
1475
|
const rel = (file) => path.relative(repoRoot, file).split(path.sep).join("/");
|
|
1520
1476
|
const heading = (text) => text.match(/^#\s+(.+?)\s*$/m)?.[1] ?? null;
|
|
@@ -1529,7 +1485,7 @@ async function buildEvidenceBook(repoRoot, targetUrls, externalSources = []) {
|
|
|
1529
1485
|
// 片付けで移した議事録のリンク(URL の鍵 → 「定例名 日付」・cortex-engine #968 R-6・A-R6-3)。表が無い・読めない案件は今どおり
|
|
1530
1486
|
// (種類の既定の名前)。資料より先に載せる(同じ鍵に資料の題名が先に付かないように)
|
|
1531
1487
|
try {
|
|
1532
|
-
const table = JSON.parse(await node_fs_1.promises.readFile(path.join(repoRoot, evidence_names_1.MOVED_MEETINGS_FILE), "utf8"));
|
|
1488
|
+
const table = JSON.parse(await node_fs_1.promises.readFile(path.join((0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDir), evidence_names_1.MOVED_MEETINGS_FILE), "utf8"));
|
|
1533
1489
|
for (const [url, name] of (0, evidence_names_1.movedMeetingNamesOf)(table))
|
|
1534
1490
|
putName(foldKeyOf(url), name);
|
|
1535
1491
|
}
|
|
@@ -2410,43 +2366,34 @@ async function build(opts) {
|
|
|
2410
2366
|
// 解決するので、あとから作ると空の表・空の実在判定が渡り、**実在するパスまで
|
|
2411
2367
|
// 「リンクにしない」に倒れて全滅する**(以前は順序が逆だった)。
|
|
2412
2368
|
const repoRoot = knowledgeRoot ? path.dirname(knowledgeRoot) : path.dirname(dirAbs);
|
|
2369
|
+
// 帳簿 9 本の置き場(既定は `<repoRoot>/.cortex`)。読み口はこの 1 つから読む
|
|
2370
|
+
const ledgerDir = (0, ledger_dir_1.ledgerDirOf)(repoRoot, opts.ledgerDir);
|
|
2413
2371
|
const targetUrls = knowledgeRoot
|
|
2414
2372
|
? await buildTargetUrlMap(repoRoot, repo.baseUrl, repo.branch)
|
|
2415
2373
|
: new Map();
|
|
2416
2374
|
// fleet-status.json は 1 回だけ読む(読み手が警告を出すので、2 回読むと警告が 2 行になる)。
|
|
2417
2375
|
// 名前の帳(チャンネル名)と、下の「データソースと自動化」で同じものを使う
|
|
2418
2376
|
const fleet = await readFleetSources(repoRoot);
|
|
2419
|
-
const evidenceBook = knowledgeRoot ? await buildEvidenceBook(repoRoot, targetUrls, fleet.externalSources) : (0, evidence_names_1.emptyEvidenceBook)();
|
|
2377
|
+
const evidenceBook = knowledgeRoot ? await buildEvidenceBook(repoRoot, targetUrls, fleet.externalSources, ledgerDir) : (0, evidence_names_1.emptyEvidenceBook)();
|
|
2420
2378
|
const refs = createRefResolver({ repoRoot, targetUrls, repoBaseUrl: repo.baseUrl, branch: repo.branch, book: evidenceBook });
|
|
2421
2379
|
// AIからの更新提案。**レコードを組み立てる前に読む**——各レコードが自分の分を
|
|
2422
2380
|
// takeProposals で引き取るので、後から読んでも載せる先が既に閉じている。
|
|
2423
2381
|
// 同一プロセスで2回ビルドしても前回の値が残らないよう、毎回入れ替える
|
|
2424
|
-
PROPOSALS_BY_PATH = await readGoldProposals(repoRoot);
|
|
2382
|
+
PROPOSALS_BY_PATH = await readGoldProposals(repoRoot, ledgerDir);
|
|
2425
2383
|
PROPOSAL_PATHS_MATCHED = new Set();
|
|
2426
|
-
//
|
|
2427
|
-
// 人か機械かの見分けは engine が帳簿(`rewritten`)に書くので、画面は git の素性を読まない(#799)
|
|
2428
|
-
//
|
|
2384
|
+
// 用語集の並びの帳簿(活性度・強さ #790)。**帳簿が無い案件では並び替えを作らない**。
|
|
2429
2385
|
// 🔴 **強さ(`state` が on のときだけ中身が入る)だけの案件でも器を作る**——作らないと、活性度の帳簿を
|
|
2430
|
-
// 持たない案件で用語集が目次(engine の `termRows
|
|
2431
|
-
//
|
|
2432
|
-
const ledgers = await (0, rederivation_1.readRederivationLedgers)(repoRoot);
|
|
2433
|
-
const rederive = ledgers.
|
|
2434
|
-
? {
|
|
2435
|
-
ledgers: ledgers,
|
|
2436
|
-
// 🔴 **`repoRoot` で走らせる**(`collectAiChangeHistory` の `process.cwd()` に倣わない)。
|
|
2437
|
-
// あちらは「リポジトリルートで実行すること」が前提の既存の制約だが、こちらは repoRoot を
|
|
2438
|
-
// 既に知っている(帳簿をそこから読んでいる)。Decisions ディレクトリから CLI を叩いた
|
|
2439
|
-
// ときも今の版と基準版が引け、帯が黙って消えない
|
|
2440
|
-
repoRoot: repoRoot,
|
|
2441
|
-
miss: { unreadable: new Set() },
|
|
2442
|
-
blobs: { read: 0, skipped: 0 },
|
|
2443
|
-
}
|
|
2386
|
+
// 持たない案件で用語集が目次(engine の `termRows`)と違う順になる。
|
|
2387
|
+
// 確認の帳簿(`confirmation`)は削除の確認の一言(`humanTouchedOf`)が使うが、並びには関係しない
|
|
2388
|
+
const ledgers = await (0, rederivation_1.readRederivationLedgers)(repoRoot, ledgerDir);
|
|
2389
|
+
const rederive = ledgers.activity.size || ledgers.strength.size
|
|
2390
|
+
? { ledgers: ledgers, repoRoot: repoRoot }
|
|
2444
2391
|
: null;
|
|
2445
2392
|
// 関与の帳簿(便 14b・#709)。関係者の一覧を目次と同じ「関わりの多い順」に並べる材料。
|
|
2446
2393
|
// **読めない・使えないなら `null`** で、関係者の並びは今までと 1 バイトも同じ
|
|
2447
|
-
const engagement = await (0, engagement_1.readEngagementLedger)(repoRoot);
|
|
2394
|
+
const engagement = await (0, engagement_1.readEngagementLedger)(repoRoot, ledgerDir);
|
|
2448
2395
|
// 目次と同じ順位(engine #551)。**読めないなら `null`** で、つながり画面の点は今までどおり一律
|
|
2449
|
-
const memoryRanking = await (0, ranking_1.readMemoryRanking)(repoRoot);
|
|
2396
|
+
const memoryRanking = await (0, ranking_1.readMemoryRanking)(repoRoot, ledgerDir);
|
|
2450
2397
|
// 記録の id → リポジトリルート相対のパス(順位のファイルの鍵と突き合わせる。`repoRoot` 起点・cwd 起点にしない)
|
|
2451
2398
|
const recordRelPaths = new Map();
|
|
2452
2399
|
const relOf = (dir, fileName) => {
|
|
@@ -2465,19 +2412,10 @@ async function build(opts) {
|
|
|
2465
2412
|
if (rd !== undefined)
|
|
2466
2413
|
rawDates.set(rec, rd);
|
|
2467
2414
|
}
|
|
2415
|
+
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)。**置き換えより前に・repoRoot で**
|
|
2416
|
+
attachHumanTouched(decisions, dirAbs, repoRoot, ledgers.confirmation);
|
|
2468
2417
|
// 置き換えの逆引き(#699 F3)。**置き換えの無い案件では 1 件も付かない**
|
|
2469
|
-
attachSupersedes(decisions, (d) => rawDates.get(d) ?? d.fm.date);
|
|
2470
|
-
// 決定の「その後」(#705)。**帳簿を持たない案件では 1 件も付かず、絞り込みの印も立たない**
|
|
2471
|
-
// (`decisionFollowup` はキーごと無い=今までと 1 バイトも同じ画面)
|
|
2472
|
-
const followupLedger = await (0, rederivation_1.readDecisionFollowup)(repoRoot);
|
|
2473
|
-
if (followupLedger) {
|
|
2474
|
-
const unmatchedFollowup = attachDecisionFollowup(decisions, dirAbs, repoRoot, followupLedger);
|
|
2475
|
-
// **突き合わなかった行を 1 行残す**(path が 1 文字違うだけで画面から静かに消えるので)
|
|
2476
|
-
if (unmatchedFollowup.length) {
|
|
2477
|
-
console.warn(`gold-decision-followup.json: 決定に突き合わない行が ${unmatchedFollowup.length} 件ありました(表示しません): ` +
|
|
2478
|
-
unmatchedFollowup.slice(0, 3).join(", ") + (unmatchedFollowup.length > 3 ? " ほか" : ""));
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2418
|
+
attachSupersedes(decisions, (d) => rawDates.get(d) ?? d.fm.date, (d) => relOf(dirAbs, d.fileName));
|
|
2481
2419
|
let home = null;
|
|
2482
2420
|
let homeGrounding;
|
|
2483
2421
|
let homeUpdatedAt;
|
|
@@ -2517,9 +2455,10 @@ async function build(opts) {
|
|
|
2517
2455
|
continue;
|
|
2518
2456
|
const recordsDir = path.join(knowledgeRoot, e.name, "records");
|
|
2519
2457
|
const records = await loadGenericRecords(recordsDir, exclude, repo.baseUrl, repo.branch);
|
|
2520
|
-
//
|
|
2521
|
-
|
|
2522
|
-
|
|
2458
|
+
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)
|
|
2459
|
+
attachHumanTouched(records, recordsDir, repoRoot, ledgers.confirmation);
|
|
2460
|
+
// 用語集の並び(活性度・強さ)。**帳簿を持たない案件では並びもそのまま**
|
|
2461
|
+
const rederived = orderRecordsByLedgers(records, recordsDir, rederive, opts.generatedAt);
|
|
2523
2462
|
// 関係者だけ、関与の多い順(engine の目次と同じ `order`・便 14b)。用語集の並び
|
|
2524
2463
|
// (`orderByActivity`)とは帳簿も式も別で、区画が重ならないので順番に当てても干渉しない
|
|
2525
2464
|
const ordered = e.name === "Members"
|
|
@@ -2554,26 +2493,22 @@ async function build(opts) {
|
|
|
2554
2493
|
// **突き合わなかった提案の件数をビルドログに出す。** path が1文字違うだけで
|
|
2555
2494
|
// 画面から静かに消えるので、出さないと「提案が出ない」の原因に辿り着けない。
|
|
2556
2495
|
// 表示からは落とす(どのレコードの話か分からない提案は、出しても行動につながらない)
|
|
2557
|
-
// 🔴 **帯が静かに消える経路を 1 行残す。** 今の版か、人が確認した版の中身を
|
|
2558
|
-
// 引けないと「説明文が変わったか」を言えないので、帯は出さない(誤報より無言)。
|
|
2559
|
-
// 出さないと「印が出ない」の原因を「中身が変わっていない」と切り分けられない
|
|
2560
|
-
if (rederive && rederive.miss.unreadable.size) {
|
|
2561
|
-
const paths = [...rederive.miss.unreadable];
|
|
2562
|
-
console.warn(`gold-confirmation.json: 人が確認した版か今の版の中身を ${paths.length} 件引けませんでした` +
|
|
2563
|
-
`(浅い clone か、確認の後に改名・削除された。変わったかを言えないので帯は出しません): ` +
|
|
2564
|
-
paths.slice(0, 3).join(", ") + (paths.length > 3 ? " ほか" : ""));
|
|
2565
|
-
}
|
|
2566
|
-
// 🔴 **指紋(engine #546)が効いているかを 1 行残す。** 一致した記録は git を読まないので、
|
|
2567
|
-
// 「読んだ件数」が候補の数より減っていれば効いている。警告ではないので console.log
|
|
2568
|
-
if (rederive?.blobs && rederive.blobs.read + rederive.blobs.skipped > 0) {
|
|
2569
|
-
console.log(`gold-confirmation.json: 人が確認した版の中身を git から ${rederive.blobs.read} 件読みました` +
|
|
2570
|
-
`(中身の指紋で決めた ${rederive.blobs.skipped} 件は読んでいません)`);
|
|
2571
|
-
}
|
|
2572
2496
|
const unmatched = [...PROPOSALS_BY_PATH.keys()].filter((k) => !PROPOSAL_PATHS_MATCHED.has(k));
|
|
2573
2497
|
if (unmatched.length) {
|
|
2574
2498
|
console.warn(`gold-proposals.json: レコードに突き合わない提案が ${unmatched.length} 件ありました(表示しません): ` +
|
|
2575
2499
|
unmatched.slice(0, 5).join(", ") + (unmatched.length > 5 ? " ほか" : ""));
|
|
2576
2500
|
}
|
|
2501
|
+
// 画面に出さなくなった提案(名寄せ以外・#1094 35d)の件数。**人の操作は足さず、ログに 1 行だけ残す**
|
|
2502
|
+
// (kind が identity でない提案は、記録に載っていても画面のどこにも出ない)
|
|
2503
|
+
let hiddenProposals = 0;
|
|
2504
|
+
for (const [k, list] of PROPOSALS_BY_PATH) {
|
|
2505
|
+
if (!PROPOSAL_PATHS_MATCHED.has(k))
|
|
2506
|
+
continue;
|
|
2507
|
+
hiddenProposals += list.filter((p) => p.kind !== "identity").length;
|
|
2508
|
+
}
|
|
2509
|
+
if (hiddenProposals) {
|
|
2510
|
+
console.warn(`gold-proposals.json: 名寄せ以外の提案が ${hiddenProposals} 件あります(画面には出しません)`);
|
|
2511
|
+
}
|
|
2577
2512
|
const graph = buildGraph(decisions, home, graphSections, targetUrls, repo.baseUrl, evidenceBook);
|
|
2578
2513
|
computeLayout(graph); // 各ノードに x/y を書き込む(クライアントはこれを初期位置に使いウォームアップ省略)
|
|
2579
2514
|
// 点の明るさと大きさ(engine #551)。順位のファイルが読めない案件では 1 点も付かない(今までと同じ画面)
|
|
@@ -2593,9 +2528,9 @@ async function build(opts) {
|
|
|
2593
2528
|
// ストーリーの日々の動き(#901 V2-5)。帳簿で on の日のファイルが無ければ null(キーごと出さない)
|
|
2594
2529
|
const story = await (0, story_1.readStory)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null,
|
|
2595
2530
|
// 動きのない日を埋める終点=ビルドの時刻の日本時間の日付(時計を注入できる)
|
|
2596
|
-
storyToday);
|
|
2531
|
+
storyToday, ledgerDir);
|
|
2597
2532
|
// 週・月のあらすじ(#901)。週・月のファイルが無ければ null(キーごと出さない=今までと同じ画面)
|
|
2598
|
-
const storyDigest = await (0, story_1.readStoryDigest)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null, storyToday);
|
|
2533
|
+
const storyDigest = await (0, story_1.readStoryDigest)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null, storyToday, ledgerDir);
|
|
2599
2534
|
// 案件アイコン(#348)。Cortex構成でなければ undefined(旧レイアウトには置き場が無い)
|
|
2600
2535
|
const projectIcon = await findProjectIcon(knowledgeRoot);
|
|
2601
2536
|
const site = {
|
|
@@ -2622,7 +2557,6 @@ async function build(opts) {
|
|
|
2622
2557
|
}
|
|
2623
2558
|
: undefined,
|
|
2624
2559
|
// 帳簿を読めた案件だけ true(無い・壊れ・版違いはキーごと出さない)
|
|
2625
|
-
decisionFollowup: followupLedger ? true : undefined,
|
|
2626
2560
|
meetings,
|
|
2627
2561
|
// **URLとトークンが両方そろったときだけ出す。** 片方だけでは貼れるURLを作れないので、
|
|
2628
2562
|
// 手順だけが出て「専用URLが空」という一番混乱する形になる(intake と同じ扱い)
|
|
@@ -2702,7 +2636,10 @@ async function build(opts) {
|
|
|
2702
2636
|
// 配置側(cortex-engine の build-viewer.yml)の責務: aws s3 sync --delete が
|
|
2703
2637
|
// 古いハッシュのファイルを消すこと、index.html に Cache-Control: no-cache を
|
|
2704
2638
|
// 付けること(assets/ は内容ハッシュ名なので長期キャッシュでよい)。
|
|
2705
|
-
|
|
2639
|
+
// 🔴 **配る JS は縮めてから名前を決める**(ハッシュは縮めた後の中身から。コメント由来の実名を配信物に載せない・#731 便 4)。
|
|
2640
|
+
// `viewerAssetSources()` の素の JS は埋め込み形(renderSite)とテストが読むので縮めない
|
|
2641
|
+
const rawAssetSources = (0, render_1.viewerAssetSources)();
|
|
2642
|
+
const assetSources = { css: rawAssetSources.css, js: (0, minify_1.minifyClientJs)(rawAssetSources.js) };
|
|
2706
2643
|
const assets = (0, render_1.viewerAssetNames)(assetSources);
|
|
2707
2644
|
await node_fs_1.promises.mkdir(path.join(outAbs, "assets"), { recursive: true });
|
|
2708
2645
|
await node_fs_1.promises.writeFile(path.join(outAbs, assets.css), assetSources.css, "utf8");
|
package/dist/cli.js
CHANGED
|
@@ -22,6 +22,7 @@ program
|
|
|
22
22
|
.option("--secret-kinds <kinds>", "鍵の入力欄を出す連携(カンマ区切り。例: figma,backlog)")
|
|
23
23
|
.option("--webhook-url <url>", "Backlog Webhook 受信のLambda URL(環境変数 WEBHOOK_URL でも可)")
|
|
24
24
|
.option("--webhook-token <token>", "リアルタイム同期の**案件別**トークン(環境変数 WEBHOOK_TOKEN でも可。艦隊共通トークンを渡さないこと)")
|
|
25
|
+
.option("--ledger-dir <dir>", "ビューアが読む帳簿(.cortex の 9 本)の置き場(未指定なら <リポジトリルート>/.cortex)")
|
|
25
26
|
.action(async (dir, opts) => {
|
|
26
27
|
try {
|
|
27
28
|
const result = await (0, build_1.build)({
|
|
@@ -38,6 +39,7 @@ program
|
|
|
38
39
|
secretKinds: opts.secretKinds,
|
|
39
40
|
webhookUrl: opts.webhookUrl ?? process.env.WEBHOOK_URL,
|
|
40
41
|
webhookToken: opts.webhookToken ?? process.env.WEBHOOK_TOKEN,
|
|
42
|
+
ledgerDir: opts.ledgerDir,
|
|
41
43
|
});
|
|
42
44
|
console.log(`✓ ${result.count} 件のレコードを ${result.outDir} にビルドしました`);
|
|
43
45
|
}
|
package/dist/engagement.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.weightOf = exports.WEIGHTS = exports.HALF_LIFE_DAYS = exports.ENGAGEMENT_LEDGER_VERSION = exports.
|
|
6
|
+
exports.weightOf = exports.WEIGHTS = exports.HALF_LIFE_DAYS = exports.ENGAGEMENT_LEDGER_VERSION = exports.ENGAGEMENT_LEDGER_FILE = void 0;
|
|
7
7
|
exports.scoreOf = scoreOf;
|
|
8
8
|
exports.engagementOrder = engagementOrder;
|
|
9
9
|
exports.parseEngagementLedger = parseEngagementLedger;
|
|
@@ -43,8 +43,9 @@ exports.orderMembersByEngagement = orderMembersByEngagement;
|
|
|
43
43
|
*/
|
|
44
44
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
45
45
|
const node_path_1 = __importDefault(require("node:path"));
|
|
46
|
+
const ledger_dir_1 = require("./ledger-dir");
|
|
46
47
|
/** 帳簿の置き場(engine `scripts/engagement/keys.mjs` の `LEDGER_PATH`) */
|
|
47
|
-
exports.
|
|
48
|
+
exports.ENGAGEMENT_LEDGER_FILE = "gold-member-engagement.json";
|
|
48
49
|
/** 帳簿の版(engine `scripts/memory-index.mjs` の `LEDGER_VERSION`。違ったら読まない) */
|
|
49
50
|
exports.ENGAGEMENT_LEDGER_VERSION = 1;
|
|
50
51
|
/** 半減期(日)。engine `weights.mjs` の `HALF_LIFE_DAYS`(正本 6-B「半減期 90 日固定」) */
|
|
@@ -187,10 +188,10 @@ function parseEngagementLedger(text) {
|
|
|
187
188
|
};
|
|
188
189
|
}
|
|
189
190
|
/** 案件リポから帳簿を読む(無ければ `null`・例外にしない) */
|
|
190
|
-
async function readEngagementLedger(repoRoot) {
|
|
191
|
+
async function readEngagementLedger(repoRoot, ledgerDir) {
|
|
191
192
|
let text;
|
|
192
193
|
try {
|
|
193
|
-
text = await promises_1.default.readFile(node_path_1.default.join(repoRoot, exports.
|
|
194
|
+
text = await promises_1.default.readFile(node_path_1.default.join((0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDir), exports.ENGAGEMENT_LEDGER_FILE), "utf8");
|
|
194
195
|
}
|
|
195
196
|
catch {
|
|
196
197
|
return null;
|
package/dist/evidence-names.js
CHANGED
|
@@ -60,7 +60,7 @@ function minuteLabel(id) {
|
|
|
60
60
|
* 片付けで移した会議の表(engine が目次と同じコミットで置く・cortex-engine #968 R-6・A-R6-3)。
|
|
61
61
|
* 写しを片付けた案件だけが持つ。無ければ今どおり(移した議事録のリンクは種類の既定の名前で出る)
|
|
62
62
|
*/
|
|
63
|
-
exports.MOVED_MEETINGS_FILE = "
|
|
63
|
+
exports.MOVED_MEETINGS_FILE = "mirror-moved-meetings.json";
|
|
64
64
|
/**
|
|
65
65
|
* 移した会議の表 → `[移した URL, 会議の名前(「定例名 日付」)]` の並び。形が違う表・行は読まない(名前を当て推量しない)。
|
|
66
66
|
* 名前は `minuteLabel`(`minute:` の根拠と同じ 1 本)で作る——同じ会議が `minute:` で書かれても URL で書かれても同じ名前になる
|
|
@@ -0,0 +1,28 @@
|
|
|
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.DEFAULT_LEDGER_DIR_NAME = void 0;
|
|
7
|
+
exports.defaultLedgerDir = defaultLedgerDir;
|
|
8
|
+
exports.ledgerDirOf = ledgerDirOf;
|
|
9
|
+
/**
|
|
10
|
+
* ビューアが読む帳簿(9 本)の置き場(cortex-engine #1094 便 3-11 の tools(T1))。
|
|
11
|
+
*
|
|
12
|
+
* 既定は `<リポジトリルート>/.cortex`(今までと同じ)。`--ledger-dir` で別のフォルダを指せる。
|
|
13
|
+
* ビューアは保管庫(S3)も栓も知らない(AWS SDK を足さない)。どこから持ってくるかは呼び出し側(workflow)の仕事で、
|
|
14
|
+
* ここは「そのフォルダの下の `<名前>.json` を読む」だけ。
|
|
15
|
+
*
|
|
16
|
+
* 🔴 `.cortex` という綴りの読み口は**ここ 1 か所だけ**(番人 `test/ledger-dir.test.mjs` が数える)。
|
|
17
|
+
*/
|
|
18
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
19
|
+
/** 帳簿の置き場の既定の名前(リポジトリルートの下) */
|
|
20
|
+
exports.DEFAULT_LEDGER_DIR_NAME = ".cortex";
|
|
21
|
+
/** 既定の置き場: `<repoRoot>/.cortex` */
|
|
22
|
+
function defaultLedgerDir(repoRoot) {
|
|
23
|
+
return node_path_1.default.join(repoRoot, exports.DEFAULT_LEDGER_DIR_NAME);
|
|
24
|
+
}
|
|
25
|
+
/** 呼び出し側が渡した置き場。無ければ既定 */
|
|
26
|
+
function ledgerDirOf(repoRoot, ledgerDir) {
|
|
27
|
+
return ledgerDir ? node_path_1.default.resolve(ledgerDir) : defaultLedgerDir(repoRoot);
|
|
28
|
+
}
|
package/dist/minify.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MINIFY_OPTIONS = void 0;
|
|
4
|
+
exports.minifyClientJs = minifyClientJs;
|
|
5
|
+
const esbuild_1 = require("esbuild");
|
|
6
|
+
/**
|
|
7
|
+
* 画面の JS(`assets/viewer.<hash>.js`)を配る前に縮める(cortex-engine #731 便 4)。
|
|
8
|
+
*
|
|
9
|
+
* 配る JS はテンプレート文字列として書いた約 15,000 行で、コメントに案件名・社内の事情が入っている。
|
|
10
|
+
* そのまま書き出すと、お客様の組織の画面のソースにも読める形で載る。ここで**コメントと余分な空白を落とす**。
|
|
11
|
+
*
|
|
12
|
+
* 🔴 **空白とコメントだけを落とす(名前の短縮・構文の書き換えはしない)。** `.toString()` で埋め込んだ関数や
|
|
13
|
+
* 名前に頼る所を壊さないため。`charset: "utf8"` は日本語の文言を `\uXXXX` に展開させない(既定の ascii だと
|
|
14
|
+
* 読めず、かえって大きくなる)。`legalComments: "none"` は `/*!` 系も残さない。
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ 番人(`test/shipped-js-minified.test.mjs`)は同じオプションを**わざと直書き**している(ここを再利用すると、縮めを恒等にされても緑になる)。
|
|
17
|
+
* ここを変えたら番人の直書きも同じにすること。
|
|
18
|
+
*
|
|
19
|
+
* 🔴 **失敗しても素のコメント入りで配らない**(例外のまま build を赤にする)。縮めに失敗した画面を黙って配ると、
|
|
20
|
+
* 番人(`test/shipped-js-minified.test.mjs`)の外で実名が載る。
|
|
21
|
+
*/
|
|
22
|
+
exports.MINIFY_OPTIONS = {
|
|
23
|
+
minifyWhitespace: true,
|
|
24
|
+
charset: "utf8",
|
|
25
|
+
legalComments: "none",
|
|
26
|
+
};
|
|
27
|
+
function minifyClientJs(js) {
|
|
28
|
+
return (0, esbuild_1.transformSync)(js, exports.MINIFY_OPTIONS).code;
|
|
29
|
+
}
|
package/dist/ranking.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.MEMORY_RANKING_SECTIONS = exports.MEMORY_RANKING_VERSION = exports.
|
|
6
|
+
exports.MEMORY_RANKING_SECTIONS = exports.MEMORY_RANKING_VERSION = exports.MEMORY_RANKING_FILE = void 0;
|
|
7
7
|
exports.parseMemoryRanking = parseMemoryRanking;
|
|
8
8
|
exports.readMemoryRanking = readMemoryRanking;
|
|
9
9
|
exports.glowByPath = glowByPath;
|
|
@@ -25,8 +25,9 @@ exports.glowByPath = glowByPath;
|
|
|
25
25
|
*/
|
|
26
26
|
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
27
27
|
const node_path_1 = __importDefault(require("node:path"));
|
|
28
|
+
const ledger_dir_1 = require("./ledger-dir");
|
|
28
29
|
/** 置き場(engine `scripts/memory-ranking.mjs` の `RANKING_PATH`) */
|
|
29
|
-
exports.
|
|
30
|
+
exports.MEMORY_RANKING_FILE = "memory-ranking.json";
|
|
30
31
|
/** 形の版(engine の `RANKING_VERSION`。違ったら読まない) */
|
|
31
32
|
exports.MEMORY_RANKING_VERSION = 1;
|
|
32
33
|
/** 載る区画(engine の `RANKING_SECTIONS`) */
|
|
@@ -57,17 +58,17 @@ function parseMemoryRanking(text) {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
/** 案件リポから読む。無い → `null`(黙る)・壊れている → `null`(build のログに 1 行) */
|
|
60
|
-
async function readMemoryRanking(repoRoot) {
|
|
61
|
+
async function readMemoryRanking(repoRoot, ledgerDir) {
|
|
61
62
|
let text;
|
|
62
63
|
try {
|
|
63
|
-
text = await promises_1.default.readFile(node_path_1.default.join(repoRoot, exports.
|
|
64
|
+
text = await promises_1.default.readFile(node_path_1.default.join((0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDir), exports.MEMORY_RANKING_FILE), "utf8");
|
|
64
65
|
}
|
|
65
66
|
catch {
|
|
66
67
|
return null;
|
|
67
68
|
}
|
|
68
69
|
const parsed = parseMemoryRanking(text);
|
|
69
70
|
if (!parsed)
|
|
70
|
-
console.warn(`${
|
|
71
|
+
console.warn(`${exports.MEMORY_RANKING_FILE}: 読めないので、つながり画面の点は一律の明るさで出します`);
|
|
71
72
|
return parsed;
|
|
72
73
|
}
|
|
73
74
|
/**
|