@clubs.place/cli 0.1.24 → 0.1.25

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/PROVENANCE.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "package": "@clubs.place/cli",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "repository": "https://github.com/frame00/@clubs.place/cli",
5
- "commit": "6d066f264458d284128da7cf981ac30e81c86be2",
5
+ "commit": "ff15dd9dd15a9cb332288d6524e74d8de47614c7",
6
6
  "license": "MIT",
7
- "generated_at": "2026-10-26T06:41:39.425Z",
7
+ "generated_at": "2026-10-28T13:13:07.338Z",
8
8
  "files": {
9
9
  ".env.example": "sha256-6b151ffb18a84ae9e468d77e82d6af1ebb344ee5f4a45f065e396c56859d6cf6",
10
+ "PROVENANCE.json": "sha256-82a47fe5806c0f66050a9b9d8cba39135311988e25b2e0c5c4e56b1252f3778d",
10
11
  "bin/clubs-nippo": "sha256-03868da2fca1cbd333f2260d08bcb0b14a258a7e7df0da8bfce3e2ed7bee2c62",
11
12
  "bin/clubs-nippo-web.mjs": "sha256-23734c47f22cd686c30fd3425b904174ee265ca113a66c34b45916905ff06b4a",
12
13
  "bin/clubs-nippo.mjs": "sha256-51102bf7467c7794770c6046305384f2209c450136af3dced39b6cc2a974cff7",
13
- "bin/clubs.mjs": "sha256-c2bb887a6f5f059e4e490e92de4e83bedd4549461adc382e273cdafa6f6fb0e4",
14
+ "bin/clubs.mjs": "sha256-2f50a079abfe134b81446e5ade7157e3c4b800b22475d6842f35e1d93a7d02d4",
14
15
  "docs/events-schema.md": "sha256-6be7a614351c2a3dbf15c5201dbf5d466649e4b91d17206c603f0c26b0290256",
15
16
  "examples/hermes-events.sample.jsonl": "sha256-bb895a3d5abeeab10a46835af2771d077b71564286a816caf8d73682dbfec9cf",
16
17
  "src/aggregate.mjs": "sha256-2b8c9185ee133a115e98e2ed6d05c536e4d9f6cc71e390ceab2fca89f7dc6512",
@@ -32,7 +33,6 @@
32
33
  "src/lemma.docHash.test.mjs": "sha256-7446ac23bdfbe7e92490134cbe74470266afc1efd176c3e40078d70bd1d1a141",
33
34
  "src/lemma.mjs": "sha256-48fdf89267bf09c90eafde180f0fe00fb443ea0dbf87b7dd970689d1fc192675",
34
35
  "src/mask.mjs": "sha256-324c47cf78db4596965f0e0f39ff8f63ed794baf8b9f1796de5feb0e69891471",
35
- "src/mcp.mjs": "sha256-d1f06c54ba174abb7979f3ec08218d1f00bd8e886f8dc1e11c04ce2fea1986bc",
36
36
  "src/narrative.blockRepos.test.mjs": "sha256-0be41c34bf5a2848667dbca9456cd7eac250f19deaec5bd2ba36ae572baf7ad3",
37
37
  "src/narrative.mjs": "sha256-5b29d30c451fd05781384c4793623c303c4e52333cb70f3ef52a4164094f5ccb",
38
38
  "src/profiles.mjs": "sha256-b5f3fe14d2469334e199a2e4a4a870735940f66117ec80c969ff300aae565c69",
package/README.md CHANGED
@@ -51,7 +51,7 @@ npx @clubs.place/cli@latest --date=2026-10-08 --only=claude-code # その収集
51
51
  リモート MCP(URL+許可)で行う。
52
52
 
53
53
  以前の `claude mcp add clubs -- npx … mcp`(手元の MCP・`clubs_register` /
54
- `clubs_link_status`)は終わる。登録してあれば `claude mcp remove clubs` で外し、
54
+ `clubs_link_status`)は 0.1.25 で終わった。登録してあれば `claude mcp remove clubs` で外し、
55
55
  接続画面からつなぎ直す。
56
56
 
57
57
  ## 環境変数
package/bin/clubs.mjs CHANGED
@@ -167,14 +167,16 @@ const main = async () => {
167
167
  return;
168
168
  }
169
169
 
