claude-code-workflow 6.0.5 → 6.1.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.
- package/.claude/agents/action-planning-agent.md +1 -1
- package/.claude/agents/cli-execution-agent.md +269 -269
- package/.claude/agents/cli-explore-agent.md +182 -182
- package/.claude/agents/context-search-agent.md +582 -582
- package/.claude/agents/memory-bridge.md +93 -93
- package/.claude/commands/cli/cli-init.md +1 -1
- package/.claude/commands/memory/docs-full-cli.md +471 -471
- package/.claude/commands/memory/docs-related-cli.md +386 -386
- package/.claude/commands/memory/docs.md +615 -615
- package/.claude/commands/memory/load.md +1 -1
- package/.claude/commands/memory/update-full.md +332 -332
- package/.claude/commands/memory/update-related.md +5 -5
- package/.claude/commands/workflow/init.md +1 -1
- package/.claude/commands/workflow/lite-fix.md +621 -621
- package/.claude/commands/workflow/lite-plan.md +592 -592
- package/.claude/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/commands/workflow/ui-design/generate.md +504 -504
- package/.claude/commands/workflow/ui-design/import-from-code.md +537 -537
- package/.claude/scripts/classify-folders.sh +4 -0
- package/.claude/scripts/convert_tokens_to_css.sh +4 -0
- package/.claude/scripts/detect_changed_modules.sh +5 -1
- package/.claude/scripts/discover-design-files.sh +87 -83
- package/.claude/scripts/generate_module_docs.sh +717 -713
- package/.claude/scripts/get_modules_by_depth.sh +5 -1
- package/.claude/scripts/ui-generate-preview.sh +4 -0
- package/.claude/scripts/ui-instantiate-prototypes.sh +4 -0
- package/.claude/scripts/update_module_claude.sh +4 -0
- package/.claude/skills/command-guide/index/all-commands.json +1 -12
- package/.claude/skills/command-guide/index/by-category.json +1 -12
- package/.claude/skills/command-guide/index/by-use-case.json +1 -12
- package/.claude/skills/command-guide/index/essential-commands.json +1 -12
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +127 -71
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +269 -269
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +182 -182
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +18 -38
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +582 -577
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
- package/.claude/skills/command-guide/reference/commands/cli/cli-init.md +1 -1
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +615 -610
- package/.claude/skills/command-guide/reference/commands/memory/load.md +1 -1
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
- package/.claude/skills/command-guide/reference/commands/memory/update-related.md +5 -5
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/artifacts.md +299 -451
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +14 -37
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/synthesis.md +252 -350
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +2 -2
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +52 -0
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +621 -602
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +46 -36
- package/.claude/skills/command-guide/reference/commands/workflow/review-fix.md +18 -58
- package/.claude/skills/command-guide/reference/commands/workflow/review-module-cycle.md +22 -52
- package/.claude/skills/command-guide/reference/commands/workflow/review-session-cycle.md +19 -48
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +25 -5
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +7 -7
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +151 -11
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +4 -4
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-task-generate.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/generate.md +504 -504
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +537 -537
- package/.claude/workflows/context-search-strategy.md +77 -77
- package/.claude/workflows/tool-strategy.md +90 -71
- package/.claude/workflows/workflow-architecture.md +1 -1
- package/ccw/src/cli.js +7 -0
- package/ccw/src/commands/tool.js +181 -0
- package/ccw/src/core/dashboard-generator.js +18 -3
- package/ccw/src/core/lite-scanner.js +35 -11
- package/ccw/src/core/server.js +531 -46
- package/ccw/src/templates/dashboard-css/01-base.css +161 -0
- package/ccw/src/templates/dashboard-css/02-session.css +726 -0
- package/ccw/src/templates/dashboard-css/03-tasks.css +512 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +843 -0
- package/ccw/src/templates/dashboard-css/05-context.css +2206 -0
- package/ccw/src/templates/dashboard-css/06-cards.css +1570 -0
- package/ccw/src/templates/dashboard-css/07-managers.css +936 -0
- package/ccw/src/templates/dashboard-css/08-review.css +1266 -0
- package/ccw/src/templates/dashboard-css/09-explorer.css +1397 -0
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +219 -0
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +10 -0
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +11 -1
- package/ccw/src/templates/dashboard-js/components/navigation.js +11 -5
- package/ccw/src/templates/dashboard-js/components/tabs-context.js +20 -20
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +11 -11
- package/ccw/src/templates/dashboard-js/components/theme.js +29 -1
- package/ccw/src/templates/dashboard-js/main.js +4 -0
- package/ccw/src/templates/dashboard-js/state.js +5 -0
- package/ccw/src/templates/dashboard-js/views/explorer.js +852 -0
- package/ccw/src/templates/dashboard-js/views/home.js +13 -9
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +8 -5
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +21 -16
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +90 -19
- package/ccw/src/templates/dashboard-js/views/project-overview.js +15 -11
- package/ccw/src/templates/dashboard-js/views/review-session.js +3 -3
- package/ccw/src/templates/dashboard-js/views/session-detail.js +38 -28
- package/ccw/src/templates/dashboard.html +129 -28
- package/ccw/src/tools/classify-folders.js +204 -0
- package/ccw/src/tools/convert-tokens-to-css.js +250 -0
- package/ccw/src/tools/detect-changed-modules.js +288 -0
- package/ccw/src/tools/discover-design-files.js +134 -0
- package/ccw/src/tools/edit-file.js +266 -0
- package/ccw/src/tools/generate-module-docs.js +416 -0
- package/ccw/src/tools/get-modules-by-depth.js +308 -0
- package/ccw/src/tools/index.js +176 -0
- package/ccw/src/tools/ui-generate-preview.js +327 -0
- package/ccw/src/tools/ui-instantiate-prototypes.js +301 -0
- package/ccw/src/tools/update-module-claude.js +380 -0
- package/package.json +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/status.md +0 -352
- package/ccw/src/core/server.js.bak +0 -385
- package/ccw/src/core/server_original.bak +0 -385
- package/ccw/src/templates/dashboard.css +0 -8187
- package/ccw/src/templates/dashboard_tailwind.html +0 -42
- package/ccw/src/templates/dashboard_test.html +0 -37
- package/ccw/src/templates/tailwind-base.css +0 -212
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
import http from 'http';
|
|
2
|
-
import { URL } from 'url';
|
|
3
|
-
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import { scanSessions } from './session-scanner.js';
|
|
6
|
-
import { aggregateData } from './data-aggregator.js';
|
|
7
|
-
import { resolvePath, getRecentPaths, trackRecentPath, normalizePathForDisplay, getWorkflowDir } from '../utils/path-resolver.js';
|
|
8
|
-
|
|
9
|
-
const TEMPLATE_PATH = join(import.meta.dirname, '../templates/dashboard.html');
|
|
10
|
-
const CSS_FILE = join(import.meta.dirname, '../templates/dashboard.css');
|
|
11
|
-
const JS_FILE = join(import.meta.dirname, '../templates/dashboard.js');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Create and start the dashboard server
|
|
15
|
-
* @param {Object} options - Server options
|
|
16
|
-
* @param {number} options.port - Port to listen on (default: 3456)
|
|
17
|
-
* @param {string} options.initialPath - Initial project path
|
|
18
|
-
* @returns {Promise<http.Server>}
|
|
19
|
-
*/
|
|
20
|
-
export async function startServer(options = {}) {
|
|
21
|
-
const port = options.port || 3456;
|
|
22
|
-
const initialPath = options.initialPath || process.cwd();
|
|
23
|
-
|
|
24
|
-
const server = http.createServer(async (req, res) => {
|
|
25
|
-
const url = new URL(req.url, `http://localhost:${port}`);
|
|
26
|
-
const pathname = url.pathname;
|
|
27
|
-
|
|
28
|
-
// CORS headers for API requests
|
|
29
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
30
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
31
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
32
|
-
|
|
33
|
-
if (req.method === 'OPTIONS') {
|
|
34
|
-
res.writeHead(200);
|
|
35
|
-
res.end();
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
// API: Get workflow data for a path
|
|
41
|
-
if (pathname === '/api/data') {
|
|
42
|
-
const projectPath = url.searchParams.get('path') || initialPath;
|
|
43
|
-
const data = await getWorkflowData(projectPath);
|
|
44
|
-
|
|
45
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
46
|
-
res.end(JSON.stringify(data));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// API: Get recent paths
|
|
51
|
-
if (pathname === '/api/recent-paths') {
|
|
52
|
-
const paths = getRecentPaths();
|
|
53
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
54
|
-
res.end(JSON.stringify({ paths }));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// API: Get session detail data (context, summaries, impl-plan, review)
|
|
59
|
-
if (pathname === '/api/session-detail') {
|
|
60
|
-
const sessionPath = url.searchParams.get('path');
|
|
61
|
-
const dataType = url.searchParams.get('type') || 'all';
|
|
62
|
-
|
|
63
|
-
if (!sessionPath) {
|
|
64
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
65
|
-
res.end(JSON.stringify({ error: 'Session path is required' }));
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const detail = await getSessionDetailData(sessionPath, dataType);
|
|
70
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
71
|
-
res.end(JSON.stringify(detail));
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Serve dashboard HTML
|
|
76
|
-
if (pathname === '/' || pathname === '/index.html') {
|
|
77
|
-
const html = generateServerDashboard(initialPath);
|
|
78
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
79
|
-
res.end(html);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// 404
|
|
84
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
85
|
-
res.end('Not Found');
|
|
86
|
-
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.error('Server error:', error);
|
|
89
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
90
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
return new Promise((resolve, reject) => {
|
|
95
|
-
server.listen(port, () => {
|
|
96
|
-
console.log(`Dashboard server running at http://localhost:${port}`);
|
|
97
|
-
resolve(server);
|
|
98
|
-
});
|
|
99
|
-
server.on('error', reject);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get workflow data for a project path
|
|
105
|
-
* @param {string} projectPath
|
|
106
|
-
* @returns {Promise<Object>}
|
|
107
|
-
*/
|
|
108
|
-
async function getWorkflowData(projectPath) {
|
|
109
|
-
const resolvedPath = resolvePath(projectPath);
|
|
110
|
-
const workflowDir = join(resolvedPath, '.workflow');
|
|
111
|
-
|
|
112
|
-
// Track this path
|
|
113
|
-
trackRecentPath(resolvedPath);
|
|
114
|
-
|
|
115
|
-
// Check if .workflow exists
|
|
116
|
-
if (!existsSync(workflowDir)) {
|
|
117
|
-
return {
|
|
118
|
-
generatedAt: new Date().toISOString(),
|
|
119
|
-
activeSessions: [],
|
|
120
|
-
archivedSessions: [],
|
|
121
|
-
liteTasks: { litePlan: [], liteFix: [] },
|
|
122
|
-
reviewData: { dimensions: {} },
|
|
123
|
-
projectOverview: null,
|
|
124
|
-
statistics: {
|
|
125
|
-
totalSessions: 0,
|
|
126
|
-
activeSessions: 0,
|
|
127
|
-
totalTasks: 0,
|
|
128
|
-
completedTasks: 0,
|
|
129
|
-
reviewFindings: 0,
|
|
130
|
-
litePlanCount: 0,
|
|
131
|
-
liteFixCount: 0
|
|
132
|
-
},
|
|
133
|
-
projectPath: normalizePathForDisplay(resolvedPath),
|
|
134
|
-
recentPaths: getRecentPaths()
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Scan and aggregate data
|
|
139
|
-
const sessions = await scanSessions(workflowDir);
|
|
140
|
-
const data = await aggregateData(sessions, workflowDir);
|
|
141
|
-
|
|
142
|
-
data.projectPath = normalizePathForDisplay(resolvedPath);
|
|
143
|
-
data.recentPaths = getRecentPaths();
|
|
144
|
-
|
|
145
|
-
return data;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Get session detail data (context, summaries, impl-plan, review)
|
|
150
|
-
* @param {string} sessionPath - Path to session directory
|
|
151
|
-
* @param {string} dataType - Type of data to load: context, summary, impl-plan, review, or all
|
|
152
|
-
* @returns {Promise<Object>}
|
|
153
|
-
*/
|
|
154
|
-
async function getSessionDetailData(sessionPath, dataType) {
|
|
155
|
-
const result = {};
|
|
156
|
-
|
|
157
|
-
// Normalize path
|
|
158
|
-
const normalizedPath = sessionPath.replace(/\\/g, '/');
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
// Load context-package.json (in .process/ subfolder)
|
|
162
|
-
if (dataType === 'context' || dataType === 'all') {
|
|
163
|
-
// Try .process/context-package.json first (common location)
|
|
164
|
-
let contextFile = join(normalizedPath, '.process', 'context-package.json');
|
|
165
|
-
if (!existsSync(contextFile)) {
|
|
166
|
-
// Fallback to session root
|
|
167
|
-
contextFile = join(normalizedPath, 'context-package.json');
|
|
168
|
-
}
|
|
169
|
-
if (existsSync(contextFile)) {
|
|
170
|
-
try {
|
|
171
|
-
result.context = JSON.parse(readFileSync(contextFile, 'utf8'));
|
|
172
|
-
} catch (e) {
|
|
173
|
-
result.context = null;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Load task JSONs from .task/ folder
|
|
179
|
-
if (dataType === 'tasks' || dataType === 'all') {
|
|
180
|
-
const taskDir = join(normalizedPath, '.task');
|
|
181
|
-
result.tasks = [];
|
|
182
|
-
if (existsSync(taskDir)) {
|
|
183
|
-
const files = readdirSync(taskDir).filter(f => f.endsWith('.json') && f.startsWith('IMPL-'));
|
|
184
|
-
for (const file of files) {
|
|
185
|
-
try {
|
|
186
|
-
const content = JSON.parse(readFileSync(join(taskDir, file), 'utf8'));
|
|
187
|
-
result.tasks.push({
|
|
188
|
-
filename: file,
|
|
189
|
-
task_id: file.replace('.json', ''),
|
|
190
|
-
...content
|
|
191
|
-
});
|
|
192
|
-
} catch (e) {
|
|
193
|
-
// Skip unreadable files
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
// Sort by task ID
|
|
197
|
-
result.tasks.sort((a, b) => a.task_id.localeCompare(b.task_id));
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Load summaries from .summaries/
|
|
202
|
-
if (dataType === 'summary' || dataType === 'all') {
|
|
203
|
-
const summariesDir = join(normalizedPath, '.summaries');
|
|
204
|
-
result.summaries = [];
|
|
205
|
-
if (existsSync(summariesDir)) {
|
|
206
|
-
const files = readdirSync(summariesDir).filter(f => f.endsWith('.md'));
|
|
207
|
-
for (const file of files) {
|
|
208
|
-
try {
|
|
209
|
-
const content = readFileSync(join(summariesDir, file), 'utf8');
|
|
210
|
-
result.summaries.push({ name: file.replace('.md', ''), content });
|
|
211
|
-
} catch (e) {
|
|
212
|
-
// Skip unreadable files
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Load plan.json (for lite tasks)
|
|
219
|
-
if (dataType === 'plan' || dataType === 'all') {
|
|
220
|
-
const planFile = join(normalizedPath, 'plan.json');
|
|
221
|
-
if (existsSync(planFile)) {
|
|
222
|
-
try {
|
|
223
|
-
result.plan = JSON.parse(readFileSync(planFile, 'utf8'));
|
|
224
|
-
} catch (e) {
|
|
225
|
-
result.plan = null;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Load IMPL_PLAN.md
|
|
231
|
-
if (dataType === 'impl-plan' || dataType === 'all') {
|
|
232
|
-
const implPlanFile = join(normalizedPath, 'IMPL_PLAN.md');
|
|
233
|
-
if (existsSync(implPlanFile)) {
|
|
234
|
-
try {
|
|
235
|
-
result.implPlan = readFileSync(implPlanFile, 'utf8');
|
|
236
|
-
} catch (e) {
|
|
237
|
-
result.implPlan = null;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Load review data from .review/
|
|
243
|
-
if (dataType === 'review' || dataType === 'all') {
|
|
244
|
-
const reviewDir = join(normalizedPath, '.review');
|
|
245
|
-
result.review = {
|
|
246
|
-
state: null,
|
|
247
|
-
dimensions: [],
|
|
248
|
-
severityDistribution: null,
|
|
249
|
-
totalFindings: 0
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
if (existsSync(reviewDir)) {
|
|
253
|
-
// Load review-state.json
|
|
254
|
-
const stateFile = join(reviewDir, 'review-state.json');
|
|
255
|
-
if (existsSync(stateFile)) {
|
|
256
|
-
try {
|
|
257
|
-
const state = JSON.parse(readFileSync(stateFile, 'utf8'));
|
|
258
|
-
result.review.state = state;
|
|
259
|
-
result.review.severityDistribution = state.severity_distribution || {};
|
|
260
|
-
result.review.totalFindings = state.total_findings || 0;
|
|
261
|
-
result.review.phase = state.phase || 'unknown';
|
|
262
|
-
result.review.dimensionSummaries = state.dimension_summaries || {};
|
|
263
|
-
result.review.crossCuttingConcerns = state.cross_cutting_concerns || [];
|
|
264
|
-
result.review.criticalFiles = state.critical_files || [];
|
|
265
|
-
} catch (e) {
|
|
266
|
-
// Skip unreadable state
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Load dimension findings
|
|
271
|
-
const dimensionsDir = join(reviewDir, 'dimensions');
|
|
272
|
-
if (existsSync(dimensionsDir)) {
|
|
273
|
-
const files = readdirSync(dimensionsDir).filter(f => f.endsWith('.json'));
|
|
274
|
-
for (const file of files) {
|
|
275
|
-
try {
|
|
276
|
-
const dimName = file.replace('.json', '');
|
|
277
|
-
const data = JSON.parse(readFileSync(join(dimensionsDir, file), 'utf8'));
|
|
278
|
-
|
|
279
|
-
// Handle array structure: [ { findings: [...] } ]
|
|
280
|
-
let findings = [];
|
|
281
|
-
let summary = null;
|
|
282
|
-
|
|
283
|
-
if (Array.isArray(data) && data.length > 0) {
|
|
284
|
-
const dimData = data[0];
|
|
285
|
-
findings = dimData.findings || [];
|
|
286
|
-
summary = dimData.summary || null;
|
|
287
|
-
} else if (data.findings) {
|
|
288
|
-
findings = data.findings;
|
|
289
|
-
summary = data.summary || null;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
result.review.dimensions.push({
|
|
293
|
-
name: dimName,
|
|
294
|
-
findings: findings,
|
|
295
|
-
summary: summary,
|
|
296
|
-
count: findings.length
|
|
297
|
-
});
|
|
298
|
-
} catch (e) {
|
|
299
|
-
// Skip unreadable files
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
} catch (error) {
|
|
307
|
-
console.error('Error loading session detail:', error);
|
|
308
|
-
result.error = error.message;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return result;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Generate dashboard HTML for server mode
|
|
316
|
-
* @param {string} initialPath
|
|
317
|
-
* @returns {string}
|
|
318
|
-
*/
|
|
319
|
-
function generateServerDashboard(initialPath) {
|
|
320
|
-
let html = readFileSync(TEMPLATE_PATH, 'utf8');
|
|
321
|
-
|
|
322
|
-
// Read CSS and JS files
|
|
323
|
-
const cssContent = existsSync(CSS_FILE) ? readFileSync(CSS_FILE, 'utf8') : '';
|
|
324
|
-
let jsContent = existsSync(JS_FILE) ? readFileSync(JS_FILE, 'utf8') : '';
|
|
325
|
-
|
|
326
|
-
// Inject CSS content
|
|
327
|
-
html = html.replace('{{CSS_CONTENT}}', cssContent);
|
|
328
|
-
|
|
329
|
-
// Prepare JS content with empty initial data (will be loaded dynamically)
|
|
330
|
-
const emptyData = {
|
|
331
|
-
generatedAt: new Date().toISOString(),
|
|
332
|
-
activeSessions: [],
|
|
333
|
-
archivedSessions: [],
|
|
334
|
-
liteTasks: { litePlan: [], liteFix: [] },
|
|
335
|
-
reviewData: { dimensions: {} },
|
|
336
|
-
projectOverview: null,
|
|
337
|
-
statistics: { totalSessions: 0, activeSessions: 0, totalTasks: 0, completedTasks: 0, reviewFindings: 0, litePlanCount: 0, liteFixCount: 0 }
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
// Replace JS placeholders
|
|
341
|
-
jsContent = jsContent.replace('{{WORKFLOW_DATA}}', JSON.stringify(emptyData, null, 2));
|
|
342
|
-
jsContent = jsContent.replace(/\{\{PROJECT_PATH\}\}/g, normalizePathForDisplay(initialPath).replace(/\\/g, '/'));
|
|
343
|
-
jsContent = jsContent.replace('{{RECENT_PATHS}}', JSON.stringify(getRecentPaths()));
|
|
344
|
-
|
|
345
|
-
// Add server mode flag and dynamic loading functions at the start of JS
|
|
346
|
-
const serverModeScript = `
|
|
347
|
-
// Server mode - load data dynamically
|
|
348
|
-
window.SERVER_MODE = true;
|
|
349
|
-
window.INITIAL_PATH = '${normalizePathForDisplay(initialPath).replace(/\\/g, '/')}';
|
|
350
|
-
|
|
351
|
-
async function loadDashboardData(path) {
|
|
352
|
-
try {
|
|
353
|
-
const res = await fetch('/api/data?path=' + encodeURIComponent(path));
|
|
354
|
-
if (!res.ok) throw new Error('Failed to load data');
|
|
355
|
-
return await res.json();
|
|
356
|
-
} catch (err) {
|
|
357
|
-
console.error('Error loading data:', err);
|
|
358
|
-
return null;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
async function loadRecentPaths() {
|
|
363
|
-
try {
|
|
364
|
-
const res = await fetch('/api/recent-paths');
|
|
365
|
-
if (!res.ok) return [];
|
|
366
|
-
const data = await res.json();
|
|
367
|
-
return data.paths || [];
|
|
368
|
-
} catch (err) {
|
|
369
|
-
return [];
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
`;
|
|
374
|
-
|
|
375
|
-
// Prepend server mode script to JS content
|
|
376
|
-
jsContent = serverModeScript + jsContent;
|
|
377
|
-
|
|
378
|
-
// Inject JS content
|
|
379
|
-
html = html.replace('{{JS_CONTENT}}', jsContent);
|
|
380
|
-
|
|
381
|
-
// Replace any remaining placeholders in HTML
|
|
382
|
-
html = html.replace(/\{\{PROJECT_PATH\}\}/g, normalizePathForDisplay(initialPath).replace(/\\/g, '/'));
|
|
383
|
-
|
|
384
|
-
return html;
|
|
385
|
-
}
|