@ryuenn3123/agentic-senior-core 2.5.18 → 2.5.20

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.
@@ -65,6 +65,7 @@ import { evaluateSkillDomainCompatibility } from '../compatibility.mjs';
65
65
  import {
66
66
  ARCHITECT_DEFAULT_TOKEN_BUDGET,
67
67
  ARCHITECT_DEFAULT_TIMEOUT_MS,
68
+ ARCHITECT_DEFAULT_RESEARCH_MODE,
68
69
  ARCHITECT_MIN_TOKEN_BUDGET,
69
70
  ARCHITECT_MAX_TOKEN_BUDGET,
70
71
  ARCHITECT_MIN_TIMEOUT_MS,
@@ -100,6 +101,9 @@ export function parseInitArguments(commandArguments) {
100
101
  projectDescription: '',
101
102
  architectTokenBudget: ARCHITECT_DEFAULT_TOKEN_BUDGET,
102
103
  architectTimeoutMs: ARCHITECT_DEFAULT_TIMEOUT_MS,
104
+ architectResearchMode: ARCHITECT_DEFAULT_RESEARCH_MODE,
105
+ enableRealtimeResearch: false,
106
+ architectRealtimeSignalFile: null,
103
107
  runtimeEnv: 'auto',
104
108
  runtimeEnvProvided: false,
105
109
  };
@@ -308,6 +312,38 @@ export function parseInitArguments(commandArguments) {
308
312
  continue;
309
313
  }
310
314
 
315
+ if (currentArgument === '--architect-research-mode') {
316
+ parsedInitOptions.architectResearchMode = commandArguments[argumentIndex + 1] || ARCHITECT_DEFAULT_RESEARCH_MODE;
317
+ argumentIndex += 1;
318
+ continue;
319
+ }
320
+
321
+ if (currentArgument.startsWith('--architect-research-mode=')) {
322
+ parsedInitOptions.architectResearchMode = currentArgument.split('=')[1] || ARCHITECT_DEFAULT_RESEARCH_MODE;
323
+ continue;
324
+ }
325
+
326
+ if (currentArgument === '--enable-realtime-research') {
327
+ parsedInitOptions.enableRealtimeResearch = true;
328
+ continue;
329
+ }
330
+
331
+ if (currentArgument === '--disable-realtime-research') {
332
+ parsedInitOptions.enableRealtimeResearch = false;
333
+ continue;
334
+ }
335
+
336
+ if (currentArgument === '--architect-realtime-signal-file') {
337
+ parsedInitOptions.architectRealtimeSignalFile = commandArguments[argumentIndex + 1] || null;
338
+ argumentIndex += 1;
339
+ continue;
340
+ }
341
+
342
+ if (currentArgument.startsWith('--architect-realtime-signal-file=')) {
343
+ parsedInitOptions.architectRealtimeSignalFile = currentArgument.split('=')[1] || null;
344
+ continue;
345
+ }
346
+
311
347
  if (currentArgument === '--runtime-env') {
312
348
  parsedInitOptions.runtimeEnv = commandArguments[argumentIndex + 1] || 'auto';
313
349
  parsedInitOptions.runtimeEnvProvided = true;
@@ -350,9 +386,18 @@ export function parseInitArguments(commandArguments) {
350
386
  throw new Error(`--architect-timeout-ms must be an integer between ${ARCHITECT_MIN_TIMEOUT_MS} and ${ARCHITECT_MAX_TIMEOUT_MS}`);
351
387
  }
352
388
 
389
+ const normalizedArchitectResearchMode = normalizeChoiceInput(
390
+ parsedInitOptions.architectResearchMode || ARCHITECT_DEFAULT_RESEARCH_MODE
391
+ );
392
+ const supportedArchitectResearchModes = new Set(['snapshot', 'realtime']);
393
+ if (!supportedArchitectResearchModes.has(normalizedArchitectResearchMode)) {
394
+ throw new Error('--architect-research-mode must be one of: snapshot, realtime');
395
+ }
396
+
353
397
  parsedInitOptions.docsLang = normalizedDocsLanguage;
354
398
  parsedInitOptions.runtimeEnv = normalizedRuntimeEnvironment;
355
399
  parsedInitOptions.tokenAgent = normalizeAgentName(parsedInitOptions.tokenAgent);
400
+ parsedInitOptions.architectResearchMode = normalizedArchitectResearchMode;
356
401
 
357
402
  return parsedInitOptions;
358
403
  }
@@ -502,6 +547,14 @@ async function askBlueprintSelection(promptMessage, selectableBlueprintFileNames
502
547
  return selectableBlueprintFileNames[selectedIndex] || selectableBlueprintFileNames[0] || null;
503
548
  }
504
549
 
550
+ function buildExistingProjectMajorConstraints() {
551
+ return [
552
+ 'Preserve existing project markers and avoid forced stack migration.',
553
+ 'Keep stack rule loading lazy and scoped to touched code.',
554
+ 'Explicit stack or blueprint overrides always win over auto-detection.',
555
+ ];
556
+ }
557
+
505
558
  export async function runInitCommand(targetDirectoryArgument, initOptions = {}) {
506
559
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
507
560
  const isTokenOptimizationEnabled = typeof initOptions.tokenOptimize === 'boolean'
@@ -654,6 +707,64 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
654
707
  console.log(`\nSelected profile: ${selectedProfile.displayName}`);
655
708
  console.log(`This profile will block these review severities in CI: ${formatBlockingSeverities(selectedProfile.blockingSeverities)}.`);
656
709
 
710
+ const detectionMajorConstraints = buildExistingProjectMajorConstraints();
711
+ const detectionTransparency = {
712
+ declaredAt: new Date().toISOString(),
713
+ declarationType: projectDetection.hasExistingProjectFiles ? 'existing-project' : 'fresh-project',
714
+ declarationShown: projectDetection.hasExistingProjectFiles,
715
+ detectionSummary: projectDetection.hasExistingProjectFiles
716
+ ? buildDetectionSummary(projectDetection)
717
+ : 'No existing project markers were detected.',
718
+ activeRulesSummary: {
719
+ canonicalSource: '.instructions.md',
720
+ compiledEntrypoints: ['.cursorrules', '.windsurfrules'],
721
+ stackLoadingMode: 'lazy',
722
+ selectedProfile: selectedProfileName,
723
+ selectedProfileDisplayName: selectedProfile.displayName,
724
+ blockingSeverities: selectedProfile.blockingSeverities,
725
+ ciGuardrailsEnabled: null,
726
+ },
727
+ majorConstraints: detectionMajorConstraints,
728
+ quickConfirmation: {
729
+ offered: false,
730
+ response: projectDetection.hasExistingProjectFiles ? 'pending' : 'not-applicable',
731
+ source: 'existing-project-detection',
732
+ },
733
+ decision: {
734
+ mode: projectDetection.hasExistingProjectFiles ? 'pending' : 'fresh-directory',
735
+ selectedStackFileName: null,
736
+ selectedBlueprintFileName: null,
737
+ },
738
+ };
739
+
740
+ if (projectDetection.hasExistingProjectFiles) {
741
+ console.log('\nExisting project detection transparency:');
742
+
743
+ if (projectDetection.recommendedStackFileName) {
744
+ const confidenceScoreLabel = Number(projectDetection.confidenceScore || 0).toFixed(2);
745
+ console.log(
746
+ `- Detected stack: ${toTitleCase(projectDetection.recommendedStackFileName)} (${projectDetection.confidenceLabel}, score ${confidenceScoreLabel})`
747
+ );
748
+
749
+ if (projectDetection.secondaryStackFileNames?.length) {
750
+ console.log(
751
+ `- Secondary stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}`
752
+ );
753
+ }
754
+ } else {
755
+ console.log('- Detected stack: unresolved (insufficient markers).');
756
+ }
757
+
758
+ console.log('- Active rules baseline: canonical .instructions.md -> compiled .cursorrules/.windsurfrules');
759
+ console.log(
760
+ `- Active review profile: ${selectedProfile.displayName} (blocking severities: ${formatBlockingSeverities(selectedProfile.blockingSeverities)})`
761
+ );
762
+ console.log('- Major constraints:');
763
+ for (const majorConstraint of detectionMajorConstraints) {
764
+ console.log(` - ${majorConstraint}`);
765
+ }
766
+ }
767
+
657
768
  if (selectedProfilePack) {
658
769
  console.log(`Applying team profile pack: ${selectedProfilePack.displayName}.`);
659
770
  console.log(`Pack defaults: stack ${toTitleCase(selectedProfilePack.defaultStackFileName)}, blueprint ${toTitleCase(selectedProfilePack.defaultBlueprintFileName)}.`);
@@ -667,11 +778,15 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
667
778
  && !selectedStackFileNameFromOption
668
779
  && !selectedPreset?.stack
669
780
  && !selectedProfilePack?.defaultStackFileName;
781
+ const detectedBlueprintFileName = projectDetection.recommendedBlueprintFileName
782
+ || BLUEPRINT_RECOMMENDATIONS[projectDetection.recommendedStackFileName]
783
+ || null;
670
784
 
671
785
  let selectedManualStackFileName = null;
672
786
  let selectedManualBlueprintFileName = null;
673
787
  let selectedAdditionalStackFileNames = [];
674
788
  let selectedAdditionalBlueprintFileNames = [];
789
+ let detectedSetupWasApplied = false;
675
790
 
676
791
  let architectureRecommendation = null;
677
792
  let architectPreferenceState = await readArchitectPreferenceState();
@@ -684,11 +799,73 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
684
799
  && !selectedProfile.defaultStackFileName;
685
800
 
686
801
  if (shouldAutoApplyDetectedStack) {
687
- console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
688
- if (projectDetection.secondaryStackFileNames?.length) {
689
- console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
802
+ if (isInteractiveSession) {
803
+ detectionTransparency.quickConfirmation.offered = true;
804
+ console.log('\nQuick confirmation for existing project detection:');
805
+ console.log(`- Suggested stack: ${toTitleCase(projectDetection.recommendedStackFileName)}`);
806
+ if (detectedBlueprintFileName) {
807
+ console.log(`- Suggested blueprint: ${toTitleCase(detectedBlueprintFileName)}`);
808
+ }
809
+
810
+ const shouldUseDetectedSetup = await askYesNo(
811
+ 'Use detected setup for this existing project?',
812
+ userInterface,
813
+ true
814
+ );
815
+
816
+ if (shouldUseDetectedSetup) {
817
+ detectedSetupWasApplied = true;
818
+ detectionTransparency.quickConfirmation.response = 'confirmed-detected';
819
+ detectionTransparency.decision.mode = 'confirmed-detected';
820
+ console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
821
+ if (projectDetection.secondaryStackFileNames?.length) {
822
+ console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
823
+ }
824
+ selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
825
+ } else {
826
+ const overrideStackFileName = await askStackSelection(
827
+ 'Override detected stack (quick selection):',
828
+ stackFileNames,
829
+ userInterface
830
+ );
831
+ const overrideBlueprintCandidates = filterBlueprintFileNamesByCandidates(
832
+ blueprintFileNames,
833
+ [BLUEPRINT_RECOMMENDATIONS[overrideStackFileName]].filter(Boolean)
834
+ );
835
+ const overrideBlueprintFileName = await askBlueprintSelection(
836
+ 'Override detected blueprint (quick selection):',
837
+ overrideBlueprintCandidates,
838
+ userInterface
839
+ );
840
+
841
+ selectedManualStackFileName = overrideStackFileName;
842
+ selectedManualBlueprintFileName = overrideBlueprintFileName;
843
+ selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
844
+ overrideStackFileName,
845
+ projectDetection.secondaryStackFileNames || []
846
+ );
847
+ detectionTransparency.quickConfirmation.response = 'overridden-detected';
848
+ detectionTransparency.decision.mode = 'overridden-detected';
849
+ console.log(
850
+ `Detection override applied: ${toTitleCase(overrideStackFileName)} + ${toTitleCase(overrideBlueprintFileName)}.`
851
+ );
852
+ }
853
+ } else {
854
+ detectedSetupWasApplied = true;
855
+ detectionTransparency.quickConfirmation.response = 'non-interactive-auto';
856
+ detectionTransparency.decision.mode = 'non-interactive-auto';
857
+ console.log(`Using detected stack automatically for this existing project: ${toTitleCase(projectDetection.recommendedStackFileName)}.`);
858
+ if (projectDetection.secondaryStackFileNames?.length) {
859
+ console.log(`Detected additional stack signals: ${projectDetection.secondaryStackFileNames.map((stackFileName) => toTitleCase(stackFileName)).join(', ')}.`);
860
+ }
861
+ selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
690
862
  }
691
- selectedAdditionalStackFileNames = projectDetection.secondaryStackFileNames || [];
863
+ } else if (projectDetection.hasExistingProjectFiles && projectDetection.recommendedStackFileName) {
864
+ detectionTransparency.quickConfirmation.response = 'explicit-selection-or-low-confidence';
865
+ detectionTransparency.decision.mode = 'explicit-selection-or-low-confidence';
866
+ } else if (!projectDetection.hasExistingProjectFiles) {
867
+ detectionTransparency.quickConfirmation.response = 'not-applicable';
868
+ detectionTransparency.decision.mode = 'fresh-directory';
692
869
  }
693
870
 
694
871
  if (shouldRunArchitectureRecommendation) {
@@ -711,6 +888,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
711
888
  blueprintFileNames,
712
889
  tokenBudget: initOptions.architectTokenBudget,
713
890
  timeoutMs: initOptions.architectTimeoutMs,
891
+ researchMode: initOptions.architectResearchMode,
892
+ enableRealtimeResearch: initOptions.enableRealtimeResearch,
893
+ realtimeSignalFilePath: initOptions.architectRealtimeSignalFile,
714
894
  });
715
895
 
716
896
  architectureRecommendation.userVeto = {
@@ -805,10 +985,10 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
805
985
 
806
986
  const selectedResolvedStackFileName = selectedStackFileNameFromOption
807
987
  || selectedPreset?.stack
808
- || (shouldAutoApplyDetectedStack ? projectDetection.recommendedStackFileName : null)
988
+ || selectedManualStackFileName
989
+ || (detectedSetupWasApplied ? projectDetection.recommendedStackFileName : null)
809
990
  || selectedProfilePack?.defaultStackFileName
810
991
  || selectedProfile.defaultStackFileName
811
- || selectedManualStackFileName
812
992
  || stackFileNames[0];
813
993
 
814
994
  selectedAdditionalStackFileNames = normalizeAdditionalStackSelection(
@@ -816,9 +996,9 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
816
996
  selectedAdditionalStackFileNames
817
997
  );
818
998
 
819
- const recommendedBlueprintFileName = projectDetection.recommendedBlueprintFileName
820
- && shouldAutoApplyDetectedStack
821
- ? projectDetection.recommendedBlueprintFileName
999
+ const recommendedBlueprintFileName = detectedSetupWasApplied
1000
+ && detectedBlueprintFileName
1001
+ ? detectedBlueprintFileName
822
1002
  : BLUEPRINT_RECOMMENDATIONS[selectedResolvedStackFileName] || null;
823
1003
 
824
1004
  if (!recommendedBlueprintFileName && !selectedBlueprintFileNameFromOption && !selectedProfile.defaultBlueprintFileName) {
@@ -864,6 +1044,12 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
864
1044
  : derivedAdditionalBlueprintFileNames
865
1045
  );
866
1046
 
1047
+ detectionTransparency.decision.selectedStackFileName = selectedResolvedStackFileName;
1048
+ detectionTransparency.decision.selectedBlueprintFileName = selectedResolvedBlueprintFileName;
1049
+ detectionTransparency.decision.selectedAdditionalStackFileNames = selectedAdditionalStackFileNames;
1050
+ detectionTransparency.decision.selectedAdditionalBlueprintFileNames = selectedAdditionalBlueprintFileNames;
1051
+ detectionTransparency.decision.usedDetectedSetup = detectedSetupWasApplied;
1052
+
867
1053
  const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
868
1054
  selectedResolvedStackFileName,
869
1055
  selectedResolvedBlueprintFileName,
@@ -883,6 +1069,8 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
883
1069
  ? selectedProfile.defaultCi
884
1070
  : await askYesNo('Enable CI/CD quality checks (guardrails) and the LLM Judge policy?', userInterface, selectedProfile.defaultCi);
885
1071
 
1072
+ detectionTransparency.activeRulesSummary.ciGuardrailsEnabled = includeCiGuardrails;
1073
+
886
1074
  await copyGovernanceAssetsToTarget(resolvedTargetDirectoryPath, {
887
1075
  includeMcpTemplate: shouldIncludeMcpTemplate,
888
1076
  });
@@ -1044,6 +1232,7 @@ export async function runInitCommand(targetDirectoryArgument, initOptions = {})
1044
1232
  stateFile: isMemoryContinuityEnabled ? '.agent-context/state/memory-continuity.json' : null,
1045
1233
  },
1046
1234
  architectRecommendation: architectureRecommendation,
1235
+ detectionTransparency,
1047
1236
  });
