@luanpdd/kit-mcp 1.30.0 → 1.30.2

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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.30.0",
3
- "timestamp": "2026-05-13T09:16:42.372Z",
2
+ "version": "1.30.2",
3
+ "timestamp": "2026-05-14T09:25:36.145Z",
4
4
  "files": {
5
5
  "COMANDOS.md": "d24ec61a6ec35db314cc5f2ae287bfb927b794789c8f1d558c55862f5e6534b2",
6
6
  "COMPATIBILITY.md": "794e336a87045cdf0161785b9a7a0975a49abbd80bdd816b8852251fcc8126ca",
@@ -297,6 +297,7 @@
297
297
  "framework/workflows/verify-work.md": "219b2e45782b0b9ef042b69f02c92232947b8144ac4f472a6f5a6577f21de8df",
298
298
  "hooks/check-update.js": "927bb6394259b8547aad508580872c92d508f5886b29e9b3ae9603076baa2a5c",
299
299
  "hooks/context-monitor.js": "8ff9295c6ab769ca766e3e612c39d72d171a97bb082bde590bdf328d557249b9",
300
+ "hooks/kit-attribution-reminder.cjs": "155e3d53d7e6120f5a147f4c3db8c468b9d85b039d0ce324184fd62516ffac11",
300
301
  "hooks/post-apply-migration.js": "cd67f24ca9ba0a064087b9abeacee094ae24baad0cdc06f776d7a2f8ccad9685",
301
302
  "hooks/prompt-guard.js": "426f0240e3ee383571a48e062e6819d8fc3df456171fbc7e2aafb17889a9a389",
302
303
  "hooks/sidecar-tool-publisher.js": "b8357ae80e82bfc875acb6c616cf82a943a2d77cf2ceba2f23a50b7d1f335f2d",
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ // hook-version: 1.30.2
3
+ // kit-mcp · Kit Attribution Reminder (UserPromptSubmit)
4
+ //
5
+ // Injeta `additionalContext` no envelope do prompt do usuário com diretiva
6
+ // canônica v1.30.1: sempre que Claude usar comandos/agents/skills do kit-mcp
7
+ // no turno corrente, deve abrir o sidecar (auto-spawn já cuida disso na 1ª
8
+ // tool call) e listar os recursos usados em bloco final do output.
9
+ //
10
+ // Objetivo: dar feedback visual + textual de uso real do kit-mcp para o
11
+ // usuário detectar bugs no fluxo precocemente.
12
+ //
13
+ // Pipeline: UserPromptSubmit hook → reads stdin envelope → writes JSON com
14
+ // `{ continue: true, hookSpecificOutput: { hookEventName: "UserPromptSubmit",
15
+ // additionalContext: "<diretiva>" } }` → exit 0.
16
+ //
17
+ // SOFT failure: qualquer erro → exit 0 sem bloquear. Skip se
18
+ // KIT_MCP_NO_ATTRIBUTION=1.
19
+ //
20
+ // Module format: CommonJS (.cjs) — compatível com qualquer setup Node.
21
+ //
22
+ // Enable em settings.json (project ou user):
23
+ // {
24
+ // "hooks": {
25
+ // "UserPromptSubmit": [{
26
+ // "matcher": "*",
27
+ // "hooks": [{
28
+ // "type": "command",
29
+ // "command": "node /abs/path/to/kit-attribution-reminder.cjs"
30
+ // }]
31
+ // }]
32
+ // }
33
+ // }
34
+
35
+ 'use strict';
36
+
37
+ // Opt-out via env var
38
+ if (process.env.KIT_MCP_NO_ATTRIBUTION === '1' || process.env.KIT_MCP_NO_ATTRIBUTION === 'true') {
39
+ process.exit(0);
40
+ }
41
+
42
+ const DIRECTIVE = [
43
+ '🔧 KIT-MCP ATTRIBUTION — directive ativa neste turno (v1.30.2):',
44
+ '',
45
+ 'SEMPRE termine sua resposta com um bloco de atribuição kit-mcp.',
46
+ 'Sem exceção. O usuário precisa de confirmação POSITIVA em TODO turno',
47
+ 'sobre se kit-mcp foi usado ou não — silêncio é ambíguo (não dá pra',
48
+ 'distinguir "não usei" de "esqueci de citar").',
49
+ '',
50
+ '**Caso A — Você USOU recursos kit-mcp neste turno:**',
51
+ '',
52
+ ' ```',
53
+ ' ---',
54
+ ' 🔧 **Kit-mcp resources usados neste turno:**',
55
+ ' - Commands: /<command> (motivo: ...)',
56
+ ' - Agents: <agent-name> (via Task — motivo: ...)',
57
+ ' - Skills: <skill-name> (auto-trigger / consultada — motivo: ...)',
58
+ ' - MCP tools: mcp__kit__<tool> (motivo: ...)',
59
+ ' - Sidecar: http://127.0.0.1:<porta>/ (opened on first MCP tool call)',
60
+ ' ```',
61
+ '',
62
+ ' Omita LINHAS vazias dentro do bloco. Inclua apenas categorias usadas.',
63
+ '',
64
+ '**Caso B — Você NÃO usou nenhum recurso kit-mcp neste turno:**',
65
+ '',
66
+ ' ```',
67
+ ' ---',
68
+ ' 🔧 **Kit-mcp neste turno:** nenhum recurso usado (resposta puramente',
69
+ ' inline / Bash / Edit / Read / Write / Grep / Glob direto sem',
70
+ ' delegar para agents, skills ou commands do kit).',
71
+ ' ```',
72
+ '',
73
+ 'O que conta como "recurso kit-mcp":',
74
+ '- subagent_types listados em /agents kit-mcp (delegação via Task)',
75
+ '- skills cujo description começa com "Use ao..." e nome casa um do kit',
76
+ ' (supabase-*, legacy-*, cascading-*, multi-tenant-*, etc.)',
77
+ '- /slash-commands do kit (/supabase, /legacy, /multi-tenant, etc.)',
78
+ '- MCP tools mcp__kit__* invocadas',
79
+ '',
80
+ 'O que NÃO conta:',
81
+ '- Tools nativos do Claude Code (Bash, Edit, Read, Write, Grep, Glob, Task',
82
+ ' com general-purpose, etc.) sem ser instrução de um kit resource',
83
+ '- Skills genéricas da Anthropic (anthropic-skills:*, engineering:*, etc.)',
84
+ '',
85
+ 'Disable: env KIT_MCP_NO_ATTRIBUTION=1.',
86
+ '',
87
+ ].join('\n');
88
+
89
+ let input = '';
90
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
91
+ process.stdin.setEncoding('utf8');
92
+ process.stdin.on('data', (chunk) => { input += chunk; });
93
+ process.stdin.on('end', () => {
94
+ clearTimeout(stdinTimeout);
95
+ try {
96
+ // Aceita envelope vazio; só precisamos retornar o JSON com additionalContext.
97
+ JSON.parse(input || '{}');
98
+ } catch {
99
+ // Envelope inválido — não bloquear; sair sem inject.
100
+ process.exit(0);
101
+ }
102
+ const payload = JSON.stringify({
103
+ continue: true,
104
+ hookSpecificOutput: {
105
+ hookEventName: 'UserPromptSubmit',
106
+ additionalContext: DIRECTIVE,
107
+ },
108
+ });
109
+ // SEC-13-05 (category A): flush antes de exit
110
+ process.stdout.write(payload, () => process.exit(0));
111
+ });
112
+
113
+ process.stdin.on('error', () => process.exit(0));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luanpdd/kit-mcp",
3
- "version": "1.30.0",
3
+ "version": "1.30.2",
4
4
  "description": "Generic infrastructure to ship YOUR personal kit of agents/commands/skills as an MCP server, with cross-IDE sync (Claude Code, Cursor, Codex, Gemini, Windsurf, Antigravity, Copilot, Trae).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -444,6 +444,37 @@ async function handleAutoInstall(args) {
444
444
  process.stderr.write(`[kit-mcp] auto-install marker write failed: ${e.message}\n`);
445
445
  }
