mstro-app 0.3.8 → 0.4.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/LICENSE +191 -21
- package/PRIVACY.md +286 -62
- package/README.md +81 -58
- package/bin/commands/status.js +1 -1
- package/dist/server/cli/headless/claude-invoker.d.ts.map +1 -1
- package/dist/server/cli/headless/claude-invoker.js +22 -12
- package/dist/server/cli/headless/claude-invoker.js.map +1 -1
- package/dist/server/cli/headless/headless-logger.d.ts +10 -0
- package/dist/server/cli/headless/headless-logger.d.ts.map +1 -0
- package/dist/server/cli/headless/headless-logger.js +66 -0
- package/dist/server/cli/headless/headless-logger.js.map +1 -0
- package/dist/server/cli/headless/mcp-config.d.ts.map +1 -1
- package/dist/server/cli/headless/mcp-config.js +6 -5
- package/dist/server/cli/headless/mcp-config.js.map +1 -1
- package/dist/server/cli/headless/runner.d.ts.map +1 -1
- package/dist/server/cli/headless/runner.js +4 -0
- package/dist/server/cli/headless/runner.js.map +1 -1
- package/dist/server/cli/headless/stall-assessor.d.ts +21 -0
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +100 -24
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts +0 -12
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.js +22 -9
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
- package/dist/server/cli/headless/types.d.ts +8 -1
- package/dist/server/cli/headless/types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +16 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +94 -11
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/mcp/bouncer-cli.d.ts +3 -0
- package/dist/server/mcp/bouncer-cli.d.ts.map +1 -0
- package/dist/server/mcp/bouncer-cli.js +54 -0
- package/dist/server/mcp/bouncer-cli.js.map +1 -0
- package/dist/server/services/plan/composer.d.ts +4 -0
- package/dist/server/services/plan/composer.d.ts.map +1 -0
- package/dist/server/services/plan/composer.js +181 -0
- package/dist/server/services/plan/composer.js.map +1 -0
- package/dist/server/services/plan/dependency-resolver.d.ts +28 -0
- package/dist/server/services/plan/dependency-resolver.d.ts.map +1 -0
- package/dist/server/services/plan/dependency-resolver.js +154 -0
- package/dist/server/services/plan/dependency-resolver.js.map +1 -0
- package/dist/server/services/plan/executor.d.ts +110 -0
- package/dist/server/services/plan/executor.d.ts.map +1 -0
- package/dist/server/services/plan/executor.js +641 -0
- package/dist/server/services/plan/executor.js.map +1 -0
- package/dist/server/services/plan/parser.d.ts +11 -0
- package/dist/server/services/plan/parser.d.ts.map +1 -0
- package/dist/server/services/plan/parser.js +445 -0
- package/dist/server/services/plan/parser.js.map +1 -0
- package/dist/server/services/plan/state-reconciler.d.ts +2 -0
- package/dist/server/services/plan/state-reconciler.d.ts.map +1 -0
- package/dist/server/services/plan/state-reconciler.js +145 -0
- package/dist/server/services/plan/state-reconciler.js.map +1 -0
- package/dist/server/services/plan/types.d.ts +121 -0
- package/dist/server/services/plan/types.d.ts.map +1 -0
- package/dist/server/services/plan/types.js +4 -0
- package/dist/server/services/plan/types.js.map +1 -0
- package/dist/server/services/plan/watcher.d.ts +14 -0
- package/dist/server/services/plan/watcher.d.ts.map +1 -0
- package/dist/server/services/plan/watcher.js +69 -0
- package/dist/server/services/plan/watcher.js.map +1 -0
- package/dist/server/services/websocket/file-explorer-handlers.js +20 -0
- package/dist/server/services/websocket/file-explorer-handlers.js.map +1 -1
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +21 -0
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/plan-handlers.d.ts +6 -0
- package/dist/server/services/websocket/plan-handlers.d.ts.map +1 -0
- package/dist/server/services/websocket/plan-handlers.js +494 -0
- package/dist/server/services/websocket/plan-handlers.js.map +1 -0
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +384 -12
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-persistence.d.ts +45 -0
- package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-persistence.js +187 -0
- package/dist/server/services/websocket/quality-persistence.js.map +1 -0
- package/dist/server/services/websocket/quality-service.d.ts +12 -2
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +162 -18
- package/dist/server/services/websocket/quality-service.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 +3 -3
- package/server/cli/headless/claude-invoker.ts +25 -12
- package/server/cli/headless/headless-logger.ts +78 -0
- package/server/cli/headless/mcp-config.ts +6 -5
- package/server/cli/headless/runner.ts +4 -0
- package/server/cli/headless/stall-assessor.ts +131 -24
- package/server/cli/headless/tool-watchdog.ts +10 -9
- package/server/cli/headless/types.ts +10 -1
- package/server/cli/improvisation-session-manager.ts +118 -11
- package/server/mcp/bouncer-cli.ts +73 -0
- package/server/services/plan/composer.ts +199 -0
- package/server/services/plan/dependency-resolver.ts +182 -0
- package/server/services/plan/executor.ts +700 -0
- package/server/services/plan/parser.ts +491 -0
- package/server/services/plan/state-reconciler.ts +174 -0
- package/server/services/plan/types.ts +166 -0
- package/server/services/plan/watcher.ts +73 -0
- package/server/services/websocket/file-explorer-handlers.ts +20 -0
- package/server/services/websocket/handler.ts +21 -0
- package/server/services/websocket/plan-handlers.ts +592 -0
- package/server/services/websocket/quality-handlers.ts +450 -12
- package/server/services/websocket/quality-persistence.ts +250 -0
- package/server/services/websocket/quality-service.ts +183 -18
- package/server/services/websocket/types.ts +48 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Plan Types — Project Plan Spec (PPS) data structures
|
|
6
|
+
*
|
|
7
|
+
* These types represent the parsed contents of .pm/ directory files.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Project Config (project.md front matter)
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
export interface ProjectConfig {
|
|
15
|
+
name: string;
|
|
16
|
+
id: string;
|
|
17
|
+
created: string;
|
|
18
|
+
status: 'active' | 'paused' | 'completed' | 'archived';
|
|
19
|
+
estimation: 'fibonacci' | 'tshirt' | 'hours' | 'none';
|
|
20
|
+
idPrefixes: Record<string, string>;
|
|
21
|
+
workflows: WorkflowStatus[];
|
|
22
|
+
labels: string[];
|
|
23
|
+
teams: Team[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface WorkflowStatus {
|
|
27
|
+
status: string;
|
|
28
|
+
category: 'unstarted' | 'started' | 'completed' | 'cancelled';
|
|
29
|
+
description: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Team {
|
|
33
|
+
name: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Project State (STATE.md front matter + body)
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
export interface ProjectState {
|
|
42
|
+
project: string;
|
|
43
|
+
currentSprint: string | null;
|
|
44
|
+
activeMilestone: string | null;
|
|
45
|
+
paused: boolean;
|
|
46
|
+
lastSession: string | null;
|
|
47
|
+
// Parsed from markdown body sections:
|
|
48
|
+
readyToWork: IssueSummary[];
|
|
49
|
+
inProgress: IssueSummary[];
|
|
50
|
+
blocked: IssueSummary[];
|
|
51
|
+
recentlyCompleted: IssueSummary[];
|
|
52
|
+
warnings: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface IssueSummary {
|
|
56
|
+
id: string;
|
|
57
|
+
title: string;
|
|
58
|
+
path: string;
|
|
59
|
+
priority: string;
|
|
60
|
+
blockedBy?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Issue / Epic / Bug (backlog/*.md)
|
|
65
|
+
// ============================================================================
|
|
66
|
+
|
|
67
|
+
export interface Issue {
|
|
68
|
+
id: string;
|
|
69
|
+
title: string;
|
|
70
|
+
type: 'issue' | 'epic' | 'bug' | 'task';
|
|
71
|
+
status: string;
|
|
72
|
+
priority: string;
|
|
73
|
+
estimate: number | string | null;
|
|
74
|
+
labels: string[];
|
|
75
|
+
epic: string | null;
|
|
76
|
+
sprint: string | null;
|
|
77
|
+
milestone: string | null;
|
|
78
|
+
assigned: string | null;
|
|
79
|
+
created: string;
|
|
80
|
+
updated: string | null;
|
|
81
|
+
due: string | null;
|
|
82
|
+
blockedBy: string[];
|
|
83
|
+
blocks: string[];
|
|
84
|
+
relatesTo: string[];
|
|
85
|
+
// Body sections
|
|
86
|
+
description: string;
|
|
87
|
+
acceptanceCriteria: AcceptanceCriterion[];
|
|
88
|
+
technicalNotes: string | null;
|
|
89
|
+
filesToModify: string[];
|
|
90
|
+
activity: string[];
|
|
91
|
+
// Children (for epics)
|
|
92
|
+
children: string[];
|
|
93
|
+
// Progress (for epics)
|
|
94
|
+
progress: string | null;
|
|
95
|
+
// Planned output file path (from front matter output_file, relative to working dir)
|
|
96
|
+
outputFile: string | null;
|
|
97
|
+
// Full markdown body
|
|
98
|
+
body: string;
|
|
99
|
+
// File path relative to .pm/
|
|
100
|
+
path: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface AcceptanceCriterion {
|
|
104
|
+
text: string;
|
|
105
|
+
checked: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Sprint (sprints/*.md)
|
|
110
|
+
// ============================================================================
|
|
111
|
+
|
|
112
|
+
export interface Sprint {
|
|
113
|
+
id: string;
|
|
114
|
+
title: string;
|
|
115
|
+
status: 'planned' | 'active' | 'completed';
|
|
116
|
+
start: string;
|
|
117
|
+
end: string;
|
|
118
|
+
goal: string;
|
|
119
|
+
capacity: number | null;
|
|
120
|
+
committed: number | null;
|
|
121
|
+
completed: number | null;
|
|
122
|
+
issues: SprintIssueSummary[];
|
|
123
|
+
path: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface SprintIssueSummary {
|
|
127
|
+
id: string;
|
|
128
|
+
title: string;
|
|
129
|
+
path: string;
|
|
130
|
+
points: number | string | null;
|
|
131
|
+
status: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Milestone (milestones/*.md)
|
|
136
|
+
// ============================================================================
|
|
137
|
+
|
|
138
|
+
export interface Milestone {
|
|
139
|
+
id: string;
|
|
140
|
+
title: string;
|
|
141
|
+
status: 'planned' | 'in_progress' | 'completed' | 'missed';
|
|
142
|
+
targetDate: string | null;
|
|
143
|
+
progress: string | null;
|
|
144
|
+
definition: string;
|
|
145
|
+
epics: MilestoneEpicSummary[];
|
|
146
|
+
path: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface MilestoneEpicSummary {
|
|
150
|
+
id: string;
|
|
151
|
+
title: string;
|
|
152
|
+
path: string;
|
|
153
|
+
progress: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ============================================================================
|
|
157
|
+
// Plan full state (sent on planInit)
|
|
158
|
+
// ============================================================================
|
|
159
|
+
|
|
160
|
+
export interface PlanFullState {
|
|
161
|
+
project: ProjectConfig;
|
|
162
|
+
state: ProjectState;
|
|
163
|
+
issues: Issue[];
|
|
164
|
+
sprints: Sprint[];
|
|
165
|
+
milestones: Milestone[];
|
|
166
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Plan Watcher — Watches .pm/ (or legacy .plan/) directory for changes and broadcasts updates.
|
|
6
|
+
*
|
|
7
|
+
* Uses fs.watch with debouncing to batch rapid changes.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { type FSWatcher, watch } from 'node:fs';
|
|
11
|
+
import type { HandlerContext } from '../websocket/handler-context.js';
|
|
12
|
+
import { parsePlanDirectory, resolvePmDir } from './parser.js';
|
|
13
|
+
|
|
14
|
+
export class PlanWatcher {
|
|
15
|
+
private watcher: FSWatcher | null = null;
|
|
16
|
+
private debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
17
|
+
private readonly workingDir: string;
|
|
18
|
+
private readonly ctx: HandlerContext;
|
|
19
|
+
private started = false;
|
|
20
|
+
|
|
21
|
+
constructor(workingDir: string, ctx: HandlerContext) {
|
|
22
|
+
this.workingDir = workingDir;
|
|
23
|
+
this.ctx = ctx;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
start(): void {
|
|
27
|
+
if (this.started) return;
|
|
28
|
+
|
|
29
|
+
const planDir = resolvePmDir(this.workingDir);
|
|
30
|
+
if (!planDir) return;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
this.watcher = watch(planDir, { recursive: true }, (_event, filename) => {
|
|
34
|
+
if (!filename || !filename.endsWith('.md')) return;
|
|
35
|
+
this.debounce();
|
|
36
|
+
});
|
|
37
|
+
this.started = true;
|
|
38
|
+
} catch {
|
|
39
|
+
// fs.watch recursive may not be supported on all platforms
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
stop(): void {
|
|
44
|
+
if (this.watcher) {
|
|
45
|
+
this.watcher.close();
|
|
46
|
+
this.watcher = null;
|
|
47
|
+
}
|
|
48
|
+
if (this.debounceTimer) {
|
|
49
|
+
clearTimeout(this.debounceTimer);
|
|
50
|
+
this.debounceTimer = null;
|
|
51
|
+
}
|
|
52
|
+
this.started = false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private debounce(): void {
|
|
56
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
57
|
+
this.debounceTimer = setTimeout(() => {
|
|
58
|
+
this.handleChange();
|
|
59
|
+
}, 200);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private handleChange(): void {
|
|
63
|
+
try {
|
|
64
|
+
// Always do a full reparse — concurrent changes may affect multiple files
|
|
65
|
+
const fullState = parsePlanDirectory(this.workingDir);
|
|
66
|
+
if (fullState) {
|
|
67
|
+
this.ctx.broadcastToAll({ type: 'planStateUpdated', data: fullState });
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
// Ignore parse errors from partial writes
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -542,6 +542,22 @@ function handleFindDefinition(ctx: HandlerContext, ws: WSContext, msg: WebSocket
|
|
|
542
542
|
`(fn|struct|enum|trait|type|const|static|mod)\\s+${s}\\b`,
|
|
543
543
|
`impl\\s+${s}\\b`,
|
|
544
544
|
],
|
|
545
|
+
swift: (s) => [
|
|
546
|
+
`(func|class|struct|enum|protocol|typealias|actor)\\s+${s}\\b`,
|
|
547
|
+
`(let|var)\\s+${s}\\b`,
|
|
548
|
+
`extension\\s+${s}\\b`,
|
|
549
|
+
],
|
|
550
|
+
kotlin: (s) => [
|
|
551
|
+
`(fun|class|object|interface|typealias|enum\\s+class)\\s+${s}\\b`,
|
|
552
|
+
`(val|var)\\s+${s}\\b`,
|
|
553
|
+
],
|
|
554
|
+
java: (s) => [
|
|
555
|
+
`(class|interface|enum)\\s+${s}\\b`,
|
|
556
|
+
`(public|private|protected|static)?\\s*(void|int|String|boolean|\\w+)\\s+${s}\\s*\\(`,
|
|
557
|
+
],
|
|
558
|
+
ruby: (s) => [
|
|
559
|
+
`(def|class|module)\\s+${s}\\b`,
|
|
560
|
+
],
|
|
545
561
|
};
|
|
546
562
|
|
|
547
563
|
const LANGUAGE_GLOBS: Record<string, string> = {
|
|
@@ -550,6 +566,10 @@ function handleFindDefinition(ctx: HandlerContext, ws: WSContext, msg: WebSocket
|
|
|
550
566
|
python: '*.py',
|
|
551
567
|
go: '*.go',
|
|
552
568
|
rust: '*.rs',
|
|
569
|
+
swift: '*.swift',
|
|
570
|
+
kotlin: '*.{kt,kts}',
|
|
571
|
+
java: '*.java',
|
|
572
|
+
ruby: '*.rb',
|
|
553
573
|
};
|
|
554
574
|
|
|
555
575
|
const patterns = DEFINITION_PATTERNS[language] || DEFINITION_PATTERNS.typescript;
|
|
@@ -19,6 +19,7 @@ import { handleFileExplorerMessage, handleFileMessage } from './file-explorer-ha
|
|
|
19
19
|
import { FileUploadHandler } from './file-upload-handler.js';
|
|
20
20
|
import { handleGitMessage } from './git-handlers.js';
|
|
21
21
|
import type { HandlerContext, UsageReporter } from './handler-context.js';
|
|
22
|
+
import { handlePlanMessage } from './plan-handlers.js';
|
|
22
23
|
import { handleQualityMessage } from './quality-handlers.js';
|
|
23
24
|
import { handleHistoryMessage, handleSessionMessage, initializeTab, resumeHistoricalSession } from './session-handlers.js';
|
|
24
25
|
import { SessionRegistry } from './session-registry.js';
|
|
@@ -226,7 +227,27 @@ export class WebSocketImproviseHandler implements HandlerContext {
|
|
|
226
227
|
case 'qualityScan':
|
|
227
228
|
case 'qualityInstallTools':
|
|
228
229
|
case 'qualityCodeReview':
|
|
230
|
+
case 'qualityFixIssues':
|
|
231
|
+
case 'qualityLoadState':
|
|
232
|
+
case 'qualitySaveDirectories':
|
|
229
233
|
return handleQualityMessage(this, ws, msg, tabId, workingDir);
|
|
234
|
+
// Plan messages
|
|
235
|
+
case 'planInit':
|
|
236
|
+
case 'planGetState':
|
|
237
|
+
case 'planListIssues':
|
|
238
|
+
case 'planGetIssue':
|
|
239
|
+
case 'planGetSprint':
|
|
240
|
+
case 'planGetMilestone':
|
|
241
|
+
case 'planCreateIssue':
|
|
242
|
+
case 'planUpdateIssue':
|
|
243
|
+
case 'planDeleteIssue':
|
|
244
|
+
case 'planScaffold':
|
|
245
|
+
case 'planPrompt':
|
|
246
|
+
case 'planExecute':
|
|
247
|
+
case 'planPause':
|
|
248
|
+
case 'planStop':
|
|
249
|
+
case 'planResume':
|
|
250
|
+
return handlePlanMessage(this, ws, msg, tabId, workingDir, permission);
|
|
230
251
|
// Settings messages
|
|
231
252
|
case 'getSettings':
|
|
232
253
|
return handleGetSettings(this, ws);
|