1048
1237
 
1049
1238
  if (architectPreferenceUpdated && architectPreferenceState) {
@@ -24,7 +24,11 @@ import {
24
24
  copyGovernanceAssetsToTarget,
25
25
  } from '../utils.mjs';
26
26
 
27
- import { detectProjectContext } from '../detector.mjs';
27
+ import {
28
+ detectProjectContext,
29
+ buildDetectionSummary,
30
+ formatDetectionCandidates,
31
+ } from '../detector.mjs';
28
32
  import {
29
33
  buildCompiledRulesContent,
30
34
  writeSelectedPolicy,
@@ -76,6 +80,14 @@ export function parseUpgradeArguments(commandArguments) {
76
80
  return parsedUpgradeOptions;
77
81
  }
78
82
 
83
+ function buildExistingProjectMajorConstraints() {
84
+ return [
85
+ 'Preserve existing project markers and avoid forced stack migration.',
86
+ 'Keep stack rule loading lazy and scoped to touched code.',
87
+ 'Upgrade keeps prior onboarding choices unless user overrides them.',
88
+ ];
89
+ }
90
+
79
91
  export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions = {}) {
80
92
  const resolvedTargetDirectoryPath = path.resolve(targetDirectoryArgument || '.');
81
93
 
@@ -143,6 +155,56 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
143
155
  ? existingOnboardingReport.ciGuardrailsEnabled
144
156
  : true;
145
157
 
158
+ const detectionMajorConstraints = buildExistingProjectMajorConstraints();
159
+ const detectionTransparency = {
160
+ declaredAt: new Date().toISOString(),
161
+ declarationType: 'existing-project',
162
+ declarationShown: true,
163
+ detectionSummary: buildDetectionSummary(projectDetection),
164
+ activeRulesSummary: {
165
+ canonicalSource: '.instructions.md',
166
+ compiledEntrypoints: ['.cursorrules', '.windsurfrules'],
167
+ stackLoadingMode: 'lazy',
168
+ selectedProfile: selectedProfileName,
169
+ selectedProfileDisplayName: toTitleCase(selectedProfileName),
170
+ blockingSeverities: PROFILE_PRESETS[selectedProfileName]?.blockingSeverities || [],
171
+ ciGuardrailsEnabled: includeCiGuardrails,
172
+ },
173
+ majorConstraints: detectionMajorConstraints,
174
+ quickConfirmation: {
175
+ offered: false,
176
+ response: 'upgrade-auto',
177
+ source: 'upgrade-assistant',
178
+ },
179
+ decision: {
180
+ mode: 'upgrade-auto',
181
+ selectedStackFileName,
182
+ selectedBlueprintFileName,
183
+ },
184
+ };
185
+
186
+ console.log('\nExisting project detection transparency:');
187
+ if (projectDetection.recommendedStackFileName) {
188
+ const confidenceScoreLabel = Number(projectDetection.confidenceScore || 0).toFixed(2);
189
+ console.log(
190
+ `- Detected stack: ${toTitleCase(projectDetection.recommendedStackFileName)} (${projectDetection.confidenceLabel}, score ${confidenceScoreLabel})`
191
+ );
192
+ } else {
193
+ console.log('- Detected stack: unresolved (insufficient markers).');
194
+ }
195
+ console.log('- Active rules baseline: canonical .instructions.md -> compiled .cursorrules/.windsurfrules');
196
+ console.log(
197
+ `- Active review profile: ${toTitleCase(selectedProfileName)} (blocking severities: ${(
198
+ PROFILE_PRESETS[selectedProfileName]?.blockingSeverities || []
199
+ ).join(', ') || 'none'})`
200
+ );
201
+ console.log('- Top candidates:');
202
+ console.log(formatDetectionCandidates(projectDetection.rankedCandidates));
203
+ console.log('- Major constraints:');
204
+ for (const majorConstraint of detectionMajorConstraints) {
205
+ console.log(` - ${majorConstraint}`);
206
+ }
207
+
146
208
  const selectedSkillDomainNames = inferSkillDomainNamesFromSelection(
147
209
  selectedStackFileName,
148
210
  selectedBlueprintFileName,
@@ -249,6 +311,7 @@ export async function runUpgradeCommand(targetDirectoryArgument, upgradeOptions
249
311
  compatibilityWarnings,
250
312
  runtimeEnvironment: existingOnboardingReport?.runtimeEnvironment || null,
251
313
  operationMode: 'upgrade',
314
+ detectionTransparency,
252
315
  });
253
316
 
254
317
  console.log('\nUpgrade complete.');
@@ -56,6 +56,7 @@ export async function writeOnboardingReport({
56
56
  tokenOptimization = undefined,
57
57
  memoryContinuity = undefined,
58
58
  architectRecommendation = null,
59
+ detectionTransparency = null,
59
60
  }) {
60
61
  const onboardingReportPath = path.join(targetDirectoryPath, '.agent-context', 'state', 'onboarding-report.json');
61
62
  const resolvedTokenOptimization = typeof tokenOptimization === 'undefined'
@@ -110,6 +111,7 @@ export async function writeOnboardingReport({
110
111
  detectionReasoning: projectDetection.detectionReasoning,
111
112
  rankedCandidates: projectDetection.rankedCandidates,
112
113
  evidence: projectDetection.evidence,
114
+ detectionTransparency: detectionTransparency || null,
113
115
  },
114
116
  };
115
117
 
package/lib/cli/utils.mjs CHANGED
@@ -29,7 +29,7 @@ export function printUsage() {
29
29
  console.log('');
30
30
  console.log('Usage:');
31
31
  console.log(' agentic-senior-core launch');
32
- console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--project-description <text>] [--architect-token-budget <number>] [--architect-timeout-ms <number>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>] [--memory-continuity] [--no-memory-continuity] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>] [--runtime-env <auto|linux-wsl|linux|windows|macos>]');
32
+ console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--project-description <text>] [--architect-token-budget <number>] [--architect-timeout-ms <number>] [--architect-research-mode <snapshot|realtime>] [--enable-realtime-research] [--architect-realtime-signal-file <path>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>] [--memory-continuity] [--no-memory-continuity] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>] [--runtime-env <auto|linux-wsl|linux|windows|macos>]');
33
33
  console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes] [--mcp-template]');
