watashi-db 0.0.11 → 0.0.13
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/LICENSE +71 -21
- package/README.md +9 -1
- package/cowork-plugin/skills/groom/SKILL.md +72 -0
- package/dist/config/schema.d.ts +21 -0
- package/dist/config/schema.js +4 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/config/validator.js +1 -0
- package/dist/config/validator.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/database/groom.js +5 -4
- package/dist/database/groom.js.map +1 -1
- package/dist/database/queries-core.d.ts +28 -2
- package/dist/database/queries-core.js +134 -17
- package/dist/database/queries-core.js.map +1 -1
- package/dist/database/queries.d.ts +18 -0
- package/dist/database/queries.js +7 -0
- package/dist/database/queries.js.map +1 -1
- package/dist/database/schema.d.ts +5 -0
- package/dist/database/schema.js +156 -1
- package/dist/database/schema.js.map +1 -1
- package/dist/embedding/embed-on-write.d.ts +3 -0
- package/dist/embedding/embed-on-write.js.map +1 -1
- package/dist/embedding/provider.d.ts +3 -0
- package/dist/embedding/provider.js +38 -1
- package/dist/embedding/provider.js.map +1 -1
- package/dist/hook.js +12 -2
- package/dist/hook.js.map +1 -1
- package/dist/resources/config-guide-content.d.ts +1 -1
- package/dist/resources/config-guide-content.js +5 -0
- package/dist/resources/config-guide-content.js.map +1 -1
- package/dist/server-instructions.js +3 -2
- package/dist/server-instructions.js.map +1 -1
- package/dist/server.js +10 -1
- package/dist/server.js.map +1 -1
- package/dist/store/federation.d.ts +21 -0
- package/dist/store/federation.js +56 -0
- package/dist/store/federation.js.map +1 -1
- package/dist/store/sync-manager.d.ts +3 -0
- package/dist/store/sync-manager.js +50 -28
- package/dist/store/sync-manager.js.map +1 -1
- package/dist/tools/claim-tools.js +1 -1
- package/dist/tools/claim-tools.js.map +1 -1
- package/dist/tools/decision-tools.js +11 -8
- package/dist/tools/decision-tools.js.map +1 -1
- package/dist/tools/episode-tools.js +13 -9
- package/dist/tools/episode-tools.js.map +1 -1
- package/dist/tools/maintenance-tools.d.ts +1 -0
- package/dist/tools/maintenance-tools.js +117 -6
- package/dist/tools/maintenance-tools.js.map +1 -1
- package/dist/tools/query-tools.js +34 -4
- package/dist/tools/query-tools.js.map +1 -1
- package/dist/types.d.ts +65 -59
- package/dist/types.js +36 -28
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/dist/database/schema.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
1
2
|
// スキーマバージョン管理
|
|
2
3
|
// 2026-02-11 修正: V2追加(L2 Core v0対応)
|
|
3
4
|
// 元の実装: SCHEMA_VERSION = 1(初期SPO三つ組 + FTS5 + decisions + claim_history)
|
|
@@ -29,9 +30,15 @@
|
|
|
29
30
|
// 2026-03-03 修正: V23追加(Claim に l1_content 追加 + embedding → l1_embedding リネーム — Issue #64)
|
|
30
31
|
// 2026-03-04 修正: V24追加(user_memo/plan/issue の content → l1_content + user_memos に user_input 追加 — Issue #54)
|
|
31
32
|
// 2026-03-06 修正: V25追加(user_issues に kind カラム追加 — Issue #74)
|
|
32
|
-
|
|
33
|
+
// 2026-03-13 修正: V28追加(evidence → l2_evidence, falsifier → l2_falsifier リネーム)
|
|
34
|
+
const SCHEMA_VERSION = 28;
|
|
33
35
|
/**
|
|
34
36
|
* データベーススキーマの初期化とマイグレーション
|
|
37
|
+
*
|
|
38
|
+
* 2026-03-14 修正: ファイルロックで排他制御
|
|
39
|
+
* 複数のMCPサーバーが同時起動した場合のレースコンディションを防止。
|
|
40
|
+
* ロックファイルが取得できない場合は一定時間リトライし、タイムアウト時はエラー。
|
|
41
|
+
* 注意: EXCLUSIVE トランザクションは使えない(applyVN 内で db.transaction() を使う箇所がありネスト不可)
|
|
35
42
|
*/
|
|
36
43
|
export function initializeSchema(db) {
|
|
37
44
|
// スキーマバージョン管理テーブル
|
|
@@ -43,6 +50,73 @@ export function initializeSchema(db) {
|
|
|
43
50
|
`);
|
|
44
51
|
const currentVersion = db.prepare("SELECT MAX(version) as version FROM schema_version").get();
|
|
45
52
|
const version = currentVersion?.version ?? 0;
|
|
53
|
+
if (version >= SCHEMA_VERSION) {
|
|
54
|
+
return; // 既に最新
|
|
55
|
+
}
|
|
56
|
+
// マイグレーションが必要 — ファイルロックで排他制御
|
|
57
|
+
const dbPath = db.name; // better-sqlite3: DBファイルパス(:memory: の場合は空文字列)
|
|
58
|
+
const isFileDb = dbPath && dbPath !== ":memory:" && dbPath !== "";
|
|
59
|
+
const lockPath = isFileDb ? dbPath + ".migration-lock" : null;
|
|
60
|
+
if (!isFileDb || !lockPath) {
|
|
61
|
+
// インメモリDBの場合はロック不要(テスト環境等)
|
|
62
|
+
_applyMigrations(db, version);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
let lockFd = null;
|
|
66
|
+
try {
|
|
67
|
+
// ロックファイル取得(リトライあり: 500ms × 20回 = 最大10秒)
|
|
68
|
+
for (let i = 0; i < 20; i++) {
|
|
69
|
+
try {
|
|
70
|
+
lockFd = fs.openSync(lockPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
|
|
71
|
+
break; // ロック取得成功
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
if (e.code === "EEXIST") {
|
|
75
|
+
// 別プロセスがマイグレーション中 — 待機
|
|
76
|
+
// ロックファイルが古すぎる場合(60秒以上)は強制削除(プロセスクラッシュ対応)
|
|
77
|
+
try {
|
|
78
|
+
const stat = fs.statSync(lockPath);
|
|
79
|
+
if (Date.now() - stat.mtimeMs > 60000) {
|
|
80
|
+
fs.unlinkSync(lockPath);
|
|
81
|
+
continue; // リトライ
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch { /* stat失敗 = 既に削除された */ }
|
|
85
|
+
// 500ms待機
|
|
86
|
+
const start = Date.now();
|
|
87
|
+
while (Date.now() - start < 500) { /* busy wait */ }
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
throw e; // 予期しないエラー
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (lockFd === null) {
|
|
95
|
+
throw new Error("[watashi-db] マイグレーションロックの取得に失敗しました(タイムアウト)");
|
|
96
|
+
}
|
|
97
|
+
// ロック取得後にバージョンを再チェック(別プロセスが先に完了した可能性)
|
|
98
|
+
const recheckVersion = db.prepare("SELECT MAX(version) as version FROM schema_version").get();
|
|
99
|
+
const currentVer = recheckVersion?.version ?? 0;
|
|
100
|
+
if (currentVer >= SCHEMA_VERSION) {
|
|
101
|
+
return; // 別プロセスが先にマイグレーション完了
|
|
102
|
+
}
|
|
103
|
+
_applyMigrations(db, currentVer);
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
// ロックファイル解放
|
|
107
|
+
if (lockFd !== null) {
|
|
108
|
+
fs.closeSync(lockFd);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
fs.unlinkSync(lockPath);
|
|
112
|
+
}
|
|
113
|
+
catch { /* 既に削除済み */ }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* マイグレーション本体(initializeSchema からファイルロック取得後に呼ばれる)
|
|
118
|
+
*/
|
|
119
|
+
function _applyMigrations(db, version) {
|
|
46
120
|
if (version < 1) {
|
|
47
121
|
applyV1(db);
|
|
48
122
|
}
|
|
@@ -124,6 +198,9 @@ export function initializeSchema(db) {
|
|
|
124
198
|
if (version < 27) {
|
|
125
199
|
applyV27(db);
|
|
126
200
|
}
|
|
201
|
+
if (version < 28) {
|
|
202
|
+
applyV28(db);
|
|
203
|
+
}
|
|
127
204
|
}
|
|
128
205
|
/**
|
|
129
206
|
* V1スキーマ: 初期テーブル構成
|
|
@@ -5499,6 +5576,84 @@ function applyV27(db) {
|
|
|
5499
5576
|
END
|
|
5500
5577
|
`);
|
|
5501
5578
|
}
|
|
5579
|
+
/**
|
|
5580
|
+
* V28: evidence → l2_evidence, falsifier → l2_falsifier リネーム + claims_fts 再構築
|
|
5581
|
+
* 冪等: 既に l2_evidence が存在する場合はリネームをスキップ
|
|
5582
|
+
*/
|
|
5583
|
+
function applyV28(db) {
|
|
5584
|
+
// カラムリネーム(冪等: 既にリネーム済みならスキップ)
|
|
5585
|
+
if (hasColumn(db, "claims", "evidence") && !hasColumn(db, "claims", "l2_evidence")) {
|
|
5586
|
+
db.exec(`ALTER TABLE claims RENAME COLUMN evidence TO l2_evidence`);
|
|
5587
|
+
}
|
|
5588
|
+
if (hasColumn(db, "claims", "falsifier") && !hasColumn(db, "claims", "l2_falsifier")) {
|
|
5589
|
+
db.exec(`ALTER TABLE claims RENAME COLUMN falsifier TO l2_falsifier`);
|
|
5590
|
+
}
|
|
5591
|
+
// claims_fts を再構築(l2_evidence/l2_falsifier 対応)
|
|
5592
|
+
db.exec(`
|
|
5593
|
+
DROP TRIGGER IF EXISTS claims_fts_insert;
|
|
5594
|
+
DROP TRIGGER IF EXISTS claims_fts_update;
|
|
5595
|
+
DROP TRIGGER IF EXISTS claims_fts_delete;
|
|
5596
|
+
DROP TABLE IF EXISTS claims_fts;
|
|
5597
|
+
|
|
5598
|
+
CREATE VIRTUAL TABLE claims_fts USING fts5(
|
|
5599
|
+
l2_subject, l2_predicate, l2_object, l2_evidence, l1_content, search_summary,
|
|
5600
|
+
content='claims', content_rowid='rowid', tokenize='trigram'
|
|
5601
|
+
);
|
|
5602
|
+
|
|
5603
|
+
-- FTS同期トリガー: INSERT
|
|
5604
|
+
CREATE TRIGGER claims_fts_insert AFTER INSERT ON claims BEGIN
|
|
5605
|
+
INSERT INTO claims_fts(rowid, l2_subject, l2_predicate, l2_object, l2_evidence, l1_content, search_summary)
|
|
5606
|
+
VALUES (new.rowid, new.l2_subject, new.l2_predicate, new.l2_object, new.l2_evidence, new.l1_content, new.search_summary);
|
|
5607
|
+
END;
|
|
5608
|
+
|
|
5609
|
+
-- FTS同期トリガー: UPDATE
|
|
5610
|
+
CREATE TRIGGER claims_fts_update AFTER UPDATE ON claims BEGIN
|
|
5611
|
+
INSERT INTO claims_fts(claims_fts, rowid, l2_subject, l2_predicate, l2_object, l2_evidence, l1_content, search_summary)
|
|
5612
|
+
VALUES ('delete', old.rowid, old.l2_subject, old.l2_predicate, old.l2_object, old.l2_evidence, old.l1_content, old.search_summary);
|
|
5613
|
+
INSERT INTO claims_fts(rowid, l2_subject, l2_predicate, l2_object, l2_evidence, l1_content, search_summary)
|
|
5614
|
+
VALUES (new.rowid, new.l2_subject, new.l2_predicate, new.l2_object, new.l2_evidence, new.l1_content, new.search_summary);
|
|
5615
|
+
END;
|
|
5616
|
+
|
|
5617
|
+
-- FTS同期トリガー: DELETE
|
|
5618
|
+
CREATE TRIGGER claims_fts_delete AFTER DELETE ON claims BEGIN
|
|
5619
|
+
INSERT INTO claims_fts(claims_fts, rowid, l2_subject, l2_predicate, l2_object, l2_evidence, l1_content, search_summary)
|
|
5620
|
+
VALUES ('delete', old.rowid, old.l2_subject, old.l2_predicate, old.l2_object, old.l2_evidence, old.l1_content, old.search_summary);
|
|
5621
|
+
END;
|
|
5622
|
+
|
|
5623
|
+
-- FTS rebuild
|
|
5624
|
+
INSERT INTO claims_fts(claims_fts) VALUES('rebuild');
|
|
5625
|
+
|
|
5626
|
+
INSERT INTO schema_version (version) VALUES (28);
|
|
5627
|
+
`);
|
|
5628
|
+
// unified_search_items の claims トリガー再作成(l2_evidence/l2_falsifier 対応)
|
|
5629
|
+
const coal = (col) => `COALESCE(${col}, '')`;
|
|
5630
|
+
const columns = "entity_type, entity_id, scope, category, title_summary, search_text, search_summary, tags, created_at, updated_at";
|
|
5631
|
+
const claimTitle = (p) => `${p}l2_subject || ' ' || ${p}l2_predicate || ' ' || ${p}l2_object`;
|
|
5632
|
+
const claimSearch = (p) => `${p}l2_subject || ' ' || ${p}l2_predicate || ' ' || ${p}l2_object || ' ' || ${coal(`${p}l2_evidence`)} || ' ' || ${coal(`${p}l2_falsifier`)} || ' ' || ${coal(`${p}l1_content`)} || ' ' || ${coal(`${p}search_summary`)}`;
|
|
5633
|
+
db.exec(`DROP TRIGGER IF EXISTS claims_unified_insert`);
|
|
5634
|
+
db.exec(`DROP TRIGGER IF EXISTS claims_unified_update`);
|
|
5635
|
+
db.exec(`DROP TRIGGER IF EXISTS claims_unified_delete`);
|
|
5636
|
+
db.exec(`
|
|
5637
|
+
CREATE TRIGGER claims_unified_insert AFTER INSERT ON claims
|
|
5638
|
+
WHEN new.status = 'active' BEGIN
|
|
5639
|
+
INSERT OR REPLACE INTO unified_search_items(${columns})
|
|
5640
|
+
VALUES ('claim', new.id, new.scope, new.category, ${claimTitle("new.")}, ${claimSearch("new.")}, new.search_summary, '[]', new.created_at, new.updated_at);
|
|
5641
|
+
END
|
|
5642
|
+
`);
|
|
5643
|
+
db.exec(`
|
|
5644
|
+
CREATE TRIGGER claims_unified_update AFTER UPDATE ON claims BEGIN
|
|
5645
|
+
DELETE FROM unified_search_items WHERE entity_type = 'claim' AND entity_id = old.id;
|
|
5646
|
+
INSERT INTO unified_search_items(${columns})
|
|
5647
|
+
SELECT 'claim', new.id, new.scope, new.category, ${claimTitle("new.")}, ${claimSearch("new.")}, new.search_summary, '[]', new.created_at, new.updated_at
|
|
5648
|
+
WHERE new.status = 'active';
|
|
5649
|
+
END
|
|
5650
|
+
`);
|
|
5651
|
+
db.exec(`
|
|
5652
|
+
CREATE TRIGGER claims_unified_delete AFTER DELETE ON claims BEGIN
|
|
5653
|
+
DELETE FROM unified_search_items WHERE entity_type = 'claim' AND entity_id = old.id;
|
|
5654
|
+
END
|
|
5655
|
+
`);
|
|
5656
|
+
}
|
|
5502
5657
|
/** テーブルに指定カラムが存在するかチェック */
|
|
5503
5658
|
function hasColumn(db, table, column) {
|
|
5504
5659
|
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|