@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,100 @@
1
+ /**
2
+ * Init Selection Helpers — stack/blueprint filtering and scope normalization.
3
+ */
4
+ import {
5
+ BLUEPRINT_RECOMMENDATIONS,
6
+ PROJECT_SCOPE_CHOICES,
7
+ PROJECT_SCOPE_STACK_FILTERS,
8
+ WEB_FRONTEND_BLUEPRINT_CANDIDATES,
9
+ WEB_BACKEND_BLUEPRINT_CANDIDATES,
10
+ } from './constants.mjs';
11
+
12
+ export function filterStackFileNamesByCandidates(allStackFileNames, preferredStackFileNames) {
13
+ if (!Array.isArray(preferredStackFileNames) || preferredStackFileNames.length === 0) {
14
+ return allStackFileNames;
15
+ }
16
+
17
+ const filteredStackFileNames = preferredStackFileNames.filter((stackFileName) => allStackFileNames.includes(stackFileName));
18
+ return filteredStackFileNames.length > 0 ? filteredStackFileNames : allStackFileNames;
19
+ }
20
+
21
+ export function filterBlueprintFileNamesByCandidates(allBlueprintFileNames, preferredBlueprintFileNames) {
22
+ if (!Array.isArray(preferredBlueprintFileNames) || preferredBlueprintFileNames.length === 0) {
23
+ return allBlueprintFileNames;
24
+ }
25
+
26
+ const filteredBlueprintFileNames = preferredBlueprintFileNames.filter(
27
+ (blueprintFileName) => allBlueprintFileNames.includes(blueprintFileName)
28
+ );
29
+
30
+ return filteredBlueprintFileNames.length > 0 ? filteredBlueprintFileNames : allBlueprintFileNames;
31
+ }
32
+
33
+ export function resolveProjectScopeKeyFromLabel(selectedProjectScopeLabel) {
34
+ const projectScopeEntry = PROJECT_SCOPE_CHOICES.find((scopeChoice) => scopeChoice.label === selectedProjectScopeLabel);
35
+ return projectScopeEntry?.key || 'both';
36
+ }
37
+
38
+ export function normalizeAdditionalStackSelection(selectedStackFileName, additionalStackFileNames) {
39
+ if (!Array.isArray(additionalStackFileNames) || additionalStackFileNames.length === 0) {
40
+ return [];
41
+ }
42
+
43
+ return Array.from(new Set(additionalStackFileNames.filter((stackFileName) => stackFileName && stackFileName !== selectedStackFileName)));
44
+ }
45
+
46
+ export function normalizeAdditionalBlueprintSelection(selectedBlueprintFileName, additionalBlueprintFileNames) {
47
+ if (!Array.isArray(additionalBlueprintFileNames) || additionalBlueprintFileNames.length === 0) {
48
+ return [];
49
+ }
50
+
51
+ return Array.from(new Set(additionalBlueprintFileNames.filter(
52
+ (blueprintFileName) => blueprintFileName && blueprintFileName !== selectedBlueprintFileName
53
+ )));
54
+ }
55
+
56
+ export function deriveAdditionalBlueprintFileNamesFromStacks(
57
+ additionalStackFileNames,
58
+ allBlueprintFileNames,
59
+ selectedBlueprintFileName
60
+ ) {
61
+ const derivedBlueprintFileNames = [];
62
+
63
+ for (const additionalStackFileName of additionalStackFileNames || []) {
64
+ const mappedBlueprintFileName = BLUEPRINT_RECOMMENDATIONS[additionalStackFileName];
65
+ if (!mappedBlueprintFileName) {
66
+ continue;
67
+ }
68
+
69
+ if (!allBlueprintFileNames.includes(mappedBlueprintFileName)) {
70
+ continue;
71
+ }
72
+
73
+ if (mappedBlueprintFileName === selectedBlueprintFileName) {
74
+ continue;
75
+ }
76
+
77
+ derivedBlueprintFileNames.push(mappedBlueprintFileName);
78
+ }
79
+
80
+ return Array.from(new Set(derivedBlueprintFileNames));
81
+ }
82
+
83
+ export function resolveScopeStackCandidates(projectScopeKey) {
84
+ return PROJECT_SCOPE_STACK_FILTERS[projectScopeKey] || null;
85
+ }
86
+
87
+ export function resolveScopeBlueprintCandidates(projectScopeKey) {
88
+ if (projectScopeKey === 'frontend-only') {
89
+ return WEB_FRONTEND_BLUEPRINT_CANDIDATES;
90
+ }
91
+
92
+ if (projectScopeKey === 'backend-only') {
93
+ return WEB_BACKEND_BLUEPRINT_CANDIDATES;
94
+ }
95
+
96
+ return Array.from(new Set([
97
+ ...WEB_FRONTEND_BLUEPRINT_CANDIDATES,
98
+ ...WEB_BACKEND_BLUEPRINT_CANDIDATES,
99
+ ]));
100
+ }
@@ -34,7 +34,7 @@ export async function runPreflightChecks(targetDirectoryPath, operationMode) {
34
34
  try {
35
35
  await fs.access(parentDir, constants.W_OK);
36
36
  result.checks.push(`Target parent directory is writable: ${parentDir}`);
37
- } catch (parentErr) {
37
+ } catch {
38
38
  result.passed = false;
39
39
  result.errors.push(`Target directory does not exist and parent is read-only: ${parentDir}`);
40
40
  }
@@ -8,6 +8,7 @@ import path from 'node:path';
8
8
  import {
9
9
  PROFILE_PACK_REQUIRED_FIELDS,
10
10
  PROFILE_PACKS_DIRECTORY_NAME,
11
+ FALLBACK_PROFILE_PACK_DEFINITIONS,
11
12
  } from './constants.mjs';
12
13
 
13
14
  import {
@@ -19,6 +20,15 @@ import {
19
20
  parseBlockingSeverities,
20
21
  } from './utils.mjs';
21
22
 
23
+ function cloneProfilePackDefinition(profilePackDefinition) {
24
+ return {
25
+ ...profilePackDefinition,
26
+ blockingSeverities: Array.isArray(profilePackDefinition.blockingSeverities)
27
+ ? [...profilePackDefinition.blockingSeverities]
28
+ : [],
29
+ };
30
+ }
31
+
22
32
  export function parseProfilePackContent(fileName, profilePackContent) {
23
33
  const parsedFields = {};
24
34
  const profilePackLines = profilePackContent.split(/\r?\n/);
@@ -64,10 +74,14 @@ export function parseProfilePackContent(fileName, profilePackContent) {
64
74
  export async function collectProfilePacks(targetDirectoryPath) {
65
75
  const profilePackDirectoryPath = path.join(targetDirectoryPath, '.agent-context', PROFILE_PACKS_DIRECTORY_NAME);
66
76
  if (!(await pathExists(profilePackDirectoryPath))) {
67
- return [];
77
+ return FALLBACK_PROFILE_PACK_DEFINITIONS.map(cloneProfilePackDefinition);
68
78
  }
69
79
 
70
80
  const profilePackFileNames = await collectFileNames(profilePackDirectoryPath);
81
+ if (profilePackFileNames.length === 0) {
82
+ return FALLBACK_PROFILE_PACK_DEFINITIONS.map(cloneProfilePackDefinition);
83
+ }
84
+
71
85
  const profilePackDefinitions = [];
72
86
 
73
87
  for (const profilePackFileName of profilePackFileNames) {
@@ -5,14 +5,9 @@
5
5
  */
6
6
  import fs from 'node:fs/promises';
7
7
  import path from 'node:path';
8
- import { fileURLToPath } from 'node:url';
9
8
 
10
- import { CLI_VERSION } from './constants.mjs';
11
9
  import { ensureDirectory, askChoice, askYesNo, toTitleCase, pathExists } from './utils.mjs';
12
10
 
13
- const CURRENT_FILE_PATH = fileURLToPath(import.meta.url);
14
- const CURRENT_DIRECTORY_PATH = path.dirname(CURRENT_FILE_PATH);
15
- const TEMPLATES_DIRECTORY_PATH = path.join(CURRENT_DIRECTORY_PATH, 'templates');
16
11
  const SUPPORTED_DOC_LANGUAGES = new Set(['en', 'id']);
17
12
  const PROJECT_DOC_FILE_NAMES = [
18
13
  'project-brief.md',
@@ -22,6 +17,7 @@ const PROJECT_DOC_FILE_NAMES = [
22
17
  'flow-overview.md',
23
18
  ];
24
19
 
20
+ // Legacy project docs may still carry this version header; keep for upgrade staleness checks.
25
21
  export const PROJECT_DOC_TEMPLATE_VERSION = '1.2.0';
26
22
  export const PROJECT_DOC_SYNTHESIS_PROMPT_VERSION = '2.0.0';
27
23
 
@@ -224,30 +220,6 @@ export function normalizeDocsLanguage(rawDocsLanguage = 'en') {
224
220
  return SUPPORTED_DOC_LANGUAGES.has(normalizedDocsLanguage) ? normalizedDocsLanguage : null;
225
221
  }
226
222
 
227
- function resolveLocalizedTemplateFileName(templateFileName, docsLanguage) {
228
- if (docsLanguage === 'en') {
229
- return templateFileName;
230
- }
231
-
232
- return templateFileName.replace(/\.md\.tmpl$/i, `.md.${docsLanguage}.tmpl`);
233
- }
234
-
235
- async function resolveTemplateFilePath(templateFileName, docsLanguage) {
236
- const localizedTemplateFileName = resolveLocalizedTemplateFileName(templateFileName, docsLanguage);
237
- const localizedTemplateFilePath = path.join(TEMPLATES_DIRECTORY_PATH, localizedTemplateFileName);
238
-
239
- if (await pathExists(localizedTemplateFilePath)) {
240
- return localizedTemplateFilePath;
241
- }
242
-
243
- const defaultTemplateFilePath = path.join(TEMPLATES_DIRECTORY_PATH, templateFileName);
244
- if (await pathExists(defaultTemplateFilePath)) {
245
- return defaultTemplateFilePath;
246
- }
247
-
248
- return null;
249
- }
250
-
251
223
  /**
252
224
  * Run the project discovery interview.
253
225
  * Returns a structured object with all user responses.
@@ -444,160 +416,52 @@ export async function runProjectDiscovery(userInterface, options = {}) {
444
416
  }
445
417
 
446
418
  /**
447
- * Determine which documents to generate based on project discovery answers.
419
+ * Determine required docs based on project discovery answers.
448
420
  */
449
- export function resolveDocumentManifest(discoveryAnswers) {
421
+ export function resolveProjectDocTargets(discoveryAnswers) {
450
422
  const hasDatabase = !discoveryAnswers.databaseChoice.toLowerCase().startsWith('none');
451
- const hasAuth = !discoveryAnswers.authStrategy.toLowerCase().startsWith('none');
452
423
  const isApiOrWebDomain = ['API service', 'Web application'].includes(discoveryAnswers.primaryDomain)
453
424
  || discoveryAnswers.primaryDomain.toLowerCase().includes('api')
454
425
  || discoveryAnswers.primaryDomain.toLowerCase().includes('web');
455
426
 
456
- const documentManifest = [
457
- { templateFileName: 'project-brief.md.tmpl', outputFileName: 'project-brief.md', alwaysInclude: true },
458
- { templateFileName: 'architecture-decision-record.md.tmpl', outputFileName: 'architecture-decision-record.md', alwaysInclude: true },
459
- { templateFileName: 'flow-overview.md.tmpl', outputFileName: 'flow-overview.md', alwaysInclude: true },
427
+ const requiredDocFileNames = [
428
+ 'project-brief.md',
429
+ 'architecture-decision-record.md',
430
+ 'flow-overview.md',
460
431
  ];
461
432
 
462
433
  if (hasDatabase) {
463
- documentManifest.push({
464
- templateFileName: 'database-schema.md.tmpl',
465
- outputFileName: 'database-schema.md',
466
- alwaysInclude: false,
467
- });
434
+ requiredDocFileNames.push('database-schema.md');
468
435
  }
469
436
 
470
437
  if (isApiOrWebDomain) {
471
- documentManifest.push({
472
- templateFileName: 'api-contract.md.tmpl',
473
- outputFileName: 'api-contract.md',
474
- alwaysInclude: false,
475
- });
438
+ requiredDocFileNames.push('api-contract.md');
476
439
  }
477
440
 
478
- return { documentManifest, hasDatabase, hasAuth };
441
+ return { requiredDocFileNames };
479
442
  }
480
443
 
481
444
  /**
482
- * Build template context from discovery answers and init selections.
445
+ * Build synthesis context from discovery answers and init selections.
483
446
  */
484
- export function buildTemplateContext(discoveryAnswers, initContext) {
485
- const hasDatabase = !discoveryAnswers.databaseChoice.toLowerCase().startsWith('none');
486
- const hasAuth = !discoveryAnswers.authStrategy.toLowerCase().startsWith('none');
447
+ export function buildSynthesisContext(_discoveryAnswers, initContext) {
487
448
  const additionalStackFileNames = Array.isArray(initContext.additionalStackFileNames)
488
449
  ? initContext.additionalStackFileNames
489
450
  : [];
490
451
  const additionalBlueprintFileNames = Array.isArray(initContext.additionalBlueprintFileNames)
491
452
  ? initContext.additionalBlueprintFileNames
492
453
  : [];
493
- const parsedDockerStrategy = parseDockerStrategy(discoveryAnswers.dockerStrategy);
494
-
495
- const baseUrlMap = {
496
- 'API service': 'http://localhost:3000',
497
- 'Web application': 'http://localhost:3000/api',
498
- 'Mobile app': 'http://localhost:3000/api',
499
- 'CLI tool': 'N/A',
500
- 'Library / SDK': 'N/A',
501
- };
502
454
 
503
455
  return {
504
- projectName: discoveryAnswers.projectName,
505
- projectDescription: discoveryAnswers.projectDescription,
506
- primaryDomain: discoveryAnswers.primaryDomain,
507
- databaseChoice: discoveryAnswers.databaseChoice,
508
- authStrategy: discoveryAnswers.authStrategy,
509
- features: discoveryAnswers.features,
510
- additionalContext: discoveryAnswers.additionalContext,
511
456
  stackFileName: initContext.stackFileName,
512
- stackDisplayName: toTitleCase(initContext.stackFileName),
513
457
  additionalStackFileNames,
514
- additionalStackDisplayNames: additionalStackFileNames.length > 0
515
- ? additionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName))
516
- : null,
517
458
  blueprintFileName: initContext.blueprintFileName,
518
- blueprintDisplayName: toTitleCase(initContext.blueprintFileName),
519
459
  additionalBlueprintFileNames,
520
- additionalBlueprintDisplayNames: additionalBlueprintFileNames.length > 0
521
- ? additionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName))
522
- : null,
523
460
  runtimeEnvironmentKey: initContext.runtimeEnvironmentKey || 'linux',
524
461
  runtimeEnvironmentLabel: initContext.runtimeEnvironmentLabel || 'Linux',
525
- cliVersion: CLI_VERSION,
526
- templateVersion: PROJECT_DOC_TEMPLATE_VERSION,
527
- generatedAt: new Date().toISOString(),
528
- generatedDate: new Date().toISOString().split('T')[0],
529
- hasDatabase,
530
- hasAuth,
531
- hasDocker: parsedDockerStrategy.hasDocker,
532
- dockerStrategy: parsedDockerStrategy.dockerStrategy,
533
- useDockerDevelopment: parsedDockerStrategy.useDockerDevelopment,
534
- useDockerProduction: parsedDockerStrategy.useDockerProduction,
535
- dockerDevelopmentGuidance: parsedDockerStrategy.useDockerDevelopment
536
- ? '- Development containers are required: optimize for fast rebuilds, bind mounts, and debug-friendly startup.'
537
- : '',
538
- dockerProductionGuidance: parsedDockerStrategy.useDockerProduction
539
- ? '- Production containers are required: use multi-stage builds, non-root runtime, and minimal image footprint.'
540
- : '',
541
- baseUrl: baseUrlMap[discoveryAnswers.primaryDomain] || 'http://localhost:3000',
542
462
  };
543
463
  }
544
464
 
545
- /**
546
- * Render a template string by replacing {{placeholder}} tokens with context values.
547
- * Supports:
548
- * - {{key}} for simple values
549
- * - {{#each key}}...{{this}}...{{/each}} for arrays
550
- * - {{#if key}}...{{/if}} for conditionals
551
- */
552
- export function renderTemplate(templateContent, templateContext) {
553
- let renderedContent = templateContent;
554
-
555
- // Process {{#each key}}...{{/each}} blocks
556
- renderedContent = renderedContent.replace(
557
- /\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g,
558
- (_fullMatch, iteratorKey, iteratorBody) => {
559
- const iteratorValues = templateContext[iteratorKey];
560
-
561
- if (!Array.isArray(iteratorValues) || iteratorValues.length === 0) {
562
- return '';
563
- }
564
-
565
- return iteratorValues
566
- .map((iteratorValue) => iteratorBody.replace(/\{\{this\}\}/g, iteratorValue))
567
- .join('');
568
- }
569
- );
570
-
571
- // Process {{#if key}}...{{/if}} blocks
572
- renderedContent = renderedContent.replace(
573
- /\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g,
574
- (_fullMatch, conditionKey, conditionBody) => {
575
- const conditionValue = templateContext[conditionKey];
576
- return conditionValue ? conditionBody : '';
577
- }
578
- );
579
-
580
- // Process simple {{key}} replacements
581
- renderedContent = renderedContent.replace(
582
- /\{\{(\w+)\}\}/g,
583
- (_fullMatch, placeholderKey) => {
584
- const placeholderValue = templateContext[placeholderKey];
585
-
586
- if (placeholderValue === undefined || placeholderValue === null) {
587
- return `{{${placeholderKey}}}`;
588
- }
589
-
590
- if (Array.isArray(placeholderValue)) {
591
- return placeholderValue.join(', ');
592
- }
593
-
594
- return String(placeholderValue);
595
- }
596
- );
597
-
598
- return renderedContent;
599
- }
600
-
601
465
  function shouldBootstrapDesignDocument(discoveryAnswers, initContext) {
602
466
  const normalizedDomain = String(discoveryAnswers.primaryDomain || '').trim().toLowerCase();
603
467
  const normalizedBlueprint = String(initContext.blueprintFileName || '').trim().toLowerCase();
@@ -670,6 +534,7 @@ function buildProjectContextBootstrapPrompt({
670
534
  '2. Every major section must explain rationale and tradeoffs.',
671
535
  '3. Keep stack, database, and auth aligned with the project constraints below unless user explicitly requests migration.',
672
536
  '4. Output must be implementation-ready for engineers, not generic textbook explanation.',
537
+ '5. For any research-backed claim, include citation metadata (source + fetchedAt timestamp) from the Architect Engine Snapshot.',
673
538
  '',
674
539
  '## Project Inputs',
675
540
  `- Project name: ${discoveryAnswers.projectName}`,
@@ -764,7 +629,6 @@ function buildDesignBootstrapPrompt({
764
629
 
765
630
  /**
766
631
  * Generate AI-first bootstrap prompts for dynamic project documentation synthesis.
767
- * Legacy template rendering utilities are retained for backward compatibility checks.
768
632
  */
769
633
  export async function generateProjectDocumentation(
770
634
  targetDirectoryPath,
@@ -781,16 +645,16 @@ export async function generateProjectDocumentation(
781
645
  const promptsDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'prompts');
782
646
  await ensureDirectory(promptsDirectoryPath);
783
647
 
784
- const templateContext = buildTemplateContext(discoveryAnswers, initContext);
785
- const { documentManifest } = resolveDocumentManifest(discoveryAnswers);
786
- const expectedDocFileNames = documentManifest.map((documentEntry) => documentEntry.outputFileName);
648
+ const synthesisContext = buildSynthesisContext(discoveryAnswers, initContext);
649
+ const { requiredDocFileNames } = resolveProjectDocTargets(discoveryAnswers);
650
+ const expectedDocFileNames = [...requiredDocFileNames];
787
651
  const generatedPromptFileNames = [];
788
652
 
789
653
  const projectContextPromptFileName = 'bootstrap-project-context.md';
790
654
  const architectureRecommendation = initContext.architectureRecommendation || null;
791
655
  const projectContextPromptContent = buildProjectContextBootstrapPrompt({
792
656
  discoveryAnswers,
793
- initContext: templateContext,
657
+ initContext: synthesisContext,
794
658
  expectedDocFileNames,
795
659
  docsLanguage: normalizedDocsLanguage,
796
660
  architectureRecommendation,
@@ -806,7 +670,7 @@ export async function generateProjectDocumentation(
806
670
  const designPromptFileName = 'bootstrap-design.md';
807
671
  const designPromptContent = buildDesignBootstrapPrompt({
808
672
  discoveryAnswers,
809
- initContext: templateContext,
673
+ initContext: synthesisContext,
810
674
  docsLanguage: normalizedDocsLanguage,
811
675
  architectureRecommendation,
812
676
  });