@ryuenn3123/agentic-senior-core 3.0.11 → 3.0.13

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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readFileSync } from 'node:fs';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
4
  import { mkdir, readFile, writeFile } from 'node:fs/promises';
5
5
  import { spawn } from 'node:child_process';
6
6
  import { dirname, resolve, sep } from 'node:path';
@@ -8,9 +8,6 @@ import { fileURLToPath } from 'node:url';
8
8
 
9
9
  const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
10
10
  const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
11
- const PACKAGE_VERSION = JSON.parse(
12
- readFileSync(resolve(REPOSITORY_ROOT, 'package.json'), 'utf8')
13
- ).version;
14
11
  const STATE_DIRECTORY = resolve(REPOSITORY_ROOT, '.agent-context', 'state');
15
12
  const DEFAULT_PROTOCOL_VERSION = '2024-11-05';
16
13
  const DEFAULT_FETCH_TIMEOUT_MS = 15000;
@@ -18,6 +15,24 @@ const DEFAULT_FETCH_MAX_CHARS = 6000;
18
15
  const MAX_FETCH_MAX_CHARS = 20000;
19
16
  const DEFAULT_TREND_WINDOW_DAYS = 90;
20
17
  const MAX_TREND_PACKAGES = 10;
18
+ const FALLBACK_PACKAGE_VERSION = '0.0.0-local';
19
+
20
+ function resolvePackageVersion() {
21
+ try {
22
+ const parsedPackageManifest = JSON.parse(
23
+ readFileSync(resolve(REPOSITORY_ROOT, 'package.json'), 'utf8')
24
+ );
25
+ const rawVersion = typeof parsedPackageManifest?.version === 'string'
26
+ ? parsedPackageManifest.version.trim()
27
+ : '';
28
+
29
+ return rawVersion || FALLBACK_PACKAGE_VERSION;
30
+ } catch {
31
+ return FALLBACK_PACKAGE_VERSION;
32
+ }
33
+ }
34
+
35
+ const PACKAGE_VERSION = resolvePackageVersion();
21
36
 
