coaia-visualizer 1.0.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.
Files changed (51) hide show
  1. package/.hch/issues.json +156 -0
  2. package/.hch/issues.md +2 -0
  3. package/README.md +67 -0
  4. package/app/api/jsonl/route.ts +71 -0
  5. package/app/globals.css +125 -0
  6. package/app/layout.tsx +48 -0
  7. package/app/page.tsx +284 -0
  8. package/cli.ts +170 -0
  9. package/components/chart-detail.tsx +213 -0
  10. package/components/chart-list.tsx +184 -0
  11. package/components/data-stats.tsx +49 -0
  12. package/components/file-upload.tsx +73 -0
  13. package/components/narrative-beats.tsx +108 -0
  14. package/components/relation-graph.tsx +81 -0
  15. package/components/theme-provider.tsx +11 -0
  16. package/components/ui/badge.tsx +46 -0
  17. package/components/ui/button.tsx +60 -0
  18. package/components/ui/card.tsx +92 -0
  19. package/components/ui/scroll-area.tsx +58 -0
  20. package/components/ui/separator.tsx +28 -0
  21. package/components/ui/tabs.tsx +66 -0
  22. package/components.json +21 -0
  23. package/dist/cli.js +144 -0
  24. package/feat-2-webui-local-editing/IMPLEMENTATION.md +245 -0
  25. package/feat-2-webui-local-editing/INTEGRATION.md +302 -0
  26. package/feat-2-webui-local-editing/QUICKSTART.md +129 -0
  27. package/feat-2-webui-local-editing/README.md +254 -0
  28. package/feat-2-webui-local-editing/api-route-jsonl.ts +71 -0
  29. package/feat-2-webui-local-editing/cli.ts +170 -0
  30. package/feat-2-webui-local-editing/demo.sh +98 -0
  31. package/feat-2-webui-local-editing/package.json +82 -0
  32. package/feat-2-webui-local-editing/test-integration.sh +93 -0
  33. package/feat-2-webui-local-editing/updated-page.tsx +284 -0
  34. package/hooks/use-toast.ts +17 -0
  35. package/lib/jsonl-parser.ts +153 -0
  36. package/lib/types.ts +39 -0
  37. package/lib/utils.ts +6 -0
  38. package/next.config.mjs +12 -0
  39. package/package.json +82 -0
  40. package/postcss.config.mjs +8 -0
  41. package/public/apple-icon.png +0 -0
  42. package/public/icon-dark-32x32.png +0 -0
  43. package/public/icon-light-32x32.png +0 -0
  44. package/public/icon.svg +26 -0
  45. package/public/placeholder-logo.png +0 -0
  46. package/public/placeholder-logo.svg +1 -0
  47. package/public/placeholder-user.jpg +0 -0
  48. package/public/placeholder.jpg +0 -0
  49. package/public/placeholder.svg +1 -0
  50. package/styles/globals.css +125 -0
  51. package/tsconfig.json +41 -0