34
34
  console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
35
35
  console.log(' agentic-senior-core mcp');
@@ -49,6 +49,9 @@ export function printUsage() {
49
49
  console.log(' --project-description Architecture intent text used for stack/blueprint recommendation');
50
50
  console.log(' --architect-token-budget Max token estimate used by recommendation research (default: 900)');
51
51
  console.log(' --architect-timeout-ms Max recommendation research time in milliseconds (default: 1500)');
52
+ console.log(' --architect-research-mode Recommendation evidence mode (snapshot or realtime; default: snapshot)');
53
+ console.log(' --enable-realtime-research Explicit gate to allow trusted realtime evidence ingestion');
54
+ console.log(' --architect-realtime-signal-file Optional JSON payload path for trusted realtime stack/design signals');
52
55
  console.log(' --ci Override CI/CD quality checks (guardrails) (true|false)');
53
56
  console.log(' --token-optimize Explicitly enable token optimization policy during init (default behavior)');
54
57
  console.log(' --token-agent Set token optimization agent target (copilot, claude, cursor, windsurf, gemini, codex, cline)');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "2.5.18",
3
+ "version": "2.5.20",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -155,6 +155,54 @@ const REQUIRED_COMPLIANCE_CANONICAL_SNIPPETS = [
155
155
  label: 'release operations checklist keeps canonical term Federated Governance',
156
156
  },
157
157
  ];
