livetap 0.1.2 → 0.1.4
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/README.md +12 -20
- package/bin/livetap.ts +1 -0
- package/package.json +2 -4
- package/src/cli/setup.ts +70 -0
- package/src/shared/catalog-generators.ts +18 -2
- package/src/shared/command-catalog.ts +6 -0
- package/scripts/postinstall.ts +0 -75
package/README.md
CHANGED
|
@@ -28,32 +28,24 @@ Then ask your agent:
|
|
|
28
28
|
|
|
29
29
|
## Setup with Claude Code (for AI agents)
|
|
30
30
|
|
|
31
|
-
If you are Claude Code or another AI agent
|
|
31
|
+
If you are Claude Code or another AI agent, run `npx livetap --llm-help` for structured setup instructions.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Quick version:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
The postinstall script creates `.mcp.json` in the project root. Verify it exists:
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
cat .mcp.json
|
|
36
|
+
npm install livetap # Step 1: install
|
|
37
|
+
npx livetap setup # Step 2: creates .mcp.json
|
|
38
|
+
# Step 3: tell user to restart Claude Code with:
|
|
39
|
+
# claude --dangerously-load-development-channels server:livetap --continue
|
|
44
40
|
```
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
> "livetap is installed. To enable live data streaming, please restart me with:
|
|
53
|
-
> `claude --dangerously-load-development-channels server:livetap`
|
|
54
|
-
> Then ask me to connect to your data source."
|
|
42
|
+
**IMPORTANT — do NOT:**
|
|
43
|
+
- Add livetap to `~/.claude/mcp.json` — it goes in `.mcp.json` in the project root
|
|
44
|
+
- Configure livetap as `type: "http"` — it is a stdio MCP server (command + args)
|
|
45
|
+
- Start the daemon manually — the MCP proxy auto-starts it on Claude restart
|
|
46
|
+
- Guess field names — always `read_stream` first to see actual payload structure
|
|
55
47
|
|
|
56
|
-
###
|
|
48
|
+
### After restart — use MCP tools
|
|
57
49
|
|
|
58
50
|
Once restarted with the channel flag, you have 12 MCP tools available. Follow this workflow:
|
|
59
51
|
|
package/bin/livetap.ts
CHANGED
|
@@ -16,6 +16,7 @@ const commands: Record<string, () => Promise<void>> = {
|
|
|
16
16
|
watch: () => import('../src/cli/watch.js').then((m) => m.run(args)),
|
|
17
17
|
unwatch: () => import('../src/cli/unwatch.js').then((m) => m.run(args)),
|
|
18
18
|
watchers: () => import('../src/cli/watchers.js').then((m) => m.run(args)),
|
|
19
|
+
setup: () => import('../src/cli/setup.js').then((m) => m.run(args)),
|
|
19
20
|
mcp: () => import('../src/mcp/channel.js'),
|
|
20
21
|
help: () => import('../src/cli/help.js').then((m) => m.run(args)),
|
|
21
22
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livetap",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Push live data streams into your AI coding agent.
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "Push live data streams into your AI coding agent. LLM/AI agent? Run: npx livetap --llm-help",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"livetap": "./bin/livetap.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"postinstall": "bun ./scripts/postinstall.ts",
|
|
11
10
|
"test": "bun test"
|
|
12
11
|
},
|
|
13
12
|
"keywords": [
|
|
@@ -24,7 +23,6 @@
|
|
|
24
23
|
"files": [
|
|
25
24
|
"bin/",
|
|
26
25
|
"src/",
|
|
27
|
-
"scripts/postinstall.ts",
|
|
28
26
|
"README.md",
|
|
29
27
|
"LICENSE"
|
|
30
28
|
],
|
package/src/cli/setup.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* livetap setup — creates .mcp.json and prints restart instructions.
|
|
3
|
+
* Works with both npm and bun. Node-compatible (no bun APIs).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
7
|
+
import { resolve } from 'path'
|
|
8
|
+
|
|
9
|
+
export async function run(_args: string[]) {
|
|
10
|
+
const root = process.cwd()
|
|
11
|
+
const mcpPath = resolve(root, '.mcp.json')
|
|
12
|
+
|
|
13
|
+
// Find the channel.ts path relative to where livetap is installed
|
|
14
|
+
const channelPaths = [
|
|
15
|
+
resolve(root, 'node_modules', 'livetap', 'src', 'mcp', 'channel.ts'),
|
|
16
|
+
resolve(root, 'node_modules', '.store', 'livetap', 'src', 'mcp', 'channel.ts'),
|
|
17
|
+
// Local dev: running from the repo itself
|
|
18
|
+
resolve(root, 'src', 'mcp', 'channel.ts'),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
let channelPath = channelPaths.find((p) => existsSync(p))
|
|
22
|
+
if (!channelPath) {
|
|
23
|
+
// Try to resolve from require
|
|
24
|
+
try {
|
|
25
|
+
const pkg = require.resolve('livetap/package.json')
|
|
26
|
+
channelPath = resolve(pkg, '..', 'src', 'mcp', 'channel.ts')
|
|
27
|
+
if (!existsSync(channelPath)) channelPath = undefined
|
|
28
|
+
} catch { /* not found */ }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!channelPath) {
|
|
32
|
+
console.error('Error: Could not find livetap channel.ts. Is livetap installed?')
|
|
33
|
+
console.error('Run: npm install livetap')
|
|
34
|
+
process.exit(1)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const mcpEntry = {
|
|
38
|
+
livetap: {
|
|
39
|
+
command: 'bun',
|
|
40
|
+
args: [channelPath],
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Read or create .mcp.json
|
|
45
|
+
let config: any = {}
|
|
46
|
+
if (existsSync(mcpPath)) {
|
|
47
|
+
try {
|
|
48
|
+
config = JSON.parse(readFileSync(mcpPath, 'utf-8'))
|
|
49
|
+
} catch {
|
|
50
|
+
console.error('Warning: .mcp.json exists but is malformed. Overwriting.')
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (config.mcpServers?.livetap) {
|
|
55
|
+
console.log('✓ livetap already configured in .mcp.json')
|
|
56
|
+
} else {
|
|
57
|
+
if (!config.mcpServers) config.mcpServers = {}
|
|
58
|
+
config.mcpServers.livetap = mcpEntry.livetap
|
|
59
|
+
writeFileSync(mcpPath, JSON.stringify(config, null, 2) + '\n')
|
|
60
|
+
console.log('✓ .mcp.json created with livetap MCP server entry')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log('')
|
|
64
|
+
console.log('→ Next step: restart Claude Code with:')
|
|
65
|
+
console.log(' claude --dangerously-load-development-channels server:livetap --continue')
|
|
66
|
+
console.log('')
|
|
67
|
+
console.log('→ After restart, MCP tools are available. Ask Claude to:')
|
|
68
|
+
console.log(' "Connect to mqtt://broker.emqx.io:1883/sensors/#"')
|
|
69
|
+
console.log(' "Watch for temperature > 50 and summarize alerts"')
|
|
70
|
+
}
|
|
@@ -15,8 +15,9 @@ export function generateHelpText(): string {
|
|
|
15
15
|
'Usage:',
|
|
16
16
|
]
|
|
17
17
|
|
|
18
|
-
// Group: daemon, connections, sampling, watchers
|
|
18
|
+
// Group: setup, daemon, connections, sampling, watchers
|
|
19
19
|
const groups: { label: string; commands: string[] }[] = [
|
|
20
|
+
{ label: '', commands: ['setup'] },
|
|
20
21
|
{ label: '', commands: ['start', 'stop', 'status'] },
|
|
21
22
|
{ label: '', commands: ['tap', 'untap', 'taps'] },
|
|
22
23
|
{ label: '', commands: ['sip'] },
|
|
@@ -50,8 +51,23 @@ export function generateHelpText(): string {
|
|
|
50
51
|
export function generateLlmHelp(): object {
|
|
51
52
|
return {
|
|
52
53
|
name: 'livetap',
|
|
53
|
-
version: '0.1.
|
|
54
|
+
version: '0.1.4',
|
|
54
55
|
description: 'Push live data streams into your AI coding agent',
|
|
56
|
+
setup: {
|
|
57
|
+
steps: [
|
|
58
|
+
'Step 1: npm install livetap (skip if already installed)',
|
|
59
|
+
'Step 2: npx livetap setup (creates .mcp.json in project root — do NOT create it manually)',
|
|
60
|
+
'Step 3: Tell user to restart Claude Code: claude --dangerously-load-development-channels server:livetap --continue',
|
|
61
|
+
'Step 4: After restart, use create_connection to connect, read_stream to sample, create_watcher to alert',
|
|
62
|
+
],
|
|
63
|
+
do_not: [
|
|
64
|
+
'Do NOT add livetap to ~/.claude/mcp.json — it goes in .mcp.json in the project root',
|
|
65
|
+
'Do NOT configure livetap as type:http — it is a stdio MCP server (command + args)',
|
|
66
|
+
'Do NOT start the daemon manually — the MCP proxy auto-starts it on Claude restart',
|
|
67
|
+
'Do NOT guess field names — always read_stream first to see actual payload structure',
|
|
68
|
+
'Do NOT use npm init — use the existing project directory',
|
|
69
|
+
],
|
|
70
|
+
},
|
|
55
71
|
commands: CLI_COMMANDS,
|
|
56
72
|
mcp_tools: TOOLS,
|
|
57
73
|
}
|
|
@@ -22,6 +22,12 @@ export interface CatalogCommand {
|
|
|
22
22
|
* are generated from this array.
|
|
23
23
|
*/
|
|
24
24
|
export const CLI_COMMANDS: CatalogCommand[] = [
|
|
25
|
+
// --- Setup ---
|
|
26
|
+
{
|
|
27
|
+
name: 'setup',
|
|
28
|
+
usage: 'livetap setup',
|
|
29
|
+
description: 'Configure .mcp.json for Claude Code and print restart instructions. Run this after npm install.',
|
|
30
|
+
},
|
|
25
31
|
// --- Daemon ---
|
|
26
32
|
{
|
|
27
33
|
name: 'start',
|
package/scripts/postinstall.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Postinstall script — auto-configures .mcp.json for Claude Code.
|
|
4
|
-
* Runs after `bun add livetap` or `npm install livetap`.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
8
|
-
import { resolve } from 'path'
|
|
9
|
-
|
|
10
|
-
const MCP_ENTRY = {
|
|
11
|
-
livetap: {
|
|
12
|
-
command: 'bun',
|
|
13
|
-
args: [resolve(import.meta.dir, '..', 'src', 'mcp', 'channel.ts')],
|
|
14
|
-
},
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function findProjectRoot(): string {
|
|
18
|
-
// If we're inside node_modules, walk up past it to find the project root
|
|
19
|
-
const scriptDir = resolve(import.meta.dir)
|
|
20
|
-
const nmIdx = scriptDir.lastIndexOf('node_modules')
|
|
21
|
-
if (nmIdx !== -1) {
|
|
22
|
-
const root = scriptDir.slice(0, nmIdx).replace(/\/$/, '')
|
|
23
|
-
if (existsSync(resolve(root, 'package.json'))) return root
|
|
24
|
-
}
|
|
25
|
-
// Fallback to cwd (e.g. when running postinstall directly for testing)
|
|
26
|
-
return process.cwd()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function run() {
|
|
30
|
-
// Skip in CI or when explicitly disabled
|
|
31
|
-
if (process.env.CI || process.env.LIVETAP_SKIP_POSTINSTALL) return
|
|
32
|
-
|
|
33
|
-
const root = findProjectRoot()
|
|
34
|
-
const mcpPath = resolve(root, '.mcp.json')
|
|
35
|
-
|
|
36
|
-
let config: any = {}
|
|
37
|
-
if (existsSync(mcpPath)) {
|
|
38
|
-
try {
|
|
39
|
-
config = JSON.parse(readFileSync(mcpPath, 'utf-8'))
|
|
40
|
-
} catch {
|
|
41
|
-
console.warn('\n ⚠ .mcp.json exists but is malformed. Skipping auto-config.')
|
|
42
|
-
console.warn(' Add the livetap entry manually (see below).\n')
|
|
43
|
-
printManualInstructions()
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Don't overwrite if livetap entry already exists
|
|
49
|
-
if (config.mcpServers?.livetap) {
|
|
50
|
-
console.log('\n ✓ livetap already configured in .mcp.json\n')
|
|
51
|
-
printRestartInstructions()
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Add livetap entry
|
|
56
|
-
if (!config.mcpServers) config.mcpServers = {}
|
|
57
|
-
config.mcpServers.livetap = MCP_ENTRY.livetap
|
|
58
|
-
writeFileSync(mcpPath, JSON.stringify(config, null, 2) + '\n')
|
|
59
|
-
|
|
60
|
-
console.log('\n ✓ livetap added to .mcp.json\n')
|
|
61
|
-
printRestartInstructions()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function printRestartInstructions() {
|
|
65
|
-
console.log(' To enable live data streaming in Claude Code, restart with:\n')
|
|
66
|
-
console.log(' claude --dangerously-load-development-channels server:livetap\n')
|
|
67
|
-
console.log(' Then ask Claude: "Connect to mqtt://broker.emqx.io:1883/sensors/#"\n')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function printManualInstructions() {
|
|
71
|
-
console.log(' Add to .mcp.json:\n')
|
|
72
|
-
console.log(' ' + JSON.stringify({ mcpServers: MCP_ENTRY }, null, 2).split('\n').join('\n ') + '\n')
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
run()
|