watashi-db 0.0.7 → 0.0.8
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 +120 -63
- package/Usersj.miyamoto.watashi-dbdefault.db +0 -0
- package/cowork-plugin/.claude-plugin/plugin.json +1 -1
- package/cowork-plugin/.mcp.json +1 -1
- package/cowork-plugin/hooks/hooks.json +7 -0
- package/cowork-plugin/skills/recall/SKILL.md +6 -3
- package/dist/config/loader.js +25 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +53 -0
- package/dist/config/schema.js +9 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/config/validator.js +11 -0
- package/dist/config/validator.js.map +1 -1
- package/dist/constants.d.ts +9 -1
- package/dist/constants.js +51 -3
- package/dist/constants.js.map +1 -1
- package/dist/context-pack.d.ts +7 -2
- package/dist/context-pack.js +137 -31
- package/dist/context-pack.js.map +1 -1
- package/dist/database/archive.d.ts +39 -0
- package/dist/database/archive.js +180 -0
- package/dist/database/archive.js.map +1 -0
- package/dist/database/groom.d.ts +39 -0
- package/dist/database/groom.js +246 -0
- package/dist/database/groom.js.map +1 -0
- package/dist/database/maintain.d.ts +39 -0
- package/dist/database/maintain.js +62 -0
- package/dist/database/maintain.js.map +1 -0
- package/dist/database/queries-core.d.ts +320 -12
- package/dist/database/queries-core.js +1834 -56
- package/dist/database/queries-core.js.map +1 -1
- package/dist/database/queries.d.ts +213 -12
- package/dist/database/queries.js +109 -0
- package/dist/database/queries.js.map +1 -1
- package/dist/database/schema.js +4199 -1
- package/dist/database/schema.js.map +1 -1
- package/dist/embedding/embed-on-write.d.ts +98 -0
- package/dist/embedding/embed-on-write.js +104 -0
- package/dist/embedding/embed-on-write.js.map +1 -0
- package/dist/embedding/ollama.d.ts +18 -0
- package/dist/embedding/ollama.js +67 -0
- package/dist/embedding/ollama.js.map +1 -0
- package/dist/embedding/openai.d.ts +17 -0
- package/dist/embedding/openai.js +77 -0
- package/dist/embedding/openai.js.map +1 -0
- package/dist/embedding/provider.d.ts +34 -0
- package/dist/embedding/provider.js +92 -0
- package/dist/embedding/provider.js.map +1 -0
- package/dist/embedding/search.d.ts +61 -0
- package/dist/embedding/search.js +165 -0
- package/dist/embedding/search.js.map +1 -0
- package/dist/embedding/similarity.d.ts +21 -0
- package/dist/embedding/similarity.js +48 -0
- package/dist/embedding/similarity.js.map +1 -0
- package/dist/embedding/transformers-local.d.ts +24 -0
- package/dist/embedding/transformers-local.js +65 -0
- package/dist/embedding/transformers-local.js.map +1 -0
- package/dist/embedding/types.d.ts +27 -0
- package/dist/embedding/types.js +6 -0
- package/dist/embedding/types.js.map +1 -0
- package/dist/hook.d.ts +54 -1
- package/dist/hook.js +560 -7
- package/dist/hook.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/policy.d.ts +7 -1
- package/dist/policy.js +30 -0
- package/dist/policy.js.map +1 -1
- package/dist/project-detect.d.ts +8 -0
- package/dist/project-detect.js +36 -0
- package/dist/project-detect.js.map +1 -0
- package/dist/prompts/bootstrap-prompts.js +48 -0
- package/dist/prompts/bootstrap-prompts.js.map +1 -1
- package/dist/resources/config-guide-content.d.ts +7 -0
- package/dist/resources/config-guide-content.js +180 -0
- package/dist/resources/config-guide-content.js.map +1 -0
- package/dist/resources/context-resources.js +18 -1
- package/dist/resources/context-resources.js.map +1 -1
- package/dist/server-instructions.js +60 -3
- package/dist/server-instructions.js.map +1 -1
- package/dist/server.js +26 -18
- package/dist/server.js.map +1 -1
- package/dist/setup.d.ts +14 -0
- package/dist/setup.js +132 -10
- package/dist/setup.js.map +1 -1
- package/dist/store/federation.d.ts +126 -2
- package/dist/store/federation.js +719 -2
- package/dist/store/federation.js.map +1 -1
- package/dist/store/merge.d.ts +11 -0
- package/dist/store/merge.js +38 -8
- package/dist/store/merge.js.map +1 -1
- package/dist/store/session-state.d.ts +12 -0
- package/dist/store/session-state.js +27 -1
- package/dist/store/session-state.js.map +1 -1
- package/dist/store/sync-manager.d.ts +7 -5
- package/dist/store/sync-manager.js +134 -58
- package/dist/store/sync-manager.js.map +1 -1
- package/dist/tools/claim-tools.d.ts +7 -1
- package/dist/tools/claim-tools.js +328 -178
- package/dist/tools/claim-tools.js.map +1 -1
- package/dist/tools/decision-tools.d.ts +3 -2
- package/dist/tools/decision-tools.js +48 -131
- package/dist/tools/decision-tools.js.map +1 -1
- package/dist/tools/episode-tools.d.ts +2 -3
- package/dist/tools/episode-tools.js +59 -130
- package/dist/tools/episode-tools.js.map +1 -1
- package/dist/tools/export-tools.d.ts +7 -1
- package/dist/tools/export-tools.js +90 -68
- package/dist/tools/export-tools.js.map +1 -1
- package/dist/tools/get-tools.d.ts +11 -0
- package/dist/tools/get-tools.js +282 -0
- package/dist/tools/get-tools.js.map +1 -0
- package/dist/tools/groom-tools.d.ts +13 -0
- package/dist/tools/groom-tools.js +197 -0
- package/dist/tools/groom-tools.js.map +1 -0
- package/dist/tools/helpers.d.ts +10 -0
- package/dist/tools/helpers.js +10 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/insight-tools.d.ts +11 -0
- package/dist/tools/insight-tools.js +167 -0
- package/dist/tools/insight-tools.js.map +1 -0
- package/dist/tools/knowledge-tools.d.ts +7 -0
- package/dist/tools/knowledge-tools.js +151 -0
- package/dist/tools/knowledge-tools.js.map +1 -0
- package/dist/tools/maintenance-tools.d.ts +11 -0
- package/dist/tools/maintenance-tools.js +1074 -0
- package/dist/tools/maintenance-tools.js.map +1 -0
- package/dist/tools/memo-tools.d.ts +15 -0
- package/dist/tools/memo-tools.js +370 -0
- package/dist/tools/memo-tools.js.map +1 -0
- package/dist/tools/model-tools.d.ts +11 -0
- package/dist/tools/model-tools.js +175 -0
- package/dist/tools/model-tools.js.map +1 -0
- package/dist/tools/profile-tools.d.ts +13 -1
- package/dist/tools/profile-tools.js +80 -113
- package/dist/tools/profile-tools.js.map +1 -1
- package/dist/tools/promote-tools.js +91 -4
- package/dist/tools/promote-tools.js.map +1 -1
- package/dist/tools/query-tools.d.ts +13 -1
- package/dist/tools/query-tools.js +358 -121
- package/dist/tools/query-tools.js.map +1 -1
- package/dist/tools/store-tools.d.ts +5 -2
- package/dist/tools/store-tools.js +94 -74
- package/dist/tools/store-tools.js.map +1 -1
- package/dist/tools/theory-tools.js +24 -0
- package/dist/tools/theory-tools.js.map +1 -1
- package/dist/types.d.ts +641 -229
- package/dist/types.js +186 -134
- package/dist/types.js.map +1 -1
- package/misc/work-notes/main 20260224.txt +98 -0
- package/misc/work-notes/plans/20260220084456_UNKNOWN_Issue-#24-Episode/343/202/277/343/202/244/343/203/210/343/203/253/343/201/256-Qiita/346/226/271/345/274/217/343/202/254/343/202/244.md +52 -0
- package/misc/work-notes/plans/20260220095602_UNKNOWN_Issue-#10-/346/233/270/343/201/215/350/276/274/343/201/277/346/231/202/343/201/256/343/202/263/343/203/263/343/203/206/343/203/263/343/203/204Lint/346/251/237.md +120 -0
- package/misc/work-notes/plans/20260220100439_UNKNOWN_Issue-#10-/346/233/270/343/201/215/350/276/274/343/201/277/346/231/202/343/201/256/343/202/263/343/203/263/343/203/206/343/203/263/343/203/204Lint/346/251/237.md +156 -0
- package/misc/work-notes/plans/20260220110445_UNKNOWN_Issue-#11-/343/203/227/343/203/255/343/203/225/343/202/241/343/202/244/343/203/253/350/246/201/347/264/204/343/201/256/343/202/271/343/202/263/343/202/242/343/203/252/303/243.md +154 -0
- package/misc/work-notes/plans/20260220114035_UNKNOWN_Issue-#15-/343/202/263/343/203/263/343/203/206/343/202/255/343/202/271/343/203/210/344/272/210/347/256/227API/357/274/210token-budg.md +178 -0
- package/misc/work-notes/plans/20260220133902_UNKNOWN_Issue-#16-/343/202/257/343/203/251/343/202/244/343/202/242/343/203/263/343/203/210/345/210/245/343/203/235/343/203/252/343/202/267/343/203/274/345/261/244/357/274/210r.md +284 -0
- package/misc/work-notes/plans/20260220151356_UNKNOWN_Issue-#28-V9/343/203/236/343/202/244/343/202/260/343/203/254/343/203/274/343/202/267/343/203/247/343/203/263/347/265/261/345/220/210/357/274/210#23-+.md +178 -0
- package/misc/work-notes/plans/20260227042805_UNKNOWN_config.json-/343/202/254/343/202/244/343/203/211/346/225/264/345/202/231-+-MCP-resourceprompt-/303/250.md +90 -0
- package/misc/work-notes/plans/20260302113135_UNKNOWN_MCP/343/203/204/343/203/274/343/203/253/343/203/210/343/203/274/343/202/257/343/203/263/343/203/200/343/202/244/343/202/250/343/203/203/343/203/210-(~17,370-/303/242.md +152 -0
- package/misc/work-notes/plans/20260302151940_UNKNOWN_README.md-/347/217/276/350/241/214API/345/217/215/346/230/240/343/202/242/343/203/203/343/203/227/343/203/207/343/203/274/343/203/210.md +87 -0
- package/misc/work-notes/plans/20260302173113_UNKNOWN_watashi-manage-claim-/343/202/250/343/203/251/343/203/274/346/224/271/345/226/204-+-search-summ.md +70 -0
- package/misc/work-notes/plans/20260303091511_UNKNOWN_Issue-#60-entity-type-/347/234/201/347/225/245/345/257/276/345/277/234-/342/200/224-ID/345/206/205/351/203/250/350/247/243.md +205 -0
- package/misc/work-notes/plans/20260304152700_UNKNOWN_Issue-#61-setup-/343/202/263/343/203/236/343/203/263/343/203/211/343/201/247-MCP-/343/202/265/343/203/274/343/203/220/343/203/274/303/247/302/231.md +67 -0
- package/misc/work-notes/plans/20260304170153_UNKNOWN_Issue-#54-user-memoplanissue-/343/201/256-content-/342/206/222-l1-co.md +76 -0
- package/package.json +12 -2
- package/scripts/backfill-search-summary.mjs +219 -0
- package/scripts/migrate-theories.mjs +231 -0
- package/{watashi-db-cowork-plugin.zip → watashi-db-plugin.zip} +0 -0
- package/dist/config/instance.d.ts +0 -10
- package/dist/config/instance.js +0 -39
- package/dist/config/instance.js.map +0 -1
- package/dist/config/types.d.ts +0 -116
- package/dist/config/types.js +0 -37
- package/dist/config/types.js.map +0 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ログアーカイブ機能
|
|
3
|
+
* 古い audit_log / claim_history レコードを別SQLiteファイルに移動
|
|
4
|
+
*
|
|
5
|
+
* 2026-02-22 新規作成 (Issue #21): 監査ログアーカイブ戦略
|
|
6
|
+
*/
|
|
7
|
+
import Database from "better-sqlite3";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { ulid } from "ulid";
|
|
10
|
+
/** アーカイブ対象テーブル(Phase 1) */
|
|
11
|
+
export const ARCHIVABLE_TABLES = ["audit_log", "claim_history"];
|
|
12
|
+
/**
|
|
13
|
+
* カットオフ日時を計算する(現在時刻から指定日数前)
|
|
14
|
+
*/
|
|
15
|
+
export function computeCutoffDate(olderThanDays) {
|
|
16
|
+
const cutoff = new Date();
|
|
17
|
+
cutoff.setDate(cutoff.getDate() - olderThanDays);
|
|
18
|
+
return cutoff.toISOString();
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* アーカイブ対象のレコード数をカウントする
|
|
22
|
+
*/
|
|
23
|
+
export function countArchiveTargets(db, cutoffDate, tables) {
|
|
24
|
+
const counts = { audit_log: 0, claim_history: 0 };
|
|
25
|
+
for (const table of tables) {
|
|
26
|
+
// audit_log は created_at、claim_history は changed_at で判定
|
|
27
|
+
const dateColumn = table === "audit_log" ? "created_at" : "changed_at";
|
|
28
|
+
const row = db.prepare(`SELECT COUNT(*) AS cnt FROM "${table}" WHERE "${dateColumn}" < ?`).get(cutoffDate);
|
|
29
|
+
counts[table] = row.cnt;
|
|
30
|
+
}
|
|
31
|
+
return counts;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* アーカイブDBを初期化する(元DBと同一テーブル構造 + archive_meta)
|
|
35
|
+
*/
|
|
36
|
+
export function initializeArchiveDb(archivePath, cutoffDate) {
|
|
37
|
+
const archiveDb = new Database(archivePath);
|
|
38
|
+
archiveDb.pragma("journal_mode = WAL");
|
|
39
|
+
// FK制約なし(アーカイブDBは参照先テーブルを持たないため)
|
|
40
|
+
archiveDb.pragma("foreign_keys = OFF");
|
|
41
|
+
archiveDb.exec(`
|
|
42
|
+
-- アーカイブメタデータ
|
|
43
|
+
CREATE TABLE IF NOT EXISTS archive_meta (
|
|
44
|
+
key TEXT PRIMARY KEY,
|
|
45
|
+
value TEXT NOT NULL
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
-- audit_log: 元DBと同一構造(FK制約なし)
|
|
49
|
+
CREATE TABLE IF NOT EXISTS audit_log (
|
|
50
|
+
id TEXT PRIMARY KEY,
|
|
51
|
+
operation TEXT NOT NULL,
|
|
52
|
+
entity_type TEXT NOT NULL,
|
|
53
|
+
entity_id TEXT NOT NULL,
|
|
54
|
+
summary TEXT NOT NULL,
|
|
55
|
+
details TEXT,
|
|
56
|
+
client_name TEXT,
|
|
57
|
+
client_version TEXT,
|
|
58
|
+
session_id TEXT,
|
|
59
|
+
source_tool TEXT,
|
|
60
|
+
created_at TEXT NOT NULL,
|
|
61
|
+
client_id TEXT
|
|
62
|
+
);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_archive_audit_created ON audit_log(created_at);
|
|
64
|
+
|
|
65
|
+
-- claim_history: 元DBと同一構造(FK制約なし)
|
|
66
|
+
CREATE TABLE IF NOT EXISTS claim_history (
|
|
67
|
+
id TEXT PRIMARY KEY,
|
|
68
|
+
claim_id TEXT NOT NULL,
|
|
69
|
+
field_name TEXT NOT NULL,
|
|
70
|
+
old_value TEXT,
|
|
71
|
+
new_value TEXT,
|
|
72
|
+
reason TEXT NOT NULL,
|
|
73
|
+
changed_at TEXT NOT NULL,
|
|
74
|
+
created_at TEXT NOT NULL
|
|
75
|
+
);
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_archive_history_changed ON claim_history(changed_at);
|
|
77
|
+
`);
|
|
78
|
+
// メタデータ記録
|
|
79
|
+
const now = new Date().toISOString();
|
|
80
|
+
archiveDb.prepare(`INSERT OR REPLACE INTO archive_meta (key, value) VALUES (?, ?)`).run("created_at", now);
|
|
81
|
+
archiveDb.prepare(`INSERT OR REPLACE INTO archive_meta (key, value) VALUES (?, ?)`).run("cutoff_date", cutoffDate);
|
|
82
|
+
archiveDb.prepare(`INSERT OR REPLACE INTO archive_meta (key, value) VALUES (?, ?)`).run("source", "watashi_archive_logs");
|
|
83
|
+
return archiveDb;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* アーカイブを実行する(レコードを別DBに移動し、元DBから削除)
|
|
87
|
+
*
|
|
88
|
+
* トランザクション内で ATTACH → INSERT → DELETE → DETACH を行う。
|
|
89
|
+
* claim_history は claims(id) へのFK参照があるため、削除時は foreign_keys を一時無効化する。
|
|
90
|
+
*/
|
|
91
|
+
export function executeArchive(db, archivePath, cutoffDate, tables, provenance) {
|
|
92
|
+
const counts = { audit_log: 0, claim_history: 0 };
|
|
93
|
+
// アーカイブDB初期化
|
|
94
|
+
const archiveDb = initializeArchiveDb(archivePath, cutoffDate);
|
|
95
|
+
archiveDb.close();
|
|
96
|
+
// FK一時無効化(claim_history の削除に必要)
|
|
97
|
+
db.pragma("foreign_keys = OFF");
|
|
98
|
+
try {
|
|
99
|
+
// ATTACH でアーカイブDBに接続
|
|
100
|
+
db.exec(`ATTACH DATABASE '${archivePath.replace(/'/g, "''")}' AS archive`);
|
|
101
|
+
try {
|
|
102
|
+
const transaction = db.transaction(() => {
|
|
103
|
+
for (const table of tables) {
|
|
104
|
+
const dateColumn = table === "audit_log" ? "created_at" : "changed_at";
|
|
105
|
+
// アーカイブDBにコピー
|
|
106
|
+
const insertResult = db.prepare(`
|
|
107
|
+
INSERT INTO archive."${table}"
|
|
108
|
+
SELECT * FROM main."${table}" WHERE "${dateColumn}" < ?
|
|
109
|
+
`).run(cutoffDate);
|
|
110
|
+
counts[table] = insertResult.changes;
|
|
111
|
+
// 元DBから削除
|
|
112
|
+
db.prepare(`DELETE FROM main."${table}" WHERE "${dateColumn}" < ?`).run(cutoffDate);
|
|
113
|
+
}
|
|
114
|
+
// アーカイブ操作自体を audit_log に記録
|
|
115
|
+
const auditId = ulid();
|
|
116
|
+
const now = new Date().toISOString();
|
|
117
|
+
db.prepare(`
|
|
118
|
+
INSERT INTO main.audit_log (id, operation, entity_type, entity_id, summary, details, client_name, client_version, session_id, source_tool, client_id, created_at)
|
|
119
|
+
VALUES (@id, @operation, @entity_type, @entity_id, @summary, @details, @client_name, @client_version, @session_id, @source_tool, @client_id, @created_at)
|
|
120
|
+
`).run({
|
|
121
|
+
id: auditId,
|
|
122
|
+
operation: "archive",
|
|
123
|
+
entity_type: "claim",
|
|
124
|
+
entity_id: path.basename(archivePath),
|
|
125
|
+
summary: `ログアーカイブ実行: audit_log=${counts.audit_log}, claim_history=${counts.claim_history}`,
|
|
126
|
+
details: JSON.stringify({
|
|
127
|
+
archive_path: archivePath,
|
|
128
|
+
cutoff_date: cutoffDate,
|
|
129
|
+
counts,
|
|
130
|
+
}),
|
|
131
|
+
client_name: provenance?.client_name ?? null,
|
|
132
|
+
client_version: provenance?.client_version ?? null,
|
|
133
|
+
session_id: provenance?.session_id ?? null,
|
|
134
|
+
source_tool: "watashi_archive_logs",
|
|
135
|
+
// 2026-03-03 追加 (V21): client_id
|
|
136
|
+
client_id: (() => {
|
|
137
|
+
try {
|
|
138
|
+
const row = db.prepare("SELECT value FROM store_meta WHERE key = 'client_id'").get();
|
|
139
|
+
return row?.value ?? null;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
})(),
|
|
145
|
+
created_at: now,
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
transaction();
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
db.exec("DETACH DATABASE archive");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
// FK制約を復元
|
|
156
|
+
db.pragma("foreign_keys = ON");
|
|
157
|
+
}
|
|
158
|
+
// アーカイブDBのメタデータにレコード数を記録
|
|
159
|
+
const archiveDb2 = new Database(archivePath);
|
|
160
|
+
try {
|
|
161
|
+
archiveDb2.prepare(`INSERT OR REPLACE INTO archive_meta (key, value) VALUES (?, ?)`).run("audit_log_count", String(counts.audit_log));
|
|
162
|
+
archiveDb2.prepare(`INSERT OR REPLACE INTO archive_meta (key, value) VALUES (?, ?)`).run("claim_history_count", String(counts.claim_history));
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
archiveDb2.close();
|
|
166
|
+
}
|
|
167
|
+
return counts;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* アーカイブファイル名を生成する
|
|
171
|
+
*/
|
|
172
|
+
export function generateArchiveFileName() {
|
|
173
|
+
const now = new Date();
|
|
174
|
+
const ts = now.toISOString()
|
|
175
|
+
.replace(/[-:]/g, "")
|
|
176
|
+
.replace("T", "_")
|
|
177
|
+
.slice(0, 15); // YYYYMMDD_HHMMSS
|
|
178
|
+
return `watashi_archive_${ts}.db`;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=archive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive.js","sourceRoot":"","sources":["../../src/database/archive.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claim棚卸(グルーミング)クエリ関数群
|
|
3
|
+
*
|
|
4
|
+
* 2026-02-22 新規作成 (Issue #22): Claim棚卸コマンド — 半自動メンテナンス機能
|
|
5
|
+
* 全active Claimを品質メトリクス付きで取得し、矛盾候補を検出する。
|
|
6
|
+
*/
|
|
7
|
+
import type Database from "better-sqlite3";
|
|
8
|
+
import type { GroomingClaimRow, ConflictCandidate, RetractImpactResult } from "../types.js";
|
|
9
|
+
/**
|
|
10
|
+
* 全active Claimを品質メトリクス付きで取得する
|
|
11
|
+
* staleness_scoreロジックはgetStaleClaims(queries-core.ts)と同一。
|
|
12
|
+
* ただし全Claimを返す(score=0の健全なClaimも含む)。
|
|
13
|
+
*/
|
|
14
|
+
export declare function getGroomingClaims(db: Database.Database, params: {
|
|
15
|
+
scope?: string;
|
|
16
|
+
category?: string;
|
|
17
|
+
}): GroomingClaimRow[];
|
|
18
|
+
/**
|
|
19
|
+
* 矛盾候補を検出する
|
|
20
|
+
* 同一 subject + predicate で異なる object を持つ active Claim ペア
|
|
21
|
+
*
|
|
22
|
+
* 2026-02-28 改善: 複数値述語フィルタを追加
|
|
23
|
+
* 元の実装: 同じ subject+predicate で object が違えば全て矛盾候補として返していた
|
|
24
|
+
* 問題: "user uses TypeScript/Java/Python/..." のような複数値述語が C(n,2) 組の
|
|
25
|
+
* 誤検出を生む(10件→45組)
|
|
26
|
+
* 変更: 同一 subject+predicate の active Claim が 2件ちょうどの場合のみ矛盾候補とする
|
|
27
|
+
* 3件以上は「複数の値を持つ述語」と判断し除外
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectConflicts(db: Database.Database, params: {
|
|
30
|
+
scope?: string;
|
|
31
|
+
category?: string;
|
|
32
|
+
}): ConflictCandidate[];
|
|
33
|
+
/**
|
|
34
|
+
* 2026-02-22 追加 (Issue #12): 撤回影響分析
|
|
35
|
+
* WITH RECURSIVE CTE で depends_on 関係を辿り、影響を受けるClaimを列挙する。
|
|
36
|
+
* depends_on の方向: A depends_on B = source=A, target=B → B撤回時にAが影響を受ける
|
|
37
|
+
*/
|
|
38
|
+
export declare function analyzeRetractImpact(db: Database.Database, claimId: string, maxDepth?: number): RetractImpactResult;
|
|
39
|
+
//# sourceMappingURL=groom.d.ts.map
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { computeClaimScore } from "../scoring.js";
|
|
2
|
+
/**
|
|
3
|
+
* 全active Claimを品質メトリクス付きで取得する
|
|
4
|
+
* staleness_scoreロジックはgetStaleClaims(queries-core.ts)と同一。
|
|
5
|
+
* ただし全Claimを返す(score=0の健全なClaimも含む)。
|
|
6
|
+
*/
|
|
7
|
+
export function getGroomingClaims(db, params) {
|
|
8
|
+
const conditions = ["c.status = 'active'"];
|
|
9
|
+
const values = {};
|
|
10
|
+
if (params.scope) {
|
|
11
|
+
conditions.push("c.scope = @scope");
|
|
12
|
+
values.scope = params.scope;
|
|
13
|
+
}
|
|
14
|
+
if (params.category) {
|
|
15
|
+
conditions.push("c.category = @category");
|
|
16
|
+
values.category = params.category;
|
|
17
|
+
}
|
|
18
|
+
const whereClause = conditions.join(" AND ");
|
|
19
|
+
const rows = db.prepare(`
|
|
20
|
+
SELECT c.*,
|
|
21
|
+
COALESCE(ec.cnt, 0) AS evidence_count,
|
|
22
|
+
COALESCE(cc.cnt, 0) AS check_count,
|
|
23
|
+
cc.last_check_at,
|
|
24
|
+
COALESCE(cc.has_failed, 0) AS has_failed,
|
|
25
|
+
COALESCE(cc.has_falsifier_eval, 0) AS has_falsifier_eval,
|
|
26
|
+
COALESCE(rc.cnt, 0) AS relation_count
|
|
27
|
+
FROM claims c
|
|
28
|
+
LEFT JOIN (
|
|
29
|
+
SELECT claim_id, COUNT(*) AS cnt FROM claim_evidence GROUP BY claim_id
|
|
30
|
+
) ec ON ec.claim_id = c.id
|
|
31
|
+
LEFT JOIN (
|
|
32
|
+
SELECT claim_id, COUNT(*) AS cnt, MAX(checked_at) AS last_check_at,
|
|
33
|
+
MAX(CASE WHEN result = 'failed' THEN 1 ELSE 0 END) AS has_failed,
|
|
34
|
+
MAX(CASE WHEN check_type = 'falsifier_eval' THEN 1 ELSE 0 END) AS has_falsifier_eval
|
|
35
|
+
FROM claim_checks GROUP BY claim_id
|
|
36
|
+
) cc ON cc.claim_id = c.id
|
|
37
|
+
LEFT JOIN (
|
|
38
|
+
SELECT claim_id, COUNT(*) AS cnt FROM (
|
|
39
|
+
SELECT source_claim_id AS claim_id FROM claim_relations
|
|
40
|
+
UNION ALL SELECT target_claim_id AS claim_id FROM claim_relations
|
|
41
|
+
) GROUP BY claim_id
|
|
42
|
+
) rc ON rc.claim_id = c.id
|
|
43
|
+
WHERE ${whereClause}
|
|
44
|
+
ORDER BY c.category, c.updated_at DESC
|
|
45
|
+
`).all(values);
|
|
46
|
+
const result = [];
|
|
47
|
+
for (const row of rows) {
|
|
48
|
+
const confidence = row.confidence;
|
|
49
|
+
const updatedAt = row.updated_at;
|
|
50
|
+
const evidence = row.evidence;
|
|
51
|
+
const falsifier = row.falsifier;
|
|
52
|
+
const hitCount = row.hit_count;
|
|
53
|
+
const checkCount = row.check_count;
|
|
54
|
+
const hasFailed = row.has_failed;
|
|
55
|
+
const hasFalsifierEval = row.has_falsifier_eval;
|
|
56
|
+
// staleness_score 計算(getStaleClaims と同一ロジック)
|
|
57
|
+
const reasons = [];
|
|
58
|
+
let score = 0;
|
|
59
|
+
// score_decayed: computeClaimScore < 0.5(30日以上経過)→ 最大30点
|
|
60
|
+
const claimScore = computeClaimScore(confidence, updatedAt);
|
|
61
|
+
if (claimScore < 0.5) {
|
|
62
|
+
reasons.push("score_decayed");
|
|
63
|
+
score += Math.round(30 * (1 - claimScore));
|
|
64
|
+
}
|
|
65
|
+
// low_confidence: confidence < 0.5 → 最大20点
|
|
66
|
+
if (confidence < 0.5) {
|
|
67
|
+
reasons.push("low_confidence");
|
|
68
|
+
score += Math.round(20 * (1 - confidence));
|
|
69
|
+
}
|
|
70
|
+
// never_hit: hit_count === 0 → 10点
|
|
71
|
+
if (hitCount === 0) {
|
|
72
|
+
reasons.push("never_hit");
|
|
73
|
+
score += 10;
|
|
74
|
+
}
|
|
75
|
+
// no_evidence: evidence === null → 10点
|
|
76
|
+
if (evidence === null) {
|
|
77
|
+
reasons.push("no_evidence");
|
|
78
|
+
score += 10;
|
|
79
|
+
}
|
|
80
|
+
// no_checks: 検証0件 → 15点
|
|
81
|
+
if (checkCount === 0) {
|
|
82
|
+
reasons.push("no_checks");
|
|
83
|
+
score += 15;
|
|
84
|
+
}
|
|
85
|
+
// falsifier_unevaluated: falsifier設定済みだが falsifier_eval 未実施 → 20点
|
|
86
|
+
if (falsifier && hasFalsifierEval === 0) {
|
|
87
|
+
reasons.push("falsifier_unevaluated");
|
|
88
|
+
score += 20;
|
|
89
|
+
}
|
|
90
|
+
// check_failed: 過去に検証失敗あり → 25点
|
|
91
|
+
if (hasFailed === 1) {
|
|
92
|
+
reasons.push("check_failed");
|
|
93
|
+
score += 25;
|
|
94
|
+
}
|
|
95
|
+
// suggested_action を決定(score=0 の場合は "ok")
|
|
96
|
+
let suggestedAction;
|
|
97
|
+
if (reasons.length === 0) {
|
|
98
|
+
suggestedAction = "ok";
|
|
99
|
+
}
|
|
100
|
+
else if (reasons.includes("check_failed")) {
|
|
101
|
+
suggestedAction = "retract_or_update";
|
|
102
|
+
}
|
|
103
|
+
else if (reasons.includes("falsifier_unevaluated")) {
|
|
104
|
+
suggestedAction = "evaluate_falsifier";
|
|
105
|
+
}
|
|
106
|
+
else if (reasons.includes("score_decayed") && reasons.includes("low_confidence")) {
|
|
107
|
+
suggestedAction = "review_and_confirm";
|
|
108
|
+
}
|
|
109
|
+
else if (reasons.includes("score_decayed")) {
|
|
110
|
+
suggestedAction = "confirm_or_update";
|
|
111
|
+
}
|
|
112
|
+
else if (reasons.includes("no_evidence")) {
|
|
113
|
+
suggestedAction = "add_evidence";
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
suggestedAction = "review";
|
|
117
|
+
}
|
|
118
|
+
result.push({
|
|
119
|
+
id: row.id,
|
|
120
|
+
subject: row.subject,
|
|
121
|
+
predicate: row.predicate,
|
|
122
|
+
object: row.object,
|
|
123
|
+
category: row.category,
|
|
124
|
+
scope: row.scope,
|
|
125
|
+
confidence,
|
|
126
|
+
evidence,
|
|
127
|
+
falsifier,
|
|
128
|
+
hit_count: hitCount,
|
|
129
|
+
search_summary: row.search_summary,
|
|
130
|
+
created_at: row.created_at,
|
|
131
|
+
updated_at: updatedAt,
|
|
132
|
+
staleness_score: score,
|
|
133
|
+
staleness_reasons: reasons,
|
|
134
|
+
suggested_action: suggestedAction,
|
|
135
|
+
evidence_count: row.evidence_count,
|
|
136
|
+
check_count: checkCount,
|
|
137
|
+
last_check_at: row.last_check_at,
|
|
138
|
+
relation_count: row.relation_count,
|
|
139
|
+
has_search_summary: row.search_summary != null,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 矛盾候補を検出する
|
|
146
|
+
* 同一 subject + predicate で異なる object を持つ active Claim ペア
|
|
147
|
+
*
|
|
148
|
+
* 2026-02-28 改善: 複数値述語フィルタを追加
|
|
149
|
+
* 元の実装: 同じ subject+predicate で object が違えば全て矛盾候補として返していた
|
|
150
|
+
* 問題: "user uses TypeScript/Java/Python/..." のような複数値述語が C(n,2) 組の
|
|
151
|
+
* 誤検出を生む(10件→45組)
|
|
152
|
+
* 変更: 同一 subject+predicate の active Claim が 2件ちょうどの場合のみ矛盾候補とする
|
|
153
|
+
* 3件以上は「複数の値を持つ述語」と判断し除外
|
|
154
|
+
*/
|
|
155
|
+
export function detectConflicts(db, params) {
|
|
156
|
+
const conditions = [
|
|
157
|
+
"c1.status = 'active'",
|
|
158
|
+
"c2.status = 'active'",
|
|
159
|
+
"c1.subject = c2.subject",
|
|
160
|
+
"c1.predicate = c2.predicate",
|
|
161
|
+
"c1.object != c2.object",
|
|
162
|
+
"c1.id < c2.id",
|
|
163
|
+
];
|
|
164
|
+
const values = {};
|
|
165
|
+
if (params.scope) {
|
|
166
|
+
conditions.push("c1.scope = @scope");
|
|
167
|
+
conditions.push("c2.scope = @scope");
|
|
168
|
+
values.scope = params.scope;
|
|
169
|
+
}
|
|
170
|
+
if (params.category) {
|
|
171
|
+
conditions.push("c1.category = @category");
|
|
172
|
+
conditions.push("c2.category = @category");
|
|
173
|
+
values.category = params.category;
|
|
174
|
+
}
|
|
175
|
+
const whereClause = conditions.join(" AND ");
|
|
176
|
+
return db.prepare(`
|
|
177
|
+
SELECT c1.id AS claim_a_id, c2.id AS claim_b_id,
|
|
178
|
+
c1.subject, c1.predicate,
|
|
179
|
+
c1.object AS object_a, c2.object AS object_b
|
|
180
|
+
FROM claims c1 JOIN claims c2
|
|
181
|
+
ON c1.subject = c2.subject AND c1.predicate = c2.predicate
|
|
182
|
+
AND c1.object != c2.object AND c1.id < c2.id
|
|
183
|
+
WHERE ${whereClause}
|
|
184
|
+
AND (SELECT COUNT(*) FROM claims c3
|
|
185
|
+
WHERE c3.subject = c1.subject
|
|
186
|
+
AND c3.predicate = c1.predicate
|
|
187
|
+
AND c3.status = 'active') = 2
|
|
188
|
+
`).all(values);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* 2026-02-22 追加 (Issue #12): 撤回影響分析
|
|
192
|
+
* WITH RECURSIVE CTE で depends_on 関係を辿り、影響を受けるClaimを列挙する。
|
|
193
|
+
* depends_on の方向: A depends_on B = source=A, target=B → B撤回時にAが影響を受ける
|
|
194
|
+
*/
|
|
195
|
+
export function analyzeRetractImpact(db, claimId, maxDepth = 10) {
|
|
196
|
+
const rows = db.prepare(`
|
|
197
|
+
WITH RECURSIVE downstream(claim_id, depth, rel_confidence) AS (
|
|
198
|
+
-- 起点: 対象Claimに depends_on しているClaim
|
|
199
|
+
SELECT cr.source_claim_id, 1, cr.confidence
|
|
200
|
+
FROM claim_relations cr
|
|
201
|
+
WHERE cr.target_claim_id = @claim_id AND cr.relation_type = 'depends_on'
|
|
202
|
+
UNION ALL
|
|
203
|
+
-- 再帰: さらに依存するClaimを辿る
|
|
204
|
+
SELECT cr.source_claim_id, d.depth + 1, cr.confidence
|
|
205
|
+
FROM claim_relations cr
|
|
206
|
+
JOIN downstream d ON cr.target_claim_id = d.claim_id
|
|
207
|
+
WHERE cr.relation_type = 'depends_on' AND d.depth < @max_depth
|
|
208
|
+
)
|
|
209
|
+
SELECT DISTINCT d.claim_id, d.depth, d.rel_confidence,
|
|
210
|
+
c.subject, c.predicate, c.object, c.category, c.scope, c.confidence
|
|
211
|
+
FROM downstream d
|
|
212
|
+
JOIN claims c ON c.id = d.claim_id
|
|
213
|
+
WHERE c.status = 'active'
|
|
214
|
+
AND d.claim_id != @claim_id -- 循環依存でターゲット自身が含まれるのを防止
|
|
215
|
+
ORDER BY d.depth, c.subject
|
|
216
|
+
`).all({ claim_id: claimId, max_depth: maxDepth });
|
|
217
|
+
// 同一Claimが複数回出現する場合は最も浅い depth を採用
|
|
218
|
+
const seen = new Map();
|
|
219
|
+
for (const row of rows) {
|
|
220
|
+
const existing = seen.get(row.claim_id);
|
|
221
|
+
if (!existing || row.depth < existing.depth) {
|
|
222
|
+
seen.set(row.claim_id, {
|
|
223
|
+
id: row.claim_id,
|
|
224
|
+
subject: row.subject,
|
|
225
|
+
predicate: row.predicate,
|
|
226
|
+
object: row.object,
|
|
227
|
+
category: row.category,
|
|
228
|
+
scope: row.scope,
|
|
229
|
+
confidence: row.confidence,
|
|
230
|
+
depth: row.depth,
|
|
231
|
+
relation_confidence: row.rel_confidence,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const allDependents = Array.from(seen.values());
|
|
236
|
+
const directDependents = allDependents.filter(d => d.depth === 1);
|
|
237
|
+
const transitiveDependents = allDependents.filter(d => d.depth >= 2);
|
|
238
|
+
return {
|
|
239
|
+
target_claim_id: claimId,
|
|
240
|
+
direct_dependents: directDependents,
|
|
241
|
+
transitive_dependents: transitiveDependents,
|
|
242
|
+
max_depth: maxDepth,
|
|
243
|
+
total_affected: allDependents.length,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=groom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groom.js","sourceRoot":"","sources":["../../src/database/groom.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,EAAqB,EACrB,MAA6C;IAE7C,MAAM,UAAU,GAAa,CAAC,qBAAqB,CAAC,CAAC;IACrD,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,UAAU,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC9B,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,UAAU,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC1C,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACpC,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;YAwBd,WAAW;;GAEpB,CAAC,CAAC,GAAG,CAAC,MAAM,CAAmC,CAAC;IAEjD,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,GAAG,CAAC,UAAoB,CAAC;QAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,UAAoB,CAAC;QAC3C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAyB,CAAC;QAC/C,MAAM,SAAS,GAAG,GAAG,CAAC,SAA0B,CAAC;QACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAmB,CAAC;QACzC,MAAM,UAAU,GAAG,GAAG,CAAC,WAAqB,CAAC;QAC7C,MAAM,SAAS,GAAG,GAAG,CAAC,UAAoB,CAAC;QAC3C,MAAM,gBAAgB,GAAG,GAAG,CAAC,kBAA4B,CAAC;QAE1D,6CAA6C;QAC7C,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,yDAAyD;QACzD,MAAM,UAAU,GAAG,iBAAiB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAC5D,IAAI,UAAU,GAAG,GAAG,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC9B,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;QAC7C,CAAC;QAED,2CAA2C;QAC3C,IAAI,UAAU,GAAG,GAAG,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC/B,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;QAC7C,CAAC;QAED,mCAAmC;QACnC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1B,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,uCAAuC;QACvC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5B,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,wBAAwB;QACxB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1B,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,kEAAkE;QAClE,IAAI,SAAS,IAAI,gBAAgB,KAAK,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YACtC,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,gCAAgC;QAChC,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC7B,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,0CAA0C;QAC1C,IAAI,eAAuB,CAAC;QAC5B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,eAAe,GAAG,IAAI,CAAC;QACzB,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC5C,eAAe,GAAG,mBAAmB,CAAC;QACxC,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACrD,eAAe,GAAG,oBAAoB,CAAC;QACzC,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACnF,eAAe,GAAG,oBAAoB,CAAC;QACzC,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YAC7C,eAAe,GAAG,mBAAmB,CAAC;QACxC,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC3C,eAAe,GAAG,cAAc,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,eAAe,GAAG,QAAQ,CAAC;QAC7B,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,GAAG,CAAC,EAAY;YACpB,OAAO,EAAE,GAAG,CAAC,OAAiB;YAC9B,SAAS,EAAE,GAAG,CAAC,SAAmB;YAClC,MAAM,EAAE,GAAG,CAAC,MAAgB;YAC5B,QAAQ,EAAE,GAAG,CAAC,QAAkB;YAChC,KAAK,EAAE,GAAG,CAAC,KAAe;YAC1B,UAAU;YACV,QAAQ;YACR,SAAS;YACT,SAAS,EAAE,QAAQ;YACnB,cAAc,EAAE,GAAG,CAAC,cAA+B;YACnD,UAAU,EAAE,GAAG,CAAC,UAAoB;YACpC,UAAU,EAAE,SAAS;YAErB,eAAe,EAAE,KAAK;YACtB,iBAAiB,EAAE,OAAO;YAC1B,gBAAgB,EAAE,eAAe;YAEjC,cAAc,EAAE,GAAG,CAAC,cAAwB;YAC5C,WAAW,EAAE,UAAU;YACvB,aAAa,EAAE,GAAG,CAAC,aAA8B;YACjD,cAAc,EAAE,GAAG,CAAC,cAAwB;YAC5C,kBAAkB,EAAE,GAAG,CAAC,cAAc,IAAI,IAAI;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC7B,EAAqB,EACrB,MAA6C;IAE7C,MAAM,UAAU,GAAa;QAC3B,sBAAsB;QACtB,sBAAsB;QACtB,yBAAyB;QACzB,6BAA6B;QAC7B,wBAAwB;QACxB,eAAe;KAChB,CAAC;IACF,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACrC,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC9B,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,UAAU,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC3C,UAAU,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACpC,CAAC;IAED,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAE7C,OAAO,EAAE,CAAC,OAAO,CAAC;;;;;;;YAOR,WAAW;;;;;GAKpB,CAAC,CAAC,GAAG,CAAC,MAAM,CAAwB,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,EAAqB,EACrB,OAAe,EACf,WAAmB,EAAE;IAErB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;GAoBvB,CAAC,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAU/C,CAAC;IAEH,mCAAmC;IACnC,MAAM,IAAI,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,IAAI,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;YAC5C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACrB,EAAE,EAAE,GAAG,CAAC,QAAQ;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,mBAAmB,EAAE,GAAG,CAAC,cAAc;aACxC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAChD,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;IAClE,MAAM,oBAAoB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IAErE,OAAO;QACL,eAAe,EAAE,OAAO;QACxB,iBAAiB,EAAE,gBAAgB;QACnC,qBAAqB,EAAE,oBAAoB;QAC3C,SAAS,EAAE,QAAQ;QACnB,cAAc,EAAE,aAAa,CAAC,MAAM;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DB保守ユーティリティ
|
|
3
|
+
* テーブル統計取得・PRAGMA optimize・VACUUM 実行
|
|
4
|
+
*
|
|
5
|
+
* 2026-02-22 新規作成 (Issue #21): 監査ログアーカイブ戦略
|
|
6
|
+
*/
|
|
7
|
+
import type Database from "better-sqlite3";
|
|
8
|
+
export interface TableStat {
|
|
9
|
+
table_name: string;
|
|
10
|
+
row_count: number;
|
|
11
|
+
}
|
|
12
|
+
export interface MaintainResult {
|
|
13
|
+
table_stats: TableStat[];
|
|
14
|
+
db_size_bytes: number;
|
|
15
|
+
vacuum_executed: boolean;
|
|
16
|
+
optimize_executed: boolean;
|
|
17
|
+
freed_bytes: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 全テーブルの行数を取得する
|
|
21
|
+
*/
|
|
22
|
+
export declare function getTableStats(db: Database.Database): TableStat[];
|
|
23
|
+
/**
|
|
24
|
+
* PRAGMA optimize を実行する
|
|
25
|
+
* SQLite の内部統計を更新し、クエリプランナーの精度を向上させる
|
|
26
|
+
*/
|
|
27
|
+
export declare function runOptimize(db: Database.Database): void;
|
|
28
|
+
/**
|
|
29
|
+
* VACUUM を実行して未使用ページを回収する
|
|
30
|
+
* ファイルベースDBでのみ有効。インメモリDBでは空き容量0を返す。
|
|
31
|
+
*/
|
|
32
|
+
export declare function runVacuum(db: Database.Database): {
|
|
33
|
+
freed_bytes: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* DBファイルサイズを取得する(インメモリDBの場合は0)
|
|
37
|
+
*/
|
|
38
|
+
export declare function getDbSizeBytes(db: Database.Database): number;
|
|
39
|
+
//# sourceMappingURL=maintain.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
/**
|
|
3
|
+
* 全テーブルの行数を取得する
|
|
4
|
+
*/
|
|
5
|
+
export function getTableStats(db) {
|
|
6
|
+
const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`).all();
|
|
7
|
+
return tables.map(({ name }) => {
|
|
8
|
+
const row = db.prepare(`SELECT COUNT(*) AS cnt FROM "${name}"`).get();
|
|
9
|
+
return { table_name: name, row_count: row.cnt };
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* PRAGMA optimize を実行する
|
|
14
|
+
* SQLite の内部統計を更新し、クエリプランナーの精度を向上させる
|
|
15
|
+
*/
|
|
16
|
+
export function runOptimize(db) {
|
|
17
|
+
db.pragma("optimize");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* VACUUM を実行して未使用ページを回収する
|
|
21
|
+
* ファイルベースDBでのみ有効。インメモリDBでは空き容量0を返す。
|
|
22
|
+
*/
|
|
23
|
+
export function runVacuum(db) {
|
|
24
|
+
const dbPath = db.name;
|
|
25
|
+
const isFileDb = dbPath !== ":memory:" && dbPath !== "";
|
|
26
|
+
let sizeBefore = 0;
|
|
27
|
+
if (isFileDb) {
|
|
28
|
+
try {
|
|
29
|
+
sizeBefore = fs.statSync(dbPath).size;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// ファイルが見つからない場合はサイズ0として扱う
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
db.exec("VACUUM");
|
|
36
|
+
let sizeAfter = 0;
|
|
37
|
+
if (isFileDb) {
|
|
38
|
+
try {
|
|
39
|
+
sizeAfter = fs.statSync(dbPath).size;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// ファイルが見つからない場合はサイズ0として扱う
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const freed = Math.max(0, sizeBefore - sizeAfter);
|
|
46
|
+
return { freed_bytes: freed };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* DBファイルサイズを取得する(インメモリDBの場合は0)
|
|
50
|
+
*/
|
|
51
|
+
export function getDbSizeBytes(db) {
|
|
52
|
+
const dbPath = db.name;
|
|
53
|
+
if (dbPath === ":memory:" || dbPath === "")
|
|
54
|
+
return 0;
|
|
55
|
+
try {
|
|
56
|
+
return fs.statSync(dbPath).size;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=maintain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintain.js","sourceRoot":"","sources":["../../src/database/maintain.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,SAAS,CAAC;AAezB;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,EAAqB;IACjD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CACvB,gGAAgG,CACjG,CAAC,GAAG,EAAwB,CAAC;IAE9B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,gCAAgC,IAAI,GAAG,CAAC,CAAC,GAAG,EAAqB,CAAC;QACzF,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,EAAqB;IAC/C,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,EAAqB;IAC7C,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,EAAE,CAAC;IAExD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,UAAU,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IAED,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAElB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,SAAS,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,CAAC;IAClD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,EAAqB;IAClD,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC;IACvB,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,CAAC,CAAC;IAErD,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|