watashi-db 0.0.12 → 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 CHANGED
@@ -1,21 +1,71 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 watashi-db contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: bareforge
6
+ Licensed Work: watashi-db 0.0.12
7
+ The Licensed Work is (c) 2026 bareforge
8
+ Additional Use Grant: You may make use of the Licensed Work, provided that
9
+ you may not use the Licensed Work for a Commercial
10
+ Purpose.
11
+ A "Commercial Purpose" means use in or for a product
12
+ or service that is sold, offered for sale, licensed,
13
+ or otherwise made available to third parties for a fee
14
+ or other commercial consideration.
15
+ Non-commercial use, personal use, educational use,
16
+ and evaluation use are always permitted.
17
+ Change Date: 2029-03-16
18
+ Change License: Apache License, Version 2.0
19
+
20
+ For information about alternative licensing arrangements for the Licensed Work,
21
+ please contact: bareforge.license@outlook.jp
22
+
23
+ -----------------------------------------------------------------------------
24
+
25
+ Notice
26
+
27
+ Business Source License 1.1
28
+
29
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
30
+ "Business Source License" is a trademark of MariaDB Corporation Ab.
31
+
32
+ Terms
33
+
34
+ The Licensor hereby grants you the right to copy, modify, create derivative
35
+ works, redistribute, and make non-production use of the Licensed Work. The
36
+ Licensor may make an Additional Use Grant, above, permitting limited production
37
+ use.
38
+
39
+ Effective on the Change Date, or the fourth anniversary of the first publicly
40
+ available distribution of a specific version of the Licensed Work under this
41
+ License, whichever comes first, the Licensor hereby grants you rights under the
42
+ terms of the Change License, and the rights granted in the paragraph above
43
+ terminate.
44
+
45
+ If your use of the Licensed Work does not comply with the requirements currently
46
+ in effect as described in this License, you must purchase a commercial license
47
+ from the Licensor, its affiliated entities, or authorized resellers, or you must
48
+ refrain from using the Licensed Work.
49
+
50
+ All copies of the original and modified Licensed Work, and derivative works of
51
+ the Licensed Work, are subject to this License. This License applies separately
52
+ for each version of the Licensed Work and the Change Date may vary for each
53
+ version of the Licensed Work released by Licensor.
54
+
55
+ You must conspicuously display this License on each original or modified copy of
56
+ the Licensed Work. If you receive the Licensed Work in original or modified form
57
+ from a third party, the terms and conditions set forth in this License apply to
58
+ your use of that work.
59
+
60
+ Any use of the Licensed Work in violation of this License will automatically
61
+ terminate your rights under this License for the current and all other versions
62
+ of the Licensed Work.
63
+
64
+ This License does not grant you any right in any trademark or logo of Licensor
65
+ or its affiliates (provided that you may use a trademark or logo of Licensor as
66
+ expressly required by this License).
67
+
68
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
69
+ "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS
70
+ OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY,
71
+ FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
package/README.md CHANGED
@@ -316,4 +316,12 @@ npm run dev
316
316
 
317
317
  ## ライセンス
318
318
 
