@luutuankiet/gsd-reader 0.2.0 → 0.2.2

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 (54) hide show
  1. package/cli.cjs +397 -161
  2. package/dist/assets/{_baseUniq-Bdn1nEwY.js → _baseUniq-BoX3bm5w.js} +1 -1
  3. package/dist/assets/{arc-fh_JU-kD.js → arc-C0lx088P.js} +1 -1
  4. package/dist/assets/{architectureDiagram-VXUJARFQ-ta8hDWLU.js → architectureDiagram-VXUJARFQ-YpNalIZk.js} +1 -1
  5. package/dist/assets/{blockDiagram-VD42YOAC-fp46vVEh.js → blockDiagram-VD42YOAC-CXKllpML.js} +1 -1
  6. package/dist/assets/{c4Diagram-YG6GDRKO-CIUWbITm.js → c4Diagram-YG6GDRKO-DCxSB21X.js} +1 -1
  7. package/dist/assets/channel-CAGH0dgh.js +1 -0
  8. package/dist/assets/{chunk-4BX2VUAB-CiUTh5Wr.js → chunk-4BX2VUAB-ClhgmvDA.js} +1 -1
  9. package/dist/assets/{chunk-55IACEB6-C0yEKdQa.js → chunk-55IACEB6-C24qY1hl.js} +1 -1
  10. package/dist/assets/{chunk-B4BG7PRW-Dph3sajP.js → chunk-B4BG7PRW-Dyh1KhI-.js} +1 -1
  11. package/dist/assets/{chunk-DI55MBZ5-aBYeKGnn.js → chunk-DI55MBZ5-CDqhGSTY.js} +1 -1
  12. package/dist/assets/{chunk-FMBD7UC4-CEhTzqEH.js → chunk-FMBD7UC4-VSH_CFfS.js} +1 -1
  13. package/dist/assets/{chunk-QN33PNHL-BHk7wgpN.js → chunk-QN33PNHL-PwRjDlN2.js} +1 -1
  14. package/dist/assets/{chunk-QZHKN3VN-CXgpYl35.js → chunk-QZHKN3VN-CPbvfzxy.js} +1 -1
  15. package/dist/assets/{chunk-TZMSLE5B-xFTTLJ9z.js → chunk-TZMSLE5B-CwrDL52U.js} +1 -1
  16. package/dist/assets/classDiagram-2ON5EDUG-NoCB_md-.js +1 -0
  17. package/dist/assets/classDiagram-v2-WZHVMYZB-NoCB_md-.js +1 -0
  18. package/dist/assets/clone-BukO2uK0.js +1 -0
  19. package/dist/assets/{cose-bilkent-S5V4N54A-DgvLJE5H.js → cose-bilkent-S5V4N54A-bAiW22vg.js} +1 -1
  20. package/dist/assets/{dagre-6UL2VRFP-D53BTNxD.js → dagre-6UL2VRFP-Cth_y_q3.js} +1 -1
  21. package/dist/assets/{diagram-PSM6KHXK-DXqmMUqU.js → diagram-PSM6KHXK-CTjjFoWw.js} +1 -1
  22. package/dist/assets/{diagram-QEK2KX5R-CLeMobu4.js → diagram-QEK2KX5R-CBoE2mxn.js} +1 -1
  23. package/dist/assets/{diagram-S2PKOQOG-D66o9MAr.js → diagram-S2PKOQOG-BiiPiXtH.js} +1 -1
  24. package/dist/assets/{erDiagram-Q2GNP2WA-CpJD1kMO.js → erDiagram-Q2GNP2WA-dYw1euHt.js} +1 -1
  25. package/dist/assets/{flowDiagram-NV44I4VS-CbFkeHvb.js → flowDiagram-NV44I4VS-Chnra_j4.js} +1 -1
  26. package/dist/assets/{ganttDiagram-JELNMOA3-3fTl17JM.js → ganttDiagram-JELNMOA3-ChCjAt-3.js} +1 -1
  27. package/dist/assets/{gitGraphDiagram-NY62KEGX-CIJK1HZz.js → gitGraphDiagram-NY62KEGX-CcseaZvf.js} +1 -1
  28. package/dist/assets/{graph-WCuwHVe9.js → graph-B6dSeZct.js} +1 -1
  29. package/dist/assets/{index-4oweX4fz.js → index-CLg7WJ1_.js} +24 -24
  30. package/dist/assets/{infoDiagram-WHAUD3N6-CvZ908oi.js → infoDiagram-WHAUD3N6-BxdtzpC1.js} +1 -1
  31. package/dist/assets/{journeyDiagram-XKPGCS4Q-BSwShGBk.js → journeyDiagram-XKPGCS4Q-KPZ5zBD4.js} +1 -1
  32. package/dist/assets/{kanban-definition-3W4ZIXB7-B0M4IroL.js → kanban-definition-3W4ZIXB7-BlA7DZuW.js} +1 -1
  33. package/dist/assets/{layout-BCTNMp28.js → layout-CSqTBUrd.js} +1 -1
  34. package/dist/assets/{linear-Bd-Gzgwq.js → linear-DkmUnIE_.js} +1 -1
  35. package/dist/assets/{mermaid.core-CWefC7Oh.js → mermaid.core-BqsnOxD3.js} +4 -4
  36. package/dist/assets/{min-CLuzHP9M.js → min-6O5YHLP4.js} +1 -1
  37. package/dist/assets/{mindmap-definition-VGOIOE7T-Cs-LAQ4V.js → mindmap-definition-VGOIOE7T-BuvvyRmn.js} +1 -1
  38. package/dist/assets/{pieDiagram-ADFJNKIX-CfEaM9L4.js → pieDiagram-ADFJNKIX-Bxoi-P0Q.js} +1 -1
  39. package/dist/assets/{quadrantDiagram-AYHSOK5B-C1eE_1Yq.js → quadrantDiagram-AYHSOK5B-CkgTCT3k.js} +1 -1
  40. package/dist/assets/{requirementDiagram-UZGBJVZJ-Mu-sTVKg.js → requirementDiagram-UZGBJVZJ-CNoPrxAF.js} +1 -1
  41. package/dist/assets/{sankeyDiagram-TZEHDZUN-Ls72W3Pm.js → sankeyDiagram-TZEHDZUN-BGwSQ9ZU.js} +1 -1
  42. package/dist/assets/{sequenceDiagram-WL72ISMW-CV9T-ld3.js → sequenceDiagram-WL72ISMW-LXHKLowS.js} +1 -1
  43. package/dist/assets/{stateDiagram-FKZM4ZOC-B_2WH-Ns.js → stateDiagram-FKZM4ZOC-DzfC5mDh.js} +1 -1
  44. package/dist/assets/stateDiagram-v2-4FDKWEC3-BTQdaR-q.js +1 -0
  45. package/dist/assets/{timeline-definition-IT6M3QCI-CGg3mPtB.js → timeline-definition-IT6M3QCI-lSHctkCL.js} +1 -1
  46. package/dist/assets/{treemap-KMMF4GRG-D84Z6fq0.js → treemap-KMMF4GRG-sesRCln1.js} +1 -1
  47. package/dist/assets/{xychartDiagram-PRI3JC2R-EVzJiOor.js → xychartDiagram-PRI3JC2R-3LkBFcTG.js} +1 -1
  48. package/dist/index.html +1 -1
  49. package/package.json +2 -1
  50. package/dist/assets/channel-BSNpO1uu.js +0 -1
  51. package/dist/assets/classDiagram-2ON5EDUG-DUftwofz.js +0 -1
  52. package/dist/assets/classDiagram-v2-WZHVMYZB-DUftwofz.js +0 -1
  53. package/dist/assets/clone-fKP9fCWC.js +0 -1
  54. package/dist/assets/stateDiagram-v2-4FDKWEC3-Cvx1tTX1.js +0 -1
