@rigour-labs/core 1.0.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,112 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Fix Packet v2 Schema
4
+ * Designed for high-fidelity communication with AI agents during the refinement loop.
5
+ */
6
+ export declare const FixPacketV2Schema: z.ZodObject<{
7
+ version: z.ZodLiteral<2>;
8
+ goal: z.ZodDefault<z.ZodString>;
9
+ violations: z.ZodArray<z.ZodObject<{
10
+ id: z.ZodString;
11
+ gate: z.ZodString;
12
+ severity: z.ZodDefault<z.ZodEnum<["low", "medium", "high", "critical"]>>;
13
+ category: z.ZodOptional<z.ZodString>;
14
+ title: z.ZodString;
15
+ details: z.ZodString;
16
+ files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
17
+ hint: z.ZodOptional<z.ZodString>;
18
+ instructions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
19
+ metrics: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
20
+ }, "strip", z.ZodTypeAny, {
21
+ id: string;
22
+ title: string;
23
+ details: string;
24
+ gate: string;
25
+ severity: "low" | "medium" | "high" | "critical";
26
+ files?: string[] | undefined;
27
+ hint?: string | undefined;
28
+ category?: string | undefined;
29
+ instructions?: string[] | undefined;
30
+ metrics?: Record<string, any> | undefined;
31
+ }, {
32
+ id: string;
33
+ title: string;
34
+ details: string;
35
+ gate: string;
36
+ files?: string[] | undefined;
37
+ hint?: string | undefined;
38
+ severity?: "low" | "medium" | "high" | "critical" | undefined;
39
+ category?: string | undefined;
40
+ instructions?: string[] | undefined;
41
+ metrics?: Record<string, any> | undefined;
42
+ }>, "many">;
43
+ constraints: z.ZodDefault<z.ZodOptional<z.ZodObject<{
44
+ protected_paths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
45
+ do_not_touch: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
46
+ max_files_changed: z.ZodOptional<z.ZodNumber>;
47
+ no_new_deps: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
48
+ allowed_dependencies: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
49
+ paradigm: z.ZodOptional<z.ZodString>;
50
+ }, "strip", z.ZodTypeAny, {
51
+ no_new_deps: boolean;
52
+ protected_paths?: string[] | undefined;
53
+ paradigm?: string | undefined;
54
+ do_not_touch?: string[] | undefined;
55
+ max_files_changed?: number | undefined;
56
+ allowed_dependencies?: string[] | undefined;
57
+ }, {
58
+ protected_paths?: string[] | undefined;
59
+ paradigm?: string | undefined;
60
+ do_not_touch?: string[] | undefined;
61
+ max_files_changed?: number | undefined;
62
+ no_new_deps?: boolean | undefined;
63
+ allowed_dependencies?: string[] | undefined;
64
+ }>>>;
65
+ }, "strip", z.ZodTypeAny, {
66
+ version: 2;
67
+ goal: string;
68
+ violations: {
69
+ id: string;
70
+ title: string;
71
+ details: string;
72
+ gate: string;
73
+ severity: "low" | "medium" | "high" | "critical";
74
+ files?: string[] | undefined;
75
+ hint?: string | undefined;
76
+ category?: string | undefined;
77
+ instructions?: string[] | undefined;
78
+ metrics?: Record<string, any> | undefined;
79
+ }[];
80
+ constraints: {
81
+ no_new_deps: boolean;
82
+ protected_paths?: string[] | undefined;
83
+ paradigm?: string | undefined;
84
+ do_not_touch?: string[] | undefined;
85
+ max_files_changed?: number | undefined;
86
+ allowed_dependencies?: string[] | undefined;
87
+ };
88
+ }, {
89
+ version: 2;
90
+ violations: {
91
+ id: string;
92
+ title: string;
93
+ details: string;
94
+ gate: string;
95
+ files?: string[] | undefined;
96
+ hint?: string | undefined;
97
+ severity?: "low" | "medium" | "high" | "critical" | undefined;
98
+ category?: string | undefined;
99
+ instructions?: string[] | undefined;
100
+ metrics?: Record<string, any> | undefined;
101
+ }[];
102
+ goal?: string | undefined;
103
+ constraints?: {
104
+ protected_paths?: string[] | undefined;
105
+ paradigm?: string | undefined;
106
+ do_not_touch?: string[] | undefined;
107
+ max_files_changed?: number | undefined;
108
+ no_new_deps?: boolean | undefined;
109
+ allowed_dependencies?: string[] | undefined;
110
+ } | undefined;
111
+ }>;
112
+ export type FixPacketV2 = z.infer<typeof FixPacketV2Schema>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FixPacketV2Schema = void 0;
4
+ const zod_1 = require("zod");
5
+ /**
6
+ * Fix Packet v2 Schema
7
+ * Designed for high-fidelity communication with AI agents during the refinement loop.
8
+ */
9
+ exports.FixPacketV2Schema = zod_1.z.object({
10
+ version: zod_1.z.literal(2),
11
+ goal: zod_1.z.string().default('Achieve PASS state for all quality gates'),
12
+ violations: zod_1.z.array(zod_1.z.object({
13
+ id: zod_1.z.string(),
14
+ gate: zod_1.z.string(),
15
+ severity: zod_1.z.enum(['low', 'medium', 'high', 'critical']).default('medium'),
16
+ category: zod_1.z.string().optional(),
17
+ title: zod_1.z.string(),
18
+ details: zod_1.z.string(),
19
+ files: zod_1.z.array(zod_1.z.string()).optional(),
20
+ hint: zod_1.z.string().optional(),
21
+ instructions: zod_1.z.array(zod_1.z.string()).optional(), // Step-by-step fix instructions
22
+ metrics: zod_1.z.record(zod_1.z.any()).optional(), // e.g., { complexity: 15, max: 10 }
23
+ })),
24
+ constraints: zod_1.z.object({
25
+ protected_paths: zod_1.z.array(zod_1.z.string()).optional(),
26
+ do_not_touch: zod_1.z.array(zod_1.z.string()).optional(), // Alias for protected_paths
27
+ max_files_changed: zod_1.z.number().optional(),
28
+ no_new_deps: zod_1.z.boolean().optional().default(true),
29
+ allowed_dependencies: zod_1.z.array(zod_1.z.string()).optional(),
30
+ paradigm: zod_1.z.string().optional(), // 'oop', 'functional'
31
+ }).optional().default({}),
32
+ });
@@ -5,18 +5,118 @@ export declare const GatesSchema: z.ZodObject<{
5
5
  forbid_fixme: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
6
6
  forbid_paths: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
7
7
  required_files: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
8
+ ast: z.ZodDefault<z.ZodOptional<z.ZodObject<{
9
+ complexity: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
10
+ max_methods: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
11
+ max_params: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
12
+ }, "strip", z.ZodTypeAny, {
13
+ complexity: number;
14
+ max_methods: number;
15
+ max_params: number;
16
+ }, {
17
+ complexity?: number | undefined;
18
+ max_methods?: number | undefined;
19
+ max_params?: number | undefined;
20
+ }>>>;
21
+ dependencies: z.ZodDefault<z.ZodOptional<z.ZodObject<{
22
+ forbid: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
23
+ trusted_registry: z.ZodOptional<z.ZodString>;
24
+ }, "strip", z.ZodTypeAny, {
25
+ forbid: string[];
26
+ trusted_registry?: string | undefined;
27
+ }, {
28
+ forbid?: string[] | undefined;
29
+ trusted_registry?: string | undefined;
30
+ }>>>;
31
+ architecture: z.ZodDefault<z.ZodOptional<z.ZodObject<{
32
+ boundaries: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
33
+ from: z.ZodString;
34
+ to: z.ZodString;
35
+ mode: z.ZodDefault<z.ZodEnum<["allow", "deny"]>>;
36
+ }, "strip", z.ZodTypeAny, {
37
+ from: string;
38
+ to: string;
39
+ mode: "allow" | "deny";
40
+ }, {
41
+ from: string;
42
+ to: string;
43
+ mode?: "allow" | "deny" | undefined;
44
+ }>, "many">>>;
45
+ }, "strip", z.ZodTypeAny, {
46
+ boundaries: {
47
+ from: string;
48
+ to: string;
49
+ mode: "allow" | "deny";
50
+ }[];
51
+ }, {
52
+ boundaries?: {
53
+ from: string;
54
+ to: string;
55
+ mode?: "allow" | "deny" | undefined;
56
+ }[] | undefined;
57
+ }>>>;
58
+ safety: z.ZodDefault<z.ZodOptional<z.ZodObject<{
59
+ max_files_changed_per_cycle: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
60
+ protected_paths: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
61
+ }, "strip", z.ZodTypeAny, {
62
+ max_files_changed_per_cycle: number;
63
+ protected_paths: string[];
64
+ }, {
65
+ max_files_changed_per_cycle?: number | undefined;
66
+ protected_paths?: string[] | undefined;
67
+ }>>>;
8
68
  }, "strip", z.ZodTypeAny, {
9
69
  max_file_lines: number;
10
70
  forbid_todos: boolean;
11
71
  forbid_fixme: boolean;
12
72
  forbid_paths: string[];
13
73
  required_files: string[];
74
+ ast: {
75
+ complexity: number;
76
+ max_methods: number;
77
+ max_params: number;
78
+ };
79
+ dependencies: {
80
+ forbid: string[];
81
+ trusted_registry?: string | undefined;
82
+ };
83
+ architecture: {
84
+ boundaries: {
85
+ from: string;
86
+ to: string;
87
+ mode: "allow" | "deny";
88
+ }[];
89
+ };
90
+ safety: {
91
+ max_files_changed_per_cycle: number;
92
+ protected_paths: string[];
93
+ };
14
94
  }, {
15
95
  max_file_lines?: number | undefined;
16
96
  forbid_todos?: boolean | undefined;
17
97
  forbid_fixme?: boolean | undefined;
18
98
  forbid_paths?: string[] | undefined;
19
99
  required_files?: string[] | undefined;
100
+ ast?: {
101
+ complexity?: number | undefined;
102
+ max_methods?: number | undefined;
103
+ max_params?: number | undefined;
104
+ } | undefined;
105
+ dependencies?: {
106
+ forbid?: string[] | undefined;
107
+ trusted_registry?: string | undefined;
108
+ } | undefined;
109
+ architecture?: {
110
+ boundaries?: {
111
+ from: string;
112
+ to: string;
113
+ mode?: "allow" | "deny" | undefined;
114
+ }[] | undefined;
115
+ } | undefined;
116
+ safety?: {
117
+ max_files_changed_per_cycle?: number | undefined;
118
+ protected_paths?: string[] | undefined;
119
+ } | undefined;
20
120
  }>;