22
37
  const TEST_SUITE_ARGS = {
23
38
  full: ['--test', './tests/cli-smoke.test.mjs', './tests/mcp-server.test.mjs', './tests/llm-judge.test.mjs', './tests/enterprise-ops.test.mjs'],
@@ -26,132 +41,172 @@ const TEST_SUITE_ARGS = {
26
41
  'llm-judge': ['--test', './tests/llm-judge.test.mjs'],
27
42
  };
28
43
 
29
- const TOOL_DEFINITIONS = [
30
- {
31
- name: 'validate',
32
- description: 'Run repository validation checks.',
33
- inputSchema: {
34
- type: 'object',
35
- properties: {},
36
- additionalProperties: false,
37
- },
38
- },
39
- {
40
- name: 'test',
41
- description: 'Run test suites (full or targeted).',
42
- inputSchema: {
43
- type: 'object',
44
- properties: {
45
- suite: {
46
- type: 'string',
47
- enum: ['full', 'cli', 'enterprise', 'llm-judge'],
48
- description: 'Target test suite. Defaults to full.',
49
- },
44
+ const INTERNAL_SCRIPT_PATHS = {
45
+ validate: resolve(REPOSITORY_ROOT, 'scripts', 'validate.mjs'),
46
+ release_gate: resolve(REPOSITORY_ROOT, 'scripts', 'release-gate.mjs'),
47
+ forbidden_content_check: resolve(REPOSITORY_ROOT, 'scripts', 'forbidden-content-check.mjs'),
48
+ };
49
+
50
+ function getAvailableTestSuites() {
51
+ return Object.entries(TEST_SUITE_ARGS)
52
+ .filter(([, commandArguments]) => (
53
+ Array.isArray(commandArguments)
54
+ && commandArguments.length > 1
55
+ && commandArguments
56
+ .slice(1)
57
+ .every((relativeTestPath) => existsSync(resolve(REPOSITORY_ROOT, relativeTestPath)))
58
+ ))
59
+ .map(([suiteName]) => suiteName);
60
+ }
61
+
62
+ const AVAILABLE_TEST_SUITES = getAvailableTestSuites();
63
+
64
+ function buildToolDefinitions() {
65
+ const toolDefinitions = [];
66
+
67
+ if (existsSync(INTERNAL_SCRIPT_PATHS.validate)) {
68
+ toolDefinitions.push({
69
+ name: 'validate',
70
+ description: 'Run repository validation checks.',
71
+ inputSchema: {
72
+ type: 'object',
73
+ properties: {},
74
+ additionalProperties: false,
50
75
  },
51
- additionalProperties: false,
52
- },
53
- },
54
- {
55
- name: 'release_gate',
56
- description: 'Run release gate checks.',
57
- inputSchema: {
58
- type: 'object',
59
- properties: {},
60
- additionalProperties: false,
61
- },
62
- },
63
- {
64
- name: 'forbidden_content_check',
65
- description: 'Run forbidden content scan used by publish gate.',
66
- inputSchema: {
67
- type: 'object',
68
- properties: {},
69
- additionalProperties: false,
70
- },
71
- },
72
- {
73
- name: 'research_fetch',
74
- description: 'Fetch external documentation/news content and return query-focused excerpts with citation metadata.',
75
- inputSchema: {
76
- type: 'object',
77
- properties: {
78
- url: {
79
- type: 'string',
80
- description: 'Absolute HTTP/HTTPS URL to fetch.',
81
- },
82
- query: {
83
- type: 'string',
84
- description: 'Optional search query used to extract focused excerpts.',
76
+ });
77
+ }
78
+
79
+ if (AVAILABLE_TEST_SUITES.length > 0) {
80
+ toolDefinitions.push({
81
+ name: 'test',
82
+ description: 'Run test suites (full or targeted).',
83
+ inputSchema: {
84
+ type: 'object',
85
+ properties: {
86
+ suite: {
87
+ type: 'string',
88
+ enum: AVAILABLE_TEST_SUITES,
89
+ description: 'Target test suite. Defaults to the first available suite.',
90
+ },
85
91
  },
86
- maxChars: {
87
- type: 'integer',
88
- description: 'Maximum characters to return when query is not provided (default 6000, max 20000).',
92
+ additionalProperties: false,
93
+ },
94
+ });
95
+ }
96
+
97
+ if (existsSync(INTERNAL_SCRIPT_PATHS.release_gate)) {
98
+ toolDefinitions.push({
99
+ name: 'release_gate',
100
+ description: 'Run release gate checks.',
101
+ inputSchema: {
102
+ type: 'object',
103
+ properties: {},
104
+ additionalProperties: false,
105
+ },
106
+ });
107
+ }
108
+
109
+ if (existsSync(INTERNAL_SCRIPT_PATHS.forbidden_content_check)) {
110
+ toolDefinitions.push({
111
+ name: 'forbidden_content_check',
112
+ description: 'Run forbidden content scan used by publish gate.',
113
+ inputSchema: {
114
+ type: 'object',
115
+ properties: {},
116
+ additionalProperties: false,
117
+ },
118
+ });
119
+ }
120
+
121
+ toolDefinitions.push(
122
+ {
123
+ name: 'research_fetch',
124
+ description: 'Fetch external documentation/news content and return query-focused excerpts with citation metadata.',
125
+ inputSchema: {
126
+ type: 'object',
127
+ properties: {
128
+ url: {
129
+ type: 'string',
130
+ description: 'Absolute HTTP/HTTPS URL to fetch.',
131
+ },
132
+ query: {
133
+ type: 'string',
134
+ description: 'Optional search query used to extract focused excerpts.',
135
+ },
136
+ maxChars: {
137
+ type: 'integer',
138
+ description: 'Maximum characters to return when query is not provided (default 6000, max 20000).',
139
+ },
89
140
  },
141
+ required: ['url'],
142
+ additionalProperties: false,
90
143
  },
91
- required: ['url'],
92
- additionalProperties: false,
93
144
  },
94
- },
95
- {
96
- name: 'trend_snapshot',
97
- description: 'Generate ecosystem trend snapshot from npm registry metadata with source timestamps.',
98
- inputSchema: {
99
- type: 'object',
100
- properties: {
101
- packages: {
102
- type: 'array',
103
- items: { type: 'string' },
104
- description: 'Package names to inspect (max 10).',
105
- },
106
- windowDays: {
107
- type: 'integer',
108
- description: 'Release activity window in days (default 90).',
145
+ {
146
+ name: 'trend_snapshot',
147
+ description: 'Generate ecosystem trend snapshot from npm registry metadata with source timestamps.',
148
+ inputSchema: {
149
+ type: 'object',
150
+ properties: {
151
+ packages: {
152
+ type: 'array',
153
+ items: { type: 'string' },
154
+ description: 'Package names to inspect (max 10).',
155
+ },
156
+ windowDays: {
157
+ type: 'integer',
158
+ description: 'Release activity window in days (default 90).',
159
+ },
109
160
  },
161
+ required: ['packages'],
162
+ additionalProperties: false,
110
163
  },
111
- required: ['packages'],
112
- additionalProperties: false,
113
164
  },
114
- },
115
- {
116
- name: 'state_read',
117
- description: 'Read a file from .agent-context/state for cross-session continuity.',
118
- inputSchema: {
119
- type: 'object',
120
- properties: {
121
- path: {
122
- type: 'string',
123
- description: 'Path relative to .agent-context/state (for example memory-continuity-benchmark.json).',
165
+ {
166
+ name: 'state_read',
167
+ description: 'Read a file from .agent-context/state for cross-session continuity.',
168
+ inputSchema: {
169
+ type: 'object',
170
+ properties: {
171
+ path: {
172
+ type: 'string',
173
+ description: 'Path relative to .agent-context/state (for example memory-continuity-benchmark.json).',
174
+ },
124
175
  },
176
+ required: ['path'],
177
+ additionalProperties: false,
125
178
  },
126
- required: ['path'],
127
- additionalProperties: false,
128
179
  },
129
- },
130
- {
131
- name: 'state_write',
132
- description: 'Write a file under .agent-context/state for cross-session continuity updates.',
133
- inputSchema: {
134
- type: 'object',
135
- properties: {
136
- path: {
137
- type: 'string',
138
- description: 'Path relative to .agent-context/state.',
139
- },
140
- content: {
141
- type: 'string',
142
- description: 'UTF-8 content to write.',
143
- },
144
- mode: {
145
- type: 'string',
146
- enum: ['overwrite', 'append'],
147
- description: 'Write mode. Defaults to overwrite.',
180
+ {
181
+ name: 'state_write',
182
+ description: 'Write a file under .agent-context/state for cross-session continuity updates.',
183
+ inputSchema: {
184
+ type: 'object',
185
+ properties: {
186
+ path: {
187
+ type: 'string',
188
+ description: 'Path relative to .agent-context/state.',
189
+ },
190
+ content: {
191
+ type: 'string',
192
+ description: 'UTF-8 content to write.',
193
+ },
194
+ mode: {
195
+ type: 'string',
196
+ enum: ['overwrite', 'append'],
197
+ description: 'Write mode. Defaults to overwrite.',
198
+ },
148
199
  },
200
+ required: ['path', 'content'],
201
+ additionalProperties: false,
149
202
  },
150
- required: ['path', 'content'],
151
- additionalProperties: false,
152
203
  },
153
- },
154
- ];
204
+ );
205
+
206
+ return toolDefinitions;
207
+ }
208
+
209
+ const TOOL_DEFINITIONS = buildToolDefinitions();
155
210
 
156
211
  let incomingBuffer = Buffer.alloc(0);
157
212
 
@@ -539,23 +594,50 @@ function runNodeCommand(commandLabel, commandArguments) {
539
594
 
540
595
  async function executeToolCall(toolName, toolArguments = {}) {
541
596
  if (toolName === 'validate') {
597
+ if (!existsSync(INTERNAL_SCRIPT_PATHS.validate)) {
598
+ return buildJsonResult({
599
+ error: 'validate tool is unavailable because scripts/validate.mjs is missing in this workspace.',
600
+ }, true);
601
+ }
602
+
542
603
  return runNodeCommand('validate', ['./scripts/validate.mjs']);
543
604
  }
544
605
 
545
606
  if (toolName === 'test') {
607
+ if (AVAILABLE_TEST_SUITES.length === 0) {
608
+ return buildJsonResult({
609
+ error: 'test tool is unavailable because the managed test suites are not present in this workspace.',
610
+ }, true);
611
+ }
612
+
613
+ const defaultSuite = AVAILABLE_TEST_SUITES[0];
546
614
  const requestedSuite = typeof toolArguments.suite === 'string'
547
615
  ? toolArguments.suite
548
- : 'full';
616
+ : defaultSuite;
549
617
 
550
- const selectedSuite = TEST_SUITE_ARGS[requestedSuite] ? requestedSuite : 'full';
618
+ const selectedSuite = AVAILABLE_TEST_SUITES.includes(requestedSuite)
619
+ ? requestedSuite
620
+ : defaultSuite;
551
621
  return runNodeCommand(`test:${selectedSuite}`, TEST_SUITE_ARGS[selectedSuite]);
552
622
  }
553
623
 
554
624
  if (toolName === 'release_gate') {
625
+ if (!existsSync(INTERNAL_SCRIPT_PATHS.release_gate)) {
626
+ return buildJsonResult({
627
+ error: 'release_gate tool is unavailable because scripts/release-gate.mjs is missing in this workspace.',
628
+ }, true);
629
+ }
630
+
555
631
  return runNodeCommand('release_gate', ['./scripts/release-gate.mjs']);
556
632
  }
557
633
 
558
634
  if (toolName === 'forbidden_content_check') {
635
+ if (!existsSync(INTERNAL_SCRIPT_PATHS.forbidden_content_check)) {
636
+ return buildJsonResult({
637
+ error: 'forbidden_content_check tool is unavailable because scripts/forbidden-content-check.mjs is missing in this workspace.',
638
+ }, true);
639
+ }
640
+
559
641
  return runNodeCommand('forbidden_content_check', ['./scripts/forbidden-content-check.mjs']);
560
642
  }
561
643
 
@@ -235,9 +235,10 @@ function buildSystemPrompt() {
235
235
  'Treat docs/DESIGN.md as explanatory context, not a generic style guide.',
236
236
  'Do not reward generic SaaS defaults or popular template patterns.',
237
237
  'Do not penalize originality when the implementation still aligns with the contract.',
238
+ 'Purposeful motion is allowed and can improve quality. Only flag motion when it drifts from the contract, ignores reduced-motion expectations, or adds avoidable performance/accessibility risk.',
238
239
  'Only flag drift when there is a clear mismatch with the contract, accessibility non-negotiables, or cross-viewport adaptation rules.',
239
240
  'This audit always runs in advisory mode for this repository workflow.',
240
- 'Focus on color intent, typographic hierarchy, responsive re-layout, interaction behavior, and genericity drift.',
241
+ 'Focus on color intent, typographic hierarchy, responsive re-layout, purposeful motion, component morphology across states, interaction behavior, and genericity drift.',
241
242
  'Return ONLY one JSON object on a single line prefixed with JSON_VERDICT:.',
242
243
  'Schema:',
243
244
  '{"alignmentScore": number|null, "notes": string[], "findings": [{"area": string, "severity": "high|medium|low", "problem": string, "evidence": string, "recommendation": string, "blockingRecommended": boolean}]}',
@@ -268,7 +269,7 @@ function buildUserMessage(designIntentContent, designGuideContent, diffContent,
268
269
  truncatedDiff.trim() || '(no UI diff)',
269
270
  '```',
270
271
  '',
271
- 'Judge alignment to the contract. Avoid aesthetic bias toward generic web trends.',
272
+ 'Judge alignment to the contract. Avoid aesthetic bias toward generic web trends or toward motionless/static outputs.',
272
273
  ].join('\n');
273
274
  }
274
275
 
@@ -285,6 +285,8 @@ const REQUIRED_UI_DESIGN_AUTOMATION_SNIPPETS = [
285
285
  'Responsive Strategy and Cross-Viewport Adaptation Matrix',
286
286
  '`colorTruth.format`',
287
287
  '`crossViewportAdaptation.mutationRules.mobile/tablet/desktop`',
288
+ '`motionSystem`',
289
+ '`componentMorphology`',
288
290
  ],
289
291
  },
290
292
  {
@@ -302,6 +304,8 @@ const REQUIRED_UI_DESIGN_AUTOMATION_SNIPPETS = [
302
304
  snippets: [
303
305
  'colorTruth',
304
306
  'crossViewportAdaptation',
307
+ 'motionSystem',
308
+ 'componentMorphology',
305
309
  'requireViewportMutationRules',
306
310
  'allowHexDerivatives',
307
311
  ],