158
+ const REQUIRED_DETECTION_TRANSPARENCY_SNIPPETS = [
159
+ {
160
+ path: 'lib/cli/commands/init.mjs',
161
+ snippets: [
162
+ 'Existing project detection transparency:',
163
+ 'Use detected setup for this existing project?',
164
+ 'detectionTransparency',
165
+ ],
166
+ },
167
+ {
168
+ path: 'lib/cli/commands/upgrade.mjs',
169
+ snippets: [
170
+ 'Existing project detection transparency:',
171
+ 'formatDetectionCandidates(projectDetection.rankedCandidates)',
172
+ 'detectionTransparency',
173
+ ],
174
+ },
175
+ {
176
+ path: 'lib/cli/compiler.mjs',
177
+ snippets: [
178
+ 'detectionTransparency = null',
179
+ 'detectionTransparency: detectionTransparency || null',
180
+ ],
181
+ },
182
+ ];
183
+ const REQUIRED_STACK_RESEARCH_ENGINE_SNIPPETS = [
184
+ {
185
+ path: 'lib/cli/architect.mjs',
186
+ snippets: [
187
+ 'ARCHITECT_RESEARCH_SNAPSHOT_FILE_PATH',
188
+ 'evidenceCitations',
189
+ 'designGuidance',
190
+ 'copiedExternalProse: false',
191
+ 'realtimeGateEnabled',
192
+ 'requestedMode: requestedResearchMode',
193
+ ],
194
+ },
195
+ {
196
+ path: 'lib/cli/commands/init.mjs',
197
+ snippets: [
198
+ '--architect-research-mode',
199
+ '--enable-realtime-research',
200
+ '--architect-realtime-signal-file',
201
+ 'researchMode: initOptions.architectResearchMode',
202
+ 'enableRealtimeResearch: initOptions.enableRealtimeResearch',
203
+ ],
204
+ },
205
+ ];
158
206
 