package/cli.cjs CHANGED
@@ -3,213 +3,449 @@
3
3
  /**
4
4
  * GSD-Lite Worklog Reader CLI
5
5
  *
6
- * A lightweight server for viewing WORK.md files with live reload.
7
- * Uses chokidar for native file watching and WebSocket for push updates.
8
- *
9
- * Usage:
10
- * npx @gsd-lite/reader [path-to-worklog] [--port=3000]
6
+ * Commands:
7
+ * serve [path] [--port=3000] Start live-reload server (default)
8
+ * dump [path] --remote=URL Build and upload to remote server
11
9
  *
12
10
  * Examples:
13
- * npx @gsd-lite/reader # Watch ./gsd-lite/WORK.md on :3000
14
- * npx @gsd-lite/reader ./my-project/WORK.md # Custom path
15
- * npx @gsd-lite/reader --port=3001 # Custom port
11
+ * npx @luutuankiet/gsd-reader # Serve ./gsd-lite/WORK.md on :3000
12
+ * npx @luutuankiet/gsd-reader serve ./project/WORK.md # Serve custom path
13
+ * npx @luutuankiet/gsd-reader dump --remote=https://gsd.kenluu.org --user=ken
16
14
  */
17
15
 
18
16
  const http = require('http');
17
+ const https = require('https');
19
18
  const fs = require('fs');
20
19
  const path = require('path');
21
20
  const { WebSocketServer } = require('ws');
22
21
  const chokidar = require('chokidar');
22
+ const { execSync } = require('child_process');
23
+ const zlib = require('zlib');
24
+ const tar = require('tar');
25
+ const readline = require('readline');
23
26
 
24
27
  // =============================================================================
25
- // Configuration
28
+ // Argument Parsing
26
29
  // =============================================================================
27
30
 
28
- // Parse command line arguments
29
31
  const args = process.argv.slice(2);
32
+ const command = args[0] && !args[0].startsWith('--') && !args[0].includes('/') && !args[0].endsWith('.md')
33
+ ? args[0]
34
+ : 'serve';
35
+
36
+ // Extract flags
37
+ function getFlag(name) {
38
+ const arg = args.find(a => a.startsWith(`--${name}=`));
39
+ return arg?.split('=')[1];
40
+ }
30
41
 
31
- // Find port from --port=XXXX argument
32
- const portArg = args.find(a => a.startsWith('--port='));
33
- const PORT = parseInt(portArg?.split('=')[1] || process.env.PORT || '3000', 10);
34
-
35
- // First non-flag argument is the worklog path
36
- const WORKLOG = args.find(a => !a.startsWith('--')) || './gsd-lite/WORK.md';
37
- const WORKLOG_PATH = path.resolve(WORKLOG);
38
-
39
- // Static assets directory (bundled with this package)
40
- const DIST = path.join(__dirname, 'dist');
41
-
42
- // MIME types for static file serving
43
- const MIME_TYPES = {
44
- '.html': 'text/html',
45
- '.js': 'application/javascript',
46
- '.css': 'text/css',
47
- '.json': 'application/json',
48
- '.png': 'image/png',
49
- '.jpg': 'image/jpeg',
50
- '.gif': 'image/gif',
51
- '.svg': 'image/svg+xml',
52
- '.ico': 'image/x-icon',
53
- '.woff': 'font/woff',
54
- '.woff2': 'font/woff2',
55
- '.ttf': 'font/ttf',
56
- };
42
+ function hasFlag(name) {
43
+ return args.includes(`--${name}`);
44
+ }
45
+
46
+ // Find non-flag arguments (excluding command)
47
+ const positionalArgs = args.filter(a => !a.startsWith('--') && a !== command);
57
48
 
58
49
  // =============================================================================
59
- // HTTP Server
50
+ // Command: dump
60
51
  // =============================================================================
61
52
 
