@ryuenn3123/agentic-senior-core 2.0.24 → 2.0.26

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.
@@ -43,55 +43,77 @@ export function formatSkillTierList(skillPlatformIndex) {
43
43
  return skillPlatformIndex.tiers.map((tierDefinition) => `${tierDefinition.name} (${tierDefinition.description})`).join('\n');
44
44
  }
45
45
 
46
- export function inferSkillDomainNamesFromSelection(selectedStackFileName, selectedBlueprintFileName) {
46
+ export function inferSkillDomainNamesFromSelection(
47
+ selectedStackFileName,
48
+ selectedBlueprintFileName,
49
+ additionalStackFileNames = [],
50
+ additionalBlueprintFileNames = []
51
+ ) {
47
52
  const inferredDomainNames = new Set();
48
53
 
49
- if (selectedBlueprintFileName === 'api-nextjs.md' || selectedBlueprintFileName === 'fastapi-service.md') {
50
- inferredDomainNames.add('frontend');
51
- inferredDomainNames.add('fullstack');
52
- inferredDomainNames.add('cli');
53
- }
54
+ function applyStackSignals(stackFileName) {
55
+ if (stackFileName === 'typescript.md') {
56
+ inferredDomainNames.add('frontend');
57
+ inferredDomainNames.add('cli');
58
+ }
54
59
 
55
- if (selectedBlueprintFileName === 'go-service.md'
56
- || selectedBlueprintFileName === 'spring-boot-api.md'
57
- || selectedBlueprintFileName === 'laravel-api.md'
58
- || selectedBlueprintFileName === 'aspnet-api.md') {
59
- inferredDomainNames.add('backend');
60
- inferredDomainNames.add('fullstack');
61
- inferredDomainNames.add('cli');
62
- }
60
+ if (stackFileName === 'go.md'
61
+ || stackFileName === 'java.md'
62
+ || stackFileName === 'php.md'
63
+ || stackFileName === 'csharp.md'
64
+ || stackFileName === 'python.md'
65
+ || stackFileName === 'ruby.md'
66
+ || stackFileName === 'rust.md') {
67
+ inferredDomainNames.add('backend');
68
+ }
63
69
 
64
- if (selectedStackFileName === 'typescript.md') {
65
- inferredDomainNames.add('frontend');
66
- inferredDomainNames.add('cli');
70
+ if (stackFileName === 'react-native.md' || stackFileName === 'flutter.md') {
71
+ inferredDomainNames.add('frontend');
72
+ inferredDomainNames.add('fullstack');
73
+ inferredDomainNames.add('cli');
74
+ }
67
75
  }
68
76
 
69
- if (selectedStackFileName === 'go.md'
70
- || selectedStackFileName === 'java.md'
71
- || selectedStackFileName === 'php.md'
72
- || selectedStackFileName === 'csharp.md'
73
- || selectedStackFileName === 'python.md'
74
- || selectedStackFileName === 'ruby.md'
75
- || selectedStackFileName === 'rust.md') {
76
- inferredDomainNames.add('backend');
77
- }
77
+ function applyBlueprintSignals(blueprintFileName) {
78
+ if (blueprintFileName === 'api-nextjs.md' || blueprintFileName === 'fastapi-service.md') {
79
+ inferredDomainNames.add('frontend');
80
+ inferredDomainNames.add('fullstack');
81
+ inferredDomainNames.add('cli');
82
+ }
78
83
 
79
- if (selectedStackFileName === 'react-native.md' || selectedStackFileName === 'flutter.md') {
80
- inferredDomainNames.add('frontend');
81
- inferredDomainNames.add('fullstack');
82
- inferredDomainNames.add('cli');
84
+ if (blueprintFileName === 'go-service.md'
85
+ || blueprintFileName === 'spring-boot-api.md'
86
+ || blueprintFileName === 'laravel-api.md'
87
+ || blueprintFileName === 'aspnet-api.md'
88
+ || blueprintFileName === 'nestjs-logic.md'
89
+ || blueprintFileName === 'graphql-grpc-api.md') {
90
+ inferredDomainNames.add('backend');
91
+ inferredDomainNames.add('fullstack');
92
+ inferredDomainNames.add('cli');
93
+ }
94
+
95
+ if (blueprintFileName === 'mobile-app.md') {
96
+ inferredDomainNames.add('frontend');
97
+ inferredDomainNames.add('fullstack');
98
+ inferredDomainNames.add('cli');
99
+ }
100
+
101
+ if (blueprintFileName === 'observability.md') {
102
+ inferredDomainNames.add('backend');
103
+ inferredDomainNames.add('fullstack');
104
+ inferredDomainNames.add('cli');
105
+ }
83
106
  }
84
107
 
85
- if (selectedBlueprintFileName === 'mobile-app.md') {
86
- inferredDomainNames.add('frontend');
87
- inferredDomainNames.add('fullstack');
88
- inferredDomainNames.add('cli');
108
+ applyBlueprintSignals(selectedBlueprintFileName);
109
+
110
+ applyStackSignals(selectedStackFileName);
111
+ for (const additionalStackFileName of additionalStackFileNames) {
112
+ applyStackSignals(additionalStackFileName);
89
113
  }
90
114
 
91
- if (selectedBlueprintFileName === 'observability.md') {
92
- inferredDomainNames.add('backend');
93
- inferredDomainNames.add('fullstack');
94
- inferredDomainNames.add('cli');
115
+ for (const additionalBlueprintFileName of additionalBlueprintFileNames) {
116
+ applyBlueprintSignals(additionalBlueprintFileName);
95
117
  }
96
118
 
97
119
  if (inferredDomainNames.size === 0) {
@@ -18,9 +18,23 @@ This project requires a {{primaryDomain}} solution. The team evaluated available
18
18
  ### Decision
19
19
 
20
20
  - **Language/Runtime**: {{stackDisplayName}} (source: `.agent-context/stacks/{{stackFileName}}`)
21
+ {{#if additionalStackDisplayNames}}
22
+ - **Additional runtime context**:
23
+ {{#each additionalStackDisplayNames}}
24
+ - {{this}}
25
+ {{/each}}
26
+ {{/if}}
21
27
  - **Architecture blueprint**: {{blueprintDisplayName}} (source: `.agent-context/blueprints/{{blueprintFileName}}`)
28
+ {{#if additionalBlueprintDisplayNames}}
29
+ - **Additional architecture blueprints**:
30
+ {{#each additionalBlueprintDisplayNames}}
31
+ - {{this}}
32
+ {{/each}}
33
+ {{/if}}
22
34
  - **Database**: {{databaseChoice}}
23
35
  - **Auth**: {{authStrategy}}
36
+ - **Runtime environment target**: {{runtimeEnvironmentLabel}}
37
+ - **Containerization strategy**: {{dockerStrategy}}
24
38
 
25
39
  ### Rationale
26
40
 
@@ -36,6 +50,31 @@ The {{stackDisplayName}} stack was selected because:
36
50
  - Database access must follow `.agent-context/rules/database-design.md`.
37
51
  - API contracts must follow `.agent-context/rules/api-docs.md`.
38
52
 
53
+ {{#if hasDocker}}
54
+ ---
55
+
56
+ ## ADR-004: Containerization Strategy (Dynamic)
57
+
58
+ **Status**: Accepted
59
+ **Date**: {{generatedDate}}
60
+
61
+ ### Context
62
+
63
+ This project requires container support with separated development and production concerns.
64
+
65
+ ### Decision
66
+
67
+ - Follow dynamic container generation based on real project dependencies and runtime profile.
68
+ - Do not rely on static Docker templates copied from unrelated repositories.
69
+ {{dockerDevelopmentGuidance}}
70
+ {{dockerProductionGuidance}}
71
+
72
+ ### Consequences
73
+
74
+ - Development and production Docker artifacts are treated as separate deliverables.
75
+ - Changes in package/runtime dependencies must regenerate container setup instructions in the same change.
76
+ {{/if}}
77
+
39
78
  ---
40
79
 
41
80
  ## ADR-002: Architecture Pattern
@@ -12,6 +12,18 @@ Template version: {{templateVersion}}
12
12
  **Domain**: {{primaryDomain}}
13
13
  **Stack**: {{stackDisplayName}}
14
14
  **Blueprint**: {{blueprintDisplayName}}
15
+ **Runtime target**: {{runtimeEnvironmentLabel}}
16
+ **Containerization**: {{dockerStrategy}}
17
+
18
+ {{#if hasDocker}}
19
+ ## Container Flow (Dynamic Dev and Prod)
20
+
21
+ - Container setup is generated dynamically by AI from current dependencies, not from static canned templates.
22
+ {{dockerDevelopmentGuidance}}
23
+ {{dockerProductionGuidance}}
24
+ - Keep dev and prod container concerns explicitly separated.
25
+
26
+ {{/if}}
15
27
 
16
28
  ## High-Level Architecture
17
29
 
@@ -18,6 +18,8 @@ Versi template: {{templateVersion}}
18
18
  **Blueprint**: {{blueprintDisplayName}}
19
19
  **Database**: {{databaseChoice}}
20
20
  **Strategi autentikasi**: {{authStrategy}}
21
+ **Target environment runtime**: {{runtimeEnvironmentLabel}}
22
+ **Strategi containerisasi**: {{dockerStrategy}}
21
23
 
22
24
  ## Fitur Kunci
23
25
 
@@ -15,9 +15,35 @@ Template version: {{templateVersion}}
15
15
  ## Technology Decisions
16
16
 
17
17
  **Stack**: {{stackDisplayName}}
18
+ {{#if additionalStackDisplayNames}}
19
+ **Additional stacks**:
20
+ {{#each additionalStackDisplayNames}}
21
+ - {{this}}
22
+ {{/each}}
23
+ {{/if}}
18
24
  **Blueprint**: {{blueprintDisplayName}}
25
+ {{#if additionalBlueprintDisplayNames}}
26
+ **Additional blueprints**:
27
+ {{#each additionalBlueprintDisplayNames}}
28
+ - {{this}}
29
+ {{/each}}
30
+ {{/if}}
19
31
  **Database**: {{databaseChoice}}
20
32
  **Auth strategy**: {{authStrategy}}
33
+ **Runtime environment target**: {{runtimeEnvironmentLabel}}
34
+ **Containerization strategy**: {{dockerStrategy}}
35
+
36
+ {{#if hasDocker}}
37
+ ## Containerization Workflow (Dynamic)
38
+
39
+ - Docker is enabled for this project: **{{dockerStrategy}}**.
40
+ - Docker setup must be generated dynamically by AI based on current dependencies and runtime constraints.
41
+ - Do not use fixed boilerplate templates that ignore actual project structure.
42
+ {{dockerDevelopmentGuidance}}
43
+ {{dockerProductionGuidance}}
44
+
45
+ - Keep development and production container strategy separated to avoid environment drift.
46
+ {{/if}}
21
47
 
22
48
  ## Key Features
23
49
 
package/lib/cli/utils.mjs CHANGED
@@ -28,7 +28,7 @@ export function printUsage() {
28
28
  console.log('');
29
29
  console.log('Usage:');
30
30
  console.log(' agentic-senior-core launch');
31
- console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>]');
31
+ console.log(' agentic-senior-core init [target-directory] [--preset <name>] [--profile <beginner|balanced|strict>] [--profile-pack <name>] [--stack <name>] [--blueprint <name>] [--ci <true|false>] [--newbie] [--token-optimize] [--no-token-optimize] [--token-agent <name>] [--scaffold-docs] [--no-scaffold-docs] [--docs-lang <en|id>] [--project-config <path>] [--runtime-env <auto|linux-wsl|linux|windows|macos>]');
32
32
  console.log(' agentic-senior-core upgrade [target-directory] [--dry-run] [--yes] [--mcp-template]');
33
33
  console.log(' agentic-senior-core optimize [target-directory] [--agent <copilot|claude|cursor|windsurf|gemini|codex|cline>] [--enable|--disable] [--show]');
34
34
  console.log(' agentic-senior-core mcp');
@@ -54,6 +54,7 @@ export function printUsage() {
54
54
  console.log(' --no-scaffold-docs Skip project documentation scaffolding');
55
55
  console.log(' --docs-lang Optional override for generated project docs language (default: en)');
56
56
  console.log(' --project-config Path to a project config file for non-interactive doc scaffolding');
57
+ console.log(' --runtime-env Override runtime environment hint (auto, linux-wsl, linux, windows, macos)');
57
58
  console.log(' --dry-run Preview upgrade without writing files');
58
59
  console.log(' --yes Skip confirmation prompts for upgrade');
59
60
  console.log(' --agent Target agent integration for token optimization mode');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "2.0.24",
3
+ "version": "2.0.26",
4
4
  "type": "module",
5
5
  "description": "Force your AI Agent to code like a Staff Engineer, not a Junior.",
6
6
  "bin": {
@@ -21,6 +21,7 @@ const REQUIRED_FILES = [
21
21
  'docs/v1.7-issue-breakdown.md',
22
22
  'docs/v1.7-execution-playbook.md',
23
23
  '.agent-context/review-checklists/frontend-usability.md',
24
+ '.agent-context/review-checklists/frontend-excellence-rubric.md',
24
25
  ];
25
26
 
26
27
  const REQUIRED_ROADMAP_SNIPPETS = [
@@ -37,6 +38,14 @@ const REQUIRED_CHECKLIST_SNIPPETS = [
37
38
  'Documentation and Release Evidence',
38
39
  ];
39
40
 
41
+ const REQUIRED_EXCELLENCE_RUBRIC_SNIPPETS = [
42
+ 'Visual Direction and Identity',
43
+ 'Typography Quality',
44
+ 'Color System Diversity and Contrast',
45
+ 'Interaction Choreography',
46
+ 'Awwwards-level reference quality',
47
+ ];
48
+
40
49
  function assertFileExists(relativeFilePath, failures) {
41
50
  const absoluteFilePath = resolve(REPOSITORY_ROOT, relativeFilePath);
42
51
  if (!existsSync(absoluteFilePath)) {
@@ -61,6 +70,7 @@ function runAudit() {
61
70
 
62
71
  const roadmapPath = 'docs/roadmap.md';
63
72
  const checklistPath = '.agent-context/review-checklists/frontend-usability.md';
73
+ const excellenceRubricPath = '.agent-context/review-checklists/frontend-excellence-rubric.md';
64
74
 
65
75
  if (existsSync(resolve(REPOSITORY_ROOT, roadmapPath))) {
66
76
  const roadmapContent = readFileSync(resolve(REPOSITORY_ROOT, roadmapPath), 'utf8');
@@ -72,6 +82,17 @@ function runAudit() {
72
82
  assertContains('Checklist', checklistPath, checklistContent, REQUIRED_CHECKLIST_SNIPPETS, failures);
73
83
  }
74
84
 
85
+ if (existsSync(resolve(REPOSITORY_ROOT, excellenceRubricPath))) {
86
+ const excellenceRubricContent = readFileSync(resolve(REPOSITORY_ROOT, excellenceRubricPath), 'utf8');
87
+ assertContains(
88
+ 'Frontend excellence rubric',
89
+ excellenceRubricPath,
90
+ excellenceRubricContent,
91
+ REQUIRED_EXCELLENCE_RUBRIC_SNIPPETS,
92
+ failures
93
+ );
94
+ }
95
+
75
96
  const reportPayload = {
76
97
  generatedAt: new Date().toISOString(),
77
98
  auditName: 'frontend-usability-audit',
@@ -28,6 +28,7 @@ const REQUIRED_SKILL_DOMAINS = [
28
28
  'review-quality',
29
29
  ];
30
30
  const FRONTEND_PARITY_CHECKLIST_PATH = '.agent-context/review-checklists/frontend-skill-parity.md';
31
+ const FRONTEND_EXCELLENCE_RUBRIC_PATH = '.agent-context/review-checklists/frontend-excellence-rubric.md';
31
32
  const FRONTEND_AUDIT_SCRIPT_PATH = 'scripts/frontend-usability-audit.mjs';
32
33
  const REQUIRED_FRONTEND_PARITY_SNIPPETS = [
33
34
  'Architecture and Composition',
@@ -36,6 +37,14 @@ const REQUIRED_FRONTEND_PARITY_SNIPPETS = [
36
37
  'UX Narrative and Conversion Clarity',
37
38
  'Release Evidence',
38
39
  ];
40
+ const REQUIRED_FRONTEND_EXCELLENCE_RUBRIC_SNIPPETS = [
41
+ 'Visual Direction and Identity',
42
+ 'Typography Quality',
43
+ 'Color System Diversity and Contrast',
44
+ 'Interaction Choreography',
45
+ 'Awwwards-level reference quality',
46
+ ];
47
+ const BENCHMARK_GATE_SCRIPT_PATH = 'scripts/benchmark-gate.mjs';
39
48
 
40
49
  function readText(relativeFilePath) {
41
50
  const absolutePath = resolve(REPOSITORY_ROOT, relativeFilePath);
@@ -54,6 +63,46 @@ function pushResult(results, isPassed, checkName, details) {
54
63
  });
55
64
  }
56
65
 
66
+ function parseMachineReadableReport(rawOutput) {
67
+ if (typeof rawOutput !== 'string' || rawOutput.trim().length === 0) {
68
+ return null;
69
+ }
70
+
71
+ try {
72
+ return JSON.parse(rawOutput);
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ function runMachineReadableScript(scriptRelativePath) {
79
+ try {
80
+ const rawOutput = execFileSync('node', [scriptRelativePath], {
81
+ cwd: REPOSITORY_ROOT,
82
+ encoding: 'utf8',
83
+ maxBuffer: 1024 * 1024,
84
+ });
85
+
86
+ return {
87
+ report: parseMachineReadableReport(rawOutput),
88
+ executionErrorMessage: null,
89
+ };
90
+ } catch (scriptExecutionError) {
91
+ const rawOutput = scriptExecutionError && typeof scriptExecutionError === 'object' && 'stdout' in scriptExecutionError
92
+ ? String(scriptExecutionError.stdout ?? '')
93
+ : '';
94
+ const parsedReport = parseMachineReadableReport(rawOutput);
95
+ const executionErrorMessage = scriptExecutionError instanceof Error
96
+ ? scriptExecutionError.message
97
+ : 'Unknown execution error';
98
+
99
+ return {
100
+ report: parsedReport,
101
+ executionErrorMessage,
102
+ };
103
+ }
104
+ }
105
+
57
106
  function validateCompatibilityManifestShape(parsedManifest, skillDomainName) {
58
107
  const validationErrors = [];
59
108
 
@@ -82,6 +131,7 @@ function validateCompatibilityManifestShape(parsedManifest, skillDomainName) {
82
131
 
83
132
  function runReleaseGate() {
84
133
  const results = [];
134
+ const diagnostics = {};
85
135
  const packageJsonPath = 'package.json';
86
136
  const changelogPath = 'CHANGELOG.md';
87
137
  const roadmapPath = 'docs/roadmap.md';
@@ -222,6 +272,28 @@ function runReleaseGate() {
222
272
  }
223
273
  }
224
274
 
275
+ const frontendExcellenceRubricContent = readText(FRONTEND_EXCELLENCE_RUBRIC_PATH);
276
+ if (!frontendExcellenceRubricContent) {
277
+ pushResult(results, false, 'frontend-excellence-rubric-exists', `Missing ${FRONTEND_EXCELLENCE_RUBRIC_PATH}`);
278
+ } else {
279
+ pushResult(results, true, 'frontend-excellence-rubric-exists', `${FRONTEND_EXCELLENCE_RUBRIC_PATH} is present`);
280
+
281
+ const missingFrontendExcellenceSnippets = REQUIRED_FRONTEND_EXCELLENCE_RUBRIC_SNIPPETS.filter(
282
+ (requiredSnippet) => !frontendExcellenceRubricContent.includes(requiredSnippet)
283
+ );
284
+
285
+ if (missingFrontendExcellenceSnippets.length === 0) {
286
+ pushResult(results, true, 'frontend-excellence-rubric-coverage', 'Frontend excellence rubric sections are complete');
287
+ } else {
288
+ pushResult(
289
+ results,
290
+ false,
291
+ 'frontend-excellence-rubric-coverage',
292
+ `Missing frontend excellence rubric sections: ${missingFrontendExcellenceSnippets.join(', ')}`
293
+ );
294
+ }
295
+ }
296
+
225
297
  try {
226
298
  const frontendAuditRawOutput = execFileSync('node', [FRONTEND_AUDIT_SCRIPT_PATH], {
227
299
  cwd: REPOSITORY_ROOT,
@@ -245,12 +317,48 @@ function runReleaseGate() {
245
317
  pushResult(results, false, 'frontend-usability-audit', `Failed to execute frontend usability audit: ${frontendAuditErrorMessage}`);
246
318
  }
247
319
 
320
+ const benchmarkGateExecution = runMachineReadableScript(BENCHMARK_GATE_SCRIPT_PATH);
321
+ if (!benchmarkGateExecution.report) {
322
+ const failureDetails = benchmarkGateExecution.executionErrorMessage
323
+ ? `Benchmark gate execution failed before producing a machine-readable report: ${benchmarkGateExecution.executionErrorMessage}`
324
+ : 'Benchmark gate did not produce machine-readable JSON output';
325
+ pushResult(results, false, 'benchmark-threshold-gate', failureDetails);
326
+ } else {
327
+ diagnostics.benchmarkGate = benchmarkGateExecution.report;
328
+ pushResult(
329
+ results,
330
+ true,
331
+ 'benchmark-threshold-gate',
332
+ `Benchmark threshold gate executed (passed=${benchmarkGateExecution.report.passed}, failures=${benchmarkGateExecution.report.failureCount})`
333
+ );
334
+
335
+ if (benchmarkGateExecution.report.passed === true) {
336
+ pushResult(results, true, 'benchmark-regression-block', 'Benchmark thresholds are healthy; release remains eligible');
337
+ } else {
338
+ const failedBenchmarkChecks = Array.isArray(benchmarkGateExecution.report.results)
339
+ ? benchmarkGateExecution.report.results
340
+ .filter((benchmarkCheckResult) => !benchmarkCheckResult.passed)
341
+ .map((benchmarkCheckResult) => `${benchmarkCheckResult.checkName}: ${benchmarkCheckResult.details}`)
342
+ : [];
343
+ const failureSummary = failedBenchmarkChecks.length > 0
344
+ ? failedBenchmarkChecks.join('; ')
345
+ : 'Benchmark gate failed but did not report individual failed checks';
346
+ pushResult(
347
+ results,
348
+ false,
349
+ 'benchmark-regression-block',
350
+ `Benchmark threshold regression detected. ${failureSummary}`
351
+ );
352
+ }
353
+ }
354
+
248
355
  const failureCount = results.filter((checkResult) => !checkResult.passed).length;
249
356
  const releaseGateReport = {
250
357
  generatedAt: new Date().toISOString(),
251
358
  gateName: 'release-gate',
252
359
  passed: failureCount === 0,
253
360
  failureCount,
361
+ diagnostics,
254
362
  results,
255
363
  };
256
364
 
@@ -258,6 +258,7 @@ async function validateRuleFiles() {
258
258
  'rules/database-design.md',
259
259
  'rules/realtime.md',
260
260
  'rules/frontend-architecture.md',
261
+ 'rules/docker-runtime.md',
261
262
  'stacks/typescript.md',
262
263
  'stacks/python.md',
263
264
  'stacks/java.md',
@@ -285,6 +286,7 @@ async function validateRuleFiles() {
285
286
  'review-checklists/pr-checklist.md',
286
287
  'review-checklists/frontend-usability.md',
287
288
  'review-checklists/frontend-skill-parity.md',
289
+ 'review-checklists/frontend-excellence-rubric.md',
288
290
  'review-checklists/release-operations.md',
289
291
  'review-checklists/security-audit.md',
290
292
  'review-checklists/performance-audit.md',