@prmichaelsen/acp-visualizer 0.1.4 → 0.1.6

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/bin/visualize.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { resolve, dirname } from 'path'
4
- import { existsSync, cpSync, mkdirSync, rmSync } from 'fs'
4
+ import { existsSync, cpSync, rmSync } from 'fs'
5
5
  import { fileURLToPath } from 'url'
6
6
  import { spawn } from 'child_process'
7
7
 
@@ -56,43 +56,37 @@ if (!existsSync(progressPath)) {
56
56
  process.exit(1)
57
57
  }
58
58
 
59
- // Strategy: copy source files into the node_modules root where deps
60
- // are hoisted. This gives vite a project root with node_modules as a
61
- // direct child, so ESM resolution works correctly for TanStack Start's
62
- // virtual modules.
63
-
59
+ // Find the directory that contains node_modules with vite installed.
60
+ // When run via npx, deps are hoisted to ~/.npm/_npx/xxx/node_modules/
64
61
  function findNodeModulesRoot() {
65
62
  let dir = packageRoot
66
63
  while (dir !== '/') {
67
- const candidate = resolve(dir, 'node_modules')
68
- if (existsSync(resolve(candidate, '.bin', 'vite'))) return dir
64
+ if (existsSync(resolve(dir, 'node_modules', '.bin', 'vite'))) return dir
69
65
  dir = resolve(dir, '..')
70
66
  }
71
67
  return packageRoot
72
68
  }
73
69
 
74
70
  const nmRoot = findNodeModulesRoot()
