@ryuenn3123/agentic-senior-core 2.5.22 → 3.0.2

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 (174) hide show
  1. package/.agent-context/prompts/bootstrap-design.md +22 -0
  2. package/.agent-context/prompts/init-project.md +55 -39
  3. package/.agent-context/prompts/refactor.md +2 -1
  4. package/.agent-context/prompts/review-code.md +3 -2
  5. package/.agent-context/review-checklists/pr-checklist.md +8 -1
  6. package/.agent-context/rules/architecture.md +11 -0
  7. package/.agent-context/rules/frontend-architecture.md +2 -2
  8. package/.agent-context/state/architecture-map.md +1 -1
  9. package/.agent-context/state/memory-continuity-benchmark.json +1 -1
  10. package/.agents/workflows/init-project.md +3 -3
  11. package/.agents/workflows/refactor.md +1 -1
  12. package/.agents/workflows/review-code.md +4 -5
  13. package/.cursorrules +27 -71
  14. package/.gemini/instructions.md +6 -7
  15. package/.github/copilot-instructions.md +5 -6
  16. package/.windsurfrules +27 -71
  17. package/AGENTS.md +7 -9
  18. package/CONTRIBUTING.md +18 -31
  19. package/README.md +17 -43
  20. package/bin/agentic-senior-core.js +0 -6
  21. package/lib/cli/commands/init.mjs +113 -650
  22. package/lib/cli/commands/launch.mjs +1 -23
  23. package/lib/cli/commands/rollback.mjs +1 -1
  24. package/lib/cli/commands/upgrade.mjs +47 -28
  25. package/lib/cli/compiler.mjs +77 -72
  26. package/lib/cli/constants.mjs +84 -26
  27. package/lib/cli/init-architecture-flow.mjs +231 -0
  28. package/lib/cli/init-detection-flow.mjs +123 -0
  29. package/lib/cli/init-options.mjs +344 -0
  30. package/lib/cli/init-selection.mjs +100 -0
  31. package/lib/cli/preflight.mjs +1 -1
  32. package/lib/cli/profile-packs.mjs +15 -1
  33. package/lib/cli/project-scaffolder.mjs +18 -154
  34. package/lib/cli/utils.mjs +224 -13
  35. package/mcp.json +19 -19
  36. package/package.json +5 -2
  37. package/scripts/context-triggered-audit.mjs +18 -18
  38. package/scripts/documentation-boundary-audit.mjs +92 -5
  39. package/scripts/forbidden-content-check.mjs +1 -1
  40. package/scripts/frontend-usability-audit.mjs +21 -28
  41. package/scripts/governance-weekly-report.mjs +29 -15
  42. package/scripts/llm-judge.mjs +2 -5
  43. package/scripts/mcp-server.mjs +389 -5
  44. package/scripts/release-gate.mjs +121 -145
  45. package/scripts/sync-thin-adapters.mjs +161 -0
  46. package/scripts/v3-purge-audit.mjs +231 -0
  47. package/scripts/validate-evidence-bundle.mjs +1 -1
  48. package/scripts/validate.mjs +224 -272
  49. package/.agent-context/blueprints/api-nextjs.md +0 -184
  50. package/.agent-context/blueprints/aspnet-api.md +0 -247
  51. package/.agent-context/blueprints/ci-github-actions.md +0 -226
  52. package/.agent-context/blueprints/ci-gitlab.md +0 -200
  53. package/.agent-context/blueprints/fastapi-service.md +0 -210
  54. package/.agent-context/blueprints/go-service.md +0 -217
  55. package/.agent-context/blueprints/graphql-grpc-api.md +0 -51
  56. package/.agent-context/blueprints/infrastructure-as-code.md +0 -62
  57. package/.agent-context/blueprints/kubernetes-manifests.md +0 -76
  58. package/.agent-context/blueprints/laravel-api.md +0 -233
  59. package/.agent-context/blueprints/mobile-app.md +0 -91
  60. package/.agent-context/blueprints/nestjs-logic.md +0 -247
  61. package/.agent-context/blueprints/observability.md +0 -227
  62. package/.agent-context/blueprints/spring-boot-api.md +0 -218
  63. package/.agent-context/profiles/platform.md +0 -13
  64. package/.agent-context/profiles/regulated.md +0 -13
  65. package/.agent-context/profiles/startup.md +0 -13
  66. package/.agent-context/review-checklists/frontend-excellence-rubric.md +0 -73
  67. package/.agent-context/review-checklists/frontend-skill-parity.md +0 -29
  68. package/.agent-context/review-checklists/frontend-usability.md +0 -35
  69. package/.agent-context/review-checklists/marketplace-acceptance.md +0 -60
  70. package/.agent-context/review-checklists/performance-audit.md +0 -71
  71. package/.agent-context/review-checklists/release-operations.md +0 -33
  72. package/.agent-context/review-checklists/security-audit.md +0 -119
  73. package/.agent-context/skills/README.md +0 -63
  74. package/.agent-context/skills/backend/README.md +0 -68
  75. package/.agent-context/skills/backend/architecture.md +0 -361
  76. package/.agent-context/skills/backend/compatibility-manifest.json +0 -8
  77. package/.agent-context/skills/backend/data-access.md +0 -231
  78. package/.agent-context/skills/backend/errors.md +0 -138
  79. package/.agent-context/skills/backend/validation.md +0 -117
  80. package/.agent-context/skills/backend.md +0 -29
  81. package/.agent-context/skills/cli/.evidence/compatibility-manifest.json +0 -5
  82. package/.agent-context/skills/cli/.evidence/sbom-excerpt.json +0 -10
  83. package/.agent-context/skills/cli/.evidence/test-report.json +0 -8
  84. package/.agent-context/skills/cli/CHANGELOG.md +0 -6
  85. package/.agent-context/skills/cli/README.md +0 -56
  86. package/.agent-context/skills/cli/compatibility-manifest.json +0 -8
  87. package/.agent-context/skills/cli/init.md +0 -38
  88. package/.agent-context/skills/cli/output.md +0 -36
  89. package/.agent-context/skills/cli/package.json +0 -5
  90. package/.agent-context/skills/cli/safety-telemetry.md +0 -39
  91. package/.agent-context/skills/cli/tests/.gitkeep +0 -1
  92. package/.agent-context/skills/cli/upgrade.md +0 -38
  93. package/.agent-context/skills/cli.md +0 -32
  94. package/.agent-context/skills/distribution/.evidence/compatibility-manifest.json +0 -9
  95. package/.agent-context/skills/distribution/.evidence/sbom-excerpt.json +0 -6
  96. package/.agent-context/skills/distribution/.evidence/test-report.json +0 -8
  97. package/.agent-context/skills/distribution/CHANGELOG.md +0 -7
  98. package/.agent-context/skills/distribution/README.md +0 -27
  99. package/.agent-context/skills/distribution/compatibility-manifest.json +0 -8
  100. package/.agent-context/skills/distribution/compatibility.md +0 -32
  101. package/.agent-context/skills/distribution/package.json +0 -5
  102. package/.agent-context/skills/distribution/provenance-attestation.md +0 -47
  103. package/.agent-context/skills/distribution/publish.md +0 -37
  104. package/.agent-context/skills/distribution/rollback.md +0 -32
  105. package/.agent-context/skills/distribution/tests/.gitkeep +0 -1
  106. package/.agent-context/skills/distribution.md +0 -32
  107. package/.agent-context/skills/frontend/.evidence/compatibility-manifest.json +0 -9
  108. package/.agent-context/skills/frontend/.evidence/sbom-excerpt.json +0 -6
  109. package/.agent-context/skills/frontend/.evidence/test-report.json +0 -8
  110. package/.agent-context/skills/frontend/CHANGELOG.md +0 -7
  111. package/.agent-context/skills/frontend/README.md +0 -50
  112. package/.agent-context/skills/frontend/accessibility.md +0 -107
  113. package/.agent-context/skills/frontend/compatibility-manifest.json +0 -8
  114. package/.agent-context/skills/frontend/conversion-clarity.md +0 -51
  115. package/.agent-context/skills/frontend/motion.md +0 -67
  116. package/.agent-context/skills/frontend/package.json +0 -5
  117. package/.agent-context/skills/frontend/performance.md +0 -63
  118. package/.agent-context/skills/frontend/responsive-delivery.md +0 -41
  119. package/.agent-context/skills/frontend/tests/.gitkeep +0 -1
  120. package/.agent-context/skills/frontend/ui-architecture.md +0 -128
  121. package/.agent-context/skills/frontend.md +0 -40
  122. package/.agent-context/skills/fullstack/.evidence/compatibility-manifest.json +0 -9
  123. package/.agent-context/skills/fullstack/.evidence/sbom-excerpt.json +0 -6
  124. package/.agent-context/skills/fullstack/.evidence/test-report.json +0 -8
  125. package/.agent-context/skills/fullstack/CHANGELOG.md +0 -7
  126. package/.agent-context/skills/fullstack/README.md +0 -27
  127. package/.agent-context/skills/fullstack/compatibility-manifest.json +0 -8
  128. package/.agent-context/skills/fullstack/contracts.md +0 -53
  129. package/.agent-context/skills/fullstack/end-to-end.md +0 -42
  130. package/.agent-context/skills/fullstack/feature-slicing.md +0 -65
  131. package/.agent-context/skills/fullstack/package.json +0 -5
  132. package/.agent-context/skills/fullstack/release-coordination.md +0 -51
  133. package/.agent-context/skills/fullstack/tests/.gitkeep +0 -1
  134. package/.agent-context/skills/fullstack.md +0 -30
  135. package/.agent-context/skills/index.json +0 -107
  136. package/.agent-context/skills/review-quality/.evidence/compatibility-manifest.json +0 -9
  137. package/.agent-context/skills/review-quality/.evidence/sbom-excerpt.json +0 -6
  138. package/.agent-context/skills/review-quality/.evidence/test-report.json +0 -8
  139. package/.agent-context/skills/review-quality/CHANGELOG.md +0 -7
  140. package/.agent-context/skills/review-quality/README.md +0 -27
  141. package/.agent-context/skills/review-quality/benchmark.md +0 -30
  142. package/.agent-context/skills/review-quality/compatibility-manifest.json +0 -8
  143. package/.agent-context/skills/review-quality/package.json +0 -5
  144. package/.agent-context/skills/review-quality/planning.md +0 -38
  145. package/.agent-context/skills/review-quality/release-decision.md +0 -49
  146. package/.agent-context/skills/review-quality/security.md +0 -34
  147. package/.agent-context/skills/review-quality/tests/.gitkeep +0 -1
  148. package/.agent-context/skills/review-quality.md +0 -34
  149. package/.agent-context/stacks/csharp.md +0 -149
  150. package/.agent-context/stacks/flutter.md +0 -16
  151. package/.agent-context/stacks/go.md +0 -181
  152. package/.agent-context/stacks/java.md +0 -135
  153. package/.agent-context/stacks/php.md +0 -192
  154. package/.agent-context/stacks/python.md +0 -153
  155. package/.agent-context/stacks/react-native.md +0 -16
  156. package/.agent-context/stacks/ruby.md +0 -80
  157. package/.agent-context/stacks/rust.md +0 -86
  158. package/.agent-context/stacks/typescript.md +0 -317
  159. package/.agent-context/state/skill-platform.json +0 -38
  160. package/lib/cli/skill-selector.mjs +0 -232
  161. package/lib/cli/templates/api-contract.md.id.tmpl +0 -143
  162. package/lib/cli/templates/api-contract.md.tmpl +0 -143
  163. package/lib/cli/templates/architecture-decision-record.md.id.tmpl +0 -106
  164. package/lib/cli/templates/architecture-decision-record.md.tmpl +0 -145
  165. package/lib/cli/templates/database-schema.md.id.tmpl +0 -74
  166. package/lib/cli/templates/database-schema.md.tmpl +0 -74
  167. package/lib/cli/templates/flow-overview.md.id.tmpl +0 -118
  168. package/lib/cli/templates/flow-overview.md.tmpl +0 -131
  169. package/lib/cli/templates/project-brief.md.id.tmpl +0 -55
  170. package/lib/cli/templates/project-brief.md.tmpl +0 -79
  171. package/scripts/init-project.ps1 +0 -105
  172. package/scripts/init-project.sh +0 -131
  173. package/scripts/skill-tier-policy.mjs +0 -76
  174. 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
+ }