159
207
  const validationResult = {
160
208
  passed: 0,
@@ -275,6 +323,7 @@ async function validateRequiredFiles() {
275
323
  '.agent-context/state/benchmark-reproducibility.json',
276
324
  '.agent-context/state/benchmark-writer-judge-config.json',
277
325
  '.agent-context/state/benchmark-watchlist.json',
326
+ '.agent-context/state/stack-research-snapshot.json',
278
327
  '.agent-context/state/memory-schema-v1.json',
279
328
  '.agent-context/state/memory-adapter-contract.json',
280
329
  '.agent-context/state/skill-platform.json',
@@ -928,6 +977,115 @@ async function validateTerminologyMapping() {
928
977
  }
929
978
  }
930
979
 
980
+ async function validateDetectionTransparencyCoverage() {
981
+ console.log('\nChecking existing-project detection transparency coverage...');
982
+
983
+ for (const transparencyRule of REQUIRED_DETECTION_TRANSPARENCY_SNIPPETS) {
984
+ const absoluteTransparencyPath = join(ROOT_DIR, transparencyRule.path);
985
+
986
+ if (!(await fileExists(absoluteTransparencyPath))) {
987
+ fail(`Missing detection transparency source: ${transparencyRule.path}`);
988
+ continue;
989
+ }
990
+
991
+ const transparencyContent = await readTextFile(absoluteTransparencyPath);
992
+ for (const requiredSnippet of transparencyRule.snippets) {
993
+ if (transparencyContent.includes(requiredSnippet)) {
994
+ pass(`${transparencyRule.path} includes detection transparency snippet: ${requiredSnippet}`);
995
+ } else {
996
+ fail(`${transparencyRule.path} is missing detection transparency snippet: ${requiredSnippet}`);
997
+ }
998
+ }
999
+ }
1000
+ }
1001
+
1002
+ async function validateStackResearchEngineCoverage() {
1003
+ console.log('\nChecking stack research engine coverage...');
1004
+
1005
+ for (const coverageRule of REQUIRED_STACK_RESEARCH_ENGINE_SNIPPETS) {
1006
+ const absoluteCoveragePath = join(ROOT_DIR, coverageRule.path);
1007
+
1008
+ if (!(await fileExists(absoluteCoveragePath))) {
1009
+ fail(`Missing stack research source: ${coverageRule.path}`);
1010
+ continue;
1011
+ }
1012
+
1013
+ const coverageContent = await readTextFile(absoluteCoveragePath);
1014
+ for (const requiredSnippet of coverageRule.snippets) {
1015
+ if (coverageContent.includes(requiredSnippet)) {
1016
+ pass(`${coverageRule.path} includes stack research snippet: ${requiredSnippet}`);
1017
+ } else {
1018
+ fail(`${coverageRule.path} is missing stack research snippet: ${requiredSnippet}`);
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+
1024
+ function isNormalizedMetricValue(value) {
1025
+ return Number.isFinite(Number(value)) && Number(value) >= 0 && Number(value) <= 1;
1026
+ }
1027
+
1028
+ async function validateStackResearchSnapshotState() {
1029
+ console.log('\nChecking deterministic stack research snapshot state...');
1030
+
1031
+ const snapshotPath = join(ROOT_DIR, '.agent-context', 'state', 'stack-research-snapshot.json');
1032
+ if (!(await fileExists(snapshotPath))) {
1033
+ fail('Missing deterministic stack research snapshot: .agent-context/state/stack-research-snapshot.json');
1034
+ return;
1035
+ }
1036
+
1037
+ let snapshotPayload;
1038
+ try {
1039
+ snapshotPayload = JSON.parse(await readTextFile(snapshotPath));
1040
+ } catch {
1041
+ fail('Invalid JSON in .agent-context/state/stack-research-snapshot.json');
1042
+ return;
1043
+ }
1044
+
1045
+ if (snapshotPayload?.deterministic === true) {
1046
+ pass('stack-research-snapshot.json declares deterministic: true');
1047
+ } else {
1048
+ fail('stack-research-snapshot.json must declare deterministic: true');
1049
+ }
1050
+
1051
+ const generatedAtValue = String(snapshotPayload?.generatedAt || '');
1052
+ if (!Number.isNaN(Date.parse(generatedAtValue))) {
1053
+ pass('stack-research-snapshot.json includes valid generatedAt timestamp');
1054
+ } else {
1055
+ fail('stack-research-snapshot.json must include a valid generatedAt timestamp');
1056
+ }
1057
+
1058
+ if (Array.isArray(snapshotPayload?.trustedRealtimeSources) && snapshotPayload.trustedRealtimeSources.length > 0) {
1059
+ pass('stack-research-snapshot.json includes trustedRealtimeSources');
1060
+ } else {
1061
+ fail('stack-research-snapshot.json must include at least one trustedRealtimeSources entry');
1062
+ }
1063
+
1064
+ if (!Array.isArray(snapshotPayload?.stackSignals) || snapshotPayload.stackSignals.length === 0) {
1065
+ fail('stack-research-snapshot.json must include non-empty stackSignals array');
1066
+ return;
1067
+ }
1068
+
1069
+ pass(`stack-research-snapshot.json includes ${snapshotPayload.stackSignals.length} stack signal entries`);
1070
+
1071
+ const invalidSignalEntries = snapshotPayload.stackSignals.filter((signalEntry) => {
1072
+ const hasStackName = typeof signalEntry?.stackFileName === 'string' && signalEntry.stackFileName.trim().length > 0;
1073
+ const hasMeasuredAt = !Number.isNaN(Date.parse(String(signalEntry?.measuredAt || '')));
1074
+ const metrics = signalEntry?.metrics || {};
1075
+ const hasValidMetrics = isNormalizedMetricValue(metrics.ecosystemMaturity)
1076
+ && isNormalizedMetricValue(metrics.talentAvailability)
1077
+ && isNormalizedMetricValue(metrics.deliveryVelocity);
1078
+
1079
+ return !(hasStackName && hasMeasuredAt && hasValidMetrics);
1080
+ });
1081
+
1082
+ if (invalidSignalEntries.length === 0) {
1083
+ pass('stack-research-snapshot.json stackSignals keep measurable metrics and timestamps');
1084
+ } else {
1085
+ fail(`stack-research-snapshot.json has invalid stackSignals entries: ${invalidSignalEntries.length}`);
1086
+ }
1087
+ }
1088
+
931
1089
  async function validateMcpConfiguration() {
932
1090
  console.log('\nChecking MCP configuration...');
933
1091
 
@@ -1177,6 +1335,9 @@ async function main() {
1177
1335
  await validateVersionConsistency();
1178
1336
  await validateDocumentationFlow();
1179
1337
  await validateTerminologyMapping();
1338
+ await validateDetectionTransparencyCoverage();
1339
+ await validateStackResearchEngineCoverage();
1340
+ await validateStackResearchSnapshotState();
1180
1341
  await validateMcpConfiguration();
1181
1342
  await validateHumanWritingGovernance();
1182
1343
  await validateInstructionAdapters();