specweave 0.28.9 → 0.28.13

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.
Files changed (58) hide show
  1. package/dist/src/cli/commands/init.d.ts.map +1 -1
  2. package/dist/src/cli/commands/init.js +35 -8
  3. package/dist/src/cli/commands/init.js.map +1 -1
  4. package/dist/src/cli/helpers/init/index.d.ts +2 -0
  5. package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
  6. package/dist/src/cli/helpers/init/index.js +4 -0
  7. package/dist/src/cli/helpers/init/index.js.map +1 -1
  8. package/dist/src/cli/helpers/init/language-selection.d.ts +40 -0
  9. package/dist/src/cli/helpers/init/language-selection.d.ts.map +1 -0
  10. package/dist/src/cli/helpers/init/language-selection.js +281 -0
  11. package/dist/src/cli/helpers/init/language-selection.js.map +1 -0
  12. package/dist/src/cli/helpers/init/repository-setup.d.ts +2 -0
  13. package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -1
  14. package/dist/src/cli/helpers/init/repository-setup.js +156 -12
  15. package/dist/src/cli/helpers/init/repository-setup.js.map +1 -1
  16. package/dist/src/cli/helpers/init/translation-config.d.ts +61 -0
  17. package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -0
  18. package/dist/src/cli/helpers/init/translation-config.js +437 -0
  19. package/dist/src/cli/helpers/init/translation-config.js.map +1 -0
  20. package/dist/src/cli/helpers/init/types.d.ts +33 -0
  21. package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
  22. package/dist/src/core/config/types.d.ts +143 -0
  23. package/dist/src/core/config/types.d.ts.map +1 -1
  24. package/dist/src/core/config/types.js.map +1 -1
  25. package/dist/src/core/repo-structure/repo-id-generator.d.ts +24 -95
  26. package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
  27. package/dist/src/core/repo-structure/repo-id-generator.js +31 -223
  28. package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
  29. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  30. package/dist/src/core/repo-structure/repo-structure-manager.js +12 -46
  31. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  32. package/dist/src/sync/sync-coordinator.d.ts +5 -0
  33. package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
  34. package/dist/src/sync/sync-coordinator.js +104 -6
  35. package/dist/src/sync/sync-coordinator.js.map +1 -1
  36. package/dist/src/utils/multi-repo-detector.d.ts +85 -0
  37. package/dist/src/utils/multi-repo-detector.d.ts.map +1 -0
  38. package/dist/src/utils/multi-repo-detector.js +264 -0
  39. package/dist/src/utils/multi-repo-detector.js.map +1 -0
  40. package/package.json +1 -1
  41. package/plugins/specweave/agents/pm/AGENT.md +178 -0
  42. package/plugins/specweave/agents/test-aware-planner/AGENT.md +54 -0
  43. package/plugins/specweave/commands/specweave-increment.md +30 -0
  44. package/plugins/specweave/commands/specweave-save.md +838 -0
  45. package/plugins/specweave/hooks/hooks.json +12 -0
  46. package/plugins/specweave/hooks/lib/update-status-line.sh +9 -1
  47. package/plugins/specweave/hooks/post-increment-completion.sh +4 -3
  48. package/plugins/specweave/hooks/post-increment-planning.sh +95 -51
  49. package/plugins/specweave/hooks/post-metadata-change.sh +18 -4
  50. package/plugins/specweave/hooks/pre-task-completion-edit.sh +355 -0
  51. package/plugins/specweave/lib/hooks/sync-living-docs.js +43 -0
  52. package/plugins/specweave/skills/increment-planner/SKILL.md +252 -2
  53. package/plugins/specweave/skills/spec-generator/SKILL.md +163 -0
  54. package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +286 -0
  55. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +18 -0
  56. package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
  57. package/plugins/specweave-release/commands/specweave-release-npm.md +14 -22
  58. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +27 -0
@@ -216,6 +216,131 @@ export interface StatusLineConfiguration {
216
216
  */
217
217
  maxNameLength: number;
218
218
  }
