@ryuenn3123/agentic-senior-core 3.0.12 → 3.0.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/.agent-context/rules/architecture.md +7 -0
- package/.agent-context/state/memory-continuity-benchmark.json +1 -1
- package/.cursorrules +1 -1
- package/.windsurfrules +1 -1
- package/lib/cli/commands/init.mjs +213 -154
- package/lib/cli/compiler.mjs +11 -0
- package/lib/cli/detector.mjs +22 -0
- package/lib/cli/project-scaffolder.mjs +39 -27
- package/package.json +1 -1
|
@@ -20,9 +20,16 @@ The `.agent-context/rules/` directory is the default guidance source for impleme
|
|
|
20
20
|
- Backend and frontend mindset checks are both required when a task spans API and UI boundaries.
|
|
21
21
|
- Security and testing are non-negotiable baseline requirements.
|
|
22
22
|
- Hard block before coding:
|
|
23
|
+
- `docs/project-brief.md` must exist.
|
|
23
24
|
- `docs/architecture-decision-record.md` (alias: `docs/Architecture-Decision-Record.md`) must exist.
|
|
25
|
+
- `docs/flow-overview.md` must exist.
|
|
26
|
+
- If the project uses persistent data, `docs/database-schema.md` must exist.
|
|
27
|
+
- If the project exposes API or web application flows, `docs/api-contract.md` must exist.
|
|
24
28
|
- For UI scope, `docs/DESIGN.md` and `docs/design-intent.json` must exist.
|
|
25
29
|
- If required project context docs are missing, stop implementation and bootstrap docs before writing application code.
|
|
30
|
+
- Bootstrap flow: analyze the real repo plus the latest user prompt before authoring those docs.
|
|
31
|
+
- Bootstrap docs must be adaptive and project-specific. Do not create generic placeholder templates.
|
|
32
|
+
- When context is incomplete, separate confirmed facts from assumptions, add an `Assumptions to Validate` section, and end with the next validation action.
|
|
26
33
|
|
|
27
34
|
## Rules as Guardian (Cross-Session Consistency)
|
|
28
35
|
|
package/.cursorrules
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
|
|
2
2
|
|
|
3
|
-
Generated by Agentic-Senior-Core CLI v3.0.
|
|
3
|
+
Generated by Agentic-Senior-Core CLI v3.0.13
|
|
4
4
|
Timestamp: 2026-04-18T00:00:00.000Z
|
|
5
5
|
Selected profile: beginner
|
|
6
6
|
Selected policy file: .agent-context/policies/llm-judge-threshold.json
|
package/.windsurfrules
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
|
|
2
2
|
|
|
3
|
-
Generated by Agentic-Senior-Core CLI v3.0.
|
|
3
|
+
Generated by Agentic-Senior-Core CLI v3.0.13
|
|
4
4
|
Timestamp: 2026-04-18T00:00:00.000Z
|
|
5
5
|
Selected profile: beginner
|
|
6
6
|
Selected policy file: .agent-context/policies/llm-judge-threshold.json
|
|
@@ -8,13 +8,13 @@ import fs from 'node:fs/promises';
|
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
PROJECT_SCOPE_CHOICES,
|
|
11
12
|
CLI_VERSION,
|
|
12
13
|
AGENT_CONTEXT_DIR,
|
|
13
14
|
INIT_PRESETS,
|
|
14
15
|
PROFILE_PRESETS,
|
|
15
16
|
GOLDEN_STANDARD_PROFILE_NAME,
|
|
16
17
|
BLUEPRINT_RECOMMENDATIONS,
|
|
17
|
-
PROJECT_SCOPE_CHOICES,
|
|
18
18
|
FALLBACK_STACK_FILE_NAMES,
|
|
19
19
|
FALLBACK_BLUEPRINT_FILE_NAMES,
|
|
20
20
|
RUNTIME_ENVIRONMENT_CHOICES,
|
|
@@ -42,10 +42,13 @@ import {
|
|
|
42
42
|
} from '../detector.mjs';
|
|
43
43
|
import { compileDynamicContext, writeSelectedPolicy, writeOnboardingReport } from '../compiler.mjs';
|
|
44
44
|
import {
|
|
45
|
+
filterStackFileNamesByCandidates,
|
|
45
46
|
filterBlueprintFileNamesByCandidates,
|
|
46
47
|
normalizeAdditionalStackSelection,
|
|
47
48
|
normalizeAdditionalBlueprintSelection,
|
|
48
49
|
deriveAdditionalBlueprintFileNamesFromStacks,
|
|
50
|
+
resolveScopeStackCandidates,
|
|
51
|
+
resolveScopeBlueprintCandidates,
|
|
49
52
|
} from '../init-selection.mjs';
|
|
50
53
|
import {
|
|
51
54
|
buildExistingProjectMajorConstraints,
|
|
@@ -75,11 +78,7 @@ import {
|
|
|
75
78
|
createMemoryContinuityState,
|
|
76
79
|
writeMemoryContinuityState,
|
|
77
80
|
} from '../memory-continuity.mjs';
|
|
78
|
-
import {
|
|
79
|
-
readArchitectPreferenceState,
|
|
80
|
-
writeArchitectPreferenceState,
|
|
81
|
-
} from '../architect.mjs';
|
|
82
|
-
import { resolveArchitectureSelection } from '../init-architecture-flow.mjs';
|
|
81
|
+
import { recommendArchitecture } from '../architect.mjs';
|
|
83
82
|
|
|
84
83
|
export { REPO_ROOT } from '../constants.mjs';
|
|
85
84
|
// Keep these architect option flags visible in the init command surface for validator coverage:
|
|
@@ -156,6 +155,82 @@ export function detectRuntimeEnvironment() {
|
|
|
156
155
|
};
|
|
157
156
|
}
|
|
158
157
|
|
|
158
|
+
function resolveProjectScopeLabelFromKey(projectScopeKey) {
|
|
159
|
+
return PROJECT_SCOPE_CHOICES.find((scopeChoice) => scopeChoice.key === projectScopeKey)?.label
|
|
160
|
+
|| PROJECT_SCOPE_CHOICES.find((scopeChoice) => scopeChoice.key === 'both')?.label
|
|
161
|
+
|| 'Both (frontend + backend)';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function inferProjectScopeFromDiscoveryAnswers(discoveryAnswers) {
|
|
165
|
+
const normalizedDomain = String(discoveryAnswers?.primaryDomain || '').trim().toLowerCase();
|
|
166
|
+
const normalizedDescription = [
|
|
167
|
+
discoveryAnswers?.projectDescription,
|
|
168
|
+
...(Array.isArray(discoveryAnswers?.features) ? discoveryAnswers.features : []),
|
|
169
|
+
].join(' ').toLowerCase();
|
|
170
|
+
|
|
171
|
+
if (
|
|
172
|
+
normalizedDomain.includes('api service')
|
|
173
|
+
|| normalizedDomain.includes('cli tool')
|
|
174
|
+
|| normalizedDomain.includes('library')
|
|
175
|
+
) {
|
|
176
|
+
return 'backend-only';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (normalizedDomain.includes('mobile app')) {
|
|
180
|
+
return 'frontend-only';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (normalizedDomain.includes('web application')) {
|
|
184
|
+
if (/(landing page|marketing site|showcase|portfolio|brochure|company profile)/.test(normalizedDescription)) {
|
|
185
|
+
return 'frontend-only';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return 'both';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return 'both';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function resolveSilentCiGuardrailsDefault({
|
|
195
|
+
initOptions,
|
|
196
|
+
selectedPreset,
|
|
197
|
+
selectedProfilePack,
|
|
198
|
+
selectedProfile,
|
|
199
|
+
}) {
|
|
200
|
+
if (typeof initOptions.ci === 'boolean') {
|
|
201
|
+
return {
|
|
202
|
+
value: initOptions.ci,
|
|
203
|
+
shouldAsk: false,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (typeof selectedPreset?.ci === 'boolean') {
|
|
208
|
+
return {
|
|
209
|
+
value: selectedPreset.ci,
|
|
210
|
+
shouldAsk: false,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (typeof selectedProfilePack?.defaultCi === 'boolean') {
|
|
215
|
+
return {
|
|
216
|
+
value: selectedProfilePack.defaultCi,
|
|
217
|
+
shouldAsk: Boolean(!selectedProfilePack.lockCi),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (selectedProfile.lockCi) {
|
|
222
|
+
return {
|
|
223
|
+
value: selectedProfile.defaultCi,
|
|
224
|
+
shouldAsk: false,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
value: selectedProfile.defaultCi,
|
|
230
|
+
shouldAsk: true,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
159
234
|
async function askStackSelection(promptMessage, selectableStackFileNames, userInterface) {
|
|
160
235
|
const stackDisplayChoices = selectableStackFileNames.map((stackFileName) => toTitleCase(stackFileName));
|
|
161
236
|
const selectedDisplayChoice = await askChoice(promptMessage, stackDisplayChoices, userInterface);
|
|
@@ -242,8 +317,6 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
242
317
|
const wasDirectoryEffectivelyEmpty = await isDirectoryEffectivelyEmpty(resolvedTargetDirectoryPath);
|
|
243
318
|
const hadExistingProjectDocsBeforeInit = await hasExistingProjectDocs(resolvedTargetDirectoryPath);
|
|
244
319
|
|
|
245
|
-
await createBackup(resolvedTargetDirectoryPath);
|
|
246
|
-
|
|
247
320
|
const userInterface = createInterface({ input: stdin, output: stdout });
|
|
248
321
|
|
|
249
322
|
try {
|
|
@@ -442,20 +515,21 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
442
515
|
let selectedAdditionalBlueprintFileNames = [];
|
|
443
516
|
let detectedSetupWasApplied = false;
|
|
444
517
|
let selectedProjectScopeKey = 'both';
|
|
445
|
-
let selectedProjectScopeLabel =
|
|
446
|
-
(scopeChoice) => scopeChoice.key === 'both'
|
|
447
|
-
)?.label || 'Both (frontend + backend)';
|
|
448
|
-
|
|
518
|
+
let selectedProjectScopeLabel = resolveProjectScopeLabelFromKey('both');
|
|
449
519
|
let architectureRecommendation = null;
|
|
450
|
-
let architectureProjectDescription = '';
|
|
451
|
-
let
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
520
|
+
let architectureProjectDescription = String(initOptions.projectDescription || '').trim();
|
|
521
|
+
let discoveryAnswers = null;
|
|
522
|
+
const ciGuardrailsSelection = resolveSilentCiGuardrailsDefault({
|
|
523
|
+
initOptions,
|
|
524
|
+
selectedPreset,
|
|
525
|
+
selectedProfilePack,
|
|
526
|
+
selectedProfile,
|
|
527
|
+
});
|
|
528
|
+
const isFreshProjectTarget = !projectDetection.hasExistingProjectFiles
|
|
529
|
+
&& wasDirectoryEffectivelyEmpty
|
|
530
|
+
&& !hadExistingProjectDocsBeforeInit;
|
|
531
|
+
const shouldRunInteractiveScaffolding = isInteractiveSession
|
|
532
|
+
&& (initOptions.scaffoldDocs === true || (initOptions.scaffoldDocs !== false && isFreshProjectTarget));
|
|
459
533
|
|
|
460
534
|
const detectedSetupDecision = await resolveDetectedSetupDecision({
|
|
461
535
|
shouldAutoApplyDetectedStack,
|
|
@@ -479,37 +553,76 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
479
553
|
selectedAdditionalStackFileNames = detectedSetupDecision.selectedAdditionalStackFileNames;
|
|
480
554
|
detectedBlueprintFileName = detectedSetupDecision.detectedBlueprintFileName;
|
|
481
555
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
556
|
+
if (initOptions.projectConfig) {
|
|
557
|
+
discoveryAnswers = await loadProjectConfig(initOptions.projectConfig);
|
|
558
|
+
console.log(`\nLoaded project configuration from: ${initOptions.projectConfig}`);
|
|
559
|
+
} else if (shouldRunInteractiveScaffolding) {
|
|
560
|
+
discoveryAnswers = await runProjectDiscovery(userInterface, {
|
|
561
|
+
defaultProjectName: path.basename(resolvedTargetDirectoryPath),
|
|
562
|
+
defaultProjectDescription: architectureProjectDescription,
|
|
563
|
+
defaultIncludeCiGuardrails: ciGuardrailsSelection.value,
|
|
564
|
+
askForCiGuardrails: ciGuardrailsSelection.shouldAsk,
|
|
565
|
+
});
|
|
566
|
+
} else if (initOptions.scaffoldDocs === true && !isInteractiveSession) {
|
|
567
|
+
throw new Error('Non-interactive scaffolding requires --project-config when --scaffold-docs is enabled.');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (discoveryAnswers?.projectDescription) {
|
|
571
|
+
architectureProjectDescription = discoveryAnswers.projectDescription;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (discoveryAnswers) {
|
|
575
|
+
selectedProjectScopeKey = inferProjectScopeFromDiscoveryAnswers(discoveryAnswers);
|
|
576
|
+
selectedProjectScopeLabel = resolveProjectScopeLabelFromKey(selectedProjectScopeKey);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const shouldUseSilentArchitectureSelection = !selectedStackFileNameFromOption
|
|
580
|
+
&& !selectedPreset?.stack
|
|
581
|
+
&& !shouldAutoApplyDetectedStack
|
|
582
|
+
&& !selectedProfilePack?.defaultStackFileName
|
|
583
|
+
&& !selectedProfile.defaultStackFileName;
|
|
584
|
+
|
|
585
|
+
if (shouldUseSilentArchitectureSelection) {
|
|
586
|
+
const architectureScopeStackCandidates = filterStackFileNamesByCandidates(
|
|
587
|
+
stackFileNames,
|
|
588
|
+
resolveScopeStackCandidates(selectedProjectScopeKey)
|
|
589
|
+
);
|
|
590
|
+
const architectureScopeBlueprintCandidates = filterBlueprintFileNamesByCandidates(
|
|
591
|
+
blueprintFileNames,
|
|
592
|
+
resolveScopeBlueprintCandidates(selectedProjectScopeKey)
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
architectureRecommendation = recommendArchitecture({
|
|
596
|
+
projectDescription: architectureProjectDescription || `A software project named ${path.basename(resolvedTargetDirectoryPath)}.`,
|
|
597
|
+
projectDetection,
|
|
598
|
+
stackFileNames: architectureScopeStackCandidates,
|
|
599
|
+
blueprintFileNames: architectureScopeBlueprintCandidates,
|
|
600
|
+
tokenBudget: initOptions.architectTokenBudget,
|
|
601
|
+
timeoutMs: initOptions.architectTimeoutMs,
|
|
487
602
|
researchMode: initOptions.architectResearchMode,
|
|
488
603
|
enableRealtimeResearch: initOptions.enableRealtimeResearch,
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
stackFileNames,
|
|
492
|
-
blueprintFileNames,
|
|
493
|
-
userInterface,
|
|
494
|
-
isInteractiveSession,
|
|
495
|
-
initialSelectedProjectScopeKey: selectedProjectScopeKey,
|
|
496
|
-
initialSelectedProjectScopeLabel: selectedProjectScopeLabel,
|
|
497
|
-
initialSelectedManualStackFileName: selectedManualStackFileName,
|
|
498
|
-
initialSelectedManualBlueprintFileName: selectedManualBlueprintFileName,
|
|
499
|
-
architectPreferenceState,
|
|
500
|
-
askStackSelection,
|
|
501
|
-
askBlueprintSelection,
|
|
502
|
-
detectionTransparency,
|
|
503
|
-
});
|
|
604
|
+
realtimeSignalFilePath: initOptions.architectRealtimeSignalFile,
|
|
605
|
+
});
|
|
504
606
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
607
|
+
architectureRecommendation.projectDomain = {
|
|
608
|
+
key: selectedProjectScopeKey,
|
|
609
|
+
label: selectedProjectScopeLabel,
|
|
610
|
+
};
|
|
611
|
+
architectureRecommendation.userVeto = {
|
|
612
|
+
applied: false,
|
|
613
|
+
selectedStackFileName: architectureRecommendation.recommendedStackFileName,
|
|
614
|
+
selectedBlueprintFileName: architectureRecommendation.recommendedBlueprintFileName,
|
|
615
|
+
source: projectDetection.hasExistingProjectFiles ? 'silent-existing-bootstrap' : 'silent-fresh-bootstrap',
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
selectedManualStackFileName = architectureRecommendation.recommendedStackFileName;
|
|
619
|
+
selectedManualBlueprintFileName = architectureRecommendation.recommendedBlueprintFileName;
|
|
620
|
+
|
|
621
|
+
if (!projectDetection.hasExistingProjectFiles) {
|
|
622
|
+
detectionTransparency.quickConfirmation.response = 'fresh-project-streamlined';
|
|
623
|
+
detectionTransparency.decision.mode = 'fresh-project-streamlined';
|
|
624
|
+
}
|
|
625
|
+
}
|
|
513
626
|
|
|
514
627
|
const blueprintDisplayChoices = blueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName));
|
|
515
628
|
|
|
@@ -550,15 +663,6 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
550
663
|
if (architectureRecommendation) {
|
|
551
664
|
architectureRecommendation.appliedStackFileName = selectedResolvedStackFileName;
|
|
552
665
|
architectureRecommendation.appliedBlueprintFileName = selectedResolvedBlueprintFileName;
|
|
553
|
-
|
|
554
|
-
if (!architectureRecommendation.userVeto) {
|
|
555
|
-
architectureRecommendation.userVeto = {
|
|
556
|
-
applied: false,
|
|
557
|
-
selectedStackFileName: selectedResolvedStackFileName,
|
|
558
|
-
selectedBlueprintFileName: selectedResolvedBlueprintFileName,
|
|
559
|
-
source: 'recommendation',
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
666
|
}
|
|
563
667
|
|
|
564
668
|
const derivedAdditionalBlueprintFileNames = deriveAdditionalBlueprintFileNamesFromStacks(
|
|
@@ -580,23 +684,25 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
580
684
|
detectionTransparency.decision.selectedAdditionalBlueprintFileNames = selectedAdditionalBlueprintFileNames;
|
|
581
685
|
detectionTransparency.decision.usedDetectedSetup = detectedSetupWasApplied;
|
|
582
686
|
|
|
583
|
-
const includeCiGuardrails = typeof
|
|
584
|
-
?
|
|
585
|
-
:
|
|
586
|
-
?
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
:
|
|
687
|
+
const includeCiGuardrails = typeof discoveryAnswers?.includeCiGuardrails === 'boolean'
|
|
688
|
+
? discoveryAnswers.includeCiGuardrails
|
|
689
|
+
: ciGuardrailsSelection.shouldAsk
|
|
690
|
+
? (!isInteractiveSession
|
|
691
|
+
? ciGuardrailsSelection.value
|
|
692
|
+
: await askYesNo(
|
|
693
|
+
'Enable CI/CD quality checks (guardrails) and the LLM Judge policy?',
|
|
694
|
+
userInterface,
|
|
695
|
+
ciGuardrailsSelection.value
|
|
696
|
+
))
|
|
697
|
+
: ciGuardrailsSelection.value;
|
|
594
698
|
|
|
595
699
|
detectionTransparency.activeRulesSummary.ciGuardrailsEnabled = includeCiGuardrails;
|
|
596
700
|
|
|
597
701
|
detectionTransparency.decision.selectedProjectScopeKey = selectedProjectScopeKey;
|
|
598
702
|
detectionTransparency.decision.selectedProjectScopeLabel = selectedProjectScopeLabel;
|
|
599
703
|
|
|
704
|
+
await createBackup(resolvedTargetDirectoryPath);
|
|
705
|
+
|
|
600
706
|
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath, {
|
|
601
707
|
includeMcpTemplate: shouldIncludeMcpTemplate,
|
|
602
708
|
});
|
|
@@ -629,83 +735,50 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
629
735
|
// --- Project Documentation Scaffolding ---
|
|
630
736
|
let scaffoldingResult = null;
|
|
631
737
|
const supplementalMaterializedDocFileNames = [];
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
if (shouldOfferScaffolding) {
|
|
638
|
-
if (initOptions.scaffoldDocs === true && !initOptions.projectConfig && !isInteractiveSession) {
|
|
639
|
-
throw new Error('Non-interactive scaffolding requires --project-config when --scaffold-docs is enabled.');
|
|
738
|
+
if (discoveryAnswers) {
|
|
739
|
+
const normalizedConfigDocsLanguage = normalizeDocsLanguage(discoveryAnswers.docsLang || '');
|
|
740
|
+
if (discoveryAnswers.docsLang && !normalizedConfigDocsLanguage) {
|
|
741
|
+
throw new Error(`Unsupported docs language in project config: ${discoveryAnswers.docsLang}. Supported values: en, id`);
|
|
640
742
|
}
|
|
641
743
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
? false
|
|
646
|
-
: await askYesNo(
|
|
647
|
-
'This is a fresh project. Want me to scaffold project documentation (architecture, database, API contract, flow)?',
|
|
648
|
-
userInterface,
|
|
649
|
-
true
|
|
650
|
-
));
|
|
744
|
+
// Keep generated docs in English by default to align with the writing scope.
|
|
745
|
+
// A different output language is only used when explicitly requested via --docs-lang.
|
|
746
|
+
const selectedDocsLanguage = initOptions.docsLang;
|
|
651
747
|
|
|
652
|
-
if (
|
|
653
|
-
|
|
748
|
+
if (!initOptions.docsLangProvided && normalizedConfigDocsLanguage && normalizedConfigDocsLanguage !== 'en') {
|
|
749
|
+
console.log('[INFO] Project config docsLang is set, but output defaults to English. Use --docs-lang to override.');
|
|
750
|
+
}
|
|
654
751
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
752
|
+
scaffoldingResult = await generateProjectDocumentation(
|
|
753
|
+
resolvedTargetDirectoryPath,
|
|
754
|
+
discoveryAnswers,
|
|
755
|
+
{
|
|
756
|
+
stackFileName: selectedResolvedStackFileName,
|
|
757
|
+
additionalStackFileNames: selectedAdditionalStackFileNames,
|
|
758
|
+
blueprintFileName: selectedResolvedBlueprintFileName,
|
|
759
|
+
additionalBlueprintFileNames: selectedAdditionalBlueprintFileNames,
|
|
760
|
+
runtimeEnvironmentKey: selectedRuntimeEnvironmentKey,
|
|
761
|
+
runtimeEnvironmentLabel: resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey),
|
|
762
|
+
architectureRecommendation,
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
docsLanguage: selectedDocsLanguage,
|
|
663
766
|
}
|
|
767
|
+
);
|
|
664
768
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
769
|
+
if (scaffoldingResult.bootstrapMode === 'ai-synthesis') {
|
|
770
|
+
console.log(`\nAI synthesis bootstrap prompts generated in .agent-context/prompts/:`);
|
|
771
|
+
for (const generatedPromptFileName of scaffoldingResult.generatedPromptFileNames || []) {
|
|
772
|
+
console.log(` - .agent-context/prompts/${generatedPromptFileName}`);
|
|
668
773
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
// A different output language is only used when explicitly requested via --docs-lang.
|
|
672
|
-
const selectedDocsLanguage = initOptions.docsLang;
|
|
673
|
-
|
|
674
|
-
if (!initOptions.docsLangProvided && normalizedConfigDocsLanguage && normalizedConfigDocsLanguage !== 'en') {
|
|
675
|
-
console.log('[INFO] Project config docsLang is set, but output defaults to English. Use --docs-lang to override.');
|
|
774
|
+
for (const materializedFileName of scaffoldingResult.materializedFileNames || []) {
|
|
775
|
+
console.log(` - docs/${materializedFileName}`);
|
|
676
776
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
{
|
|
682
|
-
stackFileName: selectedResolvedStackFileName,
|
|
683
|
-
additionalStackFileNames: selectedAdditionalStackFileNames,
|
|
684
|
-
blueprintFileName: selectedResolvedBlueprintFileName,
|
|
685
|
-
additionalBlueprintFileNames: selectedAdditionalBlueprintFileNames,
|
|
686
|
-
runtimeEnvironmentKey: selectedRuntimeEnvironmentKey,
|
|
687
|
-
runtimeEnvironmentLabel: resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey),
|
|
688
|
-
architectureRecommendation,
|
|
689
|
-
},
|
|
690
|
-
{
|
|
691
|
-
docsLanguage: selectedDocsLanguage,
|
|
692
|
-
}
|
|
693
|
-
);
|
|
694
|
-
|
|
695
|
-
if (scaffoldingResult.bootstrapMode === 'ai-synthesis') {
|
|
696
|
-
console.log(`\nAI synthesis bootstrap prompts generated in .agent-context/prompts/:`);
|
|
697
|
-
for (const generatedPromptFileName of scaffoldingResult.generatedPromptFileNames || []) {
|
|
698
|
-
console.log(` - .agent-context/prompts/${generatedPromptFileName}`);
|
|
699
|
-
}
|
|
700
|
-
for (const materializedFileName of scaffoldingResult.materializedFileNames || []) {
|
|
701
|
-
console.log(` - docs/${materializedFileName}`);
|
|
702
|
-
}
|
|
703
|
-
console.log('Project docs will be authored dynamically by your IDE assistant from these prompts.');
|
|
704
|
-
} else {
|
|
705
|
-
console.log(`\nProject documentation generated in docs/:`);
|
|
706
|
-
for (const generatedFileName of scaffoldingResult.generatedFileNames) {
|
|
707
|
-
console.log(` - docs/${generatedFileName}`);
|
|
708
|
-
}
|
|
777
|
+
console.log('Project docs will be authored dynamically by your IDE assistant from these prompts.');
|
|
778
|
+
} else {
|
|
779
|
+
console.log(`\nProject documentation generated in docs/:`);
|
|
780
|
+
for (const generatedFileName of scaffoldingResult.generatedFileNames) {
|
|
781
|
+
console.log(` - docs/${generatedFileName}`);
|
|
709
782
|
}
|
|
710
783
|
}
|
|
711
784
|
}
|
|
@@ -795,10 +868,6 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
795
868
|
uiScopeSignals: existingProjectUiScopeSignals,
|
|
796
869
|
});
|
|
797
870
|
|
|
798
|
-
if (architectPreferenceUpdated && architectPreferenceState) {
|
|
799
|
-
await writeArchitectPreferenceState(architectPreferenceState);
|
|
800
|
-
}
|
|
801
|
-
|
|
802
871
|
console.log('\nInitialization complete.');
|
|
803
872
|
console.log(`- Target directory: ${resolvedTargetDirectoryPath}`);
|
|
804
873
|
console.log(`- Profile: ${selectedProfile.displayName}`);
|
|
@@ -808,18 +877,8 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
808
877
|
if (selectedProfilePack) {
|
|
809
878
|
console.log(`- Team profile pack: ${selectedProfilePack.displayName}`);
|
|
810
879
|
}
|
|
811
|
-
if (
|
|
812
|
-
console.log(
|
|
813
|
-
`- Architect recommendation: ${toTitleCase(architectureRecommendation.recommendedStackFileName)} + ${toTitleCase(architectureRecommendation.recommendedBlueprintFileName)} (${architectureRecommendation.confidenceLabel})`
|
|
814
|
-
);
|
|
815
|
-
if (!projectDetection.hasExistingProjectFiles) {
|
|
816
|
-
console.log(`- Project domain: ${selectedProjectScopeLabel}`);
|
|
817
|
-
}
|
|
818
|
-
if (architectureRecommendation.userVeto?.applied) {
|
|
819
|
-
console.log(
|
|
820
|
-
`- User veto path: applied (${toTitleCase(architectureRecommendation.userVeto.selectedStackFileName)} + ${toTitleCase(architectureRecommendation.userVeto.selectedBlueprintFileName)})`
|
|
821
|
-
);
|
|
822
|
-
}
|
|
880
|
+
if (!projectDetection.hasExistingProjectFiles) {
|
|
881
|
+
console.log(`- Project domain: ${selectedProjectScopeLabel}`);
|
|
823
882
|
}
|
|
824
883
|
console.log(`- Stack: ${toTitleCase(selectedResolvedStackFileName)}`);
|
|
825
884
|
if (selectedAdditionalStackFileNames.length > 0) {
|
package/lib/cli/compiler.mjs
CHANGED
|
@@ -396,9 +396,15 @@ export async function buildCompiledRulesContent({
|
|
|
396
396
|
...projectDocsEntries.map((docFileName, docIndex) => `${docIndex + 1}. docs/${docFileName}`),
|
|
397
397
|
'',
|
|
398
398
|
'Universal SOP hard block policy:',
|
|
399
|
+
'- Stop implementation if docs/project-brief.md is missing.',
|
|
399
400
|
'- Stop implementation if docs/architecture-decision-record.md (alias: docs/Architecture-Decision-Record.md) is missing.',
|
|
401
|
+
'- Stop implementation if docs/flow-overview.md is missing.',
|
|
402
|
+
'- If the product uses persistent data, docs/database-schema.md must exist before coding continues.',
|
|
403
|
+
'- If the product exposes API or web application flows, docs/api-contract.md must exist before coding continues.',
|
|
400
404
|
'- For UI scope, stop implementation if docs/DESIGN.md or docs/design-intent.json is missing.',
|
|
401
405
|
'- Materialize missing docs first, then continue coding.',
|
|
406
|
+
'- Bootstrap missing docs from real repo evidence and the latest user request. Do not write generic placeholder templates.',
|
|
407
|
+
'- Separate confirmed facts from assumptions and end each major explanation with the next validation action.',
|
|
402
408
|
'',
|
|
403
409
|
'These docs were generated during project initialization and reflect the architecture,',
|
|
404
410
|
'database design, API contracts, and application flows chosen for this project.',
|
|
@@ -428,10 +434,15 @@ export async function buildCompiledRulesContent({
|
|
|
428
434
|
'',
|
|
429
435
|
'Bootstrap policy:',
|
|
430
436
|
'- Hard block: do not write application code until docs/project-brief.md and docs/architecture-decision-record.md exist.',
|
|
437
|
+
'- docs/flow-overview.md must also exist before coding continues.',
|
|
438
|
+
'- Add docs/database-schema.md when persistent data is involved.',
|
|
439
|
+
'- Add docs/api-contract.md when API or web application flows are involved.',
|
|
431
440
|
'- If docs/project-brief.md is missing, execute bootstrap-project-context prompt immediately.',
|
|
432
441
|
hasBootstrapDesignPrompt
|
|
433
442
|
? '- For UI scope: if docs/DESIGN.md or docs/design-intent.json is missing, execute bootstrap-design prompt before implementing UI surfaces.'
|
|
434
443
|
: '- For UI scope: add a design bootstrap prompt before implementing UI surfaces.',
|
|
444
|
+
'- Bootstrap docs from repo evidence and the latest user request. Do not use generic placeholder templates.',
|
|
445
|
+
'- Separate confirmed facts from assumptions, include an Assumptions to Validate section when context is incomplete, and end with the next validation action.',
|
|
435
446
|
'- Save generated docs under docs/ and keep them updated when feature scope changes.',
|
|
436
447
|
'Latest user prompt defines current feature scope and product direction.',
|
|
437
448
|
'Treat synthesized docs as living references, then continue implementation with those docs as source of truth.',
|
package/lib/cli/detector.mjs
CHANGED
|
@@ -100,6 +100,24 @@ const PROJECT_MARKER_FILE_NAMES = new Set([
|
|
|
100
100
|
'tsconfig.json',
|
|
101
101
|
...DIRECT_UI_MARKER_NAMES,
|
|
102
102
|
]);
|
|
103
|
+
const INTERNAL_GOVERNANCE_SURFACE_NAMES = new Set([
|
|
104
|
+
'.agent-context',
|
|
105
|
+
'.agent-instructions.md',
|
|
106
|
+
'.agent-override.md',
|
|
107
|
+
'.agentic-backup',
|
|
108
|
+
'.agents',
|
|
109
|
+
'.clauderc',
|
|
110
|
+
'.cursorrules',
|
|
111
|
+
'.cursor',
|
|
112
|
+
'.gemini',
|
|
113
|
+
'.github',
|
|
114
|
+
'.instructions.md',
|
|
115
|
+
'.vscode',
|
|
116
|
+
'.windsurfrules',
|
|
117
|
+
'.zed',
|
|
118
|
+
'AGENTS.md',
|
|
119
|
+
'mcp.json',
|
|
120
|
+
]);
|
|
103
121
|
|
|
104
122
|
function looksLikeWorkspaceSearchCandidate(directoryName) {
|
|
105
123
|
const normalizedDirectoryName = String(directoryName || '').trim().toLowerCase();
|
|
@@ -148,6 +166,10 @@ export async function collectProjectMarkers(targetDirectoryPath) {
|
|
|
148
166
|
continue;
|
|
149
167
|
}
|
|
150
168
|
|
|
169
|
+
if (INTERNAL_GOVERNANCE_SURFACE_NAMES.has(directoryEntry.name)) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
151
173
|
markerNames.add(directoryEntry.name);
|
|
152
174
|
}
|
|
153
175
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import fs from 'node:fs/promises';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
|
|
9
|
-
import { ensureDirectory, askChoice, toTitleCase, pathExists } from './utils.mjs';
|
|
9
|
+
import { ensureDirectory, askChoice, askYesNo, toTitleCase, pathExists } from './utils.mjs';
|
|
10
10
|
|
|
11
11
|
const SUPPORTED_DOC_LANGUAGES = new Set(['en', 'id']);
|
|
12
12
|
const PROJECT_DOC_FILE_NAMES = [
|
|
@@ -137,14 +137,18 @@ export function normalizeDocsLanguage(rawDocsLanguage = 'en') {
|
|
|
137
137
|
* Returns a structured object with all user responses.
|
|
138
138
|
*/
|
|
139
139
|
export async function runProjectDiscovery(userInterface, options = {}) {
|
|
140
|
-
console.log('\n--- Project
|
|
141
|
-
console.log('I will ask
|
|
140
|
+
console.log('\n--- Project Setup ---');
|
|
141
|
+
console.log('I will ask one focused set of questions to bootstrap project context and documentation.');
|
|
142
142
|
console.log('This helps AI agents understand your project before writing code.\n');
|
|
143
143
|
console.log('You can answer in your own language.');
|
|
144
144
|
console.log('CLI prompts stay in English, but non-English answers are fully supported.\n');
|
|
145
145
|
|
|
146
146
|
const defaultProjectName = (options.defaultProjectName || '').trim();
|
|
147
147
|
const defaultProjectDescription = String(options.defaultProjectDescription || '').trim();
|
|
148
|
+
const defaultIncludeCiGuardrails = typeof options.defaultIncludeCiGuardrails === 'boolean'
|
|
149
|
+
? options.defaultIncludeCiGuardrails
|
|
150
|
+
: true;
|
|
151
|
+
const shouldAskForCiGuardrails = options.askForCiGuardrails !== false;
|
|
148
152
|
let projectName = '';
|
|
149
153
|
|
|
150
154
|
const projectNamePrompt = defaultProjectName
|
|
@@ -171,6 +175,14 @@ export async function runProjectDiscovery(userInterface, options = {}) {
|
|
|
171
175
|
projectDescription = defaultProjectDescription || `A ${projectName} project.`;
|
|
172
176
|
}
|
|
173
177
|
|
|
178
|
+
const includeCiGuardrails = shouldAskForCiGuardrails
|
|
179
|
+
? await askYesNo(
|
|
180
|
+
'Enable CI/CD quality checks (guardrails) and the LLM Judge policy?',
|
|
181
|
+
userInterface,
|
|
182
|
+
defaultIncludeCiGuardrails
|
|
183
|
+
)
|
|
184
|
+
: defaultIncludeCiGuardrails;
|
|
185
|
+
|
|
174
186
|
const domainSelection = await askChoice(
|
|
175
187
|
'Primary domain:',
|
|
176
188
|
DOMAIN_CHOICES,
|
|
@@ -210,24 +222,18 @@ export async function runProjectDiscovery(userInterface, options = {}) {
|
|
|
210
222
|
userInterface
|
|
211
223
|
);
|
|
212
224
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (features.length === 0) {
|
|
216
|
-
features.push('Core functionality (define during development)');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const additionalContext = (await userInterface.question('\nAdditional context (optional, press Enter to skip): ')).trim()
|
|
220
|
-
|| 'No additional context provided.';
|
|
225
|
+
const features = await askFeatureList(userInterface);
|
|
221
226
|
|
|
222
227
|
return {
|
|
223
228
|
projectName,
|
|
224
229
|
projectDescription,
|
|
230
|
+
includeCiGuardrails,
|
|
225
231
|
primaryDomain,
|
|
226
232
|
databaseChoice,
|
|
227
233
|
authStrategy,
|
|
228
234
|
dockerStrategy,
|
|
229
235
|
features,
|
|
230
|
-
additionalContext,
|
|
236
|
+
additionalContext: 'No additional context provided.',
|
|
231
237
|
};
|
|
232
238
|
}
|
|
233
239
|
|
|
@@ -508,7 +514,14 @@ function buildDesignIntentContractObject({
|
|
|
508
514
|
primaryDomain,
|
|
509
515
|
features,
|
|
510
516
|
});
|
|
511
|
-
const
|
|
517
|
+
const normalizedPrimaryDomain = String(primaryDomain || '').trim().toLowerCase();
|
|
518
|
+
const resolvedSpacingPattern = inferredKeywords.densityMode === 'dense'
|
|
519
|
+
? 'compact-grid'
|
|
520
|
+
: normalizedPrimaryDomain.includes('mobile')
|
|
521
|
+
? 'mobile-first-single-axis'
|
|
522
|
+
: inferredKeywords.densityMode === 'focused'
|
|
523
|
+
? 'high-contrast-rhythm'
|
|
524
|
+
: 'balanced-grid';
|
|
512
525
|
|
|
513
526
|
return {
|
|
514
527
|
mode: 'dynamic',
|
|
@@ -531,14 +544,14 @@ function buildDesignIntentContractObject({
|
|
|
531
544
|
mathSystems: {
|
|
532
545
|
typographyScaleRatio: inferredKeywords.typographyScaleRatio,
|
|
533
546
|
baseGridUnit: inferredKeywords.baseGridUnit,
|
|
534
|
-
spacingPattern:
|
|
547
|
+
spacingPattern: resolvedSpacingPattern,
|
|
535
548
|
densityMode: inferredKeywords.densityMode,
|
|
536
549
|
},
|
|
537
550
|
colorTruth: {
|
|
538
551
|
format: 'OKLCH',
|
|
539
552
|
allowHexDerivatives: true,
|
|
540
553
|
requirePerceptualLightnessCurve: true,
|
|
541
|
-
paletteRoles:
|
|
554
|
+
paletteRoles: ['base', 'surface', 'accent'],
|
|
542
555
|
intent: inferredKeywords.colorIntent,
|
|
543
556
|
},
|
|
544
557
|
crossViewportAdaptation: {
|
|
@@ -603,7 +616,6 @@ function buildDesignIntentContractObject({
|
|
|
603
616
|
'.agent-context/rules/microservices.md',
|
|
604
617
|
],
|
|
605
618
|
},
|
|
606
|
-
architectSignals: designSignals,
|
|
607
619
|
...supplementalFields,
|
|
608
620
|
};
|
|
609
621
|
}
|
|
@@ -766,7 +778,7 @@ function buildProjectContextBootstrapPrompt({
|
|
|
766
778
|
}) {
|
|
767
779
|
const featuresList = Array.isArray(discoveryAnswers.features) && discoveryAnswers.features.length > 0
|
|
768
780
|
? discoveryAnswers.features.map((feature, featureIndex) => `${featureIndex + 1}. ${feature}`).join('\n')
|
|
769
|
-
: '
|
|
781
|
+
: 'Derive the first concrete feature set from the project name, description, and domain. Do not invent arbitrary modules just to fill space.';
|
|
770
782
|
|
|
771
783
|
const expectedDocsList = expectedDocFileNames
|
|
772
784
|
.map((fileName, fileIndex) => `${fileIndex + 1}. docs/${fileName}`)
|
|
@@ -802,6 +814,11 @@ function buildProjectContextBootstrapPrompt({
|
|
|
802
814
|
'3. Keep stack, database, and auth aligned with the project constraints below unless user explicitly requests migration.',
|
|
803
815
|
'4. Output must be implementation-ready for engineers, not generic textbook explanation.',
|
|
804
816
|
'5. For any research-backed claim, include citation metadata (source + fetchedAt timestamp) from the Architect Engine Snapshot.',
|
|
817
|
+
'6. Write for native English speakers at an 8th-grade reading level. Use clear, direct, plain language.',
|
|
818
|
+
'7. Avoid emoji, AI cliches, buzzwords, academic phrasing, padding, and generic filler.',
|
|
819
|
+
'8. Separate confirmed facts from assumptions explicitly. When context is incomplete, add an `Assumptions to Validate` section and a `Next Validation Action` line.',
|
|
820
|
+
'9. If user inputs conflict with repo evidence, call out the conflict and choose the safer interpretation instead of silently forcing a generic answer.',
|
|
821
|
+
'10. Do not invent modules or architecture layers only to make the docs look complete.',
|
|
805
822
|
'',
|
|
806
823
|
'## Project Inputs',
|
|
807
824
|
`- Project name: ${discoveryAnswers.projectName}`,
|
|
@@ -829,8 +846,10 @@ function buildProjectContextBootstrapPrompt({
|
|
|
829
846
|
'',
|
|
830
847
|
'## Required Execution',
|
|
831
848
|
'1. Create all required docs files listed above with complete Markdown content.',
|
|
832
|
-
'2.
|
|
833
|
-
'3.
|
|
849
|
+
'2. Make the docs adaptive to the real repo and prompt context. These are living references, not frozen templates.',
|
|
850
|
+
'3. In docs/project-brief.md and docs/architecture-decision-record.md, include explicit sections for confirmed facts, assumptions to validate, and next validation actions whenever context is incomplete.',
|
|
851
|
+
'4. Keep content original, specific to this project, and actionable for implementation.',
|
|
852
|
+
'5. After writing docs, continue coding tasks using these docs as living project context.',
|
|
834
853
|
'',
|
|
835
854
|
].join('\n');
|
|
836
855
|
}
|
|
@@ -841,8 +860,6 @@ function buildDesignBootstrapPrompt({
|
|
|
841
860
|
docsLanguage,
|
|
842
861
|
architectureRecommendation,
|
|
843
862
|
}) {
|
|
844
|
-
const designSignals = architectureRecommendation?.designGuidance?.normalizedSignals || null;
|
|
845
|
-
const designSignalsJson = JSON.stringify(designSignals, null, 2);
|
|
846
863
|
const designIntentSeed = buildDesignIntentSeed({
|
|
847
864
|
discoveryAnswers,
|
|
848
865
|
initContext,
|
|
@@ -918,12 +935,6 @@ function buildDesignBootstrapPrompt({
|
|
|
918
935
|
`- Stack: ${toTitleCase(initContext.stackFileName)}`,
|
|
919
936
|
`- Blueprint: ${toTitleCase(initContext.blueprintFileName)}`,
|
|
920
937
|
'',
|
|
921
|
-
'## Architect Design Signals (raw control vector)',
|
|
922
|
-
'Use this only as baseline fuel, then expand into full design direction with original reasoning:',
|
|
923
|
-
'```json',
|
|
924
|
-
designSignalsJson || 'null',
|
|
925
|
-
'```',
|
|
926
|
-
'',
|
|
927
938
|
'## Seed Machine Contract',
|
|
928
939
|
'Refine this seed instead of discarding it. Keep the final JSON aligned with the markdown design system.',
|
|
929
940
|
'```json',
|
|
@@ -1133,6 +1144,7 @@ export async function loadProjectConfig(configFilePath) {
|
|
|
1133
1144
|
return {
|
|
1134
1145
|
projectName: configEntries.projectName || configEntries.name || '',
|
|
1135
1146
|
projectDescription: configEntries.projectDescription || configEntries.description || '',
|
|
1147
|
+
includeCiGuardrails: parseBooleanLikeValue(configEntries.includeCiGuardrails) ?? parseBooleanLikeValue(configEntries.ci) ?? true,
|
|
1136
1148
|
primaryDomain: configEntries.primaryDomain || configEntries.domain || 'API service',
|
|
1137
1149
|
databaseChoice: configEntries.databaseChoice || configEntries.database || 'None (stateless service)',
|
|
1138
1150
|
authStrategy: configEntries.authStrategy || configEntries.auth || 'None (public service)',
|