dockscope 0.2.3 → 0.2.5
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 +4 -3
- package/dist/cli.js +46 -9
- package/dist/server/index.js +23 -7
- package/dist/server/routes.js +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/web/assets/{index-Cp-E9A8v.js → index-CmgdeoHt.js} +57 -57
- package/dist/web/assets/index-DUOQEliU.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +2 -4
- package/dist/web/assets/index-BVIqjCgJ.css +0 -1
package/README.md
CHANGED
|
@@ -42,11 +42,12 @@ Requires Docker to be running. Opens a browser at `http://localhost:4681`.
|
|
|
42
42
|
```
|
|
43
43
|
dockscope up [options]
|
|
44
44
|
|
|
45
|
-
-p, --port <port> Server port (default: 4681)
|
|
46
|
-
-f, --file <path> Docker Compose file path (default: auto-detect)
|
|
45
|
+
-p, --port <port> Server port (default: 4681, auto-increments if in use)
|
|
47
46
|
--no-open Don't open browser automatically
|
|
48
47
|
```
|
|
49
48
|
|
|
49
|
+
Docker Compose files are auto-detected (`compose.yml`, `docker-compose.yml`, etc.) and dependencies are read from container labels at runtime — no configuration needed.
|
|
50
|
+
|
|
50
51
|
### Scan Mode
|
|
51
52
|
|
|
52
53
|
Output the container graph as JSON (no UI):
|
|
@@ -64,7 +65,7 @@ npm install
|
|
|
64
65
|
npm run dev
|
|
65
66
|
```
|
|
66
67
|
|
|
67
|
-
This starts the
|
|
68
|
+
This starts the server on port `4681` with Vite HMR embedded — single port, same as production.
|
|
68
69
|
|
|
69
70
|
### Scripts
|
|
70
71
|
|
package/dist/cli.js
CHANGED
|
@@ -1,29 +1,67 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { createConnection } from 'net';
|
|
3
7
|
import { startServer } from './server/index.js';
|
|
4
8
|
import { buildGraph, checkConnection } from './docker/client.js';
|
|
9
|
+
function isPortInUse(port) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const conn = createConnection({ port, host: '127.0.0.1' });
|
|
12
|
+
const timeout = setTimeout(() => {
|
|
13
|
+
conn.destroy();
|
|
14
|
+
resolve(false);
|
|
15
|
+
}, 500);
|
|
16
|
+
conn.on('connect', () => {
|
|
17
|
+
clearTimeout(timeout);
|
|
18
|
+
conn.destroy();
|
|
19
|
+
resolve(true);
|
|
20
|
+
});
|
|
21
|
+
conn.on('error', () => {
|
|
22
|
+
clearTimeout(timeout);
|
|
23
|
+
resolve(false);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function findAvailablePort(start) {
|
|
28
|
+
let port = start;
|
|
29
|
+
while (await isPortInUse(port)) {
|
|
30
|
+
console.log(` Port ${port} is in use, trying ${port + 1}...`);
|
|
31
|
+
port++;
|
|
32
|
+
if (port > start + 20) {
|
|
33
|
+
console.error(` No available port found in range ${start}-${port}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return port;
|
|
38
|
+
}
|
|
39
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
40
|
+
const pkg = JSON.parse(readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8'));
|
|
41
|
+
const VERSION = pkg.version;
|
|
5
42
|
const program = new Command();
|
|
6
43
|
program
|
|
7
44
|
.name('dockscope')
|
|
8
45
|
.description('Visual, interactive Docker infrastructure debugger')
|
|
9
|
-
.version(
|
|
46
|
+
.version(VERSION);
|
|
10
47
|
program
|
|
11
|
-
.command('up')
|
|
48
|
+
.command('up', { isDefault: true })
|
|
12
49
|
.description('Start the DockScope dashboard')
|
|
13
50
|
.option('-p, --port <port>', 'Server port', '4681')
|
|
14
|
-
.option('-f, --file <path>', 'Docker Compose file path', 'docker-compose.yml')
|
|
15
51
|
.option('--no-open', "Don't open browser automatically")
|
|
52
|
+
.option('--no-port-check', 'Skip port conflict detection')
|
|
16
53
|
.action(async (opts) => {
|
|
17
|
-
const
|
|
54
|
+
const requestedPort = parseInt(opts.port, 10);
|
|
55
|
+
const port = opts.portCheck === false ? requestedPort : await findAvailablePort(requestedPort);
|
|
18
56
|
console.log(`
|
|
19
57
|
____ _ ____
|
|
20
58
|
| _ \\ ___ ___| | _/ ___| ___ ___ _ __ ___
|
|
21
59
|
| | | |/ _ \\ / __| |/ \\___ \\ / __/ _ \\| '_ \\ / _ \\
|
|
22
60
|
| |_| | (_) | (__| < ___) | (_| (_) | |_) | __/
|
|
23
61
|
|____/ \\___/ \\___|_|\\_\\____/ \\___\\___/| .__/ \\___|
|
|
24
|
-
|_|
|
|
62
|
+
|_| v${VERSION}
|
|
25
63
|
`);
|
|
26
|
-
await startServer({ port,
|
|
64
|
+
await startServer({ port, open: opts.open !== false });
|
|
27
65
|
const url = `http://localhost:${port}`;
|
|
28
66
|
console.log(` Dashboard: ${url}`);
|
|
29
67
|
console.log(` API: ${url}/api/graph`);
|
|
@@ -38,14 +76,13 @@ program
|
|
|
38
76
|
program
|
|
39
77
|
.command('scan')
|
|
40
78
|
.description('Scan Docker environment and output graph data as JSON')
|
|
41
|
-
.
|
|
42
|
-
.action(async (opts) => {
|
|
79
|
+
.action(async () => {
|
|
43
80
|
const connected = await checkConnection();
|
|
44
81
|
if (!connected) {
|
|
45
82
|
console.error('Cannot connect to Docker daemon. Is Docker running?');
|
|
46
83
|
process.exit(1);
|
|
47
84
|
}
|
|
48
|
-
const graph = await buildGraph(
|
|
85
|
+
const graph = await buildGraph();
|
|
49
86
|
console.log(JSON.stringify(graph, null, 2));
|
|
50
87
|
});
|
|
51
88
|
program.parse();
|
package/dist/server/index.js
CHANGED
|
@@ -22,12 +22,28 @@ export async function startServer(opts) {
|
|
|
22
22
|
const metricHistory = new Map();
|
|
23
23
|
// REST routes
|
|
24
24
|
setupRoutes(app, opts, metricHistory);
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
// Frontend: Vite dev server (HMR) or static files (production)
|
|
26
|
+
if (process.env.DOCKSCOPE_DEV === '1') {
|
|
27
|
+
try {
|
|
28
|
+
const { createServer: createVite } = await import('vite');
|
|
29
|
+
const vite = await createVite({
|
|
30
|
+
server: { middlewareMode: true, hmr: { server } },
|
|
31
|
+
appType: 'spa',
|
|
32
|
+
});
|
|
33
|
+
app.use(vite.middlewares);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
console.error('Vite not found — install devDependencies for dev mode');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const webDir = path.resolve(__dirname, '../web');
|
|
42
|
+
app.use(express.static(webDir));
|
|
43
|
+
app.get('*', (_req, res) => {
|
|
44
|
+
res.sendFile(path.join(webDir, 'index.html'));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
31
47
|
// --- WebSocket ---
|
|
32
48
|
const broadcast = (msg) => {
|
|
33
49
|
const data = JSON.stringify(msg);
|
|
@@ -39,7 +55,7 @@ export async function startServer(opts) {
|
|
|
39
55
|
let cachedGraph = { nodes: [], links: [] };
|
|
40
56
|
const refreshGraph = async () => {
|
|
41
57
|
try {
|
|
42
|
-
cachedGraph = await buildGraph(
|
|
58
|
+
cachedGraph = await buildGraph();
|
|
43
59
|
broadcast({ type: 'graph', data: cachedGraph });
|
|
44
60
|
}
|
|
45
61
|
catch {
|
package/dist/server/routes.js
CHANGED
|
@@ -2,7 +2,7 @@ import { buildGraph, checkConnection, composeAction, containerAction, getContain
|
|
|
2
2
|
export function setupRoutes(app, opts, metricHistory) {
|
|
3
3
|
app.get('/api/graph', async (_req, res) => {
|
|
4
4
|
try {
|
|
5
|
-
const graph = await buildGraph(
|
|
5
|
+
const graph = await buildGraph();
|
|
6
6
|
res.json(graph);
|
|
7
7
|
}
|
|
8
8
|
catch (err) {
|