21
121
  export declare const CommandsSchema: z.ZodObject<{
22
122
  format: z.ZodOptional<z.ZodString>;
@@ -36,6 +136,8 @@ export declare const CommandsSchema: z.ZodObject<{
36
136
  }>;
37
137
  export declare const ConfigSchema: z.ZodObject<{
38
138
  version: z.ZodDefault<z.ZodNumber>;
139
+ preset: z.ZodOptional<z.ZodString>;
140
+ paradigm: z.ZodOptional<z.ZodString>;
39
141
  commands: z.ZodDefault<z.ZodOptional<z.ZodObject<{
40
142
  format: z.ZodOptional<z.ZodString>;
41
143
  lint: z.ZodOptional<z.ZodString>;
@@ -58,18 +160,118 @@ export declare const ConfigSchema: z.ZodObject<{
58
160
  forbid_fixme: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
59
161
  forbid_paths: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
60
162
  required_files: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
163
+ ast: z.ZodDefault<z.ZodOptional<z.ZodObject<{
164
+ complexity: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
165
+ max_methods: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
166
+ max_params: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
167
+ }, "strip", z.ZodTypeAny, {
168
+ complexity: number;
169
+ max_methods: number;
170
+ max_params: number;
171
+ }, {
172
+ complexity?: number | undefined;
173
+ max_methods?: number | undefined;
174
+ max_params?: number | undefined;
175
+ }>>>;
176
+ dependencies: z.ZodDefault<z.ZodOptional<z.ZodObject<{
177
+ forbid: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
178
+ trusted_registry: z.ZodOptional<z.ZodString>;
179
+ }, "strip", z.ZodTypeAny, {
180
+ forbid: string[];
181
+ trusted_registry?: string | undefined;
182
+ }, {
183
+ forbid?: string[] | undefined;
184
+ trusted_registry?: string | undefined;
185
+ }>>>;
186
+ architecture: z.ZodDefault<z.ZodOptional<z.ZodObject<{
187
+ boundaries: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodObject<{
188
+ from: z.ZodString;
189
+ to: z.ZodString;
190
+ mode: z.ZodDefault<z.ZodEnum<["allow", "deny"]>>;
191
+ }, "strip", z.ZodTypeAny, {
192
+ from: string;
193
+ to: string;
194
+ mode: "allow" | "deny";
195
+ }, {
196
+ from: string;
197
+ to: string;
198
+ mode?: "allow" | "deny" | undefined;
199
+ }>, "many">>>;
200
+ }, "strip", z.ZodTypeAny, {
201
+ boundaries: {
202
+ from: string;
203
+ to: string;
204
+ mode: "allow" | "deny";
205
+ }[];
206
+ }, {
207
+ boundaries?: {
208
+ from: string;
209
+ to: string;
210
+ mode?: "allow" | "deny" | undefined;
211
+ }[] | undefined;
212
+ }>>>;
213
+ safety: z.ZodDefault<z.ZodOptional<z.ZodObject<{
214
+ max_files_changed_per_cycle: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
215
+ protected_paths: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
216
+ }, "strip", z.ZodTypeAny, {
217
+ max_files_changed_per_cycle: number;
218
+ protected_paths: string[];
219
+ }, {
220
+ max_files_changed_per_cycle?: number | undefined;
221
+ protected_paths?: string[] | undefined;
222
+ }>>>;
61
223
  }, "strip", z.ZodTypeAny, {
62
224
  max_file_lines: number;
63
225
  forbid_todos: boolean;
64
226
  forbid_fixme: boolean;
65
227
  forbid_paths: string[];
66
228
  required_files: string[];
229
+ ast: {
230
+ complexity: number;
231
+ max_methods: number;
232
+ max_params: number;
233
+ };
234
+ dependencies: {
235
+ forbid: string[];
236
+ trusted_registry?: string | undefined;
237
+ };
238
+ architecture: {
239
+ boundaries: {
240
+ from: string;
241
+ to: string;
242
+ mode: "allow" | "deny";
243
+ }[];
244
+ };
245
+ safety: {
246
+ max_files_changed_per_cycle: number;
247
+ protected_paths: string[];
248
+ };
67
249
  }, {
68
250
  max_file_lines?: number | undefined;
69
251
  forbid_todos?: boolean | undefined;
70
252
  forbid_fixme?: boolean | undefined;
71
253
  forbid_paths?: string[] | undefined;
72
254
  required_files?: string[] | undefined;
255
+ ast?: {
256
+ complexity?: number | undefined;
257
+ max_methods?: number | undefined;
258
+ max_params?: number | undefined;
259
+ } | undefined;
260
+ dependencies?: {
261
+ forbid?: string[] | undefined;
262
+ trusted_registry?: string | undefined;
263
+ } | undefined;
264
+ architecture?: {
265
+ boundaries?: {
266
+ from: string;
267
+ to: string;
268
+ mode?: "allow" | "deny" | undefined;
269
+ }[] | undefined;
270
+ } | undefined;
271
+ safety?: {
272
+ max_files_changed_per_cycle?: number | undefined;
273
+ protected_paths?: string[] | undefined;
274
+ } | undefined;
73
275
  }>>>;
74
276
  output: z.ZodDefault<z.ZodOptional<z.ZodObject<{
75
277
  report_path: z.ZodDefault<z.ZodString>;
@@ -78,6 +280,7 @@ export declare const ConfigSchema: z.ZodObject<{
78
280
  }, {
79
281
  report_path?: string | undefined;
80
282
  }>>>;
283
+ planned: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
81
284
  }, "strip", z.ZodTypeAny, {
82
285
  version: number;
83
286
  commands: {
@@ -92,12 +295,37 @@ export declare const ConfigSchema: z.ZodObject<{
92
295
  forbid_fixme: boolean;
93
296
  forbid_paths: string[];
94
297
  required_files: string[];
298
+ ast: {
299
+ complexity: number;
300
+ max_methods: number;
301
+ max_params: number;
302
+ };
303
+ dependencies: {
304
+ forbid: string[];
305
+ trusted_registry?: string | undefined;
306
+ };
307
+ architecture: {
308
+ boundaries: {
309
+ from: string;
310
+ to: string;
311
+ mode: "allow" | "deny";
312
+ }[];
313
+ };
314
+ safety: {
315
+ max_files_changed_per_cycle: number;
316
+ protected_paths: string[];
317
+ };
95
318
  };
96
319
  output: {
97
320
  report_path: string;
98
321
  };
322
+ planned: string[];
323
+ preset?: string | undefined;
324
+ paradigm?: string | undefined;
99
325
  }, {
100
326
  version?: number | undefined;
327
+ preset?: string | undefined;
328
+ paradigm?: string | undefined;
101
329
  commands?: {
102
330
  format?: string | undefined;
103
331
  lint?: string | undefined;
@@ -110,10 +338,31 @@ export declare const ConfigSchema: z.ZodObject<{
110
338
  forbid_fixme?: boolean | undefined;
111
339
  forbid_paths?: string[] | undefined;
112
340
  required_files?: string[] | undefined;
341
+ ast?: {
342
+ complexity?: number | undefined;
343
+ max_methods?: number | undefined;
344
+ max_params?: number | undefined;
345
+ } | undefined;
346
+ dependencies?: {
347
+ forbid?: string[] | undefined;
348
+ trusted_registry?: string | undefined;
349
+ } | undefined;
350
+ architecture?: {
351
+ boundaries?: {
352
+ from: string;
353
+ to: string;
354
+ mode?: "allow" | "deny" | undefined;
355
+ }[] | undefined;
356
+ } | undefined;
357
+ safety?: {
358
+ max_files_changed_per_cycle?: number | undefined;
359
+ protected_paths?: string[] | undefined;
360
+ } | undefined;
113
361
  } | undefined;
114
362
  output?: {
115
363
  report_path?: string | undefined;
116
364
  } | undefined;
365
+ planned?: string[] | undefined;
117
366
  }>;
118
367
  export type Gates = z.infer<typeof GatesSchema>;
119
368
  export type Commands = z.infer<typeof CommandsSchema>;
@@ -13,6 +13,26 @@ exports.GatesSchema = zod_1.z.object({
13
13
  'docs/DECISIONS.md',
14
14
  'docs/TASKS.md',
15
15
  ]),
16
+ ast: zod_1.z.object({
17
+ complexity: zod_1.z.number().optional().default(10),
18
+ max_methods: zod_1.z.number().optional().default(10),
19
+ max_params: zod_1.z.number().optional().default(5),
20
+ }).optional().default({}),
21
+ dependencies: zod_1.z.object({
22
+ forbid: zod_1.z.array(zod_1.z.string()).optional().default([]),
23
+ trusted_registry: zod_1.z.string().optional(),
24
+ }).optional().default({}),
25
+ architecture: zod_1.z.object({
26
+ boundaries: zod_1.z.array(zod_1.z.object({
27
+ from: zod_1.z.string(),
28
+ to: zod_1.z.string(),
29
+ mode: zod_1.z.enum(['allow', 'deny']).default('deny'),
30
+ })).optional().default([]),
31
+ }).optional().default({}),
32
+ safety: zod_1.z.object({
33
+ max_files_changed_per_cycle: zod_1.z.number().optional().default(10),
34
+ protected_paths: zod_1.z.array(zod_1.z.string()).optional().default(['.github/**', 'docs/**', 'rigour.yml']),
35
+ }).optional().default({}),
16
36
  });
17
37
  exports.CommandsSchema = zod_1.z.object({
18
38
  format: zod_1.z.string().optional(),
@@ -22,11 +42,14 @@ exports.CommandsSchema = zod_1.z.object({
22
42
  });
23
43
  exports.ConfigSchema = zod_1.z.object({
24
44
  version: zod_1.z.number().default(1),
45
+ preset: zod_1.z.string().optional(),
46
+ paradigm: zod_1.z.string().optional(),
25
47
  commands: exports.CommandsSchema.optional().default({}),
26
48
  gates: exports.GatesSchema.optional().default({}),
27
49
  output: zod_1.z.object({
28
50
  report_path: zod_1.z.string().default('rigour-report.json'),
29
51
  }).optional().default({}),
52
+ planned: zod_1.z.array(zod_1.z.string()).optional().default([]),
30
53
  });
31
54
  exports.StatusSchema = zod_1.z.enum(['PASS', 'FAIL', 'SKIP', 'ERROR']);
32
55
  exports.FailureSchema = zod_1.z.object({
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@rigour-labs/core",
3
- "version": "1.0.0",
3
+ "version": "1.4.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/erashu212/rigour"
8
+ "url": "https://github.com/rigour-labs/rigour"
9
9
  },
10
10
  "publishConfig": {
11
11
  "access": "public",
@@ -16,11 +16,14 @@
16
16
  "execa": "^8.0.1",
17
17
  "fs-extra": "^11.3.3",
18
18
  "globby": "^14.1.0",
19
+ "micromatch": "^4.0.8",
20
+ "typescript": "^5.9.3",
19
21
  "yaml": "^2.3.4",
20
22
  "zod": "^3.22.4"
21
23
  },
22
24
  "devDependencies": {
23
25
  "@types/fs-extra": "^11.0.4",
26
+ "@types/micromatch": "^4.0.10",
24
27
  "@types/node": "^25.0.3"
25
28
  },
26
29
  "scripts": {
package/src/discovery.ts CHANGED
@@ -1,30 +1,94 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import { Config } from './types/index.js';
4
- import { TEMPLATES, UNIVERSAL_CONFIG } from './templates/index.js';
4
+ import { TEMPLATES, PARADIGM_TEMPLATES, UNIVERSAL_CONFIG } from './templates/index.js';
5
+
6
+ export interface DiscoveryResult {
7
+ config: Config;
8
+ matches: {
9
+ preset?: { name: string; marker: string };
10
+ paradigm?: { name: string; marker: string };
11
+ };
12
+ }
5
13
 
6
14
  export class DiscoveryService {
7
- async discover(cwd: string): Promise<Config> {
8
- const config = { ...UNIVERSAL_CONFIG };
15
+ async discover(cwd: string): Promise<DiscoveryResult> {
16
+ let config = { ...UNIVERSAL_CONFIG };
17
+ const matches: DiscoveryResult['matches'] = {};
9
18
 
19
+ // 1. Detect Role (ui, api, infra, data)
10
20
  for (const template of TEMPLATES) {
11
- const match = await this.hasAnyMarker(cwd, template.markers);
12
- if (match) {
13
- // Merge template config
14
- config.commands = { ...config.commands, ...template.config.commands };
15
- config.gates = { ...config.gates, ...template.config.gates };
21
+ const marker = await this.findFirstMarker(cwd, template.markers, true); // Search content for roles too
22
+ if (marker) {
23
+ config = this.mergeConfig(config, template.config);
24
+ matches.preset = { name: template.name, marker };
25
+ break; // Only one role for now
26
+ }
27
+ }
28
+
29
+ // 2. Detect Paradigm (oop, functional)
30
+ for (const template of PARADIGM_TEMPLATES) {
31
+ const marker = await this.findFirstMarker(cwd, template.markers, true); // Search content
32
+ if (marker) {
33
+ config = this.mergeConfig(config, template.config);
34
+ matches.paradigm = { name: template.name, marker };
35
+ break;
16
36
  }
17
37
  }
18
38
 
19
- return config;
39
+ return { config, matches };
20
40
  }
21
41
 
22
- private async hasAnyMarker(cwd: string, markers: string[]): Promise<boolean> {
42
+ private mergeConfig(base: Config, extension: any): Config {
43
+ return {
44
+ ...base,
45
+ preset: extension.preset || base.preset,
46
+ paradigm: extension.paradigm || base.paradigm,
47
+ commands: { ...base.commands, ...extension.commands },
48
+ gates: { ...base.gates, ...extension.gates },
49
+ };
50
+ }
51
+
52
+ private async findFirstMarker(cwd: string, markers: string[], searchContent: boolean = false): Promise<string | null> {
23
53
  for (const marker of markers) {
24
- if (await fs.pathExists(path.join(cwd, marker))) {
25
- return true;
54
+ const fullPath = path.join(cwd, marker);
55
+
56
+ // File/Directory existence check
57
+ if (await fs.pathExists(fullPath)) {
58
+ return marker;
59
+ }
60
+
61
+ // Deep content check for paradigms
62
+ if (searchContent) {
63
+ const match = await this.existsInContent(cwd, marker);
64
+ if (match) return `content:${marker}`;
26
65
  }
27
66
  }
67
+ return null;
68
+ }
69
+
70
+ private async existsInContent(cwd: string, pattern: string): Promise<boolean> {
71
+ // Simple heuristic: search in top 5 source files
72
+ const files = await this.findSourceFiles(cwd);
73
+ for (const file of files) {
74
+ const content = await fs.readFile(file, 'utf-8');
75
+ if (content.includes(pattern)) return true;
76
+ }
28
77
  return false;
29
78
  }
79
+
80
+ private async findSourceFiles(cwd: string): Promise<string[]> {
81
+ // Find a few files to sample
82
+ const extensions = ['.ts', '.js', '.py', '.go', '.java', '.tf', 'package.json'];
83
+ const samples: string[] = [];
84
+
85
+ const files = await fs.readdir(cwd);
86
+ for (const file of files) {
87
+ if (extensions.some(ext => file.endsWith(ext))) {
88
+ samples.push(path.join(cwd, file));
89
+ if (samples.length >= 5) break;
90
+ }
91
+ }
92
+ return samples;
93
+ }
30
94
  }