@horizon_works/banto 0.6.0 → 0.8.0

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.
Files changed (30) hide show
  1. package/README.md +113 -109
  2. package/gate_core.js +220 -1
  3. package/license/client.js +303 -214
  4. package/package.json +1 -2
  5. package/server.js +1872 -1719
  6. package/payload/compliance/SKILL.md +0 -113
  7. package/payload/compliance/dict/00_/345/213/225/344/275/234/347/242/272/350/252/215.json +0 -14
  8. package/payload/compliance/dict/06_house_rules.json +0 -16
  9. package/payload/compliance/dict/_sample/04_common_keihyo.json +0 -270
  10. package/payload/compliance/dict/_sample/README.md +0 -72
  11. package/payload/compliance/lint.js +0 -265
  12. package/payload/disciplines//347/225/252/351/240/255/343/201/256/344/275/234/346/263/225.md +0 -64
  13. package/payload/disciplines//350/207/252/345/267/261/345/201/245/350/250/272.md +0 -74
  14. package/payload/disciplines//351/200/261/346/254/241/343/203/241/343/203/263/343/203/206.md +0 -60
  15. package/payload/migration/protocol.md +0 -35
  16. package/payload/skill-maker/SKILL_base_anthropic.md +0 -357
  17. package/payload/skill-maker/skill-maker-v1.0.md +0 -305
  18. package/payload/skills/_/343/201/202/343/201/250/343/201/247/350/266/263/343/201/233/343/202/213/343/202/202/343/201/256.md +0 -47
  19. package/payload/skills/image-gen/SKILL.md +0 -147
  20. package/payload/skills/image-gen/gen.js +0 -225
  21. package/payload/skills/remember/SETUP_Google/351/200/243/346/220/272.md +0 -106
  22. package/payload/skills/remember/SKILL.md +0 -158
  23. package/payload/skills/remember/handoff.js +0 -149
  24. package/payload/skills/remember/tasks.js +0 -320
  25. package/payload/skills/slide-deck/SKILL.md +0 -160
  26. package/payload/skills/transcribe/README.md +0 -182
  27. package/payload/skills/transcribe/dict.json +0 -10
  28. package/payload/skills/transcribe/enroll_speaker.py +0 -76
  29. package/payload/skills/transcribe/identify_speakers.py +0 -153
  30. package/payload/skills/transcribe/transcribe.py +0 -126
