@callidescope/cli 0.0.1

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.
@@ -0,0 +1,649 @@
1
+ import { AddressCommandOptions } from '@callidescope/configuration';
2
+ import { AddressService } from '@callidescope/graph';
3
+ import { CallableAddressResolution } from '@callidescope/graph';
4
+ import { CallableId } from '@callidescope/core';
5
+ import { CallablesService } from '@callidescope/graph';
6
+ import { CallGraph } from '@callidescope/graph';
7
+ import { CallGraphResult } from '@callidescope/core';
8
+ import { CallidescopeLimitOverrides } from '@callidescope/configuration';
9
+ import { CallidescopeLimits } from '@callidescope/configuration';
10
+ import { CallidescopeOutputFormat } from '@callidescope/configuration';
11
+ import { ClassesService } from '@callidescope/graph';
12
+ import { ConfigurationService } from '@callidescope/configuration';
13
+ import { ConsoleLogger } from '@nestjs/common';
14
+ import { DiscoveredCallable } from '@callidescope/graph';
15
+ import { EntriesService } from '@callidescope/graph';
16
+ import { ExternalService } from '@callidescope/graph';
17
+ import { FileFilterService } from '@callidescope/graph';
18
+ import { GraphAssemblyService } from '@callidescope/graph';
19
+ import pino from 'pino';
20
+ import { ProgramService } from '@callidescope/graph';
21
+ import { ProjectLimitsLookup } from '@callidescope/configuration';
22
+ import { ProjectReportsService } from '@callidescope/output';
23
+ import { ResolvedCallidescopeConfiguration } from '@callidescope/configuration';
24
+ import { ResolvedCallidescopeEntryPoints } from '@callidescope/configuration';
25
+ import { ResolvedCallidescopeWriteConfiguration } from '@callidescope/configuration';
26
+ import { UnresolvedEntryPointAddress } from '@callidescope/graph';
27
+ import { WorkspaceService } from '@callidescope/graph';
28
+
29
+ /**
30
+ * NestJS module that wires `depth` and `breadth`'s shared address resolution.
31
+ */
32
+ export declare class AddressLookupModule {
33
+ }
34
+
35
+ /**
36
+ * Resolves `depth` and `breadth`'s callable address into a callable, sharing
37
+ * every step the two commands would otherwise duplicate: loading the
38
+ * configuration, tracing the workspace, and matching the address against
39
+ * what was found.
40
+ */
41
+ export declare class AddressLookupService {
42
+ private readonly addressService;
43
+ private readonly callidescopeService;
44
+ private readonly configurationService;
45
+ constructor(addressService: AddressService, callidescopeService: CallidescopeService, configurationService: ConfigurationService);
46
+ /**
47
+ * States why a resolution cannot be acted on, or nothing when it can.
48
+ *
49
+ * One message per failure kind rather than a generic "not found": an
50
+ * invalid address, an address matching nothing, and an address matching
51
+ * several declarations are each fixed a different way, and only the message
52
+ * for the one that actually happened tells the caller which.
53
+ *
54
+ * The candidates of an ambiguous address are rendered by `AddressService`,
55
+ * the same renderer the workspace run's own refusal prints, so one concept
56
+ * reaches a reader one way — as an address they can paste back, rather than
57
+ * a file location they cannot.
58
+ */
59
+ describeProblem(args: {
60
+ address: string;
61
+ resolution: CallableAddressResolution;
62
+ }): string | undefined;
63
+ /**
64
+ * Every callable the trace found, written as an address that resolves to it.
65
+ *
66
+ * What a prompt completes against, so a caller picks from what is actually
67
+ * there rather than recalling a qualified name it has no way to look up.
68
+ */
69
+ listAddresses(workspace: LocatedWorkspace): string[];
70
+ /** Loads the configuration and traces the workspace, matching nothing yet. */
71
+ locate(options: AddressCommandOptions): Promise<LocatedWorkspace>;
72
+ /** Matches an address against a workspace already traced. */
73
+ resolve(args: ResolveAddressArguments): CallableAddressResolution;
74
+ }
75
+
76
+ /** What analyzing one run's callables produced. */
77
+ declare interface AnalyzeOutcome {
78
+ /**
79
+ * The depth and breadth limits each traced project is judged against.
80
+ *
81
+ * Held beside the result rather than inside it, the same as
82
+ * `unresolvedAddresses`: whether `--check breadth` even has a limit to gate
83
+ * on is a fact about the projects a run reached, not part of the report
84
+ * every destination writes.
85
+ */
86
+ readonly projectLimits: ProjectLimitsLookup;
87
+ readonly result: CallGraphResult;
88
+ /**
89
+ * Declared entry-point addresses that named no callable, or more than one.
90
+ *
91
+ * Held beside the result rather than inside it: the report shape is what
92
+ * gets written to every destination, and an address that stopped resolving
93
+ * is a fact about the configuration rather than about the code it traced.
94
+ */
95
+ readonly unresolvedAddresses: readonly UnresolvedEntryPointAddress[];
96
+ }
97
+
98
+ /**
99
+ * NestJS module that wires the callidescope command and its analysis services.
100
+ */
101
+ export declare class CallidescopeModule {
102
+ }
103
+
104
+ /**
105
+ * Runs one trace of a workspace, from tsconfig files to findings.
106
+ */
107
+ export declare class CallidescopeService {
108
+ private readonly callablesService;
109
+ private readonly classHierarchyService;
110
+ private readonly entryPointsService;
111
+ private readonly externalService;
112
+ private readonly fileFilterService;
113
+ private readonly graphAssemblyService;
114
+ private readonly programService;
115
+ private readonly configurationService;
116
+ private readonly projectReportsService;
117
+ private readonly workspaceService;
118
+ private readonly logger;
119
+ constructor(callablesService: CallablesService, classHierarchyService: ClassesService, entryPointsService: EntriesService, externalService: ExternalService, fileFilterService: FileFilterService, graphAssemblyService: GraphAssemblyService, programService: ProgramService, configurationService: ConfigurationService, projectReportsService: ProjectReportsService, workspaceService: WorkspaceService, logger: LoggerService);
120
+ /**
121
+ * Walks the workspace and collects every callable, without analyzing them.
122
+ *
123
+ * Shared by `trace`, which goes on to run the full analysis, and `locate`,
124
+ * which only needs the collected callables and their graph to resolve one
125
+ * address — entry points and project reports are work `locate`'s callers
126
+ * never asked for. Both read the same declarations, because a
127
+ * project's own `exclude` decides which files exist to be collected at all,
128
+ * and an address resolved against a different set of files from the one a
129
+ * gated run measures would be an address about a different codebase.
130
+ */
131
+ private discoverCallables;
132
+ /**
133
+ * Finds the projects a run covers and builds a program for each.
134
+ *
135
+ * Split from `discoverCallables` because the projects have to exist before
136
+ * anything can be read from beside them, and the run's own filter has to
137
+ * exist before the projects: a project the run excludes must be dropped
138
+ * before its `tsconfig.json` is opened, since opening it is what fails.
139
+ */
140
+ private discoverPrograms;
141
+ /**
142
+ * Reads what each traced project declared for itself: the callables that
143
+ * root its stacks, and the limits those stacks are judged against.
144
+ *
145
+ * Over the whole closure rather than the projects the run was pointed at: a
146
+ * dependency's callables are measured by this run, and the project that owns
147
+ * them is the one entitled to say what roots a stack through them. A run
148
+ * scoped elsewhere would otherwise judge them by whoever happened to reach
149
+ * them.
150
+ *
151
+ * One load for both, because the two answers come out of the same files, and
152
+ * reading those files twice is how a run ends up gating against limits from
153
+ * one read and rooting stacks from another.
154
+ *
155
+ * A project declaring no entry-point rules is simply absent from that map,
156
+ * and `EntriesService` falls back to the run's own configuration for it —
157
+ * which is why this returns rules rather than a whole configuration. Limits
158
+ * resolve the other way round, naming every project, because a limit has to
159
+ * be printable per project whether or not the project chose it.
160
+ *
161
+ * Exclusions are read from the file exactly as authored rather than from the
162
+ * resolved configuration, which is the split `readDeclaredLimit` already makes
163
+ * for
164
+ * a limit: resolution folds the tool's own default globs into every project's
165
+ * `exclude`, so the resolved array can never say whether this project
166
+ * excluded anything. A project that excluded nothing is left out of the map
167
+ * entirely, so a run in which no project excludes anything is handed back the
168
+ * run's own filter untouched.
169
+ */
170
+ private loadProjectDeclarations;
171
+ /**
172
+ * Reads the deepest depth any component reached, closure included.
173
+ *
174
+ * The whole trace's number, closure included, which is what belongs in a
175
+ * summary describing everything a run measured. It is **not** what a scoped
176
+ * run is judged on, which is why the log line names it `maximumDepthTraced`
177
+ * rather than `maximumDepth`.
178
+ */
179
+ private readMaximumDepth;
180
+ /** Derives every finding from the collected callables. */
181
+ analyze(args: {
182
+ callablesById: ReadonlyMap<CallableId, DiscoveredCallable>;
183
+ configuration: ResolvedCallidescopeConfiguration;
184
+ /** Entry-point rules a project declared for itself, keyed by project name. */
185
+ entryPointsByProject: ReadonlyMap<string, ResolvedCallidescopeEntryPoints>;
186
+ fileCount: number;
187
+ fileCountByProject: ReadonlyMap<string, number>;
188
+ projectCount: number;
189
+ /** The depth and breadth limits each traced project is judged against. */
190
+ projectLimits: ProjectLimitsLookup;
191
+ projectNames: readonly string[];
192
+ workspaceRoot: string;
193
+ }): AnalyzeOutcome;
194
+ /**
195
+ * Collects every callable and assembles the graph over them, without
196
+ * running the analysis a full trace does.
197
+ *
198
+ * For the `depth` and `breadth` commands, which resolve one address against
199
+ * the collected callables and then walk the graph from it — neither needs
200
+ * entry points or project reports, both of which `analyze` builds
201
+ * unconditionally.
202
+ *
203
+ * Asynchronous because discovery is: every project's own configuration is
204
+ * read before a callable is collected, since a project's `exclude` decides
205
+ * which files there are to collect. The limits those same files declare are
206
+ * loaded and thrown away here, which is the price of one answer about what a
207
+ * run's callables are rather than two.
208
+ */
209
+ locate(args: TraceArguments): Promise<LocateOutcome>;
210
+ /** Traces a workspace and returns everything the run found. */
211
+ trace(args: TraceArguments): Promise<TraceOutcome>;
212
+ }
213
+
214
+ /**
215
+ * A traced workspace, before any address has been matched against it.
216
+ *
217
+ * Held apart from the match so one trace can serve both the list a prompt
218
+ * completes against and the lookup that follows it. Tracing twice to offer a
219
+ * choice and then act on it would double the slowest thing either command
220
+ * does.
221
+ */
222
+ export declare interface LocatedWorkspace {
223
+ readonly configuration: ResolvedCallidescopeConfiguration;
224
+ /** What the lookup prints, resolved from the command line and refused if unknown. */
225
+ readonly format: CallidescopeOutputFormat;
226
+ readonly located: LocateOutcome;
227
+ readonly workspaceRoot: string;
228
+ }
229
+
230
+ /** The collected callables and their graph, without any analysis run over them. */
231
+ export declare interface LocateOutcome {
232
+ readonly callablesById: ReadonlyMap<CallableId, DiscoveredCallable>;
233
+ readonly graph: CallGraph;
234
+ /** Workspace-relative root of each project the run was scoped to, keyed by name. */
235
+ readonly startingProjectRoots: ReadonlyMap<string, string>;
236
+ }
237
+
238
+ /**
239
+ * Structured values that belong beside a log line rather than inside it.
240
+ *
241
+ * Counts, percentages, and durations are the values that change on every
242
+ * occurrence, so they are carried as fields: the message stays constant and
243
+ * groupable in telemetry, and the numbers stay queryable instead of having to
244
+ * be parsed back out of prose.
245
+ *
246
+ * The named members are the recurring ones; the index signature keeps the
247
+ * argument open for whatever a given call site needs to attach.
248
+ */
249
+ declare interface LogData {
250
+ [key: string]: unknown;
251
+ /** How many things the operation handled. */
252
+ count?: number;
253
+ /** Wall-clock milliseconds the operation took. */
254
+ durationMs?: number;
255
+ /** Completion between 0 and 100. */
256
+ percent?: number;
257
+ /** How many things the operation set out to handle. */
258
+ total?: number;
259
+ }
260
+
261
+ /**
262
+ * Transient-scoped logger so each injecting class gets its own instance.
263
+ * Each consumer calls `setContext(ClassName.name)` to tag every log line
264
+ * with the originating class. Backed by pino for structured JSON output in
265
+ * production and human-readable pretty-print in development.
266
+ *
267
+ * Messages follow one grammar: an emoji naming the subject, a verb in present
268
+ * progressive or past tense, then the object. Values that vary per call —
269
+ * counts, percentages, durations — go in the `data` argument rather than the
270
+ * message, so the message stays constant enough for telemetry to group on.
271
+ *
272
+ * ```ts
273
+ * this.logger.info("📥 Downloading CSEL sources", undefined, { total: 428 });
274
+ * this.logger.info("📥 Downloaded CSEL sources", undefined, { count: 412 });
275
+ * ```
276
+ */
277
+ declare @Injectable({ scope: Scope.TRANSIENT })
278
+ class LoggerService extends ConsoleLogger {
279
+ // 🏗 Dependency Injection
280
+
281
+ constructor() {
282
+ super();
283
+ }
284
+
285
+ // 🔐 Private Fields
286
+
287
+ private static readonly isProduction =
288
+ process.env["NODE_ENV"] === "production";
289
+
290
+ /**
291
+ * Built on first use, not when this file is evaluated.
292
+ *
293
+ * A destination fixed at import time could only ever be chosen by this
294
+ * package, since every consumer's own code runs after its imports.
295
+ */
296
+ private static rootLogger: pino.Logger | undefined;
297
+
298
+ /** Whether lines go to standard error instead of standard output. */
299
+ private static writesToStandardError = false;
300
+
301
+ private child: pino.Logger = LoggerService.root;
302
+
303
+ // 🔑 Public Fields
304
+
305
+ // 🔏 Private Methods
306
+
307
+ /** Build the pino instance for production or local development output. */
308
+ private static createRootLogger(): pino.Logger {
309
+ const level = process.env["LOG_LEVEL"] ?? "info";
310
+
311
+ if (LoggerService.isProduction) {
312
+ return LoggerService.writesToStandardError
313
+ ? pino({ level }, pino.destination(STANDARD_ERROR_DESCRIPTOR))
314
+ : pino({ level });
315
+ }
316
+
317
+ return pino({
318
+ level,
319
+ transport: {
320
+ options: {
321
+ colorize: true,
322
+ destination: LoggerService.writesToStandardError
323
+ ? STANDARD_ERROR_DESCRIPTOR
324
+ : STANDARD_OUTPUT_DESCRIPTOR,
325
+ // The emoji is a field, not part of the message, so the console can
326
+ // show it while telemetry stores unadorned prose. `ignore` then keeps
327
+ // it from being printed a second time in the trailing object.
328
+ ignore: "pid,hostname,emoji",
329
+ messageFormat: "{emoji} {msg}",
330
+ singleLine: true,
331
+ },
332
+ target: "pino-pretty",
333
+ },
334
+ });
335
+ }
336
+
337
+ /**
338
+ * Sends every subsequent line to standard error instead of standard output.
339
+ *
340
+ * For a command-line application whose standard output *is* its result. A log
341
+ * line sharing that stream is not a diagnostic beside the data, it is a
342
+ * corruption of it. Call it before anything logs — the first statement of the
343
+ * application's bootstrap.
344
+ *
345
+ * A call after the first line warns and changes nothing: the destination is
346
+ * fixed when the pino instance is built, and tearing down a transport
347
+ * somebody is writing through would be worse than refusing. The warning is
348
+ * the point — silently leaving the lines on standard output is how a caller
349
+ * would ship a corrupted pipe without ever being told.
350
+ */
351
+ static logToStandardError(): void {
352
+ if (LoggerService.rootLogger !== undefined) {
353
+ process.emitWarning(
354
+ "LoggerService.logToStandardError() was called after the first log line, so log lines still go to standard output and anything piping that stream will read them as data. Call it as the first statement of the application's bootstrap.",
355
+ );
356
+ return;
357
+ }
358
+
359
+ LoggerService.writesToStandardError = true;
360
+ }
361
+
362
+ /**
363
+ * Fails a malformed message in development, and never in production.
364
+ *
365
+ * A logger that throws in production turns an observability call into an
366
+ * outage, so the check runs only where a developer is present to fix it.
367
+ */
368
+ private assertConventionalMessage(args: {
369
+ context: string | undefined;
370
+ parsed: ParsedLogMessage;
371
+ }): void {
372
+ if (
373
+ LoggerService.isProduction ||
374
+ this.shouldSkipConventionalMessageValidation(args.context)
375
+ ) {
376
+ return;
377
+ }
378
+
379
+ const violation = this.getConventionalMessageViolation(args.parsed);
380
+
381
+ if (violation !== undefined) {
382
+ throw new Error(violation);
383
+ }
384
+ }
385
+
386
+ /** Assembles the object pino merges into the line. */
387
+ private buildBindings(args: {
388
+ context: string | undefined;
389
+ data: LogData | undefined;
390
+ parsed: ParsedLogMessage;
391
+ }): Record<string, unknown> {
392
+ this.assertConventionalMessage({
393
+ context: args.context,
394
+ parsed: args.parsed,
395
+ });
396
+
397
+ return {
398
+ ...args.data,
399
+ context: args.context,
400
+ // Telemetry gets prose; only the console-bound transport reads this.
401
+ ...(LoggerService.isProduction ? {} : { emoji: args.parsed.emoji }),
402
+ };
403
+ }
404
+
405
+ /** Returns a human-readable explanation when the message format is invalid. */
406
+ private getConventionalMessageViolation(
407
+ parsed: ParsedLogMessage,
408
+ ): string | undefined {
409
+ const emoji = parsed.emoji;
410
+ const text = parsed.text;
411
+
412
+ if (emoji === undefined) {
413
+ return `Log message must start with an emoji naming its subject, then a verb: "${text}"`;
414
+ }
415
+
416
+ const firstWord = FIRST_WORD_PATTERN.exec(text)?.[1];
417
+
418
+ if (firstWord === undefined || !this.isConventionalVerb(firstWord)) {
419
+ return `Log message must begin with a verb in present progressive or past tense, got "${firstWord ?? ""}": "${emoji} ${text}"`;
420
+ }
421
+
422
+ return undefined;
423
+ }
424
+
425
+ /**
426
+ * Whether a word is a verb in one of the two tenses the convention allows.
427
+ *
428
+ * Present progressive means the operation is under way; past means it
429
+ * finished. Regular morphology covers both, so a new verb needs no
430
+ * registration anywhere — only irregular pasts are enumerated.
431
+ */
432
+ private isConventionalVerb(word: string): boolean {
433
+ const lowercased = word.toLowerCase();
434
+
435
+ return (
436
+ lowercased.endsWith("ing") ||
437
+ lowercased.endsWith("ed") ||
438
+ IRREGULAR_PAST_VERBS.has(lowercased)
439
+ );
440
+ }
441
+
442
+ /** Splits a leading emoji off a message, leaving prose behind. */
443
+ private parseMessage(message: unknown): ParsedLogMessage {
444
+ const text = String(message);
445
+ const match = LEADING_EMOJI_PATTERN.exec(text);
446
+ const emoji = match?.[1];
447
+
448
+ return emoji === undefined
449
+ ? { emoji: undefined, text }
450
+ : { emoji, text: text.slice(match?.[0].length) };
451
+ }
452
+
453
+ /** Whether a context is intentionally exempt from the validation rule. */
454
+ private shouldSkipConventionalMessageValidation(
455
+ context: string | undefined,
456
+ ): boolean {
457
+ return context !== undefined && UNVALIDATED_LOG_CONTEXTS.has(context);
458
+ }
459
+
460
+ // 🌎 Public Methods
461
+
462
+ /** The pino instance every logger's child is taken from. */
463
+ private static get root(): pino.Logger {
464
+ LoggerService.rootLogger ??= LoggerService.createRootLogger();
465
+
466
+ return LoggerService.rootLogger;
467
+ }
468
+
469
+ /** Normalizes unknown errors into a stable message and timestamped log line. */
470
+ buildErrorLogEntry(
471
+ context: string,
472
+ error: unknown,
473
+ ): { errorMessage: string; logLine: string } {
474
+ const errorMessage =
475
+ error instanceof Error ? error.stack || error.message : String(error);
476
+
477
+ return {
478
+ errorMessage,
479
+ logLine: `[${new Date().toISOString()}] ${context}: ${errorMessage}\n`,
480
+ };
481
+ }
482
+
483
+ /** Builds a timestamped output log file path and ensures the output directory exists. */
484
+ createTimestampedOutputLogFilePath(filePrefix: string): string {
485
+ const outputDirectory = path.join(process.cwd(), "output");
486
+ if (!existsSync(outputDirectory)) {
487
+ mkdirSync(outputDirectory, { recursive: true });
488
+ }
489
+
490
+ return path.join(
491
+ outputDirectory,
492
+ `${filePrefix}-${new Date().toISOString().replaceAll(/[:.]/g, "-")}.log`,
493
+ );
494
+ }
495
+
496
+ /** Logs a debug message at the `debug` level. */
497
+ override debug(message: unknown, context?: string, data?: LogData): void {
498
+ const parsed = this.parseMessage(message);
499
+ this.child.debug(
500
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
501
+ parsed.text,
502
+ );
503
+ }
504
+
505
+ /**
506
+ * Logs an error message at the `error` level, optionally including a stack trace.
507
+ *
508
+ * `ConsoleLogger.error` spends a third slot on a context string that the
509
+ * other levels do not have, so this one accepts either: a string keeps
510
+ * NestJS's meaning, an object is structured data like everywhere else.
511
+ */
512
+ override error(
513
+ message: unknown,
514
+ stackOrContext?: string,
515
+ contextOrData?: LogData | string,
516
+ ): void {
517
+ const parsed = this.parseMessage(message);
518
+ const data = typeof contextOrData === "object" ? contextOrData : undefined;
519
+ const context =
520
+ typeof contextOrData === "string" ? contextOrData : this.context;
521
+
522
+ this.child.error(
523
+ {
524
+ ...this.buildBindings({ context, data, parsed }),
525
+ stack: stackOrContext,
526
+ },
527
+ parsed.text,
528
+ );
529
+ }
530
+
531
+ /** Logs an informational message at the `info` level. */
532
+ info(message: unknown, context?: string, data?: LogData): void {
533
+ const parsed = this.parseMessage(message);
534
+ this.child.info(
535
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
536
+ parsed.text,
537
+ );
538
+ }
539
+
540
+ /**
541
+ * Logs an informational message at the `info` level.
542
+ *
543
+ * NestJS and `nest-commander` call this method directly as part of the
544
+ * framework's own `LoggerService` contract, so it must keep working
545
+ * exactly as before. Application code should call `info` instead — the
546
+ * same behavior under a name that says what level it logs at.
547
+ */
548
+ override log(message: unknown, context?: string, data?: LogData): void {
549
+ this.info(message, context, data);
550
+ }
551
+
552
+ /** Sets the context label included in every subsequent log line. */
553
+ override setContext(context: string): void {
554
+ super.setContext(context);
555
+ this.child = LoggerService.root.child({ context });
556
+ }
557
+
558
+ /** Logs a verbose message at the `trace` level. */
559
+ override verbose(message: unknown, context?: string, data?: LogData): void {
560
+ const parsed = this.parseMessage(message);
561
+ this.child.trace(
562
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
563
+ parsed.text,
564
+ );
565
+ }
566
+
567
+ /** Logs a warning message at the `warn` level. */
568
+ override warn(message: unknown, context?: string, data?: LogData): void {
569
+ const parsed = this.parseMessage(message);
570
+ this.child.warn(
571
+ this.buildBindings({ context: context ?? this.context, data, parsed }),
572
+ parsed.text,
573
+ );
574
+ }
575
+ }
576
+
577
+ /**
578
+ * Root NestJS application module.
579
+ */
580
+ export declare class MainModule {
581
+ }
582
+
583
+ /** A message split into the emoji the console shows and the prose telemetry stores. */
584
+ declare interface ParsedLogMessage {
585
+ emoji: string | undefined;
586
+ text: string;
587
+ }
588
+
589
+ /** Arguments for matching an address against an already-traced workspace. */
590
+ declare interface ResolveAddressArguments {
591
+ readonly address: string;
592
+ readonly workspace: LocatedWorkspace;
593
+ }
594
+
595
+ /** Arguments for one full trace of a workspace. */
596
+ export declare interface TraceArguments {
597
+ /**
598
+ * The limits the workspace file itself wrote down, exactly as authored.
599
+ *
600
+ * Carried so the workspace row names the workspace file only when that file
601
+ * really wrote the number: resolution defaults `maximumDepth` for every run,
602
+ * and a path stamped from the resolved object alone would name a file for a
603
+ * number it never mentions.
604
+ */
605
+ readonly authoredLimits?: CallidescopeLimits | undefined;
606
+ readonly configuration: ResolvedCallidescopeConfiguration;
607
+ /**
608
+ * The file `configuration` was read from, when a file was found at all.
609
+ *
610
+ * Carried so the trace can skip it while resolving a configuration beside
611
+ * every project it reaches: one file holds one role per run, and a package
612
+ * whose task names its own file would otherwise have it read a second time
613
+ * as that package's project configuration.
614
+ */
615
+ readonly configurationPath?: string | undefined;
616
+ /** Project directories to trace. Every project in the workspace when empty. */
617
+ readonly directories: readonly string[];
618
+ /**
619
+ * The limits this run's command line overrode, if any.
620
+ *
621
+ * Carried into the trace because a limit is enforced per project: each
622
+ * project's own file declares the number its gate reads, so an override that
623
+ * stopped at the run's own configuration would be a flag no gate looks at.
624
+ */
625
+ readonly limitOverrides?: CallidescopeLimitOverrides | undefined;
626
+ readonly workspaceRoot: string;
627
+ }
628
+
629
+ /** What one trace produced, alongside the projects it covered. */
630
+ export declare interface TraceOutcome extends AnalyzeOutcome {
631
+ /** Every project the run measured, its dependency closure included. */
632
+ readonly projectNames: readonly string[];
633
+ /**
634
+ * Workspace-relative root of each project the run was scoped to, keyed by
635
+ * name — the starting projects, not the closure they reached.
636
+ */
637
+ readonly startingProjectRoots: ReadonlyMap<string, string>;
638
+ /**
639
+ * The written destinations each project declared for itself, by name.
640
+ *
641
+ * Carried out of the trace rather than re-read at write time: the files were
642
+ * already opened once to decide what the run measures, and reading them a
643
+ * second time is how a run comes to publish against one answer and measure
644
+ * against another.
645
+ */
646
+ readonly writeByProject: ReadonlyMap<string, ResolvedCallidescopeWriteConfiguration>;
647
+ }
648
+
649
+ export { }
@@ -0,0 +1,2 @@
1
+ import { a as e, i as t, n, r, t as i } from "../main.module-tKMvFmcY.js";
2
+ export { n as AddressLookupModule, r as AddressLookupService, t as CallidescopeModule, e as CallidescopeService, i as MainModule };
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import { o as e, t } from "../main.module-tKMvFmcY.js";
3
+ import { CommandFactory as n } from "nest-commander";
4
+ import "reflect-metadata";
5
+ //#region packages/ic-suite/callidescope/callidescope-cli/src/main.ts
6
+ async function r() {
7
+ let r = new e();
8
+ r.setContext("CommandFactory"), await n.run(t, {
9
+ bufferLogs: !0,
10
+ logger: r,
11
+ serviceErrorHandler: (e) => {
12
+ r.error("🔭 Failed a run", e.stack, { reason: e.message }), process.exitCode = 1;
13
+ }
14
+ });
15
+ }
16
+ r();
17
+ //#endregion