@ryuenn3123/agentic-senior-core 1.9.0 → 1.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-context/blueprints/mobile-app.md +21 -21
- package/.agent-context/policies/llm-judge-threshold.json +29 -20
- package/.agent-context/profiles/platform.md +13 -13
- package/.agent-context/profiles/regulated.md +13 -13
- package/.agent-context/profiles/startup.md +13 -13
- package/.agent-context/review-checklists/frontend-skill-parity.md +28 -28
- package/.agent-context/review-checklists/frontend-usability.md +33 -33
- package/.agent-context/review-checklists/release-operations.md +29 -29
- package/.agent-context/rules/security.md +92 -0
- package/.agent-context/skills/README.md +62 -62
- package/.agent-context/skills/backend/README.md +67 -67
- package/.agent-context/skills/backend/architecture.md +360 -360
- package/.agent-context/skills/backend/data-access.md +230 -230
- package/.agent-context/skills/backend/errors.md +137 -137
- package/.agent-context/skills/backend/validation.md +116 -116
- package/.agent-context/skills/backend.md +28 -28
- package/.agent-context/skills/cli/README.md +49 -49
- package/.agent-context/skills/cli/init.md +37 -37
- package/.agent-context/skills/cli/output.md +35 -35
- package/.agent-context/skills/cli/upgrade.md +37 -37
- package/.agent-context/skills/cli.md +28 -28
- package/.agent-context/skills/distribution/README.md +18 -18
- package/.agent-context/skills/distribution/compatibility.md +31 -31
- package/.agent-context/skills/distribution/publish.md +36 -36
- package/.agent-context/skills/distribution/rollback.md +31 -31
- package/.agent-context/skills/distribution.md +28 -28
- package/.agent-context/skills/frontend/README.md +35 -35
- package/.agent-context/skills/frontend/accessibility.md +107 -107
- package/.agent-context/skills/frontend/motion.md +66 -66
- package/.agent-context/skills/frontend/performance.md +62 -62
- package/.agent-context/skills/frontend/ui-architecture.md +128 -128
- package/.agent-context/skills/frontend.md +29 -29
- package/.agent-context/skills/fullstack/README.md +18 -18
- package/.agent-context/skills/fullstack/contracts.md +52 -52
- package/.agent-context/skills/fullstack/end-to-end.md +41 -41
- package/.agent-context/skills/fullstack/feature-slicing.md +64 -64
- package/.agent-context/skills/fullstack.md +26 -26
- package/.agent-context/skills/index.json +107 -107
- package/.agent-context/skills/review-quality/README.md +18 -18
- package/.agent-context/skills/review-quality/benchmark.md +29 -29
- package/.agent-context/skills/review-quality/planning.md +37 -37
- package/.agent-context/skills/review-quality/security.md +33 -33
- package/.agent-context/skills/review-quality.md +27 -27
- package/.agent-context/stacks/flutter.md +16 -16
- package/.agent-context/stacks/react-native.md +16 -16
- package/.agent-context/state/architecture-map.md +25 -25
- package/.agent-context/state/benchmark-analysis.json +431 -431
- package/.agent-context/state/benchmark-thresholds.json +10 -10
- package/.agent-context/state/benchmark-watchlist.json +19 -19
- package/.agent-context/state/dependency-map.md +32 -32
- package/.agent-context/state/onboarding-report.json +39 -0
- package/.agent-context/state/skill-platform.json +38 -38
- package/.agent-override.md +36 -36
- package/.cursorrules +3718 -140
- package/.github/ISSUE_TEMPLATE/v1.7-frontend-work-item.yml +54 -54
- package/.github/workflows/benchmark-detection.yml +38 -38
- package/.github/workflows/benchmark-intelligence.yml +50 -50
- package/.github/workflows/frontend-usability-gate.yml +36 -36
- package/.github/workflows/publish.yml +32 -0
- package/.github/workflows/release-gate.yml +32 -32
- package/.github/workflows/sbom-compliance.yml +32 -32
- package/.windsurfrules +3718 -106
- package/AGENTS.md +181 -181
- package/README.md +318 -318
- package/bin/agentic-senior-core.js +61 -1556
- package/lib/cli/commands/init.mjs +339 -0
- package/lib/cli/commands/launch.mjs +81 -0
- package/lib/cli/commands/upgrade.mjs +165 -0
- package/lib/cli/compiler.mjs +204 -0
- package/lib/cli/constants.mjs +136 -0
- package/lib/cli/detector.mjs +211 -0
- package/lib/cli/profile-packs.mjs +94 -0
- package/lib/cli/skill-selector.mjs +210 -0
- package/lib/cli/utils.mjs +227 -0
- package/mcp.json +92 -92
- package/package.json +3 -1
- package/scripts/benchmark-gate.mjs +121 -121
- package/scripts/benchmark-intelligence.mjs +140 -140
- package/scripts/detection-benchmark.mjs +138 -138
- package/scripts/frontend-usability-audit.mjs +87 -87
- package/scripts/generate-sbom.mjs +61 -61
- package/scripts/init-project.ps1 +104 -104
- package/scripts/llm-judge.mjs +664 -664
- package/scripts/release-gate.mjs +116 -116
- package/scripts/skill-tier-policy.mjs +75 -75
- package/scripts/validate.mjs +636 -636
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Init Command — Interactive project initialization.
|
|
3
|
+
* Depends on: constants, utils, profile-packs, skill-selector, detector, compiler
|
|
4
|
+
*/
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
6
|
+
import { stdin, stdout } from 'node:process';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
CLI_VERSION,
|
|
11
|
+
AGENT_CONTEXT_DIR,
|
|
12
|
+
INIT_PRESETS,
|
|
13
|
+
PROFILE_PRESETS,
|
|
14
|
+
BLUEPRINT_RECOMMENDATIONS,
|
|
15
|
+
} from '../constants.mjs';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
ensureDirectory,
|
|
19
|
+
askChoice,
|
|
20
|
+
askYesNo,
|
|
21
|
+
toTitleCase,
|
|
22
|
+
normalizeChoiceInput,
|
|
23
|
+
matchFileNameFromInput,
|
|
24
|
+
matchProfileNameFromInput,
|
|
25
|
+
collectFileNames,
|
|
26
|
+
formatBlockingSeverities,
|
|
27
|
+
formatDuration,
|
|
28
|
+
copyGovernanceAssetsToTarget,
|
|
29
|
+
} from '../utils.mjs';
|
|
30
|
+
|
|
31
|
+
import { collectProfilePacks, findProfilePackByInput } from '../profile-packs.mjs';
|
|
32
|
+
import { inferSkillDomainNamesFromSelection } from '../skill-selector.mjs';
|
|
33
|
+
import { detectProjectContext, buildDetectionSummary, formatDetectionCandidates } from '../detector.mjs';
|
|
34
|
+
import { compileDynamicContext, writeSelectedPolicy, writeOnboardingReport } from '../compiler.mjs';
|
|
35
|
+
|
|
36
|
+
export { REPO_ROOT } from '../constants.mjs';
|
|
37
|
+
|
|
38
|
+
export function parseInitArguments(commandArguments) {
|
|
39
|
+
const parsedInitOptions = {
|
|
40
|
+
targetDirectory: '.',
|
|
41
|
+
preset: undefined,
|
|
42
|
+
profile: undefined,
|
|
43
|
+
profilePack: undefined,
|
|
44
|
+
stack: undefined,
|
|
45
|
+
blueprint: undefined,
|
|
46
|
+
ci: undefined,
|
|
47
|
+
newbie: false,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
51
|
+
const currentArgument = commandArguments[argumentIndex];
|
|
52
|
+
|
|
53
|
+
if (!currentArgument.startsWith('--')) {
|
|
54
|
+
parsedInitOptions.targetDirectory = currentArgument;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (currentArgument === '--profile') {
|
|
59
|
+
parsedInitOptions.profile = matchProfileNameFromInput(commandArguments[argumentIndex + 1] || '');
|
|
60
|
+
argumentIndex += 1;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (currentArgument === '--preset') {
|
|
65
|
+
parsedInitOptions.preset = normalizeChoiceInput(commandArguments[argumentIndex + 1] || '');
|
|
66
|
+
argumentIndex += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (currentArgument.startsWith('--preset=')) {
|
|
71
|
+
parsedInitOptions.preset = normalizeChoiceInput(currentArgument.split('=')[1]);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (currentArgument.startsWith('--profile=')) {
|
|
76
|
+
parsedInitOptions.profile = matchProfileNameFromInput(currentArgument.split('=')[1]);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (currentArgument === '--profile-pack') {
|
|
81
|
+
parsedInitOptions.profilePack = commandArguments[argumentIndex + 1];
|
|
82
|
+
argumentIndex += 1;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (currentArgument.startsWith('--profile-pack=')) {
|
|
87
|
+
parsedInitOptions.profilePack = currentArgument.split('=')[1];
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (currentArgument === '--stack') {
|
|
92
|
+
parsedInitOptions.stack = commandArguments[argumentIndex + 1];
|
|
93
|
+
argumentIndex += 1;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (currentArgument.startsWith('--stack=')) {
|
|
98
|
+
parsedInitOptions.stack = currentArgument.split('=')[1];
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (currentArgument === '--blueprint') {
|
|
103
|
+
parsedInitOptions.blueprint = commandArguments[argumentIndex + 1];
|
|
104
|
+
argumentIndex += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (currentArgument.startsWith('--blueprint=')) {
|
|
109
|
+
parsedInitOptions.blueprint = currentArgument.split('=')[1];
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (currentArgument === '--ci') {
|
|
114
|
+
const ciRawValue = commandArguments[argumentIndex + 1];
|
|
115
|
+
parsedInitOptions.ci = ciRawValue?.toLowerCase() === 'true';
|
|
116
|
+
argumentIndex += 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (currentArgument.startsWith('--ci=')) {
|
|
121
|
+
parsedInitOptions.ci = currentArgument.split('=')[1]?.toLowerCase() === 'true';
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (currentArgument === '--newbie') {
|
|
126
|
+
parsedInitOptions.newbie = true;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
throw new Error(`Unknown option: ${currentArgument}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (parsedInitOptions.newbie && parsedInitOptions.profile && parsedInitOptions.profile !== 'beginner') {
|
|
134
|
+
throw new Error('--newbie can only be combined with --profile beginner');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return parsedInitOptions;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function runInitCommand(targetDirectoryArgument, initOptions = {}) {
|
|
141
|
+
const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
|
|
142
|
+
const setupStartedAt = Date.now();
|
|
143
|
+
await ensureDirectory(resolvedTargetDirectoryPath);
|
|
144
|
+
|
|
145
|
+
const userInterface = createInterface({ input: stdin, output: stdout });
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const stackFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'stacks'));
|
|
149
|
+
const blueprintFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'blueprints'));
|
|
150
|
+
const profilePackDefinitions = await collectProfilePacks(path.dirname(AGENT_CONTEXT_DIR));
|
|
151
|
+
const selectedPreset = initOptions.preset ? INIT_PRESETS[initOptions.preset] || null : null;
|
|
152
|
+
|
|
153
|
+
const selectedStackFileNameFromOption = initOptions.stack
|
|
154
|
+
? matchFileNameFromInput(initOptions.stack, stackFileNames)
|
|
155
|
+
: null;
|
|
156
|
+
const selectedBlueprintFileNameFromOption = initOptions.blueprint
|
|
157
|
+
? matchFileNameFromInput(initOptions.blueprint, blueprintFileNames)
|
|
158
|
+
: null;
|
|
159
|
+
const selectedProfilePack = initOptions.profilePack
|
|
160
|
+
? findProfilePackByInput(initOptions.profilePack, profilePackDefinitions)
|
|
161
|
+
: null;
|
|
162
|
+
|
|
163
|
+
if (initOptions.stack && !selectedStackFileNameFromOption) {
|
|
164
|
+
throw new Error(`Unknown stack: ${initOptions.stack}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (initOptions.blueprint && !selectedBlueprintFileNameFromOption) {
|
|
168
|
+
throw new Error(`Unknown blueprint: ${initOptions.blueprint}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (initOptions.profilePack && !selectedProfilePack) {
|
|
172
|
+
throw new Error(`Unknown profile pack: ${initOptions.profilePack}`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (initOptions.preset && !selectedPreset) {
|
|
176
|
+
throw new Error(`Unknown preset: ${initOptions.preset}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (selectedProfilePack && !stackFileNames.includes(selectedProfilePack.defaultStackFileName)) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`Profile pack ${selectedProfilePack.fileName} references unknown stack file: ${selectedProfilePack.defaultStackFileName}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (selectedProfilePack && !blueprintFileNames.includes(selectedProfilePack.defaultBlueprintFileName)) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Profile pack ${selectedProfilePack.fileName} references unknown blueprint file: ${selectedProfilePack.defaultBlueprintFileName}`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
console.log(`\nAgentic-Senior-Core CLI v${CLI_VERSION}`);
|
|
192
|
+
console.log('I will copy governance files into your target folder and compile a single rulebook for your AI tools.');
|
|
193
|
+
|
|
194
|
+
if (selectedPreset) {
|
|
195
|
+
console.log(`Using preset: ${initOptions.preset} (${selectedPreset.description}).`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const projectDetection = await detectProjectContext(resolvedTargetDirectoryPath);
|
|
199
|
+
if (projectDetection.hasExistingProjectFiles) {
|
|
200
|
+
console.log('I found files in the target directory, so I checked whether this already looks like an existing project.');
|
|
201
|
+
console.log(buildDetectionSummary(projectDetection));
|
|
202
|
+
console.log('Detection reasoning:');
|
|
203
|
+
console.log(projectDetection.detectionReasoning);
|
|
204
|
+
console.log('Top candidates:');
|
|
205
|
+
console.log(formatDetectionCandidates(projectDetection.rankedCandidates));
|
|
206
|
+
} else {
|
|
207
|
+
console.log('The target directory is empty, so I will guide you through a fresh setup.');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const selectedProfileName = initOptions.profile
|
|
211
|
+
? initOptions.profile
|
|
212
|
+
: selectedPreset?.profile
|
|
213
|
+
? selectedPreset.profile
|
|
214
|
+
: initOptions.newbie
|
|
215
|
+
? 'beginner'
|
|
216
|
+
: selectedProfilePack?.defaultProfileName
|
|
217
|
+
? selectedProfilePack.defaultProfileName
|
|
218
|
+
: normalizeChoiceInput(await askChoice(
|
|
219
|
+
'How much guidance do you want?',
|
|
220
|
+
Object.values(PROFILE_PRESETS).map((profilePreset) => `${profilePreset.displayName} — ${profilePreset.description}`),
|
|
221
|
+
userInterface
|
|
222
|
+
)).split('-')[0];
|
|
223
|
+
|
|
224
|
+
const selectedProfile = PROFILE_PRESETS[selectedProfileName];
|
|
225
|
+
if (!selectedProfile) {
|
|
226
|
+
throw new Error(`Unknown profile: ${selectedProfileName}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log(`\nSelected profile: ${selectedProfile.displayName}`);
|
|
230
|
+
console.log(`This profile will block these review severities in CI: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}.`);
|
|
231
|
+
|
|
232
|
+
if (selectedProfilePack) {
|
|
233
|
+
console.log(`Applying team profile pack: ${selectedProfilePack.displayName}.`);
|
|
234
|
+
console.log(`Pack defaults: stack ${toTitleCase(selectedProfilePack.defaultStackFileName)}, blueprint ${toTitleCase(selectedProfilePack.defaultBlueprintFileName)}.`);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const shouldApplyDetectedStack = projectDetection.recommendedStackFileName && !selectedStackFileNameFromOption
|
|
238
|
+
? await askYesNo(
|
|
239
|
+
`Use the detected stack recommendation (${toTitleCase(projectDetection.recommendedStackFileName)})?`,
|
|
240
|
+
userInterface,
|
|
241
|
+
projectDetection.confidenceLabel === 'high'
|
|
242
|
+
)
|
|
243
|
+
: false;
|
|
244
|
+
|
|
245
|
+
const stackDisplayChoices = stackFileNames.map((stackFileName) => toTitleCase(stackFileName));
|
|
246
|
+
const blueprintDisplayChoices = blueprintFileNames.map((blueprintFileName) => toTitleCase(blueprintFileName));
|
|
247
|
+
|
|
248
|
+
const selectedResolvedStackFileName = selectedStackFileNameFromOption
|
|
249
|
+
|| selectedPreset?.stack
|
|
250
|
+
|| (shouldApplyDetectedStack ? projectDetection.recommendedStackFileName : null)
|
|
251
|
+
|| selectedProfilePack?.defaultStackFileName
|
|
252
|
+
|| selectedProfile.defaultStackFileName
|
|
253
|
+
|| stackFileNames[
|
|
254
|
+
stackDisplayChoices.indexOf(
|
|
255
|
+
await askChoice('Which stack should this governance pack target?', stackDisplayChoices, userInterface)
|
|
256
|
+
)
|
|
257
|
+
];
|
|
258
|
+
|
|
259
|
+
const recommendedBlueprintFileName = shouldApplyDetectedStack
|
|
260
|
+
? projectDetection.recommendedBlueprintFileName
|
|
261
|
+
: BLUEPRINT_RECOMMENDATIONS[selectedResolvedStackFileName] || null;
|
|
262
|
+
|
|
263
|
+
if (!recommendedBlueprintFileName && !selectedBlueprintFileNameFromOption && !selectedProfile.defaultBlueprintFileName) {
|
|
264
|
+
console.log('\nI could not map that stack to a first-party blueprint automatically, so I will ask you to choose one.');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const selectedResolvedBlueprintFileName = selectedBlueprintFileNameFromOption
|
|
268
|
+
|| selectedPreset?.blueprint
|
|
269
|
+
|| recommendedBlueprintFileName
|
|
270
|
+
|| selectedProfilePack?.defaultBlueprintFileName
|
|
271
|
+
|| selectedProfile.defaultBlueprintFileName
|
|
272
|
+
|| blueprintFileNames[
|
|
273
|
+
blueprintDisplayChoices.indexOf(
|
|
274
|
+
await askChoice('Which blueprint should I scaffold into the compiled rulebook?', blueprintDisplayChoices, userInterface)
|
|
275
|
+
)
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
const includeCiGuardrails = typeof initOptions.ci === 'boolean'
|
|
279
|
+
? initOptions.ci
|
|
280
|
+
: typeof selectedPreset?.ci === 'boolean'
|
|
281
|
+
? selectedPreset.ci
|
|
282
|
+
: selectedProfilePack?.lockCi
|
|
283
|
+
? selectedProfilePack.defaultCi
|
|
284
|
+
: typeof selectedProfilePack?.defaultCi === 'boolean'
|
|
285
|
+
? selectedProfilePack.defaultCi
|
|
286
|
+
: selectedProfile.lockCi
|
|
287
|
+
? selectedProfile.defaultCi
|
|
288
|
+
: await askYesNo('Enable CI/CD guardrails and the LLM Judge policy?', userInterface, selectedProfile.defaultCi);
|
|
289
|
+
|
|
290
|
+
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath);
|
|
291
|
+
|
|
292
|
+
await compileDynamicContext({
|
|
293
|
+
targetDirectoryPath: resolvedTargetDirectoryPath,
|
|
294
|
+
selectedProfileName,
|
|
295
|
+
selectedProfilePack,
|
|
296
|
+
selectedStackFileName: selectedResolvedStackFileName,
|
|
297
|
+
selectedBlueprintFileName: selectedResolvedBlueprintFileName,
|
|
298
|
+
includeCiGuardrails,
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
await writeSelectedPolicy(resolvedTargetDirectoryPath, selectedProfileName);
|
|
302
|
+
|
|
303
|
+
const setupDurationMs = Date.now() - setupStartedAt;
|
|
304
|
+
await writeOnboardingReport({
|
|
305
|
+
targetDirectoryPath: resolvedTargetDirectoryPath,
|
|
306
|
+
selectedProfileName,
|
|
307
|
+
selectedProfilePack,
|
|
308
|
+
selectedPreset: initOptions.preset || null,
|
|
309
|
+
selectedStackFileName: selectedResolvedStackFileName,
|
|
310
|
+
selectedBlueprintFileName: selectedResolvedBlueprintFileName,
|
|
311
|
+
includeCiGuardrails,
|
|
312
|
+
setupDurationMs,
|
|
313
|
+
projectDetection,
|
|
314
|
+
selectedSkillDomains: inferSkillDomainNamesFromSelection(selectedResolvedStackFileName, selectedResolvedBlueprintFileName),
|
|
315
|
+
operationMode: 'init',
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
console.log('\nInitialization complete.');
|
|
319
|
+
console.log(`- Target directory: ${resolvedTargetDirectoryPath}`);
|
|
320
|
+
console.log(`- Profile: ${selectedProfile.displayName}`);
|
|
321
|
+
if (initOptions.preset) {
|
|
322
|
+
console.log(`- Preset: ${initOptions.preset}`);
|
|
323
|
+
}
|
|
324
|
+
if (selectedProfilePack) {
|
|
325
|
+
console.log(`- Team profile pack: ${selectedProfilePack.displayName}`);
|
|
326
|
+
}
|
|
327
|
+
console.log(`- Stack: ${toTitleCase(selectedResolvedStackFileName)}`);
|
|
328
|
+
console.log(`- Blueprint: ${toTitleCase(selectedResolvedBlueprintFileName)}`);
|
|
329
|
+
console.log(`- CI/CD guardrails: ${includeCiGuardrails ? 'enabled' : 'disabled'}`);
|
|
330
|
+
console.log(`- Blocking severities: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}`);
|
|
331
|
+
console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
|
|
332
|
+
console.log('- Generated files: .cursorrules, .windsurfrules, and .agent-context/state/onboarding-report.json');
|
|
333
|
+
console.log('\nPlain-language summary:');
|
|
334
|
+
console.log(`I prepared a ${selectedProfile.displayName.toLowerCase()} governance pack for a ${toTitleCase(selectedResolvedStackFileName)} project using the ${toTitleCase(selectedResolvedBlueprintFileName)} blueprint.`);
|
|
335
|
+
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.');
|
|
336
|
+
} finally {
|
|
337
|
+
userInterface.close();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Launch Command — Numbered interactive launcher.
|
|
3
|
+
* Depends on: constants, utils, init command, skill-selector
|
|
4
|
+
*/
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
6
|
+
import { stdin, stdout } from 'node:process';
|
|
7
|
+
|
|
8
|
+
import { CLI_VERSION, INIT_PRESETS } from '../constants.mjs';
|
|
9
|
+
import { askChoice, normalizeChoiceInput } from '../utils.mjs';
|
|
10
|
+
import { runInitCommand } from './init.mjs';
|
|
11
|
+
import { runSkillCommand } from '../skill-selector.mjs';
|
|
12
|
+
|
|
13
|
+
export async function runLaunchCommand() {
|
|
14
|
+
const userInterface = createInterface({ input: stdin, output: stdout });
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
console.log(`\nAgentic-Senior-Core CLI v${CLI_VERSION}`);
|
|
18
|
+
console.log('Start with a numbered choice. You can still use commands later if you want direct control.');
|
|
19
|
+
|
|
20
|
+
const launchChoice = await askChoice(
|
|
21
|
+
'How do you want to start?',
|
|
22
|
+
[
|
|
23
|
+
'GitHub template (zero install)',
|
|
24
|
+
'npm / npx path',
|
|
25
|
+
'Bootstrap scripts',
|
|
26
|
+
'Preset starter',
|
|
27
|
+
'Interactive init wizard',
|
|
28
|
+
'Skill selector',
|
|
29
|
+
'Exit',
|
|
30
|
+
],
|
|
31
|
+
userInterface
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (launchChoice === 'GitHub template (zero install)') {
|
|
35
|
+
console.log('\nOpen the GitHub template here:');
|
|
36
|
+
console.log('https://github.com/fatidaprilian/Agentic-Senior-Core/generate');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (launchChoice === 'npm / npx path') {
|
|
41
|
+
console.log('\nChoose one of these package paths:');
|
|
42
|
+
console.log('npm exec --yes @ryuenn3123/agentic-senior-core init');
|
|
43
|
+
console.log('npx @ryuenn3123/agentic-senior-core init');
|
|
44
|
+
console.log('npm install -g @ryuenn3123/agentic-senior-core && agentic-senior-core init');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (launchChoice === 'Bootstrap scripts') {
|
|
49
|
+
console.log('\nUse the repository bootstrap scripts:');
|
|
50
|
+
console.log('Windows: powershell -ExecutionPolicy Bypass -File .\\scripts\\init-project.ps1 -TargetDirectory .');
|
|
51
|
+
console.log('Linux/macOS: bash ./scripts/init-project.sh .');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (launchChoice === 'Preset starter') {
|
|
56
|
+
const presetNames = Object.keys(INIT_PRESETS);
|
|
57
|
+
const selectedPresetName = await askChoice(
|
|
58
|
+
'Choose a starter preset:',
|
|
59
|
+
presetNames.map((presetName) => `${presetName} - ${INIT_PRESETS[presetName].description}`),
|
|
60
|
+
userInterface
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
await runInitCommand('.', { preset: normalizeChoiceInput(selectedPresetName.split(' - ')[0]) });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (launchChoice === 'Interactive init wizard') {
|
|
68
|
+
await runInitCommand('.', {});
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (launchChoice === 'Skill selector') {
|
|
73
|
+
await runSkillCommand([]);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log('Exit selected.');
|
|
78
|
+
} finally {
|
|
79
|
+
userInterface.close();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upgrade Command — Governance upgrade assistant.
|
|
3
|
+
* Depends on: constants, utils, detector, compiler
|
|
4
|
+
*/
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
6
|
+
import { stdin, stdout } from 'node:process';
|
|
7
|
+
import fs from 'node:fs/promises';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
CLI_VERSION,
|
|
12
|
+
AGENT_CONTEXT_DIR,
|
|
13
|
+
PROFILE_PRESETS,
|
|
14
|
+
BLUEPRINT_RECOMMENDATIONS,
|
|
15
|
+
} from '../constants.mjs';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
ensureDirectory,
|
|
19
|
+
askYesNo,
|
|
20
|
+
toTitleCase,
|
|
21
|
+
collectFileNames,
|
|
22
|
+
formatDuration,
|
|
23
|
+
pathExists,
|
|
24
|
+
copyGovernanceAssetsToTarget,
|
|
25
|
+
} from '../utils.mjs';
|
|
26
|
+
|
|
27
|
+
import { detectProjectContext } from '../detector.mjs';
|
|
28
|
+
import {
|
|
29
|
+
buildCompiledRulesContent,
|
|
30
|
+
writeSelectedPolicy,
|
|
31
|
+
writeOnboardingReport,
|
|
32
|
+
loadOnboardingReportIfExists,
|
|
33
|
+
} from '../compiler.mjs';
|
|
34
|
+
|
|
35
|
+
export function parseUpgradeArguments(commandArguments) {
|
|
36
|
+
const parsedUpgradeOptions = {
|
|
37
|
+
targetDirectory: '.',
|
|
38
|
+
dryRun: false,
|
|
39
|
+
skipConfirmation: false,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
for (let argumentIndex = 0; argumentIndex < commandArguments.length; argumentIndex++) {
|
|
43
|
+
const currentArgument = commandArguments[argumentIndex];
|
|
44
|
+
|
|
45
|
+
if (!currentArgument.startsWith('--')) {
|
|
46
|
+
parsedUpgradeOptions.targetDirectory = currentArgument;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (currentArgument === '--dry-run') {
|
|
51
|
+
parsedUpgradeOptions.dryRun = true;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (currentArgument === '--yes') {
|
|
56
|
+
parsedUpgradeOptions.skipConfirmation = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throw new Error(`Unknown option: ${currentArgument}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return parsedUpgradeOptions;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions = {}) {
|
|
67
|
+
const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
|
|
68
|
+
const setupStartedAt = Date.now();
|
|
69
|
+
await ensureDirectory(resolvedTargetDirectoryPath);
|
|
70
|
+
|
|
71
|
+
const userInterface = createInterface({ input: stdin, output: stdout });
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
console.log(`\nAgentic-Senior-Core CLI v${CLI_VERSION}`);
|
|
75
|
+
console.log('Running upgrade assistant for an existing repository.');
|
|
76
|
+
|
|
77
|
+
await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath);
|
|
78
|
+
|
|
79
|
+
const stackFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'stacks'));
|
|
80
|
+
const blueprintFileNames = await collectFileNames(path.join(AGENT_CONTEXT_DIR, 'blueprints'));
|
|
81
|
+
const existingOnboardingReport = await loadOnboardingReportIfExists(resolvedTargetDirectoryPath);
|
|
82
|
+
const projectDetection = await detectProjectContext(resolvedTargetDirectoryPath);
|
|
83
|
+
|
|
84
|
+
const selectedProfileName = PROFILE_PRESETS[existingOnboardingReport?.selectedProfile]
|
|
85
|
+
? existingOnboardingReport.selectedProfile
|
|
86
|
+
: 'balanced';
|
|
87
|
+
|
|
88
|
+
const selectedStackFileName = stackFileNames.includes(existingOnboardingReport?.selectedStack)
|
|
89
|
+
? existingOnboardingReport.selectedStack
|
|
90
|
+
: projectDetection.recommendedStackFileName || 'typescript.md';
|
|
91
|
+
|
|
92
|
+
const selectedBlueprintFileName = blueprintFileNames.includes(existingOnboardingReport?.selectedBlueprint)
|
|
93
|
+
? existingOnboardingReport.selectedBlueprint
|
|
94
|
+
: BLUEPRINT_RECOMMENDATIONS[selectedStackFileName] || 'api-nextjs.md';
|
|
95
|
+
|
|
96
|
+
const includeCiGuardrails = typeof existingOnboardingReport?.ciGuardrailsEnabled === 'boolean'
|
|
97
|
+
? existingOnboardingReport.ciGuardrailsEnabled
|
|
98
|
+
: true;
|
|
99
|
+
|
|
100
|
+
const currentRulesPath = path.join(resolvedTargetDirectoryPath, '.cursorrules');
|
|
101
|
+
const currentRulesContent = await pathExists(currentRulesPath)
|
|
102
|
+
? await fs.readFile(currentRulesPath, 'utf8')
|
|
103
|
+
: '';
|
|
104
|
+
|
|
105
|
+
const plannedRulesContent = await buildCompiledRulesContent({
|
|
106
|
+
targetDirectoryPath: resolvedTargetDirectoryPath,
|
|
107
|
+
selectedProfileName,
|
|
108
|
+
selectedStackFileName,
|
|
109
|
+
selectedBlueprintFileName,
|
|
110
|
+
includeCiGuardrails,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const isRulesContentChanged = currentRulesContent !== plannedRulesContent;
|
|
114
|
+
const currentRuleLineCount = currentRulesContent ? currentRulesContent.split(/\r?\n/).length : 0;
|
|
115
|
+
const plannedRuleLineCount = plannedRulesContent.split(/\r?\n/).length;
|
|
116
|
+
|
|
117
|
+
console.log('\nUpgrade preview:');
|
|
118
|
+
console.log(`- Target directory: ${resolvedTargetDirectoryPath}`);
|
|
119
|
+
console.log(`- Profile: ${toTitleCase(selectedProfileName)}`);
|
|
120
|
+
console.log(`- Stack: ${toTitleCase(selectedStackFileName)}`);
|
|
121
|
+
console.log(`- Blueprint: ${toTitleCase(selectedBlueprintFileName)}`);
|
|
122
|
+
console.log(`- CI/CD guardrails: ${includeCiGuardrails ? 'enabled' : 'disabled'}`);
|
|
123
|
+
console.log(`- Existing rules lines: ${currentRuleLineCount}`);
|
|
124
|
+
console.log(`- Planned rules lines: ${plannedRuleLineCount}`);
|
|
125
|
+
console.log(`- Rules changed: ${isRulesContentChanged ? 'yes' : 'no'}`);
|
|
126
|
+
|
|
127
|
+
if (upgradeOptions.dryRun) {
|
|
128
|
+
console.log('\nDry run enabled. No files were modified.');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const shouldApplyUpgrade = upgradeOptions.skipConfirmation
|
|
133
|
+
? true
|
|
134
|
+
: await askYesNo('Apply upgrade and write migrated files?', userInterface, true);
|
|
135
|
+
|
|
136
|
+
if (!shouldApplyUpgrade) {
|
|
137
|
+
console.log('Upgrade cancelled by user.');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await fs.writeFile(currentRulesPath, plannedRulesContent, 'utf8');
|
|
142
|
+
await fs.writeFile(path.join(resolvedTargetDirectoryPath, '.windsurfrules'), plannedRulesContent, 'utf8');
|
|
143
|
+
await writeSelectedPolicy(resolvedTargetDirectoryPath, selectedProfileName);
|
|
144
|
+
|
|
145
|
+
const setupDurationMs = Date.now() - setupStartedAt;
|
|
146
|
+
await writeOnboardingReport({
|
|
147
|
+
targetDirectoryPath: resolvedTargetDirectoryPath,
|
|
148
|
+
selectedProfileName,
|
|
149
|
+
selectedProfilePack: existingOnboardingReport?.selectedProfilePack || null,
|
|
150
|
+
selectedStackFileName,
|
|
151
|
+
selectedBlueprintFileName,
|
|
152
|
+
includeCiGuardrails,
|
|
153
|
+
setupDurationMs,
|
|
154
|
+
projectDetection,
|
|
155
|
+
operationMode: 'upgrade',
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
console.log('\nUpgrade complete.');
|
|
159
|
+
console.log(`- Rules rewritten: ${isRulesContentChanged ? 'yes' : 'no (metadata refreshed)'}`);
|
|
160
|
+
console.log(`- Setup time: ${formatDuration(setupDurationMs)}`);
|
|
161
|
+
console.log('- Updated files: .cursorrules, .windsurfrules, .agent-context/state/onboarding-report.json');
|
|
162
|
+
} finally {
|
|
163
|
+
userInterface.close();
|
|
164
|
+
}
|
|
165
|
+
}
|