package/README.md CHANGED
@@ -1,109 +1,113 @@
1
- # AI番頭のOS
2
-
3
- 株式会社ホライズンワークス
4
-
5
- AIを「便利な道具」ではなく「**任された範囲を預かる番頭**」として使うための土台です。
6
- MCPを1本入れるだけで、番頭の作法・ルール・記憶・検査がそろいます。
7
-
8
- ---
9
-
10
- ## いちばん大事なこと
11
-
12
- > **AIに中身を見せずに、AIに検査させる。**
13
-
14
- 顧問先のお名前が入った下書きを、AIに貼らずに検査できます。
15
- ファイルを読むのは**あなたのパソコンの中のプログラム**で、AIが受け取るのは「何件あったか」という数字だけです。
16
-
17
- ★このプログラムは、**あなたのパソコンの中で動きます**。
18
- 検査するファイルも、書き留めた記録も、外へは出ません。
19
-
20
- ---
21
-
22
- ## 使えるようにする
23
-
24
- お使いのAIの設定(MCPの設定)に、次を足してください。
25
-
26
- ```json
27
- {
28
- "mcpServers": {
29
- "banto": {
30
- "command": "npx",
31
- "args": ["-y", "@horizon_works/banto"]
32
- }
33
- }
34
- }
35
- ```
36
-
37
- Node.js が入っていれば、ほかに何も要りません。
38
- 足したあと、AIの窓を開き直してください。
39
-
40
- ### 鍵を入れる
41
-
42
- お渡しした鍵を、環境変数に入れてください。
43
-
44
- ```
45
- BANTOU_LICENSE_KEY = (お渡しした鍵)
46
- BANTOU_LICENSE_URL = (お渡しした URL)
47
- BANTOU_LICENSE_ANON = (お渡しした 公開キー)
48
- ```
49
-
50
- ★鍵が無くても、**検査と記録は使えます**。サプリの取得だけが止まります。
51
-
52
- ---
53
-
54
- ## 最初にやること
55
-
56
- AIにこう言ってください。
57
-
58
- ```
59
- 番頭の道具を、このフォルダに入れて
60
- ```
61
-
62
- スキル(画像・スライド・文字起こし)や、週に一度の手入れの手順が入ります。
63
- 何が入るかは「**入る前に一覧を見せて**」と言えば、先に確かめられます。
64
-
65
- 続けて、こう言えます。
66
-
67
- ```
68
- 番頭の棚を見せて
69
- ```
70
-
71
- お仕事に合わせたサプリ(給与・就業規則・助成金・36協定など)の一覧がブラウザで開きます。
72
- 要るものだけ選んで入れてください。★要らなくなったら外せます(**消えません**)。
73
-
74
- ---
75
-
76
- ## できること
77
-
78
- | 頼み方 | すること |
79
- |---|---|
80
- | 「このファイル、出して大丈夫か検査して」 | ★中身を見せずに検査。件数と判定だけ返ります |
81
- | 「これ、記録しておいて」 | 1行だけ書き留めます |
82
- | 「振り返って」 | ★**同じことを3回したら「決まりごとにする番です」**と出ます |
83
- | 「片づけて」 | 散らかりを診ます。★**消しません。寄せるだけで、戻せます** |
84
- | 「棚を見せて」 | サプリを選んで入れる/外す |
85
- | 「新しくして」 | ★**あなたが書き換えたものには触りません** |
86
-
87
- ---
88
-
89
- ## 大事にしていること
90
-
91
- - ★**消しません。** 外すときも、片づけるときも、移すだけです。あとで戻せます
92
- - ★**書き換えたものには触りません。** 育てたものは、あなたのものです
93
- - ★**記録はあなたの手元のテキストです。** この道具が使えなくなっても、メモ帳で読めます
94
- - ★**「0件」は「安全」という意味ではありません。** この検査で出なかった、という意味です
95
-
96
- ---
97
-
98
- ## 気をつけていただきたいこと
99
-
100
- この道具を通したことは、**安全の証明にはなりません**。
101
- 機械が見ているのは決められた形だけで、形が違えば見つかりません。
102
-
103
- ★**最後に判断するのは、いつでも人です。**
104
-
105
- ---
106
-
107
- ## お問い合わせ
108
-
109
- 株式会社ホライズンワークス
1
+ # AI番頭のOS
2
+
3
+ 株式会社ホライズンワークス
4
+
5
+ AIを「便利な道具」ではなく「**任された範囲を預かる番頭**」として使うための土台です。
6
+ MCPを1本入れるだけで、番頭の作法・ルール・記憶・検査がそろいます。
7
+
8
+ ---
9
+
10
+ ## いちばん大事なこと
11
+
12
+ > **AIに中身を見せずに、AIに検査させる。**
13
+
14
+ 顧問先のお名前が入った下書きを、AIに貼らずに検査できます。
15
+ ファイルを読むのは**あなたのパソコンの中のプログラム**で、AIが受け取るのは「何件あったか」という数字だけです。
16
+
17
+ ★このプログラムは、**あなたのパソコンの中で動きます**。
18
+ 検査するファイルも、書き留めた記録も、外へは出ません。
19
+
20
+ ---
21
+
22
+ ## 使えるようにする
23
+
24
+ お使いのAIの設定(MCPの設定)に、次を足してください。
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "banto": {
30
+ "command": "npx",
31
+ "args": ["-y", "@horizon_works/banto"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ Node.js が入っていれば、ほかに何も要りません。
38
+ 足したあと、AIの窓を開き直してください。
39
+
40
+ ### 鍵を入れる
41
+
42
+ お渡しした鍵を、環境変数に入れてください。
43
+
44
+ ```
45
+ BANTOU_LICENSE_KEY = (お渡しした鍵)
46
+ BANTOU_LICENSE_SIG = (お渡しした 署名)
47
+ BANTOU_LICENSE_URL = (お渡しした URL)
48
+ BANTOU_LICENSE_ANON = (お渡しした 公開キー)
49
+ ```
50
+
51
+ ★**4つそろって1組**です。`SIG`(署名)が無いと止まります。
52
+ ★お渡しするファイル(`config.json`)をそのまま置いていただいても構いません。
53
+
54
+ ★鍵が無くても、**検査と記録は使えます**。サプリの取得だけが止まります。
55
+
56
+ ---
57
+
58
+ ## 最初にやること
59
+
60
+ AIにこう言ってください。
61
+
62
+ ```
63
+ 番頭の道具を、このフォルダに入れて
64
+ ```
65
+
66
+ スキル(画像・スライド・文字起こし)や、週に一度の手入れの手順が入ります。
67
+ 何が入るかは「**入る前に一覧を見せて**」と言えば、先に確かめられます。
68
+
69
+ 続けて、こう言えます。
70
+
71
+ ```
72
+ 番頭の棚を見せて
73
+ ```
74
+
75
+ お仕事に合わせたサプリ(給与・就業規則・助成金・36協定など)の一覧がブラウザで開きます。
76
+ 要るものだけ選んで入れてください。★要らなくなったら外せます(**消えません**)。
77
+
78
+ ---
79
+
80
+ ## できること
81
+
82
+ | 頼み方 | すること |
83
+ |---|---|
84
+ | 「このファイル、出して大丈夫か検査して」 | ★中身を見せずに検査。件数と判定だけ返ります |
85
+ | 「これ、記録しておいて」 | 1行だけ書き留めます |
86
+ | 「振り返って」 | ★**同じことを3回したら「決まりごとにする番です」**と出ます |
87
+ | 「片づけて」 | 散らかりを診ます。★**消しません。寄せるだけで、戻せます** |
88
+ | 「棚を見せて」 | サプリを選んで入れる/外す |
89
+ | 「新しくして」 | ★**あなたが書き換えたものには触りません** |
90
+
91
+ ---
92
+
93
+ ## 大事にしていること
94
+
95
+ - ★**消しません。** 外すときも、片づけるときも、移すだけです。あとで戻せます
96
+ - ★**書き換えたものには触りません。** 育てたものは、あなたのものです
97
+ - ★**記録はあなたの手元のテキストです。** この道具が使えなくなっても、メモ帳で読めます
98
+ - ★**「0件」は「安全」という意味ではありません。** この検査で出なかった、という意味です
99
+
100
+ ---
101
+
102
+ ## 気をつけていただきたいこと
103
+
104
+ この道具を通したことは、**安全の証明にはなりません**。
105
+ 機械が見ているのは決められた形だけで、形が違えば見つかりません。
106
+
107
+ ★**最後に判断するのは、いつでも人です。**
108
+
109
+ ---
110
+
111
+ ## お問い合わせ
112
+
113
+ 株式会社ホライズンワークス
package/gate_core.js CHANGED
@@ -219,6 +219,221 @@ function summarize(r, dict, targetLabel) {
219
219
 
220
220
  // ───────────────────────────────── 記録(学びを溜めて、ルールに落とす)
221
221
  // ★入口は絶対に止めない。書きにくくすると、記録そのものが減る。
222
+ // ═══════════════════════════════════════════════════════════════
223
+ // 正本(★同じ役割のものが2つあると、どちらも育たない)
224
+ //
225
+ // 🚨 由来: 2026-08-28。AI番頭キット(FL)をお使いの方が、このMCPも入れると
226
+ // 下書き帳が2つになることに気づいた。★形が違うので、片方の関所が
227
+ // 「数えるのに一覧に出せない」状態になる(=止まるのに閉じられない)。
228
+ //
229
+ // ★★**機械は数えるだけ。同種かどうかの判断はAIがする。**
230
+ // ファイル名だけで決めると、たまたま名前が似たものを潰す。
231
+ // ★**判断した結果は、その場の会話で終わらせずにファイルへ残す。**
232
+ // 残さないと、次のセッションでまた同じことを考える(=考えが積まない)。
233
+ // ★**残したものを、実際に読んで振る舞いを変える。**
234
+ // 読まないルールは、無いのと同じ(未配線の関所)。
235
+ // ═══════════════════════════════════════════════════════════════
236
+
237
+ // ★役割語=「同じ仕事をしていそう」の当たり付け(★これは判定ではない)
238
+ const 役割語 = {
239
+ '下書き帳': ['retain_log', 'bantou-log', 'bantou_log', '気づき', 'notes', 'メモ帳'],
240
+ '記憶の正本': ['subconscious', 'hot_memory', 'ホットメモリ', 'MEMORY.md'],
241
+ '状態': ['state.md', 'status.md', '.state.json'],
242
+ '引き継ぎ': ['handoff', '引き継ぎ', 'pending'],
243
+ '辞書': ['dict', '辞書', 'dictionary'],
244
+ '人物': ['profile', 'プロファイル', '人物'],
245
+ 'やること': ['task', 'todo', 'やること', '課題'],
246
+ 'ルール': ['rules', 'ルール', 'policy', 'CLAUDE.md', 'GEMINI.md', 'AGENTS.md'],
247
+ };
248
+
249
+ function masterFile(dir) {
250
+ const r = path.join(dir, '_agents', 'rules');
251
+ try { if (fs.existsSync(r)) return path.join(r, '正本.md'); } catch (_) {}
252
+ return path.join(dir, '正本.md');
253
+ }
254
+
255
+ function readMasters(dir) {
256
+ const f = masterFile(dir);
257
+ const out = {};
258
+ let s = '';
259
+ try { s = fs.readFileSync(f, 'utf8'); } catch (_) { return { file: f, decided: out }; }
260
+ // 形: | 役割 | 正本 | 別本(; 区切り) | 決めた日 |
261
+ for (const line of s.split(String.fromCharCode(10))) {
262
+ const m = line.match(/^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*$/);
263
+ if (!m || m[1] === '役割' || /^-+$/.test(m[1])) continue;
264
+ out[m[1]] = { 正本: m[2], 別本: m[3] ? m[3].split(';').map((x) => x.trim()).filter(Boolean) : [], 決めた日: m[4] };
265
+ }
266
+ return { file: f, decided: out };
267
+ }
268
+
269
+ function writeMaster(dir, 役割, 正本, 別本, 理由) {
270
+ const f = masterFile(dir);
271
+ const { decided } = readMasters(dir);
272
+ decided[役割] = { 正本, 別本: 別本 || [], 決めた日: stamp().slice(0, 10), 理由 };
273
+ const nl = String.fromCharCode(10);
274
+ const head = [
275
+ '# 正本(どれが本物か)',
276
+ '',
277
+ '> ★同じ役割のものが2つあると、どちらも育ちません。ここで1つに決めます。',
278
+ '> ★決めたのは番頭とあなたです。機械は候補を出しただけです。',
279
+ '> ★増えたら `check_masters` でもう一度見てください。',
280
+ '',
281
+ '| 役割 | 正本 | 別本(使わない) | 決めた日 |',
282
+ '|---|---|---|---|',
283
+ ];
284
+ const rows = Object.entries(decided).map(([k, v]) =>
285
+ '| ' + k + ' | ' + v.正本 + ' | ' + (v.別本 || []).join('; ') + ' | ' + (v.決めた日 || '') + ' |');
286
+ const notes = Object.entries(decided).filter(([, v]) => v.理由)
287
+ .map(([k, v]) => '- **' + k + '**:' + v.理由);
288
+ const body = head.concat(rows, notes.length ? ['', '## なぜそう決めたか', ''].concat(notes) : [], ['']).join(nl);
289
+ fs.mkdirSync(path.dirname(f), { recursive: true });
290
+ fs.writeFileSync(f, body, 'utf8');
291
+ return f;
292
+ }
293
+
294
+ /**
295
+ * ★候補を出す。★判定はしない。
296
+ * ★中身はAIへ返さない(ファイル名・行数・更新日・先頭の見出しだけ)。
297
+ */
298
+ function checkMasters(dir, decide) {
299
+ const d = path.resolve(String(dir || process.cwd()));
300
+ if (!fs.existsSync(d)) throw new Error('見つかりません: ' + d);
301
+
302
+ if (decide && decide.役割 && decide.正本) {
303
+ const f = writeMaster(d, decide.役割, decide.正本, decide.別本, decide.理由);
304
+ return {
305
+ 決めました: decide.役割, 正本: decide.正本,
306
+ 別本: decide.別本 || [], 書いた先: f,
307
+ note: '★これ以降、記録の道具はこの決めごとを読んで振る舞います。'
308
+ + '★決め直すときは、もう一度この道具を呼んでください。',
309
+ };
310
+ }
311
+
312
+ // ── 走査(★深すぎない・重くない)
313
+ const 見つけた = [];
314
+ (function w(p, depth) {
315
+ if (depth > 4) return;
316
+ let es = [];
317
+ try { es = fs.readdirSync(p, { withFileTypes: true }); } catch (_) { return; }
318
+ for (const e of es) {
319
+ if (e.name === 'node_modules' || e.name === '_かたづけ' || e.name.startsWith('.')) continue;
320
+ const full = path.join(p, e.name);
321
+ if (e.isDirectory()) { w(full, depth + 1); continue; }
322
+ if (!/\.(md|json|txt)$/i.test(e.name)) continue;
323
+ 見つけた.push(full);
324
+ }
325
+ })(d, 0);
326
+
327
+ const { file: mf, decided } = readMasters(d);
328
+ const 組 = [];
329
+ for (const [役割, 語s] of Object.entries(役割語)) {
330
+ const 当たり = 見つけた.filter((f) => {
331
+ const rel = path.relative(d, f).split(String.fromCharCode(92)).join('/');
332
+ return 語s.some((w2) => rel.toLowerCase().indexOf(w2.toLowerCase()) >= 0);
333
+ });
334
+ if (当たり.length < 2) continue;
335
+ 組.push({
336
+ 役割,
337
+ すでに決めてある: decided[役割] ? decided[役割].正本 : null,
338
+ 候補: 当たり.slice(0, 8).map((f) => {
339
+ let 行数 = null, 見出し = null, 更新 = null;
340
+ try {
341
+ const s = fs.readFileSync(f, 'utf8');
342
+ 行数 = s.split(String.fromCharCode(10)).length;
343
+ const h = s.split(String.fromCharCode(10)).find((l) => /^#\s/.test(l));
344
+ 見出し = h ? h.replace(/^#\s*/, '').slice(0, 40) : null;
345
+ 更新 = fs.statSync(f).mtime.toISOString().slice(0, 10);
346
+ } catch (_) {}
347
+ return { path: path.relative(d, f).split(String.fromCharCode(92)).join('/'), 行数, 見出し, 更新 };
348
+ }),
349
+ });
350
+ }
351
+
352
+ return {
353
+ 見たフォルダ: d,
354
+ 正本の帳面: mf,
355
+ 決めてある件数: Object.keys(decided).length,
356
+ 確かめてほしい組: 組.length ? 組 : '(役割が重なりそうな組は見つかりませんでした)',
357
+ note:
358
+ '★これは候補です。**同じ役割かどうかは、機械には決められません。**'
359
+ + 'あなた(番頭)が1組ずつ見て、同じ仕事をしているなら1つに決めてください。'
360
+ + '★決めたら check_masters を decide 付きで呼ぶと、帳面へ残ります。'
361
+ + '★中身は返していません(ファイル名・行数・更新日・先頭の見出しだけ)。',
362
+ '★どう決めるか': [
363
+ '同じ仕事をしているか(片方が消えても困らないなら、たぶん別の仕事)',
364
+ '★どちらを残すか=**関所が読んでいるほう**(止める・数える仕組みが見ているファイル)',
365
+ '★形が違うものを1つに混ぜない(読めなくなる)。使わないほうは別本にする',
366
+ ],
367
+ };
368
+ }
369
+
370
+ // 🚨★**AI番頭キット(FL)が入っているなら、記録はそちらへ譲る**(2026-08-28)
371
+ // ★由来=FL 2.2〜2.5 をお使いの方が、このMCPも入れた場合。
372
+ // ★FLキットは `second-brain/retain_log.md` に書き、`kit/memory/close.js` が
373
+ // **そのファイルだけ**を読んで「未処理10件で止める」関所を回している。
374
+ // ★★こちらが `bantou-log.md` に書くと、**下書き帳が2つ**になる(=正本割れ)。
375
+ // ★しかも1行の形が違う:
376
+ // FL : `- [ ] 日時 | 0.6 | failure | 本文 〔sig:key〕`(★点数の欄がある)
377
+ // こちら: `- [ ] 日時 | failure 〔key〕 | 本文`
378
+ // ★FLの関所は行頭 `- [ ]` だけを数え、一覧は正規表現で読む。
379
+ // ★→ **数えられるのに一覧に出ない**。止まるのに閉じられない、いちばん悪い形になる。
380
+ // ★→ ★**書く場所を横取りしない。FLの道具へお返しする。**
381
+ // ★型キーを3件で数える働きは、FLの retain.js が同じことをしている。失うものは無い。
382
+ function findKit() {
383
+ let d = process.cwd();
384
+ for (let i = 0; i < 6; i++) {
385
+ const p = path.join(d, 'kit', 'memory', 'retain.js');
386
+ try { if (fs.existsSync(p)) return { script: p, root: d }; } catch (_) {}
387
+ const up = path.dirname(d);
388
+ if (up === d) break;
389
+ d = up;
390
+ }
391
+ return null;
392
+ }
393
+ // ★★**機械は決めない。決めごとがあれば従い、無ければ止めて番頭に聞く。**
394
+ // ★由来(2026-08-28)=「AIが同種の記載をしているかどうか判断して、ルールを作らせるのがいい」。
395
+ // ★私は最初、キットの有無だけで機械が決める形にした。★それだと
396
+ // ①たまたま名前が似ただけのものまで潰す ②決めた理由が残らない
397
+ // ③次のセッションでまた同じことを考える(考えが積まない)。
398
+ // ★順番=① 環境変数の明示 → ② 正本.md の決めごと → ③ 未決なら止めて聞く。
399
+ function logOwner() {
400
+ if (process.env.BANTOU_LOG) return null; // ★人が明示した指定が最優先
401
+ let decided = {};
402
+ try { decided = readMasters(process.cwd()).decided; } catch (_) {}
403
+ const m = decided['下書き帳'];
404
+ if (m) {
405
+ // ★決めてある。こちらが正本なら普通に書く。よそが正本なら譲る
406
+ return /bantou-log/i.test(m.正本) ? null : { 決めてある: true, 正本: m.正本 };
407
+ }
408
+ const k = findKit(); // ★キットが在る=重なる恐れがある
409
+ return k ? { 決めてある: false, キットの場所: k.root } : null;
410
+ }
411
+
412
+ function kitNotice(cmd) {
413
+ const o = logOwner();
414
+ if (o && o.決めてある) {
415
+ return {
416
+ verdict: '書いていません',
417
+ 理由: '★このフォルダの「下書き帳」の正本は ' + o.正本 + ' と決めてあります(正本.md)。',
418
+ お使いください: 'node kit/memory/' + cmd,
419
+ };
420
+ }
421
+ return {
422
+ verdict: '書いていません',
423
+ 理由: '★このフォルダには AI番頭キットが入っていて、記録の置き場が**まだ決まっていません**。',
424
+ '★あなた(番頭)にお願いしたいこと': [
425
+ '1. `check_masters` を呼んで、役割が重なっている組を見てください',
426
+ '2. 同じ仕事をしているか、あなたが判断してください(★機械には決められません)',
427
+ '3. 決めたら `check_masters` を decide 付きで呼んでください。帳面に残り、次から迷いません',
428
+ ],
429
+ なぜ止めたか:
430
+ '★下書き帳が2つあると、どちらも育ちません。'
431
+ + 'しかも形が違うと、片方の関所が「数えるのに一覧に出せない」状態になります'
432
+ + '(止まるのに閉じられない)。★先に1つ決めてから書きます。',
433
+ キットの場所: o ? o.キットの場所 : null,
434
+ };
435
+ }
436
+
222
437
  function logPath() {
223
438
  return process.env.BANTOU_LOG || path.join(process.cwd(), 'bantou-log.md');
224
439
  }
@@ -227,6 +442,7 @@ function stamp() {
227
442
  return `${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
228
443
  }
229
444
  function remember(text, tag, sig) {
445
+ if (logOwner()) return kitNotice('retain.js add "<本文>" --score 0.5 --tag failure --sig <型キー>');
230
446
  const t = String(text || '').trim();
231
447
  if (!t) throw new Error('記録する内容がありません');
232
448
  const f = logPath();
@@ -277,6 +493,7 @@ function readLog() {
277
493
  }
278
494
 
279
495
  function recall(days, onlyOpen) {
496
+ if (logOwner()) return kitNotice('retain.js recall --min 0.5 --days 7');
280
497
  const { file, entries } = readLog();
281
498
  const since = Date.now() - (Number(days) || 7) * 86400000;
282
499
  const out = entries
@@ -291,6 +508,7 @@ function recall(days, onlyOpen) {
291
508
  * ★これが FL の山。溜めるのが目的ではなく、ルールか手順に落とすのが目的。
292
509
  */
293
510
  function review(record) {
511
+ if (logOwner()) return kitNotice('close.js');
294
512
  const { file, entries, ruled } = readLog();
295
513
  const ruledBy = {};
296
514
  for (const r of ruled) ruledBy[r.sig] = r;
@@ -353,6 +571,7 @@ function review(record) {
353
571
  * ruled_to … ルールや手順にしたときの置き場所(sig と一緒に指定)
354
572
  */
355
573
  function settle(ids, sig, ruledTo) {
574
+ if (logOwner()) return kitNotice('retain.js promote <行番号...>');
356
575
  const { file, lines, entries } = readLog();
357
576
  if (!fs.existsSync(file)) throw new Error('まだ記録がありません');
358
577
  let closed = 0;
@@ -620,7 +839,7 @@ function handle(req) {
620
839
 
621
840
  // ★このファイルは「正本」。社内版はこれを読み込んで、辞書と鍵を足すだけにする。
622
841
  // (検出のロジックを2か所に持たないため)
623
- module.exports = { inspectText, summarize, report, loadDict, walk, remember, recall, review, settle, checkup, readLog, selfDiagnosis, INTERNAL_PATTERNS, NAMEISH };
842
+ module.exports = { inspectText, summarize, report, loadDict, walk, remember, recall, review, settle, checkup, readLog, selfDiagnosis, INTERNAL_PATTERNS, NAMEISH, checkMasters, readMasters };
624
843
 
625
844
  // 直接起動されたときだけ、MCPサーバーとして動く
626
845
  if (require.main === module) {