170
- // ── mcp: 手元の MCP(stdio)。終わる(CLUBS 判断 #26・2026-10-16)──────
171
- // AI を CLUBS につなぐのはリモート MCP。前に登録した人の AI が起動したとき
172
- // 黙って落ちないよう、しばらくは動かしたまま「つなぎ直して」を伝える。
173
- // stdout はプロトコル専用になる。
170
+ // ── mcp: 手元の MCP は終わった(CLUBS 判断 #26・2026-10-16)──────────
171
+ // 前に登録した人の AI がこれを起動したとき、黙って落ちないように理由を出す。
172
+ // stdout は MCP のプロトコルが読むので、知らせは stderr に出す。
174
173
  if (argv._[0] === "mcp") {
175
- const { runMcpServer } = await import("../src/mcp.mjs");
176
- await runMcpServer();
177
- return;
174
+ console.error(
175
+ "[clubs mcp] 手元の MCP(clubs_register / clubs_link_status)は終わりました。" +
176
+ "CLUBS の接続画面 https://clubs.place/connections からリモート MCP につなぎ直し、" +
177
+ "この登録は `claude mcp remove clubs` などで外してください。日報の自動化(tick)はこのまま動きます。",
178
+ );
179
+ process.exit(1);
178
180
  }
179
181
 
180
182
  // ── init: 接続画面が発行するコマンド1行で .env を書く(npx 導入の入口)──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clubs.place/cli",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "description": "AI業務日報 — Claude Code の実行ログから前日ぶんの日報メールを生成して送る(pull型・本文生成はユーザー側LLM・生ログは端末を出ない)",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/mcp.mjs DELETED
