@ryuenn3123/agentic-senior-core 3.0.7 → 3.0.9

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.
@@ -10,10 +10,12 @@ This contract is a structure and reasoning system, not a fixed visual template.
10
10
  The agent must:
11
11
  1. Read [AGENTS.md](../../AGENTS.md) for project context and team roles.
12
12
  2. Scan all files in [.agent-context/rules/](../rules/) for UI/UX and accessibility standards.
13
- 3. Reference [docs/deep-dive.md](../../docs/deep-dive.md) and [docs/faq.md](../../docs/faq.md) for architecture and product background.
13
+ 3. Use repository evidence from [.agent-context/state/onboarding-report.json](../state/onboarding-report.json), existing UI code, product copy, route names, component names, and any existing `docs/*` project docs to infer architecture and product background.
14
14
  4. If [docs/DESIGN.md](../../docs/DESIGN.md) or `docs/design-intent.json` already exists, check for drift and improve them instead of rewriting blindly.
15
- 5. Treat any example structure or stylistic inspiration as non-normative. Use it only to judge depth and clarity, never to copy a visual language directly.
16
- 6. All references to docs or rules must be clickable markdown links.
15
+ 5. If context is incomplete, write explicit assumptions and reversible design bets instead of defaulting to generic SaaS output.
16
+ 6. Explore multiple plausible design directions internally, then commit to one cohesive direction with clear rationale tied to the product context.
17
+ 7. Treat any example structure or stylistic inspiration as non-normative. Use it only to judge depth and clarity, never to copy a visual language directly.
18
+ 8. All references to docs or rules must be clickable markdown links.
17
19
 
18
20
  Required `docs/DESIGN.md` sections:
19
21
  1. Design Intent and Product Personality
@@ -44,5 +46,5 @@ Required `docs/design-intent.json` fields:
44
46
  Output:
45
47
  - Create or update both `docs/DESIGN.md` and `docs/design-intent.json`.
46
48
  - Keep both files synchronized: the markdown explains the why, the JSON captures the contract in machine-readable form.
47
- - Use practical, modern, accessible language grounded in the project, not generic SaaS defaults.
49
+ - Use practical, modern, accessible language grounded in the project, not generic SaaS defaults or copycat brand systems.
48
50
  - Wait for user approval before generating Figma or code assets.
