monomind 1.11.14 → 1.12.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/.claude/agents/generated/channel-intelligence-director.md +87 -0
- package/.claude/agents/generated/chief-growth-officer.md +88 -0
- package/.claude/agents/generated/content-seo-strategist.md +90 -0
- package/.claude/agents/generated/developer-community-strategist.md +91 -0
- package/.claude/agents/generated/outreach-partnership-strategist.md +90 -0
- package/.claude/agents/generated/social-media-strategist.md +91 -0
- package/.claude/agents/generated/video-visual-strategist.md +90 -0
- package/.claude/commands/mastermind/master.md +1 -1
- package/.claude/helpers/auto-memory-hook.mjs +13 -4
- package/.claude/helpers/control-start.cjs +5 -0
- package/.claude/helpers/event-logger.cjs +114 -0
- package/.claude/helpers/handlers/adr-draft-handler.cjs +19 -5
- package/.claude/helpers/handlers/agent-start-handler.cjs +13 -4
- package/.claude/helpers/handlers/compact-handler.cjs +2 -0
- package/.claude/helpers/handlers/edit-handler.cjs +1 -1
- package/.claude/helpers/handlers/gates-handler.cjs +3 -0
- package/.claude/helpers/handlers/graph-status-handler.cjs +14 -8
- package/.claude/helpers/handlers/loops-status-handler.cjs +5 -2
- package/.claude/helpers/handlers/route-handler.cjs +13 -6
- package/.claude/helpers/handlers/session-handler.cjs +11 -4
- package/.claude/helpers/handlers/session-restore-handler.cjs +21 -11
- package/.claude/helpers/handlers/task-handler.cjs +13 -5
- package/.claude/helpers/intelligence.cjs +7 -2
- package/.claude/helpers/loop-tracker.cjs +15 -3
- package/.claude/helpers/memory.cjs +6 -1
- package/.claude/helpers/router.cjs +5 -2
- package/.claude/helpers/session.cjs +2 -0
- package/.claude/helpers/statusline.cjs +10 -2
- package/.claude/helpers/utils/micro-agents.cjs +20 -4
- package/.claude/scheduled_tasks.lock +1 -1
- package/.claude/settings.json +92 -1
- package/.claude/skills/mastermind/_protocol.md +25 -15
- package/.claude/skills/mastermind/architect.md +3 -3
- package/.claude/skills/mastermind/autodev.md +4 -2
- package/.claude/skills/mastermind/idea.md +10 -0
- package/.claude/skills/mastermind/ops.md +3 -3
- package/.claude/skills/mastermind/runorg.md +153 -86
- package/package.json +20 -3
- package/packages/@monomind/cli/dist/src/agents/registry-builder.js +2 -0
- package/packages/@monomind/cli/dist/src/autopilot-state.js +10 -5
- package/packages/@monomind/cli/dist/src/benchmarks/benchmark-runner.js +13 -0
- package/packages/@monomind/cli/dist/src/benchmarks/metric-evaluators.js +20 -9
- package/packages/@monomind/cli/dist/src/browser/actions.js +10 -3
- package/packages/@monomind/cli/dist/src/browser/browser.js +12 -2
- package/packages/@monomind/cli/dist/src/browser/cdp.js +21 -3
- package/packages/@monomind/cli/dist/src/browser/har.js +27 -5
- package/packages/@monomind/cli/dist/src/commands/agent.js +11 -8
- package/packages/@monomind/cli/dist/src/commands/analyze.js +36 -21
- package/packages/@monomind/cli/dist/src/commands/autopilot.js +12 -4
- package/packages/@monomind/cli/dist/src/commands/benchmark.js +51 -8
- package/packages/@monomind/cli/dist/src/commands/browse.js +5 -2
- package/packages/@monomind/cli/dist/src/commands/claims.js +29 -11
- package/packages/@monomind/cli/dist/src/commands/cleanup.js +25 -5
- package/packages/@monomind/cli/dist/src/commands/config.js +15 -7
- package/packages/@monomind/cli/dist/src/commands/daemon.js +6 -0
- package/packages/@monomind/cli/dist/src/commands/deployment.js +34 -19
- package/packages/@monomind/cli/dist/src/commands/doctor.js +97 -20
- package/packages/@monomind/cli/dist/src/commands/guidance.js +15 -2
- package/packages/@monomind/cli/dist/src/commands/hive-mind.js +37 -14
- package/packages/@monomind/cli/dist/src/commands/hooks.js +42 -25
- package/packages/@monomind/cli/dist/src/commands/init.js +9 -4
- package/packages/@monomind/cli/dist/src/commands/issues.js +29 -26
- package/packages/@monomind/cli/dist/src/commands/mcp.js +11 -5
- package/packages/@monomind/cli/dist/src/commands/memory.js +10 -0
- package/packages/@monomind/cli/dist/src/commands/migrate.js +5 -5
- package/packages/@monomind/cli/dist/src/commands/monograph.js +18 -5
- package/packages/@monomind/cli/dist/src/commands/monovector/backup.js +8 -2
- package/packages/@monomind/cli/dist/src/commands/monovector/benchmark.js +20 -7
- package/packages/@monomind/cli/dist/src/commands/monovector/import.js +15 -0
- package/packages/@monomind/cli/dist/src/commands/monovector/migrate.js +4 -1
- package/packages/@monomind/cli/dist/src/commands/monovector/optimize.js +11 -0
- package/packages/@monomind/cli/dist/src/commands/monovector/setup.js +11 -1
- package/packages/@monomind/cli/dist/src/commands/neural.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/performance.js +20 -7
- package/packages/@monomind/cli/dist/src/commands/platforms.js +90 -8
- package/packages/@monomind/cli/dist/src/commands/plugins.js +12 -5
- package/packages/@monomind/cli/dist/src/commands/process.js +33 -10
- package/packages/@monomind/cli/dist/src/commands/progress.js +5 -3
- package/packages/@monomind/cli/dist/src/commands/providers.js +5 -5
- package/packages/@monomind/cli/dist/src/commands/replay.js +8 -2
- package/packages/@monomind/cli/dist/src/commands/route.js +27 -7
- package/packages/@monomind/cli/dist/src/commands/security.js +4 -0
- package/packages/@monomind/cli/dist/src/commands/session.js +12 -1
- package/packages/@monomind/cli/dist/src/commands/start.js +11 -4
- package/packages/@monomind/cli/dist/src/commands/status.js +7 -4
- package/packages/@monomind/cli/dist/src/commands/swarm.js +27 -13
- package/packages/@monomind/cli/dist/src/commands/task.js +26 -11
- package/packages/@monomind/cli/dist/src/commands/tokens.js +7 -2
- package/packages/@monomind/cli/dist/src/commands/transfer-store.js +36 -22
- package/packages/@monomind/cli/dist/src/commands/update.js +15 -3
- package/packages/@monomind/cli/dist/src/commands/workflow.js +39 -6
- package/packages/@monomind/cli/dist/src/consensus/audit-writer.js +18 -7
- package/packages/@monomind/cli/dist/src/consensus/vote-signer.js +25 -8
- package/packages/@monomind/cli/dist/src/index.js +7 -3
- package/packages/@monomind/cli/dist/src/init/executor.js +14 -11
- package/packages/@monomind/cli/dist/src/init/shared-instructions-generator.js +20 -4
- package/packages/@monomind/cli/dist/src/init/statusline-generator.js +36 -15
- package/packages/@monomind/cli/dist/src/mcp-tools/a2a-tools.js +98 -13
- package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +16 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/analyze-tools.js +80 -17
- package/packages/@monomind/cli/dist/src/mcp-tools/browser-tools.js +84 -22
- package/packages/@monomind/cli/dist/src/mcp-tools/claims-tools.js +35 -7
- package/packages/@monomind/cli/dist/src/mcp-tools/config-tools.js +82 -17
- package/packages/@monomind/cli/dist/src/mcp-tools/coordination-tools.js +37 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/daa-tools.js +49 -7
- package/packages/@monomind/cli/dist/src/mcp-tools/embeddings-tools.js +45 -18
- package/packages/@monomind/cli/dist/src/mcp-tools/github-tools.js +75 -25
- package/packages/@monomind/cli/dist/src/mcp-tools/guidance-tools.js +32 -10
- package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +91 -20
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.js +188 -29
- package/packages/@monomind/cli/dist/src/mcp-tools/memory-tools.js +25 -7
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-compat.js +11 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +148 -26
- package/packages/@monomind/cli/dist/src/mcp-tools/neural-tools.js +44 -9
- package/packages/@monomind/cli/dist/src/mcp-tools/performance-tools.js +45 -10
- package/packages/@monomind/cli/dist/src/mcp-tools/progress-tools.js +7 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/request-tracker.js +15 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/security-tools.js +61 -9
- package/packages/@monomind/cli/dist/src/mcp-tools/session-tools.js +45 -14
- package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +15 -3
- package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +14 -7
- package/packages/@monomind/cli/dist/src/mcp-tools/task-tools.js +52 -10
- package/packages/@monomind/cli/dist/src/mcp-tools/terminal-tools.js +40 -6
- package/packages/@monomind/cli/dist/src/mcp-tools/transfer-tools.js +37 -4
- package/packages/@monomind/cli/dist/src/mcp-tools/workflow-tools.js +29 -6
- package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.js +26 -10
- package/packages/@monomind/cli/dist/src/memory/intelligence.js +80 -19
- package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +21 -2
- package/packages/@monomind/cli/dist/src/memory/memory-initializer.js +67 -3
- package/packages/@monomind/cli/dist/src/memory/sona-optimizer.js +14 -4
- package/packages/@monomind/cli/dist/src/monovector/command-outcomes.js +43 -7
- package/packages/@monomind/cli/dist/src/monovector/coverage-router.js +8 -4
- package/packages/@monomind/cli/dist/src/monovector/coverage-tools.js +6 -3
- package/packages/@monomind/cli/dist/src/monovector/diff-classifier.js +13 -0
- package/packages/@monomind/cli/dist/src/monovector/route-outcomes.d.ts +2 -1
- package/packages/@monomind/cli/dist/src/monovector/route-outcomes.js +46 -4
- package/packages/@monomind/cli/dist/src/plugins/manager.js +8 -3
- package/packages/@monomind/cli/dist/src/plugins/store/discovery.js +46 -2
- package/packages/@monomind/cli/dist/src/plugins/store/search.js +5 -4
- package/packages/@monomind/cli/dist/src/production/circuit-breaker.js +17 -3
- package/packages/@monomind/cli/dist/src/production/error-handler.js +3 -0
- package/packages/@monomind/cli/dist/src/production/monitoring.js +20 -3
- package/packages/@monomind/cli/dist/src/production/rate-limiter.js +13 -4
- package/packages/@monomind/cli/dist/src/production/retry.js +17 -9
- package/packages/@monomind/cli/dist/src/routing/embed-worker.js +6 -2
- package/packages/@monomind/cli/dist/src/routing/embedder.js +0 -0
- package/packages/@monomind/cli/dist/src/routing/llm-caller.js +13 -2
- package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +18 -3
- package/packages/@monomind/cli/dist/src/services/claim-service.d.ts +1 -0
- package/packages/@monomind/cli/dist/src/services/claim-service.js +8 -0
- package/packages/@monomind/cli/dist/src/services/config-file-manager.js +14 -2
- package/packages/@monomind/cli/dist/src/services/headless-worker-executor.js +18 -2
- package/packages/@monomind/cli/dist/src/services/worker-daemon.js +53 -12
- package/packages/@monomind/cli/dist/src/transfer/anonymization/index.d.ts +0 -3
- package/packages/@monomind/cli/dist/src/transfer/anonymization/index.js +16 -1
- package/packages/@monomind/cli/dist/src/transfer/export.js +8 -0
- package/packages/@monomind/cli/dist/src/transfer/ipfs/upload.js +33 -3
- package/packages/@monomind/cli/dist/src/transfer/serialization/cfp.js +9 -3
- package/packages/@monomind/cli/dist/src/transfer/storage/gcs.js +37 -3
- package/packages/@monomind/cli/dist/src/transfer/store/discovery.js +45 -3
- package/packages/@monomind/cli/dist/src/transfer/store/download.js +5 -0
- package/packages/@monomind/cli/dist/src/transfer/store/publish.js +13 -1
- package/packages/@monomind/cli/dist/src/transfer/store/registry.d.ts +8 -0
- package/packages/@monomind/cli/dist/src/transfer/store/registry.js +30 -5
- package/packages/@monomind/cli/dist/src/transfer/store/search.js +20 -5
- package/packages/@monomind/cli/dist/src/update/checker.js +59 -7
- package/packages/@monomind/cli/dist/src/update/executor.js +50 -3
- package/packages/@monomind/cli/dist/src/update/index.js +18 -1
- package/packages/@monomind/cli/dist/src/update/rate-limiter.d.ts +6 -0
- package/packages/@monomind/cli/dist/src/update/rate-limiter.js +79 -7
- package/packages/@monomind/cli/dist/src/update/validator.js +52 -1
- package/packages/@monomind/cli/package.json +2 -3
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* github.com/monoes/monomind
|
|
6
6
|
*/
|
|
7
|
-
import { readFileSync } from 'fs';
|
|
7
|
+
import { readFileSync, statSync } from 'fs';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import { dirname, join } from 'path';
|
|
10
10
|
import { commandParser } from './parser.js';
|
|
@@ -19,6 +19,9 @@ function getPackageVersion() {
|
|
|
19
19
|
const __dirname = dirname(__filename);
|
|
20
20
|
// Navigate from dist/src to package root
|
|
21
21
|
const pkgPath = join(__dirname, '..', '..', 'package.json');
|
|
22
|
+
// Guard: skip if package.json is unexpectedly large (> 1 MB)
|
|
23
|
+
if (statSync(pkgPath).size > 1024 * 1024)
|
|
24
|
+
return '3.0.0';
|
|
22
25
|
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
23
26
|
return pkg.version || '3.0.0';
|
|
24
27
|
}
|
|
@@ -458,10 +461,11 @@ export class CLI {
|
|
|
458
461
|
catch { /* optional — registry build failures must never block startup */ }
|
|
459
462
|
// Task 04: CapabilityMetadata — validate agent registry at startup
|
|
460
463
|
try {
|
|
461
|
-
const { readFileSync, existsSync } = await import('fs');
|
|
464
|
+
const { readFileSync, existsSync, statSync: statSyncReg } = await import('fs');
|
|
462
465
|
const { join: pathJoin } = await import('path');
|
|
463
466
|
const registryPath = pathJoin(process.cwd(), '.monomind', 'registry.json');
|
|
464
|
-
|
|
467
|
+
const MAX_REGISTRY_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
468
|
+
if (existsSync(registryPath) && statSyncReg(registryPath).size <= MAX_REGISTRY_BYTES) {
|
|
465
469
|
const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));
|
|
466
470
|
const entries = registry.agents ?? [];
|
|
467
471
|
const issues = [];
|
|
@@ -10,6 +10,7 @@ import { dirname } from 'path';
|
|
|
10
10
|
// ESM-compatible __dirname
|
|
11
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
12
12
|
const __dirname = dirname(__filename);
|
|
13
|
+
const MAX_EXEC_FILE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
13
14
|
/**
|
|
14
15
|
* Atomic write helper — writes to a sibling .tmp file then renames into place.
|
|
15
16
|
* SIGINT or crash during a partial write would otherwise corrupt user-critical
|
|
@@ -205,7 +206,7 @@ function cleanupLegacyTools(targetDir) {
|
|
|
205
206
|
}
|
|
206
207
|
// Clean ruv-swarm from .mcp.json and fix old MCP package name
|
|
207
208
|
const mcpJsonPath = path.join(targetDir, '.mcp.json');
|
|
208
|
-
if (fs.existsSync(mcpJsonPath)) {
|
|
209
|
+
if (fs.existsSync(mcpJsonPath) && fs.statSync(mcpJsonPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
209
210
|
try {
|
|
210
211
|
const mcp = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8'));
|
|
211
212
|
let mcpChanged = false;
|
|
@@ -226,7 +227,7 @@ function cleanupLegacyTools(targetDir) {
|
|
|
226
227
|
}
|
|
227
228
|
// Clean ruv-swarm from .claude/settings.json hooks and fix MCP package name
|
|
228
229
|
const settingsPath = path.join(targetDir, '.claude', 'settings.json');
|
|
229
|
-
if (fs.existsSync(settingsPath)) {
|
|
230
|
+
if (fs.existsSync(settingsPath) && fs.statSync(settingsPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
230
231
|
try {
|
|
231
232
|
const raw = fs.readFileSync(settingsPath, 'utf-8');
|
|
232
233
|
const settings = JSON.parse(raw);
|
|
@@ -449,8 +450,8 @@ async function startDaemonBackground(targetDir, result) {
|
|
|
449
450
|
const { execSync } = await import('child_process');
|
|
450
451
|
// Check if daemon is already running
|
|
451
452
|
const pidFile = path.join(targetDir, '.monomind', 'daemon.pid');
|
|
452
|
-
const { existsSync, readFileSync } = await import('fs');
|
|
453
|
-
if (existsSync(pidFile)) {
|
|
453
|
+
const { existsSync, readFileSync, statSync: statSyncPid } = await import('fs');
|
|
454
|
+
if (existsSync(pidFile) && statSyncPid(pidFile).size <= 1024) {
|
|
454
455
|
const pid = parseInt(readFileSync(pidFile, 'utf8').trim(), 10);
|
|
455
456
|
try {
|
|
456
457
|
process.kill(pid, 0);
|
|
@@ -798,7 +799,7 @@ export async function executeUpgrade(targetDir, upgradeSettings = false) {
|
|
|
798
799
|
// 3. Merge settings if requested
|
|
799
800
|
if (upgradeSettings) {
|
|
800
801
|
const settingsPath = path.join(targetDir, '.claude', 'settings.json');
|
|
801
|
-
if (fs.existsSync(settingsPath)) {
|
|
802
|
+
if (fs.existsSync(settingsPath) && fs.statSync(settingsPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
802
803
|
try {
|
|
803
804
|
const existingSettings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
804
805
|
const mergedSettings = mergeSettingsForUpgrade(existingSettings);
|
|
@@ -951,7 +952,7 @@ async function createDirectories(targetDir, options, result) {
|
|
|
951
952
|
async function writeSettings(targetDir, options, result) {
|
|
952
953
|
const settingsPath = path.join(targetDir, '.claude', 'settings.json');
|
|
953
954
|
const generated = JSON.parse(generateSettingsJson(options));
|
|
954
|
-
if (fs.existsSync(settingsPath) && !options.force) {
|
|
955
|
+
if (fs.existsSync(settingsPath) && !options.force && fs.statSync(settingsPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
955
956
|
// Merge hooks/env/permissions into existing settings instead of skipping
|
|
956
957
|
try {
|
|
957
958
|
const existing = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
@@ -1493,7 +1494,7 @@ daemon.pid
|
|
|
1493
1494
|
// A blanket ignore prevents config, metrics, and knowledge graph from being committed.
|
|
1494
1495
|
// We remove any bare `.monomind/` or `**/.monomind/` lines and add specific excludes instead.
|
|
1495
1496
|
const projectGitignorePath = path.join(targetDir, '.gitignore');
|
|
1496
|
-
if (fs.existsSync(projectGitignorePath)) {
|
|
1497
|
+
if (fs.existsSync(projectGitignorePath) && fs.statSync(projectGitignorePath).size <= MAX_EXEC_FILE_BYTES) {
|
|
1497
1498
|
const existing = fs.readFileSync(projectGitignorePath, 'utf-8');
|
|
1498
1499
|
const blanketPattern = /^(\*\*\/)?\.monomind\/?\s*$/gm;
|
|
1499
1500
|
if (blanketPattern.test(existing)) {
|
|
@@ -2060,7 +2061,7 @@ async function writeClaudeMd(targetDir, options, result) {
|
|
|
2060
2061
|
if (!fs.existsSync(globalClaudeDir)) {
|
|
2061
2062
|
fs.mkdirSync(globalClaudeDir, { recursive: true });
|
|
2062
2063
|
}
|
|
2063
|
-
if (fs.existsSync(globalClaudeMd)) {
|
|
2064
|
+
if (fs.existsSync(globalClaudeMd) && fs.statSync(globalClaudeMd).size <= MAX_EXEC_FILE_BYTES) {
|
|
2064
2065
|
const existing = fs.readFileSync(globalClaudeMd, 'utf-8');
|
|
2065
2066
|
if (!existing.includes('Monomind Integration')) {
|
|
2066
2067
|
fs.appendFileSync(globalClaudeMd, monomindBlock);
|
|
@@ -2082,7 +2083,7 @@ async function writeClaudeMd(targetDir, options, result) {
|
|
|
2082
2083
|
fs.mkdirSync(globalClaudeDir, { recursive: true });
|
|
2083
2084
|
}
|
|
2084
2085
|
let globalSettings = {};
|
|
2085
|
-
if (fs.existsSync(globalSettingsPath)) {
|
|
2086
|
+
if (fs.existsSync(globalSettingsPath) && fs.statSync(globalSettingsPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
2086
2087
|
try {
|
|
2087
2088
|
globalSettings = JSON.parse(fs.readFileSync(globalSettingsPath, 'utf-8'));
|
|
2088
2089
|
}
|
|
@@ -2227,7 +2228,9 @@ function _registerMonomindProject(dir) {
|
|
|
2227
2228
|
const registryPath = path.join(os.homedir(), '.monomind-projects.json');
|
|
2228
2229
|
let reg = { projects: [] };
|
|
2229
2230
|
try {
|
|
2230
|
-
|
|
2231
|
+
if (fs.existsSync(registryPath) && fs.statSync(registryPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
2232
|
+
reg = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
|
|
2233
|
+
}
|
|
2231
2234
|
}
|
|
2232
2235
|
catch { }
|
|
2233
2236
|
if (!Array.isArray(reg.projects))
|
|
@@ -2260,7 +2263,7 @@ export function findMonomindProjects(maxDepth = 3) {
|
|
|
2260
2263
|
].filter(r => fs.existsSync(r));
|
|
2261
2264
|
// Also check known-projects registry if it exists
|
|
2262
2265
|
const registryPath = path.join(home, '.monomind-projects.json');
|
|
2263
|
-
if (fs.existsSync(registryPath)) {
|
|
2266
|
+
if (fs.existsSync(registryPath) && fs.statSync(registryPath).size <= MAX_EXEC_FILE_BYTES) {
|
|
2264
2267
|
try {
|
|
2265
2268
|
const reg = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
|
|
2266
2269
|
if (Array.isArray(reg.projects)) {
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
import * as fs from 'node:fs';
|
|
9
9
|
import * as path from 'node:path';
|
|
10
10
|
import { execFileSync } from 'node:child_process';
|
|
11
|
+
const MAX_JSON_READ_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
12
|
+
const MAX_TEXT_READ_BYTES = 2 * 1024 * 1024; // 2 MB for plain-text config files
|
|
11
13
|
function readJSON(p) {
|
|
12
14
|
try {
|
|
15
|
+
if (!fs.existsSync(p) || fs.statSync(p).size > MAX_JSON_READ_BYTES)
|
|
16
|
+
return null;
|
|
13
17
|
return JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
14
18
|
}
|
|
15
19
|
catch {
|
|
@@ -166,7 +170,10 @@ export function detectProjectProfile(cwd) {
|
|
|
166
170
|
profile.language = 'rust';
|
|
167
171
|
profile.packageManager = 'cargo';
|
|
168
172
|
try {
|
|
169
|
-
const
|
|
173
|
+
const cargoPath = path.join(cwd, 'Cargo.toml');
|
|
174
|
+
if (fs.statSync(cargoPath).size > MAX_TEXT_READ_BYTES)
|
|
175
|
+
throw new Error('too large');
|
|
176
|
+
const cargo = fs.readFileSync(cargoPath, 'utf-8');
|
|
170
177
|
const nameM = cargo.match(/^name\s*=\s*"([^"]+)"/m);
|
|
171
178
|
if (nameM)
|
|
172
179
|
profile.name = nameM[1];
|
|
@@ -191,7 +198,10 @@ export function detectProjectProfile(cwd) {
|
|
|
191
198
|
else
|
|
192
199
|
profile.packageManager = 'pip';
|
|
193
200
|
try {
|
|
194
|
-
const
|
|
201
|
+
const ppPath = path.join(cwd, 'pyproject.toml');
|
|
202
|
+
if (fs.existsSync(ppPath) && fs.statSync(ppPath).size > MAX_TEXT_READ_BYTES)
|
|
203
|
+
throw new Error('too large');
|
|
204
|
+
const pp = fs.readFileSync(ppPath, 'utf-8');
|
|
195
205
|
if (pp.includes('fastapi') || pp.includes('FastAPI'))
|
|
196
206
|
profile.framework.push('fastapi');
|
|
197
207
|
if (pp.includes('django'))
|
|
@@ -210,7 +220,10 @@ export function detectProjectProfile(cwd) {
|
|
|
210
220
|
profile.language = 'go';
|
|
211
221
|
profile.packageManager = 'unknown'; // go mod doesn't have a separate PM
|
|
212
222
|
try {
|
|
213
|
-
const
|
|
223
|
+
const gomodPath = path.join(cwd, 'go.mod');
|
|
224
|
+
if (fs.statSync(gomodPath).size > MAX_TEXT_READ_BYTES)
|
|
225
|
+
throw new Error('too large');
|
|
226
|
+
const gomod = fs.readFileSync(gomodPath, 'utf-8');
|
|
214
227
|
if (gomod.includes('gin-gonic/gin'))
|
|
215
228
|
profile.framework.push('gin');
|
|
216
229
|
if (gomod.includes('labstack/echo'))
|
|
@@ -236,7 +249,10 @@ export function detectProjectProfile(cwd) {
|
|
|
236
249
|
}
|
|
237
250
|
// ── CLAUDE.md conventions extraction ──────────────────────────────────────
|
|
238
251
|
try {
|
|
239
|
-
const
|
|
252
|
+
const claudeMdPath = path.join(cwd, 'CLAUDE.md');
|
|
253
|
+
if (fs.existsSync(claudeMdPath) && fs.statSync(claudeMdPath).size > MAX_TEXT_READ_BYTES)
|
|
254
|
+
throw new Error('too large');
|
|
255
|
+
const claudeMd = fs.readFileSync(claudeMdPath, 'utf-8');
|
|
240
256
|
profile.maxFileLines = extractMaxFileLines(claudeMd);
|
|
241
257
|
}
|
|
242
258
|
catch { /* skip */ }
|
|
@@ -62,6 +62,8 @@ function getVersion() {
|
|
|
62
62
|
];
|
|
63
63
|
for (const p of walkCandidates) {
|
|
64
64
|
try {
|
|
65
|
+
const pkgStat = safeStat(p);
|
|
66
|
+
if (!pkgStat || pkgStat.size > 1024 * 1024) continue;
|
|
65
67
|
const pkg = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
66
68
|
if (pkg.version && (pkg.name === 'monomind' || pkg.name === '@monomind/cli' || (pkg.name || '').startsWith('@monomind'))) {
|
|
67
69
|
return \`v\${pkg.version}\`;
|
|
@@ -72,7 +74,10 @@ function getVersion() {
|
|
|
72
74
|
try {
|
|
73
75
|
const { execSync } = require('child_process');
|
|
74
76
|
const prefix = execSync('npm config get prefix', { encoding: 'utf-8', timeout: 2000 }).trim();
|
|
75
|
-
const
|
|
77
|
+
const globalPkgPath = path.join(prefix, 'lib', 'node_modules', 'monomind', 'package.json');
|
|
78
|
+
const globalPkgStat = safeStat(globalPkgPath);
|
|
79
|
+
if (!globalPkgStat || globalPkgStat.size > 1024 * 1024) throw new Error('too large');
|
|
80
|
+
const pkg = JSON.parse(fs.readFileSync(globalPkgPath, 'utf-8'));
|
|
76
81
|
if (pkg.version) return \`v\${pkg.version}\`;
|
|
77
82
|
} catch { /* ignore */ }
|
|
78
83
|
return 'v1.0.6';
|
|
@@ -113,9 +118,11 @@ function safeExec(cmd, timeoutMs = 2000) {
|
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
// Safe JSON file reader (returns null on failure)
|
|
121
|
+
// Refuses to load files > 10 MB to prevent OOM on corrupted/oversized stores.
|
|
122
|
+
const MAX_JSON_READ_BYTES = 10 * 1024 * 1024;
|
|
116
123
|
function readJSON(filePath) {
|
|
117
124
|
try {
|
|
118
|
-
if (fs.existsSync(filePath)) {
|
|
125
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).size <= MAX_JSON_READ_BYTES) {
|
|
119
126
|
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
120
127
|
}
|
|
121
128
|
} catch { /* ignore */ }
|
|
@@ -227,6 +234,8 @@ function getModelFromSessionJSONL() {
|
|
|
227
234
|
if (files.length === 0) return null;
|
|
228
235
|
|
|
229
236
|
const sessionFile = path.join(projectsDir, files[0].f);
|
|
237
|
+
const sessionStat = safeStat(sessionFile);
|
|
238
|
+
if (!sessionStat || sessionStat.size > 50 * 1024 * 1024) return null; // skip > 50 MB
|
|
230
239
|
const raw = fs.readFileSync(sessionFile, 'utf-8');
|
|
231
240
|
const lines = raw.split('\\n').filter(Boolean);
|
|
232
241
|
|
|
@@ -557,7 +566,8 @@ function getHooksStatus() {
|
|
|
557
566
|
function getActiveAgent() {
|
|
558
567
|
const routeFile = path.join(CWD, '.monomind', 'last-route.json');
|
|
559
568
|
try {
|
|
560
|
-
|
|
569
|
+
const routeStat = safeStat(routeFile);
|
|
570
|
+
if (!routeStat || routeStat.size > MAX_JSON_READ_BYTES) return null;
|
|
561
571
|
const data = JSON.parse(fs.readFileSync(routeFile, 'utf-8'));
|
|
562
572
|
if (!data || !data.agent) return null;
|
|
563
573
|
|
|
@@ -590,7 +600,7 @@ function getAgentDBStats() {
|
|
|
590
600
|
// 1. Count real entries from auto-memory-store.json
|
|
591
601
|
const storePath = path.join(CWD, '.monomind', 'data', 'auto-memory-store.json');
|
|
592
602
|
const storeStat = safeStat(storePath);
|
|
593
|
-
if (storeStat) {
|
|
603
|
+
if (storeStat && storeStat.size <= MAX_JSON_READ_BYTES) {
|
|
594
604
|
dbSizeKB += storeStat.size / 1024;
|
|
595
605
|
try {
|
|
596
606
|
const store = JSON.parse(fs.readFileSync(storePath, 'utf-8'));
|
|
@@ -804,12 +814,14 @@ function getKnowledgeStats() {
|
|
|
804
814
|
const skillsPath = path.join(CWD, '.monomind', 'skills.jsonl');
|
|
805
815
|
let chunks = 0, skills = 0;
|
|
806
816
|
try {
|
|
807
|
-
|
|
817
|
+
const chunksStat = safeStat(chunksPath);
|
|
818
|
+
if (chunksStat && chunksStat.size <= MAX_JSON_READ_BYTES) {
|
|
808
819
|
chunks = fs.readFileSync(chunksPath, 'utf-8').split('\\n').filter(Boolean).length;
|
|
809
820
|
}
|
|
810
821
|
} catch { /* ignore */ }
|
|
811
822
|
try {
|
|
812
|
-
|
|
823
|
+
const skillsStat = safeStat(skillsPath);
|
|
824
|
+
if (skillsStat && skillsStat.size <= MAX_JSON_READ_BYTES) {
|
|
813
825
|
skills = fs.readFileSync(skillsPath, 'utf-8').split('\\n').filter(Boolean).length;
|
|
814
826
|
}
|
|
815
827
|
} catch { /* ignore */ }
|
|
@@ -819,7 +831,8 @@ function getKnowledgeStats() {
|
|
|
819
831
|
function getTriggerStats() {
|
|
820
832
|
const indexPath = path.join(CWD, '.monomind', 'trigger-index.json');
|
|
821
833
|
try {
|
|
822
|
-
|
|
834
|
+
const idxStat = safeStat(indexPath);
|
|
835
|
+
if (!idxStat || idxStat.size > MAX_JSON_READ_BYTES) return { triggers: 0, agents: 0 };
|
|
823
836
|
const raw = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
|
|
824
837
|
const idx = raw.index || raw;
|
|
825
838
|
const triggers = Object.keys(idx).length;
|
|
@@ -832,7 +845,8 @@ function getTriggerStats() {
|
|
|
832
845
|
function getHookLatency() {
|
|
833
846
|
const p = path.join(CWD, '.monomind', 'metrics', 'hook-latency.json');
|
|
834
847
|
try {
|
|
835
|
-
|
|
848
|
+
const latStat = safeStat(p);
|
|
849
|
+
if (!latStat || latStat.size > MAX_JSON_READ_BYTES) return null;
|
|
836
850
|
const d = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
837
851
|
const perPrompt = ['route'];
|
|
838
852
|
let totalMs = 0; let count = 0;
|
|
@@ -854,7 +868,8 @@ function getHookLatency() {
|
|
|
854
868
|
function getGraphUsage() {
|
|
855
869
|
const usagePath = path.join(CWD, '.monomind', 'metrics', 'graph-usage.json');
|
|
856
870
|
try {
|
|
857
|
-
|
|
871
|
+
const usageStat = safeStat(usagePath);
|
|
872
|
+
if (!usageStat || usageStat.size > MAX_JSON_READ_BYTES) return null;
|
|
858
873
|
const d = JSON.parse(fs.readFileSync(usagePath, 'utf-8'));
|
|
859
874
|
const graphWins = (d.monograph_call || 0) + (d.preresolve_hit || 0)
|
|
860
875
|
+ (d.graph_assist_search || 0) + (d.graph_assist_neighbors || 0);
|
|
@@ -919,7 +934,10 @@ function getHILPending() {
|
|
|
919
934
|
const files = fs.readdirSync(loopsDir).filter(f => f.endsWith('-hil.md'));
|
|
920
935
|
for (const f of files) {
|
|
921
936
|
try {
|
|
922
|
-
const
|
|
937
|
+
const hilPath = path.join(loopsDir, f);
|
|
938
|
+
const hilStat = safeStat(hilPath);
|
|
939
|
+
if (!hilStat || hilStat.size > 512 * 1024) continue; // skip > 512 KB
|
|
940
|
+
const txt = fs.readFileSync(hilPath, 'utf-8');
|
|
923
941
|
const answered = /^[ \\t]*>[ \\t]+\\S/m.test(txt);
|
|
924
942
|
if (!answered) pending++;
|
|
925
943
|
} catch { /* ignore */ }
|
|
@@ -969,7 +987,9 @@ function getSIBudget() {
|
|
|
969
987
|
const SI_LIMIT = 1500;
|
|
970
988
|
const siPath = path.join(CWD, '.agents', 'shared_instructions.md');
|
|
971
989
|
try {
|
|
972
|
-
|
|
990
|
+
const siStat = safeStat(siPath);
|
|
991
|
+
if (!siStat) return null;
|
|
992
|
+
if (siStat.size > 2 * 1024 * 1024) return null; // skip > 2 MB
|
|
973
993
|
const len = fs.readFileSync(siPath, 'utf-8').length;
|
|
974
994
|
return { len, pct: Math.round((len / SI_LIMIT) * 100), limit: SI_LIMIT };
|
|
975
995
|
} catch { return null; }
|
|
@@ -1149,10 +1169,10 @@ function generateDashboard() {
|
|
|
1149
1169
|
|
|
1150
1170
|
const hil = getHILPending();
|
|
1151
1171
|
const hilStr = hil.pending > 0
|
|
1152
|
-
?
|
|
1153
|
-
:
|
|
1172
|
+
? \` \${DIV} \${x.coral}✨ \${x.bold}\${hil.pending}\${x.reset}\${x.coral} HIL pending\${x.reset}\`
|
|
1173
|
+
: \`\`;
|
|
1154
1174
|
|
|
1155
|
-
lines.push(\`\${x.teal}🧠 CONTEXT\${x.reset} \${graphStr}
|
|
1175
|
+
lines.push(\`\${x.teal}🧠 CONTEXT\${x.reset} \${graphStr}\${hilStr}\`);
|
|
1156
1176
|
|
|
1157
1177
|
return lines.join('\\n');
|
|
1158
1178
|
}
|
|
@@ -1180,7 +1200,8 @@ const MODE_FILE = path.join(CWD, '.monomind', 'statusline-mode.txt');
|
|
|
1180
1200
|
|
|
1181
1201
|
function readMode() {
|
|
1182
1202
|
try {
|
|
1183
|
-
|
|
1203
|
+
const modeStat = safeStat(MODE_FILE);
|
|
1204
|
+
if (modeStat && modeStat.size <= 1024) {
|
|
1184
1205
|
return fs.readFileSync(MODE_FILE, 'utf-8').trim();
|
|
1185
1206
|
}
|
|
1186
1207
|
} catch { /* ignore */ }
|
|
@@ -9,6 +9,57 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module v1/cli/mcp-tools/a2a-tools
|
|
11
11
|
*/
|
|
12
|
+
// ===== Input validation helpers =====
|
|
13
|
+
const MAX_AGENT_TYPE_LEN = 64; // slug length — catalogue keys are all < 30 chars
|
|
14
|
+
const MAX_BASE_URL_LEN = 2048; // typical browser URL limit
|
|
15
|
+
const MAX_TASK_ID_LEN = 256;
|
|
16
|
+
const MAX_SESSION_ID_LEN = 256;
|
|
17
|
+
// Allowlist of URL schemes that are safe to embed in returned Agent Card urls.
|
|
18
|
+
// Prevents javascript:, data:, file:// etc. from being reflected back to callers.
|
|
19
|
+
const ALLOWED_URL_SCHEMES = new Set(['http:', 'https:']);
|
|
20
|
+
/**
|
|
21
|
+
* Validate and return an agent type slug.
|
|
22
|
+
* Returns null when the value is not a string or exceeds the max length.
|
|
23
|
+
*/
|
|
24
|
+
function validateAgentType(value) {
|
|
25
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > MAX_AGENT_TYPE_LEN)
|
|
26
|
+
return null;
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validate and return a base URL.
|
|
31
|
+
* Accepts only http/https schemes and caps length to prevent oversized reflected values.
|
|
32
|
+
* Falls back to the default localhost URL on failure.
|
|
33
|
+
*/
|
|
34
|
+
function validateBaseUrl(value, fallback = 'http://localhost:3000') {
|
|
35
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
36
|
+
return fallback;
|
|
37
|
+
if (value.length > MAX_BASE_URL_LEN)
|
|
38
|
+
return fallback;
|
|
39
|
+
try {
|
|
40
|
+
const parsed = new URL(value);
|
|
41
|
+
if (!ALLOWED_URL_SCHEMES.has(parsed.protocol))
|
|
42
|
+
return fallback;
|
|
43
|
+
// Reject URLs with credentials — they should never appear in Agent Card endpoints
|
|
44
|
+
if (parsed.username || parsed.password)
|
|
45
|
+
return fallback;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return fallback;
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Validate an optional string ID (taskId / sessionId).
|
|
54
|
+
* Returns undefined when the value is absent; null when it is present but invalid.
|
|
55
|
+
*/
|
|
56
|
+
function validateOptionalId(value, maxLen) {
|
|
57
|
+
if (value === undefined || value === null)
|
|
58
|
+
return undefined;
|
|
59
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > maxLen)
|
|
60
|
+
return null;
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
12
63
|
// ===== Agent type catalogue =====
|
|
13
64
|
/** Well-known agent types and their A2A card metadata */
|
|
14
65
|
const AGENT_CARD_CATALOGUE = {
|
|
@@ -116,13 +167,16 @@ export const a2aTools = [
|
|
|
116
167
|
required: ['agentType'],
|
|
117
168
|
},
|
|
118
169
|
handler: async (input) => {
|
|
119
|
-
const agentType = input.agentType;
|
|
120
|
-
|
|
170
|
+
const agentType = validateAgentType(input.agentType);
|
|
171
|
+
if (!agentType) {
|
|
172
|
+
return { success: false, error: 'agentType is required (non-empty string, max 64 chars)' };
|
|
173
|
+
}
|
|
174
|
+
const baseUrl = validateBaseUrl(input.baseUrl);
|
|
121
175
|
const card = buildAgentCard(agentType, baseUrl);
|
|
122
176
|
if (!card) {
|
|
123
177
|
return {
|
|
124
178
|
success: false,
|
|
125
|
-
error: `Unknown agent type
|
|
179
|
+
error: `Unknown agent type. Available: ${Object.keys(AGENT_CARD_CATALOGUE).join(', ')}`,
|
|
126
180
|
};
|
|
127
181
|
}
|
|
128
182
|
return { success: true, agentCard: card, protocol: 'a2a', source: 'https://a2a-protocol.org' };
|
|
@@ -146,8 +200,19 @@ export const a2aTools = [
|
|
|
146
200
|
},
|
|
147
201
|
},
|
|
148
202
|
handler: async (input) => {
|
|
149
|
-
const baseUrl = input.baseUrl
|
|
150
|
-
|
|
203
|
+
const baseUrl = validateBaseUrl(input.baseUrl);
|
|
204
|
+
// Only accept a plain object capability filter to prevent prototype pollution.
|
|
205
|
+
// Object.create(null) maps and class instances are intentionally rejected.
|
|
206
|
+
const rawCap = input.capabilities;
|
|
207
|
+
const capabilityFilter = rawCap !== null &&
|
|
208
|
+
typeof rawCap === 'object' &&
|
|
209
|
+
!Array.isArray(rawCap) &&
|
|
210
|
+
Object.getPrototypeOf(rawCap) === Object.prototype
|
|
211
|
+
? rawCap
|
|
212
|
+
: undefined;
|
|
213
|
+
const KNOWN_CAPABILITY_KEYS = new Set([
|
|
214
|
+
'streaming', 'pushNotifications', 'stateTransitionHistory',
|
|
215
|
+
]);
|
|
151
216
|
const cards = Object.keys(AGENT_CARD_CATALOGUE)
|
|
152
217
|
.map(type => buildAgentCard(type, baseUrl))
|
|
153
218
|
.filter((card) => {
|
|
@@ -155,9 +220,12 @@ export const a2aTools = [
|
|
|
155
220
|
return false;
|
|
156
221
|
if (!capabilityFilter)
|
|
157
222
|
return true;
|
|
158
|
-
// Apply capability filter
|
|
159
|
-
|
|
160
|
-
|
|
223
|
+
// Apply capability filter — only iterate known keys to prevent
|
|
224
|
+
// prototype-chain access via attacker-controlled property names.
|
|
225
|
+
for (const key of KNOWN_CAPABILITY_KEYS) {
|
|
226
|
+
if (!(key in capabilityFilter))
|
|
227
|
+
continue;
|
|
228
|
+
if (card.capabilities[key] !== capabilityFilter[key])
|
|
161
229
|
return false;
|
|
162
230
|
}
|
|
163
231
|
return true;
|
|
@@ -203,15 +271,32 @@ export const a2aTools = [
|
|
|
203
271
|
required: ['agentType', 'message'],
|
|
204
272
|
},
|
|
205
273
|
handler: async (input) => {
|
|
206
|
-
const agentType = input.agentType;
|
|
274
|
+
const agentType = validateAgentType(input.agentType);
|
|
275
|
+
if (!agentType) {
|
|
276
|
+
return { success: false, error: 'agentType is required (non-empty string, max 64 chars)' };
|
|
277
|
+
}
|
|
207
278
|
const message = input.message;
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
279
|
+
const rawTaskId = validateOptionalId(input.taskId, MAX_TASK_ID_LEN);
|
|
280
|
+
if (rawTaskId === null) {
|
|
281
|
+
return { success: false, error: `taskId must be a non-empty string up to ${MAX_TASK_ID_LEN} chars` };
|
|
282
|
+
}
|
|
283
|
+
const taskId = rawTaskId ?? `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
284
|
+
const rawSessionId = validateOptionalId(input.sessionId, MAX_SESSION_ID_LEN);
|
|
285
|
+
if (rawSessionId === null) {
|
|
286
|
+
return { success: false, error: `sessionId must be a non-empty string up to ${MAX_SESSION_ID_LEN} chars` };
|
|
287
|
+
}
|
|
288
|
+
const sessionId = rawSessionId;
|
|
289
|
+
// Only accept plain objects for metadata to prevent prototype pollution
|
|
290
|
+
const metadata = input.metadata !== null &&
|
|
291
|
+
typeof input.metadata === 'object' &&
|
|
292
|
+
!Array.isArray(input.metadata) &&
|
|
293
|
+
Object.getPrototypeOf(input.metadata) === Object.prototype
|
|
294
|
+
? input.metadata
|
|
295
|
+
: {};
|
|
211
296
|
if (!AGENT_CARD_CATALOGUE[agentType]) {
|
|
212
297
|
return {
|
|
213
298
|
success: false,
|
|
214
|
-
error: `Unknown agent type
|
|
299
|
+
error: `Unknown agent type. Run a2a_discover to see available agents.`,
|
|
215
300
|
};
|
|
216
301
|
}
|
|
217
302
|
// Return the A2A-compliant task submission envelope
|
|
@@ -122,8 +122,18 @@ export const agentTools = [
|
|
|
122
122
|
},
|
|
123
123
|
handler: async (input) => {
|
|
124
124
|
const store = loadAgentStore();
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
// Cap agentId: used as the JSON object key in store.agents[agentId].
|
|
126
|
+
// An oversized key inflates the on-disk store for every spawned agent.
|
|
127
|
+
// Cap agentType/domain: persisted as AgentRecord field values.
|
|
128
|
+
const MAX_AGENT_ID_LEN = 256;
|
|
129
|
+
const MAX_AGENT_TYPE_LEN = 128;
|
|
130
|
+
const MAX_AGENT_DOMAIN_LEN = 256;
|
|
131
|
+
const rawAgentId = input.agentId || `agent-${Date.now()}-${randomBytes(4).toString('hex')}`;
|
|
132
|
+
const agentId = typeof rawAgentId === 'string' && rawAgentId.length > MAX_AGENT_ID_LEN
|
|
133
|
+
? rawAgentId.slice(0, MAX_AGENT_ID_LEN) : rawAgentId;
|
|
134
|
+
const rawAgentType = input.agentType;
|
|
135
|
+
const agentType = typeof rawAgentType === 'string' && rawAgentType.length > MAX_AGENT_TYPE_LEN
|
|
136
|
+
? rawAgentType.slice(0, MAX_AGENT_TYPE_LEN) : rawAgentType;
|
|
127
137
|
if (['__proto__', 'constructor', 'prototype'].includes(agentId)) {
|
|
128
138
|
return { success: false, agentId, error: 'Forbidden agent ID' };
|
|
129
139
|
}
|
|
@@ -141,6 +151,9 @@ export const agentTools = [
|
|
|
141
151
|
}
|
|
142
152
|
// Get task from either top-level or config (CLI passes it in config.task)
|
|
143
153
|
const task = input.task || config.task || undefined;
|
|
154
|
+
const rawDomain = input.domain;
|
|
155
|
+
const domain = typeof rawDomain === 'string' && rawDomain.length > MAX_AGENT_DOMAIN_LEN
|
|
156
|
+
? rawDomain.slice(0, MAX_AGENT_DOMAIN_LEN) : rawDomain;
|
|
144
157
|
// Determine model using ADR-026 3-tier routing logic
|
|
145
158
|
const routingResult = await determineAgentModel(agentType, config, task);
|
|
146
159
|
const agent = {
|
|
@@ -151,7 +164,7 @@ export const agentTools = [
|
|
|
151
164
|
taskCount: 0,
|
|
152
165
|
config,
|
|
153
166
|
createdAt: new Date().toISOString(),
|
|
154
|
-
domain
|
|
167
|
+
domain,
|
|
155
168
|
model: routingResult.model,
|
|
156
169
|
modelRoutedBy: routingResult.routedBy,
|
|
157
170
|
};
|