62
- const server = http.createServer((req, res) => {
63
- const url = new URL(req.url, `http://${req.headers.host}`);
64
- const pathname = url.pathname;
65
-
66
- // API endpoint: serve WORK.md content
67
- if (pathname === '/_worklog') {
68
- try {
69
- const content = fs.readFileSync(WORKLOG_PATH, 'utf-8');
70
- res.setHeader('Content-Type', 'text/plain; charset=utf-8');
71
- res.setHeader('Cache-Control', 'no-cache');
72
- res.end(content);
73
- } catch (err) {
74
- res.statusCode = 404;
75
- res.setHeader('Content-Type', 'text/plain');
76
- res.end(`WORK.md not found: ${WORKLOG_PATH}\n\nError: ${err.message}`);
77
- }
78
- return;
53
+ async function commandDump() {
54
+ const worklogPath = positionalArgs[0] || './gsd-lite/WORK.md';
55
+ const remote = getFlag('remote');
56
+ const user = getFlag('user');
57
+
58
+ if (!remote) {
59
+ console.error('❌ --remote=URL is required');
60
+ console.error('\nUsage: npx @luutuankiet/gsd-reader dump [path] --remote=URL --user=USER');
61
+ console.error('\nExample:');
62
+ console.error(' npx @luutuankiet/gsd-reader dump --remote=https://gsd.kenluu.org --user=ken');
63
+ process.exit(1);
79
64
  }
80
65
 
81
- // Static file serving from dist/
82
- let filePath = pathname === '/' ? '/index.html' : pathname;
83
- const fullPath = path.join(DIST, filePath);
66
+ // Resolve paths
67
+ const resolvedWorklog = path.resolve(worklogPath);
68
+ const projectDir = path.dirname(resolvedWorklog);
69
+
70
+ // Derive project name from path (last 2 segments)
71
+ const pathParts = projectDir.split(path.sep).filter(Boolean);
72
+ const projectName = pathParts.slice(-2).join('/');
73
+
74
+ console.log('');
75
+ console.log('┌─────────────────────────────────────────────────────┐');
76
+ console.log('│ 📤 GSD-Lite Worklog Dump │');
77
+ console.log('├─────────────────────────────────────────────────────┤');
78
+ console.log(`│ Worklog: ${path.basename(resolvedWorklog).padEnd(40)}│`);
79
+ console.log(`│ Project: ${projectName.padEnd(40)}│`);
80
+ console.log(`│ Remote: ${remote.padEnd(40)}│`);
81
+ console.log('└─────────────────────────────────────────────────────┘');
82
+ console.log('');
84
83
 
85
- // Security: prevent directory traversal
86
- if (!fullPath.startsWith(DIST)) {
87
- res.statusCode = 403;
88
- res.end('Forbidden');
89
- return;
84
+ // Check if worklog exists
85
+ if (!fs.existsSync(resolvedWorklog)) {
86
+ console.error(`❌ WORK.md not found: ${resolvedWorklog}`);
87
+ process.exit(1);
90
88
  }
91
89
 
92
- // Check if file exists
93
- if (!fs.existsSync(fullPath)) {
94
- // SPA fallback: serve index.html for non-file routes
95
- const indexPath = path.join(DIST, 'index.html');
96
- if (fs.existsSync(indexPath)) {
97
- serveFile(indexPath, '.html', res);
98
- return;
99
- }
100
- res.statusCode = 404;
101
- res.end('Not found');
102
- return;
103
- }
90
+ // Step 1: Build the static site
91
+ console.log('[dump] Building static site...');
92
+ const distDir = path.join(__dirname, 'dist');
93
+
94
+ // Copy dist to temp directory and inject worklog content
95
+ const tempDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'gsd-dump-'));
96
+ const tempDist = path.join(tempDir, 'dist');
97
+
98
+ // Copy dist directory
99
+ fs.cpSync(distDir, tempDist, { recursive: true });
100
+
101
+ // Read worklog and inject into HTML
102
+ const worklogContent = fs.readFileSync(resolvedWorklog, 'utf-8');
103
+ const indexPath = path.join(tempDist, 'index.html');
104
+ let indexHtml = fs.readFileSync(indexPath, 'utf-8');
105
+
106
+ // Fix asset paths: Vite builds with absolute paths (/assets/...) but we need
107
+ // relative paths (./assets/...) when served from subdirectories
108
+ indexHtml = indexHtml.replace(/href="\//g, 'href="./');
109
+ indexHtml = indexHtml.replace(/src="\//g, 'src="./');
110
+
111
+ // Inject worklog content as a script tag (the app will read this instead of fetching)
112
+ // Use Base64 encoding to avoid any escaping issues with special characters,
113
+ // </script> sequences, or line breaks in the markdown content
114
+ const base64Content = Buffer.from(worklogContent, 'utf-8').toString('base64');
115
+ const injectScript = `<script>window.__WORKLOG_CONTENT_B64__ = "${base64Content}";</script>`;
116
+ indexHtml = indexHtml.replace('</head>', `${injectScript}\n</head>`);
117
+ fs.writeFileSync(indexPath, indexHtml);
118
+
119
+ console.log(`[dump] Static site prepared in ${tempDist}`);
120
+
121
+ // Step 2: Create tar.gz
122
+ console.log('[dump] Creating archive...');
123
+ const tarPath = path.join(tempDir, 'dist.tar.gz');
124
+
125
+ await tar.create(
126
+ {
127
+ gzip: true,
128
+ file: tarPath,
129
+ cwd: tempDist,
130
+ },
131
+ fs.readdirSync(tempDist)
132
+ );
133
+
134
+ const tarStats = fs.statSync(tarPath);
135
+ console.log(`[dump] Archive created: ${(tarStats.size / 1024).toFixed(1)} KB`);
104
136
 
105
- // Serve the file
106
- const ext = path.extname(fullPath).toLowerCase();
107
- serveFile(fullPath, ext, res);
108
- });
137
+ // Step 3: Get password
138
+ let password = getFlag('pass');
139
+ if (!password && user) {
140
+ password = await promptPassword(`Password for ${user}: `);
141
+ }
109
142
 
110
- function serveFile(filePath, ext, res) {
111
- const mimeType = MIME_TYPES[ext] || 'application/octet-stream';
143
+ // Step 4: Upload to remote
144
+ console.log(`[dump] Uploading to ${remote}/upload/${projectName}...`);
145
+
146
+ const tarData = fs.readFileSync(tarPath);
147
+ const uploadUrl = new URL(`/upload/${projectName}`, remote);
112
148
 
149
+ const uploadOptions = {
150
+ method: 'POST',
151
+ headers: {
152
+ 'Content-Type': 'application/gzip',
153
+ 'Content-Length': tarData.length,
154
+ },
155
+ };
156
+
157
+ // Add basic auth if credentials provided
158
+ if (user && password) {
159
+ const auth = Buffer.from(`${user}:${password}`).toString('base64');
160
+ uploadOptions.headers['Authorization'] = `Basic ${auth}`;
161
+ }
162
+
113
163
  try {
114
- const content = fs.readFileSync(filePath);
115
- res.setHeader('Content-Type', mimeType);
116
- res.setHeader('Cache-Control', 'public, max-age=3600');
117
- res.end(content);
164
+ const response = await httpRequest(uploadUrl, uploadOptions, tarData);
165
+ console.log(`[dump] ✅ Upload complete: ${response}`);
166
+ console.log(`[dump] View at: ${remote}/${projectName}/`);
118
167
  } catch (err) {
119
- res.statusCode = 500;
120
- res.end(`Error reading file: ${err.message}`);
168
+ console.error(`[dump] Upload failed: ${err.message}`);
169
+ process.exit(1);
170
+ } finally {
171
+ // Cleanup
172
+ fs.rmSync(tempDir, { recursive: true, force: true });
121
173
  }
122
174
  }
123
175
 
176
+ function promptPassword(prompt) {
177
+ return new Promise((resolve) => {
178
+ const rl = readline.createInterface({
179
+ input: process.stdin,
180
+ output: process.stdout,
181
+ });
182
+
183
+ // Hide input (works on most terminals)
184
+ process.stdout.write(prompt);
185
+
186
+ // For password masking, we need to handle raw mode
187
+ if (process.stdin.isTTY) {
188
+ process.stdin.setRawMode(true);
189
+ }
190
+
191
+ let password = '';
192
+
193
+ process.stdin.on('data', (char) => {
194
+ char = char.toString();
195
+
196
+ switch (char) {
197
+ case '\n':
198
+ case '\r':
199
+ case '\u0004': // Ctrl+D
200
+ if (process.stdin.isTTY) {
201
+ process.stdin.setRawMode(false);
202
+ }
203
+ process.stdout.write('\n');
204
+ rl.close();
205
+ resolve(password);
206
+ break;
207
+ case '\u0003': // Ctrl+C
208
+ process.exit(1);
209
+ break;
210
+ case '\u007F': // Backspace
211
+ password = password.slice(0, -1);
212
+ break;
213
+ default:
214
+ password += char;
215
+ break;
216
+ }
217
+ });
218
+ });
219
+ }
220
+
221
+ function httpRequest(url, options, data) {
222
+ return new Promise((resolve, reject) => {
223
+ const protocol = url.protocol === 'https:' ? https : http;
224
+
225
+ const req = protocol.request(url, options, (res) => {
226
+ let body = '';
227
+ res.on('data', (chunk) => body += chunk);
228
+ res.on('end', () => {
229
+ if (res.statusCode >= 200 && res.statusCode < 300) {
230
+ resolve(body.trim() || `HTTP ${res.statusCode}`);
231
+ } else if (res.statusCode === 401) {
232
+ reject(new Error('Authentication failed (401). Check username/password.'));
233
+ } else {
234
+ reject(new Error(`HTTP ${res.statusCode}: ${body}`));
235
+ }
236
+ });
237
+ });
238
+
239
+ req.on('error', reject);
240
+ req.write(data);
241
+ req.end();
242
+ });
243
+ }
244
+
124
245
  // =============================================================================
125
- // WebSocket Server (Live Reload)
246
+ // Command: serve (default)
126
247
  // =============================================================================
127
248
 
128
- const wss = new WebSocketServer({ server });
249
+ function commandServe() {
250
+ // Parse serve-specific arguments
251
+ const portArg = getFlag('port');
252
+ const PORT = parseInt(portArg || process.env.PORT || '3000', 10);
253
+ const WORKLOG = positionalArgs[0] || './gsd-lite/WORK.md';
254
+ const WORKLOG_PATH = path.resolve(WORKLOG);
129
255
 
130
- wss.on('connection', (ws) => {
131
- console.log('[gsd-reader] Client connected');
132
-
133
- ws.on('close', () => {
134
- console.log('[gsd-reader] Client disconnected');
256
+ // Static assets directory (bundled with this package)
257
+ const DIST = path.join(__dirname, 'dist');
258
+
259
+ // MIME types for static file serving
260
+ const MIME_TYPES = {
261
+ '.html': 'text/html',
262
+ '.js': 'application/javascript',
263
+ '.css': 'text/css',
264
+ '.json': 'application/json',
265
+ '.png': 'image/png',
266
+ '.jpg': 'image/jpeg',
267
+ '.gif': 'image/gif',
268
+ '.svg': 'image/svg+xml',
269
+ '.ico': 'image/x-icon',
270
+ '.woff': 'font/woff',
271
+ '.woff2': 'font/woff2',
272
+ '.ttf': 'font/ttf',
273
+ };
274
+
275
+ // HTTP Server
276
+ const server = http.createServer((req, res) => {
277
+ const url = new URL(req.url, `http://${req.headers.host}`);
278
+ const pathname = url.pathname;
279
+
280
+ // API endpoint: serve WORK.md content
281
+ if (pathname === '/_worklog') {
282
+ try {
283
+ const content = fs.readFileSync(WORKLOG_PATH, 'utf-8');
284
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
285
+ res.setHeader('Cache-Control', 'no-cache');
286
+ res.end(content);
287
+ } catch (err) {
288
+ res.statusCode = 404;
289
+ res.setHeader('Content-Type', 'text/plain');
290
+ res.end(`WORK.md not found: ${WORKLOG_PATH}\n\nError: ${err.message}`);
291
+ }
292
+ return;
293
+ }
294
+
295
+ // Static file serving from dist/
296
+ let filePath = pathname === '/' ? '/index.html' : pathname;
297
+ const fullPath = path.join(DIST, filePath);
298
+
299
+ // Security: prevent directory traversal
300
+ if (!fullPath.startsWith(DIST)) {
301
+ res.statusCode = 403;
302
+ res.end('Forbidden');
303
+ return;
304
+ }
305
+
306
+ // Check if file exists
307
+ if (!fs.existsSync(fullPath)) {
308
+ // SPA fallback: serve index.html for non-file routes
309
+ const indexPath = path.join(DIST, 'index.html');
310
+ if (fs.existsSync(indexPath)) {
311
+ serveFile(indexPath, '.html', res, MIME_TYPES);
312
+ return;
313
+ }
314
+ res.statusCode = 404;
315
+ res.end('Not found');
316
+ return;
317
+ }
318
+
319
+ // Serve the file
320
+ const ext = path.extname(fullPath).toLowerCase();
321
+ serveFile(fullPath, ext, res, MIME_TYPES);
135
322
  });
136
- });
137
-
138
- function broadcastReload() {
139
- let clientCount = 0;
140
- wss.clients.forEach((client) => {
141
- if (client.readyState === 1) { // WebSocket.OPEN
142
- client.send('reload');
143
- clientCount++;
323
+
324
+ function serveFile(filePath, ext, res, mimeTypes) {
325
+ const mimeType = mimeTypes[ext] || 'application/octet-stream';
326
+
327
+ try {
328
+ const content = fs.readFileSync(filePath);
329
+ res.setHeader('Content-Type', mimeType);
330
+ res.setHeader('Cache-Control', 'public, max-age=3600');
331
+ res.end(content);
332
+ } catch (err) {
333
+ res.statusCode = 500;
334
+ res.end(`Error reading file: ${err.message}`);
144
335
  }
336
+ }
337
+
338
+ // WebSocket Server (Live Reload)
339
+ const wss = new WebSocketServer({ server });
340
+
341
+ wss.on('connection', (ws) => {
342
+ console.log('[gsd-reader] Client connected');
343
+
344
+ ws.on('close', () => {
345
+ console.log('[gsd-reader] Client disconnected');
346
+ });
145
347
  });
146
- if (clientCount > 0) {
147
- console.log(`[gsd-reader] Notified ${clientCount} client(s)`);
348
+
349
+ function broadcastReload() {
350
+ let clientCount = 0;
351
+ wss.clients.forEach((client) => {
352
+ if (client.readyState === 1) { // WebSocket.OPEN
353
+ client.send('reload');
354
+ clientCount++;
355
+ }
356
+ });
357
+ if (clientCount > 0) {
358
+ console.log(`[gsd-reader] Notified ${clientCount} client(s)`);
359
+ }
148
360
  }
149
- }
150
361
 
151
- // =============================================================================
152
- // File Watcher (Chokidar)
153
- // =============================================================================
362
+ // Check if worklog exists before starting
363
+ if (!fs.existsSync(WORKLOG_PATH)) {
364
+ console.error(`\n❌ WORK.md not found: ${WORKLOG_PATH}`);
365
+ console.error('\nUsage: npx @luutuankiet/gsd-reader [serve] [path] [--port=3000]');
366
+ console.error('\nExamples:');
367
+ console.error(' npx @luutuankiet/gsd-reader # Watch ./gsd-lite/WORK.md');
368
+ console.error(' npx @luutuankiet/gsd-reader ./my-project/WORK.md # Custom path');
369
+ process.exit(1);
370
+ }
154
371
 
155
- // Check if worklog exists before starting
156
- if (!fs.existsSync(WORKLOG_PATH)) {
157
- console.error(`\n❌ WORK.md not found: ${WORKLOG_PATH}`);
158
- console.error('\nUsage: npx @gsd-lite/reader [path-to-worklog] [--port=3000]');
159
- console.error('\nExamples:');
160
- console.error(' npx @gsd-lite/reader # Watch ./gsd-lite/WORK.md');
161
- console.error(' npx @gsd-lite/reader ./my-project/WORK.md # Custom path');
162
- process.exit(1);
163
- }
372
+ // Watch the worklog file
373
+ const watcher = chokidar.watch(WORKLOG_PATH, {
374
+ persistent: true,
375
+ ignoreInitial: true,
376
+ awaitWriteFinish: {
377
+ stabilityThreshold: 100,
378
+ pollInterval: 50,
379
+ },
380
+ });
381
+
382
+ watcher.on('change', (filepath) => {
383
+ console.log(`[gsd-reader] ${path.basename(filepath)} changed`);
384
+ broadcastReload();
385
+ });
386
+
387
+ watcher.on('error', (error) => {
388
+ console.error('[gsd-reader] Watcher error:', error.message);
389
+ });
390
+
391
+ // Startup
392
+ server.listen(PORT, () => {
393
+ console.log('');
394
+ console.log('┌─────────────────────────────────────────────────────┐');
395
+ console.log('│ 📖 GSD-Lite Worklog Reader │');
396
+ console.log('├─────────────────────────────────────────────────────┤');
397
+ console.log(`│ Server: http://localhost:${PORT.toString().padEnd(25)}│`);
398
+ console.log(`│ Watching: ${path.basename(WORKLOG_PATH).padEnd(40)}│`);
399
+ console.log('├─────────────────────────────────────────────────────┤');
400
+ console.log('│ Press Ctrl+C to stop │');
401
+ console.log('└─────────────────────────────────────────────────────┘');
402
+ console.log('');
403
+ console.log(`[gsd-reader] Full path: ${WORKLOG_PATH}`);
404
+ });
164
405
 
165
- // Watch the worklog file
166
- const watcher = chokidar.watch(WORKLOG_PATH, {
167
- persistent: true,
168
- ignoreInitial: true,
169
- awaitWriteFinish: {
170
- stabilityThreshold: 100,
171
- pollInterval: 50,
172
- },
173
- });
174
-
175
- watcher.on('change', (filepath) => {
176
- console.log(`[gsd-reader] ${path.basename(filepath)} changed`);
177
- broadcastReload();
178
- });
179
-
180
- watcher.on('error', (error) => {
181
- console.error('[gsd-reader] Watcher error:', error.message);
182
- });
406
+ // Graceful shutdown
407
+ process.on('SIGINT', () => {
408
+ console.log('\n[gsd-reader] Shutting down...');
409
+ watcher.close();
410
+ wss.close();
411
+ server.close(() => {
412
+ console.log('[gsd-reader] Goodbye!');
413
+ process.exit(0);
414
+ });
415
+ });
416
+
417
+ process.on('SIGTERM', () => {
418
+ process.emit('SIGINT');
419
+ });
420
+ }
183
421
 
184
422
  // =============================================================================
185
- // Startup
423
+ // Main
186
424
  // =============================================================================
187
425
 
188
- server.listen(PORT, () => {
189
- console.log('');
190
- console.log('┌─────────────────────────────────────────────────────┐');
191
- console.log('│ 📖 GSD-Lite Worklog Reader │');
192
- console.log('├─────────────────────────────────────────────────────┤');
193
- console.log(`│ Server: http://localhost:${PORT.toString().padEnd(25)}│`);
194
- console.log(`│ Watching: ${path.basename(WORKLOG_PATH).padEnd(40)}│`);
195
- console.log('├─────────────────────────────────────────────────────┤');
196
- console.log('│ Press Ctrl+C to stop │');
197
- console.log('└─────────────────────────────────────────────────────┘');
198
- console.log('');
199
- console.log(`[gsd-reader] Full path: ${WORKLOG_PATH}`);
200
- });
201
-
202
- // Graceful shutdown
203
- process.on('SIGINT', () => {
204
- console.log('\n[gsd-reader] Shutting down...');
205
- watcher.close();
206
- wss.close();
207
- server.close(() => {
208
- console.log('[gsd-reader] Goodbye!');
209
- process.exit(0);
426
+ if (command === 'dump') {
427
+ commandDump().catch((err) => {
428
+ console.error('❌ Unexpected error:', err.message);
429
+ process.exit(1);
210
430
  });
211
- });
431
+ } else if (command === 'serve' || command === 'help' || command === '--help' || command === '-h') {
432
+ if (command === 'help' || command === '--help' || command === '-h') {
433
+ console.log(`
434
+ 📖 GSD-Lite Worklog Reader
435
+
436
+ Commands:
437
+ serve [path] [--port=3000] Start live-reload server (default)
438
+ dump [path] --remote=URL Build and upload to remote server
212
439
 
213
- process.on('SIGTERM', () => {
214
- process.emit('SIGINT');
215
- });
440
+ Examples:
441
+ npx @luutuankiet/gsd-reader # Serve ./gsd-lite/WORK.md
442
+ npx @luutuankiet/gsd-reader serve ./project/WORK.md # Serve custom path
443
+ npx @luutuankiet/gsd-reader dump --remote=https://gsd.kenluu.org --user=ken
444
+ `);
445
+ process.exit(0);
446
+ }
447
+ commandServe();
448
+ } else {
449
+ // Assume it's a path, not a command
450
+ commandServe();
451
+ }
@@ -1 +1 @@
1
- import{aU as L,bq as ln,aE as A,aS as P,aD as z,br as gn,bs as dn,bt as hn,bu as W,bv as pn,bl as An,bw as m,aV as N,a_ as U,b1 as T,bx as _n,aY as on,by as wn,bo as On,aF as V,bm as vn,bz as I}from"./mermaid.core-CWefC7Oh.js";var Pn="[object Symbol]";function x(n){return typeof n=="symbol"||L(n)&&ln(n)==Pn}function yn(n,r){for(var e=-1,i=n==null?0:n.length,f=Array(i);++e<i;)f[e]=r(n[e],e,n);return f}var B=P?P.prototype:void 0,K=B?B.toString:void 0;function k(n){if(typeof n=="string")return n;if(A(n))return yn(n,k)+"";if(x(n))return K?K.call(n):"";var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}function En(){}function bn(n,r){for(var e=-1,i=n==null?0:n.length;++e<i&&r(n[e],e,n)!==!1;);return n}function cn(n,r,e,i){for(var f=n.length,t=e+-1;++t<f;)if(r(n[t],t,n))return t;return-1}function Tn(n){return n!==n}function Rn(n,r,e){for(var i=e-1,f=n.length;++i<f;)if(n[i]===r)return i;return-1}function In(n,r,e){return r===r?Rn(n,r,e):cn(n,Tn,e)}function Sn(n,r){var e=n==null?0:n.length;return!!e&&In(n,r,0)>-1}function M(n){return z(n)?gn(n):dn(n)}var Ln=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,xn=/^\w*$/;function $(n,r){if(A(n))return!1;var e=typeof n;return e=="number"||e=="symbol"||e=="boolean"||n==null||x(n)?!0:xn.test(n)||!Ln.test(n)||r!=null&&n in Object(r)}var Mn=500;function $n(n){var r=hn(n,function(i){return e.size===Mn&&e.clear(),i}),e=r.cache;return r}var Cn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Dn=/\\(\\)?/g,Fn=$n(function(n){var r=[];return n.charCodeAt(0)===46&&r.push(""),n.replace(Cn,function(e,i,f,t){r.push(f?t.replace(Dn,"$1"):i||e)}),r});function Gn(n){return n==null?"":k(n)}function j(n,r){return A(n)?n:$(n,r)?[n]:Fn(Gn(n))}function R(n){if(typeof n=="string"||x(n))return n;var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}function nn(n,r){r=j(r,n);for(var e=0,i=r.length;n!=null&&e<i;)n=n[R(r[e++])];return e&&e==i?n:void 0}function mn(n,r,e){var i=n==null?void 0:nn(n,r);return i===void 0?e:i}function rn(n,r){for(var e=-1,i=r.length,f=n.length;++e<i;)n[f+e]=r[e];return n}var H=P?P.isConcatSpreadable:void 0;function Nn(n){return A(n)||W(n)||!!(H&&n&&n[H])}function Hr(n,r,e,i,f){var t=-1,s=n.length;for(e||(e=Nn),f||(f=[]);++t<s;){var u=n[t];e(u)?rn(f,u):i||(f[f.length]=u)}return f}function Un(n,r,e,i){var f=-1,t=n==null?0:n.length;for(i&&t&&(e=n[++f]);++f<t;)e=r(e,n[f],f,n);return e}function en(n,r){for(var e=-1,i=n==null?0:n.length,f=0,t=[];++e<i;){var s=n[e];r(s,e,n)&&(t[f++]=s)}return t}function Bn(){return[]}var Kn=Object.prototype,Hn=Kn.propertyIsEnumerable,q=Object.getOwnPropertySymbols,qn=q?function(n){return n==null?[]:(n=Object(n),en(q(n),function(r){return Hn.call(n,r)}))}:Bn;function Yn(n,r,e){var i=r(n);return A(n)?i:rn(i,e(n))}function Y(n){return Yn(n,M,qn)}var Zn="__lodash_hash_undefined__";function Xn(n){return this.__data__.set(n,Zn),this}function Jn(n){return this.__data__.has(n)}function y(n){var r=-1,e=n==null?0:n.length;for(this.__data__=new pn;++r<e;)this.add(n[r])}y.prototype.add=y.prototype.push=Xn;y.prototype.has=Jn;function Qn(n,r){for(var e=-1,i=n==null?0:n.length;++e<i;)if(r(n[e],e,n))return!0;return!1}function tn(n,r){return n.has(r)}var zn=1,Wn=2;function fn(n,r,e,i,f,t){var s=e&zn,u=n.length,a=r.length;if(u!=a&&!(s&&a>u))return!1;var h=t.get(n),g=t.get(r);if(h&&g)return h==r&&g==n;var l=-1,d=!0,o=e&Wn?new y:void 0;for(t.set(n,r),t.set(r,n);++l<u;){var p=n[l],_=r[l];if(i)var w=s?i(_,p,l,r,n,t):i(p,_,l,n,r,t);if(w!==void 0){if(w)continue;d=!1;break}if(o){if(!Qn(r,function(O,v){if(!tn(o,v)&&(p===O||f(p,O,e,i,t)))return o.push(v)})){d=!1;break}}else if(!(p===_||f(p,_,e,i,t))){d=!1;break}}return t.delete(n),t.delete(r),d}function Vn(n){var r=-1,e=Array(n.size);return n.forEach(function(i,f){e[++r]=[f,i]}),e}function C(n){var r=-1,e=Array(n.size);return n.forEach(function(i){e[++r]=i}),e}var kn=1,jn=2,nr="[object Boolean]",rr="[object Date]",er="[object Error]",ir="[object Map]",tr="[object Number]",fr="[object RegExp]",sr="[object Set]",ur="[object String]",ar="[object Symbol]",lr="[object ArrayBuffer]",gr="[object DataView]",Z=P?P.prototype:void 0,S=Z?Z.valueOf:void 0;function dr(n,r,e,i,f,t,s){switch(e){case gr:if(n.byteLength!=r.byteLength||n.byteOffset!=r.byteOffset)return!1;n=n.buffer,r=r.buffer;case lr:return!(n.byteLength!=r.byteLength||!t(new m(n),new m(r)));case nr:case rr:case tr:return An(+n,+r);case er:return n.name==r.name&&n.message==r.message;case fr:case ur:return n==r+"";case ir:var u=Vn;case sr:var a=i&kn;if(u||(u=C),n.size!=r.size&&!a)return!1;var h=s.get(n);if(h)return h==r;i|=jn,s.set(n,r);var g=fn(u(n),u(r),i,f,t,s);return s.delete(n),g;case ar:if(S)return S.call(n)==S.call(r)}return!1}var hr=1,pr=Object.prototype,Ar=pr.hasOwnProperty;function _r(n,r,e,i,f,t){var s=e&hr,u=Y(n),a=u.length,h=Y(r),g=h.length;if(a!=g&&!s)return!1;for(var l=a;l--;){var d=u[l];if(!(s?d in r:Ar.call(r,d)))return!1}var o=t.get(n),p=t.get(r);if(o&&p)return o==r&&p==n;var _=!0;t.set(n,r),t.set(r,n);for(var w=s;++l<a;){d=u[l];var O=n[d],v=r[d];if(i)var G=s?i(v,O,d,r,n,t):i(O,v,d,n,r,t);if(!(G===void 0?O===v||f(O,v,e,i,t):G)){_=!1;break}w||(w=d=="constructor")}if(_&&!w){var E=n.constructor,b=r.constructor;E!=b&&"constructor"in n&&"constructor"in r&&!(typeof E=="function"&&E instanceof E&&typeof b=="function"&&b instanceof b)&&(_=!1)}return t.delete(n),t.delete(r),_}var or=1,X="[object Arguments]",J="[object Array]",c="[object Object]",wr=Object.prototype,Q=wr.hasOwnProperty;function Or(n,r,e,i,f,t){var s=A(n),u=A(r),a=s?J:N(n),h=u?J:N(r);a=a==X?c:a,h=h==X?c:h;var g=a==c,l=h==c,d=a==h;if(d&&U(n)){if(!U(r))return!1;s=!0,g=!1}if(d&&!g)return t||(t=new T),s||_n(n)?fn(n,r,e,i,f,t):dr(n,r,a,e,i,f,t);if(!(e&or)){var o=g&&Q.call(n,"__wrapped__"),p=l&&Q.call(r,"__wrapped__");if(o||p){var _=o?n.value():n,w=p?r.value():r;return t||(t=new T),f(_,w,e,i,t)}}return d?(t||(t=new T),_r(n,r,e,i,f,t)):!1}function D(n,r,e,i,f){return n===r?!0:n==null||r==null||!L(n)&&!L(r)?n!==n&&r!==r:Or(n,r,e,i,D,f)}var vr=1,Pr=2;function yr(n,r,e,i){var f=e.length,t=f;if(n==null)return!t;for(n=Object(n);f--;){var s=e[f];if(s[2]?s[1]!==n[s[0]]:!(s[0]in n))return!1}for(;++f<t;){s=e[f];var u=s[0],a=n[u],h=s[1];if(s[2]){if(a===void 0&&!(u in n))return!1}else{var g=new T,l;if(!(l===void 0?D(h,a,vr|Pr,i,g):l))return!1}}return!0}function sn(n){return n===n&&!on(n)}function Er(n){for(var r=M(n),e=r.length;e--;){var i=r[e],f=n[i];r[e]=[i,f,sn(f)]}return r}function un(n,r){return function(e){return e==null?!1:e[n]===r&&(r!==void 0||n in Object(e))}}function br(n){var r=Er(n);return r.length==1&&r[0][2]?un(r[0][0],r[0][1]):function(e){return e===n||yr(e,n,r)}}function cr(n,r){return n!=null&&r in Object(n)}function Tr(n,r,e){r=j(r,n);for(var i=-1,f=r.length,t=!1;++i<f;){var s=R(r[i]);if(!(t=n!=null&&e(n,s)))break;n=n[s]}return t||++i!=f?t:(f=n==null?0:n.length,!!f&&wn(f)&&On(s,f)&&(A(n)||W(n)))}function Rr(n,r){return n!=null&&Tr(n,r,cr)}var Ir=1,Sr=2;function Lr(n,r){return $(n)&&sn(r)?un(R(n),r):function(e){var i=mn(e,n);return i===void 0&&i===r?Rr(e,n):D(r,i,Ir|Sr)}}function xr(n){return function(r){return r==null?void 0:r[n]}}function Mr(n){return function(r){return nn(r,n)}}function $r(n){return $(n)?xr(R(n)):Mr(n)}function an(n){return typeof n=="function"?n:n==null?V:typeof n=="object"?A(n)?Lr(n[0],n[1]):br(n):$r(n)}function Cr(n,r){return n&&vn(n,r,M)}function Dr(n,r){return function(e,i){if(e==null)return e;if(!z(e))return n(e,i);for(var f=e.length,t=-1,s=Object(e);++t<f&&i(s[t],t,s)!==!1;);return e}}var F=Dr(Cr);function Fr(n){return typeof n=="function"?n:V}function qr(n,r){var e=A(n)?bn:F;return e(n,Fr(r))}function Gr(n,r){var e=[];return F(n,function(i,f,t){r(i,f,t)&&e.push(i)}),e}function Yr(n,r){var e=A(n)?en:Gr;return e(n,an(r))}function mr(n,r,e,i,f){return f(n,function(t,s,u){e=i?(i=!1,t):r(e,t,s,u)}),e}function Zr(n,r,e){var i=A(n)?Un:mr,f=arguments.length<3;return i(n,an(r),e,f,F)}var Nr=1/0,Ur=I&&1/C(new I([,-0]))[1]==Nr?function(n){return new I(n)}:En,Br=200;function Xr(n,r,e){var i=-1,f=Sn,t=n.length,s=!0,u=[],a=u;if(t>=Br){var h=r?null:Ur(n);if(h)return C(h);s=!1,f=tn,a=new y}else a=r?[]:u;n:for(;++i<t;){var g=n[i],l=r?r(g):g;if(g=g!==0?g:0,s&&l===l){for(var d=a.length;d--;)if(a[d]===l)continue n;r&&a.push(l),u.push(g)}else f(a,l,e)||(a!==u&&a.push(l),u.push(g))}return u}export{F as a,Hr as b,an as c,yn as d,rn as e,Yn as f,qn as g,bn as h,x as i,Y as j,M as k,Xr as l,Yr as m,qr as n,cn as o,Fr as p,Cr as q,Zr as r,Bn as s,Tr as t,j as u,R as v,nn as w,Rr as x,Gn as y};
1
+ import{aU as L,bq as ln,aE as A,aS as P,aD as z,br as gn,bs as dn,bt as hn,bu as W,bv as pn,bl as An,bw as m,aV as N,a_ as U,b1 as T,bx as _n,aY as on,by as wn,bo as On,aF as V,bm as vn,bz as I}from"./mermaid.core-BqsnOxD3.js";var Pn="[object Symbol]";function x(n){return typeof n=="symbol"||L(n)&&ln(n)==Pn}function yn(n,r){for(var e=-1,i=n==null?0:n.length,f=Array(i);++e<i;)f[e]=r(n[e],e,n);return f}var B=P?P.prototype:void 0,K=B?B.toString:void 0;function k(n){if(typeof n=="string")return n;if(A(n))return yn(n,k)+"";if(x(n))return K?K.call(n):"";var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}function En(){}function bn(n,r){for(var e=-1,i=n==null?0:n.length;++e<i&&r(n[e],e,n)!==!1;);return n}function cn(n,r,e,i){for(var f=n.length,t=e+-1;++t<f;)if(r(n[t],t,n))return t;return-1}function Tn(n){return n!==n}function Rn(n,r,e){for(var i=e-1,f=n.length;++i<f;)if(n[i]===r)return i;return-1}function In(n,r,e){return r===r?Rn(n,r,e):cn(n,Tn,e)}function Sn(n,r){var e=n==null?0:n.length;return!!e&&In(n,r,0)>-1}function M(n){return z(n)?gn(n):dn(n)}var Ln=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,xn=/^\w*$/;function $(n,r){if(A(n))return!1;var e=typeof n;return e=="number"||e=="symbol"||e=="boolean"||n==null||x(n)?!0:xn.test(n)||!Ln.test(n)||r!=null&&n in Object(r)}var Mn=500;function $n(n){var r=hn(n,function(i){return e.size===Mn&&e.clear(),i}),e=r.cache;return r}var Cn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,Dn=/\\(\\)?/g,Fn=$n(function(n){var r=[];return n.charCodeAt(0)===46&&r.push(""),n.replace(Cn,function(e,i,f,t){r.push(f?t.replace(Dn,"$1"):i||e)}),r});function Gn(n){return n==null?"":k(n)}function j(n,r){return A(n)?n:$(n,r)?[n]:Fn(Gn(n))}function R(n){if(typeof n=="string"||x(n))return n;var r=n+"";return r=="0"&&1/n==-1/0?"-0":r}function nn(n,r){r=j(r,n);for(var e=0,i=r.length;n!=null&&e<i;)n=n[R(r[e++])];return e&&e==i?n:void 0}function mn(n,r,e){var i=n==null?void 0:nn(n,r);return i===void 0?e:i}function rn(n,r){for(var e=-1,i=r.length,f=n.length;++e<i;)n[f+e]=r[e];return n}var H=P?P.isConcatSpreadable:void 0;function Nn(n){return A(n)||W(n)||!!(H&&n&&n[H])}function Hr(n,r,e,i,f){var t=-1,s=n.length;for(e||(e=Nn),f||(f=[]);++t<s;){var u=n[t];e(u)?rn(f,u):i||(f[f.length]=u)}return f}function Un(n,r,e,i){var f=-1,t=n==null?0:n.length;for(i&&t&&(e=n[++f]);++f<t;)e=r(e,n[f],f,n);return e}function en(n,r){for(var e=-1,i=n==null?0:n.length,f=0,t=[];++e<i;){var s=n[e];r(s,e,n)&&(t[f++]=s)}return t}function Bn(){return[]}var Kn=Object.prototype,Hn=Kn.propertyIsEnumerable,q=Object.getOwnPropertySymbols,qn=q?function(n){return n==null?[]:(n=Object(n),en(q(n),function(r){return Hn.call(n,r)}))}:Bn;function Yn(n,r,e){var i=r(n);return A(n)?i:rn(i,e(n))}function Y(n){return Yn(n,M,qn)}var Zn="__lodash_hash_undefined__";function Xn(n){return this.__data__.set(n,Zn),this}function Jn(n){return this.__data__.has(n)}function y(n){var r=-1,e=n==null?0:n.length;for(this.__data__=new pn;++r<e;)this.add(n[r])}y.prototype.add=y.prototype.push=Xn;y.prototype.has=Jn;function Qn(n,r){for(var e=-1,i=n==null?0:n.length;++e<i;)if(r(n[e],e,n))return!0;return!1}function tn(n,r){return n.has(r)}var zn=1,Wn=2;function fn(n,r,e,i,f,t){var s=e&zn,u=n.length,a=r.length;if(u!=a&&!(s&&a>u))return!1;var h=t.get(n),g=t.get(r);if(h&&g)return h==r&&g==n;var l=-1,d=!0,o=e&Wn?new y:void 0;for(t.set(n,r),t.set(r,n);++l<u;){var p=n[l],_=r[l];if(i)var w=s?i(_,p,l,r,n,t):i(p,_,l,n,r,t);if(w!==void 0){if(w)continue;d=!1;break}if(o){if(!Qn(r,function(O,v){if(!tn(o,v)&&(p===O||f(p,O,e,i,t)))return o.push(v)})){d=!1;break}}else if(!(p===_||f(p,_,e,i,t))){d=!1;break}}return t.delete(n),t.delete(r),d}function Vn(n){var r=-1,e=Array(n.size);return n.forEach(function(i,f){e[++r]=[f,i]}),e}function C(n){var r=-1,e=Array(n.size);return n.forEach(function(i){e[++r]=i}),e}var kn=1,jn=2,nr="[object Boolean]",rr="[object Date]",er="[object Error]",ir="[object Map]",tr="[object Number]",fr="[object RegExp]",sr="[object Set]",ur="[object String]",ar="[object Symbol]",lr="[object ArrayBuffer]",gr="[object DataView]",Z=P?P.prototype:void 0,S=Z?Z.valueOf:void 0;function dr(n,r,e,i,f,t,s){switch(e){case gr:if(n.byteLength!=r.byteLength||n.byteOffset!=r.byteOffset)return!1;n=n.buffer,r=r.buffer;case lr:return!(n.byteLength!=r.byteLength||!t(new m(n),new m(r)));case nr:case rr:case tr:return An(+n,+r);case er:return n.name==r.name&&n.message==r.message;case fr:case ur:return n==r+"";case ir:var u=Vn;case sr:var a=i&kn;if(u||(u=C),n.size!=r.size&&!a)return!1;var h=s.get(n);if(h)return h==r;i|=jn,s.set(n,r);var g=fn(u(n),u(r),i,f,t,s);return s.delete(n),g;case ar:if(S)return S.call(n)==S.call(r)}return!1}var hr=1,pr=Object.prototype,Ar=pr.hasOwnProperty;function _r(n,r,e,i,f,t){var s=e&hr,u=Y(n),a=u.length,h=Y(r),g=h.length;if(a!=g&&!s)return!1;for(var l=a;l--;){var d=u[l];if(!(s?d in r:Ar.call(r,d)))return!1}var o=t.get(n),p=t.get(r);if(o&&p)return o==r&&p==n;var _=!0;t.set(n,r),t.set(r,n);for(var w=s;++l<a;){d=u[l];var O=n[d],v=r[d];if(i)var G=s?i(v,O,d,r,n,t):i(O,v,d,n,r,t);if(!(G===void 0?O===v||f(O,v,e,i,t):G)){_=!1;break}w||(w=d=="constructor")}if(_&&!w){var E=n.constructor,b=r.constructor;E!=b&&"constructor"in n&&"constructor"in r&&!(typeof E=="function"&&E instanceof E&&typeof b=="function"&&b instanceof b)&&(_=!1)}return t.delete(n),t.delete(r),_}var or=1,X="[object Arguments]",J="[object Array]",c="[object Object]",wr=Object.prototype,Q=wr.hasOwnProperty;function Or(n,r,e,i,f,t){var s=A(n),u=A(r),a=s?J:N(n),h=u?J:N(r);a=a==X?c:a,h=h==X?c:h;var g=a==c,l=h==c,d=a==h;if(d&&U(n)){if(!U(r))return!1;s=!0,g=!1}if(d&&!g)return t||(t=new T),s||_n(n)?fn(n,r,e,i,f,t):dr(n,r,a,e,i,f,t);if(!(e&or)){var o=g&&Q.call(n,"__wrapped__"),p=l&&Q.call(r,"__wrapped__");if(o||p){var _=o?n.value():n,w=p?r.value():r;return t||(t=new T),f(_,w,e,i,t)}}return d?(t||(t=new T),_r(n,r,e,i,f,t)):!1}function D(n,r,e,i,f){return n===r?!0:n==null||r==null||!L(n)&&!L(r)?n!==n&&r!==r:Or(n,r,e,i,D,f)}var vr=1,Pr=2;function yr(n,r,e,i){var f=e.length,t=f;if(n==null)return!t;for(n=Object(n);f--;){var s=e[f];if(s[2]?s[1]!==n[s[0]]:!(s[0]in n))return!1}for(;++f<t;){s=e[f];var u=s[0],a=n[u],h=s[1];if(s[2]){if(a===void 0&&!(u in n))return!1}else{var g=new T,l;if(!(l===void 0?D(h,a,vr|Pr,i,g):l))return!1}}return!0}function sn(n){return n===n&&!on(n)}function Er(n){for(var r=M(n),e=r.length;e--;){var i=r[e],f=n[i];r[e]=[i,f,sn(f)]}return r}function un(n,r){return function(e){return e==null?!1:e[n]===r&&(r!==void 0||n in Object(e))}}function br(n){var r=Er(n);return r.length==1&&r[0][2]?un(r[0][0],r[0][1]):function(e){return e===n||yr(e,n,r)}}function cr(n,r){return n!=null&&r in Object(n)}function Tr(n,r,e){r=j(r,n);for(var i=-1,f=r.length,t=!1;++i<f;){var s=R(r[i]);if(!(t=n!=null&&e(n,s)))break;n=n[s]}return t||++i!=f?t:(f=n==null?0:n.length,!!f&&wn(f)&&On(s,f)&&(A(n)||W(n)))}function Rr(n,r){return n!=null&&Tr(n,r,cr)}var Ir=1,Sr=2;function Lr(n,r){return $(n)&&sn(r)?un(R(n),r):function(e){var i=mn(e,n);return i===void 0&&i===r?Rr(e,n):D(r,i,Ir|Sr)}}function xr(n){return function(r){return r==null?void 0:r[n]}}function Mr(n){return function(r){return nn(r,n)}}function $r(n){return $(n)?xr(R(n)):Mr(n)}function an(n){return typeof n=="function"?n:n==null?V:typeof n=="object"?A(n)?Lr(n[0],n[1]):br(n):$r(n)}function Cr(n,r){return n&&vn(n,r,M)}function Dr(n,r){return function(e,i){if(e==null)return e;if(!z(e))return n(e,i);for(var f=e.length,t=-1,s=Object(e);++t<f&&i(s[t],t,s)!==!1;);return e}}var F=Dr(Cr);function Fr(n){return typeof n=="function"?n:V}function qr(n,r){var e=A(n)?bn:F;return e(n,Fr(r))}function Gr(n,r){var e=[];return F(n,function(i,f,t){r(i,f,t)&&e.push(i)}),e}function Yr(n,r){var e=A(n)?en:Gr;return e(n,an(r))}function mr(n,r,e,i,f){return f(n,function(t,s,u){e=i?(i=!1,t):r(e,t,s,u)}),e}function Zr(n,r,e){var i=A(n)?Un:mr,f=arguments.length<3;return i(n,an(r),e,f,F)}var Nr=1/0,Ur=I&&1/C(new I([,-0]))[1]==Nr?function(n){return new I(n)}:En,Br=200;function Xr(n,r,e){var i=-1,f=Sn,t=n.length,s=!0,u=[],a=u;if(t>=Br){var h=r?null:Ur(n);if(h)return C(h);s=!1,f=tn,a=new y}else a=r?[]:u;n:for(;++i<t;){var g=n[i],l=r?r(g):g;if(g=g!==0?g:0,s&&l===l){for(var d=a.length;d--;)if(a[d]===l)continue n;r&&a.push(l),u.push(g)}else f(a,l,e)||(a!==u&&a.push(l),u.push(g))}return u}export{F as a,Hr as b,an as c,yn as d,rn as e,Yn as f,qn as g,bn as h,x as i,Y as j,M as k,Xr as l,Yr as m,qr as n,cn as o,Fr as p,Cr as q,Zr as r,Bn as s,Tr as t,j as u,R as v,nn as w,Rr as x,Gn as y};