@@ -6,7 +6,7 @@ This prompt boots a repository with strict rules operations context (Federated G
6
6
  When a new project is created or initialized, the agent should automatically:
7
7
  1. Read [AGENTS.md](../../AGENTS.md) to understand available roles and knowledge base.
8
8
  2. Scan all files in [.agent-context/rules/](../rules/) for mandatory engineering standards.
9
- 3. Review dynamic stack and architecture signals from [docs/deep-dive.md](../../docs/deep-dive.md), [docs/faq.md](../../docs/faq.md), and task constraints.
9
+ 3. Review dynamic stack and architecture signals from [.agent-context/state/onboarding-report.json](../state/onboarding-report.json), [.agent-context/state/stack-research-snapshot.json](../state/stack-research-snapshot.json), available stack and blueprint sources, and task constraints.
10
10
 
11
11
  ## Architect Mode (Recommended)
12
12
  If the user describes a project or feature, the agent should:
@@ -19,7 +19,7 @@ If the user describes a project or feature, the agent should:
19
19
  If the user specifies a framework/blueprint, the agent should:
20
20
  1. Read [AGENTS.md](../../AGENTS.md) for role context.
21
21
  2. Scan all files in [.agent-context/rules/](../rules/) for engineering standards.
22
- 3. Reference [docs/deep-dive.md](../../docs/deep-dive.md) and [docs/faq.md](../../docs/faq.md) for stack/blueprint guidance.
22
+ 3. Reference [.agent-context/state/onboarding-report.json](../state/onboarding-report.json), [.cursorrules](../../.cursorrules), and [.windsurfrules](../../.windsurfrules) for the active stack and blueprint guidance already applied to this project.
23
23
  4. Scaffold the initial project structure following the blueprint exactly:
24
24
  - Create all directories and files from the blueprint
25
25
  - Set up environment config and validation (e.g., Zod, Pydantic, FluentValidation)
@@ -32,7 +32,7 @@ If the user specifies a framework/blueprint, the agent should:
32
32
  - Every dependency must be justified per [efficiency-vs-hype.md](../rules/efficiency-vs-hype.md)
33
33
 
34
34
  ## Stacks & Blueprints Reference
35
- See [docs/roadmap.md](../../docs/roadmap.md) and [docs/deep-dive.md](../../docs/deep-dive.md) for the latest stack and blueprint list.
35
+ See [.agent-context/state/onboarding-report.json](../state/onboarding-report.json), [.cursorrules](../../.cursorrules), and [.windsurfrules](../../.windsurfrules) for the latest shipped stack and blueprint context.
36
36
 
37
37
  ## UI/UX Bootstrap
38
38
  When a user requests frontend or UI/UX design, the agent should automatically execute the [bootstrap-design.md](./bootstrap-design.md) prompt to synthesize a dynamic design contract (`docs/DESIGN.md` + `docs/design-intent.json`).
@@ -93,7 +93,7 @@ Every dependency must be justified per [efficiency-vs-hype.md](../rules/efficien
93
93
 
94
94
  ## Stacks & Blueprints Reference
95
95
 
96
- See [docs/roadmap.md](../../docs/roadmap.md) and [docs/deep-dive.md](../../docs/deep-dive.md) for the latest stack and blueprint list.
96
+ See [.agent-context/state/onboarding-report.json](../state/onboarding-report.json), [.cursorrules](../../.cursorrules), and [.windsurfrules](../../.windsurfrules) for the latest shipped stack and blueprint context.
97
97
 
98
98
  ---
99
99
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-04-20T00:30:26.121Z",
2
+ "generatedAt": "2026-04-20T02:01:47.871Z",
3
3
  "reportName": "memory-continuity-benchmark",
4
4
  "schemaVersion": "1.0.0",
5
5
  "passed": true,
package/.cursorrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v3.0.7
3
+ Generated by Agentic-Senior-Core CLI v3.0.9
4
4
  Timestamp: 2026-04-18T00:00:00.000Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/.windsurfrules CHANGED
@@ -1,6 +1,6 @@
1
1
  # AGENTIC-SENIOR-CORE DYNAMIC GOVERNANCE RULESET
2
2
 
3
- Generated by Agentic-Senior-Core CLI v3.0.7
3
+ Generated by Agentic-Senior-Core CLI v3.0.9
4
4
  Timestamp: 2026-04-18T00:00:00.000Z
5
5
  Selected profile: beginner
6
6
  Selected policy file: .agent-context/policies/llm-judge-threshold.json
package/README.md CHANGED
@@ -10,12 +10,12 @@
10
10
  **Production-grade Rules Engine (Governance Engine) for AI coding agents.**
11
11
  Works with Cursor, Windsurf, GitHub Copilot, Claude Code, Gemini, and other LLM-powered IDE workflows.
12
12
 
13
- Latest release: 3.0.7 (2026-04-20).
13
+ Latest release: 3.0.9 (2026-04-20).
14
14
 
15
- Highlights in 3.0.7:
16
- - Dynamic UI design contract bootstrap now ships paired markdown and machine-readable intent.
17
- - Upgrade warns when existing UI repositories are missing required design contract files.
18
- - Init discovery stays slimmer by reusing architecture context and removing redundant wizard branches.
15
+ Highlights in 3.0.9:
16
+ - Design bootstrap prompts now rely on shipped project evidence instead of assuming extra docs exist in every initialized repository.
17
+ - Dynamic UI design guidance now emphasizes structure, rationale, and anti-generic constraints without anchoring to example brand systems.
18
+ - Init prompts now point agents at the active onboarding and compiled-rule context that actually exists in target projects.
19
19
 
20
20
  </div>
21
21
 
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { createInterface } from 'node:readline/promises';
6
6
  import { stdin, stdout } from 'node:process';
7
+ import fs from 'node:fs/promises';
7
8
  import path from 'node:path';
8
9
 
9
10
  import {
@@ -29,10 +30,16 @@ import {
29
30
  formatBlockingSeverities,
30
31
  formatDuration,
31
32
  copyGovernanceAssetsToTarget,
33
+ pathExists,
32
34
  } from '../utils.mjs';
33
35
 
34
36
  import { collectProfilePacks, findProfilePackByInput } from '../profile-packs.mjs';
35
- import { detectProjectContext, buildDetectionSummary, formatDetectionCandidates } from '../detector.mjs';
37
+ import {
38
+ detectProjectContext,
39
+ buildDetectionSummary,
40
+ formatDetectionCandidates,
41
+ detectUiScopeSignals,
42
+ } from '../detector.mjs';
36
43
  import { compileDynamicContext, writeSelectedPolicy, writeOnboardingReport } from '../compiler.mjs';
37
44
  import {
38
45
  filterBlueprintFileNamesByCandidates,
@@ -55,6 +62,7 @@ import {
55
62
  hasExistingProjectDocs,
56
63
  loadProjectConfig,
57
64
  normalizeDocsLanguage,
65
+ buildDesignIntentSeedFromSignals,
58
66
  } from '../project-scaffolder.mjs';
59
67
  import { performRollback } from '../rollback.mjs';
60
68
  import {
@@ -162,6 +170,41 @@ async function askBlueprintSelection(promptMessage, selectableBlueprintFileNames
162
170
  return selectableBlueprintFileNames[selectedIndex] || selectableBlueprintFileNames[0] || null;
163
171
  }
164
172
 
173
+ function buildInitExistingProjectDesignIntentSeed({
174
+ targetDirectoryPath,
175
+ packageManifest,
176
+ selectedStackFileName,
177
+ selectedBlueprintFileName,
178
+ uiScopeSignals,
179
+ architectureProjectDescription,
180
+ }) {
181
+ const projectName = String(packageManifest?.name || path.basename(targetDirectoryPath)).trim() || 'existing-ui-project';
182
+ const isMobileUiProject = String(selectedStackFileName || '').toLowerCase().includes('react-native')
183
+ || String(selectedStackFileName || '').toLowerCase().includes('flutter')
184
+ || uiScopeSignals.signalReasons.some((signalReason) => signalReason.includes('android') || signalReason.includes('ios'));
185
+ const resolvedDomain = isMobileUiProject ? 'Mobile app' : 'Web application';
186
+ const projectDescription = String(packageManifest?.description || architectureProjectDescription || '').trim()
187
+ || `Existing ${resolvedDomain.toLowerCase()} detected during init. Create a project-specific dynamic design contract before shipping new UI work.`;
188
+
189
+ return buildDesignIntentSeedFromSignals({
190
+ projectName,
191
+ projectDescription,
192
+ primaryDomain: resolvedDomain,
193
+ features: [],
194
+ initContext: {
195
+ stackFileName: selectedStackFileName,
196
+ blueprintFileName: selectedBlueprintFileName,
197
+ },
198
+ status: 'seed-generated-during-init',
199
+ supplementalFields: {
200
+ initSignals: {
201
+ detectedFrom: uiScopeSignals.signalReasons,
202
+ generatedBy: 'init-existing-project-seed',
203
+ },
204
+ },
205
+ });
206
+ }
207
+
165
208
  export async function runInitCommand(targetDirectoryArgument, initOptions = {}) {
166
209
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
167
210
  const isTokenOptimizationEnabled = typeof initOptions.tokenOptimize === 'boolean'
@@ -580,6 +623,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
580
623
 
581
624
  // --- Project Documentation Scaffolding ---
582
625
  let scaffoldingResult = null;
626
+ const supplementalMaterializedDocFileNames = [];
583
627
  const isFreshProjectTarget = wasDirectoryEffectivelyEmpty && !hadExistingProjectDocsBeforeInit;
584
628
  const shouldOfferScaffolding = initOptions.scaffoldDocs === true
585
629
  || Boolean(initOptions.projectConfig)
@@ -661,6 +705,36 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
661
705
  }
662
706
  }
663
707
 
708
+ const existingProjectUiScopeSignals = projectDetection.hasExistingProjectFiles
709
+ ? await detectUiScopeSignals({
710
+ targetDirectoryPath: resolvedTargetDirectoryPath,
711
+ selectedStackFileName: selectedResolvedStackFileName,
712
+ selectedBlueprintFileName: selectedResolvedBlueprintFileName,
713
+ })
714
+ : null;
715
+ const designIntentTargetPath = path.join(resolvedTargetDirectoryPath, 'docs', 'design-intent.json');
716
+ const shouldSeedExistingUiDesignIntent = projectDetection.hasExistingProjectFiles
717
+ && existingProjectUiScopeSignals?.isUiScopeLikely === true
718
+ && !(await pathExists(designIntentTargetPath));
719
+
720
+ if (shouldSeedExistingUiDesignIntent) {
721
+ const docsDirectoryPath = path.join(resolvedTargetDirectoryPath, 'docs');
722
+ const designIntentSeedContent = buildInitExistingProjectDesignIntentSeed({
723
+ targetDirectoryPath: resolvedTargetDirectoryPath,
724
+ packageManifest: existingProjectUiScopeSignals.packageManifest,
725
+ selectedStackFileName: selectedResolvedStackFileName,
726
+ selectedBlueprintFileName: selectedResolvedBlueprintFileName,
727
+ uiScopeSignals: existingProjectUiScopeSignals,
728
+ architectureProjectDescription,
729
+ });
730
+
731
+ await ensureDirectory(docsDirectoryPath);
732
+ await fs.writeFile(designIntentTargetPath, designIntentSeedContent, 'utf8');
733
+ supplementalMaterializedDocFileNames.push('design-intent.json');
734
+
735
+ console.log('\nExisting UI/frontend scope detected. Seeded docs/design-intent.json so the machine-readable design contract exists before UI implementation work continues.');
736
+ }
737
+
664
738
  await compileDynamicContext({
665
739
  targetDirectoryPath: resolvedTargetDirectoryPath,
666
740
  selectedProfileName,
@@ -765,6 +839,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
765
839
  console.log(`- Project docs: ${scaffoldingResult.generatedFileNames.length} files generated in docs/`);
766
840
  console.log(`- Project docs language: ${scaffoldingResult.docsLanguage}`);
767
841
  }
842
+ if (supplementalMaterializedDocFileNames.length > 0) {
843
+ console.log(`- Design seed docs: ${supplementalMaterializedDocFileNames.length} files generated in docs/`);
844
+ }
768
845
  console.log(`- Repository workflows copied: no (workflows remain source-repo assets)`);
769
846
  console.log(`- MCP configuration: ${shouldIncludeMcpTemplate ? 'auto-configured for your IDEs (VS Code, Cursor, Zed, Gemini)' : 'disabled (--no-mcp-template)'}`);
770
847
  if (isMemoryContinuityEnabled) {
@@ -804,6 +881,11 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
804
881
  console.log(`- Build an MVP for ${promptProjectName}. Follow Layer 9 docs and keep the current stack, database, and auth constraints.`);
805
882
  console.log('- Add [new feature] and update docs/project-brief.md plus docs/flow-overview.md in the same change.');
806
883
  console.log('- If this change needs architecture migration, propose a migration plan first, then implement after approval.');
884
+ } else if (supplementalMaterializedDocFileNames.includes('design-intent.json')) {
885
+ console.log('I also seeded docs/design-intent.json for this existing UI repository so future UI work starts from a machine-readable design contract without forcing a canned visual concept.');
886
+ console.log('\nPrompt starter examples (copy and adapt in your IDE):');
887
+ console.log('- If docs/DESIGN.md is missing, execute .agent-context/prompts/bootstrap-design.md now and refine docs/design-intent.json into a complete design contract before building UI components.');
888
+ console.log('- Keep docs/design-intent.json and docs/DESIGN.md synchronized whenever the UI direction changes.');
807
889
  }
808
890
  console.log('Your AI tools will now receive one compiled rulebook plus the original source rules, and your review threshold is stored in .agent-context/policies/llm-judge-threshold.json.');
809
891
  console.log('MCP server registration is manual inside your IDE settings, even when mcp.json exists.');
@@ -29,7 +29,7 @@ import {
29
29
  detectProjectContext,
30
30
  buildDetectionSummary,
31
31
  formatDetectionCandidates,
32
- collectProjectMarkers,
32
+ detectUiScopeSignals,
33
33
  } from '../detector.mjs';
34
34
  import {
35
35
  buildCompiledRulesContent,
@@ -41,7 +41,10 @@ import {
41
41
  import { runPreflightChecks } from '../preflight.mjs';
42
42
  import { createBackup } from '../backup.mjs';
43
43
  import { performRollback } from '../rollback.mjs';
44
- import { detectProjectDocTemplateStaleness } from '../project-scaffolder.mjs';
44
+ import {
45
+ detectProjectDocTemplateStaleness,
46
+ buildDesignIntentSeedFromSignals,
47
+ } from '../project-scaffolder.mjs';
45
48
 
46
49
  export function parseUpgradeArguments(commandArguments) {
47
50
  const parsedUpgradeOptions = {
@@ -104,100 +107,38 @@ function buildExistingProjectMajorConstraints() {
104
107
  ];
105
108
  }
106
109
 
107
- async function readPackageJsonIfExists(targetDirectoryPath) {
108
- const packageJsonPath = path.join(targetDirectoryPath, 'package.json');
109
- if (!(await pathExists(packageJsonPath))) {
110
- return null;
111
- }
112
-
113
- try {
114
- return JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
115
- } catch {
116
- return null;
117
- }
118
- }
119
-
120
- async function detectUiScopeSignals({
110
+ function buildUpgradeDesignIntentSeed({
121
111
  targetDirectoryPath,
122
- existingOnboardingReport,
112
+ packageManifest,
123
113
  selectedStackFileName,
124
114
  selectedBlueprintFileName,
115
+ uiScopeSignals,
125
116
  }) {
126
- const signalReasons = [];
127
- const markerNames = await collectProjectMarkers(targetDirectoryPath);
128
- const packageManifest = await readPackageJsonIfExists(targetDirectoryPath);
129
-
130
- const persistedProjectScopeKey = String(existingOnboardingReport?.projectScope?.key || '').trim().toLowerCase();
131
- if (persistedProjectScopeKey === 'frontend-only' || persistedProjectScopeKey === 'both') {
132
- signalReasons.push(`onboarding project scope: ${persistedProjectScopeKey}`);
133
- }
134
-
135
- const selectedStackKey = String(selectedStackFileName || '').trim().toLowerCase();
136
- if (selectedStackKey === 'react-native.md' || selectedStackKey === 'flutter.md') {
137
- signalReasons.push(`selected stack implies UI runtime: ${selectedStackKey}`);
138
- }
139
-
140
- const selectedBlueprintKey = String(selectedBlueprintFileName || '').trim().toLowerCase();
141
- if (selectedBlueprintKey.includes('frontend') || selectedBlueprintKey.includes('landing') || selectedBlueprintKey.includes('mobile-app')) {
142
- signalReasons.push(`selected blueprint implies UI scope: ${selectedBlueprintKey}`);
143
- }
144
-
145
- const directUiMarkerNames = [
146
- 'next.config.js',
147
- 'next.config.mjs',
148
- 'next.config.ts',
149
- 'tailwind.config.js',
150
- 'tailwind.config.mjs',
151
- 'tailwind.config.ts',
152
- 'vite.config.js',
153
- 'vite.config.mjs',
154
- 'vite.config.ts',
155
- 'react-native.config.js',
156
- 'app',
157
- 'pages',
158
- 'components',
159
- 'public',
160
- 'styles',
161
- 'android',
162
- 'ios',
163
- 'index.html',
164
- ];
165
-
166
- const detectedUiMarkers = directUiMarkerNames.filter((markerName) => markerNames.has(markerName));
167
- if (detectedUiMarkers.length > 0) {
168
- signalReasons.push(`ui markers: ${detectedUiMarkers.join(', ')}`);
169
- }
170
-
171
- const dependencyMap = {
172
- next: 'next',
173
- react: 'react',
174
- reactDom: 'react-dom',
175
- reactNative: 'react-native',
176
- expo: 'expo',
177
- tailwindcss: 'tailwindcss',
178
- };
179
- const dependencySource = {
180
- ...(packageManifest?.dependencies || {}),
181
- ...(packageManifest?.devDependencies || {}),
182
- };
183
- const detectedUiDependencies = Object.values(dependencyMap).filter((dependencyName) => dependencySource[dependencyName]);
184
- if (detectedUiDependencies.length > 0) {
185
- signalReasons.push(`ui dependencies: ${detectedUiDependencies.join(', ')}`);
186
- }
187
-
188
- const hasStrongUiMarker = detectedUiMarkers.some((markerName) => (
189
- markerName.startsWith('next.config')
190
- || markerName === 'react-native.config.js'
191
- || markerName === 'android'
192
- || markerName === 'ios'
193
- ));
194
- const hasUiDependencies = detectedUiDependencies.length > 0;
195
- const hasStructuralUiMarkers = detectedUiMarkers.length >= 2;
196
-
197
- return {
198
- isUiScopeLikely: signalReasons.length > 0 && (hasStrongUiMarker || hasUiDependencies || hasStructuralUiMarkers || persistedProjectScopeKey.length > 0),
199
- signalReasons,
200
- };
117
+ const projectName = String(packageManifest?.name || path.basename(targetDirectoryPath)).trim() || 'existing-ui-project';
118
+ const isMobileUiProject = String(selectedStackFileName || '').toLowerCase().includes('react-native')
119
+ || String(selectedStackFileName || '').toLowerCase().includes('flutter')
120
+ || uiScopeSignals.signalReasons.some((signalReason) => signalReason.includes('android') || signalReason.includes('ios'));
121
+ const resolvedDomain = isMobileUiProject ? 'Mobile app' : 'Web application';
122
+ const projectDescription = String(packageManifest?.description || '').trim()
123
+ || `Existing ${resolvedDomain.toLowerCase()} detected during upgrade. Create a project-specific dynamic design contract before shipping new UI work.`;
124
+
125
+ return buildDesignIntentSeedFromSignals({
126
+ projectName,
127
+ projectDescription,
128
+ primaryDomain: resolvedDomain,
129
+ features: [],
130
+ initContext: {
131
+ stackFileName: selectedStackFileName,
132
+ blueprintFileName: selectedBlueprintFileName,
133
+ },
134
+ status: 'seed-generated-during-upgrade',
135
+ supplementalFields: {
136
+ upgradeSignals: {
137
+ detectedFrom: uiScopeSignals.signalReasons,
138
+ generatedBy: 'upgrade-seed',
139
+ },
140
+ },
141
+ });
201
142
  }
202
143
 
203
144
  export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions = {}) {
@@ -232,7 +173,6 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
232
173
  const blueprintFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'blueprints'));
233
174
  const existingOnboardingReport = await loadOnboardingReportIfExists(resolvedTargetDirectoryPath);
234
175
  const projectDetection = await detectProjectContext(resolvedTargetDirectoryPath);
235
-
236
176
  const selectedProfileName = PROFILE_PRESETS[existingOnboardingReport?.selectedProfile]
237
177
  ? existingOnboardingReport.selectedProfile
238
178
  : 'balanced';
@@ -266,10 +206,12 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
266
206
  : true;
267
207
  const uiScopeSignals = await detectUiScopeSignals({
268
208
  targetDirectoryPath: resolvedTargetDirectoryPath,
269
- existingOnboardingReport,
270
209
  selectedStackFileName,
271
210
  selectedBlueprintFileName,
211
+ projectScopeKey: existingOnboardingReport?.projectScope?.key || null,
212
+ projectScopeSourceLabel: 'onboarding project scope',
272
213
  });
214
+ const packageManifest = uiScopeSignals.packageManifest;
273
215
  const designContractPaths = ['docs/DESIGN.md', 'docs/design-intent.json'];
274
216
  const missingDesignContractPaths = [];
275
217
 
@@ -279,6 +221,17 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
279
221
  missingDesignContractPaths.push(designContractPath);
280
222
  }
281
223
  }
224
+ const shouldSeedDesignIntentOnApply = uiScopeSignals.isUiScopeLikely
225
+ && missingDesignContractPaths.includes('docs/design-intent.json');
226
+ const designIntentSeedContent = shouldSeedDesignIntentOnApply
227
+ ? buildUpgradeDesignIntentSeed({
228
+ targetDirectoryPath: resolvedTargetDirectoryPath,
229
+ packageManifest,
230
+ selectedStackFileName,
231
+ selectedBlueprintFileName,
232
+ uiScopeSignals,
233
+ })
234
+ : null;
282
235
 
283
236
  const detectionMajorConstraints = buildExistingProjectMajorConstraints();
284
237
  const detectionTransparency = {
@@ -408,8 +361,11 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
408
361
  if (uiScopeSignals.signalReasons.length > 0) {
409
362
  console.log(`- Detection signals: ${uiScopeSignals.signalReasons.join('; ')}`);
410
363
  }
364
+ if (shouldSeedDesignIntentOnApply) {
365
+ console.log('- Planned seed on apply: docs/design-intent.json');
366
+ }
411
367
  console.log('Recommendation: create or refresh docs/DESIGN.md and docs/design-intent.json before allowing UI implementation work.');
412
- console.log('Upgrade synchronizes governance assets, but it does not author project-specific design docs automatically.');
368
+ console.log('Upgrade synchronizes governance assets and can seed docs/design-intent.json, but it does not author project-specific docs/DESIGN.md automatically.');
413
369
  }
414
370
 
415
371
  if (upgradeOptions.dryRun) {
@@ -434,6 +390,15 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
434
390
  pruneManagedSurface: upgradeOptions.pruneManagedSurface === true,
435
391
  managedSurfacePlan,
436
392
  });
393
+ const supplementalCreatedFileNames = [];
394
+
395
+ if (shouldSeedDesignIntentOnApply && designIntentSeedContent) {
396
+ const docsDirectoryPath = path.join(resolvedTargetDirectoryPath, 'docs');
397
+ const designIntentTargetPath = path.join(docsDirectoryPath, 'design-intent.json');
398
+ await ensureDirectory(docsDirectoryPath);
399
+ await fs.writeFile(designIntentTargetPath, designIntentSeedContent, 'utf8');
400
+ supplementalCreatedFileNames.push('docs/design-intent.json');
401
+ }
437
402
 
438
403
  await fs.writeFile(currentRulesPath, plannedRulesContent, 'utf8');
439
404
  await fs.writeFile(path.join(resolvedTargetDirectoryPath, '.windsurfrules'), plannedRulesContent, 'utf8');
@@ -471,6 +436,12 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
471
436
  governanceSyncResult.updatedFiles.forEach((fileName) => console.log(` [UPDATED] ${fileName}`));
472
437
  governanceSyncResult.deletedManagedFiles.forEach((fileName) => console.log(` [DELETED] ${fileName}`));
473
438
  }
439
+ if (supplementalCreatedFileNames.length > 0) {
440
+ if (!(governanceSyncResult.updatedFiles.length > 0 || governanceSyncResult.createdFiles.length > 0 || governanceSyncResult.deletedManagedFiles.length > 0)) {
441
+ console.log('\nDetailed changes:');
442
+ }
443
+ supplementalCreatedFileNames.forEach((fileName) => console.log(` [NEW] ${fileName} (seed)`));
444
+ }
474
445
 
475
446
  console.log('\nRefreshed files: .cursorrules, .windsurfrules, .agent-context/state/onboarding-report.json');
476
447
  } catch (error) {
@@ -3,6 +3,7 @@
3
3
  * Depends on: constants.mjs, utils.mjs
4
4
  */
5
5
  import fs from 'node:fs/promises';
6
+ import path from 'node:path';
6
7
 
7
8
  import { BLUEPRINT_RECOMMENDATIONS } from './constants.mjs';
8
9
  import { toTitleCase } from './utils.mjs';
@@ -22,6 +23,106 @@ export async function collectProjectMarkers(targetDirectoryPath) {
22
23
  return markerNames;
23
24
  }
24
25
 
26
+ async function readPackageJsonIfExists(targetDirectoryPath) {
27
+ const packageJsonPath = path.join(targetDirectoryPath, 'package.json');
28
+
29
+ try {
30
+ const packageJsonContent = await fs.readFile(packageJsonPath, 'utf8');
31
+ return JSON.parse(packageJsonContent);
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ export async function detectUiScopeSignals({
38
+ targetDirectoryPath,
39
+ selectedStackFileName,
40
+ selectedBlueprintFileName,
41
+ packageManifest = null,
42
+ projectScopeKey = null,
43
+ projectScopeSourceLabel = 'project scope',
44
+ }) {
45
+ const signalReasons = [];
46
+ const markerNames = await collectProjectMarkers(targetDirectoryPath);
47
+ const resolvedPackageManifest = packageManifest || await readPackageJsonIfExists(targetDirectoryPath);
48
+
49
+ const normalizedProjectScopeKey = String(projectScopeKey || '').trim().toLowerCase();
50
+ if (normalizedProjectScopeKey === 'frontend-only' || normalizedProjectScopeKey === 'both') {
51
+ signalReasons.push(`${projectScopeSourceLabel}: ${normalizedProjectScopeKey}`);
52
+ }
53
+
54
+ const selectedStackKey = String(selectedStackFileName || '').trim().toLowerCase();
55
+ if (selectedStackKey === 'react-native.md' || selectedStackKey === 'flutter.md') {
56
+ signalReasons.push(`selected stack implies UI runtime: ${selectedStackKey}`);
57
+ }
58
+
59
+ const selectedBlueprintKey = String(selectedBlueprintFileName || '').trim().toLowerCase();
60
+ if (selectedBlueprintKey.includes('frontend') || selectedBlueprintKey.includes('landing') || selectedBlueprintKey.includes('mobile-app')) {
61
+ signalReasons.push(`selected blueprint implies UI scope: ${selectedBlueprintKey}`);
62
+ }
63
+
64
+ const directUiMarkerNames = [
65
+ 'next.config.js',
66
+ 'next.config.mjs',
67
+ 'next.config.ts',
68
+ 'tailwind.config.js',
69
+ 'tailwind.config.mjs',
70
+ 'tailwind.config.ts',
71
+ 'vite.config.js',
72
+ 'vite.config.mjs',
73
+ 'vite.config.ts',
74
+ 'react-native.config.js',
75
+ 'app',
76
+ 'pages',
77
+ 'components',
78
+ 'public',
79
+ 'styles',
80
+ 'android',
81
+ 'ios',
82
+ 'index.html',
83
+ ];
84
+
85
+ const detectedUiMarkers = directUiMarkerNames.filter((markerName) => markerNames.has(markerName));
86
+ if (detectedUiMarkers.length > 0) {
87
+ signalReasons.push(`ui markers: ${detectedUiMarkers.join(', ')}`);
88
+ }
89
+
90
+ const dependencySource = {
91
+ ...(resolvedPackageManifest?.dependencies || {}),
92
+ ...(resolvedPackageManifest?.devDependencies || {}),
93
+ };
94
+ const detectableUiDependencies = [
95
+ 'next',
96
+ 'react',
97
+ 'react-dom',
98
+ 'react-native',
99
+ 'expo',
100
+ 'tailwindcss',
101
+ ];
102
+ const detectedUiDependencies = detectableUiDependencies.filter((dependencyName) => dependencySource[dependencyName]);
103
+ if (detectedUiDependencies.length > 0) {
104
+ signalReasons.push(`ui dependencies: ${detectedUiDependencies.join(', ')}`);
105
+ }
106
+
107
+ const hasStrongUiMarker = detectedUiMarkers.some((markerName) => (
108
+ markerName.startsWith('next.config')
109
+ || markerName === 'react-native.config.js'
110
+ || markerName === 'android'
111
+ || markerName === 'ios'
112
+ ));
113
+ const hasUiDependencies = detectedUiDependencies.length > 0;
114
+ const hasStructuralUiMarkers = detectedUiMarkers.length >= 2;
115
+
116
+ return {
117
+ isUiScopeLikely: signalReasons.length > 0
118
+ && (hasStrongUiMarker || hasUiDependencies || hasStructuralUiMarkers || normalizedProjectScopeKey.length > 0),
119
+ signalReasons,
120
+ detectedUiMarkers,
121
+ detectedUiDependencies,
122
+ packageManifest: resolvedPackageManifest,
123
+ };
124
+ }
125
+
25
126
  export async function detectProjectContext(targetDirectoryPath) {
26
127
  const markerNames = await collectProjectMarkers(targetDirectoryPath);
27
128
  const detectionCandidates = [];
@@ -373,21 +373,30 @@ function inferDesignKeywords(discoveryAnswers) {
373
373
  };
374
374
  }
375
375
 
376
- function buildDesignIntentSeed({
377
- discoveryAnswers,
376
+ export function buildDesignIntentSeedFromSignals({
377
+ projectName,
378
+ projectDescription,
379
+ primaryDomain,
380
+ features = [],
378
381
  initContext,
379
- architectureRecommendation,
382
+ architectureRecommendation = null,
383
+ status = 'seed-needs-design-synthesis',
384
+ supplementalFields = {},
380
385
  }) {
381
- const inferredKeywords = inferDesignKeywords(discoveryAnswers);
386
+ const inferredKeywords = inferDesignKeywords({
387
+ projectDescription,
388
+ primaryDomain,
389
+ features,
390
+ });
382
391
  const designSignals = architectureRecommendation?.designGuidance?.normalizedSignals || null;
383
392
 
384
393
  return `${JSON.stringify({
385
394
  mode: 'dynamic',
386
- status: 'seed-needs-design-synthesis',
395
+ status,
387
396
  project: {
388
- name: discoveryAnswers.projectName,
389
- context: discoveryAnswers.projectDescription,
390
- domain: discoveryAnswers.primaryDomain,
397
+ name: projectName,
398
+ context: projectDescription,
399
+ domain: primaryDomain,
391
400
  stack: toTitleCase(initContext.stackFileName),
392
401
  blueprint: toTitleCase(initContext.blueprintFileName),
393
402
  },
@@ -431,9 +440,26 @@ function buildDesignIntentSeed({
431
440
  bootstrapPrompt: '.agent-context/prompts/bootstrap-design.md',
432
441
  },
433
442
  architectSignals: designSignals,
443
+ ...supplementalFields,
434
444
  }, null, 2)}\n`;
435
445
  }
436
446
 
447
+ function buildDesignIntentSeed({
448
+ discoveryAnswers,
449
+ initContext,
450
+ architectureRecommendation,
451
+ }) {
452
+ return buildDesignIntentSeedFromSignals({
453
+ projectName: discoveryAnswers.projectName,
454
+ projectDescription: discoveryAnswers.projectDescription,
455
+ primaryDomain: discoveryAnswers.primaryDomain,
456
+ features: discoveryAnswers.features,
457
+ initContext,
458
+ architectureRecommendation,
459
+ status: 'seed-needs-design-synthesis',
460
+ });
461
+ }
462
+
437
463
  function buildProjectContextBootstrapPrompt({
438
464
  discoveryAnswers,
439
465
  initContext,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "3.0.7",
3
+ "version": "3.0.9",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -261,8 +261,10 @@ const REQUIRED_UPGRADE_UI_CONTRACT_WARNING_SNIPPETS = [
261
261
  snippets: [
262
262
  'UI/frontend scope was detected, but the dynamic design contract is incomplete:',
263
263
  'docs/design-intent.json',
264
- 'Upgrade synchronizes governance assets, but it does not author project-specific design docs automatically.',
265
- 'collectProjectMarkers',
264
+ 'Planned seed on apply: docs/design-intent.json',
265
+ 'Upgrade synchronizes governance assets and can seed docs/design-intent.json, but it does not author project-specific docs/DESIGN.md automatically.',
266
+ 'detectUiScopeSignals',
267
+ 'seed-generated-during-upgrade',
266
268
  ],
267
269
  },
268
270
  ];