@ryuenn3123/agentic-senior-core 2.5.21 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/.agent-context/prompts/init-project.md +5 -5
  2. package/.agent-context/prompts/refactor.md +2 -1
  3. package/.agent-context/prompts/review-code.md +3 -2
  4. package/.agent-context/review-checklists/pr-checklist.md +8 -1
  5. package/.agent-context/rules/architecture.md +11 -0
  6. package/.agent-context/rules/frontend-architecture.md +2 -2
  7. package/.agent-context/state/architecture-map.md +1 -1
  8. package/.agent-context/state/memory-continuity-benchmark.json +1 -1
  9. package/.agents/workflows/init-project.md +3 -3
  10. package/.agents/workflows/refactor.md +1 -1
  11. package/.agents/workflows/review-code.md +4 -5
  12. package/.cursorrules +27 -71
  13. package/.gemini/instructions.md +6 -7
  14. package/.github/copilot-instructions.md +5 -6
  15. package/.windsurfrules +27 -71
  16. package/AGENTS.md +7 -9
  17. package/CONTRIBUTING.md +18 -31
  18. package/README.md +28 -4
  19. package/bin/agentic-senior-core.js +0 -6
  20. package/lib/cli/commands/init.mjs +142 -655
  21. package/lib/cli/commands/launch.mjs +1 -23
  22. package/lib/cli/commands/rollback.mjs +1 -1
  23. package/lib/cli/commands/upgrade.mjs +1 -23
  24. package/lib/cli/compiler.mjs +116 -70
  25. package/lib/cli/constants.mjs +84 -26
  26. package/lib/cli/init-architecture-flow.mjs +231 -0
  27. package/lib/cli/init-detection-flow.mjs +123 -0
  28. package/lib/cli/init-options.mjs +344 -0
  29. package/lib/cli/init-selection.mjs +100 -0
  30. package/lib/cli/preflight.mjs +1 -1
  31. package/lib/cli/profile-packs.mjs +15 -1
  32. package/lib/cli/project-scaffolder.mjs +209 -161
  33. package/lib/cli/utils.mjs +17 -13
  34. package/mcp.json +19 -19
  35. package/package.json +5 -2
  36. package/scripts/context-triggered-audit.mjs +18 -18
  37. package/scripts/documentation-boundary-audit.mjs +92 -5
  38. package/scripts/forbidden-content-check.mjs +1 -1
  39. package/scripts/frontend-usability-audit.mjs +21 -28
  40. package/scripts/governance-weekly-report.mjs +29 -15
  41. package/scripts/llm-judge.mjs +2 -5
  42. package/scripts/mcp-server.mjs +389 -5
  43. package/scripts/release-gate.mjs +121 -145
  44. package/scripts/sync-thin-adapters.mjs +161 -0
  45. package/scripts/v3-purge-audit.mjs +231 -0
  46. package/scripts/validate-evidence-bundle.mjs +1 -1
  47. package/scripts/validate.mjs +224 -272
  48. package/.agent-context/blueprints/api-nextjs.md +0 -184
  49. package/.agent-context/blueprints/aspnet-api.md +0 -247
  50. package/.agent-context/blueprints/ci-github-actions.md +0 -226
  51. package/.agent-context/blueprints/ci-gitlab.md +0 -200
  52. package/.agent-context/blueprints/fastapi-service.md +0 -210
  53. package/.agent-context/blueprints/go-service.md +0 -217
  54. package/.agent-context/blueprints/graphql-grpc-api.md +0 -51
  55. package/.agent-context/blueprints/infrastructure-as-code.md +0 -62
  56. package/.agent-context/blueprints/kubernetes-manifests.md +0 -76
  57. package/.agent-context/blueprints/laravel-api.md +0 -233
  58. package/.agent-context/blueprints/mobile-app.md +0 -91
  59. package/.agent-context/blueprints/nestjs-logic.md +0 -247
  60. package/.agent-context/blueprints/observability.md +0 -227
  61. package/.agent-context/blueprints/spring-boot-api.md +0 -218
  62. package/.agent-context/profiles/platform.md +0 -13
  63. package/.agent-context/profiles/regulated.md +0 -13
  64. package/.agent-context/profiles/startup.md +0 -13
  65. package/.agent-context/review-checklists/frontend-excellence-rubric.md +0 -73
  66. package/.agent-context/review-checklists/frontend-skill-parity.md +0 -29
  67. package/.agent-context/review-checklists/frontend-usability.md +0 -35
  68. package/.agent-context/review-checklists/marketplace-acceptance.md +0 -60
  69. package/.agent-context/review-checklists/performance-audit.md +0 -71
  70. package/.agent-context/review-checklists/release-operations.md +0 -33
  71. package/.agent-context/review-checklists/security-audit.md +0 -119
  72. package/.agent-context/skills/README.md +0 -63
  73. package/.agent-context/skills/backend/README.md +0 -68
  74. package/.agent-context/skills/backend/architecture.md +0 -361
  75. package/.agent-context/skills/backend/compatibility-manifest.json +0 -8
  76. package/.agent-context/skills/backend/data-access.md +0 -231
  77. package/.agent-context/skills/backend/errors.md +0 -138
  78. package/.agent-context/skills/backend/validation.md +0 -117
  79. package/.agent-context/skills/backend.md +0 -29
  80. package/.agent-context/skills/cli/.evidence/compatibility-manifest.json +0 -5
  81. package/.agent-context/skills/cli/.evidence/sbom-excerpt.json +0 -10
  82. package/.agent-context/skills/cli/.evidence/test-report.json +0 -8
  83. package/.agent-context/skills/cli/CHANGELOG.md +0 -6
  84. package/.agent-context/skills/cli/README.md +0 -56
  85. package/.agent-context/skills/cli/compatibility-manifest.json +0 -8
  86. package/.agent-context/skills/cli/init.md +0 -38
  87. package/.agent-context/skills/cli/output.md +0 -36
  88. package/.agent-context/skills/cli/package.json +0 -5
  89. package/.agent-context/skills/cli/safety-telemetry.md +0 -39
  90. package/.agent-context/skills/cli/tests/.gitkeep +0 -1
  91. package/.agent-context/skills/cli/upgrade.md +0 -38
  92. package/.agent-context/skills/cli.md +0 -32
  93. package/.agent-context/skills/distribution/.evidence/compatibility-manifest.json +0 -9
  94. package/.agent-context/skills/distribution/.evidence/sbom-excerpt.json +0 -6
  95. package/.agent-context/skills/distribution/.evidence/test-report.json +0 -8
  96. package/.agent-context/skills/distribution/CHANGELOG.md +0 -7
  97. package/.agent-context/skills/distribution/README.md +0 -27
  98. package/.agent-context/skills/distribution/compatibility-manifest.json +0 -8
  99. package/.agent-context/skills/distribution/compatibility.md +0 -32
  100. package/.agent-context/skills/distribution/package.json +0 -5
  101. package/.agent-context/skills/distribution/provenance-attestation.md +0 -47
  102. package/.agent-context/skills/distribution/publish.md +0 -37
  103. package/.agent-context/skills/distribution/rollback.md +0 -32
  104. package/.agent-context/skills/distribution/tests/.gitkeep +0 -1
  105. package/.agent-context/skills/distribution.md +0 -32
  106. package/.agent-context/skills/frontend/.evidence/compatibility-manifest.json +0 -9
  107. package/.agent-context/skills/frontend/.evidence/sbom-excerpt.json +0 -6
  108. package/.agent-context/skills/frontend/.evidence/test-report.json +0 -8
  109. package/.agent-context/skills/frontend/CHANGELOG.md +0 -7
  110. package/.agent-context/skills/frontend/README.md +0 -50
  111. package/.agent-context/skills/frontend/accessibility.md +0 -107
  112. package/.agent-context/skills/frontend/compatibility-manifest.json +0 -8
  113. package/.agent-context/skills/frontend/conversion-clarity.md +0 -51
  114. package/.agent-context/skills/frontend/motion.md +0 -67
  115. package/.agent-context/skills/frontend/package.json +0 -5
  116. package/.agent-context/skills/frontend/performance.md +0 -63
  117. package/.agent-context/skills/frontend/responsive-delivery.md +0 -41
  118. package/.agent-context/skills/frontend/tests/.gitkeep +0 -1
  119. package/.agent-context/skills/frontend/ui-architecture.md +0 -128
  120. package/.agent-context/skills/frontend.md +0 -40
  121. package/.agent-context/skills/fullstack/.evidence/compatibility-manifest.json +0 -9
  122. package/.agent-context/skills/fullstack/.evidence/sbom-excerpt.json +0 -6
  123. package/.agent-context/skills/fullstack/.evidence/test-report.json +0 -8
  124. package/.agent-context/skills/fullstack/CHANGELOG.md +0 -7
  125. package/.agent-context/skills/fullstack/README.md +0 -27
  126. package/.agent-context/skills/fullstack/compatibility-manifest.json +0 -8
  127. package/.agent-context/skills/fullstack/contracts.md +0 -53
  128. package/.agent-context/skills/fullstack/end-to-end.md +0 -42
  129. package/.agent-context/skills/fullstack/feature-slicing.md +0 -65
  130. package/.agent-context/skills/fullstack/package.json +0 -5
  131. package/.agent-context/skills/fullstack/release-coordination.md +0 -51
  132. package/.agent-context/skills/fullstack/tests/.gitkeep +0 -1
  133. package/.agent-context/skills/fullstack.md +0 -30
  134. package/.agent-context/skills/index.json +0 -107
  135. package/.agent-context/skills/review-quality/.evidence/compatibility-manifest.json +0 -9
  136. package/.agent-context/skills/review-quality/.evidence/sbom-excerpt.json +0 -6
  137. package/.agent-context/skills/review-quality/.evidence/test-report.json +0 -8
  138. package/.agent-context/skills/review-quality/CHANGELOG.md +0 -7
  139. package/.agent-context/skills/review-quality/README.md +0 -27
  140. package/.agent-context/skills/review-quality/benchmark.md +0 -30
  141. package/.agent-context/skills/review-quality/compatibility-manifest.json +0 -8
  142. package/.agent-context/skills/review-quality/package.json +0 -5
  143. package/.agent-context/skills/review-quality/planning.md +0 -38
  144. package/.agent-context/skills/review-quality/release-decision.md +0 -49
  145. package/.agent-context/skills/review-quality/security.md +0 -34
  146. package/.agent-context/skills/review-quality/tests/.gitkeep +0 -1
  147. package/.agent-context/skills/review-quality.md +0 -34
  148. package/.agent-context/stacks/csharp.md +0 -149
  149. package/.agent-context/stacks/flutter.md +0 -16
  150. package/.agent-context/stacks/go.md +0 -181
  151. package/.agent-context/stacks/java.md +0 -135
  152. package/.agent-context/stacks/php.md +0 -192
  153. package/.agent-context/stacks/python.md +0 -153
  154. package/.agent-context/stacks/react-native.md +0 -16
  155. package/.agent-context/stacks/ruby.md +0 -80
  156. package/.agent-context/stacks/rust.md +0 -86
  157. package/.agent-context/stacks/typescript.md +0 -317
  158. package/.agent-context/state/skill-platform.json +0 -38
  159. package/lib/cli/skill-selector.mjs +0 -232
  160. package/lib/cli/templates/api-contract.md.id.tmpl +0 -143
  161. package/lib/cli/templates/api-contract.md.tmpl +0 -143
  162. package/lib/cli/templates/architecture-decision-record.md.id.tmpl +0 -106
  163. package/lib/cli/templates/architecture-decision-record.md.tmpl +0 -145
  164. package/lib/cli/templates/database-schema.md.id.tmpl +0 -74
  165. package/lib/cli/templates/database-schema.md.tmpl +0 -74
  166. package/lib/cli/templates/flow-overview.md.id.tmpl +0 -118
  167. package/lib/cli/templates/flow-overview.md.tmpl +0 -131
  168. package/lib/cli/templates/project-brief.md.id.tmpl +0 -55
  169. package/lib/cli/templates/project-brief.md.tmpl +0 -79
  170. package/scripts/init-project.ps1 +0 -105
  171. package/scripts/init-project.sh +0 -131
  172. package/scripts/skill-tier-policy.mjs +0 -76
  173. package/scripts/trust-scorer.mjs +0 -119