219
+ /**
220
+ * Child repo configuration for umbrella mode
221
+ *
222
+ * ID STRATEGY (IMPORTANT):
223
+ * The `id` field should match the canonical name from your source of truth:
224
+ *
225
+ * | Scenario | ID Source | Example |
226
+ * |-----------------------|--------------------------|----------------------------------|
227
+ * | 1:1 Repo Mapping | Exact repo name | `sw-qr-menu-fe` |
228
+ * | JIRA Project | Project key (lowercase) | `WEBAPP` → `webapp` |
229
+ * | ADO Project | Project name (kebab) | `Frontend Team` → `frontend-team`|
230
+ * | Area Path | Last segment (kebab) | `Product\Web` → `web` |
231
+ * | Monorepo Package | Package name | `@acme/frontend` → `frontend` |
232
+ *
233
+ * RULE: ID should be predictable from source - no arbitrary abbreviations!
234
+ * - ✅ `id: "sw-qr-menu-fe"` (matches repo name)
235
+ * - ❌ `id: "fe"` (arbitrary, what if 2 frontend repos?)
236
+ */
237
+ export interface ChildRepoConfig {
238
+ /**
239
+ * Repo identifier - MUST match canonical source name:
240
+ * - GitHub repo: exact repo name (e.g., 'sw-qr-menu-fe')
241
+ * - JIRA: project key lowercase (e.g., 'webapp')
242
+ * - ADO: project name kebab-case (e.g., 'frontend-team')
243
+ */
244
+ id: string;
245
+ /** Path to repo (relative or absolute) */
246
+ path: string;
247
+ /**
248
+ * User story prefix for US-{PREFIX}-001 format.
249
+ * Can be short (FE, BE) even if id is long.
250
+ * Example: id='sw-qr-menu-fe', prefix='FE' → US-FE-001
251
+ */
252
+ prefix: string;
253
+ /** GitHub URL for this repo */
254
+ githubUrl?: string;
255
+ /** JIRA project key (if JIRA is source of truth for this project) */
256
+ jiraProject?: string;
257
+ /** ADO project name (if ADO is source of truth for this project) */
258
+ adoProject?: string;
259
+ /** Tech stack keywords for story routing */
260
+ techStack?: string[];
261
+ }
262
+ /**
263
+ * Umbrella/multi-repo configuration
264
+ */
265
+ export interface UmbrellaConfig {
266
+ /** Enable umbrella mode */
267
+ enabled: boolean;
268
+ /** Optional parent/coordination repo name */
269
+ parentRepo?: string;
270
+ /** Child repos with their prefixes */
271
+ childRepos: ChildRepoConfig[];
272
+ /** Story routing configuration */
273
+ storyRouting?: {
274
+ /** Enable automatic story routing by keywords */
275
+ enabled: boolean;
276
+ /** Default repo for cross-cutting stories */
277
+ defaultRepo: string;
278
+ };
279
+ }
280
+ /**
281
+ * Supported languages for SpecWeave
282
+ * Re-exported here for config type completeness
283
+ */
284
+ export type SupportedLanguage = 'en' | 'ru' | 'es' | 'zh' | 'de' | 'fr' | 'ja' | 'ko' | 'pt';
285
+ /**
286
+ * Translation scope - what gets auto-translated
287
+ *
288
+ * CRITICAL: Translation can ~2x token usage
289
+ * User MUST explicitly opt-in during init
290
+ */
291
+ export interface TranslationScope {
292
+ /** Auto-translate spec.md, plan.md, tasks.md after creation */
293
+ incrementSpecs: boolean;
294
+ /** Auto-translate living docs on update */
295
+ livingDocs: boolean;
296
+ /** Auto-translate GitHub/JIRA/ADO issues on sync */
297
+ externalSync: boolean;
298
+ }
299
+ /**
300
+ * Translation configuration
301
+ *
302
+ * Controls automatic translation of SpecWeave content.
303
+ * English is always the source language (for maintainability).
304
+ * User's configured language is the output language.
305
+ */
306
+ export interface TranslationConfiguration {
307
+ /**
308
+ * Master switch for auto-translation
309
+ * When false, user must use /specweave:translate manually
310
+ */
311
+ enabled: boolean;
312
+ /**
313
+ * Enabled languages for this project
314
+ * Always includes 'en' as source language
315
+ */
316
+ languages: SupportedLanguage[];
317
+ /**
318
+ * Primary output language for user
319
+ * This is the language content will be translated TO
320
+ */
321
+ primary: SupportedLanguage;
322
+ /**
323
+ * Translation method
324
+ * - 'auto': Hooks trigger translation automatically
325
+ * - 'manual': User must run /specweave:translate
326
+ * - 'none': Translation disabled entirely
327
+ */
328
+ method: 'auto' | 'manual' | 'none';
329
+ /**
330
+ * Keep SpecWeave framework terms in English
331
+ * e.g., increment, spec.md, tasks.md, /specweave:*
332
+ */
333
+ preserveFrameworkTerms: boolean;
334
+ /**
335
+ * What to auto-translate (only when method='auto')
336
+ */
337
+ scope: TranslationScope;
338
+ /**
339
+ * Keep English originals as .en.md files
340
+ * Safer option but uses more storage
341
+ */
342
+ keepEnglishOriginals: boolean;
343
+ }
219
344
  /**
220
345
  * Main SpecWeave configuration
221
346
  */
