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.
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +35 -8
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/init/index.d.ts +2 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +4 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/helpers/init/language-selection.d.ts +40 -0
- package/dist/src/cli/helpers/init/language-selection.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/language-selection.js +281 -0
- package/dist/src/cli/helpers/init/language-selection.js.map +1 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts +2 -0
- package/dist/src/cli/helpers/init/repository-setup.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/repository-setup.js +156 -12
- package/dist/src/cli/helpers/init/repository-setup.js.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.d.ts +61 -0
- package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/translation-config.js +437 -0
- package/dist/src/cli/helpers/init/translation-config.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +33 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
- package/dist/src/core/config/types.d.ts +143 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.d.ts +24 -95
- package/dist/src/core/repo-structure/repo-id-generator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-id-generator.js +31 -223
- package/dist/src/core/repo-structure/repo-id-generator.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +12 -46
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts +5 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +104 -6
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/dist/src/utils/multi-repo-detector.d.ts +85 -0
- package/dist/src/utils/multi-repo-detector.d.ts.map +1 -0
- package/dist/src/utils/multi-repo-detector.js +264 -0
- package/dist/src/utils/multi-repo-detector.js.map +1 -0
- package/package.json +1 -1
- package/plugins/specweave/agents/pm/AGENT.md +178 -0
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +54 -0
- package/plugins/specweave/commands/specweave-increment.md +30 -0
- package/plugins/specweave/commands/specweave-save.md +838 -0
- package/plugins/specweave/hooks/hooks.json +12 -0
- package/plugins/specweave/hooks/lib/update-status-line.sh +9 -1
- package/plugins/specweave/hooks/post-increment-completion.sh +4 -3
- package/plugins/specweave/hooks/post-increment-planning.sh +95 -51
- package/plugins/specweave/hooks/post-metadata-change.sh +18 -4
- package/plugins/specweave/hooks/pre-task-completion-edit.sh +355 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js +43 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +252 -2
- package/plugins/specweave/skills/spec-generator/SKILL.md +163 -0
- package/plugins/specweave/skills/umbrella-repo-detector/SKILL.md +286 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +18 -0
- package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
- package/plugins/specweave-release/commands/specweave-release-npm.md +14 -22
- 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;
|
|
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
|
-
*
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
16
|
+
* Rules:
|
|
32
17
|
* 1. Convert to lowercase
|
|
33
|
-
* 2.
|
|
34
|
-
* 3.
|
|
35
|
-
* 4.
|
|
36
|
-
* 5.
|
|
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
|
-
*
|
|
65
|
-
* //
|
|
24
|
+
* normalizeRepoName('My-SaaS-Frontend') // 'my-saas-frontend'
|
|
25
|
+
* normalizeRepoName('sw_qr_menu_be') // 'sw-qr-menu-be'
|
|
66
26
|
*/
|
|
67
|
-
export declare function
|
|
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
|
-
* -
|
|
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):
|
|
37
|
+
export declare function validateRepoId(id: string): {
|
|
38
|
+
valid: boolean;
|
|
39
|
+
error?: string;
|
|
40
|
+
};
|
|
100
41
|
/**
|
|
101
|
-
* Suggest repository name for multi-repo setup
|
|
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(
|
|
116
|
-
* suggestRepoName(
|
|
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,
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
16
|
+
* Rules:
|
|
48
17
|
* 1. Convert to lowercase
|
|
49
|
-
* 2.
|
|
50
|
-
* 3.
|
|
51
|
-
* 4.
|
|
52
|
-
* 5.
|
|
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
|
-
*
|
|
104
|
-
* //
|
|
24
|
+
* normalizeRepoName('My-SaaS-Frontend') // 'my-saas-frontend'
|
|
25
|
+
* normalizeRepoName('sw_qr_menu_be') // 'sw-qr-menu-be'
|
|
105
26
|
*/
|
|
106
|
-
export function
|
|
107
|
-
if (!repoName)
|
|
27
|
+
export function normalizeRepoName(repoName) {
|
|
28
|
+
if (!repoName)
|
|
108
29
|
return '';
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
* -
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
246
|
-
* suggestRepoName(
|
|
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,
|
|
250
|
-
|
|
251
|
-
const
|
|
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
|