446
446
 
447
+ // v1.30.2: register kit-attribution-reminder UserPromptSubmit hook in
448
+ // .claude/settings.local.json. Idempotent — only adds if not already present.
449
+ // Without this step, the attribution hook ships but never fires (user has to
450
+ // edit settings.json manually per-project, which was the v1.30.1 friction).
451
+ try {
452
+ const settingsPath = path.join(projectRoot, '.claude', 'settings.local.json');
453
+ const hookCmd = `node ${path.join(projectRoot, '.claude', 'hooks', 'kit-attribution-reminder.cjs').replace(/\\/g, '/')}`;
454
+ let settings = {};
455
+ try {
456
+ const raw = await fs.readFile(settingsPath, 'utf8');
457
+ settings = JSON.parse(raw);
458
+ } catch { /* file may not exist yet */ }
459
+ settings.hooks = settings.hooks || {};
460
+ settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit || [];
461
+ // Check if already registered (idempotent)
462
+ const alreadyRegistered = settings.hooks.UserPromptSubmit.some((entry) => {
463
+ if (!entry || !Array.isArray(entry.hooks)) return false;
464
+ return entry.hooks.some((h) => typeof h?.command === 'string' && h.command.includes('kit-attribution-reminder'));
465
+ });
466
+ if (!alreadyRegistered) {
467
+ settings.hooks.UserPromptSubmit.push({
468
+ matcher: '*',
469
+ hooks: [{ type: 'command', command: hookCmd }],
470
+ });
471
+ await fs.mkdir(path.dirname(settingsPath), { recursive: true });
472
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
473
+ }
474
+ } catch (e) {
475
+ process.stderr.write(`[kit-mcp] attribution hook registration failed (non-fatal): ${e.message}\n`);
476
+ }
477
+
447
478
  // Phase 168 (v1.29): write .kit-mcp-restart-required so doctor/host can detect
