claude-view 0.8.0 → 0.11.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.
- package/README.md +66 -16
- package/index.js +120 -106
- package/package.json +44 -9
package/README.md
CHANGED
|
@@ -1,46 +1,96 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# claude-view
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
**You have 10 Claude sessions running right now. What are they doing?**
|
|
6
|
+
|
|
7
|
+
<p>
|
|
8
|
+
<a href="https://www.npmjs.com/package/claude-view"><img src="https://img.shields.io/npm/v/claude-view.svg" alt="npm version"></a>
|
|
9
|
+
<a href="https://claudeview.ai"><img src="https://img.shields.io/badge/Website-claudeview.ai-orange" alt="Website"></a>
|
|
10
|
+
<a href="https://github.com/tombelieber/claude-view/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
11
|
+
<img src="https://img.shields.io/badge/Platform-macOS-lightgrey.svg" alt="macOS">
|
|
12
|
+
<a href="https://github.com/tombelieber/claude-view/stargazers"><img src="https://img.shields.io/github/stars/tombelieber/claude-view?style=social" alt="GitHub stars"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
Behind every "thinking..." spinner, Claude is spawning sub-agents, calling MCP servers, running skills, firing hooks — and you can't see any of it.
|
|
18
|
+
|
|
19
|
+
**You're paying $200/mo for Claude Code. You deserve a dashboard.**
|
|
4
20
|
|
|
5
|
-
|
|
21
|
+
<div align="center">
|
|
6
22
|
|
|
7
23
|
```bash
|
|
8
|
-
|
|
24
|
+
curl -fsSL https://raw.githubusercontent.com/tombelieber/claude-view/main/install.sh | sh
|
|
9
25
|
```
|
|
10
26
|
|
|
11
|
-
|
|
27
|
+
**One command. Every session visible. Real-time.**
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
| Method | Command |
|
|
36
|
+
|--------|---------|
|
|
37
|
+
| **Shell** (recommended) | `curl -fsSL https://raw.githubusercontent.com/tombelieber/claude-view/main/install.sh \| sh` |
|
|
38
|
+
| **npx** | `npx claude-view` |
|
|
39
|
+
|
|
40
|
+
---
|
|
12
41
|
|
|
13
|
-
## What
|
|
42
|
+
## What You Get
|
|
14
43
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
44
|
+
- **Live session cards** — see what every session is working on, right now
|
|
45
|
+
- **Notification sounds** — get pinged when a session finishes or needs input
|
|
46
|
+
- **Context gauge** — real-time context window usage per session
|
|
47
|
+
- **Cache warm countdown** — time your messages to save tokens
|
|
48
|
+
- **Cost tracking** — per-session and aggregate spend with cache savings
|
|
49
|
+
- **Sub-agent visualization** — see the full agent tree, tool calls, MCP invocations
|
|
50
|
+
- **Full-text search** — search across all sessions, messages, tool calls, file paths
|
|
51
|
+
- **Analytics** — activity heatmap, cost ROI, model comparison, AI Fluency Score
|
|
52
|
+
- **Rich chat history** — every conversation rendered with markdown, code blocks, tool calls
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## How It Works
|
|
57
|
+
|
|
58
|
+
On first run, `npx claude-view` downloads a platform-specific Rust binary (~10 MB) from GitHub Releases. The binary is cached at `~/.cache/claude-view/` so subsequent runs start instantly.
|
|
59
|
+
|
|
60
|
+
Everything stays on your machine. Zero telemetry, zero cloud, zero network requests.
|
|
61
|
+
|
|
62
|
+
---
|
|
19
63
|
|
|
20
64
|
## Configuration
|
|
21
65
|
|
|
22
66
|
| Env Variable | Default | Description |
|
|
23
|
-
|
|
67
|
+
| --- | --- | --- |
|
|
24
68
|
| `CLAUDE_VIEW_PORT` | `47892` | Port for the local server |
|
|
25
69
|
| `PORT` | `47892` | Alternative port override |
|
|
26
70
|
|
|
27
71
|
## Supported Platforms
|
|
28
72
|
|
|
29
73
|
| OS | Architecture |
|
|
30
|
-
|
|
74
|
+
| --- | --- |
|
|
31
75
|
| macOS | Apple Silicon (arm64), Intel (x64) |
|
|
32
76
|
| Linux | x64 |
|
|
33
77
|
| Windows | x64 |
|
|
34
78
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
On first run, `npx claude-view` downloads a platform-specific tarball from GitHub Releases containing a compiled Rust binary and bundled frontend assets. The binary is cached at `~/.cache/claude-view/` so subsequent runs start instantly.
|
|
79
|
+
---
|
|
38
80
|
|
|
39
81
|
## Links
|
|
40
82
|
|
|
41
|
-
- [
|
|
83
|
+
- [Website](https://claudeview.ai) — docs, changelog, blog
|
|
84
|
+
- [GitHub Repository](https://github.com/tombelieber/claude-view) — full feature list, comparison table, architecture details
|
|
85
|
+
- [@claude-view/plugin](https://www.npmjs.com/package/@claude-view/plugin) — Claude Code plugin with 8 MCP tools and 3 skills
|
|
86
|
+
- [claude-backup](https://github.com/tombelieber/claude-backup) — Claude Code deletes your sessions after 30 days. This saves them.
|
|
42
87
|
- [Report an Issue](https://github.com/tombelieber/claude-view/issues)
|
|
88
|
+
- [Discord](https://discord.gg/G7wdZTpRfu)
|
|
43
89
|
|
|
44
|
-
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
<div align="center">
|
|
45
93
|
|
|
46
94
|
MIT
|
|
95
|
+
|
|
96
|
+
</div>
|
package/index.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { execFileSync, spawn } = require(
|
|
4
|
-
const fs = require(
|
|
5
|
-
const path = require(
|
|
6
|
-
const os = require(
|
|
7
|
-
const https = require(
|
|
8
|
-
const zlib = require(
|
|
3
|
+
const { execFileSync, execSync, spawn } = require('child_process')
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const os = require('os')
|
|
7
|
+
const https = require('https')
|
|
8
|
+
const zlib = require('zlib')
|
|
9
9
|
|
|
10
|
-
const VERSION = require(
|
|
11
|
-
const REPO =
|
|
12
|
-
const BINARY_NAME = process.platform ===
|
|
10
|
+
const VERSION = require('./package.json').version
|
|
11
|
+
const REPO = 'tombelieber/claude-view'
|
|
12
|
+
const BINARY_NAME = process.platform === 'win32' ? 'claude-view.exe' : 'claude-view'
|
|
13
13
|
|
|
14
14
|
// --- Platform detection ---
|
|
15
15
|
|
|
16
16
|
const PLATFORM_MAP = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
17
|
+
'darwin-arm64': { artifact: 'claude-view-darwin-arm64.tar.gz', ext: 'tar.gz' },
|
|
18
|
+
'darwin-x64': { artifact: 'claude-view-darwin-x64.tar.gz', ext: 'tar.gz' },
|
|
19
|
+
'linux-x64': { artifact: 'claude-view-linux-x64.tar.gz', ext: 'tar.gz' },
|
|
20
|
+
'win32-x64': { artifact: 'claude-view-win32-x64.zip', ext: 'zip' },
|
|
21
|
+
}
|
|
22
22
|
|
|
23
|
-
const platformKey = `${process.platform}-${process.arch}
|
|
24
|
-
const platformInfo = PLATFORM_MAP[platformKey]
|
|
23
|
+
const platformKey = `${process.platform}-${process.arch}`
|
|
24
|
+
const platformInfo = PLATFORM_MAP[platformKey]
|
|
25
25
|
|
|
26
26
|
if (!platformInfo) {
|
|
27
27
|
console.error(
|
|
28
28
|
`Error: Unsupported platform "${process.platform}" with architecture "${process.arch}".\n` +
|
|
29
|
-
`Supported: macOS (arm64, x64), Linux (x64), Windows (x64)
|
|
30
|
-
)
|
|
31
|
-
process.exit(1)
|
|
29
|
+
`Supported: macOS (arm64, x64), Linux (x64), Windows (x64).`,
|
|
30
|
+
)
|
|
31
|
+
process.exit(1)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// --- Cache paths ---
|
|
35
35
|
|
|
36
|
-
const cacheDir = path.join(os.homedir(),
|
|
37
|
-
const binDir = path.join(cacheDir,
|
|
38
|
-
const versionFile = path.join(cacheDir,
|
|
39
|
-
const binaryPath = path.join(binDir, BINARY_NAME)
|
|
40
|
-
const distDir = path.join(binDir,
|
|
36
|
+
const cacheDir = path.join(os.homedir(), '.cache', 'claude-view')
|
|
37
|
+
const binDir = path.join(cacheDir, 'bin')
|
|
38
|
+
const versionFile = path.join(cacheDir, 'version')
|
|
39
|
+
const binaryPath = path.join(binDir, BINARY_NAME)
|
|
40
|
+
const distDir = path.join(binDir, 'dist')
|
|
41
41
|
|
|
42
42
|
// --- Helpers ---
|
|
43
43
|
|
|
@@ -46,80 +46,80 @@ function download(url) {
|
|
|
46
46
|
const request = https.get(url, (res) => {
|
|
47
47
|
// Follow redirects (GitHub releases redirect to S3/CDN)
|
|
48
48
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
49
|
-
return download(res.headers.location).then(resolve, reject)
|
|
49
|
+
return download(res.headers.location).then(resolve, reject)
|
|
50
50
|
}
|
|
51
51
|
if (res.statusCode !== 200) {
|
|
52
|
-
reject(new Error(`Download failed: HTTP ${res.statusCode} from ${url}`))
|
|
53
|
-
res.resume()
|
|
54
|
-
return
|
|
52
|
+
reject(new Error(`Download failed: HTTP ${res.statusCode} from ${url}`))
|
|
53
|
+
res.resume()
|
|
54
|
+
return
|
|
55
55
|
}
|
|
56
|
-
const chunks = []
|
|
57
|
-
res.on(
|
|
58
|
-
res.on(
|
|
59
|
-
res.on(
|
|
60
|
-
})
|
|
61
|
-
request.on(
|
|
62
|
-
})
|
|
56
|
+
const chunks = []
|
|
57
|
+
res.on('data', (chunk) => chunks.push(chunk))
|
|
58
|
+
res.on('end', () => resolve(Buffer.concat(chunks)))
|
|
59
|
+
res.on('error', reject)
|
|
60
|
+
})
|
|
61
|
+
request.on('error', reject)
|
|
62
|
+
})
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function extractTarGz(buffer, destDir) {
|
|
66
66
|
// Use system tar — available on macOS, Linux, and modern Windows (tar ships with Win10+)
|
|
67
|
-
fs.mkdirSync(destDir, { recursive: true })
|
|
68
|
-
const tmpFile = path.join(os.tmpdir(), `claude-view-${Date.now()}.tar.gz`)
|
|
69
|
-
fs.writeFileSync(tmpFile, buffer)
|
|
67
|
+
fs.mkdirSync(destDir, { recursive: true })
|
|
68
|
+
const tmpFile = path.join(os.tmpdir(), `claude-view-${Date.now()}.tar.gz`)
|
|
69
|
+
fs.writeFileSync(tmpFile, buffer)
|
|
70
70
|
try {
|
|
71
|
-
execFileSync(
|
|
71
|
+
execFileSync('tar', ['xzf', tmpFile, '-C', destDir], { stdio: 'pipe' })
|
|
72
72
|
} finally {
|
|
73
|
-
fs.unlinkSync(tmpFile)
|
|
73
|
+
fs.unlinkSync(tmpFile)
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function extractZip(buffer, destDir) {
|
|
78
78
|
// Use system tar on Windows 10+ (supports zip) or PowerShell as fallback
|
|
79
|
-
fs.mkdirSync(destDir, { recursive: true })
|
|
80
|
-
const tmpFile = path.join(os.tmpdir(), `claude-view-${Date.now()}.zip`)
|
|
81
|
-
fs.writeFileSync(tmpFile, buffer)
|
|
79
|
+
fs.mkdirSync(destDir, { recursive: true })
|
|
80
|
+
const tmpFile = path.join(os.tmpdir(), `claude-view-${Date.now()}.zip`)
|
|
81
|
+
fs.writeFileSync(tmpFile, buffer)
|
|
82
82
|
try {
|
|
83
|
-
if (process.platform ===
|
|
83
|
+
if (process.platform === 'win32') {
|
|
84
84
|
execFileSync(
|
|
85
|
-
|
|
86
|
-
[
|
|
87
|
-
{ stdio:
|
|
88
|
-
)
|
|
85
|
+
'powershell',
|
|
86
|
+
['-Command', `Expand-Archive -Force -Path '${tmpFile}' -DestinationPath '${destDir}'`],
|
|
87
|
+
{ stdio: 'pipe' },
|
|
88
|
+
)
|
|
89
89
|
} else {
|
|
90
|
-
execFileSync(
|
|
90
|
+
execFileSync('unzip', ['-o', tmpFile, '-d', destDir], { stdio: 'pipe' })
|
|
91
91
|
}
|
|
92
92
|
} finally {
|
|
93
|
-
fs.unlinkSync(tmpFile)
|
|
93
|
+
fs.unlinkSync(tmpFile)
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
function downloadChecksums(version) {
|
|
98
|
-
const url = `https://github.com/${REPO}/releases/download/v${version}/checksums.txt
|
|
98
|
+
const url = `https://github.com/${REPO}/releases/download/v${version}/checksums.txt`
|
|
99
99
|
return download(url)
|
|
100
100
|
.then((buf) => {
|
|
101
|
-
const map = {}
|
|
102
|
-
const lines = buf.toString(
|
|
101
|
+
const map = {}
|
|
102
|
+
const lines = buf.toString('utf-8').split('\n')
|
|
103
103
|
for (const line of lines) {
|
|
104
104
|
// Format: "<64-hex-chars> <filename>" (two spaces between hash and filename)
|
|
105
|
-
const match = line.match(/^([0-9a-f]{64})
|
|
105
|
+
const match = line.match(/^([0-9a-f]{64}) {2}(.+)$/)
|
|
106
106
|
if (match) {
|
|
107
|
-
map[match[2]] = match[1]
|
|
107
|
+
map[match[2]] = match[1]
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
return map
|
|
110
|
+
return map
|
|
111
111
|
})
|
|
112
|
-
.catch(() => null)
|
|
112
|
+
.catch(() => null) // Graceful fallback for older releases without checksums
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function verifyChecksum(buffer, expectedHash) {
|
|
116
|
-
const crypto = require(
|
|
117
|
-
const actualHash = crypto.createHash(
|
|
116
|
+
const crypto = require('crypto')
|
|
117
|
+
const actualHash = crypto.createHash('sha256').update(buffer).digest('hex')
|
|
118
118
|
if (actualHash !== expectedHash) {
|
|
119
|
-
console.error(`Checksum verification failed.`)
|
|
120
|
-
console.error(` Expected: ${expectedHash}`)
|
|
121
|
-
console.error(` Actual: ${actualHash}`)
|
|
122
|
-
process.exit(1)
|
|
119
|
+
console.error(`Checksum verification failed.`)
|
|
120
|
+
console.error(` Expected: ${expectedHash}`)
|
|
121
|
+
console.error(` Actual: ${actualHash}`)
|
|
122
|
+
process.exit(1)
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -127,81 +127,95 @@ function verifyChecksum(buffer, expectedHash) {
|
|
|
127
127
|
|
|
128
128
|
async function main() {
|
|
129
129
|
// Check if cached version matches
|
|
130
|
-
let needsDownload = true
|
|
130
|
+
let needsDownload = true
|
|
131
131
|
if (fs.existsSync(versionFile) && fs.existsSync(binaryPath)) {
|
|
132
|
-
const cached = fs.readFileSync(versionFile,
|
|
132
|
+
const cached = fs.readFileSync(versionFile, 'utf-8').trim()
|
|
133
133
|
if (cached === VERSION) {
|
|
134
|
-
needsDownload = false
|
|
134
|
+
needsDownload = false
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
if (needsDownload) {
|
|
139
|
-
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${platformInfo.artifact}
|
|
140
|
-
console.log(`Downloading claude-view v${VERSION} for ${platformKey}...`)
|
|
139
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${platformInfo.artifact}`
|
|
140
|
+
console.log(`Downloading claude-view v${VERSION} for ${platformKey}...`)
|
|
141
141
|
|
|
142
|
-
let buffer
|
|
142
|
+
let buffer
|
|
143
143
|
try {
|
|
144
|
-
buffer = await download(url)
|
|
144
|
+
buffer = await download(url)
|
|
145
145
|
} catch (err) {
|
|
146
|
-
console.error(`\nFailed to download claude-view:\n ${err.message}`)
|
|
147
|
-
console.error(`\nURL: ${url}`)
|
|
148
|
-
console.error(
|
|
149
|
-
|
|
146
|
+
console.error(`\nFailed to download claude-view:\n ${err.message}`)
|
|
147
|
+
console.error(`\nURL: ${url}`)
|
|
148
|
+
console.error(
|
|
149
|
+
`\nCheck that release v${VERSION} exists at https://github.com/${REPO}/releases`,
|
|
150
|
+
)
|
|
151
|
+
process.exit(1)
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
// Verify checksum if available
|
|
153
|
-
const checksums = await downloadChecksums(VERSION)
|
|
155
|
+
const checksums = await downloadChecksums(VERSION)
|
|
154
156
|
if (checksums && checksums[platformInfo.artifact]) {
|
|
155
|
-
verifyChecksum(buffer, checksums[platformInfo.artifact])
|
|
156
|
-
console.log(
|
|
157
|
+
verifyChecksum(buffer, checksums[platformInfo.artifact])
|
|
158
|
+
console.log('Checksum verified.')
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
// Clean previous install
|
|
160
|
-
fs.rmSync(binDir, { recursive: true, force: true })
|
|
161
|
-
fs.mkdirSync(binDir, { recursive: true })
|
|
162
|
+
fs.rmSync(binDir, { recursive: true, force: true })
|
|
163
|
+
fs.mkdirSync(binDir, { recursive: true })
|
|
162
164
|
|
|
163
165
|
// Extract
|
|
164
166
|
try {
|
|
165
|
-
if (platformInfo.ext ===
|
|
166
|
-
extractZip(buffer, binDir)
|
|
167
|
+
if (platformInfo.ext === 'zip') {
|
|
168
|
+
extractZip(buffer, binDir)
|
|
167
169
|
} else {
|
|
168
|
-
extractTarGz(buffer, binDir)
|
|
170
|
+
extractTarGz(buffer, binDir)
|
|
169
171
|
}
|
|
170
172
|
} catch (err) {
|
|
171
|
-
console.error(`\nFailed to extract archive:\n ${err.message}`)
|
|
172
|
-
process.exit(1)
|
|
173
|
+
console.error(`\nFailed to extract archive:\n ${err.message}`)
|
|
174
|
+
process.exit(1)
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
// Make binary executable (no-op on Windows)
|
|
176
|
-
if (process.platform !==
|
|
177
|
-
fs.chmodSync(binaryPath, 0o755)
|
|
178
|
+
if (process.platform !== 'win32') {
|
|
179
|
+
fs.chmodSync(binaryPath, 0o755)
|
|
178
180
|
}
|
|
179
181
|
|
|
180
182
|
// macOS Gatekeeper: remove quarantine flag from downloaded binary
|
|
181
|
-
if (process.platform ===
|
|
183
|
+
if (process.platform === 'darwin') {
|
|
182
184
|
try {
|
|
183
|
-
execFileSync(
|
|
185
|
+
execFileSync('xattr', ['-dr', 'com.apple.quarantine', binDir], { stdio: 'pipe' })
|
|
184
186
|
} catch {
|
|
185
187
|
// Ignore — xattr may not be available or quarantine flag may not be set
|
|
186
188
|
}
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
// Write version marker
|
|
190
|
-
fs.mkdirSync(cacheDir, { recursive: true })
|
|
191
|
-
fs.writeFileSync(versionFile, VERSION)
|
|
192
|
+
fs.mkdirSync(cacheDir, { recursive: true })
|
|
193
|
+
fs.writeFileSync(versionFile, VERSION)
|
|
192
194
|
|
|
193
|
-
console.log(`Installed to ${binDir}`)
|
|
195
|
+
console.log(`Installed to ${binDir}`)
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
// Verify binary exists
|
|
197
199
|
if (!fs.existsSync(binaryPath)) {
|
|
198
|
-
console.error(`Error: Binary not found at ${binaryPath}`)
|
|
199
|
-
console.error(
|
|
200
|
-
process.exit(1)
|
|
200
|
+
console.error(`Error: Binary not found at ${binaryPath}`)
|
|
201
|
+
console.error('Try deleting ~/.cache/claude-view/ and running again.')
|
|
202
|
+
process.exit(1)
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
// Set STATIC_DIR so the server finds the frontend assets
|
|
204
|
-
const env = { ...process.env, STATIC_DIR: distDir }
|
|
206
|
+
const env = { ...process.env, STATIC_DIR: distDir }
|
|
207
|
+
|
|
208
|
+
// Set SIDECAR_DIR so the server can spawn the Agent SDK sidecar
|
|
209
|
+
const sidecarDir = path.join(binDir, 'sidecar')
|
|
210
|
+
if (fs.existsSync(sidecarDir)) {
|
|
211
|
+
// Install sidecar deps if needed (first run after download)
|
|
212
|
+
const nodeModules = path.join(sidecarDir, 'node_modules')
|
|
213
|
+
if (!fs.existsSync(nodeModules)) {
|
|
214
|
+
console.log('Installing sidecar dependencies...')
|
|
215
|
+
execSync('npm install --omit=dev', { cwd: sidecarDir, stdio: 'inherit' })
|
|
216
|
+
}
|
|
217
|
+
env.SIDECAR_DIR = sidecarDir
|
|
218
|
+
}
|
|
205
219
|
|
|
206
220
|
// Run the server, forwarding signals and exit code.
|
|
207
221
|
//
|
|
@@ -211,29 +225,29 @@ async function main() {
|
|
|
211
225
|
// the Rust server's graceful shutdown to see two SIGINTs from one Ctrl+C.
|
|
212
226
|
// - SIGTERM/SIGHUP: Forward. These may be sent to our PID only (e.g. from
|
|
213
227
|
// `kill` or a process manager), so the child wouldn't get them otherwise.
|
|
214
|
-
const child = spawn(binaryPath, process.argv.slice(2), { stdio:
|
|
228
|
+
const child = spawn(binaryPath, process.argv.slice(2), { stdio: 'inherit', env })
|
|
215
229
|
|
|
216
230
|
// Prevent Node from exiting on SIGINT before the child does.
|
|
217
|
-
const ignoreSigint = () => {}
|
|
218
|
-
process.on(
|
|
231
|
+
const ignoreSigint = () => {}
|
|
232
|
+
process.on('SIGINT', ignoreSigint)
|
|
219
233
|
|
|
220
234
|
// Forward SIGTERM/SIGHUP — child may not receive these from process group.
|
|
221
|
-
for (const sig of [
|
|
222
|
-
process.on(sig, () => child.kill(sig))
|
|
235
|
+
for (const sig of ['SIGTERM', 'SIGHUP']) {
|
|
236
|
+
process.on(sig, () => child.kill(sig))
|
|
223
237
|
}
|
|
224
238
|
|
|
225
|
-
child.on(
|
|
239
|
+
child.on('exit', (code, signal) => {
|
|
226
240
|
// Remove our SIGINT handler so the re-signal below uses default behavior.
|
|
227
|
-
process.removeListener(
|
|
241
|
+
process.removeListener('SIGINT', ignoreSigint)
|
|
228
242
|
|
|
229
243
|
if (signal) {
|
|
230
244
|
// Child was killed by signal — re-signal ourselves so the parent shell
|
|
231
245
|
// sees the correct exit status (128 + signal number).
|
|
232
|
-
process.kill(process.pid, signal)
|
|
246
|
+
process.kill(process.pid, signal)
|
|
233
247
|
} else {
|
|
234
|
-
process.exit(code ?? 1)
|
|
248
|
+
process.exit(code ?? 1)
|
|
235
249
|
}
|
|
236
|
-
})
|
|
250
|
+
})
|
|
237
251
|
}
|
|
238
252
|
|
|
239
|
-
main()
|
|
253
|
+
main()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-view",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"description": "You have 10 Claude sessions running. What are they doing? Live dashboard for Claude Code — monitor every session, track costs, search history, see sub-agents. One command: npx claude-view",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claude-view": "./index.js"
|
|
7
7
|
},
|
|
@@ -10,18 +10,53 @@
|
|
|
10
10
|
"type": "git",
|
|
11
11
|
"url": "https://github.com/tombelieber/claude-view"
|
|
12
12
|
},
|
|
13
|
+
"homepage": "https://claudeview.ai",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/tombelieber/claude-view/issues"
|
|
16
|
+
},
|
|
13
17
|
"keywords": [
|
|
14
18
|
"claude",
|
|
15
19
|
"claude-code",
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
20
|
+
"anthropic",
|
|
21
|
+
"ai",
|
|
22
|
+
"ai-agents",
|
|
23
|
+
"mcp",
|
|
24
|
+
"dashboard",
|
|
25
|
+
"monitoring",
|
|
26
|
+
"mission-control",
|
|
27
|
+
"developer-tools",
|
|
28
|
+
"cli",
|
|
29
|
+
"session",
|
|
30
|
+
"session-history",
|
|
31
|
+
"session-viewer",
|
|
32
|
+
"session-monitor",
|
|
33
|
+
"full-text-search",
|
|
34
|
+
"search",
|
|
35
|
+
"tantivy",
|
|
36
|
+
"cost-tracking",
|
|
37
|
+
"analytics",
|
|
38
|
+
"metrics",
|
|
39
|
+
"heatmap",
|
|
40
|
+
"activity-log",
|
|
41
|
+
"reports",
|
|
42
|
+
"fluency-score",
|
|
43
|
+
"sub-agents",
|
|
44
|
+
"subagents",
|
|
45
|
+
"agent-monitor",
|
|
46
|
+
"context-window",
|
|
47
|
+
"cache-countdown",
|
|
48
|
+
"real-time",
|
|
49
|
+
"sse",
|
|
50
|
+
"websocket",
|
|
51
|
+
"conversation-viewer",
|
|
52
|
+
"export",
|
|
53
|
+
"rust",
|
|
54
|
+
"react",
|
|
55
|
+
"axum",
|
|
56
|
+
"sqlite"
|
|
19
57
|
],
|
|
20
58
|
"engines": {
|
|
21
59
|
"node": ">=16"
|
|
22
60
|
},
|
|
23
|
-
"files": [
|
|
24
|
-
"index.js",
|
|
25
|
-
"README.md"
|
|
26
|
-
]
|
|
61
|
+
"files": ["index.js", "README.md"]
|
|
27
62
|
}
|