@auto-engineer/cli 0.8.4 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugin-loader.d.ts +1 -0
- package/dist/src/plugin-loader.d.ts.map +1 -1
- package/dist/src/plugin-loader.js +22 -29
- package/dist/src/plugin-loader.js.map +1 -1
- package/dist/src/server/dashboard.html +330 -52
- package/dist/src/server/event-processor.d.ts +21 -9
- package/dist/src/server/event-processor.d.ts.map +1 -1
- package/dist/src/server/event-processor.js +101 -25
- package/dist/src/server/event-processor.js.map +1 -1
- package/dist/src/server/file-syncer/discovery/bareImports.d.ts +3 -0
- package/dist/src/server/file-syncer/discovery/bareImports.d.ts.map +1 -0
- package/dist/src/server/file-syncer/discovery/bareImports.js +36 -0
- package/dist/src/server/file-syncer/discovery/bareImports.js.map +1 -0
- package/dist/src/server/file-syncer/discovery/dts.d.ts +11 -0
- package/dist/src/server/file-syncer/discovery/dts.d.ts.map +1 -0
- package/dist/src/server/file-syncer/discovery/dts.js +108 -0
- package/dist/src/server/file-syncer/discovery/dts.js.map +1 -0
- package/dist/src/server/file-syncer/index.d.ts +17 -0
- package/dist/src/server/file-syncer/index.d.ts.map +1 -0
- package/dist/src/server/file-syncer/index.js +210 -0
- package/dist/src/server/file-syncer/index.js.map +1 -0
- package/dist/src/server/file-syncer/sync/resolveSyncFileSet.d.ts +7 -0
- package/dist/src/server/file-syncer/sync/resolveSyncFileSet.d.ts.map +1 -0
- package/dist/src/server/file-syncer/sync/resolveSyncFileSet.js +76 -0
- package/dist/src/server/file-syncer/sync/resolveSyncFileSet.js.map +1 -0
- package/dist/src/server/file-syncer/types/wire.d.ts +14 -0
- package/dist/src/server/file-syncer/types/wire.d.ts.map +1 -0
- package/dist/src/server/file-syncer/types/wire.js +2 -0
- package/dist/src/server/file-syncer/types/wire.js.map +1 -0
- package/dist/src/server/file-syncer/utils/hash.d.ts +5 -0
- package/dist/src/server/file-syncer/utils/hash.d.ts.map +1 -0
- package/dist/src/server/file-syncer/utils/hash.js +20 -0
- package/dist/src/server/file-syncer/utils/hash.js.map +1 -0
- package/dist/src/server/file-syncer/utils/path.d.ts +15 -0
- package/dist/src/server/file-syncer/utils/path.d.ts.map +1 -0
- package/dist/src/server/file-syncer/utils/path.js +100 -0
- package/dist/src/server/file-syncer/utils/path.js.map +1 -0
- package/dist/src/server/http-routes.d.ts +4 -5
- package/dist/src/server/http-routes.d.ts.map +1 -1
- package/dist/src/server/http-routes.js +234 -31
- package/dist/src/server/http-routes.js.map +1 -1
- package/dist/src/server/server.d.ts +8 -10
- package/dist/src/server/server.d.ts.map +1 -1
- package/dist/src/server/server.js +21 -13
- package/dist/src/server/server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -4
- package/dist/src/server/file-syncer.d.ts +0 -21
- package/dist/src/server/file-syncer.d.ts.map +0 -1
- package/dist/src/server/file-syncer.js +0 -101
- package/dist/src/server/file-syncer.js.map +0 -1
|
@@ -1,27 +1,28 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid';
|
|
1
2
|
import createDebug from 'debug';
|
|
2
3
|
const debugBus = createDebug('auto-engineer:server:bus');
|
|
3
4
|
export class EventProcessor {
|
|
4
|
-
constructor(messageBus, stateManager, onEventBroadcast) {
|
|
5
|
+
constructor(messageBus, messageStore, stateManager, onEventBroadcast) {
|
|
5
6
|
this.messageBus = messageBus;
|
|
7
|
+
this.messageStore = messageStore;
|
|
6
8
|
this.stateManager = stateManager;
|
|
7
9
|
this.onEventBroadcast = onEventBroadcast;
|
|
8
10
|
this.eventHandlers = new Map();
|
|
9
|
-
this.
|
|
10
|
-
this.maxEventHistory = 1000;
|
|
11
|
+
this.correlationContext = new Map(); // requestId -> correlationId mapping
|
|
11
12
|
}
|
|
12
13
|
setupGlobalEventListener() {
|
|
13
14
|
this.messageBus.subscribeAll({
|
|
14
15
|
name: 'ServerStateManager',
|
|
15
16
|
handle: async (event) => {
|
|
16
|
-
debugBus('Received event:', event.type);
|
|
17
|
-
// Store event in
|
|
18
|
-
|
|
19
|
-
event,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
debugBus('Received event:', event.type, JSON.stringify(event));
|
|
18
|
+
// Store event in message store
|
|
19
|
+
try {
|
|
20
|
+
await this.messageStore.saveMessages('$all-events', [event], undefined, 'event');
|
|
21
|
+
await this.messageStore.saveMessages(`event-${event.type}`, [event], undefined, 'event');
|
|
22
|
+
debugBus('Event stored in message store:', event.type);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
debugBus('Error storing event:', error);
|
|
25
26
|
}
|
|
26
27
|
// Apply event to state
|
|
27
28
|
this.stateManager.applyEvent(event);
|
|
@@ -92,16 +93,18 @@ export class EventProcessor {
|
|
|
92
93
|
typeof command === 'object' &&
|
|
93
94
|
'type' in command &&
|
|
94
95
|
'data' in command) {
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
const enhancedCommand = this.enhanceCommandWithIds(command);
|
|
97
|
+
debugBus('Dispatching command:', enhancedCommand.type);
|
|
98
|
+
await this.messageBus.sendCommand(enhancedCommand);
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
async processActionOrCommand(action) {
|
|
101
103
|
const actionObj = action;
|
|
102
104
|
if (actionObj !== null && typeof actionObj === 'object' && 'data' in actionObj) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
const enhancedCommand = this.enhanceCommandWithIds(action);
|
|
106
|
+
debugBus('Dispatching command from event handler:', enhancedCommand.type);
|
|
107
|
+
await this.messageBus.sendCommand(enhancedCommand);
|
|
105
108
|
}
|
|
106
109
|
else {
|
|
107
110
|
await this.processDispatchAction(action);
|
|
@@ -125,21 +128,24 @@ export class EventProcessor {
|
|
|
125
128
|
}
|
|
126
129
|
async handleSingleDispatch(action) {
|
|
127
130
|
if (action.command) {
|
|
128
|
-
|
|
129
|
-
|
|
131
|
+
const enhancedCommand = this.enhanceCommandWithIds(action.command);
|
|
132
|
+
debugBus('Dispatching command from dispatch action:', enhancedCommand.type);
|
|
133
|
+
await this.messageBus.sendCommand(enhancedCommand);
|
|
130
134
|
}
|
|
131
135
|
}
|
|
132
136
|
async handleParallelDispatch(action) {
|
|
133
137
|
if (action.commands) {
|
|
134
138
|
debugBus('Dispatching parallel commands from event handler');
|
|
135
|
-
|
|
139
|
+
const enhancedCommands = action.commands.map((cmd) => this.enhanceCommandWithIds(cmd));
|
|
140
|
+
await Promise.all(enhancedCommands.map((cmd) => this.messageBus.sendCommand(cmd)));
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
async handleSequentialDispatch(action) {
|
|
139
144
|
if (action.commands) {
|
|
140
145
|
debugBus('Dispatching sequential commands from event handler');
|
|
141
146
|
for (const cmd of action.commands) {
|
|
142
|
-
|
|
147
|
+
const enhancedCommand = this.enhanceCommandWithIds(cmd);
|
|
148
|
+
await this.messageBus.sendCommand(enhancedCommand);
|
|
143
149
|
}
|
|
144
150
|
}
|
|
145
151
|
}
|
|
@@ -148,18 +154,88 @@ export class EventProcessor {
|
|
|
148
154
|
const cmds = action.commandFactory();
|
|
149
155
|
const commands = Array.isArray(cmds) ? cmds : [cmds];
|
|
150
156
|
for (const cmd of commands) {
|
|
151
|
-
|
|
157
|
+
const enhancedCommand = this.enhanceCommandWithIds(cmd);
|
|
158
|
+
await this.messageBus.sendCommand(enhancedCommand);
|
|
152
159
|
}
|
|
153
160
|
}
|
|
154
161
|
}
|
|
155
162
|
getEventHandlers() {
|
|
156
163
|
return this.eventHandlers;
|
|
157
164
|
}
|
|
158
|
-
|
|
159
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Store a command in the message store
|
|
167
|
+
*/
|
|
168
|
+
async storeCommand(command) {
|
|
169
|
+
try {
|
|
170
|
+
const enhancedCommand = this.enhanceCommandWithIds(command);
|
|
171
|
+
await this.messageStore.saveMessages('$all-commands', [enhancedCommand], undefined, 'command');
|
|
172
|
+
await this.messageStore.saveMessages(`command-${enhancedCommand.type}`, [enhancedCommand], undefined, 'command');
|
|
173
|
+
// Store correlation context for this command's potential events
|
|
174
|
+
if (enhancedCommand.requestId !== undefined &&
|
|
175
|
+
enhancedCommand.requestId !== null &&
|
|
176
|
+
enhancedCommand.requestId !== '' &&
|
|
177
|
+
enhancedCommand.correlationId !== undefined &&
|
|
178
|
+
enhancedCommand.correlationId !== null &&
|
|
179
|
+
enhancedCommand.correlationId !== '') {
|
|
180
|
+
this.correlationContext.set(enhancedCommand.requestId, enhancedCommand.correlationId);
|
|
181
|
+
}
|
|
182
|
+
debugBus('Command stored in message store:', enhancedCommand.type);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
debugBus('Error storing command:', error);
|
|
186
|
+
}
|
|
160
187
|
}
|
|
161
|
-
|
|
162
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Enhance command with proper request and correlation IDs
|
|
190
|
+
*/
|
|
191
|
+
enhanceCommandWithIds(command) {
|
|
192
|
+
const now = new Date();
|
|
193
|
+
// Generate requestId if not present
|
|
194
|
+
const requestId = command.requestId ?? `req-${Date.now()}-${nanoid(8)}`;
|
|
195
|
+
// Handle correlation ID:
|
|
196
|
+
// 1. Use existing correlationId if present
|
|
197
|
+
// 2. If triggered by another command/event, inherit its correlationId
|
|
198
|
+
// 3. Otherwise, create new correlationId
|
|
199
|
+
let correlationId = command.correlationId;
|
|
200
|
+
if (correlationId === undefined || correlationId === null || correlationId === '') {
|
|
201
|
+
// Try to inherit from correlation context (if this command is triggered by an event)
|
|
202
|
+
const inheritedCorrelationId = this.findInheritedCorrelationId(command);
|
|
203
|
+
correlationId = inheritedCorrelationId ?? `corr-${Date.now()}-${nanoid(8)}`;
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
...command,
|
|
207
|
+
requestId,
|
|
208
|
+
correlationId,
|
|
209
|
+
timestamp: command.timestamp || now,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Try to find a correlation ID to inherit from the current context
|
|
214
|
+
*/
|
|
215
|
+
findInheritedCorrelationId(_command) {
|
|
216
|
+
// This is a simplified implementation - in a more sophisticated system,
|
|
217
|
+
// you might use async context tracking or other mechanisms
|
|
218
|
+
// For now, try to find the most recent correlation ID from the context map
|
|
219
|
+
const contextEntries = Array.from(this.correlationContext.entries());
|
|
220
|
+
if (contextEntries.length > 0) {
|
|
221
|
+
// Return the most recently stored correlation ID
|
|
222
|
+
return contextEntries[contextEntries.length - 1][1];
|
|
223
|
+
}
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Clear correlation context periodically to prevent memory leaks
|
|
228
|
+
*/
|
|
229
|
+
cleanupCorrelationContext() {
|
|
230
|
+
// Keep only the last 1000 entries
|
|
231
|
+
if (this.correlationContext.size > 1000) {
|
|
232
|
+
const entries = Array.from(this.correlationContext.entries());
|
|
233
|
+
this.correlationContext.clear();
|
|
234
|
+
// Keep the last 500 entries
|
|
235
|
+
entries.slice(-500).forEach(([requestId, correlationId]) => {
|
|
236
|
+
this.correlationContext.set(requestId, correlationId);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
163
239
|
}
|
|
164
240
|
}
|
|
165
241
|
//# sourceMappingURL=event-processor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-processor.js","sourceRoot":"","sources":["../../../src/server/event-processor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"event-processor.js","sourceRoot":"","sources":["../../../src/server/event-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bareImports.d.ts","sourceRoot":"","sources":["../../../../../src/server/file-syncer/discovery/bareImports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAiB1D,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkBxG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const BARE_IMPORT_RE = /\bfrom\s+['"]([^'"]+)['"]|require\(\s*['"]([^'"]+)['"]\s*\)|\bimport\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
2
|
+
function isBare(spec) {
|
|
3
|
+
return !!spec && !spec.startsWith('.') && !spec.startsWith('/') && !spec.startsWith('node:');
|
|
4
|
+
}
|
|
5
|
+
function basePackageOf(spec) {
|
|
6
|
+
if (spec.startsWith('@')) {
|
|
7
|
+
const parts = spec.split('/');
|
|
8
|
+
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : spec;
|
|
9
|
+
}
|
|
10
|
+
const i = spec.indexOf('/');
|
|
11
|
+
return i === -1 ? spec : spec.slice(0, i);
|
|
12
|
+
}
|
|
13
|
+
export async function collectBareImportsFromFiles(files, vfs) {
|
|
14
|
+
const pkgs = new Set();
|
|
15
|
+
for (const abs of files) {
|
|
16
|
+
if (!/\.(m?ts|m?js|tsx|jsx)$/i.test(abs))
|
|
17
|
+
continue;
|
|
18
|
+
try {
|
|
19
|
+
const buf = await vfs.read(abs);
|
|
20
|
+
if (!buf)
|
|
21
|
+
continue;
|
|
22
|
+
const src = new TextDecoder().decode(buf);
|
|
23
|
+
for (const m of src.matchAll(BARE_IMPORT_RE)) {
|
|
24
|
+
const raw = (m[1] ?? m[2] ?? m[3] ?? '').trim();
|
|
25
|
+
if (!isBare(raw))
|
|
26
|
+
continue;
|
|
27
|
+
pkgs.add(basePackageOf(raw));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// ignore per-file errors
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return [...pkgs];
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=bareImports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bareImports.js","sourceRoot":"","sources":["../../../../../src/server/file-syncer/discovery/bareImports.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAClB,iGAAiG,CAAC;AAEpG,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC/F,CAAC;AACD,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KAAe,EAAE,GAAkB;IACnF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACnD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1C,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC7C,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBAChD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;oBAAE,SAAS;gBAC3B,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NodeFileStore } from '@auto-engineer/file-store';
|
|
2
|
+
export declare function readJsonIfExists(vfs: NodeFileStore, p: string): Promise<Record<string, unknown> | null>;
|
|
3
|
+
export declare function exists(vfs: NodeFileStore, p: string): Promise<boolean>;
|
|
4
|
+
export declare function typesAlias(pkg: string): string;
|
|
5
|
+
/** From a list of “base directories”, add each ancestor’s node_modules*/
|
|
6
|
+
export declare function nmRootsForBases(bases: string[], maxUp?: number): string[];
|
|
7
|
+
/** Probe a single package for its entry .d.ts inside a given nm root. */
|
|
8
|
+
export declare function probeEntryDtsInRoot(vfs: NodeFileStore, nmRoot: string, pkg: string): Promise<string | null>;
|
|
9
|
+
/** For each external pkg, choose at most ONE entry d.ts by scanning across provided nm roots. */
|
|
10
|
+
export declare function probeEntryDtsForPackagesFromRoots(vfs: NodeFileStore, nmRoots: string[], pkgs: string[]): Promise<string[]>;
|
|
11
|
+
//# sourceMappingURL=dts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dts.d.ts","sourceRoot":"","sources":["../../../../../src/server/file-syncer/discovery/dts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAM1D,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAQ7G;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAYpE;AAED,yEAAyE;AACzE,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBjH;AAED,iGAAiG;AACjG,wBAAsB,iCAAiC,CACrD,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,MAAM,EAAE,CAAC,CAuCnB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import createDebug from 'debug';
|
|
2
|
+
import { posix } from '../utils/path.js';
|
|
3
|
+
const debug = createDebug('auto-engineer:file-syncer:dts');
|
|
4
|
+
export async function readJsonIfExists(vfs, p) {
|
|
5
|
+
try {
|
|
6
|
+
const buf = await vfs.read(p);
|
|
7
|
+
if (!buf)
|
|
8
|
+
return null;
|
|
9
|
+
return JSON.parse(new TextDecoder().decode(buf));
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function exists(vfs, p) {
|
|
16
|
+
try {
|
|
17
|
+
const buf = await vfs.read(p);
|
|
18
|
+
return !!buf;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function typesAlias(pkg) {
|
|
25
|
+
if (pkg.startsWith('@')) {
|
|
26
|
+
const [scope, name] = pkg.split('/');
|
|
27
|
+
return `@types/${scope.slice(1)}__${name}`;
|
|
28
|
+
}
|
|
29
|
+
return `@types/${pkg}`;
|
|
30
|
+
}
|
|
31
|
+
/** From a list of “base directories”, add each ancestor’s node_modules*/
|
|
32
|
+
export function nmRootsForBases(bases, maxUp = 8) {
|
|
33
|
+
const roots = new Set();
|
|
34
|
+
for (const base of bases) {
|
|
35
|
+
let cur = base.replace(/\\/g, '/');
|
|
36
|
+
for (let i = 0; i < maxUp; i++) {
|
|
37
|
+
roots.add(`${cur}/node_modules`);
|
|
38
|
+
const parent = cur.replace(/\/+$/, '').split('/').slice(0, -1).join('/') || '/';
|
|
39
|
+
if (parent === cur)
|
|
40
|
+
break;
|
|
41
|
+
cur = parent;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return [...roots].map((p) => p.replace(/\/+/g, '/'));
|
|
45
|
+
}
|
|
46
|
+
/** Probe a single package for its entry .d.ts inside a given nm root. */
|
|
47
|
+
export async function probeEntryDtsInRoot(vfs, nmRoot, pkg) {
|
|
48
|
+
const pkgDir = `${nmRoot}/${pkg}`.replace(/\/+/g, '/');
|
|
49
|
+
// package.json types/typings
|
|
50
|
+
const pj = await readJsonIfExists(vfs, `${pkgDir}/package.json`);
|
|
51
|
+
if (pj && (typeof pj.types === 'string' || typeof pj.typings === 'string')) {
|
|
52
|
+
const rel = String(pj.types ?? pj.typings);
|
|
53
|
+
const abs = posix(`${pkgDir}/${rel}`.replace(/\/+/g, '/'));
|
|
54
|
+
if (await exists(vfs, abs))
|
|
55
|
+
return abs;
|
|
56
|
+
}
|
|
57
|
+
// index.d.ts at root
|
|
58
|
+
const idx = posix(`${pkgDir}/index.d.ts`);
|
|
59
|
+
if (await exists(vfs, idx))
|
|
60
|
+
return idx;
|
|
61
|
+
// dist/index.d.ts (very common)
|
|
62
|
+
const distIdx = posix(`${pkgDir}/dist/index.d.ts`);
|
|
63
|
+
if (await exists(vfs, distIdx))
|
|
64
|
+
return distIdx;
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/** For each external pkg, choose at most ONE entry d.ts by scanning across provided nm roots. */
|
|
68
|
+
export async function probeEntryDtsForPackagesFromRoots(vfs, nmRoots, pkgs) {
|
|
69
|
+
function scorePath(p) {
|
|
70
|
+
// lower score = better
|
|
71
|
+
let s = 0;
|
|
72
|
+
const pathPosix = p.replace(/\\/g, '/');
|
|
73
|
+
if (pathPosix.includes('/server/node_modules/'))
|
|
74
|
+
s -= 10;
|
|
75
|
+
if (!pathPosix.includes('/.pnpm/'))
|
|
76
|
+
s -= 3;
|
|
77
|
+
if (pathPosix.includes('/node_modules/'))
|
|
78
|
+
s -= 1;
|
|
79
|
+
s += pathPosix.length / 1000;
|
|
80
|
+
return s;
|
|
81
|
+
}
|
|
82
|
+
const out = new Set();
|
|
83
|
+
for (const pkg of pkgs) {
|
|
84
|
+
const candidates = [];
|
|
85
|
+
for (const nm of nmRoots) {
|
|
86
|
+
const hit = await probeEntryDtsInRoot(vfs, nm, pkg);
|
|
87
|
+
if (hit !== null)
|
|
88
|
+
candidates.push(hit);
|
|
89
|
+
}
|
|
90
|
+
if (candidates.length === 0) {
|
|
91
|
+
const alias = typesAlias(pkg);
|
|
92
|
+
for (const nm of nmRoots) {
|
|
93
|
+
const hit = await probeEntryDtsInRoot(vfs, nm, alias);
|
|
94
|
+
if (hit !== null)
|
|
95
|
+
candidates.push(hit);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (candidates.length) {
|
|
99
|
+
candidates.sort((a, b) => scorePath(a) - scorePath(b));
|
|
100
|
+
out.add(candidates[0]);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
debug('dts-probe: ⚠ no entry .d.ts found for %s', pkg);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return [...out];
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=dts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dts.js","sourceRoot":"","sources":["../../../../../src/server/file-syncer/discovery/dts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Server as SocketIOServer } from 'socket.io';
|
|
2
|
+
export declare class FileSyncer {
|
|
3
|
+
private io;
|
|
4
|
+
private watchDir;
|
|
5
|
+
private projectRoot;
|
|
6
|
+
private vfs;
|
|
7
|
+
private active;
|
|
8
|
+
private watcher?;
|
|
9
|
+
private debounce;
|
|
10
|
+
private lastComputeTime;
|
|
11
|
+
private cachedDesiredSet;
|
|
12
|
+
private pendingInitialFiles;
|
|
13
|
+
constructor(io: SocketIOServer, watchDir?: string, _extensions?: string[]);
|
|
14
|
+
start(): void;
|
|
15
|
+
stop(): void;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/server/file-syncer/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;AAY1D,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,OAAO,CAAC,CAAqB;IACrC,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,gBAAgB,CAA4B;IACpD,OAAO,CAAC,mBAAmB,CAAqC;gBAEpD,EAAE,EAAE,cAAc,EAAE,QAAQ,SAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE;IAQtE,KAAK,IAAI,IAAI;IAiMb,IAAI,IAAI,IAAI;CAQb"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import createDebug from 'debug';
|
|
4
|
+
import { NodeFileStore } from '@auto-engineer/file-store';
|
|
5
|
+
import { resolveSyncFileSet } from './sync/resolveSyncFileSet.js';
|
|
6
|
+
import { md5, readBase64, statSize } from './utils/hash.js';
|
|
7
|
+
import { toWirePath, fromWirePath, rebuildWirePathCache } from './utils/path.js';
|
|
8
|
+
const debug = createDebug('cli:file-syncer');
|
|
9
|
+
export class FileSyncer {
|
|
10
|
+
constructor(io, watchDir = '.', _extensions) {
|
|
11
|
+
this.debounce = null;
|
|
12
|
+
this.lastComputeTime = 0;
|
|
13
|
+
this.cachedDesiredSet = null;
|
|
14
|
+
this.pendingInitialFiles = null;
|
|
15
|
+
this.io = io;
|
|
16
|
+
this.watchDir = path.resolve(watchDir);
|
|
17
|
+
this.projectRoot = path.dirname(this.watchDir);
|
|
18
|
+
this.vfs = new NodeFileStore();
|
|
19
|
+
this.active = new Map();
|
|
20
|
+
}
|
|
21
|
+
start() {
|
|
22
|
+
const compute = async () => {
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
// Cache computeDesiredSet results for 1 second to prevent rapid repeated calls
|
|
25
|
+
if (this.cachedDesiredSet && now - this.lastComputeTime < 1000) {
|
|
26
|
+
return this.cachedDesiredSet;
|
|
27
|
+
}
|
|
28
|
+
const result = await resolveSyncFileSet({
|
|
29
|
+
vfs: this.vfs,
|
|
30
|
+
watchDir: this.watchDir,
|
|
31
|
+
projectRoot: this.projectRoot,
|
|
32
|
+
});
|
|
33
|
+
this.cachedDesiredSet = result;
|
|
34
|
+
this.lastComputeTime = now;
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
const initialFiles = async () => {
|
|
38
|
+
const desired = await compute();
|
|
39
|
+
const files = [];
|
|
40
|
+
for (const abs of desired) {
|
|
41
|
+
const content = await readBase64(this.vfs, abs);
|
|
42
|
+
if (content === null) {
|
|
43
|
+
console.warn(`[sync] Skipping file due to read failure: ${abs}`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const wire = toWirePath(abs, this.projectRoot);
|
|
47
|
+
const size = await statSize(this.vfs, abs);
|
|
48
|
+
const hash = await md5(this.vfs, abs);
|
|
49
|
+
if (hash === null) {
|
|
50
|
+
console.warn(`[sync] Skipping file due to hash failure: ${abs}`);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
this.active.set(abs, { hash, size });
|
|
54
|
+
files.push({ path: wire, content });
|
|
55
|
+
}
|
|
56
|
+
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
57
|
+
return { files, directory: path.resolve(this.watchDir) };
|
|
58
|
+
};
|
|
59
|
+
const computeChanges = async (desired) => {
|
|
60
|
+
const outgoing = [];
|
|
61
|
+
for (const abs of desired) {
|
|
62
|
+
const hash = await md5(this.vfs, abs);
|
|
63
|
+
if (hash === null) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const size = await statSize(this.vfs, abs);
|
|
67
|
+
const prev = this.active.get(abs);
|
|
68
|
+
if (!prev || prev.hash !== hash || prev.size !== size) {
|
|
69
|
+
const content = await readBase64(this.vfs, abs);
|
|
70
|
+
if (content === null) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
this.active.set(abs, { hash, size });
|
|
74
|
+
const wire = toWirePath(abs, this.projectRoot);
|
|
75
|
+
outgoing.push({ event: prev ? 'change' : 'add', path: wire, content });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return outgoing;
|
|
79
|
+
};
|
|
80
|
+
const computeDeletions = (desired) => {
|
|
81
|
+
const toDelete = [];
|
|
82
|
+
for (const abs of Array.from(this.active.keys())) {
|
|
83
|
+
if (!desired.has(abs)) {
|
|
84
|
+
this.active.delete(abs);
|
|
85
|
+
const wire = toWirePath(abs, this.projectRoot);
|
|
86
|
+
toDelete.push({ event: 'delete', path: wire });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return toDelete;
|
|
90
|
+
};
|
|
91
|
+
const handleEmptyTransition = (desired, toDelete) => {
|
|
92
|
+
if (this.active.size === 0 && desired.size === 0 && toDelete.length > 0) {
|
|
93
|
+
this.io.emit('initial-sync', { files: [], directory: path.resolve(this.watchDir) });
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
};
|
|
98
|
+
const handleRehydration = (activeSizeBefore, outgoing, desired) => {
|
|
99
|
+
const allAdds = outgoing.length > 0 && outgoing.every((x) => x.event === 'add');
|
|
100
|
+
const rehydrateFromEmpty = activeSizeBefore === 0 && allAdds && desired.size === outgoing.length;
|
|
101
|
+
if (rehydrateFromEmpty) {
|
|
102
|
+
const files = outgoing
|
|
103
|
+
.map((o) => ({ path: o.path, content: o.content }))
|
|
104
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
105
|
+
debug('REHYDRATE: Sending initial-sync with %d files', files.length);
|
|
106
|
+
this.io.emit('initial-sync', { files, directory: path.resolve(this.watchDir) });
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
};
|
|
111
|
+
const rebuildAndBroadcast = async () => {
|
|
112
|
+
const desired = await compute();
|
|
113
|
+
const activeSizeBefore = this.active.size;
|
|
114
|
+
const outgoing = await computeChanges(desired);
|
|
115
|
+
const toDelete = computeDeletions(desired);
|
|
116
|
+
for (const ch of toDelete) {
|
|
117
|
+
this.io.emit('file-change', ch);
|
|
118
|
+
}
|
|
119
|
+
if (handleEmptyTransition(desired, toDelete))
|
|
120
|
+
return;
|
|
121
|
+
if (handleRehydration(activeSizeBefore, outgoing, desired))
|
|
122
|
+
return;
|
|
123
|
+
// otherwise: normal incremental flow
|
|
124
|
+
for (const ch of outgoing) {
|
|
125
|
+
this.io.emit('file-change', ch);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
const scheduleRebuild = () => {
|
|
129
|
+
if (this.debounce)
|
|
130
|
+
clearTimeout(this.debounce);
|
|
131
|
+
this.debounce = setTimeout(() => {
|
|
132
|
+
this.debounce = null;
|
|
133
|
+
rebuildAndBroadcast().catch((err) => console.error('[sync] rebuild error', err));
|
|
134
|
+
}, 100);
|
|
135
|
+
};
|
|
136
|
+
this.watcher = chokidar.watch([this.watchDir], { ignoreInitial: true, persistent: true });
|
|
137
|
+
this.watcher
|
|
138
|
+
.on('add', (_filePath) => {
|
|
139
|
+
scheduleRebuild();
|
|
140
|
+
})
|
|
141
|
+
.on('change', (_filePath) => {
|
|
142
|
+
scheduleRebuild();
|
|
143
|
+
})
|
|
144
|
+
.on('unlink', (_filePath) => {
|
|
145
|
+
scheduleRebuild();
|
|
146
|
+
})
|
|
147
|
+
.on('addDir', (_dirPath) => {
|
|
148
|
+
scheduleRebuild();
|
|
149
|
+
})
|
|
150
|
+
.on('unlinkDir', (_dirPath) => {
|
|
151
|
+
scheduleRebuild();
|
|
152
|
+
})
|
|
153
|
+
.on('error', (err) => console.error('[watcher]', err));
|
|
154
|
+
this.io.on('connection', async (socket) => {
|
|
155
|
+
try {
|
|
156
|
+
// Deduplicate concurrent initialFiles calls by reusing pending promise
|
|
157
|
+
if (this.pendingInitialFiles) {
|
|
158
|
+
const init = await this.pendingInitialFiles;
|
|
159
|
+
socket.emit('initial-sync', init);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.pendingInitialFiles = initialFiles();
|
|
163
|
+
const init = await this.pendingInitialFiles;
|
|
164
|
+
this.pendingInitialFiles = null; // Clear after completion
|
|
165
|
+
// Rebuild wire path cache for external mappings to support reconnection
|
|
166
|
+
const files = Array.from(this.active.keys()).map((abs) => ({ abs, projectRoot: this.projectRoot }));
|
|
167
|
+
rebuildWirePathCache(files);
|
|
168
|
+
socket.emit('initial-sync', init);
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
console.error('[sync] initial-sync failed:', e);
|
|
172
|
+
this.pendingInitialFiles = null; // Clear on error
|
|
173
|
+
}
|
|
174
|
+
socket.on('client-file-change', async (msg) => {
|
|
175
|
+
// Use fromWirePath to handle virtual paths correctly
|
|
176
|
+
const abs = fromWirePath(msg.path, this.projectRoot);
|
|
177
|
+
try {
|
|
178
|
+
if (msg.event === 'delete') {
|
|
179
|
+
await this.vfs.remove(abs);
|
|
180
|
+
this.active.delete(abs);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const contentStr = msg.content;
|
|
184
|
+
if (contentStr === undefined) {
|
|
185
|
+
console.warn('[sync] client write: no content provided');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const content = Buffer.from(contentStr, 'base64');
|
|
189
|
+
await this.vfs.write(abs, new Uint8Array(content));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
console.error('[sync] client-file-change failed:', e);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
scheduleRebuild();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
stop() {
|
|
202
|
+
if (this.watcher) {
|
|
203
|
+
void this.watcher.close();
|
|
204
|
+
}
|
|
205
|
+
if (this.debounce) {
|
|
206
|
+
clearTimeout(this.debounce);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=index.js.map
|