@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.
- package/.agent-context/prompts/init-project.md +5 -5
- package/.agent-context/prompts/refactor.md +2 -1
- package/.agent-context/prompts/review-code.md +3 -2
- package/.agent-context/review-checklists/pr-checklist.md +8 -1
- package/.agent-context/rules/architecture.md +11 -0
- package/.agent-context/rules/frontend-architecture.md +2 -2
- package/.agent-context/state/architecture-map.md +1 -1
- package/.agent-context/state/memory-continuity-benchmark.json +1 -1
- package/.agents/workflows/init-project.md +3 -3
- package/.agents/workflows/refactor.md +1 -1
- package/.agents/workflows/review-code.md +4 -5
- package/.cursorrules +27 -71
- package/.gemini/instructions.md +6 -7
- package/.github/copilot-instructions.md +5 -6
- package/.windsurfrules +27 -71
- package/AGENTS.md +7 -9
- package/CONTRIBUTING.md +18 -31
- package/README.md +28 -4
- package/bin/agentic-senior-core.js +0 -6
- package/lib/cli/commands/init.mjs +142 -655
- package/lib/cli/commands/launch.mjs +1 -23
- package/lib/cli/commands/rollback.mjs +1 -1
- package/lib/cli/commands/upgrade.mjs +1 -23
- package/lib/cli/compiler.mjs +116 -70
- package/lib/cli/constants.mjs +84 -26
- package/lib/cli/init-architecture-flow.mjs +231 -0
- package/lib/cli/init-detection-flow.mjs +123 -0
- package/lib/cli/init-options.mjs +344 -0
- package/lib/cli/init-selection.mjs +100 -0
- package/lib/cli/preflight.mjs +1 -1
- package/lib/cli/profile-packs.mjs +15 -1
- package/lib/cli/project-scaffolder.mjs +209 -161
- package/lib/cli/utils.mjs +17 -13
- package/mcp.json +19 -19
- package/package.json +5 -2
- package/scripts/context-triggered-audit.mjs +18 -18
- package/scripts/documentation-boundary-audit.mjs +92 -5
- package/scripts/forbidden-content-check.mjs +1 -1
- package/scripts/frontend-usability-audit.mjs +21 -28
- package/scripts/governance-weekly-report.mjs +29 -15
- package/scripts/llm-judge.mjs +2 -5
- package/scripts/mcp-server.mjs +389 -5
- package/scripts/release-gate.mjs +121 -145
- package/scripts/sync-thin-adapters.mjs +161 -0
- package/scripts/v3-purge-audit.mjs +231 -0
- package/scripts/validate-evidence-bundle.mjs +1 -1
- package/scripts/validate.mjs +224 -272
- package/.agent-context/blueprints/api-nextjs.md +0 -184
- package/.agent-context/blueprints/aspnet-api.md +0 -247
- package/.agent-context/blueprints/ci-github-actions.md +0 -226
- package/.agent-context/blueprints/ci-gitlab.md +0 -200
- package/.agent-context/blueprints/fastapi-service.md +0 -210
- package/.agent-context/blueprints/go-service.md +0 -217
- package/.agent-context/blueprints/graphql-grpc-api.md +0 -51
- package/.agent-context/blueprints/infrastructure-as-code.md +0 -62
- package/.agent-context/blueprints/kubernetes-manifests.md +0 -76
- package/.agent-context/blueprints/laravel-api.md +0 -233
- package/.agent-context/blueprints/mobile-app.md +0 -91
- package/.agent-context/blueprints/nestjs-logic.md +0 -247
- package/.agent-context/blueprints/observability.md +0 -227
- package/.agent-context/blueprints/spring-boot-api.md +0 -218
- package/.agent-context/profiles/platform.md +0 -13
- package/.agent-context/profiles/regulated.md +0 -13
- package/.agent-context/profiles/startup.md +0 -13
- package/.agent-context/review-checklists/frontend-excellence-rubric.md +0 -73
- package/.agent-context/review-checklists/frontend-skill-parity.md +0 -29
- package/.agent-context/review-checklists/frontend-usability.md +0 -35
- package/.agent-context/review-checklists/marketplace-acceptance.md +0 -60
- package/.agent-context/review-checklists/performance-audit.md +0 -71
- package/.agent-context/review-checklists/release-operations.md +0 -33
- package/.agent-context/review-checklists/security-audit.md +0 -119
- package/.agent-context/skills/README.md +0 -63
- package/.agent-context/skills/backend/README.md +0 -68
- package/.agent-context/skills/backend/architecture.md +0 -361
- package/.agent-context/skills/backend/compatibility-manifest.json +0 -8
- package/.agent-context/skills/backend/data-access.md +0 -231
- package/.agent-context/skills/backend/errors.md +0 -138
- package/.agent-context/skills/backend/validation.md +0 -117
- package/.agent-context/skills/backend.md +0 -29
- package/.agent-context/skills/cli/.evidence/compatibility-manifest.json +0 -5
- package/.agent-context/skills/cli/.evidence/sbom-excerpt.json +0 -10
- package/.agent-context/skills/cli/.evidence/test-report.json +0 -8
- package/.agent-context/skills/cli/CHANGELOG.md +0 -6
- package/.agent-context/skills/cli/README.md +0 -56
- package/.agent-context/skills/cli/compatibility-manifest.json +0 -8
- package/.agent-context/skills/cli/init.md +0 -38
- package/.agent-context/skills/cli/output.md +0 -36
- package/.agent-context/skills/cli/package.json +0 -5
- package/.agent-context/skills/cli/safety-telemetry.md +0 -39
- package/.agent-context/skills/cli/tests/.gitkeep +0 -1
- package/.agent-context/skills/cli/upgrade.md +0 -38
- package/.agent-context/skills/cli.md +0 -32
- package/.agent-context/skills/distribution/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/distribution/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/distribution/.evidence/test-report.json +0 -8
- package/.agent-context/skills/distribution/CHANGELOG.md +0 -7
- package/.agent-context/skills/distribution/README.md +0 -27
- package/.agent-context/skills/distribution/compatibility-manifest.json +0 -8
- package/.agent-context/skills/distribution/compatibility.md +0 -32
- package/.agent-context/skills/distribution/package.json +0 -5
- package/.agent-context/skills/distribution/provenance-attestation.md +0 -47
- package/.agent-context/skills/distribution/publish.md +0 -37
- package/.agent-context/skills/distribution/rollback.md +0 -32
- package/.agent-context/skills/distribution/tests/.gitkeep +0 -1
- package/.agent-context/skills/distribution.md +0 -32
- package/.agent-context/skills/frontend/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/frontend/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/frontend/.evidence/test-report.json +0 -8
- package/.agent-context/skills/frontend/CHANGELOG.md +0 -7
- package/.agent-context/skills/frontend/README.md +0 -50
- package/.agent-context/skills/frontend/accessibility.md +0 -107
- package/.agent-context/skills/frontend/compatibility-manifest.json +0 -8
- package/.agent-context/skills/frontend/conversion-clarity.md +0 -51
- package/.agent-context/skills/frontend/motion.md +0 -67
- package/.agent-context/skills/frontend/package.json +0 -5
- package/.agent-context/skills/frontend/performance.md +0 -63
- package/.agent-context/skills/frontend/responsive-delivery.md +0 -41
- package/.agent-context/skills/frontend/tests/.gitkeep +0 -1
- package/.agent-context/skills/frontend/ui-architecture.md +0 -128
- package/.agent-context/skills/frontend.md +0 -40
- package/.agent-context/skills/fullstack/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/fullstack/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/fullstack/.evidence/test-report.json +0 -8
- package/.agent-context/skills/fullstack/CHANGELOG.md +0 -7
- package/.agent-context/skills/fullstack/README.md +0 -27
- package/.agent-context/skills/fullstack/compatibility-manifest.json +0 -8
- package/.agent-context/skills/fullstack/contracts.md +0 -53
- package/.agent-context/skills/fullstack/end-to-end.md +0 -42
- package/.agent-context/skills/fullstack/feature-slicing.md +0 -65
- package/.agent-context/skills/fullstack/package.json +0 -5
- package/.agent-context/skills/fullstack/release-coordination.md +0 -51
- package/.agent-context/skills/fullstack/tests/.gitkeep +0 -1
- package/.agent-context/skills/fullstack.md +0 -30
- package/.agent-context/skills/index.json +0 -107
- package/.agent-context/skills/review-quality/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/review-quality/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/review-quality/.evidence/test-report.json +0 -8
- package/.agent-context/skills/review-quality/CHANGELOG.md +0 -7
- package/.agent-context/skills/review-quality/README.md +0 -27
- package/.agent-context/skills/review-quality/benchmark.md +0 -30
- package/.agent-context/skills/review-quality/compatibility-manifest.json +0 -8
- package/.agent-context/skills/review-quality/package.json +0 -5
- package/.agent-context/skills/review-quality/planning.md +0 -38
- package/.agent-context/skills/review-quality/release-decision.md +0 -49
- package/.agent-context/skills/review-quality/security.md +0 -34
- package/.agent-context/skills/review-quality/tests/.gitkeep +0 -1
- package/.agent-context/skills/review-quality.md +0 -34
- package/.agent-context/stacks/csharp.md +0 -149
- package/.agent-context/stacks/flutter.md +0 -16
- package/.agent-context/stacks/go.md +0 -181
- package/.agent-context/stacks/java.md +0 -135
- package/.agent-context/stacks/php.md +0 -192
- package/.agent-context/stacks/python.md +0 -153
- package/.agent-context/stacks/react-native.md +0 -16
- package/.agent-context/stacks/ruby.md +0 -80
- package/.agent-context/stacks/rust.md +0 -86
- package/.agent-context/stacks/typescript.md +0 -317
- package/.agent-context/state/skill-platform.json +0 -38
- package/lib/cli/skill-selector.mjs +0 -232
- package/lib/cli/templates/api-contract.md.id.tmpl +0 -143
- package/lib/cli/templates/api-contract.md.tmpl +0 -143
- package/lib/cli/templates/architecture-decision-record.md.id.tmpl +0 -106
- package/lib/cli/templates/architecture-decision-record.md.tmpl +0 -145
- package/lib/cli/templates/database-schema.md.id.tmpl +0 -74
- package/lib/cli/templates/database-schema.md.tmpl +0 -74
- package/lib/cli/templates/flow-overview.md.id.tmpl +0 -118
- package/lib/cli/templates/flow-overview.md.tmpl +0 -131
- package/lib/cli/templates/project-brief.md.id.tmpl +0 -55
- package/lib/cli/templates/project-brief.md.tmpl +0 -79
- package/scripts/init-project.ps1 +0 -105
- package/scripts/init-project.sh +0 -131
- package/scripts/skill-tier-policy.mjs +0 -76
- 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
|
+
}
|
package/lib/cli/preflight.mjs
CHANGED
|
@@ -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
|
-
|
|
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,7 +17,9 @@ 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';
|
|
22
|
+
export const PROJECT_DOC_SYNTHESIS_PROMPT_VERSION = '2.0.0';
|
|
26
23
|
|
|
27
24
|
const DOMAIN_CHOICES = [
|
|
28
25
|
'API service',
|
|
@@ -223,30 +220,6 @@ export function normalizeDocsLanguage(rawDocsLanguage = 'en') {
|
|
|
223
220
|
return SUPPORTED_DOC_LANGUAGES.has(normalizedDocsLanguage) ? normalizedDocsLanguage : null;
|
|
224
221
|
}
|
|
225
222
|
|
|
226
|
-
function resolveLocalizedTemplateFileName(templateFileName, docsLanguage) {
|
|
227
|
-
if (docsLanguage === 'en') {
|
|
228
|
-
return templateFileName;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return templateFileName.replace(/\.md\.tmpl$/i, `.md.${docsLanguage}.tmpl`);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async function resolveTemplateFilePath(templateFileName, docsLanguage) {
|
|
235
|
-
const localizedTemplateFileName = resolveLocalizedTemplateFileName(templateFileName, docsLanguage);
|
|
236
|
-
const localizedTemplateFilePath = path.join(TEMPLATES_DIRECTORY_PATH, localizedTemplateFileName);
|
|
237
|
-
|
|
238
|
-
if (await pathExists(localizedTemplateFilePath)) {
|
|
239
|
-
return localizedTemplateFilePath;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const defaultTemplateFilePath = path.join(TEMPLATES_DIRECTORY_PATH, templateFileName);
|
|
243
|
-
if (await pathExists(defaultTemplateFilePath)) {
|
|
244
|
-
return defaultTemplateFilePath;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return null;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
223
|
/**
|
|
251
224
|
* Run the project discovery interview.
|
|
252
225
|
* Returns a structured object with all user responses.
|
|
@@ -443,162 +416,219 @@ export async function runProjectDiscovery(userInterface, options = {}) {
|
|
|
443
416
|
}
|
|
444
417
|
|
|
445
418
|
/**
|
|
446
|
-
* Determine
|
|
419
|
+
* Determine required docs based on project discovery answers.
|
|
447
420
|
*/
|
|
448
|
-
export function
|
|
421
|
+
export function resolveProjectDocTargets(discoveryAnswers) {
|
|
449
422
|
const hasDatabase = !discoveryAnswers.databaseChoice.toLowerCase().startsWith('none');
|
|
450
|
-
const hasAuth = !discoveryAnswers.authStrategy.toLowerCase().startsWith('none');
|
|
451
423
|
const isApiOrWebDomain = ['API service', 'Web application'].includes(discoveryAnswers.primaryDomain)
|
|
452
424
|
|| discoveryAnswers.primaryDomain.toLowerCase().includes('api')
|
|
453
425
|
|| discoveryAnswers.primaryDomain.toLowerCase().includes('web');
|
|
454
426
|
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
427
|
+
const requiredDocFileNames = [
|
|
428
|
+
'project-brief.md',
|
|
429
|
+
'architecture-decision-record.md',
|
|
430
|
+
'flow-overview.md',
|
|
459
431
|
];
|
|
460
432
|
|
|
461
433
|
if (hasDatabase) {
|
|
462
|
-
|
|
463
|
-
templateFileName: 'database-schema.md.tmpl',
|
|
464
|
-
outputFileName: 'database-schema.md',
|
|
465
|
-
alwaysInclude: false,
|
|
466
|
-
});
|
|
434
|
+
requiredDocFileNames.push('database-schema.md');
|
|
467
435
|
}
|
|
468
436
|
|
|
469
437
|
if (isApiOrWebDomain) {
|
|
470
|
-
|
|
471
|
-
templateFileName: 'api-contract.md.tmpl',
|
|
472
|
-
outputFileName: 'api-contract.md',
|
|
473
|
-
alwaysInclude: false,
|
|
474
|
-
});
|
|
438
|
+
requiredDocFileNames.push('api-contract.md');
|
|
475
439
|
}
|
|
476
440
|
|
|
477
|
-
return {
|
|
441
|
+
return { requiredDocFileNames };
|
|
478
442
|
}
|
|
479
443
|
|
|
480
444
|
/**
|
|
481
|
-
* Build
|
|
445
|
+
* Build synthesis context from discovery answers and init selections.
|
|
482
446
|
*/
|
|
483
|
-
export function
|
|
484
|
-
const hasDatabase = !discoveryAnswers.databaseChoice.toLowerCase().startsWith('none');
|
|
485
|
-
const hasAuth = !discoveryAnswers.authStrategy.toLowerCase().startsWith('none');
|
|
447
|
+
export function buildSynthesisContext(_discoveryAnswers, initContext) {
|
|
486
448
|
const additionalStackFileNames = Array.isArray(initContext.additionalStackFileNames)
|
|
487
449
|
? initContext.additionalStackFileNames
|
|
488
450
|
: [];
|
|
489
451
|
const additionalBlueprintFileNames = Array.isArray(initContext.additionalBlueprintFileNames)
|
|
490
452
|
? initContext.additionalBlueprintFileNames
|
|
491
453
|
: [];
|
|
492
|
-
const parsedDockerStrategy = parseDockerStrategy(discoveryAnswers.dockerStrategy);
|
|
493
|
-
|
|
494
|
-
const baseUrlMap = {
|
|
495
|
-
'API service': 'http://localhost:3000',
|
|
496
|
-
'Web application': 'http://localhost:3000/api',
|
|
497
|
-
'Mobile app': 'http://localhost:3000/api',
|
|
498
|
-
'CLI tool': 'N/A',
|
|
499
|
-
'Library / SDK': 'N/A',
|
|
500
|
-
};
|
|
501
454
|
|
|
502
455
|
return {
|
|
503
|
-
projectName: discoveryAnswers.projectName,
|
|
504
|
-
projectDescription: discoveryAnswers.projectDescription,
|
|
505
|
-
primaryDomain: discoveryAnswers.primaryDomain,
|
|
506
|
-
databaseChoice: discoveryAnswers.databaseChoice,
|
|
507
|
-
authStrategy: discoveryAnswers.authStrategy,
|
|
508
|
-
features: discoveryAnswers.features,
|
|
509
|
-
additionalContext: discoveryAnswers.additionalContext,
|
|
510
456
|
stackFileName: initContext.stackFileName,
|
|
511
|
-
stackDisplayName: toTitleCase(initContext.stackFileName),
|
|
512
457
|
additionalStackFileNames,
|
|
513
|
-
additionalStackDisplayNames: additionalStackFileNames.length > 0
|
|
514
|
-
? additionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName))
|
|
515
|
-
: null,
|
|
516
458
|
blueprintFileName: initContext.blueprintFileName,
|
|
517
|
-
blueprintDisplayName: toTitleCase(initContext.blueprintFileName),
|
|
518
459
|
additionalBlueprintFileNames,
|
|
519
|
-
additionalBlueprintDisplayNames: additionalBlueprintFileNames.length > 0
|
|
520
|
-
? additionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName))
|
|
521
|
-
: null,
|
|
522
460
|
runtimeEnvironmentKey: initContext.runtimeEnvironmentKey || 'linux',
|
|
523
461
|
runtimeEnvironmentLabel: initContext.runtimeEnvironmentLabel || 'Linux',
|
|
524
|
-
cliVersion: CLI_VERSION,
|
|
525
|
-
templateVersion: PROJECT_DOC_TEMPLATE_VERSION,
|
|
526
|
-
generatedAt: new Date().toISOString(),
|
|
527
|
-
generatedDate: new Date().toISOString().split('T')[0],
|
|
528
|
-
hasDatabase,
|
|
529
|
-
hasAuth,
|
|
530
|
-
hasDocker: parsedDockerStrategy.hasDocker,
|
|
531
|
-
dockerStrategy: parsedDockerStrategy.dockerStrategy,
|
|
532
|
-
useDockerDevelopment: parsedDockerStrategy.useDockerDevelopment,
|
|
533
|
-
useDockerProduction: parsedDockerStrategy.useDockerProduction,
|
|
534
|
-
dockerDevelopmentGuidance: parsedDockerStrategy.useDockerDevelopment
|
|
535
|
-
? '- Development containers are required: optimize for fast rebuilds, bind mounts, and debug-friendly startup.'
|
|
536
|
-
: '',
|
|
537
|
-
dockerProductionGuidance: parsedDockerStrategy.useDockerProduction
|
|
538
|
-
? '- Production containers are required: use multi-stage builds, non-root runtime, and minimal image footprint.'
|
|
539
|
-
: '',
|
|
540
|
-
baseUrl: baseUrlMap[discoveryAnswers.primaryDomain] || 'http://localhost:3000',
|
|
541
462
|
};
|
|
542
463
|
}
|
|
543
464
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
* - {{key}} for simple values
|
|
548
|
-
* - {{#each key}}...{{this}}...{{/each}} for arrays
|
|
549
|
-
* - {{#if key}}...{{/if}} for conditionals
|
|
550
|
-
*/
|
|
551
|
-
export function renderTemplate(templateContent, templateContext) {
|
|
552
|
-
let renderedContent = templateContent;
|
|
553
|
-
|
|
554
|
-
// Process {{#each key}}...{{/each}} blocks
|
|
555
|
-
renderedContent = renderedContent.replace(
|
|
556
|
-
/\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g,
|
|
557
|
-
(_fullMatch, iteratorKey, iteratorBody) => {
|
|
558
|
-
const iteratorValues = templateContext[iteratorKey];
|
|
559
|
-
|
|
560
|
-
if (!Array.isArray(iteratorValues) || iteratorValues.length === 0) {
|
|
561
|
-
return '';
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
return iteratorValues
|
|
565
|
-
.map((iteratorValue) => iteratorBody.replace(/\{\{this\}\}/g, iteratorValue))
|
|
566
|
-
.join('');
|
|
567
|
-
}
|
|
568
|
-
);
|
|
465
|
+
function shouldBootstrapDesignDocument(discoveryAnswers, initContext) {
|
|
466
|
+
const normalizedDomain = String(discoveryAnswers.primaryDomain || '').trim().toLowerCase();
|
|
467
|
+
const normalizedBlueprint = String(initContext.blueprintFileName || '').trim().toLowerCase();
|
|
569
468
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
(
|
|
574
|
-
const conditionValue = templateContext[conditionKey];
|
|
575
|
-
return conditionValue ? conditionBody : '';
|
|
576
|
-
}
|
|
577
|
-
);
|
|
469
|
+
const isUiDomain = normalizedDomain.includes('web')
|
|
470
|
+
|| normalizedDomain.includes('mobile')
|
|
471
|
+
|| normalizedDomain.includes('frontend')
|
|
472
|
+
|| normalizedDomain.includes('ui');
|
|
578
473
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
(_fullMatch, placeholderKey) => {
|
|
583
|
-
const placeholderValue = templateContext[placeholderKey];
|
|
474
|
+
const isBackendOnlyDomain = normalizedDomain.includes('api service')
|
|
475
|
+
|| normalizedDomain.includes('cli tool')
|
|
476
|
+
|| normalizedDomain.includes('library');
|
|
584
477
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
478
|
+
const blueprintLooksUi = normalizedBlueprint.includes('frontend')
|
|
479
|
+
|| normalizedBlueprint.includes('landing')
|
|
480
|
+
|| normalizedBlueprint.includes('ui');
|
|
588
481
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
482
|
+
if (isUiDomain) {
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
592
485
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
486
|
+
if (!isBackendOnlyDomain && blueprintLooksUi) {
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function buildProjectContextBootstrapPrompt({
|
|
494
|
+
discoveryAnswers,
|
|
495
|
+
initContext,
|
|
496
|
+
expectedDocFileNames,
|
|
497
|
+
docsLanguage,
|
|
498
|
+
architectureRecommendation,
|
|
499
|
+
}) {
|
|
500
|
+
const featuresList = Array.isArray(discoveryAnswers.features) && discoveryAnswers.features.length > 0
|
|
501
|
+
? discoveryAnswers.features.map((feature, featureIndex) => `${featureIndex + 1}. ${feature}`).join('\n')
|
|
502
|
+
: '1. Core functionality (define during implementation)';
|
|
503
|
+
|
|
504
|
+
const expectedDocsList = expectedDocFileNames
|
|
505
|
+
.map((fileName, fileIndex) => `${fileIndex + 1}. docs/${fileName}`)
|
|
506
|
+
.join('\n');
|
|
507
|
+
|
|
508
|
+
const architectureSnapshot = architectureRecommendation
|
|
509
|
+
? JSON.stringify({
|
|
510
|
+
stack: architectureRecommendation.recommendedStackFileName,
|
|
511
|
+
blueprint: architectureRecommendation.recommendedBlueprintFileName,
|
|
512
|
+
confidenceLabel: architectureRecommendation.confidenceLabel,
|
|
513
|
+
confidenceScore: architectureRecommendation.confidenceScore,
|
|
514
|
+
research: architectureRecommendation.research,
|
|
515
|
+
evidenceCitations: architectureRecommendation.evidenceCitations,
|
|
516
|
+
designGuidance: architectureRecommendation.designGuidance,
|
|
517
|
+
}, null, 2)
|
|
518
|
+
: 'null';
|
|
519
|
+
|
|
520
|
+
return [
|
|
521
|
+
'# Bootstrap Prompt: Dynamic Project Context Synthesis',
|
|
522
|
+
'',
|
|
523
|
+
`Protocol version: ${PROJECT_DOC_SYNTHESIS_PROMPT_VERSION}`,
|
|
524
|
+
'',
|
|
525
|
+
'You are a Lead Solution Architect and Principal Engineer.',
|
|
526
|
+
'Write project context docs from scratch (no template rendering, no placeholder boilerplate).',
|
|
527
|
+
'',
|
|
528
|
+
'## Mission',
|
|
529
|
+
`Create or update these files in ${docsLanguage.toUpperCase()} language:`,
|
|
530
|
+
expectedDocsList,
|
|
531
|
+
'',
|
|
532
|
+
'## Hard Rules',
|
|
533
|
+
'1. No copy-paste from external prose.',
|
|
534
|
+
'2. Every major section must explain rationale and tradeoffs.',
|
|
535
|
+
'3. Keep stack, database, and auth aligned with the project constraints below unless user explicitly requests migration.',
|
|
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.',
|
|
538
|
+
'',
|
|
539
|
+
'## Project Inputs',
|
|
540
|
+
`- Project name: ${discoveryAnswers.projectName}`,
|
|
541
|
+
`- Project description: ${discoveryAnswers.projectDescription}`,
|
|
542
|
+
`- Primary domain: ${discoveryAnswers.primaryDomain}`,
|
|
543
|
+
`- Database strategy: ${discoveryAnswers.databaseChoice}`,
|
|
544
|
+
`- Auth strategy: ${discoveryAnswers.authStrategy}`,
|
|
545
|
+
`- Docker strategy: ${discoveryAnswers.dockerStrategy}`,
|
|
546
|
+
`- Runtime environment: ${initContext.runtimeEnvironmentLabel || initContext.runtimeEnvironmentKey || 'Linux'}`,
|
|
547
|
+
`- Selected stack: ${toTitleCase(initContext.stackFileName)}`,
|
|
548
|
+
`- Selected blueprint: ${toTitleCase(initContext.blueprintFileName)}`,
|
|
549
|
+
`- Additional stacks: ${Array.isArray(initContext.additionalStackFileNames) && initContext.additionalStackFileNames.length > 0 ? initContext.additionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ') : 'none'}`,
|
|
550
|
+
`- Additional blueprints: ${Array.isArray(initContext.additionalBlueprintFileNames) && initContext.additionalBlueprintFileNames.length > 0 ? initContext.additionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName)).join(', ') : 'none'}`,
|
|
551
|
+
'',
|
|
552
|
+
'## Key Features',
|
|
553
|
+
featuresList,
|
|
554
|
+
'',
|
|
555
|
+
'## Additional Context',
|
|
556
|
+
discoveryAnswers.additionalContext || 'No additional context provided.',
|
|
557
|
+
'',
|
|
558
|
+
'## Architect Engine Snapshot (for grounding)',
|
|
559
|
+
'```json',
|
|
560
|
+
architectureSnapshot,
|
|
561
|
+
'```',
|
|
562
|
+
'',
|
|
563
|
+
'## Required Execution',
|
|
564
|
+
'1. Create all required docs files listed above with complete Markdown content.',
|
|
565
|
+
'2. Keep content original, specific to this project, and actionable for implementation.',
|
|
566
|
+
'3. After writing docs, continue coding tasks using these docs as living project context.',
|
|
567
|
+
'',
|
|
568
|
+
].join('\n');
|
|
569
|
+
}
|
|
596
570
|
|
|
597
|
-
|
|
571
|
+
function buildDesignBootstrapPrompt({
|
|
572
|
+
discoveryAnswers,
|
|
573
|
+
initContext,
|
|
574
|
+
docsLanguage,
|
|
575
|
+
architectureRecommendation,
|
|
576
|
+
}) {
|
|
577
|
+
const designSignals = architectureRecommendation?.designGuidance?.normalizedSignals || null;
|
|
578
|
+
const designSignalsJson = JSON.stringify(designSignals, null, 2);
|
|
579
|
+
|
|
580
|
+
return [
|
|
581
|
+
'# Bootstrap Prompt: Dynamic DESIGN.md Synthesis',
|
|
582
|
+
'',
|
|
583
|
+
`Protocol version: ${PROJECT_DOC_SYNTHESIS_PROMPT_VERSION}`,
|
|
584
|
+
'',
|
|
585
|
+
'You are the Lead UI/UX Art Director for this project.',
|
|
586
|
+
'Write docs/DESIGN.md from zero. Do not use generic template prose.',
|
|
587
|
+
'',
|
|
588
|
+
'## Mission',
|
|
589
|
+
`Author docs/DESIGN.md in ${docsLanguage.toUpperCase()} language with strong art direction and engineering-ready guidance.`,
|
|
590
|
+
'',
|
|
591
|
+
'## Required Sections',
|
|
592
|
+
'1. Design Vision and Product Personality',
|
|
593
|
+
'2. Theme and Atmosphere Direction',
|
|
594
|
+
'3. Color System (tokens, semantic roles, accessibility rationale)',
|
|
595
|
+
'4. Typography System (pairing, scale, usage rules)',
|
|
596
|
+
'5. Spacing and Layout Rhythm',
|
|
597
|
+
'6. Motion and Interaction Principles',
|
|
598
|
+
'7. Component Language (cards, forms, nav, states)',
|
|
599
|
+
'8. Do and Don\'t Rules',
|
|
600
|
+
'9. Accessibility Non-Negotiables',
|
|
601
|
+
'10. Redesign Protocol (how to evolve without breaking design identity)',
|
|
602
|
+
'',
|
|
603
|
+
'## Hard Rules',
|
|
604
|
+
'1. No copy-paste from external style guides.',
|
|
605
|
+
'2. Every major decision must include psychological/product rationale.',
|
|
606
|
+
'3. Keep implementation feasible for the selected stack and blueprint.',
|
|
607
|
+
'4. Keep tone decisive like an art director, not generic AI boilerplate.',
|
|
608
|
+
'',
|
|
609
|
+
'## Project Inputs',
|
|
610
|
+
`- Project name: ${discoveryAnswers.projectName}`,
|
|
611
|
+
`- Product context: ${discoveryAnswers.projectDescription}`,
|
|
612
|
+
`- Domain: ${discoveryAnswers.primaryDomain}`,
|
|
613
|
+
`- Stack: ${toTitleCase(initContext.stackFileName)}`,
|
|
614
|
+
`- Blueprint: ${toTitleCase(initContext.blueprintFileName)}`,
|
|
615
|
+
'',
|
|
616
|
+
'## Architect Design Signals (raw control vector)',
|
|
617
|
+
'Use this only as baseline fuel, then expand into full design direction with original reasoning:',
|
|
618
|
+
'```json',
|
|
619
|
+
designSignalsJson || 'null',
|
|
620
|
+
'```',
|
|
621
|
+
'',
|
|
622
|
+
'## Required Execution',
|
|
623
|
+
'1. Create docs/DESIGN.md with complete content.',
|
|
624
|
+
'2. Ensure rules are practical for implementation and review.',
|
|
625
|
+
'3. After DESIGN.md exists, use it as first-class source for future UI tasks.',
|
|
626
|
+
'',
|
|
627
|
+
].join('\n');
|
|
598
628
|
}
|
|
599
629
|
|
|
600
630
|
/**
|
|
601
|
-
* Generate project documentation
|
|
631
|
+
* Generate AI-first bootstrap prompts for dynamic project documentation synthesis.
|
|
602
632
|
*/
|
|
603
633
|
export async function generateProjectDocumentation(
|
|
604
634
|
targetDirectoryPath,
|
|
@@ -612,34 +642,52 @@ export async function generateProjectDocumentation(
|
|
|
612
642
|
}
|
|
613
643
|
|
|
614
644
|
const docsDirectoryPath = path.join(targetDirectoryPath, 'docs');
|
|
615
|
-
|
|
645
|
+
const promptsDirectoryPath = path.join(targetDirectoryPath, '.agent-context', 'prompts');
|
|
646
|
+
await ensureDirectory(promptsDirectoryPath);
|
|
616
647
|
|
|
617
|
-
const
|
|
618
|
-
const {
|
|
619
|
-
const
|
|
648
|
+
const synthesisContext = buildSynthesisContext(discoveryAnswers, initContext);
|
|
649
|
+
const { requiredDocFileNames } = resolveProjectDocTargets(discoveryAnswers);
|
|
650
|
+
const expectedDocFileNames = [...requiredDocFileNames];
|
|
651
|
+
const generatedPromptFileNames = [];
|
|
620
652
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
653
|
+
const projectContextPromptFileName = 'bootstrap-project-context.md';
|
|
654
|
+
const architectureRecommendation = initContext.architectureRecommendation || null;
|
|
655
|
+
const projectContextPromptContent = buildProjectContextBootstrapPrompt({
|
|
656
|
+
discoveryAnswers,
|
|
657
|
+
initContext: synthesisContext,
|
|
658
|
+
expectedDocFileNames,
|
|
659
|
+
docsLanguage: normalizedDocsLanguage,
|
|
660
|
+
architectureRecommendation,
|
|
661
|
+
});
|
|
662
|
+
await fs.writeFile(
|
|
663
|
+
path.join(promptsDirectoryPath, projectContextPromptFileName),
|
|
664
|
+
projectContextPromptContent,
|
|
665
|
+
'utf8'
|
|
666
|
+
);
|
|
667
|
+
generatedPromptFileNames.push(projectContextPromptFileName);
|
|
668
|
+
|
|
669
|
+
if (shouldBootstrapDesignDocument(discoveryAnswers, initContext)) {
|
|
670
|
+
const designPromptFileName = 'bootstrap-design.md';
|
|
671
|
+
const designPromptContent = buildDesignBootstrapPrompt({
|
|
672
|
+
discoveryAnswers,
|
|
673
|
+
initContext: synthesisContext,
|
|
674
|
+
docsLanguage: normalizedDocsLanguage,
|
|
675
|
+
architectureRecommendation,
|
|
676
|
+
});
|
|
677
|
+
await fs.writeFile(path.join(promptsDirectoryPath, designPromptFileName), designPromptContent, 'utf8');
|
|
678
|
+
generatedPromptFileNames.push(designPromptFileName);
|
|
626
679
|
|
|
627
|
-
if (!
|
|
628
|
-
|
|
629
|
-
continue;
|
|
680
|
+
if (!expectedDocFileNames.includes('DESIGN.md')) {
|
|
681
|
+
expectedDocFileNames.push('DESIGN.md');
|
|
630
682
|
}
|
|
631
|
-
|
|
632
|
-
const templateContent = await fs.readFile(templateFilePath, 'utf8');
|
|
633
|
-
const renderedContent = renderTemplate(templateContent, templateContext);
|
|
634
|
-
const outputFilePath = path.join(docsDirectoryPath, documentEntry.outputFileName);
|
|
635
|
-
|
|
636
|
-
await fs.writeFile(outputFilePath, renderedContent, 'utf8');
|
|
637
|
-
generatedFileNames.push(documentEntry.outputFileName);
|
|
638
683
|
}
|
|
639
684
|
|
|
640
685
|
return {
|
|
641
686
|
docsDirectoryPath,
|
|
642
|
-
generatedFileNames,
|
|
687
|
+
generatedFileNames: expectedDocFileNames,
|
|
688
|
+
generatedPromptFileNames,
|
|
689
|
+
bootstrapMode: 'ai-synthesis',
|
|
690
|
+
synthesisPromptVersion: PROJECT_DOC_SYNTHESIS_PROMPT_VERSION,
|
|
643
691
|
templateVersion: PROJECT_DOC_TEMPLATE_VERSION,
|
|
644
692
|
docsLanguage: normalizedDocsLanguage,
|
|
645
693
|
discoveryAnswers,
|