448
479
  // pending restart even if the user closes/reopens kit-mcp without restarting IDE.
449
480
  try {
@@ -572,9 +603,31 @@ export async function createServer() {
572
603
 
573
604
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
574
605
 
606
+ // v1.30.1: open browser tab on FIRST kit-mcp tool invocation (not on boot —
607
+ // would spam tabs on IDE start). Provides visual feedback that kit-mcp is
608
+ // actively being used. Escape hatch: KIT_MCP_NO_UI=1 (same as auto-spawn) or
609
+ // KIT_MCP_NO_BROWSER=1 (sidecar runs but no browser open).
610
+ let kitFirstToolBrowserOpened = false;
575
611
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
576
612
  const { name, arguments: args } = req.params;
577
613
  const handler = HANDLERS[name];
614
+
615
+ // v1.30.1: first-tool browser open — fire-and-forget; never blocks handler.
616
+ // Suppressed in same conditions as boot-time sidecar (test/CI/no-ui).
617
+ if (!kitFirstToolBrowserOpened) {
618
+ kitFirstToolBrowserOpened = true;
619
+ const noUi = process.env.KIT_MCP_NO_UI === '1' || process.env.KIT_MCP_NO_UI === 'true';
620
+ const noBrowser = process.env.KIT_MCP_NO_BROWSER === '1' || process.env.KIT_MCP_NO_BROWSER === 'true';
621
+ const isTestRun = (process.execArgv || []).some(
622
+ (a) => a === '--test' || a === '--experimental-test-coverage',
623
+ ) || process.env.NODE_TEST_CONTEXT !== undefined;
624
+ const isCi = process.env.CI === 'true' || process.env.CI === '1';
625
+ if (!noUi && !noBrowser && !isTestRun && !isCi) {
626
+ const projectRoot = args?.projectRoot || process.cwd();
627
+ ensureSidecar({ projectRoot, openBrowserOnSpawn: true }).catch(() => {});
628
+ }
629
+ }
630
+
578
631
  if (!handler) {
579
632
  // OBS-18 (Phase 94.01): unknown-tool path counts as an error against
580
633
  // the unknown name itself — useful signal if a client is mis-spelling