coaia-visualizer 1.5.2 → 1.5.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/.coaia/jgwill-coaia-visualizer.jsonl +6 -0
- package/.github/workflows/docker.yml +50 -0
- package/Dockerfile +61 -0
- package/cli.ts +88 -15
- package/dist/cli.js +75 -15
- package/docker-build-push.sh +20 -0
- package/docker-entrypoint.sh +27 -0
- package/package.json +6 -2
- package/jgwill.coaia-visualizer-8--496dca71-d476-4ac9-ba9f-376add118dd8--260208.txt +0 -2612
- package/samples/tradingchart.jsonl.backup-1770783713522 +0 -31
- package/samples/tradingchart.jsonl.backup-1770783734597 +0 -31
- package/samples/tradingchart.jsonl.backup-1770786390472 +0 -38
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{"type":"entity","name":"chart_1770523106343_chart","entityType":"structural_tension_chart","observations":["Chart created for jgwill/coaia-visualizer on 2026-02-08T03:58:26.343Z"],"metadata":{"chartId":"chart_1770523106343","repository":"jgwill/coaia-visualizer","level":0,"createdAt":"2026-02-08T03:58:26.343Z","updatedAt":"2026-02-08T03:58:26.343Z"}}
|
|
2
|
+
{"type":"entity","name":"chart_1770523106343_desired_outcome","entityType":"desired_outcome","observations":["Successful development and collaboration on jgwill/coaia-visualizer"],"metadata":{"chartId":"chart_1770523106343","createdAt":"2026-02-08T03:58:26.343Z","updatedAt":"2026-02-08T03:58:26.343Z"}}
|
|
3
|
+
{"type":"entity","name":"chart_1770523106343_current_reality","entityType":"current_reality","observations":["Repository initialized with STC bot integration","[2026-02-08T03:58:26.404Z] @stcissue triggered: Issue #8 - LIVE_MODE_DESIGN.md (issues.opened)","[2026-02-08T04:38:12.548Z] @stcissue triggered: Issue #8 - Live Narrative Witness Mode (issues.edited)","[2026-02-12T04:05:37.474Z] @stcissue triggered: Issue #9 - file watching issue (issues.opened)","[2026-02-18T19:29:54.244Z] @stcissue triggered: Issue #10 - Containerization (issues.opened)"],"metadata":{"chartId":"chart_1770523106343","createdAt":"2026-02-08T03:58:26.343Z","updatedAt":"2026-02-18T19:29:54.244Z"}}
|
|
4
|
+
{"type":"relation","from":"chart_1770523106343_chart","to":"chart_1770523106343_desired_outcome","relationType":"contains","metadata":{"createdAt":"2026-02-08T03:58:26.343Z"}}
|
|
5
|
+
{"type":"relation","from":"chart_1770523106343_chart","to":"chart_1770523106343_current_reality","relationType":"contains","metadata":{"createdAt":"2026-02-08T03:58:26.343Z"}}
|
|
6
|
+
{"type":"relation","from":"chart_1770523106343_current_reality","to":"chart_1770523106343_desired_outcome","relationType":"creates_tension_with","metadata":{"createdAt":"2026-02-08T03:58:26.343Z"}}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Docker Build & Push
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tag:
|
|
10
|
+
description: 'Docker tag (default: latest)'
|
|
11
|
+
required: false
|
|
12
|
+
default: 'latest'
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
IMAGE: jgwill/coaia:visualizer
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build-push:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Docker Buildx
|
|
24
|
+
uses: docker/setup-buildx-action@v3
|
|
25
|
+
|
|
26
|
+
- name: Log in to Docker Hub
|
|
27
|
+
uses: docker/login-action@v3
|
|
28
|
+
with:
|
|
29
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
30
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
31
|
+
|
|
32
|
+
- name: Docker meta
|
|
33
|
+
id: meta
|
|
34
|
+
uses: docker/metadata-action@v5
|
|
35
|
+
with:
|
|
36
|
+
images: jgwill/coaia
|
|
37
|
+
tags: |
|
|
38
|
+
type=raw,value=visualizer
|
|
39
|
+
type=semver,pattern=visualizer-{{version}},event=tag
|
|
40
|
+
type=raw,value=visualizer-latest,enable={{is_default_branch}}
|
|
41
|
+
|
|
42
|
+
- name: Build and push
|
|
43
|
+
uses: docker/build-push-action@v6
|
|
44
|
+
with:
|
|
45
|
+
context: .
|
|
46
|
+
push: true
|
|
47
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
48
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
49
|
+
cache-from: type=gha
|
|
50
|
+
cache-to: type=gha,mode=max
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# COAIA Visualizer — Docker Image
|
|
3
|
+
# jgwill/coaia:visualizer
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# docker run --rm -p 4321:4321 \
|
|
7
|
+
# -v /abs/path/to/file.jsonl:/data/memory.jsonl \
|
|
8
|
+
# jgwill/coaia:visualizer
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
# ---- Build stage ----
|
|
12
|
+
FROM node:22-alpine AS builder
|
|
13
|
+
|
|
14
|
+
WORKDIR /app
|
|
15
|
+
|
|
16
|
+
# Install pnpm
|
|
17
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
18
|
+
|
|
19
|
+
# Copy lockfile + manifests first (layer cache)
|
|
20
|
+
COPY package.json pnpm-lock.yaml ./
|
|
21
|
+
|
|
22
|
+
# Install all deps — skip prepare hook (cli.ts not copied yet)
|
|
23
|
+
RUN pnpm install --no-frozen-lockfile --ignore-scripts
|
|
24
|
+
|
|
25
|
+
# Copy source
|
|
26
|
+
COPY . .
|
|
27
|
+
|
|
28
|
+
# Build CLI + Next.js
|
|
29
|
+
RUN pnpm run prepare && pnpm build
|
|
30
|
+
|
|
31
|
+
# ---- Runner stage ----
|
|
32
|
+
FROM node:22-alpine AS runner
|
|
33
|
+
|
|
34
|
+
WORKDIR /app
|
|
35
|
+
|
|
36
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
37
|
+
|
|
38
|
+
# Copy manifests + node_modules from builder, then prune dev deps
|
|
39
|
+
COPY package.json pnpm-lock.yaml ./
|
|
40
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
41
|
+
RUN pnpm prune --prod 2>/dev/null || true
|
|
42
|
+
|
|
43
|
+
# Copy built assets from builder
|
|
44
|
+
COPY --from=builder /app/.next ./.next
|
|
45
|
+
COPY --from=builder /app/public ./public
|
|
46
|
+
COPY --from=builder /app/next.config.mjs ./next.config.mjs
|
|
47
|
+
|
|
48
|
+
# Entrypoint script
|
|
49
|
+
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
|
50
|
+
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
|
51
|
+
|
|
52
|
+
# Volume for user JSONL files
|
|
53
|
+
VOLUME ["/data"]
|
|
54
|
+
|
|
55
|
+
ENV NODE_ENV=production
|
|
56
|
+
ENV PORT=4321
|
|
57
|
+
ENV COAIAV_MEMORY_PATH=/data/memory.jsonl
|
|
58
|
+
|
|
59
|
+
EXPOSE 4321
|
|
60
|
+
|
|
61
|
+
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
package/cli.ts
CHANGED
|
@@ -17,6 +17,9 @@ import { fileURLToPath } from 'url';
|
|
|
17
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
18
18
|
const __dirname = path.dirname(__filename);
|
|
19
19
|
|
|
20
|
+
const DOCKER_IMAGE = 'jgwill/coaia:visualizer';
|
|
21
|
+
const CONTAINER_PORT = 4321;
|
|
22
|
+
|
|
20
23
|
interface Config {
|
|
21
24
|
memoryPath: string;
|
|
22
25
|
port: number;
|
|
@@ -25,17 +28,23 @@ interface Config {
|
|
|
25
28
|
pollInterval: number;
|
|
26
29
|
autoPlay: boolean;
|
|
27
30
|
audioDir: string;
|
|
31
|
+
useDocker: boolean;
|
|
32
|
+
dockerImage: string;
|
|
33
|
+
pullImage: boolean;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
function loadConfig(args: minimist.ParsedArgs): Config {
|
|
31
37
|
let config: Config = {
|
|
32
38
|
memoryPath: path.join(process.cwd(), 'memory.jsonl'),
|
|
33
|
-
port:
|
|
39
|
+
port: 4321,
|
|
34
40
|
noOpen: false,
|
|
35
41
|
live: false,
|
|
36
42
|
pollInterval: 2000,
|
|
37
43
|
autoPlay: false,
|
|
38
|
-
audioDir: path.join(process.cwd(), 'audio')
|
|
44
|
+
audioDir: path.join(process.cwd(), 'audio'),
|
|
45
|
+
useDocker: false,
|
|
46
|
+
dockerImage: DOCKER_IMAGE,
|
|
47
|
+
pullImage: false,
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
// Load .env files
|
|
@@ -93,6 +102,16 @@ function loadConfig(args: minimist.ParsedArgs): Config {
|
|
|
93
102
|
if (args['audio-dir']) {
|
|
94
103
|
config.audioDir = args['audio-dir'];
|
|
95
104
|
}
|
|
105
|
+
if (args['docker'] || args['d']) {
|
|
106
|
+
config.useDocker = true;
|
|
107
|
+
}
|
|
108
|
+
if (args['docker-image']) {
|
|
109
|
+
config.dockerImage = args['docker-image'];
|
|
110
|
+
config.useDocker = true;
|
|
111
|
+
}
|
|
112
|
+
if (args['pull']) {
|
|
113
|
+
config.pullImage = true;
|
|
114
|
+
}
|
|
96
115
|
|
|
97
116
|
return config;
|
|
98
117
|
}
|
|
@@ -114,7 +133,10 @@ USAGE:
|
|
|
114
133
|
|
|
115
134
|
OPTIONS:
|
|
116
135
|
--memory-path PATH, -M PATH Path to memory.jsonl file (default: ./memory.jsonl)
|
|
117
|
-
--port PORT, -p PORT Server port (default:
|
|
136
|
+
--port PORT, -p PORT Server port (default: 4321)
|
|
137
|
+
--docker, -d Run in Docker container (recommended, no local deps needed)
|
|
138
|
+
--docker-image IMAGE Docker image to use (default: ${DOCKER_IMAGE})
|
|
139
|
+
--pull Pull/update the Docker image before running
|
|
118
140
|
--live Enable live monitoring mode
|
|
119
141
|
--poll-interval MS Polling interval in ms (default: 2000)
|
|
120
142
|
--auto-play Auto-play audio for new beats
|
|
@@ -131,17 +153,20 @@ ENVIRONMENT VARIABLES:
|
|
|
131
153
|
COAIAV_AUDIO_DIR Audio directory path
|
|
132
154
|
|
|
133
155
|
EXAMPLES:
|
|
134
|
-
# Launch
|
|
135
|
-
coaia-visualizer
|
|
156
|
+
# Launch in Docker (recommended — no local dependency issues)
|
|
157
|
+
coaia-visualizer --docker -M ./charts.jsonl
|
|
158
|
+
|
|
159
|
+
# Launch with default memory.jsonl in Docker
|
|
160
|
+
coaia-visualizer -d
|
|
136
161
|
|
|
137
|
-
# Launch
|
|
138
|
-
coaia-visualizer --
|
|
162
|
+
# Launch on custom port with Docker
|
|
163
|
+
coaia-visualizer --docker -M ./my-charts.jsonl --port 5555
|
|
139
164
|
|
|
140
|
-
# Launch
|
|
141
|
-
coaia-visualizer
|
|
165
|
+
# Launch with local Next.js (requires local node_modules)
|
|
166
|
+
coaia-visualizer -M ./my-charts.jsonl
|
|
142
167
|
|
|
143
168
|
# Use environment variable
|
|
144
|
-
COAIAN_MF=./charts.jsonl coaia-visualizer
|
|
169
|
+
COAIAN_MF=./charts.jsonl coaia-visualizer --docker
|
|
145
170
|
`);
|
|
146
171
|
process.exit(0);
|
|
147
172
|
}
|
|
@@ -157,7 +182,7 @@ EXAMPLES:
|
|
|
157
182
|
process.exit(1);
|
|
158
183
|
}
|
|
159
184
|
|
|
160
|
-
console.log(`🎨 COAIA Visualizer${config.live ? ' [LIVE MODE]' : ''}`);
|
|
185
|
+
console.log(`🎨 COAIA Visualizer${config.live ? ' [LIVE MODE]' : ''}${config.useDocker ? ' [DOCKER]' : ''}`);
|
|
161
186
|
console.log(`📁 Memory file: ${config.memoryPath}`);
|
|
162
187
|
console.log(`🌐 Port: ${config.port}`);
|
|
163
188
|
if (config.live) {
|
|
@@ -167,6 +192,58 @@ EXAMPLES:
|
|
|
167
192
|
}
|
|
168
193
|
console.log();
|
|
169
194
|
|
|
195
|
+
// ── Docker mode ───────────────────────────────────────────────────────────
|
|
196
|
+
if (config.useDocker) {
|
|
197
|
+
const absMemoryPath = path.resolve(config.memoryPath);
|
|
198
|
+
const image = config.dockerImage;
|
|
199
|
+
|
|
200
|
+
// Optionally pull the latest image
|
|
201
|
+
if (config.pullImage) {
|
|
202
|
+
console.log(`⬇️ Pulling ${image}...`);
|
|
203
|
+
const pullProc = spawn('docker', ['pull', image], { stdio: 'inherit' });
|
|
204
|
+
await new Promise<void>((resolve, reject) => {
|
|
205
|
+
pullProc.on('exit', (code) => code === 0 ? resolve() : reject(new Error(`docker pull failed: ${code}`)));
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const dockerArgs = [
|
|
210
|
+
'run', '--rm',
|
|
211
|
+
'-p', `${config.port}:${CONTAINER_PORT}`,
|
|
212
|
+
'-v', `${absMemoryPath}:/data/memory.jsonl`,
|
|
213
|
+
'-e', `COAIAV_MEMORY_PATH=/data/memory.jsonl`,
|
|
214
|
+
'-e', `PORT=${CONTAINER_PORT}`,
|
|
215
|
+
'-e', `NEXT_PUBLIC_LIVE_MODE=${config.live}`,
|
|
216
|
+
'-e', `NEXT_PUBLIC_POLL_INTERVAL=${config.pollInterval}`,
|
|
217
|
+
'-e', `NEXT_PUBLIC_AUTO_PLAY=${config.autoPlay}`,
|
|
218
|
+
image
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
console.log(`🐳 docker ${dockerArgs.join(' ')}\n`);
|
|
222
|
+
|
|
223
|
+
const dockerProcess = spawn('docker', dockerArgs, { stdio: 'inherit' });
|
|
224
|
+
|
|
225
|
+
if (!config.noOpen) {
|
|
226
|
+
setTimeout(() => {
|
|
227
|
+
const url = `http://localhost:${config.port}`;
|
|
228
|
+
console.log(`\n🚀 Opening browser: ${url}\n`);
|
|
229
|
+
const openCmd = process.platform === 'darwin' ? 'open' :
|
|
230
|
+
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
231
|
+
spawn(openCmd, [url], { detached: true, stdio: 'ignore' }).unref();
|
|
232
|
+
}, 4000);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
process.on('SIGINT', () => {
|
|
236
|
+
console.log('\n👋 Shutting down visualizer...');
|
|
237
|
+
dockerProcess.kill();
|
|
238
|
+
process.exit(0);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
dockerProcess.on('exit', (code) => { process.exit(code || 0); });
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ── Local Next.js mode ────────────────────────────────────────────────────
|
|
246
|
+
|
|
170
247
|
// Set environment variables for Next.js
|
|
171
248
|
process.env.COAIAV_MEMORY_PATH = path.resolve(config.memoryPath);
|
|
172
249
|
process.env.PORT = config.port.toString();
|
|
@@ -178,8 +255,6 @@ EXAMPLES:
|
|
|
178
255
|
// Navigate to visualizer root
|
|
179
256
|
const visualizerRoot = path.resolve(__dirname, '..');
|
|
180
257
|
|
|
181
|
-
// Launch Next.js dev server with explicit port flag
|
|
182
|
-
// Set TURBOPACK_PROJECT_DIR to prevent watching parent directories
|
|
183
258
|
const nextProcess = spawn('npm', ['run', 'dev', '--', '-p', config.port.toString()], {
|
|
184
259
|
cwd: visualizerRoot,
|
|
185
260
|
stdio: 'inherit',
|
|
@@ -191,9 +266,7 @@ EXAMPLES:
|
|
|
191
266
|
NEXT_PUBLIC_POLL_INTERVAL: config.pollInterval.toString(),
|
|
192
267
|
NEXT_PUBLIC_AUTO_PLAY: config.autoPlay.toString(),
|
|
193
268
|
COAIAV_AUDIO_DIR: path.resolve(config.audioDir),
|
|
194
|
-
// Constrain Turbopack to only watch the visualizer directory
|
|
195
269
|
TURBOPACK_PROJECT_DIR: visualizerRoot,
|
|
196
|
-
// Disable excessive file watching
|
|
197
270
|
WATCHPACK_POLLING: 'false'
|
|
198
271
|
}
|
|
199
272
|
});
|
package/dist/cli.js
CHANGED
|
@@ -13,15 +13,20 @@ import * as dotenv from 'dotenv';
|
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
15
|
const __dirname = path.dirname(__filename);
|
|
16
|
+
const DOCKER_IMAGE = 'jgwill/coaia:visualizer';
|
|
17
|
+
const CONTAINER_PORT = 4321;
|
|
16
18
|
function loadConfig(args) {
|
|
17
19
|
let config = {
|
|
18
20
|
memoryPath: path.join(process.cwd(), 'memory.jsonl'),
|
|
19
|
-
port:
|
|
21
|
+
port: 4321,
|
|
20
22
|
noOpen: false,
|
|
21
23
|
live: false,
|
|
22
24
|
pollInterval: 2000,
|
|
23
25
|
autoPlay: false,
|
|
24
|
-
audioDir: path.join(process.cwd(), 'audio')
|
|
26
|
+
audioDir: path.join(process.cwd(), 'audio'),
|
|
27
|
+
useDocker: false,
|
|
28
|
+
dockerImage: DOCKER_IMAGE,
|
|
29
|
+
pullImage: false,
|
|
25
30
|
};
|
|
26
31
|
// Load .env files
|
|
27
32
|
const localEnvPath = path.join(process.cwd(), '.env');
|
|
@@ -76,6 +81,16 @@ function loadConfig(args) {
|
|
|
76
81
|
if (args['audio-dir']) {
|
|
77
82
|
config.audioDir = args['audio-dir'];
|
|
78
83
|
}
|
|
84
|
+
if (args['docker'] || args['d']) {
|
|
85
|
+
config.useDocker = true;
|
|
86
|
+
}
|
|
87
|
+
if (args['docker-image']) {
|
|
88
|
+
config.dockerImage = args['docker-image'];
|
|
89
|
+
config.useDocker = true;
|
|
90
|
+
}
|
|
91
|
+
if (args['pull']) {
|
|
92
|
+
config.pullImage = true;
|
|
93
|
+
}
|
|
79
94
|
return config;
|
|
80
95
|
}
|
|
81
96
|
async function main() {
|
|
@@ -94,7 +109,10 @@ USAGE:
|
|
|
94
109
|
|
|
95
110
|
OPTIONS:
|
|
96
111
|
--memory-path PATH, -M PATH Path to memory.jsonl file (default: ./memory.jsonl)
|
|
97
|
-
--port PORT, -p PORT Server port (default:
|
|
112
|
+
--port PORT, -p PORT Server port (default: 4321)
|
|
113
|
+
--docker, -d Run in Docker container (recommended, no local deps needed)
|
|
114
|
+
--docker-image IMAGE Docker image to use (default: ${DOCKER_IMAGE})
|
|
115
|
+
--pull Pull/update the Docker image before running
|
|
98
116
|
--live Enable live monitoring mode
|
|
99
117
|
--poll-interval MS Polling interval in ms (default: 2000)
|
|
100
118
|
--auto-play Auto-play audio for new beats
|
|
@@ -111,17 +129,20 @@ ENVIRONMENT VARIABLES:
|
|
|
111
129
|
COAIAV_AUDIO_DIR Audio directory path
|
|
112
130
|
|
|
113
131
|
EXAMPLES:
|
|
114
|
-
# Launch
|
|
115
|
-
coaia-visualizer
|
|
132
|
+
# Launch in Docker (recommended — no local dependency issues)
|
|
133
|
+
coaia-visualizer --docker -M ./charts.jsonl
|
|
134
|
+
|
|
135
|
+
# Launch with default memory.jsonl in Docker
|
|
136
|
+
coaia-visualizer -d
|
|
116
137
|
|
|
117
|
-
# Launch
|
|
118
|
-
coaia-visualizer --
|
|
138
|
+
# Launch on custom port with Docker
|
|
139
|
+
coaia-visualizer --docker -M ./my-charts.jsonl --port 5555
|
|
119
140
|
|
|
120
|
-
# Launch
|
|
121
|
-
coaia-visualizer
|
|
141
|
+
# Launch with local Next.js (requires local node_modules)
|
|
142
|
+
coaia-visualizer -M ./my-charts.jsonl
|
|
122
143
|
|
|
123
144
|
# Use environment variable
|
|
124
|
-
COAIAN_MF=./charts.jsonl coaia-visualizer
|
|
145
|
+
COAIAN_MF=./charts.jsonl coaia-visualizer --docker
|
|
125
146
|
`);
|
|
126
147
|
process.exit(0);
|
|
127
148
|
}
|
|
@@ -135,7 +156,7 @@ EXAMPLES:
|
|
|
135
156
|
console.error(` Create a memory file or specify a different path with --memory-path`);
|
|
136
157
|
process.exit(1);
|
|
137
158
|
}
|
|
138
|
-
console.log(`🎨 COAIA Visualizer${config.live ? ' [LIVE MODE]' : ''}`);
|
|
159
|
+
console.log(`🎨 COAIA Visualizer${config.live ? ' [LIVE MODE]' : ''}${config.useDocker ? ' [DOCKER]' : ''}`);
|
|
139
160
|
console.log(`📁 Memory file: ${config.memoryPath}`);
|
|
140
161
|
console.log(`🌐 Port: ${config.port}`);
|
|
141
162
|
if (config.live) {
|
|
@@ -144,6 +165,49 @@ EXAMPLES:
|
|
|
144
165
|
console.log(`🔊 Auto-play: ${config.autoPlay ? 'enabled' : 'disabled'}`);
|
|
145
166
|
}
|
|
146
167
|
console.log();
|
|
168
|
+
// ── Docker mode ───────────────────────────────────────────────────────────
|
|
169
|
+
if (config.useDocker) {
|
|
170
|
+
const absMemoryPath = path.resolve(config.memoryPath);
|
|
171
|
+
const image = config.dockerImage;
|
|
172
|
+
// Optionally pull the latest image
|
|
173
|
+
if (config.pullImage) {
|
|
174
|
+
console.log(`⬇️ Pulling ${image}...`);
|
|
175
|
+
const pullProc = spawn('docker', ['pull', image], { stdio: 'inherit' });
|
|
176
|
+
await new Promise((resolve, reject) => {
|
|
177
|
+
pullProc.on('exit', (code) => code === 0 ? resolve() : reject(new Error(`docker pull failed: ${code}`)));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const dockerArgs = [
|
|
181
|
+
'run', '--rm',
|
|
182
|
+
'-p', `${config.port}:${CONTAINER_PORT}`,
|
|
183
|
+
'-v', `${absMemoryPath}:/data/memory.jsonl`,
|
|
184
|
+
'-e', `COAIAV_MEMORY_PATH=/data/memory.jsonl`,
|
|
185
|
+
'-e', `PORT=${CONTAINER_PORT}`,
|
|
186
|
+
'-e', `NEXT_PUBLIC_LIVE_MODE=${config.live}`,
|
|
187
|
+
'-e', `NEXT_PUBLIC_POLL_INTERVAL=${config.pollInterval}`,
|
|
188
|
+
'-e', `NEXT_PUBLIC_AUTO_PLAY=${config.autoPlay}`,
|
|
189
|
+
image
|
|
190
|
+
];
|
|
191
|
+
console.log(`🐳 docker ${dockerArgs.join(' ')}\n`);
|
|
192
|
+
const dockerProcess = spawn('docker', dockerArgs, { stdio: 'inherit' });
|
|
193
|
+
if (!config.noOpen) {
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
const url = `http://localhost:${config.port}`;
|
|
196
|
+
console.log(`\n🚀 Opening browser: ${url}\n`);
|
|
197
|
+
const openCmd = process.platform === 'darwin' ? 'open' :
|
|
198
|
+
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
199
|
+
spawn(openCmd, [url], { detached: true, stdio: 'ignore' }).unref();
|
|
200
|
+
}, 4000);
|
|
201
|
+
}
|
|
202
|
+
process.on('SIGINT', () => {
|
|
203
|
+
console.log('\n👋 Shutting down visualizer...');
|
|
204
|
+
dockerProcess.kill();
|
|
205
|
+
process.exit(0);
|
|
206
|
+
});
|
|
207
|
+
dockerProcess.on('exit', (code) => { process.exit(code || 0); });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// ── Local Next.js mode ────────────────────────────────────────────────────
|
|
147
211
|
// Set environment variables for Next.js
|
|
148
212
|
process.env.COAIAV_MEMORY_PATH = path.resolve(config.memoryPath);
|
|
149
213
|
process.env.PORT = config.port.toString();
|
|
@@ -153,8 +217,6 @@ EXAMPLES:
|
|
|
153
217
|
process.env.COAIAV_AUDIO_DIR = path.resolve(config.audioDir);
|
|
154
218
|
// Navigate to visualizer root
|
|
155
219
|
const visualizerRoot = path.resolve(__dirname, '..');
|
|
156
|
-
// Launch Next.js dev server with explicit port flag
|
|
157
|
-
// Set TURBOPACK_PROJECT_DIR to prevent watching parent directories
|
|
158
220
|
const nextProcess = spawn('npm', ['run', 'dev', '--', '-p', config.port.toString()], {
|
|
159
221
|
cwd: visualizerRoot,
|
|
160
222
|
stdio: 'inherit',
|
|
@@ -166,9 +228,7 @@ EXAMPLES:
|
|
|
166
228
|
NEXT_PUBLIC_POLL_INTERVAL: config.pollInterval.toString(),
|
|
167
229
|
NEXT_PUBLIC_AUTO_PLAY: config.autoPlay.toString(),
|
|
168
230
|
COAIAV_AUDIO_DIR: path.resolve(config.audioDir),
|
|
169
|
-
// Constrain Turbopack to only watch the visualizer directory
|
|
170
231
|
TURBOPACK_PROJECT_DIR: visualizerRoot,
|
|
171
|
-
// Disable excessive file watching
|
|
172
232
|
WATCHPACK_POLLING: 'false'
|
|
173
233
|
}
|
|
174
234
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Build and push jgwill/coaia:visualizer to Docker Hub
|
|
3
|
+
# Usage: ./docker-build-push.sh [tag]
|
|
4
|
+
# Requires: docker login jgwill (or DOCKERHUB_TOKEN env)
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
TAG="${1:-visualizer}"
|
|
9
|
+
IMAGE="jgwill/coaia:$TAG"
|
|
10
|
+
|
|
11
|
+
echo "🐳 Building $IMAGE..."
|
|
12
|
+
docker build -t "$IMAGE" .
|
|
13
|
+
|
|
14
|
+
echo "📤 Pushing $IMAGE..."
|
|
15
|
+
docker push "$IMAGE"
|
|
16
|
+
|
|
17
|
+
echo "✅ Done: $IMAGE"
|
|
18
|
+
echo ""
|
|
19
|
+
echo "Run with:"
|
|
20
|
+
echo " docker run --rm -p 4321:4321 -v /abs/path/to/file.jsonl:/data/memory.jsonl $IMAGE"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# COAIA Visualizer Docker Entrypoint
|
|
5
|
+
# Serves the pre-built Next.js app with the user-supplied JSONL file.
|
|
6
|
+
#
|
|
7
|
+
# The JSONL file must be mounted into /data/ in the container.
|
|
8
|
+
# COAIAV_MEMORY_PATH defaults to /data/memory.jsonl but can be overridden.
|
|
9
|
+
|
|
10
|
+
MEMORY_PATH="${COAIAV_MEMORY_PATH:-/data/memory.jsonl}"
|
|
11
|
+
PORT="${PORT:-4321}"
|
|
12
|
+
|
|
13
|
+
# Validate that the memory file exists (warn but don't block — user may mount it later)
|
|
14
|
+
if [ ! -f "$MEMORY_PATH" ]; then
|
|
15
|
+
echo "⚠️ Warning: memory file not found at $MEMORY_PATH"
|
|
16
|
+
echo " Mount your JSONL file with: -v /your/file.jsonl:$MEMORY_PATH"
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "🎨 COAIA Visualizer"
|
|
20
|
+
echo "📁 Memory file: $MEMORY_PATH"
|
|
21
|
+
echo "🌐 http://localhost:$PORT"
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
export COAIAV_MEMORY_PATH="$MEMORY_PATH"
|
|
25
|
+
export PORT="$PORT"
|
|
26
|
+
|
|
27
|
+
exec node_modules/.bin/next start -p "$PORT"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coaia-visualizer",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.tsx",
|
|
@@ -26,7 +26,11 @@
|
|
|
26
26
|
"prepare": "npm run build:cli",
|
|
27
27
|
"start": "next start",
|
|
28
28
|
"test": "playwright test",
|
|
29
|
-
"test:global-cli": "playwright test test-scripts/test-global-cli.spec.ts"
|
|
29
|
+
"test:global-cli": "playwright test test-scripts/test-global-cli.spec.ts",
|
|
30
|
+
"docker:build": "docker build -t jgwill/coaia:visualizer .",
|
|
31
|
+
"docker:push": "docker push jgwill/coaia:visualizer",
|
|
32
|
+
"docker:build-push": "npm run docker:build && npm run docker:push",
|
|
33
|
+
"docker:run": "docker run --rm -p 4321:4321 -v \"$(pwd)/memory.jsonl:/data/memory.jsonl\" jgwill/coaia:visualizer"
|
|
30
34
|
},
|
|
31
35
|
"dependencies": {
|
|
32
36
|
"@cfworker/json-schema": "latest",
|