@@ -224,6 +349,20 @@ export interface SpecWeaveConfig {
224
349
  * Config version for migration support
225
350
  */
226
351
  version: string;
352
+ /**
353
+ * Project display language
354
+ * Content will be translated TO this language if translation is enabled
355
+ * @default 'en'
356
+ */
357
+ language?: SupportedLanguage;
358
+ /**
359
+ * Translation configuration
360
+ * Controls automatic translation of specs, living docs, and external sync
361
+ *
362
+ * CRITICAL: Translation can ~2x token usage
363
+ * User MUST explicitly opt-in during init
364
+ */
365
+ translation?: TranslationConfiguration;
227
366
  /**
228
367
  * Project metadata (optional, for backward compatibility)
229
368
  */
@@ -252,6 +391,10 @@ export interface SpecWeaveConfig {
252
391
  * Status line configuration (optional)
253
392
  */
254
393
  statusLine?: StatusLineConfiguration;
394
+ /**
395
+ * Umbrella/multi-repo configuration (optional)
396
+ */
397
+ umbrella?: UmbrellaConfig;
255
398
  }
256
399
  /**
257
400
  * Default configuration values
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/config/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/config/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/config/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiSH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC7C,OAAO,EAAE,KAAK;IACd,UAAU,EAAE;QACV,QAAQ,EAAE,OAAO;KAClB;IACD,YAAY,EAAE;QACZ,QAAQ,EAAE,MAAM;KACjB;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,eAAe;QAC1B,QAAQ,EAAE,KAAK;QACf,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,IAAI;KACtB;IACD,UAAU,EAAE;QACV,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,KAAK,EAAE,aAAa;QACjC,gBAAgB,EAAE,CAAC;QACnB,aAAa,EAAE,EAAE;KAClB;CACF,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/config/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAucH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC7C,OAAO,EAAE,KAAK;IACd,UAAU,EAAE;QACV,QAAQ,EAAE,OAAO;KAClB;IACD,YAAY,EAAE;QACZ,QAAQ,EAAE,MAAM;KACjB;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,eAAe;QAC1B,QAAQ,EAAE,KAAK;QACf,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,IAAI;KACtB;IACD,UAAU,EAAE;QACV,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,KAAK,EAAE,aAAa;QACjC,gBAAgB,EAAE,CAAC;QACnB,aAAa,EAAE,EAAE;KAClB;CACF,CAAC"}
@@ -1,120 +1,49 @@
1
1
  /**
2
2
  * Repository ID Generator
3
3
  *
4
- * Auto-generates clean, unique repository IDs from repository names.
5
- * Strips common suffixes and takes last segment for readable IDs.
4
+ * Simple approach: Repository name IS the project ID (after normalization).
6
5
  *
7
- * Examples:
8
- * "my-saas-frontend-app" "frontend"
9
- * "acme-api-gateway-service" "gateway"
10
- * "backend-service" "backend"
6
+ * Why?
7
+ * - Repository names are already unique within an organization
8
+ * - No complex suffix-stripping = no collisions
9
+ * - Project folder matches repo name (predictable)
11
10
  *
12
11
  * @module repo-id-generator
13
12
  */
14
13
  /**
15
- * Validation result for repository IDs
16
- */
17
- export interface ValidationResult {
18
- valid: boolean;
19
- error?: string;
20
- }
21
- /**
22
- * Result of ensuring unique ID
23
- */
24
- export interface UniqueIdResult {
25
- id: string;
26
- wasModified: boolean;
27
- }
28
- /**
29
- * Generate a clean repository ID from a repository name.
14
+ * Normalize a repository name to a valid project ID.
30
15
  *
31
- * Algorithm (REVISED for correct service-type extraction):
16
+ * Rules:
32
17
  * 1. Convert to lowercase
33
- * 2. Strip common prefixes (sw-, app-, web-, mobile-, api-)
34
- * 3. Split by hyphens
35
- * 4. Take the last segment (this is usually the service type: frontend, backend, etc.)
36
- * 5. If that segment is a known suffix (-app, -service), take the SECOND-TO-LAST segment instead
37
- *
38
- * This correctly identifies the service type regardless of suffixes.
39
- *
40
- * Examples:
41
- * - "sw-web-calc-frontend" → remove "sw-" → "web-calc-frontend" → last segment "frontend" ✓
42
- * - "sw-web-calc-frontend-app" → remove "sw-" → "web-calc-frontend-app" → last "app" (suffix) → take "frontend" ✓
43
- * - "acme-api-gateway-service" → remove "api-" → "gateway-service" → last "service" (suffix) → take "gateway" ✓
44
- * - "backend-service" → no prefix → "backend-service" → last "service" (suffix) → take "backend" ✓
45
- *
46
- * @param repoName - Full repository name
47
- * @returns Clean repository ID
48
- */
49
- export declare function generateRepoId(repoName: string): string;
50
- /**
51
- * Generate a context-aware repository ID with conflict detection.
52
- *
53
- * This is a smarter version that considers existing IDs and tries different strategies:
54
- * 1. Try last segment (e.g., "calc-frontend" → "frontend")
55
- * 2. If conflict, try abbreviated last segment (e.g., "frontend" → "fe")
56
- * 3. If still conflict, try last two segments (e.g., "calc-fe")
57
- * 4. If still conflict, use full cleaned name
58
- *
59
- * @param repoName - Full repository name
60
- * @param existingNames - Array of existing repository names (for conflict detection)
61
- * @returns Best available repository ID
18
+ * 2. Replace underscores and spaces with hyphens
19
+ * 3. Remove invalid characters (keep only a-z, 0-9, hyphens)
20
+ * 4. Collapse multiple hyphens
21
+ * 5. Trim leading/trailing hyphens
62
22
  *
63
23
  * @example
64
- * generateRepoIdSmart("sw-web-calc-frontend", ["sw-mobile-calc-frontend"])
65
- * // Returns "calc-fe" (avoids "frontend" conflict)
24
+ * normalizeRepoName('My-SaaS-Frontend') // 'my-saas-frontend'
25
+ * normalizeRepoName('sw_qr_menu_be') // 'sw-qr-menu-be'
66
26
  */
67
- export declare function generateRepoIdSmart(repoName: string, existingNames?: string[]): string;
68
- /**
69
- * Ensure repository ID is unique by appending numeric suffix if needed.
70
- *
71
- * @param baseId - Base repository ID to make unique
72
- * @param existingIds - Set of already-used IDs
73
- * @returns Unique ID with modification flag
74
- *
75
- * @example
76
- * ensureUniqueId("frontend", new Set()) // { id: "frontend", wasModified: false }
77
- * ensureUniqueId("frontend", new Set(["frontend"])) // { id: "frontend-2", wasModified: true }
78
- * ensureUniqueId("frontend", new Set(["frontend", "frontend-2"])) // { id: "frontend-3", wasModified: true }
79
- */
80
- export declare function ensureUniqueId(baseId: string, existingIds: Set<string>): UniqueIdResult;
27
+ export declare function normalizeRepoName(repoName: string): string;
81
28
  /**
82
29
  * Validate a repository ID against naming rules.
83
30
  *
84
31
  * Rules:
85
- * - No commas (prevents "parent,fe,be" input error)
86
- * - Lowercase letters, numbers, and hyphens only
32
+ * - Lowercase letters, numbers, hyphens only
87
33
  * - Must start with a letter
88
34
  * - Length 1-50 characters
89
- * - No spaces or special characters
90
- *
91
- * @param id - Repository ID to validate
92
- * @returns Validation result with error message if invalid
93
- *
94
- * @example
95
- * validateRepoId("frontend-app") // { valid: true }
96
- * validateRepoId("parent,fe,be") // { valid: false, error: "..." }
97
- * validateRepoId("MyRepo") // { valid: false, error: "..." }
35
+ * - No commas, spaces, or special characters
98
36
  */
99
- export declare function validateRepoId(id: string): ValidationResult;
37
+ export declare function validateRepoId(id: string): {
38
+ valid: boolean;
39
+ error?: string;
40
+ };
100
41
  /**
101
- * Suggest repository name for multi-repo setup based on index.
102
- *
103
- * Uses common patterns for different repository types:
104
- * - Index 0: frontend
105
- * - Index 1: backend
106
- * - Index 2: mobile/api
107
- * - Index 3+: infra, shared, worker, etc.
108
- *
109
- * @param projectName - Base project name (e.g., "my-saas" or "acme-platform")
110
- * @param repoIndex - Zero-based repository index
111
- * @param totalRepos - Total number of repositories (helps choose patterns)
112
- * @returns Suggested repository name
42
+ * Suggest repository name for multi-repo setup.
113
43
  *
114
44
  * @example
115
- * suggestRepoName("my-saas", 0, 3) // "my-saas-frontend"
116
- * suggestRepoName("my-saas", 1, 3) // "my-saas-backend"
117
- * suggestRepoName("my-saas", 2, 3) // "my-saas-mobile"
45
+ * suggestRepoName('my-saas', 0, 3) // 'my-saas-frontend'
46
+ * suggestRepoName('my-saas', 1, 3) // 'my-saas-backend'
118
47
  */
119
- export declare function suggestRepoName(projectName: string, repoIndex: number, totalRepos: number): string;
48
+ export declare function suggestRepoName(projectName: string, repoIndex: number, _totalRepos: number): string;
120
49
  //# sourceMappingURL=repo-id-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repo-id-generator.d.ts","sourceRoot":"","sources":["../../../../src/core/repo-structure/repo-id-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAkCH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+BvD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,GAAE,MAAM,EAAO,GAAG,MAAM,CA+D1F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,cAAc,CAYvF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,CAqC3D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAyBlG"}
1
+ {"version":3,"file":"repo-id-generator.d.ts","sourceRoot":"","sources":["../../../../src/core/repo-structure/repo-id-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAS1D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAuB7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAInG"}
@@ -1,274 +1,82 @@
1
1
  /**
2
2
  * Repository ID Generator
3
3
  *
4
- * Auto-generates clean, unique repository IDs from repository names.
5
- * Strips common suffixes and takes last segment for readable IDs.
4
+ * Simple approach: Repository name IS the project ID (after normalization).
6
5
  *
7
- * Examples:
8
- * "my-saas-frontend-app" "frontend"
9
- * "acme-api-gateway-service" "gateway"
10
- * "backend-service" "backend"
6
+ * Why?
7
+ * - Repository names are already unique within an organization
8
+ * - No complex suffix-stripping = no collisions
9
+ * - Project folder matches repo name (predictable)
11
10
  *
12
11
  * @module repo-id-generator
13
12
  */
14
13
  /**
15
- * Common repository name suffixes to strip
16
- */
17
- const REPO_SUFFIXES = [
18
- '-app',
19
- '-service',
20
- '-api',
21
- '-frontend',
22
- '-backend',
23
- '-web',
24
- '-mobile'
25
- ];
26
- /**
27
- * Common word abbreviations for cleaner IDs
28
- */
29
- const WORD_ABBREVIATIONS = {
30
- 'frontend': 'fe',
31
- 'backend': 'be',
32
- 'service': 'svc',
33
- 'database': 'db',
34
- 'application': 'app',
35
- 'interface': 'ui',
36
- 'authentication': 'auth',
37
- 'authorization': 'authz',
38
- 'administration': 'admin',
39
- 'configuration': 'config',
40
- 'management': 'mgmt',
41
- 'repository': 'repo',
42
- 'documentation': 'docs'
43
- };
44
- /**
45
- * Generate a clean repository ID from a repository name.
14
+ * Normalize a repository name to a valid project ID.
46
15
  *
47
- * Algorithm (REVISED for correct service-type extraction):
16
+ * Rules:
48
17
  * 1. Convert to lowercase
49
- * 2. Strip common prefixes (sw-, app-, web-, mobile-, api-)
50
- * 3. Split by hyphens
51
- * 4. Take the last segment (this is usually the service type: frontend, backend, etc.)
52
- * 5. If that segment is a known suffix (-app, -service), take the SECOND-TO-LAST segment instead
53
- *
54
- * This correctly identifies the service type regardless of suffixes.
55
- *
56
- * Examples:
57
- * - "sw-web-calc-frontend" → remove "sw-" → "web-calc-frontend" → last segment "frontend" ✓
58
- * - "sw-web-calc-frontend-app" → remove "sw-" → "web-calc-frontend-app" → last "app" (suffix) → take "frontend" ✓
59
- * - "acme-api-gateway-service" → remove "api-" → "gateway-service" → last "service" (suffix) → take "gateway" ✓
60
- * - "backend-service" → no prefix → "backend-service" → last "service" (suffix) → take "backend" ✓
61
- *
62
- * @param repoName - Full repository name
63
- * @returns Clean repository ID
64
- */
65
- export function generateRepoId(repoName) {
66
- if (!repoName) {
67
- return '';
68
- }
69
- let cleaned = repoName.toLowerCase();
70
- // Step 1: Strip common prefixes
71
- const prefixes = [/^sw-/, /^app-/, /^web-/, /^mobile-/, /^api-/];
72
- for (const prefix of prefixes) {
73
- cleaned = cleaned.replace(prefix, '');
74
- }
75
- // Step 2: Split by hyphen
76
- const segments = cleaned.split('-').filter(seg => seg.length > 0);
77
- if (segments.length === 0) {
78
- return '';
79
- }
80
- // Step 3: Take last segment, but if it's a known suffix word, take second-to-last
81
- const lastSegment = segments[segments.length - 1];
82
- // Check if last segment is a suffix keyword (without the hyphen)
83
- const suffixKeywords = ['app', 'service', 'api', 'web', 'mobile'];
84
- if (suffixKeywords.includes(lastSegment) && segments.length >= 2) {
85
- return segments[segments.length - 2];
86
- }
87
- return lastSegment;
88
- }
89
- /**
90
- * Generate a context-aware repository ID with conflict detection.
91
- *
92
- * This is a smarter version that considers existing IDs and tries different strategies:
93
- * 1. Try last segment (e.g., "calc-frontend" → "frontend")
94
- * 2. If conflict, try abbreviated last segment (e.g., "frontend" → "fe")
95
- * 3. If still conflict, try last two segments (e.g., "calc-fe")
96
- * 4. If still conflict, use full cleaned name
97
- *
98
- * @param repoName - Full repository name
99
- * @param existingNames - Array of existing repository names (for conflict detection)
100
- * @returns Best available repository ID
18
+ * 2. Replace underscores and spaces with hyphens
19
+ * 3. Remove invalid characters (keep only a-z, 0-9, hyphens)
20
+ * 4. Collapse multiple hyphens
21
+ * 5. Trim leading/trailing hyphens
101
22
  *
102
23
  * @example
103
- * generateRepoIdSmart("sw-web-calc-frontend", ["sw-mobile-calc-frontend"])
104
- * // Returns "calc-fe" (avoids "frontend" conflict)
24
+ * normalizeRepoName('My-SaaS-Frontend') // 'my-saas-frontend'
25
+ * normalizeRepoName('sw_qr_menu_be') // 'sw-qr-menu-be'
105
26
  */
106
- export function generateRepoIdSmart(repoName, existingNames = []) {
107
- if (!repoName) {
27
+ export function normalizeRepoName(repoName) {
28
+ if (!repoName)
108
29
  return '';
109
- }
110
- // Generate base ID using standard algorithm
111
- const baseId = generateRepoId(repoName);
112
- // If no existing names, return base ID
113
- if (existingNames.length === 0) {
114
- return baseId;
115
- }
116
- // Generate IDs from existing names to check for conflicts
117
- const existingIds = new Set(existingNames.map(name => generateRepoId(name)));
118
- // Strategy 1: Try base ID
119
- if (!existingIds.has(baseId)) {
120
- return baseId;
121
- }
122
- // Strategy 2: Try abbreviated form (if available)
123
- const abbreviated = WORD_ABBREVIATIONS[baseId];
124
- if (abbreviated && !existingIds.has(abbreviated)) {
125
- return abbreviated;
126
- }
127
- // Strategy 3: Try last two segments
128
- let cleaned = repoName.toLowerCase();
129
- // Strip prefixes
130
- const prefixes = [/^sw-/, /^app-/, /^web-/, /^mobile-/, /^api-/];
131
- for (const prefix of prefixes) {
132
- cleaned = cleaned.replace(prefix, '');
133
- }
134
- const segments = cleaned.split('-').filter(seg => seg.length > 0);
135
- if (segments.length >= 2) {
136
- // Remove suffix keywords from end if present
137
- const suffixKeywords = ['app', 'service', 'api', 'web', 'mobile'];
138
- const cleanedSegments = suffixKeywords.includes(segments[segments.length - 1])
139
- ? segments.slice(0, -1)
140
- : segments;
141
- if (cleanedSegments.length >= 2) {
142
- const lastTwo = cleanedSegments.slice(-2).join('-');
143
- if (!existingIds.has(lastTwo)) {
144
- return lastTwo;
145
- }
146
- // Try abbreviated last segment with penultimate
147
- const abbrevLast = WORD_ABBREVIATIONS[cleanedSegments[cleanedSegments.length - 1]] || cleanedSegments[cleanedSegments.length - 1];
148
- const lastTwoAbbrev = `${cleanedSegments[cleanedSegments.length - 2]}-${abbrevLast}`;
149
- if (!existingIds.has(lastTwoAbbrev)) {
150
- return lastTwoAbbrev;
151
- }
152
- }
153
- }
154
- // Strategy 4: Fall back to full cleaned name
155
- const finalSegments = segments.filter(seg => !['app', 'service', 'api'].includes(seg));
156
- return finalSegments.join('-') || baseId;
157
- }
158
- /**
159
- * Ensure repository ID is unique by appending numeric suffix if needed.
160
- *
161
- * @param baseId - Base repository ID to make unique
162
- * @param existingIds - Set of already-used IDs
163
- * @returns Unique ID with modification flag
164
- *
165
- * @example
166
- * ensureUniqueId("frontend", new Set()) // { id: "frontend", wasModified: false }
167
- * ensureUniqueId("frontend", new Set(["frontend"])) // { id: "frontend-2", wasModified: true }
168
- * ensureUniqueId("frontend", new Set(["frontend", "frontend-2"])) // { id: "frontend-3", wasModified: true }
169
- */
170
- export function ensureUniqueId(baseId, existingIds) {
171
- if (!existingIds.has(baseId)) {
172
- return { id: baseId, wasModified: false };
173
- }
174
- // Find first available suffix
175
- let counter = 2;
176
- while (existingIds.has(`${baseId}-${counter}`)) {
177
- counter++;
178
- }
179
- return { id: `${baseId}-${counter}`, wasModified: true };
30
+ return repoName
31
+ .toLowerCase()
32
+ .replace(/[_\s]+/g, '-')
33
+ .replace(/[^a-z0-9-]/g, '')
34
+ .replace(/-+/g, '-')
35
+ .replace(/^-|-$/g, '');
180
36
  }
181
37
  /**
182
38
  * Validate a repository ID against naming rules.
183
39
  *
184
40
  * Rules:
185
- * - No commas (prevents "parent,fe,be" input error)
186
- * - Lowercase letters, numbers, and hyphens only
41
+ * - Lowercase letters, numbers, hyphens only
187
42
  * - Must start with a letter
188
43
  * - Length 1-50 characters
189
- * - No spaces or special characters
190
- *
191
- * @param id - Repository ID to validate
192
- * @returns Validation result with error message if invalid
193
- *
194
- * @example
195
- * validateRepoId("frontend-app") // { valid: true }
196
- * validateRepoId("parent,fe,be") // { valid: false, error: "..." }
197
- * validateRepoId("MyRepo") // { valid: false, error: "..." }
44
+ * - No commas, spaces, or special characters
198
45
  */
199
46
  export function validateRepoId(id) {
200
- // Check empty
201
- if (!id || id.trim().length === 0) {
47
+ if (!id?.trim()) {
202
48
  return { valid: false, error: 'Repository ID cannot be empty' };
203
49
  }
204
- // Check length
205
50
  if (id.length > 50) {
206
51
  return { valid: false, error: 'Repository ID exceeds maximum length (50 characters)' };
207
52
  }
208
- // Check for commas (prevents "parent,fe,be" error)
209
53
  if (id.includes(',')) {
210
54
  return { valid: false, error: 'Repository ID cannot contain commas' };
211
55
  }
212
- // Check for spaces
213
56
  if (id.includes(' ')) {
214
57
  return { valid: false, error: 'Repository ID cannot contain spaces' };
215
58
  }
216
- // Check for uppercase letters
217
59
  if (id !== id.toLowerCase()) {
218
60
  return { valid: false, error: 'Repository ID must be lowercase' };
219
61
  }
220
- // Check starts with letter
221
62
  if (!/^[a-z]/.test(id)) {
222
63
  return { valid: false, error: 'Repository ID must start with a letter' };
223
64
  }
224
- // Check alphanumeric + hyphens only
225
65
  if (!/^[a-z][a-z0-9-]*$/.test(id)) {
226
- return { valid: false, error: 'Repository ID must contain only lowercase letters, numbers, and hyphens (alphanumeric)' };
66
+ return { valid: false, error: 'Repository ID must contain only lowercase letters, numbers, and hyphens' };
227
67
  }
228
68
  return { valid: true };
229
69
  }
230
70
  /**
231
- * Suggest repository name for multi-repo setup based on index.
232
- *
233
- * Uses common patterns for different repository types:
234
- * - Index 0: frontend
235
- * - Index 1: backend
236
- * - Index 2: mobile/api
237
- * - Index 3+: infra, shared, worker, etc.
238
- *
239
- * @param projectName - Base project name (e.g., "my-saas" or "acme-platform")
240
- * @param repoIndex - Zero-based repository index
241
- * @param totalRepos - Total number of repositories (helps choose patterns)
242
- * @returns Suggested repository name
71
+ * Suggest repository name for multi-repo setup.
243
72
  *
244
73
  * @example
245
- * suggestRepoName("my-saas", 0, 3) // "my-saas-frontend"
246
- * suggestRepoName("my-saas", 1, 3) // "my-saas-backend"
247
- * suggestRepoName("my-saas", 2, 3) // "my-saas-mobile"
74
+ * suggestRepoName('my-saas', 0, 3) // 'my-saas-frontend'
75
+ * suggestRepoName('my-saas', 1, 3) // 'my-saas-backend'
248
76
  */
249
- export function suggestRepoName(projectName, repoIndex, totalRepos) {
250
- // Common repository type patterns (order matters!)
251
- const repoTypePatterns = [
252
- 'frontend', // 0: Web/UI (most common first repo)
253
- 'backend', // 1: API/Server (most common second repo)
254
- 'mobile', // 2: Mobile app
255
- 'api', // 3: API gateway
256
- 'infra', // 4: Infrastructure/DevOps
257
- 'shared', // 5: Shared libraries
258
- 'worker', // 6: Background workers
259
- 'admin', // 7: Admin panel
260
- 'docs', // 8: Documentation site
261
- 'analytics' // 9: Analytics/reporting
262
- ];
263
- // For repos beyond our predefined patterns, use generic "service-N" naming
264
- let repoType;
265
- if (repoIndex < repoTypePatterns.length) {
266
- repoType = repoTypePatterns[repoIndex];
267
- }
268
- else {
269
- // Fallback for many repos: service-4, service-5, etc.
270
- repoType = `service-${repoIndex + 1}`;
271
- }
77
+ export function suggestRepoName(projectName, repoIndex, _totalRepos) {
78
+ const patterns = ['frontend', 'backend', 'mobile', 'api', 'infra', 'shared', 'worker', 'admin', 'docs', 'analytics'];
79
+ const repoType = repoIndex < patterns.length ? patterns[repoIndex] : `service-${repoIndex + 1}`;
272
80
  return `${projectName}-${repoType}`;
273
81
  }
274
82
  //# sourceMappingURL=repo-id-generator.js.map