@@ -1,286 +0,0 @@
1
- /**
2
- * CLUBS MCP サーバー(stdio・同一バイナリ同梱=全体設計 §6 / P0 §9)。
3
- *
4
- * `clubs-nippo mcp` で起動し、Claude Code / Cursor / Gemini CLI 等の
5
- * MCP クライアントから CLUBS への登録・疎通確認を対話の中で完結させる。
6
- *
7
- * CTO裁定(clubsx#53 D-4)に従う:
8
- * - ツールは clubs_register / clubs_link_status の2本のみ。
9
- * 発行系・日報の書き込み系は載せない(B-1: 自己申告の発行経路を作らない。
10
- * 日報の取り込みは従来どおり収集器の pull 経路のみ)。
11
- * - 出力はサーバ確定値・ローカル設定の定型フィールドのみ(自由文・他ユーザー
12
- * 由来のテキストを返さない=注入面の最小化)。
13
- *
14
- * **終わる(CLUBS 判断 #26・2026-10-16)**: AI を CLUBS につなぐのはリモート MCP
15
- * (接続画面の URL+許可)になり、この CLI は日報の自動化専用になった。前に
16
- * 登録した人の AI が起動したとき黙って落ちないよう、しばらくは動かしたまま、
17
- * 起動・道具の説明・返事のすべてで「つなぎ直して」を伝える(DEPRECATION)。
18
- *
19
- * 依存ゼロ方針(このリポの流儀)のため SDK は使わず、MCP の stdio
20
- * トランスポート(JSON-RPC 2.0・1行1メッセージ)を最小実装する。
21
- * stdout はプロトコル専用。ログは必ず stderr へ。
22
- */
23
-
24
- import { createInterface } from "node:readline";
25
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
26
- import { join } from "node:path";
27
- import { APP_HOME, ROOT } from "./config.mjs";
28
- import { collectorConfigUrl } from "./remote-config.mjs";
29
- import { readHistory } from "./history.mjs";
30
-
31
- const PROTOCOL_FALLBACK = "2025-06-18";
32
-
33
- /** 終わることの知らせ。決まった文だけ(自由文を返さない方針のまま)。 */
34
- export const DEPRECATION =
35
- "この手元の MCP(clubs_register / clubs_link_status)は終わります。" +
36
- "CLUBS の接続画面 https://clubs.place/connections からリモート MCP につなぎ直し、" +
37
- "この登録は `claude mcp remove clubs` などで外してください。日報の自動化(tick)はこのまま動きます。";
38
-
39
- const pkgVersion = () => {
40
- try {
41
- return JSON.parse(readFileSync(join(ROOT, "package.json"), "utf8")).version;
42
- } catch {
43
- return "0.0.0";
44
- }
45
- };
46
-
47
- // ── 登録先 URL のガード(注入面対策) ─────────────────────
48
- // MCP 経由の register は AI の文脈から呼ばれるため、細工された取込URLで
49
- // トークンや日報の送り先を挿げ替えられないよう、既定で CLUBS のホストに限る。
50
- // 自前ホストの開発者は CLUBS_NIPPO_ALLOW_HOST=<host> で1件だけ追加できる。
51
- const urlAllowed = (raw) => {
52
- try {
53
- const u = new URL(raw);
54
- const local = u.hostname === "localhost" || u.hostname === "127.0.0.1";
55
- if (local) return true; // ローカル開発
56
- if (u.protocol !== "https:") return false;
57
- if (u.hostname === "clubs.place" || u.hostname.endsWith(".clubs.place"))
58
- return true;
59
- return u.hostname === process.env.CLUBS_NIPPO_ALLOW_HOST;
60
- } catch {
61
- return false;
62
- }
63
- };
64
-
65
- /** init コマンドと同じ書式で .env を更新(既存キーは生かす)。 */
66
- const writeEnvUpdates = (updates) => {
67
- mkdirSync(join(APP_HOME, "out"), { recursive: true });
68
- const envPath = join(APP_HOME, ".env");
69
- const lines = existsSync(envPath)
70
- ? readFileSync(envPath, "utf8").replace(/\n$/, "").split("\n")
71
- : [
72
- "# clubs-nippo の設定。キーの一覧は https://www.npmjs.com/package/clubs-nippo を参照。",
73
- ];
74
- for (const [key, value] of Object.entries(updates)) {
75
- const row = `${key}=${value}`;
76
- const idx = lines.findIndex((l) => l.match(new RegExp(`^\\s*${key}\\s*=`)));
77
- if (idx >= 0) lines[idx] = row;
78
- else lines.push(row);
79
- }
80
- writeFileSync(envPath, lines.join("\n") + "\n", "utf8");
81
- return envPath;
82
- };
83
-
84
- const withTimeout = async (fn, ms) => {
85
- const ctrl = new AbortController();
86
- const timer = setTimeout(() => ctrl.abort(), ms);
87
- try {
88
- return await fn(ctrl.signal);
89
- } finally {
90
- clearTimeout(timer);
91
- }
92
- };
93
-
94
- /** 連携トークンの実在確認=collector-config にサーバ照会する。 */
95
- const serverCheck = async (ingestUrl, ingestToken) => {
96
- const url = collectorConfigUrl(ingestUrl);
97
- if (!url || !ingestToken) return { reachable: false, token_valid: false };
98
- try {
99
- const res = await withTimeout(
100
- (signal) =>
101
- fetch(url, {
102
- signal,
103
- headers: { Authorization: `Bearer ${ingestToken}` },
104
- }),
105
- 10_000,
106
- );
107
- return { reachable: true, token_valid: res.ok };
108
- } catch {
109
- return { reachable: false, token_valid: false };
110
- }
111
- };
112
-
113
- // ── ツール定義 ────────────────────────────────────────────
114
-
115
- const TOOLS = [
116
- {
117
- name: "clubs_register",
118
- description:
119
- "【終わります】" +
120
- DEPRECATION +
121
- " / この端末を CLUBS に登録する(clubs-nippo init と同じ設定を書く)。url と token は CLUBS の接続画面(/nippo/connections)が発行した値をそのまま渡すこと。登録後にサーバへ疎通確認する。",
122
- inputSchema: {
123
- type: "object",
124
- properties: {
125
- url: {
126
- type: "string",
127
- description: "取込URL(接続画面が発行。…/api/nippo/ingest)",
128
- },
129
- token: { type: "string", description: "連携トークン(接続画面が発行)" },
130
- source: {
131
- type: "string",
132
- description: "収集元(例: claude-code / cowork。省略可)",
133
- },
134
- agent_name: { type: "string", description: "体の表示名(省略可)" },
135
- owner_name: { type: "string", description: "オーナー名(省略可)" },
136
- },
137
- required: ["url", "token"],
138
- },
139
- },
140
- {
141
- name: "clubs_link_status",
142
- description:
143
- "【終わります】" +
144
- DEPRECATION +
145
- " / CLUBS との連携状態を返す(設定の有無・サーバ疎通・トークン有効性・ローカル最終記録日)。",
146
- inputSchema: { type: "object", properties: {} },
147
- },
148
- ];
149
-
150
- export const callTool = async (name, args = {}) => ({
151
- deprecated: DEPRECATION,
152
- ...(await callToolInner(name, args)),
153
- });
154
-
155
- const callToolInner = async (name, args = {}) => {
156
- if (name === "clubs_register") {
157
- const url = String(args.url ?? "");
158
- const token = String(args.token ?? "");
159
- if (!url || !token) {
160
- return { ok: false, error: "url と token は必須です" };
161
- }
162
- let parsed;
163
- try {
164
- parsed = new URL(url);
165
- } catch {
166
- return { ok: false, error: "url が不正です" };
167
- }
168
- if (!/\/api\/nippo\/ingest\/?$/.test(parsed.pathname)) {
169
- return {
170
- ok: false,
171
- error: "url は接続画面が発行した取込URL(…/api/nippo/ingest)を渡してください",
172
- };
173
- }
174
- if (!urlAllowed(url)) {
175
- return {
176
- ok: false,
177
- error:
178
- "この url のホストには登録できません(clubs.place / localhost のみ。自前ホストは CLUBS_NIPPO_ALLOW_HOST で許可)",
179
- };
180
- }
181
- const updates = Object.fromEntries(
182
- Object.entries({
183
- NIPPO_INGEST_URL: url,
184
- NIPPO_INGEST_TOKEN: token,
185
- SOURCE: args.source,
186
- AGENT_NAME: args.agent_name,
187
- OWNER_NAME: args.owner_name,
188
- }).filter(([, v]) => v),
189
- );
190
- const envPath = writeEnvUpdates(updates);
191
- // 同一セッション内の link_status が新しい値を見られるように反映する
192
- // (config.mjs の loadDotEnv は起動時に未設定キーしか埋めない)
193
- for (const [key, value] of Object.entries(updates)) process.env[key] = value;
194
- const server = await serverCheck(url, token);
195
- return {
196
- ok: server.token_valid,
197
- wrote: Object.keys(updates),
198
- env_path: envPath,
199
- ingest_url_host: parsed.host,
200
- server,
201
- next: server.token_valid
202
- ? "毎朝の自動配信は crontab に `npx -y @clubs.place/cli@latest tick` を登録(clubs-nippo init のヘルプ参照)"
203
- : "トークンがサーバで確認できませんでした。接続画面で再発行して register し直してください",
204
- };
205
- }
206
-
207
- if (name === "clubs_link_status") {
208
- const ingestUrl = process.env.NIPPO_INGEST_URL ?? "";
209
- const ingestToken = process.env.NIPPO_INGEST_TOKEN ?? "";
210
- const configured = Boolean(ingestUrl && ingestToken);
211
- const server = configured
212
- ? await serverCheck(ingestUrl, ingestToken)
213
- : { reachable: false, token_valid: false };
214
- const history = readHistory();
215
- return {
216
- ok: configured && server.token_valid,
217
- configured,
218
- ingest_url_host: ingestUrl ? new URL(ingestUrl).host : null,
219
- agent_name: process.env.AGENT_NAME ?? null,
220
- server,
221
- last_local_report_date: history.at(-1)?.date ?? null,
222
- env_path: join(APP_HOME, ".env"),
223
- };
224
- }
225
-
226
- return { ok: false, error: `unknown tool: ${name}` };
227
- };
228
-
229
- // ── JSON-RPC 2.0 / stdio ─────────────────────────────────
230
-
231
- const reply = (id, result) => {
232
- process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result }) + "\n");
233
- };
234
-
235
- const replyError = (id, code, message) => {
236
- process.stdout.write(
237
- JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n",
238
- );
239
- };
240
-
241
- export const runMcpServer = async () => {
242
- const rl = createInterface({ input: process.stdin, terminal: false });
243
- console.error(`[clubs-nippo mcp] ${DEPRECATION}`);
244
- console.error(
245
- `[clubs-nippo mcp] stdio server ready (tools: ${TOOLS.map((t) => t.name).join(", ")})`,
246
- );
247
-
248
- for await (const line of rl) {
249
- if (!line.trim()) continue;
250
- let msg;
251
- try {
252
- msg = JSON.parse(line);
253
- } catch {
254
- continue; // 不正な行は無視(プロトコル外のノイズ)
255
- }
256
- const { id, method, params } = msg;
257
-
258
- // 通知(id なし)は initialized 含め応答しない
259
- if (id === undefined || id === null) continue;
260
-
261
- try {
262
- if (method === "initialize") {
263
- reply(id, {
264
- protocolVersion: params?.protocolVersion ?? PROTOCOL_FALLBACK,
265
- capabilities: { tools: { listChanged: false } },
266
- serverInfo: { name: "clubs-nippo", version: pkgVersion() },
267
- instructions: DEPRECATION,
268
- });
269
- } else if (method === "ping") {
270
- reply(id, {});
271
- } else if (method === "tools/list") {
272
- reply(id, { tools: TOOLS });
273
- } else if (method === "tools/call") {
274
- const result = await callTool(params?.name, params?.arguments ?? {});
275
- reply(id, {
276
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
277
- isError: result.ok === false,
278
- });
279
- } else {
280
- replyError(id, -32601, `method not found: ${method}`);
281
- }
282
- } catch (e) {
283
- replyError(id, -32603, e?.message ?? "internal error");
284
- }
285
- }
286
- };