@@ -0,0 +1,231 @@
1
+ import path from 'node:path';
2
+
3
+ import {
4
+ PROJECT_SCOPE_CHOICES,
5
+ BLUEPRINT_RECOMMENDATIONS,
6
+ } from './constants.mjs';
7
+
8
+ import {
9
+ recommendArchitecture,
10
+ formatArchitectureRecommendation,
11
+ createUpdatedArchitectPreference,
12
+ shouldApplyRepeatedOverridePreference,
13
+ } from './architect.mjs';
14
+
15
+ import {
16
+ askChoice,
17
+ askYesNo,
18
+ toTitleCase,
19
+ } from './utils.mjs';
20
+
21
+ import {
22
+ filterStackFileNamesByCandidates,
23
+ filterBlueprintFileNamesByCandidates,
24
+ resolveProjectScopeKeyFromLabel,
25
+ resolveScopeStackCandidates,
26
+ resolveScopeBlueprintCandidates,
27
+ } from './init-selection.mjs';
28
+
29
+ const DEFAULT_PROJECT_SCOPE_KEY = 'both';
30
+ const DEFAULT_PROJECT_SCOPE_LABEL = PROJECT_SCOPE_CHOICES.find(
31
+ (scopeChoice) => scopeChoice.key === DEFAULT_PROJECT_SCOPE_KEY
32
+ )?.label || 'Both (frontend + backend)';
33
+
34
+ export async function resolveArchitectureSelection({
35
+ shouldRunArchitectureRecommendation,
36
+ initOptions,
37
+ projectDetection,
38
+ stackFileNames,
39
+ blueprintFileNames,
40
+ userInterface,
41
+ isInteractiveSession,
42
+ initialSelectedProjectScopeKey,
43
+ initialSelectedProjectScopeLabel,
44
+ initialSelectedManualStackFileName,
45
+ initialSelectedManualBlueprintFileName,
46
+ architectPreferenceState,
47
+ askStackSelection,
48
+ askBlueprintSelection,
49
+ detectionTransparency,
50
+ }) {
51
+ let selectedProjectScopeKey = initialSelectedProjectScopeKey || DEFAULT_PROJECT_SCOPE_KEY;
52
+ let selectedProjectScopeLabel = initialSelectedProjectScopeLabel || DEFAULT_PROJECT_SCOPE_LABEL;
53
+ let selectedManualStackFileName = initialSelectedManualStackFileName || null;
54
+ let selectedManualBlueprintFileName = initialSelectedManualBlueprintFileName || null;
55
+ let architectureRecommendation = null;
56
+ let nextArchitectPreferenceState = architectPreferenceState;
57
+ let architectPreferenceUpdated = false;
58
+
59
+ if (!shouldRunArchitectureRecommendation) {
60
+ return {
61
+ selectedProjectScopeKey,
62
+ selectedProjectScopeLabel,
63
+ selectedManualStackFileName,
64
+ selectedManualBlueprintFileName,
65
+ architectureRecommendation,
66
+ architectPreferenceState: nextArchitectPreferenceState,
67
+ architectPreferenceUpdated,
68
+ };
69
+ }
70
+
71
+ let architectureProjectDescription = String(initOptions.projectDescription || '').trim();
72
+ const isFreshProjectFlow = !projectDetection.hasExistingProjectFiles;
73
+
74
+ if (isFreshProjectFlow && isInteractiveSession) {
75
+ const selectedProjectScopeInput = await askChoice(
76
+ 'Project domain (frontend only, backend only, or both):',
77
+ PROJECT_SCOPE_CHOICES.map((scopeChoice) => scopeChoice.label),
78
+ userInterface
79
+ );
80
+
81
+ selectedProjectScopeKey = resolveProjectScopeKeyFromLabel(selectedProjectScopeInput);
82
+ selectedProjectScopeLabel = selectedProjectScopeInput;
83
+
84
+ if (!architectureProjectDescription) {
85
+ architectureProjectDescription = (await userInterface.question(
86
+ '\nProject description (free text): '
87
+ )).trim();
88
+ }
89
+ }
90
+
91
+ if (!architectureProjectDescription && isInteractiveSession && !isFreshProjectFlow) {
92
+ architectureProjectDescription = (await userInterface.question(
93
+ '\nDescribe your project in one short paragraph for architecture recommendation: '
94
+ )).trim();
95
+ }
96
+
97
+ if (!architectureProjectDescription) {
98
+ architectureProjectDescription = `A software project named ${path.basename(initOptions.targetDirectoryPath)}.`;
99
+ }
100
+
101
+ const scopeStackCandidates = filterStackFileNamesByCandidates(
102
+ stackFileNames,
103
+ resolveScopeStackCandidates(selectedProjectScopeKey)
104
+ );
105
+ const scopeBlueprintCandidates = filterBlueprintFileNamesByCandidates(
106
+ blueprintFileNames,
107
+ resolveScopeBlueprintCandidates(selectedProjectScopeKey)
108
+ );
109
+
110
+ architectureRecommendation = recommendArchitecture({
111
+ projectDescription: architectureProjectDescription,
112
+ projectDetection,
113
+ stackFileNames: scopeStackCandidates,
114
+ blueprintFileNames: scopeBlueprintCandidates,
115
+ tokenBudget: initOptions.architectTokenBudget,
116
+ timeoutMs: initOptions.architectTimeoutMs,
117
+ researchMode: initOptions.architectResearchMode,
118
+ enableRealtimeResearch: initOptions.enableRealtimeResearch,
119
+ realtimeSignalFilePath: initOptions.architectRealtimeSignalFile,
120
+ });
121
+
122
+ architectureRecommendation.projectDomain = {
123
+ key: selectedProjectScopeKey,
124
+ label: selectedProjectScopeLabel,
125
+ };
126
+
127
+ architectureRecommendation.userVeto = {
128
+ applied: false,
129
+ selectedStackFileName: architectureRecommendation.recommendedStackFileName,
130
+ selectedBlueprintFileName: architectureRecommendation.recommendedBlueprintFileName,
131
+ source: 'recommendation',
132
+ };
133
+
134
+ console.log(formatArchitectureRecommendation(architectureRecommendation));
135
+
136
+ const shouldSkipRecommendationDebate = shouldApplyRepeatedOverridePreference(
137
+ nextArchitectPreferenceState,
138
+ architectureRecommendation.recommendedStackFileName
139
+ );
140
+
141
+ if (isFreshProjectFlow) {
142
+ selectedManualStackFileName = architectureRecommendation.recommendedStackFileName;
143
+ selectedManualBlueprintFileName = architectureRecommendation.recommendedBlueprintFileName;
144
+
145
+ if (detectionTransparency) {
146
+ detectionTransparency.quickConfirmation.response = 'fresh-project-two-question';
147
+ detectionTransparency.decision.mode = 'fresh-project-two-question-auto';
148
+ }
149
+ } else if (shouldSkipRecommendationDebate) {
150
+ architectureRecommendation.failureModes.repeatedOverride = true;
151
+ selectedManualStackFileName = stackFileNames.includes(nextArchitectPreferenceState.preferredStackFileName)
152
+ ? nextArchitectPreferenceState.preferredStackFileName
153
+ : architectureRecommendation.recommendedStackFileName;
154
+ selectedManualBlueprintFileName = blueprintFileNames.includes(nextArchitectPreferenceState.preferredBlueprintFileName)
155
+ ? nextArchitectPreferenceState.preferredBlueprintFileName
156
+ : architectureRecommendation.recommendedBlueprintFileName;
157
+ architectureRecommendation.userVeto = {
158
+ applied: true,
159
+ selectedStackFileName: selectedManualStackFileName,
160
+ selectedBlueprintFileName: selectedManualBlueprintFileName,
161
+ source: 'saved-preference',
162
+ };
163
+ console.log(
164
+ `Repeated override preference detected. Applying ${toTitleCase(selectedManualStackFileName)} + ${toTitleCase(selectedManualBlueprintFileName)} without additional debate.`
165
+ );
166
+ } else if (!isInteractiveSession) {
167
+ selectedManualStackFileName = architectureRecommendation.recommendedStackFileName;
168
+ selectedManualBlueprintFileName = architectureRecommendation.recommendedBlueprintFileName;
169
+ } else {
170
+ const shouldApplyRecommendedArchitecture = await askYesNo(
171
+ 'Apply this architecture recommendation?',
172
+ userInterface,
173
+ true
174
+ );
175
+
176
+ if (shouldApplyRecommendedArchitecture) {
177
+ selectedManualStackFileName = architectureRecommendation.recommendedStackFileName;
178
+ selectedManualBlueprintFileName = architectureRecommendation.recommendedBlueprintFileName;
179
+ } else {
180
+ const vetoStackFileName = await askStackSelection(
181
+ 'User veto received. Select stack to apply immediately:',
182
+ stackFileNames,
183
+ userInterface
184
+ );
185
+
186
+ const vetoBlueprintCandidates = filterBlueprintFileNamesByCandidates(
187
+ blueprintFileNames,
188
+ [BLUEPRINT_RECOMMENDATIONS[vetoStackFileName]].filter(Boolean)
189
+ );
190
+
191
+ const vetoBlueprintFileName = await askBlueprintSelection(
192
+ 'Select blueprint to apply immediately (no further debate):',
193
+ vetoBlueprintCandidates,
194
+ userInterface
195
+ );
196
+
197
+ selectedManualStackFileName = vetoStackFileName;
198
+ selectedManualBlueprintFileName = vetoBlueprintFileName;
199
+ architectureRecommendation.userVeto = {
200
+ applied: true,
201
+ selectedStackFileName: vetoStackFileName,
202
+ selectedBlueprintFileName: vetoBlueprintFileName,
203
+ source: 'interactive-veto',
204
+ };
205
+
206
+ nextArchitectPreferenceState = createUpdatedArchitectPreference(nextArchitectPreferenceState, {
207
+ selectedStackFileName: vetoStackFileName,
208
+ selectedBlueprintFileName: vetoBlueprintFileName,
209
+ });
210
+ architectPreferenceUpdated = true;
211
+
212
+ if (nextArchitectPreferenceState.overrideCount >= 2) {
213
+ architectureRecommendation.failureModes.repeatedOverride = true;
214
+ }
215
+
216
+ console.log(
217
+ `Veto applied. Proceeding with ${toTitleCase(vetoStackFileName)} + ${toTitleCase(vetoBlueprintFileName)} without recommendation loops.`
218
+ );
219
+ }
220
+ }
221
+
222
+ return {
223
+ selectedProjectScopeKey,
224
+ selectedProjectScopeLabel,
225
+ selectedManualStackFileName,
226
+ selectedManualBlueprintFileName,
227
+ architectureRecommendation,
228
+ architectPreferenceState: nextArchitectPreferenceState,
229
+ architectPreferenceUpdated,
230
+ };
231
+ }
@@ -0,0 +1,123 @@
1
+ import {
2
+ BLUEPRINT_RECOMMENDATIONS,
3
+ } from './constants.mjs';
4
+
5
+ import {
6
+ filterBlueprintFileNamesByCandidates,
7
+ normalizeAdditionalStackSelection,
8
+ } from './init-selection.mjs';
9
+
10
+ import {
11
+ toTitleCase,
12
+ } from './utils.mjs';
13
+
14
+ export function buildExistingProjectMajorConstraints() {
15
+ return [
16
+ 'Preserve existing project markers and avoid forced stack migration.',
17
+ 'Keep stack rule loading lazy and scoped to touched code.',
18
+ 'Explicit stack or blueprint overrides always win over auto-detection.',
19
+ ];
20
+ }
21
+
22
+ export async function resolveDetectedSetupDecision({
23
+ shouldAutoApplyDetectedStack,
24
+ projectDetection,
25
+ stackFileNames,
26
+ blueprintFileNames,
27
+ userInterface,
28
+ isInteractiveSession,
29
+ detectionTransparency,
30
+ askYesNo,
31
+ askStackSelection,
32
+ askBlueprintSelection,
33
+ initialSelectedManualStackFileName,
34
+ initialSelectedManualBlueprintFileName,
35
+ initialSelectedAdditionalStackFileNames,
36
+ }) {
37
+ let selectedManualStackFileName = initialSelectedManualStackFileName || null;
38
+ let selectedManualBlueprintFileName = initialSelectedManualBlueprintFileName || null;
39
+ let selectedAdditionalStackFileNames = initialSelectedAdditionalStackFileNames || [];
40
+ let detectedSetupWasApplied = false;
41
+
42
+ const detectedBlueprintFileName = projectDetection.recommendedBlueprintFileName
43
+ || BLUEPRINT_RECOMMENDATIONS[projectDetection.recommendedStackFileName]
44
+ || null;
45
+
46
+ if (shouldAutoApplyDetectedStack) {
47
+ if (isInteractiveSession) {
48
+ detectionTransparency.quickConfirmation.offered = true;
49
+ console.log('\nQuick confirmation for existing project detection:');
50
+ console.log(`- Suggested stack: ${toTitleCase(projectDetection.recommendedStackFileName)}`);
51
+ if (detectedBlueprintFileName) {
52
+ console.log(`- Suggested blueprint: ${toTitleCase(detectedBlueprintFileName)}`);
53
+ }
54
+
55
+ const shouldUseDetectedSetup = await askYesNo(
56
+ 'Use detected setup for this existing project?',
57
+ userInterface,
58
+ true
59
+ );
60
+
61
+ if (shouldUseDetectedSetup) {
62
+ detectedSetupWasApplied = true;
63
+ detectionTransparency.quickConfirmation.response = 'confirmed-detected';
64
+ detectionTransparency.decision.mode = 'confirmed-detected';
65
+ console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
66
+ if (projectDetection.secondaryStackFileNames?.length) {
67
+ console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
68
+ }
69
+ selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
70
+ } else {
71
+ const overrideStackFileName = await askStackSelection(
72
+ 'Override detected stack (quick selection):',
73
+ stackFileNames,
74
+ userInterface
75
+ );
76
+ const overrideBlueprintCandidates = filterBlueprintFileNamesByCandidates(
77
+ blueprintFileNames,
78
+ [BLUEPRINT_RECOMMENDATIONS[overrideStackFileName]].filter(Boolean)
79
+ );
80
+ const overrideBlueprintFileName = await askBlueprintSelection(
81
+ 'Override detected blueprint (quick selection):',
82
+ overrideBlueprintCandidates,
83
+ userInterface
84
+ );
85
+
86
+ selectedManualStackFileName = overrideStackFileName;
87
+ selectedManualBlueprintFileName = overrideBlueprintFileName;
88
+ selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
89
+ overrideStackFileName,
90
+ projectDetection.secondaryStackFileNames || []
91
+ );
92
+ detectionTransparency.quickConfirmation.response = 'overridden-detected';
93
+ detectionTransparency.decision.mode = 'overridden-detected';
94
+ console.log(
95
+ `Detection override applied: ${toTitleCase(overrideStackFileName)} + ${toTitleCase(overrideBlueprintFileName)}.`
96
+ );
97
+ }
98
+ } else {
99
+ detectedSetupWasApplied = true;
100
+ detectionTransparency.quickConfirmation.response = 'non-interactive-auto';
101
+ detectionTransparency.decision.mode = 'non-interactive-auto';
102
+ console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
103
+ if (projectDetection.secondaryStackFileNames?.length) {
104
+ console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
105
+ }
106
+ selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
107
+ }
108
+ } else if (projectDetection.hasExistingProjectFiles && projectDetection.recommendedStackFileName) {
109
+ detectionTransparency.quickConfirmation.response = 'explicit-selection-or-low-confidence';
110
+ detectionTransparency.decision.mode = 'explicit-selection-or-low-confidence';
111
+ } else if (!projectDetection.hasExistingProjectFiles) {
112
+ detectionTransparency.quickConfirmation.response = 'not-applicable';
113
+ detectionTransparency.decision.mode = 'fresh-directory';
114
+ }
115
+
116
+ return {
117
+ detectedSetupWasApplied,
118
+ selectedManualStackFileName,
119
+ selectedManualBlueprintFileName,
120
+ selectedAdditionalStackFileNames,
121
+ detectedBlueprintFileName,
122
+ };
123
+ }
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Init Options Parser — isolates CLI option parsing from init runtime flow.
3
+ */
4
+ import {
5
+ ARCHITECT_DEFAULT_TOKEN_BUDGET,
6
+ ARCHITECT_DEFAULT_TIMEOUT_MS,
7
+ ARCHITECT_MIN_TOKEN_BUDGET,
8
+ ARCHITECT_MAX_TOKEN_BUDGET,
9
+ ARCHITECT_MIN_TIMEOUT_MS,
10
+ ARCHITECT_MAX_TIMEOUT_MS,
11
+ } from './architect.mjs';
12
+ import { normalizeDocsLanguage } from './project-scaffolder.mjs';
13
+ import { normalizeAgentName } from './token-optimization.mjs';
14
+ import { normalizeChoiceInput, matchProfileNameFromInput } from './utils.mjs';
15
+
16
+ const INIT_DEFAULT_RESEARCH_MODE = 'realtime';
17
+
18
+ export function normalizeRuntimeEnvironmentKey(rawRuntimeEnvironmentKey) {
19
+ const normalizedRuntimeEnvironmentKey = normalizeChoiceInput(String(rawRuntimeEnvironmentKey || 'auto'));
20
+ const supportedRuntimeEnvironmentKeys = new Set(['auto', 'linux-wsl', 'linux', 'windows', 'macos']);
21
+ return supportedRuntimeEnvironmentKeys.has(normalizedRuntimeEnvironmentKey) ? normalizedRuntimeEnvironmentKey : null;
22
+ }
23
+
24
+ export function parseInitArguments(commandArguments) {
25
+ const parsedInitOptions = {
26
+ targetDirectory: '.',
27
+ preset: undefined,
28
+ profile: undefined,
29
+ profilePack: undefined,
30
+ stack: undefined,
31
+ blueprint: undefined,
32
+ ci: undefined,
33
+ newbie: false,
34
+ tokenOptimize: true,
35
+ memoryContinuity: true,
36
+ tokenAgent: 'copilot',
37
+ includeMcpTemplate: true,
38
+ scaffoldDocs: undefined,
39
+ docsLang: 'en',
40
+ docsLangProvided: false,
41
+ projectConfig: undefined,
42
+ projectDescription: '',
43
+ architectTokenBudget: ARCHITECT_DEFAULT_TOKEN_BUDGET,
44
+ architectTimeoutMs: ARCHITECT_DEFAULT_TIMEOUT_MS,
45
+ architectResearchMode: INIT_DEFAULT_RESEARCH_MODE,
46
+ enableRealtimeResearch: true,
47
+ architectRealtimeSignalFile: null,
48
+ runtimeEnv: 'auto',
49
+ runtimeEnvProvided: false,
50
+ };
51
+
52
+ for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
53
+ const currentArgument = commandArguments[argumentIndex];
54
+
55
+ if (!currentArgument.startsWith('--')) {
56
+ parsedInitOptions.targetDirectory = currentArgument;
57
+ continue;
58
+ }
59
+
60
+ if (currentArgument === '--profile') {
61
+ parsedInitOptions.profile = matchProfileNameFromInput(commandArguments[argumentIndex + 1] || '');
62
+ argumentIndex += 1;
63
+ continue;
64
+ }
65
+
66
+ if (currentArgument === '--preset') {
67
+ parsedInitOptions.preset = normalizeChoiceInput(commandArguments[argumentIndex + 1] || '');
68
+ argumentIndex += 1;
69
+ continue;
70
+ }
71
+
72
+ if (currentArgument.startsWith('--preset=')) {
73
+ parsedInitOptions.preset = normalizeChoiceInput(currentArgument.split('=')[1]);
74
+ continue;
75
+ }
76
+
77
+ if (currentArgument.startsWith('--profile=')) {
78
+ parsedInitOptions.profile = matchProfileNameFromInput(currentArgument.split('=')[1]);
79
+ continue;
80
+ }
81
+
82
+ if (currentArgument === '--profile-pack') {
83
+ parsedInitOptions.profilePack = commandArguments[argumentIndex + 1];
84
+ argumentIndex += 1;
85
+ continue;
86
+ }
87
+
88
+ if (currentArgument.startsWith('--profile-pack=')) {
89
+ parsedInitOptions.profilePack = currentArgument.split('=')[1];
90
+ continue;
91
+ }
92
+
93
+ if (currentArgument === '--stack') {
94
+ parsedInitOptions.stack = commandArguments[argumentIndex + 1];
95
+ argumentIndex += 1;
96
+ continue;
97
+ }
98
+
99
+ if (currentArgument.startsWith('--stack=')) {
100
+ parsedInitOptions.stack = currentArgument.split('=')[1];
101
+ continue;
102
+ }
103
+
104
+ if (currentArgument === '--blueprint') {
105
+ parsedInitOptions.blueprint = commandArguments[argumentIndex + 1];
106
+ argumentIndex += 1;
107
+ continue;
108
+ }
109
+
110
+ if (currentArgument.startsWith('--blueprint=')) {
111
+ parsedInitOptions.blueprint = currentArgument.split('=')[1];
112
+ continue;
113
+ }
114
+
115
+ if (currentArgument === '--ci') {
116
+ const ciRawValue = commandArguments[argumentIndex + 1];
117
+ parsedInitOptions.ci = ciRawValue?.toLowerCase() === 'true';
118
+ argumentIndex += 1;
119
+ continue;
120
+ }
121
+
122
+ if (currentArgument.startsWith('--ci=')) {
123
+ parsedInitOptions.ci = currentArgument.split('=')[1]?.toLowerCase() === 'true';
124
+ continue;
125
+ }
126
+
127
+ if (currentArgument === '--newbie') {
128
+ parsedInitOptions.newbie = true;
129
+ continue;
130
+ }
131
+
132
+ if (currentArgument === '--token-optimize') {
133
+ parsedInitOptions.tokenOptimize = true;
134
+ continue;
135
+ }
136
+
137
+ if (currentArgument === '--memory-continuity') {
138
+ parsedInitOptions.memoryContinuity = true;
139
+ continue;
140
+ }
141
+
142
+ if (currentArgument === '--token-agent') {
143
+ parsedInitOptions.tokenAgent = commandArguments[argumentIndex + 1] || 'copilot';
144
+ argumentIndex += 1;
145
+ continue;
146
+ }
147
+
148
+ if (currentArgument.startsWith('--token-agent=')) {
149
+ parsedInitOptions.tokenAgent = currentArgument.split('=')[1] || 'copilot';
150
+ continue;
151
+ }
152
+
153
+ if (currentArgument === '--no-token-optimize') {
154
+ parsedInitOptions.tokenOptimize = false;
155
+ continue;
156
+ }
157
+
158
+ if (currentArgument === '--no-memory-continuity') {
159
+ parsedInitOptions.memoryContinuity = false;
160
+ continue;
161
+ }
162
+
163
+ if (currentArgument === '--mcp-template') {
164
+ parsedInitOptions.includeMcpTemplate = true;
165
+ continue;
166
+ }
167
+
168
+ if (currentArgument === '--no-mcp-template') {
169
+ parsedInitOptions.includeMcpTemplate = false;
170
+ continue;
171
+ }
172
+
173
+ if (currentArgument === '--scaffold-docs') {
174
+ parsedInitOptions.scaffoldDocs = true;
175
+ continue;
176
+ }
177
+
178
+ if (currentArgument === '--no-scaffold-docs') {
179
+ parsedInitOptions.scaffoldDocs = false;
180
+ continue;
181
+ }
182
+
183
+ if (currentArgument === '--docs-lang') {
184
+ parsedInitOptions.docsLang = commandArguments[argumentIndex + 1] || 'en';
185
+ parsedInitOptions.docsLangProvided = true;
186
+ argumentIndex += 1;
187
+ continue;
188
+ }
189
+
190
+ if (currentArgument.startsWith('--docs-lang=')) {
191
+ parsedInitOptions.docsLang = currentArgument.split('=')[1] || 'en';
192
+ parsedInitOptions.docsLangProvided = true;
193
+ continue;
194
+ }
195
+
196
+ if (currentArgument === '--project-config') {
197
+ parsedInitOptions.projectConfig = commandArguments[argumentIndex + 1];
198
+ argumentIndex += 1;
199
+ continue;
200
+ }
201
+
202
+ if (currentArgument.startsWith('--project-config=')) {
203
+ parsedInitOptions.projectConfig = currentArgument.split('=')[1];
204
+ continue;
205
+ }
206
+
207
+ if (currentArgument === '--project-description') {
208
+ parsedInitOptions.projectDescription = commandArguments[argumentIndex + 1] || '';
209
+ argumentIndex += 1;
210
+ continue;
211
+ }
212
+
213
+ if (currentArgument.startsWith('--project-description=')) {
214
+ parsedInitOptions.projectDescription = currentArgument.split('=')[1] || '';
215
+ continue;
216
+ }
217
+
218
+ if (currentArgument === '--architect-token-budget') {
219
+ const rawTokenBudget = Number.parseInt(commandArguments[argumentIndex + 1], 10);
220
+ if (Number.isNaN(rawTokenBudget)) {
221
+ throw new Error('--architect-token-budget must be a number');
222
+ }
223
+ parsedInitOptions.architectTokenBudget = rawTokenBudget;
224
+ argumentIndex += 1;
225
+ continue;
226
+ }
227
+
228
+ if (currentArgument.startsWith('--architect-token-budget=')) {
229
+ const rawTokenBudget = Number.parseInt(currentArgument.split('=')[1], 10);
230
+ if (Number.isNaN(rawTokenBudget)) {
231
+ throw new Error('--architect-token-budget must be a number');
232
+ }
233
+ parsedInitOptions.architectTokenBudget = rawTokenBudget;
234
+ continue;
235
+ }
236
+
237
+ if (currentArgument === '--architect-timeout-ms') {
238
+ const rawTimeoutMs = Number.parseInt(commandArguments[argumentIndex + 1], 10);
239
+ if (Number.isNaN(rawTimeoutMs)) {
240
+ throw new Error('--architect-timeout-ms must be a number');
241
+ }
242
+ parsedInitOptions.architectTimeoutMs = rawTimeoutMs;
243
+ argumentIndex += 1;
244
+ continue;
245
+ }
246
+
247
+ if (currentArgument.startsWith('--architect-timeout-ms=')) {
248
+ const rawTimeoutMs = Number.parseInt(currentArgument.split('=')[1], 10);
249
+ if (Number.isNaN(rawTimeoutMs)) {
250
+ throw new Error('--architect-timeout-ms must be a number');
251
+ }
252
+ parsedInitOptions.architectTimeoutMs = rawTimeoutMs;
253
+ continue;
254
+ }
255
+
256
+ if (currentArgument === '--architect-research-mode') {
257
+ parsedInitOptions.architectResearchMode = commandArguments[argumentIndex + 1] || INIT_DEFAULT_RESEARCH_MODE;
258
+ argumentIndex += 1;
259
+ continue;
260
+ }
261
+
262
+ if (currentArgument.startsWith('--architect-research-mode=')) {
263
+ parsedInitOptions.architectResearchMode = currentArgument.split('=')[1] || INIT_DEFAULT_RESEARCH_MODE;
264
+ continue;
265
+ }
266
+
267
+ if (currentArgument === '--enable-realtime-research') {
268
+ parsedInitOptions.enableRealtimeResearch = true;
269
+ continue;
270
+ }
271
+
272
+ if (currentArgument === '--disable-realtime-research') {
273
+ parsedInitOptions.enableRealtimeResearch = false;
274
+ continue;
275
+ }
276
+
277
+ if (currentArgument === '--architect-realtime-signal-file') {
278
+ parsedInitOptions.architectRealtimeSignalFile = commandArguments[argumentIndex + 1] || null;
279
+ argumentIndex += 1;
280
+ continue;
281
+ }
282
+
283
+ if (currentArgument.startsWith('--architect-realtime-signal-file=')) {
284
+ parsedInitOptions.architectRealtimeSignalFile = currentArgument.split('=')[1] || null;
285
+ continue;
286
+ }
287
+
288
+ if (currentArgument === '--runtime-env') {
289
+ parsedInitOptions.runtimeEnv = commandArguments[argumentIndex + 1] || 'auto';
290
+ parsedInitOptions.runtimeEnvProvided = true;
291
+ argumentIndex += 1;
292
+ continue;
293
+ }
294
+
295
+ if (currentArgument.startsWith('--runtime-env=')) {
296
+ parsedInitOptions.runtimeEnv = currentArgument.split('=')[1] || 'auto';
297
+ parsedInitOptions.runtimeEnvProvided = true;
298
+ continue;
299
+ }
300
+
301
+ throw new Error(`Unknown option: ${currentArgument}`);
302
+ }
303
+
304
+ if (parsedInitOptions.newbie && parsedInitOptions.profile && parsedInitOptions.profile !== 'beginner') {
305
+ throw new Error('--newbie can only be combined with --profile beginner');
306
+ }
307
+
308
+ const normalizedDocsLanguage = normalizeDocsLanguage(parsedInitOptions.docsLang || 'en');
309
+ if (!normalizedDocsLanguage) {
310
+ throw new Error('--docs-lang must be one of: en, id');
311
+ }
312
+
313
+ const normalizedRuntimeEnvironment = normalizeRuntimeEnvironmentKey(parsedInitOptions.runtimeEnv || 'auto');
314
+ if (!normalizedRuntimeEnvironment) {
315
+ throw new Error('--runtime-env must be one of: auto, linux-wsl, linux, windows, macos');
316
+ }
317
+
318
+ if (!Number.isInteger(parsedInitOptions.architectTokenBudget)
319
+ || parsedInitOptions.architectTokenBudget < ARCHITECT_MIN_TOKEN_BUDGET
320
+ || parsedInitOptions.architectTokenBudget > ARCHITECT_MAX_TOKEN_BUDGET) {
321
+ throw new Error(`--architect-token-budget must be an integer between ${ARCHITECT_MIN_TOKEN_BUDGET} and ${ARCHITECT_MAX_TOKEN_BUDGET}`);
322
+ }
323
+
324
+ if (!Number.isInteger(parsedInitOptions.architectTimeoutMs)
325
+ || parsedInitOptions.architectTimeoutMs < ARCHITECT_MIN_TIMEOUT_MS
326
+ || parsedInitOptions.architectTimeoutMs > ARCHITECT_MAX_TIMEOUT_MS) {
327
+ throw new Error(`--architect-timeout-ms must be an integer between ${ARCHITECT_MIN_TIMEOUT_MS} and ${ARCHITECT_MAX_TIMEOUT_MS}`);
328
+ }
329
+
330
+ const normalizedArchitectResearchMode = normalizeChoiceInput(
331
+ parsedInitOptions.architectResearchMode || INIT_DEFAULT_RESEARCH_MODE
332
+ );
333
+ const supportedArchitectResearchModes = new Set(['snapshot', 'realtime']);
334
+ if (!supportedArchitectResearchModes.has(normalizedArchitectResearchMode)) {
335
+ throw new Error('--architect-research-mode must be one of: snapshot, realtime');
336
+ }
337
+
338
+ parsedInitOptions.docsLang = normalizedDocsLanguage;
339
+ parsedInitOptions.runtimeEnv = normalizedRuntimeEnvironment;
340
+ parsedInitOptions.tokenAgent = normalizeAgentName(parsedInitOptions.tokenAgent);
341
+ parsedInitOptions.architectResearchMode = normalizedArchitectResearchMode;
342
+
343
+ return parsedInitOptions;
344
+ }