@principal-ai/principal-view-core 0.6.3 → 0.7.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/dist/ConfigurationLoader.js +2 -1
- package/dist/ConfigurationLoader.js.map +1 -1
- package/dist/ConfigurationValidator.js.map +1 -1
- package/dist/EventProcessor.js.map +1 -1
- package/dist/EventRecorderService.js.map +1 -1
- package/dist/LibraryLoader.js.map +1 -1
- package/dist/PathBasedEventProcessor.js.map +1 -1
- package/dist/SessionManager.js +1 -1
- package/dist/SessionManager.js.map +1 -1
- package/dist/ValidationEngine.js.map +1 -1
- package/dist/cli/codegen.js.map +1 -1
- package/dist/codegen/type-generator.js.map +1 -1
- package/dist/codegen/usage-example.js.map +1 -1
- package/dist/helpers/GraphInstrumentationHelper.js +2 -2
- package/dist/helpers/GraphInstrumentationHelper.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/narrative/example.d.ts +11 -0
- package/dist/narrative/example.d.ts.map +1 -0
- package/dist/narrative/example.js +331 -0
- package/dist/narrative/example.js.map +1 -0
- package/dist/narrative/index.d.ts +12 -0
- package/dist/narrative/index.d.ts.map +1 -0
- package/dist/narrative/index.js +14 -0
- package/dist/narrative/index.js.map +1 -0
- package/dist/narrative/scenario-matcher.d.ts +87 -0
- package/dist/narrative/scenario-matcher.d.ts.map +1 -0
- package/dist/narrative/scenario-matcher.js +269 -0
- package/dist/narrative/scenario-matcher.js.map +1 -0
- package/dist/narrative/template-parser.d.ts +33 -0
- package/dist/narrative/template-parser.d.ts.map +1 -0
- package/dist/narrative/template-parser.js +288 -0
- package/dist/narrative/template-parser.js.map +1 -0
- package/dist/narrative/template-renderer.d.ts +18 -0
- package/dist/narrative/template-renderer.d.ts.map +1 -0
- package/dist/narrative/template-renderer.js +367 -0
- package/dist/narrative/template-renderer.js.map +1 -0
- package/dist/narrative/types.d.ts +268 -0
- package/dist/narrative/types.d.ts.map +1 -0
- package/dist/narrative/types.js +10 -0
- package/dist/narrative/types.js.map +1 -0
- package/dist/rules/config.js.map +1 -1
- package/dist/rules/engine.js.map +1 -1
- package/dist/rules/implementations/connection-type-references.js.map +1 -1
- package/dist/rules/implementations/dead-end-states.js.map +1 -1
- package/dist/rules/implementations/library-node-type-match.js.map +1 -1
- package/dist/rules/implementations/minimum-node-sources.js.map +1 -1
- package/dist/rules/implementations/no-unknown-fields.js.map +1 -1
- package/dist/rules/implementations/orphaned-edge-types.js.map +1 -1
- package/dist/rules/implementations/orphaned-node-types.js.map +1 -1
- package/dist/rules/implementations/required-metadata.js.map +1 -1
- package/dist/rules/implementations/state-transition-references.js.map +1 -1
- package/dist/rules/implementations/unreachable-states.js.map +1 -1
- package/dist/rules/implementations/valid-action-patterns.js.map +1 -1
- package/dist/rules/implementations/valid-color-format.js.map +1 -1
- package/dist/rules/implementations/valid-edge-types.js.map +1 -1
- package/dist/rules/implementations/valid-node-types.js.map +1 -1
- package/dist/rules/types.js.map +1 -1
- package/dist/telemetry/coverage.js.map +1 -1
- package/dist/telemetry/event-validator.js.map +1 -1
- package/dist/types/audit.js.map +1 -1
- package/dist/types/canvas.js +5 -5
- package/dist/types/canvas.js.map +1 -1
- package/dist/types/otel.js.map +1 -1
- package/dist/types/resource-match.js.map +1 -1
- package/dist/utils/CanvasConverter.js.map +1 -1
- package/dist/utils/GraphConverter.js.map +1 -1
- package/dist/utils/LibraryConverter.js.map +1 -1
- package/dist/utils/PathMatcher.js.map +1 -1
- package/dist/utils/TraceToCanvas.js +7 -7
- package/dist/utils/TraceToCanvas.js.map +1 -1
- package/dist/utils/YamlParser.js.map +1 -1
- package/package.json +15 -15
- package/src/index.ts +31 -13
- package/src/narrative/README.md +381 -0
- package/src/narrative/__tests__/scenario-matcher.test.ts +368 -0
- package/src/narrative/__tests__/template-parser.test.ts +235 -0
- package/src/narrative/__tests__/template-renderer.test.ts +377 -0
- package/src/narrative/example.ts +349 -0
- package/src/narrative/index.ts +35 -0
- package/src/narrative/scenario-matcher.ts +331 -0
- package/src/narrative/template-parser.ts +298 -0
- package/src/narrative/template-renderer.ts +423 -0
- package/src/narrative/types.ts +368 -0
- package/src/utils/GraphConverter.test.ts +0 -79
- package/dist/utils/ExecutionFileDiscovery.d.ts +0 -206
- package/dist/utils/ExecutionFileDiscovery.d.ts.map +0 -1
- package/dist/utils/ExecutionFileDiscovery.js +0 -340
- package/dist/utils/ExecutionFileDiscovery.js.map +0 -1
- package/src/utils/ExecutionFileDiscovery.ts +0 -522
|
@@ -1,522 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Execution File Discovery
|
|
3
|
-
*
|
|
4
|
-
* Discovers execution artifacts and canvas files in a repository with monorepo awareness.
|
|
5
|
-
* Uses codebase-composition (browser-safe export) to intelligently detect package boundaries
|
|
6
|
-
* and workspace patterns.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { PackageLayerModule } from '@principal-ai/codebase-composition/browser';
|
|
10
|
-
import type { PackageLayer } from '@principal-ai/codebase-composition/browser';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Represents a discovered execution artifact file
|
|
14
|
-
*/
|
|
15
|
-
export interface ExecutionFile {
|
|
16
|
-
/** Unique identifier for this execution */
|
|
17
|
-
id: string;
|
|
18
|
-
/** Display name for this execution */
|
|
19
|
-
name: string;
|
|
20
|
-
/** Full file path (relative to repository root) */
|
|
21
|
-
path: string;
|
|
22
|
-
/** Canvas basename (without extension) that this execution is linked to */
|
|
23
|
-
canvasBasename: string;
|
|
24
|
-
/** Package context if this execution belongs to a specific package */
|
|
25
|
-
packageContext?: PackageContext;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Represents a discovered canvas file
|
|
30
|
-
*/
|
|
31
|
-
export interface CanvasFile {
|
|
32
|
-
/** Unique identifier for this canvas */
|
|
33
|
-
id: string;
|
|
34
|
-
/** Display name for this canvas */
|
|
35
|
-
name: string;
|
|
36
|
-
/** Full file path (relative to repository root) */
|
|
37
|
-
path: string;
|
|
38
|
-
/** Canvas basename (without .otel.canvas or .canvas extension) */
|
|
39
|
-
basename: string;
|
|
40
|
-
/** Package context if this canvas belongs to a specific package */
|
|
41
|
-
packageContext?: PackageContext;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Package context for execution/canvas files
|
|
46
|
-
*/
|
|
47
|
-
export interface PackageContext {
|
|
48
|
-
/** Package name (from package.json, Cargo.toml, etc.) */
|
|
49
|
-
name: string;
|
|
50
|
-
/** Package directory path (relative to repository root) */
|
|
51
|
-
packagePath: string;
|
|
52
|
-
/** Package type (npm, cargo, go, etc.) */
|
|
53
|
-
packageType?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Execution artifact metadata
|
|
58
|
-
*/
|
|
59
|
-
export interface ExecutionMetadata {
|
|
60
|
-
name: string;
|
|
61
|
-
canvasName?: string;
|
|
62
|
-
exportedAt?: string;
|
|
63
|
-
source?: string;
|
|
64
|
-
framework?: string;
|
|
65
|
-
status?: 'success' | 'error' | 'OK';
|
|
66
|
-
spanCount: number;
|
|
67
|
-
eventCount: number;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Execution span structure
|
|
72
|
-
*/
|
|
73
|
-
export interface ExecutionSpan {
|
|
74
|
-
id: string;
|
|
75
|
-
name: string;
|
|
76
|
-
startTime: number;
|
|
77
|
-
endTime?: number;
|
|
78
|
-
duration?: number;
|
|
79
|
-
status?: string;
|
|
80
|
-
attributes?: Record<string, any>;
|
|
81
|
-
events: Array<{
|
|
82
|
-
time: number;
|
|
83
|
-
name: string;
|
|
84
|
-
attributes?: Record<string, any>;
|
|
85
|
-
}>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Execution artifact file structure
|
|
90
|
-
*/
|
|
91
|
-
export interface ExecutionArtifact {
|
|
92
|
-
metadata?: {
|
|
93
|
-
canvasName?: string;
|
|
94
|
-
exportedAt?: string;
|
|
95
|
-
source?: string;
|
|
96
|
-
framework?: string;
|
|
97
|
-
status?: 'success' | 'error';
|
|
98
|
-
};
|
|
99
|
-
spans: ExecutionSpan[];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* File tree entry for discovery
|
|
104
|
-
*/
|
|
105
|
-
export interface FileTreeEntry {
|
|
106
|
-
path?: string;
|
|
107
|
-
relativePath?: string;
|
|
108
|
-
name?: string;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Options for execution file discovery
|
|
113
|
-
*/
|
|
114
|
-
export interface DiscoveryOptions {
|
|
115
|
-
/** Whether to include package-level .principal-views folders */
|
|
116
|
-
includePackagePrincipalViews?: boolean;
|
|
117
|
-
/** Custom execution folder names (defaults to ['__executions__']) */
|
|
118
|
-
executionFolders?: string[];
|
|
119
|
-
/** Custom canvas extensions (defaults to ['.otel.canvas']) */
|
|
120
|
-
canvasExtensions?: string[];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Execution File Discovery Engine
|
|
125
|
-
*
|
|
126
|
-
* Discovers execution artifacts and canvas files using monorepo-aware logic.
|
|
127
|
-
*/
|
|
128
|
-
export class ExecutionFileDiscovery {
|
|
129
|
-
private packageLayerModule: PackageLayerModule;
|
|
130
|
-
private options: Required<DiscoveryOptions>;
|
|
131
|
-
|
|
132
|
-
constructor(options: DiscoveryOptions = {}) {
|
|
133
|
-
this.packageLayerModule = new PackageLayerModule();
|
|
134
|
-
this.options = {
|
|
135
|
-
includePackagePrincipalViews: options.includePackagePrincipalViews ?? true,
|
|
136
|
-
executionFolders: options.executionFolders ?? ['__executions__'],
|
|
137
|
-
canvasExtensions: options.canvasExtensions ?? ['.otel.canvas'],
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Find all execution artifact files in the repository
|
|
143
|
-
*/
|
|
144
|
-
async findExecutionFiles(files: FileTreeEntry[]): Promise<ExecutionFile[]> {
|
|
145
|
-
const executionFiles: ExecutionFile[] = [];
|
|
146
|
-
|
|
147
|
-
// Detect packages in the repository
|
|
148
|
-
const packages = await this.detectPackages(files);
|
|
149
|
-
|
|
150
|
-
// Search for execution files in each package
|
|
151
|
-
for (const pkg of packages) {
|
|
152
|
-
const pkgExecutions = this.findExecutionsInPackage(pkg, files);
|
|
153
|
-
executionFiles.push(...pkgExecutions);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Search in root-level locations
|
|
157
|
-
const rootExecutions = this.findExecutionsInRoot(files);
|
|
158
|
-
executionFiles.push(...rootExecutions);
|
|
159
|
-
|
|
160
|
-
// Sort by package name, then by basename
|
|
161
|
-
return this.sortExecutionFiles(executionFiles);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Find all canvas files in the repository
|
|
166
|
-
*/
|
|
167
|
-
async findCanvasFiles(files: FileTreeEntry[]): Promise<CanvasFile[]> {
|
|
168
|
-
const canvasFiles: CanvasFile[] = [];
|
|
169
|
-
|
|
170
|
-
// Detect packages in the repository
|
|
171
|
-
const packages = await this.detectPackages(files);
|
|
172
|
-
|
|
173
|
-
// Search for canvas files in root .principal-views/
|
|
174
|
-
const rootCanvases = this.findCanvasesInDirectory('.principal-views', files);
|
|
175
|
-
canvasFiles.push(...rootCanvases);
|
|
176
|
-
|
|
177
|
-
// Search for canvas files in package-level .principal-views/ if enabled
|
|
178
|
-
if (this.options.includePackagePrincipalViews) {
|
|
179
|
-
for (const pkg of packages) {
|
|
180
|
-
const pkgCanvases = this.findCanvasesInDirectory(
|
|
181
|
-
`${pkg.packageData.path}/.principal-views`,
|
|
182
|
-
files,
|
|
183
|
-
this.createPackageContext(pkg)
|
|
184
|
-
);
|
|
185
|
-
canvasFiles.push(...pkgCanvases);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Sort by name
|
|
190
|
-
return canvasFiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Find execution artifact for a given canvas
|
|
195
|
-
* Now package-aware - can disambiguate between packages
|
|
196
|
-
*/
|
|
197
|
-
findExecutionForCanvas(
|
|
198
|
-
canvas: CanvasFile,
|
|
199
|
-
executionFiles: ExecutionFile[]
|
|
200
|
-
): ExecutionFile | null {
|
|
201
|
-
// First, try exact package match if canvas has package context
|
|
202
|
-
if (canvas.packageContext) {
|
|
203
|
-
const exactMatch = executionFiles.find(
|
|
204
|
-
exec =>
|
|
205
|
-
exec.canvasBasename === canvas.basename &&
|
|
206
|
-
exec.packageContext?.name === canvas.packageContext?.name
|
|
207
|
-
);
|
|
208
|
-
if (exactMatch) return exactMatch;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Fallback to basename-only match (for root-level canvases)
|
|
212
|
-
return executionFiles.find(exec => exec.canvasBasename === canvas.basename) || null;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Find canvas file for a given execution
|
|
217
|
-
*/
|
|
218
|
-
findCanvasForExecution(
|
|
219
|
-
execution: ExecutionFile,
|
|
220
|
-
canvasFiles: CanvasFile[]
|
|
221
|
-
): CanvasFile | null {
|
|
222
|
-
// First, try exact package match if execution has package context
|
|
223
|
-
if (execution.packageContext) {
|
|
224
|
-
const exactMatch = canvasFiles.find(
|
|
225
|
-
canvas =>
|
|
226
|
-
canvas.basename === execution.canvasBasename &&
|
|
227
|
-
canvas.packageContext?.name === execution.packageContext?.name
|
|
228
|
-
);
|
|
229
|
-
if (exactMatch) return exactMatch;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Fallback to basename-only match (for root-level executions)
|
|
233
|
-
return canvasFiles.find(canvas => canvas.basename === execution.canvasBasename) || null;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Parse execution artifact JSON
|
|
238
|
-
*/
|
|
239
|
-
static parseExecutionArtifact(content: string): ExecutionArtifact {
|
|
240
|
-
try {
|
|
241
|
-
const parsed = JSON.parse(content);
|
|
242
|
-
return parsed as ExecutionArtifact;
|
|
243
|
-
} catch (error) {
|
|
244
|
-
throw new Error(`Failed to parse execution artifact JSON: ${(error as Error).message}`);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Get spans from an artifact
|
|
250
|
-
*/
|
|
251
|
-
static getSpans(artifact: ExecutionArtifact): ExecutionSpan[] {
|
|
252
|
-
return artifact.spans || [];
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Extract metadata from an execution artifact
|
|
257
|
-
*/
|
|
258
|
-
static getExecutionMetadata(artifact: ExecutionArtifact): ExecutionMetadata {
|
|
259
|
-
const spans = ExecutionFileDiscovery.getSpans(artifact);
|
|
260
|
-
const spanCount = spans.length;
|
|
261
|
-
|
|
262
|
-
const eventCount = spans.reduce((total, span) => {
|
|
263
|
-
return total + (span.events?.length || 0);
|
|
264
|
-
}, 0);
|
|
265
|
-
|
|
266
|
-
const metadata = artifact.metadata;
|
|
267
|
-
|
|
268
|
-
let status: 'success' | 'error' | 'OK' = 'success';
|
|
269
|
-
if (metadata?.status) {
|
|
270
|
-
status = metadata.status;
|
|
271
|
-
} else if (spans.length > 0) {
|
|
272
|
-
const hasError = spans.some(
|
|
273
|
-
s => s.status === 'ERROR' || s.status === 'error' || s.status === 'FAILED'
|
|
274
|
-
);
|
|
275
|
-
status = hasError ? 'error' : 'OK';
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return {
|
|
279
|
-
name: metadata?.canvasName || 'Untitled Execution',
|
|
280
|
-
canvasName: metadata?.canvasName,
|
|
281
|
-
exportedAt: metadata?.exportedAt,
|
|
282
|
-
source: metadata?.source,
|
|
283
|
-
framework: metadata?.framework,
|
|
284
|
-
status,
|
|
285
|
-
spanCount,
|
|
286
|
-
eventCount,
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Private helper methods
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Detect packages using codebase-composition
|
|
294
|
-
*/
|
|
295
|
-
private async detectPackages(files: FileTreeEntry[]): Promise<PackageLayer[]> {
|
|
296
|
-
try {
|
|
297
|
-
// Convert files to the format expected by codebase-composition
|
|
298
|
-
const fileTree = this.convertToFileTree(files);
|
|
299
|
-
const packages = await this.packageLayerModule.discoverPackages(fileTree);
|
|
300
|
-
return packages || [];
|
|
301
|
-
} catch (error) {
|
|
302
|
-
// If package detection fails, continue with fallback patterns
|
|
303
|
-
console.warn('Package detection failed, using fallback patterns:', error);
|
|
304
|
-
return [];
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Convert file entries to file tree format for codebase-composition
|
|
310
|
-
*/
|
|
311
|
-
private convertToFileTree(files: FileTreeEntry[]): any {
|
|
312
|
-
// This is a simplified conversion - codebase-composition expects a specific format
|
|
313
|
-
// In practice, the caller should provide a proper FileTree from repository-abstraction
|
|
314
|
-
return {
|
|
315
|
-
files: files.map(f => ({
|
|
316
|
-
path: f.relativePath || f.path || '',
|
|
317
|
-
name: f.name || (f.relativePath || f.path || '').split('/').pop() || '',
|
|
318
|
-
})),
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Find executions in a specific package
|
|
324
|
-
*/
|
|
325
|
-
private findExecutionsInPackage(
|
|
326
|
-
pkg: PackageLayer,
|
|
327
|
-
files: FileTreeEntry[]
|
|
328
|
-
): ExecutionFile[] {
|
|
329
|
-
const executions: ExecutionFile[] = [];
|
|
330
|
-
const pkgPath = pkg.packageData.path || '';
|
|
331
|
-
const packageContext = this.createPackageContext(pkg);
|
|
332
|
-
|
|
333
|
-
for (const execFolder of this.options.executionFolders) {
|
|
334
|
-
const execPath = pkgPath ? `${pkgPath}/${execFolder}` : execFolder;
|
|
335
|
-
|
|
336
|
-
for (const file of files) {
|
|
337
|
-
const filePath = file.relativePath || file.path || '';
|
|
338
|
-
const fileName = file.name || filePath.split('/').pop() || '';
|
|
339
|
-
|
|
340
|
-
if (filePath.startsWith(execPath + '/') && this.isExecutionFile(fileName)) {
|
|
341
|
-
const basename = this.extractExecutionBasename(fileName);
|
|
342
|
-
executions.push({
|
|
343
|
-
id: this.generateExecutionId(basename, packageContext),
|
|
344
|
-
name: this.formatDisplayName(basename),
|
|
345
|
-
path: filePath,
|
|
346
|
-
canvasBasename: basename,
|
|
347
|
-
packageContext,
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return executions;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Find executions in root-level locations
|
|
358
|
-
*/
|
|
359
|
-
private findExecutionsInRoot(files: FileTreeEntry[]): ExecutionFile[] {
|
|
360
|
-
const executions: ExecutionFile[] = [];
|
|
361
|
-
|
|
362
|
-
// Root __executions__/
|
|
363
|
-
for (const execFolder of this.options.executionFolders) {
|
|
364
|
-
for (const file of files) {
|
|
365
|
-
const filePath = file.relativePath || file.path || '';
|
|
366
|
-
const fileName = file.name || filePath.split('/').pop() || '';
|
|
367
|
-
|
|
368
|
-
if (filePath.startsWith(`${execFolder}/`) && this.isExecutionFile(fileName)) {
|
|
369
|
-
const basename = this.extractExecutionBasename(fileName);
|
|
370
|
-
executions.push({
|
|
371
|
-
id: `root-${basename}`,
|
|
372
|
-
name: this.formatDisplayName(basename),
|
|
373
|
-
path: filePath,
|
|
374
|
-
canvasBasename: basename,
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// .principal-views/__executions__/
|
|
381
|
-
const pvExecPath = '.principal-views/__executions__';
|
|
382
|
-
for (const file of files) {
|
|
383
|
-
const filePath = file.relativePath || file.path || '';
|
|
384
|
-
const fileName = file.name || filePath.split('/').pop() || '';
|
|
385
|
-
|
|
386
|
-
if (filePath.startsWith(pvExecPath + '/') && this.isExecutionFile(fileName)) {
|
|
387
|
-
const basename = this.extractExecutionBasename(fileName);
|
|
388
|
-
executions.push({
|
|
389
|
-
id: `pv-${basename}`,
|
|
390
|
-
name: this.formatDisplayName(basename),
|
|
391
|
-
path: filePath,
|
|
392
|
-
canvasBasename: basename,
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return executions;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Find canvas files in a specific directory
|
|
402
|
-
*/
|
|
403
|
-
private findCanvasesInDirectory(
|
|
404
|
-
directory: string,
|
|
405
|
-
files: FileTreeEntry[],
|
|
406
|
-
packageContext?: PackageContext
|
|
407
|
-
): CanvasFile[] {
|
|
408
|
-
const canvases: CanvasFile[] = [];
|
|
409
|
-
|
|
410
|
-
for (const file of files) {
|
|
411
|
-
const filePath = file.relativePath || file.path || '';
|
|
412
|
-
const fileName = file.name || filePath.split('/').pop() || '';
|
|
413
|
-
|
|
414
|
-
if (filePath.startsWith(directory + '/') && this.isCanvasFile(fileName)) {
|
|
415
|
-
const basename = this.extractCanvasBasename(fileName);
|
|
416
|
-
canvases.push({
|
|
417
|
-
id: this.generateCanvasId(basename, packageContext),
|
|
418
|
-
name: this.formatDisplayName(basename),
|
|
419
|
-
path: filePath,
|
|
420
|
-
basename,
|
|
421
|
-
packageContext,
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
return canvases;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Create package context from PackageLayer
|
|
431
|
-
*/
|
|
432
|
-
private createPackageContext(pkg: PackageLayer): PackageContext {
|
|
433
|
-
return {
|
|
434
|
-
name: pkg.packageData.name || 'unknown',
|
|
435
|
-
packagePath: pkg.packageData.path || '',
|
|
436
|
-
packageType: pkg.type,
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Check if filename is an execution file
|
|
442
|
-
*/
|
|
443
|
-
private isExecutionFile(filename: string): boolean {
|
|
444
|
-
return /\.(spans|execution|events)\.json$/.test(filename);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Check if filename is a canvas file
|
|
449
|
-
*/
|
|
450
|
-
private isCanvasFile(filename: string): boolean {
|
|
451
|
-
return this.options.canvasExtensions.some(ext => filename.endsWith(ext));
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Extract basename from execution filename
|
|
456
|
-
*/
|
|
457
|
-
private extractExecutionBasename(filename: string): string {
|
|
458
|
-
return filename.replace(/\.(spans|execution|events)\.json$/, '');
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Extract basename from canvas filename
|
|
463
|
-
*/
|
|
464
|
-
private extractCanvasBasename(filename: string): string {
|
|
465
|
-
for (const ext of this.options.canvasExtensions) {
|
|
466
|
-
if (filename.endsWith(ext)) {
|
|
467
|
-
return filename.slice(0, -ext.length);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return filename;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* Format display name from basename (kebab-case to Title Case)
|
|
475
|
-
*/
|
|
476
|
-
private formatDisplayName(basename: string): string {
|
|
477
|
-
return basename
|
|
478
|
-
.split('-')
|
|
479
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
480
|
-
.join(' ');
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Generate unique ID for execution file
|
|
485
|
-
*/
|
|
486
|
-
private generateExecutionId(basename: string, packageContext?: PackageContext): string {
|
|
487
|
-
if (packageContext) {
|
|
488
|
-
return `${packageContext.name}-${basename}`;
|
|
489
|
-
}
|
|
490
|
-
return basename;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* Generate unique ID for canvas file
|
|
495
|
-
*/
|
|
496
|
-
private generateCanvasId(basename: string, packageContext?: PackageContext): string {
|
|
497
|
-
if (packageContext) {
|
|
498
|
-
return `${packageContext.name}-${basename}`;
|
|
499
|
-
}
|
|
500
|
-
return basename;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Sort execution files by package name, then by basename
|
|
505
|
-
*/
|
|
506
|
-
private sortExecutionFiles(files: ExecutionFile[]): ExecutionFile[] {
|
|
507
|
-
return files.sort((a, b) => {
|
|
508
|
-
// Sort by package name first
|
|
509
|
-
if (a.packageContext && b.packageContext) {
|
|
510
|
-
const pkgCompare = a.packageContext.name.localeCompare(b.packageContext.name);
|
|
511
|
-
if (pkgCompare !== 0) return pkgCompare;
|
|
512
|
-
} else if (a.packageContext) {
|
|
513
|
-
return -1;
|
|
514
|
-
} else if (b.packageContext) {
|
|
515
|
-
return 1;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Then by basename
|
|
519
|
-
return a.canvasBasename.localeCompare(b.canvasBasename);
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
}
|