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,92 @@
1
+ import * as React from 'react'
2
+
3
+ import { cn } from '@/lib/utils'
4
+
5
+ function Card({ className, ...props }: React.ComponentProps<'div'>) {
6
+ return (
7
+ <div
8
+ data-slot="card"
9
+ className={cn(
10
+ 'bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm',
11
+ className,
12
+ )}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
19
+ return (
20
+ <div
21
+ data-slot="card-header"
22
+ className={cn(
23
+ '@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6',
24
+ className,
25
+ )}
26
+ {...props}
27
+ />
28
+ )
29
+ }
30
+
31
+ function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
32
+ return (
33
+ <div
34
+ data-slot="card-title"
35
+ className={cn('leading-none font-semibold', className)}
36
+ {...props}
37
+ />
38
+ )
39
+ }
40
+
41
+ function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
42
+ return (
43
+ <div
44
+ data-slot="card-description"
45
+ className={cn('text-muted-foreground text-sm', className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
52
+ return (
53
+ <div
54
+ data-slot="card-action"
55
+ className={cn(
56
+ 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
57
+ className,
58
+ )}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
65
+ return (
66
+ <div
67
+ data-slot="card-content"
68
+ className={cn('px-6', className)}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
75
+ return (
76
+ <div
77
+ data-slot="card-footer"
78
+ className={cn('flex items-center px-6 [.border-t]:pt-6', className)}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ export {
85
+ Card,
86
+ CardHeader,
87
+ CardFooter,
88
+ CardTitle,
89
+ CardAction,
90
+ CardDescription,
91
+ CardContent,
92
+ }
@@ -0,0 +1,58 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
5
+
6
+ import { cn } from '@/lib/utils'
7
+
8
+ function ScrollArea({
9
+ className,
10
+ children,
11
+ ...props
12
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
13
+ return (
14
+ <ScrollAreaPrimitive.Root
15
+ data-slot="scroll-area"
16
+ className={cn('relative', className)}
17
+ {...props}
18
+ >
19
+ <ScrollAreaPrimitive.Viewport
20
+ data-slot="scroll-area-viewport"
21
+ className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
22
+ >
23
+ {children}
24
+ </ScrollAreaPrimitive.Viewport>
25
+ <ScrollBar />
26
+ <ScrollAreaPrimitive.Corner />
27
+ </ScrollAreaPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ function ScrollBar({
32
+ className,
33
+ orientation = 'vertical',
34
+ ...props
35
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
36
+ return (
37
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
38
+ data-slot="scroll-area-scrollbar"
39
+ orientation={orientation}
40
+ className={cn(
41
+ 'flex touch-none p-px transition-colors select-none',
42
+ orientation === 'vertical' &&
43
+ 'h-full w-2.5 border-l border-l-transparent',
44
+ orientation === 'horizontal' &&
45
+ 'h-2.5 flex-col border-t border-t-transparent',
46
+ className,
47
+ )}
48
+ {...props}
49
+ >
50
+ <ScrollAreaPrimitive.ScrollAreaThumb
51
+ data-slot="scroll-area-thumb"
52
+ className="bg-border relative flex-1 rounded-full"
53
+ />
54
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
55
+ )
56
+ }
57
+
58
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1,28 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as SeparatorPrimitive from '@radix-ui/react-separator'
5
+
6
+ import { cn } from '@/lib/utils'
7
+
8
+ function Separator({
9
+ className,
10
+ orientation = 'horizontal',
11
+ decorative = true,
12
+ ...props
13
+ }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
14
+ return (
15
+ <SeparatorPrimitive.Root
16
+ data-slot="separator"
17
+ decorative={decorative}
18
+ orientation={orientation}
19
+ className={cn(
20
+ 'bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
21
+ className,
22
+ )}
23
+ {...props}
24
+ />
25
+ )
26
+ }
27
+
28
+ export { Separator }
@@ -0,0 +1,66 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import * as TabsPrimitive from '@radix-ui/react-tabs'
5
+
6
+ import { cn } from '@/lib/utils'
7
+
8
+ function Tabs({
9
+ className,
10
+ ...props
11
+ }: React.ComponentProps<typeof TabsPrimitive.Root>) {
12
+ return (
13
+ <TabsPrimitive.Root
14
+ data-slot="tabs"
15
+ className={cn('flex flex-col gap-2', className)}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ function TabsList({
22
+ className,
23
+ ...props
24
+ }: React.ComponentProps<typeof TabsPrimitive.List>) {
25
+ return (
26
+ <TabsPrimitive.List
27
+ data-slot="tabs-list"
28
+ className={cn(
29
+ 'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
30
+ className,
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ function TabsTrigger({
38
+ className,
39
+ ...props
40
+ }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
41
+ return (
42
+ <TabsPrimitive.Trigger
43
+ data-slot="tabs-trigger"
44
+ className={cn(
45
+ "data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
46
+ className,
47
+ )}
48
+ {...props}
49
+ />
50
+ )
51
+ }
52
+
53
+ function TabsContent({
54
+ className,
55
+ ...props
56
+ }: React.ComponentProps<typeof TabsPrimitive.Content>) {
57
+ return (
58
+ <TabsPrimitive.Content
59
+ data-slot="tabs-content"
60
+ className={cn('flex-1 outline-none', className)}
61
+ {...props}
62
+ />
63
+ )
64
+ }
65
+
66
+ export { Tabs, TabsList, TabsTrigger, TabsContent }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
package/dist/cli.js ADDED
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * COAIA Visualizer CLI - Launch visualizer with local memory file
4
+ *
5
+ * Launches Next.js dev server with pre-loaded memory file
6
+ * Works analogously to coaia-narrative/cli.ts
7
+ */
8
+ import { spawn } from 'child_process';
9
+ import { promises as fs } from 'fs';
10
+ import path from 'path';
11
+ import minimist from 'minimist';
12
+ import * as dotenv from 'dotenv';
13
+ import { fileURLToPath } from 'url';
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ function loadConfig(args) {
17
+ let config = {
18
+ memoryPath: path.join(process.cwd(), 'memory.jsonl'),
19
+ port: 3000,
20
+ noOpen: false
21
+ };
22
+ // Load .env files
23
+ const localEnvPath = path.join(process.cwd(), '.env');
24
+ try {
25
+ dotenv.config({ path: localEnvPath });
26
+ }
27
+ catch (error) {
28
+ // .env doesn't exist, that's okay
29
+ }
30
+ // Custom env file
31
+ if (args.env) {
32
+ dotenv.config({ path: args.env, override: true });
33
+ }
34
+ // Environment variables
35
+ if (process.env.COAIAN_MF) {
36
+ config.memoryPath = process.env.COAIAN_MF;
37
+ }
38
+ if (process.env.COAIAV_PORT) {
39
+ config.port = parseInt(process.env.COAIAV_PORT, 10);
40
+ }
41
+ // Command-line flags override everything
42
+ if (args['memory-path'] || args['M']) {
43
+ config.memoryPath = args['memory-path'] || args['M'];
44
+ }
45
+ if (args['port'] || args['p']) {
46
+ config.port = args['port'] || args['p'];
47
+ }
48
+ if (args['no-open']) {
49
+ config.noOpen = true;
50
+ }
51
+ return config;
52
+ }
53
+ async function main() {
54
+ const args = minimist(process.argv.slice(2));
55
+ if (args.help || args.h) {
56
+ console.log(`
57
+ 🎨 COAIA Visualizer - Interactive Chart Viewer
58
+
59
+ DESCRIPTION:
60
+ Web-based visualizer for structural tension charts from coaia-narrative.
61
+ Launches a local web server to interactively explore your charts.
62
+
63
+ USAGE:
64
+ coaia-visualizer [OPTIONS]
65
+ npx coaia-visualizer [OPTIONS]
66
+
67
+ OPTIONS:
68
+ --memory-path PATH, -M PATH Path to memory.jsonl file (default: ./memory.jsonl)
69
+ --port PORT, -p PORT Server port (default: 3000)
70
+ --no-open Don't auto-open browser
71
+ --help, -h Show this help message
72
+
73
+ ENVIRONMENT VARIABLES:
74
+ COAIAN_MF Default memory file path
75
+ COAIAV_PORT Default server port
76
+
77
+ EXAMPLES:
78
+ # Launch with default memory.jsonl
79
+ coaia-visualizer
80
+
81
+ # Launch with specific memory file
82
+ coaia-visualizer --memory-path ./my-charts.jsonl
83
+
84
+ # Launch on different port
85
+ coaia-visualizer --port 3001
86
+
87
+ # Use environment variable
88
+ COAIAN_MF=./charts.jsonl coaia-visualizer
89
+ `);
90
+ process.exit(0);
91
+ }
92
+ const config = loadConfig(args);
93
+ // Verify memory file exists
94
+ try {
95
+ await fs.access(config.memoryPath);
96
+ }
97
+ catch (error) {
98
+ console.error(`❌ Memory file not found: ${config.memoryPath}`);
99
+ console.error(` Create a memory file or specify a different path with --memory-path`);
100
+ process.exit(1);
101
+ }
102
+ console.log(`🎨 COAIA Visualizer`);
103
+ console.log(`📁 Memory file: ${config.memoryPath}`);
104
+ console.log(`🌐 Port: ${config.port}`);
105
+ console.log();
106
+ // Set environment variables for Next.js
107
+ process.env.COAIAV_MEMORY_PATH = path.resolve(config.memoryPath);
108
+ process.env.PORT = config.port.toString();
109
+ // Navigate to visualizer root
110
+ const visualizerRoot = path.resolve(__dirname, '..');
111
+ // Launch Next.js dev server with explicit port flag
112
+ const nextProcess = spawn('npm', ['run', 'dev', '--', '-p', config.port.toString()], {
113
+ cwd: visualizerRoot,
114
+ stdio: 'inherit',
115
+ env: {
116
+ ...process.env,
117
+ COAIAV_MEMORY_PATH: path.resolve(config.memoryPath),
118
+ PORT: config.port.toString()
119
+ }
120
+ });
121
+ // Open browser if not disabled
122
+ if (!config.noOpen) {
123
+ setTimeout(() => {
124
+ const url = `http://localhost:${config.port}`;
125
+ console.log(`\n🚀 Opening browser: ${url}\n`);
126
+ const openCmd = process.platform === 'darwin' ? 'open' :
127
+ process.platform === 'win32' ? 'start' : 'xdg-open';
128
+ spawn(openCmd, [url], { detached: true, stdio: 'ignore' }).unref();
129
+ }, 3000);
130
+ }
131
+ // Handle shutdown
132
+ process.on('SIGINT', () => {
133
+ console.log('\n👋 Shutting down visualizer...');
134
+ nextProcess.kill();
135
+ process.exit(0);
136
+ });
137
+ nextProcess.on('exit', (code) => {
138
+ process.exit(code || 0);
139
+ });
140
+ }
141
+ main().catch((error) => {
142
+ console.error('❌ Fatal error:', error);
143
+ process.exit(1);
144
+ });
@@ -0,0 +1,245 @@
1
+ # Implementation Summary - COAIA Visualizer Local Editing
2
+
3
+ ## Changes Made
4
+
5
+ ### New Files Created
6
+
7
+ 1. **`cli.ts`** - CLI launcher
8
+ - Parses command-line arguments (--memory-path, --port, --no-open)
9
+ - Loads configuration from env vars and .env files
10
+ - Launches Next.js dev server with environment variables
11
+ - Auto-opens browser unless --no-open specified
12
+
13
+ 2. **`app/api/jsonl/route.ts`** - API endpoints
14
+ - GET endpoint: reads memory file from filesystem
15
+ - POST endpoint: writes updated data with automatic backup
16
+ - Uses `COAIAV_MEMORY_PATH` environment variable
17
+
18
+ 3. **`hooks/use-toast.ts`** - Toast notifications
19
+ - Wrapper around sonner for consistent toast API
20
+ - Used for success/error feedback
21
+
22
+ ### Modified Files
23
+
24
+ 1. **`app/page.tsx`** - Enhanced main UI
25
+ - Auto-loads file on mount if launched via CLI
26
+ - Adds "Save Changes" button for local persistence
27
+ - Adds "Reload" button to refresh from file
28
+ - Shows file path when auto-loaded
29
+ - Toast notifications for user feedback
30
+
31
+ 2. **`app/layout.tsx`** - Added Toaster
32
+ - Imports and renders Sonner Toaster component
33
+ - Enables toast notifications throughout app
34
+
35
+ 3. **`package.json`** - Updated configuration
36
+ - Changed name to `@coaia/visualizer`
37
+ - Added `bin` entry for CLI
38
+ - Added dependencies: minimist, dotenv, @types/minimist
39
+ - Added `build:cli` and `prepare` scripts
40
+ - Set `type: "module"` for ES modules
41
+
42
+ ### Dependencies Added
43
+
44
+ - `minimist` - Command-line argument parsing
45
+ - `dotenv` - Environment variable loading
46
+ - `@types/minimist` - TypeScript types
47
+
48
+ ### Build Process
49
+
50
+ ```bash
51
+ npm run build:cli # Compiles cli.ts to dist/cli.js
52
+ npm run prepare # Runs automatically on npm install
53
+ ```
54
+
55
+ ## Architecture
56
+
57
+ ### Data Flow
58
+
59
+ ```
60
+ ┌──────────────────┐
61
+ │ CLI Launcher │ node dist/cli.js --memory-path file.jsonl
62
+ │ (cli.ts) │ Sets COAIAV_MEMORY_PATH env var
63
+ └────────┬─────────┘
64
+
65
+
66
+ ┌──────────────────┐
67
+ │ Next.js Server │ Reads env var, starts on specified port
68
+ │ │
69
+ └────────┬─────────┘
70
+
71
+
72
+ ┌──────────────────┐
73
+ │ API Route │ GET/POST /api/jsonl
74
+ │ (route.ts) │ Reads/writes filesystem using env var
75
+ └────────┬─────────┘
76
+
77
+
78
+ ┌──────────────────┐
79
+ │ React UI │ Auto-loads on mount via fetch()
80
+ │ (page.tsx) │ Save/Reload buttons call API
81
+ └──────────────────┘
82
+ ```
83
+
84
+ ### Configuration Priority
85
+
86
+ CLI follows same pattern as coaia-narrative/cli.ts:
87
+
88
+ 1. Command-line flags (highest)
89
+ 2. Custom env file (--env flag)
90
+ 3. .env file in cwd
91
+ 4. Environment variables
92
+ 5. Defaults (lowest)
93
+
94
+ ## Usage Examples
95
+
96
+ ### Basic Launch
97
+ ```bash
98
+ node dist/cli.js --memory-path ./charts.jsonl
99
+ # Opens http://localhost:3000 automatically
100
+ ```
101
+
102
+ ### Custom Port
103
+ ```bash
104
+ node dist/cli.js --memory-path ./charts.jsonl --port 3001
105
+ ```
106
+
107
+ ### Environment Variables
108
+ ```bash
109
+ export COAIAN_MF=./my-charts.jsonl
110
+ export COAIAV_PORT=3001
111
+ node dist/cli.js
112
+ ```
113
+
114
+ ### No Auto-Open
115
+ ```bash
116
+ node dist/cli.js --memory-path ./charts.jsonl --no-open
117
+ ```
118
+
119
+ ## API Endpoints
120
+
121
+ ### GET /api/jsonl
122
+ Returns file content from `COAIAV_MEMORY_PATH`:
123
+ ```json
124
+ {
125
+ "content": "...",
126
+ "filename": "memory.jsonl",
127
+ "path": "/absolute/path/to/memory.jsonl"
128
+ }
129
+ ```
130
+
131
+ ### POST /api/jsonl
132
+ Saves content to file:
133
+ ```json
134
+ Request: { "content": "..." }
135
+ Response: {
136
+ "success": true,
137
+ "backup": "/path/to/backup-123456.jsonl",
138
+ "message": "Memory file updated successfully"
139
+ }
140
+ ```
141
+
142
+ ## Testing
143
+
144
+ ### Integration Tests
145
+ ```bash
146
+ cd coaia-visualizer
147
+ bash feat-2-webui-local-editing/test-integration.sh
148
+ ```
149
+
150
+ Tests:
151
+ - ✓ CLI help output
152
+ - ✓ CLI builds successfully
153
+ - ✓ CLI is executable
154
+ - ✓ Test file exists
155
+ - ✓ Server starts correctly
156
+ - ✓ API endpoint works
157
+ - ✓ Homepage loads
158
+
159
+ ### Demo Script
160
+ ```bash
161
+ bash feat-2-webui-local-editing/demo.sh
162
+ ```
163
+
164
+ Interactive demo that:
165
+ - Starts server with test file
166
+ - Tests all endpoints
167
+ - Displays data stats
168
+ - Leaves server running for manual testing
169
+
170
+ ## Key Features
171
+
172
+ ### 1. Auto-Loading
173
+ - If `COAIAV_MEMORY_PATH` is set, file auto-loads on page mount
174
+ - Shows filename in header
175
+ - Enables save/reload functionality
176
+
177
+ ### 2. Backup System
178
+ - Every save creates timestamped backup
179
+ - Format: `{filename}.backup-{timestamp}`
180
+ - Prevents accidental data loss
181
+
182
+ ### 3. User Feedback
183
+ - Toast notifications for all operations
184
+ - Loading states on buttons
185
+ - Error messages with details
186
+
187
+ ### 4. Flexible Configuration
188
+ - Works like coaia-narrative/cli.ts
189
+ - Same flags and env vars
190
+ - Consistent user experience
191
+
192
+ ## Files in feat-2-webui-local-editing/
193
+
194
+ ```
195
+ feat-2-webui-local-editing/
196
+ ├── cli.ts # Original CLI source
197
+ ├── api-route-jsonl.ts # Original API route source
198
+ ├── updated-page.tsx # Original page.tsx source
199
+ ├── package.json # Reference package.json with changes
200
+ ├── test-integration.sh # Automated test script
201
+ ├── demo.sh # Interactive demo script
202
+ └── INTEGRATION.md # This documentation
203
+ ```
204
+
205
+ ## Integration with coaia-narrative
206
+
207
+ ### Shared Components
208
+ - Both use `--memory-path` / `-M` flag
209
+ - Both use `COAIAN_MF` environment variable
210
+ - Both read/write same JSONL format
211
+ - Compatible data structures
212
+
213
+ ### Workflow
214
+ 1. LLM creates charts via coaia-narrative MCP
215
+ 2. Human views with coaia-narrative CLI
216
+ 3. Human visualizes with coaia-visualizer
217
+ 4. Edit in web UI and save
218
+ 5. Verify with coaia-narrative CLI
219
+
220
+ ## Next Steps
221
+
222
+ To deploy as npm package:
223
+ ```bash
224
+ npm login
225
+ npm publish --access public
226
+ ```
227
+
228
+ To install globally:
229
+ ```bash
230
+ npm install -g @coaia/visualizer
231
+ coaia-visualizer --memory-path ./charts.jsonl
232
+ ```
233
+
234
+ ## Complete Implementation ✓
235
+
236
+ All requirements met:
237
+ - ✓ CLI launcher with --memory-path flag
238
+ - ✓ Environment variable support
239
+ - ✓ API routes for file read/write
240
+ - ✓ Auto-loading in web UI
241
+ - ✓ Save/reload functionality
242
+ - ✓ Backup system
243
+ - ✓ Works with coaia-narrative charts
244
+ - ✓ Analogous to coaia-narrative/cli.ts
245
+ - ✓ Tested and working