@ryuenn3123/agentic-senior-core 2.0.25 → 2.0.27
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/.agent-context/review-checklists/frontend-excellence-rubric.md +54 -0
- package/.agent-context/review-checklists/frontend-skill-parity.md +1 -0
- package/.agent-context/review-checklists/frontend-usability.md +1 -0
- package/.agent-context/rules/docker-runtime.md +29 -0
- package/.agent-context/skills/frontend/README.md +1 -0
- package/.agent-context/skills/frontend.md +4 -0
- package/.agent-context/state/benchmark-evidence-bundle.json +672 -22
- package/.agent-context/state/benchmark-history.json +75 -0
- package/.agent-context/state/benchmark-trend-report.csv +5 -0
- package/.agent-context/state/benchmark-trend-report.json +140 -0
- package/.agent-context/state/benchmark-watchlist.json +3 -3
- package/.agent-context/state/memory-adapter-contract.json +52 -0
- package/.agent-context/state/memory-continuity-benchmark.json +132 -0
- package/.agent-context/state/memory-schema-v1.json +88 -0
- package/.cursorrules +1 -1
- package/.windsurfrules +1 -1
- package/README.md +29 -0
- package/lib/cli/commands/init.mjs +358 -16
- package/lib/cli/commands/optimize.mjs +12 -0
- package/lib/cli/commands/upgrade.mjs +30 -1
- package/lib/cli/compiler.mjs +55 -1
- package/lib/cli/constants.mjs +83 -0
- package/lib/cli/detector.mjs +11 -1
- package/lib/cli/memory-continuity.mjs +266 -0
- package/lib/cli/project-scaffolder.mjs +174 -1
- package/lib/cli/skill-selector.mjs +60 -38
- package/lib/cli/templates/architecture-decision-record.md.tmpl +39 -0
- package/lib/cli/templates/flow-overview.md.tmpl +12 -0
- package/lib/cli/templates/project-brief.md.id.tmpl +2 -0
- package/lib/cli/templates/project-brief.md.tmpl +26 -0
- package/lib/cli/utils.mjs +2 -1
- package/package.json +2 -1
- package/scripts/benchmark-evidence-bundle.mjs +493 -16
- package/scripts/frontend-usability-audit.mjs +21 -0
- package/scripts/memory-continuity-benchmark.mjs +322 -0
- package/scripts/release-gate.mjs +30 -0
- package/scripts/validate.mjs +5 -0
|
@@ -12,6 +12,13 @@ import {
|
|
|
12
12
|
INIT_PRESETS,
|
|
13
13
|
PROFILE_PRESETS,
|
|
14
14
|
BLUEPRINT_RECOMMENDATIONS,
|
|
15
|
+
PROJECT_SCOPE_CHOICES,
|
|
16
|
+
PROJECT_SCOPE_STACK_FILTERS,
|
|
17
|
+
WEB_FRONTEND_STACK_CANDIDATES,
|
|
18
|
+
WEB_BACKEND_STACK_CANDIDATES,
|
|
19
|
+
WEB_FRONTEND_BLUEPRINT_CANDIDATES,
|
|
20
|
+
WEB_BACKEND_BLUEPRINT_CANDIDATES,
|
|
21
|
+
RUNTIME_ENVIRONMENT_CHOICES,
|
|
15
22
|
} from '../constants.mjs';
|
|
16
23
|
|
|
17
24
|
import {
|
|
@@ -70,6 +77,8 @@ export function parseInitArguments(commandArguments) {
|
|
|
70
77
|
docsLang: 'en',
|
|
71
78
|
docsLangProvided: false,
|
|
72
79
|
projectConfig: undefined,
|
|
80
|
+
runtimeEnv: 'auto',
|
|
81
|
+
runtimeEnvProvided: false,
|
|
73
82
|
};
|
|
74
83
|
|
|
75
84
|
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
@@ -212,6 +221,19 @@ export function parseInitArguments(commandArguments) {
|
|
|
212
221
|
continue;
|
|
213
222
|
}
|
|
214
223
|
|
|
224
|
+
if (currentArgument === '--runtime-env') {
|
|
225
|
+
parsedInitOptions.runtimeEnv = commandArguments[argumentIndex + 1] || 'auto';
|
|
226
|
+
parsedInitOptions.runtimeEnvProvided = true;
|
|
227
|
+
argumentIndex += 1;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (currentArgument.startsWith('--runtime-env=')) {
|
|
232
|
+
parsedInitOptions.runtimeEnv = currentArgument.split('=')[1] || 'auto';
|
|
233
|
+
parsedInitOptions.runtimeEnvProvided = true;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
|
|
215
237
|
throw new Error(`Unknown option: ${currentArgument}`);
|
|
216
238
|
}
|
|
217
239
|
|
|
@@ -224,12 +246,163 @@ export function parseInitArguments(commandArguments) {
|
|
|
224
246
|
throw new Error('--docs-lang must be one of: en, id');
|
|
225
247
|
}
|
|
226
248
|
|
|
249
|
+
const normalizedRuntimeEnvironment = normalizeRuntimeEnvironmentKey(parsedInitOptions.runtimeEnv || 'auto');
|
|
250
|
+
if (!normalizedRuntimeEnvironment) {
|
|
251
|
+
throw new Error('--runtime-env must be one of: auto, linux-wsl, linux, windows, macos');
|
|
252
|
+
}
|
|
253
|
+
|
|
227
254
|
parsedInitOptions.docsLang = normalizedDocsLanguage;
|
|
255
|
+
parsedInitOptions.runtimeEnv = normalizedRuntimeEnvironment;
|
|
228
256
|
parsedInitOptions.tokenAgent = normalizeAgentName(parsedInitOptions.tokenAgent);
|
|
229
257
|
|
|
230
258
|
return parsedInitOptions;
|
|
231
259
|
}
|
|
232
260
|
|
|
261
|
+
export function filterStackFileNamesByCandidates(allStackFileNames, preferredStackFileNames) {
|
|
262
|
+
if (!Array.isArray(preferredStackFileNames) || preferredStackFileNames.length === 0) {
|
|
263
|
+
return allStackFileNames;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const filteredStackFileNames = preferredStackFileNames.filter((stackFileName) => allStackFileNames.includes(stackFileName));
|
|
267
|
+
return filteredStackFileNames.length > 0 ? filteredStackFileNames : allStackFileNames;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function filterBlueprintFileNamesByCandidates(allBlueprintFileNames, preferredBlueprintFileNames) {
|
|
271
|
+
if (!Array.isArray(preferredBlueprintFileNames) || preferredBlueprintFileNames.length === 0) {
|
|
272
|
+
return allBlueprintFileNames;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const filteredBlueprintFileNames = preferredBlueprintFileNames.filter(
|
|
276
|
+
(blueprintFileName) => allBlueprintFileNames.includes(blueprintFileName)
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
return filteredBlueprintFileNames.length > 0 ? filteredBlueprintFileNames : allBlueprintFileNames;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function normalizeRuntimeEnvironmentKey(rawRuntimeEnvironmentKey) {
|
|
283
|
+
const normalizedRuntimeEnvironmentKey = normalizeChoiceInput(String(rawRuntimeEnvironmentKey || 'auto'));
|
|
284
|
+
const supportedRuntimeEnvironmentKeys = new Set(['auto', 'linux-wsl', 'linux', 'windows', 'macos']);
|
|
285
|
+
return supportedRuntimeEnvironmentKeys.has(normalizedRuntimeEnvironmentKey) ? normalizedRuntimeEnvironmentKey : null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function resolveRuntimeEnvironmentKeyFromLabel(selectedRuntimeEnvironmentLabel) {
|
|
289
|
+
const runtimeEnvironmentEntry = RUNTIME_ENVIRONMENT_CHOICES.find(
|
|
290
|
+
(runtimeEnvironmentChoice) => runtimeEnvironmentChoice.label === selectedRuntimeEnvironmentLabel
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
return runtimeEnvironmentEntry?.key || null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function resolveRuntimeEnvironmentLabelFromKey(runtimeEnvironmentKey) {
|
|
297
|
+
const runtimeEnvironmentEntry = RUNTIME_ENVIRONMENT_CHOICES.find(
|
|
298
|
+
(runtimeEnvironmentChoice) => runtimeEnvironmentChoice.key === runtimeEnvironmentKey
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return runtimeEnvironmentEntry?.label || runtimeEnvironmentKey;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function detectRuntimeEnvironment() {
|
|
305
|
+
const isWslEnvironment = Boolean(process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP || process.env.__IS_WSL_TEST__);
|
|
306
|
+
|
|
307
|
+
if (isWslEnvironment) {
|
|
308
|
+
return {
|
|
309
|
+
key: 'linux-wsl',
|
|
310
|
+
label: resolveRuntimeEnvironmentLabelFromKey('linux-wsl'),
|
|
311
|
+
shellFamily: 'bash',
|
|
312
|
+
isAutoDetected: true,
|
|
313
|
+
source: 'WSL environment markers',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (process.platform === 'win32') {
|
|
318
|
+
return {
|
|
319
|
+
key: 'windows',
|
|
320
|
+
label: resolveRuntimeEnvironmentLabelFromKey('windows'),
|
|
321
|
+
shellFamily: 'powershell',
|
|
322
|
+
isAutoDetected: true,
|
|
323
|
+
source: 'process.platform',
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (process.platform === 'darwin') {
|
|
328
|
+
return {
|
|
329
|
+
key: 'macos',
|
|
330
|
+
label: resolveRuntimeEnvironmentLabelFromKey('macos'),
|
|
331
|
+
shellFamily: 'bash',
|
|
332
|
+
isAutoDetected: true,
|
|
333
|
+
source: 'process.platform',
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return {
|
|
338
|
+
key: 'linux',
|
|
339
|
+
label: resolveRuntimeEnvironmentLabelFromKey('linux'),
|
|
340
|
+
shellFamily: 'bash',
|
|
341
|
+
isAutoDetected: true,
|
|
342
|
+
source: 'process.platform',
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export function resolveProjectScopeKeyFromLabel(selectedProjectScopeLabel) {
|
|
347
|
+
const projectScopeEntry = PROJECT_SCOPE_CHOICES.find((scopeChoice) => scopeChoice.label === selectedProjectScopeLabel);
|
|
348
|
+
return projectScopeEntry?.key || 'other';
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function normalizeAdditionalStackSelection(selectedStackFileName, additionalStackFileNames) {
|
|
352
|
+
if (!Array.isArray(additionalStackFileNames) || additionalStackFileNames.length === 0) {
|
|
353
|
+
return [];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return Array.from(new Set(additionalStackFileNames.filter((stackFileName) => stackFileName && stackFileName !== selectedStackFileName)));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export function normalizeAdditionalBlueprintSelection(selectedBlueprintFileName, additionalBlueprintFileNames) {
|
|
360
|
+
if (!Array.isArray(additionalBlueprintFileNames) || additionalBlueprintFileNames.length === 0) {
|
|
361
|
+
return [];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return Array.from(new Set(additionalBlueprintFileNames.filter(
|
|
365
|
+
(blueprintFileName) => blueprintFileName && blueprintFileName !== selectedBlueprintFileName
|
|
366
|
+
)));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function deriveAdditionalBlueprintFileNamesFromStacks(additionalStackFileNames, allBlueprintFileNames, selectedBlueprintFileName) {
|
|
370
|
+
const derivedBlueprintFileNames = [];
|
|
371
|
+
|
|
372
|
+
for (const additionalStackFileName of additionalStackFileNames || []) {
|
|
373
|
+
const mappedBlueprintFileName = BLUEPRINT_RECOMMENDATIONS[additionalStackFileName];
|
|
374
|
+
if (!mappedBlueprintFileName) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (!allBlueprintFileNames.includes(mappedBlueprintFileName)) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (mappedBlueprintFileName === selectedBlueprintFileName) {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
derivedBlueprintFileNames.push(mappedBlueprintFileName);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return Array.from(new Set(derivedBlueprintFileNames));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async function askStackSelection(promptMessage, selectableStackFileNames, userInterface) {
|
|
393
|
+
const stackDisplayChoices = selectableStackFileNames.map((stackFileName) => toTitleCase(stackFileName));
|
|
394
|
+
const selectedDisplayChoice = await askChoice(promptMessage, stackDisplayChoices, userInterface);
|
|
395
|
+
const selectedIndex = stackDisplayChoices.indexOf(selectedDisplayChoice);
|
|
396
|
+
return selectableStackFileNames[selectedIndex] || selectableStackFileNames[0] || null;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function askBlueprintSelection(promptMessage, selectableBlueprintFileNames, userInterface) {
|
|
400
|
+
const blueprintDisplayChoices = selectableBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName));
|
|
401
|
+
const selectedDisplayChoice = await askChoice(promptMessage, blueprintDisplayChoices, userInterface);
|
|
402
|
+
const selectedIndex = blueprintDisplayChoices.indexOf(selectedDisplayChoice);
|
|
403
|
+
return selectableBlueprintFileNames[selectedIndex] || selectableBlueprintFileNames[0] || null;
|
|
404
|
+
}
|
|
405
|
+
|
|
233
406
|
export async function runInitCommand(targetDirectoryArgument, initOptions = {}) {
|
|
234
407
|
const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
|
|
235
408
|
const isTokenOptimizationEnabled = typeof initOptions.tokenOptimize === 'boolean'
|
|
@@ -326,6 +499,30 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
326
499
|
console.log('The target directory is empty, so I will guide you through a fresh setup.');
|
|
327
500
|
}
|
|
328
501
|
|
|
502
|
+
const detectedRuntimeEnvironment = detectRuntimeEnvironment();
|
|
503
|
+
let selectedRuntimeEnvironmentKey = initOptions.runtimeEnv === 'auto'
|
|
504
|
+
? detectedRuntimeEnvironment.key
|
|
505
|
+
: initOptions.runtimeEnv;
|
|
506
|
+
|
|
507
|
+
if (isInteractiveSession && !initOptions.runtimeEnvProvided) {
|
|
508
|
+
const defaultRuntimeEnvironmentLabel = resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey);
|
|
509
|
+
const orderedRuntimeEnvironmentChoices = [
|
|
510
|
+
defaultRuntimeEnvironmentLabel,
|
|
511
|
+
...RUNTIME_ENVIRONMENT_CHOICES
|
|
512
|
+
.map((runtimeEnvironmentChoice) => runtimeEnvironmentChoice.label)
|
|
513
|
+
.filter((runtimeEnvironmentLabel) => runtimeEnvironmentLabel !== defaultRuntimeEnvironmentLabel),
|
|
514
|
+
];
|
|
515
|
+
|
|
516
|
+
const selectedRuntimeEnvironmentLabel = await askChoice(
|
|
517
|
+
`Runtime environment (auto-detected: ${defaultRuntimeEnvironmentLabel}).`,
|
|
518
|
+
orderedRuntimeEnvironmentChoices,
|
|
519
|
+
userInterface
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
selectedRuntimeEnvironmentKey = resolveRuntimeEnvironmentKeyFromLabel(selectedRuntimeEnvironmentLabel)
|
|
523
|
+
|| selectedRuntimeEnvironmentKey;
|
|
524
|
+
}
|
|
525
|
+
|
|
329
526
|
const selectedProfileName = initOptions.profile
|
|
330
527
|
? initOptions.profile
|
|
331
528
|
: selectedPreset?.profile
|
|
@@ -353,29 +550,130 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
353
550
|
console.log(`Pack defaults: stack ${toTitleCase(selectedProfilePack.defaultStackFileName)}, blueprint ${toTitleCase(selectedProfilePack.defaultBlueprintFileName)}.`);
|
|
354
551
|
}
|
|
355
552
|
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
553
|
+
const hasReliableDetectedStack = projectDetection.hasExistingProjectFiles
|
|
554
|
+
&& projectDetection.recommendedStackFileName
|
|
555
|
+
&& (projectDetection.confidenceLabel === 'high' || projectDetection.confidenceLabel === 'medium');
|
|
556
|
+
|
|
557
|
+
const shouldAutoApplyDetectedStack = hasReliableDetectedStack
|
|
558
|
+
&& !selectedStackFileNameFromOption
|
|
559
|
+
&& !selectedPreset?.stack
|
|
560
|
+
&& !selectedProfilePack?.defaultStackFileName;
|
|
561
|
+
|
|
562
|
+
let selectedManualStackFileName = null;
|
|
563
|
+
let selectedManualBlueprintFileName = null;
|
|
564
|
+
let selectedAdditionalStackFileNames = [];
|
|
565
|
+
let selectedAdditionalBlueprintFileNames = [];
|
|
566
|
+
|
|
567
|
+
const shouldAskManualStackSelection = !selectedStackFileNameFromOption
|
|
568
|
+
&& !selectedPreset?.stack
|
|
569
|
+
&& !shouldAutoApplyDetectedStack
|
|
570
|
+
&& !selectedProfilePack?.defaultStackFileName
|
|
571
|
+
&& !selectedProfile.defaultStackFileName;
|
|
572
|
+
|
|
573
|
+
if (shouldAutoApplyDetectedStack) {
|
|
574
|
+
console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
|
|
575
|
+
if (projectDetection.secondaryStackFileNames?.length) {
|
|
576
|
+
console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
|
|
577
|
+
}
|
|
578
|
+
selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (shouldAskManualStackSelection) {
|
|
582
|
+
const selectedProjectScopeLabel = await askChoice(
|
|
583
|
+
'What are you building?',
|
|
584
|
+
PROJECT_SCOPE_CHOICES.map((scopeChoice) => scopeChoice.label),
|
|
585
|
+
userInterface
|
|
586
|
+
);
|
|
587
|
+
const selectedProjectScopeKey = resolveProjectScopeKeyFromLabel(selectedProjectScopeLabel);
|
|
588
|
+
const scopeStackFilter = PROJECT_SCOPE_STACK_FILTERS[selectedProjectScopeKey];
|
|
589
|
+
const scopedStackFileNames = filterStackFileNamesByCandidates(stackFileNames, scopeStackFilter);
|
|
590
|
+
|
|
591
|
+
if (selectedProjectScopeKey === 'web-application') {
|
|
592
|
+
const usesSplitWebStacks = await askYesNo(
|
|
593
|
+
'For this web project, do frontend and backend use different primary stacks?',
|
|
594
|
+
userInterface,
|
|
595
|
+
false
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
if (usesSplitWebStacks) {
|
|
599
|
+
const selectableFrontendStacks = filterStackFileNamesByCandidates(scopedStackFileNames, WEB_FRONTEND_STACK_CANDIDATES);
|
|
600
|
+
const selectableBackendStacks = filterStackFileNamesByCandidates(scopedStackFileNames, WEB_BACKEND_STACK_CANDIDATES);
|
|
601
|
+
|
|
602
|
+
const selectedFrontendStackFileName = await askStackSelection(
|
|
603
|
+
'Which frontend stack should this governance pack target?',
|
|
604
|
+
selectableFrontendStacks,
|
|
605
|
+
userInterface
|
|
606
|
+
);
|
|
607
|
+
const selectedBackendStackFileName = await askStackSelection(
|
|
608
|
+
'Which backend stack should this governance pack target?',
|
|
609
|
+
selectableBackendStacks,
|
|
610
|
+
userInterface
|
|
611
|
+
);
|
|
612
|
+
|
|
613
|
+
selectedManualStackFileName = selectedBackendStackFileName;
|
|
614
|
+
if (selectedFrontendStackFileName && selectedFrontendStackFileName !== selectedBackendStackFileName) {
|
|
615
|
+
selectedAdditionalStackFileNames = [selectedFrontendStackFileName];
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (!selectedBlueprintFileNameFromOption && !selectedPreset?.blueprint) {
|
|
619
|
+
const selectableFrontendBlueprints = filterBlueprintFileNamesByCandidates(
|
|
620
|
+
blueprintFileNames,
|
|
621
|
+
WEB_FRONTEND_BLUEPRINT_CANDIDATES
|
|
622
|
+
);
|
|
623
|
+
const selectableBackendBlueprints = filterBlueprintFileNamesByCandidates(
|
|
624
|
+
blueprintFileNames,
|
|
625
|
+
WEB_BACKEND_BLUEPRINT_CANDIDATES
|
|
626
|
+
);
|
|
627
|
+
|
|
628
|
+
const selectedFrontendBlueprintFileName = await askBlueprintSelection(
|
|
629
|
+
'Which frontend blueprint should guide UI architecture?',
|
|
630
|
+
selectableFrontendBlueprints,
|
|
631
|
+
userInterface
|
|
632
|
+
);
|
|
633
|
+
const selectedBackendBlueprintFileName = await askBlueprintSelection(
|
|
634
|
+
'Which backend blueprint should guide service architecture?',
|
|
635
|
+
selectableBackendBlueprints,
|
|
636
|
+
userInterface
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
selectedManualBlueprintFileName = selectedBackendBlueprintFileName;
|
|
640
|
+
if (selectedFrontendBlueprintFileName && selectedFrontendBlueprintFileName !== selectedBackendBlueprintFileName) {
|
|
641
|
+
selectedAdditionalBlueprintFileNames = [selectedFrontendBlueprintFileName];
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
} else {
|
|
645
|
+
selectedManualStackFileName = await askStackSelection(
|
|
646
|
+
'Which stack should this governance pack target?',
|
|
647
|
+
scopedStackFileNames,
|
|
648
|
+
userInterface
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
selectedManualStackFileName = await askStackSelection(
|
|
653
|
+
'Which stack should this governance pack target?',
|
|
654
|
+
scopedStackFileNames,
|
|
655
|
+
userInterface
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
363
659
|
|
|
364
|
-
const stackDisplayChoices = stackFileNames.map((stackFileName) => toTitleCase(stackFileName));
|
|
365
660
|
const blueprintDisplayChoices = blueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName));
|
|
366
661
|
|
|
367
662
|
const selectedResolvedStackFileName = selectedStackFileNameFromOption
|
|
368
663
|
|| selectedPreset?.stack
|
|
369
|
-
|| (
|
|
664
|
+
|| (shouldAutoApplyDetectedStack ? projectDetection.recommendedStackFileName : null)
|
|
370
665
|
|| selectedProfilePack?.defaultStackFileName
|
|
371
666
|
|| selectedProfile.defaultStackFileName
|
|
372
|
-
||
|
|
373
|
-
|
|
374
|
-
await askChoice('Which stack should this governance pack target?', stackDisplayChoices, userInterface)
|
|
375
|
-
)
|
|
376
|
-
];
|
|
667
|
+
|| selectedManualStackFileName
|
|
668
|
+
|| stackFileNames[0];
|
|
377
669
|
|
|
378
|
-
|
|
670
|
+
selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
|
|
671
|
+
selectedResolvedStackFileName,
|
|
672
|
+
selectedAdditionalStackFileNames
|
|
673
|
+
);
|
|
674
|
+
|
|
675
|
+
const recommendedBlueprintFileName = projectDetection.recommendedBlueprintFileName
|
|
676
|
+
&& shouldAutoApplyDetectedStack
|
|
379
677
|
? projectDetection.recommendedBlueprintFileName
|
|
380
678
|
: BLUEPRINT_RECOMMENDATIONS[selectedResolvedStackFileName] || null;
|
|
381
679
|
|
|
@@ -385,6 +683,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
385
683
|
|
|
386
684
|
const selectedResolvedBlueprintFileName = selectedBlueprintFileNameFromOption
|
|
387
685
|
|| selectedPreset?.blueprint
|
|
686
|
+
|| selectedManualBlueprintFileName
|
|
388
687
|
|| recommendedBlueprintFileName
|
|
389
688
|
|| selectedProfilePack?.defaultBlueprintFileName
|
|
390
689
|
|| selectedProfile.defaultBlueprintFileName
|
|
@@ -394,9 +693,24 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
394
693
|
)
|
|
395
694
|
];
|
|
396
695
|
|
|
696
|
+
const derivedAdditionalBlueprintFileNames = deriveAdditionalBlueprintFileNamesFromStacks(
|
|
697
|
+
selectedAdditionalStackFileNames,
|
|
698
|
+
blueprintFileNames,
|
|
699
|
+
selectedResolvedBlueprintFileName
|
|
700
|
+
);
|
|
701
|
+
|
|
702
|
+
selectedAdditionalBlueprintFileNames = normalizeAdditionalBlueprintSelection(
|
|
703
|
+
selectedResolvedBlueprintFileName,
|
|
704
|
+
selectedAdditionalBlueprintFileNames.length > 0
|
|
705
|
+
? selectedAdditionalBlueprintFileNames
|
|
706
|
+
: derivedAdditionalBlueprintFileNames
|
|
707
|
+
);
|
|
708
|
+
|
|
397
709
|
const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
|
|
398
710
|
selectedResolvedStackFileName,
|
|
399
|
-
selectedResolvedBlueprintFileName
|
|
711
|
+
selectedResolvedBlueprintFileName,
|
|
712
|
+
selectedAdditionalStackFileNames,
|
|
713
|
+
selectedAdditionalBlueprintFileNames
|
|
400
714
|
);
|
|
401
715
|
|
|
402
716
|
const includeCiGuardrails = typeof initOptions.ci === 'boolean'
|
|
@@ -494,7 +808,11 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
494
808
|
discoveryAnswers,
|
|
495
809
|
{
|
|
496
810
|
stackFileName: selectedResolvedStackFileName,
|
|
811
|
+
additionalStackFileNames: selectedAdditionalStackFileNames,
|
|
497
812
|
blueprintFileName: selectedResolvedBlueprintFileName,
|
|
813
|
+
additionalBlueprintFileNames: selectedAdditionalBlueprintFileNames,
|
|
814
|
+
runtimeEnvironmentKey: selectedRuntimeEnvironmentKey,
|
|
815
|
+
runtimeEnvironmentLabel: resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey),
|
|
498
816
|
},
|
|
499
817
|
{
|
|
500
818
|
docsLanguage: selectedDocsLanguage,
|
|
@@ -513,7 +831,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
513
831
|
selectedProfileName,
|
|
514
832
|
selectedProfilePack,
|
|
515
833
|
selectedStackFileName: selectedResolvedStackFileName,
|
|
834
|
+
selectedAdditionalStackFileNames,
|
|
516
835
|
selectedBlueprintFileName: selectedResolvedBlueprintFileName,
|
|
836
|
+
selectedAdditionalBlueprintFileNames,
|
|
517
837
|
includeCiGuardrails,
|
|
518
838
|
});
|
|
519
839
|
|
|
@@ -526,12 +846,21 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
526
846
|
selectedProfilePack,
|
|
527
847
|
selectedPreset: initOptions.preset || null,
|
|
528
848
|
selectedStackFileName: selectedResolvedStackFileName,
|
|
849
|
+
selectedAdditionalStackFileNames,
|
|
529
850
|
selectedBlueprintFileName: selectedResolvedBlueprintFileName,
|
|
851
|
+
selectedAdditionalBlueprintFileNames,
|
|
530
852
|
includeCiGuardrails,
|
|
531
853
|
setupDurationMs,
|
|
532
854
|
projectDetection,
|
|
533
855
|
selectedSkillDomains: selectedSkillDomainNames,
|
|
534
856
|
compatibilityWarnings,
|
|
857
|
+
runtimeEnvironment: {
|
|
858
|
+
selected: selectedRuntimeEnvironmentKey,
|
|
859
|
+
selectedLabel: resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey),
|
|
860
|
+
detected: detectedRuntimeEnvironment.key,
|
|
861
|
+
detectedLabel: detectedRuntimeEnvironment.label,
|
|
862
|
+
detectionSource: detectedRuntimeEnvironment.source,
|
|
863
|
+
},
|
|
535
864
|
operationMode: 'init',
|
|
536
865
|
});
|
|
537
866
|
|
|
@@ -545,7 +874,14 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
545
874
|
console.log(`- Team profile pack: ${selectedProfilePack.displayName}`);
|
|
546
875
|
}
|
|
547
876
|
console.log(`- Stack: ${toTitleCase(selectedResolvedStackFileName)}`);
|
|
877
|
+
if (selectedAdditionalStackFileNames.length > 0) {
|
|
878
|
+
console.log(`- Additional stacks: ${selectedAdditionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}`);
|
|
879
|
+
}
|
|
548
880
|
console.log(`- Blueprint: ${toTitleCase(selectedResolvedBlueprintFileName)}`);
|
|
881
|
+
if (selectedAdditionalBlueprintFileNames.length > 0) {
|
|
882
|
+
console.log(`- Additional blueprints: ${selectedAdditionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName)).join(', ')}`);
|
|
883
|
+
}
|
|
884
|
+
console.log(`- Runtime environment: ${resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey)} (detected: ${detectedRuntimeEnvironment.label})`);
|
|
549
885
|
console.log(`- CI/CD guardrails: ${includeCiGuardrails ? 'enabled' : 'disabled'}`);
|
|
550
886
|
console.log(`- Blocking severities: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}`);
|
|
551
887
|
console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
|
|
@@ -563,6 +899,12 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
563
899
|
}
|
|
564
900
|
console.log('\nPlain-language summary:');
|
|
565
901
|
console.log(`I prepared a ${selectedProfile.displayName.toLowerCase()} governance pack for a ${toTitleCase(selectedResolvedStackFileName)} project using the ${toTitleCase(selectedResolvedBlueprintFileName)} blueprint.`);
|
|
902
|
+
if (selectedAdditionalStackFileNames.length > 0) {
|
|
903
|
+
console.log(`I also included additional stack context for ${selectedAdditionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
|
|
904
|
+
}
|
|
905
|
+
if (selectedAdditionalBlueprintFileNames.length > 0) {
|
|
906
|
+
console.log(`I also included additional blueprint context for ${selectedAdditionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName)).join(', ')}.`);
|
|
907
|
+
}
|
|
566
908
|
if (scaffoldingResult) {
|
|
567
909
|
console.log(`I also generated project documentation (${scaffoldingResult.docsLanguage}) based on your project description. AI agents will use docs/ as project context.`);
|
|
568
910
|
|
|
@@ -119,7 +119,17 @@ export async function runOptimizeCommand(targetDirectoryArgument, optimizeOption
|
|
|
119
119
|
? onboardingReport.selectedProfile
|
|
120
120
|
: 'balanced';
|
|
121
121
|
const selectedStackFileName = normalizeMarkdownFileName(onboardingReport.selectedStack, 'typescript.md');
|
|
122
|
+
const selectedAdditionalStackFileNames = Array.isArray(onboardingReport.selectedAdditionalStacks)
|
|
123
|
+
? onboardingReport.selectedAdditionalStacks
|
|
124
|
+
.map((stackFileName) => normalizeMarkdownFileName(stackFileName, ''))
|
|
125
|
+
.filter((stackFileName) => stackFileName && stackFileName !== selectedStackFileName)
|
|
126
|
+
: [];
|
|
122
127
|
const selectedBlueprintFileName = normalizeMarkdownFileName(onboardingReport.selectedBlueprint, 'api-nextjs.md');
|
|
128
|
+
const selectedAdditionalBlueprintFileNames = Array.isArray(onboardingReport.selectedAdditionalBlueprints)
|
|
129
|
+
? onboardingReport.selectedAdditionalBlueprints
|
|
130
|
+
.map((blueprintFileName) => normalizeMarkdownFileName(blueprintFileName, ''))
|
|
131
|
+
.filter((blueprintFileName) => blueprintFileName && blueprintFileName !== selectedBlueprintFileName)
|
|
132
|
+
: [];
|
|
123
133
|
const includeCiGuardrails = typeof onboardingReport.ciGuardrailsEnabled === 'boolean'
|
|
124
134
|
? onboardingReport.ciGuardrailsEnabled
|
|
125
135
|
: true;
|
|
@@ -128,7 +138,9 @@ export async function runOptimizeCommand(targetDirectoryArgument, optimizeOption
|
|
|
128
138
|
targetDirectoryPath: resolvedTargetDirectoryPath,
|
|
129
139
|
selectedProfileName,
|
|
130
140
|
selectedStackFileName,
|
|
141
|
+
selectedAdditionalStackFileNames,
|
|
131
142
|
selectedBlueprintFileName,
|
|
143
|
+
selectedAdditionalBlueprintFileNames,
|
|
132
144
|
includeCiGuardrails,
|
|
133
145
|
});
|
|
134
146
|
|
|
@@ -119,17 +119,35 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
119
119
|
? existingOnboardingReport.selectedStack
|
|
120
120
|
: projectDetection.recommendedStackFileName || 'typescript.md';
|
|
121
121
|
|
|
122
|
+
const selectedAdditionalStackFileNames = Array.isArray(existingOnboardingReport?.selectedAdditionalStacks)
|
|
123
|
+
? Array.from(new Set(existingOnboardingReport.selectedAdditionalStacks.filter(
|
|
124
|
+
(stackFileName) => stackFileNames.includes(stackFileName) && stackFileName !== selectedStackFileName
|
|
125
|
+
)))
|
|
126
|
+
: Array.from(new Set((projectDetection.secondaryStackFileNames || []).filter(
|
|
127
|
+
(stackFileName) => stackFileNames.includes(stackFileName) && stackFileName !== selectedStackFileName
|
|
128
|
+
)));
|
|
129
|
+
|
|
122
130
|
const selectedBlueprintFileName = blueprintFileNames.includes(existingOnboardingReport?.selectedBlueprint)
|
|
123
131
|
? existingOnboardingReport.selectedBlueprint
|
|
124
132
|
: BLUEPRINT_RECOMMENDATIONS[selectedStackFileName] || 'api-nextjs.md';
|
|
125
133
|
|
|
134
|
+
const selectedAdditionalBlueprintFileNames = Array.isArray(existingOnboardingReport?.selectedAdditionalBlueprints)
|
|
135
|
+
? Array.from(new Set(existingOnboardingReport.selectedAdditionalBlueprints.filter(
|
|
136
|
+
(blueprintFileName) => blueprintFileNames.includes(blueprintFileName) && blueprintFileName !== selectedBlueprintFileName
|
|
137
|
+
)))
|
|
138
|
+
: Array.from(new Set(selectedAdditionalStackFileNames
|
|
139
|
+
.map((stackFileName) => BLUEPRINT_RECOMMENDATIONS[stackFileName] || null)
|
|
140
|
+
.filter((blueprintFileName) => blueprintFileName && blueprintFileName !== selectedBlueprintFileName)));
|
|
141
|
+
|
|
126
142
|
const includeCiGuardrails = typeof existingOnboardingReport?.ciGuardrailsEnabled === 'boolean'
|
|
127
143
|
? existingOnboardingReport.ciGuardrailsEnabled
|
|
128
144
|
: true;
|
|
129
145
|
|
|
130
146
|
const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
|
|
131
147
|
selectedStackFileName,
|
|
132
|
-
selectedBlueprintFileName
|
|
148
|
+
selectedBlueprintFileName,
|
|
149
|
+
selectedAdditionalStackFileNames,
|
|
150
|
+
selectedAdditionalBlueprintFileNames
|
|
133
151
|
);
|
|
134
152
|
const compatibilityWarnings = await evaluateSkillDomainCompatibility(
|
|
135
153
|
resolvedTargetDirectoryPath,
|
|
@@ -154,7 +172,9 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
154
172
|
targetDirectoryPath: resolvedTargetDirectoryPath,
|
|
155
173
|
selectedProfileName,
|
|
156
174
|
selectedStackFileName,
|
|
175
|
+
selectedAdditionalStackFileNames,
|
|
157
176
|
selectedBlueprintFileName,
|
|
177
|
+
selectedAdditionalBlueprintFileNames,
|
|
158
178
|
includeCiGuardrails,
|
|
159
179
|
});
|
|
160
180
|
|
|
@@ -166,7 +186,13 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
166
186
|
console.log(`- Target directory: ${resolvedTargetDirectoryPath}`);
|
|
167
187
|
console.log(`- Profile: ${toTitleCase(selectedProfileName)}`);
|
|
168
188
|
console.log(`- Stack: ${toTitleCase(selectedStackFileName)}`);
|
|
189
|
+
if (selectedAdditionalStackFileNames.length > 0) {
|
|
190
|
+
console.log(`- Additional stacks: ${selectedAdditionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}`);
|
|
191
|
+
}
|
|
169
192
|
console.log(`- Blueprint: ${toTitleCase(selectedBlueprintFileName)}`);
|
|
193
|
+
if (selectedAdditionalBlueprintFileNames.length > 0) {
|
|
194
|
+
console.log(`- Additional blueprints: ${selectedAdditionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName)).join(', ')}`);
|
|
195
|
+
}
|
|
170
196
|
console.log(`- CI/CD guardrails: ${includeCiGuardrails ? 'enabled' : 'disabled'}`);
|
|
171
197
|
console.log(`- Existing rules lines: ${currentRuleLineCount}`);
|
|
172
198
|
console.log(`- Planned rules lines: ${plannedRuleLineCount}`);
|
|
@@ -213,12 +239,15 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
|
|
|
213
239
|
selectedProfileName,
|
|
214
240
|
selectedProfilePack: existingOnboardingReport?.selectedProfilePack || null,
|
|
215
241
|
selectedStackFileName,
|
|
242
|
+
selectedAdditionalStackFileNames,
|
|
216
243
|
selectedBlueprintFileName,
|
|
244
|
+
selectedAdditionalBlueprintFileNames,
|
|
217
245
|
includeCiGuardrails,
|
|
218
246
|
setupDurationMs,
|
|
219
247
|
projectDetection,
|
|
220
248
|
selectedSkillDomains: selectedSkillDomainNames,
|
|
221
249
|
compatibilityWarnings,
|
|
250
|
+
runtimeEnvironment: existingOnboardingReport?.runtimeEnvironment || null,
|
|
222
251
|
operationMode: 'upgrade',
|
|
223
252
|
});
|
|
224
253
|
|