@ryuenn3123/agentic-senior-core 2.5.22 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-context/prompts/init-project.md +5 -5
- package/.agent-context/prompts/refactor.md +2 -1
- package/.agent-context/prompts/review-code.md +3 -2
- package/.agent-context/review-checklists/pr-checklist.md +8 -1
- package/.agent-context/rules/architecture.md +11 -0
- package/.agent-context/rules/frontend-architecture.md +2 -2
- package/.agent-context/state/architecture-map.md +1 -1
- package/.agent-context/state/memory-continuity-benchmark.json +1 -1
- package/.agents/workflows/init-project.md +3 -3
- package/.agents/workflows/refactor.md +1 -1
- package/.agents/workflows/review-code.md +4 -5
- package/.cursorrules +27 -71
- package/.gemini/instructions.md +6 -7
- package/.github/copilot-instructions.md +5 -6
- package/.windsurfrules +27 -71
- package/AGENTS.md +7 -9
- package/CONTRIBUTING.md +18 -31
- package/README.md +21 -4
- package/bin/agentic-senior-core.js +0 -6
- package/lib/cli/commands/init.mjs +113 -650
- package/lib/cli/commands/launch.mjs +1 -23
- package/lib/cli/commands/rollback.mjs +1 -1
- package/lib/cli/commands/upgrade.mjs +1 -23
- package/lib/cli/compiler.mjs +77 -72
- package/lib/cli/constants.mjs +84 -26
- package/lib/cli/init-architecture-flow.mjs +231 -0
- package/lib/cli/init-detection-flow.mjs +123 -0
- package/lib/cli/init-options.mjs +344 -0
- package/lib/cli/init-selection.mjs +100 -0
- package/lib/cli/preflight.mjs +1 -1
- package/lib/cli/profile-packs.mjs +15 -1
- package/lib/cli/project-scaffolder.mjs +18 -154
- package/lib/cli/utils.mjs +16 -12
- package/mcp.json +19 -19
- package/package.json +5 -2
- package/scripts/context-triggered-audit.mjs +18 -18
- package/scripts/documentation-boundary-audit.mjs +92 -5
- package/scripts/forbidden-content-check.mjs +1 -1
- package/scripts/frontend-usability-audit.mjs +21 -28
- package/scripts/governance-weekly-report.mjs +29 -15
- package/scripts/llm-judge.mjs +2 -5
- package/scripts/mcp-server.mjs +389 -5
- package/scripts/release-gate.mjs +121 -145
- package/scripts/sync-thin-adapters.mjs +161 -0
- package/scripts/v3-purge-audit.mjs +231 -0
- package/scripts/validate-evidence-bundle.mjs +1 -1
- package/scripts/validate.mjs +224 -272
- package/.agent-context/blueprints/api-nextjs.md +0 -184
- package/.agent-context/blueprints/aspnet-api.md +0 -247
- package/.agent-context/blueprints/ci-github-actions.md +0 -226
- package/.agent-context/blueprints/ci-gitlab.md +0 -200
- package/.agent-context/blueprints/fastapi-service.md +0 -210
- package/.agent-context/blueprints/go-service.md +0 -217
- package/.agent-context/blueprints/graphql-grpc-api.md +0 -51
- package/.agent-context/blueprints/infrastructure-as-code.md +0 -62
- package/.agent-context/blueprints/kubernetes-manifests.md +0 -76
- package/.agent-context/blueprints/laravel-api.md +0 -233
- package/.agent-context/blueprints/mobile-app.md +0 -91
- package/.agent-context/blueprints/nestjs-logic.md +0 -247
- package/.agent-context/blueprints/observability.md +0 -227
- package/.agent-context/blueprints/spring-boot-api.md +0 -218
- package/.agent-context/profiles/platform.md +0 -13
- package/.agent-context/profiles/regulated.md +0 -13
- package/.agent-context/profiles/startup.md +0 -13
- package/.agent-context/review-checklists/frontend-excellence-rubric.md +0 -73
- package/.agent-context/review-checklists/frontend-skill-parity.md +0 -29
- package/.agent-context/review-checklists/frontend-usability.md +0 -35
- package/.agent-context/review-checklists/marketplace-acceptance.md +0 -60
- package/.agent-context/review-checklists/performance-audit.md +0 -71
- package/.agent-context/review-checklists/release-operations.md +0 -33
- package/.agent-context/review-checklists/security-audit.md +0 -119
- package/.agent-context/skills/README.md +0 -63
- package/.agent-context/skills/backend/README.md +0 -68
- package/.agent-context/skills/backend/architecture.md +0 -361
- package/.agent-context/skills/backend/compatibility-manifest.json +0 -8
- package/.agent-context/skills/backend/data-access.md +0 -231
- package/.agent-context/skills/backend/errors.md +0 -138
- package/.agent-context/skills/backend/validation.md +0 -117
- package/.agent-context/skills/backend.md +0 -29
- package/.agent-context/skills/cli/.evidence/compatibility-manifest.json +0 -5
- package/.agent-context/skills/cli/.evidence/sbom-excerpt.json +0 -10
- package/.agent-context/skills/cli/.evidence/test-report.json +0 -8
- package/.agent-context/skills/cli/CHANGELOG.md +0 -6
- package/.agent-context/skills/cli/README.md +0 -56
- package/.agent-context/skills/cli/compatibility-manifest.json +0 -8
- package/.agent-context/skills/cli/init.md +0 -38
- package/.agent-context/skills/cli/output.md +0 -36
- package/.agent-context/skills/cli/package.json +0 -5
- package/.agent-context/skills/cli/safety-telemetry.md +0 -39
- package/.agent-context/skills/cli/tests/.gitkeep +0 -1
- package/.agent-context/skills/cli/upgrade.md +0 -38
- package/.agent-context/skills/cli.md +0 -32
- package/.agent-context/skills/distribution/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/distribution/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/distribution/.evidence/test-report.json +0 -8
- package/.agent-context/skills/distribution/CHANGELOG.md +0 -7
- package/.agent-context/skills/distribution/README.md +0 -27
- package/.agent-context/skills/distribution/compatibility-manifest.json +0 -8
- package/.agent-context/skills/distribution/compatibility.md +0 -32
- package/.agent-context/skills/distribution/package.json +0 -5
- package/.agent-context/skills/distribution/provenance-attestation.md +0 -47
- package/.agent-context/skills/distribution/publish.md +0 -37
- package/.agent-context/skills/distribution/rollback.md +0 -32
- package/.agent-context/skills/distribution/tests/.gitkeep +0 -1
- package/.agent-context/skills/distribution.md +0 -32
- package/.agent-context/skills/frontend/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/frontend/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/frontend/.evidence/test-report.json +0 -8
- package/.agent-context/skills/frontend/CHANGELOG.md +0 -7
- package/.agent-context/skills/frontend/README.md +0 -50
- package/.agent-context/skills/frontend/accessibility.md +0 -107
- package/.agent-context/skills/frontend/compatibility-manifest.json +0 -8
- package/.agent-context/skills/frontend/conversion-clarity.md +0 -51
- package/.agent-context/skills/frontend/motion.md +0 -67
- package/.agent-context/skills/frontend/package.json +0 -5
- package/.agent-context/skills/frontend/performance.md +0 -63
- package/.agent-context/skills/frontend/responsive-delivery.md +0 -41
- package/.agent-context/skills/frontend/tests/.gitkeep +0 -1
- package/.agent-context/skills/frontend/ui-architecture.md +0 -128
- package/.agent-context/skills/frontend.md +0 -40
- package/.agent-context/skills/fullstack/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/fullstack/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/fullstack/.evidence/test-report.json +0 -8
- package/.agent-context/skills/fullstack/CHANGELOG.md +0 -7
- package/.agent-context/skills/fullstack/README.md +0 -27
- package/.agent-context/skills/fullstack/compatibility-manifest.json +0 -8
- package/.agent-context/skills/fullstack/contracts.md +0 -53
- package/.agent-context/skills/fullstack/end-to-end.md +0 -42
- package/.agent-context/skills/fullstack/feature-slicing.md +0 -65
- package/.agent-context/skills/fullstack/package.json +0 -5
- package/.agent-context/skills/fullstack/release-coordination.md +0 -51
- package/.agent-context/skills/fullstack/tests/.gitkeep +0 -1
- package/.agent-context/skills/fullstack.md +0 -30
- package/.agent-context/skills/index.json +0 -107
- package/.agent-context/skills/review-quality/.evidence/compatibility-manifest.json +0 -9
- package/.agent-context/skills/review-quality/.evidence/sbom-excerpt.json +0 -6
- package/.agent-context/skills/review-quality/.evidence/test-report.json +0 -8
- package/.agent-context/skills/review-quality/CHANGELOG.md +0 -7
- package/.agent-context/skills/review-quality/README.md +0 -27
- package/.agent-context/skills/review-quality/benchmark.md +0 -30
- package/.agent-context/skills/review-quality/compatibility-manifest.json +0 -8
- package/.agent-context/skills/review-quality/package.json +0 -5
- package/.agent-context/skills/review-quality/planning.md +0 -38
- package/.agent-context/skills/review-quality/release-decision.md +0 -49
- package/.agent-context/skills/review-quality/security.md +0 -34
- package/.agent-context/skills/review-quality/tests/.gitkeep +0 -1
- package/.agent-context/skills/review-quality.md +0 -34
- package/.agent-context/stacks/csharp.md +0 -149
- package/.agent-context/stacks/flutter.md +0 -16
- package/.agent-context/stacks/go.md +0 -181
- package/.agent-context/stacks/java.md +0 -135
- package/.agent-context/stacks/php.md +0 -192
- package/.agent-context/stacks/python.md +0 -153
- package/.agent-context/stacks/react-native.md +0 -16
- package/.agent-context/stacks/ruby.md +0 -80
- package/.agent-context/stacks/rust.md +0 -86
- package/.agent-context/stacks/typescript.md +0 -317
- package/.agent-context/state/skill-platform.json +0 -38
- package/lib/cli/skill-selector.mjs +0 -232
- package/lib/cli/templates/api-contract.md.id.tmpl +0 -143
- package/lib/cli/templates/api-contract.md.tmpl +0 -143
- package/lib/cli/templates/architecture-decision-record.md.id.tmpl +0 -106
- package/lib/cli/templates/architecture-decision-record.md.tmpl +0 -145
- package/lib/cli/templates/database-schema.md.id.tmpl +0 -74
- package/lib/cli/templates/database-schema.md.tmpl +0 -74
- package/lib/cli/templates/flow-overview.md.id.tmpl +0 -118
- package/lib/cli/templates/flow-overview.md.tmpl +0 -131
- package/lib/cli/templates/project-brief.md.id.tmpl +0 -55
- package/lib/cli/templates/project-brief.md.tmpl +0 -79
- package/scripts/init-project.ps1 +0 -105
- package/scripts/init-project.sh +0 -131
- package/scripts/skill-tier-policy.mjs +0 -76
- package/scripts/trust-scorer.mjs +0 -119
package/scripts/mcp-server.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
5
|
import { spawn } from 'node:child_process';
|
|
5
|
-
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { dirname, resolve, sep } from 'node:path';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
8
|
|
|
8
9
|
const SCRIPT_FILE_PATH = fileURLToPath(import.meta.url);
|
|
@@ -10,14 +11,19 @@ const REPOSITORY_ROOT = resolve(dirname(SCRIPT_FILE_PATH), '..');
|
|
|
10
11
|
const PACKAGE_VERSION = JSON.parse(
|
|
11
12
|
readFileSync(resolve(REPOSITORY_ROOT, 'package.json'), 'utf8')
|
|
12
13
|
).version;
|
|
14
|
+
const STATE_DIRECTORY = resolve(REPOSITORY_ROOT, '.agent-context', 'state');
|
|
13
15
|
const DEFAULT_PROTOCOL_VERSION = '2024-11-05';
|
|
16
|
+
const DEFAULT_FETCH_TIMEOUT_MS = 15000;
|
|
17
|
+
const DEFAULT_FETCH_MAX_CHARS = 6000;
|
|
18
|
+
const MAX_FETCH_MAX_CHARS = 20000;
|
|
19
|
+
const DEFAULT_TREND_WINDOW_DAYS = 90;
|
|
20
|
+
const MAX_TREND_PACKAGES = 10;
|
|
14
21
|
|
|
15
22
|
const TEST_SUITE_ARGS = {
|
|
16
|
-
full: ['--test', './tests/cli-smoke.test.mjs', './tests/
|
|
23
|
+
full: ['--test', './tests/cli-smoke.test.mjs', './tests/mcp-server.test.mjs', './tests/llm-judge.test.mjs', './tests/enterprise-ops.test.mjs'],
|
|
17
24
|
cli: ['--test', './tests/cli-smoke.test.mjs'],
|
|
18
25
|
enterprise: ['--test', './tests/enterprise-ops.test.mjs'],
|
|
19
26
|
'llm-judge': ['--test', './tests/llm-judge.test.mjs'],
|
|
20
|
-
'skill-tier': ['--test', './tests/skill-tier-gate.test.mjs'],
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
const TOOL_DEFINITIONS = [
|
|
@@ -38,7 +44,7 @@ const TOOL_DEFINITIONS = [
|
|
|
38
44
|
properties: {
|
|
39
45
|
suite: {
|
|
40
46
|
type: 'string',
|
|
41
|
-
enum: ['full', 'cli', 'enterprise', 'llm-judge'
|
|
47
|
+
enum: ['full', 'cli', 'enterprise', 'llm-judge'],
|
|
42
48
|
description: 'Target test suite. Defaults to full.',
|
|
43
49
|
},
|
|
44
50
|
},
|
|
@@ -63,6 +69,88 @@ const TOOL_DEFINITIONS = [
|
|
|
63
69
|
additionalProperties: false,
|
|
64
70
|
},
|
|
65
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.',
|
|
85
|
+
},
|
|
86
|
+
maxChars: {
|
|
87
|
+
type: 'integer',
|
|
88
|
+
description: 'Maximum characters to return when query is not provided (default 6000, max 20000).',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
required: ['url'],
|
|
92
|
+
additionalProperties: false,
|
|
93
|
+
},
|
|
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).',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
required: ['packages'],
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
},
|
|
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).',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
required: ['path'],
|
|
127
|
+
additionalProperties: false,
|
|
128
|
+
},
|
|
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.',
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
required: ['path', 'content'],
|
|
151
|
+
additionalProperties: false,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
66
154
|
];
|
|
67
155
|
|
|
68
156
|
let incomingBuffer = Buffer.alloc(0);
|
|
@@ -117,6 +205,287 @@ function buildCommandOutput(commandLabel, commandArguments, exitCode, stdoutCont
|
|
|
117
205
|
].join('\n\n');
|
|
118
206
|
}
|
|
119
207
|
|
|
208
|
+
function buildJsonResult(payload, isError = false) {
|
|
209
|
+
return {
|
|
210
|
+
content: [
|
|
211
|
+
{
|
|
212
|
+
type: 'text',
|
|
213
|
+
text: JSON.stringify(payload, null, 2),
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
isError,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function normalizePlainText(rawText) {
|
|
221
|
+
return rawText
|
|
222
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
223
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
224
|
+
.replace(/<[^>]+>/g, ' ')
|
|
225
|
+
.replace(/ /gi, ' ')
|
|
226
|
+
.replace(/&/gi, '&')
|
|
227
|
+
.replace(/</gi, '<')
|
|
228
|
+
.replace(/>/gi, '>')
|
|
229
|
+
.replace(/\s+/g, ' ')
|
|
230
|
+
.trim();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function extractQuerySnippets(textContent, queryText) {
|
|
234
|
+
const normalizedQuery = String(queryText || '').trim().toLowerCase();
|
|
235
|
+
if (!normalizedQuery) {
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const normalizedContent = String(textContent || '');
|
|
240
|
+
const normalizedLowerContent = normalizedContent.toLowerCase();
|
|
241
|
+
const snippets = [];
|
|
242
|
+
let searchStartIndex = 0;
|
|
243
|
+
|
|
244
|
+
while (snippets.length < 5) {
|
|
245
|
+
const matchedIndex = normalizedLowerContent.indexOf(normalizedQuery, searchStartIndex);
|
|
246
|
+
if (matchedIndex === -1) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const contextRadius = 180;
|
|
251
|
+
const snippetStart = Math.max(0, matchedIndex - contextRadius);
|
|
252
|
+
const snippetEnd = Math.min(normalizedContent.length, matchedIndex + normalizedQuery.length + contextRadius);
|
|
253
|
+
const prefix = snippetStart > 0 ? '...' : '';
|
|
254
|
+
const suffix = snippetEnd < normalizedContent.length ? '...' : '';
|
|
255
|
+
snippets.push(`${prefix}${normalizedContent.slice(snippetStart, snippetEnd).trim()}${suffix}`);
|
|
256
|
+
searchStartIndex = matchedIndex + normalizedQuery.length;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return snippets;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function fetchWithTimeout(targetUrl, timeoutMs) {
|
|
263
|
+
const fetchController = new AbortController();
|
|
264
|
+
const timeoutHandle = setTimeout(() => fetchController.abort(), timeoutMs);
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
return await fetch(targetUrl, {
|
|
268
|
+
signal: fetchController.signal,
|
|
269
|
+
headers: {
|
|
270
|
+
'User-Agent': `agentic-senior-core/${PACKAGE_VERSION}`,
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
} finally {
|
|
274
|
+
clearTimeout(timeoutHandle);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function runResearchFetchTool(toolArguments = {}) {
|
|
279
|
+
const targetUrl = String(toolArguments.url || '').trim();
|
|
280
|
+
const queryText = typeof toolArguments.query === 'string' ? toolArguments.query.trim() : '';
|
|
281
|
+
const maxCharsInput = Number(toolArguments.maxChars);
|
|
282
|
+
const maxChars = Number.isFinite(maxCharsInput)
|
|
283
|
+
? Math.max(200, Math.min(MAX_FETCH_MAX_CHARS, Math.floor(maxCharsInput)))
|
|
284
|
+
: DEFAULT_FETCH_MAX_CHARS;
|
|
285
|
+
|
|
286
|
+
if (!/^https?:\/\//i.test(targetUrl)) {
|
|
287
|
+
return buildJsonResult({
|
|
288
|
+
error: 'Invalid url. Provide absolute HTTP/HTTPS URL.',
|
|
289
|
+
input: targetUrl,
|
|
290
|
+
}, true);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
const startedAt = new Date().toISOString();
|
|
295
|
+
const fetchResponse = await fetchWithTimeout(targetUrl, DEFAULT_FETCH_TIMEOUT_MS);
|
|
296
|
+
const rawBody = await fetchResponse.text();
|
|
297
|
+
const plainTextBody = normalizePlainText(rawBody);
|
|
298
|
+
const querySnippets = queryText ? extractQuerySnippets(plainTextBody, queryText) : [];
|
|
299
|
+
const selectedContent = querySnippets.length > 0
|
|
300
|
+
? querySnippets.join('\n\n')
|
|
301
|
+
: plainTextBody.slice(0, maxChars);
|
|
302
|
+
|
|
303
|
+
return buildJsonResult({
|
|
304
|
+
source: {
|
|
305
|
+
url: targetUrl,
|
|
306
|
+
status: fetchResponse.status,
|
|
307
|
+
ok: fetchResponse.ok,
|
|
308
|
+
fetchedAt: new Date().toISOString(),
|
|
309
|
+
requestedAt: startedAt,
|
|
310
|
+
contentType: fetchResponse.headers.get('content-type') || null,
|
|
311
|
+
},
|
|
312
|
+
query: queryText || null,
|
|
313
|
+
excerptCount: querySnippets.length,
|
|
314
|
+
truncated: !queryText && plainTextBody.length > selectedContent.length,
|
|
315
|
+
content: selectedContent,
|
|
316
|
+
}, !fetchResponse.ok);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
return buildJsonResult({
|
|
319
|
+
error: error instanceof Error ? error.message : String(error),
|
|
320
|
+
source: targetUrl,
|
|
321
|
+
}, true);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function runTrendSnapshotTool(toolArguments = {}) {
|
|
326
|
+
const packageInputs = Array.isArray(toolArguments.packages)
|
|
327
|
+
? toolArguments.packages.filter((packageName) => typeof packageName === 'string' && packageName.trim().length > 0)
|
|
328
|
+
: [];
|
|
329
|
+
const packageNames = Array.from(new Set(packageInputs.map((packageName) => packageName.trim()))).slice(0, MAX_TREND_PACKAGES);
|
|
330
|
+
const windowDaysInput = Number(toolArguments.windowDays);
|
|
331
|
+
const windowDays = Number.isFinite(windowDaysInput)
|
|
332
|
+
? Math.max(1, Math.min(3650, Math.floor(windowDaysInput)))
|
|
333
|
+
: DEFAULT_TREND_WINDOW_DAYS;
|
|
334
|
+
|
|
335
|
+
if (packageNames.length === 0) {
|
|
336
|
+
return buildJsonResult({
|
|
337
|
+
error: 'packages[] must include at least one package name.',
|
|
338
|
+
}, true);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const nowTimestamp = Date.now();
|
|
342
|
+
const windowStartTimestamp = nowTimestamp - (windowDays * 24 * 60 * 60 * 1000);
|
|
343
|
+
const packageReports = [];
|
|
344
|
+
|
|
345
|
+
for (const packageName of packageNames) {
|
|
346
|
+
const registryUrl = `https://registry.npmjs.org/${encodeURIComponent(packageName)}`;
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
const response = await fetchWithTimeout(registryUrl, DEFAULT_FETCH_TIMEOUT_MS);
|
|
350
|
+
if (!response.ok) {
|
|
351
|
+
packageReports.push({
|
|
352
|
+
package: packageName,
|
|
353
|
+
source: registryUrl,
|
|
354
|
+
status: response.status,
|
|
355
|
+
error: `Registry request failed with HTTP ${response.status}`,
|
|
356
|
+
});
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const registryPayload = await response.json();
|
|
361
|
+
const latestVersion = registryPayload?.['dist-tags']?.latest || null;
|
|
362
|
+
const releaseTimes = Object.entries(registryPayload?.time || {})
|
|
363
|
+
.filter(([versionName, publishedAt]) => {
|
|
364
|
+
if (versionName === 'created' || versionName === 'modified') {
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return typeof publishedAt === 'string' && Number.isFinite(Date.parse(publishedAt));
|
|
369
|
+
})
|
|
370
|
+
.map(([versionName, publishedAt]) => ({
|
|
371
|
+
version: versionName,
|
|
372
|
+
publishedAt,
|
|
373
|
+
publishedAtMs: Date.parse(publishedAt),
|
|
374
|
+
}))
|
|
375
|
+
.sort((leftEntry, rightEntry) => rightEntry.publishedAtMs - leftEntry.publishedAtMs);
|
|
376
|
+
|
|
377
|
+
const releasesInWindow = releaseTimes.filter((releaseEntry) => releaseEntry.publishedAtMs >= windowStartTimestamp);
|
|
378
|
+
const latestPublishedAt = latestVersion && typeof registryPayload?.time?.[latestVersion] === 'string'
|
|
379
|
+
? registryPayload.time[latestVersion]
|
|
380
|
+
: registryPayload?.time?.modified || null;
|
|
381
|
+
|
|
382
|
+
packageReports.push({
|
|
383
|
+
package: packageName,
|
|
384
|
+
source: registryUrl,
|
|
385
|
+
latestVersion,
|
|
386
|
+
latestPublishedAt,
|
|
387
|
+
releasesInWindow: releasesInWindow.length,
|
|
388
|
+
recentReleases: releasesInWindow.slice(0, 5).map((releaseEntry) => ({
|
|
389
|
+
version: releaseEntry.version,
|
|
390
|
+
publishedAt: releaseEntry.publishedAt,
|
|
391
|
+
})),
|
|
392
|
+
});
|
|
393
|
+
} catch (error) {
|
|
394
|
+
packageReports.push({
|
|
395
|
+
package: packageName,
|
|
396
|
+
source: registryUrl,
|
|
397
|
+
error: error instanceof Error ? error.message : String(error),
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const errorCount = packageReports.filter((packageReport) => typeof packageReport.error === 'string').length;
|
|
403
|
+
|
|
404
|
+
return buildJsonResult({
|
|
405
|
+
generatedAt: new Date().toISOString(),
|
|
406
|
+
windowDays,
|
|
407
|
+
packageCount: packageNames.length,
|
|
408
|
+
errorCount,
|
|
409
|
+
packages: packageReports,
|
|
410
|
+
citation: {
|
|
411
|
+
source: 'npm registry public API',
|
|
412
|
+
fetchedAt: new Date().toISOString(),
|
|
413
|
+
},
|
|
414
|
+
}, errorCount > 0);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function resolveStatePath(relativeStatePath) {
|
|
418
|
+
const normalizedRelativePath = String(relativeStatePath || '').replace(/\\/g, '/').replace(/^\/+/, '').trim();
|
|
419
|
+
if (!normalizedRelativePath) {
|
|
420
|
+
throw new Error('path is required and must be relative to .agent-context/state');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const resolvedStatePath = resolve(STATE_DIRECTORY, normalizedRelativePath);
|
|
424
|
+
const stateRootPrefix = `${STATE_DIRECTORY}${sep}`;
|
|
425
|
+
if (resolvedStatePath !== STATE_DIRECTORY && !resolvedStatePath.startsWith(stateRootPrefix)) {
|
|
426
|
+
throw new Error('path traversal is not allowed outside .agent-context/state');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
normalizedRelativePath,
|
|
431
|
+
resolvedStatePath,
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
async function runStateReadTool(toolArguments = {}) {
|
|
436
|
+
try {
|
|
437
|
+
const { normalizedRelativePath, resolvedStatePath } = resolveStatePath(toolArguments.path);
|
|
438
|
+
const fileContent = await readFile(resolvedStatePath, 'utf8');
|
|
439
|
+
|
|
440
|
+
return buildJsonResult({
|
|
441
|
+
path: normalizedRelativePath,
|
|
442
|
+
readAt: new Date().toISOString(),
|
|
443
|
+
bytes: Buffer.byteLength(fileContent, 'utf8'),
|
|
444
|
+
content: fileContent,
|
|
445
|
+
});
|
|
446
|
+
} catch (error) {
|
|
447
|
+
return buildJsonResult({
|
|
448
|
+
error: error instanceof Error ? error.message : String(error),
|
|
449
|
+
path: toolArguments.path || null,
|
|
450
|
+
}, true);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async function runStateWriteTool(toolArguments = {}) {
|
|
455
|
+
const writeMode = toolArguments.mode === 'append' ? 'append' : 'overwrite';
|
|
456
|
+
const contentToWrite = typeof toolArguments.content === 'string' ? toolArguments.content : '';
|
|
457
|
+
|
|
458
|
+
if (typeof toolArguments.content !== 'string') {
|
|
459
|
+
return buildJsonResult({
|
|
460
|
+
error: 'content must be a string.',
|
|
461
|
+
}, true);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
try {
|
|
465
|
+
const { normalizedRelativePath, resolvedStatePath } = resolveStatePath(toolArguments.path);
|
|
466
|
+
await mkdir(dirname(resolvedStatePath), { recursive: true });
|
|
467
|
+
|
|
468
|
+
if (writeMode === 'append') {
|
|
469
|
+
await writeFile(resolvedStatePath, contentToWrite, { encoding: 'utf8', flag: 'a' });
|
|
470
|
+
} else {
|
|
471
|
+
await writeFile(resolvedStatePath, contentToWrite, 'utf8');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return buildJsonResult({
|
|
475
|
+
path: normalizedRelativePath,
|
|
476
|
+
wroteAt: new Date().toISOString(),
|
|
477
|
+
mode: writeMode,
|
|
478
|
+
bytesWritten: Buffer.byteLength(contentToWrite, 'utf8'),
|
|
479
|
+
});
|
|
480
|
+
} catch (error) {
|
|
481
|
+
return buildJsonResult({
|
|
482
|
+
error: error instanceof Error ? error.message : String(error),
|
|
483
|
+
path: toolArguments.path || null,
|
|
484
|
+
mode: writeMode,
|
|
485
|
+
}, true);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
120
489
|
function runNodeCommand(commandLabel, commandArguments) {
|
|
121
490
|
return new Promise((resolveResult) => {
|
|
122
491
|
const childProcess = spawn(process.execPath, commandArguments, {
|
|
@@ -190,6 +559,22 @@ async function executeToolCall(toolName, toolArguments = {}) {
|
|
|
190
559
|
return runNodeCommand('forbidden_content_check', ['./scripts/forbidden-content-check.mjs']);
|
|
191
560
|
}
|
|
192
561
|
|
|
562
|
+
if (toolName === 'research_fetch') {
|
|
563
|
+
return runResearchFetchTool(toolArguments);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (toolName === 'trend_snapshot') {
|
|
567
|
+
return runTrendSnapshotTool(toolArguments);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (toolName === 'state_read') {
|
|
571
|
+
return runStateReadTool(toolArguments);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (toolName === 'state_write') {
|
|
575
|
+
return runStateWriteTool(toolArguments);
|
|
576
|
+
}
|
|
577
|
+
|
|
193
578
|
return {
|
|
194
579
|
content: [
|
|
195
580
|
{
|
|
@@ -274,7 +659,6 @@ function processIncomingBuffer() {
|
|
|
274
659
|
|
|
275
660
|
// Try to parse as line-delimited JSON first (modern MCP standard)
|
|
276
661
|
let parseMode = 'line-delimited';
|
|
277
|
-
let contentToProcess = fullContent;
|
|
278
662
|
|
|
279
663
|
// Check if Content-Length header is present (LSP-style for backward compatibility)
|
|
280
664
|
if (fullContent.includes('Content-Length:')) {
|