@horizon_works/banto 0.7.0 → 0.8.1
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/add_to_config.js +107 -0
- package/gate_core.js +220 -1
- package/law_bridge.js +183 -0
- package/license/client.js +20 -1
- package/package.json +3 -2
- package/server.js +140 -37
- package/payload/compliance/SKILL.md +0 -113
- package/payload/compliance/dict/00_/345/213/225/344/275/234/347/242/272/350/252/215.json +0 -14
- package/payload/compliance/dict/06_house_rules.json +0 -16
- package/payload/compliance/dict/_sample/04_common_keihyo.json +0 -270
- package/payload/compliance/dict/_sample/README.md +0 -72
- package/payload/compliance/lint.js +0 -265
- package/payload/disciplines//347/225/252/351/240/255/343/201/256/344/275/234/346/263/225.md +0 -64
- package/payload/disciplines//350/207/252/345/267/261/345/201/245/350/250/272.md +0 -74
- package/payload/disciplines//351/200/261/346/254/241/343/203/241/343/203/263/343/203/206.md +0 -60
- package/payload/migration/protocol.md +0 -35
- package/payload/skill-maker/SKILL_base_anthropic.md +0 -357
- package/payload/skill-maker/skill-maker-v1.0.md +0 -305
- 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
- package/payload/skills/image-gen/SKILL.md +0 -147
- package/payload/skills/image-gen/gen.js +0 -225
- package/payload/skills/remember/SETUP_Google/351/200/243/346/220/272.md +0 -106
- package/payload/skills/remember/SKILL.md +0 -158
- package/payload/skills/remember/handoff.js +0 -149
- package/payload/skills/remember/tasks.js +0 -320
- package/payload/skills/slide-deck/SKILL.md +0 -160
- package/payload/skills/transcribe/README.md +0 -182
- package/payload/skills/transcribe/dict.json +0 -10
- package/payload/skills/transcribe/enroll_speaker.py +0 -76
- package/payload/skills/transcribe/identify_speakers.py +0 -153
- package/payload/skills/transcribe/transcribe.py +0 -126
package/server.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// 🚨★**`setup` で呼ばれたら、MCPサーバーとしてではなく「設定を書く道具」として動く**
|
|
3
|
+
// (2026-08-28)。★由来=配った1行が Claude Code 前提で、Antigravity の方が入れられなかった。
|
|
4
|
+
// ★★**どのクライアントでも、ターミナルの1行で入る**ようにする:
|
|
5
|
+
// npx -y @horizon_works/banto setup "<鍵.署名>"
|
|
6
|
+
// ★既にある設定は消さない。★読めなければ書かない。★書いたら読み直して確かめる。
|
|
7
|
+
if (process.argv[2] === 'setup') {
|
|
8
|
+
require('./add_to_config.js');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
12
|
* 番頭ゲート MCP サーバー(最小版 v0.1)
|
|
4
13
|
*
|
|
@@ -221,6 +230,9 @@ function secondOpinion(targetPath) {
|
|
|
221
230
|
|
|
222
231
|
// ---------------------------------------------------------------- 道具の定義
|
|
223
232
|
|
|
233
|
+
// ★法令パーツの橋(★無くても番頭は動く。★あれば道具が4つ増える)
|
|
234
|
+
const LAW = (() => { try { return require('./law_bridge.js'); } catch (_) { return null; } })();
|
|
235
|
+
|
|
224
236
|
const TOOLS = [
|
|
225
237
|
{
|
|
226
238
|
name: 'check_file',
|
|
@@ -552,6 +564,31 @@ const TOOLS = [
|
|
|
552
564
|
required: ['name'],
|
|
553
565
|
},
|
|
554
566
|
},
|
|
567
|
+
{
|
|
568
|
+
name: 'check_masters',
|
|
569
|
+
description:
|
|
570
|
+
'★同じ役割のものが2つ以上ないかを見ます(正本割れの点検)。'
|
|
571
|
+
+ '★機械は候補を出すだけで、**同じ仕事かどうかは判断しません**。あなたが1組ずつ見て決めてください。'
|
|
572
|
+
+ '★中身は返しません(ファイル名・行数・更新日・先頭の見出しだけ)。'
|
|
573
|
+
+ '決めたら decide を付けて呼ぶと `正本.md` に残り、記録の道具がそれを読んで振る舞います。',
|
|
574
|
+
inputSchema: {
|
|
575
|
+
type: 'object',
|
|
576
|
+
properties: {
|
|
577
|
+
dir: { type: 'string', description: '見るフォルダ(省略すると今の場所)' },
|
|
578
|
+
decide: {
|
|
579
|
+
type: 'object',
|
|
580
|
+
description: '★決まったときだけ付けます',
|
|
581
|
+
properties: {
|
|
582
|
+
役割: { type: 'string', description: '例: 下書き帳 / 記憶の正本 / やること' },
|
|
583
|
+
正本: { type: 'string', description: '本物にするファイル(フォルダからの相対)' },
|
|
584
|
+
別本: { type: 'array', items: { type: 'string' }, description: '使わないほう' },
|
|
585
|
+
理由: { type: 'string', description: '★なぜそう決めたか(次に読む人のため)' },
|
|
586
|
+
},
|
|
587
|
+
required: ['役割', '正本'],
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
},
|
|
555
592
|
{
|
|
556
593
|
name: 'tidy',
|
|
557
594
|
description:
|
|
@@ -727,6 +764,44 @@ function resources() {
|
|
|
727
764
|
// 実体・作法 → ここ(利用者のフォルダ)
|
|
728
765
|
// 記憶 → MCP(tools)
|
|
729
766
|
const PAYLOAD = path.join(__dirname, 'payload');
|
|
767
|
+
|
|
768
|
+
// 🚨★**配るものは、パッケージに同梱しない。配布口(サーバー)から取る**(2026-08-28)
|
|
769
|
+
// ★由来=「payload をサーバー側へ移す(sync_core と同じ口にする=鍵が要る形)」。
|
|
770
|
+
// ★★同梱したままだと、鍵で `install` を止めても意味がない。
|
|
771
|
+
// `npm pack @horizon_works/banto` して解凍すれば、**誰でも中身を読める**から。
|
|
772
|
+
// ★鍵の話ではなく、同梱の話だった。
|
|
773
|
+
// ★取り方は `add_supplement` と同じ口(`get_supplement`)に寄せる。★新しい口を作らない。
|
|
774
|
+
// ★鍵が無ければ `supPost` が止める(★入口を1つにしたので、抜け道ができない)。
|
|
775
|
+
// ★手元に控えを残す。取れなかったときは控えで進める(★切れても止まらない)。
|
|
776
|
+
const BASE_NAME = 'base';
|
|
777
|
+
let PAYLOAD_DIR = PAYLOAD; // ★実際に読む場所
|
|
778
|
+
function baseCacheDir() {
|
|
779
|
+
return path.join(process.env.BANTO_HOME || path.join(require('os').homedir(), '.banto'), 'base');
|
|
780
|
+
}
|
|
781
|
+
async function ensurePayload(force) {
|
|
782
|
+
// ★開発中(リポジトリの中)は同梱されたものを使う
|
|
783
|
+
try { if (fs.existsSync(PAYLOAD) && fs.readdirSync(PAYLOAD).length) { PAYLOAD_DIR = PAYLOAD; return; } } catch (_) {}
|
|
784
|
+
const cache = baseCacheDir();
|
|
785
|
+
const 控えがある = (() => { try { return fs.existsSync(cache) && fs.readdirSync(cache).length > 0; } catch (_) { return false; } })();
|
|
786
|
+
if (控えがある && !force) { PAYLOAD_DIR = cache; return; }
|
|
787
|
+
let rows;
|
|
788
|
+
try {
|
|
789
|
+
rows = await supPost('get_supplement', { p_name: BASE_NAME });
|
|
790
|
+
} catch (e) {
|
|
791
|
+
if (控えがある) { PAYLOAD_DIR = cache; return; } // ★取れなくても控えで進む
|
|
792
|
+
throw new Error('配るものを取ってこられませんでした(' + e.message + ')');
|
|
793
|
+
}
|
|
794
|
+
if (!rows.length) {
|
|
795
|
+
if (控えがある) { PAYLOAD_DIR = cache; return; }
|
|
796
|
+
throw new Error('配布口に「' + BASE_NAME + '」がありません');
|
|
797
|
+
}
|
|
798
|
+
for (const r of rows) {
|
|
799
|
+
const dst = path.join(cache, r.path);
|
|
800
|
+
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
801
|
+
fs.writeFileSync(dst, r.content, 'utf8');
|
|
802
|
+
}
|
|
803
|
+
PAYLOAD_DIR = cache;
|
|
804
|
+
}
|
|
730
805
|
// ★版は package.json だけに書く(2026-08-21)。
|
|
731
806
|
// コードにも書くと、上げ忘れて**別々の版を名乗る**。正本は1つ。
|
|
732
807
|
const VERSION = (() => {
|
|
@@ -755,13 +830,13 @@ const NEEDS = {
|
|
|
755
830
|
|
|
756
831
|
function listPayload() {
|
|
757
832
|
const out = [];
|
|
758
|
-
if (!fs.existsSync(
|
|
833
|
+
if (!fs.existsSync(PAYLOAD_DIR)) return out;
|
|
759
834
|
(function w(d) {
|
|
760
835
|
for (const e of fs.readdirSync(d)) {
|
|
761
836
|
const p = path.join(d, e);
|
|
762
|
-
fs.statSync(p).isDirectory() ? w(p) : out.push(path.relative(
|
|
837
|
+
fs.statSync(p).isDirectory() ? w(p) : out.push(path.relative(PAYLOAD_DIR, p).split('\\').join('/'));
|
|
763
838
|
}
|
|
764
|
-
})(
|
|
839
|
+
})(PAYLOAD_DIR);
|
|
765
840
|
return out.sort();
|
|
766
841
|
}
|
|
767
842
|
|
|
@@ -782,6 +857,21 @@ function writeManifest(dest, m) {
|
|
|
782
857
|
fs.writeFileSync(path.join(dest, MANIFEST), JSON.stringify(m, null, 2), 'utf8');
|
|
783
858
|
}
|
|
784
859
|
|
|
860
|
+
function listInstallable() {
|
|
861
|
+
const files = listPayload();
|
|
862
|
+
const groups = {};
|
|
863
|
+
for (const f of files) {
|
|
864
|
+
const g = f.split('/').slice(0, 2).join('/').replace(/\.[^.]+$/, '');
|
|
865
|
+
(groups[g] = groups[g] || []).push(f);
|
|
866
|
+
}
|
|
867
|
+
return {
|
|
868
|
+
置けるもの: Object.entries(groups).map(([g, fs2]) => ({ 名前: g, 件数: fs2.length })),
|
|
869
|
+
合計: files.length,
|
|
870
|
+
別に要るもの: Object.entries(NEEDS).map(([k, v]) => k + ':' + v),
|
|
871
|
+
note: '★ルールと番頭の核は、このMCPが持っています。置く必要はありません。',
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
|
|
785
875
|
function install(to, overwrite) {
|
|
786
876
|
const files = listPayload();
|
|
787
877
|
if (!files.length) throw new Error('配るものが見つかりません(payload が空です)');
|
|
@@ -791,7 +881,7 @@ function install(to, overwrite) {
|
|
|
791
881
|
const m = readManifest(dest);
|
|
792
882
|
const placed = [], skipped = [], backed = [];
|
|
793
883
|
for (const f of files) {
|
|
794
|
-
const src = path.join(
|
|
884
|
+
const src = path.join(PAYLOAD_DIR, f);
|
|
795
885
|
const dst = path.join(dest, f);
|
|
796
886
|
if (fs.existsSync(dst)) {
|
|
797
887
|
if (!overwrite) { skipped.push(f); continue; }
|
|
@@ -847,7 +937,7 @@ function update(to, apply) {
|
|
|
847
937
|
|
|
848
938
|
const 入れ替える = [], 新しく足す = [], 触らない = [], 変わっていない = [];
|
|
849
939
|
for (const f of files) {
|
|
850
|
-
const src = path.join(
|
|
940
|
+
const src = path.join(PAYLOAD_DIR, f);
|
|
851
941
|
const dst = path.join(dest, f);
|
|
852
942
|
const now = digest(src);
|
|
853
943
|
if (!fs.existsSync(dst)) { 新しく足す.push(f); continue; }
|
|
@@ -884,21 +974,21 @@ function update(to, apply) {
|
|
|
884
974
|
const dst = path.join(dest, f);
|
|
885
975
|
try {
|
|
886
976
|
fs.renameSync(dst, dst + '.bak-' + stampCompact()); // ★消さずに控えへ
|
|
887
|
-
fs.copyFileSync(path.join(
|
|
888
|
-
m.files[f] = digest(path.join(
|
|
977
|
+
fs.copyFileSync(path.join(PAYLOAD_DIR, f), dst);
|
|
978
|
+
m.files[f] = digest(path.join(PAYLOAD_DIR, f));
|
|
889
979
|
done.push(f);
|
|
890
980
|
} catch (_) {}
|
|
891
981
|
}
|
|
892
982
|
for (const f of 新しく足す) {
|
|
893
983
|
const dst = path.join(dest, f);
|
|
894
984
|
fs.mkdirSync(path.dirname(dst), { recursive: true });
|
|
895
|
-
fs.copyFileSync(path.join(
|
|
896
|
-
m.files[f] = digest(path.join(
|
|
985
|
+
fs.copyFileSync(path.join(PAYLOAD_DIR, f), dst);
|
|
986
|
+
m.files[f] = digest(path.join(PAYLOAD_DIR, f));
|
|
897
987
|
added.push(f);
|
|
898
988
|
}
|
|
899
989
|
for (const f of 触らない) {
|
|
900
990
|
// ★元は動かさない。新しい版を隣に置くだけ。見比べて、要るところだけ写してもらう
|
|
901
|
-
try { fs.copyFileSync(path.join(
|
|
991
|
+
try { fs.copyFileSync(path.join(PAYLOAD_DIR, f), path.join(dest, f + '.new')); asNew.push(f + '.new'); } catch (_) {}
|
|
902
992
|
}
|
|
903
993
|
m.version = VERSION;
|
|
904
994
|
try { writeManifest(dest, m); } catch (_) {}
|
|
@@ -1062,20 +1152,22 @@ function supEndpoint(fn) {
|
|
|
1062
1152
|
if (!url) return null;
|
|
1063
1153
|
return url.replace(/\/rpc\/[^/]+$/, '/rpc/' + fn);
|
|
1064
1154
|
}
|
|
1155
|
+
// 🚨★**同じ役割のものを2つ持たない**(2026-08-28)
|
|
1156
|
+
// ★ここには `licenseConfig()` という写しがあった。★`client.js` の `config()` と同じ仕事をしていた。
|
|
1157
|
+
// ★★実際に事故った=`BANTO_KEY`(鍵と署名を1つにまとめた形)の読み取りを client.js にだけ入れ、
|
|
1158
|
+
// ★こちらを直し忘れた。★署名の検査は通るのに、サプリの口だけ「鍵が設定されていません」と言う、
|
|
1159
|
+
// ★**静かなズレ**になった。★2つあると、必ずこうなる。
|
|
1160
|
+
// ★→ ★**写しを消して、正本(client.js の config)を呼ぶ。**
|
|
1161
|
+
// ★client.js が無い構成でも落ちないように、無ければ環境変数だけで組む。
|
|
1065
1162
|
function licenseConfig() {
|
|
1066
|
-
// 🚨★2026-08-28=★sig を足した。★client.js 側だけ直して、★こちらを忘れていた
|
|
1067
|
-
// (★同じ役割のものが2箇所にある=★正本割れ。★片方だけ直すと静かにずれる)
|
|
1068
|
-
const c = { key: process.env.BANTOU_LICENSE_KEY || '', url: process.env.BANTOU_LICENSE_URL || '',
|
|
1069
|
-
anonKey: process.env.BANTOU_LICENSE_ANON || '',
|
|
1070
|
-
sig: process.env.BANTOU_LICENSE_SIG || '' };
|
|
1071
1163
|
try {
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
c.url = c.url || j.url || '';
|
|
1075
|
-
c.anonKey = c.anonKey || j.anonKey || '';
|
|
1076
|
-
c.sig = c.sig || j.sig || '';
|
|
1164
|
+
const LIC = require('./license/client.js');
|
|
1165
|
+
if (LIC && LIC.config) return LIC.config();
|
|
1077
1166
|
} catch (_) {}
|
|
1078
|
-
return
|
|
1167
|
+
return { key: process.env.BANTO_KEY ? String(process.env.BANTO_KEY).split('.')[0] : (process.env.BANTOU_LICENSE_KEY || ''),
|
|
1168
|
+
url: process.env.BANTOU_LICENSE_URL || '',
|
|
1169
|
+
anonKey: process.env.BANTOU_LICENSE_ANON || '',
|
|
1170
|
+
sig: process.env.BANTOU_LICENSE_SIG || '' };
|
|
1079
1171
|
}
|
|
1080
1172
|
|
|
1081
1173
|
function supPost(fn, body) {
|
|
@@ -1442,7 +1534,7 @@ const 変えるかもしれない道具 = new Set([
|
|
|
1442
1534
|
'mask_file', 'unmask_file', 'render', 'make_dict', 'policy',
|
|
1443
1535
|
'tidy', 'tidy_undo', 'set_polaris', 'learn', 'remember', 'settle',
|
|
1444
1536
|
'setup_google', 'connect_google', 'add_task', 'complete_task',
|
|
1445
|
-
'share_stats', 'open_shelf',
|
|
1537
|
+
'share_stats', 'open_shelf', 'check_masters',
|
|
1446
1538
|
]);
|
|
1447
1539
|
|
|
1448
1540
|
function 足あとを残す(name, args) {
|
|
@@ -1462,7 +1554,21 @@ function 足あとを残す(name, args) {
|
|
|
1462
1554
|
|
|
1463
1555
|
// ---------------------------------------------------------------- 道具の実行
|
|
1464
1556
|
|
|
1557
|
+
// ★その鍵が、そのサプリを契約しているか(★サーバーに聞く。手元では決めない)
|
|
1558
|
+
async function 契約あり(名前) {
|
|
1559
|
+
try {
|
|
1560
|
+
// ★取れれば契約あり。★取れなければ無い(★例外の中身では判定しない)
|
|
1561
|
+
const rows = await supPost('get_supplement', { p_name: 名前 });
|
|
1562
|
+
return Array.isArray(rows) && rows.length > 0;
|
|
1563
|
+
} catch (_) { return false; }
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1465
1566
|
function callTool(name, args) {
|
|
1567
|
+
// ★法令パーツ(別のMCP)への中継
|
|
1568
|
+
if (LAW && LAW.これか(name)) {
|
|
1569
|
+
return 契約あり(LAW.SUPPLEMENT).then((ok) => LAW.中継(name, args, ok));
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1466
1572
|
if (name === 'check_file') {
|
|
1467
1573
|
const p = String(args && args.path || '');
|
|
1468
1574
|
if (!p) throw new Error('path が指定されていません');
|
|
@@ -1550,11 +1656,11 @@ function callTool(name, args) {
|
|
|
1550
1656
|
}
|
|
1551
1657
|
|
|
1552
1658
|
if (name === 'install') {
|
|
1553
|
-
return install(args && args.to, args && args.overwrite);
|
|
1659
|
+
return ensurePayload(true).then(() => install(args && args.to, args && args.overwrite));
|
|
1554
1660
|
}
|
|
1555
1661
|
|
|
1556
1662
|
if (name === 'update') {
|
|
1557
|
-
return update(args && args.to, args && args.apply);
|
|
1663
|
+
return ensurePayload(true).then(() => update(args && args.to, args && args.apply));
|
|
1558
1664
|
}
|
|
1559
1665
|
|
|
1560
1666
|
if (name === 'policy') {
|
|
@@ -1585,6 +1691,10 @@ function callTool(name, args) {
|
|
|
1585
1691
|
return PRIV.render(FREE, args && args.mask_id, args && args.text, args && args.to, args && args.dir);
|
|
1586
1692
|
}
|
|
1587
1693
|
|
|
1694
|
+
if (name === 'check_masters') {
|
|
1695
|
+
return FREE.checkMasters(args && args.dir, args && args.decide);
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1588
1698
|
if (name === 'tidy') return tidy(args && args.dir, args && args.days, args && args.apply);
|
|
1589
1699
|
if (name === 'tidy_undo') return tidyUndo(args && args.dir);
|
|
1590
1700
|
|
|
@@ -1620,18 +1730,8 @@ function callTool(name, args) {
|
|
|
1620
1730
|
if (name === 'remove_supplement') return removeSupplement(args && args.name, args && args.to);
|
|
1621
1731
|
|
|
1622
1732
|
if (name === 'list_installable') {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
for (const f of files) {
|
|
1626
|
-
const g = f.split('/').slice(0, 2).join('/').replace(/\.[^.]+$/, '');
|
|
1627
|
-
(groups[g] = groups[g] || []).push(f);
|
|
1628
|
-
}
|
|
1629
|
-
return {
|
|
1630
|
-
置けるもの: Object.entries(groups).map(([g, fs2]) => ({ 名前: g, 件数: fs2.length })),
|
|
1631
|
-
合計: files.length,
|
|
1632
|
-
別に要るもの: Object.entries(NEEDS).map(([k, v]) => k + ':' + v),
|
|
1633
|
-
note: '★ルールと番頭の核は、このMCPが持っています。置く必要はありません。',
|
|
1634
|
-
};
|
|
1733
|
+
// ★一覧も配布口から。★控えがあれば通信しない(force を付けない)
|
|
1734
|
+
return ensurePayload(false).then(() => listInstallable());
|
|
1635
1735
|
}
|
|
1636
1736
|
|
|
1637
1737
|
if (name === 'check_text') {
|
|
@@ -1699,7 +1799,10 @@ async function handle(req) {
|
|
|
1699
1799
|
}
|
|
1700
1800
|
|
|
1701
1801
|
if (method === 'tools/list') {
|
|
1702
|
-
|
|
1802
|
+
// ★法令パーツの道具も**誰にでも見せる**(2026-08-28 裁定)。
|
|
1803
|
+
// ★契約が無い方には、呼んだときに「含まれていません」と返る。
|
|
1804
|
+
// ★見えないと存在を知られないので、入口として見せる。
|
|
1805
|
+
return { jsonrpc: '2.0', id, result: { tools: TOOLS.concat(LAW ? LAW.TOOLS : []) } };
|
|
1703
1806
|
}
|
|
1704
1807
|
|
|
1705
1808
|
if (method === 'tools/call') {
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: compliance
|
|
3
|
-
description: 文章を出す前の関所。★このプレーン版では、辞書は空にしてあります。商売の文章(商品の紹介・広告・宣伝)を書くようになったときに、その業種の辞書を足して使います。個人の文章には使いません。
|
|
4
|
-
layer: L0
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 文章を出す前の関所(compliance)
|
|
8
|
-
|
|
9
|
-
> ★**このプレーン版では、この関所はまだ仕事をしていません。**
|
|
10
|
-
> 辞書が空だからです。**それでいいです。**
|
|
11
|
-
>
|
|
12
|
-
> 個人で使うぶんには、止めなければいけない言葉はほとんどありません。
|
|
13
|
-
> ここは「**商売の文章を書くようになったときのための器**」として置いてあります。
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## いまの状態
|
|
18
|
-
|
|
19
|
-
| 辞書 | 中身 |
|
|
20
|
-
|---|---|
|
|
21
|
-
| `dict/00_動作確認.json` | 関所そのものが動くかを確かめる1件だけ。★消さないでください |
|
|
22
|
-
| `dict/06_house_rules.json` | **空**。自分ルールを足す場所 |
|
|
23
|
-
| `dict/_sample/` | 見本(美容・健康の商材向け)。★既定では**読み込まれません** |
|
|
24
|
-
|
|
25
|
-
`node kit/compliance/lint.js <ファイル>` は、いま走らせても
|
|
26
|
-
「危ない表現は見つかりませんでした」としか出ません。**それが正常です。**
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## いつ使い始めるか
|
|
31
|
-
|
|
32
|
-
次のことをするようになったら、この関所を起こします。
|
|
33
|
-
|
|
34
|
-
- 商品やサービスを**売る**文章を書く(紹介文・広告・SNSの宣伝・フリマの説明)
|
|
35
|
-
- 人から**お金をもらう**活動の告知を書く
|
|
36
|
-
- 健康・美容・食品・医療にかかわることを人に勧める
|
|
37
|
-
|
|
38
|
-
★これらは、**言い方ひとつで法律に触れます**。個人でも例外ではありません。
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## 起こし方
|
|
43
|
-
|
|
44
|
-
### 1. 自分ルールから始める(★いちばん効く)
|
|
45
|
-
|
|
46
|
-
`dict/06_house_rules.json` の `entries` に足します。法律の話ではなく、
|
|
47
|
-
「**前にこれで嫌な思いをした**」を1件ずつ入れていくだけです。
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"ng": ["絶対に儲かる"],
|
|
52
|
-
"ok": "(数字と条件を書く。例:3ヶ月で◯件の実績があります)",
|
|
53
|
-
"why": "言い切ると、そうならなかったときに責任を問われる",
|
|
54
|
-
"flag": "auto"
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
★**必ず `ok`(言い換え候補)を書いてください。** 「言えません」で止めると、人は回り道を探します。
|
|
59
|
-
|
|
60
|
-
### 2. 業種の辞書を足す
|
|
61
|
-
|
|
62
|
-
その業種で踏むと事故になる法律を、辞書にします。
|
|
63
|
-
作り方の見本が `dict/_sample/` にあります(美容・健康の商材向け)。
|
|
64
|
-
|
|
65
|
-
**そのまま使わないでください。** 業種が違えば、見るべき法律も違います。
|
|
66
|
-
見本は「どういう形で書くか」の参考にしてください。
|
|
67
|
-
|
|
68
|
-
★一次情報(行政・公式のページ)に当たってから書くこと。**記憶で条番号を書かない。**
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## 通し方
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
# ファイルを検査
|
|
76
|
-
node kit/compliance/lint.js 下書き.txt
|
|
77
|
-
|
|
78
|
-
# その場の文章を検査
|
|
79
|
-
echo "検査したい文章" | node kit/compliance/lint.js
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
終了コードの意味:
|
|
83
|
-
|
|
84
|
-
| コード | 意味 | どうする |
|
|
85
|
-
|---|---|---|
|
|
86
|
-
| 0 | 辞書に載っている言い方は無かった | ★**まだ出してよい、ではありません。** 下の4点を自分の目で見る |
|
|
87
|
-
| 1 | **要確認**あり | 言い換え候補を添えて、本人に判断を返す。勝手にOKにしない |
|
|
88
|
-
| 2 | **要修正**あり | 言い換えて、もう一度通す。通るまで出さない |
|
|
89
|
-
| 3 | **検査できなかった** | 辞書が空・壊れている・カテゴリ名が違う。★**0と混同しない** |
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## ★辞書に無いものは検出できません
|
|
94
|
-
|
|
95
|
-
0件は「**辞書に載っている表現が無かった**」だけで、安全の証明ではありません。
|
|
96
|
-
0件のときも、次の4つは自分の目で見てください。
|
|
97
|
-
|
|
98
|
-
1. **病気・治療を思わせないか**(病名/治る・効く・改善する)
|
|
99
|
-
2. **体が変わると言い切っていないか**(消える・なくなる・落ちる・生える)
|
|
100
|
-
3. **数字や実績に根拠があるか**(母数・時期・対象・比べた相手を書けるか)
|
|
101
|
-
4. **他社・他人を下げていないか**
|
|
102
|
-
|
|
103
|
-
見つけたら、**辞書に足してください**。辞書は使いながら育てるものです。
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## やってはいけないこと
|
|
108
|
-
|
|
109
|
-
- ❌ **0件だったことを「安全の証明」として報告する**
|
|
110
|
-
- ❌ **[要確認]を自分の判断でOKにする**
|
|
111
|
-
- ❌ **「個人の感想です」を付けて危ない表現を通す**(注記は免罪符になりません)
|
|
112
|
-
- ❌ **数値・成分・実績を自分で作る**(分からない数字は `■要確認:○○`)
|
|
113
|
-
- ❌ 見本の辞書を、業種を確かめずにそのまま使う
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"category": "selftest",
|
|
3
|
-
"label": "動作確認(★消さないでください)",
|
|
4
|
-
"note": "この辞書は、関所そのものが動いているかを確かめるためだけに入っています。ふだんの文章には出てこない言葉なので、誤って引っかかることはありません。中身を空にすると点検が通らなくなります。",
|
|
5
|
-
"entries": [
|
|
6
|
-
{
|
|
7
|
-
"ng": ["ゲート動作確認テスト"],
|
|
8
|
-
"ok": "(これは動作確認用の言葉です。文章から消してください)",
|
|
9
|
-
"why": "関所が動いているかを確かめるための言葉です。ここが検出されれば、関所は生きています",
|
|
10
|
-
"law": "",
|
|
11
|
-
"flag": "auto"
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"category": "house_rules",
|
|
3
|
-
"label": "自分ルール",
|
|
4
|
-
"note": "★ここは空の器です。使っていくうちに『これは書かないでほしい』が出てきたら、下の entries に足してください。法律でも規約でもない、その人の判断です。実際の現場では、この層がいちばん効きます。",
|
|
5
|
-
"_書き方の見本": {
|
|
6
|
-
"ng": ["止めたい言い方をここに書く", "言い換えも複数書ける"],
|
|
7
|
-
"regex": ["正規表現でしか拾えないものだけ。ふつうは要りません"],
|
|
8
|
-
"ok": "★代わりに使える言い方(必須。ここを空にしない)",
|
|
9
|
-
"why": "なぜ止めるのか(あとで自分が読んで分かるように)",
|
|
10
|
-
"law": "根拠があれば。無ければ空でよい",
|
|
11
|
-
"flag": "auto なら要修正 / human なら人が判断",
|
|
12
|
-
"near": ["この語が同じ行にあるときだけ検出する(誤検出よけ)"],
|
|
13
|
-
"except": ["この語が同じ行にあるときは検出しない(否定文よけ)"]
|
|
14
|
-
},
|
|
15
|
-
"entries": []
|
|
16
|
-
}
|