@ryuenn3123/agentic-senior-core 3.0.19 → 3.0.21
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/bootstrap-design.md +96 -103
- package/.agent-context/prompts/init-project.md +32 -100
- package/.agent-context/prompts/refactor.md +22 -44
- package/.agent-context/prompts/review-code.md +28 -52
- package/.agent-context/review-checklists/architecture-review.md +31 -62
- package/.agent-context/review-checklists/pr-checklist.md +74 -108
- package/.agent-context/rules/api-docs.md +18 -206
- package/.agent-context/rules/architecture.md +40 -207
- package/.agent-context/rules/database-design.md +10 -199
- package/.agent-context/rules/docker-runtime.md +5 -5
- package/.agent-context/rules/efficiency-vs-hype.md +11 -149
- package/.agent-context/rules/error-handling.md +9 -231
- package/.agent-context/rules/event-driven.md +17 -221
- package/.agent-context/rules/frontend-architecture.md +74 -119
- package/.agent-context/rules/git-workflow.md +1 -1
- package/.agent-context/rules/microservices.md +28 -161
- package/.agent-context/rules/naming-conv.md +8 -138
- package/.agent-context/rules/performance.md +9 -175
- package/.agent-context/rules/realtime.md +11 -44
- package/.agent-context/rules/security.md +11 -295
- package/.agent-context/rules/testing.md +9 -174
- package/.agent-context/state/benchmark-analysis.json +3 -3
- package/.agent-context/state/memory-continuity-benchmark.json +1 -1
- package/.agent-context/state/onboarding-report.json +71 -11
- package/.agents/workflows/init-project.md +7 -24
- package/.agents/workflows/refactor.md +7 -24
- package/.agents/workflows/review-code.md +7 -24
- package/.cursorrules +22 -21
- package/.gemini/instructions.md +2 -2
- package/.github/copilot-instructions.md +2 -2
- package/.instructions.md +112 -213
- package/.windsurfrules +22 -21
- package/AGENTS.md +4 -4
- package/CONTRIBUTING.md +13 -22
- package/README.md +6 -20
- package/lib/cli/commands/init.mjs +102 -148
- package/lib/cli/commands/launch.mjs +3 -3
- package/lib/cli/commands/optimize.mjs +14 -4
- package/lib/cli/commands/upgrade.mjs +25 -23
- package/lib/cli/compiler.mjs +96 -62
- package/lib/cli/constants.mjs +28 -136
- package/lib/cli/detector/design-evidence.mjs +189 -6
- package/lib/cli/detector.mjs +6 -7
- package/lib/cli/init-detection-flow.mjs +10 -93
- package/lib/cli/init-selection.mjs +2 -68
- package/lib/cli/project-scaffolder/constants.mjs +1 -1
- package/lib/cli/project-scaffolder/design-contract.mjs +183 -108
- package/lib/cli/project-scaffolder/discovery.mjs +36 -82
- package/lib/cli/project-scaffolder/prompt-builders.mjs +45 -55
- package/lib/cli/project-scaffolder/storage.mjs +0 -2
- package/lib/cli/token-optimization.mjs +1 -1
- package/lib/cli/utils.mjs +75 -9
- package/package.json +2 -2
- package/scripts/detection-benchmark.mjs +4 -15
- package/scripts/documentation-boundary-audit.mjs +9 -9
- package/scripts/explain-on-demand-audit.mjs +11 -11
- package/scripts/forbidden-content-check.mjs +9 -9
- package/scripts/frontend-usability-audit.mjs +45 -35
- package/scripts/llm-judge.mjs +1 -1
- package/scripts/mcp-server/constants.mjs +2 -2
- package/scripts/mcp-server/tool-registry.mjs +1 -1
- package/scripts/release-gate/audit-checks.mjs +22 -7
- package/scripts/release-gate/static-checks.mjs +5 -5
- package/scripts/release-gate.mjs +1 -1
- package/scripts/rules-guardian-audit.mjs +14 -13
- package/scripts/single-source-lazy-loading-audit.mjs +3 -3
- package/scripts/sync-thin-adapters.mjs +5 -5
- package/scripts/ui-design-judge/design-execution-summary.mjs +27 -1
- package/scripts/ui-design-judge/prompting.mjs +5 -5
- package/scripts/ui-design-judge/reporting.mjs +3 -1
- package/scripts/ui-design-judge/rubric-calibration.mjs +8 -5
- package/scripts/ui-design-judge/rubric-goldset.json +2 -2
- package/scripts/ui-design-judge.mjs +75 -7
- package/scripts/validate/config.mjs +138 -48
- package/scripts/validate/coverage-checks.mjs +32 -7
- package/scripts/validate.mjs +8 -4
- package/lib/cli/architect.mjs +0 -431
package/CONTRIBUTING.md
CHANGED
|
@@ -10,13 +10,13 @@ Thanks for wanting to make AI agents write better code. Here's how to contribute
|
|
|
10
10
|
|------|-------|-------------|
|
|
11
11
|
| New rule | `.agent-context/rules/` | Universal engineering standard |
|
|
12
12
|
| Stack strategy update | `.agent-context/rules/`, `.agent-context/state/stack-research-snapshot.json` | Dynamic language/runtime guidance and evidence |
|
|
13
|
-
|
|
|
13
|
+
| Structural planning guidance update | `.agent-context/prompts/`, `lib/cli/compiler.mjs` | Scope planning, docs bootstrap, and project-context guidance |
|
|
14
14
|
| New checklist | `.agent-context/review-checklists/` | Self-audit guide |
|
|
15
15
|
| State intelligence update | `.agent-context/state/` | Architecture boundaries and dependency map |
|
|
16
|
-
| Override policy update | `.agent-override.md` | Scoped
|
|
16
|
+
| Override policy update | `.agent-override.md` | Scoped rule exceptions |
|
|
17
17
|
| MCP workflow update | `mcp.json` | Self-healing automation flow |
|
|
18
|
-
| Bug fix | Any file | Typos, broken links, incorrect
|
|
19
|
-
| Improvement | Any file | Sharper wording,
|
|
18
|
+
| Bug fix | Any file | Typos, broken links, incorrect rules |
|
|
19
|
+
| Improvement | Any file | Sharper wording, stricter boundaries |
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
@@ -24,19 +24,10 @@ Thanks for wanting to make AI agents write better code. Here's how to contribute
|
|
|
24
24
|
|
|
25
25
|
This is the single most important rule: **every file must be "galak" (strict/fierce).**
|
|
26
26
|
|
|
27
|
-
Your contribution MUST be opinionated, specific, and enforceable. We reject generic advice.
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
BAD (generic, useless):
|
|
31
|
-
"Use descriptive variable names."
|
|
32
|
-
|
|
33
|
-
GOOD (specific, enforceable):
|
|
34
|
-
"NEVER use single-letter variables except `i` in `for(let i=0; i<n; i++)`.
|
|
35
|
-
Function names MUST start with a verb. Booleans MUST use is/has/can prefix."
|
|
36
|
-
```
|
|
27
|
+
Your contribution MUST be opinionated, specific, and enforceable. We reject generic advice, externally anchored rules, and borrowed-pattern guidance that can become accidental style anchors.
|
|
37
28
|
|
|
38
29
|
### The Litmus Test
|
|
39
|
-
- Does your rule include concrete BANNED / REQUIRED
|
|
30
|
+
- Does your rule include concrete BANNED / REQUIRED boundaries?
|
|
40
31
|
- Would an AI agent be able to enforce it without ambiguity?
|
|
41
32
|
- Does it teach the reader WHY, not just WHAT?
|
|
42
33
|
|
|
@@ -54,11 +45,11 @@ If all three are "yes", it belongs here.
|
|
|
54
45
|
|
|
55
46
|
---
|
|
56
47
|
|
|
57
|
-
## How to Add or Adjust
|
|
48
|
+
## How to Add or Adjust Structural Planning Guidance
|
|
58
49
|
|
|
59
|
-
1. Update the
|
|
50
|
+
1. Update the planning guidance in `.agent-context/prompts/init-project.md` and related discovery guidance.
|
|
60
51
|
2. Update compiler/init behavior if generated project-context guidance or bootstrap flow changes.
|
|
61
|
-
3. Keep
|
|
52
|
+
3. Keep system boundaries, required docs, and validation boundaries explicit without silently recommending a framework from offline heuristics.
|
|
62
53
|
4. Run `npm run validate` and `npm test`.
|
|
63
54
|
5. Open a PR.
|
|
64
55
|
|
|
@@ -70,10 +61,10 @@ If all three are "yes", it belongs here.
|
|
|
70
61
|
2. Structure:
|
|
71
62
|
- Opening quote (sets the tone)
|
|
72
63
|
- Core principle (1-2 sentences)
|
|
73
|
-
- BANNED / REQUIRED sections with
|
|
74
|
-
- Decision tree or quick
|
|
64
|
+
- BANNED / REQUIRED sections with enforceable boundaries
|
|
65
|
+
- Decision tree or quick ruleset when it reduces ambiguity
|
|
75
66
|
3. Update `AGENTS.md` rules manifest table
|
|
76
|
-
4. Update `review-checklists/pr-checklist.md`
|
|
67
|
+
4. Update `review-checklists/pr-checklist.md` when the rule is part of review scope
|
|
77
68
|
5. Validate and PR
|
|
78
69
|
|
|
79
70
|
---
|
|
@@ -95,7 +86,7 @@ If all three are "yes", it belongs here.
|
|
|
95
86
|
## What We Don't Accept
|
|
96
87
|
|
|
97
88
|
- Generic content that reads like it was auto-generated without thought
|
|
98
|
-
- Rules without concrete
|
|
89
|
+
- Rules without concrete enforcement boundaries
|
|
99
90
|
- Stack profiles for languages the author doesn't actually use in production
|
|
100
91
|
- Blueprints that are just folder structures without code patterns
|
|
101
92
|
- PRs that don't update the relevant manifest files (AGENTS.md, checklists)
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Latest release: 3.0.9 (2026-04-20).
|
|
|
14
14
|
|
|
15
15
|
Highlights in 3.0.9:
|
|
16
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
|
|
17
|
+
- Dynamic UI design guidance now emphasizes structure, rationale, and anti-generic constraints without anchoring to brand systems.
|
|
18
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>
|
|
@@ -31,26 +31,12 @@ npx @ryuenn3123/agentic-senior-core init
|
|
|
31
31
|
|
|
32
32
|
One command to initialize rules, checklists, and strict AI coding guidelines context for your project.
|
|
33
33
|
|
|
34
|
-
> **See [docs/deep-dive.md](docs/deep-dive.md) and [docs/roadmap.md](docs/roadmap.md) for advanced configuration,
|
|
34
|
+
> **See [docs/deep-dive.md](docs/deep-dive.md) and [docs/roadmap.md](docs/roadmap.md) for advanced configuration, planning mode, snapshot, and realtime options.**
|
|
35
35
|
|
|
36
36
|
- This command writes `.agent-context/state/v3-purge-audit.json` and reports whether static directory deletion is safe.
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
-
## Before / After
|
|
41
|
-
|
|
42
|
-
```text
|
|
43
|
-
Before:
|
|
44
|
-
"Build me a user registration API"
|
|
45
|
-
=> one file, weak validation, no typed errors, weak structure
|
|
46
|
-
|
|
47
|
-
After:
|
|
48
|
-
"Build me a user registration API"
|
|
49
|
-
=> layered modules, validated inputs, typed errors, tests, docs updates
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
40
|
## MCP Quick Setup (VS Code)
|
|
55
41
|
|
|
56
42
|
1. Generate workspace MCP config:
|
|
@@ -73,7 +59,7 @@ If you see `Property $schema is not allowed`, keep `.vscode/mcp.json` without `$
|
|
|
73
59
|
|
|
74
60
|
| Command | Purpose |
|
|
75
61
|
|---------|---------|
|
|
76
|
-
| `agentic-senior-core init` | Initialize
|
|
62
|
+
| `agentic-senior-core init` | Initialize the project guidance pack and compiled AI rulebook |
|
|
77
63
|
| `agentic-senior-core upgrade --dry-run` | Preview safe upgrades |
|
|
78
64
|
| `agentic-senior-core optimize --show` | Show token optimization state |
|
|
79
65
|
| `npm run audit:v3-purge` | Run deep purge readiness audit (no deletion) |
|
|
@@ -97,9 +83,9 @@ Use `--no-prune` if you want to keep legacy managed files.
|
|
|
97
83
|
|
|
98
84
|
## Terminology Mapping (Final)
|
|
99
85
|
|
|
100
|
-
| Canonical
|
|
101
|
-
|
|
102
|
-
| Federated Governance | Federated Rules Operations | Use canonical term in
|
|
86
|
+
| Canonical Term | Developer-Facing Alias | Usage Rule |
|
|
87
|
+
|----------------|------------------------|------------|
|
|
88
|
+
| Federated Governance | Federated Rules Operations | Use canonical term in formal policy artifacts. |
|
|
103
89
|
| Governance Engine | Rules Engine | Use alias in onboarding and day-to-day developer docs. |
|
|
104
90
|
| Guardrails | Quality Checks | Use alias in implementation guidance and quickstart docs. |
|
|
105
91
|
|
|
@@ -14,18 +14,17 @@ import {
|
|
|
14
14
|
INIT_PRESETS,
|
|
15
15
|
PROFILE_PRESETS,
|
|
16
16
|
GOLDEN_STANDARD_PROFILE_NAME,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
FALLBACK_BLUEPRINT_FILE_NAMES,
|
|
17
|
+
AGENT_DECISION_STACK_FILE_NAME,
|
|
18
|
+
AGENT_DECISION_BLUEPRINT_FILE_NAME,
|
|
20
19
|
RUNTIME_ENVIRONMENT_CHOICES,
|
|
21
20
|
} from '../constants.mjs';
|
|
22
21
|
|
|
23
22
|
import {
|
|
24
23
|
ensureDirectory,
|
|
25
|
-
askChoice,
|
|
26
24
|
askYesNo,
|
|
27
25
|
toTitleCase,
|
|
28
26
|
matchFileNameFromInput,
|
|
27
|
+
normalizeChoiceInput,
|
|
29
28
|
collectFileNames,
|
|
30
29
|
formatBlockingSeverities,
|
|
31
30
|
formatDuration,
|
|
@@ -41,20 +40,13 @@ import {
|
|
|
41
40
|
} from '../detector.mjs';
|
|
42
41
|
import { compileDynamicContext, writeSelectedPolicy, writeOnboardingReport } from '../compiler.mjs';
|
|
43
42
|
import {
|
|
44
|
-
filterStackFileNamesByCandidates,
|
|
45
|
-
filterBlueprintFileNamesByCandidates,
|
|
46
43
|
normalizeAdditionalStackSelection,
|
|
47
44
|
normalizeAdditionalBlueprintSelection,
|
|
48
|
-
deriveAdditionalBlueprintFileNamesFromStacks,
|
|
49
|
-
resolveScopeStackCandidates,
|
|
50
|
-
resolveScopeBlueprintCandidates,
|
|
51
45
|
} from '../init-selection.mjs';
|
|
52
46
|
import {
|
|
53
47
|
buildExistingProjectMajorConstraints,
|
|
54
48
|
resolveDetectedSetupDecision,
|
|
55
49
|
} from '../init-detection-flow.mjs';
|
|
56
|
-
// Existing project quick confirmation prompt string is preserved for validator coverage:
|
|
57
|
-
// Use detected setup for this existing project?
|
|
58
50
|
import { runPreflightChecks } from '../preflight.mjs';
|
|
59
51
|
import { createBackup } from '../backup.mjs';
|
|
60
52
|
import {
|
|
@@ -77,7 +69,6 @@ import {
|
|
|
77
69
|
createMemoryContinuityState,
|
|
78
70
|
writeMemoryContinuityState,
|
|
79
71
|
} from '../memory-continuity.mjs';
|
|
80
|
-
import { recommendArchitecture } from '../architect.mjs';
|
|
81
72
|
|
|
82
73
|
export { REPO_ROOT } from '../constants.mjs';
|
|
83
74
|
export {
|
|
@@ -85,13 +76,67 @@ export {
|
|
|
85
76
|
normalizeRuntimeEnvironmentKey,
|
|
86
77
|
} from '../init-options.mjs';
|
|
87
78
|
export {
|
|
88
|
-
filterStackFileNamesByCandidates,
|
|
89
|
-
filterBlueprintFileNamesByCandidates,
|
|
90
79
|
resolveProjectScopeKeyFromLabel,
|
|
91
80
|
normalizeAdditionalStackSelection,
|
|
92
81
|
normalizeAdditionalBlueprintSelection,
|
|
93
82
|
} from '../init-selection.mjs';
|
|
94
83
|
|
|
84
|
+
function normalizeContextLine(rawText) {
|
|
85
|
+
return String(rawText || '')
|
|
86
|
+
.replace(/\s+/g, ' ')
|
|
87
|
+
.trim();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function readTextIfExists(filePath) {
|
|
91
|
+
try {
|
|
92
|
+
return await fs.readFile(filePath, 'utf8');
|
|
93
|
+
} catch {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function extractMarkdownContext(rawMarkdown) {
|
|
99
|
+
return String(rawMarkdown || '')
|
|
100
|
+
.split(/\r?\n/)
|
|
101
|
+
.map((line) => normalizeContextLine(line.replace(/^#+\s*/, '')))
|
|
102
|
+
.filter((line) => line && !line.startsWith('---') && !line.startsWith('```'))
|
|
103
|
+
.slice(0, 3)
|
|
104
|
+
.join(' ');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function inferExistingProjectDescriptionHint(targetDirectoryPath) {
|
|
108
|
+
const evidence = [];
|
|
109
|
+
const packageJsonContent = await readTextIfExists(path.join(targetDirectoryPath, 'package.json'));
|
|
110
|
+
|
|
111
|
+
if (packageJsonContent) {
|
|
112
|
+
try {
|
|
113
|
+
const packageManifest = JSON.parse(packageJsonContent);
|
|
114
|
+
const packageSummary = [
|
|
115
|
+
normalizeContextLine(packageManifest.name),
|
|
116
|
+
normalizeContextLine(packageManifest.description),
|
|
117
|
+
].filter(Boolean).join(': ');
|
|
118
|
+
|
|
119
|
+
if (packageSummary) {
|
|
120
|
+
evidence.push(`package.json: ${packageSummary}`);
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
// Invalid package metadata should not block init; other files can still provide context.
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const relativeDocPath of ['docs/project-brief.md', 'docs/README.md', 'README.md']) {
|
|
128
|
+
const docContext = extractMarkdownContext(
|
|
129
|
+
await readTextIfExists(path.join(targetDirectoryPath, relativeDocPath))
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
if (docContext) {
|
|
133
|
+
evidence.push(`${relativeDocPath}: ${docContext}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return evidence.slice(0, 3).join(' | ');
|
|
138
|
+
}
|
|
139
|
+
|
|
95
140
|
export function resolveRuntimeEnvironmentKeyFromLabel(selectedRuntimeEnvironmentLabel) {
|
|
96
141
|
const runtimeEnvironmentEntry = RUNTIME_ENVIRONMENT_CHOICES.find(
|
|
97
142
|
(runtimeEnvironmentChoice) => runtimeEnvironmentChoice.label === selectedRuntimeEnvironmentLabel
|
|
@@ -218,18 +263,17 @@ function resolveSilentCiGuardrailsDefault({
|
|
|
218
263
|
};
|
|
219
264
|
}
|
|
220
265
|
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
266
|
+
function normalizeExplicitProfileFileName(rawInput, discoveredFileNames) {
|
|
267
|
+
const matchedFileName = Array.isArray(discoveredFileNames) && discoveredFileNames.length > 0
|
|
268
|
+
? matchFileNameFromInput(rawInput, discoveredFileNames)
|
|
269
|
+
: null;
|
|
270
|
+
|
|
271
|
+
if (matchedFileName) {
|
|
272
|
+
return matchedFileName;
|
|
273
|
+
}
|
|
227
274
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const selectedDisplayChoice = await askChoice(promptMessage, blueprintDisplayChoices, userInterface);
|
|
231
|
-
const selectedIndex = blueprintDisplayChoices.indexOf(selectedDisplayChoice);
|
|
232
|
-
return selectableBlueprintFileNames[selectedIndex] || selectableBlueprintFileNames[0] || null;
|
|
275
|
+
const normalizedBaseName = normalizeChoiceInput(String(rawInput || '').replace(/\.md$/i, ''));
|
|
276
|
+
return normalizedBaseName ? `${normalizedBaseName}.md` : null;
|
|
233
277
|
}
|
|
234
278
|
|
|
235
279
|
function buildInitExistingProjectDesignIntentSeed({
|
|
@@ -238,14 +282,14 @@ function buildInitExistingProjectDesignIntentSeed({
|
|
|
238
282
|
selectedStackFileName,
|
|
239
283
|
selectedBlueprintFileName,
|
|
240
284
|
uiScopeSignals,
|
|
241
|
-
|
|
285
|
+
projectDescriptionHint,
|
|
242
286
|
}) {
|
|
243
287
|
const projectName = String(packageManifest?.name || path.basename(targetDirectoryPath)).trim() || 'existing-ui-project';
|
|
244
288
|
const isMobileUiProject = String(selectedStackFileName || '').toLowerCase().includes('react-native')
|
|
245
289
|
|| String(selectedStackFileName || '').toLowerCase().includes('flutter')
|
|
246
290
|
|| uiScopeSignals.signalReasons.some((signalReason) => signalReason.includes('android') || signalReason.includes('ios'));
|
|
247
291
|
const resolvedDomain = isMobileUiProject ? 'Mobile app' : 'Web application';
|
|
248
|
-
const projectDescription = String(packageManifest?.description ||
|
|
292
|
+
const projectDescription = String(packageManifest?.description || projectDescriptionHint || '').trim()
|
|
249
293
|
|| `Existing ${resolvedDomain.toLowerCase()} detected during init. Create a project-specific dynamic design contract before shipping new UI work.`;
|
|
250
294
|
|
|
251
295
|
return buildDesignIntentSeedFromSignals({
|
|
@@ -310,12 +354,6 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
310
354
|
try {
|
|
311
355
|
const discoveredStackFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'stacks'));
|
|
312
356
|
const discoveredBlueprintFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'blueprints'));
|
|
313
|
-
const stackFileNames = discoveredStackFileNames.length > 0
|
|
314
|
-
? discoveredStackFileNames
|
|
315
|
-
: FALLBACK_STACK_FILE_NAMES;
|
|
316
|
-
const blueprintFileNames = discoveredBlueprintFileNames.length > 0
|
|
317
|
-
? discoveredBlueprintFileNames
|
|
318
|
-
: FALLBACK_BLUEPRINT_FILE_NAMES;
|
|
319
357
|
|
|
320
358
|
if (discoveredStackFileNames.length === 0 || discoveredBlueprintFileNames.length === 0) {
|
|
321
359
|
console.log('[INFO] Static stack/blueprint profiles are not fully present. Using compatibility labels for dynamic reasoning mode.');
|
|
@@ -324,25 +362,18 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
324
362
|
const selectedPreset = initOptions.preset ? INIT_PRESETS[initOptions.preset] || null : null;
|
|
325
363
|
|
|
326
364
|
const selectedStackFileNameFromOption = initOptions.stack
|
|
327
|
-
?
|
|
365
|
+
? normalizeExplicitProfileFileName(initOptions.stack, discoveredStackFileNames)
|
|
328
366
|
: null;
|
|
329
367
|
const selectedBlueprintFileNameFromOption = initOptions.blueprint
|
|
330
|
-
?
|
|
368
|
+
? normalizeExplicitProfileFileName(initOptions.blueprint, discoveredBlueprintFileNames)
|
|
331
369
|
: null;
|
|
332
|
-
if (initOptions.stack && !selectedStackFileNameFromOption) {
|
|
333
|
-
throw new Error(`Unknown stack: ${initOptions.stack}`);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (initOptions.blueprint && !selectedBlueprintFileNameFromOption) {
|
|
337
|
-
throw new Error(`Unknown blueprint: ${initOptions.blueprint}`);
|
|
338
|
-
}
|
|
339
370
|
|
|
340
371
|
if (initOptions.preset && !selectedPreset) {
|
|
341
372
|
throw new Error(`Unknown preset: ${initOptions.preset}`);
|
|
342
373
|
}
|
|
343
374
|
|
|
344
375
|
console.log(`\nAgentic-Senior-Core CLI v${CLI_VERSION}`);
|
|
345
|
-
console.log('I will copy
|
|
376
|
+
console.log('I will copy the project guidance pack into your target folder and compile a single rulebook for your AI tools.');
|
|
346
377
|
|
|
347
378
|
if (selectedPreset) {
|
|
348
379
|
console.log(`Using preset: ${initOptions.preset} (${selectedPreset.description}).`);
|
|
@@ -418,10 +449,10 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
418
449
|
if (projectDetection.hasExistingProjectFiles) {
|
|
419
450
|
console.log('\nExisting project detection transparency:');
|
|
420
451
|
|
|
421
|
-
if (projectDetection.
|
|
452
|
+
if (projectDetection.detectedStackFileName) {
|
|
422
453
|
const confidenceScoreLabel = Number(projectDetection.confidenceScore || 0).toFixed(2);
|
|
423
454
|
console.log(
|
|
424
|
-
`- Detected stack: ${toTitleCase(projectDetection.
|
|
455
|
+
`- Detected stack: ${toTitleCase(projectDetection.detectedStackFileName)} (${projectDetection.confidenceLabel}, score ${confidenceScoreLabel})`
|
|
425
456
|
);
|
|
426
457
|
|
|
427
458
|
if (projectDetection.secondaryStackFileNames?.length) {
|
|
@@ -444,17 +475,10 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
444
475
|
}
|
|
445
476
|
|
|
446
477
|
const hasReliableDetectedStack = projectDetection.hasExistingProjectFiles
|
|
447
|
-
&& projectDetection.
|
|
478
|
+
&& projectDetection.detectedStackFileName
|
|
448
479
|
&& (projectDetection.confidenceLabel === 'high' || projectDetection.confidenceLabel === 'medium');
|
|
449
480
|
|
|
450
|
-
const shouldAutoApplyDetectedStack =
|
|
451
|
-
&& !selectedStackFileNameFromOption
|
|
452
|
-
&& !selectedPreset?.stack
|
|
453
|
-
&& !selectedPolicyProfile.defaultStackFileName;
|
|
454
|
-
let detectedBlueprintFileName = projectDetection.recommendedBlueprintFileName
|
|
455
|
-
|| BLUEPRINT_RECOMMENDATIONS[projectDetection.recommendedStackFileName]
|
|
456
|
-
|| null;
|
|
457
|
-
|
|
481
|
+
const shouldAutoApplyDetectedStack = false;
|
|
458
482
|
let selectedManualStackFileName = null;
|
|
459
483
|
let selectedManualBlueprintFileName = null;
|
|
460
484
|
let selectedAdditionalStackFileNames = [];
|
|
@@ -462,8 +486,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
462
486
|
let detectedSetupWasApplied = false;
|
|
463
487
|
let selectedProjectScopeKey = 'both';
|
|
464
488
|
let selectedProjectScopeLabel = resolveProjectScopeLabelFromKey('both');
|
|
465
|
-
let
|
|
466
|
-
let architectureProjectDescription = String(initOptions.projectDescription || '').trim();
|
|
489
|
+
let projectDescriptionHint = String(initOptions.projectDescription || '').trim();
|
|
467
490
|
let discoveryAnswers = null;
|
|
468
491
|
const ciGuardrailsSelection = resolveSilentCiGuardrailsDefault({
|
|
469
492
|
initOptions,
|
|
@@ -476,17 +499,20 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
476
499
|
const shouldRunInteractiveScaffolding = isInteractiveSession
|
|
477
500
|
&& (initOptions.scaffoldDocs === true || (initOptions.scaffoldDocs !== false && isFreshProjectTarget));
|
|
478
501
|
|
|
502
|
+
if (projectDetection.hasExistingProjectFiles && !projectDescriptionHint) {
|
|
503
|
+
projectDescriptionHint = await inferExistingProjectDescriptionHint(resolvedTargetDirectoryPath);
|
|
504
|
+
if (projectDescriptionHint) {
|
|
505
|
+
console.log(`- Project context evidence: ${projectDescriptionHint}`);
|
|
506
|
+
} else {
|
|
507
|
+
console.log('- Project context evidence: unresolved from lightweight file scan; agent must inspect project files before coding.');
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
detectionTransparency.projectContextEvidence = projectDescriptionHint || null;
|
|
511
|
+
|
|
479
512
|
const detectedSetupDecision = await resolveDetectedSetupDecision({
|
|
480
513
|
shouldAutoApplyDetectedStack,
|
|
481
514
|
projectDetection,
|
|
482
|
-
stackFileNames,
|
|
483
|
-
blueprintFileNames,
|
|
484
|
-
userInterface,
|
|
485
|
-
isInteractiveSession,
|
|
486
515
|
detectionTransparency,
|
|
487
|
-
askYesNo,
|
|
488
|
-
askStackSelection,
|
|
489
|
-
askBlueprintSelection,
|
|
490
516
|
initialSelectedManualStackFileName: selectedManualStackFileName,
|
|
491
517
|
initialSelectedManualBlueprintFileName: selectedManualBlueprintFileName,
|
|
492
518
|
initialSelectedAdditionalStackFileNames: selectedAdditionalStackFileNames,
|
|
@@ -496,15 +522,13 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
496
522
|
selectedManualStackFileName = detectedSetupDecision.selectedManualStackFileName;
|
|
497
523
|
selectedManualBlueprintFileName = detectedSetupDecision.selectedManualBlueprintFileName;
|
|
498
524
|
selectedAdditionalStackFileNames = detectedSetupDecision.selectedAdditionalStackFileNames;
|
|
499
|
-
detectedBlueprintFileName = detectedSetupDecision.detectedBlueprintFileName;
|
|
500
|
-
|
|
501
525
|
if (initOptions.projectConfig) {
|
|
502
526
|
discoveryAnswers = await loadProjectConfig(initOptions.projectConfig);
|
|
503
527
|
console.log(`\nLoaded project configuration from: ${initOptions.projectConfig}`);
|
|
504
528
|
} else if (shouldRunInteractiveScaffolding) {
|
|
505
529
|
discoveryAnswers = await runProjectDiscovery(userInterface, {
|
|
506
530
|
defaultProjectName: path.basename(resolvedTargetDirectoryPath),
|
|
507
|
-
defaultProjectDescription:
|
|
531
|
+
defaultProjectDescription: projectDescriptionHint,
|
|
508
532
|
defaultIncludeCiGuardrails: ciGuardrailsSelection.value,
|
|
509
533
|
askForCiGuardrails: ciGuardrailsSelection.shouldAsk,
|
|
510
534
|
});
|
|
@@ -513,7 +537,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
513
537
|
}
|
|
514
538
|
|
|
515
539
|
if (discoveryAnswers?.projectDescription) {
|
|
516
|
-
|
|
540
|
+
projectDescriptionHint = discoveryAnswers.projectDescription;
|
|
517
541
|
}
|
|
518
542
|
|
|
519
543
|
if (discoveryAnswers) {
|
|
@@ -521,98 +545,26 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
521
545
|
selectedProjectScopeLabel = resolveProjectScopeLabelFromKey(selectedProjectScopeKey);
|
|
522
546
|
}
|
|
523
547
|
|
|
524
|
-
const shouldUseSilentArchitectureSelection = !selectedStackFileNameFromOption
|
|
525
|
-
&& !selectedPreset?.stack
|
|
526
|
-
&& !shouldAutoApplyDetectedStack
|
|
527
|
-
&& !selectedPolicyProfile.defaultStackFileName;
|
|
528
|
-
|
|
529
|
-
if (shouldUseSilentArchitectureSelection) {
|
|
530
|
-
const architectureScopeStackCandidates = filterStackFileNamesByCandidates(
|
|
531
|
-
stackFileNames,
|
|
532
|
-
resolveScopeStackCandidates(selectedProjectScopeKey)
|
|
533
|
-
);
|
|
534
|
-
const architectureScopeBlueprintCandidates = filterBlueprintFileNamesByCandidates(
|
|
535
|
-
blueprintFileNames,
|
|
536
|
-
resolveScopeBlueprintCandidates(selectedProjectScopeKey)
|
|
537
|
-
);
|
|
538
|
-
|
|
539
|
-
architectureRecommendation = recommendArchitecture({
|
|
540
|
-
projectDescription: architectureProjectDescription || `A software project named ${path.basename(resolvedTargetDirectoryPath)}.`,
|
|
541
|
-
projectDetection,
|
|
542
|
-
stackFileNames: architectureScopeStackCandidates,
|
|
543
|
-
blueprintFileNames: architectureScopeBlueprintCandidates,
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
architectureRecommendation.projectDomain = {
|
|
547
|
-
key: selectedProjectScopeKey,
|
|
548
|
-
label: selectedProjectScopeLabel,
|
|
549
|
-
};
|
|
550
|
-
architectureRecommendation.userVeto = {
|
|
551
|
-
applied: false,
|
|
552
|
-
selectedStackFileName: architectureRecommendation.recommendedStackFileName,
|
|
553
|
-
selectedBlueprintFileName: architectureRecommendation.recommendedBlueprintFileName,
|
|
554
|
-
source: projectDetection.hasExistingProjectFiles ? 'silent-existing-bootstrap' : 'silent-fresh-bootstrap',
|
|
555
|
-
};
|
|
556
|
-
|
|
557
|
-
selectedManualStackFileName = architectureRecommendation.recommendedStackFileName;
|
|
558
|
-
selectedManualBlueprintFileName = architectureRecommendation.recommendedBlueprintFileName;
|
|
559
|
-
|
|
560
|
-
if (!projectDetection.hasExistingProjectFiles) {
|
|
561
|
-
detectionTransparency.quickConfirmation.response = 'fresh-project-streamlined';
|
|
562
|
-
detectionTransparency.decision.mode = 'fresh-project-streamlined';
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
const blueprintDisplayChoices = blueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName));
|
|
567
|
-
|
|
568
548
|
const selectedResolvedStackFileName = selectedStackFileNameFromOption
|
|
569
|
-
|| selectedPreset?.stack
|
|
570
549
|
|| selectedManualStackFileName
|
|
571
|
-
|| (detectedSetupWasApplied ? projectDetection.recommendedStackFileName : null)
|
|
572
550
|
|| selectedPolicyProfile.defaultStackFileName
|
|
573
|
-
||
|
|
551
|
+
|| AGENT_DECISION_STACK_FILE_NAME;
|
|
574
552
|
|
|
575
553
|
selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
|
|
576
554
|
selectedResolvedStackFileName,
|
|
577
555
|
selectedAdditionalStackFileNames
|
|
578
556
|
);
|
|
579
557
|
|
|
580
|
-
const recommendedBlueprintFileName = detectedSetupWasApplied
|
|
581
|
-
&& detectedBlueprintFileName
|
|
582
|
-
? detectedBlueprintFileName
|
|
583
|
-
: BLUEPRINT_RECOMMENDATIONS[selectedResolvedStackFileName] || null;
|
|
584
|
-
|
|
585
|
-
if (!recommendedBlueprintFileName && !selectedBlueprintFileNameFromOption && !selectedPolicyProfile.defaultBlueprintFileName) {
|
|
586
|
-
console.log('\nI could not map that stack to a first-party blueprint automatically, so I will ask you to choose one.');
|
|
587
|
-
}
|
|
588
|
-
|
|
589
558
|
const selectedResolvedBlueprintFileName = selectedBlueprintFileNameFromOption
|
|
590
|
-
|| selectedPreset?.blueprint
|
|
591
559
|
|| selectedManualBlueprintFileName
|
|
592
|
-
|| recommendedBlueprintFileName
|
|
593
560
|
|| selectedPolicyProfile.defaultBlueprintFileName
|
|
594
|
-
||
|
|
595
|
-
blueprintDisplayChoices.indexOf(
|
|
596
|
-
await askChoice('Which blueprint should I scaffold into the compiled rulebook?', blueprintDisplayChoices, userInterface)
|
|
597
|
-
)
|
|
598
|
-
];
|
|
599
|
-
|
|
600
|
-
if (architectureRecommendation) {
|
|
601
|
-
architectureRecommendation.appliedStackFileName = selectedResolvedStackFileName;
|
|
602
|
-
architectureRecommendation.appliedBlueprintFileName = selectedResolvedBlueprintFileName;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
const derivedAdditionalBlueprintFileNames = deriveAdditionalBlueprintFileNamesFromStacks(
|
|
606
|
-
selectedAdditionalStackFileNames,
|
|
607
|
-
blueprintFileNames,
|
|
608
|
-
selectedResolvedBlueprintFileName
|
|
609
|
-
);
|
|
561
|
+
|| AGENT_DECISION_BLUEPRINT_FILE_NAME;
|
|
610
562
|
|
|
611
563
|
selectedAdditionalBlueprintFileNames = normalizeAdditionalBlueprintSelection(
|
|
612
564
|
selectedResolvedBlueprintFileName,
|
|
613
565
|
selectedAdditionalBlueprintFileNames.length > 0
|
|
614
566
|
? selectedAdditionalBlueprintFileNames
|
|
615
|
-
:
|
|
567
|
+
: []
|
|
616
568
|
);
|
|
617
569
|
|
|
618
570
|
detectionTransparency.decision.selectedStackFileName = selectedResolvedStackFileName;
|
|
@@ -696,7 +648,6 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
696
648
|
additionalBlueprintFileNames: selectedAdditionalBlueprintFileNames,
|
|
697
649
|
runtimeEnvironmentKey: selectedRuntimeEnvironmentKey,
|
|
698
650
|
runtimeEnvironmentLabel: resolveRuntimeEnvironmentLabelFromKey(selectedRuntimeEnvironmentKey),
|
|
699
|
-
architectureRecommendation,
|
|
700
651
|
},
|
|
701
652
|
{
|
|
702
653
|
docsLanguage: selectedDocsLanguage,
|
|
@@ -740,7 +691,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
740
691
|
selectedStackFileName: selectedResolvedStackFileName,
|
|
741
692
|
selectedBlueprintFileName: selectedResolvedBlueprintFileName,
|
|
742
693
|
uiScopeSignals: existingProjectUiScopeSignals,
|
|
743
|
-
|
|
694
|
+
projectDescriptionHint,
|
|
744
695
|
});
|
|
745
696
|
|
|
746
697
|
await ensureDirectory(docsDirectoryPath);
|
|
@@ -798,7 +749,6 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
798
749
|
adapters: memoryContinuityState?.adapters || [],
|
|
799
750
|
stateFile: isMemoryContinuityEnabled ? '.agent-context/state/memory-continuity.json' : null,
|
|
800
751
|
},
|
|
801
|
-
architectRecommendation: architectureRecommendation,
|
|
802
752
|
detectionTransparency,
|
|
803
753
|
uiScopeSignals: existingProjectUiScopeSignals,
|
|
804
754
|
});
|
|
@@ -814,11 +764,11 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
814
764
|
console.log(`- Project topology: ${discoveryAnswers.architectureStyle}`);
|
|
815
765
|
}
|
|
816
766
|
}
|
|
817
|
-
console.log(`-
|
|
767
|
+
console.log(`- Runtime decision: ${selectedResolvedStackFileName === AGENT_DECISION_STACK_FILE_NAME ? 'agent recommendation required from current repo/brief evidence' : toTitleCase(selectedResolvedStackFileName)}`);
|
|
818
768
|
if (selectedAdditionalStackFileNames.length > 0) {
|
|
819
769
|
console.log(`- Additional stacks: ${selectedAdditionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}`);
|
|
820
770
|
}
|
|
821
|
-
console.log(`-
|
|
771
|
+
console.log(`- Architecture decision: ${selectedResolvedBlueprintFileName === AGENT_DECISION_BLUEPRINT_FILE_NAME ? 'agent recommendation required from current repo/brief evidence' : toTitleCase(selectedResolvedBlueprintFileName)}`);
|
|
822
772
|
if (selectedAdditionalBlueprintFileNames.length > 0) {
|
|
823
773
|
console.log(`- Additional blueprints: ${selectedAdditionalBlueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName)).join(', ')}`);
|
|
824
774
|
}
|
|
@@ -854,7 +804,11 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
|
|
|
854
804
|
console.log('- Token optimization policy: disabled (--no-token-optimize)');
|
|
855
805
|
}
|
|
856
806
|
console.log('\nPlain-language summary:');
|
|
857
|
-
|
|
807
|
+
if (selectedResolvedStackFileName === AGENT_DECISION_STACK_FILE_NAME || selectedResolvedBlueprintFileName === AGENT_DECISION_BLUEPRINT_FILE_NAME) {
|
|
808
|
+
console.log('I prepared a repo-grounded guidance pack that asks your AI agent to recommend runtime and architecture choices from the current brief, repo evidence, and live research before coding.');
|
|
809
|
+
} else {
|
|
810
|
+
console.log(`I prepared a repo-grounded guidance pack using your explicit runtime constraint (${toTitleCase(selectedResolvedStackFileName)}) and architecture constraint (${toTitleCase(selectedResolvedBlueprintFileName)}).`);
|
|
811
|
+
}
|
|
858
812
|
if (selectedAdditionalStackFileNames.length > 0) {
|
|
859
813
|
console.log(`I also included additional stack context for ${selectedAdditionalStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
|
|
860
814
|
}
|
|
@@ -21,7 +21,7 @@ export async function runLaunchCommand() {
|
|
|
21
21
|
'How do you want to start?',
|
|
22
22
|
[
|
|
23
23
|
'npm / npx path',
|
|
24
|
-
'
|
|
24
|
+
'Scope hint preset',
|
|
25
25
|
'Interactive init wizard',
|
|
26
26
|
'Enable token optimization',
|
|
27
27
|
'Exit',
|
|
@@ -37,10 +37,10 @@ export async function runLaunchCommand() {
|
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
if (launchChoice === '
|
|
40
|
+
if (launchChoice === 'Scope hint preset') {
|
|
41
41
|
const presetNames = Object.keys(INIT_PRESETS);
|
|
42
42
|
const selectedPresetName = await askChoice(
|
|
43
|
-
'Choose a
|
|
43
|
+
'Choose a scope hint preset:',
|
|
44
44
|
presetNames.map((presetName) => `${presetName} - ${INIT_PRESETS[presetName].description}`),
|
|
45
45
|
userInterface
|
|
46
46
|
);
|
|
@@ -3,6 +3,10 @@ import path from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
import { ensureDirectory, formatDuration } from '../utils.mjs';
|
|
5
5
|
import { compileDynamicContext, loadOnboardingReportIfExists } from '../compiler.mjs';
|
|
6
|
+
import {
|
|
7
|
+
AGENT_DECISION_STACK_FILE_NAME,
|
|
8
|
+
AGENT_DECISION_BLUEPRINT_FILE_NAME,
|
|
9
|
+
} from '../constants.mjs';
|
|
6
10
|
import {
|
|
7
11
|
TOKEN_OPTIMIZATION_REPORT_FILE_NAME,
|
|
8
12
|
normalizeAgentName,
|
|
@@ -115,14 +119,20 @@ export async function runOptimizeCommand(targetDirectoryArgument, optimizeOption
|
|
|
115
119
|
|
|
116
120
|
await writeTokenOptimizationState(resolvedTargetDirectoryPath, tokenOptimizationState);
|
|
117
121
|
|
|
118
|
-
const
|
|
119
|
-
const
|
|
122
|
+
const hasExplicitRuntimeConstraint = onboardingReport?.runtimeDecision?.mode === 'explicit-constraint';
|
|
123
|
+
const hasExplicitArchitectureConstraint = onboardingReport?.architectureDecision?.mode === 'explicit-constraint';
|
|
124
|
+
const selectedStackFileName = hasExplicitRuntimeConstraint
|
|
125
|
+
? normalizeMarkdownFileName(onboardingReport.selectedStack, AGENT_DECISION_STACK_FILE_NAME)
|
|
126
|
+
: AGENT_DECISION_STACK_FILE_NAME;
|
|
127
|
+
const selectedAdditionalStackFileNames = hasExplicitRuntimeConstraint && Array.isArray(onboardingReport.selectedAdditionalStacks)
|
|
120
128
|
? onboardingReport.selectedAdditionalStacks
|
|
121
129
|
.map((stackFileName) => normalizeMarkdownFileName(stackFileName, ''))
|
|
122
130
|
.filter((stackFileName) => stackFileName && stackFileName !== selectedStackFileName)
|
|
123
131
|
: [];
|
|
124
|
-
const selectedBlueprintFileName =
|
|
125
|
-
|
|
132
|
+
const selectedBlueprintFileName = hasExplicitArchitectureConstraint
|
|
133
|
+
? normalizeMarkdownFileName(onboardingReport.selectedBlueprint, AGENT_DECISION_BLUEPRINT_FILE_NAME)
|
|
134
|
+
: AGENT_DECISION_BLUEPRINT_FILE_NAME;
|
|
135
|
+
const selectedAdditionalBlueprintFileNames = hasExplicitArchitectureConstraint && Array.isArray(onboardingReport.selectedAdditionalBlueprints)
|
|
126
136
|
? onboardingReport.selectedAdditionalBlueprints
|
|
127
137
|
.map((blueprintFileName) => normalizeMarkdownFileName(blueprintFileName, ''))
|
|
128
138
|
.filter((blueprintFileName) => blueprintFileName && blueprintFileName !== selectedBlueprintFileName)
|