@packmind/cli 0.2.5

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/main.cjs ADDED
@@ -0,0 +1,4084 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __copyProps = (to, from, except, desc) => {
8
+ if (from && typeof from === "object" || typeof from === "function") {
9
+ for (let key of __getOwnPropNames(from))
10
+ if (!__hasOwnProp.call(to, key) && key !== except)
11
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
+ }
13
+ return to;
14
+ };
15
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
16
+ // If the importer is in node compatibility mode or this is not an ESM
17
+ // file that has been converted to a CommonJS file using a Babel-
18
+ // compatible transform (i.e. "__esModule" has not been set), then set
19
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
+ mod
22
+ ));
23
+
24
+ // apps/cli/src/main.ts
25
+ var import_chalk2 = __toESM(require("chalk"));
26
+ var import_cmd_ts2 = require("cmd-ts");
27
+
28
+ // apps/cli/src/infra/commands/LinterCommand.ts
29
+ var import_cmd_ts = require("cmd-ts");
30
+
31
+ // packages/shared/src/ai/prompts/OpenAIService.ts
32
+ var import_openai = __toESM(require("openai"));
33
+
34
+ // packages/shared/src/config/infra/Infisical/InfisicalConfig.ts
35
+ var import_sdk = require("@infisical/sdk");
36
+
37
+ // packages/shared/src/logger/PackmindLogger.ts
38
+ var import_winston = __toESM(require("winston"));
39
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
40
+ LogLevel2["SILENT"] = "silent";
41
+ LogLevel2["ERROR"] = "error";
42
+ LogLevel2["WARN"] = "warn";
43
+ LogLevel2["INFO"] = "info";
44
+ LogLevel2["HTTP"] = "http";
45
+ LogLevel2["VERBOSE"] = "verbose";
46
+ LogLevel2["DEBUG"] = "debug";
47
+ LogLevel2["SILLY"] = "silly";
48
+ return LogLevel2;
49
+ })(LogLevel || {});
50
+ var PackmindLogger = class {
51
+ constructor(name, level = "info" /* INFO */) {
52
+ this.name = name;
53
+ const envLogLevel = process.env["PACKMIND_LOG_LEVEL"];
54
+ let finalLevel = level;
55
+ if (envLogLevel && Object.values(LogLevel).includes(envLogLevel)) {
56
+ finalLevel = envLogLevel;
57
+ }
58
+ this.currentLevel = finalLevel;
59
+ if (finalLevel !== "silent" /* SILENT */) {
60
+ this.logger = import_winston.default.createLogger({
61
+ level: finalLevel,
62
+ format: import_winston.default.format.combine(
63
+ import_winston.default.format.timestamp(),
64
+ import_winston.default.format.errors({ stack: true }),
65
+ import_winston.default.format.label({ label: this.name }),
66
+ import_winston.default.format.json()
67
+ ),
68
+ transports: [
69
+ new import_winston.default.transports.Console({
70
+ format: import_winston.default.format.combine(
71
+ import_winston.default.format.colorize(),
72
+ import_winston.default.format.printf(
73
+ ({ timestamp, level: level2, message, label, ...meta }) => {
74
+ const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : "";
75
+ return `${timestamp} [${label}] ${level2}: ${message}${metaStr}`;
76
+ }
77
+ )
78
+ )
79
+ })
80
+ ]
81
+ });
82
+ } else {
83
+ this.logger = null;
84
+ }
85
+ }
86
+ error(message, meta) {
87
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
88
+ this.logger.error(message, meta);
89
+ }
90
+ warn(message, meta) {
91
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
92
+ this.logger.warn(message, meta);
93
+ }
94
+ info(message, meta) {
95
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
96
+ this.logger.info(message, meta);
97
+ }
98
+ http(message, meta) {
99
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
100
+ this.logger.http(message, meta);
101
+ }
102
+ verbose(message, meta) {
103
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
104
+ this.logger.verbose(message, meta);
105
+ }
106
+ debug(message, meta) {
107
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
108
+ this.logger.debug(message, meta);
109
+ }
110
+ silly(message, meta) {
111
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
112
+ this.logger.silly(message, meta);
113
+ }
114
+ log(level, message, meta) {
115
+ if (this.currentLevel === "silent" /* SILENT */ || !this.logger) return;
116
+ this.logger.log(level, message, meta);
117
+ }
118
+ setLevel(level) {
119
+ this.currentLevel = level;
120
+ if (level !== "silent" /* SILENT */ && this.logger) {
121
+ this.logger.level = level;
122
+ }
123
+ }
124
+ getName() {
125
+ return this.name;
126
+ }
127
+ };
128
+
129
+ // packages/shared/src/config/infra/Infisical/InfisicalConfig.ts
130
+ var origin = "InfisicalConfig";
131
+ var InfisicalConfig = class {
132
+ constructor(clientId, clientSecret, env, projectId, logger = new PackmindLogger(origin)) {
133
+ this.clientId = clientId;
134
+ this.clientSecret = clientSecret;
135
+ this.env = env;
136
+ this.projectId = projectId;
137
+ this.logger = logger;
138
+ this.logger.info("Initializing InfisicalConfig", { env, projectId });
139
+ try {
140
+ this.client = new import_sdk.InfisicalSDK({
141
+ siteUrl: "https://eu.infisical.com"
142
+ // Optional, defaults to https://app.infisical.com
143
+ });
144
+ this.logger.info("InfisicalSDK client created successfully", {
145
+ siteUrl: "https://eu.infisical.com"
146
+ });
147
+ } catch (error) {
148
+ this.logger.error("Failed to create InfisicalSDK client", {
149
+ error: error instanceof Error ? error.message : String(error)
150
+ });
151
+ throw error;
152
+ }
153
+ }
154
+ async initClient() {
155
+ this.logger.info("Initializing Infisical client authentication");
156
+ try {
157
+ this.logger.debug("Authenticating with Infisical using universal auth");
158
+ await this.client.auth().universalAuth.login({
159
+ clientId: this.clientId,
160
+ clientSecret: this.clientSecret
161
+ });
162
+ this.logger.info("Infisical client authenticated successfully");
163
+ } catch (error) {
164
+ this.logger.error("Failed to authenticate Infisical client", {
165
+ error: error instanceof Error ? error.message : String(error)
166
+ });
167
+ throw error;
168
+ }
169
+ }
170
+ async getValue(secretName) {
171
+ this.logger.info("Retrieving secret from Infisical", {
172
+ secretName,
173
+ env: this.env,
174
+ projectId: this.projectId
175
+ });
176
+ try {
177
+ this.logger.debug("Fetching secret from Infisical API", { secretName });
178
+ const nameSecret = await this.client.secrets().getSecret({
179
+ projectId: this.projectId,
180
+ environment: this.env,
181
+ secretName
182
+ });
183
+ if (nameSecret?.secretValue) {
184
+ this.logger.info("Secret retrieved from Infisical successfully", {
185
+ secretName
186
+ });
187
+ return nameSecret.secretValue;
188
+ } else {
189
+ this.logger.warn("Secret not found or has no value in Infisical", {
190
+ secretName
191
+ });
192
+ return null;
193
+ }
194
+ } catch (error) {
195
+ this.logger.warn("Failed to retrieve secret from Infisical", {
196
+ secretName,
197
+ env: this.env,
198
+ projectId: this.projectId,
199
+ error: error instanceof Error ? error.message : String(error)
200
+ });
201
+ throw error;
202
+ }
203
+ }
204
+ };
205
+
206
+ // packages/shared/src/config/config/Configuration.ts
207
+ var origin2 = "Configuration";
208
+ var Configuration = class _Configuration {
209
+ constructor() {
210
+ this.initialized = false;
211
+ this.initializationPromise = null;
212
+ }
213
+ static {
214
+ this.logger = new PackmindLogger(
215
+ origin2,
216
+ "info" /* INFO */
217
+ );
218
+ }
219
+ static getInstance(logger) {
220
+ if (logger) {
221
+ _Configuration.logger = logger;
222
+ }
223
+ _Configuration.logger.debug("Getting Configuration instance");
224
+ if (!_Configuration.instance) {
225
+ _Configuration.logger.info("Creating new Configuration instance");
226
+ _Configuration.instance = new _Configuration();
227
+ }
228
+ return _Configuration.instance;
229
+ }
230
+ async initialize(env) {
231
+ if (this.initialized) {
232
+ _Configuration.logger.debug("Configuration already initialized, skipping");
233
+ return;
234
+ }
235
+ if (this.initializationPromise) {
236
+ _Configuration.logger.debug(
237
+ "Configuration initialization already in progress, waiting for completion"
238
+ );
239
+ await this.initializationPromise;
240
+ return;
241
+ }
242
+ this.initializationPromise = this.performInitialization(env);
243
+ try {
244
+ await this.initializationPromise;
245
+ } finally {
246
+ this.initializationPromise = null;
247
+ }
248
+ }
249
+ async performInitialization(env) {
250
+ _Configuration.logger.info("Initializing Configuration");
251
+ try {
252
+ const configurationMode = env["CONFIGURATION"]?.toLowerCase();
253
+ _Configuration.logger.debug("Configuration mode detected", {
254
+ mode: configurationMode
255
+ });
256
+ if (configurationMode === "infisical") {
257
+ _Configuration.logger.info("Initializing Infisical configuration");
258
+ const clientId = env["INFISICAL_CLIENT_ID"];
259
+ const clientSecret = env["INFISICAL_CLIENT_SECRET"];
260
+ const infisicalEnv = env["INFISICAL_ENV"];
261
+ const projectId = env["INFISICAL_PROJECT_ID"];
262
+ if (!clientId || !clientSecret || !infisicalEnv || !projectId) {
263
+ _Configuration.logger.error("Infisical configuration is incomplete", {
264
+ hasClientId: !!clientId,
265
+ hasClientSecret: !!clientSecret,
266
+ hasInfisicalEnv: !!infisicalEnv,
267
+ hasProjectId: !!projectId
268
+ });
269
+ throw new Error(
270
+ "Infisical configuration is incomplete. Please set INFISICAL_CLIENT_ID, INFISICAL_CLIENT_SECRET, INFISICAL_ENV, and INFISICAL_PROJECT_ID environment variables."
271
+ );
272
+ }
273
+ this.infisicalConfig = new InfisicalConfig(
274
+ clientId,
275
+ clientSecret,
276
+ infisicalEnv,
277
+ projectId
278
+ );
279
+ _Configuration.logger.debug("Initializing Infisical client");
280
+ await this.infisicalConfig.initClient();
281
+ _Configuration.logger.info(
282
+ "Infisical configuration initialized successfully"
283
+ );
284
+ } else {
285
+ _Configuration.logger.info(
286
+ "Using environment variables only (no Infisical)"
287
+ );
288
+ }
289
+ this.initialized = true;
290
+ _Configuration.logger.info("Configuration initialization completed");
291
+ } catch (error) {
292
+ _Configuration.logger.error("Failed to initialize Configuration", {
293
+ error: error instanceof Error ? error.message : String(error)
294
+ });
295
+ throw error;
296
+ }
297
+ }
298
+ static async getConfigWithDefault(key, defaultValue) {
299
+ const value = await _Configuration.getConfig(key);
300
+ return value ?? defaultValue;
301
+ }
302
+ static async getConfig(key, env = process.env, logger) {
303
+ if (logger) {
304
+ _Configuration.logger = logger;
305
+ }
306
+ _Configuration.logger.info("Getting configuration value", { key });
307
+ try {
308
+ const instance = _Configuration.getInstance();
309
+ await instance.initialize(env);
310
+ const envValue = env[key];
311
+ if (envValue) {
312
+ _Configuration.logger.debug(
313
+ "Configuration value found in environment variables",
314
+ { key }
315
+ );
316
+ return envValue;
317
+ }
318
+ if (instance.infisicalConfig) {
319
+ _Configuration.logger.debug(
320
+ "Checking Infisical for configuration value",
321
+ { key }
322
+ );
323
+ const infisicalValue = await instance.infisicalConfig.getValue(key);
324
+ if (infisicalValue) {
325
+ _Configuration.logger.debug("Configuration value found in Infisical", {
326
+ key
327
+ });
328
+ return infisicalValue;
329
+ }
330
+ }
331
+ _Configuration.logger.warn("Configuration value not found", { key });
332
+ return null;
333
+ } catch (error) {
334
+ _Configuration.logger.warn("Failed to get configuration value", {
335
+ key,
336
+ error: error instanceof Error ? error.message : String(error)
337
+ });
338
+ return null;
339
+ }
340
+ }
341
+ };
342
+
343
+ // packages/shared/src/cache/Cache.ts
344
+ var import_ioredis = __toESM(require("ioredis"));
345
+ var origin3 = "Cache";
346
+ var Cache = class _Cache {
347
+ constructor() {
348
+ this.initialized = false;
349
+ this.connectionConfig = {
350
+ host: "redis",
351
+ port: 6379,
352
+ maxRetriesPerRequest: 3
353
+ };
354
+ }
355
+ static {
356
+ this.logger = new PackmindLogger(
357
+ origin3,
358
+ "info" /* INFO */
359
+ );
360
+ }
361
+ static {
362
+ // Default cache expiration time in seconds (5 minutes)
363
+ this.DEFAULT_EXPIRATION_SECONDS = 300;
364
+ }
365
+ /**
366
+ * Get the singleton instance of Cache
367
+ */
368
+ static getInstance() {
369
+ _Cache.logger.debug("Getting Cache instance");
370
+ if (!_Cache.instance) {
371
+ _Cache.logger.info("Creating new Cache instance");
372
+ _Cache.instance = new _Cache();
373
+ }
374
+ return _Cache.instance;
375
+ }
376
+ /**
377
+ * Initialize the Redis client with configuration
378
+ * This should be called during application startup
379
+ */
380
+ async initialize() {
381
+ if (this.initialized) {
382
+ return;
383
+ }
384
+ _Cache.logger.info("Initializing Redis cache client");
385
+ try {
386
+ const redisUri = await Configuration.getConfig("REDIS_URI");
387
+ if (!redisUri) {
388
+ throw new Error("REDIS_URI configuration is required");
389
+ }
390
+ _Cache.logger.info("Using REDIS_URI configuration");
391
+ this.client = new import_ioredis.default(redisUri, {
392
+ maxRetriesPerRequest: 3
393
+ });
394
+ this.client.on("error", (error) => {
395
+ _Cache.logger.error("Redis cache client error", {
396
+ error: error instanceof Error ? error.message : String(error)
397
+ });
398
+ });
399
+ this.client.on("connect", () => {
400
+ _Cache.logger.info("Redis cache client connected successfully");
401
+ });
402
+ this.initialized = true;
403
+ _Cache.logger.info("Cache initialization completed");
404
+ } catch (error) {
405
+ _Cache.logger.error("Failed to initialize cache", {
406
+ error: error instanceof Error ? error.message : String(error)
407
+ });
408
+ throw new Error(
409
+ `Cache initialization failed: ${error instanceof Error ? error.message : String(error)}`
410
+ );
411
+ }
412
+ }
413
+ /**
414
+ * Set a value in the cache with optional expiration
415
+ * @param key - The cache key
416
+ * @param value - The value to cache (will be JSON serialized)
417
+ * @param expirationSeconds - Expiration time in seconds (default: 300s)
418
+ */
419
+ async set(key, value, expirationSeconds = _Cache.DEFAULT_EXPIRATION_SECONDS) {
420
+ if (!this.initialized || !this.client) {
421
+ _Cache.logger.warn("Cache not initialized, skipping set operation", {
422
+ key
423
+ });
424
+ return;
425
+ }
426
+ try {
427
+ const serializedValue = JSON.stringify(value);
428
+ await this.client.setex(key, expirationSeconds, serializedValue);
429
+ } catch (error) {
430
+ _Cache.logger.warn(
431
+ "Failed to set cache value, continuing without caching",
432
+ {
433
+ key,
434
+ error: error instanceof Error ? error.message : String(error)
435
+ }
436
+ );
437
+ }
438
+ }
439
+ /**
440
+ * Get a value from the cache
441
+ * @param key - The cache key
442
+ * @returns The cached value or null if not found, expired, or error occurred
443
+ */
444
+ async get(key) {
445
+ if (!this.initialized || !this.client) {
446
+ _Cache.logger.warn(
447
+ "Cache not initialized, returning null for get operation",
448
+ { key }
449
+ );
450
+ return null;
451
+ }
452
+ try {
453
+ const serializedValue = await this.client.get(key);
454
+ if (serializedValue === null) {
455
+ return null;
456
+ }
457
+ const value = JSON.parse(serializedValue);
458
+ return value;
459
+ } catch (error) {
460
+ _Cache.logger.warn("Failed to get cache value, returning null", {
461
+ key,
462
+ error: error instanceof Error ? error.message : String(error)
463
+ });
464
+ return null;
465
+ }
466
+ }
467
+ /**
468
+ * Invalidate (delete) a cache entry
469
+ * @param key - The cache key to invalidate
470
+ */
471
+ async invalidate(key) {
472
+ if (!this.initialized || !this.client) {
473
+ _Cache.logger.warn(
474
+ "Cache not initialized, skipping invalidate operation",
475
+ { key }
476
+ );
477
+ return;
478
+ }
479
+ try {
480
+ await this.client.del(key);
481
+ } catch (error) {
482
+ _Cache.logger.warn(
483
+ "Failed to invalidate cache key, continuing without invalidation",
484
+ {
485
+ key,
486
+ error: error instanceof Error ? error.message : String(error)
487
+ }
488
+ );
489
+ }
490
+ }
491
+ /**
492
+ * Disconnect the Redis client (for cleanup during shutdown)
493
+ */
494
+ async disconnect() {
495
+ _Cache.logger.info("Disconnecting cache client");
496
+ if (this.client) {
497
+ try {
498
+ await this.client.disconnect();
499
+ _Cache.logger.info("Cache client disconnected successfully");
500
+ } catch (error) {
501
+ _Cache.logger.error("Error disconnecting cache client", {
502
+ error: error instanceof Error ? error.message : String(error)
503
+ });
504
+ }
505
+ }
506
+ this.initialized = false;
507
+ }
508
+ /**
509
+ * Get cache statistics (for monitoring/debugging)
510
+ */
511
+ async getStats() {
512
+ return {
513
+ connected: this.client?.status === "ready",
514
+ initialized: this.initialized
515
+ };
516
+ }
517
+ };
518
+
519
+ // packages/shared/src/types/brandedTypes.ts
520
+ function brandedIdFactory() {
521
+ return (id) => id;
522
+ }
523
+
524
+ // packages/shared/src/repositories/AbstractRepository.ts
525
+ var import_common = require("@nestjs/common");
526
+
527
+ // packages/shared/src/sse/RedisSSEClient.ts
528
+ var import_ioredis2 = __toESM(require("ioredis"));
529
+ var origin4 = "RedisSSEClient";
530
+ var RedisSSEClient = class _RedisSSEClient {
531
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
532
+ constructor() {
533
+ this.initialized = false;
534
+ }
535
+ static {
536
+ this.logger = new PackmindLogger(origin4);
537
+ }
538
+ static getInstance() {
539
+ _RedisSSEClient.logger.debug("Getting RedisSSEClient instance");
540
+ if (!_RedisSSEClient.instance) {
541
+ _RedisSSEClient.logger.info("Creating new RedisSSEClient instance");
542
+ _RedisSSEClient.instance = new _RedisSSEClient();
543
+ }
544
+ return _RedisSSEClient.instance;
545
+ }
546
+ /**
547
+ * Initialize Redis clients using the same configuration as BullMQ
548
+ */
549
+ async initialize() {
550
+ if (this.initialized) return;
551
+ _RedisSSEClient.logger.info("Initializing Redis SSE clients");
552
+ try {
553
+ const redisURI = await Configuration.getConfig("REDIS_URI") || "redis";
554
+ this.publisherClient = new import_ioredis2.default(redisURI);
555
+ this.subscriberClient = new import_ioredis2.default(redisURI);
556
+ this.publisherClient.on("error", (error) => {
557
+ _RedisSSEClient.logger.error("Redis publisher client error", {
558
+ error: error.message
559
+ });
560
+ });
561
+ this.subscriberClient.on("error", (error) => {
562
+ _RedisSSEClient.logger.error("Redis subscriber client error", {
563
+ error: error.message
564
+ });
565
+ });
566
+ await this.publisherClient.ping();
567
+ await this.subscriberClient.ping();
568
+ this.initialized = true;
569
+ _RedisSSEClient.logger.info("Redis SSE clients initialized successfully");
570
+ } catch (error) {
571
+ _RedisSSEClient.logger.error("Failed to initialize Redis SSE clients", {
572
+ error: error instanceof Error ? error.message : String(error)
573
+ });
574
+ throw error;
575
+ }
576
+ }
577
+ /**
578
+ * Publish a message to a Redis channel
579
+ */
580
+ async publish(channel, message) {
581
+ await this.initialize();
582
+ if (!this.publisherClient) {
583
+ throw new Error("Publisher client not initialized");
584
+ }
585
+ _RedisSSEClient.logger.debug("Publishing message to Redis channel", {
586
+ channel,
587
+ messageLength: message.length
588
+ });
589
+ try {
590
+ const subscriberCount = await this.publisherClient.publish(
591
+ channel,
592
+ message
593
+ );
594
+ _RedisSSEClient.logger.debug("Message published successfully", {
595
+ channel,
596
+ subscriberCount
597
+ });
598
+ return subscriberCount;
599
+ } catch (error) {
600
+ _RedisSSEClient.logger.error("Failed to publish message", {
601
+ channel,
602
+ error: error instanceof Error ? error.message : String(error)
603
+ });
604
+ throw error;
605
+ }
606
+ }
607
+ /**
608
+ * Subscribe to a Redis channel
609
+ */
610
+ async subscribe(channel, callback) {
611
+ await this.initialize();
612
+ if (!this.subscriberClient) {
613
+ throw new Error("Subscriber client not initialized");
614
+ }
615
+ _RedisSSEClient.logger.info("Subscribing to Redis channel", { channel });
616
+ try {
617
+ this.subscriberClient.on("message", (receivedChannel, message) => {
618
+ if (receivedChannel === channel) {
619
+ _RedisSSEClient.logger.debug("Received message from Redis channel", {
620
+ channel: receivedChannel,
621
+ messageLength: message.length
622
+ });
623
+ callback(message);
624
+ }
625
+ });
626
+ await this.subscriberClient.subscribe(channel);
627
+ _RedisSSEClient.logger.info("Successfully subscribed to Redis channel", {
628
+ channel
629
+ });
630
+ } catch (error) {
631
+ _RedisSSEClient.logger.error("Failed to subscribe to Redis channel", {
632
+ channel,
633
+ error: error instanceof Error ? error.message : String(error)
634
+ });
635
+ throw error;
636
+ }
637
+ }
638
+ /**
639
+ * Unsubscribe from a Redis channel
640
+ */
641
+ async unsubscribe(channel) {
642
+ if (!this.subscriberClient) {
643
+ return;
644
+ }
645
+ _RedisSSEClient.logger.info("Unsubscribing from Redis channel", { channel });
646
+ try {
647
+ await this.subscriberClient.unsubscribe(channel);
648
+ _RedisSSEClient.logger.info(
649
+ "Successfully unsubscribed from Redis channel",
650
+ { channel }
651
+ );
652
+ } catch (error) {
653
+ _RedisSSEClient.logger.error("Failed to unsubscribe from Redis channel", {
654
+ channel,
655
+ error: error instanceof Error ? error.message : String(error)
656
+ });
657
+ }
658
+ }
659
+ /**
660
+ * Clean up Redis connections
661
+ */
662
+ async disconnect() {
663
+ _RedisSSEClient.logger.info("Disconnecting Redis SSE clients");
664
+ try {
665
+ if (this.publisherClient) {
666
+ this.publisherClient.disconnect();
667
+ }
668
+ if (this.subscriberClient) {
669
+ this.subscriberClient.disconnect();
670
+ }
671
+ this.initialized = false;
672
+ _RedisSSEClient.logger.info("Redis SSE clients disconnected successfully");
673
+ } catch (error) {
674
+ _RedisSSEClient.logger.error("Error disconnecting Redis SSE clients", {
675
+ error: error instanceof Error ? error.message : String(error)
676
+ });
677
+ }
678
+ }
679
+ /**
680
+ * Get connection status
681
+ */
682
+ isConnected() {
683
+ return this.initialized && this.publisherClient?.status === "ready" && this.subscriberClient?.status === "ready";
684
+ }
685
+ };
686
+
687
+ // packages/shared/src/sse/types.ts
688
+ var SSE_REDIS_CHANNELS = {
689
+ /**
690
+ * Channel for subscription management messages
691
+ * Used when clients subscribe/unsubscribe to specific event types
692
+ */
693
+ SUBSCRIPTIONS: "sse:subscriptions",
694
+ /**
695
+ * Channel for event notifications
696
+ * Used to broadcast SSE events to all API instances
697
+ */
698
+ EVENTS: "sse:events"
699
+ };
700
+ function createSSEEventMessage(eventType, params, data, targetUserIds) {
701
+ return {
702
+ eventType,
703
+ params,
704
+ data,
705
+ targetUserIds,
706
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
707
+ };
708
+ }
709
+ function serializeSSERedisMessage(message) {
710
+ try {
711
+ return JSON.stringify(message);
712
+ } catch (error) {
713
+ throw new Error(
714
+ `Failed to serialize SSE Redis message: ${error instanceof Error ? error.message : String(error)}`
715
+ );
716
+ }
717
+ }
718
+
719
+ // packages/shared/src/types/sse/SSEEvent.ts
720
+ function createProgramStatusChangeEvent(ruleId, language) {
721
+ return {
722
+ type: "PROGRAM_STATUS_CHANGE",
723
+ data: { ruleId, language },
724
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
725
+ };
726
+ }
727
+ function createAssessmentStatusChangeEvent(ruleId, language) {
728
+ return {
729
+ type: "ASSESSMENT_STATUS_CHANGE",
730
+ data: {
731
+ ruleId,
732
+ language
733
+ },
734
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
735
+ };
736
+ }
737
+ function createUserContextChangeEvent(userId, organizationId, changeType, role) {
738
+ return {
739
+ type: "USER_CONTEXT_CHANGE",
740
+ data: {
741
+ userId,
742
+ organizationId,
743
+ changeType,
744
+ role
745
+ },
746
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
747
+ };
748
+ }
749
+
750
+ // packages/shared/src/sse/SSEEventPublisher.ts
751
+ var origin5 = "SSEEventPublisher";
752
+ var SSEEventPublisher = class _SSEEventPublisher {
753
+ static {
754
+ this.logger = new PackmindLogger(origin5);
755
+ }
756
+ /**
757
+ * Get the singleton instance
758
+ */
759
+ static getInstance() {
760
+ _SSEEventPublisher.logger.debug("Getting SSEEventPublisher instance");
761
+ if (!_SSEEventPublisher.instance) {
762
+ _SSEEventPublisher.logger.info("Creating new SSEEventPublisher instance");
763
+ _SSEEventPublisher.instance = new _SSEEventPublisher();
764
+ _SSEEventPublisher.redisClient = RedisSSEClient.getInstance();
765
+ }
766
+ return _SSEEventPublisher.instance;
767
+ }
768
+ constructor() {
769
+ }
770
+ /**
771
+ * Publish a program status change event for cache invalidation
772
+ * This triggers React Query to refetch the program data
773
+ */
774
+ static async publishProgramStatusEvent(programId, ruleId, language, userId, organizationId) {
775
+ _SSEEventPublisher.logger.info("Publishing program status change event", {
776
+ programId,
777
+ ruleId,
778
+ language,
779
+ userId,
780
+ organizationId
781
+ });
782
+ try {
783
+ const event = createProgramStatusChangeEvent(ruleId, language);
784
+ await _SSEEventPublisher.publishEvent(
785
+ "program_status_change",
786
+ [ruleId, language],
787
+ event,
788
+ userId ? [userId] : void 0
789
+ );
790
+ _SSEEventPublisher.logger.debug(
791
+ "Successfully published program status change event",
792
+ { programId, ruleId, language }
793
+ );
794
+ } catch (error) {
795
+ _SSEEventPublisher.logger.error(
796
+ "Failed to publish program status change event",
797
+ {
798
+ programId,
799
+ userId,
800
+ error: error instanceof Error ? error.message : String(error)
801
+ }
802
+ );
803
+ throw error;
804
+ }
805
+ }
806
+ /**
807
+ * Publish an assessment status change event for cache invalidation
808
+ * This triggers React Query to refetch the assessment data
809
+ */
810
+ static async publishAssessmentStatusEvent(ruleId, language, userId, organizationId) {
811
+ _SSEEventPublisher.logger.info("Publishing assessment status change event", {
812
+ ruleId,
813
+ language,
814
+ userId,
815
+ organizationId
816
+ });
817
+ try {
818
+ const event = createAssessmentStatusChangeEvent(ruleId, language);
819
+ await _SSEEventPublisher.publishEvent(
820
+ "assessment_status_change",
821
+ [ruleId, language],
822
+ event,
823
+ userId ? [userId] : void 0
824
+ );
825
+ _SSEEventPublisher.logger.debug(
826
+ "Successfully published assessment status change event",
827
+ { ruleId, language }
828
+ );
829
+ } catch (error) {
830
+ _SSEEventPublisher.logger.error(
831
+ "Failed to publish assessment status change event",
832
+ {
833
+ userId,
834
+ error: error instanceof Error ? error.message : String(error)
835
+ }
836
+ );
837
+ throw error;
838
+ }
839
+ }
840
+ /**
841
+ * Publish an event to notify a user that their context (role or membership) changed
842
+ * This should trigger a refetch of the /me route on the frontend
843
+ */
844
+ static async publishUserContextChangeEvent(userId, organizationId, changeType, role) {
845
+ _SSEEventPublisher.logger.info("Publishing user context change event", {
846
+ userId,
847
+ organizationId,
848
+ changeType,
849
+ role
850
+ });
851
+ try {
852
+ const event = createUserContextChangeEvent(
853
+ userId,
854
+ organizationId,
855
+ changeType,
856
+ role
857
+ );
858
+ await _SSEEventPublisher.publishEvent("user_context_change", [], event, [
859
+ userId
860
+ ]);
861
+ _SSEEventPublisher.logger.debug(
862
+ "Successfully published user context change event",
863
+ {
864
+ userId,
865
+ organizationId,
866
+ changeType
867
+ }
868
+ );
869
+ } catch (error) {
870
+ _SSEEventPublisher.logger.error(
871
+ "Failed to publish user context change event",
872
+ {
873
+ userId,
874
+ organizationId,
875
+ changeType,
876
+ error: error instanceof Error ? error.message : String(error)
877
+ }
878
+ );
879
+ throw error;
880
+ }
881
+ }
882
+ /**
883
+ * Generic method to publish any SSE event type to Redis pub/sub
884
+ */
885
+ static async publishEvent(eventType, params, data, targetUserIds) {
886
+ _SSEEventPublisher.logger.info("Publishing SSE event", {
887
+ eventType,
888
+ params,
889
+ targetUserIds: targetUserIds?.length || "all"
890
+ });
891
+ try {
892
+ _SSEEventPublisher.getInstance();
893
+ const redisClient = _SSEEventPublisher.redisClient;
894
+ const message = createSSEEventMessage(
895
+ eventType,
896
+ params,
897
+ data,
898
+ targetUserIds
899
+ );
900
+ const serializedMessage = serializeSSERedisMessage(message);
901
+ await redisClient.publish(SSE_REDIS_CHANNELS.EVENTS, serializedMessage);
902
+ _SSEEventPublisher.logger.debug("Successfully published SSE event", {
903
+ eventType,
904
+ params
905
+ });
906
+ } catch (error) {
907
+ _SSEEventPublisher.logger.error("Failed to publish SSE event", {
908
+ eventType,
909
+ params,
910
+ error: error instanceof Error ? error.message : String(error)
911
+ });
912
+ throw error;
913
+ }
914
+ }
915
+ };
916
+
917
+ // packages/shared/src/types/git/GitCommit.ts
918
+ var createGitCommitId = brandedIdFactory();
919
+
920
+ // packages/shared/src/types/git/GitProvider.ts
921
+ var createGitProviderId = brandedIdFactory();
922
+
923
+ // packages/shared/src/types/git/GitRepo.ts
924
+ var createGitRepoId = brandedIdFactory();
925
+
926
+ // packages/shared/src/types/standards/StandardVersion.ts
927
+ var createStandardVersionId = brandedIdFactory();
928
+
929
+ // packages/shared/src/types/standards/Rule.ts
930
+ var createRuleId = brandedIdFactory();
931
+
932
+ // packages/shared/src/types/standards/RuleExample.ts
933
+ var createRuleExampleId = brandedIdFactory();
934
+
935
+ // packages/shared/src/types/standards/Standard.ts
936
+ var createStandardId = brandedIdFactory();
937
+
938
+ // packages/shared/src/types/accounts/Organization.ts
939
+ var createOrganizationId = brandedIdFactory();
940
+
941
+ // packages/shared/src/types/accounts/User.ts
942
+ var createUserId = brandedIdFactory();
943
+
944
+ // packages/shared/src/types/deployments/RenderMode.ts
945
+ var REQUIRED_RENDER_MODE = "PACKMIND" /* PACKMIND */;
946
+ var RENDER_MODE_ORDER = [
947
+ "PACKMIND" /* PACKMIND */,
948
+ "AGENTS_MD" /* AGENTS_MD */,
949
+ "JUNIE" /* JUNIE */,
950
+ "GH_COPILOT" /* GH_COPILOT */,
951
+ "CLAUDE" /* CLAUDE */,
952
+ "CURSOR" /* CURSOR */
953
+ ];
954
+ var normalizeRenderModes = (modes) => {
955
+ const uniqueModes = new Set(modes);
956
+ uniqueModes.add(REQUIRED_RENDER_MODE);
957
+ return RENDER_MODE_ORDER.filter((mode) => uniqueModes.has(mode));
958
+ };
959
+
960
+ // packages/shared/src/types/deployments/RenderModeConfiguration.ts
961
+ var createRenderModeConfigurationId = brandedIdFactory();
962
+ var DEFAULT_ACTIVE_RENDER_MODES = normalizeRenderModes([
963
+ "AGENTS_MD" /* AGENTS_MD */
964
+ ]);
965
+
966
+ // packages/shared/src/types/deployments/RecipesDeployment.ts
967
+ var createRecipesDeploymentId = brandedIdFactory();
968
+
969
+ // packages/shared/src/types/deployments/StandardsDeployment.ts
970
+ var createStandardsDeploymentId = brandedIdFactory();
971
+
972
+ // packages/shared/src/types/deployments/Target.ts
973
+ var createTargetId = brandedIdFactory();
974
+
975
+ // packages/shared/src/types/recipes/RecipeVersion.ts
976
+ var createRecipeVersionId = brandedIdFactory();
977
+
978
+ // packages/shared/src/types/recipes/Recipe.ts
979
+ var createRecipeId = brandedIdFactory();
980
+
981
+ // packages/shared/src/types/spaces/Space.ts
982
+ var createSpaceId = brandedIdFactory();
983
+
984
+ // packages/shared/src/types/languages/Language.ts
985
+ var ProgrammingLanguage = /* @__PURE__ */ ((ProgrammingLanguage3) => {
986
+ ProgrammingLanguage3["JAVASCRIPT"] = "JAVASCRIPT";
987
+ ProgrammingLanguage3["JAVASCRIPT_JSX"] = "JAVASCRIPT_JSX";
988
+ ProgrammingLanguage3["TYPESCRIPT"] = "TYPESCRIPT";
989
+ ProgrammingLanguage3["TYPESCRIPT_TSX"] = "TYPESCRIPT_TSX";
990
+ ProgrammingLanguage3["PYTHON"] = "PYTHON";
991
+ ProgrammingLanguage3["PHP"] = "PHP";
992
+ ProgrammingLanguage3["JAVA"] = "JAVA";
993
+ ProgrammingLanguage3["SCSS"] = "SCSS";
994
+ ProgrammingLanguage3["HTML"] = "HTML";
995
+ ProgrammingLanguage3["CSHARP"] = "CSHARP";
996
+ ProgrammingLanguage3["GENERIC"] = "GENERIC";
997
+ ProgrammingLanguage3["GO"] = "GO";
998
+ ProgrammingLanguage3["C"] = "C";
999
+ ProgrammingLanguage3["CPP"] = "CPP";
1000
+ ProgrammingLanguage3["SQL"] = "SQL";
1001
+ ProgrammingLanguage3["KOTLIN"] = "KOTLIN";
1002
+ ProgrammingLanguage3["VUE"] = "VUE";
1003
+ ProgrammingLanguage3["CSS"] = "CSS";
1004
+ ProgrammingLanguage3["YAML"] = "YAML";
1005
+ ProgrammingLanguage3["JSON"] = "JSON";
1006
+ ProgrammingLanguage3["XML"] = "XML";
1007
+ ProgrammingLanguage3["BASH"] = "BASH";
1008
+ ProgrammingLanguage3["MARKDOWN"] = "MARKDOWN";
1009
+ ProgrammingLanguage3["RUBY"] = "RUBY";
1010
+ ProgrammingLanguage3["RUST"] = "RUST";
1011
+ ProgrammingLanguage3["SAP_ABAP"] = "SAP_ABAP";
1012
+ ProgrammingLanguage3["SAP_CDS"] = "SAP_CDS";
1013
+ ProgrammingLanguage3["SAP_HANA_SQL"] = "SAP_HANA_SQL";
1014
+ ProgrammingLanguage3["SWIFT"] = "SWIFT";
1015
+ ProgrammingLanguage3["PROPERTIES"] = "PROPERTIES";
1016
+ return ProgrammingLanguage3;
1017
+ })(ProgrammingLanguage || {});
1018
+ var ProgrammingLanguageDetails = {
1019
+ ["GENERIC" /* GENERIC */]: {
1020
+ displayName: "Generic",
1021
+ fileExtensions: []
1022
+ },
1023
+ ["JAVASCRIPT" /* JAVASCRIPT */]: {
1024
+ displayName: "JavaScript",
1025
+ fileExtensions: ["js"]
1026
+ },
1027
+ ["JAVASCRIPT_JSX" /* JAVASCRIPT_JSX */]: {
1028
+ displayName: "JavaScript (JSX)",
1029
+ fileExtensions: ["jsx"]
1030
+ },
1031
+ ["TYPESCRIPT" /* TYPESCRIPT */]: {
1032
+ displayName: "TypeScript",
1033
+ fileExtensions: ["ts"]
1034
+ },
1035
+ ["TYPESCRIPT_TSX" /* TYPESCRIPT_TSX */]: {
1036
+ displayName: "TypeScript (TSX)",
1037
+ fileExtensions: ["tsx"]
1038
+ },
1039
+ ["PYTHON" /* PYTHON */]: {
1040
+ displayName: "Python",
1041
+ fileExtensions: ["py", "pyx", "pyw"]
1042
+ },
1043
+ ["PHP" /* PHP */]: {
1044
+ displayName: "PHP",
1045
+ fileExtensions: ["php", "phtml"]
1046
+ },
1047
+ ["JAVA" /* JAVA */]: {
1048
+ displayName: "Java",
1049
+ fileExtensions: ["java"]
1050
+ },
1051
+ ["SCSS" /* SCSS */]: {
1052
+ displayName: "SCSS",
1053
+ fileExtensions: ["scss"]
1054
+ },
1055
+ ["HTML" /* HTML */]: {
1056
+ displayName: "HTML",
1057
+ fileExtensions: ["html", "htm"]
1058
+ },
1059
+ ["CSHARP" /* CSHARP */]: {
1060
+ displayName: "C#",
1061
+ fileExtensions: ["cs"]
1062
+ },
1063
+ ["GO" /* GO */]: {
1064
+ displayName: "Go",
1065
+ fileExtensions: ["go"]
1066
+ },
1067
+ ["C" /* C */]: {
1068
+ displayName: "C",
1069
+ fileExtensions: ["c", "h"]
1070
+ },
1071
+ ["CPP" /* CPP */]: {
1072
+ displayName: "C++",
1073
+ fileExtensions: ["cpp", "cc", "cxx", "c++", "hpp", "hxx"]
1074
+ },
1075
+ ["SQL" /* SQL */]: {
1076
+ displayName: "SQL",
1077
+ fileExtensions: ["sql"]
1078
+ },
1079
+ ["KOTLIN" /* KOTLIN */]: {
1080
+ displayName: "Kotlin",
1081
+ fileExtensions: ["kt", "kts"]
1082
+ },
1083
+ ["VUE" /* VUE */]: {
1084
+ displayName: "Vue",
1085
+ fileExtensions: ["vue"]
1086
+ },
1087
+ ["CSS" /* CSS */]: {
1088
+ displayName: "CSS",
1089
+ fileExtensions: ["css"]
1090
+ },
1091
+ ["YAML" /* YAML */]: {
1092
+ displayName: "YAML",
1093
+ fileExtensions: ["yaml", "yml"]
1094
+ },
1095
+ ["JSON" /* JSON */]: {
1096
+ displayName: "JSON",
1097
+ fileExtensions: ["json"]
1098
+ },
1099
+ ["XML" /* XML */]: {
1100
+ displayName: "XML",
1101
+ fileExtensions: ["xml"]
1102
+ },
1103
+ ["BASH" /* BASH */]: {
1104
+ displayName: "Bash",
1105
+ fileExtensions: ["sh", "bash"]
1106
+ },
1107
+ ["MARKDOWN" /* MARKDOWN */]: {
1108
+ displayName: "Markdown",
1109
+ fileExtensions: ["md"]
1110
+ },
1111
+ ["RUST" /* RUST */]: {
1112
+ displayName: "Rust",
1113
+ fileExtensions: ["rs"]
1114
+ },
1115
+ ["RUBY" /* RUBY */]: {
1116
+ displayName: "Ruby",
1117
+ fileExtensions: ["rb"]
1118
+ },
1119
+ ["SAP_ABAP" /* SAP_ABAP */]: {
1120
+ displayName: "SAP ABAP",
1121
+ fileExtensions: ["abap", "ab4"]
1122
+ },
1123
+ ["SAP_CDS" /* SAP_CDS */]: {
1124
+ displayName: "SAP CDS",
1125
+ fileExtensions: ["cds"]
1126
+ },
1127
+ ["SAP_HANA_SQL" /* SAP_HANA_SQL */]: {
1128
+ displayName: "SAP HANA SQL",
1129
+ fileExtensions: [
1130
+ "hdbprocedure",
1131
+ "hdbfunction",
1132
+ "hdbview",
1133
+ "hdbcalculationview"
1134
+ ]
1135
+ },
1136
+ ["SWIFT" /* SWIFT */]: {
1137
+ displayName: "Swift",
1138
+ fileExtensions: ["swift"]
1139
+ },
1140
+ ["PROPERTIES" /* PROPERTIES */]: {
1141
+ displayName: "Properties",
1142
+ fileExtensions: ["properties"]
1143
+ }
1144
+ };
1145
+ var stringToProgrammingLanguage = (input) => {
1146
+ const trimmedInput = input.trim();
1147
+ if (!trimmedInput) {
1148
+ throw new Error("Language input cannot be empty");
1149
+ }
1150
+ const lowerInput = trimmedInput.toLowerCase();
1151
+ for (const enumValue of Object.values(ProgrammingLanguage)) {
1152
+ if (enumValue.toLowerCase() === lowerInput) {
1153
+ return enumValue;
1154
+ }
1155
+ }
1156
+ for (const [language, info] of Object.entries(ProgrammingLanguageDetails)) {
1157
+ if (info.displayName.toLowerCase() === lowerInput) {
1158
+ return language;
1159
+ }
1160
+ }
1161
+ for (const [language, info] of Object.entries(ProgrammingLanguageDetails)) {
1162
+ if (info.fileExtensions.some((ext) => ext.toLowerCase() === lowerInput)) {
1163
+ return language;
1164
+ }
1165
+ }
1166
+ const availableLanguages = Object.values(ProgrammingLanguageDetails).map((info) => info.displayName).join(", ");
1167
+ throw new Error(
1168
+ `Unknown programming language: "${trimmedInput}". Available languages: ${availableLanguages}`
1169
+ );
1170
+ };
1171
+
1172
+ // packages/shared/src/mail/SmtpMailService.ts
1173
+ var import_nodemailer = __toESM(require("nodemailer"));
1174
+
1175
+ // packages/shared/src/dataSources/local.ts
1176
+ var import_typeorm = require("typeorm");
1177
+ var dataSource = makeDatasource();
1178
+ function makeDatasource() {
1179
+ try {
1180
+ return new import_typeorm.DataSource({
1181
+ type: "postgres",
1182
+ url: process.env["DATABASE_URL"],
1183
+ entities: [],
1184
+ migrations: []
1185
+ });
1186
+ } catch {
1187
+ return {};
1188
+ }
1189
+ }
1190
+
1191
+ // apps/cli/src/application/useCases/ExecuteSingleFileAstUseCase.ts
1192
+ var ExecuteSingleFileAstUseCase = class _ExecuteSingleFileAstUseCase {
1193
+ constructor(linterExecutionUseCase) {
1194
+ this.linterExecutionUseCase = linterExecutionUseCase;
1195
+ }
1196
+ static {
1197
+ this.fallbackStandardSlug = "adhoc-linter";
1198
+ }
1199
+ static {
1200
+ this.fallbackRuleContent = "adhoc-rule";
1201
+ }
1202
+ async execute(command2) {
1203
+ const { program, fileContent, language } = command2;
1204
+ const result = await this.linterExecutionUseCase.execute({
1205
+ filePath: "cli-single-file",
1206
+ fileContent,
1207
+ language,
1208
+ programs: [
1209
+ {
1210
+ code: program,
1211
+ ruleContent: _ExecuteSingleFileAstUseCase.fallbackRuleContent,
1212
+ standardSlug: _ExecuteSingleFileAstUseCase.fallbackStandardSlug,
1213
+ sourceCodeState: "AST",
1214
+ language
1215
+ }
1216
+ ]
1217
+ });
1218
+ return result.violations.map(({ line, character }) => ({
1219
+ line,
1220
+ character
1221
+ }));
1222
+ }
1223
+ };
1224
+
1225
+ // apps/cli/src/application/services/GitService.ts
1226
+ var import_child_process = require("child_process");
1227
+ var import_util = require("util");
1228
+ var execAsync = (0, import_util.promisify)(import_child_process.exec);
1229
+ var origin6 = "GitService";
1230
+ var GitService = class {
1231
+ constructor(logger = new PackmindLogger(origin6)) {
1232
+ this.logger = logger;
1233
+ }
1234
+ async getGitRepositoryRoot(path2) {
1235
+ try {
1236
+ const { stdout } = await execAsync("git rev-parse --show-toplevel", {
1237
+ cwd: path2
1238
+ });
1239
+ const gitRoot = stdout.trim();
1240
+ this.logger.debug("Resolved git repository root", {
1241
+ inputPath: path2,
1242
+ gitRoot
1243
+ });
1244
+ return gitRoot;
1245
+ } catch (error) {
1246
+ if (error instanceof Error) {
1247
+ throw new Error(
1248
+ `Failed to get Git repository root. The path '${path2}' does not appear to be inside a Git repository.
1249
+ ${error.message}`
1250
+ );
1251
+ }
1252
+ throw new Error("Failed to get Git repository root: Unknown error");
1253
+ }
1254
+ }
1255
+ async getCurrentBranches(repoPath) {
1256
+ try {
1257
+ const { stdout } = await execAsync("git branch -a --contains HEAD", {
1258
+ cwd: repoPath
1259
+ });
1260
+ const branches = this.parseBranches(stdout);
1261
+ return { branches };
1262
+ } catch (error) {
1263
+ if (error instanceof Error) {
1264
+ throw new Error(
1265
+ `Failed to get Git branches. packmind-cli lint must be run in a Git repository.
1266
+ ${error.message}`
1267
+ );
1268
+ }
1269
+ throw new Error("Failed to get Git branches: Unknown error");
1270
+ }
1271
+ }
1272
+ async getGitRemoteUrl(repoPath, origin10) {
1273
+ try {
1274
+ const { stdout } = await execAsync("git remote -v", {
1275
+ cwd: repoPath
1276
+ });
1277
+ const remotes = this.parseRemotes(stdout);
1278
+ if (remotes.length === 0) {
1279
+ throw new Error("No Git remotes found in the repository");
1280
+ }
1281
+ let selectedRemote;
1282
+ if (origin10) {
1283
+ const foundRemote = remotes.find((remote) => remote.name === origin10);
1284
+ if (!foundRemote) {
1285
+ throw new Error(`Remote '${origin10}' not found in repository`);
1286
+ }
1287
+ selectedRemote = foundRemote.url;
1288
+ } else if (remotes.length === 1) {
1289
+ selectedRemote = remotes[0].url;
1290
+ } else {
1291
+ const originRemote = remotes.find((remote) => remote.name === "origin");
1292
+ if (!originRemote) {
1293
+ throw new Error(
1294
+ "Multiple remotes found but no 'origin' remote. Please specify the remote name."
1295
+ );
1296
+ }
1297
+ selectedRemote = originRemote.url;
1298
+ }
1299
+ return {
1300
+ gitRemoteUrl: this.normalizeGitUrl(selectedRemote)
1301
+ };
1302
+ } catch (error) {
1303
+ if (error instanceof Error) {
1304
+ throw new Error(
1305
+ `Failed to get Git remote URL. packmind-cli lint must be run in a Git repository.
1306
+ ${error.message}`
1307
+ );
1308
+ }
1309
+ throw new Error("Failed to get Git remote URL: Unknown error");
1310
+ }
1311
+ }
1312
+ parseRemotes(gitRemoteOutput) {
1313
+ const lines = gitRemoteOutput.trim().split("\n");
1314
+ const remotes = [];
1315
+ for (const line of lines) {
1316
+ const match = line.match(/^(\S+)\s+(\S+)\s+\((\w+)\)$/);
1317
+ if (match) {
1318
+ const [, name, url, type] = match;
1319
+ if (type === "fetch") {
1320
+ remotes.push({ name, url, type });
1321
+ }
1322
+ }
1323
+ }
1324
+ return remotes;
1325
+ }
1326
+ parseBranches(gitBranchOutput) {
1327
+ const lines = gitBranchOutput.trim().split("\n");
1328
+ const branchNames = /* @__PURE__ */ new Set();
1329
+ for (const line of lines) {
1330
+ let branchName = line.trim();
1331
+ if (branchName.startsWith("* ")) {
1332
+ branchName = branchName.substring(2).trim();
1333
+ }
1334
+ if (branchName.startsWith("remotes/origin/")) {
1335
+ branchName = branchName.substring("remotes/origin/".length);
1336
+ }
1337
+ if (branchName.startsWith("remotes/")) {
1338
+ const parts = branchName.split("/");
1339
+ if (parts.length > 2) {
1340
+ branchName = parts.slice(2).join("/");
1341
+ }
1342
+ }
1343
+ if (branchName.includes("HEAD ->")) {
1344
+ continue;
1345
+ }
1346
+ if (branchName) {
1347
+ branchNames.add(branchName);
1348
+ }
1349
+ }
1350
+ return Array.from(branchNames);
1351
+ }
1352
+ normalizeGitUrl(url) {
1353
+ const sshMatch = url.match(/^git@([^:]+):(.+)$/);
1354
+ if (sshMatch) {
1355
+ const [, host, path2] = sshMatch;
1356
+ const cleanPath = path2.replace(/\.git$/, "");
1357
+ return `${host}/${cleanPath}`;
1358
+ }
1359
+ const httpsMatch = url.match(/^https?:\/\/([^/]+)\/(.+)$/);
1360
+ if (httpsMatch) {
1361
+ const [, host, path2] = httpsMatch;
1362
+ const cleanPath = path2.replace(/\.git$/, "");
1363
+ return `${host}/${cleanPath}`;
1364
+ }
1365
+ return url;
1366
+ }
1367
+ };
1368
+
1369
+ // apps/cli/src/application/useCases/GetGitRemoteUrlUseCase.ts
1370
+ var GetGitRemoteUrlUseCase = class {
1371
+ constructor(gitRemoteUrlService = new GitService()) {
1372
+ this.gitRemoteUrlService = gitRemoteUrlService;
1373
+ }
1374
+ async execute(command2) {
1375
+ const { path: repoPath, origin: origin10 } = command2;
1376
+ return this.gitRemoteUrlService.getGitRemoteUrl(repoPath, origin10);
1377
+ }
1378
+ };
1379
+
1380
+ // apps/cli/src/application/services/ListFiles.ts
1381
+ var fs = __toESM(require("fs/promises"));
1382
+ var path = __toESM(require("path"));
1383
+ var ListFiles = class {
1384
+ async listFilesInDirectory(directoryPath, extensions, excludes = [], skipHidden = true) {
1385
+ const results = [];
1386
+ const normalizedExtensions = extensions.map(
1387
+ (ext) => ext.startsWith(".") ? ext : `.${ext}`
1388
+ );
1389
+ const includeAllExtensions = normalizedExtensions.length === 0;
1390
+ await this.findFilesRecursively(
1391
+ directoryPath,
1392
+ normalizedExtensions,
1393
+ excludes,
1394
+ results,
1395
+ includeAllExtensions,
1396
+ skipHidden
1397
+ );
1398
+ return results;
1399
+ }
1400
+ async findFilesRecursively(directoryPath, extensions, excludes, results, includeAllExtensions, skipHidden) {
1401
+ try {
1402
+ const entries = await fs.readdir(directoryPath, { withFileTypes: true });
1403
+ for (const entry of entries) {
1404
+ const fullPath = path.join(directoryPath, entry.name);
1405
+ if (this.shouldExcludePath(fullPath, excludes)) {
1406
+ continue;
1407
+ }
1408
+ if (skipHidden && entry.name.startsWith(".")) {
1409
+ continue;
1410
+ }
1411
+ if (entry.isDirectory()) {
1412
+ await this.findFilesRecursively(
1413
+ fullPath,
1414
+ extensions,
1415
+ excludes,
1416
+ results,
1417
+ includeAllExtensions,
1418
+ skipHidden
1419
+ );
1420
+ } else if (entry.isFile()) {
1421
+ const fileExtension = path.extname(entry.name);
1422
+ if (includeAllExtensions || extensions.includes(fileExtension)) {
1423
+ results.push({
1424
+ path: fullPath
1425
+ });
1426
+ }
1427
+ }
1428
+ }
1429
+ } catch (error) {
1430
+ console.error(`Error reading directory ${directoryPath}:`, error);
1431
+ }
1432
+ }
1433
+ shouldExcludePath(filePath, excludes) {
1434
+ if (excludes.length === 0) {
1435
+ return false;
1436
+ }
1437
+ const normalizedPath = path.normalize(filePath).replace(/\\/g, "/");
1438
+ for (const exclude of excludes) {
1439
+ if (this.matchesGlobPattern(normalizedPath, exclude)) {
1440
+ return true;
1441
+ }
1442
+ }
1443
+ return false;
1444
+ }
1445
+ matchesGlobPattern(filePath, pattern) {
1446
+ if (!pattern.includes("*") && !pattern.includes("/")) {
1447
+ const pathSegments = filePath.split("/");
1448
+ return pathSegments.some((segment) => segment === pattern);
1449
+ }
1450
+ let regexPattern = pattern.replace(/\*\*/g, "__DOUBLE_STAR__").replace(/\*/g, "[^/]*").replace(/__DOUBLE_STAR__/g, ".*").replace(/\//g, "\\/");
1451
+ if (!pattern.startsWith("**/")) {
1452
+ regexPattern = "(^|/)" + regexPattern;
1453
+ }
1454
+ if (!pattern.endsWith("/**")) {
1455
+ regexPattern = regexPattern + "($|/)";
1456
+ }
1457
+ const regex = new RegExp(regexPattern);
1458
+ return regex.test(filePath);
1459
+ }
1460
+ async readFileContent(filePath) {
1461
+ try {
1462
+ return await fs.readFile(filePath, "utf-8");
1463
+ } catch (error) {
1464
+ console.error(`Error reading file ${filePath}:`, error);
1465
+ throw error;
1466
+ }
1467
+ }
1468
+ };
1469
+
1470
+ // apps/cli/src/application/useCases/ListFilesInDirectoryUseCase.ts
1471
+ var ListFilesInDirectoryUseCase = class {
1472
+ constructor(listFiles = new ListFiles()) {
1473
+ this.listFiles = listFiles;
1474
+ }
1475
+ async execute(command2) {
1476
+ const { path: directoryPath, extensions, excludes = [] } = command2;
1477
+ const files = await this.listFiles.listFilesInDirectory(
1478
+ directoryPath,
1479
+ extensions,
1480
+ excludes
1481
+ );
1482
+ const filesWithContent = [];
1483
+ for (const file of files) {
1484
+ try {
1485
+ const content = await this.listFiles.readFileContent(file.path);
1486
+ filesWithContent.push({
1487
+ path: file.path,
1488
+ content
1489
+ });
1490
+ } catch (error) {
1491
+ console.error(`Error reading file ${file.path}:`, error);
1492
+ }
1493
+ }
1494
+ return filesWithContent;
1495
+ }
1496
+ };
1497
+
1498
+ // apps/cli/src/application/useCases/LintFilesInDirectoryUseCase.ts
1499
+ var import_minimatch = require("minimatch");
1500
+ var origin7 = "LintFilesInDirectoryUseCase";
1501
+ var LintFilesInDirectoryUseCase = class {
1502
+ constructor(services, repositories, logger = new PackmindLogger(origin7)) {
1503
+ this.services = services;
1504
+ this.repositories = repositories;
1505
+ this.logger = logger;
1506
+ }
1507
+ fileMatchesScope(filePath, scopePatterns) {
1508
+ if (!scopePatterns || scopePatterns.length === 0) {
1509
+ return true;
1510
+ }
1511
+ return scopePatterns.some((pattern) => (0, import_minimatch.minimatch)(filePath, pattern));
1512
+ }
1513
+ fileMatchesTargetAndScope(filePath, targetPath, scopePatterns) {
1514
+ if (!scopePatterns || scopePatterns.length === 0) {
1515
+ const effectivePattern = this.buildEffectivePattern(targetPath, null);
1516
+ const matches2 = (0, import_minimatch.minimatch)(filePath, effectivePattern, {
1517
+ matchBase: false
1518
+ });
1519
+ this.logger.debug(
1520
+ `File matching check: file="${filePath}", target="${targetPath}", scope=null, pattern="${effectivePattern}", matches=${matches2}`
1521
+ );
1522
+ return matches2;
1523
+ }
1524
+ const matches = scopePatterns.some((scopePattern) => {
1525
+ const effectivePattern = this.buildEffectivePattern(
1526
+ targetPath,
1527
+ scopePattern
1528
+ );
1529
+ const patternMatches = (0, import_minimatch.minimatch)(filePath, effectivePattern, {
1530
+ matchBase: false
1531
+ });
1532
+ this.logger.debug(
1533
+ `File matching check: file="${filePath}", target="${targetPath}", scope="${scopePattern}", pattern="${effectivePattern}", matches=${patternMatches}`
1534
+ );
1535
+ return patternMatches;
1536
+ });
1537
+ return matches;
1538
+ }
1539
+ buildEffectivePattern(targetPath, scope) {
1540
+ const normalizedTarget = targetPath === "/" ? "/" : targetPath.replace(/\/$/, "");
1541
+ if (!scope) {
1542
+ return normalizedTarget === "/" ? "/**" : normalizedTarget + "/**";
1543
+ }
1544
+ if (scope.startsWith(normalizedTarget + "/") || scope === normalizedTarget) {
1545
+ return scope.endsWith("/") ? scope + "**" : scope;
1546
+ }
1547
+ const cleanScope = scope.startsWith("/") ? scope.substring(1) : scope;
1548
+ let pattern;
1549
+ if (normalizedTarget === "/") {
1550
+ pattern = "/" + cleanScope;
1551
+ } else {
1552
+ pattern = normalizedTarget + "/" + cleanScope;
1553
+ }
1554
+ if (pattern.endsWith("/")) {
1555
+ pattern = pattern + "**";
1556
+ }
1557
+ return pattern;
1558
+ }
1559
+ async execute(command2) {
1560
+ const { path: path2, draftMode, standardSlug, ruleId, language } = command2;
1561
+ this.logger.debug(
1562
+ `Starting linting: path="${path2}", draftMode=${!!draftMode}, standardSlug="${standardSlug || "N/A"}", ruleId="${ruleId || "N/A"}", language="${language || "N/A"}"`
1563
+ );
1564
+ const gitRepoRoot = await this.services.gitRemoteUrlService.getGitRepositoryRoot(path2);
1565
+ const files = await this.services.listFiles.listFilesInDirectory(
1566
+ gitRepoRoot,
1567
+ [],
1568
+ ["node_modules", "dist", ".min.", ".map.", ".git"]
1569
+ );
1570
+ const { gitRemoteUrl } = await this.services.gitRemoteUrlService.getGitRemoteUrl(gitRepoRoot);
1571
+ const { branches } = await this.services.gitRemoteUrlService.getCurrentBranches(gitRepoRoot);
1572
+ this.logger.debug(
1573
+ `Git repository: url="${gitRemoteUrl}", branches=${JSON.stringify(branches)}, filesCount=${files.length}`
1574
+ );
1575
+ let detectionPrograms;
1576
+ let isDraftMode = false;
1577
+ if (draftMode && standardSlug && ruleId) {
1578
+ isDraftMode = true;
1579
+ const draftProgramsResult = await this.repositories.packmindGateway.getDraftDetectionProgramsForRule(
1580
+ {
1581
+ standardSlug,
1582
+ ruleId,
1583
+ language
1584
+ }
1585
+ );
1586
+ detectionPrograms = {
1587
+ targets: [
1588
+ {
1589
+ name: "Draft Target",
1590
+ path: "/",
1591
+ standards: [
1592
+ {
1593
+ name: standardSlug,
1594
+ slug: standardSlug,
1595
+ scope: draftProgramsResult.scope ? [draftProgramsResult.scope] : [],
1596
+ rules: [
1597
+ {
1598
+ content: draftProgramsResult.ruleContent || "Draft Rule",
1599
+ activeDetectionPrograms: draftProgramsResult.programs.map(
1600
+ (program) => ({
1601
+ language: program.language,
1602
+ detectionProgram: {
1603
+ mode: program.mode,
1604
+ code: program.code,
1605
+ sourceCodeState: program.sourceCodeState
1606
+ }
1607
+ })
1608
+ )
1609
+ }
1610
+ ]
1611
+ }
1612
+ ]
1613
+ }
1614
+ ]
1615
+ };
1616
+ } else if (!draftMode && standardSlug && ruleId) {
1617
+ const activeProgramsResult = await this.repositories.packmindGateway.getActiveDetectionProgramsForRule(
1618
+ {
1619
+ standardSlug,
1620
+ ruleId,
1621
+ language
1622
+ }
1623
+ );
1624
+ detectionPrograms = {
1625
+ targets: [
1626
+ {
1627
+ name: "Active Target",
1628
+ path: "/",
1629
+ standards: [
1630
+ {
1631
+ name: standardSlug,
1632
+ slug: standardSlug,
1633
+ scope: activeProgramsResult.scope ? [activeProgramsResult.scope] : [],
1634
+ rules: [
1635
+ {
1636
+ content: activeProgramsResult.ruleContent || "Active Rule",
1637
+ activeDetectionPrograms: activeProgramsResult.programs.map(
1638
+ (program) => ({
1639
+ language: program.language,
1640
+ detectionProgram: {
1641
+ mode: program.mode,
1642
+ code: program.code,
1643
+ sourceCodeState: program.sourceCodeState
1644
+ }
1645
+ })
1646
+ )
1647
+ }
1648
+ ]
1649
+ }
1650
+ ]
1651
+ }
1652
+ ]
1653
+ };
1654
+ } else {
1655
+ detectionPrograms = await this.repositories.packmindGateway.listExecutionPrograms({
1656
+ gitRemoteUrl,
1657
+ branches
1658
+ });
1659
+ }
1660
+ this.logger.debug(
1661
+ `Retrieved detection programs: targetsCount=${detectionPrograms.targets.length}`
1662
+ );
1663
+ const violations = [];
1664
+ for (const file of files) {
1665
+ const fileViolations = [];
1666
+ const relativeFilePath = file.path.startsWith(gitRepoRoot) ? file.path.substring(gitRepoRoot.length) : file.path;
1667
+ const normalizedFilePath = relativeFilePath.startsWith("/") ? relativeFilePath : "/" + relativeFilePath;
1668
+ this.logger.debug(
1669
+ `Processing file: absolute="${file.path}", relative="${normalizedFilePath}"`
1670
+ );
1671
+ const fileExtension = this.extractExtensionFromFile(file.path);
1672
+ const fileLanguage = this.resolveProgrammingLanguage(fileExtension);
1673
+ if (!fileLanguage) {
1674
+ continue;
1675
+ }
1676
+ const programsByLanguage = /* @__PURE__ */ new Map();
1677
+ for (const target of detectionPrograms.targets) {
1678
+ this.logger.debug(
1679
+ `Processing target: name="${target.name}", path="${target.path}", standardsCount=${target.standards.length}`
1680
+ );
1681
+ for (const standard of target.standards) {
1682
+ this.logger.debug(
1683
+ `Checking standard: name="${standard.name}", scope=${JSON.stringify(standard.scope)}, rulesCount=${standard.rules.length}`
1684
+ );
1685
+ if (!this.fileMatchesTargetAndScope(
1686
+ normalizedFilePath,
1687
+ target.path,
1688
+ standard.scope
1689
+ )) {
1690
+ this.logger.debug(
1691
+ `File "${normalizedFilePath}" does not match target/scope - skipping standard "${standard.name}"`
1692
+ );
1693
+ continue;
1694
+ }
1695
+ if (!isDraftMode) {
1696
+ this.logger.debug(
1697
+ `File "${normalizedFilePath}" matches target/scope - processing standard "${standard.name}"`
1698
+ );
1699
+ }
1700
+ for (const rule of standard.rules) {
1701
+ for (const activeProgram of rule.activeDetectionPrograms) {
1702
+ try {
1703
+ const programLanguage = this.resolveProgrammingLanguage(
1704
+ activeProgram.language
1705
+ );
1706
+ if (!programLanguage) {
1707
+ console.error(
1708
+ `Unsupported language "${activeProgram.language}" for file ${file.path}`
1709
+ );
1710
+ continue;
1711
+ }
1712
+ if (programLanguage !== fileLanguage) {
1713
+ continue;
1714
+ }
1715
+ const programsForLanguage = programsByLanguage.get(programLanguage) ?? [];
1716
+ programsForLanguage.push({
1717
+ code: activeProgram.detectionProgram.code,
1718
+ ruleContent: rule.content,
1719
+ standardSlug: standard.slug,
1720
+ sourceCodeState: activeProgram.detectionProgram.sourceCodeState,
1721
+ language: fileLanguage
1722
+ });
1723
+ programsByLanguage.set(programLanguage, programsForLanguage);
1724
+ } catch (error) {
1725
+ console.error(
1726
+ `Error preparing program for file ${file.path}: ${error}`
1727
+ );
1728
+ }
1729
+ }
1730
+ }
1731
+ }
1732
+ }
1733
+ if (programsByLanguage.size > 0) {
1734
+ try {
1735
+ const fileContent = await this.services.listFiles.readFileContent(
1736
+ file.path
1737
+ );
1738
+ for (const [language2, programs] of programsByLanguage.entries()) {
1739
+ try {
1740
+ const result = await this.executeProgramsForFile({
1741
+ filePath: file.path,
1742
+ fileContent,
1743
+ language: language2,
1744
+ programs
1745
+ });
1746
+ fileViolations.push(...result);
1747
+ } catch (error) {
1748
+ console.error(
1749
+ `Error executing programs for file ${file.path} (${language2}): ${error}`
1750
+ );
1751
+ }
1752
+ }
1753
+ } catch (error) {
1754
+ console.error(
1755
+ `Error reading file content for ${file.path}: ${error}`
1756
+ );
1757
+ }
1758
+ }
1759
+ if (fileViolations.length > 0) {
1760
+ violations.push({
1761
+ file: file.path,
1762
+ violations: fileViolations
1763
+ });
1764
+ }
1765
+ }
1766
+ const totalViolations = violations.reduce(
1767
+ (sum, violation) => sum + violation.violations.length,
1768
+ 0
1769
+ );
1770
+ const standardsChecked = Array.from(
1771
+ new Set(
1772
+ detectionPrograms.targets.flatMap(
1773
+ (target) => target.standards.map((standard) => standard.slug)
1774
+ )
1775
+ )
1776
+ );
1777
+ return {
1778
+ gitRemoteUrl,
1779
+ violations,
1780
+ summary: {
1781
+ totalFiles: files.length,
1782
+ violatedFiles: violations.length,
1783
+ totalViolations,
1784
+ standardsChecked
1785
+ }
1786
+ };
1787
+ }
1788
+ resolveProgrammingLanguage(language) {
1789
+ try {
1790
+ return stringToProgrammingLanguage(language);
1791
+ } catch (error) {
1792
+ return null;
1793
+ }
1794
+ }
1795
+ async executeProgramsForFile(command2) {
1796
+ const result = await this.services.linterExecutionUseCase.execute(command2);
1797
+ return result.violations;
1798
+ }
1799
+ extractExtensionFromFile(filePath) {
1800
+ const lastDotIndex = filePath.lastIndexOf(".");
1801
+ if (lastDotIndex === -1 || lastDotIndex === filePath.length - 1) {
1802
+ return "";
1803
+ }
1804
+ return filePath.substring(lastDotIndex + 1);
1805
+ }
1806
+ };
1807
+
1808
+ // apps/cli/src/infra/repositories/PackmindGateway.ts
1809
+ function decodeApiKey(apiKey) {
1810
+ if (!apiKey) {
1811
+ return {
1812
+ payload: { host: "", jwt: "" },
1813
+ isValid: false,
1814
+ error: "Please set the PACKMIND_API_KEY_V3 environment variable"
1815
+ };
1816
+ }
1817
+ try {
1818
+ const trimmedKey = apiKey.trim();
1819
+ const jsonString = Buffer.from(trimmedKey, "base64").toString("utf-8");
1820
+ const payload = JSON.parse(jsonString);
1821
+ if (!payload.host || typeof payload.host !== "string") {
1822
+ return {
1823
+ payload,
1824
+ isValid: false,
1825
+ error: "Invalid API key: missing or invalid host field"
1826
+ };
1827
+ }
1828
+ if (!payload.jwt || typeof payload.jwt !== "string") {
1829
+ return {
1830
+ payload,
1831
+ isValid: false,
1832
+ error: "Invalid API key: missing or invalid jwt field"
1833
+ };
1834
+ }
1835
+ return {
1836
+ payload,
1837
+ isValid: true
1838
+ };
1839
+ } catch (error) {
1840
+ return {
1841
+ payload: { host: "", jwt: "" },
1842
+ isValid: false,
1843
+ error: `Failed to decode API key: ${error}`
1844
+ };
1845
+ }
1846
+ }
1847
+ var PackmindGateway = class {
1848
+ constructor(apiKey) {
1849
+ this.apiKey = apiKey;
1850
+ this.listExecutionPrograms = async (params) => {
1851
+ const decodedApiKey = decodeApiKey(this.apiKey);
1852
+ if (!decodedApiKey.isValid) {
1853
+ throw new Error(`Invalid API key: ${decodedApiKey.error}`);
1854
+ }
1855
+ const { host } = decodedApiKey.payload;
1856
+ const url = `${host}/api/v0/list-detection-program`;
1857
+ const payload = {
1858
+ gitRemoteUrl: params.gitRemoteUrl,
1859
+ branches: params.branches
1860
+ };
1861
+ try {
1862
+ const response = await fetch(url, {
1863
+ method: "POST",
1864
+ headers: {
1865
+ "Content-Type": "application/json",
1866
+ Authorization: `Bearer ${this.apiKey}`
1867
+ },
1868
+ body: JSON.stringify(payload)
1869
+ });
1870
+ if (!response.ok) {
1871
+ let errorMsg = `API request failed: ${response.status} ${response.statusText}`;
1872
+ try {
1873
+ const errorBody = await response.json();
1874
+ if (errorBody && errorBody.message) {
1875
+ errorMsg = `${errorBody.message}`;
1876
+ }
1877
+ } catch {
1878
+ }
1879
+ throw new Error(errorMsg);
1880
+ }
1881
+ const result = await response.json();
1882
+ return result;
1883
+ } catch (error) {
1884
+ const err = error;
1885
+ const code = err?.code || err?.cause?.code;
1886
+ if (code === "ECONNREFUSED" || code === "ENOTFOUND" || err?.name === "FetchError" || typeof err?.message === "string" && (err.message.includes("Failed to fetch") || err.message.includes("network") || err.message.includes("NetworkError"))) {
1887
+ throw new Error(
1888
+ `Packmind server is not accessible at ${host}. Please check your network connection or the server URL.`
1889
+ );
1890
+ }
1891
+ throw new Error(
1892
+ `Failed to fetch detection programs: Error: ${err?.message || JSON.stringify(error)}`
1893
+ );
1894
+ }
1895
+ };
1896
+ this.getDraftDetectionProgramsForRule = async (params) => {
1897
+ const decodedApiKey = decodeApiKey(this.apiKey);
1898
+ if (!decodedApiKey.isValid) {
1899
+ throw new Error(`Invalid API key: ${decodedApiKey.error}`);
1900
+ }
1901
+ const { host } = decodedApiKey.payload;
1902
+ const url = `${host}/api/v0/list-draft-detection-program`;
1903
+ const payload = {
1904
+ standardSlug: params.standardSlug,
1905
+ ruleId: params.ruleId
1906
+ };
1907
+ if (params.language) {
1908
+ payload.language = params.language;
1909
+ }
1910
+ try {
1911
+ const response = await fetch(url, {
1912
+ method: "POST",
1913
+ headers: {
1914
+ "Content-Type": "application/json",
1915
+ Authorization: `Bearer ${this.apiKey}`
1916
+ },
1917
+ body: JSON.stringify(payload)
1918
+ });
1919
+ if (!response.ok) {
1920
+ let errorMsg = `API request failed: ${response.status} ${response.statusText}`;
1921
+ try {
1922
+ const errorBody = await response.json();
1923
+ if (errorBody && errorBody.message) {
1924
+ errorMsg = `${errorBody.message}`;
1925
+ }
1926
+ } catch {
1927
+ }
1928
+ throw new Error(errorMsg);
1929
+ }
1930
+ const result = await response.json();
1931
+ if (result.programs.length === 0) {
1932
+ const languageMsg = params.language ? ` for language ${params.language}` : "";
1933
+ throw new Error(
1934
+ `No draft detection programs found for rule ${params.ruleId} in standard ${params.standardSlug}${languageMsg}`
1935
+ );
1936
+ }
1937
+ const transformedResult = {
1938
+ programs: result.programs.map((program) => ({
1939
+ language: program.language,
1940
+ code: program.code,
1941
+ mode: program.mode,
1942
+ sourceCodeState: program.sourceCodeState
1943
+ })),
1944
+ ruleContent: result.ruleContent,
1945
+ standardSlug: params.standardSlug,
1946
+ scope: result.scope
1947
+ };
1948
+ return transformedResult;
1949
+ } catch (error) {
1950
+ const err = error;
1951
+ const code = err?.code || err?.cause?.code;
1952
+ if (code === "ECONNREFUSED" || code === "ENOTFOUND" || err?.name === "FetchError" || typeof err?.message === "string" && (err.message.includes("Failed to fetch") || err.message.includes("network") || err.message.includes("NetworkError"))) {
1953
+ throw new Error(
1954
+ `Packmind server is not accessible at ${host}. Please check your network connection or the server URL.`
1955
+ );
1956
+ }
1957
+ throw new Error(
1958
+ `Failed to fetch draft detection programs: Error: ${err?.message || JSON.stringify(error)}`
1959
+ );
1960
+ }
1961
+ };
1962
+ this.getActiveDetectionProgramsForRule = async (params) => {
1963
+ const decodedApiKey = decodeApiKey(this.apiKey);
1964
+ if (!decodedApiKey.isValid) {
1965
+ throw new Error(`Invalid API key: ${decodedApiKey.error}`);
1966
+ }
1967
+ const { host } = decodedApiKey.payload;
1968
+ const url = `${host}/api/v0/list-active-detection-program`;
1969
+ const payload = {
1970
+ standardSlug: params.standardSlug,
1971
+ ruleId: params.ruleId
1972
+ };
1973
+ if (params.language) {
1974
+ payload.language = params.language;
1975
+ }
1976
+ try {
1977
+ const response = await fetch(url, {
1978
+ method: "POST",
1979
+ headers: {
1980
+ "Content-Type": "application/json",
1981
+ Authorization: `Bearer ${this.apiKey}`
1982
+ },
1983
+ body: JSON.stringify(payload)
1984
+ });
1985
+ if (!response.ok) {
1986
+ let errorMsg = `API request failed: ${response.status} ${response.statusText}`;
1987
+ try {
1988
+ const errorBody = await response.json();
1989
+ if (errorBody && errorBody.message) {
1990
+ errorMsg = `${errorBody.message}`;
1991
+ }
1992
+ } catch {
1993
+ }
1994
+ throw new Error(errorMsg);
1995
+ }
1996
+ const result = await response.json();
1997
+ if (result.programs.length === 0) {
1998
+ const languageMsg = params.language ? ` for language ${params.language}` : "";
1999
+ throw new Error(
2000
+ `No active detection programs found for rule ${params.ruleId} in standard ${params.standardSlug}${languageMsg}`
2001
+ );
2002
+ }
2003
+ const transformedResult = {
2004
+ programs: result.programs.map((program) => ({
2005
+ language: program.language,
2006
+ code: program.code,
2007
+ mode: program.mode,
2008
+ sourceCodeState: program.sourceCodeState
2009
+ })),
2010
+ ruleContent: result.ruleContent,
2011
+ standardSlug: params.standardSlug,
2012
+ scope: result.scope
2013
+ };
2014
+ return transformedResult;
2015
+ } catch (error) {
2016
+ const err = error;
2017
+ const code = err?.code || err?.cause?.code;
2018
+ if (code === "ECONNREFUSED" || code === "ENOTFOUND" || err?.name === "FetchError" || typeof err?.message === "string" && (err.message.includes("Failed to fetch") || err.message.includes("network") || err.message.includes("NetworkError"))) {
2019
+ throw new Error(
2020
+ `Packmind server is not accessible at ${host}. Please check your network connection or the server URL.`
2021
+ );
2022
+ }
2023
+ throw new Error(
2024
+ `Failed to fetch active detection programs: Error: ${err?.message || JSON.stringify(error)}`
2025
+ );
2026
+ }
2027
+ };
2028
+ }
2029
+ };
2030
+
2031
+ // packages/linter-ast/src/core/ParserError.ts
2032
+ var ParserNotAvailableError = class extends Error {
2033
+ constructor(language, cause) {
2034
+ super(`Parser for ${language} not available`);
2035
+ this.name = "ParserNotAvailableError";
2036
+ this.originalError = cause;
2037
+ }
2038
+ };
2039
+ var ParserInitializationError = class extends Error {
2040
+ constructor(language, message, cause) {
2041
+ super(`Failed to initialize parser for ${language}: ${message}`);
2042
+ this.name = "ParserInitializationError";
2043
+ this.originalError = cause;
2044
+ }
2045
+ };
2046
+
2047
+ // packages/linter-ast/src/core/BaseParser.ts
2048
+ var import_path = require("path");
2049
+ var import_fs = require("fs");
2050
+ var BaseParser = class _BaseParser {
2051
+ constructor() {
2052
+ this.initialized = false;
2053
+ }
2054
+ /**
2055
+ * Helper to locate tree-sitter WASM files for CLI executable
2056
+ */
2057
+ static getTreeSitterWasmPaths() {
2058
+ const execDir = process.argv[0] ? (0, import_path.dirname)(process.argv[0]) : process.cwd();
2059
+ const scriptDir = require.main?.filename ? (0, import_path.dirname)(require.main.filename) : process.cwd();
2060
+ return [
2061
+ // Next to the main script (for npm packages like @packmind/scan)
2062
+ scriptDir,
2063
+ (0, import_path.join)(scriptDir, "tree-sitter"),
2064
+ // Next to the Bun executable in tree-sitter/ subdirectory
2065
+ (0, import_path.join)(execDir, "tree-sitter"),
2066
+ // Fallback paths
2067
+ (0, import_path.join)(process.cwd(), "tree-sitter"),
2068
+ (0, import_path.join)(process.cwd(), "dist/apps/cli-executables/tree-sitter"),
2069
+ (0, import_path.resolve)(__dirname, "tree-sitter"),
2070
+ (0, import_path.resolve)(__dirname, "../../res"),
2071
+ (0, import_path.resolve)(__dirname, "../../../packages/linter-ast/res")
2072
+ ];
2073
+ }
2074
+ /**
2075
+ * Get the locateFile function for TreeSitter Parser initialization
2076
+ */
2077
+ static getTreeSitterLocateFile() {
2078
+ const wasmDirs = _BaseParser.getTreeSitterWasmPaths();
2079
+ return (fileName) => {
2080
+ for (const dir of wasmDirs) {
2081
+ const fullPath = (0, import_path.join)(dir, fileName);
2082
+ if ((0, import_fs.existsSync)(fullPath)) {
2083
+ return fullPath;
2084
+ }
2085
+ }
2086
+ return (0, import_path.join)(process.cwd(), fileName);
2087
+ };
2088
+ }
2089
+ /**
2090
+ * Get all possible paths for a language-specific WASM file
2091
+ */
2092
+ static getLanguageWasmPaths(languageName) {
2093
+ const wasmDirs = _BaseParser.getTreeSitterWasmPaths();
2094
+ const wasmFileName = `tree-sitter-${languageName}.wasm`;
2095
+ return wasmDirs.map((dir) => (0, import_path.join)(dir, wasmFileName)).concat([
2096
+ // Additional fallback paths
2097
+ (0, import_path.resolve)(__dirname, `tree-sitter/${wasmFileName}`),
2098
+ (0, import_path.resolve)(__dirname, wasmFileName),
2099
+ (0, import_path.resolve)(__dirname, `res/${wasmFileName}`),
2100
+ (0, import_path.resolve)(__dirname, `../../res/${wasmFileName}`),
2101
+ (0, import_path.resolve)(__dirname, `../res/${wasmFileName}`),
2102
+ (0, import_path.resolve)(__dirname, `../../../packages/linter-ast/res/${wasmFileName}`),
2103
+ (0, import_path.join)(process.cwd(), `packages/linter-ast/res/${wasmFileName}`)
2104
+ ]);
2105
+ }
2106
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2107
+ nodeToJson(node) {
2108
+ return {
2109
+ type: node.type,
2110
+ text: node.type === "program" ? "<skipped>" : node.text,
2111
+ line: node.startPosition.row,
2112
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2113
+ children: node.children.map((child) => this.nodeToJson(child))
2114
+ };
2115
+ }
2116
+ };
2117
+
2118
+ // packages/linter-ast/src/parsers/TypeScriptParser.ts
2119
+ var TreeSitter = __toESM(require("web-tree-sitter"));
2120
+ var import_fs2 = require("fs");
2121
+ var TypeScriptParser = class extends BaseParser {
2122
+ async initialize() {
2123
+ try {
2124
+ let lang = null;
2125
+ await TreeSitter.Parser.init({
2126
+ locateFile: BaseParser.getTreeSitterLocateFile()
2127
+ });
2128
+ const wasmPaths = BaseParser.getLanguageWasmPaths("typescript");
2129
+ for (const wasmPath of wasmPaths) {
2130
+ if ((0, import_fs2.existsSync)(wasmPath)) {
2131
+ try {
2132
+ lang = await TreeSitter.Language.load(wasmPath);
2133
+ break;
2134
+ } catch {
2135
+ continue;
2136
+ }
2137
+ }
2138
+ }
2139
+ if (!lang) {
2140
+ throw new Error(
2141
+ `Failed to load tree-sitter-typescript WASM file. Tried paths: ${wasmPaths.join(", ")}`
2142
+ );
2143
+ }
2144
+ this.parser = new TreeSitter.Parser();
2145
+ this.parser.setLanguage(lang);
2146
+ this.initialized = true;
2147
+ } catch (error) {
2148
+ throw new ParserInitializationError(
2149
+ "typescript",
2150
+ "Failed to load TypeScript WASM parser module",
2151
+ error
2152
+ );
2153
+ }
2154
+ }
2155
+ async parse(sourceCode) {
2156
+ if (!this.initialized) {
2157
+ await this.initialize();
2158
+ }
2159
+ if (!this.parser) {
2160
+ throw new ParserInitializationError(
2161
+ "typescript",
2162
+ "Parser not initialized"
2163
+ );
2164
+ }
2165
+ const tree = this.parser.parse(sourceCode);
2166
+ if (!tree) {
2167
+ throw new ParserInitializationError(
2168
+ "typescript",
2169
+ "Failed to parse source code"
2170
+ );
2171
+ }
2172
+ return this.nodeToJson(tree.rootNode);
2173
+ }
2174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2175
+ async parseRaw(sourceCode) {
2176
+ if (!this.initialized) {
2177
+ await this.initialize();
2178
+ }
2179
+ if (!this.parser) {
2180
+ throw new ParserInitializationError(
2181
+ "typescript",
2182
+ "Parser not initialized"
2183
+ );
2184
+ }
2185
+ const tree = this.parser.parse(sourceCode);
2186
+ if (!tree) {
2187
+ throw new ParserInitializationError(
2188
+ "typescript",
2189
+ "Failed to parse source code"
2190
+ );
2191
+ }
2192
+ return tree;
2193
+ }
2194
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2195
+ nodeToJson(node) {
2196
+ return {
2197
+ type: node.type,
2198
+ text: node.type === "program" ? "<skipped>" : node.text,
2199
+ line: node.startPosition.row + 1,
2200
+ children: Array.from({ length: node.childCount }, (_, i) => {
2201
+ const child = node.child(i);
2202
+ return child ? this.nodeToJson(child) : null;
2203
+ }).filter((c) => c !== null)
2204
+ };
2205
+ }
2206
+ getLanguage() {
2207
+ return "typescript";
2208
+ }
2209
+ };
2210
+
2211
+ // packages/linter-ast/src/parsers/JavaScriptParser.ts
2212
+ var TreeSitter2 = __toESM(require("web-tree-sitter"));
2213
+ var import_fs3 = require("fs");
2214
+ var JavaScriptParser = class extends BaseParser {
2215
+ async initialize() {
2216
+ try {
2217
+ let lang = null;
2218
+ await TreeSitter2.Parser.init({
2219
+ locateFile: BaseParser.getTreeSitterLocateFile()
2220
+ });
2221
+ const wasmPaths = BaseParser.getLanguageWasmPaths("javascript");
2222
+ for (const wasmPath of wasmPaths) {
2223
+ if ((0, import_fs3.existsSync)(wasmPath)) {
2224
+ try {
2225
+ lang = await TreeSitter2.Language.load(wasmPath);
2226
+ break;
2227
+ } catch {
2228
+ continue;
2229
+ }
2230
+ }
2231
+ }
2232
+ if (!lang) {
2233
+ throw new Error(
2234
+ `Failed to load tree-sitter-javascript WASM file. Tried paths: ${wasmPaths.join(", ")}`
2235
+ );
2236
+ }
2237
+ this.parser = new TreeSitter2.Parser();
2238
+ this.parser.setLanguage(lang);
2239
+ this.initialized = true;
2240
+ } catch (error) {
2241
+ throw new ParserInitializationError(
2242
+ "javascript",
2243
+ "Failed to load JavaScript WASM parser module",
2244
+ error
2245
+ );
2246
+ }
2247
+ }
2248
+ async parse(sourceCode) {
2249
+ if (!this.initialized) {
2250
+ await this.initialize();
2251
+ }
2252
+ if (!this.parser) {
2253
+ throw new ParserInitializationError(
2254
+ "javascript",
2255
+ "Parser not initialized"
2256
+ );
2257
+ }
2258
+ const tree = this.parser.parse(sourceCode);
2259
+ if (!tree) {
2260
+ throw new ParserInitializationError(
2261
+ "javascript",
2262
+ "Failed to parse source code"
2263
+ );
2264
+ }
2265
+ return this.nodeToJson(tree.rootNode);
2266
+ }
2267
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2268
+ async parseRaw(sourceCode) {
2269
+ if (!this.initialized) {
2270
+ await this.initialize();
2271
+ }
2272
+ if (!this.parser) {
2273
+ throw new ParserInitializationError(
2274
+ "javascript",
2275
+ "Parser not initialized"
2276
+ );
2277
+ }
2278
+ const tree = this.parser.parse(sourceCode);
2279
+ if (!tree) {
2280
+ throw new ParserInitializationError(
2281
+ "javascript",
2282
+ "Failed to parse source code"
2283
+ );
2284
+ }
2285
+ return tree;
2286
+ }
2287
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2288
+ nodeToJson(node) {
2289
+ return {
2290
+ type: node.type,
2291
+ text: node.type === "program" ? "<skipped>" : node.text,
2292
+ line: node.startPosition.row + 1,
2293
+ children: Array.from({ length: node.childCount }, (_, i) => {
2294
+ const child = node.child(i);
2295
+ return child ? this.nodeToJson(child) : null;
2296
+ }).filter((c) => c !== null)
2297
+ };
2298
+ }
2299
+ getLanguage() {
2300
+ return "javascript";
2301
+ }
2302
+ };
2303
+
2304
+ // packages/linter-ast/src/parsers/CPPParser.ts
2305
+ var TreeSitter3 = __toESM(require("web-tree-sitter"));
2306
+ var import_fs4 = require("fs");
2307
+ var CPPParser = class extends BaseParser {
2308
+ async initialize() {
2309
+ try {
2310
+ let lang = null;
2311
+ await TreeSitter3.Parser.init({
2312
+ locateFile: BaseParser.getTreeSitterLocateFile()
2313
+ });
2314
+ const wasmPaths = BaseParser.getLanguageWasmPaths("cpp");
2315
+ for (const wasmPath of wasmPaths) {
2316
+ if ((0, import_fs4.existsSync)(wasmPath)) {
2317
+ try {
2318
+ lang = await TreeSitter3.Language.load(wasmPath);
2319
+ break;
2320
+ } catch {
2321
+ continue;
2322
+ }
2323
+ }
2324
+ }
2325
+ if (!lang) {
2326
+ throw new Error(
2327
+ `Failed to load tree-sitter-cpp WASM file. Tried paths: ${wasmPaths.join(", ")}`
2328
+ );
2329
+ }
2330
+ this.parser = new TreeSitter3.Parser();
2331
+ this.parser.setLanguage(lang);
2332
+ this.initialized = true;
2333
+ } catch (error) {
2334
+ throw new ParserInitializationError(
2335
+ "cpp",
2336
+ "Failed to load C++ WASM parser module",
2337
+ error
2338
+ );
2339
+ }
2340
+ }
2341
+ async parse(sourceCode) {
2342
+ if (!this.initialized) {
2343
+ await this.initialize();
2344
+ }
2345
+ if (!this.parser) {
2346
+ throw new ParserInitializationError("cpp", "Parser not initialized");
2347
+ }
2348
+ const tree = this.parser.parse(sourceCode);
2349
+ if (!tree) {
2350
+ throw new ParserInitializationError("cpp", "Failed to parse source code");
2351
+ }
2352
+ return this.nodeToJson(tree.rootNode);
2353
+ }
2354
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2355
+ async parseRaw(sourceCode) {
2356
+ if (!this.initialized) {
2357
+ await this.initialize();
2358
+ }
2359
+ if (!this.parser) {
2360
+ throw new ParserInitializationError("cpp", "Parser not initialized");
2361
+ }
2362
+ const tree = this.parser.parse(sourceCode);
2363
+ if (!tree) {
2364
+ throw new ParserInitializationError("cpp", "Failed to parse source code");
2365
+ }
2366
+ return tree;
2367
+ }
2368
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2369
+ nodeToJson(node) {
2370
+ return {
2371
+ type: node.type,
2372
+ text: node.type === "program" || node.type === "binary_expression" || node.type === "translation_unit" ? "<skipped>" : node.text,
2373
+ line: node.startPosition.row + 1,
2374
+ children: Array.from({ length: node.childCount }, (_, i) => {
2375
+ const child = node.child(i);
2376
+ return child ? this.nodeToJson(child) : null;
2377
+ }).filter((c) => c !== null)
2378
+ };
2379
+ }
2380
+ getLanguage() {
2381
+ return "cpp";
2382
+ }
2383
+ };
2384
+
2385
+ // packages/linter-ast/src/parsers/GoParser.ts
2386
+ var TreeSitter4 = __toESM(require("web-tree-sitter"));
2387
+ var import_fs5 = require("fs");
2388
+ var GoParser = class extends BaseParser {
2389
+ async initialize() {
2390
+ try {
2391
+ let lang = null;
2392
+ await TreeSitter4.Parser.init({
2393
+ locateFile: BaseParser.getTreeSitterLocateFile()
2394
+ });
2395
+ const wasmPaths = BaseParser.getLanguageWasmPaths("go");
2396
+ for (const wasmPath of wasmPaths) {
2397
+ if ((0, import_fs5.existsSync)(wasmPath)) {
2398
+ try {
2399
+ lang = await TreeSitter4.Language.load(wasmPath);
2400
+ break;
2401
+ } catch {
2402
+ continue;
2403
+ }
2404
+ }
2405
+ }
2406
+ if (!lang) {
2407
+ throw new Error(
2408
+ `Failed to load tree-sitter-go WASM file. Tried paths: ${wasmPaths.join(", ")}`
2409
+ );
2410
+ }
2411
+ this.parser = new TreeSitter4.Parser();
2412
+ this.parser.setLanguage(lang);
2413
+ this.initialized = true;
2414
+ } catch (error) {
2415
+ throw new ParserInitializationError(
2416
+ "go",
2417
+ "Failed to load Go WASM parser module",
2418
+ error
2419
+ );
2420
+ }
2421
+ }
2422
+ async parse(sourceCode) {
2423
+ if (!this.initialized) {
2424
+ await this.initialize();
2425
+ }
2426
+ if (!this.parser) {
2427
+ throw new ParserInitializationError("go", "Parser not initialized");
2428
+ }
2429
+ const tree = this.parser.parse(sourceCode);
2430
+ if (!tree) {
2431
+ throw new ParserInitializationError("go", "Failed to parse source code");
2432
+ }
2433
+ return this.nodeToJson(tree.rootNode);
2434
+ }
2435
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2436
+ async parseRaw(sourceCode) {
2437
+ if (!this.initialized) {
2438
+ await this.initialize();
2439
+ }
2440
+ if (!this.parser) {
2441
+ throw new ParserInitializationError("go", "Parser not initialized");
2442
+ }
2443
+ const tree = this.parser.parse(sourceCode);
2444
+ if (!tree) {
2445
+ throw new ParserInitializationError("go", "Failed to parse source code");
2446
+ }
2447
+ return tree;
2448
+ }
2449
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2450
+ nodeToJson(node) {
2451
+ return {
2452
+ type: node.type,
2453
+ text: node.type === "program" ? "<skipped>" : node.text,
2454
+ line: node.startPosition.row + 1,
2455
+ children: Array.from({ length: node.childCount }, (_, i) => {
2456
+ const child = node.child(i);
2457
+ return child ? this.nodeToJson(child) : null;
2458
+ }).filter((c) => c !== null)
2459
+ };
2460
+ }
2461
+ getLanguage() {
2462
+ return "go";
2463
+ }
2464
+ };
2465
+
2466
+ // packages/linter-ast/src/parsers/KotlinParser.ts
2467
+ var TreeSitter5 = __toESM(require("web-tree-sitter"));
2468
+ var import_fs6 = require("fs");
2469
+ var KotlinParser = class extends BaseParser {
2470
+ async initialize() {
2471
+ try {
2472
+ let lang = null;
2473
+ await TreeSitter5.Parser.init({
2474
+ locateFile: BaseParser.getTreeSitterLocateFile()
2475
+ });
2476
+ const wasmPaths = BaseParser.getLanguageWasmPaths("kotlin");
2477
+ for (const wasmPath of wasmPaths) {
2478
+ if ((0, import_fs6.existsSync)(wasmPath)) {
2479
+ try {
2480
+ lang = await TreeSitter5.Language.load(wasmPath);
2481
+ break;
2482
+ } catch {
2483
+ continue;
2484
+ }
2485
+ }
2486
+ }
2487
+ if (!lang) {
2488
+ throw new Error(
2489
+ `Failed to load tree-sitter-kotlin WASM file. Tried paths: ${wasmPaths.join(", ")}`
2490
+ );
2491
+ }
2492
+ this.parser = new TreeSitter5.Parser();
2493
+ this.parser.setLanguage(lang);
2494
+ this.initialized = true;
2495
+ } catch (error) {
2496
+ throw new ParserInitializationError(
2497
+ "kotlin",
2498
+ "Failed to load Kotlin WASM parser module",
2499
+ error
2500
+ );
2501
+ }
2502
+ }
2503
+ async parse(sourceCode) {
2504
+ if (!this.initialized) {
2505
+ await this.initialize();
2506
+ }
2507
+ if (!this.parser) {
2508
+ throw new ParserInitializationError("kotlin", "Parser not initialized");
2509
+ }
2510
+ const tree = this.parser.parse(sourceCode);
2511
+ if (!tree) {
2512
+ throw new ParserInitializationError(
2513
+ "kotlin",
2514
+ "Failed to parse source code"
2515
+ );
2516
+ }
2517
+ return this.nodeToJson(tree.rootNode);
2518
+ }
2519
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2520
+ async parseRaw(sourceCode) {
2521
+ if (!this.initialized) {
2522
+ await this.initialize();
2523
+ }
2524
+ if (!this.parser) {
2525
+ throw new ParserInitializationError("kotlin", "Parser not initialized");
2526
+ }
2527
+ const tree = this.parser.parse(sourceCode);
2528
+ if (!tree) {
2529
+ throw new ParserInitializationError(
2530
+ "kotlin",
2531
+ "Failed to parse source code"
2532
+ );
2533
+ }
2534
+ return tree;
2535
+ }
2536
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2537
+ nodeToJson(node) {
2538
+ return {
2539
+ type: node.type,
2540
+ text: node.type === "program" ? "<skipped>" : node.text,
2541
+ line: node.startPosition.row + 1,
2542
+ children: Array.from({ length: node.childCount }, (_, i) => {
2543
+ const child = node.child(i);
2544
+ return child ? this.nodeToJson(child) : null;
2545
+ }).filter((c) => c !== null)
2546
+ };
2547
+ }
2548
+ getLanguage() {
2549
+ return "kotlin";
2550
+ }
2551
+ };
2552
+
2553
+ // packages/linter-ast/src/parsers/CSSParser.ts
2554
+ var TreeSitter6 = __toESM(require("web-tree-sitter"));
2555
+ var import_fs7 = require("fs");
2556
+ var CSSParser = class extends BaseParser {
2557
+ async initialize() {
2558
+ try {
2559
+ let lang = null;
2560
+ await TreeSitter6.Parser.init({
2561
+ locateFile: BaseParser.getTreeSitterLocateFile()
2562
+ });
2563
+ const wasmPaths = BaseParser.getLanguageWasmPaths("css");
2564
+ for (const wasmPath of wasmPaths) {
2565
+ if ((0, import_fs7.existsSync)(wasmPath)) {
2566
+ try {
2567
+ lang = await TreeSitter6.Language.load(wasmPath);
2568
+ break;
2569
+ } catch {
2570
+ continue;
2571
+ }
2572
+ }
2573
+ }
2574
+ if (!lang) {
2575
+ throw new Error(
2576
+ `Failed to load tree-sitter-css.wasm file. Tried paths: ${wasmPaths.join(", ")}`
2577
+ );
2578
+ }
2579
+ this.parser = new TreeSitter6.Parser();
2580
+ this.parser.setLanguage(lang);
2581
+ this.initialized = true;
2582
+ } catch (error) {
2583
+ throw new ParserInitializationError(
2584
+ "css",
2585
+ "Failed to load CSS WASM parser module",
2586
+ error
2587
+ );
2588
+ }
2589
+ }
2590
+ async parse(sourceCode) {
2591
+ if (!this.initialized) {
2592
+ await this.initialize();
2593
+ }
2594
+ if (!this.parser) {
2595
+ throw new ParserInitializationError("css", "Parser not initialized");
2596
+ }
2597
+ const tree = this.parser.parse(sourceCode);
2598
+ if (!tree) {
2599
+ throw new ParserInitializationError("css", "Failed to parse source code");
2600
+ }
2601
+ return this.nodeToJson(tree.rootNode);
2602
+ }
2603
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2604
+ async parseRaw(sourceCode) {
2605
+ if (!this.initialized) {
2606
+ await this.initialize();
2607
+ }
2608
+ if (!this.parser) {
2609
+ throw new ParserInitializationError("css", "Parser not initialized");
2610
+ }
2611
+ const tree = this.parser.parse(sourceCode);
2612
+ if (!tree) {
2613
+ throw new ParserInitializationError("css", "Failed to parse source code");
2614
+ }
2615
+ return tree;
2616
+ }
2617
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2618
+ nodeToJson(node) {
2619
+ return {
2620
+ type: node.type,
2621
+ text: node.type === "program" || node.type === "stylesheet" ? "<skipped>" : node.text,
2622
+ line: node.startPosition.row + 1,
2623
+ children: Array.from({ length: node.childCount }, (_, i) => {
2624
+ const child = node.child(i);
2625
+ return child ? this.nodeToJson(child) : null;
2626
+ }).filter((c) => c !== null)
2627
+ };
2628
+ }
2629
+ getLanguage() {
2630
+ return "css";
2631
+ }
2632
+ };
2633
+
2634
+ // packages/linter-ast/src/parsers/CSharpParser.ts
2635
+ var TreeSitter7 = __toESM(require("web-tree-sitter"));
2636
+ var import_fs8 = require("fs");
2637
+ var CSharpParser = class extends BaseParser {
2638
+ async initialize() {
2639
+ try {
2640
+ let lang = null;
2641
+ await TreeSitter7.Parser.init({
2642
+ locateFile: BaseParser.getTreeSitterLocateFile()
2643
+ });
2644
+ const wasmPaths = BaseParser.getLanguageWasmPaths("c_sharp");
2645
+ for (const wasmPath of wasmPaths) {
2646
+ if ((0, import_fs8.existsSync)(wasmPath)) {
2647
+ try {
2648
+ lang = await TreeSitter7.Language.load(wasmPath);
2649
+ break;
2650
+ } catch {
2651
+ continue;
2652
+ }
2653
+ }
2654
+ }
2655
+ if (!lang) {
2656
+ throw new Error(
2657
+ `Failed to load tree-sitter-c_sharp WASM file. Tried paths: ${wasmPaths.join(", ")}`
2658
+ );
2659
+ }
2660
+ this.parser = new TreeSitter7.Parser();
2661
+ this.parser.setLanguage(lang);
2662
+ this.initialized = true;
2663
+ } catch (error) {
2664
+ throw new ParserInitializationError(
2665
+ "csharp",
2666
+ "Failed to load C# WASM parser module",
2667
+ error
2668
+ );
2669
+ }
2670
+ }
2671
+ async parse(sourceCode) {
2672
+ if (!this.initialized) {
2673
+ await this.initialize();
2674
+ }
2675
+ if (!this.parser) {
2676
+ throw new ParserInitializationError("csharp", "Parser not initialized");
2677
+ }
2678
+ const tree = this.parser.parse(sourceCode);
2679
+ if (!tree) {
2680
+ throw new ParserInitializationError(
2681
+ "csharp",
2682
+ "Failed to parse source code"
2683
+ );
2684
+ }
2685
+ return this.nodeToJson(tree.rootNode);
2686
+ }
2687
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2688
+ async parseRaw(sourceCode) {
2689
+ if (!this.initialized) {
2690
+ await this.initialize();
2691
+ }
2692
+ if (!this.parser) {
2693
+ throw new ParserInitializationError("csharp", "Parser not initialized");
2694
+ }
2695
+ const tree = this.parser.parse(sourceCode);
2696
+ if (!tree) {
2697
+ throw new ParserInitializationError(
2698
+ "csharp",
2699
+ "Failed to parse source code"
2700
+ );
2701
+ }
2702
+ return tree;
2703
+ }
2704
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2705
+ nodeToJson(node) {
2706
+ return {
2707
+ type: node.type,
2708
+ text: node.type === "program" || node.type === "compilation_unit" ? "<skipped>" : node.text,
2709
+ line: node.startPosition.row + 1,
2710
+ children: Array.from({ length: node.childCount }, (_, i) => {
2711
+ const child = node.child(i);
2712
+ return child ? this.nodeToJson(child) : null;
2713
+ }).filter((c) => c !== null)
2714
+ };
2715
+ }
2716
+ getLanguage() {
2717
+ return "csharp";
2718
+ }
2719
+ };
2720
+
2721
+ // packages/linter-ast/src/parsers/PHPParser.ts
2722
+ var TreeSitter8 = __toESM(require("web-tree-sitter"));
2723
+ var import_fs9 = require("fs");
2724
+ var PHPParser = class extends BaseParser {
2725
+ async initialize() {
2726
+ try {
2727
+ let lang = null;
2728
+ await TreeSitter8.Parser.init({
2729
+ locateFile: BaseParser.getTreeSitterLocateFile()
2730
+ });
2731
+ const wasmPaths = BaseParser.getLanguageWasmPaths("php_only").concat(
2732
+ BaseParser.getLanguageWasmPaths("php")
2733
+ );
2734
+ for (const wasmPath of wasmPaths) {
2735
+ if ((0, import_fs9.existsSync)(wasmPath)) {
2736
+ try {
2737
+ lang = await TreeSitter8.Language.load(wasmPath);
2738
+ break;
2739
+ } catch {
2740
+ continue;
2741
+ }
2742
+ }
2743
+ }
2744
+ if (!lang) {
2745
+ throw new Error(
2746
+ `Failed to load tree-sitter-php WASM file. Tried paths: ${wasmPaths.join(", ")}`
2747
+ );
2748
+ }
2749
+ this.parser = new TreeSitter8.Parser();
2750
+ this.parser.setLanguage(lang);
2751
+ this.initialized = true;
2752
+ } catch (error) {
2753
+ throw new ParserInitializationError(
2754
+ "php",
2755
+ "Failed to load PHP WASM parser module",
2756
+ error
2757
+ );
2758
+ }
2759
+ }
2760
+ async parse(sourceCode) {
2761
+ if (!this.initialized) {
2762
+ await this.initialize();
2763
+ }
2764
+ if (!this.parser) {
2765
+ throw new ParserInitializationError("php", "Parser not initialized");
2766
+ }
2767
+ const tree = this.parser.parse(sourceCode);
2768
+ if (!tree) {
2769
+ throw new ParserInitializationError("php", "Failed to parse source code");
2770
+ }
2771
+ const astJson = this.nodeToJson(tree.rootNode);
2772
+ return astJson;
2773
+ }
2774
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2775
+ async parseRaw(sourceCode) {
2776
+ if (!this.initialized) {
2777
+ await this.initialize();
2778
+ }
2779
+ if (!this.parser) {
2780
+ throw new ParserInitializationError("php", "Parser not initialized");
2781
+ }
2782
+ const tree = this.parser.parse(sourceCode);
2783
+ if (!tree) {
2784
+ throw new ParserInitializationError("php", "Failed to parse source code");
2785
+ }
2786
+ return tree;
2787
+ }
2788
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2789
+ nodeToJson(node) {
2790
+ return {
2791
+ type: node.type,
2792
+ text: node.type === "program" ? "<skipped>" : node.text,
2793
+ line: node.startPosition.row + 1,
2794
+ children: Array.from({ length: node.childCount }, (_, i) => {
2795
+ const child = node.child(i);
2796
+ return child ? this.nodeToJson(child) : null;
2797
+ }).filter((c) => c !== null)
2798
+ };
2799
+ }
2800
+ getLanguage() {
2801
+ return "php";
2802
+ }
2803
+ };
2804
+
2805
+ // packages/linter-ast/src/parsers/PythonParser.ts
2806
+ var TreeSitter9 = __toESM(require("web-tree-sitter"));
2807
+ var import_fs10 = require("fs");
2808
+ var PythonParser = class extends BaseParser {
2809
+ async initialize() {
2810
+ try {
2811
+ let lang = null;
2812
+ await TreeSitter9.Parser.init({
2813
+ locateFile: BaseParser.getTreeSitterLocateFile()
2814
+ });
2815
+ const wasmPaths = BaseParser.getLanguageWasmPaths("python");
2816
+ for (const wasmPath of wasmPaths) {
2817
+ if ((0, import_fs10.existsSync)(wasmPath)) {
2818
+ try {
2819
+ lang = await TreeSitter9.Language.load(wasmPath);
2820
+ break;
2821
+ } catch {
2822
+ continue;
2823
+ }
2824
+ }
2825
+ }
2826
+ if (!lang) {
2827
+ throw new Error(
2828
+ `Failed to load tree-sitter-python WASM file. Tried paths: ${wasmPaths.join(", ")}`
2829
+ );
2830
+ }
2831
+ this.parser = new TreeSitter9.Parser();
2832
+ this.parser.setLanguage(lang);
2833
+ this.initialized = true;
2834
+ } catch (error) {
2835
+ throw new ParserInitializationError(
2836
+ "python",
2837
+ "Failed to load Python WASM parser module",
2838
+ error
2839
+ );
2840
+ }
2841
+ }
2842
+ async parse(sourceCode) {
2843
+ if (!this.initialized) {
2844
+ await this.initialize();
2845
+ }
2846
+ if (!this.parser) {
2847
+ throw new ParserInitializationError("python", "Parser not initialized");
2848
+ }
2849
+ const tree = this.parser.parse(sourceCode);
2850
+ if (!tree) {
2851
+ throw new ParserInitializationError(
2852
+ "python",
2853
+ "Failed to parse source code"
2854
+ );
2855
+ }
2856
+ return this.nodeToJson(tree.rootNode);
2857
+ }
2858
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2859
+ async parseRaw(sourceCode) {
2860
+ if (!this.initialized) {
2861
+ await this.initialize();
2862
+ }
2863
+ if (!this.parser) {
2864
+ throw new ParserInitializationError("python", "Parser not initialized");
2865
+ }
2866
+ const tree = this.parser.parse(sourceCode);
2867
+ if (!tree) {
2868
+ throw new ParserInitializationError(
2869
+ "python",
2870
+ "Failed to parse source code"
2871
+ );
2872
+ }
2873
+ return tree;
2874
+ }
2875
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2876
+ nodeToJson(node) {
2877
+ return {
2878
+ type: node.type,
2879
+ text: node.type === "program" ? "<skipped>" : node.text,
2880
+ line: node.startPosition.row + 1,
2881
+ children: Array.from({ length: node.childCount }, (_, i) => {
2882
+ const child = node.child(i);
2883
+ return child ? this.nodeToJson(child) : null;
2884
+ }).filter((c) => c !== null)
2885
+ };
2886
+ }
2887
+ getLanguage() {
2888
+ return "python";
2889
+ }
2890
+ };
2891
+
2892
+ // packages/linter-ast/src/parsers/RubyParser.ts
2893
+ var TreeSitter10 = __toESM(require("web-tree-sitter"));
2894
+ var import_fs11 = require("fs");
2895
+ var RubyParser = class extends BaseParser {
2896
+ async initialize() {
2897
+ try {
2898
+ let lang = null;
2899
+ await TreeSitter10.Parser.init({
2900
+ locateFile: BaseParser.getTreeSitterLocateFile()
2901
+ });
2902
+ const wasmPaths = BaseParser.getLanguageWasmPaths("ruby");
2903
+ for (const wasmPath of wasmPaths) {
2904
+ if ((0, import_fs11.existsSync)(wasmPath)) {
2905
+ try {
2906
+ lang = await TreeSitter10.Language.load(wasmPath);
2907
+ break;
2908
+ } catch {
2909
+ continue;
2910
+ }
2911
+ }
2912
+ }
2913
+ if (!lang) {
2914
+ throw new Error(
2915
+ `Failed to load tree-sitter-ruby WASM file. Tried paths: ${wasmPaths.join(", ")}`
2916
+ );
2917
+ }
2918
+ this.parser = new TreeSitter10.Parser();
2919
+ this.parser.setLanguage(lang);
2920
+ this.initialized = true;
2921
+ } catch (error) {
2922
+ throw new ParserInitializationError(
2923
+ "ruby",
2924
+ "Failed to load Ruby WASM parser module",
2925
+ error
2926
+ );
2927
+ }
2928
+ }
2929
+ async parse(sourceCode) {
2930
+ if (!this.initialized) {
2931
+ await this.initialize();
2932
+ }
2933
+ if (!this.parser) {
2934
+ throw new ParserInitializationError("ruby", "Parser not initialized");
2935
+ }
2936
+ const tree = this.parser.parse(sourceCode);
2937
+ if (!tree) {
2938
+ throw new ParserInitializationError(
2939
+ "ruby",
2940
+ "Failed to parse source code"
2941
+ );
2942
+ }
2943
+ return this.nodeToJson(tree.rootNode);
2944
+ }
2945
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2946
+ async parseRaw(sourceCode) {
2947
+ if (!this.initialized) {
2948
+ await this.initialize();
2949
+ }
2950
+ if (!this.parser) {
2951
+ throw new ParserInitializationError("ruby", "Parser not initialized");
2952
+ }
2953
+ const tree = this.parser.parse(sourceCode);
2954
+ if (!tree) {
2955
+ throw new ParserInitializationError(
2956
+ "ruby",
2957
+ "Failed to parse source code"
2958
+ );
2959
+ }
2960
+ return tree;
2961
+ }
2962
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2963
+ nodeToJson(node) {
2964
+ return {
2965
+ type: node.type,
2966
+ text: node.type === "program" ? "<skipped>" : node.text,
2967
+ line: node.startPosition.row + 1,
2968
+ children: Array.from({ length: node.childCount }, (_, i) => {
2969
+ const child = node.child(i);
2970
+ return child ? this.nodeToJson(child) : null;
2971
+ }).filter((c) => c !== null)
2972
+ };
2973
+ }
2974
+ getLanguage() {
2975
+ return "ruby";
2976
+ }
2977
+ };
2978
+
2979
+ // packages/linter-ast/src/parsers/JSONParser.ts
2980
+ var TreeSitter11 = __toESM(require("web-tree-sitter"));
2981
+ var import_fs12 = require("fs");
2982
+ var JSONParser = class extends BaseParser {
2983
+ async initialize() {
2984
+ try {
2985
+ let lang = null;
2986
+ await TreeSitter11.Parser.init({
2987
+ locateFile: BaseParser.getTreeSitterLocateFile()
2988
+ });
2989
+ const wasmPaths = BaseParser.getLanguageWasmPaths("json");
2990
+ for (const wasmPath of wasmPaths) {
2991
+ if ((0, import_fs12.existsSync)(wasmPath)) {
2992
+ try {
2993
+ lang = await TreeSitter11.Language.load(wasmPath);
2994
+ break;
2995
+ } catch {
2996
+ continue;
2997
+ }
2998
+ }
2999
+ }
3000
+ if (!lang) {
3001
+ throw new Error(
3002
+ `Failed to load tree-sitter-json WASM file. Tried paths: ${wasmPaths.join(", ")}`
3003
+ );
3004
+ }
3005
+ this.parser = new TreeSitter11.Parser();
3006
+ this.parser.setLanguage(lang);
3007
+ this.initialized = true;
3008
+ } catch (error) {
3009
+ throw new ParserInitializationError(
3010
+ "json",
3011
+ "Failed to load JSON WASM parser module",
3012
+ error
3013
+ );
3014
+ }
3015
+ }
3016
+ async parse(sourceCode) {
3017
+ if (!this.initialized) {
3018
+ await this.initialize();
3019
+ }
3020
+ if (!this.parser) {
3021
+ throw new ParserInitializationError("json", "Parser not initialized");
3022
+ }
3023
+ const tree = this.parser.parse(sourceCode);
3024
+ if (!tree) {
3025
+ throw new ParserInitializationError(
3026
+ "json",
3027
+ "Failed to parse source code"
3028
+ );
3029
+ }
3030
+ return this.nodeToJson(tree.rootNode);
3031
+ }
3032
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3033
+ async parseRaw(sourceCode) {
3034
+ if (!this.initialized) {
3035
+ await this.initialize();
3036
+ }
3037
+ if (!this.parser) {
3038
+ throw new ParserInitializationError("json", "Parser not initialized");
3039
+ }
3040
+ const tree = this.parser.parse(sourceCode);
3041
+ if (!tree) {
3042
+ throw new ParserInitializationError(
3043
+ "json",
3044
+ "Failed to parse source code"
3045
+ );
3046
+ }
3047
+ return tree;
3048
+ }
3049
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3050
+ nodeToJson(node) {
3051
+ return {
3052
+ type: node.type,
3053
+ text: node.type === "document" ? "<skipped>" : node.text,
3054
+ line: node.startPosition.row + 1,
3055
+ children: Array.from({ length: node.childCount }, (_, i) => {
3056
+ const child = node.child(i);
3057
+ return child ? this.nodeToJson(child) : null;
3058
+ }).filter((c) => c !== null)
3059
+ };
3060
+ }
3061
+ getLanguage() {
3062
+ return "json";
3063
+ }
3064
+ };
3065
+
3066
+ // packages/linter-ast/src/parsers/HTMLParser.ts
3067
+ var TreeSitter12 = __toESM(require("web-tree-sitter"));
3068
+ var import_fs13 = require("fs");
3069
+ var HTMLParser = class extends BaseParser {
3070
+ async initialize() {
3071
+ try {
3072
+ let lang = null;
3073
+ await TreeSitter12.Parser.init({
3074
+ locateFile: BaseParser.getTreeSitterLocateFile()
3075
+ });
3076
+ const wasmPaths = BaseParser.getLanguageWasmPaths("html");
3077
+ for (const wasmPath of wasmPaths) {
3078
+ if ((0, import_fs13.existsSync)(wasmPath)) {
3079
+ try {
3080
+ lang = await TreeSitter12.Language.load(wasmPath);
3081
+ break;
3082
+ } catch {
3083
+ continue;
3084
+ }
3085
+ }
3086
+ }
3087
+ if (!lang) {
3088
+ throw new Error(
3089
+ `Failed to load tree-sitter-html WASM file. Tried paths: ${wasmPaths.join(", ")}`
3090
+ );
3091
+ }
3092
+ this.parser = new TreeSitter12.Parser();
3093
+ this.parser.setLanguage(lang);
3094
+ this.initialized = true;
3095
+ } catch (error) {
3096
+ throw new ParserInitializationError(
3097
+ "html",
3098
+ "Failed to load HTML WASM parser module",
3099
+ error
3100
+ );
3101
+ }
3102
+ }
3103
+ async parse(sourceCode) {
3104
+ if (!this.initialized) {
3105
+ await this.initialize();
3106
+ }
3107
+ if (!this.parser) {
3108
+ throw new ParserInitializationError("html", "Parser not initialized");
3109
+ }
3110
+ const tree = this.parser.parse(sourceCode);
3111
+ if (!tree) {
3112
+ throw new ParserInitializationError(
3113
+ "html",
3114
+ "Failed to parse source code"
3115
+ );
3116
+ }
3117
+ return this.nodeToJson(tree.rootNode);
3118
+ }
3119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3120
+ async parseRaw(sourceCode) {
3121
+ if (!this.initialized) {
3122
+ await this.initialize();
3123
+ }
3124
+ if (!this.parser) {
3125
+ throw new ParserInitializationError("html", "Parser not initialized");
3126
+ }
3127
+ const tree = this.parser.parse(sourceCode);
3128
+ if (!tree) {
3129
+ throw new ParserInitializationError(
3130
+ "html",
3131
+ "Failed to parse source code"
3132
+ );
3133
+ }
3134
+ return tree;
3135
+ }
3136
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3137
+ nodeToJson(node) {
3138
+ return {
3139
+ type: node.type,
3140
+ text: node.type === "program" ? "<skipped>" : node.text,
3141
+ line: node.startPosition.row + 1,
3142
+ children: Array.from({ length: node.childCount }, (_, i) => {
3143
+ const child = node.child(i);
3144
+ return child ? this.nodeToJson(child) : null;
3145
+ }).filter((c) => c !== null)
3146
+ };
3147
+ }
3148
+ getLanguage() {
3149
+ return "html";
3150
+ }
3151
+ };
3152
+
3153
+ // packages/linter-ast/src/parsers/JavaParser.ts
3154
+ var TreeSitter13 = __toESM(require("web-tree-sitter"));
3155
+ var import_fs14 = require("fs");
3156
+ var JavaParser = class extends BaseParser {
3157
+ async initialize() {
3158
+ try {
3159
+ let lang = null;
3160
+ await TreeSitter13.Parser.init({
3161
+ locateFile: BaseParser.getTreeSitterLocateFile()
3162
+ });
3163
+ const wasmPaths = BaseParser.getLanguageWasmPaths("java");
3164
+ for (const wasmPath of wasmPaths) {
3165
+ if ((0, import_fs14.existsSync)(wasmPath)) {
3166
+ try {
3167
+ lang = await TreeSitter13.Language.load(wasmPath);
3168
+ break;
3169
+ } catch {
3170
+ continue;
3171
+ }
3172
+ }
3173
+ }
3174
+ if (!lang) {
3175
+ throw new Error(
3176
+ `Failed to load tree-sitter-java WASM file. Tried paths: ${wasmPaths.join(", ")}`
3177
+ );
3178
+ }
3179
+ this.parser = new TreeSitter13.Parser();
3180
+ this.parser.setLanguage(lang);
3181
+ this.initialized = true;
3182
+ } catch (error) {
3183
+ throw new ParserInitializationError(
3184
+ "java",
3185
+ "Failed to load Java WASM parser module",
3186
+ error
3187
+ );
3188
+ }
3189
+ }
3190
+ async parse(sourceCode) {
3191
+ if (!this.initialized) {
3192
+ await this.initialize();
3193
+ }
3194
+ if (!this.parser) {
3195
+ throw new ParserInitializationError("java", "Parser not initialized");
3196
+ }
3197
+ const tree = this.parser.parse(sourceCode);
3198
+ if (!tree) {
3199
+ throw new ParserInitializationError(
3200
+ "java",
3201
+ "Failed to parse source code"
3202
+ );
3203
+ }
3204
+ return this.nodeToJson(tree.rootNode);
3205
+ }
3206
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3207
+ async parseRaw(sourceCode) {
3208
+ if (!this.initialized) {
3209
+ await this.initialize();
3210
+ }
3211
+ if (!this.parser) {
3212
+ throw new ParserInitializationError("java", "Parser not initialized");
3213
+ }
3214
+ const tree = this.parser.parse(sourceCode);
3215
+ if (!tree) {
3216
+ throw new ParserInitializationError(
3217
+ "java",
3218
+ "Failed to parse source code"
3219
+ );
3220
+ }
3221
+ return tree;
3222
+ }
3223
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3224
+ nodeToJson(node) {
3225
+ return {
3226
+ type: node.type,
3227
+ text: node.type === "program" ? "<skipped>" : node.text,
3228
+ line: node.startPosition.row + 1,
3229
+ children: Array.from({ length: node.childCount }, (_, i) => {
3230
+ const child = node.child(i);
3231
+ return child ? this.nodeToJson(child) : null;
3232
+ }).filter((c) => c !== null)
3233
+ };
3234
+ }
3235
+ getLanguage() {
3236
+ return "java";
3237
+ }
3238
+ };
3239
+
3240
+ // packages/linter-ast/src/parsers/SwiftParser.ts
3241
+ var TreeSitter14 = __toESM(require("web-tree-sitter"));
3242
+ var import_fs15 = require("fs");
3243
+ var SwiftParser = class extends BaseParser {
3244
+ async initialize() {
3245
+ try {
3246
+ let lang = null;
3247
+ await TreeSitter14.Parser.init({
3248
+ locateFile: BaseParser.getTreeSitterLocateFile()
3249
+ });
3250
+ const wasmPaths = BaseParser.getLanguageWasmPaths("swift");
3251
+ for (const wasmPath of wasmPaths) {
3252
+ if ((0, import_fs15.existsSync)(wasmPath)) {
3253
+ try {
3254
+ lang = await TreeSitter14.Language.load(wasmPath);
3255
+ break;
3256
+ } catch {
3257
+ continue;
3258
+ }
3259
+ }
3260
+ }
3261
+ if (!lang) {
3262
+ throw new Error(
3263
+ `Failed to load tree-sitter-swift WASM file. Tried paths: ${wasmPaths.join(", ")}`
3264
+ );
3265
+ }
3266
+ this.parser = new TreeSitter14.Parser();
3267
+ this.parser.setLanguage(lang);
3268
+ this.initialized = true;
3269
+ } catch (error) {
3270
+ throw new ParserInitializationError(
3271
+ "swift",
3272
+ "Failed to load Swift WASM parser module",
3273
+ error
3274
+ );
3275
+ }
3276
+ }
3277
+ async parse(sourceCode) {
3278
+ if (!this.initialized) {
3279
+ await this.initialize();
3280
+ }
3281
+ if (!this.parser) {
3282
+ throw new ParserInitializationError("swift", "Parser not initialized");
3283
+ }
3284
+ const tree = this.parser.parse(sourceCode);
3285
+ if (!tree) {
3286
+ throw new ParserInitializationError(
3287
+ "swift",
3288
+ "Failed to parse source code"
3289
+ );
3290
+ }
3291
+ return this.nodeToJson(tree.rootNode);
3292
+ }
3293
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3294
+ async parseRaw(sourceCode) {
3295
+ if (!this.initialized) {
3296
+ await this.initialize();
3297
+ }
3298
+ if (!this.parser) {
3299
+ throw new ParserInitializationError("swift", "Parser not initialized");
3300
+ }
3301
+ const tree = this.parser.parse(sourceCode);
3302
+ if (!tree) {
3303
+ throw new ParserInitializationError(
3304
+ "swift",
3305
+ "Failed to parse source code"
3306
+ );
3307
+ }
3308
+ return tree;
3309
+ }
3310
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3311
+ nodeToJson(node) {
3312
+ return {
3313
+ type: node.type,
3314
+ text: node.type === "program" || node.type === "source_file" ? "<skipped>" : node.text,
3315
+ line: node.startPosition.row + 1,
3316
+ children: Array.from({ length: node.childCount }, (_, i) => {
3317
+ const child = node.child(i);
3318
+ return child ? this.nodeToJson(child) : null;
3319
+ }).filter((c) => c !== null)
3320
+ };
3321
+ }
3322
+ getLanguage() {
3323
+ return "swift";
3324
+ }
3325
+ };
3326
+
3327
+ // packages/linter-ast/src/parsers/SCSSParser.ts
3328
+ var TreeSitter15 = __toESM(require("web-tree-sitter"));
3329
+ var import_fs16 = require("fs");
3330
+ var SCSSParser = class extends BaseParser {
3331
+ async initialize() {
3332
+ try {
3333
+ let lang = null;
3334
+ await TreeSitter15.Parser.init({
3335
+ locateFile: BaseParser.getTreeSitterLocateFile()
3336
+ });
3337
+ const wasmPaths = BaseParser.getLanguageWasmPaths("scss");
3338
+ for (const wasmPath of wasmPaths) {
3339
+ if ((0, import_fs16.existsSync)(wasmPath)) {
3340
+ try {
3341
+ lang = await TreeSitter15.Language.load(wasmPath);
3342
+ break;
3343
+ } catch {
3344
+ continue;
3345
+ }
3346
+ }
3347
+ }
3348
+ if (!lang) {
3349
+ throw new Error(
3350
+ `Failed to load tree-sitter-scss WASM file. Tried paths: ${wasmPaths.join(", ")}`
3351
+ );
3352
+ }
3353
+ this.parser = new TreeSitter15.Parser();
3354
+ this.parser.setLanguage(lang);
3355
+ this.initialized = true;
3356
+ } catch (error) {
3357
+ throw new ParserInitializationError(
3358
+ "scss",
3359
+ "Failed to load SCSS WASM parser module",
3360
+ error
3361
+ );
3362
+ }
3363
+ }
3364
+ async parse(sourceCode) {
3365
+ if (!this.initialized) {
3366
+ await this.initialize();
3367
+ }
3368
+ if (!this.parser) {
3369
+ throw new ParserInitializationError("scss", "Parser not initialized");
3370
+ }
3371
+ const tree = this.parser.parse(sourceCode);
3372
+ if (!tree) {
3373
+ throw new ParserInitializationError(
3374
+ "scss",
3375
+ "Failed to parse source code"
3376
+ );
3377
+ }
3378
+ return this.nodeToJson(tree.rootNode);
3379
+ }
3380
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3381
+ async parseRaw(sourceCode) {
3382
+ if (!this.initialized) {
3383
+ await this.initialize();
3384
+ }
3385
+ if (!this.parser) {
3386
+ throw new ParserInitializationError("scss", "Parser not initialized");
3387
+ }
3388
+ const tree = this.parser.parse(sourceCode);
3389
+ if (!tree) {
3390
+ throw new ParserInitializationError(
3391
+ "scss",
3392
+ "Failed to parse source code"
3393
+ );
3394
+ }
3395
+ return tree;
3396
+ }
3397
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3398
+ nodeToJson(node) {
3399
+ return {
3400
+ type: node.type,
3401
+ text: node.type === "program" || node.type === "stylesheet" ? "<skipped>" : node.text,
3402
+ line: node.startPosition.row + 1,
3403
+ children: Array.from({ length: node.childCount }, (_, i) => {
3404
+ const child = node.child(i);
3405
+ return child ? this.nodeToJson(child) : null;
3406
+ }).filter((c) => c !== null)
3407
+ };
3408
+ }
3409
+ getLanguage() {
3410
+ return "scss";
3411
+ }
3412
+ };
3413
+
3414
+ // packages/linter-ast/src/parsers/YAMLParser.ts
3415
+ var TreeSitter16 = __toESM(require("web-tree-sitter"));
3416
+ var import_fs17 = require("fs");
3417
+ var YAMLParser = class extends BaseParser {
3418
+ async initialize() {
3419
+ try {
3420
+ let lang = null;
3421
+ await TreeSitter16.Parser.init({
3422
+ locateFile: BaseParser.getTreeSitterLocateFile()
3423
+ });
3424
+ const wasmPaths = BaseParser.getLanguageWasmPaths("yaml");
3425
+ for (const wasmPath of wasmPaths) {
3426
+ if ((0, import_fs17.existsSync)(wasmPath)) {
3427
+ try {
3428
+ lang = await TreeSitter16.Language.load(wasmPath);
3429
+ break;
3430
+ } catch {
3431
+ continue;
3432
+ }
3433
+ }
3434
+ }
3435
+ if (!lang) {
3436
+ throw new Error(
3437
+ `Failed to load tree-sitter-yaml WASM file. Tried paths: ${wasmPaths.join(", ")}`
3438
+ );
3439
+ }
3440
+ this.parser = new TreeSitter16.Parser();
3441
+ this.parser.setLanguage(lang);
3442
+ this.initialized = true;
3443
+ } catch (error) {
3444
+ throw new ParserInitializationError(
3445
+ "yaml",
3446
+ "Failed to load YAML WASM parser module",
3447
+ error
3448
+ );
3449
+ }
3450
+ }
3451
+ async parse(sourceCode) {
3452
+ if (!this.initialized) {
3453
+ await this.initialize();
3454
+ }
3455
+ if (!this.parser) {
3456
+ throw new ParserInitializationError("yaml", "Parser not initialized");
3457
+ }
3458
+ const tree = this.parser.parse(sourceCode);
3459
+ if (!tree) {
3460
+ throw new ParserInitializationError(
3461
+ "yaml",
3462
+ "Failed to parse source code"
3463
+ );
3464
+ }
3465
+ return this.nodeToJson(tree.rootNode);
3466
+ }
3467
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3468
+ async parseRaw(sourceCode) {
3469
+ if (!this.initialized) {
3470
+ await this.initialize();
3471
+ }
3472
+ if (!this.parser) {
3473
+ throw new ParserInitializationError("yaml", "Parser not initialized");
3474
+ }
3475
+ const tree = this.parser.parse(sourceCode);
3476
+ if (!tree) {
3477
+ throw new ParserInitializationError(
3478
+ "yaml",
3479
+ "Failed to parse source code"
3480
+ );
3481
+ }
3482
+ return tree;
3483
+ }
3484
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3485
+ nodeToJson(node) {
3486
+ return {
3487
+ type: node.type,
3488
+ text: node.type === "stream" ? "<skipped>" : node.text,
3489
+ line: node.startPosition.row + 1,
3490
+ children: Array.from({ length: node.childCount }, (_, i) => {
3491
+ const child = node.child(i);
3492
+ return child ? this.nodeToJson(child) : null;
3493
+ }).filter((c) => c !== null)
3494
+ };
3495
+ }
3496
+ getLanguage() {
3497
+ return "yaml";
3498
+ }
3499
+ };
3500
+
3501
+ // packages/linter-ast/src/core/ParserRegistry.ts
3502
+ var ParserRegistry = class {
3503
+ constructor() {
3504
+ this.parsers = /* @__PURE__ */ new Map();
3505
+ this.parserClasses = {
3506
+ typescript: TypeScriptParser,
3507
+ javascript: JavaScriptParser,
3508
+ cpp: CPPParser,
3509
+ go: GoParser,
3510
+ kotlin: KotlinParser,
3511
+ css: CSSParser,
3512
+ csharp: CSharpParser,
3513
+ php: PHPParser,
3514
+ python: PythonParser,
3515
+ ruby: RubyParser,
3516
+ json: JSONParser,
3517
+ html: HTMLParser,
3518
+ java: JavaParser,
3519
+ swift: SwiftParser,
3520
+ scss: SCSSParser,
3521
+ yaml: YAMLParser
3522
+ };
3523
+ }
3524
+ async getParser(language) {
3525
+ const cached = this.parsers.get(language);
3526
+ if (cached) {
3527
+ return cached;
3528
+ }
3529
+ const ParserClass = this.parserClasses[language];
3530
+ if (!ParserClass) {
3531
+ throw new ParserNotAvailableError(language);
3532
+ }
3533
+ const parser = new ParserClass();
3534
+ await parser.initialize();
3535
+ this.parsers.set(language, parser);
3536
+ return parser;
3537
+ }
3538
+ getAvailableParsers() {
3539
+ return Object.keys(this.parserClasses);
3540
+ }
3541
+ clearCache() {
3542
+ this.parsers.clear();
3543
+ }
3544
+ };
3545
+
3546
+ // packages/linter-ast/src/application/ConsoleLogRemovalService.ts
3547
+ var ConsoleLogRemovalService = class {
3548
+ constructor() {
3549
+ this.jsParser = new JavaScriptParser();
3550
+ }
3551
+ /**
3552
+ * Removes all console method calls from JavaScript source code using AST parsing
3553
+ * @param sourceCode The source code to clean
3554
+ * @param language The programming language (must be JAVASCRIPT)
3555
+ * @returns The cleaned source code with console statements removed
3556
+ * @throws Error if language is not JAVASCRIPT
3557
+ */
3558
+ async removeConsoleLogStatements(sourceCode, language) {
3559
+ if (language !== "JAVASCRIPT" /* JAVASCRIPT */) {
3560
+ throw new Error(
3561
+ `ConsoleRemovalService only supports JAVASCRIPT, received: ${language}`
3562
+ );
3563
+ }
3564
+ try {
3565
+ const tree = await this.jsParser.parseRaw(sourceCode);
3566
+ const ast = tree.rootNode;
3567
+ const ranges = [];
3568
+ const visit = (node) => {
3569
+ if (node.type === "expression_statement") {
3570
+ const expr = node.firstChild;
3571
+ if (expr?.type === "call_expression") {
3572
+ const callee = expr.child(0);
3573
+ if (callee?.text.startsWith("console.")) {
3574
+ ranges.push([node.startIndex, node.endIndex]);
3575
+ }
3576
+ }
3577
+ }
3578
+ for (let i = 0; i < node.childCount; i++) {
3579
+ visit(node.child(i));
3580
+ }
3581
+ };
3582
+ visit(ast);
3583
+ ranges.sort((a, b) => b[0] - a[0]);
3584
+ let cleaned = sourceCode;
3585
+ for (const [start, end] of ranges) {
3586
+ cleaned = cleaned.slice(0, start) + cleaned.slice(end);
3587
+ }
3588
+ return cleaned;
3589
+ } catch (error) {
3590
+ throw new Error(`Can not parse JS CODE ${error}`);
3591
+ }
3592
+ }
3593
+ };
3594
+
3595
+ // packages/linter-ast/src/application/LinterAstAdapter.ts
3596
+ var LinterAstAdapter = class {
3597
+ constructor() {
3598
+ this.registry = new ParserRegistry();
3599
+ this.consoleRemovalService = new ConsoleLogRemovalService();
3600
+ }
3601
+ async parseSourceCode(sourceCode, language) {
3602
+ const languageKey = this.mapLanguageToParserKey(language);
3603
+ if (!languageKey) {
3604
+ throw new ParserNotAvailableError(language);
3605
+ }
3606
+ const parser = await this.registry.getParser(languageKey);
3607
+ return parser.parse(sourceCode);
3608
+ }
3609
+ isLanguageSupported(language) {
3610
+ const languageKey = this.mapLanguageToParserKey(language);
3611
+ return languageKey !== null;
3612
+ }
3613
+ getAvailableLanguages() {
3614
+ return [
3615
+ "TYPESCRIPT" /* TYPESCRIPT */,
3616
+ "TYPESCRIPT_TSX" /* TYPESCRIPT_TSX */,
3617
+ "JAVASCRIPT" /* JAVASCRIPT */,
3618
+ "JAVASCRIPT_JSX" /* JAVASCRIPT_JSX */,
3619
+ "CPP" /* CPP */,
3620
+ "GO" /* GO */,
3621
+ "KOTLIN" /* KOTLIN */,
3622
+ "CSS" /* CSS */,
3623
+ "CSHARP" /* CSHARP */,
3624
+ "PHP" /* PHP */,
3625
+ "PYTHON" /* PYTHON */,
3626
+ "RUBY" /* RUBY */,
3627
+ "JSON" /* JSON */,
3628
+ "HTML" /* HTML */,
3629
+ "JAVA" /* JAVA */,
3630
+ "SWIFT" /* SWIFT */,
3631
+ "SCSS" /* SCSS */,
3632
+ "YAML" /* YAML */
3633
+ ];
3634
+ }
3635
+ async removeConsoleStatements(sourceCode, language) {
3636
+ return this.consoleRemovalService.removeConsoleLogStatements(
3637
+ sourceCode,
3638
+ language
3639
+ );
3640
+ }
3641
+ mapLanguageToParserKey(language) {
3642
+ const mapping = {
3643
+ ["TYPESCRIPT" /* TYPESCRIPT */]: "typescript",
3644
+ ["TYPESCRIPT_TSX" /* TYPESCRIPT_TSX */]: "typescript",
3645
+ ["JAVASCRIPT" /* JAVASCRIPT */]: "javascript",
3646
+ ["JAVASCRIPT_JSX" /* JAVASCRIPT_JSX */]: "javascript",
3647
+ ["CPP" /* CPP */]: "cpp",
3648
+ ["GO" /* GO */]: "go",
3649
+ ["KOTLIN" /* KOTLIN */]: "kotlin",
3650
+ ["CSS" /* CSS */]: "css",
3651
+ ["CSHARP" /* CSHARP */]: "csharp",
3652
+ ["PHP" /* PHP */]: "php",
3653
+ ["PYTHON" /* PYTHON */]: "python",
3654
+ ["RUBY" /* RUBY */]: "ruby",
3655
+ ["JSON" /* JSON */]: "json",
3656
+ ["HTML" /* HTML */]: "html",
3657
+ ["JAVA" /* JAVA */]: "java",
3658
+ ["SWIFT" /* SWIFT */]: "swift",
3659
+ ["SCSS" /* SCSS */]: "scss",
3660
+ ["YAML" /* YAML */]: "yaml"
3661
+ };
3662
+ return mapping[language] || null;
3663
+ }
3664
+ };
3665
+
3666
+ // packages/linter-ast/src/parsers/TypeScriptTSXParser.ts
3667
+ var TreeSitter17 = __toESM(require("web-tree-sitter"));
3668
+
3669
+ // packages/linter-execution/src/application/useCases/ExecuteLinterProgramsUseCase.ts
3670
+ var origin8 = "ExecuteLinterProgramsUseCase";
3671
+ var ExecuteLinterProgramsUseCase = class {
3672
+ constructor(linterAstAdapter = new LinterAstAdapter(), logger = new PackmindLogger(origin8)) {
3673
+ this.linterAstAdapter = linterAstAdapter;
3674
+ this.logger = logger;
3675
+ }
3676
+ async execute(command2) {
3677
+ const { filePath, fileContent, language, programs } = command2;
3678
+ if (programs.length === 0) {
3679
+ return {
3680
+ file: filePath,
3681
+ violations: []
3682
+ };
3683
+ }
3684
+ const matchingPrograms = this.filterProgramsByLanguage(programs, language);
3685
+ if (matchingPrograms.length === 0) {
3686
+ return {
3687
+ file: filePath,
3688
+ violations: []
3689
+ };
3690
+ }
3691
+ const violations = [];
3692
+ this.extractAndExecutePrograms(matchingPrograms, fileContent, violations);
3693
+ await this.extractAndExecuteASTPrograms(
3694
+ matchingPrograms,
3695
+ language,
3696
+ filePath,
3697
+ fileContent,
3698
+ violations
3699
+ );
3700
+ return {
3701
+ file: filePath,
3702
+ violations
3703
+ };
3704
+ }
3705
+ async extractAndExecuteASTPrograms(programs, language, filePath, fileContent, violations) {
3706
+ const astPrograms = programs.filter((p) => p.sourceCodeState === "AST");
3707
+ if (astPrograms.length > 0) {
3708
+ if (!this.linterAstAdapter.isLanguageSupported(language)) {
3709
+ this.logger.warn("Unsupported language for AST execution", {
3710
+ language,
3711
+ filePath
3712
+ });
3713
+ } else {
3714
+ let ast;
3715
+ try {
3716
+ ast = await this.linterAstAdapter.parseSourceCode(
3717
+ fileContent,
3718
+ language
3719
+ );
3720
+ const astViolations = astPrograms.flatMap(
3721
+ (program) => this.executeAstProgram(program, ast)
3722
+ );
3723
+ violations.push(...astViolations);
3724
+ } catch (error) {
3725
+ this.logger.error("Failed to parse source code for AST execution", {
3726
+ language,
3727
+ filePath,
3728
+ error: this.normalizeError(error)
3729
+ });
3730
+ }
3731
+ }
3732
+ }
3733
+ }
3734
+ extractAndExecutePrograms(programs, fileContent, violations) {
3735
+ const rawPrograms = programs.filter((p) => p.sourceCodeState === "RAW");
3736
+ if (rawPrograms.length > 0) {
3737
+ const rawViolations = rawPrograms.flatMap(
3738
+ (program) => this.executeRawProgram(program, fileContent)
3739
+ );
3740
+ violations.push(...rawViolations);
3741
+ }
3742
+ }
3743
+ executeRawProgram(program, fileContent) {
3744
+ const ruleName = this.extractRuleName(program.ruleContent);
3745
+ try {
3746
+ const checkSourceCode = this.createProgramFunction(program.code);
3747
+ const rawResult = checkSourceCode(fileContent);
3748
+ return this.mapProgramResult(rawResult, ruleName, program);
3749
+ } catch (error) {
3750
+ this.logger.error("Failed to execute detection program", {
3751
+ standardSlug: program.standardSlug,
3752
+ ruleContent: program.ruleContent,
3753
+ error: this.normalizeError(error)
3754
+ });
3755
+ return [];
3756
+ }
3757
+ }
3758
+ executeAstProgram(program, ast) {
3759
+ const ruleName = this.extractRuleName(program.ruleContent);
3760
+ try {
3761
+ const checkSourceCode = this.createProgramFunction(program.code);
3762
+ const rawResult = checkSourceCode(ast);
3763
+ return this.mapProgramResult(rawResult, ruleName, program);
3764
+ } catch (error) {
3765
+ this.logger.error("Failed to execute detection program", {
3766
+ standardSlug: program.standardSlug,
3767
+ ruleContent: program.ruleContent,
3768
+ error: this.normalizeError(error)
3769
+ });
3770
+ return [];
3771
+ }
3772
+ }
3773
+ createProgramFunction(program) {
3774
+ try {
3775
+ const func = new Function(
3776
+ "input",
3777
+ `
3778
+ ${program}
3779
+ return checkSourceCode(input);
3780
+ `
3781
+ );
3782
+ return func;
3783
+ } catch (error) {
3784
+ throw new Error(`Failed to parse program: ${this.normalizeError(error)}`);
3785
+ }
3786
+ }
3787
+ mapProgramResult(rawResult, ruleName, program) {
3788
+ if (!Array.isArray(rawResult)) {
3789
+ this.logger.warn("Program result is not an array", {
3790
+ standardSlug: program.standardSlug,
3791
+ ruleContent: program.ruleContent
3792
+ });
3793
+ return [];
3794
+ }
3795
+ return rawResult.map((value) => this.toViolation(value, ruleName, program)).filter(
3796
+ (violation) => violation !== null
3797
+ );
3798
+ }
3799
+ toViolation(value, ruleName, program) {
3800
+ let line;
3801
+ let character = 0;
3802
+ if (typeof value === "number" && Number.isFinite(value)) {
3803
+ line = value;
3804
+ } else if (this.isViolationLike(value)) {
3805
+ line = value.line;
3806
+ character = value.character ?? 0;
3807
+ }
3808
+ if (!this.isValidLine(line)) {
3809
+ this.logger.warn("Invalid violation line detected", {
3810
+ standardSlug: program.standardSlug,
3811
+ ruleContent: program.ruleContent,
3812
+ line
3813
+ });
3814
+ return null;
3815
+ }
3816
+ return {
3817
+ line,
3818
+ character,
3819
+ rule: ruleName,
3820
+ standard: program.standardSlug
3821
+ };
3822
+ }
3823
+ isViolationLike(value) {
3824
+ return typeof value === "object" && value !== null && "line" in value && typeof value.line === "number";
3825
+ }
3826
+ isValidLine(line) {
3827
+ return typeof line === "number" && Number.isInteger(line) && line >= 0;
3828
+ }
3829
+ extractRuleName(ruleContent) {
3830
+ if (!ruleContent.includes("/")) {
3831
+ return ruleContent;
3832
+ }
3833
+ return ruleContent.split("/").pop()?.replace(".js", "") ?? ruleContent;
3834
+ }
3835
+ filterProgramsByLanguage(programs, fileLanguage) {
3836
+ const filtered = programs.filter((p) => p.language === fileLanguage);
3837
+ if (filtered.length < programs.length) {
3838
+ this.logger.debug("Filtered out programs with mismatched languages", {
3839
+ totalPrograms: programs.length,
3840
+ matchingPrograms: filtered.length,
3841
+ fileLanguage
3842
+ });
3843
+ }
3844
+ return filtered;
3845
+ }
3846
+ normalizeError(error) {
3847
+ if (error instanceof Error) {
3848
+ return error.message;
3849
+ }
3850
+ if (typeof error === "string") {
3851
+ return error;
3852
+ }
3853
+ if (error && typeof error === "object") {
3854
+ if ("message" in error && typeof error.message === "string") {
3855
+ return error.message;
3856
+ }
3857
+ try {
3858
+ return JSON.stringify(error);
3859
+ } catch {
3860
+ return "[object Object]";
3861
+ }
3862
+ }
3863
+ return String(error);
3864
+ }
3865
+ };
3866
+
3867
+ // apps/cli/src/PackmindCliHexaFactory.ts
3868
+ var PackmindCliHexaFactory = class {
3869
+ constructor(logger) {
3870
+ this.logger = logger;
3871
+ this.repositories = {
3872
+ packmindGateway: new PackmindGateway(
3873
+ process.env.PACKMIND_API_KEY_V3 || ""
3874
+ )
3875
+ };
3876
+ this.services = {
3877
+ listFiles: new ListFiles(),
3878
+ gitRemoteUrlService: new GitService(this.logger),
3879
+ linterExecutionUseCase: new ExecuteLinterProgramsUseCase()
3880
+ };
3881
+ this.useCases = {
3882
+ executeSingleFileAst: new ExecuteSingleFileAstUseCase(
3883
+ this.services.linterExecutionUseCase
3884
+ ),
3885
+ getGitRemoteUrl: new GetGitRemoteUrlUseCase(),
3886
+ listFilesInDirectoryUseCase: new ListFilesInDirectoryUseCase(),
3887
+ lintFilesInDirectory: new LintFilesInDirectoryUseCase(
3888
+ this.services,
3889
+ this.repositories,
3890
+ this.logger
3891
+ )
3892
+ };
3893
+ }
3894
+ };
3895
+
3896
+ // apps/cli/src/PackmindCliHexa.ts
3897
+ var origin9 = "PackmindCliHexa";
3898
+ var PackmindCliHexa = class {
3899
+ constructor(logger = new PackmindLogger(origin9)) {
3900
+ this.logger = logger;
3901
+ try {
3902
+ this.hexa = new PackmindCliHexaFactory(this.logger);
3903
+ } catch (error) {
3904
+ this.logger.error("Failed to initialize PackmindCliHexa", {
3905
+ error: error instanceof Error ? error.message : String(error)
3906
+ });
3907
+ throw error;
3908
+ }
3909
+ }
3910
+ /**
3911
+ * Destroys the DeploymentsHexa and cleans up resources
3912
+ */
3913
+ destroy() {
3914
+ this.logger.info("Destroying PackmindCliHexa");
3915
+ this.logger.info("PackmindCliHexa destroyed");
3916
+ }
3917
+ async getGitRemoteUrl(command2) {
3918
+ return this.hexa.useCases.getGitRemoteUrl.execute(command2);
3919
+ }
3920
+ async executeSingleFileAst(command2) {
3921
+ return this.hexa.useCases.executeSingleFileAst.execute(command2);
3922
+ }
3923
+ async listFilesInDirectory(command2) {
3924
+ return this.hexa.useCases.listFilesInDirectoryUseCase.execute(command2);
3925
+ }
3926
+ async lintFilesInDirectory(command2) {
3927
+ return this.hexa.useCases.lintFilesInDirectory.execute(command2);
3928
+ }
3929
+ };
3930
+
3931
+ // apps/cli/src/infra/repositories/IDELintLogger.ts
3932
+ var IDELintLogger = class {
3933
+ logViolations(violations) {
3934
+ violations.forEach((violation) => {
3935
+ this.logViolation(violation);
3936
+ });
3937
+ }
3938
+ logViolation(violation) {
3939
+ violation.violations.forEach(({ line, character, standard, rule }) => {
3940
+ console.log(
3941
+ `${violation.file}:${line}:${character}:error:@${standard}/${rule}`
3942
+ );
3943
+ });
3944
+ }
3945
+ };
3946
+
3947
+ // apps/cli/src/infra/repositories/HumanReadableLogger.ts
3948
+ var import_chalk = __toESM(require("chalk"));
3949
+ var HumanReadableLogger = class {
3950
+ logViolations(violations) {
3951
+ violations.forEach((violation) => {
3952
+ this.logViolation(violation);
3953
+ });
3954
+ if (violations.length > 0) {
3955
+ const totalViolationCount = violations.reduce(
3956
+ (acc, violation) => acc + violation.violations.length,
3957
+ 0
3958
+ );
3959
+ console.log(
3960
+ import_chalk.default.bgRed.bold("packmind-cli"),
3961
+ import_chalk.default.red(
3962
+ `\u274C Found ${import_chalk.default.bold(totalViolationCount)} violation(s) in ${import_chalk.default.bold(violations.length)} file(s)`
3963
+ )
3964
+ );
3965
+ } else {
3966
+ console.log(
3967
+ import_chalk.default.bgGreen.bold("packmind-cli"),
3968
+ import_chalk.default.green.bold(`\u2705 No violations found`)
3969
+ );
3970
+ }
3971
+ }
3972
+ logViolation(violation) {
3973
+ console.log(import_chalk.default.underline.gray(violation.file));
3974
+ violation.violations.forEach(({ line, character, standard, rule }) => {
3975
+ console.log(
3976
+ import_chalk.default.red(` ${line}:${character} error @${standard}/${rule}`)
3977
+ );
3978
+ });
3979
+ }
3980
+ };
3981
+
3982
+ // apps/cli/src/infra/commands/LinterCommand.ts
3983
+ var Logger = {
3984
+ from: async (input) => {
3985
+ switch (input) {
3986
+ case "ide":
3987
+ return "ide" /* ide */;
3988
+ case "human":
3989
+ return "human" /* human */;
3990
+ }
3991
+ throw new Error(
3992
+ `${input} is not a valid value for the --logger option. Expected values are: ide, human`
3993
+ );
3994
+ }
3995
+ };
3996
+ var RuleID = {
3997
+ from: async (input) => {
3998
+ const match = input.match(/^@([^/]+)\/(.+)$/);
3999
+ if (!match) {
4000
+ throw new Error(
4001
+ "Error: Invalid --rule format. Expected format: @standard-slug/ruleId"
4002
+ );
4003
+ }
4004
+ return {
4005
+ standardSlug: match[1],
4006
+ ruleId: createRuleId(match[2])
4007
+ };
4008
+ }
4009
+ };
4010
+ var lintCommand = (0, import_cmd_ts.command)({
4011
+ name: "lint",
4012
+ description: "Lint code at the specified path",
4013
+ args: {
4014
+ path: (0, import_cmd_ts.positional)({
4015
+ displayName: "path",
4016
+ description: "Path to lint (e.g., . for current directory)",
4017
+ type: import_cmd_ts.string
4018
+ }),
4019
+ logger: (0, import_cmd_ts.option)({
4020
+ long: "logger",
4021
+ description: "Output format (ide | human). Default is human",
4022
+ type: Logger,
4023
+ defaultValue: () => "human" /* human */,
4024
+ defaultValueIsSerializable: true
4025
+ }),
4026
+ rule: (0, import_cmd_ts.option)({
4027
+ long: "rule",
4028
+ description: "Specify rule in format @standard-slug/ruleId (runs active programs without --draft)",
4029
+ type: (0, import_cmd_ts.optional)(RuleID)
4030
+ }),
4031
+ language: (0, import_cmd_ts.option)({
4032
+ long: "language",
4033
+ description: "Filter detection programs by language",
4034
+ type: (0, import_cmd_ts.optional)(import_cmd_ts.string)
4035
+ }),
4036
+ draft: (0, import_cmd_ts.flag)({
4037
+ long: "draft",
4038
+ description: "Use draft detection programs (requires --rule)"
4039
+ }),
4040
+ debug: (0, import_cmd_ts.flag)({
4041
+ long: "debug",
4042
+ description: "Enable debug logging"
4043
+ })
4044
+ },
4045
+ handler: async ({ path: path2, draft, rule, debug, language, logger }) => {
4046
+ if (draft && !rule) {
4047
+ throw new Error("option --rule is required to use --draft mode");
4048
+ }
4049
+ const startedAt = Date.now();
4050
+ const packmindLogger = new PackmindLogger(
4051
+ "PackmindCLI",
4052
+ debug ? "debug" /* DEBUG */ : "info" /* INFO */
4053
+ );
4054
+ const packmindCliHexa = new PackmindCliHexa(packmindLogger);
4055
+ const { violations } = await packmindCliHexa.lintFilesInDirectory({
4056
+ path: path2,
4057
+ draftMode: draft,
4058
+ standardSlug: rule?.standardSlug,
4059
+ ruleId: rule?.ruleId,
4060
+ language
4061
+ });
4062
+ (logger === "ide" /* ide */ ? new IDELintLogger() : new HumanReadableLogger()).logViolations(violations);
4063
+ const durationSeconds = (Date.now() - startedAt) / 1e3;
4064
+ console.log(`Lint completed in ${durationSeconds.toFixed(2)}s`);
4065
+ if (violations.length > 0) {
4066
+ process.exit(1);
4067
+ } else {
4068
+ process.exit(0);
4069
+ }
4070
+ }
4071
+ });
4072
+
4073
+ // apps/cli/src/main.ts
4074
+ var app = (0, import_cmd_ts2.subcommands)({
4075
+ name: "packmind-cli",
4076
+ description: "Packmind CLI tool",
4077
+ cmds: {
4078
+ lint: lintCommand
4079
+ }
4080
+ });
4081
+ (0, import_cmd_ts2.run)(app, process.argv.slice(2)).catch((error) => {
4082
+ console.error(import_chalk2.default.bgRed.bold("packmind-cli"), import_chalk2.default.red(error.message));
4083
+ process.exit(1);
4084
+ });