@@ -0,0 +1,71 @@
1
+ // app/api/jsonl/route.ts
2
+ import { NextRequest, NextResponse } from 'next/server';
3
+ import { promises as fs } from 'fs';
4
+ import path from 'path';
5
+
6
+ export async function GET(request: NextRequest) {
7
+ const memoryPath = process.env.COAIAV_MEMORY_PATH;
8
+
9
+ if (!memoryPath) {
10
+ return NextResponse.json(
11
+ { error: 'No memory file configured. Launch with --memory-path flag.' },
12
+ { status: 400 }
13
+ );
14
+ }
15
+
16
+ try {
17
+ const content = await fs.readFile(memoryPath, 'utf-8');
18
+ const filename = path.basename(memoryPath);
19
+
20
+ return NextResponse.json({
21
+ content,
22
+ filename,
23
+ path: memoryPath
24
+ });
25
+ } catch (error: any) {
26
+ return NextResponse.json(
27
+ { error: `Failed to read memory file: ${error.message}` },
28
+ { status: 500 }
29
+ );
30
+ }
31
+ }
32
+
33
+ export async function POST(request: NextRequest) {
34
+ const memoryPath = process.env.COAIAV_MEMORY_PATH;
35
+
36
+ if (!memoryPath) {
37
+ return NextResponse.json(
38
+ { error: 'No memory file configured' },
39
+ { status: 400 }
40
+ );
41
+ }
42
+
43
+ try {
44
+ const { content } = await request.json();
45
+
46
+ if (!content) {
47
+ return NextResponse.json(
48
+ { error: 'No content provided' },
49
+ { status: 400 }
50
+ );
51
+ }
52
+
53
+ // Backup original file
54
+ const backupPath = `${memoryPath}.backup-${Date.now()}`;
55
+ await fs.copyFile(memoryPath, backupPath);
56
+
57
+ // Write new content
58
+ await fs.writeFile(memoryPath, content, 'utf-8');
59
+
60
+ return NextResponse.json({
61
+ success: true,
62
+ backup: backupPath,
63
+ message: 'Memory file updated successfully'
64
+ });
65
+ } catch (error: any) {
66
+ return NextResponse.json(
67
+ { error: `Failed to write memory file: ${error.message}` },
68
+ { status: 500 }
69
+ );
70
+ }
71
+ }
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * COAIA Visualizer CLI - Launch visualizer with local memory file
5
+ *
6
+ * Launches Next.js dev server with pre-loaded memory file
7
+ * Works analogously to coaia-narrative/cli.ts
8
+ */
9
+
10
+ import { spawn } from 'child_process';
11
+ import { promises as fs } from 'fs';
12
+ import path from 'path';
13
+ import minimist from 'minimist';
14
+ import * as dotenv from 'dotenv';
15
+ import { fileURLToPath } from 'url';
16
+
17
+ const __filename = fileURLToPath(import.meta.url);
18
+ const __dirname = path.dirname(__filename);
19
+
20
+ interface Config {
21
+ memoryPath: string;
22
+ port: number;
23
+ noOpen: boolean;
24
+ }
25
+
26
+ function loadConfig(args: minimist.ParsedArgs): Config {
27
+ let config: Config = {
28
+ memoryPath: path.join(process.cwd(), 'memory.jsonl'),
29
+ port: 3000,
30
+ noOpen: false
31
+ };
32
+
33
+ // Load .env files
34
+ const localEnvPath = path.join(process.cwd(), '.env');
35
+ try {
36
+ dotenv.config({ path: localEnvPath });
37
+ } catch (error) {
38
+ // .env doesn't exist, that's okay
39
+ }
40
+
41
+ // Custom env file
42
+ if (args.env) {
43
+ dotenv.config({ path: args.env, override: true });
44
+ }
45
+
46
+ // Environment variables
47
+ if (process.env.COAIAN_MF) {
48
+ config.memoryPath = process.env.COAIAN_MF;
49
+ }
50
+ if (process.env.COAIAV_PORT) {
51
+ config.port = parseInt(process.env.COAIAV_PORT, 10);
52
+ }
53
+
54
+ // Command-line flags override everything
55
+ if (args['memory-path'] || args['M']) {
56
+ config.memoryPath = args['memory-path'] || args['M'];
57
+ }
58
+ if (args['port'] || args['p']) {
59
+ config.port = args['port'] || args['p'];
60
+ }
61
+ if (args['no-open']) {
62
+ config.noOpen = true;
63
+ }
64
+
65
+ return config;
66
+ }
67
+
68
+ async function main() {
69
+ const args = minimist(process.argv.slice(2));
70
+
71
+ if (args.help || args.h) {
72
+ console.log(`
73
+ ๐ŸŽจ COAIA Visualizer - Interactive Chart Viewer
74
+
75
+ DESCRIPTION:
76
+ Web-based visualizer for structural tension charts from coaia-narrative.
77
+ Launches a local web server to interactively explore your charts.
78
+
79
+ USAGE:
80
+ coaia-visualizer [OPTIONS]
81
+ npx coaia-visualizer [OPTIONS]
82
+
83
+ OPTIONS:
84
+ --memory-path PATH, -M PATH Path to memory.jsonl file (default: ./memory.jsonl)
85
+ --port PORT, -p PORT Server port (default: 3000)
86
+ --no-open Don't auto-open browser
87
+ --help, -h Show this help message
88
+
89
+ ENVIRONMENT VARIABLES:
90
+ COAIAN_MF Default memory file path
91
+ COAIAV_PORT Default server port
92
+
93
+ EXAMPLES:
94
+ # Launch with default memory.jsonl
95
+ coaia-visualizer
96
+
97
+ # Launch with specific memory file
98
+ coaia-visualizer --memory-path ./my-charts.jsonl
99
+
100
+ # Launch on different port
101
+ coaia-visualizer --port 3001
102
+
103
+ # Use environment variable
104
+ COAIAN_MF=./charts.jsonl coaia-visualizer
105
+ `);
106
+ process.exit(0);
107
+ }
108
+
109
+ const config = loadConfig(args);
110
+
111
+ // Verify memory file exists
112
+ try {
113
+ await fs.access(config.memoryPath);
114
+ } catch (error) {
115
+ console.error(`โŒ Memory file not found: ${config.memoryPath}`);
116
+ console.error(` Create a memory file or specify a different path with --memory-path`);
117
+ process.exit(1);
118
+ }
119
+
120
+ console.log(`๐ŸŽจ COAIA Visualizer`);
121
+ console.log(`๐Ÿ“ Memory file: ${config.memoryPath}`);
122
+ console.log(`๐ŸŒ Port: ${config.port}`);
123
+ console.log();
124
+
125
+ // Set environment variables for Next.js
126
+ process.env.COAIAV_MEMORY_PATH = path.resolve(config.memoryPath);
127
+ process.env.PORT = config.port.toString();
128
+
129
+ // Navigate to visualizer root
130
+ const visualizerRoot = path.resolve(__dirname, '..');
131
+
132
+ // Launch Next.js dev server
133
+ const nextProcess = spawn('npm', ['run', 'dev'], {
134
+ cwd: visualizerRoot,
135
+ stdio: 'inherit',
136
+ env: {
137
+ ...process.env,
138
+ COAIAV_MEMORY_PATH: path.resolve(config.memoryPath),
139
+ PORT: config.port.toString()
140
+ }
141
+ });
142
+
143
+ // Open browser if not disabled
144
+ if (!config.noOpen) {
145
+ setTimeout(() => {
146
+ const url = `http://localhost:${config.port}`;
147
+ console.log(`\n๐Ÿš€ Opening browser: ${url}\n`);
148
+
149
+ const openCmd = process.platform === 'darwin' ? 'open' :
150
+ process.platform === 'win32' ? 'start' : 'xdg-open';
151
+ spawn(openCmd, [url], { detached: true, stdio: 'ignore' }).unref();
152
+ }, 3000);
153
+ }
154
+
155
+ // Handle shutdown
156
+ process.on('SIGINT', () => {
157
+ console.log('\n๐Ÿ‘‹ Shutting down visualizer...');
158
+ nextProcess.kill();
159
+ process.exit(0);
160
+ });
161
+
162
+ nextProcess.on('exit', (code) => {
163
+ process.exit(code || 0);
164
+ });
165
+ }
166
+
167
+ main().catch((error) => {
168
+ console.error('โŒ Fatal error:', error);
169
+ process.exit(1);
170
+ });
@@ -0,0 +1,98 @@
1
+ #!/bin/bash
2
+ # Comprehensive test and demo of coaia-visualizer integration
3
+
4
+ set -e
5
+
6
+ echo "๐ŸŽจ COAIA Visualizer - Full Integration Test"
7
+ echo "==========================================="
8
+ echo
9
+
10
+ # Configuration
11
+ TEST_FILE="../coaia-narrative/test-cli-memory.jsonl"
12
+ PORT=3459
13
+
14
+ # Clean up any existing processes
15
+ echo "๐Ÿงน Cleaning up existing processes..."
16
+ EXISTING_PID=$(ps aux | grep "node.*next dev" | grep visualizer | grep -v grep | awk '{print $2}' || true)
17
+ if [ -n "$EXISTING_PID" ]; then
18
+ kill $EXISTING_PID 2>/dev/null || true
19
+ sleep 2
20
+ fi
21
+
22
+ # Test 1: Verify CLI exists and works
23
+ echo "โœ“ Test 1: CLI Help"
24
+ node dist/cli.js --help | head -5
25
+ echo
26
+
27
+ # Test 2: Start server with specific memory file
28
+ echo "โœ“ Test 2: Starting server with memory file"
29
+ echo " File: $TEST_FILE"
30
+ echo " Port: $PORT"
31
+ node dist/cli.js --memory-path "$TEST_FILE" --port $PORT --no-open > /tmp/viz-demo.log 2>&1 &
32
+ SERVER_PID=$!
33
+ echo " PID: $SERVER_PID"
34
+ echo
35
+
36
+ # Wait for server
37
+ echo "โณ Waiting for server startup..."
38
+ sleep 10
39
+
40
+ # Test 3: API endpoint
41
+ echo "โœ“ Test 3: API Endpoint Test"
42
+ API_RESPONSE=$(curl -s http://localhost:$PORT/api/jsonl)
43
+ FILENAME=$(echo "$API_RESPONSE" | jq -r '.filename')
44
+ FILE_PATH=$(echo "$API_RESPONSE" | jq -r '.path')
45
+ echo " Filename: $FILENAME"
46
+ echo " Path: $FILE_PATH"
47
+ echo
48
+
49
+ # Test 4: Homepage
50
+ echo "โœ“ Test 4: Homepage Test"
51
+ HOME_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/)
52
+ echo " HTTP Status: $HOME_STATUS"
53
+ if [ "$HOME_STATUS" = "200" ]; then
54
+ echo " โœ“ Homepage loads successfully"
55
+ else
56
+ echo " โœ— Homepage failed to load"
57
+ kill $SERVER_PID
58
+ exit 1
59
+ fi
60
+ echo
61
+
62
+ # Test 5: Data parsing
63
+ echo "โœ“ Test 5: JSONL Data Parsing"
64
+ CONTENT=$(echo "$API_RESPONSE" | jq -r '.content')
65
+ LINE_COUNT=$(echo "$CONTENT" | grep -c "^" || echo "0")
66
+ echo " Lines in file: $LINE_COUNT"
67
+ ENTITY_COUNT=$(echo "$CONTENT" | grep -c '"type":"entity"' || echo "0")
68
+ RELATION_COUNT=$(echo "$CONTENT" | grep -c '"type":"relation"' || echo "0")
69
+ echo " Entities: $ENTITY_COUNT"
70
+ echo " Relations: $RELATION_COUNT"
71
+ echo
72
+
73
+ # Summary
74
+ echo "โœ… All Tests Passed!"
75
+ echo
76
+ echo "๐Ÿ“Š Integration Summary:"
77
+ echo " โœ“ CLI launcher works with --memory-path and --port flags"
78
+ echo " โœ“ API endpoint serves JSONL files from filesystem"
79
+ echo " โœ“ Homepage renders correctly"
80
+ echo " โœ“ Data parsing works (entities and relations)"
81
+ echo
82
+ echo "๐Ÿš€ Server is running at: http://localhost:$PORT"
83
+ echo " Memory file: $TEST_FILE"
84
+ echo " PID: $SERVER_PID"
85
+ echo
86
+ echo "๐Ÿ’ก To use:"
87
+ echo " 1. Open browser to http://localhost:$PORT"
88
+ echo " 2. Charts will auto-load from the memory file"
89
+ echo " 3. Use 'Save Changes' to write back to file"
90
+ echo " 4. Use 'Reload' to refresh from file"
91
+ echo
92
+ echo "๐Ÿ›‘ To stop: kill $SERVER_PID"
93
+ echo
94
+
95
+ # Keep running or cleanup
96
+ read -p "Press Enter to stop server, or Ctrl+C to keep running..." DUMMY
97
+ kill $SERVER_PID
98
+ echo "Server stopped."
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@coaia/visualizer",
3
+ "version": "1.0.0",
4
+ "description": "Interactive web visualizer for COAIA Narrative structural tension charts",
5
+ "type": "module",
6
+ "bin": {
7
+ "coaia-visualizer": "./dist/cli.js"
8
+ },
9
+ "scripts": {
10
+ "build": "next build",
11
+ "dev": "next dev",
12
+ "start": "next start",
13
+ "lint": "eslint .",
14
+ "build:cli": "tsc cli.ts --outDir dist --module esnext --target es2022 --moduleResolution bundler --esModuleInterop --skipLibCheck",
15
+ "prepare": "npm run build:cli"
16
+ },
17
+ "dependencies": {
18
+ "@hookform/resolvers": "^3.10.0",
19
+ "@radix-ui/react-accordion": "1.2.2",
20
+ "@radix-ui/react-alert-dialog": "1.1.4",
21
+ "@radix-ui/react-aspect-ratio": "1.1.1",
22
+ "@radix-ui/react-avatar": "1.1.2",
23
+ "@radix-ui/react-checkbox": "1.1.3",
24
+ "@radix-ui/react-collapsible": "1.1.2",
25
+ "@radix-ui/react-context-menu": "2.2.4",
26
+ "@radix-ui/react-dialog": "1.1.4",
27
+ "@radix-ui/react-dropdown-menu": "2.1.4",
28
+ "@radix-ui/react-hover-card": "1.1.4",
29
+ "@radix-ui/react-label": "2.1.1",
30
+ "@radix-ui/react-menubar": "1.1.4",
31
+ "@radix-ui/react-navigation-menu": "1.2.3",
32
+ "@radix-ui/react-popover": "1.1.4",
33
+ "@radix-ui/react-progress": "1.1.1",
34
+ "@radix-ui/react-radio-group": "1.2.2",
35
+ "@radix-ui/react-scroll-area": "1.2.2",
36
+ "@radix-ui/react-select": "2.1.4",
37
+ "@radix-ui/react-separator": "1.1.1",
38
+ "@radix-ui/react-slider": "1.2.2",
39
+ "@radix-ui/react-slot": "1.1.1",
40
+ "@radix-ui/react-switch": "1.1.2",
41
+ "@radix-ui/react-tabs": "1.1.2",
42
+ "@radix-ui/react-toast": "1.2.4",
43
+ "@radix-ui/react-toggle": "1.1.1",
44
+ "@radix-ui/react-toggle-group": "1.1.1",
45
+ "@radix-ui/react-tooltip": "1.1.6",
46
+ "@vercel/analytics": "1.3.1",
47
+ "autoprefixer": "^10.4.20",
48
+ "class-variance-authority": "^0.7.1",
49
+ "clsx": "^2.1.1",
50
+ "cmdk": "1.0.4",
51
+ "date-fns": "4.1.0",
52
+ "dotenv": "^16.4.5",
53
+ "embla-carousel-react": "8.5.1",
54
+ "input-otp": "1.4.1",
55
+ "lucide-react": "^0.454.0",
56
+ "minimist": "^1.2.8",
57
+ "next": "16.0.10",
58
+ "next-themes": "^0.4.6",
59
+ "react": "19.2.0",
60
+ "react-day-picker": "9.8.0",
61
+ "react-dom": "19.2.0",
62
+ "react-hook-form": "^7.60.0",
63
+ "react-resizable-panels": "^2.1.7",
64
+ "recharts": "2.15.4",
65
+ "sonner": "^1.7.4",
66
+ "tailwind-merge": "^3.3.1",
67
+ "tailwindcss-animate": "^1.0.7",
68
+ "vaul": "^1.1.2",
69
+ "zod": "3.25.76"
70
+ },
71
+ "devDependencies": {
72
+ "@tailwindcss/postcss": "^4.1.9",
73
+ "@types/minimist": "^1.2.5",
74
+ "@types/node": "^22",
75
+ "@types/react": "^19",
76
+ "@types/react-dom": "^19",
77
+ "postcss": "^8.5",
78
+ "tailwindcss": "^4.1.9",
79
+ "tw-animate-css": "1.3.3",
80
+ "typescript": "^5"
81
+ }
82
+ }
@@ -0,0 +1,93 @@
1
+ #!/bin/bash
2
+ # Test script for coaia-visualizer CLI integration
3
+
4
+ set -e
5
+
6
+ echo "๐Ÿงช Testing COAIA Visualizer CLI Integration"
7
+ echo "==========================================="
8
+ echo
9
+
10
+ # Test 1: Help command
11
+ echo "โœ“ Test 1: Help command"
12
+ node dist/cli.js --help > /dev/null
13
+ echo " โœ“ Help output works"
14
+ echo
15
+
16
+ # Test 2: Build CLI
17
+ echo "โœ“ Test 2: Building CLI"
18
+ npm run build:cli > /dev/null 2>&1
19
+ echo " โœ“ CLI built successfully"
20
+ echo
21
+
22
+ # Test 3: Check executable
23
+ echo "โœ“ Test 3: Checking CLI executable"
24
+ if [ -x dist/cli.js ]; then
25
+ echo " โœ“ CLI is executable"
26
+ else
27
+ chmod +x dist/cli.js
28
+ echo " โœ“ Made CLI executable"
29
+ fi
30
+ echo
31
+
32
+ # Test 4: Verify test file exists
33
+ TEST_FILE="../coaia-narrative/test-cli-memory.jsonl"
34
+ echo "โœ“ Test 4: Checking test file"
35
+ if [ -f "$TEST_FILE" ]; then
36
+ echo " โœ“ Test file exists: $TEST_FILE"
37
+ else
38
+ echo " โœ— Test file missing: $TEST_FILE"
39
+ exit 1
40
+ fi
41
+ echo
42
+
43
+ # Test 5: Start server in background
44
+ echo "โœ“ Test 5: Starting server (background mode)"
45
+ PORT=3457 node dist/cli.js --memory-path "$TEST_FILE" --no-open > /tmp/visualizer-test.log 2>&1 &
46
+ SERVER_PID=$!
47
+ echo " โœ“ Server started with PID: $SERVER_PID"
48
+ echo
49
+
50
+ # Wait for server to start
51
+ echo "โณ Waiting for server to be ready..."
52
+ sleep 8
53
+
54
+ # Test 6: Test API endpoint
55
+ echo "โœ“ Test 6: Testing API endpoint"
56
+ RESPONSE=$(curl -s http://localhost:3457/api/jsonl)
57
+ if echo "$RESPONSE" | grep -q "test-cli-memory.jsonl"; then
58
+ echo " โœ“ API returns correct filename"
59
+ else
60
+ echo " โœ— API test failed"
61
+ kill $SERVER_PID
62
+ exit 1
63
+ fi
64
+ echo
65
+
66
+ # Test 7: Test homepage
67
+ echo "โœ“ Test 7: Testing homepage"
68
+ HOME_RESPONSE=$(curl -s http://localhost:3457/)
69
+ if echo "$HOME_RESPONSE" | grep -q "COAIA Narrative Visualizer"; then
70
+ echo " โœ“ Homepage loads correctly"
71
+ else
72
+ echo " โœ— Homepage test failed"
73
+ kill $SERVER_PID
74
+ exit 1
75
+ fi
76
+ echo
77
+
78
+ # Cleanup
79
+ echo "๐Ÿงน Cleaning up..."
80
+ kill $SERVER_PID
81
+ sleep 2
82
+ echo " โœ“ Server stopped"
83
+ echo
84
+
85
+ echo "โœ… All tests passed!"
86
+ echo
87
+ echo "๐Ÿ“ฆ Integration Summary:"
88
+ echo " โ€ข CLI launcher works with --memory-path flag"
89
+ echo " โ€ข API endpoint serves JSONL files"
90
+ echo " โ€ข Homepage renders correctly"
91
+ echo " โ€ข Auto-loading from filesystem works"
92
+ echo
93
+ echo "๐Ÿš€ Ready for use!"