mstro-app 0.4.34 → 0.4.35
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/dist/server/cli/headless/claude-invoker-stream.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker-stream.js +63 -0
- package/dist/server/cli/headless/claude-invoker-stream.js.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.d.ts.map +1 -1
- package/dist/server/cli/headless/haiku-assessments.js +10 -5
- package/dist/server/cli/headless/haiku-assessments.js.map +1 -1
- package/dist/server/cli/improvisation-retry.d.ts.map +1 -1
- package/dist/server/cli/improvisation-retry.js +17 -2
- package/dist/server/cli/improvisation-retry.js.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +1 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +13 -5
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/improvisation-types.d.ts +1 -0
- package/dist/server/cli/improvisation-types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-types.js.map +1 -1
- package/dist/server/services/websocket/git-head-watcher.d.ts +25 -0
- package/dist/server/services/websocket/git-head-watcher.d.ts.map +1 -0
- package/dist/server/services/websocket/git-head-watcher.js +136 -0
- package/dist/server/services/websocket/git-head-watcher.js.map +1 -0
- package/dist/server/services/websocket/git-worktree-handlers.js +37 -5
- package/dist/server/services/websocket/git-worktree-handlers.js.map +1 -1
- package/dist/server/services/websocket/handler-context.d.ts +2 -0
- package/dist/server/services/websocket/handler-context.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.d.ts +3 -1
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +18 -6
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.d.ts +1 -0
- package/dist/server/services/websocket/plan-board-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-board-handlers.js +94 -0
- package/dist/server/services/websocket/plan-board-handlers.js.map +1 -1
- package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/plan-handlers.js +3 -1
- package/dist/server/services/websocket/plan-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-persistence.d.ts +7 -0
- package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-persistence.js +15 -7
- package/dist/server/services/websocket/quality-persistence.js.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.js +2 -13
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
- package/dist/server/services/websocket/quality-service.d.ts +12 -3
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +101 -81
- package/dist/server/services/websocket/quality-service.js.map +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-tools.js +6 -1
- package/dist/server/services/websocket/quality-tools.js.map +1 -1
- package/dist/server/services/websocket/quality-types.d.ts +15 -2
- package/dist/server/services/websocket/quality-types.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-types.js.map +1 -1
- package/dist/server/services/websocket/session-handlers.js +2 -2
- package/dist/server/services/websocket/session-handlers.js.map +1 -1
- package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-handlers.js +9 -2
- package/dist/server/services/websocket/tab-handlers.js.map +1 -1
- package/dist/server/services/websocket/types.d.ts +2 -2
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/server/cli/headless/claude-invoker-stream.ts +63 -0
- package/server/cli/headless/haiku-assessments.ts +10 -5
- package/server/cli/improvisation-retry.ts +18 -2
- package/server/cli/improvisation-session-manager.ts +13 -5
- package/server/cli/improvisation-types.ts +1 -0
- package/server/services/plan/agents/assess-stall.md +21 -0
- package/server/services/plan/agents/check-injection.md +36 -0
- package/server/services/plan/agents/classify-error.md +29 -0
- package/server/services/plan/agents/detect-context-loss.md +29 -0
- package/server/services/plan/agents/execute-issue.md +42 -0
- package/server/services/plan/agents/plan-coordinator.md +71 -0
- package/server/services/plan/agents/retry-task.md +26 -0
- package/server/services/plan/agents/review-code.md +4 -1
- package/server/services/plan/agents/review-criteria.md +53 -0
- package/server/services/plan/agents/review-custom.md +4 -1
- package/server/services/plan/agents/review-quality.md +4 -1
- package/server/services/plan/agents/verify-review.md +56 -0
- package/server/services/websocket/git-head-watcher.ts +120 -0
- package/server/services/websocket/git-worktree-handlers.ts +40 -6
- package/server/services/websocket/handler-context.ts +2 -0
- package/server/services/websocket/handler.ts +19 -6
- package/server/services/websocket/plan-board-handlers.ts +116 -0
- package/server/services/websocket/plan-handlers.ts +3 -1
- package/server/services/websocket/quality-persistence.ts +23 -7
- package/server/services/websocket/quality-review-agent.ts +2 -12
- package/server/services/websocket/quality-service.ts +116 -99
- package/server/services/websocket/quality-tools.ts +6 -1
- package/server/services/websocket/quality-types.ts +17 -2
- package/server/services/websocket/session-handlers.ts +2 -2
- package/server/services/websocket/tab-handlers.ts +8 -2
- package/server/services/websocket/types.ts +7 -2
|
@@ -5,11 +5,11 @@ import { extname } from 'node:path';
|
|
|
5
5
|
import { analyzeComplexity, analyzeFunctionLength } from './quality-complexity.js';
|
|
6
6
|
import { analyzeLinting } from './quality-linting.js';
|
|
7
7
|
import { collectSourceFiles, detectEcosystem, runCommand, type SourceFile } from './quality-tools.js';
|
|
8
|
-
import { type CategoryScore, type Ecosystem, FILE_LENGTH_THRESHOLD, hasInstalledToolInCategory, type QualityFinding, type QualityResults, type ScanProgress, TOTAL_STEPS } from './quality-types.js';
|
|
8
|
+
import { type CategoryPenalty, type CategoryScore, type Ecosystem, FILE_LENGTH_THRESHOLD, hasInstalledToolInCategory, type QualityFinding, type QualityResults, type ScanProgress, type ScoreBreakdown, TOTAL_STEPS } from './quality-types.js';
|
|
9
9
|
|
|
10
10
|
export { detectEcosystem, detectTools, installTools } from './quality-tools.js';
|
|
11
11
|
// Re-export public API for backward compatibility
|
|
12
|
-
export type { CategoryScore, QualityFinding, QualityResults, QualityTool, ScanProgress } from './quality-types.js';
|
|
12
|
+
export type { CategoryPenalty, CategoryScore, QualityFinding, QualityResults, QualityTool, ScanProgress, ScoreBreakdown } from './quality-types.js';
|
|
13
13
|
|
|
14
14
|
// ============================================================================
|
|
15
15
|
// Formatting Analysis
|
|
@@ -124,7 +124,7 @@ function analyzeFileLength(files: SourceFile[]): { score: number; findings: Qual
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// ============================================================================
|
|
127
|
-
// Scoring
|
|
127
|
+
// Deterministic Scoring — penalty-density exponential decay
|
|
128
128
|
// ============================================================================
|
|
129
129
|
|
|
130
130
|
function computeGrade(score: number): string {
|
|
@@ -135,66 +135,107 @@ function computeGrade(score: number): string {
|
|
|
135
135
|
return 'F';
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
aiReview: number;
|
|
145
|
-
}
|
|
138
|
+
const SEVERITY_WEIGHT: Record<string, number> = {
|
|
139
|
+
critical: 10,
|
|
140
|
+
high: 5,
|
|
141
|
+
medium: 2,
|
|
142
|
+
low: 0.5,
|
|
143
|
+
};
|
|
146
144
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
const CATEGORY_MULTIPLIER: Record<string, number> = {
|
|
146
|
+
security: 2.0,
|
|
147
|
+
bugs: 1.5,
|
|
148
|
+
architecture: 1.2,
|
|
149
|
+
logic: 1.2,
|
|
150
|
+
performance: 1.0,
|
|
151
|
+
oop: 0.8,
|
|
152
|
+
maintainability: 0.8,
|
|
153
|
+
complexity: 0.7,
|
|
154
|
+
lint: 0.5,
|
|
155
|
+
linting: 0.5,
|
|
156
|
+
format: 0.3,
|
|
157
|
+
'file-length': 0.3,
|
|
158
|
+
'function-length': 0.3,
|
|
154
159
|
};
|
|
155
160
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// ============================================================================
|
|
161
|
+
const OVERALL_DECAY = 0.09;
|
|
162
|
+
const CATEGORY_DECAY = 0.20;
|
|
159
163
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
164
|
+
function findingPenalty(f: { severity: string; category: string }): number {
|
|
165
|
+
return (SEVERITY_WEIGHT[f.severity] ?? 2) * (CATEGORY_MULTIPLIER[f.category] ?? 1.0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function computeFormulaScore(
|
|
169
|
+
allFindings: Array<{ severity: string; category: string }>,
|
|
170
|
+
totalLines: number,
|
|
171
|
+
): { score: number; breakdown: ScoreBreakdown } {
|
|
172
|
+
const kloc = Math.max(totalLines / 1000, 1.0);
|
|
173
|
+
|
|
174
|
+
if (allFindings.length === 0) {
|
|
175
|
+
return {
|
|
176
|
+
score: 100,
|
|
177
|
+
breakdown: { penaltyDensity: 0, totalPenalty: 0, issueDensity: 0, kloc, categoryPenalties: [] },
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const byCategory = new Map<string, { penalty: number; count: number }>();
|
|
182
|
+
let totalPenalty = 0;
|
|
183
|
+
|
|
184
|
+
for (const f of allFindings) {
|
|
185
|
+
const p = findingPenalty(f);
|
|
186
|
+
totalPenalty += p;
|
|
187
|
+
const existing = byCategory.get(f.category);
|
|
188
|
+
if (existing) {
|
|
189
|
+
existing.penalty += p;
|
|
190
|
+
existing.count++;
|
|
191
|
+
} else {
|
|
192
|
+
byCategory.set(f.category, { penalty: p, count: 1 });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const penaltyDensity = totalPenalty / kloc;
|
|
197
|
+
const score = Math.round(100 * Math.exp(-OVERALL_DECAY * penaltyDensity));
|
|
198
|
+
|
|
199
|
+
const categoryPenalties: CategoryPenalty[] = [];
|
|
200
|
+
for (const [cat, data] of byCategory) {
|
|
201
|
+
const catDensity = data.penalty / kloc;
|
|
202
|
+
const catScore = Math.round(100 * Math.exp(-CATEGORY_DECAY * catDensity));
|
|
203
|
+
categoryPenalties.push({
|
|
204
|
+
category: cat,
|
|
205
|
+
score: catScore,
|
|
206
|
+
grade: computeGrade(catScore),
|
|
207
|
+
penalty: Math.round(data.penalty * 10) / 10,
|
|
208
|
+
findingCount: data.count,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
166
211
|
|
|
167
|
-
|
|
168
|
-
const AI_REVIEW_DECAY = 0.10;
|
|
212
|
+
categoryPenalties.sort((a, b) => a.score - b.score);
|
|
169
213
|
|
|
214
|
+
return {
|
|
215
|
+
score,
|
|
216
|
+
breakdown: {
|
|
217
|
+
penaltyDensity: Math.round(penaltyDensity * 100) / 100,
|
|
218
|
+
totalPenalty: Math.round(totalPenalty * 10) / 10,
|
|
219
|
+
issueDensity: Math.round((allFindings.length / kloc) * 100) / 100,
|
|
220
|
+
kloc: Math.round(kloc * 10) / 10,
|
|
221
|
+
categoryPenalties,
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** @deprecated — use computeFormulaScore instead */
|
|
170
227
|
export function computeAiReviewScore(
|
|
171
228
|
findings: Array<{ severity: string }>,
|
|
172
229
|
totalLines: number,
|
|
173
230
|
): number {
|
|
174
231
|
if (findings.length === 0) return 100;
|
|
175
|
-
|
|
176
232
|
const effectiveKloc = Math.max(totalLines / 1000, 1.0);
|
|
177
233
|
const totalPenalty = findings.reduce(
|
|
178
|
-
(sum, f) => sum + (
|
|
234
|
+
(sum, f) => sum + (SEVERITY_WEIGHT[f.severity] ?? 2.0),
|
|
179
235
|
0,
|
|
180
236
|
);
|
|
181
237
|
const penaltyDensity = totalPenalty / effectiveKloc;
|
|
182
|
-
return Math.round(100 * Math.exp(-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function computeOverallScore(categories: CategoryScore[]): number {
|
|
186
|
-
const available = categories.filter((c) => c.available);
|
|
187
|
-
if (available.length === 0) return 0;
|
|
188
|
-
|
|
189
|
-
const totalWeight = available.reduce((sum, c) => sum + c.weight, 0);
|
|
190
|
-
let weighted = 0;
|
|
191
|
-
for (const cat of available) {
|
|
192
|
-
const effectiveWeight = cat.weight / totalWeight;
|
|
193
|
-
cat.effectiveWeight = effectiveWeight;
|
|
194
|
-
weighted += cat.score * effectiveWeight;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return Math.round(Math.max(0, Math.min(100, weighted)));
|
|
238
|
+
return Math.round(100 * Math.exp(-0.10 * penaltyDensity));
|
|
198
239
|
}
|
|
199
240
|
|
|
200
241
|
// ============================================================================
|
|
@@ -250,64 +291,58 @@ export async function runQualityScan(
|
|
|
250
291
|
// Step 7: Compute scores
|
|
251
292
|
progress('Computing scores', 7);
|
|
252
293
|
|
|
294
|
+
const allFindings = [
|
|
295
|
+
...lintResult.findings,
|
|
296
|
+
...fmtResult.findings,
|
|
297
|
+
...complexityResult.findings,
|
|
298
|
+
...fileLengthResult.findings,
|
|
299
|
+
...funcLengthResult.findings,
|
|
300
|
+
];
|
|
301
|
+
|
|
302
|
+
const totalLines = files.reduce((sum, f) => sum + f.lines, 0);
|
|
303
|
+
const { score: overall, breakdown } = computeFormulaScore(allFindings, totalLines);
|
|
304
|
+
|
|
253
305
|
const categories: CategoryScore[] = [
|
|
254
306
|
{
|
|
255
307
|
name: 'Linting',
|
|
256
308
|
score: lintResult.score,
|
|
257
|
-
weight:
|
|
258
|
-
effectiveWeight:
|
|
309
|
+
weight: 0,
|
|
310
|
+
effectiveWeight: 0,
|
|
259
311
|
available: lintResult.available,
|
|
260
312
|
issueCount: lintResult.issueCount,
|
|
261
313
|
},
|
|
262
314
|
{
|
|
263
315
|
name: 'Formatting',
|
|
264
316
|
score: fmtResult.score,
|
|
265
|
-
weight:
|
|
266
|
-
effectiveWeight:
|
|
317
|
+
weight: 0,
|
|
318
|
+
effectiveWeight: 0,
|
|
267
319
|
available: fmtResult.available,
|
|
268
320
|
issueCount: fmtResult.issueCount,
|
|
269
321
|
},
|
|
270
322
|
{
|
|
271
323
|
name: 'Complexity',
|
|
272
324
|
score: complexityResult.score,
|
|
273
|
-
weight:
|
|
274
|
-
effectiveWeight:
|
|
325
|
+
weight: 0,
|
|
326
|
+
effectiveWeight: 0,
|
|
275
327
|
available: complexityResult.available,
|
|
276
328
|
issueCount: complexityResult.issueCount,
|
|
277
329
|
},
|
|
278
330
|
{
|
|
279
331
|
name: 'File Length',
|
|
280
332
|
score: fileLengthResult.score,
|
|
281
|
-
weight:
|
|
282
|
-
effectiveWeight:
|
|
333
|
+
weight: 0,
|
|
334
|
+
effectiveWeight: 0,
|
|
283
335
|
available: true,
|
|
284
336
|
issueCount: fileLengthResult.issueCount,
|
|
285
337
|
},
|
|
286
338
|
{
|
|
287
339
|
name: 'Function Length',
|
|
288
340
|
score: funcLengthResult.score,
|
|
289
|
-
weight:
|
|
290
|
-
effectiveWeight:
|
|
341
|
+
weight: 0,
|
|
342
|
+
effectiveWeight: 0,
|
|
291
343
|
available: true,
|
|
292
344
|
issueCount: funcLengthResult.issueCount,
|
|
293
345
|
},
|
|
294
|
-
{
|
|
295
|
-
name: 'AI Review',
|
|
296
|
-
score: 0,
|
|
297
|
-
weight: DEFAULT_WEIGHTS.aiReview,
|
|
298
|
-
effectiveWeight: DEFAULT_WEIGHTS.aiReview,
|
|
299
|
-
available: false,
|
|
300
|
-
issueCount: 0,
|
|
301
|
-
},
|
|
302
|
-
];
|
|
303
|
-
|
|
304
|
-
const overall = computeOverallScore(categories);
|
|
305
|
-
const allFindings = [
|
|
306
|
-
...lintResult.findings,
|
|
307
|
-
...fmtResult.findings,
|
|
308
|
-
...complexityResult.findings,
|
|
309
|
-
...fileLengthResult.findings,
|
|
310
|
-
...funcLengthResult.findings,
|
|
311
346
|
];
|
|
312
347
|
|
|
313
348
|
return {
|
|
@@ -317,9 +352,10 @@ export async function runQualityScan(
|
|
|
317
352
|
findings: allFindings.slice(0, 200),
|
|
318
353
|
codeReview: [],
|
|
319
354
|
analyzedFiles: files.length,
|
|
320
|
-
totalLines
|
|
355
|
+
totalLines,
|
|
321
356
|
timestamp: new Date().toISOString(),
|
|
322
357
|
ecosystem: ecosystems,
|
|
358
|
+
scoreBreakdown: breakdown,
|
|
323
359
|
};
|
|
324
360
|
}
|
|
325
361
|
|
|
@@ -329,39 +365,20 @@ export async function runQualityScan(
|
|
|
329
365
|
|
|
330
366
|
/**
|
|
331
367
|
* Recompute the overall score after AI code review findings become available.
|
|
332
|
-
*
|
|
368
|
+
* Merges CLI + AI findings and runs the deterministic penalty-density formula.
|
|
333
369
|
*/
|
|
334
370
|
export function recomputeWithAiReview(
|
|
335
371
|
results: QualityResults,
|
|
336
|
-
aiFindings: Array<{ severity: string }>,
|
|
372
|
+
aiFindings: Array<{ severity: string; category: string }>,
|
|
337
373
|
): QualityResults {
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
// Update or add the AI Review category
|
|
341
|
-
const categories = results.categories.map((cat) => ({ ...cat }));
|
|
342
|
-
const aiCatIndex = categories.findIndex((c) => c.name === 'AI Review');
|
|
343
|
-
const aiCategory: CategoryScore = {
|
|
344
|
-
name: 'AI Review',
|
|
345
|
-
score: aiScore,
|
|
346
|
-
weight: DEFAULT_WEIGHTS.aiReview,
|
|
347
|
-
effectiveWeight: DEFAULT_WEIGHTS.aiReview,
|
|
348
|
-
available: true,
|
|
349
|
-
issueCount: aiFindings.length,
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
if (aiCatIndex >= 0) {
|
|
353
|
-
categories[aiCatIndex] = aiCategory;
|
|
354
|
-
} else {
|
|
355
|
-
categories.push(aiCategory);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const overall = computeOverallScore(categories);
|
|
374
|
+
const allFindings = [...results.findings, ...aiFindings];
|
|
375
|
+
const { score: overall, breakdown } = computeFormulaScore(allFindings, results.totalLines);
|
|
359
376
|
|
|
360
377
|
return {
|
|
361
378
|
...results,
|
|
362
379
|
overall,
|
|
363
380
|
grade: computeGrade(overall),
|
|
364
|
-
categories,
|
|
365
381
|
codeReview: results.codeReview,
|
|
382
|
+
scoreBreakdown: breakdown,
|
|
366
383
|
};
|
|
367
384
|
}
|
|
@@ -65,6 +65,7 @@ async function checkToolInstalled(check: string[], cwd: string): Promise<boolean
|
|
|
65
65
|
return new Promise((resolve) => {
|
|
66
66
|
const proc = spawn(check[0], check.slice(1), {
|
|
67
67
|
cwd,
|
|
68
|
+
shell: true,
|
|
68
69
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
69
70
|
timeout: 10000,
|
|
70
71
|
});
|
|
@@ -109,13 +110,16 @@ export async function installTools(
|
|
|
109
110
|
if (tool.installCommand.startsWith('(')) continue;
|
|
110
111
|
const commands = tool.installCommand.split(' || ');
|
|
111
112
|
let installed = false;
|
|
113
|
+
let lastStderr = '';
|
|
112
114
|
for (const cmd of commands) {
|
|
113
115
|
const parts = cmd.trim().split(' ');
|
|
114
116
|
const result = await runCommand(parts[0], parts.slice(1), dirPath);
|
|
115
117
|
if (result.exitCode === 0) { installed = true; break; }
|
|
118
|
+
lastStderr = result.stderr;
|
|
116
119
|
}
|
|
117
120
|
if (!installed) {
|
|
118
|
-
|
|
121
|
+
const detail = lastStderr ? ` (${lastStderr.trim().split('\n').pop()})` : '';
|
|
122
|
+
failures.push(`${tool.name}: install failed${detail}`);
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
|
|
@@ -241,6 +245,7 @@ export function runCommand(cmd: string, args: string[], cwd: string): Promise<{
|
|
|
241
245
|
return new Promise((resolve) => {
|
|
242
246
|
const proc = spawn(cmd, args, {
|
|
243
247
|
cwd,
|
|
248
|
+
shell: true,
|
|
244
249
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
245
250
|
timeout: 120000,
|
|
246
251
|
});
|
|
@@ -35,6 +35,22 @@ export interface QualityFinding {
|
|
|
35
35
|
verificationNote?: string;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export interface CategoryPenalty {
|
|
39
|
+
category: string;
|
|
40
|
+
score: number;
|
|
41
|
+
grade: string;
|
|
42
|
+
penalty: number;
|
|
43
|
+
findingCount: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ScoreBreakdown {
|
|
47
|
+
penaltyDensity: number;
|
|
48
|
+
totalPenalty: number;
|
|
49
|
+
issueDensity: number;
|
|
50
|
+
kloc: number;
|
|
51
|
+
categoryPenalties: CategoryPenalty[];
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
export interface QualityResults {
|
|
39
55
|
overall: number;
|
|
40
56
|
grade: string;
|
|
@@ -45,8 +61,7 @@ export interface QualityResults {
|
|
|
45
61
|
totalLines: number;
|
|
46
62
|
timestamp: string;
|
|
47
63
|
ecosystem: string[];
|
|
48
|
-
|
|
49
|
-
scoreRationale?: string;
|
|
64
|
+
scoreBreakdown?: ScoreBreakdown;
|
|
50
65
|
}
|
|
51
66
|
|
|
52
67
|
export interface ScanProgress {
|
|
@@ -104,8 +104,8 @@ export function setupSessionListeners(ctx: HandlerContext, session: Improvisatio
|
|
|
104
104
|
ctx.send(ws, { type: 'thinking', tabId, data: { text } });
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
session.on('onMovementStart', (sequenceNumber: number, prompt: string) => {
|
|
108
|
-
ctx.send(ws, { type: 'movementStart', tabId, data: { sequenceNumber, prompt, timestamp: Date.now(), executionStartTimestamp: session.executionStartTimestamp } });
|
|
107
|
+
session.on('onMovementStart', (sequenceNumber: number, prompt: string, isAutoContinue?: boolean) => {
|
|
108
|
+
ctx.send(ws, { type: 'movementStart', tabId, data: { sequenceNumber, prompt, timestamp: Date.now(), executionStartTimestamp: session.executionStartTimestamp, isAutoContinue } });
|
|
109
109
|
ctx.broadcastToAll({ type: 'tabStateChanged', data: { tabId, isExecuting: true, executionStartTimestamp: session.executionStartTimestamp } });
|
|
110
110
|
});
|
|
111
111
|
|
|
@@ -51,8 +51,14 @@ export function handleGetActiveTabs(ctx: HandlerContext, ws: WSContext, workingD
|
|
|
51
51
|
const tabs: Record<string, unknown> = {};
|
|
52
52
|
for (const [tabId, regTab] of Object.entries(allTabs)) {
|
|
53
53
|
const session = ctx.sessions.get(regTab.sessionId);
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
let worktreePath = ctx.gitDirectories.get(tabId);
|
|
55
|
+
let worktreeBranch = ctx.gitBranches.get(tabId);
|
|
56
|
+
if (!worktreePath && regTab.worktreePath) {
|
|
57
|
+
worktreePath = regTab.worktreePath;
|
|
58
|
+
worktreeBranch = regTab.worktreeBranch;
|
|
59
|
+
ctx.gitDirectories.set(tabId, worktreePath);
|
|
60
|
+
if (worktreeBranch) ctx.gitBranches.set(tabId, worktreeBranch);
|
|
61
|
+
}
|
|
56
62
|
tabs[tabId] = session
|
|
57
63
|
? buildActiveTabData(regTab, session, worktreePath, worktreeBranch)
|
|
58
64
|
: buildInactiveTabData(regTab, worktreePath, worktreeBranch);
|
|
@@ -170,7 +170,9 @@ export interface WebSocketMessage {
|
|
|
170
170
|
| 'deployUsageReport'
|
|
171
171
|
| 'deployAiHealthUpdate'
|
|
172
172
|
// Skill discovery
|
|
173
|
-
| 'listSkills'
|
|
173
|
+
| 'listSkills'
|
|
174
|
+
// Chat-to-board (cross-view skill actions)
|
|
175
|
+
| 'chatToBoard';
|
|
174
176
|
tabId?: string;
|
|
175
177
|
terminalId?: string;
|
|
176
178
|
// biome-ignore lint/suspicious/noExplicitAny: message envelope carries heterogeneous payloads
|
|
@@ -262,6 +264,7 @@ export interface WebSocketResponse {
|
|
|
262
264
|
| 'gitWorktreeCreatedAndAssigned'
|
|
263
265
|
| 'gitWorktreeRemoved'
|
|
264
266
|
| 'tabWorktreeSwitched'
|
|
267
|
+
| 'gitBranchChanged'
|
|
265
268
|
| 'gitWorktreePushed'
|
|
266
269
|
| 'gitWorktreePRCreated'
|
|
267
270
|
// Merge response types
|
|
@@ -350,7 +353,9 @@ export interface WebSocketResponse {
|
|
|
350
353
|
| 'deployUsageReportAck'
|
|
351
354
|
| 'deployAiHealthAck'
|
|
352
355
|
// Skill discovery response types
|
|
353
|
-
| 'skillsList'
|
|
356
|
+
| 'skillsList'
|
|
357
|
+
// Chat-to-board response types
|
|
358
|
+
| 'chatToBoardCreated';
|
|
354
359
|
tabId?: string;
|
|
355
360
|
terminalId?: string;
|
|
356
361
|
// biome-ignore lint/suspicious/noExplicitAny: message envelope carries heterogeneous payloads
|