@takagaki/cortex-decisions-viewer 0.12.118 → 0.12.120
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 +80 -128
- package/dist/change-log.js +187 -0
- 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/ranking.js +6 -5
- package/dist/rederivation.js +14 -113
- package/dist/render.js +281 -346
- package/dist/repo.js +11 -587
- package/dist/story.js +77 -11
- package/dist/supersedes.js +12 -20
- package/package.json +2 -1
package/dist/build.js
CHANGED
|
@@ -40,11 +40,12 @@ 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.
|
|
43
|
+
exports.orderRecordsByLedgers = orderRecordsByLedgers;
|
|
44
44
|
exports.humanTouchedOf = humanTouchedOf;
|
|
45
45
|
exports.attachHumanTouched = attachHumanTouched;
|
|
46
46
|
exports.rawFrontmatterDate = rawFrontmatterDate;
|
|
47
47
|
exports.attachSupersedes = attachSupersedes;
|
|
48
|
+
exports.attachRetractedBy = attachRetractedBy;
|
|
48
49
|
exports.readGoldProposals = readGoldProposals;
|
|
49
50
|
exports.buildHomeGrounding = buildHomeGrounding;
|
|
50
51
|
exports.collectMeetings = collectMeetings;
|
|
@@ -68,6 +69,7 @@ const marked_1 = require("marked");
|
|
|
68
69
|
const sanitize_html_1 = __importDefault(require("sanitize-html"));
|
|
69
70
|
const canonical_evidence_1 = require("./canonical-evidence");
|
|
70
71
|
const evidence_names_1 = require("./evidence-names");
|
|
72
|
+
const change_log_1 = require("./change-log");
|
|
71
73
|
const repo_1 = require("./repo");
|
|
72
74
|
const engagement_1 = require("./engagement");
|
|
73
75
|
const story_1 = require("./story");
|
|
@@ -114,6 +116,7 @@ const supersedes_1 = require("./supersedes");
|
|
|
114
116
|
const confirmed_1 = require("./confirmed");
|
|
115
117
|
const minify_1 = require("./minify");
|
|
116
118
|
const render_1 = require("./render");
|
|
119
|
+
const ledger_dir_1 = require("./ledger-dir");
|
|
117
120
|
/**
|
|
118
121
|
* この画面を作ったパッケージの版。**package.json を唯一の出どころにする。**
|
|
119
122
|
* 別に持つと、公開した版と画面に出る版がずれる(しかも気づけない)。
|
|
@@ -706,85 +709,16 @@ async function readFleetSources(repoRoot) {
|
|
|
706
709
|
return { externalSources, slackWorkspaces, internalSources, pipelines, capabilities, fleetGeneratedAt, secretSources, secretSpaces, checks, githubOwners, backlogTarget, tools };
|
|
707
710
|
}
|
|
708
711
|
/**
|
|
709
|
-
*
|
|
712
|
+
* 区画のレコードを活性度・強さの順に並べる(用語集だけが動く・#665 便 12b → #1094 便 e4 で帯を外した)。
|
|
710
713
|
*
|
|
711
|
-
* 🔴
|
|
712
|
-
* 44 案件のうち帳簿を持つのは栓 `rederive` を入れた案件だけなので、ここが「何もしない」に
|
|
713
|
-
* 倒れることが**既定の経路**である。
|
|
714
|
-
*
|
|
715
|
-
* 🔴 **突き合わせはビルド時にここで閉じる**(`proposals` と同じ)。画面側でパスを組み立て直すと、
|
|
716
|
-
* `repoPathOf` が `editUrl` 由来なので **`repoBaseUrl` が無い案件で帯が黙って消える**。
|
|
714
|
+
* 🔴 **帳簿が無い案件では、渡された配列をそのまま返す**(並びも従来のまま)。
|
|
717
715
|
*/
|
|
718
|
-
|
|
719
|
-
// 番人テストが「git に渡った key」を数えるための差し替え口。本番は常に既定の `readBlobsAt`
|
|
720
|
-
readBlobs = repo_1.readBlobsAt) {
|
|
716
|
+
function orderRecordsByLedgers(records, recordsDir, ctx, nowIso) {
|
|
721
717
|
if (!ctx)
|
|
722
718
|
return records;
|
|
723
|
-
// 🔴 **レコードのパスは `repoRoot` から作る**(`toRepoRelative` の `process.cwd()` 起点で
|
|
724
|
-
// 作らない)。帳簿のキーは常にリポジトリルート相対(`Cortex/Glossary/records/…`)なので、
|
|
725
|
-
// Decisions ディレクトリから CLI を叩いた案件では cwd 起点だと 1 件も突き合わない
|
|
726
719
|
const recordsRel = path.relative(ctx.repoRoot, recordsDir).split(path.sep).join("/");
|
|
727
720
|
const pathOf = (r) => (recordsRel ? `${recordsRel}/${r.fileName}` : r.fileName);
|
|
728
|
-
|
|
729
|
-
// ——ここで別のものを渡すと、画面の札と食い違う(「未確認」の札が付いた記録に帯が出る)
|
|
730
|
-
const statusOf = (r) => r.rstatus;
|
|
731
|
-
// 決定表の行 5〜7 の材料。**帯の候補になったレコードのぶんだけ**今の版を読み、指紋を作る。
|
|
732
|
-
// 帳簿に人が確認した版の指紋が無い候補だけ、`<基準コミット>:<path>` をまとめて 1 回 git から引く。
|
|
733
|
-
// 🔴 **キーが 0 件の区画では git を起こさない**(この関数は区画ごとに呼ばれる)
|
|
734
|
-
const keyOf = new Map();
|
|
735
|
-
// 今の版は**作業ツリーから読む**——画面が描いているのはこのファイルであって HEAD ではない
|
|
736
|
-
const now = new Map();
|
|
737
|
-
const nowSha = new Map();
|
|
738
|
-
for (const r of records) {
|
|
739
|
-
const key = (0, rederivation_1.rederivedContentKey)(pathOf(r), statusOf(r), ctx.ledgers);
|
|
740
|
-
if (!key)
|
|
741
|
-
continue;
|
|
742
|
-
const p = pathOf(r);
|
|
743
|
-
let nowRaw;
|
|
744
|
-
try {
|
|
745
|
-
nowRaw = await node_fs_1.promises.readFile(path.join(ctx.repoRoot, p), "utf8");
|
|
746
|
-
}
|
|
747
|
-
catch {
|
|
748
|
-
// 読めなければ「読めなかった」側(`rederivedBandOf` が帯を出さずに数える)
|
|
749
|
-
continue;
|
|
750
|
-
}
|
|
751
|
-
now.set(p, nowRaw);
|
|
752
|
-
const sha = (0, rederivation_1.contentShaOf)(nowRaw);
|
|
753
|
-
nowSha.set(p, sha);
|
|
754
|
-
const conf = ctx.ledgers.confirmation.get(p);
|
|
755
|
-
// 🔴 **今の版が機械の書き直しの版でなければ git を読まない**(帯は出ないと決まっている)。
|
|
756
|
-
// 人が確認した版の指紋が帳簿にあれば、それで決まるので git を読まない(engine #546)
|
|
757
|
-
if (sha !== conf?.rewritten?.contentSha)
|
|
758
|
-
continue;
|
|
759
|
-
if (conf.contentSha) {
|
|
760
|
-
if (ctx.blobs)
|
|
761
|
-
ctx.blobs.skipped++;
|
|
762
|
-
continue;
|
|
763
|
-
}
|
|
764
|
-
keyOf.set(r, key);
|
|
765
|
-
}
|
|
766
|
-
if (ctx.blobs)
|
|
767
|
-
ctx.blobs.read += keyOf.size;
|
|
768
|
-
const bases = keyOf.size ? readBlobs(ctx.repoRoot, [...keyOf.values()]) : new Map();
|
|
769
|
-
const verdict = (p, baseCommit) => {
|
|
770
|
-
const nowRaw = now.get(p);
|
|
771
|
-
const baseRaw = bases.get(`${baseCommit}:${p}`);
|
|
772
|
-
if (nowRaw == null || baseRaw == null) {
|
|
773
|
-
// 浅い clone の窓の外・確認の後に改名された・基準コミットにこの path が無い。
|
|
774
|
-
// **帯は出さない**(誤報より無言)が、静かに消える経路なのでログの器に数える
|
|
775
|
-
ctx.miss.unreadable.add(p);
|
|
776
|
-
return "unknown";
|
|
777
|
-
}
|
|
778
|
-
return (0, rederivation_1.sameRederivedContent)(baseRaw, nowRaw) ? "same" : "changed";
|
|
779
|
-
};
|
|
780
|
-
const nowShaOf = (p) => nowSha.get(p) ?? null;
|
|
781
|
-
for (const r of records) {
|
|
782
|
-
const band = (0, rederivation_1.rederivedBandOf)(pathOf(r), statusOf(r), ctx.ledgers, nowShaOf, verdict, ctx.miss);
|
|
783
|
-
// **印が立たないレコードにはキーごと付けない**(空の器を通さない)
|
|
784
|
-
if (band)
|
|
785
|
-
r.rederived = band;
|
|
786
|
-
}
|
|
787
|
-
return (0, rederivation_1.orderByActivity)(records, pathOf, statusOf, ctx.ledgers, nowIso);
|
|
721
|
+
return (0, rederivation_1.orderByActivity)(records, pathOf, (r) => r.rstatus, ctx.ledgers, nowIso);
|
|
788
722
|
}
|
|
789
723
|
/**
|
|
790
724
|
* 記録に人の手があるか(cortex-engine #1094 段 4・削除の確認の文面を替える材料)。
|
|
@@ -824,7 +758,8 @@ function attachHumanTouched(records, recordsDir, repoRoot, confirmation) {
|
|
|
824
758
|
*
|
|
825
759
|
* 🔴 **逆引きは `supersedes.ts`(engine `scripts/gold/supersedes-index.mjs` の写し)だけで組む**。
|
|
826
760
|
* 材料は新しい側の `relations[supersedes]` だけで、古い側の `superseded_by`(夜間の精製が書く写し)は
|
|
827
|
-
*
|
|
761
|
+
* 読まない。確定=古い側に人の手が無い(status が人の値でない)か、新しい側を人が確認した(cortex-engine #1094 段 4)。
|
|
762
|
+
* 口には記録の path(`Cortex/Decisions/records/…`・`repoRoot` 起点)を渡す。
|
|
828
763
|
*
|
|
829
764
|
* 置き換えが無い決定には**キーごと付けない**(今までと同じ SiteData)
|
|
830
765
|
*/
|
|
@@ -846,9 +781,11 @@ function rawFrontmatterDate(raw) {
|
|
|
846
781
|
v = v.replace(/\s+#.*$/, "").trim();
|
|
847
782
|
return v;
|
|
848
783
|
}
|
|
849
|
-
function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date) {
|
|
784
|
+
function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date, pathOf = () => undefined) {
|
|
850
785
|
const input = decisions.map((d) => ({
|
|
851
786
|
id: d.id,
|
|
787
|
+
// 口(`humanOwned`)に区画を伝える path。無ければ写しが決定の区画で聞く
|
|
788
|
+
path: pathOf(d),
|
|
852
789
|
// 🔴 **frontmatter に書かれたままの date の文字列**(`rawFrontmatterDate`)。gray-matter は時刻・時差つきの
|
|
853
790
|
// date を Date に読み、sanitizeFm は UTC の日付にするので、`2026-07-01T01:00:00+09:00` が 6/30 にずれる。
|
|
854
791
|
// engine は日付を Date にしない読み方(CORE_SCHEMA)で書かれた文字列の先頭 8 桁を使う。
|
|
@@ -891,6 +828,35 @@ function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date) {
|
|
|
891
828
|
d.supersedesIds = replaced;
|
|
892
829
|
}
|
|
893
830
|
}
|
|
831
|
+
/**
|
|
832
|
+
* ルールに取り下げ(`relations[retracted_by]`・cortex-engine #1094 便 4-2d)を載せる。
|
|
833
|
+
*
|
|
834
|
+
* 取り下げ=この線が 1 本以上(決定の「置き換えられた」と同じ導出・engine の目次と同じ)。
|
|
835
|
+
* target は取り下げを決めた決定の ID。実在する決定なら記録の綴りと決定日を添える(無ければ ID のまま・日付は空)。
|
|
836
|
+
* **取り下げの無いルール・ルール以外の区画にはキーごと付けない**(今までと同じ SiteData)
|
|
837
|
+
*/
|
|
838
|
+
function attachRetractedBy(records, decisions, rawDateOf = (d) => d.date) {
|
|
839
|
+
const byKey = new Map();
|
|
840
|
+
for (const d of decisions) {
|
|
841
|
+
const k = (0, supersedes_1.decisionKeyOf)(d.id);
|
|
842
|
+
if (!byKey.has(k))
|
|
843
|
+
byKey.set(k, d);
|
|
844
|
+
}
|
|
845
|
+
for (const r of records) {
|
|
846
|
+
const out = [];
|
|
847
|
+
for (const rel of r.relations) {
|
|
848
|
+
if (rel.rel !== "retracted_by")
|
|
849
|
+
continue;
|
|
850
|
+
const k = (0, supersedes_1.decisionKeyOf)(rel.target);
|
|
851
|
+
if (!k || out.some((x) => (0, supersedes_1.decisionKeyOf)(x.id) === k))
|
|
852
|
+
continue;
|
|
853
|
+
const d = byKey.get(k);
|
|
854
|
+
out.push({ id: d ? d.id : k, date: d ? (0, supersedes_1.decisionDateOf)(rawDateOf(d), d.id) : "" });
|
|
855
|
+
}
|
|
856
|
+
if (out.length)
|
|
857
|
+
r.retractedBy = out;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
894
860
|
/**
|
|
895
861
|
* AIからの更新提案(`.cortex/gold-proposals.json`)を読む。
|
|
896
862
|
*
|
|
@@ -908,11 +874,16 @@ function attachSupersedes(decisions, rawDateOf = (d) => d.fm.date) {
|
|
|
908
874
|
function optionalText(v) {
|
|
909
875
|
return typeof v === "string" && v.trim() !== "" ? v : "";
|
|
910
876
|
}
|
|
911
|
-
|
|
877
|
+
/**
|
|
878
|
+
* engine の `normalized_match`(表記ゆれ)のカードの理由の文に入っている句。画面から外す印(#1094 便 35a-1)。
|
|
879
|
+
* 🔴 engine の `scripts/silver/build.mjs` の `WHY_NOT_DECIDED.normalized_match` の文を変えるときはここも揃える(片方だけだと静かに外れなくなる)
|
|
880
|
+
*/
|
|
881
|
+
const NORMALIZE_CARD_WHY = /区切り・姓と名の順・会社名を除くと同じ名前/;
|
|
882
|
+
async function readGoldProposals(repoRoot, ledgerDir) {
|
|
912
883
|
const empty = new Map();
|
|
913
884
|
let json;
|
|
914
885
|
try {
|
|
915
|
-
const raw = await node_fs_1.promises.readFile(path.join(
|
|
886
|
+
const raw = await node_fs_1.promises.readFile(path.join((0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDir), "gold-proposals.json"), "utf8");
|
|
916
887
|
json = JSON.parse(raw);
|
|
917
888
|
}
|
|
918
889
|
catch (e) {
|
|
@@ -997,6 +968,11 @@ async function readGoldProposals(repoRoot) {
|
|
|
997
968
|
// この 1 欄だけ覆した(決定ログ 20260925-699-f7b.md)
|
|
998
969
|
if (row.decide === "portal")
|
|
999
970
|
proposal.decide = "portal";
|
|
971
|
+
// 表記ゆれ(区切り・姓と名の順・会社名を直すと名簿に当たる)の名寄せカードは出さない(cortex-engine #1094 便 35a-1・
|
|
972
|
+
// 10/5 オーナー: 画面に人が押す操作を残さない)。engine は今後これを数えるだけにして自動で結ぶ。
|
|
973
|
+
// 🔴 見分けは engine の理由の文(`normalized_match` の `why`)。ほかの名寄せカードは今までどおり出す
|
|
974
|
+
if (proposal.kind === "identity" && NORMALIZE_CARD_WHY.test(proposal.why ?? ""))
|
|
975
|
+
continue;
|
|
1000
976
|
const list = byPath.get(recordPath);
|
|
1001
977
|
if (list)
|
|
1002
978
|
list.push(proposal);
|
|
@@ -1525,7 +1501,7 @@ async function buildTargetUrlMap(repoRoot, repoBaseUrl, branch) {
|
|
|
1525
1501
|
* 🔴 **`buildTargetUrlMap` は触らない**(移る間だけ残す表・詳細画面の飛び先の正本)。ここは名前と、
|
|
1526
1502
|
* 写しのパス → 根拠の ID の対応だけを持つ。資料の題名を Drive の鍵にも載せるために、表の URL を読むだけ
|
|
1527
1503
|
*/
|
|
1528
|
-
async function buildEvidenceBook(repoRoot, targetUrls, externalSources = []) {
|
|
1504
|
+
async function buildEvidenceBook(repoRoot, targetUrls, externalSources = [], ledgerDir) {
|
|
1529
1505
|
const book = (0, evidence_names_1.emptyEvidenceBook)();
|
|
1530
1506
|
const rel = (file) => path.relative(repoRoot, file).split(path.sep).join("/");
|
|
1531
1507
|
const heading = (text) => text.match(/^#\s+(.+?)\s*$/m)?.[1] ?? null;
|
|
@@ -1540,7 +1516,7 @@ async function buildEvidenceBook(repoRoot, targetUrls, externalSources = []) {
|
|
|
1540
1516
|
// 片付けで移した議事録のリンク(URL の鍵 → 「定例名 日付」・cortex-engine #968 R-6・A-R6-3)。表が無い・読めない案件は今どおり
|
|
1541
1517
|
// (種類の既定の名前)。資料より先に載せる(同じ鍵に資料の題名が先に付かないように)
|
|
1542
1518
|
try {
|
|
1543
|
-
const table = JSON.parse(await node_fs_1.promises.readFile(path.join(repoRoot, evidence_names_1.MOVED_MEETINGS_FILE), "utf8"));
|
|
1519
|
+
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"));
|
|
1544
1520
|
for (const [url, name] of (0, evidence_names_1.movedMeetingNamesOf)(table))
|
|
1545
1521
|
putName(foldKeyOf(url), name);
|
|
1546
1522
|
}
|
|
@@ -2421,43 +2397,34 @@ async function build(opts) {
|
|
|
2421
2397
|
// 解決するので、あとから作ると空の表・空の実在判定が渡り、**実在するパスまで
|
|
2422
2398
|
// 「リンクにしない」に倒れて全滅する**(以前は順序が逆だった)。
|
|
2423
2399
|
const repoRoot = knowledgeRoot ? path.dirname(knowledgeRoot) : path.dirname(dirAbs);
|
|
2400
|
+
// 帳簿 10 本の置き場(既定は `<repoRoot>/.cortex`)。読み口はこの 1 つから読む
|
|
2401
|
+
const ledgerDir = (0, ledger_dir_1.ledgerDirOf)(repoRoot, opts.ledgerDir);
|
|
2424
2402
|
const targetUrls = knowledgeRoot
|
|
2425
2403
|
? await buildTargetUrlMap(repoRoot, repo.baseUrl, repo.branch)
|
|
2426
2404
|
: new Map();
|
|
2427
2405
|
// fleet-status.json は 1 回だけ読む(読み手が警告を出すので、2 回読むと警告が 2 行になる)。
|
|
2428
2406
|
// 名前の帳(チャンネル名)と、下の「データソースと自動化」で同じものを使う
|
|
2429
2407
|
const fleet = await readFleetSources(repoRoot);
|
|
2430
|
-
const evidenceBook = knowledgeRoot ? await buildEvidenceBook(repoRoot, targetUrls, fleet.externalSources) : (0, evidence_names_1.emptyEvidenceBook)();
|
|
2408
|
+
const evidenceBook = knowledgeRoot ? await buildEvidenceBook(repoRoot, targetUrls, fleet.externalSources, ledgerDir) : (0, evidence_names_1.emptyEvidenceBook)();
|
|
2431
2409
|
const refs = createRefResolver({ repoRoot, targetUrls, repoBaseUrl: repo.baseUrl, branch: repo.branch, book: evidenceBook });
|
|
2432
2410
|
// AIからの更新提案。**レコードを組み立てる前に読む**——各レコードが自分の分を
|
|
2433
2411
|
// takeProposals で引き取るので、後から読んでも載せる先が既に閉じている。
|
|
2434
2412
|
// 同一プロセスで2回ビルドしても前回の値が残らないよう、毎回入れ替える
|
|
2435
|
-
PROPOSALS_BY_PATH = await readGoldProposals(repoRoot);
|
|
2413
|
+
PROPOSALS_BY_PATH = await readGoldProposals(repoRoot, ledgerDir);
|
|
2436
2414
|
PROPOSAL_PATHS_MATCHED = new Set();
|
|
2437
|
-
//
|
|
2438
|
-
// 人か機械かの見分けは engine が帳簿(`rewritten`)に書くので、画面は git の素性を読まない(#799)
|
|
2439
|
-
//
|
|
2415
|
+
// 用語集の並びの帳簿(活性度・強さ #790)。**帳簿が無い案件では並び替えを作らない**。
|
|
2440
2416
|
// 🔴 **強さ(`state` が on のときだけ中身が入る)だけの案件でも器を作る**——作らないと、活性度の帳簿を
|
|
2441
|
-
// 持たない案件で用語集が目次(engine の `termRows
|
|
2442
|
-
//
|
|
2443
|
-
const ledgers = await (0, rederivation_1.readRederivationLedgers)(repoRoot);
|
|
2444
|
-
const rederive = ledgers.
|
|
2445
|
-
? {
|
|
2446
|
-
ledgers: ledgers,
|
|
2447
|
-
// 🔴 **`repoRoot` で走らせる**(`collectAiChangeHistory` の `process.cwd()` に倣わない)。
|
|
2448
|
-
// あちらは「リポジトリルートで実行すること」が前提の既存の制約だが、こちらは repoRoot を
|
|
2449
|
-
// 既に知っている(帳簿をそこから読んでいる)。Decisions ディレクトリから CLI を叩いた
|
|
2450
|
-
// ときも今の版と基準版が引け、帯が黙って消えない
|
|
2451
|
-
repoRoot: repoRoot,
|
|
2452
|
-
miss: { unreadable: new Set() },
|
|
2453
|
-
blobs: { read: 0, skipped: 0 },
|
|
2454
|
-
}
|
|
2417
|
+
// 持たない案件で用語集が目次(engine の `termRows`)と違う順になる。
|
|
2418
|
+
// 確認の帳簿(`confirmation`)は削除の確認の一言(`humanTouchedOf`)が使うが、並びには関係しない
|
|
2419
|
+
const ledgers = await (0, rederivation_1.readRederivationLedgers)(repoRoot, ledgerDir);
|
|
2420
|
+
const rederive = ledgers.activity.size || ledgers.strength.size
|
|
2421
|
+
? { ledgers: ledgers, repoRoot: repoRoot }
|
|
2455
2422
|
: null;
|
|
2456
2423
|
// 関与の帳簿(便 14b・#709)。関係者の一覧を目次と同じ「関わりの多い順」に並べる材料。
|
|
2457
2424
|
// **読めない・使えないなら `null`** で、関係者の並びは今までと 1 バイトも同じ
|
|
2458
|
-
const engagement = await (0, engagement_1.readEngagementLedger)(repoRoot);
|
|
2425
|
+
const engagement = await (0, engagement_1.readEngagementLedger)(repoRoot, ledgerDir);
|
|
2459
2426
|
// 目次と同じ順位(engine #551)。**読めないなら `null`** で、つながり画面の点は今までどおり一律
|
|
2460
|
-
const memoryRanking = await (0, ranking_1.readMemoryRanking)(repoRoot);
|
|
2427
|
+
const memoryRanking = await (0, ranking_1.readMemoryRanking)(repoRoot, ledgerDir);
|
|
2461
2428
|
// 記録の id → リポジトリルート相対のパス(順位のファイルの鍵と突き合わせる。`repoRoot` 起点・cwd 起点にしない)
|
|
2462
2429
|
const recordRelPaths = new Map();
|
|
2463
2430
|
const relOf = (dir, fileName) => {
|
|
@@ -2479,7 +2446,7 @@ async function build(opts) {
|
|
|
2479
2446
|
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)。**置き換えより前に・repoRoot で**
|
|
2480
2447
|
attachHumanTouched(decisions, dirAbs, repoRoot, ledgers.confirmation);
|
|
2481
2448
|
// 置き換えの逆引き(#699 F3)。**置き換えの無い案件では 1 件も付かない**
|
|
2482
|
-
attachSupersedes(decisions, (d) => rawDates.get(d) ?? d.fm.date);
|
|
2449
|
+
attachSupersedes(decisions, (d) => rawDates.get(d) ?? d.fm.date, (d) => relOf(dirAbs, d.fileName));
|
|
2483
2450
|
let home = null;
|
|
2484
2451
|
let homeGrounding;
|
|
2485
2452
|
let homeUpdatedAt;
|
|
@@ -2521,9 +2488,11 @@ async function build(opts) {
|
|
|
2521
2488
|
const records = await loadGenericRecords(recordsDir, exclude, repo.baseUrl, repo.branch);
|
|
2522
2489
|
// 人の手(削除の確認の文面を替える材料・cortex-engine #1094 段 4)
|
|
2523
2490
|
attachHumanTouched(records, recordsDir, repoRoot, ledgers.confirmation);
|
|
2524
|
-
//
|
|
2525
|
-
|
|
2526
|
-
|
|
2491
|
+
// ルールの取り下げ(`retracted_by`・cortex-engine #1094 便 4-2d)。ルールの区画だけ・取り下げの無い案件では何も付かない
|
|
2492
|
+
if (e.name === "Rules")
|
|
2493
|
+
attachRetractedBy(records, decisions, (d) => rawDates.get(d) ?? d.fm.date);
|
|
2494
|
+
// 用語集の並び(活性度・強さ)。**帳簿を持たない案件では並びもそのまま**
|
|
2495
|
+
const rederived = orderRecordsByLedgers(records, recordsDir, rederive, opts.generatedAt);
|
|
2527
2496
|
// 関係者だけ、関与の多い順(engine の目次と同じ `order`・便 14b)。用語集の並び
|
|
2528
2497
|
// (`orderByActivity`)とは帳簿も式も別で、区画が重ならないので順番に当てても干渉しない
|
|
2529
2498
|
const ordered = e.name === "Members"
|
|
@@ -2558,21 +2527,6 @@ async function build(opts) {
|
|
|
2558
2527
|
// **突き合わなかった提案の件数をビルドログに出す。** path が1文字違うだけで
|
|
2559
2528
|
// 画面から静かに消えるので、出さないと「提案が出ない」の原因に辿り着けない。
|
|
2560
2529
|
// 表示からは落とす(どのレコードの話か分からない提案は、出しても行動につながらない)
|
|
2561
|
-
// 🔴 **帯が静かに消える経路を 1 行残す。** 今の版か、人が確認した版の中身を
|
|
2562
|
-
// 引けないと「説明文が変わったか」を言えないので、帯は出さない(誤報より無言)。
|
|
2563
|
-
// 出さないと「印が出ない」の原因を「中身が変わっていない」と切り分けられない
|
|
2564
|
-
if (rederive && rederive.miss.unreadable.size) {
|
|
2565
|
-
const paths = [...rederive.miss.unreadable];
|
|
2566
|
-
console.warn(`gold-confirmation.json: 人が確認した版か今の版の中身を ${paths.length} 件引けませんでした` +
|
|
2567
|
-
`(浅い clone か、確認の後に改名・削除された。変わったかを言えないので帯は出しません): ` +
|
|
2568
|
-
paths.slice(0, 3).join(", ") + (paths.length > 3 ? " ほか" : ""));
|
|
2569
|
-
}
|
|
2570
|
-
// 🔴 **指紋(engine #546)が効いているかを 1 行残す。** 一致した記録は git を読まないので、
|
|
2571
|
-
// 「読んだ件数」が候補の数より減っていれば効いている。警告ではないので console.log
|
|
2572
|
-
if (rederive?.blobs && rederive.blobs.read + rederive.blobs.skipped > 0) {
|
|
2573
|
-
console.log(`gold-confirmation.json: 人が確認した版の中身を git から ${rederive.blobs.read} 件読みました` +
|
|
2574
|
-
`(中身の指紋で決めた ${rederive.blobs.skipped} 件は読んでいません)`);
|
|
2575
|
-
}
|
|
2576
2530
|
const unmatched = [...PROPOSALS_BY_PATH.keys()].filter((k) => !PROPOSAL_PATHS_MATCHED.has(k));
|
|
2577
2531
|
if (unmatched.length) {
|
|
2578
2532
|
console.warn(`gold-proposals.json: レコードに突き合わない提案が ${unmatched.length} 件ありました(表示しません): ` +
|
|
@@ -2598,19 +2552,17 @@ async function build(opts) {
|
|
|
2598
2552
|
// すでにある会議(投入モーダルの「会議名」の選択肢)。intake の有無に関わらず載せる——
|
|
2599
2553
|
// 出し分けは表示側の仕事で、ここで絞ると「投入の口を後から付けたら選択肢が空」になる
|
|
2600
2554
|
const meetings = await collectMeetings(repoRoot);
|
|
2601
|
-
//
|
|
2602
|
-
//
|
|
2603
|
-
|
|
2604
|
-
// Decisions ディレクトリで実行すると pathspec に一致せず常に空になる
|
|
2605
|
-
const aiHistory = (0, repo_1.collectAiChangeHistory)(process.cwd());
|
|
2555
|
+
// 記録ページの「更新履歴」。engine が毎晩書く帳簿(ledger-dir の gold-change-log.json)だけを読む(git は読まない)。
|
|
2556
|
+
// 無い・壊れ・版違いは null で、画面は「更新履歴はまだありません」の 1 つの形になる
|
|
2557
|
+
const changeLog = await (0, change_log_1.readChangeLog)(repoRoot, ledgerDir);
|
|
2606
2558
|
// ストーリー(#901 V2-5)の日本時間の今日。日・週・月の3つで同じ日にそろえるため1回だけ計算する
|
|
2607
2559
|
const storyToday = (0, story_1.todayJst)(new Date(opts.generatedAt));
|
|
2608
2560
|
// ストーリーの日々の動き(#901 V2-5)。帳簿で on の日のファイルが無ければ null(キーごと出さない)
|
|
2609
2561
|
const story = await (0, story_1.readStory)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null,
|
|
2610
2562
|
// 動きのない日を埋める終点=ビルドの時刻の日本時間の日付(時計を注入できる)
|
|
2611
|
-
storyToday);
|
|
2563
|
+
storyToday, ledgerDir);
|
|
2612
2564
|
// 週・月のあらすじ(#901)。週・月のファイルが無ければ null(キーごと出さない=今までと同じ画面)
|
|
2613
|
-
const storyDigest = await (0, story_1.readStoryDigest)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null, storyToday);
|
|
2565
|
+
const storyDigest = await (0, story_1.readStoryDigest)(repoRoot, renderGroundingSection, (p) => repo.baseUrl ? `${repo.baseUrl}/edit/${repo.branch}/${encodePath(p)}` : null, storyToday, ledgerDir);
|
|
2614
2566
|
// 案件アイコン(#348)。Cortex構成でなければ undefined(旧レイアウトには置き場が無い)
|
|
2615
2567
|
const projectIcon = await findProjectIcon(knowledgeRoot);
|
|
2616
2568
|
const site = {
|
|
@@ -2667,7 +2619,7 @@ async function build(opts) {
|
|
|
2667
2619
|
// null(無い・壊れ・version違い)は undefined へ落とす——SiteData の
|
|
2668
2620
|
// 「知らないことはキーが無いことで表す」に合わせる(空の器を通さない)
|
|
2669
2621
|
// 空の器は通さない(0件なら undefined = キーごと出さない)
|
|
2670
|
-
|
|
2622
|
+
changeLog: changeLog ?? undefined,
|
|
2671
2623
|
// 載せる日が無い案件(帳簿なし・壊れ・shadow の日だけ・ファイルなし)はキーごと出さない
|
|
2672
2624
|
story: story ?? undefined,
|
|
2673
2625
|
storyDigest: storyDigest ?? undefined,
|
|
@@ -0,0 +1,187 @@
|
|
|
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.CHANGE_LOG_MAX_ROWS = exports.CHANGE_LOG_VERSION = exports.CHANGE_LOG_FILE = void 0;
|
|
7
|
+
exports.isCleanUrl = isCleanUrl;
|
|
8
|
+
exports.jstDay = jstDay;
|
|
9
|
+
exports.parseChangeLog = parseChangeLog;
|
|
10
|
+
exports.readChangeLog = readChangeLog;
|
|
11
|
+
/**
|
|
12
|
+
* 記録ページの「更新履歴」の材料(cortex-engine #1094 便 35b-1 U2・設計 D3)。
|
|
13
|
+
*
|
|
14
|
+
* 読むのは engine が毎晩書く帳簿 `gold-change-log.json`(ledger-dir の下)だけ。git は読まない。
|
|
15
|
+
* 形の契約は engine `test/fixtures/change-log-contract.json`(tools の `viewer/test/fixtures/` へ配られる)。
|
|
16
|
+
*
|
|
17
|
+
* ## 🔴 読めなければ空(縮退は 1 つの形)
|
|
18
|
+
*
|
|
19
|
+
* 帳簿が無い・壊れ・版違い・形違いは `null`(画面は「更新履歴はまだありません」。今の欄には戻さない)。
|
|
20
|
+
* 1 行でも契約に反すれば全体を捨てる(engine は書く前に同じ基準で検査するので、viewer を engine より厳しくしない)。
|
|
21
|
+
*
|
|
22
|
+
* ## 🔴 禁止語の表は写さない
|
|
23
|
+
*
|
|
24
|
+
* 機械の語(frontmatter・commit …)を `what` に出さない番人は engine の持ち物(`hasForbiddenTerm`)。
|
|
25
|
+
* 写すと表が 2 つになるので、ここは**構造・表示の安全・メールの形・Operated-By**だけを見る。
|
|
26
|
+
*
|
|
27
|
+
* ## 日付
|
|
28
|
+
*
|
|
29
|
+
* `at` は git の author date(作者のオフセット付き)。engine は同じ日のまとめを JST で行うので、画面の日付も
|
|
30
|
+
* **固定 +9 時間の UTC 算術**で JST に直す(閲覧者のタイムゾーンに依存しない・Date の地域表示は使わない)。
|
|
31
|
+
*/
|
|
32
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
33
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
34
|
+
const ledger_dir_1 = require("./ledger-dir");
|
|
35
|
+
/** 置き場(engine `scripts/gold/change-log.mjs` の `CHANGE_LOG_PATH`) */
|
|
36
|
+
exports.CHANGE_LOG_FILE = "gold-change-log.json";
|
|
37
|
+
/** 形の版(engine の `CHANGE_LOG_VERSION`。違ったら読まない) */
|
|
38
|
+
exports.CHANGE_LOG_VERSION = 1;
|
|
39
|
+
/** 1 記録で画面に渡す行数の上限(窓の `per_record` と同じ 50) */
|
|
40
|
+
exports.CHANGE_LOG_MAX_ROWS = 50;
|
|
41
|
+
/** `why` は 1 行 3 本まで(engine の `WHY_MAX`) */
|
|
42
|
+
const WHY_MAX = 3;
|
|
43
|
+
/** 載る記録のパス(4 区画の記録。README・雛形・入れ子は載らない) */
|
|
44
|
+
const RECORD_PATH = /^Cortex\/(Decisions|Glossary|Members|Rules)\/records\/[^/]+\.md$/;
|
|
45
|
+
const isObj = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
46
|
+
/** メールの形(URL の部分を除いて見る) */
|
|
47
|
+
// engine `change-log.mjs` の定義と同じ(緩めると、URL の後ろのメールや非 ASCII のローカル部が通る)
|
|
48
|
+
const URL_IN_TEXT_RE = /https?:\/\/[^\s"'<>)\]]+/g;
|
|
49
|
+
const EMAIL_RE = /[^\s@/:]+@[^\s@/:]+\.[^\s@/:]+/;
|
|
50
|
+
const hasEmailShape = (text) => EMAIL_RE.test(text.replace(URL_IN_TEXT_RE, " "));
|
|
51
|
+
/**
|
|
52
|
+
* `why.url` の検査(engine `cleanUrl` と同じ述語)。http(s) だけ・userinfo なし・クエリとフラグメントなし・
|
|
53
|
+
* 正規化しても同じ文字列。`javascript:` や `mailto:` は通らない
|
|
54
|
+
*/
|
|
55
|
+
function isCleanUrl(raw) {
|
|
56
|
+
if (typeof raw !== "string")
|
|
57
|
+
return false;
|
|
58
|
+
const s = raw.trim().replace(/[.,;:!?)\]>"'、。)」』]+$/u, "");
|
|
59
|
+
if (!/^https?:\/\//i.test(s))
|
|
60
|
+
return false;
|
|
61
|
+
let u;
|
|
62
|
+
try {
|
|
63
|
+
u = new URL(s);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (!/^https?:$/.test(u.protocol))
|
|
69
|
+
return false;
|
|
70
|
+
if (u.username || u.password)
|
|
71
|
+
return false;
|
|
72
|
+
u.search = "";
|
|
73
|
+
u.hash = "";
|
|
74
|
+
return u.toString() === raw;
|
|
75
|
+
}
|
|
76
|
+
/** 日本時間の `YYYY/M/D`。読めない値は `null` */
|
|
77
|
+
function jstDay(at) {
|
|
78
|
+
const t = Date.parse(at);
|
|
79
|
+
if (!Number.isFinite(t))
|
|
80
|
+
return null;
|
|
81
|
+
const d = new Date(t + 9 * 3600 * 1000);
|
|
82
|
+
return `${d.getUTCFullYear()}/${d.getUTCMonth() + 1}/${d.getUTCDate()}`;
|
|
83
|
+
}
|
|
84
|
+
const ROW_KEYS = ["at", "by", "what", "why", "commit"];
|
|
85
|
+
const BY_KINDS = ["member", "night", "unknown"];
|
|
86
|
+
const norm = (p) => p.normalize("NFC");
|
|
87
|
+
/** 中身を読む(投げない)。契約に 1 つでも反すれば `null` */
|
|
88
|
+
function parseChangeLog(text) {
|
|
89
|
+
let value;
|
|
90
|
+
try {
|
|
91
|
+
value = JSON.parse(text);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (!isObj(value) || value.version !== exports.CHANGE_LOG_VERSION)
|
|
97
|
+
return null;
|
|
98
|
+
if (Object.keys(value).some((k) => !["version", "window", "records"].includes(k)))
|
|
99
|
+
return null;
|
|
100
|
+
const w = value.window;
|
|
101
|
+
if (!isObj(w) || !Number.isInteger(w.days) || w.days <= 0 || !Number.isInteger(w.per_record) || w.per_record <= 0)
|
|
102
|
+
return null;
|
|
103
|
+
if (!isObj(value.records))
|
|
104
|
+
return null;
|
|
105
|
+
const rows = Object.create(null);
|
|
106
|
+
let seq = 0;
|
|
107
|
+
for (const rec of Object.values(value.records)) {
|
|
108
|
+
if (!isObj(rec))
|
|
109
|
+
return null;
|
|
110
|
+
if (Object.keys(rec).some((k) => k !== "path" && k !== "rows"))
|
|
111
|
+
return null;
|
|
112
|
+
if (typeof rec.path !== "string" || !rec.path || !Array.isArray(rec.rows))
|
|
113
|
+
return null;
|
|
114
|
+
const recPath = norm(rec.path);
|
|
115
|
+
const out = [];
|
|
116
|
+
for (const r of rec.rows) {
|
|
117
|
+
if (!isObj(r))
|
|
118
|
+
return null;
|
|
119
|
+
if (Object.keys(r).some((k) => !ROW_KEYS.includes(k)))
|
|
120
|
+
return null;
|
|
121
|
+
if (typeof r.at !== "string")
|
|
122
|
+
return null;
|
|
123
|
+
const t = Date.parse(r.at);
|
|
124
|
+
const day = jstDay(r.at);
|
|
125
|
+
if (!Number.isFinite(t) || !day)
|
|
126
|
+
return null;
|
|
127
|
+
const by = r.by;
|
|
128
|
+
if (!isObj(by) || typeof by.kind !== "string" || !BY_KINDS.includes(by.kind))
|
|
129
|
+
return null;
|
|
130
|
+
if (Object.keys(by).some((k) => k !== "kind" && k !== "member"))
|
|
131
|
+
return null;
|
|
132
|
+
if (by.kind === "member" && (typeof by.member !== "string" || !by.member))
|
|
133
|
+
return null;
|
|
134
|
+
if (by.kind !== "member" && "member" in by)
|
|
135
|
+
return null;
|
|
136
|
+
if (typeof r.what !== "string" || !r.what)
|
|
137
|
+
return null;
|
|
138
|
+
if (!/^[0-9a-f]{7,64}$/.test(String(r.commit ?? "")))
|
|
139
|
+
return null;
|
|
140
|
+
if (!Array.isArray(r.why) || r.why.length > WHY_MAX)
|
|
141
|
+
return null;
|
|
142
|
+
const why = [];
|
|
143
|
+
for (const x of r.why) {
|
|
144
|
+
if (!isObj(x) || Object.keys(x).some((k) => k !== "label" && k !== "url"))
|
|
145
|
+
return null;
|
|
146
|
+
if (typeof x.label !== "string" || !x.label || !isCleanUrl(x.url))
|
|
147
|
+
return null;
|
|
148
|
+
why.push({ label: x.label, url: x.url });
|
|
149
|
+
}
|
|
150
|
+
const row = {
|
|
151
|
+
day, who: by.kind, what: r.what, why, commit: r.commit, _t: t, _i: seq++,
|
|
152
|
+
};
|
|
153
|
+
if (by.kind === "member")
|
|
154
|
+
row.member = by.member;
|
|
155
|
+
out.push(row);
|
|
156
|
+
}
|
|
157
|
+
// 記録の鍵(id)の綴りは走査しない。載る記録のパスの形でないものは捨てる(__proto__ などの鍵も入らない)
|
|
158
|
+
if (!RECORD_PATH.test(recPath))
|
|
159
|
+
continue;
|
|
160
|
+
(rows[recPath] ||= []).push(...out);
|
|
161
|
+
}
|
|
162
|
+
// メール・Operated-By は行の中のどこにも持たない(URL の部分を除いたメールの形も)
|
|
163
|
+
const rowsText = JSON.stringify([value.window, ...Object.values(value.records).map((r) => (isObj(r) ? r.rows : null))]);
|
|
164
|
+
if (hasEmailShape(rowsText) || /operated-by/i.test(rowsText))
|
|
165
|
+
return null;
|
|
166
|
+
const result = { windowDays: w.days, rows: {} };
|
|
167
|
+
for (const [p, list] of Object.entries(rows)) {
|
|
168
|
+
// 新しい順(時刻の数値で・同じ時刻は元の並びのまま)→ 50 行で切る
|
|
169
|
+
list.sort((a, b) => b._t - a._t || a._i - b._i);
|
|
170
|
+
result.rows[p] = list.slice(0, exports.CHANGE_LOG_MAX_ROWS).map(({ _t, _i, ...row }) => row);
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
/** 案件リポから読む。無い → `null`(黙る)・壊れている → `null`(build のログに 1 行) */
|
|
175
|
+
async function readChangeLog(repoRoot, ledgerDir) {
|
|
176
|
+
let text;
|
|
177
|
+
try {
|
|
178
|
+
text = await promises_1.default.readFile(node_path_1.default.join((0, ledger_dir_1.ledgerDirOf)(repoRoot, ledgerDir), exports.CHANGE_LOG_FILE), "utf8");
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const parsed = parseChangeLog(text);
|
|
184
|
+
if (!parsed)
|
|
185
|
+
console.warn(`${exports.CHANGE_LOG_FILE}: 読めないので、記録ページの更新履歴は「まだありません」と出します`);
|
|
186
|
+
return parsed;
|
|
187
|
+
}
|
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 の 10 本)の置き場(未指定なら <リポジトリルート>/.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
|
+
* ビューアが読む帳簿(10 本)の置き場(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
|
+
}
|