319
- [MIT](LICENSE)
319
+ [Business Source License 1.1](LICENSE)
320
+
321
+ - **個人利用・非商用利用・教育利用・評価利用**: 常に無料
322
+ - **商用利用**: ライセンス契約が必要(bareforge.license@outlook.jp)
323
+ - **Change Date**: 2029-03-16 以降、Apache License 2.0 に自動転換
324
+
325
+ > [!NOTE]
326
+ > v0.0.12 以前は MIT License で公開されていました。
327
+ > 既に MIT 版を取得済みの方は、その時点のバージョンを MIT 条件で引き続き利用できます。
@@ -0,0 +1,72 @@
1
+ ---
2
+ description: >
3
+ 記録の棚卸し(蒸留)を行う。未処理のEpisode/Decisionからパターンを抽出し、
4
+ Insight/Theory/Modelとして蒸留する。蒸留済みの古いレコードはアーカイブする。
5
+ ---
6
+
7
+ 記録の棚卸し(蒸留)を行います。
8
+
9
+ ## 引数
10
+ - `$ARGUMENTS`: (オプション)蒸留したいトピックやスコープ
11
+
12
+ ## 手順
13
+
14
+ ### Step 1: 素材の収集
15
+ 以下のツールを並行して呼び出し、蒸留対象のデータを収集する:
16
+ - `watashi_maintain(action='groom_episodes')`: 未グルーミングのEpisode一覧
17
+ - `watashi_search(entity_types=["decision"], limit=50)`: active Decision一覧
18
+ - `watashi_search(entity_types=["insight"], limit=20)`: 既存Insight(重複回避用)
19
+
20
+ ### Step 2: パターン分析と蒸留
21
+ 収集したEpisode/Decisionから以下を分析:
22
+
23
+ 1. **繰り返しテーマの検出**: 複数のEpisodeに共通するトピック・問題パターン
24
+ 2. **原則の統合**: 個別Episodeの l2_principles を横断分析し、汎用的な原則を抽出
25
+ 3. **既存Insightとの照合**: 重複・矛盾がないか確認
26
+
27
+ 分析結果に基づき生成:
28
+ - **Insight**: 具体的で再利用可能な知見(1つのパターン)
29
+ → `watashi_store_knowledge(kind='insight', supporting_episode_ids=[...])`
30
+ - **Theory**: 体系的なフレームワーク(複数パターンの統合)
31
+ → `watashi_store_knowledge(kind='theory', supporting_episode_ids=[...])`
32
+
33
+ l2_trigger_conditions(いつ適用するか)と l2_resolution_steps(具体的に何をするか)を必ず記入すること。
34
+ 「まとめただけ」にならないよう、「次に同じ状況になったときの行動が変わる」レベルの知見を目指す。
35
+
36
+ ### Step 3: グルーミング済みマーク
37
+ 蒸留に使用したEpisodeをマーク:
38
+ - `watashi_maintain(action='mark_groomed', episode_ids=[...])`
39
+
40
+ ### Step 4: アーカイブ(ユーザー承認制)
41
+ 蒸留済みの古いレコードをアーカイブ(最新20件は維持):
42
+ 1. `watashi_maintain(action='archive_episodes', archive_keep_latest=20, dry_run=true)` でプレビュー
43
+ 2. 件数と対象をユーザーに提示し、承認を得る
44
+ 3. 承認後 `dry_run=false` で実行
45
+ 4. Decision も同様に実行
46
+
47
+ ### Step 5: サマリー報告
48
+
49
+ ## 出力形式
50
+
51
+ ```
52
+ ## 棚卸しサマリー
53
+
54
+ ### 分析した素材
55
+ - Episode: X件(うち未グルーミング: Y件)
56
+ - Decision: Z件
57
+
58
+ ### 蒸留結果
59
+ - 新規Insight: N件
60
+ - [タイトル](出典: [Episode ID一覧])
61
+ - 新規Theory: N件(該当があれば)
62
+
63
+ ### アーカイブ
64
+ - Episode: X件をアーカイブ(最新20件は維持)
65
+ - Decision: Y件をアーカイブ(最新20件は維持)
66
+ ```
67
+
68
+ ## 注意事項
69
+ - 素材が5件未満の場合は蒸留を見送り、蓄積を促す
70
+ - アーカイブは必ず dry_run でプレビュー → ユーザー承認後に実行
71
+ - supporting_episode_ids を必ず設定する
72
+ - 既存のInsight/Theoryと重複する場合は統合を提案する
@@ -8,7 +8,7 @@ export declare const SERVER_VERSION = "0.0.8";
8
8
  export declare const CLAIM_CATEGORIES: readonly ["preference", "identity", "skill", "value", "workflow", "knowledge", "custom"];
9
9
  export declare const CLAIM_SCOPES: readonly ["global", "persona", "project", "tool", "temporal"];
10
10
  export declare const CLAIM_STATUSES: readonly ["active", "retracted", "superseded", "promoted"];
11
- export declare const DECISION_STATUSES: readonly ["active", "reversed", "obsolete", "promoted"];
11
+ export declare const DECISION_STATUSES: readonly ["active", "reversed", "obsolete", "archived", "promoted"];
12
12
  export declare const THEORY_STATUSES: readonly ["active", "archived", "promoted"];
13
13
  export declare const INSIGHT_STATUSES: readonly ["active", "archived", "promoted"];
14
14
  export declare const MODEL_STATUSES: readonly ["active", "archived", "promoted"];
package/dist/constants.js CHANGED
@@ -47,6 +47,7 @@ export const DECISION_STATUSES = [
47
47
  "active", // 有効
48
48
  "reversed", // 撤回済み
49
49
  "obsolete", // 廃止
50
+ "archived", // アーカイブ済み(蒸留済み)
50
51
  "promoted", // 別Storeへ昇格済み
51
52
  ];
52
53
  // Theoryのステータス
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"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"}
@@ -178,6 +178,24 @@ export declare function listUngroomedEpisodes(db: Database.Database, params: {
178
178
  limit: number;
179
179
  }): GroomingEpisodeRow[];
180
180
  export declare function markEpisodesGroomed(db: Database.Database, episodeIds: string[]): string[];