75
- const workDir = resolve(nmRoot, '.acp-visualizer-app')
76
-
77
- // Copy source files into workDir (small~60KB)
78
- rmSync(workDir, { recursive: true, force: true })
79
- mkdirSync(workDir, { recursive: true })
80
- cpSync(resolve(packageRoot, 'src'), resolve(workDir, 'src'), { recursive: true })
81
- cpSync(resolve(packageRoot, 'vite.config.ts'), resolve(workDir, 'vite.config.ts'))
82
- cpSync(resolve(packageRoot, 'tsconfig.json'), resolve(workDir, 'tsconfig.json'))
83
- cpSync(resolve(packageRoot, 'package.json'), resolve(workDir, 'package.json'))
84
-
85
- // Symlink the existing node_modules into the workdir
86
- // (they're one level up, so ../node_modules)
87
- const existingNM = resolve(nmRoot, 'node_modules')
88
- const targetNM = resolve(workDir, 'node_modules')
89
- if (!existsSync(targetNM)) {
90
- const { symlinkSync } = await import('fs')
91
- symlinkSync(existingNM, targetNM)
71
+
72
+ // Copy source files directly into nmRoot (the dir that already has
73
+ // node_modules/ as a direct child). No symlinks vite gets a real
74
+ // project root with real node_modules, so ESM resolution works.
75
+ const filesToCopy = ['src', 'vite.config.ts', 'tsconfig.json', 'package.json']
76
+ const copied = []
77
+
78
+ for (const f of filesToCopy) {
79
+ const src = resolve(packageRoot, f)
80
+ const dest = resolve(nmRoot, f)
81
+ if (src === dest) continue // already in the right place (local dev)
82
+ cpSync(src, dest, { recursive: true })
83
+ copied.push(dest)
92
84
  }
93
85
 
94
86
  function cleanup() {
95
- try { rmSync(workDir, { recursive: true, force: true }) } catch { /* best effort */ }
87
+ for (const f of copied) {
88
+ try { rmSync(f, { recursive: true, force: true }) } catch { /* best effort */ }
89
+ }
96
90
  }
97
91
  process.on('exit', cleanup)
98
92
  process.on('SIGINT', () => { cleanup(); process.exit(130) })
@@ -102,10 +96,10 @@ console.log(`\n ACP Progress Visualizer`)
102
96
  console.log(` Loading: ${progressPath}`)
103
97
  console.log(` Port: ${port}\n`)
104
98
 
105
- const viteBin = resolve(workDir, 'node_modules', '.bin', 'vite')
99
+ const viteBin = resolve(nmRoot, 'node_modules', '.bin', 'vite')
106
100
 
107
101
  const child = spawn(viteBin, ['dev', '--port', port, '--host'], {
108
- cwd: workDir,
102
+ cwd: nmRoot,
109
103
  stdio: 'inherit',
110
104
  env: {
111
105
  ...process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/acp-visualizer",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "Browser-based dashboard for visualizing ACP progress.yaml data",
6
6
  "bin": {
@@ -1,6 +1,3 @@
1
- import { watch } from 'fs'
2
- import { getProgressYamlPath } from './config'
3
-
4
1
  type Controller = ReadableStreamDefaultController
5
2
 
6
3
  let watcher: {
@@ -8,9 +5,12 @@ let watcher: {
8
5
  removeClient: (controller: Controller) => void
9
6
  } | null = null
10
7
 
11
- export function getFileWatcher() {
8
+ export async function getFileWatcher() {
12
9
  if (watcher) return watcher
13
10
 
11
+ const { watch } = await import('fs')
12
+ const { getProgressYamlPath } = await import('./config')
13
+
14
14
  const filePath = getProgressYamlPath()
15
15
  const clients = new Set<Controller>()
16
16
 
@@ -2,7 +2,7 @@ import { HeadContent, Scripts, createRootRoute, Outlet } from '@tanstack/react-r
2
2
  import { useAutoRefresh } from '../lib/useAutoRefresh'
3
3
  import { Sidebar } from '../components/Sidebar'
4
4
  import { Header } from '../components/Header'
5
- import { ProgressDatabaseService } from '../services/progress-database.service'
5
+ import { getProgressData } from '../services/progress-database.service'
6
6
  import type { ProgressData } from '../lib/types'
7
7
 
8
8
  import appCss from '../styles.css?url'
@@ -12,7 +12,7 @@ export const Route = createRootRoute({
12
12
  let progressData: ProgressData | null = null
13
13
 
14
14
  try {
15
- const result = ProgressDatabaseService.getProgressData()
15
+ const result = await getProgressData()
16
16
  if (result.ok) {
17
17
  progressData = result.data
18
18
  }
@@ -5,7 +5,7 @@ export const Route = createFileRoute('/api/watch')({
5
5
  server: {
6
6
  handlers: {
7
7
  GET: async () => {
8
- const watcher = getFileWatcher()
8
+ const watcher = await getFileWatcher()
9
9
 
10
10
  const stream = new ReadableStream({
11
11
  start(controller) {
@@ -1,14 +1,17 @@
1
- import { readFileSync } from 'fs'
2
- import { parseProgressYaml } from '../lib/yaml-loader'
3
- import { getProgressYamlPath } from '../lib/config'
1
+ import { createServerFn } from '@tanstack/react-start'
4
2
  import type { ProgressData } from '../lib/types'
5
3
 
6
4
  export type ProgressResult =
7
5
  | { ok: true; data: ProgressData }
8
6
  | { ok: false; error: 'FILE_NOT_FOUND' | 'PARSE_ERROR'; message: string; path: string }
9
7
 
10
- export class ProgressDatabaseService {
11
- static getProgressData(): ProgressResult {
8
+ export const getProgressData = createServerFn({ method: 'GET' }).handler(
9
+ async (): Promise<ProgressResult> => {
10
+ // Dynamic imports keep fs and yaml-loader out of the client bundle
11
+ const { readFileSync } = await import('fs')
12
+ const { parseProgressYaml } = await import('../lib/yaml-loader')
13
+ const { getProgressYamlPath } = await import('../lib/config')
14
+
12
15
  const filePath = getProgressYamlPath()
13
16
 
14
17
  try {
@@ -42,5 +45,5 @@ export class ProgressDatabaseService {
42
45
  path: filePath,
43
46
  }
44
47
  }
45
- }
46
- }
48
+ },
49
+ )