181
+ /** Episode をアーカイブ(蒸留済み + 最新N件を除外) */
182
+ export declare function archiveEpisodes(db: Database.Database, params: {
183
+ episodeIds?: string[];
184
+ keepLatest?: number;
185
+ scope?: string;
186
+ }): {
187
+ archivedIds: string[];
188
+ archivedCount: number;
189
+ };
190
+ /** Decision をアーカイブ(最新N件を除外) */
191
+ export declare function archiveDecisions(db: Database.Database, params: {
192
+ decisionIds?: string[];
193
+ keepLatest?: number;
194
+ scope?: string;
195
+ }): {
196
+ archivedIds: string[];
197
+ archivedCount: number;
198
+ };
181
199
  export declare function getTopicSummary(db: Database.Database, tagLimit?: number, decisionLimit?: number, scope?: string): TopicSummary;
182
200
  export declare function insertTheory(db: Database.Database, params: {
183
201
  title: string;
@@ -518,6 +536,12 @@ export declare function resolveEntityType(db: Database.Database, entityId: strin
518
536
  * @returns 更新された行数(0 = ID不在)
519
537
  */
520
538
  export declare function updateSearchSummary(db: Database.Database, entityType: string, entityId: string, searchSummary: string): number;
539
+ /** archived を含む FTS 検索(unified_search_items ではなくソーステーブルの FTS を直接クエリ) */
540
+ export declare function searchIncludingArchived(db: Database.Database, params: {
541
+ query: string;
542
+ scope?: string;
543
+ limit: number;
544
+ }): UnifiedSearchRow[];
521
545
  /**
522
546
  * エンティティを物理削除し、tombstone を記録する。
523
547
  * entity_type が省略された場合は unified_search_items から自動解決する。
@@ -996,6 +996,82 @@ export function markEpisodesGroomed(db, episodeIds) {
996
996
  transaction();
997
997
  return markedIds;
998
998
  }
999
+ // === Episode/Decision アーカイブ ===
1000
+ /** Episode をアーカイブ(蒸留済み + 最新N件を除外) */
1001
+ export function archiveEpisodes(db, params) {
1002
+ const keepLatest = params.keepLatest ?? 20;
1003
+ if (params.episodeIds && params.episodeIds.length > 0) {
1004
+ // 個別指定モード: 指定IDのみアーカイブ
1005
+ const updated = [];
1006
+ const stmt = db.prepare("UPDATE episodes SET status = 'archived', updated_at = @now WHERE id = @id AND status = 'active'");
1007
+ const now = new Date().toISOString();
1008
+ for (const id of params.episodeIds) {
1009
+ const result = stmt.run({ id, now });
1010
+ if (result.changes > 0)
1011
+ updated.push(id);
1012
+ }
1013
+ return { archivedIds: updated, archivedCount: updated.length };
1014
+ }
1015
+ // 自動モード: groomed_at IS NOT NULL かつ最新 keepLatest 件を除外
1016
+ const scopeFilter = params.scope ? " AND scope = @scope" : "";
1017
+ const scopeValues = params.scope ? { scope: params.scope } : {};
1018
+ // 最新 keepLatest 件の ID を取得(保護対象)
1019
+ const protectedIds = db.prepare(`
1020
+ SELECT id FROM episodes
1021
+ WHERE status = 'active'${scopeFilter}
1022
+ ORDER BY created_at DESC
1023
+ LIMIT @keepLatest
1024
+ `).all({ ...scopeValues, keepLatest });
1025
+ const protectedSet = new Set(protectedIds.map(r => r.id));
1026
+ // groomed_at IS NOT NULL かつ保護対象外をアーカイブ
1027
+ const candidates = db.prepare(`
1028
+ SELECT id FROM episodes
1029
+ WHERE status = 'active' AND groomed_at IS NOT NULL${scopeFilter}
1030
+ `).all(scopeValues);
1031
+ const toArchive = candidates.filter(r => !protectedSet.has(r.id));
1032
+ const now = new Date().toISOString();
1033
+ const stmt = db.prepare("UPDATE episodes SET status = 'archived', updated_at = @now WHERE id = @id");
1034
+ for (const r of toArchive) {
1035
+ stmt.run({ id: r.id, now });
1036
+ }
1037
+ return { archivedIds: toArchive.map(r => r.id), archivedCount: toArchive.length };
1038
+ }
1039
+ /** Decision をアーカイブ(最新N件を除外) */
1040
+ export function archiveDecisions(db, params) {
1041
+ const keepLatest = params.keepLatest ?? 20;
1042
+ if (params.decisionIds && params.decisionIds.length > 0) {
1043
+ const updated = [];
1044
+ const stmt = db.prepare("UPDATE decisions SET status = 'archived', updated_at = @now WHERE id = @id AND status = 'active'");
1045
+ const now = new Date().toISOString();
1046
+ for (const id of params.decisionIds) {
1047
+ const result = stmt.run({ id, now });
1048
+ if (result.changes > 0)
1049
+ updated.push(id);
1050
+ }
1051
+ return { archivedIds: updated, archivedCount: updated.length };
1052
+ }
1053
+ // 自動モード: 最新 keepLatest 件を除外してアーカイブ
1054
+ const scopeFilter = params.scope ? " AND scope = @scope" : "";
1055
+ const scopeValues = params.scope ? { scope: params.scope } : {};
1056
+ const protectedIds = db.prepare(`
1057
+ SELECT id FROM decisions
1058
+ WHERE status = 'active'${scopeFilter}
1059
+ ORDER BY created_at DESC
1060
+ LIMIT @keepLatest
1061
+ `).all({ ...scopeValues, keepLatest });
1062
+ const protectedSet = new Set(protectedIds.map(r => r.id));
1063
+ const candidates = db.prepare(`
1064
+ SELECT id FROM decisions
1065
+ WHERE status = 'active'${scopeFilter}
1066
+ `).all(scopeValues);
1067
+ const toArchive = candidates.filter(r => !protectedSet.has(r.id));
1068
+ const now = new Date().toISOString();
1069
+ const stmt = db.prepare("UPDATE decisions SET status = 'archived', updated_at = @now WHERE id = @id");
1070
+ for (const r of toArchive) {
1071
+ stmt.run({ id: r.id, now });
1072
+ }
1073
+ return { archivedIds: toArchive.map(r => r.id), archivedCount: toArchive.length };
1074
+ }
999
1075
  // === Issue #35: トピック集計 ===
1000
1076
  // 2026-02-22 修正 (Codex P2指摘): scope パラメータを追加し、スコープ絞り込みに対応
1001
1077
  export function getTopicSummary(db, tagLimit = 10, decisionLimit = 5, scope) {
@@ -2784,6 +2860,42 @@ export function updateSearchSummary(db, entityType, entityId, searchSummary) {
2784
2860
  const result = db.prepare(`UPDATE ${table} SET search_summary = @searchSummary, updated_at = @now WHERE id = @entityId`).run({ searchSummary, now, entityId });
2785
2861
  return result.changes;
2786
2862
  }
2863
+ // === archived 含む検索(フォールバック用) ===
2864
+ /** archived を含む FTS 検索(unified_search_items ではなくソーステーブルの FTS を直接クエリ) */
2865
+ export function searchIncludingArchived(db, params) {
2866
+ const results = [];
2867
+ const targets = [
2868
+ { fts: "episodes_fts", table: "episodes", type: "episode", titleExpr: "t.title" },
2869
+ { fts: "decisions_fts", table: "decisions", type: "decision", titleExpr: "t.title" },
2870
+ { fts: "claims_fts", table: "claims", type: "claim", titleExpr: "t.l2_subject || ' ' || t.l2_predicate || ' ' || t.l2_object" },
2871
+ ];
2872
+ for (const target of targets) {
2873
+ try {
2874
+ const scopeFilter = params.scope
2875
+ ? " AND (t.scope = @scope OR t.scope = 'global')"
2876
+ : "";
2877
+ const rows = db.prepare(`
2878
+ SELECT t.id as entity_id, '${target.type}' as entity_type,
2879
+ ${target.titleExpr} as title_summary, t.scope,
2880
+ COALESCE(t.search_summary, '') as search_summary,
2881
+ '[]' as tags, '' as search_text,
2882
+ NULL as l1_embedding,
2883
+ t.created_at, t.updated_at,
2884
+ NULL as _fts_rank, NULL as category
2885
+ FROM ${target.table} t
2886
+ JOIN ${target.fts} f ON f.rowid = t.rowid
2887
+ WHERE ${target.fts} MATCH @query${scopeFilter}
2888
+ ORDER BY rank
2889
+ LIMIT @limit
2890
+ `).all({ query: params.query, scope: params.scope, limit: params.limit });
2891
+ results.push(...rows);
2892
+ }
2893
+ catch {
2894
+ // FTS テーブル未存在等はスキップ
2895
+ }
2896
+ }
2897
+ return results.slice(0, params.limit);
2898
+ }
2787
2899
  // === Issue #63: 物理削除 + tombstone ===
2788
2900
  /**
2789
2901
  * エンティティを物理削除し、tombstone を記録する。